@gtivr4/a1-design-system-react 0.1.0 → 0.2.3

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 (108) hide show
  1. package/package.json +1 -1
  2. package/src/color-scheme.css +586 -24
  3. package/src/components/accordion/Accordion.jsx +80 -0
  4. package/src/components/accordion/accordion.css +118 -0
  5. package/src/components/banner/Banner.jsx +66 -0
  6. package/src/components/banner/banner.css +205 -0
  7. package/src/components/bleed/Bleed.jsx +27 -0
  8. package/src/components/bleed/bleed.css +5 -0
  9. package/src/components/blockquote/Blockquote.jsx +40 -0
  10. package/src/components/blockquote/blockquote.css +166 -0
  11. package/src/components/breadcrumb/Breadcrumb.jsx +82 -0
  12. package/src/components/breadcrumb/breadcrumb.css +133 -0
  13. package/src/components/button/button.css +42 -12
  14. package/src/components/button-container/ButtonContainer.jsx +20 -1
  15. package/src/components/button-container/button-container.css +19 -1
  16. package/src/components/calendar/Calendar.jsx +383 -0
  17. package/src/components/calendar/calendar.css +225 -0
  18. package/src/components/card/Card.jsx +50 -12
  19. package/src/components/card/card.css +178 -14
  20. package/src/components/checkbox-group/CheckboxGroup.jsx +120 -0
  21. package/src/components/checkbox-group/checkbox-group.css +304 -0
  22. package/src/components/cluster/Cluster.jsx +52 -0
  23. package/src/components/cluster/cluster.css +9 -0
  24. package/src/components/code/Code.jsx +135 -0
  25. package/src/components/code/code.css +60 -0
  26. package/src/components/data-table/DataTable.jsx +721 -0
  27. package/src/components/data-table/DataTableFilters.jsx +339 -0
  28. package/src/components/data-table/data-table-filters.css +259 -0
  29. package/src/components/data-table/data-table.css +425 -0
  30. package/src/components/dialog/Dialog.jsx +45 -2
  31. package/src/components/dialog/dialog.css +13 -4
  32. package/src/components/divider/Divider.jsx +64 -0
  33. package/src/components/divider/divider.css +170 -0
  34. package/src/components/field/CreditCardField.jsx +131 -0
  35. package/src/components/field/DateField.jsx +11 -0
  36. package/src/components/field/NumberField.jsx +11 -0
  37. package/src/components/field/PhoneField.jsx +107 -0
  38. package/src/components/field/SelectField.jsx +86 -0
  39. package/src/components/field/TextField.jsx +83 -0
  40. package/src/components/field/TextareaField.jsx +147 -0
  41. package/src/components/field/TimeField.jsx +11 -0
  42. package/src/components/field/ZipField.jsx +114 -0
  43. package/src/components/field/credit-card.css +30 -0
  44. package/src/components/field/field.css +380 -0
  45. package/src/components/field/textarea-field.css +185 -0
  46. package/src/components/field-row/FieldRow.jsx +23 -0
  47. package/src/components/field-row/field-row.css +51 -0
  48. package/src/components/fieldset/Fieldset.jsx +49 -0
  49. package/src/components/fieldset/fieldset.css +75 -0
  50. package/src/components/figure/Figure.jsx +63 -0
  51. package/src/components/figure/figure.css +97 -0
  52. package/src/components/grid/Grid.jsx +36 -2
  53. package/src/components/grid/grid.css +129 -4
  54. package/src/components/heading/Heading.jsx +41 -1
  55. package/src/components/heading/heading.css +65 -4
  56. package/src/components/icon/icon.css +1 -0
  57. package/src/components/icon-button/icon-button.css +1 -0
  58. package/src/components/inline/inline.css +51 -0
  59. package/src/components/inline-editable/InlineEditable.jsx +77 -0
  60. package/src/components/inline-editable/inline-editable.css +47 -0
  61. package/src/components/inset/Inset.jsx +27 -0
  62. package/src/components/inset/inset.css +6 -0
  63. package/src/components/labels/Labels.jsx +5 -5
  64. package/src/components/link/Link.jsx +2 -3
  65. package/src/components/link/link.css +30 -1
  66. package/src/components/list/List.jsx +92 -0
  67. package/src/components/list/list.css +178 -0
  68. package/src/components/menu/Menu.jsx +243 -10
  69. package/src/components/menu/menu.css +157 -17
  70. package/src/components/message/Message.jsx +25 -50
  71. package/src/components/message/message.css +50 -33
  72. package/src/components/notification/Notification.jsx +1 -1
  73. package/src/components/page-layout/PageLayout.jsx +16 -1
  74. package/src/components/page-layout/page-layout.css +97 -4
  75. package/src/components/page-nav/PageNav.jsx +110 -0
  76. package/src/components/page-nav/page-nav.css +167 -0
  77. package/src/components/paragraph/Paragraph.jsx +35 -2
  78. package/src/components/paragraph/paragraph.css +38 -1
  79. package/src/components/radio-group/RadioGroup.jsx +121 -0
  80. package/src/components/radio-group/radio-group.css +268 -0
  81. package/src/components/section/Section.jsx +108 -0
  82. package/src/components/section/section.css +280 -0
  83. package/src/components/segmented-control/SegmentedControl.jsx +4 -0
  84. package/src/components/segmented-control/segmented.css +13 -0
  85. package/src/components/side-nav/SideNav.jsx +29 -9
  86. package/src/components/side-nav/scrim.css +1 -1
  87. package/src/components/side-nav/side-nav.css +70 -32
  88. package/src/components/snackbar/Snackbar.jsx +56 -0
  89. package/src/components/snackbar/snackbar.css +113 -0
  90. package/src/components/spacer/Spacer.jsx +36 -0
  91. package/src/components/spacer/spacer.css +44 -0
  92. package/src/components/stack/Stack.jsx +100 -0
  93. package/src/components/stack/stack.css +37 -0
  94. package/src/components/switch/Switch.jsx +114 -0
  95. package/src/components/switch/switch.css +276 -0
  96. package/src/components/system-banner/SystemBanner.jsx +57 -0
  97. package/src/components/system-banner/system-banner.css +118 -0
  98. package/src/components/tabs/Tabs.jsx +96 -28
  99. package/src/components/tabs/tabs.css +352 -15
  100. package/src/components/token-select/TokenSelect.jsx +159 -0
  101. package/src/components/token-select/token-select.css +110 -0
  102. package/src/components/top-header/TopHeader.jsx +641 -0
  103. package/src/components/top-header/top-header.css +337 -0
  104. package/src/illustrations/ComponentThumbnails.jsx +227 -0
  105. package/src/index.js +41 -5
  106. package/src/themes.css +256 -5
  107. package/src/utilities/spacing.css +8 -0
  108. package/src/utilities/sr-only.css +16 -0
@@ -0,0 +1,80 @@
1
+ import { useId, useLayoutEffect, useRef, useState } from "react";
2
+ import { Icon } from "../icon/Icon.jsx";
3
+ import "./accordion.css";
4
+
5
+ const SIZES = ["sm", "md", "lg"];
6
+
7
+ export function Accordion({
8
+ label,
9
+ children,
10
+ open: controlledOpen,
11
+ defaultOpen = false,
12
+ onChange,
13
+ size = "md",
14
+ disabled = false,
15
+ className = "",
16
+ }) {
17
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
18
+ const isControlled = controlledOpen !== undefined;
19
+ const open = isControlled ? controlledOpen : uncontrolledOpen;
20
+
21
+ const uid = useId();
22
+ const triggerId = `${uid}-trigger`;
23
+ const panelId = `${uid}-panel`;
24
+ const bodyRef = useRef(null);
25
+
26
+ useLayoutEffect(() => {
27
+ const el = bodyRef.current;
28
+ if (!el) return;
29
+ if (open) el.removeAttribute("inert");
30
+ else el.setAttribute("inert", "");
31
+ }, [open]);
32
+
33
+ const resolvedSize = SIZES.includes(size) ? size : "md";
34
+
35
+ function handleToggle() {
36
+ if (disabled) return;
37
+ const next = !open;
38
+ if (!isControlled) setUncontrolledOpen(next);
39
+ onChange?.(next);
40
+ }
41
+
42
+ return (
43
+ <div
44
+ className={[
45
+ "a1-accordion",
46
+ `a1-accordion--${resolvedSize}`,
47
+ open && "a1-accordion--open",
48
+ disabled && "a1-accordion--disabled",
49
+ className,
50
+ ].filter(Boolean).join(" ")}
51
+ >
52
+ <button
53
+ id={triggerId}
54
+ type="button"
55
+ className="a1-accordion__trigger"
56
+ aria-expanded={open}
57
+ aria-controls={panelId}
58
+ disabled={disabled}
59
+ onClick={handleToggle}
60
+ >
61
+ <span className="a1-accordion__chevron" aria-hidden="true">
62
+ <Icon name="expand_more" />
63
+ </span>
64
+ <span className="a1-accordion__label">{label}</span>
65
+ </button>
66
+
67
+ <div
68
+ ref={bodyRef}
69
+ id={panelId}
70
+ role="region"
71
+ aria-labelledby={triggerId}
72
+ className="a1-accordion__body"
73
+ >
74
+ <div className="a1-accordion__body-inner">
75
+ {children}
76
+ </div>
77
+ </div>
78
+ </div>
79
+ );
80
+ }
@@ -0,0 +1,118 @@
1
+ /* ─── Accordion ─────────────────────────────────────────────────────────────── */
2
+
3
+ .a1-accordion {
4
+ /* Size tokens — default (md) */
5
+ --a1-ac-height: var(--component-accordion-trigger-height-md);
6
+ --a1-ac-px: var(--component-accordion-padding-inline-md);
7
+ --a1-ac-py: var(--base-spacing-8);
8
+ --a1-ac-icon-size: var(--component-accordion-icon-size-md);
9
+ --a1-ac-font-size: var(--semantic-font-size-body-md);
10
+ --a1-ac-font-weight: var(--base-font-weight-medium);
11
+ }
12
+
13
+ /* ─── Sizes ─────────────────────────────────────────────────────────────────── */
14
+
15
+ .a1-accordion--sm {
16
+ --a1-ac-height: var(--component-accordion-trigger-height-sm);
17
+ --a1-ac-px: var(--component-accordion-padding-inline-sm);
18
+ --a1-ac-py: var(--base-spacing-6);
19
+ --a1-ac-icon-size: var(--component-accordion-icon-size-sm);
20
+ --a1-ac-font-size: var(--semantic-font-size-body-sm);
21
+ --a1-ac-font-weight: var(--base-font-weight-medium);
22
+ }
23
+
24
+ .a1-accordion--lg {
25
+ --a1-ac-height: var(--component-accordion-trigger-height-lg);
26
+ --a1-ac-px: var(--component-accordion-padding-inline-lg);
27
+ --a1-ac-py: var(--base-spacing-12);
28
+ --a1-ac-icon-size: var(--component-accordion-icon-size-lg);
29
+ --a1-ac-font-size: var(--semantic-font-size-body-lg);
30
+ --a1-ac-font-weight: var(--base-font-weight-bold);
31
+ }
32
+
33
+ /* ─── Trigger ───────────────────────────────────────────────────────────────── */
34
+
35
+ .a1-accordion__trigger {
36
+ display: flex;
37
+ align-items: center;
38
+ gap: var(--base-spacing-6);
39
+ width: 100%;
40
+ min-height: var(--a1-ac-height);
41
+ padding-inline: var(--a1-ac-px);
42
+ padding-block: var(--a1-ac-py);
43
+ border: none;
44
+ border-radius: var(--component-accordion-border-radius);
45
+ background: transparent;
46
+ cursor: pointer;
47
+ color: var(--semantic-color-text-default);
48
+ font-family: var(--semantic-font-family-body);
49
+ font-size: var(--a1-ac-font-size);
50
+ font-weight: var(--a1-ac-font-weight);
51
+ line-height: var(--semantic-font-line-height-body);
52
+ text-align: start;
53
+ transition: background var(--semantic-motion-duration-fast) var(--semantic-motion-easing-standard);
54
+ }
55
+
56
+ .a1-accordion__trigger:hover {
57
+ background: var(--semantic-color-surface-raised);
58
+ }
59
+
60
+ .a1-accordion__trigger:active {
61
+ background: color-mix(in srgb, var(--semantic-color-surface-raised), var(--semantic-color-text-default) 6%);
62
+ }
63
+
64
+ .a1-accordion__trigger:focus-visible {
65
+ outline: var(--component-accordion-focus-ring-width) solid var(--semantic-color-text-accent);
66
+ outline-offset: var(--component-accordion-focus-ring-offset);
67
+ }
68
+
69
+ /* ─── Chevron ───────────────────────────────────────────────────────────────── */
70
+
71
+ .a1-accordion__chevron {
72
+ display: flex;
73
+ align-items: center;
74
+ justify-content: center;
75
+ flex-shrink: 0;
76
+ font-size: var(--a1-ac-icon-size);
77
+ color: var(--semantic-color-text-muted);
78
+ /* Start rotated -90deg (pointing right →) when collapsed */
79
+ transform: rotate(-90deg);
80
+ transition: transform var(--semantic-motion-duration-fast) var(--semantic-motion-easing-standard);
81
+ }
82
+
83
+ .a1-accordion--open .a1-accordion__chevron {
84
+ /* Rotate to 0deg (pointing down ↓) when expanded */
85
+ transform: rotate(0deg);
86
+ }
87
+
88
+ /* ─── Label ─────────────────────────────────────────────────────────────────── */
89
+
90
+ .a1-accordion__label {
91
+ flex: 1;
92
+ min-width: 0;
93
+ }
94
+
95
+ /* ─── Body — CSS grid height animation ──────────────────────────────────────── */
96
+
97
+ .a1-accordion__body {
98
+ display: grid;
99
+ grid-template-rows: 0fr;
100
+ transition: grid-template-rows var(--semantic-motion-duration-fast) var(--semantic-motion-easing-standard);
101
+ }
102
+
103
+ .a1-accordion--open .a1-accordion__body {
104
+ grid-template-rows: 1fr;
105
+ }
106
+
107
+ .a1-accordion__body-inner {
108
+ overflow: hidden;
109
+ min-height: 0;
110
+ }
111
+
112
+ /* ─── Disabled ──────────────────────────────────────────────────────────────── */
113
+
114
+ .a1-accordion--disabled .a1-accordion__trigger {
115
+ cursor: not-allowed;
116
+ opacity: 0.55;
117
+ pointer-events: none;
118
+ }
@@ -0,0 +1,66 @@
1
+ import "./banner.css";
2
+ import { Icon } from "../icon/Icon.jsx";
3
+ import { IconButton } from "../icon-button/IconButton.jsx";
4
+
5
+ const INLINE_ICONS = {
6
+ neutral: "info",
7
+ info: "info",
8
+ success: "check_circle",
9
+ warn: "warning",
10
+ error: "error",
11
+ };
12
+
13
+ const SYSTEM_ICONS = {
14
+ neutral: "campaign",
15
+ info: "info",
16
+ success: "check_circle",
17
+ warn: "warning",
18
+ error: "error",
19
+ };
20
+
21
+ const STATUSES = ["neutral", "info", "success", "warn", "error"];
22
+ const VARIANTS = ["inline", "system"];
23
+
24
+ export function Banner({
25
+ variant = "inline",
26
+ status = "neutral",
27
+ title,
28
+ icon,
29
+ action,
30
+ onDismiss,
31
+ children,
32
+ }) {
33
+ const resolvedVariant = VARIANTS.includes(variant) ? variant : "inline";
34
+ const resolvedStatus = STATUSES.includes(status) ? status : "neutral";
35
+ const resolvedIcon = icon ?? (resolvedVariant === "system" ? SYSTEM_ICONS : INLINE_ICONS)[resolvedStatus];
36
+
37
+ return (
38
+ <div
39
+ className={`a1-banner a1-banner--${resolvedVariant} a1-banner--${resolvedStatus}`}
40
+ role="alert"
41
+ aria-live="polite"
42
+ >
43
+ <div className="a1-banner__inner">
44
+ <span className="a1-banner__icon" aria-hidden="true">
45
+ <Icon name={resolvedIcon} />
46
+ </span>
47
+
48
+ <div className="a1-banner__content">
49
+ {title && <span className="a1-banner__title">{title}</span>}
50
+ {children && <span className="a1-banner__body">{children}</span>}
51
+ </div>
52
+
53
+ {action && <div className="a1-banner__action">{action}</div>}
54
+
55
+ {onDismiss && (
56
+ <IconButton
57
+ icon="close"
58
+ label="Dismiss"
59
+ onClick={onDismiss}
60
+ className="a1-banner__dismiss"
61
+ />
62
+ )}
63
+ </div>
64
+ </div>
65
+ );
66
+ }
@@ -0,0 +1,205 @@
1
+ /* ─── Banner – shared status tokens ───────────────────────────────────────── */
2
+
3
+ .a1-banner {
4
+ --a1-banner-surface: var(--semantic-color-surface-panel);
5
+ --a1-banner-border: var(--semantic-color-border-subtle);
6
+ --a1-banner-accent: var(--semantic-color-text-muted);
7
+ --a1-banner-bg: var(--semantic-color-surface-inverse);
8
+ --a1-banner-fg: var(--semantic-color-text-inverse);
9
+ }
10
+
11
+ .a1-banner--info {
12
+ --a1-banner-surface: var(--semantic-color-status-info-surface);
13
+ --a1-banner-border: var(--semantic-color-status-info-border);
14
+ --a1-banner-accent: var(--semantic-color-status-info-background);
15
+ --a1-banner-bg: var(--semantic-color-status-info-background);
16
+ }
17
+ .a1-banner--success {
18
+ --a1-banner-surface: var(--semantic-color-status-success-surface);
19
+ --a1-banner-border: var(--semantic-color-status-success-border);
20
+ --a1-banner-accent: var(--semantic-color-status-success-background);
21
+ --a1-banner-bg: var(--semantic-color-status-success-background);
22
+ }
23
+ .a1-banner--warn {
24
+ --a1-banner-surface: var(--semantic-color-status-warn-surface);
25
+ --a1-banner-border: var(--semantic-color-status-warn-border);
26
+ --a1-banner-accent: var(--semantic-color-status-warn-background);
27
+ --a1-banner-bg: var(--semantic-color-status-warn-background);
28
+ }
29
+
30
+ /* System banners render white text on a solid background — warn.500 only hits
31
+ 3.18:1. Use warn.text (warn.600 in light, warn.300 in dark) which always passes. */
32
+ .a1-banner--system.a1-banner--warn {
33
+ --a1-banner-bg: var(--semantic-color-status-warn-text);
34
+ }
35
+ .a1-banner--error {
36
+ --a1-banner-surface: var(--semantic-color-status-error-surface);
37
+ --a1-banner-border: var(--semantic-color-status-error-border);
38
+ --a1-banner-accent: var(--semantic-color-status-error-background);
39
+ --a1-banner-bg: var(--semantic-color-status-error-background);
40
+ }
41
+
42
+ /* ─── Shared inner structure ───────────────────────────────────────────────── */
43
+
44
+ .a1-banner__inner {
45
+ display: flex;
46
+ gap: var(--component-message-banner-padding);
47
+ }
48
+
49
+ .a1-banner__content {
50
+ flex: 1;
51
+ min-width: 0;
52
+ display: flex;
53
+ }
54
+
55
+ .a1-banner__title,
56
+ .a1-banner__body {
57
+ font-family: var(--component-paragraph-font-family);
58
+ font-size: var(--semantic-font-size-body-sm);
59
+ }
60
+
61
+ .a1-banner__title {
62
+ font-weight: var(--component-message-banner-title-font-weight);
63
+ line-height: var(--semantic-font-line-height-heading);
64
+ }
65
+
66
+ .a1-banner__body {
67
+ font-weight: var(--semantic-font-weight-body);
68
+ line-height: var(--semantic-font-line-height-body);
69
+ }
70
+
71
+ .a1-banner__action {
72
+ flex-shrink: 0;
73
+ }
74
+
75
+ .a1-banner__dismiss {
76
+ flex-shrink: 0;
77
+ }
78
+
79
+ /* ─── Inline variant ───────────────────────────────────────────────────────── */
80
+
81
+ .a1-banner--inline .a1-banner__inner {
82
+ align-items: flex-start;
83
+ padding: var(--component-message-banner-padding);
84
+ border: var(--component-message-banner-border-width) solid var(--a1-banner-border);
85
+ border-radius: var(--component-message-banner-border-radius);
86
+ background: var(--a1-banner-surface);
87
+ }
88
+
89
+ .a1-banner--inline .a1-banner__icon {
90
+ flex-shrink: 0;
91
+ color: var(--a1-banner-accent);
92
+ font-size: var(--component-message-banner-icon-size);
93
+ line-height: 1;
94
+ margin-top: var(--component-message-banner-icon-margin-top);
95
+ --a1-icon-opsz: var(--component-message-banner-icon-optical-size);
96
+ }
97
+
98
+ .a1-banner--inline .a1-banner__content {
99
+ flex-direction: column;
100
+ gap: var(--base-spacing-4);
101
+ }
102
+
103
+ .a1-banner--inline .a1-banner__title {
104
+ color: var(--semantic-color-text-default);
105
+ }
106
+
107
+ .a1-banner--inline .a1-banner__body {
108
+ color: var(--semantic-color-text-muted);
109
+ }
110
+
111
+ .a1-banner--inline .a1-banner__action {
112
+ align-self: center;
113
+ }
114
+
115
+ .a1-banner--inline .a1-banner__dismiss {
116
+ margin-top: var(--component-message-banner-dismiss-offset);
117
+ margin-right: var(--component-message-banner-dismiss-offset);
118
+ }
119
+
120
+ /* ─── System variant ───────────────────────────────────────────────────────── */
121
+
122
+ .a1-banner--system {
123
+ background: var(--a1-banner-bg);
124
+ color: var(--a1-banner-fg);
125
+ width: 100%;
126
+ }
127
+
128
+ .a1-banner--system .a1-banner__inner {
129
+ align-items: center;
130
+ flex-wrap: wrap;
131
+ gap: var(--base-spacing-8) var(--base-spacing-12);
132
+ max-width: var(--component-message-banner-system-max-width);
133
+ margin-inline: auto;
134
+ padding-block: var(--base-spacing-12);
135
+ padding-inline: var(--base-spacing-24);
136
+ }
137
+
138
+ .a1-banner--system .a1-banner__icon {
139
+ flex-shrink: 0;
140
+ display: flex;
141
+ font-size: var(--component-message-banner-system-icon-size, var(--base-spacing-24));
142
+ line-height: 1;
143
+ --a1-icon-opsz: 24;
144
+ }
145
+
146
+ .a1-banner--system .a1-banner__content {
147
+ flex-direction: row;
148
+ flex-wrap: wrap;
149
+ align-items: baseline;
150
+ gap: 0 var(--base-spacing-8);
151
+ }
152
+
153
+ .a1-banner--system .a1-banner__title {
154
+ color: var(--a1-banner-fg);
155
+ }
156
+
157
+ .a1-banner--system .a1-banner__body {
158
+ color: var(--a1-banner-fg);
159
+ }
160
+
161
+ .a1-banner--system .a1-banner__dismiss {
162
+ margin-inline-start: var(--base-spacing-4);
163
+ }
164
+
165
+ /* ─── System: link override on solid bg ────────────────────────────────────── */
166
+
167
+ .a1-banner--system .a1-link {
168
+ color: var(--a1-banner-fg);
169
+ }
170
+
171
+ .a1-banner--system .a1-link:hover {
172
+ color: color-mix(in srgb, var(--a1-banner-fg) 80%, transparent);
173
+ }
174
+
175
+ .a1-banner--system .a1-link:active {
176
+ color: color-mix(in srgb, var(--a1-banner-fg) 65%, transparent);
177
+ }
178
+
179
+ /* ─── System: tertiary button override on solid bg ──────────────────────────── */
180
+
181
+ .a1-banner--system .a1-button--tertiary {
182
+ --a1-button-foreground: var(--a1-banner-fg);
183
+ --a1-button-foreground-hover: var(--a1-banner-fg);
184
+ --a1-button-foreground-pressed: var(--a1-banner-fg);
185
+ --a1-button-background: transparent;
186
+ --a1-button-background-hover: color-mix(in srgb, var(--a1-banner-fg) 12%, transparent);
187
+ --a1-button-background-pressed: color-mix(in srgb, var(--a1-banner-fg) 20%, transparent);
188
+ --a1-button-border: color-mix(in srgb, var(--a1-banner-fg) 40%, transparent);
189
+ --a1-button-border-hover: color-mix(in srgb, var(--a1-banner-fg) 60%, transparent);
190
+ --a1-button-border-pressed: color-mix(in srgb, var(--a1-banner-fg) 75%, transparent);
191
+ }
192
+
193
+ /* ─── System: icon button (dismiss) override on solid bg ────────────────────── */
194
+
195
+ .a1-banner--system .a1-icon-button {
196
+ --a1-icon-button-foreground: var(--a1-banner-fg);
197
+ --a1-icon-button-foreground-hover: var(--a1-banner-fg);
198
+ --a1-icon-button-foreground-pressed: var(--a1-banner-fg);
199
+ --a1-icon-button-background: transparent;
200
+ --a1-icon-button-background-hover: color-mix(in srgb, var(--a1-banner-fg) 12%, transparent);
201
+ --a1-icon-button-background-pressed: color-mix(in srgb, var(--a1-banner-fg) 20%, transparent);
202
+ --a1-icon-button-border: transparent;
203
+ --a1-icon-button-border-hover: transparent;
204
+ --a1-icon-button-border-pressed: transparent;
205
+ }
@@ -0,0 +1,27 @@
1
+ import "./bleed.css";
2
+ import { resolveSpacing } from "../structure-utils.js";
3
+
4
+ export function Bleed({
5
+ as: Component = "div",
6
+ space = 16,
7
+ block = "none",
8
+ inline,
9
+ className = "",
10
+ children,
11
+ ...props
12
+ }) {
13
+ const blockValue = resolveSpacing(block) ?? resolveSpacing(space);
14
+ const inlineValue = resolveSpacing(inline) ?? resolveSpacing(space);
15
+
16
+ const style = {
17
+ "--a1-bleed-block": blockValue,
18
+ "--a1-bleed-inline": inlineValue,
19
+ ...props.style,
20
+ };
21
+
22
+ return (
23
+ <Component className={["a1-bleed", className].filter(Boolean).join(" ")} style={style} {...props}>
24
+ {children}
25
+ </Component>
26
+ );
27
+ }
@@ -0,0 +1,5 @@
1
+ .a1-bleed {
2
+ margin-block: calc(var(--a1-bleed-block, 0) * -1);
3
+ margin-inline: calc(var(--a1-bleed-inline, var(--base-spacing-16)) * -1);
4
+ min-width: 0;
5
+ }
@@ -0,0 +1,40 @@
1
+ import "./blockquote.css";
2
+
3
+ const VARIANTS = ["border", "filled", "feature", "minimal", "accent", "pull", "ruled"];
4
+
5
+ export function Blockquote({
6
+ variant = "border",
7
+ cite,
8
+ citeUrl,
9
+ className = "",
10
+ children,
11
+ ...props
12
+ }) {
13
+ const resolvedVariant = VARIANTS.includes(variant) ? variant : "border";
14
+
15
+ return (
16
+ <figure
17
+ className={[
18
+ "a1-blockquote",
19
+ `a1-blockquote--${resolvedVariant}`,
20
+ className,
21
+ ]
22
+ .filter(Boolean)
23
+ .join(" ")}
24
+ {...props}
25
+ >
26
+ <blockquote className="a1-blockquote__quote">{children}</blockquote>
27
+ {cite && (
28
+ <figcaption className="a1-blockquote__cite">
29
+ {citeUrl ? (
30
+ <a href={citeUrl} className="a1-blockquote__cite-link">
31
+ {cite}
32
+ </a>
33
+ ) : (
34
+ cite
35
+ )}
36
+ </figcaption>
37
+ )}
38
+ </figure>
39
+ );
40
+ }