gridsmith-ui 0.27.0 → 0.28.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 (61) hide show
  1. package/CHANGELOG.md +42 -1
  2. package/dist/charts.js +2 -2
  3. package/dist/charts.js.map +1 -1
  4. package/dist/chat.js +5 -5
  5. package/dist/chat.js.map +1 -1
  6. package/dist/{chunk-64TXZ4L7.js → chunk-2ROVDVLZ.js} +3 -3
  7. package/dist/{chunk-64TXZ4L7.js.map → chunk-2ROVDVLZ.js.map} +1 -1
  8. package/dist/chunk-66JJCQU3.js +46 -0
  9. package/dist/chunk-66JJCQU3.js.map +1 -0
  10. package/dist/chunk-7RKC5C7G.js +35 -0
  11. package/dist/chunk-7RKC5C7G.js.map +1 -0
  12. package/dist/{chunk-OTCEJN64.js → chunk-BRAXJEEP.js} +7 -6
  13. package/dist/chunk-BRAXJEEP.js.map +1 -0
  14. package/dist/{chunk-IXR4UEF4.js → chunk-DQCHCLEJ.js} +9 -8
  15. package/dist/chunk-DQCHCLEJ.js.map +1 -0
  16. package/dist/{chunk-5TUVX4B2.js → chunk-EIWXVICU.js} +3 -3
  17. package/dist/{chunk-5TUVX4B2.js.map → chunk-EIWXVICU.js.map} +1 -1
  18. package/dist/{chunk-SFY2KMHG.js → chunk-FD4YED7O.js} +5 -4
  19. package/dist/chunk-FD4YED7O.js.map +1 -0
  20. package/dist/{chunk-MD2EFMES.js → chunk-GXMTS3YD.js} +3 -3
  21. package/dist/{chunk-MD2EFMES.js.map → chunk-GXMTS3YD.js.map} +1 -1
  22. package/dist/chunk-HTXP5BMM.js +38 -0
  23. package/dist/chunk-HTXP5BMM.js.map +1 -0
  24. package/dist/{chunk-R5NFCEZ3.js → chunk-OPFJEL3Z.js} +52 -24
  25. package/dist/chunk-OPFJEL3Z.js.map +1 -0
  26. package/dist/{chunk-EKBWWA6P.js → chunk-R4GXKH4U.js} +7 -7
  27. package/dist/chunk-R4GXKH4U.js.map +1 -0
  28. package/dist/{chunk-PO65I3MQ.js → chunk-TRDXWHD2.js} +6 -6
  29. package/dist/chunk-TRDXWHD2.js.map +1 -0
  30. package/dist/{chunk-2CKSSWYG.js → chunk-YUTF2X6B.js} +39 -20
  31. package/dist/chunk-YUTF2X6B.js.map +1 -0
  32. package/dist/data-grid.js +18 -11
  33. package/dist/data-grid.js.map +1 -1
  34. package/dist/editor-mentions.js +2 -2
  35. package/dist/editor.js +44 -24
  36. package/dist/editor.js.map +1 -1
  37. package/dist/index.d.ts +39 -2
  38. package/dist/index.js +397 -279
  39. package/dist/index.js.map +1 -1
  40. package/dist/kanban.js +18 -11
  41. package/dist/kanban.js.map +1 -1
  42. package/dist/resizable.js +20 -15
  43. package/dist/resizable.js.map +1 -1
  44. package/dist/roots.css +91 -15
  45. package/dist/tokens.css +111 -26
  46. package/dist/utils.d.ts +47 -5
  47. package/dist/utils.js +15 -5
  48. package/dist/utils.js.map +1 -1
  49. package/dist/virtualized.js +17 -11
  50. package/dist/virtualized.js.map +1 -1
  51. package/dist-static/tokens.css +111 -26
  52. package/package.json +1 -1
  53. package/dist/chunk-2CKSSWYG.js.map +0 -1
  54. package/dist/chunk-EKBWWA6P.js.map +0 -1
  55. package/dist/chunk-IXR4UEF4.js.map +0 -1
  56. package/dist/chunk-M2QRNBDQ.js +0 -42
  57. package/dist/chunk-M2QRNBDQ.js.map +0 -1
  58. package/dist/chunk-OTCEJN64.js.map +0 -1
  59. package/dist/chunk-PO65I3MQ.js.map +0 -1
  60. package/dist/chunk-R5NFCEZ3.js.map +0 -1
  61. package/dist/chunk-SFY2KMHG.js.map +0 -1
@@ -1,17 +1,19 @@
1
1
  "use client";
2
- import { useWholeListCheck, pagerPart, Pagination } from './chunk-2CKSSWYG.js';
3
- import './chunk-EKBWWA6P.js';
2
+ import { useWholeListCheck, pagerPart, Pagination } from './chunk-YUTF2X6B.js';
3
+ import './chunk-R4GXKH4U.js';
4
4
  import './chunk-OYNUU346.js';
5
+ import './chunk-7RKC5C7G.js';
5
6
  import './chunk-XVB55M3N.js';
6
7
  import { useScrollsInside } from './chunk-QM4SJKWV.js';
8
+ import { useRevealFocus } from './chunk-HTXP5BMM.js';
7
9
  import './chunk-ZI3OQDET.js';
8
- import './chunk-MD2EFMES.js';
10
+ import './chunk-GXMTS3YD.js';
9
11
  import './chunk-7Q46JXSK.js';
10
12
  import './chunk-TJEV7YAY.js';
11
13
  import './chunk-HP7WUZPK.js';
12
14
  import { useLatest } from './chunk-WH2FUFAC.js';
13
- import { cn } from './chunk-M2QRNBDQ.js';
14
- import { useRef, useEffect } from 'react';
15
+ import { cn } from './chunk-66JJCQU3.js';
16
+ import { useRef, useState, useCallback, useEffect } from 'react';
15
17
  import { useVirtualizer } from '@tanstack/react-virtual';
16
18
  import { jsxs, jsx } from 'react/jsx-runtime';
17
19
 
@@ -28,6 +30,14 @@ function VirtualizedList({
28
30
  useScrollsInside();
29
31
  const parentRef = useRef(null);
30
32
  const endRef = useRef(null);
33
+ const [scroller, setScroller] = useState(null);
34
+ useRevealFocus(scroller);
35
+ const setList = useCallback((node) => {
36
+ parentRef.current = node;
37
+ setScroller(node);
38
+ if (typeof ref === "function") ref(node);
39
+ else if (ref) ref.current = node;
40
+ }, [ref]);
31
41
  useWholeListCheck("VirtualizedList", allItems.length, pager);
32
42
  const items = pagerPart(allItems, pager);
33
43
  const offset = pager ? Math.max(0, pager.range[0] - 1) : 0;
@@ -68,14 +78,10 @@ function VirtualizedList({
68
78
  const list = /* @__PURE__ */ jsxs(
69
79
  "div",
70
80
  {
71
- ref: (node) => {
72
- parentRef.current = node;
73
- if (typeof ref === "function") ref(node);
74
- else if (ref) ref.current = node;
75
- },
81
+ ref: setList,
76
82
  "data-ds-list": pager ? "" : void 0,
77
83
  className: cn(
78
- "overflow-auto",
84
+ "overflow-auto scroll-p-[4px]",
79
85
  "rounded-[var(--ds-radius-md)]",
80
86
  "border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
81
87
  "bg-[var(--ds-bg-surface)]",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../showcase/src/components/VirtualizedList.tsx"],"names":[],"mappings":"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","file":"virtualized.js","sourcesContent":["import { useEffect, useRef, type ReactNode, type Ref } from \"react\";\nimport { useVirtualizer, type VirtualItem } from \"@tanstack/react-virtual\";\nimport { cn } from \"../lib/utils\";\nimport { useLatest } from \"../lib/use-latest\";\nimport { Pagination } from \"./Pagination\";\nimport { pagerPart, useWholeListCheck, type Pager } from \"../lib/use-pagination\";\nimport { useScrollsInside } from \"../lib/surface-context\";\n\nexport interface VirtualizedListProps<T> {\n items: T[];\n estimateSize: (index: number) => number;\n /** An item, with its index in `items` (the whole list, when the list is paged). */\n renderItem: (item: T, index: number, virtualItem: VirtualItem) => ReactNode;\n overscan?: number;\n height?: number | string;\n className?: string;\n ref?: Ref<HTMLDivElement>;\n /**\n * The list's pager (Sprint 25.13 A49): paging and drawing only the rows on screen combine. Pass every item and\n * `usePagination(items)`'s pager: the list mounts only the rows on screen of the pager's part, and beneath it draws the\n * control in the project's style. A new page starts at its top; with infinite scroll, scrolling inside the list loads\n * more. For a long page (logs, feeds) the user asked to page differently, pass the size to the hook\n * (`usePagination(rows, { pageSize: 100 })`) with its override note.\n */\n pager?: Pager<unknown>;\n}\n\nexport function VirtualizedList<T>({\n items: allItems,\n estimateSize,\n renderItem,\n overscan = 5,\n height = 400,\n className,\n ref,\n pager,\n}: VirtualizedListProps<T>) {\n // Sprint 25.14 A44: a list with no frame of its own: a SplitView's list pane keeps its hairline around it\n useScrollsInside();\n const parentRef = useRef<HTMLDivElement>(null);\n const endRef = useRef<HTMLDivElement>(null);\n useWholeListCheck(\"VirtualizedList\", allItems.length, pager);\n const items = pagerPart(allItems, pager);\n const offset = pager ? Math.max(0, pager.range[0] - 1) : 0;\n\n // eslint-disable-next-line react-hooks/incompatible-library -- TanStack Virtual is not compiler-compatible (informational; the project does not use the React Compiler)\n const virtualizer = useVirtualizer({\n count: items.length,\n getScrollElement: () => parentRef.current,\n estimateSize: (index) => estimateSize(offset + index),\n // a row is known by its place in the whole list, so page 2's third row isn't page 1's (the review of 30 September:\n // an entry opened on page 1 showed opened on page 2, and page 1's heights carried over)\n getItemKey: (index) => offset + index,\n overscan,\n });\n\n // A49: a new page starts at its top, and so does a growing list that starts again at its first page (a new order, a\n // search): left scrolled to its end, it loaded the next page at once (the review of 30 September)\n const page = pager ? pager.page : null;\n const pageBefore = useRef(page);\n const numbered = pager?.style === \"pagination\";\n useEffect(() => {\n const before = pageBefore.current;\n pageBefore.current = page;\n if (page === null || !parentRef.current) return;\n if (numbered ? page !== before : before !== null && page < before) parentRef.current.scrollTop = 0;\n }, [page, numbered]);\n\n // A49: with infinite scroll, the trigger sits at the end of the list's own content and watches the list's scroller\n // (it watched the viewport, so scrolling inside the list never loaded more); it loads once per growth of the list\n const loadMore = useLatest(pager?.loadMore);\n const growing = pager?.style === \"infinite-scroll\" && pager.hasMore;\n const loadedAt = useRef(-1);\n useEffect(() => {\n const root = parentRef.current;\n const end = endRef.current;\n // the list's length changed since the last load (it grew, or started again at page 1): it may load again (the\n // review of 30 September: after a reset to the first page it never loaded again)\n if (loadedAt.current !== items.length) loadedAt.current = -1;\n if (!growing || !root || !end || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver((entries) => {\n if (!entries.some((e) => e.isIntersecting) || loadedAt.current === items.length) return;\n loadedAt.current = items.length;\n loadMore.current?.();\n }, { root, rootMargin: \"200px 0px\" });\n observer.observe(end);\n return () => observer.disconnect();\n }, [growing, items.length, loadMore]);\n\n const list = (\n <div\n ref={(node) => {\n (parentRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;\n }}\n data-ds-list={pager ? \"\" : undefined}\n className={cn(\n \"overflow-auto\",\n \"rounded-[var(--ds-radius-md)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"bg-[var(--ds-bg-surface)]\",\n !pager && className,\n )}\n style={{ height }}\n >\n <div className=\"relative w-full\" style={{ height: virtualizer.getTotalSize() }}>\n {virtualizer.getVirtualItems().map((virtualItem) => (\n <div\n key={virtualItem.key}\n data-index={virtualItem.index}\n ref={virtualizer.measureElement}\n className=\"absolute top-0 left-0 w-full\"\n style={{ transform: `translateY(${virtualItem.start}px)` }}\n >\n {renderItem(items[virtualItem.index], offset + virtualItem.index, virtualItem)}\n </div>\n ))}\n </div>\n {growing && <div ref={endRef} data-load-more-trigger=\"\" aria-hidden=\"true\" className=\"h-px w-full\" />}\n </div>\n );\n // A3: the pager's control is the list's next sibling, as <Pagination {...pager.props} /> would be. With infinite\n // scroll it is the Load more button alone, for keyboard users: the list's own trigger loads as it scrolls (A49). The\n // two are one element, which takes the className, so in a grid or a flex row they stay one item, and the list keeps\n // its element while its items come and go (the review of 30 September).\n if (!pager) return list;\n return (\n <div data-gs-paged=\"\" className={cn(\"flex flex-col min-w-0\", className)}>\n {list}\n {allItems.length > 0 && <Pagination {...pager.props} mode={pager.style === \"infinite-scroll\" ? \"load-more\" : pager.props.mode} />}\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../../../showcase/src/components/VirtualizedList.tsx"],"names":[],"mappings":"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","file":"virtualized.js","sourcesContent":["import { useCallback, useEffect, useRef, useState, type ReactNode, type Ref } from \"react\";\nimport { useVirtualizer, type VirtualItem } from \"@tanstack/react-virtual\";\nimport { cn } from \"../lib/utils\";\nimport { useLatest } from \"../lib/use-latest\";\nimport { Pagination } from \"./Pagination\";\nimport { pagerPart, useWholeListCheck, type Pager } from \"../lib/use-pagination\";\nimport { useScrollsInside } from \"../lib/surface-context\";\nimport { useRevealFocus } from \"../lib/reveal-focus\";\n\nexport interface VirtualizedListProps<T> {\n items: T[];\n estimateSize: (index: number) => number;\n /** An item, with its index in `items` (the whole list, when the list is paged). */\n renderItem: (item: T, index: number, virtualItem: VirtualItem) => ReactNode;\n overscan?: number;\n height?: number | string;\n className?: string;\n ref?: Ref<HTMLDivElement>;\n /**\n * The list's pager (Sprint 25.13 A49): paging and drawing only the rows on screen combine. Pass every item and\n * `usePagination(items)`'s pager: the list mounts only the rows on screen of the pager's part, and beneath it draws the\n * control in the project's style. A new page starts at its top; with infinite scroll, scrolling inside the list loads\n * more. For a long page (logs, feeds) the user asked to page differently, pass the size to the hook\n * (`usePagination(rows, { pageSize: 100 })`) with its override note.\n */\n pager?: Pager<unknown>;\n}\n\nexport function VirtualizedList<T>({\n items: allItems,\n estimateSize,\n renderItem,\n overscan = 5,\n height = 400,\n className,\n ref,\n pager,\n}: VirtualizedListProps<T>) {\n // Sprint 25.14 A44: a list with no frame of its own: a SplitView's list pane keeps its hairline around it\n useScrollsInside();\n const parentRef = useRef<HTMLDivElement>(null);\n const endRef = useRef<HTMLDivElement>(null);\n // what the keyboard reaches in a row comes into view whole, with its outline (Sprint 30, P3)\n const [scroller, setScroller] = useState<HTMLDivElement | null>(null);\n useRevealFocus(scroller);\n const setList = useCallback((node: HTMLDivElement | null) => {\n (parentRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n setScroller(node);\n if (typeof ref === \"function\") ref(node);\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;\n }, [ref]);\n useWholeListCheck(\"VirtualizedList\", allItems.length, pager);\n const items = pagerPart(allItems, pager);\n const offset = pager ? Math.max(0, pager.range[0] - 1) : 0;\n\n // eslint-disable-next-line react-hooks/incompatible-library -- TanStack Virtual is not compiler-compatible (informational; the project does not use the React Compiler)\n const virtualizer = useVirtualizer({\n count: items.length,\n getScrollElement: () => parentRef.current,\n estimateSize: (index) => estimateSize(offset + index),\n // a row is known by its place in the whole list, so page 2's third row isn't page 1's (the review of 30 September:\n // an entry opened on page 1 showed opened on page 2, and page 1's heights carried over)\n getItemKey: (index) => offset + index,\n overscan,\n });\n\n // A49: a new page starts at its top, and so does a growing list that starts again at its first page (a new order, a\n // search): left scrolled to its end, it loaded the next page at once (the review of 30 September)\n const page = pager ? pager.page : null;\n const pageBefore = useRef(page);\n const numbered = pager?.style === \"pagination\";\n useEffect(() => {\n const before = pageBefore.current;\n pageBefore.current = page;\n if (page === null || !parentRef.current) return;\n if (numbered ? page !== before : before !== null && page < before) parentRef.current.scrollTop = 0;\n }, [page, numbered]);\n\n // A49: with infinite scroll, the trigger sits at the end of the list's own content and watches the list's scroller\n // (it watched the viewport, so scrolling inside the list never loaded more); it loads once per growth of the list\n const loadMore = useLatest(pager?.loadMore);\n const growing = pager?.style === \"infinite-scroll\" && pager.hasMore;\n const loadedAt = useRef(-1);\n useEffect(() => {\n const root = parentRef.current;\n const end = endRef.current;\n // the list's length changed since the last load (it grew, or started again at page 1): it may load again (the\n // review of 30 September: after a reset to the first page it never loaded again)\n if (loadedAt.current !== items.length) loadedAt.current = -1;\n if (!growing || !root || !end || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver((entries) => {\n if (!entries.some((e) => e.isIntersecting) || loadedAt.current === items.length) return;\n loadedAt.current = items.length;\n loadMore.current?.();\n }, { root, rootMargin: \"200px 0px\" });\n observer.observe(end);\n return () => observer.disconnect();\n }, [growing, items.length, loadMore]);\n\n const list = (\n <div\n ref={setList}\n data-ds-list={pager ? \"\" : undefined}\n className={cn(\n \"overflow-auto scroll-p-[4px]\",\n \"rounded-[var(--ds-radius-md)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"bg-[var(--ds-bg-surface)]\",\n !pager && className,\n )}\n style={{ height }}\n >\n <div className=\"relative w-full\" style={{ height: virtualizer.getTotalSize() }}>\n {virtualizer.getVirtualItems().map((virtualItem) => (\n <div\n key={virtualItem.key}\n data-index={virtualItem.index}\n ref={virtualizer.measureElement}\n className=\"absolute top-0 left-0 w-full\"\n style={{ transform: `translateY(${virtualItem.start}px)` }}\n >\n {renderItem(items[virtualItem.index], offset + virtualItem.index, virtualItem)}\n </div>\n ))}\n </div>\n {growing && <div ref={endRef} data-load-more-trigger=\"\" aria-hidden=\"true\" className=\"h-px w-full\" />}\n </div>\n );\n // A3: the pager's control is the list's next sibling, as <Pagination {...pager.props} /> would be. With infinite\n // scroll it is the Load more button alone, for keyboard users: the list's own trigger loads as it scrolls (A49). The\n // two are one element, which takes the className, so in a grid or a flex row they stay one item, and the list keeps\n // its element while its items come and go (the review of 30 September).\n if (!pager) return list;\n return (\n <div data-gs-paged=\"\" className={cn(\"flex flex-col min-w-0\", className)}>\n {list}\n {allItems.length > 0 && <Pagination {...pager.props} mode={pager.style === \"infinite-scroll\" ? \"load-more\" : pager.props.mode} />}\n </div>\n );\n}\n"]}
@@ -65,10 +65,7 @@
65
65
  --ds-accent-primary: var(--ds-primary-700);
66
66
  --ds-accent-primary-hover: var(--ds-primary-800);
67
67
  --ds-accent-primary-active: var(--ds-primary-900);
68
- --ds-border-focus: var(--ds-primary-700);
69
68
  --ds-ring-active: var(--ds-accent-soft);
70
- --ds-input-focus-ring: var(--ds-ring-active);
71
- --ds-shadow-focus: 0 0 0 2px var(--ds-primary-700);
72
69
  --ds-tint-strength: 0.15;
73
70
  --ds-gradient: linear-gradient(135deg, oklch(0.4 0.1320 250), oklch(0.550 0.1100 210));
74
71
  --ds-gradient-start: oklch(0.4 0.1320 250);
@@ -80,7 +77,7 @@
80
77
  --ds-accent-subtle: color-mix(in srgb, var(--ds-accent-primary) 10%, transparent);
81
78
  --ds-accent-muted: color-mix(in srgb, var(--ds-accent-primary) 20%, transparent);
82
79
  --ds-accent-soft: color-mix(in srgb, var(--ds-accent-primary) 30%, transparent);
83
- --ds-accent-subtle-text: var(--ds-accent-primary);
80
+ --ds-accent-subtle-text: var(--ds-accent-text, var(--ds-accent-primary));
84
81
  --ds-accent-bg: oklch(0.92 0.0300 250);
85
82
  --ds-accent-text: oklch(0.35 0.1000 250);
86
83
  --ds-status-success: oklch(0.55 0.12 150);
@@ -155,7 +152,7 @@
155
152
  --ds-nav-h-track-gap: 0px;
156
153
  --ds-nav-h-badge-bg: var(--ds-accent-primary);
157
154
  --ds-nav-v-active-bg: var(--ds-tab-active-bg);
158
- --ds-nav-v-active-text: var(--ds-accent-primary);
155
+ --ds-nav-v-active-text: var(--ds-accent-ink);
159
156
  --ds-nav-v-active-rail: var(--ds-border-width-thick);
160
157
  --ds-nav-v-item-radius: var(--ds-radius-sm);
161
158
  --ds-nav-v-track-border: 0px;
@@ -163,12 +160,12 @@
163
160
  --ds-nav-v-active-muted: var(--ds-text-secondary);
164
161
  --ds-nav-v-badge-bg: var(--ds-accent-primary);
165
162
  --ds-tree-active-bg: var(--ds-tab-active-bg);
166
- --ds-tree-active-text: var(--ds-accent-primary);
163
+ --ds-tree-active-text: var(--ds-accent-ink);
167
164
  --ds-tree-active-muted: var(--ds-text-muted);
168
165
  --ds-tree-active-rail: var(--ds-border-width-thick);
169
166
  --ds-sidebar-active-bg: var(--ds-sidebar-accent-subtle);
170
- --ds-sidebar-active-text: var(--ds-sidebar-accent);
171
- --ds-sidebar-active-accent: var(--ds-sidebar-accent);
167
+ --ds-sidebar-active-text: var(--ds-sidebar-accent-ink);
168
+ --ds-sidebar-active-accent: var(--ds-sidebar-accent-ink);
172
169
  --ds-sidebar-active-rail: var(--ds-border-width-thick);
173
170
  --ds-sidebar-active-image: none;
174
171
  --ds-switch-off-fill: transparent;
@@ -188,7 +185,7 @@
188
185
  --ds-nav-h-track-gap: 0px;
189
186
  --ds-nav-h-badge-bg: var(--ds-accent-primary);
190
187
  --ds-nav-v-active-bg: var(--ds-tab-active-bg);
191
- --ds-nav-v-active-text: var(--ds-accent-primary);
188
+ --ds-nav-v-active-text: var(--ds-accent-ink);
192
189
  --ds-nav-v-active-rail: var(--ds-border-width-thick);
193
190
  --ds-nav-v-item-radius: var(--ds-radius-sm);
194
191
  --ds-nav-v-track-border: 0px;
@@ -196,12 +193,12 @@
196
193
  --ds-nav-v-active-muted: var(--ds-text-secondary);
197
194
  --ds-nav-v-badge-bg: var(--ds-accent-primary);
198
195
  --ds-tree-active-bg: var(--ds-tab-active-bg);
199
- --ds-tree-active-text: var(--ds-accent-primary);
196
+ --ds-tree-active-text: var(--ds-accent-ink);
200
197
  --ds-tree-active-muted: var(--ds-text-muted);
201
198
  --ds-tree-active-rail: var(--ds-border-width-thick);
202
199
  --ds-sidebar-active-bg: var(--ds-sidebar-accent-subtle);
203
- --ds-sidebar-active-text: var(--ds-sidebar-accent);
204
- --ds-sidebar-active-accent: var(--ds-sidebar-accent);
200
+ --ds-sidebar-active-text: var(--ds-sidebar-accent-ink);
201
+ --ds-sidebar-active-accent: var(--ds-sidebar-accent-ink);
205
202
  --ds-sidebar-active-rail: var(--ds-border-width-thick);
206
203
  --ds-sidebar-active-image: none;
207
204
  --ds-switch-off-fill: transparent;
@@ -229,6 +226,23 @@
229
226
  --ds-sidebar-item-active: var(--ds-neutral-200);
230
227
  }
231
228
 
229
+ /* Readable colours — light mode: derived to reach their minimum contrast on this theme's grounds */
230
+ :root:not([data-mode="dark"]), [data-mode="light"] {
231
+ --ds-focus: var(--ds-accent-primary);
232
+ --ds-accent-ink: var(--ds-accent-primary);
233
+ --ds-text-muted: oklch(0.52 calc(0.0067 * var(--ds-sat-neutral)) var(--ds-hue-neutral));
234
+ --ds-text-secondary: var(--ds-neutral-600);
235
+ --ds-status-success-text: oklch(0.35 0.1000 150);
236
+ --ds-status-warning-text: oklch(0.35 0.1000 55);
237
+ --ds-status-error-text: oklch(0.35 0.1000 20);
238
+ --ds-status-info-text: oklch(0.35 0.1000 200);
239
+ --ds-text-on-primary-muted: var(--ds-text-on-primary);
240
+ --ds-sidebar-text-muted: var(--ds-text-muted);
241
+ --ds-sidebar-text-secondary: var(--ds-text-secondary);
242
+ --ds-sidebar-focus: var(--ds-focus);
243
+ --ds-sidebar-accent-ink: var(--ds-sidebar-accent);
244
+ }
245
+
232
246
  /* Dark palette overrides — dark mode */
233
247
  /* This theme defaults to light. To offer a mode switch, set data-mode="dark" on <html>. No attribute renders the default. */
234
248
  [data-mode="dark"] {
@@ -240,10 +254,7 @@
240
254
  --ds-accent-primary: var(--ds-primary-500);
241
255
  --ds-accent-primary-hover: var(--ds-primary-400);
242
256
  --ds-accent-primary-active: var(--ds-primary-300);
243
- --ds-border-focus: var(--ds-primary-500);
244
257
  --ds-ring-active: var(--ds-accent-soft);
245
- --ds-input-focus-ring: var(--ds-ring-active);
246
- --ds-shadow-focus: 0 0 0 2px var(--ds-primary-500);
247
258
  --ds-tint-strength: 0.15;
248
259
  --ds-gradient: linear-gradient(135deg, oklch(0.55 0.1300 223), oklch(0.330 0.0945 240));
249
260
  --ds-gradient-start: oklch(0.55 0.1300 223);
@@ -310,7 +321,7 @@
310
321
  --ds-status-success-bg: oklch(0.22 0.02 150);
311
322
  --ds-status-warning: oklch(0.75 0.12 55);
312
323
  --ds-status-warning-bg: oklch(0.22 0.025 55);
313
- --ds-status-warning-text: oklch(0.75 0.12 55);
324
+ --ds-status-warning-text: oklch(0.92 0.0300 55);
314
325
  --ds-status-error: oklch(0.65 0.15 20);
315
326
  --ds-status-error-bg: oklch(0.22 0.02 20);
316
327
  --ds-status-info: oklch(0.65 0.10 200);
@@ -319,6 +330,77 @@
319
330
  --ds-text-on-warning: oklch(0.350 0.1000 55);
320
331
  --ds-text-on-error: oklch(0.220 0.1000 20);
321
332
  --ds-text-on-info: oklch(0.230 0.1000 200);
333
+ --ds-focus: oklch(0.67 calc(0.1773 * var(--ds-sat-primary)) var(--ds-hue-primary));
334
+ --ds-accent-ink: oklch(0.78 calc(0.145 * var(--ds-sat-primary)) var(--ds-hue-primary));
335
+ --ds-text-muted: oklch(0.74 calc(0.0092 * var(--ds-sat-neutral)) var(--ds-hue-neutral));
336
+ --ds-text-secondary: var(--ds-neutral-300);
337
+ --ds-status-success-text: oklch(0.92 0.0300 150);
338
+ --ds-status-error-text: oklch(0.92 0.0300 20);
339
+ --ds-status-info-text: oklch(0.92 0.0300 200);
340
+ --ds-text-on-primary-muted: var(--ds-text-on-primary);
341
+ --ds-sidebar-text-muted: var(--ds-text-muted);
342
+ --ds-sidebar-text-secondary: var(--ds-text-secondary);
343
+ --ds-sidebar-focus: var(--ds-focus);
344
+ --ds-sidebar-accent-ink: oklch(0.66 calc(0.18 * var(--ds-sat-primary)) var(--ds-hue-primary));
345
+ }
346
+
347
+ /* A wrapper in the light mode inside the page switched to dark (a component given its own mode) takes its own values back */
348
+ [data-mode="light"] {
349
+ --ds-hue-primary: 250;
350
+ --ds-sat-primary: 0.8;
351
+ --ds-accent-primary: var(--ds-primary-700);
352
+ --ds-accent-primary-hover: var(--ds-primary-800);
353
+ --ds-accent-primary-active: var(--ds-primary-900);
354
+ --ds-gradient: linear-gradient(135deg, oklch(0.4 0.1320 250), oklch(0.550 0.1100 210));
355
+ --ds-gradient-start: oklch(0.4 0.1320 250);
356
+ --ds-gradient-end: oklch(0.550 0.1100 210);
357
+ --ds-text-muted-on-tint: var(--ds-neutral-600);
358
+ --ds-accent-bg: oklch(0.92 0.0300 250);
359
+ --ds-accent-text: oklch(0.35 0.1000 250);
360
+ --ds-check-bg: var(--ds-accent-primary);
361
+ --ds-check-fg: var(--ds-text-on-primary);
362
+ --ds-check-border: var(--ds-accent-primary);
363
+ --ds-palette-1-bold: oklch(0.55 0.1200 110);
364
+ --ds-palette-1-subtle: oklch(0.92 0.0300 110);
365
+ --ds-palette-1-dark: oklch(0.35 0.1000 110);
366
+ --ds-palette-1-bg: var(--ds-palette-1-subtle);
367
+ --ds-palette-1-text: var(--ds-palette-1-dark);
368
+ --ds-palette-1-chart: var(--ds-palette-1-bold);
369
+ --ds-palette-2-bold: oklch(0.54 0.1200 207.50800000000004);
370
+ --ds-palette-2-subtle: oklch(0.92 0.0300 207.50800000000004);
371
+ --ds-palette-2-dark: oklch(0.35 0.1000 207.50800000000004);
372
+ --ds-palette-2-bg: var(--ds-palette-2-subtle);
373
+ --ds-palette-2-text: var(--ds-palette-2-dark);
374
+ --ds-palette-2-chart: var(--ds-palette-2-bold);
375
+ --ds-palette-3-bold: oklch(0.55 0.1200 345.0160000000001);
376
+ --ds-palette-3-subtle: oklch(0.92 0.0300 345.0160000000001);
377
+ --ds-palette-3-dark: oklch(0.35 0.1000 345.0160000000001);
378
+ --ds-palette-3-bg: var(--ds-palette-3-subtle);
379
+ --ds-palette-3-text: var(--ds-palette-3-dark);
380
+ --ds-palette-3-chart: var(--ds-palette-3-bold);
381
+ --ds-palette-4-bold: oklch(0.55 0.1200 162.524);
382
+ --ds-palette-4-subtle: oklch(0.92 0.0300 162.524);
383
+ --ds-palette-4-dark: oklch(0.35 0.1000 162.524);
384
+ --ds-palette-4-bg: var(--ds-palette-4-subtle);
385
+ --ds-palette-4-text: var(--ds-palette-4-dark);
386
+ --ds-palette-4-chart: var(--ds-palette-4-bold);
387
+ --ds-palette-5-bold: oklch(0.55 0.1200 275.03200000000004);
388
+ --ds-palette-5-subtle: oklch(0.92 0.0300 275.03200000000004);
389
+ --ds-palette-5-dark: oklch(0.35 0.1000 275.03200000000004);
390
+ --ds-palette-5-bg: var(--ds-palette-5-subtle);
391
+ --ds-palette-5-text: var(--ds-palette-5-dark);
392
+ --ds-palette-5-chart: var(--ds-palette-5-bold);
393
+ --ds-chart-1: var(--ds-accent-primary);
394
+ --ds-chart-1-soft: color-mix(in oklch, var(--ds-accent-primary) 30%, transparent);
395
+ --ds-status-success: oklch(0.55 0.12 150);
396
+ --ds-status-success-bg: oklch(0.92 0.03 150);
397
+ --ds-status-warning: oklch(0.70 0.12 55);
398
+ --ds-status-warning-bg: oklch(0.92 0.035 55);
399
+ --ds-status-error: oklch(0.55 0.15 20);
400
+ --ds-status-error-bg: oklch(0.92 0.03 20);
401
+ --ds-status-info: oklch(0.55 0.10 200);
402
+ --ds-status-info-bg: oklch(0.92 0.025 200);
403
+ --ds-text-on-warning: oklch(0.300 0.1000 55);
322
404
  }
323
405
 
324
406
  /* Dark portals on a light page (a dark sidebar's tooltips and menus carry data-ds-overlay="dark") */
@@ -331,7 +413,7 @@
331
413
  --ds-bg-emphasis: var(--ds-neutral-600);
332
414
  --ds-text-primary: var(--ds-neutral-50);
333
415
  --ds-text-secondary: var(--ds-neutral-300);
334
- --ds-text-muted: var(--ds-neutral-400);
416
+ --ds-text-muted: oklch(0.74 calc(0.0092 * var(--ds-sat-neutral)) var(--ds-hue-neutral));
335
417
  --ds-text-on-success: oklch(0.240 0.1000 150);
336
418
  --ds-text-on-warning: oklch(0.350 0.1000 55);
337
419
  --ds-text-on-error: oklch(0.220 0.1000 20);
@@ -339,12 +421,11 @@
339
421
  --ds-border-default: var(--ds-neutral-600);
340
422
  --ds-border-subtle: var(--ds-neutral-700);
341
423
  --ds-border-strong: var(--ds-neutral-400);
342
- --ds-border-focus: var(--ds-primary-500);
343
424
  --ds-status-success: oklch(0.65 0.12 150);
344
425
  --ds-status-success-bg: oklch(0.22 0.02 150);
345
426
  --ds-status-warning: oklch(0.75 0.12 55);
346
427
  --ds-status-warning-bg: oklch(0.22 0.025 55);
347
- --ds-status-warning-text: oklch(0.75 0.12 55);
428
+ --ds-status-warning-text: oklch(0.92 0.0300 55);
348
429
  --ds-status-error: oklch(0.65 0.15 20);
349
430
  --ds-status-error-bg: oklch(0.22 0.02 20);
350
431
  --ds-status-info: oklch(0.65 0.10 200);
@@ -358,8 +439,6 @@
358
439
  --ds-input-border: var(--ds-neutral-600);
359
440
  --ds-input-border-hover: var(--ds-neutral-500);
360
441
  --ds-control-edge-strong: oklch(0.645 calc(0.008 * var(--ds-sat-neutral)) var(--ds-hue-neutral));
361
- --ds-input-focus-ring: var(--ds-ring-active);
362
- --ds-shadow-focus: 0 0 0 2px var(--ds-primary-500);
363
442
  --ds-accent-primary: var(--ds-primary-500);
364
443
  --ds-accent-primary-hover: var(--ds-primary-400);
365
444
  --ds-accent-primary-active: var(--ds-primary-300);
@@ -375,7 +454,7 @@
375
454
  --ds-accent-subtle: color-mix(in srgb, var(--ds-accent-primary) 10%, transparent);
376
455
  --ds-accent-muted: color-mix(in srgb, var(--ds-accent-primary) 20%, transparent);
377
456
  --ds-accent-soft: color-mix(in srgb, var(--ds-accent-primary) 30%, transparent);
378
- --ds-accent-subtle-text: var(--ds-accent-primary);
457
+ --ds-accent-subtle-text: var(--ds-accent-text, var(--ds-accent-primary));
379
458
  --ds-accent-bg: oklch(0.35 0.1000 223);
380
459
  --ds-accent-text: oklch(0.92 0.0300 223);
381
460
  --ds-check-bg: var(--ds-primary-400);
@@ -391,7 +470,7 @@
391
470
  --ds-nav-h-track-gap: 0px;
392
471
  --ds-nav-h-badge-bg: var(--ds-accent-primary);
393
472
  --ds-nav-v-active-bg: var(--ds-tab-active-bg);
394
- --ds-nav-v-active-text: var(--ds-accent-primary);
473
+ --ds-nav-v-active-text: var(--ds-accent-ink);
395
474
  --ds-nav-v-active-rail: var(--ds-border-width-thick);
396
475
  --ds-nav-v-item-radius: var(--ds-radius-sm);
397
476
  --ds-nav-v-track-border: 0px;
@@ -399,16 +478,22 @@
399
478
  --ds-nav-v-active-muted: var(--ds-text-secondary);
400
479
  --ds-nav-v-badge-bg: var(--ds-accent-primary);
401
480
  --ds-tree-active-bg: var(--ds-tab-active-bg);
402
- --ds-tree-active-text: var(--ds-accent-primary);
481
+ --ds-tree-active-text: var(--ds-accent-ink);
403
482
  --ds-tree-active-muted: var(--ds-text-muted);
404
483
  --ds-tree-active-rail: var(--ds-border-width-thick);
405
484
  --ds-sidebar-active-bg: var(--ds-sidebar-accent-subtle);
406
- --ds-sidebar-active-text: var(--ds-sidebar-accent);
407
- --ds-sidebar-active-accent: var(--ds-sidebar-accent);
485
+ --ds-sidebar-active-text: var(--ds-sidebar-accent-ink);
486
+ --ds-sidebar-active-accent: var(--ds-sidebar-accent-ink);
408
487
  --ds-sidebar-active-rail: var(--ds-border-width-thick);
409
488
  --ds-sidebar-active-image: none;
410
489
  --ds-switch-off-fill: transparent;
411
490
  --ds-switch-off-edge: var(--ds-control-edge-strong);
412
491
  --ds-switch-off-knob: color-mix(in oklab, var(--ds-control-edge-strong) var(--ds-switch-knob-share, 100%), var(--ds-bg-surface));
413
492
  --ds-check-gradient: none;
493
+ --ds-focus: oklch(0.67 calc(0.1773 * var(--ds-sat-primary)) var(--ds-hue-primary));
494
+ --ds-accent-ink: oklch(0.78 calc(0.145 * var(--ds-sat-primary)) var(--ds-hue-primary));
495
+ --ds-status-success-text: oklch(0.92 0.0300 150);
496
+ --ds-status-error-text: oklch(0.92 0.0300 20);
497
+ --ds-status-info-text: oklch(0.92 0.0300 200);
498
+ --ds-text-on-primary-muted: var(--ds-text-on-primary);
414
499
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gridsmith-ui",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "description": "Gridsmith component library — React components and charts with design tokens and a CSS custom property theming engine",
5
5
  "type": "module",
6
6
  "sideEffects": [