@carrier-dpx/air-react-library 0.7.20 → 0.7.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carrier-dpx/air-react-library",
3
- "version": "0.7.20",
3
+ "version": "0.7.22",
4
4
  "description": "Air web React component library for Figma Make",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Figma Code Connect Configuration for Avatar Component
3
+ *
4
+ * Figma URL: https://www.figma.com/design/vkoHdM6rchIhH9IWetZeP0/Air--Components?node-id=6587-47403
5
+ *
6
+ * Figma Properties:
7
+ * - variant (circle, rounded)
8
+ * - size (large: 48px, medium: 40px, small: 32px, xsmall: 24px, micro: 20px)
9
+ * - type (image, letter, icon)
10
+ * - ✏️ Letter (text property) - layer name "Letter"
11
+ */
12
+
13
+ import figma from "@figma/code-connect";
14
+ import Avatar from "./Avatar";
15
+ import Icon from "../Icon";
16
+
17
+ figma.connect(
18
+ Avatar,
19
+ "https://www.figma.com/design/vkoHdM6rchIhH9IWetZeP0/Air--Components?node-id=6587-47403",
20
+ {
21
+ props: {
22
+ /**
23
+ * VARIANT MAPPING
24
+ * Maps Figma's "variant" property to React's "variant" prop
25
+ * Figma: circle → React: "circular"
26
+ * Figma: rounded → React: "rounded"
27
+ */
28
+ variant: figma.enum("variant", {
29
+ circle: "circular",
30
+ rounded: "rounded",
31
+ }),
32
+
33
+ /**
34
+ * SIZE MAPPING
35
+ * Maps Figma's "size" property to React's "size" prop
36
+ * Figma: large (48px), medium (40px), small (32px), xsmall (24px), micro (20px)
37
+ */
38
+ size: figma.enum("size", {
39
+ large: "large",
40
+ medium: "medium",
41
+ small: "small",
42
+ xsmall: "xsmall",
43
+ micro: "micro",
44
+ }),
45
+
46
+ /**
47
+ * TYPE MAPPING
48
+ * Maps Figma's "type" property to determine how Avatar is rendered
49
+ * - image: uses src prop
50
+ * - letter: uses children with text from "✏️ Letter"
51
+ * - icon: uses children with Icon component
52
+ */
53
+ type: figma.enum("type", {
54
+ image: "image",
55
+ letter: "letter",
56
+ icon: "icon",
57
+ }),
58
+
59
+ /**
60
+ * LETTER TEXT
61
+ * Maps text property "✏️ Letter" from layer "Letter"
62
+ * Used when type="letter"
63
+ */
64
+ letter: figma.string("✏️ Letter"),
65
+
66
+ /**
67
+ * ICON NESTED PROPERTIES
68
+ * Access Icon's fontSize and SVG through nested properties
69
+ * Used when type="icon"
70
+ */
71
+ icon: figma.nestedProps("Icon", {
72
+ fontSize: figma.enum("fontSize", {
73
+ large: "large",
74
+ medium: "medium",
75
+ small: "small",
76
+ xsmall: "xsmall",
77
+ }),
78
+ children: figma.instance("SVG"),
79
+ }),
80
+ },
81
+
82
+ /**
83
+ * EXAMPLE CODE TEMPLATE
84
+ * Shows how Avatar should be used based on type
85
+ */
86
+ example: ({ variant, size, type, letter, icon }) => {
87
+ if (type === "icon") {
88
+ return (
89
+ <Avatar variant={variant} size={size}>
90
+ <Icon fontSize={icon.fontSize}>
91
+ {icon.children}
92
+ </Icon>
93
+ </Avatar>
94
+ );
95
+ }
96
+
97
+ // Default to letter type (or image if src is provided via sx)
98
+ return (
99
+ <Avatar variant={variant} size={size}>
100
+ {letter}
101
+ </Avatar>
102
+ );
103
+ },
104
+ }
105
+ );
@@ -0,0 +1,111 @@
1
+ import { forwardRef } from "react";
2
+
3
+ import MuiAvatar, { AvatarProps as MuiAvatarProps } from "@mui/material/Avatar";
4
+ import { blueGrey } from "@mui/material/colors";
5
+ import { CSSObject, styled } from "@mui/material/styles";
6
+
7
+ import { styleTokens } from "../theme/constants/styleTokens";
8
+ import { getDisplayStringForAvatar } from "../utils/DataDisplayUtils";
9
+ import { getSxStyles } from "../utils/styles";
10
+
11
+ export interface AvatarProps extends MuiAvatarProps {
12
+ variant?: "circular" | "rounded";
13
+ /**
14
+ * Size of the Avatar
15
+ * - large: 48px
16
+ * - medium: 40px
17
+ * - small: 32px
18
+ * - xsmall: 24px
19
+ * - micro: 20px
20
+ */
21
+ size?: "large" | "medium" | "small" | "xsmall" | "micro";
22
+ }
23
+
24
+ /** The Avatar component represents a unique user or entity through a custom image, initials or icon.
25
+ *
26
+ * // Default import
27
+ * import Avatar from '@carrier-dpx/air-react-library/Avatar'
28
+ *
29
+ * // Named import
30
+ * import { Avatar } from '@carrier-dpx/air-react-library'
31
+ */
32
+
33
+ const MuiAvatarStyled = styled(MuiAvatar)({
34
+ "&.MuiAvatar-rounded": {
35
+ borderRadius: styleTokens.borderRadius.large,
36
+ },
37
+ });
38
+
39
+ const Avatar = forwardRef<HTMLDivElement, AvatarProps>(
40
+ ({ children, sx, size = "medium", ...rest }, ref) => {
41
+ const getSize = () => {
42
+ switch (size) {
43
+ case "large":
44
+ return "48px";
45
+ case "medium":
46
+ return "40px";
47
+ case "small":
48
+ return "32px";
49
+ case "xsmall":
50
+ return "24px";
51
+ case "micro":
52
+ return "20px";
53
+ default:
54
+ return "40px";
55
+ }
56
+ };
57
+
58
+ const getFontSize = () => {
59
+ switch (size) {
60
+ case "large":
61
+ return "18px";
62
+ case "medium":
63
+ return "16px";
64
+ case "small":
65
+ return "14px";
66
+ case "xsmall":
67
+ return "12px";
68
+ case "micro":
69
+ return "10px";
70
+ default:
71
+ return "16px";
72
+ }
73
+ };
74
+
75
+ const avatarSize = getSize();
76
+ const isLargeVariant = size === "large";
77
+
78
+ return (
79
+ <MuiAvatarStyled
80
+ sx={(theme) => {
81
+ const resolvedSx = (getSxStyles(theme, sx) ?? {}) as CSSObject;
82
+
83
+ return {
84
+ backgroundColor: blueGrey[500],
85
+ cursor: "default",
86
+ fontSize: getFontSize(),
87
+ fontWeight: 600,
88
+ width: avatarSize,
89
+ height: avatarSize,
90
+ ...(isLargeVariant && {
91
+ "& .MuiSvgIcon-root": {
92
+ fontSize: "24px",
93
+ },
94
+ }),
95
+ ...resolvedSx,
96
+ } as CSSObject;
97
+ }}
98
+ {...rest}
99
+ ref={ref}
100
+ >
101
+ {typeof children === "string"
102
+ ? getDisplayStringForAvatar(children)
103
+ : children}
104
+ </MuiAvatarStyled>
105
+ );
106
+ }
107
+ );
108
+
109
+ Avatar.displayName = "Avatar";
110
+
111
+ export default Avatar;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Figma Code Connect Configuration for AvatarGroup Component
3
+ *
4
+ * Figma URL: https://www.figma.com/design/vkoHdM6rchIhH9IWetZeP0/Air--Components?node-id=15889-77636
5
+ *
6
+ * Figma Properties:
7
+ * - spacing (small, medium)
8
+ * - size (large: 48px, medium: 40px, small: 32px, xsmall: 24px)
9
+ */
10
+
11
+ import figma from "@figma/code-connect";
12
+ import AvatarGroup from "./AvatarGroup";
13
+ import Avatar from "./Avatar";
14
+
15
+ figma.connect(
16
+ AvatarGroup,
17
+ "https://www.figma.com/design/vkoHdM6rchIhH9IWetZeP0/Air--Components?node-id=15889-77636",
18
+ {
19
+ props: {
20
+ /**
21
+ * SPACING MAPPING
22
+ * Maps Figma's "spacing" property to React's "spacing" prop
23
+ * Figma: small, medium
24
+ */
25
+ spacing: figma.enum("spacing", {
26
+ small: "small",
27
+ medium: "medium",
28
+ }),
29
+
30
+ /**
31
+ * SIZE MAPPING
32
+ * Maps Figma's "size" property - size is applied to Avatar children, not the group
33
+ * Figma: large (48px), medium (40px), small (32px), xsmall (24px)
34
+ */
35
+ size: figma.enum("size", {
36
+ large: "large",
37
+ medium: "medium",
38
+ small: "small",
39
+ xsmall: "xsmall",
40
+ }),
41
+
42
+ /**
43
+ * CHILDREN
44
+ * Maps Avatar instances within the AvatarGroup
45
+ */
46
+ children: figma.children("Avatar"),
47
+ },
48
+
49
+ /**
50
+ * EXAMPLE CODE TEMPLATE
51
+ * Shows how AvatarGroup should be used with Avatar children
52
+ * Note: size prop is passed to individual Avatar components, not the group
53
+ */
54
+ example: ({ spacing, size, children }) => (
55
+ <AvatarGroup spacing={spacing}>
56
+ {children}
57
+ </AvatarGroup>
58
+ ),
59
+ }
60
+ );
@@ -0,0 +1,45 @@
1
+ import { forwardRef } from "react";
2
+
3
+ import MuiAvatarGroup, {
4
+ AvatarGroupProps as MuiAvatarGroupProps,
5
+ } from "@mui/material/AvatarGroup";
6
+ import { styled } from "@mui/material/styles";
7
+
8
+ export interface AvatarGroupProps extends MuiAvatarGroupProps {
9
+ variant?: "circular";
10
+ }
11
+
12
+ /** The AvatarGroup component represents a set of unique users or entities through custom images, initials or icons.
13
+ *
14
+ * // Default import
15
+ * import AvatarGroup from '@carrier-dpx/air-react-library/Avatar'
16
+ *
17
+ * // Named import
18
+ * import { AvatarGroup } from '@carrier-dpx/air-react-library'
19
+ */
20
+
21
+ const MuiAvatarGroupStyled = styled(MuiAvatarGroup)<AvatarGroupProps>(
22
+ ({ spacing, theme }) => ({
23
+ ...(spacing === "small" && {
24
+ ".MuiAvatarGroup-avatar": {
25
+ marginLeft: "-12px !important",
26
+ ":last-child": {
27
+ marginLeft: "0px!important",
28
+ },
29
+ },
30
+ }),
31
+ "& .MuiAvatarGroup-avatar": {
32
+ fontWeight: 600,
33
+ fontSize: "16px",
34
+ border: `2px solid ${theme.palette.base?.background.paper}`,
35
+ },
36
+ })
37
+ );
38
+
39
+ const AvatarGroup = forwardRef<unknown, AvatarGroupProps>((props, ref) => {
40
+ return <MuiAvatarGroupStyled {...props} ref={ref} />;
41
+ });
42
+
43
+ AvatarGroup.displayName = "AvatarGroup";
44
+
45
+ export default AvatarGroup;
@@ -0,0 +1,9 @@
1
+ // Avatar component family exports
2
+ export { default } from "./Avatar";
3
+ export { default as Avatar } from "./Avatar";
4
+ export * from "./Avatar";
5
+ export type { AvatarProps } from "./Avatar";
6
+
7
+ export { default as AvatarGroup } from "./AvatarGroup";
8
+ export * from "./AvatarGroup";
9
+ export type { AvatarGroupProps } from "./AvatarGroup";
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Get display string for Avatar component
3
+ * Formats a string (name, initials, etc.) for display in Avatar
4
+ */
5
+ export const getDisplayStringForAvatar = (input: string): string => {
6
+ if (!input) return "";
7
+
8
+ // If it's already initials (2-3 characters), return as-is
9
+ if (input.length <= 3 && input.split(" ").length === 1) {
10
+ return input.toUpperCase();
11
+ }
12
+
13
+ // Extract initials from name
14
+ const words = input.trim().split(/\s+/);
15
+ if (words.length >= 2) {
16
+ // First letter of first word + first letter of last word
17
+ return (words[0][0] + words[words.length - 1][0]).toUpperCase();
18
+ } else if (words.length === 1 && words[0].length > 0) {
19
+ // Single word - take first 2 characters
20
+ return words[0].substring(0, 2).toUpperCase();
21
+ }
22
+
23
+ return input.toUpperCase();
24
+ };
package/src/index.ts CHANGED
@@ -28,6 +28,8 @@ export { default as Toolbar } from "./components/Toolbar";
28
28
  export type { ToolbarProps } from "./components/Toolbar";
29
29
  export { default as IconButton } from "./components/IconButton";
30
30
  export type { IconButtonProps } from "./components/IconButton";
31
+ export { default as Avatar, AvatarGroup } from "./components/Avatar";
32
+ export type { AvatarProps, AvatarGroupProps } from "./components/Avatar";
31
33
  export * from "./components/theme";
32
34
 
33
35
  // Demo Icons - exported from main index to avoid deep-path imports