@astryxdesign/core 0.1.4-canary.37c19d3 → 0.1.4-canary.39ffd21
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.
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +1 -8
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +11 -31
- package/dist/Calendar/styles.d.ts +2 -2
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +2 -2
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +0 -1
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +1 -8
- package/dist/CheckboxInput/CheckboxInput.d.ts +1 -1
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +1 -3
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +3 -26
- package/dist/CodeBlock/CodeBlock.d.ts +1 -10
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +5 -23
- package/dist/Collapsible/Collapsible.d.ts +3 -9
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +13 -101
- package/dist/Collapsible/CollapsibleGroup.d.ts +7 -39
- package/dist/Collapsible/CollapsibleGroup.d.ts.map +1 -1
- package/dist/Collapsible/CollapsibleGroup.js +9 -70
- package/dist/Collapsible/CollapsibleGroupContext.d.ts +0 -31
- package/dist/Collapsible/CollapsibleGroupContext.d.ts.map +1 -1
- package/dist/Collapsible/CollapsibleGroupContext.js +3 -33
- package/dist/Collapsible/index.d.ts +0 -1
- package/dist/Collapsible/index.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +0 -2
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +0 -2
- package/dist/Grid/Grid.d.ts +3 -4
- package/dist/Grid/Grid.d.ts.map +1 -1
- package/dist/Grid/Grid.js +9 -26
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +1 -5
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +2 -26
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +16 -32
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +36 -87
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +21 -39
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +1 -2
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +2 -10
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +2 -6
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +7 -34
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +2 -12
- package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
- package/dist/Table/plugins/columnResize/useTableColumnResize.js +2 -5
- package/dist/Table/plugins/pagination/paginateData.d.ts.map +1 -1
- package/dist/Table/plugins/pagination/paginateData.js +1 -5
- package/dist/Table/plugins/selection/useTableSelectionState.d.ts.map +1 -1
- package/dist/Table/plugins/selection/useTableSelectionState.js +1 -11
- package/dist/Table/plugins/sortable/useTableSortableState.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortableState.js +4 -8
- package/dist/Thumbnail/Thumbnail.d.ts +2 -3
- package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
- package/dist/Thumbnail/Thumbnail.js +0 -1
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +1 -6
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +3 -11
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +0 -12
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +2 -5
- package/dist/astryx.css +0 -7
- package/dist/astryx.umd.js +48 -48
- package/dist/astryx.umd.js.map +4 -4
- package/dist/hooks/focusableSelector.d.ts +1 -1
- package/dist/hooks/focusableSelector.d.ts.map +1 -1
- package/dist/hooks/focusableSelector.js +1 -1
- package/dist/hooks/useFocusTrap.d.ts +0 -3
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +1 -38
- package/dist/theme/defineTheme.d.ts +1 -1
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/expandColorScale.d.ts.map +1 -1
- package/dist/theme/expandColorScale.js +3 -10
- package/dist/theme/hct.d.ts +15 -0
- package/dist/theme/hct.d.ts.map +1 -1
- package/dist/theme/hct.js +9 -9
- package/dist/theme/tokens.d.ts +2 -10
- package/dist/theme/tokens.d.ts.map +1 -1
- package/dist/theme/tokens.js +4 -220
- package/dist/utils/index.d.ts +0 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -2
- package/dist/utils/timeParser.d.ts.map +1 -1
- package/dist/utils/timeParser.js +5 -8
- package/package.json +1 -1
- package/src/Avatar/Avatar.doc.mjs +0 -11
- package/src/Banner/Banner.doc.mjs +0 -8
- package/src/Banner/Banner.test.tsx +0 -38
- package/src/Banner/Banner.tsx +1 -8
- package/src/Calendar/Calendar.doc.mjs +1 -1
- package/src/Calendar/Calendar.test.tsx +4 -112
- package/src/Calendar/Calendar.tsx +5 -26
- package/src/Calendar/styles.ts +2 -12
- package/src/Carousel/Carousel.doc.mjs +12 -12
- package/src/Carousel/Carousel.test.tsx +0 -13
- package/src/Carousel/Carousel.tsx +0 -1
- package/src/Chat/Chat.doc.mjs +1 -1
- package/src/Chat/ChatToolCalls.test.tsx +0 -55
- package/src/Chat/ChatToolCalls.tsx +12 -10
- package/src/CheckboxInput/CheckboxInput.doc.mjs +3 -3
- package/src/CheckboxInput/CheckboxInput.test.tsx +4 -71
- package/src/CheckboxInput/CheckboxInput.tsx +0 -2
- package/src/Citation/Citation.doc.mjs +0 -5
- package/src/ClickableCard/ClickableCard.tsx +2 -45
- package/src/CodeBlock/CodeBlock.doc.mjs +2 -7
- package/src/CodeBlock/CodeBlock.test.tsx +3 -87
- package/src/CodeBlock/CodeBlock.tsx +3 -43
- package/src/Collapsible/Collapsible.doc.mjs +4 -8
- package/src/Collapsible/Collapsible.tsx +10 -86
- package/src/Collapsible/CollapsibleGroup.doc.mjs +3 -27
- package/src/Collapsible/CollapsibleGroup.test.tsx +0 -288
- package/src/Collapsible/CollapsibleGroup.tsx +9 -107
- package/src/Collapsible/CollapsibleGroupContext.tsx +2 -42
- package/src/Collapsible/index.ts +0 -4
- package/src/CommandPalette/CommandPaletteEmpty.doc.mjs +0 -5
- package/src/CommandPalette/CommandPaletteGroup.doc.mjs +0 -10
- package/src/CommandPalette/CommandPaletteInput.doc.mjs +0 -6
- package/src/CommandPalette/CommandPaletteItem.doc.mjs +0 -6
- package/src/CommandPalette/CommandPaletteList.doc.mjs +0 -9
- package/src/ContextMenu/ContextMenu.doc.mjs +0 -15
- package/src/ContextMenu/ContextMenu.test.tsx +0 -15
- package/src/ContextMenu/ContextMenu.tsx +0 -2
- package/src/ContextMenu/ContextMenuItem.doc.mjs +0 -6
- package/src/DateTimeInput/DateTimeInput.test.tsx +0 -70
- package/src/DateTimeInput/DateTimeInput.tsx +0 -2
- package/src/Dialog/DialogHeader.doc.mjs +0 -45
- package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -1
- package/src/Field/FieldLabel.test.tsx +2 -2
- package/src/FormLayout/__snapshots__/FormLayout.test.tsx.snap +3 -0
- package/src/Grid/Grid.test.tsx +18 -43
- package/src/Grid/Grid.tsx +9 -26
- package/src/Icon/Icon.test.tsx +29 -41
- package/src/Icon/Icon.tsx +2 -6
- package/src/Layout/LayoutContent.doc.mjs +0 -12
- package/src/Layout/LayoutPanel.doc.mjs +0 -40
- package/src/Lightbox/Lightbox.doc.mjs +0 -5
- package/src/Lightbox/Lightbox.test.tsx +2 -123
- package/src/Lightbox/Lightbox.tsx +1 -29
- package/src/NavMenu/NavMenu.doc.mjs +0 -15
- package/src/NumberInput/NumberInput.test.tsx +3 -48
- package/src/NumberInput/NumberInput.tsx +15 -32
- package/src/Overlay/Overlay.doc.mjs +0 -6
- package/src/Pagination/Pagination.test.tsx +0 -143
- package/src/Pagination/Pagination.tsx +23 -75
- package/src/Popover/Popover.test.tsx +0 -65
- package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
- package/src/PowerSearch/PowerSearch.test.tsx +1 -109
- package/src/PowerSearch/PowerSearch.tsx +16 -37
- package/src/ProgressBar/ProgressBar.test.tsx +0 -10
- package/src/ProgressBar/ProgressBar.tsx +1 -2
- package/src/Resizable/ResizeHandle.tsx +2 -10
- package/src/SegmentedControl/SegmentedControl.doc.mjs +1 -1
- package/src/SelectableCard/SelectableCard.doc.mjs +1 -1
- package/src/SideNav/SideNav.doc.mjs +1 -7
- package/src/SideNav/SideNav.test.tsx +0 -20
- package/src/SideNav/SideNav.tsx +2 -6
- package/src/TabList/TabList.test.tsx +1 -185
- package/src/TabList/TabMenu.tsx +9 -45
- package/src/Table/BaseTable.tsx +1 -11
- package/src/Table/Table.test.tsx +0 -51
- package/src/Table/plugins/columnResize/useTableColumnResize.test.tsx +0 -13
- package/src/Table/plugins/columnResize/useTableColumnResize.tsx +1 -3
- package/src/Table/plugins/pagination/paginateData.ts +1 -5
- package/src/Table/plugins/pagination/useTablePagination.test.tsx +0 -13
- package/src/Table/plugins/selection/useTableSelectionState.test.tsx +0 -23
- package/src/Table/plugins/selection/useTableSelectionState.tsx +6 -11
- package/src/Table/plugins/sortable/useTableSortableState.test.tsx +1 -35
- package/src/Table/plugins/sortable/useTableSortableState.tsx +4 -8
- package/src/TextArea/TextArea.test.tsx +3 -3
- package/src/TextInput/TextInput.test.tsx +3 -3
- package/src/Thumbnail/Thumbnail.test.tsx +2 -36
- package/src/Thumbnail/Thumbnail.tsx +2 -4
- package/src/TimeInput/TimeInput.test.tsx +0 -37
- package/src/TimeInput/TimeInput.tsx +1 -11
- package/src/Timestamp/Timestamp.doc.mjs +1 -1
- package/src/Toast/Toast.tsx +3 -11
- package/src/Toast/ToastViewport.test.tsx +0 -64
- package/src/Toast/ToastViewport.tsx +0 -12
- package/src/ToggleButton/ToggleButton.doc.mjs +0 -1
- package/src/Tokenizer/Tokenizer.doc.mjs +2 -2
- package/src/TopNav/TopNav.doc.mjs +1 -1
- package/src/TreeList/TreeList.doc.mjs +2 -2
- package/src/Typeahead/BaseTypeahead.doc.mjs +0 -19
- package/src/Typeahead/BaseTypeahead.tsx +2 -5
- package/src/Typeahead/Typeahead.doc.mjs +1 -1
- package/src/Typeahead/Typeahead.test.tsx +1 -45
- package/src/hooks/focusableSelector.ts +1 -1
- package/src/hooks/useFocusTrap.doc.mjs +2 -4
- package/src/hooks/useFocusTrap.test.tsx +1 -149
- package/src/hooks/useFocusTrap.ts +1 -50
- package/src/theme/SyntaxTheme.doc.mjs +4 -4
- package/src/theme/defineTheme.ts +13 -4
- package/src/theme/derivedVarRegistry.test.ts +2 -2
- package/src/theme/expandColorScale.test.ts +0 -29
- package/src/theme/expandColorScale.ts +6 -11
- package/src/theme/hct.ts +17 -9
- package/src/theme/tokens.test.ts +9 -182
- package/src/theme/tokens.ts +4 -239
- package/src/theme/useTheme.test.tsx +0 -20
- package/src/utils/index.ts +0 -3
- package/src/utils/timeParser.test.ts +0 -13
- package/src/utils/timeParser.ts +5 -8
- package/dist/utils/color.d.ts +0 -42
- package/dist/utils/color.d.ts.map +0 -1
- package/dist/utils/color.js +0 -150
- package/src/Resizable/ResizeHandle.test.tsx +0 -180
- package/src/__tests__/TestIcon.tsx +0 -26
- package/src/docPropReferences.test.ts +0 -178
- package/src/utils/color.test.ts +0 -133
- package/src/utils/color.ts +0 -148
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
import {
|
|
20
20
|
useCallback,
|
|
21
21
|
useEffect,
|
|
22
|
-
useMemo,
|
|
23
22
|
useRef,
|
|
24
23
|
useState,
|
|
25
24
|
type MouseEvent as ReactMouseEvent,
|
|
@@ -29,7 +28,6 @@ import * as stylex from '@stylexjs/stylex';
|
|
|
29
28
|
import {colorVars, spacingVars, typeScaleVars} from '../theme/tokens.stylex';
|
|
30
29
|
import {Icon} from '../Icon';
|
|
31
30
|
import {IconButton} from '../IconButton';
|
|
32
|
-
import {useAnnounce} from '../hooks/useAnnounce';
|
|
33
31
|
import {useScrollLock} from '../hooks/useScrollLock';
|
|
34
32
|
import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
|
|
35
33
|
import {mergeProps, mergeRefs} from '../utils';
|
|
@@ -308,10 +306,7 @@ export function Lightbox({
|
|
|
308
306
|
const dragStartRef = useRef({x: 0, y: 0, panX: 0, panY: 0});
|
|
309
307
|
|
|
310
308
|
// Resolve current media item
|
|
311
|
-
const mediaArray =
|
|
312
|
-
() => (Array.isArray(media) ? media : [media]),
|
|
313
|
-
[media],
|
|
314
|
-
);
|
|
309
|
+
const mediaArray = Array.isArray(media) ? media : [media];
|
|
315
310
|
const isGallery = mediaArray.length > 1;
|
|
316
311
|
const currentItem =
|
|
317
312
|
mediaArray.length > 0
|
|
@@ -334,29 +329,6 @@ export function Lightbox({
|
|
|
334
329
|
setPan({x: 0, y: 0});
|
|
335
330
|
}, [index, currentItem?.src]);
|
|
336
331
|
|
|
337
|
-
// Announce gallery navigation to screen readers. Moving between images only
|
|
338
|
-
// updates the visual counter, which is silent to assistive tech, so mirror
|
|
339
|
-
// each change in a polite live region ("<alt>, 3 of 12", or "Image 3 of 12"
|
|
340
|
-
// when the image has no alt). Announce only when the image changes during an
|
|
341
|
-
// already-open session — not on mount, not when opening (even at a new
|
|
342
|
-
// index, since the dialog's aria-label already names the current image), and
|
|
343
|
-
// not on close.
|
|
344
|
-
const announce = useAnnounce();
|
|
345
|
-
const prevIndexRef = useRef(index);
|
|
346
|
-
const wasOpenRef = useRef(isOpen);
|
|
347
|
-
useEffect(() => {
|
|
348
|
-
const indexChanged = prevIndexRef.current !== index;
|
|
349
|
-
const wasOpen = wasOpenRef.current;
|
|
350
|
-
prevIndexRef.current = index;
|
|
351
|
-
wasOpenRef.current = isOpen;
|
|
352
|
-
if (!indexChanged || !isOpen || !wasOpen) {
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
const item = mediaArray[Math.min(index, mediaArray.length - 1)];
|
|
356
|
-
const position = `${index + 1} of ${mediaArray.length}`;
|
|
357
|
-
announce(item?.alt ? `${item.alt}, ${position}` : `Image ${position}`);
|
|
358
|
-
}, [index, isOpen, announce, mediaArray]);
|
|
359
|
-
|
|
360
332
|
// Open/close dialog
|
|
361
333
|
useIsomorphicLayoutEffect(() => {
|
|
362
334
|
const dialog = dialogRef.current;
|
|
@@ -17,27 +17,12 @@ export const docs = {
|
|
|
17
17
|
'NavHeadingMenuItem renders individual selectable items. ' +
|
|
18
18
|
'Pass as the menu prop of SideNavHeading or TopNavHeading.',
|
|
19
19
|
},
|
|
20
|
-
playground: {
|
|
21
|
-
defaults: {
|
|
22
|
-
children: [
|
|
23
|
-
{__element: 'NavHeadingMenuItem', props: {label: 'Dashboard', href: '#'}},
|
|
24
|
-
{__element: 'NavHeadingMenuItem', props: {label: 'Analytics', href: '#'}},
|
|
25
|
-
{__element: 'NavHeadingMenuItem', props: {label: 'Settings', href: '#'}},
|
|
26
|
-
],
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
20
|
props: [
|
|
30
21
|
{name: 'children', type: 'ReactNode', required: true, description: 'Menu items.'},
|
|
31
22
|
{name: 'size', type: "'sm' | 'md' | 'lg'", default: "'md'", description: 'Controls min-width and item padding.'},
|
|
32
23
|
{name: 'minWidth', type: 'number | string', description: 'Minimum width override.'},
|
|
33
24
|
{name: 'xstyle', type: 'StyleXStyles', description: 'StyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value, not an inline style object like style={{}}.'},
|
|
34
25
|
],
|
|
35
|
-
theming: {
|
|
36
|
-
targets: [
|
|
37
|
-
{className: 'astryx-nav-heading-menu', visualProps: ['size']},
|
|
38
|
-
{className: 'astryx-nav-heading-menu-item', visualProps: ['size']},
|
|
39
|
-
],
|
|
40
|
-
},
|
|
41
26
|
};
|
|
42
27
|
|
|
43
28
|
/** @type {import('../docs-types').TranslationDoc} */
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import {describe, it, expect, vi, beforeEach} from 'vitest';
|
|
13
13
|
import {render, screen, fireEvent, waitFor} from '@testing-library/react';
|
|
14
14
|
import userEvent from '@testing-library/user-event';
|
|
15
|
-
import {
|
|
15
|
+
import {HashtagIcon} from '@heroicons/react/24/outline';
|
|
16
16
|
import {NumberInput} from './NumberInput';
|
|
17
17
|
|
|
18
18
|
// Mock showPopover/hidePopover since jsdom does not implement them. Used by the
|
|
@@ -174,7 +174,7 @@ describe('NumberInput', () => {
|
|
|
174
174
|
label="Count"
|
|
175
175
|
value={null}
|
|
176
176
|
onChange={() => {}}
|
|
177
|
-
startIcon={
|
|
177
|
+
startIcon={HashtagIcon}
|
|
178
178
|
/>,
|
|
179
179
|
);
|
|
180
180
|
expect(screen.getByRole('spinbutton')).toBeInTheDocument();
|
|
@@ -707,7 +707,7 @@ describe('NumberInput', () => {
|
|
|
707
707
|
label="Qty"
|
|
708
708
|
value={0}
|
|
709
709
|
onChange={() => {}}
|
|
710
|
-
startIcon={<
|
|
710
|
+
startIcon={<HashtagIcon />}
|
|
711
711
|
/>,
|
|
712
712
|
);
|
|
713
713
|
|
|
@@ -867,48 +867,3 @@ describe('NumberInput', () => {
|
|
|
867
867
|
});
|
|
868
868
|
});
|
|
869
869
|
});
|
|
870
|
-
|
|
871
|
-
describe('keyboard clearing with hasClear (#3599)', () => {
|
|
872
|
-
it('commits null when the input is emptied and blurred', () => {
|
|
873
|
-
const onChange = vi.fn();
|
|
874
|
-
render(
|
|
875
|
-
<NumberInput label="Qty" hasClear value={42} onChange={onChange} />,
|
|
876
|
-
);
|
|
877
|
-
const input = screen.getByLabelText('Qty');
|
|
878
|
-
fireEvent.change(input, {target: {value: ''}});
|
|
879
|
-
fireEvent.blur(input);
|
|
880
|
-
expect(onChange).toHaveBeenCalledWith(null);
|
|
881
|
-
});
|
|
882
|
-
|
|
883
|
-
it('commits null when the input is emptied and Enter is pressed', () => {
|
|
884
|
-
const onChange = vi.fn();
|
|
885
|
-
render(
|
|
886
|
-
<NumberInput label="Qty" hasClear value={42} onChange={onChange} />,
|
|
887
|
-
);
|
|
888
|
-
const input = screen.getByLabelText('Qty');
|
|
889
|
-
fireEvent.change(input, {target: {value: ''}});
|
|
890
|
-
fireEvent.keyDown(input, {key: 'Enter'});
|
|
891
|
-
expect(onChange).toHaveBeenCalledWith(null);
|
|
892
|
-
});
|
|
893
|
-
|
|
894
|
-
it('does not fire when emptied and blurred with no prior value', () => {
|
|
895
|
-
const onChange = vi.fn();
|
|
896
|
-
render(
|
|
897
|
-
<NumberInput label="Qty" hasClear value={null} onChange={onChange} />,
|
|
898
|
-
);
|
|
899
|
-
const input = screen.getByLabelText('Qty');
|
|
900
|
-
fireEvent.change(input, {target: {value: ''}});
|
|
901
|
-
fireEvent.blur(input);
|
|
902
|
-
expect(onChange).not.toHaveBeenCalled();
|
|
903
|
-
});
|
|
904
|
-
|
|
905
|
-
it('still reverts on blur when hasClear is not set', () => {
|
|
906
|
-
const onChange = vi.fn();
|
|
907
|
-
render(<NumberInput label="Qty" value={42} onChange={onChange} />);
|
|
908
|
-
const input = screen.getByLabelText('Qty');
|
|
909
|
-
fireEvent.change(input, {target: {value: ''}});
|
|
910
|
-
fireEvent.blur(input);
|
|
911
|
-
expect(onChange).not.toHaveBeenCalled();
|
|
912
|
-
expect((input as HTMLInputElement).value).toBe('42');
|
|
913
|
-
});
|
|
914
|
-
});
|
|
@@ -503,21 +503,13 @@ export function NumberInput({
|
|
|
503
503
|
const handleBlur = useCallback(
|
|
504
504
|
(e: FocusEvent<HTMLInputElement>) => {
|
|
505
505
|
if (pendingInput !== null) {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
const parsed = parseNumberInput(pendingInput, {
|
|
514
|
-
min,
|
|
515
|
-
max,
|
|
516
|
-
isIntegerOnly,
|
|
517
|
-
});
|
|
518
|
-
if (parsed !== null && parsed !== value) {
|
|
519
|
-
onChange(parsed);
|
|
520
|
-
}
|
|
506
|
+
const parsed = parseNumberInput(pendingInput, {
|
|
507
|
+
min,
|
|
508
|
+
max,
|
|
509
|
+
isIntegerOnly,
|
|
510
|
+
});
|
|
511
|
+
if (parsed !== null && parsed !== value) {
|
|
512
|
+
onChange(parsed);
|
|
521
513
|
}
|
|
522
514
|
}
|
|
523
515
|
|
|
@@ -525,7 +517,7 @@ export function NumberInput({
|
|
|
525
517
|
setPendingInput(null);
|
|
526
518
|
onBlur?.(e);
|
|
527
519
|
},
|
|
528
|
-
[pendingInput, value, onChange, min, max, isIntegerOnly, onBlur
|
|
520
|
+
[pendingInput, value, onChange, min, max, isIntegerOnly, onBlur],
|
|
529
521
|
);
|
|
530
522
|
|
|
531
523
|
// Handle keyboard events
|
|
@@ -534,21 +526,13 @@ export function NumberInput({
|
|
|
534
526
|
if (e.key === 'Enter') {
|
|
535
527
|
// Validate and commit on Enter
|
|
536
528
|
if (pendingInput !== null) {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
const parsed = parseNumberInput(pendingInput, {
|
|
545
|
-
min,
|
|
546
|
-
max,
|
|
547
|
-
isIntegerOnly,
|
|
548
|
-
});
|
|
549
|
-
if (parsed !== null && parsed !== value) {
|
|
550
|
-
onChange(parsed);
|
|
551
|
-
}
|
|
529
|
+
const parsed = parseNumberInput(pendingInput, {
|
|
530
|
+
min,
|
|
531
|
+
max,
|
|
532
|
+
isIntegerOnly,
|
|
533
|
+
});
|
|
534
|
+
if (parsed !== null && parsed !== value) {
|
|
535
|
+
onChange(parsed);
|
|
552
536
|
}
|
|
553
537
|
}
|
|
554
538
|
onEnter?.();
|
|
@@ -564,7 +548,6 @@ export function NumberInput({
|
|
|
564
548
|
isIntegerOnly,
|
|
565
549
|
onEnter,
|
|
566
550
|
onKeyDown,
|
|
567
|
-
hasClear,
|
|
568
551
|
],
|
|
569
552
|
);
|
|
570
553
|
|
|
@@ -180,12 +180,6 @@ export const docs = {
|
|
|
180
180
|
description: 'Ref forwarded to the overlay root element.',
|
|
181
181
|
},
|
|
182
182
|
],
|
|
183
|
-
theming: {
|
|
184
|
-
targets: [
|
|
185
|
-
{className: 'astryx-overlay'},
|
|
186
|
-
{className: 'astryx-overlay-scrim', visualProps: ['position']},
|
|
187
|
-
],
|
|
188
|
-
},
|
|
189
183
|
};
|
|
190
184
|
|
|
191
185
|
/** @type {import('../docs-types').TranslationDoc} */
|
|
@@ -345,149 +345,6 @@ describe('Pagination', () => {
|
|
|
345
345
|
const activeDot = screen.getByRole('button', {name: 'Go to page 3'});
|
|
346
346
|
expect(activeDot).toHaveAttribute('aria-current', 'page');
|
|
347
347
|
});
|
|
348
|
-
|
|
349
|
-
// -------------------------------------------------------------------------
|
|
350
|
-
// Keyboard navigation (roving tabindex + arrow keys via useListFocus).
|
|
351
|
-
// Selection follows focus: arrow/Home/End move focus and select that page.
|
|
352
|
-
// -------------------------------------------------------------------------
|
|
353
|
-
|
|
354
|
-
it('uses roving tabindex — active dot has tabIndex 0, others -1', () => {
|
|
355
|
-
render(
|
|
356
|
-
<Pagination
|
|
357
|
-
page={2}
|
|
358
|
-
onChange={() => {}}
|
|
359
|
-
totalPages={4}
|
|
360
|
-
variant="dots"
|
|
361
|
-
/>,
|
|
362
|
-
);
|
|
363
|
-
expect(
|
|
364
|
-
screen.getByRole('button', {name: 'Go to page 2'}),
|
|
365
|
-
).toHaveAttribute('tabindex', '0');
|
|
366
|
-
expect(
|
|
367
|
-
screen.getByRole('button', {name: 'Go to page 1'}),
|
|
368
|
-
).toHaveAttribute('tabindex', '-1');
|
|
369
|
-
expect(
|
|
370
|
-
screen.getByRole('button', {name: 'Go to page 3'}),
|
|
371
|
-
).toHaveAttribute('tabindex', '-1');
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
it('ArrowRight moves focus to the next dot and selects it', async () => {
|
|
375
|
-
const user = userEvent.setup();
|
|
376
|
-
const onChange = vi.fn();
|
|
377
|
-
render(
|
|
378
|
-
<Pagination
|
|
379
|
-
page={2}
|
|
380
|
-
onChange={onChange}
|
|
381
|
-
totalPages={4}
|
|
382
|
-
variant="dots"
|
|
383
|
-
/>,
|
|
384
|
-
);
|
|
385
|
-
screen.getByRole('button', {name: 'Go to page 2'}).focus();
|
|
386
|
-
await user.keyboard('{ArrowRight}');
|
|
387
|
-
expect(onChange).toHaveBeenCalledWith(3);
|
|
388
|
-
expect(screen.getByRole('button', {name: 'Go to page 3'})).toHaveFocus();
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
it('ArrowLeft moves focus to the previous dot and selects it', async () => {
|
|
392
|
-
const user = userEvent.setup();
|
|
393
|
-
const onChange = vi.fn();
|
|
394
|
-
render(
|
|
395
|
-
<Pagination
|
|
396
|
-
page={3}
|
|
397
|
-
onChange={onChange}
|
|
398
|
-
totalPages={4}
|
|
399
|
-
variant="dots"
|
|
400
|
-
/>,
|
|
401
|
-
);
|
|
402
|
-
screen.getByRole('button', {name: 'Go to page 3'}).focus();
|
|
403
|
-
await user.keyboard('{ArrowLeft}');
|
|
404
|
-
expect(onChange).toHaveBeenCalledWith(2);
|
|
405
|
-
expect(screen.getByRole('button', {name: 'Go to page 2'})).toHaveFocus();
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
it('Home selects the first page, End the last', async () => {
|
|
409
|
-
const user = userEvent.setup();
|
|
410
|
-
const onChange = vi.fn();
|
|
411
|
-
const {rerender} = render(
|
|
412
|
-
<Pagination
|
|
413
|
-
page={3}
|
|
414
|
-
onChange={onChange}
|
|
415
|
-
totalPages={5}
|
|
416
|
-
variant="dots"
|
|
417
|
-
/>,
|
|
418
|
-
);
|
|
419
|
-
screen.getByRole('button', {name: 'Go to page 3'}).focus();
|
|
420
|
-
await user.keyboard('{Home}');
|
|
421
|
-
expect(onChange).toHaveBeenCalledWith(1);
|
|
422
|
-
expect(screen.getByRole('button', {name: 'Go to page 1'})).toHaveFocus();
|
|
423
|
-
|
|
424
|
-
onChange.mockClear();
|
|
425
|
-
rerender(
|
|
426
|
-
<Pagination
|
|
427
|
-
page={3}
|
|
428
|
-
onChange={onChange}
|
|
429
|
-
totalPages={5}
|
|
430
|
-
variant="dots"
|
|
431
|
-
/>,
|
|
432
|
-
);
|
|
433
|
-
screen.getByRole('button', {name: 'Go to page 3'}).focus();
|
|
434
|
-
await user.keyboard('{End}');
|
|
435
|
-
expect(onChange).toHaveBeenCalledWith(5);
|
|
436
|
-
expect(screen.getByRole('button', {name: 'Go to page 5'})).toHaveFocus();
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
it('wraps from the last dot to the first with ArrowRight', async () => {
|
|
440
|
-
const user = userEvent.setup();
|
|
441
|
-
const onChange = vi.fn();
|
|
442
|
-
render(
|
|
443
|
-
<Pagination
|
|
444
|
-
page={4}
|
|
445
|
-
onChange={onChange}
|
|
446
|
-
totalPages={4}
|
|
447
|
-
variant="dots"
|
|
448
|
-
/>,
|
|
449
|
-
);
|
|
450
|
-
screen.getByRole('button', {name: 'Go to page 4'}).focus();
|
|
451
|
-
await user.keyboard('{ArrowRight}');
|
|
452
|
-
expect(onChange).toHaveBeenCalledWith(1);
|
|
453
|
-
expect(screen.getByRole('button', {name: 'Go to page 1'})).toHaveFocus();
|
|
454
|
-
});
|
|
455
|
-
|
|
456
|
-
it('wraps from the first dot to the last with ArrowLeft', async () => {
|
|
457
|
-
const user = userEvent.setup();
|
|
458
|
-
const onChange = vi.fn();
|
|
459
|
-
render(
|
|
460
|
-
<Pagination
|
|
461
|
-
page={1}
|
|
462
|
-
onChange={onChange}
|
|
463
|
-
totalPages={4}
|
|
464
|
-
variant="dots"
|
|
465
|
-
/>,
|
|
466
|
-
);
|
|
467
|
-
screen.getByRole('button', {name: 'Go to page 1'}).focus();
|
|
468
|
-
await user.keyboard('{ArrowLeft}');
|
|
469
|
-
expect(onChange).toHaveBeenCalledWith(4);
|
|
470
|
-
expect(screen.getByRole('button', {name: 'Go to page 4'})).toHaveFocus();
|
|
471
|
-
});
|
|
472
|
-
|
|
473
|
-
it('does not navigate with arrow keys when disabled', async () => {
|
|
474
|
-
const user = userEvent.setup();
|
|
475
|
-
const onChange = vi.fn();
|
|
476
|
-
render(
|
|
477
|
-
<Pagination
|
|
478
|
-
page={2}
|
|
479
|
-
onChange={onChange}
|
|
480
|
-
totalPages={4}
|
|
481
|
-
variant="dots"
|
|
482
|
-
isDisabled
|
|
483
|
-
/>,
|
|
484
|
-
);
|
|
485
|
-
const dot = screen.getByRole('button', {name: 'Go to page 2'});
|
|
486
|
-
expect(dot).toBeDisabled();
|
|
487
|
-
dot.focus();
|
|
488
|
-
await user.keyboard('{ArrowRight}');
|
|
489
|
-
expect(onChange).not.toHaveBeenCalled();
|
|
490
|
-
});
|
|
491
348
|
});
|
|
492
349
|
|
|
493
350
|
// ---------------------------------------------------------------------------
|
|
@@ -35,7 +35,6 @@ import {Icon} from '../Icon';
|
|
|
35
35
|
import {Selector} from '../Selector';
|
|
36
36
|
import {Text} from '../Text';
|
|
37
37
|
import {useAnnounce} from '../hooks/useAnnounce';
|
|
38
|
-
import {useListFocus} from '../hooks/useListFocus';
|
|
39
38
|
import {mergeProps} from '../utils';
|
|
40
39
|
import type {BaseProps} from '../BaseProps';
|
|
41
40
|
import {themeProps} from '../utils/themeProps';
|
|
@@ -371,21 +370,6 @@ export function Pagination({
|
|
|
371
370
|
// in-flight target instead of stalling on the last committed page.
|
|
372
371
|
const [optimisticPage, setOptimisticPage] = useOptimistic(page);
|
|
373
372
|
|
|
374
|
-
// Roving-tabindex + arrow/Home/End keyboard nav for the dots variant, owned
|
|
375
|
-
// by the shared useListFocus primitive (mirrors SegmentedControl). It stamps a
|
|
376
|
-
// single tab stop across the dots and moves focus horizontally; selection
|
|
377
|
-
// follows focus via handleDotsFocus so arrow keys move the active page.
|
|
378
|
-
const {
|
|
379
|
-
listRef: dotsListRef,
|
|
380
|
-
handleKeyDown: handleDotsKeyDown,
|
|
381
|
-
handleFocus: handleDotsRovingFocus,
|
|
382
|
-
} = useListFocus<HTMLDivElement>({
|
|
383
|
-
itemSelector: 'button',
|
|
384
|
-
hasRovingTabIndex: true,
|
|
385
|
-
wrap: true,
|
|
386
|
-
orientation: 'horizontal',
|
|
387
|
-
});
|
|
388
|
-
|
|
389
373
|
// Compute pagination state
|
|
390
374
|
const computedTotalPages =
|
|
391
375
|
totalPagesProp ??
|
|
@@ -426,28 +410,6 @@ export function Pagination({
|
|
|
426
410
|
});
|
|
427
411
|
};
|
|
428
412
|
|
|
429
|
-
// Selection-follows-focus for the dots (APG radiogroup pattern): useListFocus
|
|
430
|
-
// only *moves* focus, so when focus lands on a dot -- via arrow/Home/End, or a
|
|
431
|
-
// click that focuses it -- we select that dot's page. handleDotsRovingFocus
|
|
432
|
-
// keeps the roving tab stop in sync. The current page is skipped so tabbing
|
|
433
|
-
// into the group is a no-op.
|
|
434
|
-
const handleDotsFocus = (e: React.FocusEvent) => {
|
|
435
|
-
handleDotsRovingFocus(e);
|
|
436
|
-
if (isDisabled) {
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
const focused = (e.target as HTMLElement | null)?.closest<HTMLElement>(
|
|
440
|
-
'button[data-page]',
|
|
441
|
-
);
|
|
442
|
-
if (!focused) {
|
|
443
|
-
return;
|
|
444
|
-
}
|
|
445
|
-
const nextPage = Number(focused.dataset.page);
|
|
446
|
-
if (Number.isFinite(nextPage) && nextPage !== optimisticPage) {
|
|
447
|
-
handlePageChange(nextPage);
|
|
448
|
-
}
|
|
449
|
-
};
|
|
450
|
-
|
|
451
413
|
const handlePrevious = () => {
|
|
452
414
|
if (hasPrevious) {
|
|
453
415
|
handlePageChange(optimisticPage - 1);
|
|
@@ -556,47 +518,33 @@ export function Pagination({
|
|
|
556
518
|
if (computedTotalPages == null) {
|
|
557
519
|
return null;
|
|
558
520
|
}
|
|
559
|
-
|
|
560
521
|
return (
|
|
561
522
|
<div
|
|
562
|
-
ref={dotsListRef}
|
|
563
523
|
{...stylex.props(styles.dotsContainer)}
|
|
564
524
|
role="group"
|
|
565
|
-
aria-label="Page indicators"
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
size,
|
|
589
|
-
}),
|
|
590
|
-
stylex.props(
|
|
591
|
-
styles.dot,
|
|
592
|
-
isSm && styles.dotSm,
|
|
593
|
-
isActive && styles.dotActive,
|
|
594
|
-
isDisabled && styles.dotDisabled,
|
|
595
|
-
),
|
|
596
|
-
)}
|
|
597
|
-
/>
|
|
598
|
-
);
|
|
599
|
-
})}
|
|
525
|
+
aria-label="Page indicators">
|
|
526
|
+
{Array.from({length: computedTotalPages}, (_, i) => (
|
|
527
|
+
<button
|
|
528
|
+
key={i + 1}
|
|
529
|
+
type="button"
|
|
530
|
+
aria-label={`Go to page ${i + 1}`}
|
|
531
|
+
aria-current={i + 1 === optimisticPage ? 'page' : undefined}
|
|
532
|
+
onClick={() => handlePageChange(i + 1)}
|
|
533
|
+
disabled={isDisabled}
|
|
534
|
+
{...mergeProps(
|
|
535
|
+
themeProps('pagination-dot', {
|
|
536
|
+
active: i + 1 === optimisticPage ? 'active' : null,
|
|
537
|
+
size,
|
|
538
|
+
}),
|
|
539
|
+
stylex.props(
|
|
540
|
+
styles.dot,
|
|
541
|
+
isSm && styles.dotSm,
|
|
542
|
+
i + 1 === optimisticPage && styles.dotActive,
|
|
543
|
+
isDisabled && styles.dotDisabled,
|
|
544
|
+
),
|
|
545
|
+
)}
|
|
546
|
+
/>
|
|
547
|
+
))}
|
|
600
548
|
</div>
|
|
601
549
|
);
|
|
602
550
|
}
|
|
@@ -354,69 +354,4 @@ describe('Popover', () => {
|
|
|
354
354
|
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
355
355
|
});
|
|
356
356
|
});
|
|
357
|
-
|
|
358
|
-
describe('focus restoration', () => {
|
|
359
|
-
it('returns focus to the trigger when closed via Escape', () => {
|
|
360
|
-
render(
|
|
361
|
-
<Popover
|
|
362
|
-
content={
|
|
363
|
-
<button type="button" data-testid="inside-content">
|
|
364
|
-
Inside
|
|
365
|
-
</button>
|
|
366
|
-
}
|
|
367
|
-
label="Test">
|
|
368
|
-
<button type="button">Open</button>
|
|
369
|
-
</Popover>,
|
|
370
|
-
);
|
|
371
|
-
const trigger = screen.getByRole('button', {name: 'Open'});
|
|
372
|
-
trigger.focus();
|
|
373
|
-
expect(trigger).toHaveFocus();
|
|
374
|
-
|
|
375
|
-
fireEvent.click(trigger);
|
|
376
|
-
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
377
|
-
|
|
378
|
-
// Move focus into the open popover, as a keyboard user would.
|
|
379
|
-
const inside = screen.getByTestId('inside-content');
|
|
380
|
-
inside.focus();
|
|
381
|
-
expect(inside).toHaveFocus();
|
|
382
|
-
|
|
383
|
-
fireEvent.keyDown(document, {key: 'Escape'});
|
|
384
|
-
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
385
|
-
expect(trigger).toHaveFocus();
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
it('returns focus to the trigger on light dismiss', () => {
|
|
389
|
-
render(
|
|
390
|
-
<Popover
|
|
391
|
-
content={
|
|
392
|
-
<button type="button" data-testid="inside-content">
|
|
393
|
-
Inside
|
|
394
|
-
</button>
|
|
395
|
-
}
|
|
396
|
-
label="Test">
|
|
397
|
-
<button type="button">Open</button>
|
|
398
|
-
</Popover>,
|
|
399
|
-
);
|
|
400
|
-
const trigger = screen.getByRole('button', {name: 'Open'});
|
|
401
|
-
trigger.focus();
|
|
402
|
-
|
|
403
|
-
fireEvent.click(trigger);
|
|
404
|
-
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
405
|
-
|
|
406
|
-
const inside = screen.getByTestId('inside-content');
|
|
407
|
-
inside.focus();
|
|
408
|
-
expect(inside).toHaveFocus();
|
|
409
|
-
|
|
410
|
-
// Simulate the browser's light dismiss for popover="auto": clicking
|
|
411
|
-
// outside fires a `toggle` event with newState "closed".
|
|
412
|
-
const popoverEl = document.querySelector('[popover]');
|
|
413
|
-
expect(popoverEl).not.toBeNull();
|
|
414
|
-
const toggleEvent = new Event('toggle');
|
|
415
|
-
Object.defineProperty(toggleEvent, 'newState', {value: 'closed'});
|
|
416
|
-
fireEvent(popoverEl as HTMLElement, toggleEvent);
|
|
417
|
-
|
|
418
|
-
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
419
|
-
expect(trigger).toHaveFocus();
|
|
420
|
-
});
|
|
421
|
-
});
|
|
422
357
|
});
|
|
@@ -120,7 +120,7 @@ export const docs = {
|
|
|
120
120
|
name: 'resultCount',
|
|
121
121
|
type: 'number | string',
|
|
122
122
|
description:
|
|
123
|
-
'Number of results matching the current filters. When a number, formatted as "N results". When a string, displayed as-is.
|
|
123
|
+
'Number of results matching the current filters. When a number, formatted as "N results". When a string, displayed as-is.',
|
|
124
124
|
},
|
|
125
125
|
{
|
|
126
126
|
name: 'size',
|
|
@@ -261,7 +261,7 @@ export const docsZh = {
|
|
|
261
261
|
name: 'resultCount',
|
|
262
262
|
type: 'number | string',
|
|
263
263
|
description:
|
|
264
|
-
'匹配当前过滤器的结果数量。数字类型时格式化为"N results"
|
|
264
|
+
'匹配当前过滤器的结果数量。数字类型时格式化为"N results"。字符串类型时按原样显示。',
|
|
265
265
|
},
|
|
266
266
|
{
|
|
267
267
|
name: 'size',
|