tharaday 0.7.2 → 0.7.4

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 (55) hide show
  1. package/.storybook/main.ts +1 -1
  2. package/.storybook/preview.ts +0 -2
  3. package/.storybook/vitest.setup.ts +2 -0
  4. package/dist/ds.css +1 -1
  5. package/dist/ds.js +883 -815
  6. package/dist/ds.umd.cjs +1 -1
  7. package/dist/src/components/Tree/Tree.d.ts +1 -1
  8. package/dist/src/components/Tree/Tree.stories.d.ts +1 -1
  9. package/dist/src/components/Tree/TreeItem.d.ts +1 -1
  10. package/dist/src/components/Tree/TreeItem.types.d.ts +6 -0
  11. package/package.json +8 -1
  12. package/src/components/Accordion/Accordion.test.tsx +82 -0
  13. package/src/components/Avatar/Avatar.test.tsx +36 -0
  14. package/src/components/Badge/Badge.test.tsx +15 -0
  15. package/src/components/Breadcrumbs/Breadcrumbs.test.tsx +96 -0
  16. package/src/components/Checkbox/Checkbox.module.css +8 -7
  17. package/src/components/Checkbox/Checkbox.test.tsx +68 -0
  18. package/src/components/Dropdown/Dropdown.test.tsx +104 -0
  19. package/src/components/Input/Input.test.tsx +61 -0
  20. package/src/components/List/List.module.css +12 -12
  21. package/src/components/List/List.test.tsx +46 -0
  22. package/src/components/Modal/Modal.module.css +5 -5
  23. package/src/components/Modal/Modal.test.tsx +86 -0
  24. package/src/components/NavBar/NavBar.module.css +3 -3
  25. package/src/components/Notification/Notification.module.css +6 -6
  26. package/src/components/Notification/Notification.test.tsx +38 -0
  27. package/src/components/Pagination/Pagination.test.tsx +70 -0
  28. package/src/components/ProgressBar/ProgressBar.test.tsx +58 -0
  29. package/src/components/RadioButton/RadioButton.test.tsx +51 -0
  30. package/src/components/Select/Select.test.tsx +64 -0
  31. package/src/components/Slider/Slider.test.tsx +49 -0
  32. package/src/components/Stepper/Step.module.css +2 -2
  33. package/src/components/Stepper/Stepper.test.tsx +51 -0
  34. package/src/components/Switch/Switch.test.tsx +53 -0
  35. package/src/components/Table/Table.test.tsx +78 -0
  36. package/src/components/Tabs/Tabs.test.tsx +83 -0
  37. package/src/components/Textarea/Textarea.test.tsx +56 -0
  38. package/src/components/Tooltip/Tooltip.module.css +6 -6
  39. package/src/components/Tree/Tree.test.tsx +116 -0
  40. package/src/components/Tree/Tree.tsx +65 -1
  41. package/src/components/Tree/TreeItem.module.css +20 -26
  42. package/src/components/Tree/TreeItem.tsx +144 -79
  43. package/src/components/Tree/TreeItem.types.ts +6 -0
  44. package/src/styles/ds.css +14 -9
  45. package/src/styles/palette.css +71 -0
  46. package/src/styles/themes/dark.css +35 -35
  47. package/src/styles/themes/light.css +35 -35
  48. package/src/styles/themes/retro-dark.css +35 -35
  49. package/src/styles/themes/retro-light.css +35 -35
  50. package/src/styles/themes/retro-palette.css +85 -0
  51. package/src/styles/themes/sanzo-152-dark.css +35 -35
  52. package/src/styles/themes/sanzo-152-light.css +35 -35
  53. package/src/styles/themes/sanzo-152-palette.css +66 -0
  54. package/src/styles/tokens.css +14 -224
  55. package/src/styles/semantic.css +0 -56
@@ -0,0 +1,116 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+
4
+ import { Tree } from './Tree.tsx';
5
+
6
+ const objectData = { name: 'Alice', age: 30, address: { city: 'Warsaw', zip: '00-001' } };
7
+
8
+ describe('Tree', () => {
9
+ it('renders a tree widget', () => {
10
+ render(<Tree data={objectData} />);
11
+ expect(screen.getByRole('tree')).toBeInTheDocument();
12
+ });
13
+
14
+ it('renders top-level keys as treeitems', () => {
15
+ render(<Tree data={objectData} />);
16
+ const items = screen.getAllByRole('treeitem');
17
+ const labels = items.map((el) => el.textContent);
18
+ expect(labels.some((t) => t?.includes('name'))).toBe(true);
19
+ expect(labels.some((t) => t?.includes('age'))).toBe(true);
20
+ });
21
+
22
+ it('renders leaf values inline', () => {
23
+ render(<Tree data={{ score: 42 }} />);
24
+ expect(screen.getByText('42')).toBeInTheDocument();
25
+ });
26
+
27
+ it('collapses nested objects by default', () => {
28
+ render(<Tree data={objectData} />);
29
+ expect(screen.queryByText('Warsaw')).not.toBeInTheDocument();
30
+ });
31
+
32
+ it('expands a branch on click', async () => {
33
+ render(<Tree data={objectData} />);
34
+ const addressItem = screen
35
+ .getAllByRole('treeitem')
36
+ .find((el) => el.textContent?.includes('address'))!;
37
+ await userEvent.click(addressItem);
38
+ expect(screen.getByText('Warsaw')).toBeInTheDocument();
39
+ });
40
+
41
+ it('collapses an expanded branch on click', async () => {
42
+ render(<Tree data={objectData} defaultExpanded />);
43
+ const addressItem = screen
44
+ .getAllByRole('treeitem')
45
+ .find((el) => el.textContent?.includes('address'))!;
46
+ await userEvent.click(addressItem);
47
+ expect(screen.queryByText('Warsaw')).not.toBeInTheDocument();
48
+ });
49
+
50
+ it('sets aria-expanded on branch items', () => {
51
+ render(<Tree data={objectData} />);
52
+ const addressItem = screen
53
+ .getAllByRole('treeitem')
54
+ .find((el) => el.textContent?.includes('address'))!;
55
+ expect(addressItem).toHaveAttribute('aria-expanded', 'false');
56
+ });
57
+
58
+ it('sets correct aria-level on top-level items', () => {
59
+ render(<Tree data={objectData} />);
60
+ const items = screen.getAllByRole('treeitem');
61
+ items.forEach((item) => expect(item).toHaveAttribute('aria-level', '1'));
62
+ });
63
+
64
+ it('expands all branches when defaultExpanded is true', () => {
65
+ render(<Tree data={objectData} defaultExpanded />);
66
+ expect(screen.getByText('Warsaw')).toBeInTheDocument();
67
+ });
68
+
69
+ it('navigates down with ArrowDown', async () => {
70
+ render(<Tree data={objectData} />);
71
+ const items = screen.getAllByRole('treeitem');
72
+ items[0].focus();
73
+ await userEvent.keyboard('{ArrowDown}');
74
+ expect(document.activeElement).toBe(items[1]);
75
+ });
76
+
77
+ it('navigates up with ArrowUp', async () => {
78
+ render(<Tree data={objectData} />);
79
+ const items = screen.getAllByRole('treeitem');
80
+ items[1].tabIndex = 0;
81
+ items[1].focus();
82
+ await userEvent.keyboard('{ArrowUp}');
83
+ expect(document.activeElement).toBe(items[0]);
84
+ });
85
+
86
+ it('expands a branch with ArrowRight', async () => {
87
+ render(<Tree data={objectData} />);
88
+ const addressItem = screen
89
+ .getAllByRole('treeitem')
90
+ .find((el) => el.textContent?.includes('address'))!;
91
+ addressItem.focus();
92
+ await userEvent.keyboard('{ArrowRight}');
93
+ expect(addressItem).toHaveAttribute('aria-expanded', 'true');
94
+ });
95
+
96
+ it('collapses a branch with ArrowLeft', async () => {
97
+ render(<Tree data={objectData} defaultExpanded />);
98
+ const addressItem = screen
99
+ .getAllByRole('treeitem')
100
+ .find((el) => el.textContent?.startsWith('address'))!;
101
+ addressItem.focus();
102
+ await userEvent.keyboard('{ArrowLeft}');
103
+ expect(addressItem).toHaveAttribute('aria-expanded', 'false');
104
+ });
105
+
106
+ it('renders array data with indexed items', () => {
107
+ render(<Tree data={['x', 'y', 'z']} />);
108
+ expect(screen.getByText('x')).toBeInTheDocument();
109
+ expect(screen.getByText('y')).toBeInTheDocument();
110
+ });
111
+
112
+ it('renders null value', () => {
113
+ render(<Tree data={{ val: null }} />);
114
+ expect(screen.getByText('null')).toBeInTheDocument();
115
+ });
116
+ });
@@ -1,4 +1,6 @@
1
1
  import clsx from 'clsx';
2
+ import { useEffect, useRef } from 'react';
3
+ import type { KeyboardEvent } from 'react';
2
4
  import type { TreeProps } from './Tree.types';
3
5
  import styles from './Tree.module.css';
4
6
  import { TreeItem } from './TreeItem';
@@ -11,14 +13,76 @@ export const Tree = ({
11
13
  collapseIcon,
12
14
  ...props
13
15
  }: TreeProps) => {
16
+ const treeRef = useRef<HTMLDivElement>(null);
17
+
18
+ useEffect(() => {
19
+ const first = treeRef.current?.querySelector<HTMLElement>('[role="treeitem"]');
20
+ if (first) {
21
+ first.tabIndex = 0;
22
+ }
23
+ }, []);
24
+
25
+ const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {
26
+ const tree = treeRef.current;
27
+ if (!tree) {
28
+ return;
29
+ }
30
+ const items = Array.from(tree.querySelectorAll<HTMLElement>('[role="treeitem"]'));
31
+ if (items.length === 0) {
32
+ return;
33
+ }
34
+ const current = items.find((el) => el.tabIndex === 0) ?? items[0];
35
+ const idx = items.indexOf(current);
36
+
37
+ switch (e.key) {
38
+ case 'ArrowDown':
39
+ e.preventDefault();
40
+ if (idx < items.length - 1) {
41
+ current.tabIndex = -1;
42
+ items[idx + 1].tabIndex = 0;
43
+ items[idx + 1].focus();
44
+ }
45
+ break;
46
+ case 'ArrowUp':
47
+ e.preventDefault();
48
+ if (idx > 0) {
49
+ current.tabIndex = -1;
50
+ items[idx - 1].tabIndex = 0;
51
+ items[idx - 1].focus();
52
+ }
53
+ break;
54
+ case 'Home':
55
+ e.preventDefault();
56
+ current.tabIndex = -1;
57
+ items[0].tabIndex = 0;
58
+ items[0].focus();
59
+ break;
60
+ case 'End':
61
+ e.preventDefault();
62
+ current.tabIndex = -1;
63
+ items[items.length - 1].tabIndex = 0;
64
+ items[items.length - 1].focus();
65
+ break;
66
+ }
67
+ };
68
+
14
69
  return (
15
- <div className={clsx(styles.root, className)} {...props}>
70
+ <div
71
+ ref={treeRef}
72
+ role="tree"
73
+ className={clsx(styles.root, className)}
74
+ onKeyDown={handleKeyDown}
75
+ {...props}
76
+ >
16
77
  <TreeItem
17
78
  data={data}
18
79
  defaultExpanded={defaultExpanded}
19
80
  expandIcon={expandIcon}
20
81
  collapseIcon={collapseIcon}
21
82
  isRoot
83
+ level={1}
84
+ setSize={1}
85
+ posInSet={1}
22
86
  />
23
87
  </div>
24
88
  );
@@ -1,25 +1,32 @@
1
- .list {
2
- list-style: none;
3
- padding-left: var(--ds-space-4);
4
- margin: 0;
1
+ .item {
2
+ outline: none;
5
3
  }
6
4
 
7
- .item {
8
- margin: 0;
5
+ .item:focus-visible > .itemHeader {
6
+ box-shadow:
7
+ 0 0 0 2px var(--ds-ring-offset),
8
+ 0 0 0 4px var(--ds-ring);
9
+ border-radius: var(--ds-radius-sm);
9
10
  }
10
11
 
11
12
  .itemHeader {
12
13
  display: flex;
13
14
  align-items: center;
14
15
  min-height: var(--ds-space-6);
16
+ padding: 0 var(--ds-space-1);
17
+ border-radius: var(--ds-radius-sm);
18
+ cursor: default;
15
19
  }
16
20
 
17
- .toggleButton {
18
- background: none;
19
- border: none;
20
- padding: 0;
21
- margin: 0;
21
+ .branch > .itemHeader {
22
22
  cursor: pointer;
23
+ }
24
+
25
+ .itemHeader:hover {
26
+ background-color: var(--ds-surface-1);
27
+ }
28
+
29
+ .toggleIcon {
23
30
  display: inline-flex;
24
31
  align-items: center;
25
32
  justify-content: center;
@@ -27,11 +34,6 @@
27
34
  width: var(--ds-space-5);
28
35
  height: var(--ds-space-5);
29
36
  flex-shrink: 0;
30
- transition: transform var(--ds-transition-fast);
31
- }
32
-
33
- .toggleButton:hover {
34
- color: var(--ds-text-1);
35
37
  }
36
38
 
37
39
  .key {
@@ -50,14 +52,6 @@
50
52
  margin-left: var(--ds-space-1);
51
53
  }
52
54
 
53
- .collapsibleContent {
54
- display: none;
55
- }
56
-
57
- .expanded {
58
- display: block;
59
- }
60
-
61
- .rootList {
62
- padding-left: 0;
55
+ .childGroup {
56
+ padding-left: var(--ds-space-4);
63
57
  }
@@ -1,8 +1,21 @@
1
1
  import clsx from 'clsx';
2
- import { useState } from 'react';
2
+ import { useRef, useState } from 'react';
3
+ import type { FocusEvent, KeyboardEvent, MouseEvent } from 'react';
3
4
  import type { TreeItemProps } from './TreeItem.types';
4
5
  import styles from './TreeItem.module.css';
5
6
 
7
+ function focusTreeItem(item: HTMLElement) {
8
+ const tree = item.closest('[role="tree"]');
9
+ if (!tree) {
10
+ return;
11
+ }
12
+ tree.querySelectorAll<HTMLElement>('[role="treeitem"]').forEach((el) => {
13
+ el.tabIndex = -1;
14
+ });
15
+ item.tabIndex = 0;
16
+ item.focus();
17
+ }
18
+
6
19
  export const TreeItem = ({
7
20
  data,
8
21
  label,
@@ -10,14 +23,91 @@ export const TreeItem = ({
10
23
  expandIcon,
11
24
  collapseIcon,
12
25
  isRoot,
26
+ level,
27
+ setSize,
28
+ posInSet,
13
29
  }: TreeItemProps) => {
14
30
  const [isExpanded, setIsExpanded] = useState(isRoot ? true : (defaultExpanded ?? false));
31
+ const itemRef = useRef<HTMLDivElement>(null);
15
32
 
16
33
  const isObject = data !== null && typeof data === 'object';
17
34
  const hasChildren =
18
- isObject && (Array.isArray(data) ? data.length > 0 : Object.keys(data).length > 0);
35
+ isObject && (Array.isArray(data) ? data.length > 0 : Object.keys(data as object).length > 0);
36
+
37
+ const childLevel = isRoot ? level : level + 1;
38
+
39
+ const getChildren = (): { key: string; value: unknown }[] => {
40
+ if (!isObject) {
41
+ return [];
42
+ }
43
+ if (Array.isArray(data)) {
44
+ return (data as unknown[]).map((v, i) => ({ key: String(i), value: v }));
45
+ }
46
+ return Object.entries(data as Record<string, unknown>).map(([k, v]) => ({ key: k, value: v }));
47
+ };
19
48
 
20
- const toggle = () => setIsExpanded(!isExpanded);
49
+ const children = getChildren();
50
+
51
+ const handleClick = (e: MouseEvent) => {
52
+ e.stopPropagation();
53
+ if (hasChildren) {
54
+ setIsExpanded((prev) => !prev);
55
+ }
56
+ if (itemRef.current) {
57
+ focusTreeItem(itemRef.current);
58
+ }
59
+ };
60
+
61
+ const handleFocus = (e: FocusEvent) => {
62
+ e.stopPropagation();
63
+ if (!itemRef.current) {
64
+ return;
65
+ }
66
+ const tree = itemRef.current.closest('[role="tree"]');
67
+ if (!tree) {
68
+ return;
69
+ }
70
+ tree.querySelectorAll<HTMLElement>('[role="treeitem"]').forEach((el) => {
71
+ el.tabIndex = -1;
72
+ });
73
+ itemRef.current.tabIndex = 0;
74
+ };
75
+
76
+ const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {
77
+ switch (e.key) {
78
+ case 'Enter':
79
+ case ' ':
80
+ e.preventDefault();
81
+ if (hasChildren) {
82
+ setIsExpanded((prev) => !prev);
83
+ }
84
+ break;
85
+ case 'ArrowRight':
86
+ e.preventDefault();
87
+ e.stopPropagation();
88
+ if (hasChildren && !isExpanded) {
89
+ setIsExpanded(true);
90
+ } else if (hasChildren && isExpanded) {
91
+ const firstChild = itemRef.current?.querySelector<HTMLElement>('[role="treeitem"]');
92
+ if (firstChild) {
93
+ focusTreeItem(firstChild);
94
+ }
95
+ }
96
+ break;
97
+ case 'ArrowLeft':
98
+ e.preventDefault();
99
+ e.stopPropagation();
100
+ if (hasChildren && isExpanded) {
101
+ setIsExpanded(false);
102
+ } else {
103
+ const parent = itemRef.current?.parentElement?.closest<HTMLElement>('[role="treeitem"]');
104
+ if (parent) {
105
+ focusTreeItem(parent);
106
+ }
107
+ }
108
+ break;
109
+ }
110
+ };
21
111
 
22
112
  const defaultExpandIcon = (
23
113
  <svg
@@ -49,98 +139,73 @@ export const TreeItem = ({
49
139
  </svg>
50
140
  );
51
141
 
52
- const renderContent = () => {
142
+ const renderLeafContent = () => {
53
143
  if (data === undefined) {
54
144
  return <span className={styles.empty}>undefined</span>;
55
145
  }
56
-
57
146
  if (data === null) {
58
147
  return <span className={styles.empty}>null</span>;
59
148
  }
60
-
61
149
  if (typeof data !== 'object') {
62
150
  return <span className={styles.value}>{String(data)}</span>;
63
151
  }
64
-
65
- if (Array.isArray(data)) {
66
- if (data.length === 0) {
67
- return <span className={styles.empty}>[]</span>;
68
- }
69
- return (
70
- <ul
71
- className={clsx(
72
- styles.list,
73
- styles.collapsibleContent,
74
- isExpanded && styles.expanded,
75
- isRoot && styles.rootList
76
- )}
77
- >
78
- {data.map((item, index) => (
79
- <li key={index} className={styles.item}>
80
- <TreeItem
81
- data={item}
82
- defaultExpanded={defaultExpanded}
83
- expandIcon={expandIcon}
84
- collapseIcon={collapseIcon}
85
- />
86
- </li>
87
- ))}
88
- </ul>
89
- );
152
+ if (Array.isArray(data) && (data as unknown[]).length === 0) {
153
+ return <span className={styles.empty}>[]</span>;
90
154
  }
91
-
92
- if (Object.keys(data).length === 0) {
93
- return <span className={styles.empty}>{}</span>;
155
+ if (!Array.isArray(data) && Object.keys(data as object).length === 0) {
156
+ return <span className={styles.empty}>{'{}'}</span>;
94
157
  }
95
-
96
- return (
97
- <ul
98
- className={clsx(
99
- styles.list,
100
- styles.collapsibleContent,
101
- isExpanded && styles.expanded,
102
- isRoot && styles.rootList
103
- )}
104
- >
105
- {Object.entries(data).map(([key, value]) => (
106
- <li key={key} className={styles.item}>
107
- <TreeItem
108
- label={key}
109
- data={value}
110
- defaultExpanded={defaultExpanded}
111
- expandIcon={expandIcon}
112
- collapseIcon={collapseIcon}
113
- />
114
- </li>
115
- ))}
116
- </ul>
117
- );
158
+ return null;
118
159
  };
119
160
 
161
+ const childrenNodes = children.map((child, index) => (
162
+ <TreeItem
163
+ key={child.key}
164
+ label={Array.isArray(data) ? undefined : child.key}
165
+ data={child.value}
166
+ defaultExpanded={defaultExpanded}
167
+ expandIcon={expandIcon}
168
+ collapseIcon={collapseIcon}
169
+ level={childLevel}
170
+ setSize={children.length}
171
+ posInSet={index + 1}
172
+ />
173
+ ));
174
+
175
+ if (isRoot) {
176
+ return hasChildren ? <>{childrenNodes}</> : <>{renderLeafContent()}</>;
177
+ }
178
+
120
179
  return (
121
- <div>
122
- {!isRoot && (
123
- <div className={styles.itemHeader}>
124
- {hasChildren ? (
125
- <button
126
- type="button"
127
- className={styles.toggleButton}
128
- onClick={toggle}
129
- aria-expanded={isExpanded}
130
- >
131
- {isExpanded
132
- ? (collapseIcon ?? defaultCollapseIcon)
133
- : (expandIcon ?? defaultExpandIcon)}
134
- </button>
135
- ) : (
136
- <div className={styles.toggleButton} aria-hidden="true" />
137
- )}
138
- {label && <span className={styles.key}>{label}:</span>}
139
- {!hasChildren && renderContent()}
180
+ <div
181
+ ref={itemRef}
182
+ role="treeitem"
183
+ aria-expanded={hasChildren ? isExpanded : undefined}
184
+ aria-level={level}
185
+ aria-setsize={setSize}
186
+ aria-posinset={posInSet}
187
+ tabIndex={-1}
188
+ className={clsx(styles.item, hasChildren && styles.branch)}
189
+ onClick={handleClick}
190
+ onFocus={handleFocus}
191
+ onKeyDown={handleKeyDown}
192
+ >
193
+ <div className={styles.itemHeader}>
194
+ <span className={styles.toggleIcon} aria-hidden="true">
195
+ {hasChildren
196
+ ? isExpanded
197
+ ? (collapseIcon ?? defaultCollapseIcon)
198
+ : (expandIcon ?? defaultExpandIcon)
199
+ : null}
200
+ </span>
201
+ {label !== undefined && <span className={styles.key}>{label}:</span>}
202
+ {!hasChildren && renderLeafContent()}
203
+ </div>
204
+ {hasChildren && isExpanded && (
205
+ <div role="group" className={styles.childGroup}>
206
+ {childrenNodes}
140
207
  </div>
141
208
  )}
142
- {hasChildren && renderContent()}
143
- {isRoot && !hasChildren && <div className={styles.itemHeader}>{renderContent()}</div>}
144
209
  </div>
145
210
  );
146
211
  };
@@ -13,4 +13,10 @@ export interface TreeItemProps {
13
13
  collapseIcon?: ReactNode;
14
14
  /** Whether the tree item is a root element */
15
15
  isRoot?: boolean;
16
+ /** ARIA level (depth in the tree, 1-based) */
17
+ level: number;
18
+ /** Total number of siblings at this level */
19
+ setSize: number;
20
+ /** 1-based position among siblings */
21
+ posInSet: number;
16
22
  }
package/src/styles/ds.css CHANGED
@@ -1,12 +1,17 @@
1
- /* Layered Design Tokens (foundation -> theme refs -> semantics) */
2
- @import 'tokens.css';
3
- @import 'themes/light.css';
4
- @import 'themes/dark.css';
5
- @import 'themes/retro-light.css';
6
- @import 'themes/retro-dark.css';
7
- @import 'themes/sanzo-152-light.css';
8
- @import 'themes/sanzo-152-dark.css';
9
- @import 'semantic.css';
1
+ /* Explicit layer order: tokens < theme */
2
+ @layer ds.tokens, ds.theme;
3
+
4
+ /* Design tokens: primitives (palette.css, tokens.css) → theme semantics (themes/*.css) */
5
+ @import 'palette.css' layer(ds.tokens);
6
+ @import 'tokens.css' layer(ds.tokens);
7
+ @import 'themes/retro-palette.css' layer(ds.tokens);
8
+ @import 'themes/sanzo-152-palette.css' layer(ds.tokens);
9
+ @import 'themes/light.css' layer(ds.theme);
10
+ @import 'themes/dark.css' layer(ds.theme);
11
+ @import 'themes/retro-light.css' layer(ds.theme);
12
+ @import 'themes/retro-dark.css' layer(ds.theme);
13
+ @import 'themes/sanzo-152-light.css' layer(ds.theme);
14
+ @import 'themes/sanzo-152-dark.css' layer(ds.theme);
10
15
 
11
16
  :root {
12
17
  font-family: var(--ds-font-family-base);
@@ -0,0 +1,71 @@
1
+ :root {
2
+ /* Neutral */
3
+ --ds-p-neutral-0: #ffffff;
4
+ --ds-p-neutral-50: #fafafa;
5
+ --ds-p-neutral-100: #f5f5f5;
6
+ --ds-p-neutral-200: #eeeeee;
7
+ --ds-p-neutral-300: #e0e0e0;
8
+ --ds-p-neutral-400: #a5a5ae;
9
+ --ds-p-neutral-500: #7b7b85;
10
+ --ds-p-neutral-600: #63636e;
11
+ --ds-p-neutral-700: #424249;
12
+ --ds-p-neutral-800: #323237;
13
+ --ds-p-neutral-900: #242429;
14
+ --ds-p-neutral-950: #09090b;
15
+
16
+ /* Blue */
17
+ --ds-p-blue: #637ab3;
18
+ --ds-p-blue-50: color-mix(in srgb, var(--ds-p-blue) 10%, #ffffff);
19
+ --ds-p-blue-100: color-mix(in srgb, var(--ds-p-blue) 20%, #ffffff);
20
+ --ds-p-blue-200: color-mix(in srgb, var(--ds-p-blue) 35%, #ffffff);
21
+ --ds-p-blue-300: color-mix(in srgb, var(--ds-p-blue) 55%, #ffffff);
22
+ --ds-p-blue-400: color-mix(in srgb, var(--ds-p-blue) 75%, #ffffff);
23
+ --ds-p-blue-500: var(--ds-p-blue);
24
+ --ds-p-blue-600: color-mix(in srgb, var(--ds-p-blue) 85%, #000000);
25
+ --ds-p-blue-700: color-mix(in srgb, var(--ds-p-blue) 70%, #000000);
26
+ --ds-p-blue-800: color-mix(in srgb, var(--ds-p-blue) 55%, #000000);
27
+ --ds-p-blue-900: color-mix(in srgb, var(--ds-p-blue) 40%, #000000);
28
+ --ds-p-blue-950: color-mix(in srgb, var(--ds-p-blue) 25%, #000000);
29
+
30
+ /* Green */
31
+ --ds-p-green: #64af76;
32
+ --ds-p-green-50: color-mix(in srgb, var(--ds-p-green) 10%, #ffffff);
33
+ --ds-p-green-100: color-mix(in srgb, var(--ds-p-green) 20%, #ffffff);
34
+ --ds-p-green-200: color-mix(in srgb, var(--ds-p-green) 35%, #ffffff);
35
+ --ds-p-green-300: color-mix(in srgb, var(--ds-p-green) 55%, #ffffff);
36
+ --ds-p-green-400: color-mix(in srgb, var(--ds-p-green) 75%, #ffffff);
37
+ --ds-p-green-500: var(--ds-p-green);
38
+ --ds-p-green-600: color-mix(in srgb, var(--ds-p-green) 85%, #000000);
39
+ --ds-p-green-700: color-mix(in srgb, var(--ds-p-green) 70%, #000000);
40
+ --ds-p-green-800: color-mix(in srgb, var(--ds-p-green) 55%, #000000);
41
+ --ds-p-green-900: color-mix(in srgb, var(--ds-p-green) 40%, #000000);
42
+ --ds-p-green-950: color-mix(in srgb, var(--ds-p-green) 25%, #000000);
43
+
44
+ /* Red */
45
+ --ds-p-red: #d55a5a;
46
+ --ds-p-red-50: color-mix(in srgb, var(--ds-p-red) 10%, #ffffff);
47
+ --ds-p-red-100: color-mix(in srgb, var(--ds-p-red) 20%, #ffffff);
48
+ --ds-p-red-200: color-mix(in srgb, var(--ds-p-red) 35%, #ffffff);
49
+ --ds-p-red-300: color-mix(in srgb, var(--ds-p-red) 55%, #ffffff);
50
+ --ds-p-red-400: color-mix(in srgb, var(--ds-p-red) 75%, #ffffff);
51
+ --ds-p-red-500: var(--ds-p-red);
52
+ --ds-p-red-600: color-mix(in srgb, var(--ds-p-red) 85%, #000000);
53
+ --ds-p-red-700: color-mix(in srgb, var(--ds-p-red) 70%, #000000);
54
+ --ds-p-red-800: color-mix(in srgb, var(--ds-p-red) 55%, #000000);
55
+ --ds-p-red-900: color-mix(in srgb, var(--ds-p-red) 40%, #000000);
56
+ --ds-p-red-950: color-mix(in srgb, var(--ds-p-red) 25%, #000000);
57
+
58
+ /* Orange */
59
+ --ds-p-orange: #bf914f;
60
+ --ds-p-orange-50: color-mix(in srgb, var(--ds-p-orange) 10%, #ffffff);
61
+ --ds-p-orange-100: color-mix(in srgb, var(--ds-p-orange) 20%, #ffffff);
62
+ --ds-p-orange-200: color-mix(in srgb, var(--ds-p-orange) 35%, #ffffff);
63
+ --ds-p-orange-300: color-mix(in srgb, var(--ds-p-orange) 55%, #ffffff);
64
+ --ds-p-orange-400: color-mix(in srgb, var(--ds-p-orange) 75%, #ffffff);
65
+ --ds-p-orange-500: var(--ds-p-orange);
66
+ --ds-p-orange-600: color-mix(in srgb, var(--ds-p-orange) 85%, #000000);
67
+ --ds-p-orange-700: color-mix(in srgb, var(--ds-p-orange) 70%, #000000);
68
+ --ds-p-orange-800: color-mix(in srgb, var(--ds-p-orange) 55%, #000000);
69
+ --ds-p-orange-900: color-mix(in srgb, var(--ds-p-orange) 40%, #000000);
70
+ --ds-p-orange-950: color-mix(in srgb, var(--ds-p-orange) 25%, #000000);
71
+ }