@astryxdesign/lab 0.7.7-canary.36f8ea1 → 0.7.7-canary.381c0d2

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 (32) hide show
  1. package/dist/InfoTip/index.d.ts +21 -3
  2. package/dist/InfoTip/index.d.ts.map +1 -1
  3. package/dist/InfoTip/index.js +22 -2
  4. package/dist/MobilePowerSearch/MobilePowerSearch.d.ts.map +1 -1
  5. package/dist/MobilePowerSearch/MobilePowerSearch.js +5 -4
  6. package/dist/MobileTokenizer/MobileTokenizer.d.ts +1 -1
  7. package/dist/MobileTokenizer/MobileTokenizer.d.ts.map +1 -1
  8. package/dist/MobileTokenizer/MobileTokenizer.js +10 -37
  9. package/dist/lab.css +0 -3
  10. package/package.json +5 -5
  11. package/src/InfoTip/InfoTip.test.tsx +24 -229
  12. package/src/InfoTip/index.ts +28 -3
  13. package/src/MobilePowerSearch/MobilePowerSearch.test.tsx +3 -0
  14. package/src/MobilePowerSearch/MobilePowerSearch.tsx +18 -7
  15. package/src/MobileTokenizer/MobileTokenizer.test.tsx +3 -0
  16. package/src/MobileTokenizer/MobileTokenizer.tsx +25 -51
  17. package/src/Schedule/__tests__/ScheduleEventPopover.a11y.chromium.spec.ts +59 -23
  18. package/dist/InfoTip/InfoTip.d.ts +0 -58
  19. package/dist/InfoTip/InfoTip.d.ts.map +0 -1
  20. package/dist/InfoTip/InfoTip.js +0 -94
  21. package/dist/internal/MobileSheetConfirmation.d.ts +0 -12
  22. package/dist/internal/MobileSheetConfirmation.d.ts.map +0 -1
  23. package/dist/internal/MobileSheetConfirmation.js +0 -88
  24. package/dist/internal/useDismissSearchOnTouchDrag.d.ts +0 -21
  25. package/dist/internal/useDismissSearchOnTouchDrag.d.ts.map +0 -1
  26. package/dist/internal/useDismissSearchOnTouchDrag.js +0 -43
  27. package/src/InfoTip/InfoTip.doc.mjs +0 -100
  28. package/src/InfoTip/InfoTip.tsx +0 -128
  29. package/src/internal/MobileSheetConfirmation.test.tsx +0 -68
  30. package/src/internal/MobileSheetConfirmation.tsx +0 -97
  31. package/src/internal/useDismissSearchOnTouchDrag.test.tsx +0 -94
  32. package/src/internal/useDismissSearchOnTouchDrag.ts +0 -57
@@ -1,6 +1,24 @@
1
1
  /**
2
- * @file InfoTip component barrel export
2
+ * @file InfoTip deprecated re-export
3
+ * @input `@astryxdesign/core/InfoTip`
4
+ * @output Exports InfoTip, InfoTipProps, InfoTipSize, each deprecated
5
+ * @position Lab entry kept for one release after InfoTip moved to Core;
6
+ * consumed by packages/lab/src/index.ts
3
7
  */
4
- export { InfoTip } from './InfoTip.js';
5
- export type { InfoTipProps, InfoTipSize } from './InfoTip.js';
8
+ import { InfoTip as CoreInfoTip, type InfoTipProps as CoreInfoTipProps, type InfoTipSize as CoreInfoTipSize } from '@astryxdesign/core/InfoTip';
9
+ /**
10
+ * @deprecated InfoTip moved to Core: import it from `@astryxdesign/core`.
11
+ * This Lab export is removed in the next release.
12
+ */
13
+ export declare const InfoTip: typeof CoreInfoTip;
14
+ /**
15
+ * @deprecated Import `InfoTipProps` from `@astryxdesign/core`. This Lab
16
+ * export is removed in the next release.
17
+ */
18
+ export type InfoTipProps = CoreInfoTipProps;
19
+ /**
20
+ * @deprecated Import `InfoTipSize` from `@astryxdesign/core`. This Lab export
21
+ * is removed in the next release.
22
+ */
23
+ export type InfoTipSize = CoreInfoTipSize;
6
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/InfoTip/index.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAClC,YAAY,EAAC,YAAY,EAAE,WAAW,EAAC,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/InfoTip/index.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,OAAO,EACL,OAAO,IAAI,WAAW,EACtB,KAAK,YAAY,IAAI,gBAAgB,EACrC,KAAK,WAAW,IAAI,eAAe,EACpC,MAAM,4BAA4B,CAAC;AAEpC;;;GAGG;AACH,eAAO,MAAM,OAAO,oBAAc,CAAC;AAEnC;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,gBAAgB,CAAC;AAE5C;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,eAAe,CAAC"}
@@ -3,6 +3,26 @@
3
3
  'use client';
4
4
 
5
5
  /**
6
- * @file InfoTip component barrel export
6
+ * @file InfoTip deprecated re-export
7
+ * @input `@astryxdesign/core/InfoTip`
8
+ * @output Exports InfoTip, InfoTipProps, InfoTipSize, each deprecated
9
+ * @position Lab entry kept for one release after InfoTip moved to Core;
10
+ * consumed by packages/lab/src/index.ts
7
11
  */
8
- export { InfoTip } from "./InfoTip.js";
12
+ import { InfoTip as CoreInfoTip } from '@astryxdesign/core/InfoTip';
13
+
14
+ /**
15
+ * @deprecated InfoTip moved to Core: import it from `@astryxdesign/core`.
16
+ * This Lab export is removed in the next release.
17
+ */
18
+ export const InfoTip = CoreInfoTip;
19
+
20
+ /**
21
+ * @deprecated Import `InfoTipProps` from `@astryxdesign/core`. This Lab
22
+ * export is removed in the next release.
23
+ */
24
+
25
+ /**
26
+ * @deprecated Import `InfoTipSize` from `@astryxdesign/core`. This Lab export
27
+ * is removed in the next release.
28
+ */
@@ -1 +1 @@
1
- {"version":3,"file":"MobilePowerSearch.d.ts","sourceRoot":"","sources":["../../src/MobilePowerSearch/MobilePowerSearch.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MobilePowerSearch.d.ts","sourceRoot":"","sources":["../../src/MobilePowerSearch/MobilePowerSearch.tsx"],"names":[],"mappings":"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"}
@@ -97,8 +97,7 @@ import { useLocale, useTranslator } from '@astryxdesign/core/i18n';
97
97
  import '@astryxdesign/core/theme/tokens.stylex';
98
98
  import { colorVars, fontWeightVars, radiusVars, sizeVars, spacingVars, typeScaleVars, typographyVars } from '@astryxdesign/core/theme/tokens.stylex';
99
99
  import { isImeKeyEvent, isRenderable, rtlStyles } from '@astryxdesign/core/utils';
100
- import { MobileSheetConfirmation } from "../internal/MobileSheetConfirmation.js";
101
- import { useDismissSearchOnTouchDrag } from "../internal/useDismissSearchOnTouchDrag.js";
100
+ import { SheetConfirmation, useDismissSearchOnTouchDrag } from '@astryxdesign/core/internal/touch-sheet';
102
101
  import { MobilePowerSearchValueEditor } from "./MobilePowerSearchValueEditor.js";
103
102
  import { createContentSearchSource, createFilterIdentities, fieldMatchesQuery, filterSignature, isSupportedOperator, nearestEditableIndex, resolveFilterIdentityIndex, useMobilePowerSearchConfig } from "./mobilePowerSearchUtils.js";
104
103
 
@@ -493,7 +492,9 @@ export function MobilePowerSearch({
493
492
 
494
493
  // ------------------------------------------------------------------ focus --
495
494
 
496
- const fieldPickerDragProps = useDismissSearchOnTouchDrag(() => [contentSearchRef.current?.querySelector('input'), fieldSearchRef.current?.querySelector('input')]);
495
+ // A drag moves focus to the sheet's panel, never to the page body behind
496
+ // the open modal.
497
+ const fieldPickerDragProps = useDismissSearchOnTouchDrag(() => [contentSearchRef.current?.querySelector('input'), fieldSearchRef.current?.querySelector('input')], () => (fieldSearchRef.current ?? contentSearchRef.current)?.closest('[tabindex="-1"]'));
497
498
  const focusPendingSheetTarget = useCallback(() => {
498
499
  const target = pendingSheetFocusRef.current;
499
500
  if (target == null) {
@@ -1721,7 +1722,7 @@ export function MobilePowerSearch({
1721
1722
  })]
1722
1723
  })]
1723
1724
  })
1724
- }), /*#__PURE__*/_jsx(MobileSheetConfirmation, {
1725
+ }), /*#__PURE__*/_jsx(SheetConfirmation, {
1725
1726
  isOpen: isClearConfirmationOpen,
1726
1727
  onOpenChange: setIsClearConfirmationOpen,
1727
1728
  title: "Clear all filters?",
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @file MobileTokenizer.tsx
3
3
  * @input Public @astryxdesign/core components and hooks, plus private Lab
4
- * mobile-sheet confirmation and search-drag dismissal owners
4
+ * touch-sheet confirmation and search-drag dismissal from Core's internal entry
5
5
  * @output Exports MobileTokenizer — Lab prototype of the touch Tokenizer
6
6
  * flow with the inline-compatible closed trigger, a searchable draft-selection
7
7
  * sheet, persistent Clear all / Save footer, dirty-dismiss confirmation,
@@ -1 +1 @@
1
- {"version":3,"file":"MobileTokenizer.d.ts","sourceRoot":"","sources":["../../src/MobileTokenizer/MobileTokenizer.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EASL,KAAK,SAAS,EAEf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAclD,OAAO,KAAK,EAAC,cAAc,EAAE,YAAY,EAAC,MAAM,8BAA8B,CAAC;AAY/E,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,cAAc,IACtD;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAC,GACtB;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,GACzB;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,GACzB;IAAC,IAAI,EAAE,SAAS,CAAA;CAAC,CAAC;AAEtB,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,cAAc,CAAE,SAAQ,IAAI,CAC1E,SAAS,CAAC,cAAc,CAAC,EACzB,UAAU,CACX;IACC,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAC9B,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IACjE;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,SAAS,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,MAAM,CAAC,EAAE;QAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC;IAClE;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAoMD,wBAAgB,eAAe,CAAC,CAAC,SAAS,cAAc,EAAE,EACxD,KAAK,EACL,aAAa,EACb,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,UAAU,EACV,WAAW,EACX,WAAW,EACX,MAAM,EACN,eAAe,EACf,QAAQ,EACR,UAAU,EACV,UAAkB,EAClB,SAAiB,EACjB,UAAU,EACV,YAAiB,EACjB,cAAkB,EAClB,UAAgB,EAChB,sBAAsB,EACtB,aAAa,EACb,MAAM,EACN,EAAE,EACF,SAAS,EACT,KAAK,EACL,YAAY,EAAE,aAAa,EAC3B,kBAAkB,EAAE,mBAAmB,EACvC,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,YAAY,EACpB,GAAG,IAAI,EACR,EAAE,oBAAoB,CAAC,CAAC,CAAC,qBAwPzB;yBAvRe,eAAe"}
1
+ {"version":3,"file":"MobileTokenizer.d.ts","sourceRoot":"","sources":["../../src/MobileTokenizer/MobileTokenizer.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EASL,KAAK,SAAS,EAEf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAclD,OAAO,KAAK,EAAC,cAAc,EAAE,YAAY,EAAC,MAAM,8BAA8B,CAAC;AAiB/E,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,cAAc,IACtD;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAC,GACtB;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,GACzB;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,GACzB;IAAC,IAAI,EAAE,SAAS,CAAA;CAAC,CAAC;AAEtB,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,cAAc,CAAE,SAAQ,IAAI,CAC1E,SAAS,CAAC,cAAc,CAAC,EACzB,UAAU,CACX;IACC,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAC9B,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IACjE;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,SAAS,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,MAAM,CAAC,EAAE;QAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC;IAClE;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAwLD,wBAAgB,eAAe,CAAC,CAAC,SAAS,cAAc,EAAE,EACxD,KAAK,EACL,aAAa,EACb,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,UAAU,EACV,WAAW,EACX,WAAW,EACX,MAAM,EACN,eAAe,EACf,QAAQ,EACR,UAAU,EACV,UAAkB,EAClB,SAAiB,EACjB,UAAU,EACV,YAAiB,EACjB,cAAkB,EAClB,UAAgB,EAChB,sBAAsB,EACtB,aAAa,EACb,MAAM,EACN,EAAE,EACF,SAAS,EACT,KAAK,EACL,YAAY,EAAE,aAAa,EAC3B,kBAAkB,EAAE,mBAAmB,EACvC,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,YAAY,EACpB,GAAG,IAAI,EACR,EAAE,oBAAoB,CAAC,CAAC,CAAC,qBAwPzB;yBAvRe,eAAe"}
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * @file MobileTokenizer.tsx
7
7
  * @input Public @astryxdesign/core components and hooks, plus private Lab
8
- * mobile-sheet confirmation and search-drag dismissal owners
8
+ * touch-sheet confirmation and search-drag dismissal from Core's internal entry
9
9
  * @output Exports MobileTokenizer — Lab prototype of the touch Tokenizer
10
10
  * flow with the inline-compatible closed trigger, a searchable draft-selection
11
11
  * sheet, persistent Clear all / Save footer, dirty-dismiss confirmation,
@@ -53,8 +53,7 @@ import { composeEventHandlers, mergeProps } from '@astryxdesign/core/utils';
53
53
  import { VisuallyHidden } from '@astryxdesign/core/VisuallyHidden';
54
54
  import '@astryxdesign/core/theme/tokens.stylex';
55
55
  import { colorVars, radiusVars, sizeVars, spacingVars } from '@astryxdesign/core/theme/tokens.stylex';
56
- import { MobileSheetConfirmation } from "../internal/MobileSheetConfirmation.js";
57
- import { useDismissSearchOnTouchDrag } from "../internal/useDismissSearchOnTouchDrag.js";
56
+ import { SheetConfirmation, hasSameSelection, nameSheetDraftChange, useDismissSearchOnTouchDrag } from '@astryxdesign/core/internal/touch-sheet';
58
57
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
59
58
  const CREATABLE_ID_PREFIX = '__xds_create__';
60
59
  const LIST_RENDER_BATCH_SIZE = 50;
@@ -64,9 +63,6 @@ const LIST_LOAD_MORE_THRESHOLD_PX = 200;
64
63
  // concentric with the field's (radius-2) when inset = radius-2 − radius-1 −
65
64
  // border = 3px. The same number is the row gap, so wrapped rows read evenly.
66
65
  const TOKEN_ROW_INSET = `calc(${spacingVars['--spacing-1']} - 1px)`;
67
- function hasSameSelection(a, b) {
68
- return a.length === b.length && a.every(item => b.some(candidate => candidate.id === item.id));
69
- }
70
66
  const styles = {
71
67
  trigger: {
72
68
  kzqmXN: "xh8yej3",
@@ -657,34 +653,9 @@ function MobileTokenizerSheetContent({
657
653
  if (isDraftOverMax) {
658
654
  return;
659
655
  }
660
- if (isDraftDirty) {
661
- const added = draftValue.find(item => !valueAtOpen.some(openItem => openItem.id === item.id));
662
- const removed = valueAtOpen.find(item => !draftValue.some(draftItem => draftItem.id === item.id));
663
- const lastDraftChange = lastDraftChangeRef.current;
664
- const lastChangeIsNet = lastDraftChange != null && (lastDraftChange.type === 'remove' ? valueAtOpen.some(item => item.id === lastDraftChange.item.id) && !draftValue.some(item => item.id === lastDraftChange.item.id) : draftValue.some(item => item.id === lastDraftChange.item.id) && !valueAtOpen.some(item => item.id === lastDraftChange.item.id));
665
- let change = null;
666
- if (lastChangeIsNet) {
667
- change = lastDraftChange;
668
- } else if (lastDraftChange?.type === 'remove' && removed != null) {
669
- change = {
670
- item: removed,
671
- type: 'remove'
672
- };
673
- } else if (added != null) {
674
- const type = lastDraftChange?.item.id === added.id && lastDraftChange.type === 'create' ? 'create' : 'add';
675
- change = {
676
- item: added,
677
- type
678
- };
679
- } else if (removed != null) {
680
- change = {
681
- item: removed,
682
- type: 'remove'
683
- };
684
- }
685
- if (change != null) {
686
- onCommit([...draftValue], change);
687
- }
656
+ const change = isDraftDirty ? nameSheetDraftChange(valueAtOpen, draftValue, lastDraftChangeRef.current) : null;
657
+ if (change != null) {
658
+ onCommit([...draftValue], change);
688
659
  }
689
660
  onCloseSheet();
690
661
  };
@@ -692,7 +663,9 @@ function MobileTokenizerSheetContent({
692
663
  label
693
664
  });
694
665
  const noResultsTitle = emptySearchResultsText ?? t('@astryx.typeahead.emptySearchResults');
695
- const listDragProps = useDismissSearchOnTouchDrag(() => [searchRef.current]);
666
+ // A drag moves focus to the sheet's panel, never to the page body behind
667
+ // the open modal.
668
+ const listDragProps = useDismissSearchOnTouchDrag(() => [searchRef.current], () => searchRef.current?.closest('[tabindex="-1"]'));
696
669
  return /*#__PURE__*/_jsxs("div", {
697
670
  ...{
698
671
  className: "x78zum5 xdt5ytf x5yr21d x2lwn1j xrrkdod xoxd1wu xvmdzux"
@@ -881,7 +854,7 @@ function MobileTokenizerSheetContent({
881
854
  onClick: handleSave,
882
855
  xstyle: styles.footerAction
883
856
  })]
884
- }), isClearConfirmationOpen && /*#__PURE__*/_jsx(MobileSheetConfirmation, {
857
+ }), isClearConfirmationOpen && /*#__PURE__*/_jsx(SheetConfirmation, {
885
858
  isOpen: true,
886
859
  onOpenChange: next => {
887
860
  if (!next) {
@@ -905,7 +878,7 @@ function MobileTokenizerSheetContent({
905
878
  }
906
879
  closeClearConfirmation(true);
907
880
  }
908
- }), isDiscardConfirmationOpen && /*#__PURE__*/_jsx(MobileSheetConfirmation, {
881
+ }), isDiscardConfirmationOpen && /*#__PURE__*/_jsx(SheetConfirmation, {
909
882
  isOpen: true,
910
883
  onOpenChange: next => {
911
884
  if (!next) {
package/dist/lab.css CHANGED
@@ -71,7 +71,6 @@
71
71
  .x1fx55se:not(#\#){padding:calc((var(--size-element-lg) - 28px) / 2 - var(--border-width))}
72
72
  .xnvfkzk:not(#\#){padding:calc((var(--size-element-md) - 24px) / 2 - var(--border-width))}
73
73
  .x5pt662:not(#\#){padding:calc((var(--size-element-sm) - 22px) / 2 - var(--border-width))}
74
- .x12nba7r:not(#\#){padding:var(--spacing-0-5)}
75
74
  .x1b2ylru:not(#\#){padding:var(--spacing-3)}
76
75
  .x1shk3sm:not(#\#){padding:var(--spacing-4)}
77
76
  .x70o2i5:not(#\#):not(#\#){border-color:#26262a}
@@ -563,7 +562,6 @@
563
562
  .x80gvsz:not(#\#):not(#\#):not(#\#){transition-duration:var(--duration-medium)}
564
563
  .x15406qy:not(#\#):not(#\#):not(#\#){transition-property:background-color}
565
564
  .xq90yva:not(#\#):not(#\#):not(#\#){transition-property:border-color,background-color}
566
- .xt3l3uh:not(#\#):not(#\#):not(#\#){transition-property:color}
567
565
  .x13b0p5u:not(#\#):not(#\#):not(#\#){transition-property:none}
568
566
  .x19991ni:not(#\#):not(#\#):not(#\#){transition-property:opacity}
569
567
  .x1gfj591:not(#\#):not(#\#):not(#\#){transition-property:top,left,width,height}
@@ -635,7 +633,6 @@
635
633
  @media (hover: hover){.x1fkayqs.x1fkayqs.x1fkayqs:hover:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#):not(#\#){background-color:#1d1d21}}
636
634
  @media (hover: hover){.xkqrm7g.xkqrm7g.xkqrm7g:hover:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#):not(#\#){background-color:var(--color-background-muted)}}
637
635
  @media (hover: hover){.xoevpu5.xoevpu5.xoevpu5:hover:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#):not(#\#){background-color:var(--color-overlay-hover)}}
638
- @media (hover: hover){.x10ue8fs.x10ue8fs.x10ue8fs:hover:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#):not(#\#){color:var(--color-icon-primary)}}
639
636
  @container (max-width: 40rem){.x101j7pr.x101j7pr:not(#\#):not(#\#):not(#\#){background-color:var(--color-background-body)}}
640
637
  @container (max-width: 40rem){.x12eanku.x12eanku:not(#\#):not(#\#):not(#\#){border-inline-start-width:0}}
641
638
  @container list-input (max-width: 640px){.x1jiamoa.x1jiamoa:not(#\#):not(#\#):not(#\#){display:block}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/lab",
3
- "version": "0.7.7-canary.36f8ea1",
3
+ "version": "0.7.7-canary.381c0d2",
4
4
  "description": "Experimental Astryx components — published to npm only under the @canary dist-tag for early testing; never released as a stable (latest) version.",
5
5
  "author": "Meta Open Source",
6
6
  "license": "MIT",
@@ -49,7 +49,7 @@
49
49
  },
50
50
  "peerDependencies": {
51
51
  "@stylexjs/stylex": ">=0.10.0",
52
- "@astryxdesign/core": "0.7.7-canary.36f8ea1",
52
+ "@astryxdesign/core": "0.7.7-canary.381c0d2",
53
53
  "react": ">=19.0.0",
54
54
  "react-dom": ">=19.0.0"
55
55
  },
@@ -59,9 +59,9 @@
59
59
  "d3-shape": "^3.2.0"
60
60
  },
61
61
  "devDependencies": {
62
- "@astryxdesign/a11y-spec": "0.7.7-canary.36f8ea1",
63
- "@astryxdesign/cli": "0.7.7-canary.36f8ea1",
64
- "@astryxdesign/interaction-harness": "0.7.7-canary.36f8ea1",
62
+ "@astryxdesign/a11y-spec": "0.7.7-canary.381c0d2",
63
+ "@astryxdesign/cli": "0.7.7-canary.381c0d2",
64
+ "@astryxdesign/interaction-harness": "0.7.7-canary.381c0d2",
65
65
  "@babel/cli": "^7.29.7",
66
66
  "@babel/core": "^7.29.7",
67
67
  "@babel/preset-react": "^7.29.7",
@@ -2,237 +2,32 @@
2
2
 
3
3
  /**
4
4
  * @file InfoTip.test.tsx
5
- * @input Uses vitest, @testing-library/react, @testing-library/user-event, InfoTip component
6
- * @output Unit tests for InfoTip trigger accessibility and tooltip behavior
7
- * @position Testing; validates InfoTip.tsx implementation
8
- *
9
- * SYNC: When InfoTip.tsx changes, update tests to match new behavior
5
+ * @input The Lab InfoTip entry and the Core component
6
+ * @output Tests that the Lab entry re-exports the Core component, deprecated
7
+ * @position Testing; validates index.ts (component:InfoTip FR4)
10
8
  */
11
9
 
12
- import {describe, it, expect, vi, beforeAll, afterAll} from 'vitest';
13
- import {render, screen, fireEvent, waitFor, act} from '@testing-library/react';
14
- import userEvent from '@testing-library/user-event';
15
- import {InfoTip} from './InfoTip';
16
-
17
- // Store original matches to restore later
18
- const originalMatches = HTMLElement.prototype.matches;
19
-
20
- // Track popover open state per element
21
- const popoverOpenState = new WeakMap<HTMLElement, boolean>();
22
-
23
- // Mock Popover API for jsdom, and :focus-visible for keyboard-focus tests
24
- // (same harness as core Tooltip.test.tsx, plus :focus-visible)
25
- beforeAll(() => {
26
- HTMLElement.prototype.showPopover = vi.fn(function (this: HTMLElement) {
27
- popoverOpenState.set(this, true);
28
- });
29
- HTMLElement.prototype.hidePopover = vi.fn(function (this: HTMLElement) {
30
- popoverOpenState.set(this, false);
31
- });
32
-
33
- // Intercept :popover-open and :focus-visible, delegate everything else
34
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
- (HTMLElement.prototype as any).matches = function (
36
- selector: string,
37
- ): boolean {
38
- if (selector === ':popover-open') {
39
- return popoverOpenState.get(this) ?? false;
40
- }
41
- if (selector === ':focus-visible') {
42
- // Treat any focused element as keyboard-focused in tests
43
- return this === document.activeElement;
10
+ import {readFileSync} from 'node:fs';
11
+ import path from 'node:path';
12
+ import {describe, expect, it} from 'vitest';
13
+ import {InfoTip as CoreInfoTip} from '@astryxdesign/core/InfoTip';
14
+ import {InfoTip} from './index';
15
+
16
+ describe('Lab InfoTip', () => {
17
+ it('is the Core component', () => {
18
+ expect(InfoTip).toBe(CoreInfoTip);
19
+ });
20
+
21
+ it('marks each of its exports deprecated', () => {
22
+ // Static metadata only: editors and type checkers show it, and nothing
23
+ // warns at runtime.
24
+ const source = readFileSync(path.join(__dirname, 'index.ts'), 'utf8');
25
+ for (const name of ['InfoTip', 'InfoTipProps', 'InfoTipSize']) {
26
+ // The doc comment right above the export, whatever it contains.
27
+ const comment = new RegExp(
28
+ String.raw`/\*\*((?:(?!\*/)[\s\S])*)\*/\nexport (?:const|type) ${name}\b`,
29
+ ).exec(source);
30
+ expect(comment?.[1], name).toContain('@deprecated');
44
31
  }
45
- return originalMatches.call(this, selector);
46
- };
47
- });
48
-
49
- afterAll(() => {
50
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
51
- (HTMLElement.prototype as any).matches = originalMatches;
52
- });
53
-
54
- /** Focus the trigger the way a keyboard user would land on it. */
55
- function focusTrigger(trigger: HTMLElement) {
56
- act(() => {
57
- trigger.focus();
58
- });
59
- fireEvent.focusIn(trigger);
60
- }
61
-
62
- describe('InfoTip', () => {
63
- it('renders a button trigger with the default accessible name', () => {
64
- render(<InfoTip content="Helpful context" />);
65
- expect(
66
- screen.getByRole('button', {name: 'More information'}),
67
- ).toBeInTheDocument();
68
- });
69
-
70
- it('uses a custom label as the accessible name', () => {
71
- render(
72
- <InfoTip content="30-day rolling average." label="About this metric" />,
73
- );
74
- const trigger = screen.getByRole('button', {name: 'About this metric'});
75
- expect(trigger).toHaveAttribute('aria-label', 'About this metric');
76
- });
77
-
78
- it('links the trigger to the tooltip layer via aria-describedby', () => {
79
- render(<InfoTip content="Helpful context" />);
80
- const layer = screen.getByRole('tooltip', {hidden: true});
81
- expect(layer).toHaveTextContent('Helpful context');
82
- const trigger = screen.getByRole('button', {name: 'More information'});
83
- expect(trigger.getAttribute('aria-describedby')).toBe(layer.id);
84
- });
85
-
86
- it('is reachable with Tab', async () => {
87
- const user = userEvent.setup();
88
- render(<InfoTip content="Helpful context" />);
89
- const trigger = screen.getByRole('button', {name: 'More information'});
90
- await user.tab();
91
- expect(trigger).toHaveFocus();
92
- });
93
-
94
- it('shows the tooltip on hover', async () => {
95
- vi.mocked(HTMLElement.prototype.showPopover).mockClear();
96
- render(<InfoTip content="Helpful context" />);
97
- const trigger = screen.getByRole('button', {name: 'More information'});
98
-
99
- fireEvent.mouseEnter(trigger);
100
-
101
- await waitFor(() => {
102
- expect(HTMLElement.prototype.showPopover).toHaveBeenCalled();
103
- });
104
- });
105
-
106
- it('shows the tooltip on keyboard focus', async () => {
107
- vi.mocked(HTMLElement.prototype.showPopover).mockClear();
108
- render(<InfoTip content="Helpful context" />);
109
- const trigger = screen.getByRole('button', {name: 'More information'});
110
-
111
- focusTrigger(trigger);
112
-
113
- await waitFor(() => {
114
- expect(HTMLElement.prototype.showPopover).toHaveBeenCalled();
115
- });
116
- const layer = screen.getByRole('tooltip', {hidden: true});
117
- expect(popoverOpenState.get(layer)).toBe(true);
118
- });
119
-
120
- it('closes the tooltip on Escape', async () => {
121
- render(<InfoTip content="Helpful context" />);
122
- const trigger = screen.getByRole('button', {name: 'More information'});
123
- const layer = screen.getByRole('tooltip', {hidden: true});
124
-
125
- focusTrigger(trigger);
126
- await waitFor(() => {
127
- expect(popoverOpenState.get(layer)).toBe(true);
128
- });
129
-
130
- fireEvent.keyDown(trigger, {key: 'Escape'});
131
-
132
- await waitFor(() => {
133
- expect(popoverOpenState.get(layer)).toBe(false);
134
- });
135
- });
136
-
137
- it('re-opens after Escape once the trigger is left and re-hovered', async () => {
138
- render(<InfoTip content="Helpful context" />);
139
- const trigger = screen.getByRole('button', {name: 'More information'});
140
- const layer = screen.getByRole('tooltip', {hidden: true});
141
-
142
- focusTrigger(trigger);
143
- await waitFor(() => {
144
- expect(popoverOpenState.get(layer)).toBe(true);
145
- });
146
-
147
- fireEvent.keyDown(trigger, {key: 'Escape'});
148
- await waitFor(() => {
149
- expect(popoverOpenState.get(layer)).toBe(false);
150
- });
151
-
152
- // Leave (resets dismissal), then re-enter
153
- act(() => {
154
- trigger.blur();
155
- });
156
- fireEvent.focusOut(trigger);
157
- fireEvent.mouseLeave(trigger);
158
-
159
- fireEvent.mouseEnter(trigger);
160
- await waitFor(() => {
161
- expect(popoverOpenState.get(layer)).toBe(true);
162
- });
163
- });
164
-
165
- it('renders ReactNode tooltip content', () => {
166
- render(<InfoTip content={<span data-testid="rich-content">Rich</span>} />);
167
- expect(screen.getByTestId('rich-content')).toBeInTheDocument();
168
- });
169
- describe('touch', () => {
170
- /**
171
- * A tap, in the order a browser dispatches it: the finger's pointer events,
172
- * the hover it synthesizes, then the `click` that says the touch was a tap.
173
- */
174
- const tap = (element: HTMLElement) => {
175
- fireEvent.pointerEnter(element, {pointerType: 'touch'});
176
- fireEvent.pointerDown(element, {pointerType: 'touch'});
177
- fireEvent.pointerUp(element, {pointerType: 'touch'});
178
- fireEvent.mouseEnter(element);
179
- fireEvent.click(element);
180
- };
181
-
182
- it('opens on a tap, though the trigger is a button', async () => {
183
- render(<InfoTip content="30-day rolling average." />);
184
- const trigger = screen.getByRole('button');
185
- const layer = screen.getByRole('tooltip', {hidden: true});
186
-
187
- // Tooltip's `auto` rule would give this tap to the button and suppress
188
- // the tooltip; revealing it is the button's whole purpose, so InfoTip
189
- // opts in. Without this its content is unreachable on a phone.
190
- tap(trigger);
191
-
192
- await waitFor(() => {
193
- expect(popoverOpenState.get(layer)).toBe(true);
194
- });
195
- });
196
-
197
- it('closes on a second tap of the trigger', async () => {
198
- render(<InfoTip content="30-day rolling average." />);
199
- const trigger = screen.getByRole('button');
200
- const layer = screen.getByRole('tooltip', {hidden: true});
201
-
202
- tap(trigger);
203
- await waitFor(() => {
204
- expect(popoverOpenState.get(layer)).toBe(true);
205
- });
206
-
207
- tap(trigger);
208
- await waitFor(() => {
209
- expect(popoverOpenState.get(layer)).toBe(false);
210
- });
211
- });
212
-
213
- it('closes on a tap outside', async () => {
214
- render(
215
- <>
216
- <InfoTip content="30-day rolling average." />
217
- <button type="button">Elsewhere</button>
218
- </>,
219
- );
220
- const trigger = screen.getByRole('button', {name: 'More information'});
221
- const layer = screen.getByRole('tooltip', {hidden: true});
222
-
223
- tap(trigger);
224
- await waitFor(() => {
225
- expect(popoverOpenState.get(layer)).toBe(true);
226
- });
227
-
228
- // The tap outside counts when the finger lifts.
229
- const elsewhere = screen.getByRole('button', {name: 'Elsewhere'});
230
- fireEvent.pointerDown(elsewhere, {pointerType: 'touch'});
231
- fireEvent.pointerUp(elsewhere, {pointerType: 'touch'});
232
-
233
- await waitFor(() => {
234
- expect(popoverOpenState.get(layer)).toBe(false);
235
- });
236
- });
237
32
  });
238
33
  });
@@ -3,8 +3,33 @@
3
3
  'use client';
4
4
 
5
5
  /**
6
- * @file InfoTip component barrel export
6
+ * @file InfoTip deprecated re-export
7
+ * @input `@astryxdesign/core/InfoTip`
8
+ * @output Exports InfoTip, InfoTipProps, InfoTipSize, each deprecated
9
+ * @position Lab entry kept for one release after InfoTip moved to Core;
10
+ * consumed by packages/lab/src/index.ts
7
11
  */
8
12
 
9
- export {InfoTip} from './InfoTip';
10
- export type {InfoTipProps, InfoTipSize} from './InfoTip';
13
+ import {
14
+ InfoTip as CoreInfoTip,
15
+ type InfoTipProps as CoreInfoTipProps,
16
+ type InfoTipSize as CoreInfoTipSize,
17
+ } from '@astryxdesign/core/InfoTip';
18
+
19
+ /**
20
+ * @deprecated InfoTip moved to Core: import it from `@astryxdesign/core`.
21
+ * This Lab export is removed in the next release.
22
+ */
23
+ export const InfoTip = CoreInfoTip;
24
+
25
+ /**
26
+ * @deprecated Import `InfoTipProps` from `@astryxdesign/core`. This Lab
27
+ * export is removed in the next release.
28
+ */
29
+ export type InfoTipProps = CoreInfoTipProps;
30
+
31
+ /**
32
+ * @deprecated Import `InfoTipSize` from `@astryxdesign/core`. This Lab export
33
+ * is removed in the next release.
34
+ */
35
+ export type InfoTipSize = CoreInfoTipSize;
@@ -822,6 +822,9 @@ describe('MobilePowerSearch Filters sheet', () => {
822
822
  const confirmation = screen.getByRole('alertdialog', {
823
823
  name: 'Clear all filters?',
824
824
  });
825
+ // A scrim press starts and ends on the dialog itself.
826
+ fireEvent.pointerDown(confirmation);
827
+ fireEvent.pointerUp(confirmation);
825
828
  fireEvent.click(confirmation);
826
829
  expect(
827
830
  screen.queryByRole('alertdialog', {name: 'Clear all filters?'}),
@@ -142,8 +142,11 @@ import {
142
142
  typographyVars,
143
143
  } from '@astryxdesign/core/theme/tokens.stylex';
144
144
  import {isImeKeyEvent, isRenderable, rtlStyles} from '@astryxdesign/core/utils';
145
- import {MobileSheetConfirmation} from '../internal/MobileSheetConfirmation';
146
- import {useDismissSearchOnTouchDrag} from '../internal/useDismissSearchOnTouchDrag';
145
+
146
+ import {
147
+ SheetConfirmation,
148
+ useDismissSearchOnTouchDrag,
149
+ } from '@astryxdesign/core/internal/touch-sheet';
147
150
  import {MobilePowerSearchValueEditor} from './MobilePowerSearchValueEditor';
148
151
  import {
149
152
  createContentSearchSource,
@@ -889,10 +892,18 @@ export function MobilePowerSearch({
889
892
 
890
893
  // ------------------------------------------------------------------ focus --
891
894
 
892
- const fieldPickerDragProps = useDismissSearchOnTouchDrag(() => [
893
- contentSearchRef.current?.querySelector('input'),
894
- fieldSearchRef.current?.querySelector('input'),
895
- ]);
895
+ // A drag moves focus to the sheet's panel, never to the page body behind
896
+ // the open modal.
897
+ const fieldPickerDragProps = useDismissSearchOnTouchDrag(
898
+ () => [
899
+ contentSearchRef.current?.querySelector('input'),
900
+ fieldSearchRef.current?.querySelector('input'),
901
+ ],
902
+ () =>
903
+ (
904
+ fieldSearchRef.current ?? contentSearchRef.current
905
+ )?.closest<HTMLElement>('[tabindex="-1"]'),
906
+ );
896
907
 
897
908
  const focusPendingSheetTarget = useCallback(() => {
898
909
  const target = pendingSheetFocusRef.current;
@@ -2356,7 +2367,7 @@ export function MobilePowerSearch({
2356
2367
  </div>
2357
2368
  </BottomSheet>
2358
2369
 
2359
- <MobileSheetConfirmation
2370
+ <SheetConfirmation
2360
2371
  isOpen={isClearConfirmationOpen}
2361
2372
  onOpenChange={setIsClearConfirmationOpen}
2362
2373
  title="Clear all filters?"
@@ -185,6 +185,9 @@ describe('MobileTokenizer (Lab, single-sheet flow)', () => {
185
185
  let discard = await screen.findByRole('alertdialog', {
186
186
  name: 'Discard changes?',
187
187
  });
188
+ // A scrim press starts and ends on the dialog itself.
189
+ fireEvent.pointerDown(discard);
190
+ fireEvent.pointerUp(discard);
188
191
  fireEvent.click(discard);
189
192
  await waitFor(() =>
190
193
  expect(screen.queryByRole('alertdialog')).not.toBeInTheDocument(),