@astryxdesign/core 0.1.7-canary.fb9c68c → 0.1.7

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 (137) hide show
  1. package/README.md +15 -24
  2. package/dist/Collapsible/Collapsible.d.ts +1 -11
  3. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  4. package/dist/Collapsible/Collapsible.js +4 -36
  5. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  6. package/dist/ContextMenu/ContextMenu.js +3 -4
  7. package/dist/ContextMenu/index.d.ts +0 -3
  8. package/dist/ContextMenu/index.d.ts.map +1 -1
  9. package/dist/ContextMenu/index.js +1 -7
  10. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  11. package/dist/DropdownMenu/DropdownMenu.js +4 -8
  12. package/dist/DropdownMenu/DropdownMenuContext.d.ts +1 -17
  13. package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
  14. package/dist/DropdownMenu/DropdownMenuContext.js +0 -18
  15. package/dist/DropdownMenu/index.d.ts +1 -5
  16. package/dist/DropdownMenu/index.d.ts.map +1 -1
  17. package/dist/DropdownMenu/index.js +1 -10
  18. package/dist/Icon/Icon.d.ts +12 -17
  19. package/dist/Icon/Icon.d.ts.map +1 -1
  20. package/dist/Icon/Icon.js +20 -28
  21. package/dist/Outline/Outline.d.ts +3 -69
  22. package/dist/Outline/Outline.d.ts.map +1 -1
  23. package/dist/Outline/Outline.js +26 -129
  24. package/dist/Outline/useScrollSpy.d.ts +7 -27
  25. package/dist/Outline/useScrollSpy.d.ts.map +1 -1
  26. package/dist/Outline/useScrollSpy.js +70 -202
  27. package/dist/TabList/Tab.d.ts.map +1 -1
  28. package/dist/TabList/Tab.js +2 -2
  29. package/dist/TabList/TabList.d.ts.map +1 -1
  30. package/dist/TabList/TabList.js +0 -2
  31. package/dist/TabList/TabMenu.d.ts.map +1 -1
  32. package/dist/TabList/TabMenu.js +1 -1
  33. package/dist/Table/index.d.ts +0 -2
  34. package/dist/Table/index.d.ts.map +1 -1
  35. package/dist/Table/index.js +0 -1
  36. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  37. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +2 -24
  38. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  39. package/dist/Table/plugins/sortable/useTableSortable.js +7 -18
  40. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  41. package/dist/Table/useBaseTablePlugins.js +3 -6
  42. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  43. package/dist/Toolbar/Toolbar.js +1 -8
  44. package/dist/astryx.css +2 -18
  45. package/dist/astryx.umd.js +48 -48
  46. package/dist/astryx.umd.js.map +4 -4
  47. package/dist/theme/Theme.js +1 -1
  48. package/dist/theme/defineTheme.d.ts +1 -1
  49. package/dist/theme/defineTheme.js +1 -1
  50. package/dist/theme/hct.d.ts +1 -0
  51. package/dist/theme/hct.d.ts.map +1 -1
  52. package/dist/theme/hct.js +3 -0
  53. package/locales/en.json +0 -28
  54. package/locales/pseudo.json +0 -21
  55. package/package.json +1 -3
  56. package/src/CheckboxInput/CheckboxInput.doc.mjs +1 -1
  57. package/src/Collapsible/Collapsible.doc.mjs +0 -7
  58. package/src/Collapsible/Collapsible.test.tsx +0 -80
  59. package/src/Collapsible/Collapsible.tsx +5 -58
  60. package/src/ContextMenu/ContextMenu.test.tsx +1 -75
  61. package/src/ContextMenu/ContextMenu.tsx +5 -10
  62. package/src/ContextMenu/index.ts +0 -15
  63. package/src/DropdownMenu/DropdownMenu.doc.mjs +0 -23
  64. package/src/DropdownMenu/DropdownMenu.tsx +6 -11
  65. package/src/DropdownMenu/DropdownMenuContext.tsx +1 -29
  66. package/src/DropdownMenu/DropdownMenuItem.doc.mjs +1 -7
  67. package/src/DropdownMenu/index.ts +3 -23
  68. package/src/Field/Field.doc.mjs +1 -1
  69. package/src/Field/FieldLabel.doc.mjs +1 -1
  70. package/src/Icon/Icon.test.tsx +0 -46
  71. package/src/Icon/Icon.tsx +24 -37
  72. package/src/NumberInput/NumberInput.doc.mjs +2 -2
  73. package/src/Outline/Outline.doc.mjs +3 -123
  74. package/src/Outline/Outline.test.tsx +0 -735
  75. package/src/Outline/Outline.tsx +33 -184
  76. package/src/Outline/useScrollSpy.ts +72 -248
  77. package/src/Selector/SelectorOption.doc.mjs +1 -1
  78. package/src/SideNav/SideNavItem.doc.mjs +2 -2
  79. package/src/Switch/Switch.doc.mjs +1 -1
  80. package/src/TabList/Tab.tsx +1 -5
  81. package/src/TabList/TabList.doc.mjs +3 -3
  82. package/src/TabList/TabList.test.tsx +0 -66
  83. package/src/TabList/TabList.tsx +0 -8
  84. package/src/TabList/TabMenu.tsx +1 -4
  85. package/src/Table/Table.doc.mjs +0 -2
  86. package/src/Table/index.ts +0 -7
  87. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +1 -90
  88. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +5 -37
  89. package/src/Table/plugins/sortable/useTableSortable.test.tsx +9 -95
  90. package/src/Table/plugins/sortable/useTableSortable.tsx +7 -23
  91. package/src/Table/useBaseTablePlugins.ts +2 -6
  92. package/src/TextArea/TextArea.doc.mjs +1 -1
  93. package/src/TextInput/TextInput.doc.mjs +1 -1
  94. package/src/Toolbar/Toolbar.tsx +3 -10
  95. package/src/theme/Theme.doc.mjs +4 -4
  96. package/src/theme/Theme.tsx +1 -1
  97. package/src/theme/defineTheme.ts +1 -1
  98. package/src/theme/hct.ts +4 -0
  99. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +0 -89
  100. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +0 -1
  101. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +0 -170
  102. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +0 -69
  103. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +0 -1
  104. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +0 -70
  105. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +0 -69
  106. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +0 -1
  107. package/dist/DropdownMenu/DropdownMenuRadioItem.js +0 -178
  108. package/dist/DropdownMenu/menuItemRoles.d.ts +0 -13
  109. package/dist/DropdownMenu/menuItemRoles.d.ts.map +0 -1
  110. package/dist/DropdownMenu/menuItemRoles.js +0 -15
  111. package/dist/Table/plugins/tree/index.d.ts +0 -5
  112. package/dist/Table/plugins/tree/index.d.ts.map +0 -1
  113. package/dist/Table/plugins/tree/index.js +0 -4
  114. package/dist/Table/plugins/tree/useTableTreeData.d.ts +0 -38
  115. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +0 -1
  116. package/dist/Table/plugins/tree/useTableTreeData.js +0 -358
  117. package/dist/Table/plugins/tree/useTableTreeState.d.ts +0 -51
  118. package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +0 -1
  119. package/dist/Table/plugins/tree/useTableTreeState.js +0 -175
  120. package/scripts/postinstall.mjs +0 -93
  121. package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +0 -95
  122. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +0 -237
  123. package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +0 -80
  124. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +0 -119
  125. package/src/DropdownMenu/DropdownMenuRadioItem.doc.mjs +0 -80
  126. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +0 -232
  127. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +0 -163
  128. package/src/DropdownMenu/menuItemRoles.ts +0 -22
  129. package/src/Table/plugins/tree/index.ts +0 -12
  130. package/src/Table/plugins/tree/useTableTreeData-perf.test.tsx +0 -163
  131. package/src/Table/plugins/tree/useTableTreeData.test.tsx +0 -594
  132. package/src/Table/plugins/tree/useTableTreeData.tsx +0 -495
  133. package/src/Table/plugins/tree/useTableTreeState.test.tsx +0 -636
  134. package/src/Table/plugins/tree/useTableTreeState.tsx +0 -253
  135. package/src/Table/useTableTreeData.doc.mjs +0 -75
  136. package/src/Table/useTableTreeState.doc.mjs +0 -98
  137. package/src/postinstall.test.mjs +0 -71
@@ -1,7 +1,7 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
3
  import {describe, it, expect, vi, beforeEach} from 'vitest';
4
- import {render, renderHook, screen, fireEvent} from '@testing-library/react';
4
+ import {render, screen, fireEvent} from '@testing-library/react';
5
5
  import {useState} from 'react';
6
6
  import {Table} from '../../Table';
7
7
  import type {TableColumn} from '../../types';
@@ -153,92 +153,3 @@ describe('useTableRowExpansion', () => {
153
153
  expect(screen.queryByText('File B1')).not.toBeInTheDocument();
154
154
  });
155
155
  });
156
-
157
- describe('useTableRowExpansionState cycle guard', () => {
158
- /** A row whose children array contains the row itself (plus a real child). */
159
- function makeSelfReferential(): TreeItem[] {
160
- const x: TreeItem = {id: 'x', name: 'Self', children: []};
161
- const y: TreeItem = {id: 'y', name: 'Leaf Y', children: []};
162
- x.children.push(x, y);
163
- return [x];
164
- }
165
-
166
- /** root -> child -> grand, where grand's children point back at root. */
167
- function makeDeepCycle(): TreeItem[] {
168
- const root: TreeItem = {id: 'root', name: 'Root', children: []};
169
- const child: TreeItem = {id: 'child', name: 'Child', children: []};
170
- const grand: TreeItem = {id: 'grand', name: 'Grand', children: []};
171
- root.children.push(child);
172
- child.children.push(grand);
173
- grand.children.push(root);
174
- return [root];
175
- }
176
-
177
- function renderState(baseData: TreeItem[], expandedKeys: Set<string>) {
178
- const setExpandedKeys = vi.fn();
179
- const hook = renderHook(() =>
180
- useTableRowExpansionState<TreeItem>({
181
- baseData,
182
- getChildren: item => item.children,
183
- getRowKey: item => item.id,
184
- expandedKeys,
185
- setExpandedKeys,
186
- }),
187
- );
188
- return {hook, setExpandedKeys};
189
- }
190
-
191
- it('terminates on a self-referential expanded row and flattens each key once', () => {
192
- const {hook} = renderState(makeSelfReferential(), new Set(['x']));
193
- const {data, expansionConfig} = hook.result.current;
194
- expect(data.map(item => item.id)).toEqual(['x', 'y']);
195
- expect(expansionConfig.getDepth?.(data[0])).toBe(0);
196
- expect(expansionConfig.getDepth?.(data[1])).toBe(1);
197
- });
198
-
199
- it('terminates on a deeper cycle back to the root and flattens each key once', () => {
200
- const {hook} = renderState(
201
- makeDeepCycle(),
202
- new Set(['root', 'child', 'grand']),
203
- );
204
- const {data, expansionConfig} = hook.result.current;
205
- expect(data.map(item => item.id)).toEqual(['root', 'child', 'grand']);
206
- expect(expansionConfig.getDepth?.(data[0])).toBe(0);
207
- expect(expansionConfig.getDepth?.(data[1])).toBe(1);
208
- expect(expansionConfig.getDepth?.(data[2])).toBe(2);
209
- // The cycle guard keeps isAllExpanded computable — true, not a crash.
210
- expect(expansionConfig.isAllExpanded).toBe(true);
211
- });
212
-
213
- it('terminates when collecting allExpandableKeys on cyclic data with nothing expanded', () => {
214
- const {hook, setExpandedKeys} = renderState(
215
- makeDeepCycle(),
216
- new Set<string>(),
217
- );
218
- const {data, expansionConfig} = hook.result.current;
219
- expect(data.map(item => item.id)).toEqual(['root']);
220
- expansionConfig.onToggleExpandAll?.(true);
221
- const nextKeys = setExpandedKeys.mock.calls[0][0] as Set<string>;
222
- expect(Array.from(nextKeys)).toEqual(['root', 'child', 'grand']);
223
- });
224
-
225
- it('re-walks a shared child under each expanded parent (ancestor-path, not visited-set, semantics)', () => {
226
- const leaf: TreeItem = {id: 'leaf', name: 'Leaf', children: []};
227
- const shared: TreeItem = {id: 's', name: 'Shared', children: [leaf]};
228
- const p1: TreeItem = {id: 'p1', name: 'Parent 1', children: [shared]};
229
- const p2: TreeItem = {id: 'p2', name: 'Parent 2', children: [shared]};
230
- const {hook} = renderState([p1, p2], new Set(['p1', 'p2', 's']));
231
- // 's' is on neither parent's ancestor path, so it must flatten under
232
- // both — the guard only skips true cycles, matching pre-guard behavior
233
- // for acyclic (DAG-shaped) data.
234
- const {data} = hook.result.current;
235
- expect(data.map(item => item.id)).toEqual([
236
- 'p1',
237
- 's',
238
- 'leaf',
239
- 'p2',
240
- 's',
241
- 'leaf',
242
- ]);
243
- });
244
- });
@@ -141,19 +141,12 @@ export function useTableRowExpansionState<T extends Record<string, unknown>>({
141
141
 
142
142
  const depthMap = useMemo(() => {
143
143
  const map = new Map<string, number>();
144
- // Ancestor keys on the current walk path — guards against cyclic data.
145
- const path = new Set<string>();
146
144
  function walk(items: T[], depth: number) {
147
145
  for (const item of items) {
148
146
  const key = getRowKey(item);
149
- if (path.has(key)) {
150
- continue; // cyclic edge — skip
151
- }
152
147
  map.set(key, depth);
153
148
  if (expandedKeys.has(key)) {
154
- path.add(key);
155
149
  walk(getChildren(item), depth + 1);
156
- path.delete(key);
157
150
  }
158
151
  }
159
152
  }
@@ -163,19 +156,12 @@ export function useTableRowExpansionState<T extends Record<string, unknown>>({
163
156
 
164
157
  const data = useMemo(() => {
165
158
  const result: T[] = [];
166
- // Ancestor keys on the current walk path — guards against cyclic data.
167
- const path = new Set<string>();
168
159
  function walk(items: T[]) {
169
160
  for (const item of items) {
170
- const key = getRowKey(item);
171
- if (path.has(key)) {
172
- continue; // cyclic edge — skip
173
- }
174
161
  result.push(item);
162
+ const key = getRowKey(item);
175
163
  if (expandedKeys.has(key)) {
176
- path.add(key);
177
164
  walk(getChildren(item));
178
- path.delete(key);
179
165
  }
180
166
  }
181
167
  }
@@ -186,19 +172,11 @@ export function useTableRowExpansionState<T extends Record<string, unknown>>({
186
172
  // Every expandable key across the whole tree (drives expand-all).
187
173
  const allExpandableKeys = useMemo(() => {
188
174
  const keys: string[] = [];
189
- // Ancestor keys on the current walk path — guards against cyclic data.
190
- const path = new Set<string>();
191
175
  function walk(items: T[]) {
192
176
  for (const item of items) {
193
- const key = getRowKey(item);
194
- if (path.has(key)) {
195
- continue; // cyclic edge — skip
196
- }
197
177
  if (isExpandable(item)) {
198
- keys.push(key);
199
- path.add(key);
178
+ keys.push(getRowKey(item));
200
179
  walk(getChildren(item));
201
- path.delete(key);
202
180
  }
203
181
  }
204
182
  }
@@ -421,11 +399,7 @@ export function useTableRowExpansion<T extends Record<string, unknown>>(
421
399
  <ExpansionChevron
422
400
  isExpanded={isExpanded}
423
401
  onToggle={() => onToggle(key)}
424
- ariaLabel={
425
- isExpanded
426
- ? t('@astryx.tableRowExpansion.collapseRow')
427
- : t('@astryx.tableRowExpansion.expandRow')
428
- }
402
+ ariaLabel={isExpanded ? t('@astryx.tableRowExpansion.collapseRow') : t('@astryx.tableRowExpansion.expandRow')}
429
403
  />
430
404
  );
431
405
  },
@@ -483,11 +457,7 @@ export function useTableRowExpansion<T extends Record<string, unknown>>(
483
457
  <ExpansionChevron
484
458
  isExpanded={isExpanded}
485
459
  onToggle={() => onToggle(key)}
486
- ariaLabel={
487
- isExpanded
488
- ? t('@astryx.tableRowExpansion.collapseRow')
489
- : t('@astryx.tableRowExpansion.expandRow')
490
- }
460
+ ariaLabel={isExpanded ? t('@astryx.tableRowExpansion.collapseRow') : t('@astryx.tableRowExpansion.expandRow')}
491
461
  />
492
462
  ) : (
493
463
  <span {...stylex.props(expansionStyles.placeholder)} />
@@ -529,9 +499,7 @@ export function useTableRowExpansion<T extends Record<string, unknown>>(
529
499
  {...stylex.props(expansionStyles.chevronButton)}
530
500
  onClick={() => onToggleExpandAll(!allExpanded)}
531
501
  aria-label={
532
- allExpanded
533
- ? t('@astryx.tableRowExpansion.collapseAllRows')
534
- : t('@astryx.tableRowExpansion.expandAllRows')
502
+ allExpanded ? t('@astryx.tableRowExpansion.collapseAllRows') : t('@astryx.tableRowExpansion.expandAllRows')
535
503
  }>
536
504
  <span
537
505
  {...stylex.props(
@@ -12,9 +12,11 @@ import {render, screen, fireEvent} from '@testing-library/react';
12
12
  import userEvent from '@testing-library/user-event';
13
13
  import {useState} from 'react';
14
14
  import {Table} from '../../Table';
15
- import {InternationalizationProvider} from '../../../i18n';
16
15
  import type {TableColumn} from '../../types';
17
- import {useTableSortable, type TableSortState} from './useTableSortable';
16
+ import {
17
+ useTableSortable,
18
+ type TableSortState,
19
+ } from './useTableSortable';
18
20
 
19
21
  // =============================================================================
20
22
  // Test Data
@@ -71,7 +73,9 @@ function SortableTable({
71
73
  isMultiSortEnabled,
72
74
  });
73
75
 
74
- return <Table data={data} columns={columns} plugins={{sort: sortPlugin}} />;
76
+ return (
77
+ <Table data={data} columns={columns} plugins={{sort: sortPlugin}} />
78
+ );
75
79
  }
76
80
 
77
81
  // =============================================================================
@@ -668,15 +672,11 @@ describe('useTableSortable — context menu actions', () => {
668
672
 
669
673
  // Apply ascending → "Clear sort" now appears.
670
674
  fireEvent.click(
671
- screen.getAllByRole('menuitem', {
672
- name: 'Sort ascending',
673
- hidden: true,
674
- })[0],
675
+ screen.getAllByRole('menuitem', {name: 'Sort ascending', hidden: true})[0],
675
676
  );
676
677
  fireEvent.contextMenu(screen.getByText('Name'));
677
678
  expect(
678
- screen.getAllByRole('menuitem', {name: 'Clear sort', hidden: true})
679
- .length,
679
+ screen.getAllByRole('menuitem', {name: 'Clear sort', hidden: true}).length,
680
680
  ).toBeGreaterThan(0);
681
681
  });
682
682
 
@@ -709,89 +709,3 @@ describe('useTableSortable — context menu actions', () => {
709
709
  expect(onSortChange).toHaveBeenLastCalledWith([]);
710
710
  });
711
711
  });
712
-
713
- // =============================================================================
714
- // i18n (header-button aria-labels route through the catalog)
715
- // =============================================================================
716
-
717
- describe('useTableSortable — i18n', () => {
718
- it('localizes the unsorted sort-by aria-label via @astryx.table.sort.sortBy', () => {
719
- render(
720
- <InternationalizationProvider
721
- locale="fr"
722
- overrides={{
723
- fr: {'@astryx.table.sort.sortBy': 'Trier par {label}'},
724
- }}>
725
- <SortableTable />
726
- </InternationalizationProvider>,
727
- );
728
-
729
- expect(
730
- screen.getByRole('button', {name: 'Trier par Name'}),
731
- ).toBeInTheDocument();
732
- expect(
733
- screen.getByRole('button', {name: 'Trier par Age'}),
734
- ).toBeInTheDocument();
735
- });
736
-
737
- it('localizes the multi-sort priority aria-label with ICU number args', () => {
738
- render(
739
- <InternationalizationProvider
740
- locale="fr"
741
- overrides={{
742
- fr: {
743
- '@astryx.table.sort.sortedByWithPriority':
744
- 'Trier par {label}, tri {direction}, priorité {rank, number} sur {total, number}',
745
- '@astryx.table.sort.direction.ascending': 'croissant',
746
- '@astryx.table.sort.direction.descending': 'décroissant',
747
- },
748
- }}>
749
- <SortableTable
750
- isMultiSortEnabled
751
- initialSort={[
752
- {sortKey: 'name', direction: 'ascending'},
753
- {sortKey: 'age', direction: 'descending'},
754
- ]}
755
- />
756
- </InternationalizationProvider>,
757
- );
758
-
759
- // The overridden direction words deliberately differ from the raw enum
760
- // values ('ascending'/'descending'), so an implementation interpolating
761
- // the enum without translating it cannot pass — for either direction.
762
- expect(
763
- screen.getByRole('button', {
764
- name: 'Trier par Name, tri croissant, priorité 1 sur 2',
765
- }),
766
- ).toBeInTheDocument();
767
- expect(
768
- screen.getByRole('button', {
769
- name: 'Trier par Age, tri décroissant, priorité 2 sur 2',
770
- }),
771
- ).toBeInTheDocument();
772
- });
773
-
774
- it('localizes the sorted aria-label and direction word via their own keys', () => {
775
- render(
776
- <InternationalizationProvider
777
- locale="fr"
778
- overrides={{
779
- fr: {
780
- '@astryx.table.sort.sortedBy': 'Trié par {label}, {direction}',
781
- '@astryx.table.sort.direction.ascending': 'croissant',
782
- },
783
- }}>
784
- <SortableTable
785
- initialSort={[{sortKey: 'name', direction: 'ascending'}]}
786
- />
787
- </InternationalizationProvider>,
788
- );
789
-
790
- // Both the composed template and the direction word resolve through
791
- // their own catalog keys; 'croissant' differs from the raw enum value,
792
- // so neither a hardcoded English frame nor raw-enum interpolation passes.
793
- expect(
794
- screen.getByRole('button', {name: 'Trié par Name, croissant'}),
795
- ).toBeInTheDocument();
796
- });
797
- });
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file useTableSortable.tsx
7
- * @input React, types, Icon, theme tokens, i18n (useTranslator)
7
+ * @input React, types, Icon, theme tokens
8
8
  * @output Exports useTableSortable hook and sort-related types
9
9
  * @position Sortable plugin; consumed by Table via plugins prop
10
10
  *
@@ -18,7 +18,7 @@ import * as stylex from '@stylexjs/stylex';
18
18
  import {colorVars, spacingVars, radiusVars} from '../../../theme/tokens.stylex';
19
19
  import {Icon} from '../../../Icon';
20
20
  import {resolveContextActions} from '../../tableContextMenu';
21
- import {useTranslator, type TranslatorFn} from '../../../i18n';
21
+ import {useTranslator} from '../../../i18n';
22
22
  import type {
23
23
  TablePlugin,
24
24
  HeaderCellRenderProps,
@@ -184,7 +184,6 @@ function getHeaderLabel<T extends Record<string, unknown>>(
184
184
  }
185
185
 
186
186
  function buildAriaLabel<T extends Record<string, unknown>>(
187
- t: TranslatorFn,
188
187
  column: TableColumn<T>,
189
188
  direction: TableSortDirection | null,
190
189
  rank: number | null,
@@ -192,21 +191,13 @@ function buildAriaLabel<T extends Record<string, unknown>>(
192
191
  ): string {
193
192
  const label = getHeaderLabel(column);
194
193
  if (direction == null) {
195
- return t('@astryx.table.sort.sortBy', {label});
194
+ return `Sort by ${label}`;
196
195
  }
197
- const directionLabel =
198
- direction === 'ascending'
199
- ? t('@astryx.table.sort.direction.ascending')
200
- : t('@astryx.table.sort.direction.descending');
196
+ let ariaLabel = `Sort by ${label}, sorted ${direction}`;
201
197
  if (rank != null && total > 1) {
202
- return t('@astryx.table.sort.sortedByWithPriority', {
203
- label,
204
- direction: directionLabel,
205
- rank,
206
- total,
207
- });
198
+ ariaLabel += `, priority ${rank} of ${total}`;
208
199
  }
209
- return t('@astryx.table.sort.sortedBy', {label, direction: directionLabel});
200
+ return ariaLabel;
210
201
  }
211
202
 
212
203
  function getNextDirection(
@@ -236,7 +227,6 @@ function SortHeaderButton<T extends Record<string, unknown>>({
236
227
  children: ReactNode;
237
228
  configRef: React.RefObject<UseTableSortableConfig>;
238
229
  }) {
239
- const t = useTranslator();
240
230
  const config = configRef.current;
241
231
  const sortKey = resolveSortKey(column) ?? '';
242
232
  const entryIndex = config.sort.findIndex(e => e.sortKey === sortKey);
@@ -254,13 +244,7 @@ function SortHeaderButton<T extends Record<string, unknown>>({
254
244
  ? 'arrowDown'
255
245
  : 'arrowsUpDown';
256
246
 
257
- const ariaLabel = buildAriaLabel(
258
- t,
259
- column,
260
- direction,
261
- rank,
262
- config.sort.length,
263
- );
247
+ const ariaLabel = buildAriaLabel(column, direction, rank, config.sort.length);
264
248
 
265
249
  const handleClick = (e: React.MouseEvent | React.KeyboardEvent) => {
266
250
  const cfg = configRef.current;
@@ -18,15 +18,12 @@
18
18
  * Canonical order:
19
19
  * 1. columnSettings — column filtering (future: transformColumns)
20
20
  * 2. sort — header cell sort controls
21
- * 3. tree — indent + expander on the tree column
22
- * 4. selection — checkbox column + row selection
23
- * 5. pagination — pagination controls around the table
21
+ * 3. selection — checkbox column + row selection
22
+ * 4. pagination — pagination controls around the table
24
23
  *
25
24
  * Rationale:
26
25
  * - columnSettings filters columns before sort/selection see them
27
26
  * - sort adds header cell UI before selection adds its header column
28
- * - tree wraps the first *user* column before selection prepends its
29
- * checkbox column, so the expander never lands in the checkbox column
30
27
  * - selection adds its column after sort so the checkbox header
31
28
  * doesn't get a sort button
32
29
  * - pagination wraps the table in context last (outermost provider)
@@ -49,7 +46,6 @@ import type {TablePlugin} from './types';
49
46
  const PLUGIN_ORDER: ReadonlyArray<string> = [
50
47
  'columnSettings',
51
48
  'sort',
52
- 'tree',
53
49
  'selection',
54
50
  'pagination',
55
51
  ];
@@ -116,7 +116,7 @@ export const docs = {
116
116
  name: 'startIcon',
117
117
  type: 'IconType',
118
118
  description:
119
- 'Icon component rendered inside the leading edge of the textarea wrapper. See `astryx docs icons` for valid semantic names.',
119
+ 'Icon component rendered inside the leading edge of the textarea wrapper. See `npx astryx docs icons` for valid semantic names.',
120
120
  },
121
121
  {
122
122
  name: 'hasSpellCheck',
@@ -106,7 +106,7 @@ export const docs = {
106
106
  name: 'startIcon',
107
107
  type: 'IconType',
108
108
  description:
109
- 'SVG icon component displayed at the start of the input. See `astryx docs icons` for valid semantic names.',
109
+ 'SVG icon component displayed at the start of the input. See `npx astryx docs icons` for valid semantic names.',
110
110
  },
111
111
  {
112
112
  name: 'status',
@@ -239,7 +239,6 @@ export function Toolbar({
239
239
  const hasCenterContent = centerContent != null;
240
240
  const hasStartContent = startContent != null;
241
241
  const hasEndContent = endContent != null;
242
- const hasBottomDivider = dividers?.includes('bottom') ?? false;
243
242
 
244
243
  const gapVar = spacingVars[spacingStepToVar[gap]] as string;
245
244
 
@@ -317,15 +316,9 @@ export function Toolbar({
317
316
  orientation === 'vertical' && styles.vertical,
318
317
  sizeStyles.base,
319
318
  dynamicStyles.gap(gapVar),
320
- // Only drop the tab indicator through the toolbar's block padding
321
- // onto the rail when a bottom divider is actually present.
322
- // Without a divider, leave `--_tab-indicator-bottom` unset so a
323
- // nested TabList's indicator keeps its own default (hugging the
324
- // tab) instead of floating down into the toolbar's padding.
325
- hasBottomDivider &&
326
- dynamicStyles.tabIndicatorBottom(
327
- `calc(-1 * (${blockPaddingVarForSize[size]} + 1px))`,
328
- ),
319
+ dynamicStyles.tabIndicatorBottom(
320
+ `calc(-1 * (${blockPaddingVarForSize[size]}${dividers?.includes('bottom') ? ' + 1px' : ''}))`,
321
+ ),
329
322
  ),
330
323
  )}
331
324
  {...props}>
@@ -39,12 +39,12 @@ export const docs = {
39
39
  },
40
40
  usage: {
41
41
  description:
42
- 'Wraps a subtree with a specific Astryx theme. For static production themes, use `astryx theme build` and import the generated CSS plus built theme object for first-paint and SSR performance. Use runtime `defineTheme()` when themes are dynamic or for prototyping.\n\n`defineTheme` accepts a `tokens` object whose keys are CSS custom property names (always prefixed with `--`). Common token names include `--color-accent`, `--color-background-surface`, `--color-background-body`, `--color-text-primary`, `--color-text-secondary`, `--radius-container`, `--spacing-1` through `--spacing-6`. Values can be a string (same for light/dark) or a `[light, dark]` tuple.\n\nExample:\n```ts\nimport {defineTheme} from \'@astryxdesign/core/theme\';\nconst myTheme = defineTheme({\n name: \'ocean\',\n tokens: {\n \'--color-accent\': [\'#0077B6\', \'#48CAE4\'],\n \'--color-background-surface\': [\'#F0F8FF\', \'#0A1628\'],\n \'--color-text-primary\': [\'#0A1317\', \'#FFFFFF\'],\n \'--radius-container\': \'16px\',\n },\n});\n```',
42
+ 'Wraps a subtree with a specific Astryx theme. For static production themes, use `npx astryx theme build` and import the generated CSS plus built theme object for first-paint and SSR performance. Use runtime `defineTheme()` when themes are dynamic or for prototyping.\n\n`defineTheme` accepts a `tokens` object whose keys are CSS custom property names (always prefixed with `--`). Common token names include `--color-accent`, `--color-background-surface`, `--color-background-body`, `--color-text-primary`, `--color-text-secondary`, `--radius-container`, `--spacing-1` through `--spacing-6`. Values can be a string (same for light/dark) or a `[light, dark]` tuple.\n\nExample:\n```ts\nimport {defineTheme} from \'@astryxdesign/core/theme\';\nconst myTheme = defineTheme({\n name: \'ocean\',\n tokens: {\n \'--color-accent\': [\'#0077B6\', \'#48CAE4\'],\n \'--color-background-surface\': [\'#F0F8FF\', \'#0A1628\'],\n \'--color-text-primary\': [\'#0A1317\', \'#FFFFFF\'],\n \'--radius-container\': \'16px\',\n },\n});\n```',
43
43
  bestPractices: [
44
44
  {
45
45
  guidance: true,
46
46
  description:
47
- 'Build app themes that are known ahead of time with `astryx theme build`, then import the generated CSS and built theme object.',
47
+ 'Build app themes that are known ahead of time with `npx astryx theme build`, then import the generated CSS and built theme object.',
48
48
  },
49
49
  {
50
50
  guidance: true,
@@ -90,12 +90,12 @@ export const docs = {
90
90
  export const docsDense = {
91
91
  usage: {
92
92
  description:
93
- 'Wraps subtree w/ specific Astryx theme. For static production themes, use `astryx theme build` + generated CSS + built theme object for first-paint/SSR performance. Use runtime `defineTheme()` for dynamic themes or prototyping. Token names always start with `--` (e.g. `--color-accent`, `--color-background-surface`).',
93
+ 'Wraps subtree w/ specific Astryx theme. For static production themes, use `npx astryx theme build` + generated CSS + built theme object for first-paint/SSR performance. Use runtime `defineTheme()` for dynamic themes or prototyping. Token names always start with `--` (e.g. `--color-accent`, `--color-background-surface`).',
94
94
  bestPractices: [
95
95
  {
96
96
  guidance: true,
97
97
  description:
98
- 'Build app themes known ahead of time w/ `astryx theme build`; import generated CSS + built theme object.',
98
+ 'Build app themes known ahead of time w/ `npx astryx theme build`; import generated CSS + built theme object.',
99
99
  },
100
100
  {
101
101
  guidance: true,
@@ -127,7 +127,7 @@ function useThemeStyleInjection(theme: DefinedTheme): void {
127
127
  `For better performance, use the pre-built theme:\n\n` +
128
128
  ` import {${theme.name}Theme} from '@astryxdesign/theme-${theme.name}/built';\n` +
129
129
  ` import '@astryxdesign/theme-${theme.name}/theme.css';\n\n` +
130
- `For custom themes, run \`npx @astryxdesign/cli theme build <file>\` to generate ` +
130
+ `For custom themes, run \`npx astryx theme build <file>\` to generate ` +
131
131
  `the built artifacts.`,
132
132
  );
133
133
  }
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Two distribution modes:
7
7
  * - Unbuilt: Theme generates CSS and injects a <style> tag at runtime
8
- * - Built: `astryx theme build` pre-compiles to a CSS file; Theme just
8
+ * - Built: `npx astryx theme build` pre-compiles to a CSS file; Theme just
9
9
  * sets the data-astryx-theme attribute
10
10
  *
11
11
  * Token values can be:
package/src/theme/hct.ts CHANGED
@@ -114,6 +114,10 @@ export function toneToY(tone: number): number {
114
114
  return labFInv((tone + 16) / 116);
115
115
  }
116
116
 
117
+ export function yToTone(y: number): number {
118
+ return 116 * labF(y) - 16;
119
+ }
120
+
117
121
  // =============================================================================
118
122
  // Hex <-> RGB
119
123
  // =============================================================================
@@ -1,89 +0,0 @@
1
- /**
2
- * @file DropdownMenuCheckboxItem.tsx
3
- * @input React, stylex, Item + Icon + DropdownMenu context + tokens from core
4
- * @output DropdownMenuCheckboxItem — a standalone checkable menu item.
5
- * @position Sub-component; used inside DropdownMenu.
6
- *
7
- * A menu item that toggles an independent boolean (role="menuitemcheckbox").
8
- * Unlike CheckboxInput, there is no nested native <input>: the row itself owns
9
- * the role and aria-checked, per the WAI-ARIA menuitemcheckbox pattern.
10
- * Keyboard navigation (arrows/typeahead) and Enter/Space activation come from
11
- * the parent DropdownMenu's useListFocus + activation path, which matches
12
- * menuitemcheckbox alongside plain menuitem rows.
13
- *
14
- * The square checkbox visual is decorative (aria-hidden) — the row owns the
15
- * checked state. Its size is derived from the menu's item size (a `sm` menu
16
- * gets the compact control; `md`/`lg` get the standard one) and it swaps to the
17
- * inline-end of the row on coarse-pointer (touch) devices via CSS `order`, so
18
- * it lands where selection toggles are conventionally placed on mobile. The
19
- * checkmark uses the `check` icon from the active theme's icon registry.
20
- */
21
- import { type ReactNode } from 'react';
22
- import { type IconType } from '../Icon';
23
- import type { BaseProps } from '../BaseProps';
24
- export interface DropdownMenuCheckboxItemProps extends Omit<BaseProps, 'onChange' | 'role' | 'aria-checked' | 'tabIndex'> {
25
- /**
26
- * Primary label text identifying the item.
27
- */
28
- label: ReactNode;
29
- /**
30
- * Secondary description text displayed below the label.
31
- */
32
- description?: ReactNode;
33
- /**
34
- * Icon to display before the label. Accepts a semantic icon name (see
35
- * `npx astryx docs icons`) or a rendered node.
36
- */
37
- icon?: ReactNode | IconType;
38
- /**
39
- * Whether the item is checked. Controlled — pair with `onChange`.
40
- */
41
- value: boolean;
42
- /**
43
- * Callback fired with the next checked state when the item is toggled.
44
- */
45
- onChange?: (checked: boolean) => void;
46
- /**
47
- * Whether the item is disabled. Disabled items stay focusable (via
48
- * `aria-disabled`) so they remain discoverable by keyboard and assistive
49
- * technology, but activation is blocked.
50
- * @default false
51
- */
52
- isDisabled?: boolean;
53
- /**
54
- * Whether toggling the item closes the menu. Checkbox items default to
55
- * staying open so several can be toggled in a single session, unlike radio
56
- * items which default to closing on selection.
57
- * @default false
58
- */
59
- hasCloseOnSelect?: boolean;
60
- /**
61
- * Content to render after the label and description, such as a keyboard
62
- * shortcut hint or badge.
63
- */
64
- endContent?: ReactNode;
65
- }
66
- /**
67
- * A checkable dropdown menu item (role="menuitemcheckbox").
68
- *
69
- * Must be used inside a DropdownMenu. Toggles an independent boolean; for a
70
- * one-of-N choice use DropdownMenuRadioGroup + DropdownMenuRadioItem instead.
71
- *
72
- * @example
73
- * ```
74
- * * import {DropdownMenuCheckboxItem} from '@astryxdesign/core/DropdownMenu';
75
- *
76
- * <DropdownMenu button={{label: 'View'}}>
77
- * <DropdownMenuCheckboxItem
78
- * label="Show archived"
79
- * value={showArchived}
80
- * onChange={setShowArchived}
81
- * />
82
- * </DropdownMenu>
83
- * ```
84
- */
85
- export declare function DropdownMenuCheckboxItem({ label, description, icon, value, onChange, isDisabled, hasCloseOnSelect, endContent, xstyle, className, style, ...rest }: DropdownMenuCheckboxItemProps): import("react").JSX.Element;
86
- export declare namespace DropdownMenuCheckboxItem {
87
- var displayName: string;
88
- }
89
- //# sourceMappingURL=DropdownMenuCheckboxItem.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DropdownMenuCheckboxItem.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuCheckboxItem.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAc,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAElD,OAAO,EAAuB,KAAK,QAAQ,EAAC,MAAM,SAAS,CAAC;AAY5D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AA6D5C,MAAM,WAAW,6BAA8B,SAAQ,IAAI,CACzD,SAAS,EACT,UAAU,GAAG,MAAM,GAAG,cAAc,GAAG,UAAU,CAClD;IACC;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IACjB;;OAEG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B;;OAEG;IACH,KAAK,EAAE,OAAO,CAAC;IACf;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,KAAK,EACL,WAAW,EACX,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,UAAkB,EAClB,gBAAwB,EACxB,UAAU,EACV,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,6BAA6B,+BAwD/B;yBArEe,wBAAwB"}