@astryxdesign/core 0.7.1 → 0.7.2-canary.c68f5e8

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 (35) hide show
  1. package/dist/Button/Button.d.ts.map +1 -1
  2. package/dist/Button/Button.js +38 -14
  3. package/dist/Pagination/Pagination.d.ts +8 -5
  4. package/dist/Pagination/Pagination.d.ts.map +1 -1
  5. package/dist/Pagination/Pagination.js +21 -8
  6. package/dist/Switch/Switch.d.ts +1 -1
  7. package/dist/Switch/Switch.d.ts.map +1 -1
  8. package/dist/Switch/Switch.js +6 -0
  9. package/dist/astryx.css +1 -0
  10. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  11. package/dist/i18n/generated-locales/en.generated.js +19 -0
  12. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  13. package/dist/i18n/generated-locales/pseudo.generated.js +19 -0
  14. package/locales/en.json +76 -0
  15. package/locales/pseudo.json +57 -0
  16. package/package.json +4 -4
  17. package/src/Button/Button.doc.mjs +2 -2
  18. package/src/Button/Button.test.tsx +155 -9
  19. package/src/Button/Button.tsx +39 -16
  20. package/src/Button/__tests__/Button.a11y.known-failures.ts +1 -62
  21. package/src/Button/__tests__/Button.a11y.states.ts +0 -10
  22. package/src/IconButton/IconButton.doc.mjs +2 -2
  23. package/src/IconButton/IconButton.test.tsx +3 -1
  24. package/src/Pagination/Pagination.doc.mjs +7 -7
  25. package/src/Pagination/Pagination.spec.md +9 -9
  26. package/src/Pagination/Pagination.test.tsx +242 -0
  27. package/src/Pagination/Pagination.tsx +27 -11
  28. package/src/Switch/Switch.test.tsx +28 -0
  29. package/src/Switch/Switch.tsx +6 -0
  30. package/src/i18n/InternationalizationProvider.doc.mjs +8 -0
  31. package/src/i18n/InternationalizationProvider.spec.md +252 -0
  32. package/src/i18n/__tests__/InternationalizationProvider.test.tsx +128 -0
  33. package/src/i18n/generated-locales/en.generated.ts +21 -0
  34. package/src/i18n/generated-locales/pseudo.generated.ts +21 -0
  35. package/src/i18n/useTranslator.test.tsx +37 -0
@@ -1 +1 @@
1
- {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../src/Button/Button.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../src/Button/Button.tsx"],"names":[],"mappings":"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"}
@@ -364,25 +364,35 @@ export function Button({
364
364
  // the consumer is deliberately showing it.
365
365
  const delaySpinner = isPending || isInterruptible;
366
366
  const groupDisabled = buttonGroup?.isDisabled ?? false;
367
- // When interruptible, the loading state drives the spinner and aria-busy but
368
- // not disabled, so clicks keep landing and can interrupt the in-flight action.
369
- const buttonDisabled = isDisabled || groupDisabled || isLoadingState && !isInterruptible;
370
- // A loading button remains non-interactive, but its spinner communicates an
371
- // active state and must retain contrast. Only explicitly disabled controls
372
- // receive the visually dimmed treatment.
373
- const visuallyDisabled = isDisabled || groupDisabled;
367
+ const isTrueDisabled = isDisabled || groupDisabled;
368
+ // Busy-only: the button can't fire again purely because an action is in
369
+ // flight, not because it's genuinely isDisabled/group-disabled. Per the API
370
+ // Conventions "Disabled vs Busy" rule, busy is visual-only (aria-busy +
371
+ // spinner) and must never take focusability away — the click-handler ref
372
+ // guard (actionInFlightRef) is what actually makes a fire-once action fire
373
+ // once, so the native disabled attribute adds nothing but a focus loss
374
+ // here. When interruptible, the loading state drives the spinner and
375
+ // aria-busy but not disabled at all, so clicks keep landing and can
376
+ // interrupt the in-flight action.
377
+ const isBusyOnlyDisabled = !isTrueDisabled && isLoadingState && !isInterruptible;
378
+ const buttonDisabled = isTrueDisabled || isBusyOnlyDisabled;
374
379
  // isIconOnly prop is the source of truth for icon-only rendering.
375
380
  // When false (default), label is always rendered as visible text.
376
381
 
377
382
  const LinkComponent = useLinkComponent(as);
378
383
 
379
- // Render as link when href is provided and button is not disabled.
380
- // Disabled links are an accessibility anti-pattern — fall back to <button>.
381
- const renderAsLink = href != null && !buttonDisabled;
384
+ // Render as link when href is provided and the button is not TRULY
385
+ // disabled. Disabled links are an accessibility anti-pattern, so a
386
+ // genuinely isDisabled/group-disabled button falls back to <button>.
387
+ // Busy-only does NOT fall back: swapping <a> for a disabled <button>
388
+ // mid-action would drop focus the same way the native attribute does
389
+ // (credit @AKnassa, #4879), which is exactly the bug this PR fixes.
390
+ const renderAsLink = href != null && !isTrueDisabled;
382
391
 
383
- // Use aria-disabled when tooltip is present so the button remains focusable
384
- // for keyboard users to reach the tooltip. Otherwise use native disabled.
385
- const useAriaDisabled = tooltip != null && buttonDisabled;
392
+ // Use aria-disabled (button stays focusable) when busy-only, or when a
393
+ // tooltip is present so keyboard users can still reach it. A genuinely
394
+ // isDisabled/group-disabled button (not busy) keeps native disabled.
395
+ const useAriaDisabled = buttonDisabled && (isBusyOnlyDisabled || tooltip != null);
386
396
 
387
397
  // Attach tooltip behavior via the hook rather than wrapping the button in a
388
398
  // <Tooltip> element. The hook adds hover/focus triggers to the button itself,
@@ -398,6 +408,16 @@ export function Button({
398
408
  // a re-click while pending starts a fresh action that interrupts the prior.
399
409
  if (buttonDisabled || actionInFlightRef.current && !isInterruptible) {
400
410
  e.preventDefault();
411
+ // A native `disabled` element never dispatches a click at all, so it
412
+ // never reaches a wrapping element's own handler either. An
413
+ // aria-disabled button (busy-only, or with a tooltip) is still a real,
414
+ // interactive element the DOM keeps dispatching clicks on —
415
+ // preventDefault alone only cancels the button's OWN default action
416
+ // (form submit, link navigation), not propagation. Without this, an
417
+ // unavailable Button inside a clickable row/card/backdrop still
418
+ // triggers that ancestor's action, which the previously native-disabled
419
+ // control never did.
420
+ e.stopPropagation();
401
421
  return;
402
422
  }
403
423
  props.onClick?.(e);
@@ -431,7 +451,7 @@ export function Button({
431
451
  } : null;
432
452
 
433
453
  // Shared StyleX props for both button and link rendering
434
- const sharedStylexProps = focusOutlineProps.focusVisible(styles.base, sizeStyles[size], isIconOnly && styles.iconOnly, interactionOverlayStyles.backgroundImage, buttonDisabled && styles.inactive, visuallyDisabled && styles.disabled, useAriaDisabled && styles.ariaDisabled, renderAsLink && styles.link, !buttonGroup && styles.pressable, buttonGroup && (buttonGroup.orientation === 'horizontal' ? groupStyles.horizontal : groupStyles.vertical), inputGroup != null && buttonGroup == null && inputGroupStyles.buttonAddon, buttonGroup && (variant === 'primary' || variant === 'destructive') && (buttonGroup.orientation === 'horizontal' ? groupStyles.onSolidHorizontal : groupStyles.onSolidVertical),
454
+ const sharedStylexProps = focusOutlineProps.focusVisible(styles.base, sizeStyles[size], isIconOnly && styles.iconOnly, interactionOverlayStyles.backgroundImage, buttonDisabled && styles.inactive, isTrueDisabled && styles.disabled, useAriaDisabled && styles.ariaDisabled, renderAsLink && styles.link, !buttonGroup && styles.pressable, buttonGroup && (buttonGroup.orientation === 'horizontal' ? groupStyles.horizontal : groupStyles.vertical), inputGroup != null && buttonGroup == null && inputGroupStyles.buttonAddon, buttonGroup && (variant === 'primary' || variant === 'destructive') && (buttonGroup.orientation === 'horizontal' ? groupStyles.onSolidHorizontal : groupStyles.onSolidVertical),
435
455
  // Standalone floating buttons only — a grouped button's elevation is owned
436
456
  // by the ButtonGroup so the shared surface lifts as one unit.
437
457
  !buttonGroup && elevationStyles[elevation], width != null && dynamicStyles.width(width),
@@ -523,7 +543,11 @@ export function Button({
523
543
  ...describedByProp,
524
544
  ...edgeCompAttr,
525
545
  "aria-busy": isLoadingState || undefined,
546
+ "aria-disabled": useAriaDisabled || undefined,
526
547
  onClick: handleClick,
548
+ ...(handleKeyDown ? {
549
+ onKeyDown: handleKeyDown
550
+ } : null),
527
551
  children: buttonContent
528
552
  });
529
553
  } else {
@@ -42,7 +42,8 @@ export interface PaginationProps extends Omit<BaseProps<HTMLElement>, 'onChange'
42
42
  * Visual variant controlling what appears between prev/next buttons.
43
43
  * - pages: Page number buttons with ellipsis (default)
44
44
  * - count: "X–Y of Z" text
45
- * - compact: "Page X of Y" text
45
+ * - compact: "Page X of Y" text. First/last buttons are opt-in (see
46
+ * hasFirstLast).
46
47
  * - dots: Dot indicators
47
48
  * - input: An editable number box rendering "Page [ n ] / N". The leading
48
49
  * noun is controlled by `pageLabel`. First/last double-chevron buttons
@@ -59,9 +60,11 @@ export interface PaginationProps extends Omit<BaseProps<HTMLElement>, 'onChange'
59
60
  pageLabel?: string;
60
61
  /**
61
62
  * Whether to show first/last («/») double-chevron buttons flanking
62
- * prev/next. Only applies to the `input` variant; other variants ignore it.
63
- * The last button needs a known total — it is omitted when the page count is
64
- * unknown (cursor/hasMore pagination). @default true
63
+ * prev/next. Applies to the `input` variant (shown unless false) and the
64
+ * `compact` variant (shown only when true); other variants ignore it.
65
+ * The last button needs a known total — both are omitted when the page count
66
+ * is unknown (cursor/hasMore pagination).
67
+ * @default true for `input`, false for `compact`
65
68
  */
66
69
  hasFirstLast?: boolean;
67
70
  /**
@@ -121,7 +124,7 @@ export declare function generatePageRange(currentPage: number, totalPages: numbe
121
124
  * />
122
125
  * ```
123
126
  */
124
- export declare function Pagination({ page, onChange, changeAction, totalItems, totalPages: totalPagesProp, hasMore, pageSize: pageSizeProp, pageSizeOptions, onPageSizeChange, variant, pageLabel, hasFirstLast, step: stepProp, siblingCount, size, isDisabled, label: labelFromProps, 'data-testid': testId, xstyle, className, style, ref, ...rest }: PaginationProps): import("react").JSX.Element | null;
127
+ export declare function Pagination({ page, onChange, changeAction, totalItems, totalPages: totalPagesProp, hasMore, pageSize: pageSizeProp, pageSizeOptions, onPageSizeChange, variant, pageLabel, hasFirstLast: hasFirstLastProp, step: stepProp, siblingCount, size, isDisabled, label: labelFromProps, 'data-testid': testId, xstyle, className, style, ref, ...rest }: PaginationProps): import("react").JSX.Element | null;
125
128
  export declare namespace Pagination {
126
129
  var displayName: string;
127
130
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Pagination.d.ts","sourceRoot":"","sources":["../../src/Pagination/Pagination.tsx"],"names":[],"mappings":"AA2CA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAI5C,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,SAAS,CAAC;AAMlD;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,oBAAoB,CAAC;AAE3D,uCAAuC;AACvC,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,CAAC;AAEzC,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,SAAS,CAAC,WAAW,CAAC,EACtB,UAAU,CACX;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAE7B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGtD;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAGlB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAG9C;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC;IAGtB,wDAAwD;IACxD,UAAU,CAAC,EAAE,OAAO,CAAC;IAGrB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,qCAAqC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAkHD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GACnB,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE,CA6CpB;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,UAAU,EAAE,cAAc,EAC1B,OAAO,EACP,QAAQ,EAAE,YAAiB,EAC3B,eAAe,EACf,gBAAgB,EAChB,OAAiB,EACjB,SAAS,EACT,YAAmB,EACnB,IAAI,EAAE,QAAY,EAClB,YAAgB,EAChB,IAAW,EACX,UAAkB,EAClB,KAAK,EAAE,cAAc,EACrB,aAAa,EAAE,MAAM,EACrB,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,IAAI,EACR,EAAE,eAAe,sCAkfjB;yBA1gBe,UAAU"}
1
+ {"version":3,"file":"Pagination.d.ts","sourceRoot":"","sources":["../../src/Pagination/Pagination.tsx"],"names":[],"mappings":"AA4CA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAI5C,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,SAAS,CAAC;AAMlD;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,oBAAoB,CAAC;AAE3D,uCAAuC;AACvC,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,CAAC;AAEzC,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,SAAS,CAAC,WAAW,CAAC,EACtB,UAAU,CACX;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAE7B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGtD;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAGlB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAG9C;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC;IAGtB,wDAAwD;IACxD,UAAU,CAAC,EAAE,OAAO,CAAC;IAGrB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,qCAAqC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAwHD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GACnB,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE,CA6CpB;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,UAAU,EAAE,cAAc,EAC1B,OAAO,EACP,QAAQ,EAAE,YAAiB,EAC3B,eAAe,EACf,gBAAgB,EAChB,OAAiB,EACjB,SAAS,EACT,YAAY,EAAE,gBAAgB,EAC9B,IAAI,EAAE,QAAY,EAClB,YAAgB,EAChB,IAAW,EACX,UAAkB,EAClB,KAAK,EAAE,cAAc,EACrB,aAAa,EAAE,MAAM,EACrB,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,IAAI,EACR,EAAE,eAAe,sCAwfjB;yBAhhBe,UAAU"}
@@ -5,9 +5,10 @@
5
5
  /**
6
6
  * @file Pagination.tsx
7
7
  * @input Uses React, StyleX, Button, Icon, Selector, Text; page number buttons delegate to Button.
8
+ * Compact first/last buttons cancel the inside control gap with logical token margins.
8
9
  * Prev/next and first/last chevrons mirror under RTL via the shared rtlStyles.mirror
9
- * (CSS scaleX), not a JS direction read. The input variant uses the chevronsLeft/chevronsRight
10
- * (first/last) icons.
10
+ * (CSS scaleX), not a JS direction read. The input and compact variants use the
11
+ * chevronsLeft/chevronsRight (first/last) icons.
11
12
  * @output Exports Pagination component, PaginationProps, PaginationVariant, PaginationSize types
12
13
  * @position Core implementation; consumed by index.ts, tested by Pagination.test.tsx
13
14
  *
@@ -61,6 +62,14 @@ const styles = {
61
62
  kOIVth: "x18g69wz",
62
63
  $$css: true
63
64
  },
65
+ compactFirst: {
66
+ k71WvV: "xkd40ry",
67
+ $$css: true
68
+ },
69
+ compactLast: {
70
+ keTefX: "x547jwd",
71
+ $$css: true
72
+ },
64
73
  dot: {
65
74
  kzqmXN: "x1f0dxl5",
66
75
  kZKoxP: "xoqw5ej",
@@ -188,7 +197,7 @@ export function Pagination({
188
197
  onPageSizeChange,
189
198
  variant = 'pages',
190
199
  pageLabel,
191
- hasFirstLast = true,
200
+ hasFirstLast: hasFirstLastProp,
192
201
  step: stepProp = 1,
193
202
  siblingCount = 1,
194
203
  size = 'md',
@@ -363,9 +372,11 @@ export function Pagination({
363
372
  const buttonSize = size === 'sm' ? 'sm' : 'md';
364
373
  const isSm = size === 'sm';
365
374
 
366
- // First/last buttons only exist in the input variant, and only when the page
367
- // count is known (they'd have no target otherwise).
368
- const showFirstLast = hasFirstLast && variant === 'input' && computedTotalPages != null;
375
+ // First/last buttons are on by default in the input variant and opt-in for
376
+ // compact; other variants never render them. They also need a known page
377
+ // count (the last button would have no target otherwise).
378
+ const hasFirstLast = variant === 'input' ? hasFirstLastProp ?? true : variant === 'compact' && hasFirstLastProp === true;
379
+ const showFirstLast = hasFirstLast && computedTotalPages != null;
369
380
  const renderIndicator = () => {
370
381
  switch (variant) {
371
382
  case 'pages':
@@ -600,7 +611,8 @@ export function Pagination({
600
611
  }),
601
612
  onClick: handleFirst,
602
613
  isDisabled: isDisabled || !hasPrevious,
603
- isIconOnly: true
614
+ isIconOnly: true,
615
+ xstyle: variant === 'compact' && styles.compactFirst
604
616
  }), /*#__PURE__*/_jsx(Button, {
605
617
  label: previousLabel,
606
618
  tooltip: isDisabled || !hasPrevious ? undefined : previousLabel,
@@ -639,7 +651,8 @@ export function Pagination({
639
651
  }),
640
652
  onClick: handleLast,
641
653
  isDisabled: isDisabled || !hasNext,
642
- isIconOnly: true
654
+ isIconOnly: true,
655
+ xstyle: variant === 'compact' && styles.compactLast
643
656
  })]
644
657
  })]
645
658
  });
@@ -159,7 +159,7 @@ export interface SwitchProps extends Omit<BaseProps, 'onChange'> {
159
159
  * />
160
160
  * ```
161
161
  */
162
- export declare function Switch({ label, isLabelHidden, description, onChange, changeAction, isLoading, value, isDisabled, htmlName, disabledMessage, isOptional, isRequired, onFocus, onBlur, labelIcon, labelTooltip, labelPosition, labelSpacing, status, size, width, xstyle, className, style, ref, ...rest }: SwitchProps): import("react").JSX.Element;
162
+ export declare function Switch({ label, isLabelHidden, description, onChange, changeAction, isLoading, value, isDisabled, htmlName, disabledMessage, isOptional, isRequired, onFocus, onBlur, labelIcon, labelTooltip, labelPosition, labelSpacing, status, size, width, xstyle, className, style, ref, 'aria-describedby': ariaDescribedByProp, ...rest }: SwitchProps): import("react").JSX.Element;
163
163
  export declare namespace Switch {
164
164
  var displayName: string;
165
165
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Switch.d.ts","sourceRoot":"","sources":["../../src/Switch/Switch.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Switch.d.ts","sourceRoot":"","sources":["../../src/Switch/Switch.tsx"],"names":[],"mappings":"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"}
@@ -291,6 +291,7 @@ export function Switch({
291
291
  className,
292
292
  style,
293
293
  ref,
294
+ 'aria-describedby': ariaDescribedByProp,
294
295
  ...rest
295
296
  }) {
296
297
  const t = useTranslator();
@@ -335,7 +336,12 @@ export function Switch({
335
336
  // Only include descriptionID when the element actually renders.
336
337
  // FieldLabel renders the description (with descriptionID) even when the
337
338
  // label is visually hidden — it's sr-only, so keep it linked.
339
+ // A consumer's own `aria-describedby` describes the control, so it comes
340
+ // first here rather than landing on the field wrapper via `...rest`.
338
341
  const describedByParts = [];
342
+ if (ariaDescribedByProp) {
343
+ describedByParts.push(ariaDescribedByProp);
344
+ }
339
345
  if (description) {
340
346
  describedByParts.push(descriptionID);
341
347
  }
package/dist/astryx.css CHANGED
@@ -1127,6 +1127,7 @@
1127
1127
  .xd10s4z:not(#\#):not(#\#):not(#\#){margin-inline-start:calc(-1 * var(--border-width))}
1128
1128
  .xojxgvx:not(#\#):not(#\#):not(#\#){margin-inline-start:calc(-1 * var(--container-padding-inline-start,0px))}
1129
1129
  .x1wim8z0:not(#\#):not(#\#):not(#\#){margin-inline-start:calc(-1 * var(--layout-padding-inner-x,var(--spacing-4)))}
1130
+ .x547jwd:not(#\#):not(#\#):not(#\#){margin-inline-start:calc(-1 * var(--spacing-1))}
1130
1131
  .x1s1akpx:not(#\#):not(#\#):not(#\#){margin-inline-start:calc(-1 * var(--spacing-2))}
1131
1132
  .x6n8pbd:not(#\#):not(#\#):not(#\#){margin-inline-start:calc((40px - min(var(--spacing-6),40px)) / 2 - var(--spacing-2))}
1132
1133
  .xs69w1r:not(#\#):not(#\#):not(#\#){margin-inline-start:calc((40px - min(var(--spacing-6),40px)) / 2 - var(--spacing-3))}
@@ -1 +1 @@
1
- {"version":3,"file":"en.generated.d.ts","sourceRoot":"","sources":["../../../src/i18n/generated-locales/en.generated.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,QAAA,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAqcpD,CAAC;AAEF,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"en.generated.d.ts","sourceRoot":"","sources":["../../../src/i18n/generated-locales/en.generated.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,QAAA,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA0dpD,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -139,6 +139,25 @@ const runtimeCatalog = {
139
139
  '@astryx.listInput.announceReturnedToPosition': '{itemName} returned to position {position, number}.',
140
140
  '@astryx.listInput.announceDropped': '{itemName} dropped at position {position, number} of {total, number}.',
141
141
  '@astryx.listInput.announceAlreadyAtBoundary': 'This {itemName} is already {boundary, select, first {first} last {last} other {}}.',
142
+ '@astryx.diffViewer.label': 'Diff',
143
+ '@astryx.diffViewer.renamedPath': '{oldPath} → {newPath}',
144
+ '@astryx.diffViewer.statusAdded': 'Added',
145
+ '@astryx.diffViewer.statusDeleted': 'Deleted',
146
+ '@astryx.diffViewer.statusRenamed': 'Renamed',
147
+ '@astryx.diffViewer.addedCount': '+{count, number}',
148
+ '@astryx.diffViewer.removedCount': '−{count, number}',
149
+ '@astryx.diffViewer.stats': '{added, plural, one {# line added} other {# lines added}}, {removed, plural, one {# line removed} other {# lines removed}}',
150
+ '@astryx.diffViewer.added': 'Added',
151
+ '@astryx.diffViewer.removed': 'Removed',
152
+ '@astryx.diffViewer.lineNumberButton': '{side, select, old {Original line {line, number}} other {Changed line {line, number}}}',
153
+ '@astryx.diffViewer.columnOldLine': 'Original line number',
154
+ '@astryx.diffViewer.columnNewLine': 'Changed line number',
155
+ '@astryx.diffViewer.columnChange': 'Change',
156
+ '@astryx.diffViewer.columnCode': 'Code',
157
+ '@astryx.diffViewer.columnOldCode': 'Original code',
158
+ '@astryx.diffViewer.columnNewCode': 'Changed code',
159
+ '@astryx.diffViewer.binary': 'Binary file not shown',
160
+ '@astryx.diffViewer.noChanges': 'No content changes',
142
161
  '@astryx.markdownHeadingLinks.copied': 'Link copied',
143
162
  '@astryx.markdownHeadingLinks.copy': 'Copy link to {heading}',
144
163
  '@astryx.richTextEditor.tabEscapeHint': 'Press Escape then Tab to move focus out of the editor.',
@@ -1 +1 @@
1
- {"version":3,"file":"pseudo.generated.d.ts","sourceRoot":"","sources":["../../../src/i18n/generated-locales/pseudo.generated.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,QAAA,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA8cpD,CAAC;AAEF,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"pseudo.generated.d.ts","sourceRoot":"","sources":["../../../src/i18n/generated-locales/pseudo.generated.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,QAAA,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmepD,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -139,6 +139,25 @@ const runtimeCatalog = {
139
139
  '@astryx.listInput.announceReturnedToPosition': '⟦{itemName} řéţúřñéð ţó þóšíţíóñ {position, number}.⟧',
140
140
  '@astryx.listInput.announceDropped': '⟦{itemName} ðřóþþéð àţ þóšíţíóñ {position, number} óƒ {total, number}.⟧',
141
141
  '@astryx.listInput.announceAlreadyAtBoundary': '⟦Ţĥíš {itemName} íš àłřéàðý {boundary, select, first {first} last {last} other {}}.⟧',
142
+ '@astryx.diffViewer.label': '⟦Ð탃⟧',
143
+ '@astryx.diffViewer.renamedPath': '⟦{oldPath} → {newPath}⟧',
144
+ '@astryx.diffViewer.statusAdded': '⟦Àððéð⟧',
145
+ '@astryx.diffViewer.statusDeleted': '⟦Ðéłéţéð⟧',
146
+ '@astryx.diffViewer.statusRenamed': '⟦Řéñàɱéð⟧',
147
+ '@astryx.diffViewer.addedCount': '⟦+{count, number}⟧',
148
+ '@astryx.diffViewer.removedCount': '⟦−{count, number}⟧',
149
+ '@astryx.diffViewer.stats': '⟦{added, plural, one {# line added} other {# lines added}}, {removed, plural, one {# line removed} other {# lines removed}}⟧',
150
+ '@astryx.diffViewer.added': '⟦Àððéð⟧',
151
+ '@astryx.diffViewer.removed': '⟦Řéɱóṽéð⟧',
152
+ '@astryx.diffViewer.lineNumberButton': '⟦{side, select, old {Original line {line, number}} other {Changed line {line, number}}}⟧',
153
+ '@astryx.diffViewer.columnOldLine': '⟦Óříĝíñàł łíñé ñúɱƀéř⟧',
154
+ '@astryx.diffViewer.columnNewLine': '⟦Çĥàñĝéð łíñé ñúɱƀéř⟧',
155
+ '@astryx.diffViewer.columnChange': '⟦Çĥàñĝé⟧',
156
+ '@astryx.diffViewer.columnCode': '⟦Çóðé⟧',
157
+ '@astryx.diffViewer.columnOldCode': '⟦Óříĝíñàł çóðé⟧',
158
+ '@astryx.diffViewer.columnNewCode': '⟦Çĥàñĝéð çóðé⟧',
159
+ '@astryx.diffViewer.binary': '⟦Ɓíñàřý ƒíłé ñóţ šĥóŵñ⟧',
160
+ '@astryx.diffViewer.noChanges': '⟦Ñó çóñţéñţ çĥàñĝéš⟧',
142
161
  '@astryx.markdownHeadingLinks.copied': '⟦Łíñķ çóþíéð⟧',
143
162
  '@astryx.markdownHeadingLinks.copy': '⟦Çóþý łíñķ ţó {heading}⟧',
144
163
  '@astryx.richTextEditor.tabEscapeHint': '⟦Þřéšš Éšçàþé ţĥéñ Ţàƀ ţó ɱóṽé ƒóçúš óúţ óƒ ţĥé éðíţóř.⟧',
package/locales/en.json CHANGED
@@ -527,6 +527,82 @@
527
527
  "defaultMessage": "This {itemName} is already {boundary, select, first {first} last {last} other {}}.",
528
528
  "description": "Screen-reader-only live announcement when an arrow-key reorder attempt has no effect because the record is already at that end of the list. `{itemName}` is the consumer's singular noun for one record; `{boundary}` is always exactly \"first\" or \"last\"."
529
529
  },
530
+ "@astryx.diffViewer.label": {
531
+ "defaultMessage": "Diff",
532
+ "description": "Accessible name of a lab DiffViewer's scrollable code area when the file has no path to name it."
533
+ },
534
+ "@astryx.diffViewer.renamedPath": {
535
+ "defaultMessage": "{oldPath} → {newPath}",
536
+ "description": "File path shown in a lab DiffViewer header when the file was renamed. `{oldPath}` and `{newPath}` are file paths and must stay untranslated; keep the arrow pointing from the old path to the new one."
537
+ },
538
+ "@astryx.diffViewer.statusAdded": {
539
+ "defaultMessage": "Added",
540
+ "description": "Badge in a lab DiffViewer file header marking a file that the change creates."
541
+ },
542
+ "@astryx.diffViewer.statusDeleted": {
543
+ "defaultMessage": "Deleted",
544
+ "description": "Badge in a lab DiffViewer file header marking a file that the change removes."
545
+ },
546
+ "@astryx.diffViewer.statusRenamed": {
547
+ "defaultMessage": "Renamed",
548
+ "description": "Badge in a lab DiffViewer file header marking a file that the change moves to a new path."
549
+ },
550
+ "@astryx.diffViewer.addedCount": {
551
+ "defaultMessage": "+{count, number}",
552
+ "description": "Compact count of added lines shown in a lab DiffViewer file header, e.g. \"+12\". Hidden from screen readers, which hear `@astryx.diffViewer.stats` instead."
553
+ },
554
+ "@astryx.diffViewer.removedCount": {
555
+ "defaultMessage": "−{count, number}",
556
+ "description": "Compact count of removed lines shown in a lab DiffViewer file header, e.g. \"−3\" (a minus sign). Hidden from screen readers, which hear `@astryx.diffViewer.stats` instead."
557
+ },
558
+ "@astryx.diffViewer.stats": {
559
+ "defaultMessage": "{added, plural, one {# line added} other {# lines added}}, {removed, plural, one {# line removed} other {# lines removed}}",
560
+ "description": "Screen-reader text for the line counts in a lab DiffViewer file header, e.g. \"12 lines added, 3 lines removed\"."
561
+ },
562
+ "@astryx.diffViewer.added": {
563
+ "defaultMessage": "Added",
564
+ "description": "Screen-reader text marking one line of a lab DiffViewer as added by the change; sighted readers see a + sign and a tinted row."
565
+ },
566
+ "@astryx.diffViewer.removed": {
567
+ "defaultMessage": "Removed",
568
+ "description": "Screen-reader text marking one line of a lab DiffViewer as removed by the change; sighted readers see a - sign and a tinted row."
569
+ },
570
+ "@astryx.diffViewer.lineNumberButton": {
571
+ "defaultMessage": "{side, select, old {Original line {line, number}} other {Changed line {line, number}}}",
572
+ "description": "Accessible label of a clickable line number in a lab DiffViewer (callers use it, for example, to start a comment on that line). `side` is `old` for the file before the change and `new` for the file after it; `line` is the line number in that version."
573
+ },
574
+ "@astryx.diffViewer.columnOldLine": {
575
+ "defaultMessage": "Original line number",
576
+ "description": "Screen-reader-only header of a lab DiffViewer column holding line numbers in the file before the change. Pairs with `@astryx.diffViewer.lineNumberButton` (\"Original line …\")."
577
+ },
578
+ "@astryx.diffViewer.columnNewLine": {
579
+ "defaultMessage": "Changed line number",
580
+ "description": "Screen-reader-only header of a lab DiffViewer column holding line numbers in the file after the change. Pairs with `@astryx.diffViewer.lineNumberButton` (\"Changed line …\")."
581
+ },
582
+ "@astryx.diffViewer.columnChange": {
583
+ "defaultMessage": "Change",
584
+ "description": "Screen-reader-only header of a lab DiffViewer column that marks each line as added or removed (noun: the kind of change)."
585
+ },
586
+ "@astryx.diffViewer.columnCode": {
587
+ "defaultMessage": "Code",
588
+ "description": "Screen-reader-only header of the source-code column in a lab DiffViewer's single-column (unified) view."
589
+ },
590
+ "@astryx.diffViewer.columnOldCode": {
591
+ "defaultMessage": "Original code",
592
+ "description": "Screen-reader-only header of the source-code column for the file before the change, in a lab DiffViewer's side-by-side (split) view."
593
+ },
594
+ "@astryx.diffViewer.columnNewCode": {
595
+ "defaultMessage": "Changed code",
596
+ "description": "Screen-reader-only header of the source-code column for the file after the change, in a lab DiffViewer's side-by-side (split) view."
597
+ },
598
+ "@astryx.diffViewer.binary": {
599
+ "defaultMessage": "Binary file not shown",
600
+ "description": "Message in place of line changes in a lab DiffViewer when the file is binary and has no text diff."
601
+ },
602
+ "@astryx.diffViewer.noChanges": {
603
+ "defaultMessage": "No content changes",
604
+ "description": "Message in a lab DiffViewer when a file changed only its path or mode, so there are no line changes to show."
605
+ },
530
606
  "@astryx.markdownHeadingLinks.copied": {
531
607
  "defaultMessage": "Link copied",
532
608
  "description": "Accessible name on the Markdown heading copy button and text announced to a polite live region for ~1.5s after a successful copy. Sentence meaning \"Link copied\"; pairs with `markdownHeadingLinks.copy`."
@@ -395,6 +395,63 @@
395
395
  "@astryx.listInput.announceAlreadyAtBoundary": {
396
396
  "defaultMessage": "⟦Ţĥíš {itemName} íš àłřéàðý {boundary, select, first {first} last {last} other {}}.⟧"
397
397
  },
398
+ "@astryx.diffViewer.label": {
399
+ "defaultMessage": "⟦Ð탃⟧"
400
+ },
401
+ "@astryx.diffViewer.renamedPath": {
402
+ "defaultMessage": "⟦{oldPath} → {newPath}⟧"
403
+ },
404
+ "@astryx.diffViewer.statusAdded": {
405
+ "defaultMessage": "⟦Àððéð⟧"
406
+ },
407
+ "@astryx.diffViewer.statusDeleted": {
408
+ "defaultMessage": "⟦Ðéłéţéð⟧"
409
+ },
410
+ "@astryx.diffViewer.statusRenamed": {
411
+ "defaultMessage": "⟦Řéñàɱéð⟧"
412
+ },
413
+ "@astryx.diffViewer.addedCount": {
414
+ "defaultMessage": "⟦+{count, number}⟧"
415
+ },
416
+ "@astryx.diffViewer.removedCount": {
417
+ "defaultMessage": "⟦−{count, number}⟧"
418
+ },
419
+ "@astryx.diffViewer.stats": {
420
+ "defaultMessage": "⟦{added, plural, one {# line added} other {# lines added}}, {removed, plural, one {# line removed} other {# lines removed}}⟧"
421
+ },
422
+ "@astryx.diffViewer.added": {
423
+ "defaultMessage": "⟦Àððéð⟧"
424
+ },
425
+ "@astryx.diffViewer.removed": {
426
+ "defaultMessage": "⟦Řéɱóṽéð⟧"
427
+ },
428
+ "@astryx.diffViewer.lineNumberButton": {
429
+ "defaultMessage": "⟦{side, select, old {Original line {line, number}} other {Changed line {line, number}}}⟧"
430
+ },
431
+ "@astryx.diffViewer.columnOldLine": {
432
+ "defaultMessage": "⟦Óříĝíñàł łíñé ñúɱƀéř⟧"
433
+ },
434
+ "@astryx.diffViewer.columnNewLine": {
435
+ "defaultMessage": "⟦Çĥàñĝéð łíñé ñúɱƀéř⟧"
436
+ },
437
+ "@astryx.diffViewer.columnChange": {
438
+ "defaultMessage": "⟦Çĥàñĝé⟧"
439
+ },
440
+ "@astryx.diffViewer.columnCode": {
441
+ "defaultMessage": "⟦Çóðé⟧"
442
+ },
443
+ "@astryx.diffViewer.columnOldCode": {
444
+ "defaultMessage": "⟦Óříĝíñàł çóðé⟧"
445
+ },
446
+ "@astryx.diffViewer.columnNewCode": {
447
+ "defaultMessage": "⟦Çĥàñĝéð çóðé⟧"
448
+ },
449
+ "@astryx.diffViewer.binary": {
450
+ "defaultMessage": "⟦Ɓíñàřý ƒíłé ñóţ šĥóŵñ⟧"
451
+ },
452
+ "@astryx.diffViewer.noChanges": {
453
+ "defaultMessage": "⟦Ñó çóñţéñţ çĥàñĝéš⟧"
454
+ },
398
455
  "@astryx.markdownHeadingLinks.copied": {
399
456
  "defaultMessage": "⟦Łíñķ çóþíéð⟧"
400
457
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/core",
3
- "version": "0.7.1",
3
+ "version": "0.7.2-canary.c68f5e8",
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",
@@ -787,6 +787,8 @@
787
787
  "react-dom": ">=19.0.0"
788
788
  },
789
789
  "devDependencies": {
790
+ "@astryxdesign/a11y-spec": "0.7.2-canary.c68f5e8",
791
+ "@astryxdesign/cli": "0.7.2-canary.c68f5e8",
790
792
  "@babel/cli": "^7.29.7",
791
793
  "@babel/core": "^7.29.7",
792
794
  "@babel/preset-react": "^7.29.7",
@@ -797,9 +799,7 @@
797
799
  "@testing-library/jest-dom": "^6.6.0",
798
800
  "@testing-library/react": "^16.3.2",
799
801
  "@types/babel__core": "^7.20.5",
800
- "tailwindcss": "^4.3.2",
801
- "@astryxdesign/a11y-spec": "0.0.0",
802
- "@astryxdesign/cli": "0.7.1"
802
+ "tailwindcss": "^4.3.2"
803
803
  },
804
804
  "dependencies": {
805
805
  "intl-messageformat": "^11.2.9"
@@ -138,7 +138,7 @@ export const docs = {
138
138
  {
139
139
  name: 'isLoading',
140
140
  type: 'boolean',
141
- description: 'Shows a loading spinner and disables interaction. Announces "Loading" via a live region.',
141
+ description: 'Shows a loading spinner and blocks re-activation while staying focusable (aria-busy + aria-disabled, not native disabled, so keyboard focus is never dropped mid-action). Announces "Loading" via a live region.',
142
142
  default: 'false',
143
143
  },
144
144
  {
@@ -419,7 +419,7 @@ export const docsDense = {
419
419
  displayName: 'HTML name for form submission',
420
420
  value: 'HTML value for form submission',
421
421
  form: 'associates button with form element by ID',
422
- isLoading: 'shows spinner+disables interaction; announces via live region',
422
+ isLoading: 'shows spinner, blocks re-activation but stays focusable (aria-disabled, not native disabled); announces via live region',
423
423
  icon: 'icon element rendered before label text; unsized Astryx Icon defaults to sm for sm/md buttons and md for lg',
424
424
  isIconOnly: 'when true, renders square icon-only button; label becomes aria-label',
425
425
  width: "Width of button. Numbers=pixels, strings=as-is (e.g. '100%' for full-width). Default: content width, capped at the container; label truncates w/ ellipsis in a narrow row; icon-only stays square.",