Experimental iOS Component "Avatar" (#482)
* initial commit * AvatarData also wrapped * Change files * Used Memo Cache to map JS API to Native API * Update from PR comments * Address PR Comments * remove experimental avatar from core * Remove commented code, fix dependencies * Remove dependency from fluent-tester-ios * Change include path * Updated fluent tester package.json * remove extra tab space
This commit is contained in:
Родитель
b951659d25
Коммит
6a48956ff1
|
@ -63,7 +63,11 @@
|
|||
"editor.formatOnSave": false
|
||||
},
|
||||
"cSpell.words": [
|
||||
"TESTPAGE",
|
||||
"beachball",
|
||||
"consts",
|
||||
"fluentui",
|
||||
"macos",
|
||||
"nuget"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
"@fluentui-react-native/framework": ">=0.3.8 <1.0.0",
|
||||
"@fluentui-react-native/stack": ">=0.2.18 <1.0.0",
|
||||
"@fluentui-react-native/interactive-hooks": ">=0.6.0 <1.0.0",
|
||||
"@fluentui-react-native/experimental-avatar": ">= 0.1.0 < 1.0.0",
|
||||
"@fluentui-react-native/experimental-button": "0.2.0",
|
||||
"@uifabricshared/theming-react-native": ">=0.9.0 <1.0.0",
|
||||
"@uifabricshared/theme-registry": ">=0.3.71 <1.0.0",
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
import * as React from 'react';
|
||||
import { Avatar } from '@fluentui-react-native/experimental-avatar';
|
||||
import { Stack } from '@fluentui-react-native/stack';
|
||||
import { stackStyle } from '../Common/styles';
|
||||
import { AVATAR_TESTPAGE } from './consts';
|
||||
import { Test, TestSection, PlatformStatus } from '../Test';
|
||||
|
||||
const avatar: React.FunctionComponent<{}> = () => {
|
||||
return (
|
||||
<Stack style={stackStyle}>
|
||||
<Avatar primaryText="John Smith" />
|
||||
<Avatar primaryText="John Smith" avatarStyle="square" />
|
||||
<Avatar primaryText="John Smith" presence="available" />
|
||||
<Avatar primaryText="John Smith" secondaryText="johnsmith@microsoft.com" presence="outOfOffice" />
|
||||
<Avatar secondaryText="johnsmith@microsoft.com" presence="outOfOffice" />
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
const stylizedAvatar: React.FunctionComponent<{}> = () => {
|
||||
const CustomizedAvatar = Avatar.customize({
|
||||
size: 'large',
|
||||
});
|
||||
|
||||
return (
|
||||
<Stack style={stackStyle}>
|
||||
<CustomizedAvatar primaryText="John Smith" />
|
||||
<CustomizedAvatar primaryText="John Smith" avatarStyle="square" />
|
||||
<CustomizedAvatar primaryText="John Smith" presence="available" />
|
||||
<CustomizedAvatar primaryText="John Smith" secondaryText="johnsmith@microsoft.com" presence="outOfOffice" />
|
||||
<CustomizedAvatar secondaryText="johnsmith@microsoft.com" presence="outOfOffice" />
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
const avatarSections: TestSection[] = [
|
||||
{
|
||||
name: 'Basic Avatar',
|
||||
testID: AVATAR_TESTPAGE,
|
||||
component: avatar,
|
||||
},
|
||||
{
|
||||
name: 'Stylized Avatar',
|
||||
component: stylizedAvatar,
|
||||
},
|
||||
];
|
||||
|
||||
export const AvatarTest: React.FunctionComponent<{}> = () => {
|
||||
const status: PlatformStatus = {
|
||||
win32Status: 'Backlog',
|
||||
uwpStatus: 'Backlog',
|
||||
iosStatus: 'Beta',
|
||||
macosStatus: 'Backlog',
|
||||
androidStatus: 'Backlog',
|
||||
};
|
||||
|
||||
const description =
|
||||
'AvatarView is a visual representation of a user, entity, or group. If an image is supplied, it is cropped to a circle of the requested size. If an image is not supplied, initials are extracted from the given name and email address provided and displayed on a colorful background.';
|
||||
|
||||
return <Test name="Avatar Test" description={description} sections={avatarSections} status={status}></Test>;
|
||||
};
|
|
@ -0,0 +1,2 @@
|
|||
export const HOMEPAGE_AVATAR_BUTTON = 'Homepage_Avatar_Button';
|
||||
export const AVATAR_TESTPAGE = 'Avatar_TestPage';
|
|
@ -0,0 +1,2 @@
|
|||
export * from './AvatarTest';
|
||||
export * from './consts';
|
|
@ -1,4 +1,5 @@
|
|||
import { TestDescription } from './TestComponents';
|
||||
import { AvatarTest, HOMEPAGE_AVATAR_BUTTON } from './TestComponents/Avatar';
|
||||
import { ButtonTest, HOMEPAGE_BUTTON_BUTTON } from './TestComponents/Button';
|
||||
import { CalloutTest, HOMEPAGE_CALLOUT_BUTTON } from './TestComponents/Callout';
|
||||
import { CheckboxTest, HOMEPAGE_CHECKBOX_BUTTON } from './TestComponents/Checkbox';
|
||||
|
@ -16,6 +17,11 @@ import { HOMEPAGE_TEXT_BUTTON, TextTest } from './TestComponents/Text';
|
|||
import { HOMEPAGE_THEME_BUTTON, ThemeTest } from './TestComponents/Theme';
|
||||
|
||||
export const tests: TestDescription[] = [
|
||||
{
|
||||
name: 'Avatar Test',
|
||||
component: AvatarTest,
|
||||
testPage: HOMEPAGE_AVATAR_BUTTON,
|
||||
},
|
||||
{
|
||||
name: 'Button Test',
|
||||
component: ButtonTest,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { TestDescription } from './TestComponents';
|
||||
import { AvatarTest, HOMEPAGE_AVATAR_BUTTON } from './TestComponents/Avatar';
|
||||
import { ButtonTest, HOMEPAGE_BUTTON_BUTTON } from './TestComponents/Button';
|
||||
import { CheckboxTest, HOMEPAGE_CHECKBOX_BUTTON } from './TestComponents/Checkbox';
|
||||
import { FocusTrapTest, HOMEPAGE_FOCUSTRAPZONE_BUTTON } from './TestComponents/FocusTrapZone';
|
||||
|
@ -16,6 +17,11 @@ import { HOMEPAGE_BUTTON_BUTTONEXPERIMENTAL, ExperimentalButtonTest } from './Te
|
|||
import { HOMEPAGE_FOCUSZONE_BUTTON, FocusZoneTest } from './TestComponents/FocusZone';
|
||||
|
||||
export const tests: TestDescription[] = [
|
||||
{
|
||||
name: 'Avatar Test',
|
||||
component: AvatarTest,
|
||||
testPage: HOMEPAGE_AVATAR_BUTTON,
|
||||
},
|
||||
{
|
||||
name: 'Button Test',
|
||||
component: ButtonTest,
|
||||
|
|
|
@ -27,7 +27,7 @@ fi
|
|||
use_flipper!(false)
|
||||
use_test_app! do |target|
|
||||
target.app do
|
||||
|
||||
pod 'FluentUI-React-Native-Avatar', :path => '../../../packages/experimental/Avatar/FluentUIReactNativeAvatar.podspec'
|
||||
pod 'FluentUI-React-Native-Shimmer', :path => '../../../packages/components/Shimmer/FluentUIReactNativeShimmer.podspec'
|
||||
|
||||
script_phase name: 'Start Packager',
|
||||
|
|
|
@ -9,7 +9,10 @@ PODS:
|
|||
- React-Core (= 0.62.2)
|
||||
- React-jsi (= 0.62.2)
|
||||
- ReactCommon/turbomodule/core (= 0.62.2)
|
||||
- FluentUI-React-Native-Shimmer (0.2.9):
|
||||
- FluentUI-React-Native-Avatar (0.1.0):
|
||||
- MicrosoftFluentUI (~> 0.1.12)
|
||||
- React
|
||||
- FluentUI-React-Native-Shimmer (0.2.10):
|
||||
- MicrosoftFluentUI (~> 0.1.12)
|
||||
- React
|
||||
- Folly (2018.10.22.00):
|
||||
|
@ -22,7 +25,7 @@ PODS:
|
|||
- DoubleConversion
|
||||
- glog
|
||||
- glog (0.3.5)
|
||||
- MicrosoftFluentUI (0.1.12)
|
||||
- MicrosoftFluentUI (0.1.13)
|
||||
- QRCodeReader.swift (10.1.0)
|
||||
- RCTRequired (0.62.2)
|
||||
- RCTTypeSafety (0.62.2):
|
||||
|
@ -248,13 +251,14 @@ PODS:
|
|||
- ReactCommon/callinvoker (= 0.62.2)
|
||||
- ReactTestApp-DevSupport (0.2.9)
|
||||
- ReactTestApp-Resources (1.0.0-dev)
|
||||
- SwiftLint (0.40.1)
|
||||
- SwiftLint (0.40.3)
|
||||
- Yoga (1.14.0)
|
||||
|
||||
DEPENDENCIES:
|
||||
- DoubleConversion (from `../../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||
- FBLazyVector (from `../../../node_modules/react-native/Libraries/FBLazyVector`)
|
||||
- FBReactNativeSpec (from `../../../node_modules/react-native/Libraries/FBReactNativeSpec`)
|
||||
- FluentUI-React-Native-Avatar (from `../../../packages/experimental/Avatar/FluentUIReactNativeAvatar.podspec`)
|
||||
- FluentUI-React-Native-Shimmer (from `../../../packages/components/Shimmer/FluentUIReactNativeShimmer.podspec`)
|
||||
- Folly (from `../../../node_modules/react-native/third-party-podspecs/Folly.podspec`)
|
||||
- glog (from `../../../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
||||
|
@ -300,6 +304,8 @@ EXTERNAL SOURCES:
|
|||
:path: "../../../node_modules/react-native/Libraries/FBLazyVector"
|
||||
FBReactNativeSpec:
|
||||
:path: "../../../node_modules/react-native/Libraries/FBReactNativeSpec"
|
||||
FluentUI-React-Native-Avatar:
|
||||
:path: "../../../packages/experimental/Avatar/FluentUIReactNativeAvatar.podspec"
|
||||
FluentUI-React-Native-Shimmer:
|
||||
:path: "../../../packages/components/Shimmer/FluentUIReactNativeShimmer.podspec"
|
||||
Folly:
|
||||
|
@ -356,10 +362,11 @@ SPEC CHECKSUMS:
|
|||
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
|
||||
FBLazyVector: 4aab18c93cd9546e4bfed752b4084585eca8b245
|
||||
FBReactNativeSpec: 5465d51ccfeecb7faa12f9ae0024f2044ce4044e
|
||||
FluentUI-React-Native-Shimmer: 74b1e66f2672d4351b16ec36904f20fb1b41713c
|
||||
FluentUI-React-Native-Avatar: 4043d10df5dad8107a2a71f9ea627fd62811ff34
|
||||
FluentUI-React-Native-Shimmer: a89d87c12baec72b263153f01f2eb61c30850f6f
|
||||
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
|
||||
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
|
||||
MicrosoftFluentUI: 6800fd4c017a5c5b946a24851ac2218748da45d2
|
||||
MicrosoftFluentUI: dbebf152cd2e7864ace2d5079d509ec1fee19cbf
|
||||
QRCodeReader.swift: 373a389fe9a22d513c879a32a6f647c58f4ef572
|
||||
RCTRequired: cec6a34b3ac8a9915c37e7e4ad3aa74726ce4035
|
||||
RCTTypeSafety: 93006131180074cffa227a1075802c89a49dd4ce
|
||||
|
@ -382,9 +389,9 @@ SPEC CHECKSUMS:
|
|||
ReactCommon: ed4e11d27609d571e7eee8b65548efc191116eb3
|
||||
ReactTestApp-DevSupport: 9a0663d12f90115e646ddbf070566c646a7b9fd1
|
||||
ReactTestApp-Resources: 5950ae44720217c6778ff03fb1d906c8fb3ce483
|
||||
SwiftLint: bbfed21bf4451dcbd0f5cdbee44a18e06cf91b12
|
||||
SwiftLint: dfd554ff0dff17288ee574814ccdd5cea85d76f7
|
||||
Yoga: 3ebccbdd559724312790e7742142d062476b698e
|
||||
|
||||
PODFILE CHECKSUM: 42dde6a3630fe1498f92905782bda6387e25596e
|
||||
PODFILE CHECKSUM: 92b58eb5d35bda5732fd91cad06be75b94e8f6b1
|
||||
|
||||
COCOAPODS: 1.9.3
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"type": "minor",
|
||||
"comment": "New experimental component avatar",
|
||||
"packageName": "@fluentui/react-native",
|
||||
"email": "saadnajmi2@gmail.com",
|
||||
"dependentChangeType": "patch",
|
||||
"date": "2020-09-24T08:29:24.155Z"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"type": "minor",
|
||||
"comment": "New experimental component avatar",
|
||||
"packageName": "@fluentui-react-native/experimental-avatar",
|
||||
"email": "saadnajmi2@gmail.com",
|
||||
"dependentChangeType": "patch",
|
||||
"date": "2020-09-24T08:29:18.037Z"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"type": "minor",
|
||||
"comment": "New experimental component avatar",
|
||||
"packageName": "@fluentui-react-native/tester",
|
||||
"email": "saadnajmi2@gmail.com",
|
||||
"dependentChangeType": "patch",
|
||||
"date": "2020-09-24T08:28:56.757Z"
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
require 'json'
|
||||
|
||||
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
||||
version = package['version']
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'FluentUI-React-Native-Avatar'
|
||||
s.version = "#{version}"
|
||||
s.summary = 'Fluent UI React Native Avatar Control'
|
||||
s.homepage = "https://www.microsoft.com/design/fluent/#/"
|
||||
s.author = { "Microsoft" => "fluentuinativeowners@microsoft.com"}
|
||||
s.source = { :git => "https://github.com/microsoft/fluentui-react-native.git", :tag => "#{s.version}" }
|
||||
s.swift_version = "5"
|
||||
s.module_name = 'FluentUIReactNativeAvatar'
|
||||
|
||||
s.ios.deployment_target = "11.0"
|
||||
s.ios.source_files = "ios/*.{swift,h,m}"
|
||||
|
||||
s.dependency 'React'
|
||||
s.dependency 'MicrosoftFluentUI', '~> 0.1.12'
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": "@uifabricshared/build-native/api-extractor.json"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
module.exports = require('@uifabricshared/build-native/babel.config');
|
|
@ -0,0 +1 @@
|
|||
#import <React/RCTViewManager.h>
|
|
@ -0,0 +1,27 @@
|
|||
import Foundation
|
||||
import FluentUI
|
||||
|
||||
@objc(MSFAvatarViewManager)
|
||||
class AvatarViewManager: RCTViewManager {
|
||||
override func view()->UIView! {
|
||||
let avatarView = AvatarView(avatarSize: .small)
|
||||
return avatarView
|
||||
}
|
||||
|
||||
override class func requiresMainQueueSetup() -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
override func constantsToExport() -> [AnyHashable : Any]! {
|
||||
return [
|
||||
"sizes" : [
|
||||
"xSmall" : AvatarSize.extraSmall.size.width,
|
||||
"small" : AvatarSize.small.size.width,
|
||||
"medium" : AvatarSize.medium.size.width,
|
||||
"large" : AvatarSize.large.size.width,
|
||||
"xLarge" : AvatarSize.extraLarge.size.width,
|
||||
"xxLarge" : AvatarSize.extraExtraLarge.size.width
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
#import <React/RCTComponent.h>
|
||||
#import <React/RCTViewManager.h>
|
||||
|
||||
@import FluentUI;
|
||||
|
||||
@implementation RCTConvert (MSFAvatarViewAdditions)
|
||||
|
||||
RCT_ENUM_CONVERTER(MSFAvatarSize, (@{
|
||||
@"xSmall": @(MSFAvatarSizeExtraSmall),
|
||||
@"small": @(MSFAvatarSizeSmall),
|
||||
@"medium": @(MSFAvatarSizeMedium),
|
||||
@"large": @(MSFAvatarSizeLarge),
|
||||
@"xLarge": @(MSFAvatarSizeExtraLarge),
|
||||
@"xxLarge": @(MSFAvatarSizeExtraExtraLarge),
|
||||
}), MSFAvatarSizeSmall, integerValue);
|
||||
|
||||
RCT_ENUM_CONVERTER(MSFAvatarStyle, (@{
|
||||
@"circle": @(MSFAvatarStyleCircle),
|
||||
@"square": @(MSFAvatarStyleSquare),
|
||||
}), MSFAvatarStyleCircle, integerValue);
|
||||
|
||||
RCT_ENUM_CONVERTER(MSFAvatarFallbackImageStyle, (@{
|
||||
@"onAccentFilled": @(MSFAvatarFallbackImageStyleOnAccentFilled),
|
||||
@"outlined": @(MSFAvatarFallbackImageStyleOutlined),
|
||||
@"primaryFilled": @(MSFAvatarFallbackImageStylePrimaryFilled),
|
||||
@"primaryOutlined": @(MSFAvatarFallbackImageStylePrimaryOutlined),
|
||||
}), MSFAvatarFallbackImageStyleOutlined, integerValue);
|
||||
|
||||
RCT_ENUM_CONVERTER(MSFPresence, (@{
|
||||
@"none": @(MSFPresenceNone),
|
||||
@"available": @(MSFPresenceAvailable),
|
||||
@"away": @(MSFPresenceAway),
|
||||
@"busy": @(MSFPresenceBusy),
|
||||
@"doNotDisturb": @(MSFPresenceDoNotDisturb),
|
||||
@"outOfOffice": @(MSFPresenceOutOfOffice),
|
||||
@"offline": @(MSFPresenceOffline),
|
||||
@"unknown": @(MSFPresenceUnknown),
|
||||
@"blocked": @(MSFPresenceBlocked),
|
||||
}), MSFPresenceNone, integerValue);
|
||||
|
||||
+ (MSFAvatarData *)MSFAvatarData:(id)json
|
||||
{
|
||||
return [[MSFAvatarData alloc]initWithPrimaryText:[RCTConvert NSString:json[@"primaryText"]]
|
||||
secondaryText:[RCTConvert NSString:json[@"secondaryText"]]
|
||||
image:[RCTConvert UIImage:json[@"image"]]
|
||||
presence:[RCTConvert MSFPresence:json[@"presence"]]
|
||||
color:[RCTConvert UIColor:json[@"color"]]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RCT_EXTERN_MODULE(MSFAvatarViewManager, RCTViewManager)
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(avatarSize, MSFAvatarSize);
|
||||
RCT_EXPORT_VIEW_PROPERTY(avatarBackgroundColor, UIColor);
|
||||
RCT_EXPORT_VIEW_PROPERTY(customBorderImage, UIImage);
|
||||
|
||||
RCT_REMAP_VIEW_PROPERTY(avatarStyle, style, MSFAvatarStyle)
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(borderColor, UIColor);
|
||||
RCT_EXPORT_VIEW_PROPERTY(presence, MSFPresence);
|
||||
RCT_EXPORT_VIEW_PROPERTY(useOpaquePresenceBorder, bool);
|
||||
|
||||
RCT_REMAP_VIEW_PROPERTY(accessibilityLabel, overrideAccessibilityLabel, NSString);
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(preferredFallbackImageStyle, MSFAvatarFallbackImageStyle);
|
||||
|
||||
RCT_REMAP_VIEW_PROPERTY(hasPointerInteractionIOS, hasPointerInteraction, bool)
|
||||
|
||||
RCT_CUSTOM_VIEW_PROPERTY(avatarData, MSFAvatarData, MSFAvatarView)
|
||||
{
|
||||
MSFAvatarData *avatarData = [RCTConvert MSFAvatarData:json];
|
||||
[view setupWithAvatar:avatarData];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,3 @@
|
|||
const { preset } = require('@uifabricshared/build-native');
|
||||
|
||||
preset();
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"name": "@fluentui-react-native/experimental-avatar",
|
||||
"version": "0.1.0",
|
||||
"description": "An Avatar view",
|
||||
"main": "src/index.ts",
|
||||
"module": "src/index.ts",
|
||||
"typings": "lib/index.d.ts",
|
||||
"onPublish": {
|
||||
"main": "lib-commonjs/index.js",
|
||||
"module": "lib/index.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "fluentui-scripts build",
|
||||
"just": "fluentui-scripts",
|
||||
"clean": "fluentui-scripts clean",
|
||||
"lint": "fluentui-scripts eslint",
|
||||
"depcheck": "fluentui-scripts depcheck",
|
||||
"test": "fluentui-scripts jest",
|
||||
"update-snapshots": "fluentui-scripts jest -u",
|
||||
"verify-api": "fluentui-scripts verify-api-extractor",
|
||||
"update-api": "fluentui-scripts update-api-extractor"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluentui-react-native/component-cache": "^1.0.3",
|
||||
"@fluentui-react-native/framework": "0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-native": "^0.62.0",
|
||||
"@uifabricshared/build-native": "^0.1.1",
|
||||
"@uifabricshared/eslint-config-rules": "^0.1.1",
|
||||
"react-native": "0.62.2",
|
||||
"react": "16.11.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-native": ">=0.60.0",
|
||||
"react": "16.11.0"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT"
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
/** @jsx withSlots */
|
||||
import { compose, UseSlots, buildProps, mergeProps, withSlots } from '@fluentui-react-native/framework';
|
||||
import { Image, NativeModules, ViewProps } from 'react-native';
|
||||
import { ensureNativeComponent } from '@fluentui-react-native/component-cache';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
const avatarName = 'Avatar';
|
||||
|
||||
const NativeAvatarView = ensureNativeComponent('MSFAvatarView');
|
||||
|
||||
export type Size = 'xSmall' | 'small' | 'medium' | 'large' | 'xLarge' | 'xxLarge';
|
||||
|
||||
export type AvatarStyle = 'circle' | 'square';
|
||||
|
||||
export type Presence = 'none' | 'available' | 'away' | 'doNotDisturb' | 'outOfOffice' | 'offline' | 'unknown' | 'unknown' | 'blocked';
|
||||
|
||||
interface ExportedConstants {
|
||||
sizes: { [key in Size]: number };
|
||||
}
|
||||
|
||||
const ExportedNativeConstants: ExportedConstants = NativeModules.MSFAvatarViewManager;
|
||||
|
||||
export type AvatarData = {
|
||||
/**
|
||||
* The primary text to create initials with (e.g. a name)
|
||||
*/
|
||||
primaryText?: string;
|
||||
|
||||
/**
|
||||
* The secondary text to create initials with if primary text is not provided (e.g. an email address)
|
||||
*/
|
||||
secondaryText?: string;
|
||||
|
||||
/**
|
||||
* The image to be displayed
|
||||
*/
|
||||
image?: Image;
|
||||
|
||||
/**
|
||||
* The color that represents this avatar.
|
||||
* This color will override the initials view's background color.
|
||||
* If the avatar view is configured to display a border, this will be the border's color.
|
||||
* The colored border will not be displayed if a custom border image is provided.
|
||||
*/
|
||||
color?: string;
|
||||
|
||||
/**
|
||||
* Image to be used as border around the avatar. It will be used as a pattern image color,
|
||||
* but It will be scaled to fit the avatar size. If set, the hasBorder initializer value will be ignored,
|
||||
* since it's assumed that the client intends to have a custom border.
|
||||
*/
|
||||
customBorderImage?: Image;
|
||||
|
||||
/**
|
||||
* The avatar view's presence state.
|
||||
* The presence state is only shown when the style is set to AvatarStyle.circle.
|
||||
*/
|
||||
presence?: Presence;
|
||||
};
|
||||
|
||||
export type otherAvatarProps = {
|
||||
/**
|
||||
* Supported Avatar sizes
|
||||
*/
|
||||
size?: Size;
|
||||
|
||||
/**
|
||||
* Background Color of initials
|
||||
*/
|
||||
backgroundColor?: string;
|
||||
|
||||
/**
|
||||
* Image to be used as border around the avatar. It will be used as a pattern image color,
|
||||
* but It will be scaled to fit the avatar size. If set, the hasBorder initializer value will be ignored,
|
||||
* since it's assumed that the client intends to have a custom border.
|
||||
*/
|
||||
customBorderImage?: Image;
|
||||
|
||||
/**
|
||||
* Shape of the AvatarView
|
||||
* Circle is used to represent people
|
||||
* Square is used to represent organizations or teams
|
||||
*/
|
||||
avatarStyle?: AvatarStyle;
|
||||
|
||||
/**
|
||||
* The color of the border of the avatar view
|
||||
*/
|
||||
borderColor?: string;
|
||||
|
||||
/**
|
||||
* When true, the presence status border is opaque. Otherwise, it is transparent.
|
||||
*/
|
||||
usesOpaquePresenceBorder?: boolean;
|
||||
|
||||
/**
|
||||
* Used when avatarView doesn't have image or can't generate initials string
|
||||
*/
|
||||
preferredFallBackImageStyle?: string;
|
||||
|
||||
/**
|
||||
* Set to true to enable the iPadOS pointer interactions on the avatar view, false by default.
|
||||
*/
|
||||
hasPointerInteractionIOS?: boolean;
|
||||
};
|
||||
|
||||
export type AvatarTokens = {
|
||||
/**
|
||||
* Supported Avatar sizes
|
||||
*/
|
||||
size?: Size;
|
||||
};
|
||||
|
||||
const tokensThatAreAlsoProps: (keyof AvatarTokens)[] = ['size'];
|
||||
|
||||
// The Javascript API is a flat list for all the props we can set on our component
|
||||
export type AvatarProps = ViewProps & otherAvatarProps & AvatarData;
|
||||
|
||||
// The Native component API has a sub object that we flattened out in AvatarProps
|
||||
export type NativeAvatarViewProps = ViewProps &
|
||||
otherAvatarProps & {
|
||||
avatarData?: AvatarData;
|
||||
};
|
||||
|
||||
interface AvatarType {
|
||||
props: AvatarProps;
|
||||
slotProps: { root: NativeAvatarViewProps };
|
||||
tokens: AvatarTokens;
|
||||
}
|
||||
|
||||
export const Avatar = compose<AvatarType>({
|
||||
displayName: avatarName,
|
||||
tokens: [
|
||||
{
|
||||
size: 'small',
|
||||
},
|
||||
avatarName,
|
||||
],
|
||||
tokensThatAreAlsoProps,
|
||||
slots: { root: NativeAvatarView },
|
||||
slotProps: {
|
||||
root: buildProps<NativeAvatarViewProps, AvatarTokens>(
|
||||
(tokens) => ({
|
||||
size: tokens.size,
|
||||
style: {
|
||||
height: ExportedNativeConstants.sizes[tokens.size],
|
||||
width: ExportedNativeConstants.sizes[tokens.size],
|
||||
},
|
||||
}),
|
||||
['size'],
|
||||
),
|
||||
},
|
||||
render: (props: AvatarProps, useSlots: UseSlots<AvatarType>) => {
|
||||
const Root = useSlots(props).root;
|
||||
|
||||
const memoizedAvatarData = useMemo(
|
||||
() => ({
|
||||
primaryText: props.primaryText,
|
||||
secondaryText: props.secondaryText,
|
||||
image: props.image,
|
||||
color: props.color,
|
||||
customBorderImage: props.customBorderImage,
|
||||
presence: props.presence,
|
||||
}),
|
||||
[props.primaryText, props.secondaryText, props.image, props.color, props.customBorderImage, props.presence],
|
||||
);
|
||||
|
||||
return (rest: AvatarProps) => <Root {...mergeProps(props, rest)} avatarData={memoizedAvatarData} />;
|
||||
},
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
export * from './Avatar';
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": "@uifabricshared/build-native/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
15
yarn.lock
15
yarn.lock
|
@ -1184,6 +1184,21 @@
|
|||
exec-sh "^0.3.2"
|
||||
minimist "^1.2.0"
|
||||
|
||||
"@fluentui-react-native/framework@0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui-react-native/framework/-/framework-0.3.0.tgz#dff9a330136db795b67bef805f57c6bb72c251b3"
|
||||
integrity sha512-BAKOf0lX241Zy5G4qrACXcBjgVIWEYWPaQXo+7p7Ausc0/OD9Q/t9K6ndu2MeQkDz8O6lObd6mNs3uXee6YOfA==
|
||||
dependencies:
|
||||
"@fluentui-react-native/composition" ">=0.3.6 <1.0.0"
|
||||
"@fluentui-react-native/immutable-merge" "^1.0.1"
|
||||
"@fluentui-react-native/memo-cache" "^1.0.2"
|
||||
"@fluentui-react-native/merge-props" ">=0.1.1 <1.0.0"
|
||||
"@fluentui-react-native/tokens" ">=0.5.6 <1.0.0"
|
||||
"@fluentui-react-native/use-slots" ">=0.3.6 <1.0.0"
|
||||
"@fluentui-react-native/use-styling" ">=0.3.0 <1.0.0"
|
||||
"@uifabricshared/theming-ramp" ">=0.10.5 <1.0.0"
|
||||
"@uifabricshared/theming-react-native" ">=0.7.76 <1.0.0"
|
||||
|
||||
"@hapi/address@2.x.x":
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"
|
||||
|
|
Загрузка…
Ссылка в новой задаче