@carrier-dpx/air-react-library 0.7.27 → 0.7.29

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.27",
3
+ "version": "0.7.29",
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,110 @@
1
+ /**
2
+ * Figma Code Connect Configuration for StatusLed Component
3
+ *
4
+ * Figma URL: https://www.figma.com/design/vkoHdM6rchIhH9IWetZeP0/Air--Components?node-id=37599-424674
5
+ *
6
+ * Figma Properties:
7
+ * - severity (error, warning, success, info, default, static)
8
+ * - size (xsmall: 24px, micro: 20px)
9
+ * - labelPosition (start, end)
10
+ * - label (true, false) - controls visibility of nested "Label" Typography component
11
+ *
12
+ * Notes:
13
+ * - labelPosition changes where the label is placed, either before or after the StatusLED
14
+ * - The "label" boolean prop hides/shows the nested "Label" component which is an instance of the Typography component
15
+ * - Size can be customized in code for any size, but design only supports two sizes
16
+ * - Size mapping: xsmall (24px) → size 12, micro (20px) → size 10 (since circleSize = size * 2)
17
+ */
18
+
19
+ import figma from "@figma/code-connect";
20
+ import StatusLed from "./StatusLed";
21
+
22
+ figma.connect(
23
+ StatusLed,
24
+ "https://www.figma.com/design/vkoHdM6rchIhH9IWetZeP0/Air--Components?node-id=37599-424674",
25
+ {
26
+ props: {
27
+ /**
28
+ * SEVERITY MAPPING
29
+ * Maps Figma's "severity" property to React's "severity" prop
30
+ * Controls the color of the StatusLED
31
+ */
32
+ severity: figma.enum("severity", {
33
+ error: "error",
34
+ warning: "warning",
35
+ success: "success",
36
+ info: "info",
37
+ default: "default",
38
+ static: "static",
39
+ }),
40
+
41
+ /**
42
+ * SIZE MAPPING
43
+ * Maps Figma's "size" property to React's "size" prop
44
+ * Figma: xsmall (24px), micro (20px)
45
+ * React: size is the inner circle size in pixels
46
+ * - xsmall (24px total) → size 12 (12 * 2 = 24)
47
+ * - micro (20px total) → size 10 (10 * 2 = 20)
48
+ */
49
+ size: figma.enum("size", {
50
+ "xsmall: 24px": 12,
51
+ "micro: 20px": 10,
52
+ // Handle cases where Figma might show just the size name
53
+ xsmall: 12,
54
+ micro: 10,
55
+ }),
56
+
57
+ /**
58
+ * LABEL POSITION MAPPING
59
+ * Maps Figma's "labelPosition" property to React's "labelPosition" prop
60
+ * Controls where the label is placed relative to the StatusLED
61
+ */
62
+ labelPosition: figma.enum("labelPosition", {
63
+ start: "start",
64
+ end: "end",
65
+ }),
66
+
67
+ /**
68
+ * LABEL VISIBILITY
69
+ * Maps Figma's "label" boolean property
70
+ * When true, shows the nested "Label" Typography component
71
+ * When false, hides the label
72
+ */
73
+ showLabel: figma.boolean("label"),
74
+
75
+ /**
76
+ * LABEL TEXT CONTENT
77
+ * Maps text property "✏️ Label" from the nested "Label" Typography component
78
+ * The Label is an instance of the Typography component
79
+ * The text property must be surfaced from the "Label" layer
80
+ * Only used when showLabel is true
81
+ */
82
+ label: figma.string("✏️ Label"),
83
+ },
84
+
85
+ /**
86
+ * EXAMPLE CODE TEMPLATE
87
+ * Shows how StatusLed should be used with optional label
88
+ */
89
+ example: ({ severity, size, labelPosition, showLabel, label }) => {
90
+ if (showLabel && label) {
91
+ return (
92
+ <StatusLed
93
+ severity={severity}
94
+ size={size}
95
+ labelPosition={labelPosition}
96
+ label={label}
97
+ />
98
+ );
99
+ }
100
+
101
+ return (
102
+ <StatusLed
103
+ severity={severity}
104
+ size={size}
105
+ labelPosition={labelPosition}
106
+ />
107
+ );
108
+ },
109
+ }
110
+ );
@@ -0,0 +1,77 @@
1
+ import React from "react";
2
+ import { styled } from "@mui/material/styles";
3
+ import Box from "../Box";
4
+ import { Severity, StatusLedProps, StyleProps } from "./types";
5
+ import Typography from "../Typography";
6
+ import styles from "./styles";
7
+
8
+ const CircleInnerStyled = styled(Box, {
9
+ shouldForwardProp: (prop) => prop !== "size",
10
+ })<Omit<StyleProps, "theme">>(styles.circleInner);
11
+
12
+ const CircleOuterStyled = styled(Box, {
13
+ shouldForwardProp: (prop) => prop !== "size",
14
+ })<Omit<StyleProps, "theme">>(styles.circleOuter);
15
+
16
+ const BoxCircleStyled = styled(Box, {
17
+ shouldForwardProp: (prop) => prop !== "size",
18
+ })<Pick<StyleProps, "size">>(styles.containerCircle);
19
+
20
+ const BoxStyled = styled(Box)(styles.container);
21
+
22
+ /**
23
+ * The StatusLED pattern provides on and off states and serves as a visual cue intended to attract
24
+ * the user's attention and communicate severity level information.
25
+ *
26
+ * //Default Import
27
+ * `import StatusLed from '@carrier-io/air-react/StatusLed'`
28
+ */
29
+ const StatusLed: React.FC<StatusLedProps> = ({
30
+ severity = Severity.Default,
31
+ glow = false,
32
+ size = 12,
33
+ label,
34
+ labelPosition = "end",
35
+ ...rest
36
+ }) => {
37
+ const circleSize = size * 2;
38
+
39
+ return (
40
+ <BoxStyled data-testid={rest["data-testid"]}>
41
+ {label && labelPosition === "start" && (
42
+ <Typography
43
+ variant="body2"
44
+ aria-label="label"
45
+ sx={(theme) => ({ mr: 0.5, color: theme.palette.base?.text.primary })}
46
+ >
47
+ {label}
48
+ </Typography>
49
+ )}
50
+ <BoxCircleStyled size={circleSize}>
51
+ {glow && (
52
+ <CircleOuterStyled
53
+ severity={severity}
54
+ size={size}
55
+ aria-label="circle-outer"
56
+ />
57
+ )}
58
+ <CircleInnerStyled
59
+ severity={severity}
60
+ size={size}
61
+ aria-label="circle-inner"
62
+ />
63
+ </BoxCircleStyled>
64
+ {label && labelPosition === "end" && (
65
+ <Typography
66
+ variant="body2"
67
+ aria-label="label"
68
+ sx={(theme) => ({ mr: 0.5, color: theme.palette.base?.text.primary })}
69
+ >
70
+ {label}
71
+ </Typography>
72
+ )}
73
+ </BoxStyled>
74
+ );
75
+ };
76
+
77
+ export default StatusLed;
@@ -0,0 +1,4 @@
1
+ export { default } from "./StatusLed";
2
+ export { default as StatusLed } from "./StatusLed";
3
+ export * from "./StatusLed";
4
+ export * from "./types";
@@ -0,0 +1,39 @@
1
+ import { CSSObject } from "@mui/material";
2
+ import { Theme } from "@mui/material/styles";
3
+
4
+ import { getColorInner, getColorOuter } from "./utils";
5
+ import { StyleProps } from "./types";
6
+
7
+ export default {
8
+ circleInner: ({ theme, severity, size }: StyleProps): CSSObject => ({
9
+ height: size,
10
+ width: size,
11
+ borderRadius: "50%",
12
+ backgroundColor: getColorInner(theme as unknown as Theme, severity),
13
+ position: "absolute",
14
+ }),
15
+ circleOuter: ({ theme, severity, size }: StyleProps): CSSObject => {
16
+ const roundedOuterSize = Math.round(size * 1.5);
17
+ return {
18
+ height: roundedOuterSize,
19
+ width: roundedOuterSize,
20
+ borderRadius: "50%",
21
+ filter: `blur(${size / 6}px)`,
22
+ backgroundColor: getColorOuter(theme as unknown as Theme, severity),
23
+ "will-change": "transform",
24
+ };
25
+ },
26
+ containerCircle: ({ size }: Pick<StyleProps, "size">): CSSObject => ({
27
+ position: "relative",
28
+ display: "flex",
29
+ justifyContent: "center",
30
+ alignItems: "center",
31
+ width: size,
32
+ height: size,
33
+ }),
34
+ container: {
35
+ display: "flex",
36
+ flexDirection: "row",
37
+ alignItems: "center",
38
+ } as CSSObject,
39
+ };
@@ -0,0 +1,59 @@
1
+ import { Theme } from "@mui/material/styles";
2
+
3
+ export enum Severity {
4
+ Success = "success",
5
+ Info = "info",
6
+ Warning = "warning",
7
+ Error = "error",
8
+ Default = "default",
9
+ Static = "static",
10
+ }
11
+
12
+ export interface StyleProps {
13
+ severity: Severity;
14
+ size: number;
15
+ theme: Theme;
16
+ }
17
+
18
+ export interface StatusLedProps {
19
+ /**
20
+ * The severity of the StatusLed. This defines the color.
21
+ *
22
+ * @default 'default'
23
+ */
24
+ severity?: Severity;
25
+
26
+ /**
27
+ * A boolean that controls the presence of outer circle (glow) of the StatusLed.
28
+ * The overall size is rounded 150% of the size property value if glow is enabled
29
+ *
30
+ * @default False
31
+ */
32
+ glow?: boolean;
33
+
34
+ /**
35
+ * The size of the inner circle in pixels.
36
+ * The size of the outer circle (glow) is rounded 50% larger if present.
37
+ *
38
+ * @default 12
39
+ */
40
+ size?: number;
41
+
42
+ /**
43
+ * The label content.
44
+ */
45
+ label?: string;
46
+
47
+ /**
48
+ * Controls where the label should be placed.
49
+ *
50
+ * @default end
51
+ */
52
+
53
+ labelPosition?: "start" | "end";
54
+
55
+ /**
56
+ * For testing purposes
57
+ */
58
+ "data-testid"?: string;
59
+ }
@@ -0,0 +1,31 @@
1
+ import { lighten, PaletteOptions } from "@mui/material";
2
+ import { Theme } from "@mui/material/styles";
3
+ import { SimplePaletteColorOptions } from "@mui/material/styles/createPalette";
4
+
5
+ import { Severity } from "./types";
6
+
7
+ export const getColorInner = (theme: Theme, severity: Severity): string => {
8
+ const key = severity.toLowerCase() as keyof PaletteOptions;
9
+ const palette = theme.palette[key] as SimplePaletteColorOptions;
10
+ const finalColor =
11
+ palette?.main ||
12
+ (severity == Severity.Static
13
+ ? theme.palette.base?.dark || theme.palette.common.black
14
+ : theme.palette.base?.state?.disabledContent ||
15
+ lighten(theme.palette.common.black, 0.7));
16
+
17
+ return finalColor;
18
+ };
19
+
20
+ export const getColorOuter = (theme: Theme, severity: Severity): string => {
21
+ const key = severity.toLowerCase() as keyof PaletteOptions;
22
+ const palette = theme.palette[key] as SimplePaletteColorOptions;
23
+ const finalColor =
24
+ palette?.light ??
25
+ (severity == Severity.Static
26
+ ? theme.palette.base?.dark || theme.palette.common.black
27
+ : theme.palette.base?.state?.disabledContent ||
28
+ lighten(theme.palette.common.black, 0.8));
29
+
30
+ return finalColor;
31
+ };
package/src/index.ts CHANGED
@@ -32,6 +32,8 @@ export { default as Avatar, AvatarGroup } from "./components/Avatar";
32
32
  export type { AvatarProps, AvatarGroupProps } from "./components/Avatar";
33
33
  export { default as MobileStatusBar } from "./components/MobileStatusBar";
34
34
  export type { MobileStatusBarProps } from "./components/MobileStatusBar";
35
+ export { default as StatusLed } from "./components/StatusLed";
36
+ export type { StatusLedProps, Severity } from "./components/StatusLed";
35
37
  export * from "./components/theme";
36
38
 
37
39
  // Demo Icons - exported from main index to avoid deep-path imports