@carrier-dpx/air-react-library 0.7.35 → 0.7.37
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 +1 -1
- package/src/components/Breadcrumbs/BreadcrumbLink.figma.tsx +137 -0
- package/src/components/Breadcrumbs/BreadcrumbLink.tsx +82 -0
- package/src/components/Breadcrumbs/Breadcrumbs.figma.tsx +117 -0
- package/src/components/Breadcrumbs/Breadcrumbs.tsx +53 -0
- package/src/components/Breadcrumbs/index.ts +5 -0
- package/src/components/Breadcrumbs/styles.ts +20 -0
- package/src/components/Tag/Tag.figma.tsx +130 -0
- package/src/components/Tag/Tag.tsx +40 -0
- package/src/components/Tag/index.ts +4 -0
- package/src/components/Tag/styles.ts +93 -0
- package/src/components/Tag/types.ts +39 -0
- package/src/components/useMediaQuery/index.ts +3 -0
- package/src/components/useMediaQuery/useMediaQuery.ts +35 -0
- package/src/index.ts +4 -0
package/package.json
CHANGED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Figma Code Connect Configuration for Breadcrumb Link Component
|
|
3
|
+
*
|
|
4
|
+
* Figma URL: https://www.figma.com/design/vkoHdM6rchIhH9IWetZeP0/Air--Components?node-id=20464-143034
|
|
5
|
+
*
|
|
6
|
+
* Figma Properties:
|
|
7
|
+
* - color (primary, main)
|
|
8
|
+
* - active (true, false)
|
|
9
|
+
* - state (enabled, hover) - visual state, not a prop
|
|
10
|
+
* - disabled (true, false)
|
|
11
|
+
* - Icon (true, false) - boolean hide/show
|
|
12
|
+
* - separator (true, false) - boolean hide/show
|
|
13
|
+
*
|
|
14
|
+
* Structure:
|
|
15
|
+
* - Icon: Nested Icon component instance (when Icon=true)
|
|
16
|
+
* - Link: Nested Link component instance with text content
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import figma from "@figma/code-connect";
|
|
20
|
+
import BreadcrumbLink from "./BreadcrumbLink";
|
|
21
|
+
import Link from "../Link";
|
|
22
|
+
import Icon from "../Icon";
|
|
23
|
+
|
|
24
|
+
figma.connect(
|
|
25
|
+
BreadcrumbLink,
|
|
26
|
+
"https://www.figma.com/design/vkoHdM6rchIhH9IWetZeP0/Air--Components?node-id=20464-143034",
|
|
27
|
+
{
|
|
28
|
+
props: {
|
|
29
|
+
/**
|
|
30
|
+
* COLOR MAPPING
|
|
31
|
+
* Maps Figma's "color" property to React's "color" prop
|
|
32
|
+
* Figma: primary, main → React: primary, base
|
|
33
|
+
*/
|
|
34
|
+
color: figma.enum("color", {
|
|
35
|
+
primary: "primary",
|
|
36
|
+
main: "base",
|
|
37
|
+
}),
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* ACTIVE STATE
|
|
41
|
+
* Maps Figma's "active" boolean to React's "active" prop
|
|
42
|
+
*/
|
|
43
|
+
active: figma.boolean("active"),
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* DISABLED STATE
|
|
47
|
+
* Maps Figma's "disabled" boolean to React's "disabled" prop
|
|
48
|
+
*/
|
|
49
|
+
disabled: figma.boolean("disabled"),
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* ICON VISIBILITY
|
|
53
|
+
* Maps Figma's "Icon" boolean - controls visibility of nested Icon component
|
|
54
|
+
*/
|
|
55
|
+
showIcon: figma.boolean("Icon"),
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* SEPARATOR VISIBILITY
|
|
59
|
+
* Maps Figma's "separator" boolean - controls visibility of separator
|
|
60
|
+
* Note: Separator is typically handled by parent Breadcrumbs component
|
|
61
|
+
*/
|
|
62
|
+
showSeparator: figma.boolean("separator"),
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* ICON NESTED PROPERTIES
|
|
66
|
+
* Access Icon's fontSize and SVG through nested properties
|
|
67
|
+
* The Icon component is nested within BreadcrumbLink when Icon is visible
|
|
68
|
+
*/
|
|
69
|
+
icon: figma.nestedProps("Icon", {
|
|
70
|
+
fontSize: figma.enum("fontSize", {
|
|
71
|
+
large: "large",
|
|
72
|
+
medium: "medium",
|
|
73
|
+
small: "small",
|
|
74
|
+
xsmall: "xsmall",
|
|
75
|
+
}),
|
|
76
|
+
children: figma.instance("SVG"),
|
|
77
|
+
}),
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* LINK COMPONENT INSTANCE
|
|
81
|
+
* Maps nested Link component instance
|
|
82
|
+
* The Link component is nested within BreadcrumbLink
|
|
83
|
+
* Using figma.instance() to get the Link component instance
|
|
84
|
+
*/
|
|
85
|
+
link: figma.instance("Link"),
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* EXAMPLE CODE TEMPLATE
|
|
90
|
+
* Shows how BreadcrumbLink should be used with optional icon and link
|
|
91
|
+
*/
|
|
92
|
+
example: ({ color, active, disabled, showIcon, icon, link }) => {
|
|
93
|
+
// Handle case with icon
|
|
94
|
+
if (showIcon && icon && icon.fontSize && icon.children && link) {
|
|
95
|
+
return (
|
|
96
|
+
<BreadcrumbLink
|
|
97
|
+
color={color}
|
|
98
|
+
active={active}
|
|
99
|
+
disabled={disabled}
|
|
100
|
+
icon={
|
|
101
|
+
<Icon fontSize={icon.fontSize}>
|
|
102
|
+
{icon.children}
|
|
103
|
+
</Icon>
|
|
104
|
+
}
|
|
105
|
+
href="#"
|
|
106
|
+
>
|
|
107
|
+
{link}
|
|
108
|
+
</BreadcrumbLink>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Handle case without icon
|
|
113
|
+
if (link) {
|
|
114
|
+
return (
|
|
115
|
+
<BreadcrumbLink
|
|
116
|
+
color={color}
|
|
117
|
+
active={active}
|
|
118
|
+
disabled={disabled}
|
|
119
|
+
href="#"
|
|
120
|
+
>
|
|
121
|
+
{link}
|
|
122
|
+
</BreadcrumbLink>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Fallback
|
|
127
|
+
return (
|
|
128
|
+
<BreadcrumbLink
|
|
129
|
+
color={color}
|
|
130
|
+
active={active}
|
|
131
|
+
disabled={disabled}
|
|
132
|
+
href="#"
|
|
133
|
+
/>
|
|
134
|
+
);
|
|
135
|
+
},
|
|
136
|
+
}
|
|
137
|
+
);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import Link from "../Link";
|
|
3
|
+
import Icon from "../Icon";
|
|
4
|
+
import { styled } from "@mui/material/styles";
|
|
5
|
+
import { Theme } from "@mui/material";
|
|
6
|
+
|
|
7
|
+
export interface BreadcrumbLinkProps {
|
|
8
|
+
/**
|
|
9
|
+
* The color of the breadcrumb link
|
|
10
|
+
*/
|
|
11
|
+
color?: "primary" | "base";
|
|
12
|
+
/**
|
|
13
|
+
* Whether the breadcrumb link is active
|
|
14
|
+
*/
|
|
15
|
+
active?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Whether the breadcrumb link is disabled
|
|
18
|
+
*/
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Icon element to display before the link text
|
|
22
|
+
*/
|
|
23
|
+
icon?: React.ReactElement;
|
|
24
|
+
/**
|
|
25
|
+
* Link content (text)
|
|
26
|
+
*/
|
|
27
|
+
children?: React.ReactNode;
|
|
28
|
+
/**
|
|
29
|
+
* href for the link
|
|
30
|
+
*/
|
|
31
|
+
href?: string;
|
|
32
|
+
/**
|
|
33
|
+
* onClick handler
|
|
34
|
+
*/
|
|
35
|
+
onClick?: () => void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const StyledLink = styled(Link)<{ active?: boolean; disabled?: boolean }>(
|
|
39
|
+
({ theme, active, disabled }: { theme: Theme; active?: boolean; disabled?: boolean }) => ({
|
|
40
|
+
...(active && {
|
|
41
|
+
color: theme.palette.base?.text.primary,
|
|
42
|
+
fontWeight: 600,
|
|
43
|
+
}),
|
|
44
|
+
...(disabled && {
|
|
45
|
+
color: theme.palette.base?.text.disabled,
|
|
46
|
+
cursor: "not-allowed",
|
|
47
|
+
pointerEvents: "none",
|
|
48
|
+
}),
|
|
49
|
+
})
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
/** BreadcrumbLink component used within Breadcrumbs
|
|
53
|
+
*
|
|
54
|
+
* `import BreadcrumbLink from '@carrier-io/air-react/Breadcrumbs/BreadcrumbLink'`
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
const BreadcrumbLink = forwardRef<HTMLAnchorElement, BreadcrumbLinkProps>(
|
|
58
|
+
({ color, active, disabled, icon, children, href, onClick, ...rest }, ref) => {
|
|
59
|
+
// If children is a Link component instance, extract its content
|
|
60
|
+
const linkContent = children;
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<StyledLink
|
|
64
|
+
ref={ref}
|
|
65
|
+
href={href}
|
|
66
|
+
onClick={onClick}
|
|
67
|
+
active={active}
|
|
68
|
+
disabled={disabled}
|
|
69
|
+
color={color === "base" ? undefined : color}
|
|
70
|
+
{...rest}
|
|
71
|
+
>
|
|
72
|
+
{icon}
|
|
73
|
+
{linkContent}
|
|
74
|
+
</StyledLink>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
BreadcrumbLink.displayName = "BreadcrumbLink";
|
|
80
|
+
|
|
81
|
+
export default BreadcrumbLink;
|
|
82
|
+
export type { BreadcrumbLinkProps };
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Figma Code Connect Configuration for Breadcrumbs Component
|
|
3
|
+
*
|
|
4
|
+
* Figma URL: https://www.figma.com/design/vkoHdM6rchIhH9IWetZeP0/Air--Components?node-id=20464-143181
|
|
5
|
+
*
|
|
6
|
+
* Figma Properties:
|
|
7
|
+
* - color (primary, main)
|
|
8
|
+
* - icon (true, false)
|
|
9
|
+
* - separator (slash, icon)
|
|
10
|
+
* - collapsed (true, false)
|
|
11
|
+
* - mobile (true, false)
|
|
12
|
+
*
|
|
13
|
+
* Structure:
|
|
14
|
+
* - Breadcrumb 01-06: Multiple Breadcrumb Link instances with numbered layer names
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import figma from "@figma/code-connect";
|
|
18
|
+
import Breadcrumbs from "./Breadcrumbs";
|
|
19
|
+
|
|
20
|
+
figma.connect(
|
|
21
|
+
Breadcrumbs,
|
|
22
|
+
"https://www.figma.com/design/vkoHdM6rchIhH9IWetZeP0/Air--Components?node-id=20464-143181",
|
|
23
|
+
{
|
|
24
|
+
props: {
|
|
25
|
+
/**
|
|
26
|
+
* COLOR MAPPING
|
|
27
|
+
* Maps Figma's "color" property to React's "color" prop
|
|
28
|
+
* Figma: primary, main → React: primary, base
|
|
29
|
+
*/
|
|
30
|
+
color: figma.enum("color", {
|
|
31
|
+
primary: "primary",
|
|
32
|
+
main: "base",
|
|
33
|
+
}),
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* ICON VISIBILITY
|
|
37
|
+
* Maps Figma's "icon" boolean property
|
|
38
|
+
* Controls visibility of icons in breadcrumbs
|
|
39
|
+
*/
|
|
40
|
+
icon: figma.boolean("icon"),
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* SEPARATOR TYPE
|
|
44
|
+
* Maps Figma's "separator" property to React separator prop
|
|
45
|
+
* Figma: slash, icon → React: "/", icon component
|
|
46
|
+
*/
|
|
47
|
+
separator: figma.enum("separator", {
|
|
48
|
+
slash: "/",
|
|
49
|
+
icon: "icon",
|
|
50
|
+
}),
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* COLLAPSED STATE
|
|
54
|
+
* Maps Figma's "collapsed" boolean property
|
|
55
|
+
* Controls collapsed state of breadcrumbs
|
|
56
|
+
*/
|
|
57
|
+
collapsed: figma.boolean("collapsed"),
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* MOBILE STATE
|
|
61
|
+
* Maps Figma's "mobile" boolean property
|
|
62
|
+
* Controls mobile-specific behavior
|
|
63
|
+
*/
|
|
64
|
+
mobile: figma.boolean("mobile"),
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* BREADCRUMB LINK CHILDREN
|
|
68
|
+
* Maps nested Breadcrumb Link instances from Figma
|
|
69
|
+
* Each "Breadcrumb XX" is an instance of the Breadcrumb Link component
|
|
70
|
+
* We map each one individually using the exact layer names
|
|
71
|
+
*/
|
|
72
|
+
breadcrumb01: figma.children("Breadcrumb 01"),
|
|
73
|
+
breadcrumb02: figma.children("Breadcrumb 02"),
|
|
74
|
+
breadcrumb03: figma.children("Breadcrumb 03"),
|
|
75
|
+
breadcrumb04: figma.children("Breadcrumb 04"),
|
|
76
|
+
breadcrumb05: figma.children("Breadcrumb 05"),
|
|
77
|
+
breadcrumb06: figma.children("Breadcrumb 06"),
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* EXAMPLE CODE TEMPLATE
|
|
82
|
+
* Shows how Breadcrumbs should be used with Breadcrumb Link children
|
|
83
|
+
* Note: separator prop handling may need adjustment based on actual implementation
|
|
84
|
+
*/
|
|
85
|
+
example: ({ color, separator, breadcrumb01, breadcrumb02, breadcrumb03, breadcrumb04, breadcrumb05, breadcrumb06 }) => {
|
|
86
|
+
// Handle separator - if icon, use undefined (separator handled by parent), otherwise use the separator string
|
|
87
|
+
if (separator === "icon") {
|
|
88
|
+
return (
|
|
89
|
+
<Breadcrumbs
|
|
90
|
+
color={color}
|
|
91
|
+
>
|
|
92
|
+
{breadcrumb01}
|
|
93
|
+
{breadcrumb02}
|
|
94
|
+
{breadcrumb03}
|
|
95
|
+
{breadcrumb04}
|
|
96
|
+
{breadcrumb05}
|
|
97
|
+
{breadcrumb06}
|
|
98
|
+
</Breadcrumbs>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<Breadcrumbs
|
|
104
|
+
color={color}
|
|
105
|
+
separator={separator}
|
|
106
|
+
>
|
|
107
|
+
{breadcrumb01}
|
|
108
|
+
{breadcrumb02}
|
|
109
|
+
{breadcrumb03}
|
|
110
|
+
{breadcrumb04}
|
|
111
|
+
{breadcrumb05}
|
|
112
|
+
{breadcrumb06}
|
|
113
|
+
</Breadcrumbs>
|
|
114
|
+
);
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
|
|
3
|
+
import MuiBreadcrumbs, {
|
|
4
|
+
BreadcrumbsProps as MuiBreadcrumbsProps,
|
|
5
|
+
} from "@mui/material/Breadcrumbs";
|
|
6
|
+
import { CSSObject, Theme } from "@mui/material/styles";
|
|
7
|
+
|
|
8
|
+
import { baseBreadcrumbsSx } from "./styles";
|
|
9
|
+
import { getSxStyles } from "../utils/styles";
|
|
10
|
+
import useMediaQuery from "../useMediaQuery/useMediaQuery";
|
|
11
|
+
|
|
12
|
+
export interface BreadcrumbsProps extends MuiBreadcrumbsProps {
|
|
13
|
+
color?: "primary" | "base";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** The Breadcrumbs component is a set of links that help users navigate
|
|
17
|
+
* and visualize the current location within a hierarchical structure.
|
|
18
|
+
*
|
|
19
|
+
* // Default import
|
|
20
|
+
* import Breadcrumbs from '@carrier-io/air-react/Breadcrumbs'
|
|
21
|
+
*
|
|
22
|
+
* // Named import
|
|
23
|
+
* import { Breadcrumbs } from '@carrier-io/air-react'
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const Breadcrumbs = forwardRef<HTMLElement, BreadcrumbsProps>(
|
|
27
|
+
({ sx, color, ...rest }, ref) => {
|
|
28
|
+
const isMobile = useMediaQuery(`(max-width:599px)`);
|
|
29
|
+
|
|
30
|
+
const breadcrumbSX = (theme: Theme) => {
|
|
31
|
+
const baseStyles = getSxStyles(theme, sx);
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
...baseStyles,
|
|
35
|
+
...baseBreadcrumbsSx(theme, color),
|
|
36
|
+
} as CSSObject;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<MuiBreadcrumbs
|
|
41
|
+
{...rest}
|
|
42
|
+
sx={breadcrumbSX}
|
|
43
|
+
ref={ref}
|
|
44
|
+
separator={isMobile ? "" : "/"}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
Breadcrumbs.displayName = "Breadcrumbs";
|
|
51
|
+
|
|
52
|
+
export default Breadcrumbs;
|
|
53
|
+
export type { BreadcrumbsProps };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { CSSObject, Theme } from "@mui/material";
|
|
2
|
+
import { styleTokens } from "../theme/constants/styleTokens";
|
|
3
|
+
|
|
4
|
+
export const baseBreadcrumbsSx = (
|
|
5
|
+
theme: Theme,
|
|
6
|
+
color: "primary" | "base" | undefined
|
|
7
|
+
): CSSObject => ({
|
|
8
|
+
"& .MuiBreadcrumbs-separator": {
|
|
9
|
+
color: theme.palette.base?.filledInput.outlinedBorder,
|
|
10
|
+
marginRight: styleTokens.margin.medium,
|
|
11
|
+
marginLeft: styleTokens.margin.medium,
|
|
12
|
+
},
|
|
13
|
+
"& .MuiBreadcrumbs-li:last-child": {
|
|
14
|
+
color: theme.palette.base?.text.primary,
|
|
15
|
+
},
|
|
16
|
+
color:
|
|
17
|
+
color == "primary"
|
|
18
|
+
? theme.palette.primary.main
|
|
19
|
+
: theme.palette.base?.state.active,
|
|
20
|
+
});
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Figma Code Connect Configuration for Tag Component
|
|
3
|
+
*
|
|
4
|
+
* Figma URL: https://www.figma.com/design/vkoHdM6rchIhH9IWetZeP0/Air--Components?node-id=20692-169354
|
|
5
|
+
*
|
|
6
|
+
* Figma Properties:
|
|
7
|
+
* - size (xsmall-24px, micro-small-20px)
|
|
8
|
+
* - color (purple, primary, info, cyan, success, warning, orange, error, pink)
|
|
9
|
+
* - uppercase (true, false)
|
|
10
|
+
* - disabled (true, false)
|
|
11
|
+
* - startIcon (true, false) - boolean hide/show
|
|
12
|
+
* - ✏️ Text - text property with layer name "Label"
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import figma from "@figma/code-connect";
|
|
16
|
+
import Tag from "./Tag";
|
|
17
|
+
import Icon from "../Icon";
|
|
18
|
+
|
|
19
|
+
figma.connect(
|
|
20
|
+
Tag,
|
|
21
|
+
"https://www.figma.com/design/vkoHdM6rchIhH9IWetZeP0/Air--Components?node-id=20692-169354",
|
|
22
|
+
{
|
|
23
|
+
props: {
|
|
24
|
+
/**
|
|
25
|
+
* SIZE MAPPING
|
|
26
|
+
* Maps Figma's "size" property to React's "size" prop
|
|
27
|
+
* Figma: xsmall-24px, micro-small-20px
|
|
28
|
+
*/
|
|
29
|
+
size: figma.enum("size", {
|
|
30
|
+
"xsmall-24px": "xsmall",
|
|
31
|
+
"micro-small-20px": "micro",
|
|
32
|
+
xsmall: "xsmall",
|
|
33
|
+
micro: "micro",
|
|
34
|
+
}),
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* COLOR MAPPING
|
|
38
|
+
* Maps Figma's "color" property to React's "color" prop
|
|
39
|
+
* Note: Some Figma colors may map to similar React colors
|
|
40
|
+
* purple -> primary, cyan -> info, orange -> warning, pink -> error
|
|
41
|
+
*/
|
|
42
|
+
color: figma.enum("color", {
|
|
43
|
+
base: "base",
|
|
44
|
+
purple: "primary",
|
|
45
|
+
primary: "primary",
|
|
46
|
+
info: "info",
|
|
47
|
+
cyan: "info",
|
|
48
|
+
success: "success",
|
|
49
|
+
warning: "warning",
|
|
50
|
+
orange: "warning",
|
|
51
|
+
error: "error",
|
|
52
|
+
pink: "error",
|
|
53
|
+
}),
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* UPPERCASE MAPPING
|
|
57
|
+
* Maps Figma's "uppercase" boolean to React's "uppercase" prop
|
|
58
|
+
*/
|
|
59
|
+
uppercase: figma.boolean("uppercase"),
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* DISABLED STATE
|
|
63
|
+
* Maps Figma's "disabled" boolean to React's "disabled" prop
|
|
64
|
+
*/
|
|
65
|
+
disabled: figma.boolean("disabled"),
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* START ICON VISIBILITY
|
|
69
|
+
* Maps Figma's "startIcon" boolean - controls visibility of icon
|
|
70
|
+
*/
|
|
71
|
+
showStartIcon: figma.boolean("startIcon"),
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* START ICON NESTED PROPERTIES
|
|
75
|
+
* Access Icon's fontSize and SVG through nested properties
|
|
76
|
+
* The Icon component is nested within Tag when startIcon is visible
|
|
77
|
+
*/
|
|
78
|
+
startIcon: figma.nestedProps("startIcon", {
|
|
79
|
+
fontSize: figma.enum("fontSize", {
|
|
80
|
+
large: "large",
|
|
81
|
+
medium: "medium",
|
|
82
|
+
small: "small",
|
|
83
|
+
xsmall: "xsmall",
|
|
84
|
+
}),
|
|
85
|
+
children: figma.instance("SVG"),
|
|
86
|
+
}),
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* TEXT CONTENT
|
|
90
|
+
* Maps text property "✏️ Text" from layer "Label"
|
|
91
|
+
*/
|
|
92
|
+
label: figma.string("✏️ Text"),
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* EXAMPLE CODE TEMPLATE
|
|
97
|
+
* Shows how Tag should be used with optional startIcon
|
|
98
|
+
*/
|
|
99
|
+
example: ({ size, color, uppercase, disabled, showStartIcon, startIcon, label }) => {
|
|
100
|
+
// Handle case with startIcon
|
|
101
|
+
if (showStartIcon && startIcon && startIcon.fontSize && startIcon.children) {
|
|
102
|
+
return (
|
|
103
|
+
<Tag
|
|
104
|
+
size={size}
|
|
105
|
+
color={color}
|
|
106
|
+
uppercase={uppercase}
|
|
107
|
+
disabled={disabled}
|
|
108
|
+
startIcon={
|
|
109
|
+
<Icon fontSize={startIcon.fontSize}>
|
|
110
|
+
{startIcon.children}
|
|
111
|
+
</Icon>
|
|
112
|
+
}
|
|
113
|
+
label={label}
|
|
114
|
+
/>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Handle case without startIcon
|
|
119
|
+
return (
|
|
120
|
+
<Tag
|
|
121
|
+
size={size}
|
|
122
|
+
color={color}
|
|
123
|
+
uppercase={uppercase}
|
|
124
|
+
disabled={disabled}
|
|
125
|
+
label={label}
|
|
126
|
+
/>
|
|
127
|
+
);
|
|
128
|
+
},
|
|
129
|
+
}
|
|
130
|
+
);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Chip, Typography, styled } from "@mui/material";
|
|
2
|
+
import { StyledTagProps, TagProps } from "./types";
|
|
3
|
+
import styles from "./styles";
|
|
4
|
+
|
|
5
|
+
const StyledMuiChip = styled(Chip)<StyledTagProps>(styles);
|
|
6
|
+
|
|
7
|
+
const Tag = ({
|
|
8
|
+
label,
|
|
9
|
+
size = "xsmall",
|
|
10
|
+
color = "success",
|
|
11
|
+
uppercase,
|
|
12
|
+
startIcon,
|
|
13
|
+
disabled = false,
|
|
14
|
+
...rest
|
|
15
|
+
}: TagProps) => {
|
|
16
|
+
const formattedLabel =
|
|
17
|
+
typeof label === "string" && uppercase ? label.toUpperCase() : label;
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<StyledMuiChip
|
|
21
|
+
data-testid="tag"
|
|
22
|
+
label={
|
|
23
|
+
<Typography variant="body4Semibold" sx={{ padding: "0px 4px" }}>
|
|
24
|
+
{formattedLabel}
|
|
25
|
+
</Typography>
|
|
26
|
+
}
|
|
27
|
+
size={size}
|
|
28
|
+
style={{ borderRadius: "999px" }}
|
|
29
|
+
color={color}
|
|
30
|
+
icon={startIcon ?? undefined}
|
|
31
|
+
disabled={disabled}
|
|
32
|
+
{...rest}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
Tag.displayName = "Tag";
|
|
38
|
+
|
|
39
|
+
export default Tag;
|
|
40
|
+
export type { TagProps };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { chipClasses } from "@mui/material/Chip";
|
|
2
|
+
import { Theme } from "@mui/material/styles";
|
|
3
|
+
import { StyledTagProps, TagProps } from "./types";
|
|
4
|
+
import { StyledComponentDefaultProps } from "../types/common";
|
|
5
|
+
import { ChipHeightMap } from "../utils/HeightUtils";
|
|
6
|
+
|
|
7
|
+
const getBackgroundColor = (
|
|
8
|
+
theme: Theme,
|
|
9
|
+
color: TagProps["color"] = "success"
|
|
10
|
+
) => {
|
|
11
|
+
if (color === "base") {
|
|
12
|
+
return theme.palette.base?.state.selected;
|
|
13
|
+
}
|
|
14
|
+
return (
|
|
15
|
+
theme.palette[color]?.selectedHover ?? theme.palette.success.selectedHover
|
|
16
|
+
);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const getContentColor = (
|
|
20
|
+
theme: Theme,
|
|
21
|
+
color: TagProps["color"] = "success"
|
|
22
|
+
) => {
|
|
23
|
+
if (color === "base") {
|
|
24
|
+
return theme.palette.base?.text.secondary;
|
|
25
|
+
}
|
|
26
|
+
if (color === "primary") {
|
|
27
|
+
return theme.palette.primary.main;
|
|
28
|
+
}
|
|
29
|
+
if (color === "warning") {
|
|
30
|
+
return theme.palette.warning.dark;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
theme.palette[color]?.containedHoverBackground ??
|
|
35
|
+
theme.palette.success.containedHoverBackground
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
const styles = ({
|
|
39
|
+
theme,
|
|
40
|
+
color = "success",
|
|
41
|
+
disabled,
|
|
42
|
+
size,
|
|
43
|
+
}: StyledTagProps & StyledComponentDefaultProps) => {
|
|
44
|
+
const commonLabelStyles = {
|
|
45
|
+
fontSize: "0.75rem",
|
|
46
|
+
itemSpacing: "4px",
|
|
47
|
+
padding: "4px",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const commonIconStyles = {
|
|
51
|
+
marginLeft: "4px",
|
|
52
|
+
marginRight: "-4px",
|
|
53
|
+
width: "16px",
|
|
54
|
+
height: "16px",
|
|
55
|
+
itemSpacing: "4px",
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const sizeStyles = (size === "xsmall" || size === "micro") && {
|
|
59
|
+
height: ChipHeightMap[size],
|
|
60
|
+
[`.${chipClasses.label}`]: commonLabelStyles,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const disabledStyles = disabled && {
|
|
64
|
+
backgroundColor: `${theme.palette.base?.state.disabledBackground}!important`,
|
|
65
|
+
opacity: "1 !important",
|
|
66
|
+
[`& .${chipClasses.label}`]: {
|
|
67
|
+
color: theme.palette.base?.text.disabled,
|
|
68
|
+
},
|
|
69
|
+
[`& .${chipClasses.icon}`]: {
|
|
70
|
+
...commonIconStyles,
|
|
71
|
+
color: theme.palette.base?.text.disabled,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const enabledStyles = !disabled && {
|
|
76
|
+
backgroundColor: getBackgroundColor(theme, color),
|
|
77
|
+
[`& .${chipClasses.label}`]: {
|
|
78
|
+
color: getContentColor(theme, color),
|
|
79
|
+
},
|
|
80
|
+
[`& .${chipClasses.icon}`]: {
|
|
81
|
+
...commonIconStyles,
|
|
82
|
+
color: getContentColor(theme, color),
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
...sizeStyles,
|
|
88
|
+
...disabledStyles,
|
|
89
|
+
...enabledStyles,
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export default styles;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ChipProps as MuiChipProps } from "@mui/material";
|
|
2
|
+
import fleetPalette from "../theme/constants/colors";
|
|
3
|
+
|
|
4
|
+
declare module "@mui/material/Chip" {
|
|
5
|
+
export interface ChipPropsColorOverrides {
|
|
6
|
+
base: true;
|
|
7
|
+
default: typeof fleetPalette;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export interface TagProps extends Omit<MuiChipProps, "color" | "size"> {
|
|
11
|
+
/**
|
|
12
|
+
* Represents the desired size of the component
|
|
13
|
+
* @default xsmall
|
|
14
|
+
*/
|
|
15
|
+
size?: "micro" | "xsmall";
|
|
16
|
+
/**
|
|
17
|
+
* The color of the component. It supports those theme colors that make sense for this component.
|
|
18
|
+
* @default success
|
|
19
|
+
*/
|
|
20
|
+
color?:
|
|
21
|
+
| "base"
|
|
22
|
+
| "primary"
|
|
23
|
+
| "secondary"
|
|
24
|
+
| "warning"
|
|
25
|
+
| "success"
|
|
26
|
+
| "info"
|
|
27
|
+
| "error";
|
|
28
|
+
/**
|
|
29
|
+
* It capitalizes the label and adds custom styling.
|
|
30
|
+
* @default false
|
|
31
|
+
*/
|
|
32
|
+
uppercase?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* If defined, then the startIcon is added to the front of the label
|
|
35
|
+
*/
|
|
36
|
+
startIcon?: React.ReactElement;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type StyledTagProps = TagProps;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import muiUseMediaQuery from "@mui/material/useMediaQuery";
|
|
2
|
+
|
|
3
|
+
export interface Options {
|
|
4
|
+
/**
|
|
5
|
+
* As `window.matchMedia()` is unavailable on the server,
|
|
6
|
+
* `useMediaQuery` returns `false` during server-side rendering by default.
|
|
7
|
+
* To change this behavior, set `noSsr` to `true`.
|
|
8
|
+
*/
|
|
9
|
+
noSsr?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* You can provide a custom `matchMedia` implementation. This can be used for handling an `iframe` content window.
|
|
12
|
+
*/
|
|
13
|
+
matchMedia?: (query: string) => MediaQueryList;
|
|
14
|
+
/**
|
|
15
|
+
* The default value to return when the hook is called on the server.
|
|
16
|
+
*/
|
|
17
|
+
defaultMatches?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type QueryInput = string | ((theme: unknown) => string);
|
|
21
|
+
|
|
22
|
+
/** useMediaQuery
|
|
23
|
+
*
|
|
24
|
+
* This is a CSS media query hook for React. It listens for matches to a CSS media query.
|
|
25
|
+
* It allows the rendering of components based on whether the query matches or not.
|
|
26
|
+
*
|
|
27
|
+
* `import useMediaQuery from '@carrier-io/air-react/useMediaQuery'`
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
export default function useMediaQuery(
|
|
31
|
+
queryInput: QueryInput,
|
|
32
|
+
options?: Options
|
|
33
|
+
): boolean {
|
|
34
|
+
return muiUseMediaQuery(queryInput, options);
|
|
35
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -59,6 +59,10 @@ export { default as AccentIndicator } from "./components/AccentIndicator";
|
|
|
59
59
|
export type { AccentIndicatorProps } from "./components/AccentIndicator";
|
|
60
60
|
export { default as Menu } from "./components/Menu";
|
|
61
61
|
export type { MenuProps } from "./components/Menu";
|
|
62
|
+
export { default as Tag } from "./components/Tag";
|
|
63
|
+
export type { TagProps } from "./components/Tag";
|
|
64
|
+
export { default as Breadcrumbs, BreadcrumbLink } from "./components/Breadcrumbs";
|
|
65
|
+
export type { BreadcrumbsProps, BreadcrumbLinkProps } from "./components/Breadcrumbs";
|
|
62
66
|
export * from "./components/theme";
|
|
63
67
|
|
|
64
68
|
// Demo Icons - exported from main index to avoid deep-path imports
|