@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,283 @@
1
+ /* ── Container ─────────────────────────────────────────────────────────── */
2
+
3
+ .a1-side-nav {
4
+ box-sizing: border-box;
5
+ display: flex;
6
+ flex-direction: column;
7
+ width: var(--component-side-nav-width, 280px);
8
+ height: 100%;
9
+ background: var(--semantic-color-surface-panel);
10
+ border-inline-end: 1px solid var(--semantic-color-border-subtle);
11
+ overflow: hidden;
12
+ }
13
+
14
+ .a1-side-nav--placement-end {
15
+ border-inline-end: none;
16
+ border-inline-start: 1px solid var(--semantic-color-border-subtle);
17
+ }
18
+
19
+ /* ── Header row — logo/content inline with close or collapse button ─────── */
20
+
21
+ .a1-side-nav__header-row {
22
+ flex-shrink: 0;
23
+ display: flex;
24
+ flex-direction: row;
25
+ align-items: center;
26
+ gap: var(--base-spacing-4);
27
+ padding: var(--base-spacing-8) var(--base-spacing-8) var(--base-spacing-8) var(--base-spacing-12);
28
+ border-block-end: 1px solid var(--semantic-color-border-subtle);
29
+ min-height: 52px;
30
+ }
31
+
32
+ .a1-side-nav__header-content {
33
+ flex: 1 1 auto;
34
+ min-width: 0;
35
+ }
36
+
37
+ /* Close button: xs/sm/md only */
38
+ .a1-side-nav .a1-side-nav__close-btn {
39
+ display: none;
40
+ flex-shrink: 0;
41
+ }
42
+
43
+ @media (max-width: 1024px) {
44
+ .a1-side-nav .a1-side-nav__close-btn {
45
+ display: inline-flex;
46
+ }
47
+ }
48
+
49
+ /* Collapse button: lg/xl only */
50
+ .a1-side-nav .a1-side-nav__collapse-btn {
51
+ display: none;
52
+ flex-shrink: 0;
53
+ }
54
+
55
+ @media (min-width: 1025px) {
56
+ .a1-side-nav .a1-side-nav__collapse-btn {
57
+ display: inline-flex;
58
+ }
59
+ }
60
+
61
+ /* ── Nav scroll area ───────────────────────────────────────────────────── */
62
+
63
+ .a1-side-nav__nav {
64
+ flex: 1 1 auto;
65
+ min-height: 0;
66
+ overflow-y: auto;
67
+ padding: var(--component-side-nav-padding-block, var(--base-spacing-8))
68
+ var(--component-side-nav-padding-inline, var(--base-spacing-8));
69
+ display: flex;
70
+ flex-direction: column;
71
+ gap: var(--base-spacing-2);
72
+ }
73
+
74
+ /* ── Footer ─────────────────────────────────────────────────────────────── */
75
+
76
+ .a1-side-nav__footer {
77
+ flex-shrink: 0;
78
+ padding: var(--component-side-nav-padding-block, var(--base-spacing-8))
79
+ var(--component-side-nav-padding-inline, var(--base-spacing-8));
80
+ border-block-start: 1px solid var(--semantic-color-border-subtle);
81
+ }
82
+
83
+ /* ── Item — shared by SideNavItem and SideNavGroup trigger ─────────────── */
84
+
85
+ .a1-side-nav-item {
86
+ box-sizing: border-box;
87
+ display: flex;
88
+ align-items: center;
89
+ gap: var(--component-side-nav-item-gap, var(--base-spacing-8));
90
+ width: 100%;
91
+ min-height: var(--component-side-nav-item-height, 36px);
92
+ padding-block: var(--base-spacing-4);
93
+ padding-inline-start: calc(
94
+ var(--component-side-nav-item-padding-inline, var(--base-spacing-8)) +
95
+ var(--component-side-nav-item-indent, var(--base-spacing-20)) * var(--a1-side-nav-depth, 0)
96
+ );
97
+ padding-inline-end: var(--component-side-nav-item-padding-inline, var(--base-spacing-8));
98
+ border: none;
99
+ border-radius: var(--component-side-nav-item-border-radius, 6px);
100
+ font-family: var(--semantic-font-family-body);
101
+ font-size: var(--semantic-font-size-body-sm, 14px);
102
+ line-height: 1.5;
103
+ color: var(--semantic-color-text-default);
104
+ text-decoration: none;
105
+ text-align: start;
106
+ white-space: nowrap;
107
+ overflow: hidden;
108
+ cursor: pointer;
109
+ background: transparent;
110
+ transition: background 150ms ease, color 150ms ease;
111
+ }
112
+
113
+ .a1-side-nav-item:hover {
114
+ background: color-mix(in srgb, var(--semantic-color-surface-panel), var(--semantic-color-text-default) 6%);
115
+ }
116
+
117
+ .a1-side-nav-item:active {
118
+ background: color-mix(in srgb, var(--semantic-color-surface-panel), var(--semantic-color-text-default) 12%);
119
+ }
120
+
121
+ .a1-side-nav-item:focus-visible {
122
+ outline: var(--component-side-nav-item-focus-ring-width, 3px) solid var(--semantic-color-text-accent);
123
+ outline-offset: var(--component-side-nav-item-focus-ring-offset, -2px);
124
+ }
125
+
126
+ /* ── Active state ──────────────────────────────────────────────────────── */
127
+
128
+ .a1-side-nav-item--active {
129
+ background: color-mix(in srgb, transparent, var(--semantic-color-text-accent) 10%);
130
+ color: var(--semantic-color-text-accent);
131
+ font-weight: 500;
132
+ }
133
+
134
+ .a1-side-nav-item--active:hover {
135
+ background: color-mix(in srgb, transparent, var(--semantic-color-text-accent) 16%);
136
+ }
137
+
138
+ /* ── Icon & label ──────────────────────────────────────────────────────── */
139
+
140
+ .a1-side-nav-item__icon {
141
+ font-size: var(--component-side-nav-item-icon-size, var(--base-spacing-20));
142
+ flex-shrink: 0;
143
+ }
144
+
145
+ .a1-side-nav-item__label {
146
+ flex: 1 1 auto;
147
+ min-width: 0;
148
+ overflow: hidden;
149
+ text-overflow: ellipsis;
150
+ }
151
+
152
+ /* ── Group ─────────────────────────────────────────────────────────────── */
153
+
154
+ .a1-side-nav-group {
155
+ display: flex;
156
+ flex-direction: column;
157
+ gap: var(--base-spacing-2);
158
+ }
159
+
160
+ .a1-side-nav-group__chevron {
161
+ font-size: 18px;
162
+ flex-shrink: 0;
163
+ color: var(--semantic-color-text-muted);
164
+ transition: transform 200ms ease;
165
+ }
166
+
167
+ .a1-side-nav-group__trigger--open .a1-side-nav-group__chevron {
168
+ transform: rotate(90deg);
169
+ }
170
+
171
+ /* ── Expand / collapse animation (CSS grid trick) ──────────────────────── */
172
+
173
+ .a1-side-nav-group__children {
174
+ display: grid;
175
+ grid-template-rows: 0fr;
176
+ transition: grid-template-rows 200ms ease;
177
+ }
178
+
179
+ .a1-side-nav-group__children--open {
180
+ grid-template-rows: 1fr;
181
+ }
182
+
183
+ .a1-side-nav-group__children-inner {
184
+ overflow: hidden;
185
+ min-height: 0;
186
+ display: flex;
187
+ flex-direction: column;
188
+ gap: var(--base-spacing-2);
189
+ }
190
+
191
+ /* ── Responsive overlay behavior ───────────────────────────────────────── */
192
+
193
+ /* Scrim — sm/md only (xs nav is full-width, lg+ nav is persistent) */
194
+ @media (max-width: 480px) {
195
+ .a1-side-nav__scrim {
196
+ display: none;
197
+ }
198
+ }
199
+
200
+ @media (min-width: 1025px) {
201
+ .a1-side-nav__scrim {
202
+ display: none;
203
+ }
204
+ }
205
+
206
+ /* xs + sm + md (≤1024px): fixed overlay, slides in from the start edge */
207
+ @media (max-width: 1024px) {
208
+ .a1-side-nav {
209
+ position: fixed;
210
+ inset-block: 0;
211
+ inset-inline-start: 0;
212
+ z-index: 200;
213
+ transform: translateX(-100%);
214
+ transition: transform 250ms ease;
215
+ will-change: transform;
216
+ }
217
+
218
+ .a1-side-nav--placement-end {
219
+ inset-inline-start: auto;
220
+ inset-inline-end: 0;
221
+ transform: translateX(100%);
222
+ }
223
+
224
+ .a1-side-nav--open {
225
+ transform: translateX(0);
226
+ box-shadow: 8px 0 40px rgba(0, 0, 0, 0.18);
227
+ }
228
+
229
+ .a1-side-nav--placement-end.a1-side-nav--open {
230
+ box-shadow: -8px 0 40px rgba(0, 0, 0, 0.18);
231
+ }
232
+ }
233
+
234
+ /* xs only (≤480px): full viewport width */
235
+ @media (max-width: 480px) {
236
+ .a1-side-nav {
237
+ width: 100%;
238
+ max-width: 100vw;
239
+ border-inline-end: none;
240
+ }
241
+
242
+ .a1-side-nav--placement-end {
243
+ border-inline-start: none;
244
+ }
245
+ }
246
+
247
+ /* ── Collapsed state (lg/xl only) ──────────────────────────────────────── */
248
+
249
+ @media (min-width: 1025px) {
250
+ .a1-side-nav {
251
+ transition: width 250ms ease;
252
+ }
253
+
254
+ .a1-side-nav--collapsed {
255
+ width: var(--component-side-nav-collapsed-width, 52px);
256
+ }
257
+
258
+ /* Stack header content above the expand button when collapsed */
259
+ .a1-side-nav--collapsed .a1-side-nav__header-row {
260
+ flex-direction: column;
261
+ align-items: center;
262
+ padding: var(--base-spacing-8) var(--base-spacing-4);
263
+ gap: var(--base-spacing-4);
264
+ }
265
+
266
+ /* Hide footer in collapsed state */
267
+ .a1-side-nav--collapsed .a1-side-nav__footer {
268
+ display: none;
269
+ }
270
+
271
+ /* Center items and remove indentation in collapsed state */
272
+ .a1-side-nav--collapsed .a1-side-nav-item {
273
+ justify-content: center;
274
+ padding-inline: var(--base-spacing-8);
275
+ }
276
+
277
+ /* Hide labels, chevrons, and group children in collapsed state */
278
+ .a1-side-nav--collapsed .a1-side-nav-item__label,
279
+ .a1-side-nav--collapsed .a1-side-nav-group__chevron,
280
+ .a1-side-nav--collapsed .a1-side-nav-group__children {
281
+ display: none;
282
+ }
283
+ }
@@ -0,0 +1,102 @@
1
+ import { createContext, useContext, useId } from "react";
2
+ import "./tabs.css";
3
+
4
+ const TabsContext = createContext(null);
5
+
6
+ /* ─── Tabs ─────────────────────────────────────────────────────────────────── */
7
+
8
+ export function Tabs({
9
+ children,
10
+ value,
11
+ onChange,
12
+ variant = "line",
13
+ level = 1,
14
+ }) {
15
+ const uid = useId();
16
+ return (
17
+ <TabsContext.Provider value={{ value, onChange, variant, level, uid }}>
18
+ <div className={`a1-tabs a1-tabs--level-${level}`}>
19
+ {children}
20
+ </div>
21
+ </TabsContext.Provider>
22
+ );
23
+ }
24
+
25
+ /* ─── TabList ───────────────────────────────────────────────────────────────── */
26
+
27
+ export function TabList({ children }) {
28
+ const { variant } = useContext(TabsContext);
29
+
30
+ const handleKeyDown = (e) => {
31
+ const tabs = Array.from(e.currentTarget.querySelectorAll('[role="tab"]:not([disabled])'));
32
+ const idx = tabs.indexOf(document.activeElement);
33
+ if (idx === -1) return;
34
+
35
+ let next = -1;
36
+ if (e.key === "ArrowRight" || e.key === "ArrowDown") {
37
+ next = (idx + 1) % tabs.length;
38
+ } else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
39
+ next = (idx - 1 + tabs.length) % tabs.length;
40
+ } else if (e.key === "Home") {
41
+ next = 0;
42
+ } else if (e.key === "End") {
43
+ next = tabs.length - 1;
44
+ }
45
+
46
+ if (next !== -1) {
47
+ e.preventDefault();
48
+ tabs[next].focus();
49
+ tabs[next].click();
50
+ }
51
+ };
52
+
53
+ return (
54
+ <div
55
+ role="tablist"
56
+ className={`a1-tab-list a1-tab-list--${variant}`}
57
+ onKeyDown={handleKeyDown}
58
+ >
59
+ {children}
60
+ </div>
61
+ );
62
+ }
63
+
64
+ /* ─── Tab ───────────────────────────────────────────────────────────────────── */
65
+
66
+ export function Tab({ children, value: tabValue }) {
67
+ const { value, onChange, variant, uid } = useContext(TabsContext);
68
+ const isSelected = value === tabValue;
69
+
70
+ return (
71
+ <button
72
+ role="tab"
73
+ type="button"
74
+ id={`${uid}-tab-${tabValue}`}
75
+ aria-selected={isSelected}
76
+ aria-controls={`${uid}-panel-${tabValue}`}
77
+ tabIndex={isSelected ? 0 : -1}
78
+ className={`a1-tab a1-tab--${variant}`}
79
+ onClick={() => onChange?.(tabValue)}
80
+ >
81
+ {children}
82
+ </button>
83
+ );
84
+ }
85
+
86
+ /* ─── TabPanel ──────────────────────────────────────────────────────────────── */
87
+
88
+ export function TabPanel({ children, value: panelValue }) {
89
+ const { value, variant, uid } = useContext(TabsContext);
90
+ if (value !== panelValue) return null;
91
+
92
+ return (
93
+ <div
94
+ role="tabpanel"
95
+ id={`${uid}-panel-${panelValue}`}
96
+ aria-labelledby={`${uid}-tab-${panelValue}`}
97
+ className={`a1-tab-panel a1-tab-panel--${variant}`}
98
+ >
99
+ {children}
100
+ </div>
101
+ );
102
+ }
@@ -0,0 +1,135 @@
1
+ /* ─── Tabs ────────────────────────────────────────────────────────────────── */
2
+
3
+ .a1-tabs {
4
+ display: flex;
5
+ flex-direction: column;
6
+ }
7
+
8
+ /* ─── Tab list ────────────────────────────────────────────────────────────── */
9
+
10
+ .a1-tab-list {
11
+ display: flex;
12
+ flex-shrink: 0;
13
+ }
14
+
15
+ /* ── Line variant ───────────────────────────────────────────────────────── */
16
+
17
+ .a1-tab-list--line {
18
+ border-bottom: var(--component-tab-border-width) solid var(--semantic-color-border-subtle);
19
+ gap: 0;
20
+ }
21
+
22
+ /* ── Folder variant ─────────────────────────────────────────────────────── */
23
+
24
+ .a1-tab-list--folder {
25
+ align-items: flex-end;
26
+ gap: var(--base-spacing-4);
27
+ padding: var(--base-spacing-8) var(--base-spacing-8) 0;
28
+ border-bottom: var(--component-tab-border-width) solid var(--semantic-color-border-strong);
29
+ }
30
+
31
+ /* ─── Tab button ──────────────────────────────────────────────────────────── */
32
+
33
+ .a1-tab {
34
+ display: inline-flex;
35
+ align-items: center;
36
+ gap: var(--base-spacing-8);
37
+ border: none;
38
+ background: transparent;
39
+ cursor: pointer;
40
+ white-space: nowrap;
41
+ font-family: var(--component-paragraph-font-family);
42
+ transition: color var(--semantic-motion-duration-fast), background var(--semantic-motion-duration-fast);
43
+ }
44
+
45
+ .a1-tab:focus-visible {
46
+ outline: var(--component-tab-focus-ring-width) solid var(--semantic-color-action-background);
47
+ outline-offset: var(--component-tab-focus-ring-offset);
48
+ border-radius: var(--base-radius-control);
49
+ }
50
+
51
+ /* ── Line tab ───────────────────────────────────────────────────────────── */
52
+
53
+ .a1-tab--line {
54
+ padding: var(--component-tab-padding-block) var(--component-tab-padding-inline);
55
+ font-size: var(--semantic-font-size-body-sm);
56
+ font-weight: var(--component-tab-font-weight-default);
57
+ color: var(--semantic-color-text-muted);
58
+ border-bottom: var(--component-tab-indicator-size) solid transparent;
59
+ margin-bottom: var(--component-tab-margin-bottom);
60
+ }
61
+
62
+ .a1-tab--line:hover:not([aria-selected="true"]) {
63
+ color: var(--semantic-color-text-default);
64
+ background: var(--semantic-color-surface-panel);
65
+ }
66
+
67
+ .a1-tab--line[aria-selected="true"] {
68
+ color: var(--semantic-color-action-background);
69
+ font-weight: var(--component-tab-font-weight-active);
70
+ border-bottom-color: var(--semantic-color-action-background);
71
+ }
72
+
73
+ /* ── Folder tab ─────────────────────────────────────────────────────────── */
74
+
75
+ .a1-tab--folder {
76
+ padding: var(--component-tab-padding-block) var(--component-tab-padding-inline);
77
+ font-size: var(--semantic-font-size-body-sm);
78
+ font-weight: var(--component-tab-font-weight-default);
79
+ color: var(--semantic-color-text-muted);
80
+ background: var(--semantic-color-surface-panel);
81
+ border: var(--component-tab-border-width) solid var(--semantic-color-border-default);
82
+ border-bottom: none;
83
+ border-radius: var(--base-radius-lg) var(--base-radius-lg) 0 0;
84
+ margin-bottom: var(--component-tab-margin-bottom);
85
+ position: relative;
86
+ }
87
+
88
+ .a1-tab--folder:hover:not([aria-selected="true"]) {
89
+ background: var(--semantic-color-surface-raised);
90
+ color: var(--semantic-color-text-default);
91
+ }
92
+
93
+ .a1-tab--folder[aria-selected="true"] {
94
+ background: var(--semantic-color-surface-page);
95
+ color: var(--semantic-color-text-default);
96
+ font-weight: var(--component-tab-font-weight-active);
97
+ border-color: var(--semantic-color-border-strong);
98
+ z-index: var(--component-tab-z-index-active);
99
+ }
100
+
101
+ /* ─── Level 2 ─────────────────────────────────────────────────────────────── */
102
+
103
+ .a1-tabs--level-2 .a1-tab--line {
104
+ padding: var(--component-tab-padding-block-sm) var(--component-tab-padding-inline-sm);
105
+ font-size: var(--semantic-font-size-body-xs);
106
+ }
107
+
108
+ .a1-tabs--level-2 .a1-tab--folder {
109
+ padding: var(--component-tab-padding-block-sm) var(--component-tab-padding-inline-sm);
110
+ font-size: var(--semantic-font-size-body-xs);
111
+ border-radius: var(--base-radius-control) var(--base-radius-control) 0 0;
112
+ }
113
+
114
+ .a1-tabs--level-2 .a1-tab-list--folder {
115
+ padding: var(--base-spacing-4) var(--base-spacing-4) 0;
116
+ }
117
+
118
+ /* ─── Tab panel ───────────────────────────────────────────────────────────── */
119
+
120
+ .a1-tab-panel--line {
121
+ padding: var(--base-spacing-16) 0;
122
+ }
123
+
124
+ .a1-tab-panel--folder {
125
+ background: var(--semantic-color-surface-page);
126
+ border: var(--component-tab-border-width) solid var(--semantic-color-border-strong);
127
+ border-top: none;
128
+ border-radius: 0 0 var(--base-radius-lg) var(--base-radius-lg);
129
+ padding: var(--base-spacing-16);
130
+ }
131
+
132
+ .a1-tabs--level-2 .a1-tab-panel--folder {
133
+ border-radius: 0 0 var(--base-radius-control) var(--base-radius-control);
134
+ padding: var(--base-spacing-12);
135
+ }
package/src/index.js ADDED
@@ -0,0 +1,20 @@
1
+ export { Notification } from "./components/notification/Notification.jsx";
2
+ export { IconButton } from "./components/icon-button/IconButton.jsx";
3
+ export { Button } from "./components/button/Button.jsx";
4
+ export { ButtonContainer } from "./components/button-container/ButtonContainer.jsx";
5
+ export { Card } from "./components/card/Card.jsx";
6
+ export { Dialog } from "./components/dialog/Dialog.jsx";
7
+ export { Heading } from "./components/heading/Heading.jsx";
8
+ export { Icon } from "./components/icon/Icon.jsx";
9
+ export { Link } from "./components/link/Link.jsx";
10
+ export { Paragraph } from "./components/paragraph/Paragraph.jsx";
11
+ export { MessageBanner, MessageBadge, MessageEmptyState } from "./components/message/Message.jsx";
12
+ export { Pagination } from "./components/pagination/Pagination.jsx";
13
+ export { SegmentedControl } from "./components/segmented-control/SegmentedControl.jsx";
14
+ export { Tabs, TabList, Tab, TabPanel } from "./components/tabs/Tabs.jsx";
15
+ export { Grid, GridItem } from "./components/grid/Grid.jsx";
16
+ export { Inverse } from "./components/inverse/Inverse.jsx";
17
+ export { PageLayout } from "./components/page-layout/PageLayout.jsx";
18
+ export { LabelsProvider, useLabel } from "./components/labels/Labels.jsx";
19
+ export { Menu, MenuSection } from "./components/menu/Menu.jsx";
20
+ export { SideNav, SideNavItem, SideNavGroup } from "./components/side-nav/SideNav.jsx";