@gtivr4/a1-design-system-react 0.1.0

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.
Files changed (45) hide show
  1. package/README.md +32 -0
  2. package/package.json +40 -0
  3. package/src/color-scheme.css +213 -0
  4. package/src/components/button/Button.jsx +45 -0
  5. package/src/components/button/button.css +135 -0
  6. package/src/components/button-container/ButtonContainer.jsx +27 -0
  7. package/src/components/button-container/button-container.css +38 -0
  8. package/src/components/card/Card.jsx +29 -0
  9. package/src/components/card/card.css +37 -0
  10. package/src/components/dialog/Dialog.jsx +44 -0
  11. package/src/components/dialog/dialog.css +58 -0
  12. package/src/components/grid/Grid.jsx +77 -0
  13. package/src/components/grid/grid.css +86 -0
  14. package/src/components/heading/Heading.jsx +69 -0
  15. package/src/components/heading/heading.css +76 -0
  16. package/src/components/icon/Icon.jsx +32 -0
  17. package/src/components/icon/icon.css +10 -0
  18. package/src/components/icon-button/IconButton.jsx +34 -0
  19. package/src/components/icon-button/icon-button.css +196 -0
  20. package/src/components/inverse/Inverse.jsx +18 -0
  21. package/src/components/labels/Labels.jsx +29 -0
  22. package/src/components/link/Link.jsx +41 -0
  23. package/src/components/link/link.css +50 -0
  24. package/src/components/menu/Menu.jsx +45 -0
  25. package/src/components/menu/menu.css +45 -0
  26. package/src/components/message/Message.jsx +103 -0
  27. package/src/components/message/message.css +226 -0
  28. package/src/components/notification/Notification.jsx +55 -0
  29. package/src/components/notification/notification.css +69 -0
  30. package/src/components/page-layout/PageLayout.jsx +40 -0
  31. package/src/components/page-layout/page-layout.css +61 -0
  32. package/src/components/pagination/Pagination.jsx +64 -0
  33. package/src/components/pagination/pagination.css +85 -0
  34. package/src/components/paragraph/Paragraph.jsx +26 -0
  35. package/src/components/paragraph/paragraph.css +16 -0
  36. package/src/components/segmented-control/SegmentedControl.jsx +77 -0
  37. package/src/components/segmented-control/segmented.css +76 -0
  38. package/src/components/side-nav/SideNav.jsx +208 -0
  39. package/src/components/side-nav/scrim.css +17 -0
  40. package/src/components/side-nav/side-nav.css +283 -0
  41. package/src/components/tabs/Tabs.jsx +102 -0
  42. package/src/components/tabs/tabs.css +135 -0
  43. package/src/index.js +20 -0
  44. package/src/themes.css +186 -0
  45. package/src/utilities/spacing.css +230 -0
@@ -0,0 +1,58 @@
1
+ .a1-dialog {
2
+ box-sizing: border-box;
3
+ border: var(--component-dialog-border-width) solid var(--semantic-color-border-strong);
4
+ border-radius: var(--component-dialog-border-radius);
5
+ padding: var(--component-dialog-padding);
6
+ background: var(--semantic-color-surface-page);
7
+ box-shadow: var(--component-dialog-shadow);
8
+ color: var(--semantic-color-text-default);
9
+ width: min(560px, calc(100vw - var(--base-spacing-64)));
10
+ max-height: calc(100dvh - var(--base-spacing-64));
11
+ overflow: hidden;
12
+ }
13
+
14
+ .a1-dialog[open] {
15
+ display: flex;
16
+ flex-direction: column;
17
+ gap: var(--base-spacing-16);
18
+ }
19
+
20
+ .a1-dialog::backdrop {
21
+ background: var(--component-scrim-color);
22
+ backdrop-filter: blur(var(--component-scrim-blur));
23
+ }
24
+
25
+ .a1-dialog__header {
26
+ display: flex;
27
+ align-items: flex-start;
28
+ gap: var(--base-spacing-16);
29
+ }
30
+
31
+ .a1-dialog__title {
32
+ flex: 1;
33
+ margin: 0;
34
+ font-family: var(--component-heading-font-family-heading);
35
+ font-size: var(--semantic-font-size-heading-sm);
36
+ font-weight: var(--component-heading-font-weight-heading);
37
+ line-height: var(--component-heading-font-line-height-heading);
38
+ color: var(--semantic-color-text-default);
39
+ }
40
+
41
+ .a1-dialog__close {
42
+ flex-shrink: 0;
43
+ margin-top: var(--component-dialog-close-offset);
44
+ margin-right: var(--component-dialog-close-offset);
45
+ }
46
+
47
+ .a1-dialog__body {
48
+ flex: 1;
49
+ overflow-y: auto;
50
+ }
51
+
52
+ .a1-dialog__footer {
53
+ display: flex;
54
+ justify-content: flex-end;
55
+ gap: var(--base-spacing-12);
56
+ padding-top: var(--base-spacing-16);
57
+ border-top: var(--component-dialog-footer-border-width) solid var(--semantic-color-border-subtle);
58
+ }
@@ -0,0 +1,77 @@
1
+ import "./grid.css";
2
+
3
+ const SPACING_KEYS = [1, 2, 4, 6, 8, 12, 16, 20, 24, 32, 40, 64, 96, 128];
4
+
5
+ function resolveGap(key) {
6
+ if (key == null) return undefined;
7
+ const n = Number(key);
8
+ return SPACING_KEYS.includes(n) ? `var(--base-spacing-${n})` : undefined;
9
+ }
10
+
11
+ export function Grid({
12
+ columns,
13
+ gap,
14
+ rowGap,
15
+ columnGap,
16
+ className = "",
17
+ children,
18
+ ...props
19
+ }) {
20
+ const classes = ["a1-grid"];
21
+
22
+ let inlineCols;
23
+ if (typeof columns === "number") {
24
+ inlineCols = columns;
25
+ } else if (columns && typeof columns === "object") {
26
+ for (const [bp, count] of Object.entries(columns)) {
27
+ classes.push(`a1-grid--${bp}-${count}`);
28
+ }
29
+ }
30
+
31
+ if (className) classes.push(className);
32
+
33
+ const gapVal = resolveGap(gap);
34
+ const rowGapVal = resolveGap(rowGap) ?? gapVal;
35
+ const colGapVal = resolveGap(columnGap) ?? gapVal;
36
+
37
+ const style = {
38
+ ...(inlineCols != null ? { "--a1-grid-cols": inlineCols } : {}),
39
+ ...(rowGapVal ? { rowGap: rowGapVal } : {}),
40
+ ...(colGapVal ? { columnGap: colGapVal } : {}),
41
+ ...props.style,
42
+ };
43
+
44
+ return (
45
+ <div className={classes.join(" ")} style={style} {...props}>
46
+ {children}
47
+ </div>
48
+ );
49
+ }
50
+
51
+ export function GridItem({
52
+ span,
53
+ rowSpan,
54
+ className = "",
55
+ children,
56
+ ...props
57
+ }) {
58
+ const classes = ["a1-grid-item"];
59
+
60
+ if (span === "full") {
61
+ classes.push("a1-grid-item--span-full");
62
+ } else if (typeof span === "number") {
63
+ classes.push(`a1-grid-item--span-${span}`);
64
+ }
65
+
66
+ if (typeof rowSpan === "number") {
67
+ classes.push(`a1-grid-item--row-span-${rowSpan}`);
68
+ }
69
+
70
+ if (className) classes.push(className);
71
+
72
+ return (
73
+ <div className={classes.join(" ")} {...props}>
74
+ {children}
75
+ </div>
76
+ );
77
+ }
@@ -0,0 +1,86 @@
1
+ .a1-grid {
2
+ display: grid;
3
+ grid-template-columns: repeat(var(--a1-grid-cols, 1), minmax(0, 1fr));
4
+ }
5
+
6
+ /* ── Static column-count modifiers ─────────────────────────────────────────── */
7
+
8
+ .a1-grid--cols-1 { --a1-grid-cols: 1; }
9
+ .a1-grid--cols-2 { --a1-grid-cols: 2; }
10
+ .a1-grid--cols-3 { --a1-grid-cols: 3; }
11
+ .a1-grid--cols-4 { --a1-grid-cols: 4; }
12
+ .a1-grid--cols-5 { --a1-grid-cols: 5; }
13
+ .a1-grid--cols-6 { --a1-grid-cols: 6; }
14
+ .a1-grid--cols-8 { --a1-grid-cols: 8; }
15
+ .a1-grid--cols-10 { --a1-grid-cols: 10; }
16
+ .a1-grid--cols-12 { --a1-grid-cols: 12; }
17
+
18
+ /* ── Responsive column-count modifiers (mobile-first) ───────────────────────
19
+ xs has no min-width — it is the base/mobile default.
20
+ Each subsequent tier overrides via a min-width query. ─────── */
21
+
22
+ .a1-grid--xs-1 { --a1-grid-cols: 1; }
23
+ .a1-grid--xs-2 { --a1-grid-cols: 2; }
24
+ .a1-grid--xs-3 { --a1-grid-cols: 3; }
25
+ .a1-grid--xs-4 { --a1-grid-cols: 4; }
26
+ .a1-grid--xs-6 { --a1-grid-cols: 6; }
27
+ .a1-grid--xs-12 { --a1-grid-cols: 12; }
28
+
29
+ @media (min-width: 481px) {
30
+ .a1-grid--sm-1 { --a1-grid-cols: 1; }
31
+ .a1-grid--sm-2 { --a1-grid-cols: 2; }
32
+ .a1-grid--sm-3 { --a1-grid-cols: 3; }
33
+ .a1-grid--sm-4 { --a1-grid-cols: 4; }
34
+ .a1-grid--sm-6 { --a1-grid-cols: 6; }
35
+ .a1-grid--sm-12 { --a1-grid-cols: 12; }
36
+ }
37
+
38
+ @media (min-width: 641px) {
39
+ .a1-grid--md-1 { --a1-grid-cols: 1; }
40
+ .a1-grid--md-2 { --a1-grid-cols: 2; }
41
+ .a1-grid--md-3 { --a1-grid-cols: 3; }
42
+ .a1-grid--md-4 { --a1-grid-cols: 4; }
43
+ .a1-grid--md-6 { --a1-grid-cols: 6; }
44
+ .a1-grid--md-12 { --a1-grid-cols: 12; }
45
+ }
46
+
47
+ @media (min-width: 1025px) {
48
+ .a1-grid--lg-1 { --a1-grid-cols: 1; }
49
+ .a1-grid--lg-2 { --a1-grid-cols: 2; }
50
+ .a1-grid--lg-3 { --a1-grid-cols: 3; }
51
+ .a1-grid--lg-4 { --a1-grid-cols: 4; }
52
+ .a1-grid--lg-6 { --a1-grid-cols: 6; }
53
+ .a1-grid--lg-12 { --a1-grid-cols: 12; }
54
+ }
55
+
56
+ @media (min-width: 1441px) {
57
+ .a1-grid--xl-1 { --a1-grid-cols: 1; }
58
+ .a1-grid--xl-2 { --a1-grid-cols: 2; }
59
+ .a1-grid--xl-3 { --a1-grid-cols: 3; }
60
+ .a1-grid--xl-4 { --a1-grid-cols: 4; }
61
+ .a1-grid--xl-6 { --a1-grid-cols: 6; }
62
+ .a1-grid--xl-12 { --a1-grid-cols: 12; }
63
+ }
64
+
65
+ /* ── GridItem span classes ──────────────────────────────────────────────────── */
66
+
67
+ .a1-grid-item--span-1 { grid-column: span 1; }
68
+ .a1-grid-item--span-2 { grid-column: span 2; }
69
+ .a1-grid-item--span-3 { grid-column: span 3; }
70
+ .a1-grid-item--span-4 { grid-column: span 4; }
71
+ .a1-grid-item--span-5 { grid-column: span 5; }
72
+ .a1-grid-item--span-6 { grid-column: span 6; }
73
+ .a1-grid-item--span-7 { grid-column: span 7; }
74
+ .a1-grid-item--span-8 { grid-column: span 8; }
75
+ .a1-grid-item--span-9 { grid-column: span 9; }
76
+ .a1-grid-item--span-10 { grid-column: span 10; }
77
+ .a1-grid-item--span-11 { grid-column: span 11; }
78
+ .a1-grid-item--span-12 { grid-column: span 12; }
79
+ .a1-grid-item--span-full { grid-column: 1 / -1; }
80
+
81
+ .a1-grid-item--row-span-1 { grid-row: span 1; }
82
+ .a1-grid-item--row-span-2 { grid-row: span 2; }
83
+ .a1-grid-item--row-span-3 { grid-row: span 3; }
84
+ .a1-grid-item--row-span-4 { grid-row: span 4; }
85
+ .a1-grid-item--row-span-5 { grid-row: span 5; }
86
+ .a1-grid-item--row-span-6 { grid-row: span 6; }
@@ -0,0 +1,69 @@
1
+ import "./heading.css";
2
+
3
+ const headingSizes = ["xl", "lg", "md", "sm", "xs"];
4
+ const displaySizes = ["sm", "md", "lg", "xl", "xxl", "jumbo", "xJumbo"];
5
+ const colors = ["default", "muted", "accent"];
6
+ const levels = ["h1", "h2", "h3", "h4", "h5", "h6"];
7
+ const breakpoints = ["xs", "sm", "md", "lg", "xl"];
8
+
9
+ const levelDefaults = { h1: "xl", h2: "lg", h3: "md", h4: "sm", h5: "xs", h6: "xs" };
10
+
11
+ function isResponsiveSize(size) {
12
+ return size && typeof size === "object" && !Array.isArray(size);
13
+ }
14
+
15
+ function resolveSize(size, validSizes, defaultSize) {
16
+ if (!isResponsiveSize(size)) {
17
+ return validSizes.includes(size) ? size : defaultSize;
18
+ }
19
+
20
+ return validSizes.includes(size.xs) ? size.xs : defaultSize;
21
+ }
22
+
23
+ function getResponsiveSizeStyle(size, type, validSizes) {
24
+ if (!isResponsiveSize(size)) return {};
25
+
26
+ return breakpoints.slice(1).reduce((style, breakpoint) => {
27
+ const breakpointSize = size[breakpoint];
28
+
29
+ if (validSizes.includes(breakpointSize)) {
30
+ style[`--a1-heading-size-${breakpoint}`] =
31
+ `var(--semantic-font-size-${type}-${breakpointSize === "xJumbo" ? "x-jumbo" : breakpointSize})`;
32
+ }
33
+
34
+ return style;
35
+ }, {});
36
+ }
37
+
38
+ export function Heading({
39
+ as: Component = "h2",
40
+ type = "heading",
41
+ size,
42
+ color = "default",
43
+ className = "",
44
+ style,
45
+ ...props
46
+ }) {
47
+ const resolvedAs = levels.includes(Component) ? Component : "h2";
48
+ const isDisplay = type === "display";
49
+ const validSizes = isDisplay ? displaySizes : headingSizes;
50
+ const defaultSize = isDisplay ? "md" : (levelDefaults[resolvedAs] ?? "md");
51
+ const resolvedSize = resolveSize(size, validSizes, defaultSize);
52
+ const resolvedColor = colors.includes(color) ? color : "default";
53
+ const responsiveSizeStyle = getResponsiveSizeStyle(size, type, validSizes);
54
+ const resolvedStyle = Object.keys(responsiveSizeStyle).length
55
+ ? { ...responsiveSizeStyle, ...style }
56
+ : style;
57
+
58
+ const classes = [
59
+ "a1-heading",
60
+ `a1-heading--${type}`,
61
+ `a1-heading--${type}-${resolvedSize}`,
62
+ resolvedColor !== "default" && `a1-heading--${resolvedColor}`,
63
+ className
64
+ ]
65
+ .filter(Boolean)
66
+ .join(" ");
67
+
68
+ return <Component className={classes} style={resolvedStyle} {...props} />;
69
+ }
@@ -0,0 +1,76 @@
1
+ .a1-heading {
2
+ margin: 0;
3
+ font-family: var(--a1-heading-family);
4
+ font-size: var(--a1-heading-responsive-size, var(--a1-heading-size));
5
+ font-weight: var(--a1-heading-weight);
6
+ line-height: var(--a1-heading-line-height);
7
+ color: var(--a1-heading-color, var(--semantic-color-text-default));
8
+ }
9
+
10
+ @media (min-width: 481px) {
11
+ .a1-heading {
12
+ --a1-heading-responsive-size: var(--a1-heading-size-sm, var(--a1-heading-size));
13
+ }
14
+ }
15
+
16
+ @media (min-width: 641px) {
17
+ .a1-heading {
18
+ --a1-heading-responsive-size: var(
19
+ --a1-heading-size-md,
20
+ var(--a1-heading-size-sm, var(--a1-heading-size))
21
+ );
22
+ }
23
+ }
24
+
25
+ @media (min-width: 1025px) {
26
+ .a1-heading {
27
+ --a1-heading-responsive-size: var(
28
+ --a1-heading-size-lg,
29
+ var(--a1-heading-size-md, var(--a1-heading-size-sm, var(--a1-heading-size)))
30
+ );
31
+ }
32
+ }
33
+
34
+ @media (min-width: 1441px) {
35
+ .a1-heading {
36
+ --a1-heading-responsive-size: var(
37
+ --a1-heading-size-xl,
38
+ var(
39
+ --a1-heading-size-lg,
40
+ var(--a1-heading-size-md, var(--a1-heading-size-sm, var(--a1-heading-size)))
41
+ )
42
+ );
43
+ }
44
+ }
45
+
46
+ .a1-heading--heading {
47
+ --a1-heading-family: var(--component-heading-font-family-heading);
48
+ --a1-heading-weight: var(--component-heading-font-weight-heading);
49
+ --a1-heading-line-height: var(--component-heading-font-line-height-heading);
50
+ }
51
+
52
+ .a1-heading--display {
53
+ --a1-heading-family: var(--component-heading-font-family-display);
54
+ --a1-heading-weight: var(--component-heading-font-weight-display);
55
+ --a1-heading-line-height: var(--component-heading-font-line-height-display);
56
+ }
57
+
58
+ /* Heading sizes */
59
+ .a1-heading--heading-xl { --a1-heading-size: var(--semantic-font-size-heading-xl); }
60
+ .a1-heading--heading-lg { --a1-heading-size: var(--semantic-font-size-heading-lg); }
61
+ .a1-heading--heading-md { --a1-heading-size: var(--semantic-font-size-heading-md); }
62
+ .a1-heading--heading-sm { --a1-heading-size: var(--semantic-font-size-heading-sm); }
63
+ .a1-heading--heading-xs { --a1-heading-size: var(--semantic-font-size-heading-xs); }
64
+
65
+ /* Display sizes */
66
+ .a1-heading--display-sm { --a1-heading-size: var(--semantic-font-size-display-sm); }
67
+ .a1-heading--display-md { --a1-heading-size: var(--semantic-font-size-display-md); }
68
+ .a1-heading--display-lg { --a1-heading-size: var(--semantic-font-size-display-lg); }
69
+ .a1-heading--display-xl { --a1-heading-size: var(--semantic-font-size-display-xl); }
70
+ .a1-heading--display-xxl { --a1-heading-size: var(--semantic-font-size-display-xxl); }
71
+ .a1-heading--display-jumbo { --a1-heading-size: var(--semantic-font-size-display-jumbo); }
72
+ .a1-heading--display-xJumbo { --a1-heading-size: var(--semantic-font-size-display-x-jumbo); }
73
+
74
+ /* Color modifiers */
75
+ .a1-heading--muted { --a1-heading-color: var(--semantic-color-text-muted); }
76
+ .a1-heading--accent { --a1-heading-color: var(--semantic-color-text-accent); }
@@ -0,0 +1,32 @@
1
+ import "./icon.css";
2
+
3
+ export function Icon({
4
+ name,
5
+ weight,
6
+ grade,
7
+ opticalSize,
8
+ fill,
9
+ className = "",
10
+ style,
11
+ ...props
12
+ }) {
13
+ const vars = {
14
+ ...(weight != null && { "--a1-icon-weight": weight }),
15
+ ...(grade != null && { "--a1-icon-grade": grade }),
16
+ ...(opticalSize != null && { "--a1-icon-opsz": opticalSize }),
17
+ ...(fill != null && { "--a1-icon-fill": fill ? 1 : 0 }),
18
+ };
19
+
20
+ return (
21
+ <span
22
+ className={["a1-icon", "material-symbols-outlined", className]
23
+ .filter(Boolean)
24
+ .join(" ")}
25
+ style={{ ...vars, ...style }}
26
+ aria-hidden="true"
27
+ {...props}
28
+ >
29
+ {name}
30
+ </span>
31
+ );
32
+ }
@@ -0,0 +1,10 @@
1
+ .a1-icon {
2
+ font-size: inherit;
3
+ line-height: 1;
4
+ user-select: none;
5
+ font-variation-settings:
6
+ "FILL" var(--a1-icon-fill, 0),
7
+ "wght" var(--a1-icon-weight, var(--base-font-weight-regular)),
8
+ "GRAD" var(--a1-icon-grade, 0),
9
+ "opsz" var(--a1-icon-opsz, var(--base-icon-optical-size));
10
+ }
@@ -0,0 +1,34 @@
1
+ import "./icon-button.css";
2
+ import { Icon } from "../icon/Icon.jsx";
3
+
4
+ const variants = ["tertiary", "secondary", "destructive", "success"];
5
+
6
+ export function IconButton({
7
+ icon,
8
+ label,
9
+ variant = "tertiary",
10
+ disabled = false,
11
+ onClick,
12
+ className = "",
13
+ ...props
14
+ }) {
15
+ const resolvedVariant = variants.includes(variant) ? variant : "tertiary";
16
+ const classes = [
17
+ "a1-icon-button",
18
+ `a1-icon-button--${resolvedVariant}`,
19
+ className,
20
+ ].filter(Boolean).join(" ");
21
+
22
+ return (
23
+ <button
24
+ type="button"
25
+ className={classes}
26
+ aria-label={label}
27
+ disabled={disabled}
28
+ onClick={onClick}
29
+ {...props}
30
+ >
31
+ <Icon name={icon} />
32
+ </button>
33
+ );
34
+ }
@@ -0,0 +1,196 @@
1
+ /* ═══════════════════════════════════════════════════════════════════════════
2
+ IconButton
3
+ ═══════════════════════════════════════════════════════════════════════════ */
4
+
5
+ .a1-icon-button {
6
+ display: inline-flex;
7
+ align-items: center;
8
+ justify-content: center;
9
+ flex-shrink: 0;
10
+ height: var(--component-icon-button-size);
11
+ aspect-ratio: 1;
12
+ padding: 0;
13
+ border-radius: var(--component-icon-button-border-radius);
14
+ cursor: pointer;
15
+ background: var(--a1-icon-button-background);
16
+ border-width: var(--a1-icon-button-border-width, var(--component-button-tertiary-border-width));
17
+ border-style: solid;
18
+ border-color: var(--a1-icon-button-border);
19
+ color: var(--a1-icon-button-foreground);
20
+ }
21
+
22
+ .a1-icon-button:hover {
23
+ background: var(--a1-icon-button-background-hover);
24
+ border-color: var(--a1-icon-button-border-hover);
25
+ color: var(--a1-icon-button-foreground-hover);
26
+ }
27
+
28
+ .a1-icon-button:active {
29
+ background: var(--a1-icon-button-background-pressed);
30
+ border-color: var(--a1-icon-button-border-pressed);
31
+ color: var(--a1-icon-button-foreground-pressed);
32
+ }
33
+
34
+ .a1-icon-button .a1-icon {
35
+ font-size: var(--component-icon-button-icon-size);
36
+ --a1-icon-opsz: var(--component-icon-button-icon-optical-size);
37
+ }
38
+
39
+ .a1-icon-button:focus-visible {
40
+ outline: var(--component-button-focus-ring-width) solid var(--component-button-focus-ring);
41
+ outline-offset: var(--component-icon-button-focus-ring-offset);
42
+ }
43
+
44
+ .a1-icon-button:disabled {
45
+ opacity: var(--component-button-disabled-opacity);
46
+ cursor: not-allowed;
47
+ pointer-events: none;
48
+ }
49
+
50
+ /* ── Variant: tertiary ───────────────────────────────────────────────────── */
51
+
52
+ .a1-icon-button--tertiary {
53
+ --a1-icon-button-background: var(--component-button-tertiary-background);
54
+ --a1-icon-button-background-hover: var(--component-button-tertiary-background-hover);
55
+ --a1-icon-button-background-pressed: var(--component-button-tertiary-background-pressed);
56
+ --a1-icon-button-foreground: var(--component-button-tertiary-foreground);
57
+ --a1-icon-button-foreground-hover: var(--component-button-tertiary-foreground-hover);
58
+ --a1-icon-button-foreground-pressed: var(--component-button-tertiary-foreground-pressed);
59
+ --a1-icon-button-border: var(--component-button-tertiary-border);
60
+ --a1-icon-button-border-hover: var(--component-button-tertiary-border-hover);
61
+ --a1-icon-button-border-pressed: var(--component-button-tertiary-border-pressed);
62
+ --a1-icon-button-border-width: var(--component-button-tertiary-border-width);
63
+ }
64
+
65
+ /* ── Variant: secondary ──────────────────────────────────────────────────── */
66
+
67
+ .a1-icon-button--secondary {
68
+ --a1-icon-button-background: var(--component-button-secondary-background);
69
+ --a1-icon-button-background-hover: var(--component-button-secondary-background-hover);
70
+ --a1-icon-button-background-pressed: var(--component-button-secondary-background-pressed);
71
+ --a1-icon-button-foreground: var(--component-button-secondary-foreground);
72
+ --a1-icon-button-foreground-hover: var(--component-button-secondary-foreground-hover);
73
+ --a1-icon-button-foreground-pressed: var(--component-button-secondary-foreground-pressed);
74
+ --a1-icon-button-border: var(--component-button-secondary-border);
75
+ --a1-icon-button-border-hover: var(--component-button-secondary-border-hover);
76
+ --a1-icon-button-border-pressed: var(--component-button-secondary-border-pressed);
77
+ --a1-icon-button-border-width: var(--component-button-secondary-border-width);
78
+ }
79
+
80
+ /* ── Variant: destructive ───────────────────────────────────────────────── */
81
+
82
+ .a1-icon-button--destructive {
83
+ background: var(--semantic-color-status-error-surface);
84
+ border-color: var(--semantic-color-status-error-border);
85
+ color: var(--semantic-color-status-error-background);
86
+ }
87
+
88
+ .a1-icon-button--destructive:hover {
89
+ background: color-mix(in srgb, var(--semantic-color-status-error-surface), var(--semantic-color-status-error-background) 8%);
90
+ border-color: var(--semantic-color-status-error-background);
91
+ color: var(--semantic-color-status-error-background);
92
+ }
93
+
94
+ .a1-icon-button--destructive:active {
95
+ background: color-mix(in srgb, var(--semantic-color-status-error-surface), var(--semantic-color-status-error-background) 16%);
96
+ border-color: var(--semantic-color-status-error-background);
97
+ color: var(--semantic-color-status-error-background);
98
+ }
99
+
100
+ /* ── Variant: success ───────────────────────────────────────────────────── */
101
+
102
+ .a1-icon-button--success {
103
+ background: var(--semantic-color-status-success-surface);
104
+ border-color: var(--semantic-color-status-success-border);
105
+ color: var(--semantic-color-status-success-background);
106
+ }
107
+
108
+ .a1-icon-button--success:hover {
109
+ background: color-mix(in srgb, var(--semantic-color-status-success-surface), var(--semantic-color-status-success-background) 8%);
110
+ border-color: var(--semantic-color-status-success-background);
111
+ color: var(--semantic-color-status-success-background);
112
+ }
113
+
114
+ .a1-icon-button--success:active {
115
+ background: color-mix(in srgb, var(--semantic-color-status-success-surface), var(--semantic-color-status-success-background) 16%);
116
+ border-color: var(--semantic-color-status-success-background);
117
+ color: var(--semantic-color-status-success-background);
118
+ }
119
+
120
+ .a1-theme-dark .a1-icon-button--destructive,
121
+ .a1-inverse .a1-icon-button--destructive {
122
+ background: var(--semantic-color-status-error-background);
123
+ border-color: var(--semantic-color-status-error-background);
124
+ color: var(--semantic-color-status-error-foreground);
125
+ }
126
+
127
+ .a1-theme-dark .a1-icon-button--destructive:hover,
128
+ .a1-inverse .a1-icon-button--destructive:hover {
129
+ background: color-mix(in srgb, var(--semantic-color-status-error-background), black 16%);
130
+ border-color: var(--semantic-color-status-error-background);
131
+ color: var(--semantic-color-status-error-foreground);
132
+ }
133
+
134
+ .a1-theme-dark .a1-icon-button--destructive:active,
135
+ .a1-inverse .a1-icon-button--destructive:active {
136
+ background: color-mix(in srgb, var(--semantic-color-status-error-background), black 32%);
137
+ border-color: var(--semantic-color-status-error-background);
138
+ color: var(--semantic-color-status-error-foreground);
139
+ }
140
+
141
+ .a1-theme-dark .a1-icon-button--success,
142
+ .a1-inverse .a1-icon-button--success {
143
+ background: var(--semantic-color-status-success-background);
144
+ border-color: var(--semantic-color-status-success-background);
145
+ color: var(--semantic-color-status-success-foreground);
146
+ }
147
+
148
+ .a1-theme-dark .a1-icon-button--success:hover,
149
+ .a1-inverse .a1-icon-button--success:hover {
150
+ background: color-mix(in srgb, var(--semantic-color-status-success-background), black 16%);
151
+ border-color: var(--semantic-color-status-success-background);
152
+ color: var(--semantic-color-status-success-foreground);
153
+ }
154
+
155
+ .a1-theme-dark .a1-icon-button--success:active,
156
+ .a1-inverse .a1-icon-button--success:active {
157
+ background: color-mix(in srgb, var(--semantic-color-status-success-background), black 32%);
158
+ border-color: var(--semantic-color-status-success-background);
159
+ color: var(--semantic-color-status-success-foreground);
160
+ }
161
+
162
+ .a1-theme-dark .a1-inverse .a1-icon-button--destructive {
163
+ background: var(--semantic-color-status-error-surface);
164
+ border-color: var(--semantic-color-status-error-border);
165
+ color: var(--semantic-color-status-error-background);
166
+ }
167
+
168
+ .a1-theme-dark .a1-inverse .a1-icon-button--destructive:hover {
169
+ background: color-mix(in srgb, var(--semantic-color-status-error-surface), var(--semantic-color-status-error-background) 8%);
170
+ border-color: var(--semantic-color-status-error-background);
171
+ color: var(--semantic-color-status-error-background);
172
+ }
173
+
174
+ .a1-theme-dark .a1-inverse .a1-icon-button--destructive:active {
175
+ background: color-mix(in srgb, var(--semantic-color-status-error-surface), var(--semantic-color-status-error-background) 16%);
176
+ border-color: var(--semantic-color-status-error-background);
177
+ color: var(--semantic-color-status-error-background);
178
+ }
179
+
180
+ .a1-theme-dark .a1-inverse .a1-icon-button--success {
181
+ background: var(--semantic-color-status-success-surface);
182
+ border-color: var(--semantic-color-status-success-border);
183
+ color: var(--semantic-color-status-success-background);
184
+ }
185
+
186
+ .a1-theme-dark .a1-inverse .a1-icon-button--success:hover {
187
+ background: color-mix(in srgb, var(--semantic-color-status-success-surface), var(--semantic-color-status-success-background) 8%);
188
+ border-color: var(--semantic-color-status-success-background);
189
+ color: var(--semantic-color-status-success-background);
190
+ }
191
+
192
+ .a1-theme-dark .a1-inverse .a1-icon-button--success:active {
193
+ background: color-mix(in srgb, var(--semantic-color-status-success-surface), var(--semantic-color-status-success-background) 16%);
194
+ border-color: var(--semantic-color-status-success-background);
195
+ color: var(--semantic-color-status-success-background);
196
+ }
@@ -0,0 +1,18 @@
1
+ import "../../themes.css";
2
+ import "../../color-scheme.css";
3
+
4
+ export function Inverse({
5
+ as: Component = "div",
6
+ className = "",
7
+ children,
8
+ ...props
9
+ }) {
10
+ return (
11
+ <Component
12
+ className={["a1-inverse", className].filter(Boolean).join(" ")}
13
+ {...props}
14
+ >
15
+ {children}
16
+ </Component>
17
+ );
18
+ }
@@ -0,0 +1,29 @@
1
+ import { createContext, useContext } from "react";
2
+
3
+ const LabelsContext = createContext({ locale: null, brand: null, labels: null });
4
+
5
+ export function LabelsProvider({ locale = null, brand = null, labels, children }) {
6
+ return (
7
+ <LabelsContext.Provider value={{ locale, brand, labels }}>
8
+ {children}
9
+ </LabelsContext.Provider>
10
+ );
11
+ }
12
+
13
+ export function useLabel(key) {
14
+ const { locale, brand, labels } = useContext(LabelsContext);
15
+ if (!labels) return key;
16
+
17
+ const parts = key.split(".");
18
+ let node = labels?.label;
19
+ for (const part of parts) {
20
+ if (node == null || typeof node !== "object") return key;
21
+ node = node[part];
22
+ }
23
+ if (node == null) return key;
24
+
25
+ // Resolution order: locale > brand > default
26
+ if (locale && node.locale?.[locale] != null) return node.locale[locale];
27
+ if (brand && node.brand?.[brand] != null) return node.brand[brand];
28
+ return node.$value ?? key;
29
+ }