@mortenbrudvik/waveui 0.15.0 → 0.17.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 (188) hide show
  1. package/README.md +339 -40
  2. package/dist/components/data-display/List.cjs +1 -1
  3. package/dist/components/data-display/List.cjs.map +1 -1
  4. package/dist/components/data-display/List.mjs +405 -219
  5. package/dist/components/data-display/List.mjs.map +1 -1
  6. package/dist/components/data-display/List.registry.cjs +1 -1
  7. package/dist/components/data-display/List.registry.cjs.map +1 -1
  8. package/dist/components/data-display/List.registry.mjs +12 -6
  9. package/dist/components/data-display/List.registry.mjs.map +1 -1
  10. package/dist/components/input/Combobox.cjs +1 -1
  11. package/dist/components/input/Combobox.cjs.map +1 -1
  12. package/dist/components/input/Combobox.mjs +163 -148
  13. package/dist/components/input/Combobox.mjs.map +1 -1
  14. package/dist/components/input/Dropdown.cjs +1 -1
  15. package/dist/components/input/Dropdown.cjs.map +1 -1
  16. package/dist/components/input/Dropdown.mjs +132 -117
  17. package/dist/components/input/Dropdown.mjs.map +1 -1
  18. package/dist/components/input/Label.cjs +1 -1
  19. package/dist/components/input/Label.cjs.map +1 -1
  20. package/dist/components/input/Label.mjs +1 -0
  21. package/dist/components/input/Label.mjs.map +1 -1
  22. package/dist/components/input/Listbox.cjs +1 -1
  23. package/dist/components/input/Listbox.cjs.map +1 -1
  24. package/dist/components/input/Listbox.mjs +90 -78
  25. package/dist/components/input/Listbox.mjs.map +1 -1
  26. package/dist/components/input/Option.cjs +1 -1
  27. package/dist/components/input/Option.cjs.map +1 -1
  28. package/dist/components/input/Option.data.cjs +2 -0
  29. package/dist/components/input/Option.data.cjs.map +1 -0
  30. package/dist/components/input/Option.data.mjs +114 -0
  31. package/dist/components/input/Option.data.mjs.map +1 -0
  32. package/dist/components/input/Option.mjs +21 -17
  33. package/dist/components/input/Option.mjs.map +1 -1
  34. package/dist/components/layout/FlatTree.cjs +2 -0
  35. package/dist/components/layout/FlatTree.cjs.map +1 -0
  36. package/dist/components/layout/FlatTree.context.cjs +2 -0
  37. package/dist/components/layout/FlatTree.context.cjs.map +1 -0
  38. package/dist/components/layout/FlatTree.context.mjs +20 -0
  39. package/dist/components/layout/FlatTree.context.mjs.map +1 -0
  40. package/dist/components/layout/FlatTree.item.cjs +2 -0
  41. package/dist/components/layout/FlatTree.item.cjs.map +1 -0
  42. package/dist/components/layout/FlatTree.item.mjs +90 -0
  43. package/dist/components/layout/FlatTree.item.mjs.map +1 -0
  44. package/dist/components/layout/FlatTree.mjs +276 -0
  45. package/dist/components/layout/FlatTree.mjs.map +1 -0
  46. package/dist/components/layout/Tree.core.cjs +1 -1
  47. package/dist/components/layout/Tree.core.cjs.map +1 -1
  48. package/dist/components/layout/Tree.core.mjs +166 -165
  49. package/dist/components/layout/Tree.core.mjs.map +1 -1
  50. package/dist/components/layout/Tree.selection.cjs +1 -1
  51. package/dist/components/layout/Tree.selection.cjs.map +1 -1
  52. package/dist/components/layout/Tree.selection.mjs +11 -57
  53. package/dist/components/layout/Tree.selection.mjs.map +1 -1
  54. package/dist/components/layout/useFlatTree.cjs +2 -0
  55. package/dist/components/layout/useFlatTree.cjs.map +1 -0
  56. package/dist/components/layout/useFlatTree.mjs +83 -0
  57. package/dist/components/layout/useFlatTree.mjs.map +1 -0
  58. package/dist/components/portal/Portal.cjs +1 -1
  59. package/dist/components/portal/Portal.cjs.map +1 -1
  60. package/dist/components/portal/Portal.mjs +12 -11
  61. package/dist/components/portal/Portal.mjs.map +1 -1
  62. package/dist/components/provider/WaveProvider.cjs +1 -1
  63. package/dist/components/provider/WaveProvider.cjs.map +1 -1
  64. package/dist/components/provider/WaveProvider.mjs +59 -35
  65. package/dist/components/provider/WaveProvider.mjs.map +1 -1
  66. package/dist/components/table/DataGrid.cjs +1 -1
  67. package/dist/components/table/DataGrid.cjs.map +1 -1
  68. package/dist/components/table/DataGrid.context.cjs +2 -0
  69. package/dist/components/table/DataGrid.context.cjs.map +1 -0
  70. package/dist/components/table/DataGrid.context.mjs +74 -0
  71. package/dist/components/table/DataGrid.context.mjs.map +1 -0
  72. package/dist/components/table/DataGrid.header.cjs +2 -0
  73. package/dist/components/table/DataGrid.header.cjs.map +1 -0
  74. package/dist/components/table/DataGrid.header.mjs +168 -0
  75. package/dist/components/table/DataGrid.header.mjs.map +1 -0
  76. package/dist/components/table/DataGrid.mjs +488 -591
  77. package/dist/components/table/DataGrid.mjs.map +1 -1
  78. package/dist/components/table/DataGrid.sizing.cjs +2 -0
  79. package/dist/components/table/DataGrid.sizing.cjs.map +1 -0
  80. package/dist/components/table/DataGrid.sizing.mjs +187 -0
  81. package/dist/components/table/DataGrid.sizing.mjs.map +1 -0
  82. package/dist/components/table/DataGrid.store.cjs +2 -0
  83. package/dist/components/table/DataGrid.store.cjs.map +1 -0
  84. package/dist/components/table/DataGrid.store.mjs +108 -0
  85. package/dist/components/table/DataGrid.store.mjs.map +1 -0
  86. package/dist/components/table/DataGrid.window.cjs +2 -0
  87. package/dist/components/table/DataGrid.window.cjs.map +1 -0
  88. package/dist/components/table/DataGrid.window.mjs +165 -0
  89. package/dist/components/table/DataGrid.window.mjs.map +1 -0
  90. package/dist/components/table/Table.cjs +1 -1
  91. package/dist/components/table/Table.cjs.map +1 -1
  92. package/dist/components/table/Table.mjs +74 -72
  93. package/dist/components/table/Table.mjs.map +1 -1
  94. package/dist/components/table/Table.resize.cjs +2 -0
  95. package/dist/components/table/Table.resize.cjs.map +1 -0
  96. package/dist/components/table/Table.resize.mjs +98 -0
  97. package/dist/components/table/Table.resize.mjs.map +1 -0
  98. package/dist/components/table/useGridNavigation.cjs +1 -1
  99. package/dist/components/table/useGridNavigation.cjs.map +1 -1
  100. package/dist/components/table/useGridNavigation.mjs +343 -140
  101. package/dist/components/table/useGridNavigation.mjs.map +1 -1
  102. package/dist/components/table/useTableColumnSizing.cjs +2 -0
  103. package/dist/components/table/useTableColumnSizing.cjs.map +1 -0
  104. package/dist/components/table/useTableColumnSizing.mjs +76 -0
  105. package/dist/components/table/useTableColumnSizing.mjs.map +1 -0
  106. package/dist/components/table/useTableFeatures.cjs +2 -0
  107. package/dist/components/table/useTableFeatures.cjs.map +1 -0
  108. package/dist/components/table/useTableFeatures.mjs +110 -0
  109. package/dist/components/table/useTableFeatures.mjs.map +1 -0
  110. package/dist/components/table/useTableSelection.cjs +2 -0
  111. package/dist/components/table/useTableSelection.cjs.map +1 -0
  112. package/dist/components/table/useTableSelection.mjs +39 -0
  113. package/dist/components/table/useTableSelection.mjs.map +1 -0
  114. package/dist/components/table/useTableSort.cjs +2 -0
  115. package/dist/components/table/useTableSort.cjs.map +1 -0
  116. package/dist/components/table/useTableSort.mjs +58 -0
  117. package/dist/components/table/useTableSort.mjs.map +1 -0
  118. package/dist/components/typography/Text.cjs +1 -1
  119. package/dist/components/typography/Text.cjs.map +1 -1
  120. package/dist/components/typography/Text.mjs +11 -7
  121. package/dist/components/typography/Text.mjs.map +1 -1
  122. package/dist/hooks/useActiveDescendant.cjs +1 -1
  123. package/dist/hooks/useActiveDescendant.cjs.map +1 -1
  124. package/dist/hooks/useActiveDescendant.mjs +33 -25
  125. package/dist/hooks/useActiveDescendant.mjs.map +1 -1
  126. package/dist/hooks/useListbox.cjs +1 -1
  127. package/dist/hooks/useListbox.cjs.map +1 -1
  128. package/dist/hooks/useListbox.mjs +140 -130
  129. package/dist/hooks/useListbox.mjs.map +1 -1
  130. package/dist/hooks/useRovingTabIndex.cjs +1 -1
  131. package/dist/hooks/useRovingTabIndex.cjs.map +1 -1
  132. package/dist/hooks/useRovingTabIndex.mjs +1 -1
  133. package/dist/hooks/useRovingTabIndex.mjs.map +1 -1
  134. package/dist/hooks/useSelection.cjs +2 -0
  135. package/dist/hooks/useSelection.cjs.map +1 -0
  136. package/dist/hooks/useSelection.mjs +57 -0
  137. package/dist/hooks/useSelection.mjs.map +1 -0
  138. package/dist/hooks/useVirtualWindow.cjs +2 -0
  139. package/dist/hooks/useVirtualWindow.cjs.map +1 -0
  140. package/dist/hooks/useVirtualWindow.mjs +102 -0
  141. package/dist/hooks/useVirtualWindow.mjs.map +1 -0
  142. package/dist/index.cjs +1 -1
  143. package/dist/index.d.cts +1799 -63
  144. package/dist/index.d.ts +1799 -63
  145. package/dist/index.mjs +150 -136
  146. package/dist/lib/brand.cjs +2 -0
  147. package/dist/lib/brand.cjs.map +1 -0
  148. package/dist/lib/brand.mjs +358 -0
  149. package/dist/lib/brand.mjs.map +1 -0
  150. package/dist/lib/classNames.cjs +1 -1
  151. package/dist/lib/classNames.cjs.map +1 -1
  152. package/dist/lib/classNames.mjs +68 -49
  153. package/dist/lib/classNames.mjs.map +1 -1
  154. package/dist/lib/cn.cjs +1 -1
  155. package/dist/lib/cn.cjs.map +1 -1
  156. package/dist/lib/cn.mjs +5 -1
  157. package/dist/lib/cn.mjs.map +1 -1
  158. package/dist/lib/columnSizing.cjs +2 -0
  159. package/dist/lib/columnSizing.cjs.map +1 -0
  160. package/dist/lib/columnSizing.mjs +27 -0
  161. package/dist/lib/columnSizing.mjs.map +1 -0
  162. package/dist/lib/flatTree.cjs +2 -0
  163. package/dist/lib/flatTree.cjs.map +1 -0
  164. package/dist/lib/flatTree.mjs +118 -0
  165. package/dist/lib/flatTree.mjs.map +1 -0
  166. package/dist/lib/selection.cjs +2 -0
  167. package/dist/lib/selection.cjs.map +1 -0
  168. package/dist/lib/selection.mjs +28 -0
  169. package/dist/lib/selection.mjs.map +1 -0
  170. package/dist/lib/tokens.cjs +2 -0
  171. package/dist/lib/tokens.cjs.map +1 -0
  172. package/dist/lib/tokens.mjs +43 -0
  173. package/dist/lib/tokens.mjs.map +1 -0
  174. package/dist/lib/treeCascade.cjs +2 -0
  175. package/dist/lib/treeCascade.cjs.map +1 -0
  176. package/dist/lib/treeCascade.mjs +52 -0
  177. package/dist/lib/treeCascade.mjs.map +1 -0
  178. package/dist/lib/virtual.cjs +2 -0
  179. package/dist/lib/virtual.cjs.map +1 -0
  180. package/dist/lib/virtual.mjs +54 -0
  181. package/dist/lib/virtual.mjs.map +1 -0
  182. package/dist/lib/waveTokens.cjs +2 -0
  183. package/dist/lib/waveTokens.cjs.map +1 -0
  184. package/dist/lib/waveTokens.mjs +24 -0
  185. package/dist/lib/waveTokens.mjs.map +1 -0
  186. package/dist/styles.css +1 -1
  187. package/package.json +3 -1
  188. package/src/styles/tokens.css +210 -10
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flatTree.cjs","names":["buildFlatTreeIndex","issues","drafts","items","item","value","draft","state","start","path","current","repeated","roots","childValues","siblings","byValue","queue","at","children","child","level","childAt","ordered","visibleFlatItems","visible","stack","index","record","open","expanded","flatTreeForest","nodes","node"],"sources":["../../src/lib/flatTree.ts"],"sourcesContent":["// The pure model behind `useFlatTree` and `FlatTree`: server-safe, no React import. A flat list of\n// items with `parentValue` links becomes an index (one pass, no recursion), the visible rows for an\n// expanded set (a walk that enters only expanded branches) and a `TreeNode` forest for the check\n// cascade of `treeCascade.ts`. Every walk is iterative, so a chain thousands of levels deep cannot\n// overflow the stack.\nimport type { TreeNode } from './treeCascade';\n\n/** One item of a flat tree: `parentValue` places it, items are listed in any order. */\nexport interface FlatTreeItemData {\n /** The item's identity; it must be unique among the items (a later duplicate is ignored). */\n value: string;\n /** The `value` of the item this one is nested in; absent for a root. */\n parentValue?: string;\n /**\n * `'branch'` marks an item that can expand even while it has no child items (children loaded\n * on demand). An item with child items is a branch whatever its type says.\n */\n itemType?: 'leaf' | 'branch';\n /** The text the item shows. */\n label?: string;\n /**\n * Whether the item is disabled. `FlatTree` reads it (the keys and typeahead skip the item, it is\n * not the tab stop, and the user cannot activate, expand or check it); the model ignores it:\n * `expand`, `collapse`, `toggle` and `setChecked` change a disabled item too, and a check of its\n * parent includes it.\n */\n disabled?: boolean;\n}\n\n/**\n * One row of the visible list: an item under expanded branches only, with the facts a row needs\n * for its tree semantics. A row is a branch when `hasChildren` is true or when\n * `item.itemType === 'branch'`; `expanded` is true only for a branch whose value is in the\n * expanded set (so a childless `'branch'` item can be expanded).\n */\nexport interface VisibleFlatItem {\n /** The item data, as passed in. */\n item: FlatTreeItemData;\n /** The depth, 1 for a root (`aria-level`). */\n level: number;\n /** The 1-based place among its siblings, in the order of `items` (`aria-posinset`). */\n position: number;\n /** The number of siblings, itself included (`aria-setsize`). */\n setSize: number;\n /** The value of the parent as indexed (`undefined` for a root, an unknown parent included). */\n parentValue: string | undefined;\n /** Whether other items are nested in it. */\n hasChildren: boolean;\n /** Whether it can expand: `hasChildren`, or `item.itemType === 'branch'` (`aria-expanded` is set for these). */\n isBranch: boolean;\n /** Whether it is a branch in the expanded set. */\n expanded: boolean;\n /** The place in the visible list, 0-based. */\n index: number;\n}\n\n/** What the index knows about one item. */\nexport interface FlatTreeNodeRecord {\n /** The item data, as passed in. */\n item: FlatTreeItemData;\n /** The place of the item in `items`, 0-based. */\n index: number;\n /** The value of the parent as indexed: `undefined` for a root, also when the parent was unknown or the link was cut as a cycle. */\n parentValue: string | undefined;\n /** The depth, 1 for a root. */\n level: number;\n /** The 1-based place among its siblings. */\n position: number;\n /** The number of siblings, itself included. */\n setSize: number;\n /** The values of the items nested in it, in the order of `items`. */\n children: readonly string[];\n /** Whether other items are nested in it (`children` is not empty). */\n hasChildren: boolean;\n /** Whether it can expand: `hasChildren`, or `item.itemType === 'branch'`. */\n isBranch: boolean;\n}\n\n/** A problem the index found in the items and repaired. Stable: `useFlatTree` reports these in development. */\nexport type FlatTreeIssue =\n | {\n /** A later item with a value an earlier one has: it is ignored (the first is kept). */\n kind: 'duplicate-value';\n value: string;\n /** The place of the ignored item in `items`. */\n index: number;\n }\n | {\n /** An item whose `parentValue` matches no item: it is indexed as a root. */\n kind: 'unknown-parent';\n value: string;\n parentValue: string;\n }\n | {\n /** A loop of parents: the link of this value to its parent is cut, so it is a root. */\n kind: 'cycle';\n value: string;\n };\n\n/** The indexed items of a flat tree, from `buildFlatTreeIndex`. */\nexport interface FlatTreeIndex {\n /** Every item by value (one record per value). */\n byValue: Map<string, FlatTreeNodeRecord>;\n /** The values of the roots, in the order of `items`. */\n roots: readonly string[];\n /** What was repaired, in the order it was found: duplicates first, then unknown parents, then cycles. */\n issues: readonly FlatTreeIssue[];\n}\n\ninterface Draft {\n item: FlatTreeItemData;\n index: number;\n parent: string | undefined;\n}\n\n/**\n * Indexes `items` in one pass over them (linear time, no recursion). Repairs, each reported as an\n * issue: a repeated value keeps its first item; an item whose parent is unknown becomes a root;\n * a loop of parents is cut at the first of its values met by the walk up from the first item, in\n * `items` order, whose parent chain reaches the loop (an item outside the loop that leads into it\n * can start that walk: `[x→b, a→b, b→a]` cuts at `b`), and that value becomes a root. Siblings\n * keep the order of `items`.\n */\nexport function buildFlatTreeIndex(items: readonly FlatTreeItemData[]): FlatTreeIndex {\n const issues: FlatTreeIssue[] = [];\n const drafts = new Map<string, Draft>();\n items.forEach((item, index) => {\n if (drafts.has(item.value)) {\n issues.push({ kind: 'duplicate-value', value: item.value, index });\n return;\n }\n drafts.set(item.value, { item, index, parent: item.parentValue });\n });\n\n for (const [value, draft] of drafts) {\n if (draft.parent !== undefined && !drafts.has(draft.parent)) {\n issues.push({ kind: 'unknown-parent', value, parentValue: draft.parent });\n draft.parent = undefined;\n }\n }\n\n // Colour walk: 1 while on the current path, 2 once settled. A walk that reaches a value of its\n // own path has found a loop; cutting that value's parent link ends it.\n const state = new Map<string, 1 | 2>();\n for (const start of drafts.keys()) {\n if (state.has(start)) continue;\n const path: string[] = [];\n let current: string | undefined = start;\n while (current !== undefined && !state.has(current)) {\n state.set(current, 1);\n path.push(current);\n current = drafts.get(current)?.parent;\n }\n if (current !== undefined && state.get(current) === 1) {\n issues.push({ kind: 'cycle', value: current });\n const repeated = drafts.get(current);\n if (repeated) repeated.parent = undefined;\n }\n for (const value of path) state.set(value, 2);\n }\n\n const roots: string[] = [];\n const childValues = new Map<string, string[]>();\n for (const [value, draft] of drafts) {\n if (draft.parent === undefined) {\n roots.push(value);\n continue;\n }\n const siblings = childValues.get(draft.parent);\n if (siblings) siblings.push(value);\n else childValues.set(draft.parent, [value]);\n }\n\n const byValue = new Map<string, FlatTreeNodeRecord>();\n const queue: Array<{ value: string; level: number; position: number; setSize: number }> = [];\n roots.forEach((value, at) =>\n queue.push({ value, level: 1, position: at + 1, setSize: roots.length }),\n );\n // Every item is reachable from a root now: the loops are cut and the unknown parents are roots.\n for (let at = 0; at < queue.length; at += 1) {\n const { value, level, position, setSize } = queue[at];\n const draft = drafts.get(value) as Draft;\n const children = childValues.get(value) ?? [];\n byValue.set(value, {\n item: draft.item,\n index: draft.index,\n parentValue: draft.parent,\n level,\n position,\n setSize,\n children,\n hasChildren: children.length > 0,\n isBranch: children.length > 0 || draft.item.itemType === 'branch',\n });\n children.forEach((child, childAt) =>\n queue.push({\n value: child,\n level: level + 1,\n position: childAt + 1,\n setSize: children.length,\n }),\n );\n }\n // `byValue` is filled in breadth-first order; present it in the order of `items`.\n const ordered = new Map<string, FlatTreeNodeRecord>();\n for (const value of drafts.keys()) ordered.set(value, byValue.get(value) as FlatTreeNodeRecord);\n\n return { byValue: ordered, roots, issues };\n}\n\n/**\n * The rows visible with `expanded`: the roots, and the children of every branch in the set, in\n * tree order. Only expanded branches are entered, so the cost is the number of rows returned plus\n * the depth of the stack, never the number of items. A value in `expanded` that is no branch (a\n * leaf, or no item at all) has no effect.\n */\nexport function visibleFlatItems(\n index: FlatTreeIndex,\n expanded: ReadonlySet<string>,\n): readonly VisibleFlatItem[] {\n const visible: VisibleFlatItem[] = [];\n const stack: string[] = [];\n for (let at = index.roots.length - 1; at >= 0; at -= 1) stack.push(index.roots[at]);\n while (stack.length > 0) {\n const record = index.byValue.get(stack.pop() as string);\n if (!record) continue;\n const open = record.isBranch && expanded.has(record.item.value);\n visible.push({\n item: record.item,\n level: record.level,\n position: record.position,\n setSize: record.setSize,\n parentValue: record.parentValue,\n hasChildren: record.hasChildren,\n isBranch: record.isBranch,\n expanded: open,\n index: visible.length,\n });\n if (open) {\n for (let at = record.children.length - 1; at >= 0; at -= 1) stack.push(record.children[at]);\n }\n }\n return visible;\n}\n\n/**\n * The items as a `TreeNode` forest (one node per indexed item, children in the order of `items`),\n * the input of `computeCheckStates` and `toggleCheck`. Built without recursion; walking the result\n * with those recursive functions is as deep as the tree is.\n */\nexport function flatTreeForest(index: FlatTreeIndex): TreeNode[] {\n const nodes = new Map<string, TreeNode>();\n for (const value of index.byValue.keys()) nodes.set(value, { value, children: [] });\n for (const [value, record] of index.byValue) {\n const node = nodes.get(value) as TreeNode;\n for (const child of record.children) node.children.push(nodes.get(child) as TreeNode);\n }\n return index.roots.map((value) => nodes.get(value) as TreeNode);\n}\n"],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+ //#region src/lib/flatTree.ts
2
+ function e(e) {
3
+ let t = [], n = /* @__PURE__ */ new Map();
4
+ e.forEach((e, r) => {
5
+ if (n.has(e.value)) {
6
+ t.push({
7
+ kind: "duplicate-value",
8
+ value: e.value,
9
+ index: r
10
+ });
11
+ return;
12
+ }
13
+ n.set(e.value, {
14
+ item: e,
15
+ index: r,
16
+ parent: e.parentValue
17
+ });
18
+ });
19
+ for (let [e, r] of n) r.parent !== void 0 && !n.has(r.parent) && (t.push({
20
+ kind: "unknown-parent",
21
+ value: e,
22
+ parentValue: r.parent
23
+ }), r.parent = void 0);
24
+ let r = /* @__PURE__ */ new Map();
25
+ for (let e of n.keys()) {
26
+ if (r.has(e)) continue;
27
+ let i = [], a = e;
28
+ for (; a !== void 0 && !r.has(a);) r.set(a, 1), i.push(a), a = n.get(a)?.parent;
29
+ if (a !== void 0 && r.get(a) === 1) {
30
+ t.push({
31
+ kind: "cycle",
32
+ value: a
33
+ });
34
+ let e = n.get(a);
35
+ e && (e.parent = void 0);
36
+ }
37
+ for (let e of i) r.set(e, 2);
38
+ }
39
+ let i = [], a = /* @__PURE__ */ new Map();
40
+ for (let [e, t] of n) {
41
+ if (t.parent === void 0) {
42
+ i.push(e);
43
+ continue;
44
+ }
45
+ let n = a.get(t.parent);
46
+ n ? n.push(e) : a.set(t.parent, [e]);
47
+ }
48
+ let o = /* @__PURE__ */ new Map(), s = [];
49
+ i.forEach((e, t) => s.push({
50
+ value: e,
51
+ level: 1,
52
+ position: t + 1,
53
+ setSize: i.length
54
+ }));
55
+ for (let e = 0; e < s.length; e += 1) {
56
+ let { value: t, level: r, position: i, setSize: c } = s[e], l = n.get(t), u = a.get(t) ?? [];
57
+ o.set(t, {
58
+ item: l.item,
59
+ index: l.index,
60
+ parentValue: l.parent,
61
+ level: r,
62
+ position: i,
63
+ setSize: c,
64
+ children: u,
65
+ hasChildren: u.length > 0,
66
+ isBranch: u.length > 0 || l.item.itemType === "branch"
67
+ }), u.forEach((e, t) => s.push({
68
+ value: e,
69
+ level: r + 1,
70
+ position: t + 1,
71
+ setSize: u.length
72
+ }));
73
+ }
74
+ let c = /* @__PURE__ */ new Map();
75
+ for (let e of n.keys()) c.set(e, o.get(e));
76
+ return {
77
+ byValue: c,
78
+ roots: i,
79
+ issues: t
80
+ };
81
+ }
82
+ function t(e, t) {
83
+ let n = [], r = [];
84
+ for (let t = e.roots.length - 1; t >= 0; --t) r.push(e.roots[t]);
85
+ for (; r.length > 0;) {
86
+ let i = e.byValue.get(r.pop());
87
+ if (!i) continue;
88
+ let a = i.isBranch && t.has(i.item.value);
89
+ if (n.push({
90
+ item: i.item,
91
+ level: i.level,
92
+ position: i.position,
93
+ setSize: i.setSize,
94
+ parentValue: i.parentValue,
95
+ hasChildren: i.hasChildren,
96
+ isBranch: i.isBranch,
97
+ expanded: a,
98
+ index: n.length
99
+ }), a) for (let e = i.children.length - 1; e >= 0; --e) r.push(i.children[e]);
100
+ }
101
+ return n;
102
+ }
103
+ function n(e) {
104
+ let t = /* @__PURE__ */ new Map();
105
+ for (let n of e.byValue.keys()) t.set(n, {
106
+ value: n,
107
+ children: []
108
+ });
109
+ for (let [n, r] of e.byValue) {
110
+ let e = t.get(n);
111
+ for (let n of r.children) e.children.push(t.get(n));
112
+ }
113
+ return e.roots.map((e) => t.get(e));
114
+ }
115
+ //#endregion
116
+ export { e as buildFlatTreeIndex, n as flatTreeForest, t as visibleFlatItems };
117
+
118
+ //# sourceMappingURL=flatTree.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flatTree.mjs","names":["buildFlatTreeIndex","issues","drafts","item","value","draft","state","start","path","current","repeated","roots","childValues","siblings","byValue","queue","at","children","child","level","childAt","ordered","visibleFlatItems","visible","stack","index","record","open","expanded","flatTreeForest","nodes","node"],"sources":["../../src/lib/flatTree.ts"],"sourcesContent":["// The pure model behind `useFlatTree` and `FlatTree`: server-safe, no React import. A flat list of\n// items with `parentValue` links becomes an index (one pass, no recursion), the visible rows for an\n// expanded set (a walk that enters only expanded branches) and a `TreeNode` forest for the check\n// cascade of `treeCascade.ts`. Every walk is iterative, so a chain thousands of levels deep cannot\n// overflow the stack.\nimport type { TreeNode } from './treeCascade';\n\n/** One item of a flat tree: `parentValue` places it, items are listed in any order. */\nexport interface FlatTreeItemData {\n /** The item's identity; it must be unique among the items (a later duplicate is ignored). */\n value: string;\n /** The `value` of the item this one is nested in; absent for a root. */\n parentValue?: string;\n /**\n * `'branch'` marks an item that can expand even while it has no child items (children loaded\n * on demand). An item with child items is a branch whatever its type says.\n */\n itemType?: 'leaf' | 'branch';\n /** The text the item shows. */\n label?: string;\n /**\n * Whether the item is disabled. `FlatTree` reads it (the keys and typeahead skip the item, it is\n * not the tab stop, and the user cannot activate, expand or check it); the model ignores it:\n * `expand`, `collapse`, `toggle` and `setChecked` change a disabled item too, and a check of its\n * parent includes it.\n */\n disabled?: boolean;\n}\n\n/**\n * One row of the visible list: an item under expanded branches only, with the facts a row needs\n * for its tree semantics. A row is a branch when `hasChildren` is true or when\n * `item.itemType === 'branch'`; `expanded` is true only for a branch whose value is in the\n * expanded set (so a childless `'branch'` item can be expanded).\n */\nexport interface VisibleFlatItem {\n /** The item data, as passed in. */\n item: FlatTreeItemData;\n /** The depth, 1 for a root (`aria-level`). */\n level: number;\n /** The 1-based place among its siblings, in the order of `items` (`aria-posinset`). */\n position: number;\n /** The number of siblings, itself included (`aria-setsize`). */\n setSize: number;\n /** The value of the parent as indexed (`undefined` for a root, an unknown parent included). */\n parentValue: string | undefined;\n /** Whether other items are nested in it. */\n hasChildren: boolean;\n /** Whether it can expand: `hasChildren`, or `item.itemType === 'branch'` (`aria-expanded` is set for these). */\n isBranch: boolean;\n /** Whether it is a branch in the expanded set. */\n expanded: boolean;\n /** The place in the visible list, 0-based. */\n index: number;\n}\n\n/** What the index knows about one item. */\nexport interface FlatTreeNodeRecord {\n /** The item data, as passed in. */\n item: FlatTreeItemData;\n /** The place of the item in `items`, 0-based. */\n index: number;\n /** The value of the parent as indexed: `undefined` for a root, also when the parent was unknown or the link was cut as a cycle. */\n parentValue: string | undefined;\n /** The depth, 1 for a root. */\n level: number;\n /** The 1-based place among its siblings. */\n position: number;\n /** The number of siblings, itself included. */\n setSize: number;\n /** The values of the items nested in it, in the order of `items`. */\n children: readonly string[];\n /** Whether other items are nested in it (`children` is not empty). */\n hasChildren: boolean;\n /** Whether it can expand: `hasChildren`, or `item.itemType === 'branch'`. */\n isBranch: boolean;\n}\n\n/** A problem the index found in the items and repaired. Stable: `useFlatTree` reports these in development. */\nexport type FlatTreeIssue =\n | {\n /** A later item with a value an earlier one has: it is ignored (the first is kept). */\n kind: 'duplicate-value';\n value: string;\n /** The place of the ignored item in `items`. */\n index: number;\n }\n | {\n /** An item whose `parentValue` matches no item: it is indexed as a root. */\n kind: 'unknown-parent';\n value: string;\n parentValue: string;\n }\n | {\n /** A loop of parents: the link of this value to its parent is cut, so it is a root. */\n kind: 'cycle';\n value: string;\n };\n\n/** The indexed items of a flat tree, from `buildFlatTreeIndex`. */\nexport interface FlatTreeIndex {\n /** Every item by value (one record per value). */\n byValue: Map<string, FlatTreeNodeRecord>;\n /** The values of the roots, in the order of `items`. */\n roots: readonly string[];\n /** What was repaired, in the order it was found: duplicates first, then unknown parents, then cycles. */\n issues: readonly FlatTreeIssue[];\n}\n\ninterface Draft {\n item: FlatTreeItemData;\n index: number;\n parent: string | undefined;\n}\n\n/**\n * Indexes `items` in one pass over them (linear time, no recursion). Repairs, each reported as an\n * issue: a repeated value keeps its first item; an item whose parent is unknown becomes a root;\n * a loop of parents is cut at the first of its values met by the walk up from the first item, in\n * `items` order, whose parent chain reaches the loop (an item outside the loop that leads into it\n * can start that walk: `[x→b, a→b, b→a]` cuts at `b`), and that value becomes a root. Siblings\n * keep the order of `items`.\n */\nexport function buildFlatTreeIndex(items: readonly FlatTreeItemData[]): FlatTreeIndex {\n const issues: FlatTreeIssue[] = [];\n const drafts = new Map<string, Draft>();\n items.forEach((item, index) => {\n if (drafts.has(item.value)) {\n issues.push({ kind: 'duplicate-value', value: item.value, index });\n return;\n }\n drafts.set(item.value, { item, index, parent: item.parentValue });\n });\n\n for (const [value, draft] of drafts) {\n if (draft.parent !== undefined && !drafts.has(draft.parent)) {\n issues.push({ kind: 'unknown-parent', value, parentValue: draft.parent });\n draft.parent = undefined;\n }\n }\n\n // Colour walk: 1 while on the current path, 2 once settled. A walk that reaches a value of its\n // own path has found a loop; cutting that value's parent link ends it.\n const state = new Map<string, 1 | 2>();\n for (const start of drafts.keys()) {\n if (state.has(start)) continue;\n const path: string[] = [];\n let current: string | undefined = start;\n while (current !== undefined && !state.has(current)) {\n state.set(current, 1);\n path.push(current);\n current = drafts.get(current)?.parent;\n }\n if (current !== undefined && state.get(current) === 1) {\n issues.push({ kind: 'cycle', value: current });\n const repeated = drafts.get(current);\n if (repeated) repeated.parent = undefined;\n }\n for (const value of path) state.set(value, 2);\n }\n\n const roots: string[] = [];\n const childValues = new Map<string, string[]>();\n for (const [value, draft] of drafts) {\n if (draft.parent === undefined) {\n roots.push(value);\n continue;\n }\n const siblings = childValues.get(draft.parent);\n if (siblings) siblings.push(value);\n else childValues.set(draft.parent, [value]);\n }\n\n const byValue = new Map<string, FlatTreeNodeRecord>();\n const queue: Array<{ value: string; level: number; position: number; setSize: number }> = [];\n roots.forEach((value, at) =>\n queue.push({ value, level: 1, position: at + 1, setSize: roots.length }),\n );\n // Every item is reachable from a root now: the loops are cut and the unknown parents are roots.\n for (let at = 0; at < queue.length; at += 1) {\n const { value, level, position, setSize } = queue[at];\n const draft = drafts.get(value) as Draft;\n const children = childValues.get(value) ?? [];\n byValue.set(value, {\n item: draft.item,\n index: draft.index,\n parentValue: draft.parent,\n level,\n position,\n setSize,\n children,\n hasChildren: children.length > 0,\n isBranch: children.length > 0 || draft.item.itemType === 'branch',\n });\n children.forEach((child, childAt) =>\n queue.push({\n value: child,\n level: level + 1,\n position: childAt + 1,\n setSize: children.length,\n }),\n );\n }\n // `byValue` is filled in breadth-first order; present it in the order of `items`.\n const ordered = new Map<string, FlatTreeNodeRecord>();\n for (const value of drafts.keys()) ordered.set(value, byValue.get(value) as FlatTreeNodeRecord);\n\n return { byValue: ordered, roots, issues };\n}\n\n/**\n * The rows visible with `expanded`: the roots, and the children of every branch in the set, in\n * tree order. Only expanded branches are entered, so the cost is the number of rows returned plus\n * the depth of the stack, never the number of items. A value in `expanded` that is no branch (a\n * leaf, or no item at all) has no effect.\n */\nexport function visibleFlatItems(\n index: FlatTreeIndex,\n expanded: ReadonlySet<string>,\n): readonly VisibleFlatItem[] {\n const visible: VisibleFlatItem[] = [];\n const stack: string[] = [];\n for (let at = index.roots.length - 1; at >= 0; at -= 1) stack.push(index.roots[at]);\n while (stack.length > 0) {\n const record = index.byValue.get(stack.pop() as string);\n if (!record) continue;\n const open = record.isBranch && expanded.has(record.item.value);\n visible.push({\n item: record.item,\n level: record.level,\n position: record.position,\n setSize: record.setSize,\n parentValue: record.parentValue,\n hasChildren: record.hasChildren,\n isBranch: record.isBranch,\n expanded: open,\n index: visible.length,\n });\n if (open) {\n for (let at = record.children.length - 1; at >= 0; at -= 1) stack.push(record.children[at]);\n }\n }\n return visible;\n}\n\n/**\n * The items as a `TreeNode` forest (one node per indexed item, children in the order of `items`),\n * the input of `computeCheckStates` and `toggleCheck`. Built without recursion; walking the result\n * with those recursive functions is as deep as the tree is.\n */\nexport function flatTreeForest(index: FlatTreeIndex): TreeNode[] {\n const nodes = new Map<string, TreeNode>();\n for (const value of index.byValue.keys()) nodes.set(value, { value, children: [] });\n for (const [value, record] of index.byValue) {\n const node = nodes.get(value) as TreeNode;\n for (const child of record.children) node.children.push(nodes.get(child) as TreeNode);\n }\n return index.roots.map((value) => nodes.get(value) as TreeNode);\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ function e(e,t,n,r){if(n===`single`)return e.has(t)&&r?.allowEmpty?new Set:new Set([t]);let i=new Set(e);return i.delete(t)||i.add(t),i}function t(e,t){let n=new Set(e);for(let e of t)n.add(e);return n}function n(e,t){let n=new Set(e);for(let e of t)n.delete(e);return n}function r(e,t,n=t){let r=n.length>0&&n.every(t=>e.has(t)),i=!r&&t.some(t=>e.has(t));return{all:r,some:i,none:!r&&!i}}exports.clearIds=n,exports.selectAllIds=t,exports.summarizeSelection=r,exports.toggleId=e;
2
+ //# sourceMappingURL=selection.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selection.cjs","names":["toggleId","mode","selected","id","options","next","selectAllIds","selectableIds","clearIds","universe","summarizeSelection","all","some"],"sources":["../../src/lib/selection.ts"],"sourcesContent":["import type { SelectionMode } from './types';\n\n/**\n * Toggles `id` in a selection and returns a new set; the argument is never mutated.\n *\n * `multiple` adds or removes the id. `single` replaces the selection with the id; when that id\n * is the selection already it stays selected, unless `options.allowEmpty` clears it.\n */\nexport function toggleId(\n selected: ReadonlySet<string>,\n id: string,\n mode: SelectionMode,\n options?: { allowEmpty?: boolean },\n): Set<string> {\n if (mode === 'single') {\n return selected.has(id) && options?.allowEmpty ? new Set() : new Set([id]);\n }\n const next = new Set(selected);\n if (!next.delete(id)) next.add(id);\n return next;\n}\n\n/** Adds `selectableIds` to a selection, keeping every id already in it (foreign ones too). */\nexport function selectAllIds(\n selected: ReadonlySet<string>,\n selectableIds: readonly string[],\n): Set<string> {\n const next = new Set(selected);\n for (const id of selectableIds) next.add(id);\n return next;\n}\n\n/** Removes the ids of `universe` from a selection; ids outside the universe stay selected. */\nexport function clearIds(selected: ReadonlySet<string>, universe: readonly string[]): Set<string> {\n const next = new Set(selected);\n for (const id of universe) next.delete(id);\n return next;\n}\n\n/**\n * Summarises a selection over `universe`. `all`: `selectableIds` (default `universe`) is\n * non-empty and every id in it is selected. `some`: an id of `universe` is selected and not\n * `all`, so a selected disabled id counts. `none`: neither. Ids outside `universe` count toward\n * nothing.\n */\nexport function summarizeSelection(\n selected: ReadonlySet<string>,\n universe: readonly string[],\n selectableIds: readonly string[] = universe,\n): { all: boolean; some: boolean; none: boolean } {\n const all = selectableIds.length > 0 && selectableIds.every((id) => selected.has(id));\n const some = !all && universe.some((id) => selected.has(id));\n return { all, some, none: !all && !some };\n}\n"],"mappings":"AAQA,SAAgBA,EACd,EACA,EACA,EACA,EACa,CACb,GAAIC,IAAS,SACX,OAAOC,EAAS,IAAIC,CAAE,GAAKC,GAAS,WAAa,IAAI,IAAQ,IAAI,IAAI,CAACD,CAAE,CAAC,EAE3E,IAAME,EAAO,IAAI,IAAIH,CAAQ,EAE7B,OADKG,EAAK,OAAOF,CAAE,GAAGE,EAAK,IAAIF,CAAE,EAC1BE,CACT,CAGA,SAAgBC,EACd,EACA,EACa,CACb,IAAMD,EAAO,IAAI,IAAIH,CAAQ,EAC7B,IAAK,IAAMC,KAAMI,EAAeF,EAAK,IAAIF,CAAE,EAC3C,OAAOE,CACT,CAGA,SAAgBG,EAAS,EAA+B,EAA0C,CAChG,IAAMH,EAAO,IAAI,IAAIH,CAAQ,EAC7B,IAAK,IAAMC,KAAMM,EAAUJ,EAAK,OAAOF,CAAE,EACzC,OAAOE,CACT,CAQA,SAAgBK,EACd,EACA,EACA,EAAmCD,EACa,CAChD,IAAME,EAAMJ,EAAc,OAAS,GAAKA,EAAc,MAAO,GAAOL,EAAS,IAAIC,CAAE,CAAC,EAC9ES,EAAO,CAACD,GAAOF,EAAS,KAAM,GAAOP,EAAS,IAAIC,CAAE,CAAC,EAC3D,MAAO,CAAE,MAAK,OAAM,KAAM,CAACQ,GAAO,CAACC,CAAK,CAC1C"}
@@ -0,0 +1,28 @@
1
+ //#region src/lib/selection.ts
2
+ function e(e, t, n, r) {
3
+ if (n === "single") return e.has(t) && r?.allowEmpty ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([t]);
4
+ let i = new Set(e);
5
+ return i.delete(t) || i.add(t), i;
6
+ }
7
+ function t(e, t) {
8
+ let n = new Set(e);
9
+ for (let e of t) n.add(e);
10
+ return n;
11
+ }
12
+ function n(e, t) {
13
+ let n = new Set(e);
14
+ for (let e of t) n.delete(e);
15
+ return n;
16
+ }
17
+ function r(e, t, n = t) {
18
+ let r = n.length > 0 && n.every((t) => e.has(t)), i = !r && t.some((t) => e.has(t));
19
+ return {
20
+ all: r,
21
+ some: i,
22
+ none: !r && !i
23
+ };
24
+ }
25
+ //#endregion
26
+ export { n as clearIds, t as selectAllIds, r as summarizeSelection, e as toggleId };
27
+
28
+ //# sourceMappingURL=selection.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selection.mjs","names":["toggleId","mode","selected","id","options","next","selectAllIds","selectableIds","clearIds","universe","summarizeSelection","all","some"],"sources":["../../src/lib/selection.ts"],"sourcesContent":["import type { SelectionMode } from './types';\n\n/**\n * Toggles `id` in a selection and returns a new set; the argument is never mutated.\n *\n * `multiple` adds or removes the id. `single` replaces the selection with the id; when that id\n * is the selection already it stays selected, unless `options.allowEmpty` clears it.\n */\nexport function toggleId(\n selected: ReadonlySet<string>,\n id: string,\n mode: SelectionMode,\n options?: { allowEmpty?: boolean },\n): Set<string> {\n if (mode === 'single') {\n return selected.has(id) && options?.allowEmpty ? new Set() : new Set([id]);\n }\n const next = new Set(selected);\n if (!next.delete(id)) next.add(id);\n return next;\n}\n\n/** Adds `selectableIds` to a selection, keeping every id already in it (foreign ones too). */\nexport function selectAllIds(\n selected: ReadonlySet<string>,\n selectableIds: readonly string[],\n): Set<string> {\n const next = new Set(selected);\n for (const id of selectableIds) next.add(id);\n return next;\n}\n\n/** Removes the ids of `universe` from a selection; ids outside the universe stay selected. */\nexport function clearIds(selected: ReadonlySet<string>, universe: readonly string[]): Set<string> {\n const next = new Set(selected);\n for (const id of universe) next.delete(id);\n return next;\n}\n\n/**\n * Summarises a selection over `universe`. `all`: `selectableIds` (default `universe`) is\n * non-empty and every id in it is selected. `some`: an id of `universe` is selected and not\n * `all`, so a selected disabled id counts. `none`: neither. Ids outside `universe` count toward\n * nothing.\n */\nexport function summarizeSelection(\n selected: ReadonlySet<string>,\n universe: readonly string[],\n selectableIds: readonly string[] = universe,\n): { all: boolean; some: boolean; none: boolean } {\n const all = selectableIds.length > 0 && selectableIds.every((id) => selected.has(id));\n const some = !all && universe.some((id) => selected.has(id));\n return { all, some, none: !all && !some };\n}\n"],"mappings":";AAQA,SAAgBA,EACd,GACA,GACA,GACA,GACa;CACb,IAAIC,MAAS,UACX,OAAOC,EAAS,IAAIC,CAAE,KAAKC,GAAS,6BAAa,IAAI,IAAI,oBAAI,IAAI,IAAI,CAACD,CAAE,CAAC;CAE3E,IAAME,IAAO,IAAI,IAAIH,CAAQ;CAE7B,OADKG,EAAK,OAAOF,CAAE,KAAGE,EAAK,IAAIF,CAAE,GAC1BE;AACT;AAGA,SAAgBC,EACd,GACA,GACa;CACb,IAAMD,IAAO,IAAI,IAAIH,CAAQ;CAC7B,KAAK,IAAMC,KAAMI,GAAe,EAAK,IAAIJ,CAAE;CAC3C,OAAOE;AACT;AAGA,SAAgBG,EAAS,GAA+B,GAA0C;CAChG,IAAMH,IAAO,IAAI,IAAIH,CAAQ;CAC7B,KAAK,IAAMC,KAAMM,GAAU,EAAK,OAAON,CAAE;CACzC,OAAOE;AACT;AAQA,SAAgBK,EACd,GACA,GACA,IAAmCD,GACa;CAChD,IAAME,IAAMJ,EAAc,SAAS,KAAKA,EAAc,OAAO,MAAOL,EAAS,IAAIC,CAAE,CAAC,GAC9ES,IAAO,CAACD,KAAOF,EAAS,MAAM,MAAOP,EAAS,IAAIC,CAAE,CAAC;CAC3D,OAAO;EAAE;EAAK;EAAM,MAAM,CAACQ,KAAO,CAACC;CAAK;AAC1C"}
@@ -0,0 +1,2 @@
1
+ const e=require("./dev.cjs");function t(e){return`--wave-${e.replace(/([A-Za-z])(\d)/g,`$1-$2`).replace(/[A-Z]/g,e=>`-${e}`).toLowerCase()}`}var n=/^[a-z][A-Za-z0-9]*$/,r=/[;{}]/;function i(e){let i=[];if(e==null)return{style:void 0,invalid:i};let a={},o=!0;for(let[s,c]of Object.entries(e))c!==void 0&&(n.test(s)?typeof c==`string`&&!r.test(c)||typeof c==`number`&&Number.isFinite(c)?(a[t(s)]=String(c),o=!1):i.push({key:s,reason:`value`}):i.push({key:s,reason:`name`}));return{style:o?void 0:a,invalid:i}}function a(t){let{style:n,invalid:r}=i(t);for(let{key:t,reason:n}of r)n===`name`?e.warnOnce(`tokens:name:${t}`,`getTokenStyle: \`${t}\` is not a token name, so it is skipped. Token names are the CSS variable in camelCase without its \`--wave-\` prefix (\`primaryForeground\` for \`--wave-primary-foreground\`).`):e.warnOnce(`tokens:value:${t}`,`getTokenStyle: the value of \`${t}\` is skipped: it must be a finite number or a string without \`;\`, \`{\` or \`}\`.`);return n}function o(e,t){if(t===null)return{};if(t===void 0)return e;let n=Object.fromEntries(Object.entries(t).filter(([,e])=>e!==void 0));return{...e,...n}}exports.collectTokenStyle=i,exports.getTokenStyle=a,exports.mergeTokenOverrides=o,exports.tokenVariable=t;
2
+ //# sourceMappingURL=tokens.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.cjs","names":["require_dev","tokenVariable","name","capital","TOKEN_NAME","DECLARATION_BREAK","collectTokenStyle","invalid","overrides","style","empty","key","value","getTokenStyle","reason","mergeTokenOverrides","own","parent","defined"],"sources":["../../src/lib/tokens.ts"],"sourcesContent":["/**\n * The design tokens in JavaScript: their names, the overrides `WaveProvider` takes and the inline\n * style that applies them. Server-safe and light enough for the provider: it imports only types\n * and the development warnings, never the list of token names (`waveTokens.ts`).\n */\nimport type * as React from 'react';\nimport { warnOnce } from './dev';\nimport type { WAVE_TOKEN_NAMES } from './waveTokens';\n\n/**\n * The name of a design token: its CSS custom property without the `--wave-` prefix, in camelCase.\n * `--wave-primary-foreground` is `primaryForeground`, `--wave-brand-80` is `brand80` and\n * `--wave-palette-red-tint` is `paletteRedTint`.\n */\nexport type WaveTokenName = (typeof WAVE_TOKEN_NAMES)[number];\n\n/** The shape of `waveTokens`: every token name mapped to the CSS value that reads the token. */\nexport type WaveTokens = { readonly [K in WaveTokenName]: string };\n\n/**\n * Token overrides: CSS values by token name, as `WaveProvider tokens` and `getTokenStyle` take\n * them. A number is written as its string (`zOverlay: 2000`); a key whose value is `undefined`\n * sets nothing.\n */\nexport type WaveTokenOverrides = { [K in WaveTokenName]?: string | number };\n\n/**\n * The inline style that applies token overrides: a React style object whose `--wave-*` custom\n * properties set the tokens, so it can be merged with other style properties.\n */\nexport type TokenStyle = React.CSSProperties & { [K in `--wave-${string}`]?: string };\n\n/**\n * The CSS custom property of a token name at the type level: `TokenVariable<'brand80'>` is\n * `'--wave-brand-80'`, by the rule of {@link tokenVariable}. It spells out the literal values of\n * `waveTokens`. It walks the name one character at a time (tail-recursive, so long names stay\n * within the compiler's depth limit): `AfterLetter` says whether the previous character was a\n * letter, `Done` holds the converted text so far.\n */\nexport type TokenVariable<\n Name extends string,\n AfterLetter extends boolean = false,\n Done extends string = '',\n> = Name extends `${infer Char}${infer Rest}`\n ? Char extends '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'\n ? TokenVariable<Rest, false, `${Done}${AfterLetter extends true ? '-' : ''}${Char}`>\n : Char extends Lowercase<Char>\n ? TokenVariable<Rest, true, `${Done}${Char}`>\n : TokenVariable<Rest, true, `${Done}-${Lowercase<Char>}`>\n : `--wave-${Done}`;\n\n/**\n * The CSS custom property of a token name: a hyphen before each capital letter and before a digit\n * run that follows a letter, lowercased, with the `--wave-` prefix. `'paletteRedTint'` gives\n * `'--wave-palette-red-tint'` and `'brand80'` gives `'--wave-brand-80'`. The name is not checked\n * against the list of tokens.\n */\nexport function tokenVariable(name: string): string {\n return `--wave-${name\n .replace(/([A-Za-z])(\\d)/g, '$1-$2')\n .replace(/[A-Z]/g, (capital) => `-${capital}`)\n .toLowerCase()}`;\n}\n\n/** A camelCase identifier: the only key shape a token name can have. */\nconst TOKEN_NAME = /^[a-z][A-Za-z0-9]*$/;\n\n/**\n * The characters no token value may hold. React writes a custom property's value into the\n * server-rendered `style` attribute as text, where a semicolon would end the declaration and let\n * the rest of the value declare a property of its own (and a brace could close the rule around\n * it); in the client the CSSOM refuses a value with a semicolon, so the two renders would also\n * differ.\n */\nconst DECLARATION_BREAK = /[;{}]/;\n\n/**\n * The custom properties of `overrides`, and the entries it skipped. Pure: it never warns, so the\n * provider can call it during render; {@link getTokenStyle} reports the skipped entries.\n *\n * `undefined` values are skipped first (they set nothing); a key that is not a camelCase\n * identifier is skipped with the reason `'name'`, and a value that is neither a finite number nor a\n * string without `;`, `{` or `}` with the reason `'value'`. Numbers are written as strings, and the\n * style keeps the order of the input. `style` is `undefined` when nothing is left.\n */\nexport function collectTokenStyle(overrides: WaveTokenOverrides | null | undefined): {\n style: TokenStyle | undefined;\n invalid: readonly { key: string; reason: 'name' | 'value' }[];\n} {\n const invalid: { key: string; reason: 'name' | 'value' }[] = [];\n if (overrides == null) return { style: undefined, invalid };\n const style: Record<string, string> = {};\n let empty = true;\n for (const [key, value] of Object.entries(overrides as Record<string, unknown>)) {\n if (value === undefined) continue;\n if (!TOKEN_NAME.test(key)) {\n invalid.push({ key, reason: 'name' });\n } else if (\n (typeof value === 'string' && !DECLARATION_BREAK.test(value)) ||\n (typeof value === 'number' && Number.isFinite(value))\n ) {\n style[tokenVariable(key)] = String(value);\n empty = false;\n } else {\n invalid.push({ key, reason: 'value' });\n }\n }\n return { style: empty ? undefined : (style as TokenStyle), invalid };\n}\n\n/**\n * The inline style that applies token overrides: one `--wave-*` custom property per entry, the\n * object `WaveProvider` puts on its root and its portals. Use it where no provider renders, such\n * as a Server Component's document element. Server-safe.\n *\n * Returns `undefined` for `null`, `undefined` or a map with nothing to set. An `undefined` value is\n * skipped, a number is written as its string, and the properties keep the order of the input. A\n * key that is not a camelCase identifier, or a value that is neither a finite number nor a string\n * without `;`, `{` or `}` (which could add a declaration of its own to a server-rendered `style`\n * attribute), is skipped with a development warning (once per key). Names are not checked against\n * the list of tokens: TypeScript refuses a misspelled one, and in JavaScript it sets a property\n * nothing reads.\n *\n * @example\n * // app/layout.tsx (a Server Component)\n * <html style={getTokenStyle({ brand80: '#c43e00' })}>\n *\n * @example\n * <div style={{ ...getTokenStyle(overrides), padding: 16 }} />\n */\nexport function getTokenStyle(\n overrides: WaveTokenOverrides | null | undefined,\n): TokenStyle | undefined {\n const { style, invalid } = collectTokenStyle(overrides);\n for (const { key, reason } of invalid) {\n if (reason === 'name') {\n warnOnce(\n `tokens:name:${key}`,\n `getTokenStyle: \\`${key}\\` is not a token name, so it is skipped. Token names are the CSS ` +\n 'variable in camelCase without its `--wave-` prefix (`primaryForeground` for ' +\n '`--wave-primary-foreground`).',\n );\n } else {\n warnOnce(\n `tokens:value:${key}`,\n `getTokenStyle: the value of \\`${key}\\` is skipped: it must be a finite number or a string ` +\n 'without `;`, `{` or `}`.',\n );\n }\n }\n return style;\n}\n\n/**\n * The overrides of a nested provider: `own` merged key by key over `parent`. `undefined` inherits\n * `parent` as it is, `null` clears everything inherited, and a key whose own value is `undefined`\n * keeps the parent's value.\n */\nexport function mergeTokenOverrides(\n parent: WaveTokenOverrides,\n own: WaveTokenOverrides | null | undefined,\n): WaveTokenOverrides {\n if (own === null) return {};\n if (own === undefined) return parent;\n // Spread, never assignment, so a `__proto__` key is an own entry like any other.\n const defined = Object.fromEntries(\n Object.entries(own).filter(([, value]) => value !== undefined),\n );\n return { ...parent, ...defined };\n}\n"],"mappings":"6BAyDA,SAAgBC,EAAc,EAAsB,CAClD,MAAO,UAAUC,EACd,QAAQ,kBAAmB,OAAO,CAAC,CACnC,QAAQ,SAAW,GAAY,IAAIC,GAAS,CAAC,CAC7C,YAAY,GACjB,CAGA,IAAMC,EAAa,sBASbC,EAAoB,QAW1B,SAAgBC,EAAkB,EAGhC,CACA,IAAMC,EAAuD,CAAC,EAC9D,GAAIC,GAAa,KAAM,MAAO,CAAE,MAAO,IAAA,GAAW,SAAQ,EAC1D,IAAMC,EAAgC,CAAC,EACnCC,EAAQ,GACZ,IAAK,GAAM,CAACC,EAAKC,KAAU,OAAO,QAAQJ,CAAoC,EACxEI,IAAU,IAAA,KACTR,EAAW,KAAKO,CAAG,EAGrB,OAAOC,GAAU,UAAY,CAACP,EAAkB,KAAKO,CAAK,GAC1D,OAAOA,GAAU,UAAY,OAAO,SAASA,CAAK,GAEnD,EAAMX,EAAcU,CAAG,GAAK,OAAOC,CAAK,EACxC,EAAQ,IAERL,EAAQ,KAAK,CAAE,MAAK,OAAQ,OAAQ,CAAC,EARrCA,EAAQ,KAAK,CAAE,MAAK,OAAQ,MAAO,CAAC,GAWxC,MAAO,CAAE,MAAOG,EAAQ,IAAA,GAAaD,EAAsB,SAAQ,CACrE,CAsBA,SAAgBI,EACd,EACwB,CACxB,GAAM,CAAE,QAAO,WAAYP,EAAkBE,CAAS,EACtD,IAAK,GAAM,CAAE,MAAK,YAAYD,EACxBO,IAAW,OACbd,EAAA,SACE,eAAeW,IACf,oBAAoBA,EAAI,kLAG1B,EAEAX,EAAA,SACE,gBAAgBW,IAChB,iCAAiCA,EAAI,qFAEvC,EAGJ,OAAOF,CACT,CAOA,SAAgBM,EACd,EACA,EACoB,CACpB,GAAIC,IAAQ,KAAM,MAAO,CAAC,EAC1B,GAAIA,IAAQ,IAAA,GAAW,OAAOC,EAE9B,IAAMC,EAAU,OAAO,YACrB,OAAO,QAAQF,CAAG,CAAC,CAAC,QAAQ,EAAGJ,KAAWA,IAAU,IAAA,EAAS,CAC/D,EACA,MAAO,CAAE,GAAGK,EAAQ,GAAGC,CAAQ,CACjC"}
@@ -0,0 +1,43 @@
1
+ import { warnOnce as e } from "./dev.mjs";
2
+ //#region src/lib/tokens.ts
3
+ function t(e) {
4
+ return `--wave-${e.replace(/([A-Za-z])(\d)/g, "$1-$2").replace(/[A-Z]/g, (e) => `-${e}`).toLowerCase()}`;
5
+ }
6
+ var n = /^[a-z][A-Za-z0-9]*$/, r = /[;{}]/;
7
+ function i(e) {
8
+ let i = [];
9
+ if (e == null) return {
10
+ style: void 0,
11
+ invalid: i
12
+ };
13
+ let a = {}, o = !0;
14
+ for (let [s, c] of Object.entries(e)) c !== void 0 && (n.test(s) ? typeof c == "string" && !r.test(c) || typeof c == "number" && Number.isFinite(c) ? (a[t(s)] = String(c), o = !1) : i.push({
15
+ key: s,
16
+ reason: "value"
17
+ }) : i.push({
18
+ key: s,
19
+ reason: "name"
20
+ }));
21
+ return {
22
+ style: o ? void 0 : a,
23
+ invalid: i
24
+ };
25
+ }
26
+ function a(t) {
27
+ let { style: n, invalid: r } = i(t);
28
+ for (let { key: t, reason: n } of r) n === "name" ? e(`tokens:name:${t}`, `getTokenStyle: \`${t}\` is not a token name, so it is skipped. Token names are the CSS variable in camelCase without its \`--wave-\` prefix (\`primaryForeground\` for \`--wave-primary-foreground\`).`) : e(`tokens:value:${t}`, `getTokenStyle: the value of \`${t}\` is skipped: it must be a finite number or a string without \`;\`, \`{\` or \`}\`.`);
29
+ return n;
30
+ }
31
+ function o(e, t) {
32
+ if (t === null) return {};
33
+ if (t === void 0) return e;
34
+ let n = Object.fromEntries(Object.entries(t).filter(([, e]) => e !== void 0));
35
+ return {
36
+ ...e,
37
+ ...n
38
+ };
39
+ }
40
+ //#endregion
41
+ export { i as collectTokenStyle, a as getTokenStyle, o as mergeTokenOverrides, t as tokenVariable };
42
+
43
+ //# sourceMappingURL=tokens.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.mjs","names":["tokenVariable","name","capital","TOKEN_NAME","DECLARATION_BREAK","collectTokenStyle","invalid","overrides","style","empty","key","value","getTokenStyle","reason","warnOnce","mergeTokenOverrides","own","parent","defined"],"sources":["../../src/lib/tokens.ts"],"sourcesContent":["/**\n * The design tokens in JavaScript: their names, the overrides `WaveProvider` takes and the inline\n * style that applies them. Server-safe and light enough for the provider: it imports only types\n * and the development warnings, never the list of token names (`waveTokens.ts`).\n */\nimport type * as React from 'react';\nimport { warnOnce } from './dev';\nimport type { WAVE_TOKEN_NAMES } from './waveTokens';\n\n/**\n * The name of a design token: its CSS custom property without the `--wave-` prefix, in camelCase.\n * `--wave-primary-foreground` is `primaryForeground`, `--wave-brand-80` is `brand80` and\n * `--wave-palette-red-tint` is `paletteRedTint`.\n */\nexport type WaveTokenName = (typeof WAVE_TOKEN_NAMES)[number];\n\n/** The shape of `waveTokens`: every token name mapped to the CSS value that reads the token. */\nexport type WaveTokens = { readonly [K in WaveTokenName]: string };\n\n/**\n * Token overrides: CSS values by token name, as `WaveProvider tokens` and `getTokenStyle` take\n * them. A number is written as its string (`zOverlay: 2000`); a key whose value is `undefined`\n * sets nothing.\n */\nexport type WaveTokenOverrides = { [K in WaveTokenName]?: string | number };\n\n/**\n * The inline style that applies token overrides: a React style object whose `--wave-*` custom\n * properties set the tokens, so it can be merged with other style properties.\n */\nexport type TokenStyle = React.CSSProperties & { [K in `--wave-${string}`]?: string };\n\n/**\n * The CSS custom property of a token name at the type level: `TokenVariable<'brand80'>` is\n * `'--wave-brand-80'`, by the rule of {@link tokenVariable}. It spells out the literal values of\n * `waveTokens`. It walks the name one character at a time (tail-recursive, so long names stay\n * within the compiler's depth limit): `AfterLetter` says whether the previous character was a\n * letter, `Done` holds the converted text so far.\n */\nexport type TokenVariable<\n Name extends string,\n AfterLetter extends boolean = false,\n Done extends string = '',\n> = Name extends `${infer Char}${infer Rest}`\n ? Char extends '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'\n ? TokenVariable<Rest, false, `${Done}${AfterLetter extends true ? '-' : ''}${Char}`>\n : Char extends Lowercase<Char>\n ? TokenVariable<Rest, true, `${Done}${Char}`>\n : TokenVariable<Rest, true, `${Done}-${Lowercase<Char>}`>\n : `--wave-${Done}`;\n\n/**\n * The CSS custom property of a token name: a hyphen before each capital letter and before a digit\n * run that follows a letter, lowercased, with the `--wave-` prefix. `'paletteRedTint'` gives\n * `'--wave-palette-red-tint'` and `'brand80'` gives `'--wave-brand-80'`. The name is not checked\n * against the list of tokens.\n */\nexport function tokenVariable(name: string): string {\n return `--wave-${name\n .replace(/([A-Za-z])(\\d)/g, '$1-$2')\n .replace(/[A-Z]/g, (capital) => `-${capital}`)\n .toLowerCase()}`;\n}\n\n/** A camelCase identifier: the only key shape a token name can have. */\nconst TOKEN_NAME = /^[a-z][A-Za-z0-9]*$/;\n\n/**\n * The characters no token value may hold. React writes a custom property's value into the\n * server-rendered `style` attribute as text, where a semicolon would end the declaration and let\n * the rest of the value declare a property of its own (and a brace could close the rule around\n * it); in the client the CSSOM refuses a value with a semicolon, so the two renders would also\n * differ.\n */\nconst DECLARATION_BREAK = /[;{}]/;\n\n/**\n * The custom properties of `overrides`, and the entries it skipped. Pure: it never warns, so the\n * provider can call it during render; {@link getTokenStyle} reports the skipped entries.\n *\n * `undefined` values are skipped first (they set nothing); a key that is not a camelCase\n * identifier is skipped with the reason `'name'`, and a value that is neither a finite number nor a\n * string without `;`, `{` or `}` with the reason `'value'`. Numbers are written as strings, and the\n * style keeps the order of the input. `style` is `undefined` when nothing is left.\n */\nexport function collectTokenStyle(overrides: WaveTokenOverrides | null | undefined): {\n style: TokenStyle | undefined;\n invalid: readonly { key: string; reason: 'name' | 'value' }[];\n} {\n const invalid: { key: string; reason: 'name' | 'value' }[] = [];\n if (overrides == null) return { style: undefined, invalid };\n const style: Record<string, string> = {};\n let empty = true;\n for (const [key, value] of Object.entries(overrides as Record<string, unknown>)) {\n if (value === undefined) continue;\n if (!TOKEN_NAME.test(key)) {\n invalid.push({ key, reason: 'name' });\n } else if (\n (typeof value === 'string' && !DECLARATION_BREAK.test(value)) ||\n (typeof value === 'number' && Number.isFinite(value))\n ) {\n style[tokenVariable(key)] = String(value);\n empty = false;\n } else {\n invalid.push({ key, reason: 'value' });\n }\n }\n return { style: empty ? undefined : (style as TokenStyle), invalid };\n}\n\n/**\n * The inline style that applies token overrides: one `--wave-*` custom property per entry, the\n * object `WaveProvider` puts on its root and its portals. Use it where no provider renders, such\n * as a Server Component's document element. Server-safe.\n *\n * Returns `undefined` for `null`, `undefined` or a map with nothing to set. An `undefined` value is\n * skipped, a number is written as its string, and the properties keep the order of the input. A\n * key that is not a camelCase identifier, or a value that is neither a finite number nor a string\n * without `;`, `{` or `}` (which could add a declaration of its own to a server-rendered `style`\n * attribute), is skipped with a development warning (once per key). Names are not checked against\n * the list of tokens: TypeScript refuses a misspelled one, and in JavaScript it sets a property\n * nothing reads.\n *\n * @example\n * // app/layout.tsx (a Server Component)\n * <html style={getTokenStyle({ brand80: '#c43e00' })}>\n *\n * @example\n * <div style={{ ...getTokenStyle(overrides), padding: 16 }} />\n */\nexport function getTokenStyle(\n overrides: WaveTokenOverrides | null | undefined,\n): TokenStyle | undefined {\n const { style, invalid } = collectTokenStyle(overrides);\n for (const { key, reason } of invalid) {\n if (reason === 'name') {\n warnOnce(\n `tokens:name:${key}`,\n `getTokenStyle: \\`${key}\\` is not a token name, so it is skipped. Token names are the CSS ` +\n 'variable in camelCase without its `--wave-` prefix (`primaryForeground` for ' +\n '`--wave-primary-foreground`).',\n );\n } else {\n warnOnce(\n `tokens:value:${key}`,\n `getTokenStyle: the value of \\`${key}\\` is skipped: it must be a finite number or a string ` +\n 'without `;`, `{` or `}`.',\n );\n }\n }\n return style;\n}\n\n/**\n * The overrides of a nested provider: `own` merged key by key over `parent`. `undefined` inherits\n * `parent` as it is, `null` clears everything inherited, and a key whose own value is `undefined`\n * keeps the parent's value.\n */\nexport function mergeTokenOverrides(\n parent: WaveTokenOverrides,\n own: WaveTokenOverrides | null | undefined,\n): WaveTokenOverrides {\n if (own === null) return {};\n if (own === undefined) return parent;\n // Spread, never assignment, so a `__proto__` key is an own entry like any other.\n const defined = Object.fromEntries(\n Object.entries(own).filter(([, value]) => value !== undefined),\n );\n return { ...parent, ...defined };\n}\n"],"mappings":";;AAyDA,SAAgBA,EAAc,GAAsB;CAClD,OAAO,UAAUC,EACd,QAAQ,mBAAmB,OAAO,CAAC,CACnC,QAAQ,WAAW,MAAY,IAAIC,GAAS,CAAC,CAC7C,YAAY;AACjB;AAGA,IAAMC,IAAa,uBASbC,IAAoB;AAW1B,SAAgBC,EAAkB,GAGhC;CACA,IAAMC,IAAuD,CAAC;CAC9D,IAAIC,KAAa,MAAM,OAAO;EAAE,OAAO,KAAA;EAAW;CAAQ;CAC1D,IAAMC,IAAgC,CAAC,GACnCC,IAAQ;CACZ,KAAK,IAAM,CAACC,GAAKC,MAAU,OAAO,QAAQJ,CAAoC,GAC5E,AAAII,MAAU,KAAA,MACTR,EAAW,KAAKO,CAAG,IAGrB,OAAOC,KAAU,YAAY,CAACP,EAAkB,KAAKO,CAAK,KAC1D,OAAOA,KAAU,YAAY,OAAO,SAASA,CAAK,KAEnD,EAAMX,EAAcU,CAAG,KAAK,OAAOC,CAAK,GACxC,IAAQ,MAERL,EAAQ,KAAK;EAAE;EAAK,QAAQ;CAAQ,CAAC,IARrCA,EAAQ,KAAK;EAAE;EAAK,QAAQ;CAAO,CAAC;CAWxC,OAAO;EAAE,OAAOG,IAAQ,KAAA,IAAaD;EAAsB;CAAQ;AACrE;AAsBA,SAAgBI,EACd,GACwB;CACxB,IAAM,EAAE,UAAO,eAAYP,EAAkBE,CAAS;CACtD,KAAK,IAAM,EAAE,QAAK,eAAYD,GAC5B,AAAIO,MAAW,SACbC,EACE,eAAeJ,KACf,oBAAoBA,EAAI,kLAG1B,IAEAI,EACE,gBAAgBJ,KAChB,iCAAiCA,EAAI,qFAEvC;CAGJ,OAAOF;AACT;AAOA,SAAgBO,EACd,GACA,GACoB;CACpB,IAAIC,MAAQ,MAAM,OAAO,CAAC;CAC1B,IAAIA,MAAQ,KAAA,GAAW,OAAOC;CAE9B,IAAMC,IAAU,OAAO,YACrB,OAAO,QAAQF,CAAG,CAAC,CAAC,QAAQ,GAAGL,OAAWA,MAAU,KAAA,CAAS,CAC/D;CACA,OAAO;EAAE,GAAGM;EAAQ,GAAGC;CAAQ;AACjC"}
@@ -0,0 +1,2 @@
1
+ function e(t,n){for(let r of t)n(r),e(r.children,n)}function t(e,n){for(let r of e){if(r.value===n)return[r];let e=t(r.children,n);if(e)return[r,...e]}return null}function n(t,n,r=!1){let i=new Map;e(t,e=>{i.has(e.value)||i.set(e.value,e)});let a=new Map,o=(e,t)=>{let r=t||n.has(e.value),s=e.children.map(e=>o(e,r)),c;return c=r?`checked`:s.length===0?`unchecked`:s.every(e=>e===`checked`)?`checked`:s.some(e=>e!==`unchecked`)?`mixed`:`unchecked`,i.get(e.value)===e&&a.set(e.value,c),c};for(let e of t)o(e,r);return a}function r(r,i,a){let o=n(r,new Set(i)),s=new Set;for(let[e,t]of o)t===`checked`&&s.add(e);let c=new Set;e(r,e=>c.add(e.value));let l=Array.from(new Set(i.filter(e=>!c.has(e)))),u=t(r,a);if(u){let t=u[u.length-1],n=o.get(a)!==`checked`;e([t],e=>{n?s.add(e.value):s.delete(e.value)});for(let e=u.length-2;e>=0;--e){let t=u[e];t.children.every(e=>s.has(e.value))?s.add(t.value):s.delete(t.value)}}else{let e=l.indexOf(a);e===-1?l.push(a):l.splice(e,1)}let d=[],f=new Set;return e(r,e=>{s.has(e.value)&&!f.has(e.value)&&(f.add(e.value),d.push(e.value))}),[...d,...l]}exports.computeCheckStates=n,exports.toggleCheck=r;
2
+ //# sourceMappingURL=treeCascade.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"treeCascade.cjs","names":["forEachNode","node","nodes","visit","findPath","value","below","computeCheckStates","first","candidate","states","forced","forcedAbove","listed","current","childStates","child","state","childState","top","ancestorListed","toggleCheck","checked","itemValue","known","unmatched","listedValue","path","target","turnOn","index","ancestor","at","ordered","seen"],"sources":["../../src/lib/treeCascade.ts"],"sourcesContent":["// The pure check-state cascade of the trees: server-safe, no React import. The nested Tree feeds it\n// a forest read from its elements (`Tree.selection.ts`), the flat tree a forest built from flat data\n// (`flatTree.ts`).\n\n/** One Tree.Item of the cascade model: its value and the items nested in it. */\nexport interface TreeNode {\n value: string;\n children: TreeNode[];\n}\n\n/** The check state of an item in a `selectionMode=\"multiple\"` tree. */\nexport type CheckState = 'checked' | 'mixed' | 'unchecked';\n\nfunction forEachNode(nodes: readonly TreeNode[], visit: (node: TreeNode) => void): void {\n for (const node of nodes) {\n visit(node);\n forEachNode(node.children, visit);\n }\n}\n\n/** The first item with `value` in tree order and its ancestors, from the top down; `null` if none. */\nfunction findPath(nodes: readonly TreeNode[], value: string): TreeNode[] | null {\n for (const node of nodes) {\n if (node.value === value) return [node];\n const below = findPath(node.children, value);\n if (below) return [node, ...below];\n }\n return null;\n}\n\n/**\n * The check state of every item: checked when its value is listed, when an ancestor's value is\n * listed (or `ancestorListed`), or when it has nested items and all of them are checked; mixed\n * when some of them are checked or mixed; else unchecked. For a value that several items share,\n * the first item in tree order decides the entry.\n */\nexport function computeCheckStates(\n nodes: readonly TreeNode[],\n listed: ReadonlySet<string>,\n ancestorListed = false,\n): Map<string, CheckState> {\n const first = new Map<string, TreeNode>();\n forEachNode(nodes, (candidate) => {\n if (!first.has(candidate.value)) first.set(candidate.value, candidate);\n });\n const states = new Map<string, CheckState>();\n const visit = (current: TreeNode, forcedAbove: boolean): CheckState => {\n const forced = forcedAbove || listed.has(current.value);\n const childStates = current.children.map((child) => visit(child, forced));\n let state: CheckState;\n if (forced) state = 'checked';\n else if (childStates.length === 0) state = 'unchecked';\n else if (childStates.every((childState) => childState === 'checked')) state = 'checked';\n else if (childStates.some((childState) => childState !== 'unchecked')) state = 'mixed';\n else state = 'unchecked';\n if (first.get(current.value) === current) states.set(current.value, state);\n return state;\n };\n for (const top of nodes) visit(top, ancestorListed);\n return states;\n}\n\n/**\n * The checked items after toggling `value`. A checked item and every item nested in it become\n * unchecked; an unchecked or mixed one and every item nested in it become checked; its ancestors\n * then follow their nested items. Returns every checked item in tree order (fully checked parents\n * included, mixed ones not), each value once, followed by the listed values that match no item,\n * in their order; a value that no item has is added to, or removed from, those.\n */\nexport function toggleCheck(\n nodes: readonly TreeNode[],\n listed: readonly string[],\n value: string,\n): string[] {\n const states = computeCheckStates(nodes, new Set(listed));\n const checked = new Set<string>();\n for (const [itemValue, state] of states) {\n if (state === 'checked') checked.add(itemValue);\n }\n const known = new Set<string>();\n forEachNode(nodes, (candidate) => known.add(candidate.value));\n const unmatched = Array.from(new Set(listed.filter((listedValue) => !known.has(listedValue))));\n\n const path = findPath(nodes, value);\n if (path) {\n const target = path[path.length - 1];\n const turnOn = states.get(value) !== 'checked';\n forEachNode([target], (candidate) => {\n if (turnOn) checked.add(candidate.value);\n else checked.delete(candidate.value);\n });\n for (let index = path.length - 2; index >= 0; index -= 1) {\n const ancestor = path[index];\n if (ancestor.children.every((child) => checked.has(child.value))) checked.add(ancestor.value);\n else checked.delete(ancestor.value);\n }\n } else {\n const at = unmatched.indexOf(value);\n if (at === -1) unmatched.push(value);\n else unmatched.splice(at, 1);\n }\n\n const ordered: string[] = [];\n const seen = new Set<string>();\n forEachNode(nodes, (candidate) => {\n if (checked.has(candidate.value) && !seen.has(candidate.value)) {\n seen.add(candidate.value);\n ordered.push(candidate.value);\n }\n });\n return [...ordered, ...unmatched];\n}\n"],"mappings":"AAaA,SAASA,EAAY,EAA4B,EAAuC,CACtF,IAAK,IAAMC,KAAQC,EACjBC,EAAMF,CAAI,EACVD,EAAYC,EAAK,SAAUE,CAAK,CAEpC,CAGA,SAASC,EAAS,EAA4B,EAAkC,CAC9E,IAAK,IAAMH,KAAQC,EAAO,CACxB,GAAID,EAAK,QAAUI,EAAO,MAAO,CAACJ,CAAI,EACtC,IAAMK,EAAQF,EAASH,EAAK,SAAUI,CAAK,EAC3C,GAAIC,EAAO,MAAO,CAACL,EAAM,GAAGK,CAAK,CACnC,CACA,OAAO,IACT,CAQA,SAAgBC,EACd,EACA,EACA,EAAiB,GACQ,CACzB,IAAMC,EAAQ,IAAI,IAClBR,EAAYE,EAAQ,GAAc,CAC3BM,EAAM,IAAIC,EAAU,KAAK,GAAGD,EAAM,IAAIC,EAAU,MAAOA,CAAS,CACvE,CAAC,EACD,IAAMC,EAAS,IAAI,IACbP,GAAS,EAAmB,IAAqC,CACrE,IAAMQ,EAASC,GAAeC,EAAO,IAAIC,EAAQ,KAAK,EAChDC,EAAcD,EAAQ,SAAS,IAAK,GAAUX,EAAMa,EAAOL,CAAM,CAAC,EACpEM,EAOJ,MANA,CAIKA,EAJDN,EAAgB,UACXI,EAAY,SAAW,EAAW,YAClCA,EAAY,MAAO,GAAeG,IAAe,SAAS,EAAW,UACrEH,EAAY,KAAM,GAAeG,IAAe,WAAW,EAAW,QAClE,YACTV,EAAM,IAAIM,EAAQ,KAAK,IAAMA,GAASJ,EAAO,IAAII,EAAQ,MAAOG,CAAK,EAClEA,CACT,EACA,IAAK,IAAME,KAAOjB,EAAOC,EAAMgB,EAAKC,CAAc,EAClD,OAAOV,CACT,CASA,SAAgBW,EACd,EACA,EACA,EACU,CACV,IAAMX,EAASH,EAAmBL,EAAO,IAAI,IAAIW,CAAM,CAAC,EAClDS,EAAU,IAAI,IACpB,IAAK,GAAM,CAACC,EAAWN,KAAUP,EAC3BO,IAAU,WAAWK,EAAQ,IAAIC,CAAS,EAEhD,IAAMC,EAAQ,IAAI,IAClBxB,EAAYE,EAAQ,GAAcsB,EAAM,IAAIf,EAAU,KAAK,CAAC,EAC5D,IAAMgB,EAAY,MAAM,KAAK,IAAI,IAAIZ,EAAO,OAAQ,GAAgB,CAACW,EAAM,IAAIE,CAAW,CAAC,CAAC,CAAC,EAEvFC,EAAOvB,EAASF,EAAOG,CAAK,EAClC,GAAIsB,EAAM,CACR,IAAMC,EAASD,EAAKA,EAAK,OAAS,GAC5BE,EAASnB,EAAO,IAAIL,CAAK,IAAM,UACrCL,EAAY,CAAC4B,CAAM,EAAI,GAAc,CAC/BC,EAAQP,EAAQ,IAAIb,EAAU,KAAK,EAClCa,EAAQ,OAAOb,EAAU,KAAK,CACrC,CAAC,EACD,IAAK,IAAIqB,EAAQH,EAAK,OAAS,EAAGG,GAAS,EAAG,IAAY,CACxD,IAAMC,EAAWJ,EAAKG,GAClBC,EAAS,SAAS,MAAO,GAAUT,EAAQ,IAAIN,EAAM,KAAK,CAAC,EAAGM,EAAQ,IAAIS,EAAS,KAAK,EACvFT,EAAQ,OAAOS,EAAS,KAAK,CACpC,CACF,KAAO,CACL,IAAMC,EAAKP,EAAU,QAAQpB,CAAK,EAC9B2B,IAAO,GAAIP,EAAU,KAAKpB,CAAK,EAC9BoB,EAAU,OAAOO,EAAI,CAAC,CAC7B,CAEA,IAAMC,EAAoB,CAAC,EACrBC,EAAO,IAAI,IAOjB,OANAlC,EAAYE,EAAQ,GAAc,CAC5BoB,EAAQ,IAAIb,EAAU,KAAK,GAAK,CAACyB,EAAK,IAAIzB,EAAU,KAAK,IAC3DyB,EAAK,IAAIzB,EAAU,KAAK,EACxBwB,EAAQ,KAAKxB,EAAU,KAAK,EAEhC,CAAC,EACM,CAAC,GAAGwB,EAAS,GAAGR,CAAS,CAClC"}
@@ -0,0 +1,52 @@
1
+ //#region src/lib/treeCascade.ts
2
+ function e(t, n) {
3
+ for (let r of t) n(r), e(r.children, n);
4
+ }
5
+ function t(e, n) {
6
+ for (let r of e) {
7
+ if (r.value === n) return [r];
8
+ let e = t(r.children, n);
9
+ if (e) return [r, ...e];
10
+ }
11
+ return null;
12
+ }
13
+ function n(t, n, r = !1) {
14
+ let i = /* @__PURE__ */ new Map();
15
+ e(t, (e) => {
16
+ i.has(e.value) || i.set(e.value, e);
17
+ });
18
+ let a = /* @__PURE__ */ new Map(), o = (e, t) => {
19
+ let r = t || n.has(e.value), s = e.children.map((e) => o(e, r)), c;
20
+ return c = r ? "checked" : s.length === 0 ? "unchecked" : s.every((e) => e === "checked") ? "checked" : s.some((e) => e !== "unchecked") ? "mixed" : "unchecked", i.get(e.value) === e && a.set(e.value, c), c;
21
+ };
22
+ for (let e of t) o(e, r);
23
+ return a;
24
+ }
25
+ function r(r, i, a) {
26
+ let o = n(r, new Set(i)), s = /* @__PURE__ */ new Set();
27
+ for (let [e, t] of o) t === "checked" && s.add(e);
28
+ let c = /* @__PURE__ */ new Set();
29
+ e(r, (e) => c.add(e.value));
30
+ let l = Array.from(new Set(i.filter((e) => !c.has(e)))), u = t(r, a);
31
+ if (u) {
32
+ let t = u[u.length - 1], n = o.get(a) !== "checked";
33
+ e([t], (e) => {
34
+ n ? s.add(e.value) : s.delete(e.value);
35
+ });
36
+ for (let e = u.length - 2; e >= 0; --e) {
37
+ let t = u[e];
38
+ t.children.every((e) => s.has(e.value)) ? s.add(t.value) : s.delete(t.value);
39
+ }
40
+ } else {
41
+ let e = l.indexOf(a);
42
+ e === -1 ? l.push(a) : l.splice(e, 1);
43
+ }
44
+ let d = [], f = /* @__PURE__ */ new Set();
45
+ return e(r, (e) => {
46
+ s.has(e.value) && !f.has(e.value) && (f.add(e.value), d.push(e.value));
47
+ }), [...d, ...l];
48
+ }
49
+ //#endregion
50
+ export { n as computeCheckStates, r as toggleCheck };
51
+
52
+ //# sourceMappingURL=treeCascade.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"treeCascade.mjs","names":["forEachNode","node","nodes","visit","findPath","value","below","computeCheckStates","first","candidate","states","forced","forcedAbove","listed","current","childStates","child","state","childState","top","ancestorListed","toggleCheck","checked","itemValue","known","unmatched","listedValue","path","target","turnOn","index","ancestor","at","ordered","seen"],"sources":["../../src/lib/treeCascade.ts"],"sourcesContent":["// The pure check-state cascade of the trees: server-safe, no React import. The nested Tree feeds it\n// a forest read from its elements (`Tree.selection.ts`), the flat tree a forest built from flat data\n// (`flatTree.ts`).\n\n/** One Tree.Item of the cascade model: its value and the items nested in it. */\nexport interface TreeNode {\n value: string;\n children: TreeNode[];\n}\n\n/** The check state of an item in a `selectionMode=\"multiple\"` tree. */\nexport type CheckState = 'checked' | 'mixed' | 'unchecked';\n\nfunction forEachNode(nodes: readonly TreeNode[], visit: (node: TreeNode) => void): void {\n for (const node of nodes) {\n visit(node);\n forEachNode(node.children, visit);\n }\n}\n\n/** The first item with `value` in tree order and its ancestors, from the top down; `null` if none. */\nfunction findPath(nodes: readonly TreeNode[], value: string): TreeNode[] | null {\n for (const node of nodes) {\n if (node.value === value) return [node];\n const below = findPath(node.children, value);\n if (below) return [node, ...below];\n }\n return null;\n}\n\n/**\n * The check state of every item: checked when its value is listed, when an ancestor's value is\n * listed (or `ancestorListed`), or when it has nested items and all of them are checked; mixed\n * when some of them are checked or mixed; else unchecked. For a value that several items share,\n * the first item in tree order decides the entry.\n */\nexport function computeCheckStates(\n nodes: readonly TreeNode[],\n listed: ReadonlySet<string>,\n ancestorListed = false,\n): Map<string, CheckState> {\n const first = new Map<string, TreeNode>();\n forEachNode(nodes, (candidate) => {\n if (!first.has(candidate.value)) first.set(candidate.value, candidate);\n });\n const states = new Map<string, CheckState>();\n const visit = (current: TreeNode, forcedAbove: boolean): CheckState => {\n const forced = forcedAbove || listed.has(current.value);\n const childStates = current.children.map((child) => visit(child, forced));\n let state: CheckState;\n if (forced) state = 'checked';\n else if (childStates.length === 0) state = 'unchecked';\n else if (childStates.every((childState) => childState === 'checked')) state = 'checked';\n else if (childStates.some((childState) => childState !== 'unchecked')) state = 'mixed';\n else state = 'unchecked';\n if (first.get(current.value) === current) states.set(current.value, state);\n return state;\n };\n for (const top of nodes) visit(top, ancestorListed);\n return states;\n}\n\n/**\n * The checked items after toggling `value`. A checked item and every item nested in it become\n * unchecked; an unchecked or mixed one and every item nested in it become checked; its ancestors\n * then follow their nested items. Returns every checked item in tree order (fully checked parents\n * included, mixed ones not), each value once, followed by the listed values that match no item,\n * in their order; a value that no item has is added to, or removed from, those.\n */\nexport function toggleCheck(\n nodes: readonly TreeNode[],\n listed: readonly string[],\n value: string,\n): string[] {\n const states = computeCheckStates(nodes, new Set(listed));\n const checked = new Set<string>();\n for (const [itemValue, state] of states) {\n if (state === 'checked') checked.add(itemValue);\n }\n const known = new Set<string>();\n forEachNode(nodes, (candidate) => known.add(candidate.value));\n const unmatched = Array.from(new Set(listed.filter((listedValue) => !known.has(listedValue))));\n\n const path = findPath(nodes, value);\n if (path) {\n const target = path[path.length - 1];\n const turnOn = states.get(value) !== 'checked';\n forEachNode([target], (candidate) => {\n if (turnOn) checked.add(candidate.value);\n else checked.delete(candidate.value);\n });\n for (let index = path.length - 2; index >= 0; index -= 1) {\n const ancestor = path[index];\n if (ancestor.children.every((child) => checked.has(child.value))) checked.add(ancestor.value);\n else checked.delete(ancestor.value);\n }\n } else {\n const at = unmatched.indexOf(value);\n if (at === -1) unmatched.push(value);\n else unmatched.splice(at, 1);\n }\n\n const ordered: string[] = [];\n const seen = new Set<string>();\n forEachNode(nodes, (candidate) => {\n if (checked.has(candidate.value) && !seen.has(candidate.value)) {\n seen.add(candidate.value);\n ordered.push(candidate.value);\n }\n });\n return [...ordered, ...unmatched];\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ function e(e,t){return Number.isFinite(e)?Math.max(0,Math.floor(e)):t}function t(t){let{itemSize:n,keep:r}=t,i=e(t.count,0);if(i===0)return[];let a=Number.isFinite(n)&&n>0?n:1,o=Math.max(1,Number.isFinite(t.viewportSize)?Math.ceil(t.viewportSize/a):1),s=e(t.overscan,0),c=Math.min(e(t.firstVisible,0),Math.max(0,i-o)),l=Math.max(0,c-s),u=Math.min(i,c+o+s),d=[...new Set(r??[])].filter(e=>Number.isInteger(e)&&e>=0&&e<i).filter(e=>e<l||e>=u).sort((e,t)=>e-t),f=[],p=(e,t)=>{let n=f[f.length-1];n&&e<=n[1]?n[1]=Math.max(n[1],t):f.push([e,t])},m=!1;for(let e of d)!m&&e>l&&(p(l,u),m=!0),p(e,e+1);m||p(l,u);let h=[],g=0;for(let[e,t]of f){e>g&&h.push({kind:`spacer`,size:(e-g)*a,key:`spacer-${e}`});for(let n=e;n<t;n++)h.push({kind:`item`,index:n});g=t}return g<i&&h.push({kind:`spacer`,size:(i-g)*a,key:`spacer-end`}),h}function n(t){let{align:n,scrollTop:r,viewportSize:i}=t,a=e(t.count,0),o=Number.isFinite(t.itemSize)&&t.itemSize>0?t.itemSize:0,s=Number.isFinite(i)?Math.max(0,i):0,c=Math.max(0,a*o-s);if(a===0||c===0)return 0;let l=Math.min(Math.max(0,Number.isFinite(t.index)?Math.floor(t.index):0),a-1)*o,u=l+o,d=Number.isFinite(r)?r:0,f;switch(n){case`start`:f=l;break;case`end`:f=u-s;break;case`center`:f=l+o/2-s/2;break;default:f=l<d?l:u>d+s?u-s:d}return Math.min(Math.max(0,f),c)}exports.computeVirtualLayout=t,exports.scrollOffsetForIndex=n;
2
+ //# sourceMappingURL=virtual.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual.cjs","names":["toCount","value","fallback","computeVirtualLayout","input","count","rowSize","itemSize","visibleCount","overscan","first","start","end","extra","keep","index","a","b","runs","push","last","from","to","windowPushed","entries","next","scrollOffsetForIndex","viewport","viewportSize","maxOffset","top","bottom","current","scrollTop","target","align"],"sources":["../../src/lib/virtual.ts"],"sourcesContent":["/**\n * One entry of a windowed list: a row to render, or the empty space that stands in for the rows\n * that are not rendered. A spacer's `key` is stable for React: `spacer-<index of the next item>`,\n * or `spacer-end` for the one after the last item.\n */\nexport type VirtualEntry =\n { kind: 'item'; index: number } | { kind: 'spacer'; size: number; key: string };\n\n/** Input of {@link computeVirtualLayout}. */\nexport interface VirtualLayoutInput {\n /** Number of rows in the whole list. */\n count: number;\n /** Height (or width) of one row, in pixels. */\n itemSize: number;\n /** Index of the first row in view. Clamped to `[0, max(0, count - rows in view)]`. */\n firstVisible: number;\n /** Height (or width) of the scroll viewport, in pixels. */\n viewportSize: number;\n /** Rows rendered beyond each edge of the view. */\n overscan: number;\n /**\n * Indexes that stay rendered outside the window (the focused row, the row a drag holds).\n * Entries that are not integers inside the list are ignored.\n */\n keep?: readonly number[];\n}\n\n/** An index run, `[from, to)`. */\ntype Run = readonly [from: number, to: number];\n\nfunction toCount(value: number, fallback: number): number {\n return Number.isFinite(value) ? Math.max(0, Math.floor(value)) : fallback;\n}\n\n/**\n * The rows to render for a scrolled list and the spacers that keep its scroll height: the rows in\n * view with `overscan` rows on both sides, plus every `keep` index as a run of its own. The sizes\n * of the items and the spacers add up to `count * itemSize`; a spacer is never empty.\n */\nexport function computeVirtualLayout(input: VirtualLayoutInput): readonly VirtualEntry[] {\n const { itemSize, keep } = input;\n const count = toCount(input.count, 0);\n if (count === 0) return [];\n\n const rowSize = Number.isFinite(itemSize) && itemSize > 0 ? itemSize : 1;\n const visibleCount = Math.max(\n 1,\n Number.isFinite(input.viewportSize) ? Math.ceil(input.viewportSize / rowSize) : 1,\n );\n const overscan = toCount(input.overscan, 0);\n // A scroller never shows a first row past the last full page: a list that shrank under a\n // scrolled window is clamped the way the browser clamps `scrollTop`.\n const first = Math.min(toCount(input.firstVisible, 0), Math.max(0, count - visibleCount));\n const start = Math.max(0, first - overscan);\n const end = Math.min(count, first + visibleCount + overscan);\n\n // The window and the kept rows outside it, sorted; touching runs merge into one.\n const extra = [...new Set(keep ?? [])]\n .filter((index) => Number.isInteger(index) && index >= 0 && index < count)\n .filter((index) => index < start || index >= end)\n .sort((a, b) => a - b);\n const runs: [number, number][] = [];\n const push = (from: number, to: number) => {\n const last = runs[runs.length - 1];\n if (last && from <= last[1]) last[1] = Math.max(last[1], to);\n else runs.push([from, to]);\n };\n let windowPushed = false;\n for (const index of extra) {\n if (!windowPushed && index > start) {\n push(start, end);\n windowPushed = true;\n }\n push(index, index + 1);\n }\n if (!windowPushed) push(start, end);\n\n const entries: VirtualEntry[] = [];\n let next = 0;\n for (const [from, to] of runs as readonly Run[]) {\n if (from > next)\n entries.push({ kind: 'spacer', size: (from - next) * rowSize, key: `spacer-${from}` });\n for (let index = from; index < to; index++) entries.push({ kind: 'item', index });\n next = to;\n }\n if (next < count)\n entries.push({ kind: 'spacer', size: (count - next) * rowSize, key: 'spacer-end' });\n return entries;\n}\n\n/** Input of {@link scrollOffsetForIndex}. */\nexport interface ScrollOffsetInput {\n index: number;\n /**\n * Where the row ends up: `'start'`, `'center'` or `'end'` of the viewport, or `'auto'`, the\n * smallest move that shows it whole (the current offset when it already is).\n */\n align: 'auto' | 'start' | 'center' | 'end';\n itemSize: number;\n count: number;\n scrollTop: number;\n viewportSize: number;\n}\n\n/** The scroll offset, clamped to the content, that brings row `index` to the requested place. */\nexport function scrollOffsetForIndex(input: ScrollOffsetInput): number {\n const { align, scrollTop, viewportSize } = input;\n const count = toCount(input.count, 0);\n const rowSize = Number.isFinite(input.itemSize) && input.itemSize > 0 ? input.itemSize : 0;\n const viewport = Number.isFinite(viewportSize) ? Math.max(0, viewportSize) : 0;\n const maxOffset = Math.max(0, count * rowSize - viewport);\n if (count === 0 || maxOffset === 0) return 0;\n\n const index = Math.min(\n Math.max(0, Number.isFinite(input.index) ? Math.floor(input.index) : 0),\n count - 1,\n );\n const top = index * rowSize;\n const bottom = top + rowSize;\n const current = Number.isFinite(scrollTop) ? scrollTop : 0;\n\n let target: number;\n switch (align) {\n case 'start':\n target = top;\n break;\n case 'end':\n target = bottom - viewport;\n break;\n case 'center':\n target = top + rowSize / 2 - viewport / 2;\n break;\n default:\n target = top < current ? top : bottom > current + viewport ? bottom - viewport : current;\n }\n return Math.min(Math.max(0, target), maxOffset);\n}\n"],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ //#region src/lib/virtual.ts
2
+ function e(e, t) {
3
+ return Number.isFinite(e) ? Math.max(0, Math.floor(e)) : t;
4
+ }
5
+ function t(t) {
6
+ let { itemSize: n, keep: r } = t, i = e(t.count, 0);
7
+ if (i === 0) return [];
8
+ let a = Number.isFinite(n) && n > 0 ? n : 1, o = Math.max(1, Number.isFinite(t.viewportSize) ? Math.ceil(t.viewportSize / a) : 1), s = e(t.overscan, 0), c = Math.min(e(t.firstVisible, 0), Math.max(0, i - o)), l = Math.max(0, c - s), u = Math.min(i, c + o + s), d = [...new Set(r ?? [])].filter((e) => Number.isInteger(e) && e >= 0 && e < i).filter((e) => e < l || e >= u).sort((e, t) => e - t), f = [], p = (e, t) => {
9
+ let n = f[f.length - 1];
10
+ n && e <= n[1] ? n[1] = Math.max(n[1], t) : f.push([e, t]);
11
+ }, m = !1;
12
+ for (let e of d) !m && e > l && (p(l, u), m = !0), p(e, e + 1);
13
+ m || p(l, u);
14
+ let h = [], g = 0;
15
+ for (let [e, t] of f) {
16
+ e > g && h.push({
17
+ kind: "spacer",
18
+ size: (e - g) * a,
19
+ key: `spacer-${e}`
20
+ });
21
+ for (let n = e; n < t; n++) h.push({
22
+ kind: "item",
23
+ index: n
24
+ });
25
+ g = t;
26
+ }
27
+ return g < i && h.push({
28
+ kind: "spacer",
29
+ size: (i - g) * a,
30
+ key: "spacer-end"
31
+ }), h;
32
+ }
33
+ function n(t) {
34
+ let { align: n, scrollTop: r, viewportSize: i } = t, a = e(t.count, 0), o = Number.isFinite(t.itemSize) && t.itemSize > 0 ? t.itemSize : 0, s = Number.isFinite(i) ? Math.max(0, i) : 0, c = Math.max(0, a * o - s);
35
+ if (a === 0 || c === 0) return 0;
36
+ let l = Math.min(Math.max(0, Number.isFinite(t.index) ? Math.floor(t.index) : 0), a - 1) * o, u = l + o, d = Number.isFinite(r) ? r : 0, f;
37
+ switch (n) {
38
+ case "start":
39
+ f = l;
40
+ break;
41
+ case "end":
42
+ f = u - s;
43
+ break;
44
+ case "center":
45
+ f = l + o / 2 - s / 2;
46
+ break;
47
+ default: f = l < d ? l : u > d + s ? u - s : d;
48
+ }
49
+ return Math.min(Math.max(0, f), c);
50
+ }
51
+ //#endregion
52
+ export { t as computeVirtualLayout, n as scrollOffsetForIndex };
53
+
54
+ //# sourceMappingURL=virtual.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual.mjs","names":["toCount","value","fallback","computeVirtualLayout","input","count","rowSize","itemSize","visibleCount","overscan","first","start","end","extra","keep","index","a","b","runs","push","last","from","to","windowPushed","entries","next","scrollOffsetForIndex","viewport","viewportSize","maxOffset","top","bottom","current","scrollTop","target","align"],"sources":["../../src/lib/virtual.ts"],"sourcesContent":["/**\n * One entry of a windowed list: a row to render, or the empty space that stands in for the rows\n * that are not rendered. A spacer's `key` is stable for React: `spacer-<index of the next item>`,\n * or `spacer-end` for the one after the last item.\n */\nexport type VirtualEntry =\n { kind: 'item'; index: number } | { kind: 'spacer'; size: number; key: string };\n\n/** Input of {@link computeVirtualLayout}. */\nexport interface VirtualLayoutInput {\n /** Number of rows in the whole list. */\n count: number;\n /** Height (or width) of one row, in pixels. */\n itemSize: number;\n /** Index of the first row in view. Clamped to `[0, max(0, count - rows in view)]`. */\n firstVisible: number;\n /** Height (or width) of the scroll viewport, in pixels. */\n viewportSize: number;\n /** Rows rendered beyond each edge of the view. */\n overscan: number;\n /**\n * Indexes that stay rendered outside the window (the focused row, the row a drag holds).\n * Entries that are not integers inside the list are ignored.\n */\n keep?: readonly number[];\n}\n\n/** An index run, `[from, to)`. */\ntype Run = readonly [from: number, to: number];\n\nfunction toCount(value: number, fallback: number): number {\n return Number.isFinite(value) ? Math.max(0, Math.floor(value)) : fallback;\n}\n\n/**\n * The rows to render for a scrolled list and the spacers that keep its scroll height: the rows in\n * view with `overscan` rows on both sides, plus every `keep` index as a run of its own. The sizes\n * of the items and the spacers add up to `count * itemSize`; a spacer is never empty.\n */\nexport function computeVirtualLayout(input: VirtualLayoutInput): readonly VirtualEntry[] {\n const { itemSize, keep } = input;\n const count = toCount(input.count, 0);\n if (count === 0) return [];\n\n const rowSize = Number.isFinite(itemSize) && itemSize > 0 ? itemSize : 1;\n const visibleCount = Math.max(\n 1,\n Number.isFinite(input.viewportSize) ? Math.ceil(input.viewportSize / rowSize) : 1,\n );\n const overscan = toCount(input.overscan, 0);\n // A scroller never shows a first row past the last full page: a list that shrank under a\n // scrolled window is clamped the way the browser clamps `scrollTop`.\n const first = Math.min(toCount(input.firstVisible, 0), Math.max(0, count - visibleCount));\n const start = Math.max(0, first - overscan);\n const end = Math.min(count, first + visibleCount + overscan);\n\n // The window and the kept rows outside it, sorted; touching runs merge into one.\n const extra = [...new Set(keep ?? [])]\n .filter((index) => Number.isInteger(index) && index >= 0 && index < count)\n .filter((index) => index < start || index >= end)\n .sort((a, b) => a - b);\n const runs: [number, number][] = [];\n const push = (from: number, to: number) => {\n const last = runs[runs.length - 1];\n if (last && from <= last[1]) last[1] = Math.max(last[1], to);\n else runs.push([from, to]);\n };\n let windowPushed = false;\n for (const index of extra) {\n if (!windowPushed && index > start) {\n push(start, end);\n windowPushed = true;\n }\n push(index, index + 1);\n }\n if (!windowPushed) push(start, end);\n\n const entries: VirtualEntry[] = [];\n let next = 0;\n for (const [from, to] of runs as readonly Run[]) {\n if (from > next)\n entries.push({ kind: 'spacer', size: (from - next) * rowSize, key: `spacer-${from}` });\n for (let index = from; index < to; index++) entries.push({ kind: 'item', index });\n next = to;\n }\n if (next < count)\n entries.push({ kind: 'spacer', size: (count - next) * rowSize, key: 'spacer-end' });\n return entries;\n}\n\n/** Input of {@link scrollOffsetForIndex}. */\nexport interface ScrollOffsetInput {\n index: number;\n /**\n * Where the row ends up: `'start'`, `'center'` or `'end'` of the viewport, or `'auto'`, the\n * smallest move that shows it whole (the current offset when it already is).\n */\n align: 'auto' | 'start' | 'center' | 'end';\n itemSize: number;\n count: number;\n scrollTop: number;\n viewportSize: number;\n}\n\n/** The scroll offset, clamped to the content, that brings row `index` to the requested place. */\nexport function scrollOffsetForIndex(input: ScrollOffsetInput): number {\n const { align, scrollTop, viewportSize } = input;\n const count = toCount(input.count, 0);\n const rowSize = Number.isFinite(input.itemSize) && input.itemSize > 0 ? input.itemSize : 0;\n const viewport = Number.isFinite(viewportSize) ? Math.max(0, viewportSize) : 0;\n const maxOffset = Math.max(0, count * rowSize - viewport);\n if (count === 0 || maxOffset === 0) return 0;\n\n const index = Math.min(\n Math.max(0, Number.isFinite(input.index) ? Math.floor(input.index) : 0),\n count - 1,\n );\n const top = index * rowSize;\n const bottom = top + rowSize;\n const current = Number.isFinite(scrollTop) ? scrollTop : 0;\n\n let target: number;\n switch (align) {\n case 'start':\n target = top;\n break;\n case 'end':\n target = bottom - viewport;\n break;\n case 'center':\n target = top + rowSize / 2 - viewport / 2;\n break;\n default:\n target = top < current ? top : bottom > current + viewport ? bottom - viewport : current;\n }\n return Math.min(Math.max(0, target), maxOffset);\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require("./tokens.cjs");var t=`fontFamily.fontFamilyMonospace.fontFamilyNumeric.zOverlay.zToast.zTooltip.durationUltraFast.durationFaster.durationFast.durationNormal.durationGentle.durationSlow.durationSlower.durationUltraSlow.curveAccelerateMax.curveAccelerateMid.curveAccelerateMin.curveDecelerateMax.curveDecelerateMid.curveDecelerateMin.curveEasyEaseMax.curveEasyEase.curveLinear.brand10.brand20.brand30.brand40.brand50.brand60.brand70.brand80.brand90.brand100.brand110.brand120.brand130.brand140.brand150.brand160.grey2.grey4.grey6.grey8.grey10.grey12.grey14.grey16.grey20.grey24.grey26.grey30.grey34.grey38.grey40.grey44.grey50.grey60.grey68.grey74.grey78.grey82.grey86.grey88.grey90.grey92.grey94.grey96.grey98.background.foreground.card.secondary.muted.mutedForeground.mutedHover.mutedPressed.primary.primaryForeground.primaryHover.primaryPressed.destructive.destructiveForeground.error.errorForeground.subtle.subtleHover.subtlePressed.subtleSelected.selected.selectedForeground.selectedHover.selectedPressed.border.stroke.strokeHover.strokeAccessible.input.inputFilledDarker.inputFilledStroke.ring.success.successForeground.successTint.successTintForeground.warning.warningForeground.warningTint.warningTintForeground.errorTint.errorTintForeground.severe.severeForeground.severeTint.severeTintForeground.info.infoForeground.infoTint.infoTintForeground.inverted.invertedForeground.invertedBorder.track.skeleton.rating.presenceAvailable.presenceBusy.presenceAway.presenceOffline.presenceOof.presenceGlyph.backdrop.paletteRed.paletteRedForeground.paletteRedTint.paletteRedTintForeground.paletteRedBorder.palettePumpkin.palettePumpkinForeground.palettePumpkinTint.palettePumpkinTintForeground.palettePumpkinBorder.paletteGold.paletteGoldForeground.paletteGoldTint.paletteGoldTintForeground.paletteGoldBorder.paletteForest.paletteForestForeground.paletteForestTint.paletteForestTintForeground.paletteForestBorder.paletteTeal.paletteTealForeground.paletteTealTint.paletteTealTintForeground.paletteTealBorder.paletteBlue.paletteBlueForeground.paletteBlueTint.paletteBlueTintForeground.paletteBlueBorder.paletteNavy.paletteNavyForeground.paletteNavyTint.paletteNavyTintForeground.paletteNavyBorder.paletteLavender.paletteLavenderForeground.paletteLavenderTint.paletteLavenderTintForeground.paletteLavenderBorder.palettePurple.palettePurpleForeground.palettePurpleTint.palettePurpleTintForeground.palettePurpleBorder.paletteMagenta.paletteMagentaForeground.paletteMagentaTint.paletteMagentaTintForeground.paletteMagentaBorder.paletteBrown.paletteBrownForeground.paletteBrownTint.paletteBrownTintForeground.paletteBrownBorder.paletteSteel.paletteSteelForeground.paletteSteelTint.paletteSteelTintForeground.paletteSteelBorder.shadow2.shadow4.shadow8.shadow16.shadow28.shadow64.cardForeground.secondaryForeground.accent.accentForeground.inputFilledLighter`.split(`.`);function n(){return Object.freeze(Object.fromEntries(t.map(t=>[t,`var(${e.tokenVariable(t)})`])))}var r=n(),i=Object.freeze([`paletteBlue`,`palettePurple`,`paletteBrown`,`paletteTeal`,`paletteRed`,`paletteNavy`,`palettePumpkin`,`paletteSteel`,`paletteGold`,`paletteLavender`,`paletteForest`,`paletteMagenta`]);exports.WAVE_TOKEN_NAMES=t,exports.chartPalette=i,exports.waveTokens=r;
2
+ //# sourceMappingURL=waveTokens.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waveTokens.cjs","names":["tokenVariable","require_tokens","WAVE_TOKEN_NAMES","createWaveTokens","name","waveTokens","chartPalette"],"sources":["../../src/lib/waveTokens.ts"],"sourcesContent":["/**\n * The typed token object and the chart palette. Server-safe. No component imports this module:\n * the provider converts token names with a rule, so the list of names reaches only the bundles\n * that use `waveTokens` or `chartPalette`.\n */\nimport { tokenVariable } from './tokens';\nimport type { TokenVariable, WaveTokenName } from './tokens';\n\n/**\n * The name of every `--wave-*` variable of `tokens.css`, in camelCase, in the file's groups and\n * order. A test parses `tokens.css` and fails when a variable is missing here or a name has none.\n */\nexport const WAVE_TOKEN_NAMES = [\n // Theme-independent constants: font families\n 'fontFamily',\n 'fontFamilyMonospace',\n 'fontFamilyNumeric',\n // z-index layers\n 'zOverlay',\n 'zToast',\n 'zTooltip',\n // Motion: durations and curves (Fluent's motion tokens)\n 'durationUltraFast',\n 'durationFaster',\n 'durationFast',\n 'durationNormal',\n 'durationGentle',\n 'durationSlow',\n 'durationSlower',\n 'durationUltraSlow',\n 'curveAccelerateMax',\n 'curveAccelerateMid',\n 'curveAccelerateMin',\n 'curveDecelerateMax',\n 'curveDecelerateMid',\n 'curveDecelerateMin',\n 'curveEasyEaseMax',\n 'curveEasyEase',\n 'curveLinear',\n // Brand ramp\n 'brand10',\n 'brand20',\n 'brand30',\n 'brand40',\n 'brand50',\n 'brand60',\n 'brand70',\n 'brand80',\n 'brand90',\n 'brand100',\n 'brand110',\n 'brand120',\n 'brand130',\n 'brand140',\n 'brand150',\n 'brand160',\n // Neutral grey ramp\n 'grey2',\n 'grey4',\n 'grey6',\n 'grey8',\n 'grey10',\n 'grey12',\n 'grey14',\n 'grey16',\n 'grey20',\n 'grey24',\n 'grey26',\n 'grey30',\n 'grey34',\n 'grey38',\n 'grey40',\n 'grey44',\n 'grey50',\n 'grey60',\n 'grey68',\n 'grey74',\n 'grey78',\n 'grey82',\n 'grey86',\n 'grey88',\n 'grey90',\n 'grey92',\n 'grey94',\n 'grey96',\n 'grey98',\n // Every theme group (light, dark, high contrast) declares the rest. Surfaces and text\n 'background',\n 'foreground',\n 'card',\n 'secondary',\n 'muted',\n 'mutedForeground',\n 'mutedHover',\n 'mutedPressed',\n // Primary (brand)\n 'primary',\n 'primaryForeground',\n 'primaryHover',\n 'primaryPressed',\n // Destructive / error\n 'destructive',\n 'destructiveForeground',\n 'error',\n 'errorForeground',\n // Subtle (transparent) controls and selection\n 'subtle',\n 'subtleHover',\n 'subtlePressed',\n 'subtleSelected',\n 'selected',\n 'selectedForeground',\n 'selectedHover',\n 'selectedPressed',\n // Strokes\n 'border',\n 'stroke',\n 'strokeHover',\n 'strokeAccessible',\n 'input',\n 'inputFilledDarker',\n 'inputFilledStroke',\n 'ring',\n // Status\n 'success',\n 'successForeground',\n 'successTint',\n 'successTintForeground',\n 'warning',\n 'warningForeground',\n 'warningTint',\n 'warningTintForeground',\n 'errorTint',\n 'errorTintForeground',\n 'severe',\n 'severeForeground',\n 'severeTint',\n 'severeTintForeground',\n 'info',\n 'infoForeground',\n 'infoTint',\n 'infoTintForeground',\n // Inverted surfaces (tooltips)\n 'inverted',\n 'invertedForeground',\n 'invertedBorder',\n // Tracks, placeholders, rating, presence, backdrop (the file declares the backdrop after the\n // palette)\n 'track',\n 'skeleton',\n 'rating',\n 'presenceAvailable',\n 'presenceBusy',\n 'presenceAway',\n 'presenceOffline',\n 'presenceOof',\n 'presenceGlyph',\n 'backdrop',\n // Persona palette: per hue the fill, its text, the tint, the tint's text and the border\n 'paletteRed',\n 'paletteRedForeground',\n 'paletteRedTint',\n 'paletteRedTintForeground',\n 'paletteRedBorder',\n 'palettePumpkin',\n 'palettePumpkinForeground',\n 'palettePumpkinTint',\n 'palettePumpkinTintForeground',\n 'palettePumpkinBorder',\n 'paletteGold',\n 'paletteGoldForeground',\n 'paletteGoldTint',\n 'paletteGoldTintForeground',\n 'paletteGoldBorder',\n 'paletteForest',\n 'paletteForestForeground',\n 'paletteForestTint',\n 'paletteForestTintForeground',\n 'paletteForestBorder',\n 'paletteTeal',\n 'paletteTealForeground',\n 'paletteTealTint',\n 'paletteTealTintForeground',\n 'paletteTealBorder',\n 'paletteBlue',\n 'paletteBlueForeground',\n 'paletteBlueTint',\n 'paletteBlueTintForeground',\n 'paletteBlueBorder',\n 'paletteNavy',\n 'paletteNavyForeground',\n 'paletteNavyTint',\n 'paletteNavyTintForeground',\n 'paletteNavyBorder',\n 'paletteLavender',\n 'paletteLavenderForeground',\n 'paletteLavenderTint',\n 'paletteLavenderTintForeground',\n 'paletteLavenderBorder',\n 'palettePurple',\n 'palettePurpleForeground',\n 'palettePurpleTint',\n 'palettePurpleTintForeground',\n 'palettePurpleBorder',\n 'paletteMagenta',\n 'paletteMagentaForeground',\n 'paletteMagentaTint',\n 'paletteMagentaTintForeground',\n 'paletteMagentaBorder',\n 'paletteBrown',\n 'paletteBrownForeground',\n 'paletteBrownTint',\n 'paletteBrownTintForeground',\n 'paletteBrownBorder',\n 'paletteSteel',\n 'paletteSteelForeground',\n 'paletteSteelTint',\n 'paletteSteelTintForeground',\n 'paletteSteelBorder',\n // Elevation\n 'shadow2',\n 'shadow4',\n 'shadow8',\n 'shadow16',\n 'shadow28',\n 'shadow64',\n // Derived (re-declared per theme so nested themes re-resolve them)\n 'cardForeground',\n 'secondaryForeground',\n 'accent',\n 'accentForeground',\n 'inputFilledLighter',\n] as const;\n\n// Object.fromEntries types its result as a record of strings; the names give it its keys.\nfunction createWaveTokens() {\n return Object.freeze(\n Object.fromEntries(WAVE_TOKEN_NAMES.map((name) => [name, `var(${tokenVariable(name)})`])),\n ) as typeof waveTokens;\n}\n\n/**\n * Every design token as the CSS value that reads it: `waveTokens.primary` is\n * `'var(--wave-primary)'`, typed as that literal. Use it where a style is written in JavaScript\n * (an inline style, a CSS-in-JS rule, the colours of an SVG chart), so the value follows the theme\n * and the provider's token overrides. The counterpart of Fluent's `tokens` object\n * (`tokens.colorBrandBackground`), with Wave's names: the CSS variable in camelCase without its\n * `--wave-` prefix. A canvas library cannot read a CSS variable: resolve the value with\n * `getComputedStyle` on an element inside the provider, and again when the theme changes.\n * Frozen and server-safe; no component imports it.\n *\n * @example\n * <span style={{ color: waveTokens.primary, boxShadow: waveTokens.shadow8 }} />\n */\nexport const waveTokens: { readonly [K in WaveTokenName]: `var(${TokenVariable<K>})` } =\n /* @__PURE__ */ createWaveTokens();\n\n/**\n * The 12 palette fills as token names, in the order a categorical chart gives them to its series.\n * The order keeps neighbouring series as far apart as the palette allows, for colour vision and\n * for hue: in the light and dark themes, every two neighbours (the first and second, the second\n * and third, up to the eleventh and twelfth) differ by at least 6.3 (OKLab ΔE ×100) under\n * simulated protanopia, deuteranopia and tritanopia and by at least 15.7 for full colour vision,\n * and their hues are at least 49° apart. The first six are the six fills that stay furthest apart\n * as a set, yet no six fills of the palette keep every pair apart for colour-vision deficiencies:\n * two series that are not neighbours can differ by only about 3.2 among the first six, and by\n * less further on. So colour never identifies a series on its own: every chart needs a second\n * encoding (a pattern, a marker shape or a direct label), whatever its number of series, and in\n * high contrast every palette fill is white. Read each colour through `waveTokens`\n * (`waveTokens[chartPalette[index]]`), so the series follow the theme. Frozen and server-safe.\n *\n * @example\n * const color = waveTokens[chartPalette[index % chartPalette.length]];\n */\nexport const chartPalette: readonly WaveTokenName[] = /* @__PURE__ */ Object.freeze([\n 'paletteBlue',\n 'palettePurple',\n 'paletteBrown',\n 'paletteTeal',\n 'paletteRed',\n 'paletteNavy',\n 'palettePumpkin',\n 'paletteSteel',\n 'paletteGold',\n 'paletteLavender',\n 'paletteForest',\n 'paletteMagenta',\n]);\n"],"mappings":"gCAYA,IAAaE,EAAmB,ixFA4NhC,EAGA,SAASC,GAAmB,CAC1B,OAAO,OAAO,OACZ,OAAO,YAAYD,EAAiB,IAAK,GAAS,CAACE,EAAM,OAAOJ,EAAAA,cAAcI,CAAI,EAAE,EAAE,CAAC,CAAC,CAC1F,CACF,CAeA,IAAaC,EACKF,EAAiB,EAmBtBG,EAAyD,OAAO,OAAO,CAClF,cACA,gBACA,eACA,cACA,aACA,cACA,iBACA,eACA,cACA,kBACA,gBACA,gBACF,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { tokenVariable as e } from "./tokens.mjs";
2
+ //#region src/lib/waveTokens.ts
3
+ var t = /* @__PURE__ */ "fontFamily.fontFamilyMonospace.fontFamilyNumeric.zOverlay.zToast.zTooltip.durationUltraFast.durationFaster.durationFast.durationNormal.durationGentle.durationSlow.durationSlower.durationUltraSlow.curveAccelerateMax.curveAccelerateMid.curveAccelerateMin.curveDecelerateMax.curveDecelerateMid.curveDecelerateMin.curveEasyEaseMax.curveEasyEase.curveLinear.brand10.brand20.brand30.brand40.brand50.brand60.brand70.brand80.brand90.brand100.brand110.brand120.brand130.brand140.brand150.brand160.grey2.grey4.grey6.grey8.grey10.grey12.grey14.grey16.grey20.grey24.grey26.grey30.grey34.grey38.grey40.grey44.grey50.grey60.grey68.grey74.grey78.grey82.grey86.grey88.grey90.grey92.grey94.grey96.grey98.background.foreground.card.secondary.muted.mutedForeground.mutedHover.mutedPressed.primary.primaryForeground.primaryHover.primaryPressed.destructive.destructiveForeground.error.errorForeground.subtle.subtleHover.subtlePressed.subtleSelected.selected.selectedForeground.selectedHover.selectedPressed.border.stroke.strokeHover.strokeAccessible.input.inputFilledDarker.inputFilledStroke.ring.success.successForeground.successTint.successTintForeground.warning.warningForeground.warningTint.warningTintForeground.errorTint.errorTintForeground.severe.severeForeground.severeTint.severeTintForeground.info.infoForeground.infoTint.infoTintForeground.inverted.invertedForeground.invertedBorder.track.skeleton.rating.presenceAvailable.presenceBusy.presenceAway.presenceOffline.presenceOof.presenceGlyph.backdrop.paletteRed.paletteRedForeground.paletteRedTint.paletteRedTintForeground.paletteRedBorder.palettePumpkin.palettePumpkinForeground.palettePumpkinTint.palettePumpkinTintForeground.palettePumpkinBorder.paletteGold.paletteGoldForeground.paletteGoldTint.paletteGoldTintForeground.paletteGoldBorder.paletteForest.paletteForestForeground.paletteForestTint.paletteForestTintForeground.paletteForestBorder.paletteTeal.paletteTealForeground.paletteTealTint.paletteTealTintForeground.paletteTealBorder.paletteBlue.paletteBlueForeground.paletteBlueTint.paletteBlueTintForeground.paletteBlueBorder.paletteNavy.paletteNavyForeground.paletteNavyTint.paletteNavyTintForeground.paletteNavyBorder.paletteLavender.paletteLavenderForeground.paletteLavenderTint.paletteLavenderTintForeground.paletteLavenderBorder.palettePurple.palettePurpleForeground.palettePurpleTint.palettePurpleTintForeground.palettePurpleBorder.paletteMagenta.paletteMagentaForeground.paletteMagentaTint.paletteMagentaTintForeground.paletteMagentaBorder.paletteBrown.paletteBrownForeground.paletteBrownTint.paletteBrownTintForeground.paletteBrownBorder.paletteSteel.paletteSteelForeground.paletteSteelTint.paletteSteelTintForeground.paletteSteelBorder.shadow2.shadow4.shadow8.shadow16.shadow28.shadow64.cardForeground.secondaryForeground.accent.accentForeground.inputFilledLighter".split(".");
4
+ function n() {
5
+ return Object.freeze(Object.fromEntries(t.map((t) => [t, `var(${e(t)})`])));
6
+ }
7
+ var r = /* @__PURE__ */ n(), i = /* @__PURE__ */ Object.freeze([
8
+ "paletteBlue",
9
+ "palettePurple",
10
+ "paletteBrown",
11
+ "paletteTeal",
12
+ "paletteRed",
13
+ "paletteNavy",
14
+ "palettePumpkin",
15
+ "paletteSteel",
16
+ "paletteGold",
17
+ "paletteLavender",
18
+ "paletteForest",
19
+ "paletteMagenta"
20
+ ]);
21
+ //#endregion
22
+ export { t as WAVE_TOKEN_NAMES, i as chartPalette, r as waveTokens };
23
+
24
+ //# sourceMappingURL=waveTokens.mjs.map