@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.
- package/package.json +1 -1
- package/src/color-scheme.css +586 -24
- package/src/components/accordion/Accordion.jsx +80 -0
- package/src/components/accordion/accordion.css +118 -0
- package/src/components/banner/Banner.jsx +66 -0
- package/src/components/banner/banner.css +205 -0
- package/src/components/bleed/Bleed.jsx +27 -0
- package/src/components/bleed/bleed.css +5 -0
- package/src/components/blockquote/Blockquote.jsx +40 -0
- package/src/components/blockquote/blockquote.css +166 -0
- package/src/components/breadcrumb/Breadcrumb.jsx +82 -0
- package/src/components/breadcrumb/breadcrumb.css +133 -0
- package/src/components/button/button.css +42 -12
- package/src/components/button-container/ButtonContainer.jsx +20 -1
- package/src/components/button-container/button-container.css +19 -1
- package/src/components/calendar/Calendar.jsx +383 -0
- package/src/components/calendar/calendar.css +225 -0
- package/src/components/card/Card.jsx +50 -12
- package/src/components/card/card.css +178 -14
- package/src/components/checkbox-group/CheckboxGroup.jsx +120 -0
- package/src/components/checkbox-group/checkbox-group.css +304 -0
- package/src/components/cluster/Cluster.jsx +52 -0
- package/src/components/cluster/cluster.css +9 -0
- package/src/components/code/Code.jsx +135 -0
- package/src/components/code/code.css +60 -0
- package/src/components/data-table/DataTable.jsx +721 -0
- package/src/components/data-table/DataTableFilters.jsx +339 -0
- package/src/components/data-table/data-table-filters.css +259 -0
- package/src/components/data-table/data-table.css +425 -0
- package/src/components/dialog/Dialog.jsx +45 -2
- package/src/components/dialog/dialog.css +13 -4
- package/src/components/divider/Divider.jsx +64 -0
- package/src/components/divider/divider.css +170 -0
- package/src/components/field/CreditCardField.jsx +131 -0
- package/src/components/field/DateField.jsx +11 -0
- package/src/components/field/NumberField.jsx +11 -0
- package/src/components/field/PhoneField.jsx +107 -0
- package/src/components/field/SelectField.jsx +86 -0
- package/src/components/field/TextField.jsx +83 -0
- package/src/components/field/TextareaField.jsx +147 -0
- package/src/components/field/TimeField.jsx +11 -0
- package/src/components/field/ZipField.jsx +114 -0
- package/src/components/field/credit-card.css +30 -0
- package/src/components/field/field.css +380 -0
- package/src/components/field/textarea-field.css +185 -0
- package/src/components/field-row/FieldRow.jsx +23 -0
- package/src/components/field-row/field-row.css +51 -0
- package/src/components/fieldset/Fieldset.jsx +49 -0
- package/src/components/fieldset/fieldset.css +75 -0
- package/src/components/figure/Figure.jsx +63 -0
- package/src/components/figure/figure.css +97 -0
- package/src/components/grid/Grid.jsx +36 -2
- package/src/components/grid/grid.css +129 -4
- package/src/components/heading/Heading.jsx +41 -1
- package/src/components/heading/heading.css +65 -4
- package/src/components/icon/icon.css +1 -0
- package/src/components/icon-button/icon-button.css +1 -0
- package/src/components/inline/inline.css +51 -0
- package/src/components/inline-editable/InlineEditable.jsx +77 -0
- package/src/components/inline-editable/inline-editable.css +47 -0
- package/src/components/inset/Inset.jsx +27 -0
- package/src/components/inset/inset.css +6 -0
- package/src/components/labels/Labels.jsx +5 -5
- package/src/components/link/Link.jsx +2 -3
- package/src/components/link/link.css +30 -1
- package/src/components/list/List.jsx +92 -0
- package/src/components/list/list.css +178 -0
- package/src/components/menu/Menu.jsx +243 -10
- package/src/components/menu/menu.css +157 -17
- package/src/components/message/Message.jsx +25 -50
- package/src/components/message/message.css +50 -33
- package/src/components/notification/Notification.jsx +1 -1
- package/src/components/page-layout/PageLayout.jsx +16 -1
- package/src/components/page-layout/page-layout.css +97 -4
- package/src/components/page-nav/PageNav.jsx +110 -0
- package/src/components/page-nav/page-nav.css +167 -0
- package/src/components/paragraph/Paragraph.jsx +35 -2
- package/src/components/paragraph/paragraph.css +38 -1
- package/src/components/radio-group/RadioGroup.jsx +121 -0
- package/src/components/radio-group/radio-group.css +268 -0
- package/src/components/section/Section.jsx +108 -0
- package/src/components/section/section.css +280 -0
- package/src/components/segmented-control/SegmentedControl.jsx +4 -0
- package/src/components/segmented-control/segmented.css +13 -0
- package/src/components/side-nav/SideNav.jsx +29 -9
- package/src/components/side-nav/scrim.css +1 -1
- package/src/components/side-nav/side-nav.css +70 -32
- package/src/components/snackbar/Snackbar.jsx +56 -0
- package/src/components/snackbar/snackbar.css +113 -0
- package/src/components/spacer/Spacer.jsx +36 -0
- package/src/components/spacer/spacer.css +44 -0
- package/src/components/stack/Stack.jsx +100 -0
- package/src/components/stack/stack.css +37 -0
- package/src/components/switch/Switch.jsx +114 -0
- package/src/components/switch/switch.css +276 -0
- package/src/components/system-banner/SystemBanner.jsx +57 -0
- package/src/components/system-banner/system-banner.css +118 -0
- package/src/components/tabs/Tabs.jsx +96 -28
- package/src/components/tabs/tabs.css +352 -15
- package/src/components/token-select/TokenSelect.jsx +159 -0
- package/src/components/token-select/token-select.css +110 -0
- package/src/components/top-header/TopHeader.jsx +641 -0
- package/src/components/top-header/top-header.css +337 -0
- package/src/illustrations/ComponentThumbnails.jsx +227 -0
- package/src/index.js +41 -5
- package/src/themes.css +256 -5
- package/src/utilities/spacing.css +8 -0
- package/src/utilities/sr-only.css +16 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* ─── Segmented control ───────────────────────────────────────────────────── */
|
|
2
2
|
|
|
3
3
|
.a1-segmented {
|
|
4
|
+
box-sizing: border-box;
|
|
4
5
|
display: inline-flex;
|
|
5
6
|
align-items: stretch;
|
|
6
7
|
background: var(--semantic-color-surface-raised);
|
|
@@ -69,6 +70,18 @@
|
|
|
69
70
|
padding-inline: var(--component-segmented-segment-padding-block);
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
/* ─── Dark mode ───────────────────────────────────────────────────────────── */
|
|
74
|
+
|
|
75
|
+
.a1-theme-dark .a1-segment:not([aria-checked="true"]),
|
|
76
|
+
.a1-inverse .a1-segment:not([aria-checked="true"]) {
|
|
77
|
+
color: var(--base-color-neutral-300);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.a1-theme-dark .a1-segment:hover:not([aria-checked="true"]),
|
|
81
|
+
.a1-inverse .a1-segment:hover:not([aria-checked="true"]) {
|
|
82
|
+
color: var(--base-color-neutral-100);
|
|
83
|
+
}
|
|
84
|
+
|
|
72
85
|
/* ─── Full width ──────────────────────────────────────────────────────────── */
|
|
73
86
|
|
|
74
87
|
.a1-segmented--full-width .a1-segment {
|
|
@@ -17,7 +17,7 @@ const SideNavCtx = createContext({ collapsed: false, onExpand: null });
|
|
|
17
17
|
* @param {boolean} [props.active] - Marks this item as the current page
|
|
18
18
|
* @param {string} [props.className]
|
|
19
19
|
*/
|
|
20
|
-
export function SideNavItem({ as: Component = "a", icon, label, active, className = "", ...props }) {
|
|
20
|
+
export function SideNavItem({ as: Component = "a", icon, label, badge, active, className = "", ...props }) {
|
|
21
21
|
const depth = useContext(DepthCtx);
|
|
22
22
|
const { collapsed } = useContext(SideNavCtx);
|
|
23
23
|
|
|
@@ -37,6 +37,7 @@ export function SideNavItem({ as: Component = "a", icon, label, active, classNam
|
|
|
37
37
|
>
|
|
38
38
|
{icon && <Icon name={icon} className="a1-side-nav-item__icon" />}
|
|
39
39
|
<span className="a1-side-nav-item__label">{label}</span>
|
|
40
|
+
{badge && !collapsed && <span className="a1-side-nav-item__badge">{badge}</span>}
|
|
40
41
|
</Component>
|
|
41
42
|
);
|
|
42
43
|
}
|
|
@@ -112,7 +113,8 @@ export function SideNavGroup({ icon, label, defaultOpen = false, open: controlle
|
|
|
112
113
|
* - sm/md (481–1024px): fixed-width overlay with scrim; built-in close (✕) button
|
|
113
114
|
* - lg/xl (≥1025px): persistent in the document flow; built-in collapse (‹/›) toggle
|
|
114
115
|
*
|
|
115
|
-
* The close
|
|
116
|
+
* The close button is rendered inline with the header content. The desktop
|
|
117
|
+
* collapse button can be rendered in the header or footer.
|
|
116
118
|
*
|
|
117
119
|
* @param {object} props
|
|
118
120
|
* @param {React.ReactNode | ((collapsed: boolean) => React.ReactNode)} [props.header]
|
|
@@ -125,6 +127,7 @@ export function SideNavGroup({ icon, label, defaultOpen = false, open: controlle
|
|
|
125
127
|
* @param {boolean} [props.defaultCollapsed=false] - Initial collapsed state for lg/xl (uncontrolled)
|
|
126
128
|
* @param {boolean} [props.collapsed] - Controlled collapsed state for lg/xl
|
|
127
129
|
* @param {function} [props.onCollapsedChange] - Called with next boolean when collapsed state changes
|
|
130
|
+
* @param {"header"|"footer"} [props.collapseButtonPlacement="header"] - Where the desktop collapse button appears
|
|
128
131
|
* @param {"start"|"end"} [props.placement="start"] - Side of the viewport/layout where the nav appears
|
|
129
132
|
* @param {string} [props.className]
|
|
130
133
|
*/
|
|
@@ -132,6 +135,7 @@ export function SideNav({
|
|
|
132
135
|
header, footer, children,
|
|
133
136
|
open = false, onClose,
|
|
134
137
|
collapsed: controlledCollapsed, defaultCollapsed = false, onCollapsedChange,
|
|
138
|
+
collapseButtonPlacement = "header",
|
|
135
139
|
placement = "start",
|
|
136
140
|
className = "", ...props
|
|
137
141
|
}) {
|
|
@@ -157,10 +161,12 @@ export function SideNav({
|
|
|
157
161
|
}, [open, onClose]);
|
|
158
162
|
|
|
159
163
|
const resolvedHeader = typeof header === "function" ? header(isCollapsed) : header;
|
|
164
|
+
const resolvedFooter = typeof footer === "function" ? footer(isCollapsed) : footer;
|
|
160
165
|
|
|
161
166
|
const navClasses = [
|
|
162
167
|
"a1-side-nav",
|
|
163
168
|
`a1-side-nav--placement-${placement}`,
|
|
169
|
+
collapseButtonPlacement === "footer" && "a1-side-nav--collapse-footer",
|
|
164
170
|
open && "a1-side-nav--open",
|
|
165
171
|
isCollapsed && "a1-side-nav--collapsed",
|
|
166
172
|
className,
|
|
@@ -189,19 +195,33 @@ export function SideNav({
|
|
|
189
195
|
className="a1-side-nav__close-btn"
|
|
190
196
|
onClick={onClose}
|
|
191
197
|
/>
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
+
{collapseButtonPlacement === "header" && (
|
|
199
|
+
<IconButton
|
|
200
|
+
icon={collapseIcon}
|
|
201
|
+
label={isCollapsed ? "Expand navigation" : "Collapse navigation"}
|
|
202
|
+
className="a1-side-nav__collapse-btn"
|
|
203
|
+
onClick={toggleCollapse}
|
|
204
|
+
/>
|
|
205
|
+
)}
|
|
198
206
|
</div>
|
|
199
207
|
|
|
200
208
|
<SideNavCtx.Provider value={{ collapsed: isCollapsed, onExpand: handleExpand }}>
|
|
201
209
|
<div className="a1-side-nav__nav">{children}</div>
|
|
202
210
|
</SideNavCtx.Provider>
|
|
203
211
|
|
|
204
|
-
{
|
|
212
|
+
{(resolvedFooter || collapseButtonPlacement === "footer") && (
|
|
213
|
+
<div className="a1-side-nav__footer">
|
|
214
|
+
{resolvedFooter && <div className="a1-side-nav__footer-content">{resolvedFooter}</div>}
|
|
215
|
+
{collapseButtonPlacement === "footer" && (
|
|
216
|
+
<IconButton
|
|
217
|
+
icon={collapseIcon}
|
|
218
|
+
label={isCollapsed ? "Expand navigation" : "Collapse navigation"}
|
|
219
|
+
className="a1-side-nav__collapse-btn"
|
|
220
|
+
onClick={toggleCollapse}
|
|
221
|
+
/>
|
|
222
|
+
)}
|
|
223
|
+
</div>
|
|
224
|
+
)}
|
|
205
225
|
</nav>
|
|
206
226
|
</>
|
|
207
227
|
);
|
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
box-sizing: border-box;
|
|
5
5
|
display: flex;
|
|
6
6
|
flex-direction: column;
|
|
7
|
-
width: var(--component-side-nav-width
|
|
7
|
+
width: var(--component-side-nav-width);
|
|
8
8
|
height: 100%;
|
|
9
9
|
background: var(--semantic-color-surface-panel);
|
|
10
|
-
border-inline-end:
|
|
10
|
+
border-inline-end: var(--component-side-nav-border-width) solid var(--semantic-color-border-subtle);
|
|
11
11
|
overflow: hidden;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
.a1-side-nav--placement-end {
|
|
15
15
|
border-inline-end: none;
|
|
16
|
-
border-inline-start:
|
|
16
|
+
border-inline-start: var(--component-side-nav-border-width) solid var(--semantic-color-border-subtle);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/* ── Header row — logo/content inline with close or collapse button ─────── */
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
align-items: center;
|
|
26
26
|
gap: var(--base-spacing-4);
|
|
27
27
|
padding: var(--base-spacing-8) var(--base-spacing-8) var(--base-spacing-8) var(--base-spacing-12);
|
|
28
|
-
border-block-end:
|
|
29
|
-
min-height:
|
|
28
|
+
border-block-end: var(--component-side-nav-border-width) solid var(--semantic-color-border-subtle);
|
|
29
|
+
min-height: var(--component-side-nav-header-min-height);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
.a1-side-nav__header-content {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
flex-shrink: 0;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
@media (
|
|
43
|
+
@media (--bp-md-down) {
|
|
44
44
|
.a1-side-nav .a1-side-nav__close-btn {
|
|
45
45
|
display: inline-flex;
|
|
46
46
|
}
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
flex-shrink: 0;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
@media (
|
|
55
|
+
@media (--bp-lg-up) {
|
|
56
56
|
.a1-side-nav .a1-side-nav__collapse-btn {
|
|
57
57
|
display: inline-flex;
|
|
58
58
|
}
|
|
@@ -77,7 +77,18 @@
|
|
|
77
77
|
flex-shrink: 0;
|
|
78
78
|
padding: var(--component-side-nav-padding-block, var(--base-spacing-8))
|
|
79
79
|
var(--component-side-nav-padding-inline, var(--base-spacing-8));
|
|
80
|
-
border-block-start:
|
|
80
|
+
border-block-start: var(--component-side-nav-border-width) solid var(--semantic-color-border-subtle);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.a1-side-nav--collapse-footer .a1-side-nav__footer {
|
|
84
|
+
display: flex;
|
|
85
|
+
align-items: center;
|
|
86
|
+
gap: var(--base-spacing-4);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.a1-side-nav__footer-content {
|
|
90
|
+
flex: 1 1 auto;
|
|
91
|
+
min-width: 0;
|
|
81
92
|
}
|
|
82
93
|
|
|
83
94
|
/* ── Item — shared by SideNavItem and SideNavGroup trigger ─────────────── */
|
|
@@ -88,7 +99,7 @@
|
|
|
88
99
|
align-items: center;
|
|
89
100
|
gap: var(--component-side-nav-item-gap, var(--base-spacing-8));
|
|
90
101
|
width: 100%;
|
|
91
|
-
min-height: var(--component-side-nav-item-height
|
|
102
|
+
min-height: var(--component-side-nav-item-height);
|
|
92
103
|
padding-block: var(--base-spacing-4);
|
|
93
104
|
padding-inline-start: calc(
|
|
94
105
|
var(--component-side-nav-item-padding-inline, var(--base-spacing-8)) +
|
|
@@ -96,10 +107,10 @@
|
|
|
96
107
|
);
|
|
97
108
|
padding-inline-end: var(--component-side-nav-item-padding-inline, var(--base-spacing-8));
|
|
98
109
|
border: none;
|
|
99
|
-
border-radius: var(--component-side-nav-item-border-radius
|
|
110
|
+
border-radius: var(--component-side-nav-item-border-radius);
|
|
100
111
|
font-family: var(--semantic-font-family-body);
|
|
101
|
-
font-size: var(--semantic-font-size-body-sm
|
|
102
|
-
line-height:
|
|
112
|
+
font-size: var(--semantic-font-size-body-sm);
|
|
113
|
+
line-height: var(--component-side-nav-item-font-line-height);
|
|
103
114
|
color: var(--semantic-color-text-default);
|
|
104
115
|
text-decoration: none;
|
|
105
116
|
text-align: start;
|
|
@@ -107,7 +118,9 @@
|
|
|
107
118
|
overflow: hidden;
|
|
108
119
|
cursor: pointer;
|
|
109
120
|
background: transparent;
|
|
110
|
-
transition:
|
|
121
|
+
transition:
|
|
122
|
+
background var(--semantic-motion-duration-fast) var(--semantic-motion-easing-standard),
|
|
123
|
+
color var(--semantic-motion-duration-fast) var(--semantic-motion-easing-standard);
|
|
111
124
|
}
|
|
112
125
|
|
|
113
126
|
.a1-side-nav-item:hover {
|
|
@@ -119,8 +132,8 @@
|
|
|
119
132
|
}
|
|
120
133
|
|
|
121
134
|
.a1-side-nav-item:focus-visible {
|
|
122
|
-
outline: var(--component-side-nav-item-focus-ring-width
|
|
123
|
-
outline-offset: var(--component-side-nav-item-focus-ring-offset
|
|
135
|
+
outline: var(--component-side-nav-item-focus-ring-width) solid var(--semantic-color-text-accent);
|
|
136
|
+
outline-offset: var(--component-side-nav-item-focus-ring-offset);
|
|
124
137
|
}
|
|
125
138
|
|
|
126
139
|
/* ── Active state ──────────────────────────────────────────────────────── */
|
|
@@ -128,7 +141,7 @@
|
|
|
128
141
|
.a1-side-nav-item--active {
|
|
129
142
|
background: color-mix(in srgb, transparent, var(--semantic-color-text-accent) 10%);
|
|
130
143
|
color: var(--semantic-color-text-accent);
|
|
131
|
-
font-weight:
|
|
144
|
+
font-weight: var(--component-side-nav-item-active-font-weight);
|
|
132
145
|
}
|
|
133
146
|
|
|
134
147
|
.a1-side-nav-item--active:hover {
|
|
@@ -149,6 +162,11 @@
|
|
|
149
162
|
text-overflow: ellipsis;
|
|
150
163
|
}
|
|
151
164
|
|
|
165
|
+
.a1-side-nav-item__badge {
|
|
166
|
+
flex-shrink: 0;
|
|
167
|
+
line-height: 1;
|
|
168
|
+
}
|
|
169
|
+
|
|
152
170
|
/* ── Group ─────────────────────────────────────────────────────────────── */
|
|
153
171
|
|
|
154
172
|
.a1-side-nav-group {
|
|
@@ -158,10 +176,10 @@
|
|
|
158
176
|
}
|
|
159
177
|
|
|
160
178
|
.a1-side-nav-group__chevron {
|
|
161
|
-
font-size:
|
|
179
|
+
font-size: var(--component-side-nav-item-chevron-size);
|
|
162
180
|
flex-shrink: 0;
|
|
163
181
|
color: var(--semantic-color-text-muted);
|
|
164
|
-
transition: transform
|
|
182
|
+
transition: transform var(--semantic-motion-duration-normal) var(--semantic-motion-easing-standard);
|
|
165
183
|
}
|
|
166
184
|
|
|
167
185
|
.a1-side-nav-group__trigger--open .a1-side-nav-group__chevron {
|
|
@@ -173,7 +191,7 @@
|
|
|
173
191
|
.a1-side-nav-group__children {
|
|
174
192
|
display: grid;
|
|
175
193
|
grid-template-rows: 0fr;
|
|
176
|
-
transition: grid-template-rows
|
|
194
|
+
transition: grid-template-rows var(--semantic-motion-duration-normal) var(--semantic-motion-easing-standard);
|
|
177
195
|
}
|
|
178
196
|
|
|
179
197
|
.a1-side-nav-group__children--open {
|
|
@@ -191,27 +209,27 @@
|
|
|
191
209
|
/* ── Responsive overlay behavior ───────────────────────────────────────── */
|
|
192
210
|
|
|
193
211
|
/* Scrim — sm/md only (xs nav is full-width, lg+ nav is persistent) */
|
|
194
|
-
@media (
|
|
212
|
+
@media (--bp-xs) {
|
|
195
213
|
.a1-side-nav__scrim {
|
|
196
214
|
display: none;
|
|
197
215
|
}
|
|
198
216
|
}
|
|
199
217
|
|
|
200
|
-
@media (
|
|
218
|
+
@media (--bp-lg-up) {
|
|
201
219
|
.a1-side-nav__scrim {
|
|
202
220
|
display: none;
|
|
203
221
|
}
|
|
204
222
|
}
|
|
205
223
|
|
|
206
224
|
/* xs + sm + md (≤1024px): fixed overlay, slides in from the start edge */
|
|
207
|
-
@media (
|
|
225
|
+
@media (--bp-md-down) {
|
|
208
226
|
.a1-side-nav {
|
|
209
227
|
position: fixed;
|
|
210
228
|
inset-block: 0;
|
|
211
229
|
inset-inline-start: 0;
|
|
212
|
-
z-index:
|
|
230
|
+
z-index: var(--component-side-nav-overlay-z-index);
|
|
213
231
|
transform: translateX(-100%);
|
|
214
|
-
transition: transform
|
|
232
|
+
transition: transform var(--semantic-motion-duration-slow) var(--semantic-motion-easing-standard);
|
|
215
233
|
will-change: transform;
|
|
216
234
|
}
|
|
217
235
|
|
|
@@ -223,16 +241,16 @@
|
|
|
223
241
|
|
|
224
242
|
.a1-side-nav--open {
|
|
225
243
|
transform: translateX(0);
|
|
226
|
-
box-shadow:
|
|
244
|
+
box-shadow: var(--component-side-nav-overlay-shadow-start);
|
|
227
245
|
}
|
|
228
246
|
|
|
229
247
|
.a1-side-nav--placement-end.a1-side-nav--open {
|
|
230
|
-
box-shadow: -
|
|
248
|
+
box-shadow: var(--component-side-nav-overlay-shadow-end);
|
|
231
249
|
}
|
|
232
250
|
}
|
|
233
251
|
|
|
234
252
|
/* xs only (≤480px): full viewport width */
|
|
235
|
-
@media (
|
|
253
|
+
@media (--bp-xs) {
|
|
236
254
|
.a1-side-nav {
|
|
237
255
|
width: 100%;
|
|
238
256
|
max-width: 100vw;
|
|
@@ -246,13 +264,21 @@
|
|
|
246
264
|
|
|
247
265
|
/* ── Collapsed state (lg/xl only) ──────────────────────────────────────── */
|
|
248
266
|
|
|
249
|
-
@media (
|
|
267
|
+
@media (--bp-lg-up) {
|
|
268
|
+
/*
|
|
269
|
+
* Sticky sidebar: the nav sticks to the viewport top and never scrolls with
|
|
270
|
+
* the page. Internal nav content scrolls via .a1-side-nav__nav (overflow-y:
|
|
271
|
+
* auto). The header row and footer remain anchored at all times.
|
|
272
|
+
*/
|
|
250
273
|
.a1-side-nav {
|
|
251
|
-
|
|
274
|
+
position: sticky;
|
|
275
|
+
top: 0;
|
|
276
|
+
height: 100vh;
|
|
277
|
+
transition: width var(--semantic-motion-duration-slow) var(--semantic-motion-easing-standard);
|
|
252
278
|
}
|
|
253
279
|
|
|
254
280
|
.a1-side-nav--collapsed {
|
|
255
|
-
width: var(--component-side-nav-collapsed-width
|
|
281
|
+
width: var(--component-side-nav-collapsed-width);
|
|
256
282
|
}
|
|
257
283
|
|
|
258
284
|
/* Stack header content above the expand button when collapsed */
|
|
@@ -263,11 +289,23 @@
|
|
|
263
289
|
gap: var(--base-spacing-4);
|
|
264
290
|
}
|
|
265
291
|
|
|
266
|
-
/* Hide footer in collapsed state */
|
|
267
|
-
.a1-side-nav--collapsed .a1-side-nav__footer {
|
|
292
|
+
/* Hide footer in collapsed state unless it owns the collapse button */
|
|
293
|
+
.a1-side-nav--collapsed:not(.a1-side-nav--collapse-footer) .a1-side-nav__footer {
|
|
268
294
|
display: none;
|
|
269
295
|
}
|
|
270
296
|
|
|
297
|
+
.a1-side-nav--collapsed.a1-side-nav--collapse-footer .a1-side-nav__footer {
|
|
298
|
+
flex-direction: column;
|
|
299
|
+
align-items: center;
|
|
300
|
+
justify-content: center;
|
|
301
|
+
padding-inline: var(--base-spacing-4);
|
|
302
|
+
gap: var(--base-spacing-2);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.a1-side-nav--collapsed.a1-side-nav--collapse-footer .a1-side-nav__footer-content {
|
|
306
|
+
flex: none;
|
|
307
|
+
}
|
|
308
|
+
|
|
271
309
|
/* Center items and remove indentation in collapsed state */
|
|
272
310
|
.a1-side-nav--collapsed .a1-side-nav-item {
|
|
273
311
|
justify-content: center;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import "./snackbar.css";
|
|
2
|
+
import { Button } from "../button/Button.jsx";
|
|
3
|
+
import { IconButton } from "../icon-button/IconButton.jsx";
|
|
4
|
+
|
|
5
|
+
const variants = ["default", "success", "info", "warn", "error"];
|
|
6
|
+
const positions = ["bottom", "bottom-left", "bottom-right", "top", "top-left", "top-right"];
|
|
7
|
+
|
|
8
|
+
export function Snackbar({
|
|
9
|
+
open = false,
|
|
10
|
+
children,
|
|
11
|
+
actionLabel,
|
|
12
|
+
onAction,
|
|
13
|
+
onClose,
|
|
14
|
+
variant = "default",
|
|
15
|
+
position = "bottom",
|
|
16
|
+
inverse = true,
|
|
17
|
+
role,
|
|
18
|
+
className = "",
|
|
19
|
+
...props
|
|
20
|
+
}) {
|
|
21
|
+
if (!open) return null;
|
|
22
|
+
|
|
23
|
+
const resolvedVariant = variants.includes(variant) ? variant : "default";
|
|
24
|
+
const resolvedPosition = positions.includes(position) ? position : "bottom";
|
|
25
|
+
const classes = [
|
|
26
|
+
"a1-snackbar",
|
|
27
|
+
inverse && "a1-inverse",
|
|
28
|
+
`a1-snackbar--${resolvedVariant}`,
|
|
29
|
+
`a1-snackbar--${resolvedPosition}`,
|
|
30
|
+
className,
|
|
31
|
+
].filter(Boolean).join(" ");
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div
|
|
35
|
+
className={classes}
|
|
36
|
+
role={role ?? (resolvedVariant === "error" ? "alert" : "status")}
|
|
37
|
+
aria-live={resolvedVariant === "error" ? "assertive" : "polite"}
|
|
38
|
+
{...props}
|
|
39
|
+
>
|
|
40
|
+
<div className="a1-snackbar__content">{children}</div>
|
|
41
|
+
{(actionLabel && onAction) && (
|
|
42
|
+
<Button size="sm" variant="tertiary" onClick={onAction}>
|
|
43
|
+
{actionLabel}
|
|
44
|
+
</Button>
|
|
45
|
+
)}
|
|
46
|
+
{onClose && (
|
|
47
|
+
<IconButton
|
|
48
|
+
icon="close"
|
|
49
|
+
label="Dismiss"
|
|
50
|
+
variant="tertiary"
|
|
51
|
+
onClick={onClose}
|
|
52
|
+
/>
|
|
53
|
+
)}
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
@keyframes a1-snackbar-in {
|
|
2
|
+
from {
|
|
3
|
+
opacity: 0;
|
|
4
|
+
translate: 0 8px;
|
|
5
|
+
}
|
|
6
|
+
to {
|
|
7
|
+
opacity: 1;
|
|
8
|
+
translate: 0 0;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.a1-snackbar {
|
|
13
|
+
position: fixed;
|
|
14
|
+
z-index: var(--component-snackbar-z-index, 1100);
|
|
15
|
+
box-sizing: border-box;
|
|
16
|
+
width: min(420px, calc(100vw - var(--base-spacing-32)));
|
|
17
|
+
min-height: 56px;
|
|
18
|
+
padding: var(--base-spacing-12) var(--base-spacing-24);
|
|
19
|
+
border: 1px solid var(--a1-snackbar-border);
|
|
20
|
+
border-radius: var(--component-card-border-radius);
|
|
21
|
+
background: var(--a1-snackbar-background);
|
|
22
|
+
color: var(--a1-snackbar-foreground);
|
|
23
|
+
box-shadow: var(--semantic-shadow-lg, 0 16px 40px rgba(0, 0, 0, 0.18));
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
gap: var(--base-spacing-8);
|
|
27
|
+
animation: a1-snackbar-in var(--semantic-motion-duration-standard, 200ms) var(--semantic-motion-easing-standard, ease-out) both;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@media (prefers-reduced-motion: reduce) {
|
|
31
|
+
.a1-snackbar {
|
|
32
|
+
animation: none;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.a1-snackbar--bottom,
|
|
37
|
+
.a1-snackbar--top {
|
|
38
|
+
left: 50%;
|
|
39
|
+
transform: translateX(-50%);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.a1-snackbar--bottom,
|
|
43
|
+
.a1-snackbar--bottom-left,
|
|
44
|
+
.a1-snackbar--bottom-right {
|
|
45
|
+
bottom: var(--base-spacing-24);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.a1-snackbar--top,
|
|
49
|
+
.a1-snackbar--top-left,
|
|
50
|
+
.a1-snackbar--top-right {
|
|
51
|
+
top: var(--base-spacing-24);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.a1-snackbar--bottom-left,
|
|
55
|
+
.a1-snackbar--top-left {
|
|
56
|
+
left: var(--base-spacing-24);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.a1-snackbar--bottom-right,
|
|
60
|
+
.a1-snackbar--top-right {
|
|
61
|
+
right: var(--base-spacing-24);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.a1-snackbar__content {
|
|
65
|
+
min-width: 0;
|
|
66
|
+
flex: 1;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.a1-snackbar--default,
|
|
70
|
+
.a1-snackbar--info {
|
|
71
|
+
--a1-snackbar-background: var(--semantic-color-surface-inverse, var(--base-color-neutral-900));
|
|
72
|
+
--a1-snackbar-border: var(--semantic-color-surface-inverse, var(--base-color-neutral-900));
|
|
73
|
+
--a1-snackbar-foreground: var(--semantic-color-text-default, var(--base-color-neutral-0));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.a1-snackbar--success {
|
|
77
|
+
--a1-snackbar-background: var(--semantic-color-status-success-background);
|
|
78
|
+
--a1-snackbar-border: var(--semantic-color-status-success-border, var(--semantic-color-status-success-background));
|
|
79
|
+
--a1-snackbar-foreground: var(--semantic-color-status-success-foreground);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.a1-snackbar--warn {
|
|
83
|
+
--a1-snackbar-background: var(--semantic-color-status-warn-background);
|
|
84
|
+
--a1-snackbar-border: var(--semantic-color-status-warn-border, var(--semantic-color-status-warn-background));
|
|
85
|
+
--a1-snackbar-foreground: var(--semantic-color-status-warn-foreground);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.a1-snackbar--error {
|
|
89
|
+
--a1-snackbar-background: var(--semantic-color-status-error-background);
|
|
90
|
+
--a1-snackbar-border: var(--semantic-color-status-error-border, var(--semantic-color-status-error-background));
|
|
91
|
+
--a1-snackbar-foreground: var(--semantic-color-status-error-foreground);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@media (max-width: 720px) {
|
|
95
|
+
.a1-snackbar {
|
|
96
|
+
right: var(--base-spacing-16);
|
|
97
|
+
left: var(--base-spacing-16);
|
|
98
|
+
width: auto;
|
|
99
|
+
transform: none;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.a1-snackbar--bottom,
|
|
103
|
+
.a1-snackbar--bottom-left,
|
|
104
|
+
.a1-snackbar--bottom-right {
|
|
105
|
+
bottom: var(--base-spacing-16);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.a1-snackbar--top,
|
|
109
|
+
.a1-snackbar--top-left,
|
|
110
|
+
.a1-snackbar--top-right {
|
|
111
|
+
top: var(--base-spacing-16);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import "./spacer.css";
|
|
2
|
+
|
|
3
|
+
const sizes = ["xs", "sm", "md", "lg", "xl", "xxl"];
|
|
4
|
+
const breakpoints = ["xs", "sm", "md", "lg", "xl"];
|
|
5
|
+
|
|
6
|
+
const sizeMap = {
|
|
7
|
+
xs: "var(--base-spacing-8)",
|
|
8
|
+
sm: "var(--base-spacing-16)",
|
|
9
|
+
md: "var(--base-spacing-24)",
|
|
10
|
+
lg: "var(--base-spacing-40)",
|
|
11
|
+
xl: "var(--base-spacing-64)",
|
|
12
|
+
xxl: "var(--base-spacing-96)",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function isResponsive(value) {
|
|
16
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function resolveBase(size) {
|
|
20
|
+
if (!isResponsive(size)) return sizeMap[size] ?? sizeMap.md;
|
|
21
|
+
return sizeMap[size.xs] ?? sizeMap.md;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function Spacer({ size = "md", ...props }) {
|
|
25
|
+
const style = { "--a1-spacer-size": resolveBase(size) };
|
|
26
|
+
|
|
27
|
+
if (isResponsive(size)) {
|
|
28
|
+
let lastKnown = resolveBase(size);
|
|
29
|
+
breakpoints.slice(1).forEach((bp) => {
|
|
30
|
+
if (sizes.includes(size[bp])) lastKnown = sizeMap[size[bp]];
|
|
31
|
+
style[`--a1-spacer-size-${bp}`] = lastKnown;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return <div className="a1-spacer" role="none" aria-hidden="true" style={style} {...props} />;
|
|
36
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/* ══════════════════════════════════════════════════════════════════════════
|
|
2
|
+
Spacer
|
|
3
|
+
══════════════════════════════════════════════════════════════════════════ */
|
|
4
|
+
|
|
5
|
+
.a1-spacer {
|
|
6
|
+
display: block;
|
|
7
|
+
height: var(--a1-spacer-responsive-size, var(--a1-spacer-size, 0px));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@media (--bp-sm-up) {
|
|
11
|
+
.a1-spacer {
|
|
12
|
+
--a1-spacer-responsive-size: var(--a1-spacer-size-sm, var(--a1-spacer-size));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@media (--bp-md-up) {
|
|
17
|
+
.a1-spacer {
|
|
18
|
+
--a1-spacer-responsive-size: var(
|
|
19
|
+
--a1-spacer-size-md,
|
|
20
|
+
var(--a1-spacer-size-sm, var(--a1-spacer-size))
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@media (--bp-lg-up) {
|
|
26
|
+
.a1-spacer {
|
|
27
|
+
--a1-spacer-responsive-size: var(
|
|
28
|
+
--a1-spacer-size-lg,
|
|
29
|
+
var(--a1-spacer-size-md, var(--a1-spacer-size-sm, var(--a1-spacer-size)))
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@media (--bp-xl) {
|
|
35
|
+
.a1-spacer {
|
|
36
|
+
--a1-spacer-responsive-size: var(
|
|
37
|
+
--a1-spacer-size-xl,
|
|
38
|
+
var(
|
|
39
|
+
--a1-spacer-size-lg,
|
|
40
|
+
var(--a1-spacer-size-md, var(--a1-spacer-size-sm, var(--a1-spacer-size)))
|
|
41
|
+
)
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|