@astryxdesign/core 0.7.2-canary.fdd384f → 0.7.2

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 (132) hide show
  1. package/CHANGELOG.md +156 -2
  2. package/README.md +4 -4
  3. package/dist/Avatar/Avatar.d.ts.map +1 -1
  4. package/dist/Avatar/Avatar.js +8 -1
  5. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  6. package/dist/AvatarGroup/AvatarGroupOverflow.js +4 -1
  7. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  8. package/dist/Chat/ChatLayoutScrollButton.js +1 -0
  9. package/dist/CheckboxList/CheckboxList.d.ts +1 -1
  10. package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
  11. package/dist/CheckboxList/CheckboxList.js +6 -2
  12. package/dist/DropdownMenu/DropdownMenu.d.ts +1 -1
  13. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  14. package/dist/DropdownMenu/DropdownMenu.js +38 -110
  15. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +1 -1
  16. package/dist/DropdownMenu/DropdownMenuGroup.d.ts +6 -4
  17. package/dist/DropdownMenu/DropdownMenuGroup.d.ts.map +1 -1
  18. package/dist/DropdownMenu/DropdownMenuGroup.js +4 -3
  19. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +1 -1
  20. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +24 -0
  21. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -0
  22. package/dist/DropdownMenu/lazyMenuBottomSheet.js +46 -0
  23. package/dist/DropdownMenu/menuRegionStops.d.ts +38 -0
  24. package/dist/DropdownMenu/menuRegionStops.d.ts.map +1 -0
  25. package/dist/DropdownMenu/menuRegionStops.js +131 -0
  26. package/dist/FormLayout/FormLayout.d.ts +5 -4
  27. package/dist/FormLayout/FormLayout.d.ts.map +1 -1
  28. package/dist/FormLayout/FormLayout.js +1 -1
  29. package/dist/FormLayout/FormLayoutContext.d.ts +3 -3
  30. package/dist/FormLayout/FormLayoutContext.js +3 -3
  31. package/dist/Grid/Grid.d.ts +8 -7
  32. package/dist/Grid/Grid.d.ts.map +1 -1
  33. package/dist/Grid/Grid.js +5 -4
  34. package/dist/Grid/GridSpan.d.ts +1 -1
  35. package/dist/Markdown/parser.d.ts.map +1 -1
  36. package/dist/Markdown/parser.js +8 -2
  37. package/dist/Markdown/plugins/headingLinks.d.ts.map +1 -1
  38. package/dist/Markdown/plugins/headingLinks.js +9 -1
  39. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  40. package/dist/PowerSearch/PowerSearch.js +5 -0
  41. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  42. package/dist/PowerSearch/PowerSearchValueEditor.js +45 -11
  43. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  44. package/dist/SideNav/SideNavItem.js +6 -2
  45. package/dist/Token/Token.js +1 -1
  46. package/dist/TopNav/TopNavMegaMenu.js +2 -0
  47. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  48. package/dist/TopNav/TopNavMenu.js +2 -0
  49. package/dist/astryx.css +1 -1
  50. package/dist/reset.a11y.chromium.spec.js +50 -1
  51. package/docs.mjs +4 -4
  52. package/package.json +4 -4
  53. package/scripts/agent-doc-state.mjs +66 -6
  54. package/scripts/postinstall.mjs +44 -3
  55. package/src/Avatar/Avatar.tsx +11 -2
  56. package/src/AvatarGroup/AvatarGroupOverflow.test.tsx +24 -1
  57. package/src/AvatarGroup/AvatarGroupOverflow.tsx +2 -0
  58. package/src/Chat/ChatLayoutScrollButton.test.tsx +13 -0
  59. package/src/Chat/ChatLayoutScrollButton.tsx +4 -2
  60. package/src/Chat/__tests__/ChatLayoutScrollButton.a11y.chromium.spec.ts +64 -19
  61. package/src/CheckboxList/CheckboxList.fr10.test.tsx +29 -2
  62. package/src/CheckboxList/CheckboxList.tsx +4 -1
  63. package/src/Code/Code.doc.mjs +1 -0
  64. package/src/CommandPalette/CommandPalette.doc.mjs +2 -0
  65. package/src/ContextMenu/ContextMenu.test.tsx +12 -2
  66. package/src/Drawer/Drawer.doc.mjs +1 -0
  67. package/src/DropdownMenu/DropdownMenu.ssr.test.tsx +57 -0
  68. package/src/DropdownMenu/DropdownMenu.test.tsx +17 -5
  69. package/src/DropdownMenu/DropdownMenu.tsx +43 -142
  70. package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +1 -1
  71. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +1 -1
  72. package/src/DropdownMenu/DropdownMenuGroup.doc.mjs +169 -10
  73. package/src/DropdownMenu/DropdownMenuGroup.tsx +6 -4
  74. package/src/DropdownMenu/DropdownMenuLazySheet.test.tsx +126 -0
  75. package/src/DropdownMenu/DropdownMenuRadioItem.doc.mjs +1 -1
  76. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +1 -1
  77. package/src/DropdownMenu/__tests__/DropdownMenuGroupAudit.a11y.chromium.spec.ts +334 -0
  78. package/src/DropdownMenu/__tests__/warmMenuBottomSheet.tsx +43 -0
  79. package/src/DropdownMenu/lazyMenuBottomSheet.ts +71 -0
  80. package/src/DropdownMenu/menuRegionStops.ts +167 -0
  81. package/src/Field/FieldLabel.doc.mjs +133 -26
  82. package/src/Field/FieldLabel.spec.md +172 -0
  83. package/src/Field/__tests__/FieldLabelAudit.a11y.chromium.spec.ts +296 -0
  84. package/src/FormLayout/FormLayout.doc.mjs +6 -3
  85. package/src/FormLayout/FormLayout.spec.md +192 -0
  86. package/src/FormLayout/FormLayout.test.tsx +15 -0
  87. package/src/FormLayout/FormLayout.tsx +7 -6
  88. package/src/FormLayout/FormLayoutContext.ts +3 -3
  89. package/src/Grid/Grid.doc.mjs +7 -1
  90. package/src/Grid/Grid.spec.md +93 -113
  91. package/src/Grid/Grid.test.tsx +22 -0
  92. package/src/Grid/Grid.tsx +10 -9
  93. package/src/Grid/GridSpan.doc.mjs +3 -3
  94. package/src/Grid/GridSpan.tsx +1 -1
  95. package/src/Icon/Icon.doc.mjs +36 -0
  96. package/src/Indicator/Indicator.doc.mjs +3 -3
  97. package/src/Layout/LayoutHeader.doc.mjs +5 -0
  98. package/src/Markdown/parser.ts +8 -2
  99. package/src/Markdown/plugins/headingLinks.ts +9 -1
  100. package/src/MetadataList/MetadataList.doc.mjs +1 -1
  101. package/src/MoreMenu/MoreMenu.test.tsx +5 -1
  102. package/src/PowerSearch/PowerSearch.test.tsx +62 -0
  103. package/src/PowerSearch/PowerSearch.tsx +9 -0
  104. package/src/PowerSearch/PowerSearchValueEditor.test.tsx +71 -0
  105. package/src/PowerSearch/PowerSearchValueEditor.tsx +45 -0
  106. package/src/ProgressBar/ProgressBar.doc.mjs +1 -0
  107. package/src/Resizable/useResizable.doc.mjs +2 -0
  108. package/src/ScrollableArea/ScrollableArea.doc.mjs +1 -1
  109. package/src/SideNav/SideNav.spec.md +227 -0
  110. package/src/SideNav/SideNav.test.tsx +41 -0
  111. package/src/SideNav/SideNavItem.tsx +5 -2
  112. package/src/Spinner/Spinner.doc.mjs +1 -1
  113. package/src/Table/Table.spec.md +6 -1
  114. package/src/Table/plugins/activation/useTableActivation.spec.md +254 -0
  115. package/src/Timestamp/Timestamp.doc.mjs +1 -1
  116. package/src/ToggleButton/ToggleButtonGroup.doc.mjs +4 -0
  117. package/src/Token/Token.tsx +1 -1
  118. package/src/Token/__tests__/TokenRemoveTarget.a11y.chromium.spec.ts +86 -0
  119. package/src/Toolbar/Toolbar.test.tsx +0 -8
  120. package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +163 -0
  121. package/src/Toolbar/__tests__/Toolbar.a11y.renders.tsx +63 -0
  122. package/src/Toolbar/__tests__/Toolbar.a11y.states.ts +142 -0
  123. package/src/Toolbar/__tests__/Toolbar.a11y.test.tsx +126 -0
  124. package/src/TopNav/TopNavMegaMenu.test.tsx +25 -0
  125. package/src/TopNav/TopNavMegaMenu.tsx +2 -0
  126. package/src/TopNav/TopNavMenu.test.tsx +27 -1
  127. package/src/TopNav/TopNavMenu.tsx +2 -0
  128. package/src/postinstall.test.mjs +79 -0
  129. package/src/reset.a11y.chromium.spec.ts +52 -1
  130. package/src/reset.css +9 -0
  131. package/src/reset.test.ts +11 -0
  132. package/src/unicodePropertyEscapes.source-build.test.mjs +69 -0
@@ -59,7 +59,8 @@ function StringEditor({
59
59
  filterValue,
60
60
  onChange,
61
61
  onEnter: _onEnter,
62
- maxMenuItems
62
+ maxMenuItems,
63
+ isDisabled
63
64
  }) {
64
65
  const t = useTranslator();
65
66
  const currentValue = filterValue?.type === 'string' ? filterValue.value : '';
@@ -74,6 +75,7 @@ function StringEditor({
74
75
  return /*#__PURE__*/_jsx(Typeahead, {
75
76
  label: t('@astryx.powersearch.valueEditor.value'),
76
77
  isLabelHidden: true,
78
+ isDisabled: isDisabled,
77
79
  searchSource: operatorValue.searchSource,
78
80
  value: selectedItem,
79
81
  onChange: item => {
@@ -97,6 +99,7 @@ function StringEditor({
97
99
  return /*#__PURE__*/_jsx(TextInput, {
98
100
  label: t('@astryx.powersearch.valueEditor.value'),
99
101
  isLabelHidden: true,
102
+ isDisabled: isDisabled,
100
103
  value: currentValue,
101
104
  placeholder: t('@astryx.powersearch.valueEditor.enterValuePlaceholder'),
102
105
  onChange: value => {
@@ -111,7 +114,8 @@ function StringListEditor({
111
114
  operatorValue,
112
115
  filterValue,
113
116
  onChange,
114
- maxMenuItems
117
+ maxMenuItems,
118
+ isDisabled
115
119
  }) {
116
120
  const t = useTranslator();
117
121
  const currentValue = useMemo(() => {
@@ -140,6 +144,7 @@ function StringListEditor({
140
144
  return /*#__PURE__*/_jsx(Tokenizer, {
141
145
  label: t('@astryx.powersearch.valueEditor.values'),
142
146
  isLabelHidden: true,
147
+ isDisabled: isDisabled,
143
148
  searchSource: source,
144
149
  value: currentValue,
145
150
  onChange: items => {
@@ -212,7 +217,8 @@ function IntegerEditor({
212
217
  operatorValue,
213
218
  filterValue,
214
219
  onChange,
215
- onEnter
220
+ onEnter,
221
+ isDisabled
216
222
  }) {
217
223
  const t = useTranslator();
218
224
  const currentValue = filterValue?.type === 'integer' ? filterValue.value : undefined;
@@ -227,6 +233,7 @@ function IntegerEditor({
227
233
  return /*#__PURE__*/_jsx(NumberInput, {
228
234
  label: t('@astryx.powersearch.valueEditor.value'),
229
235
  isLabelHidden: true,
236
+ isDisabled: isDisabled,
230
237
  value: currentValue ?? null,
231
238
  onChange: handlers.handleChange,
232
239
  onFocus: handlers.handleFocus,
@@ -244,7 +251,8 @@ function FloatEditor({
244
251
  operatorValue,
245
252
  filterValue,
246
253
  onChange,
247
- onEnter
254
+ onEnter,
255
+ isDisabled
248
256
  }) {
249
257
  const t = useTranslator();
250
258
  const currentValue = filterValue?.type === 'float' ? filterValue.value : undefined;
@@ -259,6 +267,7 @@ function FloatEditor({
259
267
  return /*#__PURE__*/_jsx(NumberInput, {
260
268
  label: t('@astryx.powersearch.valueEditor.value'),
261
269
  isLabelHidden: true,
270
+ isDisabled: isDisabled,
262
271
  value: currentValue ?? null,
263
272
  onChange: handlers.handleChange,
264
273
  onFocus: handlers.handleFocus,
@@ -274,13 +283,15 @@ function FloatEditor({
274
283
  function TimeEditor({
275
284
  operatorValue,
276
285
  filterValue,
277
- onChange
286
+ onChange,
287
+ isDisabled
278
288
  }) {
279
289
  const t = useTranslator();
280
290
  const currentValue = filterValue?.type === 'time' ? filterValue.value : undefined;
281
291
  return /*#__PURE__*/_jsx(TimeInput, {
282
292
  label: t('@astryx.powersearch.valueEditor.time'),
283
293
  isLabelHidden: true,
294
+ isDisabled: isDisabled,
284
295
  value: currentValue,
285
296
  onChange: value => {
286
297
  if (value != null) {
@@ -296,7 +307,8 @@ function TimeEditor({
296
307
  }
297
308
  function DateAbsoluteEditor({
298
309
  filterValue,
299
- onChange
310
+ onChange,
311
+ isDisabled
300
312
  }) {
301
313
  const t = useTranslator();
302
314
  // Convert unixSeconds to ISO date string for the date input
@@ -310,6 +322,7 @@ function DateAbsoluteEditor({
310
322
  return /*#__PURE__*/_jsx(DateInput, {
311
323
  label: t('@astryx.powersearch.valueEditor.date'),
312
324
  isLabelHidden: true,
325
+ isDisabled: isDisabled,
313
326
  value: currentValue,
314
327
  onChange: value => {
315
328
  if (value != null) {
@@ -325,7 +338,8 @@ function DateAbsoluteEditor({
325
338
  function DateRelativeEditor({
326
339
  operatorValue,
327
340
  filterValue,
328
- onChange
341
+ onChange,
342
+ isDisabled
329
343
  }) {
330
344
  const t = useTranslator();
331
345
  const currentValue = filterValue?.type === 'date_relative' ? filterValue.value : undefined;
@@ -366,6 +380,7 @@ function DateRelativeEditor({
366
380
  return /*#__PURE__*/_jsx(Selector, {
367
381
  label: t('@astryx.powersearch.valueEditor.relativeDate'),
368
382
  isLabelHidden: true,
383
+ isDisabled: isDisabled,
369
384
  options: options,
370
385
  value: currentValue,
371
386
  onChange: value => {
@@ -378,7 +393,8 @@ function DateRelativeEditor({
378
393
  }
379
394
  function DateRangeEditor({
380
395
  filterValue,
381
- onChange
396
+ onChange,
397
+ isDisabled
382
398
  }) {
383
399
  const t = useTranslator();
384
400
  const currentValue = useMemo(() => {
@@ -425,6 +441,7 @@ function DateRangeEditor({
425
441
  children: /*#__PURE__*/_jsx(DateRangeInput, {
426
442
  label: t('@astryx.powersearch.valueEditor.dateRange'),
427
443
  isLabelHidden: true,
444
+ isDisabled: isDisabled,
428
445
  value: currentValue,
429
446
  onChange: handleChange,
430
447
  hasClear: false
@@ -434,7 +451,8 @@ function DateRangeEditor({
434
451
  function EnumEditor({
435
452
  operatorValue,
436
453
  filterValue,
437
- onChange
454
+ onChange,
455
+ isDisabled
438
456
  }) {
439
457
  const t = useTranslator();
440
458
  const currentValue = filterValue?.type === 'enum' ? filterValue.value : undefined;
@@ -445,6 +463,7 @@ function EnumEditor({
445
463
  return /*#__PURE__*/_jsx(Selector, {
446
464
  label: t('@astryx.powersearch.valueEditor.value'),
447
465
  isLabelHidden: true,
466
+ isDisabled: isDisabled,
448
467
  options: options,
449
468
  value: currentValue,
450
469
  onChange: value => {
@@ -458,7 +477,8 @@ function EnumEditor({
458
477
  function EnumListEditor({
459
478
  operatorValue,
460
479
  filterValue,
461
- onChange
480
+ onChange,
481
+ isDisabled
462
482
  }) {
463
483
  const t = useTranslator();
464
484
  const items = useMemo(() => enumItemsToSearchableItems(operatorValue.values), [operatorValue.values]);
@@ -478,6 +498,7 @@ function EnumListEditor({
478
498
  return /*#__PURE__*/_jsx(Tokenizer, {
479
499
  label: t('@astryx.powersearch.valueEditor.values'),
480
500
  isLabelHidden: true,
501
+ isDisabled: isDisabled,
481
502
  searchSource: source,
482
503
  value: currentValue,
483
504
  onChange: selectedItems => {
@@ -500,7 +521,8 @@ function EntityListEditor({
500
521
  operatorValue,
501
522
  filterValue,
502
523
  onChange,
503
- maxMenuItems
524
+ maxMenuItems,
525
+ isDisabled
504
526
  }) {
505
527
  const t = useTranslator();
506
528
  const source = useMemo(() => {
@@ -529,6 +551,7 @@ function EntityListEditor({
529
551
  return /*#__PURE__*/_jsx(Tokenizer, {
530
552
  label: t('@astryx.powersearch.valueEditor.entities'),
531
553
  isLabelHidden: true,
554
+ isDisabled: isDisabled,
532
555
  searchSource: source,
533
556
  value: currentValue,
534
557
  onChange: items => {
@@ -594,6 +617,7 @@ export function PowerSearchValueEditor({
594
617
  return null;
595
618
  case 'string':
596
619
  return /*#__PURE__*/_jsx(StringEditor, {
620
+ isDisabled: isDisabled,
597
621
  operatorValue: operatorValue,
598
622
  filterValue: filterValue,
599
623
  onChange: onChange,
@@ -602,6 +626,7 @@ export function PowerSearchValueEditor({
602
626
  });
603
627
  case 'string_list':
604
628
  return /*#__PURE__*/_jsx(StringListEditor, {
629
+ isDisabled: isDisabled,
605
630
  operatorValue: operatorValue,
606
631
  filterValue: filterValue,
607
632
  onChange: onChange,
@@ -609,6 +634,7 @@ export function PowerSearchValueEditor({
609
634
  });
610
635
  case 'integer':
611
636
  return /*#__PURE__*/_jsx(IntegerEditor, {
637
+ isDisabled: isDisabled,
612
638
  operatorValue: operatorValue,
613
639
  filterValue: filterValue,
614
640
  onChange: onChange,
@@ -616,6 +642,7 @@ export function PowerSearchValueEditor({
616
642
  });
617
643
  case 'float':
618
644
  return /*#__PURE__*/_jsx(FloatEditor, {
645
+ isDisabled: isDisabled,
619
646
  operatorValue: operatorValue,
620
647
  filterValue: filterValue,
621
648
  onChange: onChange,
@@ -623,42 +650,49 @@ export function PowerSearchValueEditor({
623
650
  });
624
651
  case 'time':
625
652
  return /*#__PURE__*/_jsx(TimeEditor, {
653
+ isDisabled: isDisabled,
626
654
  operatorValue: operatorValue,
627
655
  filterValue: filterValue,
628
656
  onChange: onChange
629
657
  });
630
658
  case 'date_absolute':
631
659
  return /*#__PURE__*/_jsx(DateAbsoluteEditor, {
660
+ isDisabled: isDisabled,
632
661
  operatorValue: operatorValue,
633
662
  filterValue: filterValue,
634
663
  onChange: onChange
635
664
  });
636
665
  case 'date_relative':
637
666
  return /*#__PURE__*/_jsx(DateRelativeEditor, {
667
+ isDisabled: isDisabled,
638
668
  operatorValue: operatorValue,
639
669
  filterValue: filterValue,
640
670
  onChange: onChange
641
671
  });
642
672
  case 'date_range':
643
673
  return /*#__PURE__*/_jsx(DateRangeEditor, {
674
+ isDisabled: isDisabled,
644
675
  operatorValue: operatorValue,
645
676
  filterValue: filterValue,
646
677
  onChange: onChange
647
678
  });
648
679
  case 'enum':
649
680
  return /*#__PURE__*/_jsx(EnumEditor, {
681
+ isDisabled: isDisabled,
650
682
  operatorValue: operatorValue,
651
683
  filterValue: filterValue,
652
684
  onChange: onChange
653
685
  });
654
686
  case 'enum_list':
655
687
  return /*#__PURE__*/_jsx(EnumListEditor, {
688
+ isDisabled: isDisabled,
656
689
  operatorValue: operatorValue,
657
690
  filterValue: filterValue,
658
691
  onChange: onChange
659
692
  });
660
693
  case 'entity_list':
661
694
  return /*#__PURE__*/_jsx(EntityListEditor, {
695
+ isDisabled: isDisabled,
662
696
  operatorValue: operatorValue,
663
697
  filterValue: filterValue,
664
698
  onChange: onChange,
@@ -1 +1 @@
1
- {"version":3,"file":"SideNavItem.d.ts","sourceRoot":"","sources":["../../src/SideNav/SideNavItem.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAYf,OAAO,EAAuB,KAAK,QAAQ,EAAC,MAAM,SAAS,CAAC;AAE5D,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,eAAe,CAAC;AAIrD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAgB,KAAK,WAAW,EAAC,MAAM,iCAAiC,CAAC;AA4ShF,MAAM,WAAW,gBAAiB,SAAQ,SAAS,CAAC,WAAW,CAAC;IAC9D,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7B;;;;OAIG;IACH,EAAE,CAAC,EAAE,iBAAiB,CAAC;IACvB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B;;OAEG;IACH,YAAY,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IACpC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IACxC;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EACR,OAAO,GACP;QACE,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,iBAAiB,CAAC,EAAE,CAAC,WAAW,EAAE,OAAO,KAAK,IAAI,CAAC;KACpD,CAAC;IACN;;;OAGG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,WAAW,CAAC,EAC1B,EAAE,EACF,KAAK,EACL,IAAI,EACJ,YAAY,EACZ,UAAkB,EAClB,UAAkB,EAClB,IAAI,EACJ,OAAO,EACP,UAAU,EACV,OAAO,EACP,QAAQ,EACR,WAAW,EAAE,eAAe,EAC5B,IAAW,EACX,aAAa,EAAE,MAAM,EACrB,GAAG,EACH,MAAM,EACN,GAAG,IAAI,EACR,EAAE,gBAAgB,sCAkalB;yBApbe,WAAW"}
1
+ {"version":3,"file":"SideNavItem.d.ts","sourceRoot":"","sources":["../../src/SideNav/SideNavItem.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAYf,OAAO,EAAuB,KAAK,QAAQ,EAAC,MAAM,SAAS,CAAC;AAE5D,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,eAAe,CAAC;AAIrD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAgB,KAAK,WAAW,EAAC,MAAM,iCAAiC,CAAC;AA4ShF,MAAM,WAAW,gBAAiB,SAAQ,SAAS,CAAC,WAAW,CAAC;IAC9D,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7B;;;;OAIG;IACH,EAAE,CAAC,EAAE,iBAAiB,CAAC;IACvB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B;;OAEG;IACH,YAAY,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IACpC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IACxC;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EACR,OAAO,GACP;QACE,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,iBAAiB,CAAC,EAAE,CAAC,WAAW,EAAE,OAAO,KAAK,IAAI,CAAC;KACpD,CAAC;IACN;;;OAGG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,WAAW,CAAC,EAC1B,EAAE,EACF,KAAK,EACL,IAAI,EACJ,YAAY,EACZ,UAAkB,EAClB,UAAkB,EAClB,IAAI,EACJ,OAAO,EACP,UAAU,EACV,OAAO,EACP,QAAQ,EACR,WAAW,EAAE,eAAe,EAC5B,IAAW,EACX,aAAa,EAAE,MAAM,EACrB,GAAG,EACH,MAAM,EACN,GAAG,IAAI,EACR,EAAE,gBAAgB,sCAqalB;yBAvbe,WAAW"}
@@ -405,7 +405,9 @@ export function SideNavItem({
405
405
  size,
406
406
  selected: isSelected ? 'selected' : null,
407
407
  disabled: isDisabled ? 'disabled' : null
408
- }), focusOutlineProps.focusVisible(navItemStyles.item, interactionOverlayStyles.backgroundColor, navItemStyles[size], styles.itemCollapsed, size === 'sm' && styles.itemCollapsedSm, size === 'lg' && styles.itemCollapsedLg, isSelected && navItemStyles.selected, isDisabled && navItemStyles.disabled)),
408
+ }), focusOutlineProps.focusVisible(navItemStyles.item, interactionOverlayStyles.backgroundColor, navItemStyles[size], styles.itemCollapsed, size === 'sm' && styles.itemCollapsedSm, size === 'lg' && styles.itemCollapsedLg, isSelected && navItemStyles.selected, isDisabled && navItemStyles.disabled),
409
+ // Spread after `rest`, so keep the caller's class beside these.
410
+ rest.className),
409
411
  ...pressable
410
412
  };
411
413
  const collapsedAccessibleLabel = rest['aria-label'] != null && rest['aria-label'].trim() !== '' ? rest['aria-label'] : label;
@@ -512,8 +514,10 @@ export function SideNavItem({
512
514
 
513
515
  // The indent is a runtime value, so it reaches the element as an inline
514
516
  // style. These props are spread after `rest`, so fold the caller's `style`
515
- // back in (caller wins) rather than letting the indent replace it.
517
+ // back in (caller wins) rather than letting the indent replace it, and the
518
+ // caller's `className` beside the row's own classes.
516
519
  const callerStyle = {
520
+ className: rest.className,
517
521
  style: rest.style
518
522
  };
519
523
 
@@ -89,7 +89,7 @@ const styles = {
89
89
  kMwMTN: "x1heor9g",
90
90
  k5JduY: "x1s928wv",
91
91
  kwXMNM: "x1j6awrg",
92
- kv0HGH: "x1xsm0q9",
92
+ kv0HGH: "xramuyw",
93
93
  $$css: true
94
94
  }
95
95
  };
@@ -409,6 +409,8 @@ function DrawerMegaMenu({
409
409
  })]
410
410
  }), /*#__PURE__*/_jsx("div", {
411
411
  id: `${menuId}-items`,
412
+ "aria-hidden": !isExpanded,
413
+ inert: !isExpanded ? true : undefined,
412
414
  ...{
413
415
  0: {
414
416
  className: "xrvj5dj xihq33y xb3r6kr x6kj92 xd00j3c x1eizr8u xlr8y92"
@@ -1 +1 @@
1
- {"version":3,"file":"TopNavMenu.d.ts","sourceRoot":"","sources":["../../src/TopNav/TopNavMenu.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,EAKZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AASf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAkN5C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAMD,MAAM,WAAW,eAAgB,SAAQ,SAAS,CAAC,iBAAiB,CAAC;IACnE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACnC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAE5B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,wBAAgB,UAAU,CAAC,EACzB,GAAG,EACH,KAAK,EACL,KAAK,EACL,KAAW,EACX,SAAe,EACf,MAAM,EACN,SAAS,EACT,KAAK,EACL,OAAO,EAAE,WAAW,EACpB,YAAY,EAAE,gBAAgB,EAC9B,YAAY,EAAE,gBAAgB,EAC9B,GAAG,IAAI,EACR,EAAE,eAAe,4BA4QjB;yBAzRe,UAAU"}
1
+ {"version":3,"file":"TopNavMenu.d.ts","sourceRoot":"","sources":["../../src/TopNav/TopNavMenu.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,EAKZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AASf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAkN5C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAMD,MAAM,WAAW,eAAgB,SAAQ,SAAS,CAAC,iBAAiB,CAAC;IACnE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACnC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAE5B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,wBAAgB,UAAU,CAAC,EACzB,GAAG,EACH,KAAK,EACL,KAAK,EACL,KAAW,EACX,SAAe,EACf,MAAM,EACN,SAAS,EACT,KAAK,EACL,OAAO,EAAE,WAAW,EACpB,YAAY,EAAE,gBAAgB,EAC9B,YAAY,EAAE,gBAAgB,EAC9B,GAAG,IAAI,EACR,EAAE,eAAe,4BA8QjB;yBA3Re,UAAU"}
@@ -309,6 +309,8 @@ export function TopNavMenu({
309
309
  })]
310
310
  }), /*#__PURE__*/_jsx("div", {
311
311
  id: `${menuId}-items`,
312
+ "aria-hidden": !drawerExpanded,
313
+ inert: !drawerExpanded ? true : undefined,
312
314
  ...{
313
315
  0: {
314
316
  className: "xrvj5dj xihq33y xb3r6kr x6kj92 xd00j3c x1eizr8u xlr8y92"
package/dist/astryx.css CHANGED
@@ -2077,7 +2077,7 @@
2077
2077
  .x1bev2v5[data-astryx-press="on"]:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){background-image:none}
2078
2078
  .x524tya[data-astryx-press="fading"]:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){background-image:none}
2079
2079
  @starting-style{.x1sopeo2.x1sopeo2:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){grid-template-rows:0fr}}
2080
- .x1xsm0q9:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{inset:-14px}
2080
+ .xramuyw:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{inset:-4px}
2081
2081
  .xarstr8:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{inset:0}
2082
2082
  .xxx281p:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{inset:0}
2083
2083
  .xht581f:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{inset:var(--_input-clear-hit-inset)}
@@ -4,7 +4,8 @@
4
4
  * @file reset.a11y.chromium.spec.ts
5
5
  * @input packages/core/src/reset.css, alone on a blank Chromium page
6
6
  * @output Browser evidence that the reset reaches ::before, ::after,
7
- * ::placeholder and the search field's cancel button
7
+ * ::placeholder, the search field's cancel button and the dropdown marker
8
+ * of a field with a list
8
9
  * @position reset.css integration proof. A pseudo-element inside :where() is
9
10
  * invalid, and the forgiving list drops it without an error, so only a
10
11
  * shipping engine shows which of the reset's rules still match.
@@ -13,6 +14,8 @@
13
14
  import * as fs from 'node:fs';
14
15
  import { fileURLToPath } from 'node:url';
15
16
  import { expect, test } from '@playwright/test';
17
+ // @ts-expect-error -- pngjs ships no declarations; runtime support is pinned.
18
+ import { PNG } from 'pngjs';
16
19
  const RESET_CSS = fs.readFileSync(fileURLToPath(new URL('./reset.css', import.meta.url)), 'utf8');
17
20
 
18
21
  // No Astryx CSS is loaded, so --color-text-secondary is undefined and a
@@ -149,6 +152,52 @@ test('a search field has no cancel button to clear it', async ({
149
152
  await page.mouse.click(box.x + box.width - 8, box.y + box.height / 2);
150
153
  await expect(query).toHaveValue('query');
151
154
  });
155
+ test('the dropdown marker of a field with a list sits in its middle', async ({
156
+ page
157
+ }) => {
158
+ // Chromium shows the marker while the pointer is over the field and draws
159
+ // it as a glyph set on the field's line-height, the 1.5 the reset inherits.
160
+ await page.evaluate(() => {
161
+ const field = document.createElement('input');
162
+ field.id = 'fruit';
163
+ field.setAttribute('list', 'fruits');
164
+ const options = document.createElement('datalist');
165
+ options.id = 'fruits';
166
+ options.append(new Option('Apple'));
167
+ document.body.append(field, options);
168
+ });
169
+ await page.addStyleTag({
170
+ content: `
171
+ #fruit {
172
+ display: block;
173
+ width: 240px;
174
+ padding: 7px 11px;
175
+ border: 1px solid;
176
+ line-height: 1.5;
177
+ }
178
+ `
179
+ });
180
+ const field = page.locator('#fruit');
181
+ await field.hover();
182
+ const png = PNG.sync.read(await field.screenshot({
183
+ caret: 'hide'
184
+ }));
185
+ // The marker is the only ink in the field's last 32px, inside the border.
186
+ const inkRows = [];
187
+ for (let y = 2; y < png.height - 2; y++) {
188
+ for (let x = png.width - 32; x < png.width - 2; x++) {
189
+ const offset = (y * png.width + x) * 4;
190
+ const luminance = (png.data[offset] + png.data[offset + 1] + png.data[offset + 2]) / 3;
191
+ if (luminance < 160) {
192
+ inkRows.push(y);
193
+ break;
194
+ }
195
+ }
196
+ }
197
+ expect(inkRows.length, 'the hovered field shows its marker').toBeGreaterThan(0);
198
+ const markerMiddle = (inkRows[0] + inkRows[inkRows.length - 1] + 1) / 2;
199
+ expect(Math.abs(markerMiddle - png.height / 2)).toBeLessThanOrEqual(1);
200
+ });
152
201
  test('a later layer and an unlayered rule still override the reset', async ({
153
202
  page
154
203
  }) => {
package/docs.mjs CHANGED
@@ -13,8 +13,8 @@
13
13
  * ==========================================================================
14
14
  * AI AGENT: do NOT guess component APIs or hand-write CSS. Run:
15
15
  * npx @astryxdesign/cli init
16
- * Use the SCOPED name `@astryxdesign/cli` — bare `npx astryx` resolves to an
17
- * unrelated package until the CLI is a dependency. Then, per component:
16
+ * Use the SCOPED name `@astryxdesign/cli` — the unscoped `astryx` resolves to
17
+ * an unrelated npm package until the CLI is a dependency. Then, per component:
18
18
  * npx @astryxdesign/cli component <Name>
19
19
  * npx @astryxdesign/cli component --list
20
20
  * ==========================================================================
@@ -27,8 +27,8 @@ const BANNER = `
27
27
 
28
28
  npx @astryxdesign/cli init
29
29
 
30
- (Use the scoped name @astryxdesign/cli. Bare \`npx astryx\` resolves to an
31
- unrelated package until the CLI is installed as a dependency.)
30
+ (Use the scoped name @astryxdesign/cli. The unscoped name astryx resolves
31
+ to an unrelated npm package until the CLI is installed as a dependency.)
32
32
 
33
33
  init writes the full component guide, page templates, design rules & tokens
34
34
  into your AGENTS.md / CLAUDE.md. Then, for any component:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/core",
3
- "version": "0.7.2-canary.fdd384f",
3
+ "version": "0.7.2",
4
4
  "displayName": "Astryx Core",
5
5
  "description": "The component library. Accessible, themeable React components with built-in spacing, dark mode, and StyleX styling.",
6
6
  "author": "Meta Open Source",
@@ -792,8 +792,6 @@
792
792
  "react-dom": ">=19.0.0"
793
793
  },
794
794
  "devDependencies": {
795
- "@astryxdesign/a11y-spec": "0.7.2-canary.fdd384f",
796
- "@astryxdesign/cli": "0.7.2-canary.fdd384f",
797
795
  "@babel/cli": "^7.29.7",
798
796
  "@babel/core": "^7.29.7",
799
797
  "@babel/preset-react": "^7.29.7",
@@ -804,7 +802,9 @@
804
802
  "@testing-library/jest-dom": "^6.6.0",
805
803
  "@testing-library/react": "^16.3.2",
806
804
  "@types/babel__core": "^7.20.5",
807
- "tailwindcss": "^4.3.2"
805
+ "tailwindcss": "^4.3.2",
806
+ "@astryxdesign/a11y-spec": "0.0.0",
807
+ "@astryxdesign/cli": "0.7.2"
808
808
  },
809
809
  "dependencies": {
810
810
  "intl-messageformat": "^11.2.9"
@@ -107,15 +107,75 @@ export function isAstryxInitialized(targetDir = process.cwd()) {
107
107
  }
108
108
 
109
109
  /**
110
- * The one-line next-step both postinstall nudges print. Kept here so layer 1
111
- * (core) and layer 2 (cli) can never word it differently.
110
+ * Does an agent working in `startDir` already have the Astryx prompt in reach?
112
111
  *
113
- * Scoped package form (`@astryxdesign/cli`) — always resolves to us, even before
114
- * the CLI is installed. Bare `npx astryx` would fetch an unrelated look-alike
112
+ * Coding agents read the agent docs between the repository root and the folder
113
+ * they work in. So inside a git repository, init's block in any folder from
114
+ * `startDir` up to the repository root counts: a workspace package of a
115
+ * monorepo initialized at its root is set up. Outside a repository only
116
+ * `startDir` itself is checked, as {@link isAstryxInitialized} does. Both the
117
+ * per-command nudge and the postinstall nudges ask this.
118
+ *
119
+ * @param {string} [startDir=process.cwd()]
120
+ * @returns {boolean}
121
+ */
122
+ export function isAstryxPromptInReach(startDir = process.cwd()) {
123
+ const start = path.resolve(startDir);
124
+ const repositoryRoot = findRepositoryRoot(start);
125
+ if (!repositoryRoot) return isAstryxInitialized(start);
126
+ for (let dir = start; ; dir = path.dirname(dir)) {
127
+ if (isAstryxInitialized(dir)) return true;
128
+ if (dir === repositoryRoot) return false;
129
+ }
130
+ }
131
+
132
+ /**
133
+ * The nearest folder at or above `start` that holds `.git` (a folder, or the
134
+ * file a worktree uses), or null outside a repository.
135
+ * @param {string} start
136
+ * @returns {string | null}
137
+ */
138
+ function findRepositoryRoot(start) {
139
+ for (let dir = start; ; ) {
140
+ if (fs.existsSync(path.join(dir, '.git'))) return dir;
141
+ const parent = path.dirname(dir);
142
+ if (parent === dir) return null;
143
+ dir = parent;
144
+ }
145
+ }
146
+
147
+ /**
148
+ * The invocation the setup nudge falls back to when the CLI's picker
149
+ * (`getCliInvocation`) cannot be loaded. Scoped package form
150
+ * (`@astryxdesign/cli`) — always resolves to us, even before the CLI is
151
+ * installed. npx with the unscoped name would fetch an unrelated look-alike
115
152
  * package (see PR #4151).
116
153
  */
117
- export const SETUP_NUDGE =
118
- '\nNext step: run `npx @astryxdesign/cli init` to finish setup and install the Astryx agent prompt.\n\n';
154
+ export const SETUP_INVOCATION = 'npx @astryxdesign/cli';
155
+
156
+ /**
157
+ * The one-line next-step every setup layer prints. Kept here so layer 1
158
+ * (core), layer 2 (cli postinstall) and layer 3 (each command) can never word
159
+ * it differently. Each layer passes the stem from the CLI's picker when it can
160
+ * load it.
161
+ *
162
+ * @param {string} [invocation] the CLI invocation stem, e.g. `pnpm exec astryx`
163
+ * @param {{before?: string | null}} [options] `before`: a command to run
164
+ * first, such as the one that adds the CLI to a project that has none
165
+ * @returns {string}
166
+ */
167
+ export function setupNudge(
168
+ invocation = SETUP_INVOCATION,
169
+ {before = null} = {},
170
+ ) {
171
+ const run = before
172
+ ? `\`${before}\`, then \`${invocation} init\``
173
+ : `\`${invocation} init\``;
174
+ return `\nNext step: run ${run} to finish setup and install the Astryx agent prompt.\n\n`;
175
+ }
176
+
177
+ /** The nudge with the fallback invocation. */
178
+ export const SETUP_NUDGE = setupNudge();
119
179
 
120
180
  /**
121
181
  * Pure decision: should a postinstall print the setup nudge? Shared by BOTH
@@ -1,7 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
3
  /**
4
- * @file @astryxdesign/core postinstall — nudge to run `npx @astryxdesign/cli init`.
4
+ * @file @astryxdesign/core postinstall — nudge to run `astryx init`, prefixed
5
+ * the way the project's installed CLI prints commands.
5
6
  *
6
7
  * Enforcement layer 1 of making `astryx init` foolproof: when the design system
7
8
  * is installed and the project hasn't run init yet, print a one-line next-step
@@ -19,6 +20,8 @@
19
20
  * during npx's fetch, and once set up.
20
21
  */
21
22
 
23
+ import * as fs from 'node:fs';
24
+ import * as path from 'node:path';
22
25
  import {fileURLToPath, pathToFileURL} from 'node:url';
23
26
 
24
27
  const HERE = fileURLToPath(import.meta.url);
@@ -37,6 +40,39 @@ async function loadContract() {
37
40
  }
38
41
  }
39
42
 
43
+ /**
44
+ * The stem the project's installed CLI would print, from its picker
45
+ * (`getCliInvocation`). Core cannot depend on the CLI, so this looks for an
46
+ * installed copy from the project upward and imports the picker by path; with
47
+ * no CLI there, or one too old to have the picker, it returns undefined and
48
+ * the contract's scoped fallback is printed. At install time no integration is
49
+ * loaded, so this is the package-manager guess.
50
+ * @param {string} root
51
+ * @returns {Promise<string | undefined>}
52
+ */
53
+ export async function cliInvocation(root) {
54
+ try {
55
+ let dir = path.resolve(root);
56
+ for (;;) {
57
+ const picker = path.join(
58
+ dir,
59
+ 'node_modules/@astryxdesign/cli/foundation/env/package-manager.mjs',
60
+ );
61
+ if (fs.existsSync(picker)) {
62
+ const {getCliInvocation} = await import(pathToFileURL(picker).href);
63
+ return typeof getCliInvocation === 'function'
64
+ ? getCliInvocation(root)
65
+ : undefined;
66
+ }
67
+ const parent = path.dirname(dir);
68
+ if (parent === dir) return undefined;
69
+ dir = parent;
70
+ }
71
+ } catch {
72
+ return undefined;
73
+ }
74
+ }
75
+
40
76
  async function main() {
41
77
  const contract = await loadContract();
42
78
  if (!contract) return;
@@ -45,10 +81,15 @@ async function main() {
45
81
  contract.shouldNudge({
46
82
  scriptPath: HERE,
47
83
  npmCommand: process.env.npm_command,
48
- isSetUp: contract.isAstryxInitialized(root),
84
+ isSetUp: contract.isAstryxPromptInReach(root),
49
85
  })
50
86
  ) {
51
- process.stdout.write(contract.SETUP_NUDGE);
87
+ const invocation = await cliInvocation(root);
88
+ process.stdout.write(
89
+ typeof contract.setupNudge === 'function'
90
+ ? contract.setupNudge(invocation)
91
+ : contract.SETUP_NUDGE,
92
+ );
52
93
  }
53
94
  }
54
95
 
@@ -387,9 +387,18 @@ export interface AvatarProps extends BaseProps<HTMLDivElement> {
387
387
  /**
388
388
  * A character that can stand for a word in initials: a letter, a digit, or an
389
389
  * emoji. Punctuation and other symbols, such as `(`, `"` or `-`, cannot.
390
+ *
391
+ * Built at runtime, not written as a literal: for targets without property
392
+ * escapes, or when no browserslist is set, Babel's
393
+ * transform-unicode-property-regex rewrites a `\p{…}` literal, and the copy
394
+ * bundled with Next.js lacks the Unicode data it needs, so a source build fails
395
+ * with "Unknown property". A literal is safe once Next's bundled Babel ships
396
+ * that data.
390
397
  */
391
- const INITIAL_CHARACTER =
392
- /[\p{L}\p{N}\p{Extended_Pictographic}\p{Regional_Indicator}]/u;
398
+ const INITIAL_CHARACTER = new RegExp(
399
+ '[\\p{L}\\p{N}\\p{Extended_Pictographic}\\p{Regional_Indicator}]',
400
+ 'u',
401
+ );
393
402
 
394
403
  /**
395
404
  * The first character of a word that can stand for it in initials, skipping