@robr0/design-system 0.2.0 → 0.3.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 (66) hide show
  1. package/README.md +8 -6
  2. package/components/Accordion/Accordion.js +0 -1
  3. package/components/Avatar/Avatar.js +1 -0
  4. package/components/Breadcrumb/Breadcrumb.d.ts +7 -1
  5. package/components/Breadcrumb/Breadcrumb.js +3 -2
  6. package/components/Button/Button.css +18 -0
  7. package/components/Button/Button.d.ts +6 -0
  8. package/components/Button/Button.js +13 -3
  9. package/components/Card/Card.css +6 -0
  10. package/components/CircularButton/CircularButton.css +11 -0
  11. package/components/CircularButton/CircularButton.d.ts +7 -1
  12. package/components/CircularButton/CircularButton.js +15 -4
  13. package/components/CodeBlock/CodeBlock.js +10 -1
  14. package/components/ColorPicker/ColorPicker.css +278 -0
  15. package/components/ColorPicker/ColorPicker.d.ts +50 -0
  16. package/components/ColorPicker/ColorPicker.js +338 -0
  17. package/components/Combobox/Combobox.css +0 -36
  18. package/components/Combobox/Combobox.js +90 -82
  19. package/components/CommandPalette/CommandPalette.css +1 -15
  20. package/components/CommandPalette/CommandPalette.js +6 -5
  21. package/components/ContextMenu/ContextMenu.css +262 -0
  22. package/components/ContextMenu/ContextMenu.d.ts +26 -0
  23. package/components/ContextMenu/ContextMenu.js +350 -0
  24. package/components/DateInput/DateInput.css +0 -36
  25. package/components/DateInput/DateInput.js +37 -33
  26. package/components/DatePicker/DatePicker.js +45 -34
  27. package/components/Dialog/Dialog.js +5 -4
  28. package/components/Drawer/Drawer.js +7 -2
  29. package/components/Dropdown/Dropdown.css +0 -36
  30. package/components/Dropdown/Dropdown.js +119 -109
  31. package/components/DropdownMenu/DropdownMenu.js +10 -7
  32. package/components/Field/Field.css +80 -0
  33. package/components/Field/Field.d.ts +50 -0
  34. package/components/Field/Field.js +58 -0
  35. package/components/Field/FieldContext.d.ts +42 -0
  36. package/components/Field/FieldContext.js +7 -0
  37. package/components/FileInput/FileInput.css +0 -36
  38. package/components/FileInput/FileInput.js +111 -103
  39. package/components/Input/Input.css +0 -43
  40. package/components/Input/Input.js +51 -46
  41. package/components/Kbd/Kbd.css +28 -0
  42. package/components/Kbd/Kbd.d.ts +19 -0
  43. package/components/Kbd/Kbd.js +14 -0
  44. package/components/Popover/Popover.d.ts +0 -6
  45. package/components/Popover/Popover.js +22 -16
  46. package/components/ProgressBar/ProgressBar.js +1 -1
  47. package/components/SelectionCard/SelectionCard.css +6 -2
  48. package/components/Skeleton/Skeleton.css +2 -0
  49. package/components/Spinner/Spinner.css +11 -0
  50. package/components/Spinner/Spinner.d.ts +2 -2
  51. package/components/Swatch/Swatch.css +52 -0
  52. package/components/Swatch/Swatch.d.ts +34 -0
  53. package/components/Swatch/Swatch.js +44 -0
  54. package/components/Table/Table.css +19 -0
  55. package/components/Table/Table.js +1 -1
  56. package/components/Textarea/Textarea.css +0 -43
  57. package/components/Textarea/Textarea.js +37 -35
  58. package/components/ToggleSwitch/ToggleSwitch.css +7 -2
  59. package/components/registry.d.ts +47 -10
  60. package/components/registry.js +5 -1
  61. package/components/registry.json +498 -56
  62. package/components/registry.json.d.ts +498 -56
  63. package/components/registry.json.js +4 -1
  64. package/index.d.ts +8 -1
  65. package/index.js +16 -1
  66. package/package.json +1 -1
@@ -0,0 +1,262 @@
1
+ /* ============================================
2
+ CONTEXT MENU COMPONENT
3
+ Right-click menu anchored at the pointer.
4
+ Panel and item styling mirror DropdownMenu.
5
+ ============================================ */
6
+
7
+ /* Base — a plain block wrapper around the right-clickable area
8
+ (a real box, so the keyboard-invocation fallback can measure it) */
9
+ .ds-context-menu {
10
+ display: block;
11
+ }
12
+
13
+ /* ============================================
14
+ PANEL
15
+ Fixed-positioned at the pointer; left/top are
16
+ set inline from the contextmenu event coords.
17
+ ============================================ */
18
+
19
+ .ds-context-menu__panel {
20
+ position: fixed;
21
+ z-index: 50;
22
+ min-width: 200px;
23
+
24
+ /* Appearance — same recipe as DropdownMenu */
25
+ background: var(--color-bg-page-primary);
26
+ border: var(--border-xs) solid var(--color-input-border-primary);
27
+ border-radius: var(--radius-md);
28
+ box-shadow: var(--shadow-floating);
29
+
30
+ /* Inset gap */
31
+ padding: var(--padding-xxs);
32
+
33
+ /* Reset list */
34
+ list-style: none;
35
+ margin: 0;
36
+
37
+ outline: none;
38
+
39
+ /* Animation */
40
+ animation: ds-context-menu-appear var(--motion-duration-fast) var(--motion-ease-entrance);
41
+ }
42
+
43
+ /* Compact items: paragraph-sm-em, tighter padding, radius-sm */
44
+ .ds-context-menu__panel--compact .ds-context-menu__item {
45
+ padding: var(--padding-xs) var(--padding-sm-md);
46
+ border-radius: var(--radius-sm);
47
+ font-family: var(--font-paragraph-sm-em-family);
48
+ font-size: var(--font-paragraph-sm-em-size);
49
+ font-weight: var(--font-paragraph-sm-em-weight);
50
+ line-height: var(--font-paragraph-sm-em-line-height);
51
+ letter-spacing: var(--font-paragraph-sm-em-letter-spacing);
52
+ }
53
+
54
+ .ds-context-menu__panel--compact .ds-context-menu__item-icon {
55
+ --icon-size: var(--icon-size-sm);
56
+ }
57
+
58
+ .ds-context-menu__panel--compact .ds-context-menu__submenu-icon {
59
+ --icon-size: var(--icon-size-sm);
60
+ }
61
+
62
+ .ds-context-menu__panel--compact .ds-context-menu__group-label {
63
+ min-height: auto;
64
+ padding: var(--padding-xs) var(--padding-sm-md);
65
+ font-size: var(--font-paragraph-sm-em-size);
66
+ line-height: var(--font-paragraph-sm-em-line-height);
67
+ letter-spacing: var(--font-paragraph-sm-em-letter-spacing);
68
+ }
69
+
70
+ .ds-context-menu__panel--compact .ds-context-menu__separator {
71
+ margin: var(--padding-xxs) var(--padding-sm-md);
72
+ }
73
+
74
+ .ds-context-menu__panel--compact .ds-context-menu__shortcut {
75
+ font-size: var(--font-caption-size);
76
+ }
77
+
78
+ /* ============================================
79
+ SUB-MENU PANEL
80
+ Positioned relative to its parent item.
81
+ ============================================ */
82
+
83
+ .ds-context-menu__submenu {
84
+ position: absolute;
85
+ left: 100%;
86
+ top: 0;
87
+ margin-left: var(--gap-xxs);
88
+ }
89
+
90
+ /* ============================================
91
+ MENU ITEM
92
+ ============================================ */
93
+
94
+ .ds-context-menu__item {
95
+ display: flex;
96
+ align-items: center;
97
+ justify-content: space-between;
98
+ gap: var(--gap-md);
99
+ padding: var(--padding-sm) var(--padding-md);
100
+ border-radius: var(--radius-md);
101
+ cursor: pointer;
102
+ position: relative;
103
+ white-space: nowrap;
104
+ list-style: none;
105
+
106
+ font-family: var(--font-paragraph-em-family);
107
+ font-size: var(--font-paragraph-em-size);
108
+ font-weight: var(--font-paragraph-em-weight);
109
+ line-height: var(--font-paragraph-em-line-height);
110
+ letter-spacing: var(--font-paragraph-em-letter-spacing);
111
+ color: var(--color-action-passive-text);
112
+
113
+ transition: background-color var(--motion-duration-fast) var(--motion-ease-standard), color var(--motion-duration-fast) var(--motion-ease-standard);
114
+ }
115
+
116
+ .ds-context-menu__item:hover,
117
+ .ds-context-menu__item--focused {
118
+ background-color: var(--color-action-passive-bg-hover);
119
+ }
120
+
121
+ /* States — disabled */
122
+ .ds-context-menu__item--disabled {
123
+ opacity: 0.4;
124
+ cursor: not-allowed;
125
+ }
126
+
127
+ .ds-context-menu__item--disabled:hover,
128
+ .ds-context-menu__item--disabled.ds-context-menu__item--focused {
129
+ background-color: transparent;
130
+ }
131
+
132
+ /* ============================================
133
+ ITEM LABEL (text + optional icon)
134
+ ============================================ */
135
+
136
+ .ds-context-menu__item-label {
137
+ display: flex;
138
+ align-items: center;
139
+ gap: var(--gap-sm);
140
+ line-height: 1;
141
+ }
142
+
143
+ .ds-context-menu__item-icon {
144
+ --icon-size: var(--icon-size-md);
145
+ color: var(--color-icon-secondary);
146
+ flex-shrink: 0;
147
+ display: flex;
148
+ align-items: center;
149
+ justify-content: center;
150
+ line-height: 1;
151
+ }
152
+
153
+ /* ============================================
154
+ KEYBOARD SHORTCUT
155
+ ============================================ */
156
+
157
+ .ds-context-menu__shortcut {
158
+ font-family: var(--font-paragraph-sm-family);
159
+ font-size: var(--font-paragraph-sm-size);
160
+ font-weight: var(--font-paragraph-sm-weight);
161
+ line-height: var(--font-paragraph-sm-line-height);
162
+ letter-spacing: var(--font-paragraph-sm-letter-spacing);
163
+ color: var(--color-text-tertiary);
164
+ margin-left: auto;
165
+ flex-shrink: 0;
166
+ }
167
+
168
+ /* ============================================
169
+ SUB-MENU INDICATOR
170
+ ============================================ */
171
+
172
+ .ds-context-menu__submenu-icon {
173
+ --icon-size: var(--icon-size-md);
174
+ color: var(--color-text-tertiary);
175
+ margin-left: auto;
176
+ flex-shrink: 0;
177
+ display: flex;
178
+ align-items: center;
179
+ justify-content: center;
180
+ line-height: 1;
181
+ }
182
+
183
+ .ds-context-menu__item--has-submenu {
184
+ padding-right: var(--padding-sm-md);
185
+ }
186
+
187
+ /* ============================================
188
+ SEPARATOR
189
+ ============================================ */
190
+
191
+ .ds-context-menu__separator {
192
+ height: 1px;
193
+ background: var(--color-input-border-primary);
194
+ margin: var(--padding-xxs) var(--padding-md);
195
+ list-style: none;
196
+ }
197
+
198
+ /* ============================================
199
+ GROUP
200
+ ============================================ */
201
+
202
+ .ds-context-menu__group {
203
+ list-style: none;
204
+ }
205
+
206
+ .ds-context-menu__group-label {
207
+ display: flex;
208
+ align-items: center;
209
+ min-height: 40px;
210
+ font-family: var(--font-paragraph-em-family);
211
+ font-size: var(--font-paragraph-em-size);
212
+ font-weight: var(--font-paragraph-em-weight);
213
+ line-height: var(--font-paragraph-em-line-height);
214
+ letter-spacing: var(--font-paragraph-em-letter-spacing);
215
+ color: var(--color-text-tertiary);
216
+ padding-left: var(--padding-md);
217
+ padding-right: var(--padding-md);
218
+ user-select: none;
219
+ }
220
+
221
+ .ds-context-menu__group-list {
222
+ list-style: none;
223
+ margin: 0;
224
+ padding: 0;
225
+ }
226
+
227
+ /* ============================================
228
+ DESTRUCTIVE ITEM
229
+ ============================================ */
230
+
231
+ .ds-context-menu__item--destructive {
232
+ color: var(--color-core-accent-coral);
233
+ }
234
+
235
+ .ds-context-menu__item--destructive .ds-context-menu__item-icon {
236
+ color: var(--color-core-accent-coral);
237
+ }
238
+
239
+ .ds-context-menu__item--destructive .ds-context-menu__shortcut {
240
+ color: var(--color-core-accent-coral);
241
+ opacity: 0.7;
242
+ }
243
+
244
+ .ds-context-menu__item--destructive:hover,
245
+ .ds-context-menu__item--destructive.ds-context-menu__item--focused {
246
+ background-color: var(--color-status-error-bg);
247
+ }
248
+
249
+ /* ============================================
250
+ APPEAR ANIMATION
251
+ ============================================ */
252
+
253
+ @keyframes ds-context-menu-appear {
254
+ from {
255
+ opacity: 0;
256
+ transform: scale(0.96);
257
+ }
258
+ to {
259
+ opacity: 1;
260
+ transform: scale(1);
261
+ }
262
+ }
@@ -0,0 +1,26 @@
1
+ import { default as React } from 'react';
2
+ import { DropdownMenuEntry } from '../DropdownMenu/DropdownMenu';
3
+ /** Props owned by ContextMenu itself — everything else falls through to the wrapper div. */
4
+ type ContextMenuOwnProps = {
5
+ /** Menu entries — the same model as DropdownMenu (items, groups, separators) */
6
+ items: DropdownMenuEntry[];
7
+ /** Component size */
8
+ size?: 'default' | 'compact';
9
+ /** Accessible name for the menu */
10
+ ariaLabel?: string;
11
+ /** Additional CSS classes */
12
+ className?: string;
13
+ /** The right-clickable area the menu is attached to */
14
+ children: React.ReactNode;
15
+ };
16
+ export interface ContextMenuProps extends ContextMenuOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof ContextMenuOwnProps> {
17
+ }
18
+ /**
19
+ * ContextMenu opens a floating menu at the pointer position when the wrapped
20
+ * area is right-clicked (or the keyboard ContextMenu / Shift+F10 key is used).
21
+ * Entries use the same model as DropdownMenu — items, groups, separators,
22
+ * icons, shortcut hints, destructive and disabled states, and one level of
23
+ * sub-menus.
24
+ */
25
+ export declare const ContextMenu: React.ForwardRefExoticComponent<ContextMenuProps & React.RefAttributes<HTMLDivElement>>;
26
+ export {};
@@ -0,0 +1,350 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import React, { useState, useRef, useCallback, useEffect, useLayoutEffect } from "react";
3
+ import "./ContextMenu.css";
4
+ import "../../fonts/material-symbols.css";
5
+ function collectItems(entries) {
6
+ const result = [];
7
+ for (const entry of entries) {
8
+ if (entry.type === "separator") continue;
9
+ if (entry.type === "group") {
10
+ result.push(...collectItems(entry.items));
11
+ } else {
12
+ result.push(entry);
13
+ }
14
+ }
15
+ return result;
16
+ }
17
+ const SubMenuItem = ({ item, baseClass, focused, size, onActivate }) => {
18
+ const [subOpen, setSubOpen] = useState(false);
19
+ const timeoutRef = useRef(null);
20
+ const handleMouseEnter = () => {
21
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
22
+ setSubOpen(true);
23
+ };
24
+ const handleMouseLeave = () => {
25
+ timeoutRef.current = setTimeout(() => setSubOpen(false), 150);
26
+ };
27
+ useEffect(() => {
28
+ return () => {
29
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
30
+ };
31
+ }, []);
32
+ useEffect(() => {
33
+ if (focused && item.children && item.children.length > 0) {
34
+ setSubOpen(true);
35
+ }
36
+ }, [focused, item.children]);
37
+ const classes = [
38
+ `${baseClass}__item`,
39
+ focused ? `${baseClass}__item--focused` : "",
40
+ item.disabled ? `${baseClass}__item--disabled` : "",
41
+ item.destructive ? `${baseClass}__item--destructive` : "",
42
+ `${baseClass}__item--has-submenu`
43
+ ].filter(Boolean).join(" ");
44
+ return /* @__PURE__ */ jsxs(
45
+ "li",
46
+ {
47
+ className: classes,
48
+ role: "menuitem",
49
+ "aria-haspopup": "menu",
50
+ "aria-expanded": subOpen,
51
+ "aria-disabled": item.disabled || void 0,
52
+ onMouseEnter: handleMouseEnter,
53
+ onMouseLeave: handleMouseLeave,
54
+ onClick: (e) => {
55
+ e.stopPropagation();
56
+ if (!item.disabled) setSubOpen((prev) => !prev);
57
+ },
58
+ children: [
59
+ /* @__PURE__ */ jsxs("span", { className: `${baseClass}__item-label`, children: [
60
+ item.icon && /* @__PURE__ */ jsx("span", { className: `${baseClass}__item-icon material-symbols-rounded`, "aria-hidden": "true", children: item.icon }),
61
+ item.label
62
+ ] }),
63
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__submenu-icon material-symbols-rounded`, "aria-hidden": "true", children: "chevron_right" }),
64
+ subOpen && item.children && /* @__PURE__ */ jsx("ul", { className: `${baseClass}__panel ${baseClass}__submenu`, role: "menu", children: item.children.map((entry, index) => /* @__PURE__ */ jsx(
65
+ SubEntry,
66
+ {
67
+ entry,
68
+ baseClass,
69
+ size,
70
+ onActivate
71
+ },
72
+ index
73
+ )) })
74
+ ]
75
+ }
76
+ );
77
+ };
78
+ const SubEntry = ({
79
+ entry,
80
+ baseClass,
81
+ size,
82
+ onActivate
83
+ }) => {
84
+ if (entry.type === "separator") {
85
+ return /* @__PURE__ */ jsx("li", { className: `${baseClass}__separator`, role: "separator" });
86
+ }
87
+ if (entry.type === "group") {
88
+ return /* @__PURE__ */ jsxs("li", { className: `${baseClass}__group`, role: "none", children: [
89
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__group-label`, role: "presentation", children: entry.label }),
90
+ /* @__PURE__ */ jsx("ul", { className: `${baseClass}__group-list`, role: "group", "aria-label": entry.label, children: entry.items.map((subEntry, subIndex) => /* @__PURE__ */ jsx(
91
+ SubEntry,
92
+ {
93
+ entry: subEntry,
94
+ baseClass,
95
+ size,
96
+ onActivate
97
+ },
98
+ subIndex
99
+ )) })
100
+ ] });
101
+ }
102
+ if (entry.children && entry.children.length > 0) {
103
+ return /* @__PURE__ */ jsx(
104
+ SubMenuItem,
105
+ {
106
+ item: entry,
107
+ baseClass,
108
+ focused: false,
109
+ size,
110
+ onActivate
111
+ }
112
+ );
113
+ }
114
+ const itemClasses = [
115
+ `${baseClass}__item`,
116
+ entry.disabled ? `${baseClass}__item--disabled` : "",
117
+ entry.destructive ? `${baseClass}__item--destructive` : ""
118
+ ].filter(Boolean).join(" ");
119
+ return /* @__PURE__ */ jsxs(
120
+ "li",
121
+ {
122
+ className: itemClasses,
123
+ role: "menuitem",
124
+ "aria-disabled": entry.disabled || void 0,
125
+ onClick: (e) => {
126
+ e.stopPropagation();
127
+ if (!entry.disabled) {
128
+ entry.onClick?.();
129
+ onActivate();
130
+ }
131
+ },
132
+ children: [
133
+ /* @__PURE__ */ jsxs("span", { className: `${baseClass}__item-label`, children: [
134
+ entry.icon && /* @__PURE__ */ jsx("span", { className: `${baseClass}__item-icon material-symbols-rounded`, "aria-hidden": "true", children: entry.icon }),
135
+ entry.label
136
+ ] }),
137
+ entry.shortcut && /* @__PURE__ */ jsx("span", { className: `${baseClass}__shortcut`, children: entry.shortcut })
138
+ ]
139
+ }
140
+ );
141
+ };
142
+ const ContextMenu = React.forwardRef(
143
+ ({
144
+ items,
145
+ size = "default",
146
+ ariaLabel,
147
+ className = "",
148
+ children,
149
+ onContextMenu,
150
+ ...rest
151
+ }, ref) => {
152
+ const [position, setPosition] = useState(null);
153
+ const [focusedIndex, setFocusedIndex] = useState(-1);
154
+ const rootRef = useRef(null);
155
+ const panelRef = useRef(null);
156
+ const baseClass = "ds-context-menu";
157
+ const classes = [baseClass, className].filter(Boolean).join(" ");
158
+ const isOpen = position !== null;
159
+ const flatItems = collectItems(items);
160
+ const setRootRef = (node) => {
161
+ rootRef.current = node;
162
+ if (typeof ref === "function") ref(node);
163
+ else if (ref) ref.current = node;
164
+ };
165
+ const handleClose = useCallback(() => {
166
+ setPosition(null);
167
+ setFocusedIndex(-1);
168
+ }, []);
169
+ const handleContextMenu = (e) => {
170
+ onContextMenu?.(e);
171
+ e.preventDefault();
172
+ let x = e.clientX;
173
+ let y = e.clientY;
174
+ if (x === 0 && y === 0 && rootRef.current) {
175
+ const rect = rootRef.current.getBoundingClientRect();
176
+ x = rect.left + rect.width / 2;
177
+ y = rect.top + rect.height / 2;
178
+ }
179
+ setPosition({ x, y });
180
+ setFocusedIndex(-1);
181
+ };
182
+ useEffect(() => {
183
+ if (!isOpen) return;
184
+ const handler = (e) => {
185
+ if (panelRef.current && !panelRef.current.contains(e.target)) {
186
+ handleClose();
187
+ }
188
+ };
189
+ document.addEventListener("mousedown", handler);
190
+ return () => document.removeEventListener("mousedown", handler);
191
+ }, [isOpen, handleClose]);
192
+ useEffect(() => {
193
+ if (!isOpen) return;
194
+ const handler = () => handleClose();
195
+ window.addEventListener("scroll", handler, true);
196
+ window.addEventListener("resize", handler);
197
+ return () => {
198
+ window.removeEventListener("scroll", handler, true);
199
+ window.removeEventListener("resize", handler);
200
+ };
201
+ }, [isOpen, handleClose]);
202
+ useLayoutEffect(() => {
203
+ if (!isOpen || !panelRef.current || !position) return;
204
+ const panel = panelRef.current;
205
+ const rect = panel.getBoundingClientRect();
206
+ const margin = 8;
207
+ let { x, y } = position;
208
+ if (x + rect.width + margin > window.innerWidth) {
209
+ x = Math.max(margin, window.innerWidth - rect.width - margin);
210
+ }
211
+ if (y + rect.height + margin > window.innerHeight) {
212
+ y = Math.max(margin, window.innerHeight - rect.height - margin);
213
+ }
214
+ if (x !== position.x || y !== position.y) {
215
+ setPosition({ x, y });
216
+ return;
217
+ }
218
+ panel.focus({ preventScroll: true });
219
+ }, [isOpen, position]);
220
+ const handleKeyDown = (e) => {
221
+ switch (e.key) {
222
+ case "Enter":
223
+ case " ": {
224
+ e.preventDefault();
225
+ if (focusedIndex >= 0) {
226
+ const item = flatItems[focusedIndex];
227
+ if (item && !item.disabled && !item.children) {
228
+ item.onClick?.();
229
+ handleClose();
230
+ }
231
+ }
232
+ break;
233
+ }
234
+ case "ArrowDown":
235
+ e.preventDefault();
236
+ setFocusedIndex((prev) => {
237
+ let next = prev + 1;
238
+ while (next < flatItems.length && flatItems[next].disabled) next++;
239
+ return next < flatItems.length ? next : prev;
240
+ });
241
+ break;
242
+ case "ArrowUp":
243
+ e.preventDefault();
244
+ setFocusedIndex((prev) => {
245
+ let next = prev < 0 ? flatItems.length - 1 : prev - 1;
246
+ while (next >= 0 && flatItems[next].disabled) next--;
247
+ return next >= 0 ? next : prev;
248
+ });
249
+ break;
250
+ case "Escape":
251
+ case "Tab":
252
+ e.preventDefault();
253
+ handleClose();
254
+ break;
255
+ }
256
+ };
257
+ const renderEntry = (entry, index, itemCounter2) => {
258
+ if (entry.type === "separator") {
259
+ return /* @__PURE__ */ jsx("li", { className: `${baseClass}__separator`, role: "separator" }, `sep-${index}`);
260
+ }
261
+ if (entry.type === "group") {
262
+ return /* @__PURE__ */ jsxs("li", { className: `${baseClass}__group`, role: "none", children: [
263
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__group-label`, role: "presentation", children: entry.label }),
264
+ /* @__PURE__ */ jsx("ul", { className: `${baseClass}__group-list`, role: "group", "aria-label": entry.label, children: entry.items.map(
265
+ (subEntry, subIndex) => renderEntry(subEntry, subIndex, itemCounter2)
266
+ ) })
267
+ ] }, `group-${index}`);
268
+ }
269
+ const myIndex = itemCounter2.count;
270
+ itemCounter2.count++;
271
+ const isFocused = myIndex === focusedIndex;
272
+ if (entry.children && entry.children.length > 0) {
273
+ return /* @__PURE__ */ jsx(
274
+ SubMenuItem,
275
+ {
276
+ item: entry,
277
+ baseClass,
278
+ focused: isFocused,
279
+ size,
280
+ onActivate: handleClose
281
+ },
282
+ `submenu-${index}`
283
+ );
284
+ }
285
+ const itemClasses = [
286
+ `${baseClass}__item`,
287
+ isFocused ? `${baseClass}__item--focused` : "",
288
+ entry.disabled ? `${baseClass}__item--disabled` : "",
289
+ entry.destructive ? `${baseClass}__item--destructive` : ""
290
+ ].filter(Boolean).join(" ");
291
+ return /* @__PURE__ */ jsxs(
292
+ "li",
293
+ {
294
+ className: itemClasses,
295
+ role: "menuitem",
296
+ "aria-disabled": entry.disabled || void 0,
297
+ onClick: (e) => {
298
+ e.stopPropagation();
299
+ if (!entry.disabled) {
300
+ entry.onClick?.();
301
+ handleClose();
302
+ }
303
+ },
304
+ children: [
305
+ /* @__PURE__ */ jsxs("span", { className: `${baseClass}__item-label`, children: [
306
+ entry.icon && /* @__PURE__ */ jsx(
307
+ "span",
308
+ {
309
+ className: `${baseClass}__item-icon material-symbols-rounded`,
310
+ "aria-hidden": "true",
311
+ children: entry.icon
312
+ }
313
+ ),
314
+ entry.label
315
+ ] }),
316
+ entry.shortcut && /* @__PURE__ */ jsx("span", { className: `${baseClass}__shortcut`, children: entry.shortcut })
317
+ ]
318
+ },
319
+ `item-${index}`
320
+ );
321
+ };
322
+ const panelClasses = [
323
+ `${baseClass}__panel`,
324
+ size === "compact" ? `${baseClass}__panel--compact` : ""
325
+ ].filter(Boolean).join(" ");
326
+ const itemCounter = { count: 0 };
327
+ return /* @__PURE__ */ jsxs("div", { ...rest, ref: setRootRef, className: classes, onContextMenu: handleContextMenu, children: [
328
+ children,
329
+ isOpen && /* @__PURE__ */ jsx(
330
+ "ul",
331
+ {
332
+ className: panelClasses,
333
+ role: "menu",
334
+ "aria-label": ariaLabel,
335
+ tabIndex: -1,
336
+ ref: (el) => {
337
+ panelRef.current = el;
338
+ },
339
+ style: { left: position.x, top: position.y },
340
+ onKeyDown: handleKeyDown,
341
+ children: items.map((entry, index) => renderEntry(entry, index, itemCounter))
342
+ }
343
+ )
344
+ ] });
345
+ }
346
+ );
347
+ ContextMenu.displayName = "ContextMenu";
348
+ export {
349
+ ContextMenu
350
+ };
@@ -14,19 +14,6 @@
14
14
  LABEL
15
15
  ============================================ */
16
16
 
17
- .ds-date-input__label {
18
- font-family: var(--font-paragraph-em-family);
19
- font-size: var(--font-paragraph-em-size);
20
- font-weight: var(--font-paragraph-em-weight);
21
- line-height: var(--font-paragraph-em-line-height);
22
- letter-spacing: var(--font-paragraph-em-letter-spacing);
23
- color: var(--color-text-primary);
24
- }
25
-
26
- .ds-date-input__required {
27
- color: var(--color-core-accent-coral);
28
- }
29
-
30
17
  /* ============================================
31
18
  FIELD WRAPPER
32
19
  ============================================ */
@@ -108,25 +95,10 @@
108
95
  --icon-size: var(--icon-size-sm);
109
96
  }
110
97
 
111
- .ds-date-input--compact .ds-date-input__label {
112
- font-size: var(--font-paragraph-sm-size);
113
- line-height: var(--font-paragraph-sm-line-height);
114
- }
115
-
116
98
  /* ============================================
117
99
  HELPER TEXT
118
100
  ============================================ */
119
101
 
120
- .ds-date-input__helper {
121
- font-family: var(--font-paragraph-sm-family);
122
- font-size: var(--font-paragraph-sm-size);
123
- font-weight: var(--font-paragraph-sm-weight);
124
- line-height: var(--font-paragraph-sm-line-height);
125
- letter-spacing: var(--font-paragraph-sm-letter-spacing);
126
- color: var(--color-text-tertiary);
127
- margin: 0;
128
- }
129
-
130
102
  /* ============================================
131
103
  ERROR STATE
132
104
  ============================================ */
@@ -139,18 +111,10 @@
139
111
  border-color: var(--color-status-error-border);
140
112
  }
141
113
 
142
- .ds-date-input--error .ds-date-input__helper {
143
- color: var(--color-status-error-border);
144
- }
145
-
146
114
  /* ============================================
147
115
  DISABLED STATE
148
116
  ============================================ */
149
117
 
150
- .ds-date-input--disabled .ds-date-input__label {
151
- color: var(--color-input-text-disabled);
152
- }
153
-
154
118
  .ds-date-input--disabled .ds-date-input__field {
155
119
  background-color: var(--color-input-bg-disabled);
156
120
  border-color: var(--color-input-border-disabled);