@box/metadata-taxonomy-picker 2.18.0

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 (170) hide show
  1. package/LICENSE +379 -0
  2. package/README.md +57 -0
  3. package/dist/chunks/empty-state.js +22 -0
  4. package/dist/chunks/error-state.js +41 -0
  5. package/dist/chunks/load-more-error-row.js +53 -0
  6. package/dist/chunks/load-more-loading-row.js +17 -0
  7. package/dist/chunks/loading-state.js +17 -0
  8. package/dist/chunks/metadata-taxonomy-picker-shell.js +278 -0
  9. package/dist/chunks/taxonomy-ancestor-breadcrumb.js +115 -0
  10. package/dist/chunks/taxonomy-items-list.js +114 -0
  11. package/dist/chunks/taxonomy-level-filter.js +47 -0
  12. package/dist/chunks/taxonomy-menu-item.js +99 -0
  13. package/dist/esm/index.js +3 -0
  14. package/dist/esm/lib/components/metadata-taxonomy-picker-shell/index.js +2 -0
  15. package/dist/esm/lib/components/metadata-taxonomy-picker-shell/messages.js +24 -0
  16. package/dist/esm/lib/components/metadata-taxonomy-picker-shell/metadata-taxonomy-picker-shell.js +2 -0
  17. package/dist/esm/lib/components/taxonomy-ancestor-breadcrumb/index.js +2 -0
  18. package/dist/esm/lib/components/taxonomy-ancestor-breadcrumb/taxonomy-ancestor-breadcrumb.js +2 -0
  19. package/dist/esm/lib/components/taxonomy-items-list/empty-state/empty-state.js +2 -0
  20. package/dist/esm/lib/components/taxonomy-items-list/empty-state/index.js +2 -0
  21. package/dist/esm/lib/components/taxonomy-items-list/error-state/error-state.js +2 -0
  22. package/dist/esm/lib/components/taxonomy-items-list/error-state/index.js +2 -0
  23. package/dist/esm/lib/components/taxonomy-items-list/index.js +6 -0
  24. package/dist/esm/lib/components/taxonomy-items-list/load-more-feedback/index.js +3 -0
  25. package/dist/esm/lib/components/taxonomy-items-list/load-more-feedback/load-more-error-row.js +2 -0
  26. package/dist/esm/lib/components/taxonomy-items-list/load-more-feedback/load-more-loading-row.js +2 -0
  27. package/dist/esm/lib/components/taxonomy-items-list/load-more-feedback/messages.js +20 -0
  28. package/dist/esm/lib/components/taxonomy-items-list/loading-state/index.js +2 -0
  29. package/dist/esm/lib/components/taxonomy-items-list/loading-state/loading-state.js +2 -0
  30. package/dist/esm/lib/components/taxonomy-items-list/messages.js +36 -0
  31. package/dist/esm/lib/components/taxonomy-items-list/taxonomy-items-list.js +2 -0
  32. package/dist/esm/lib/components/taxonomy-level-filter/index.js +2 -0
  33. package/dist/esm/lib/components/taxonomy-level-filter/messages.js +6 -0
  34. package/dist/esm/lib/components/taxonomy-level-filter/taxonomy-level-filter.js +2 -0
  35. package/dist/esm/lib/components/taxonomy-menu-item/index.js +2 -0
  36. package/dist/esm/lib/components/taxonomy-menu-item/messages.js +6 -0
  37. package/dist/esm/lib/components/taxonomy-menu-item/taxonomy-menu-item.js +2 -0
  38. package/dist/esm/lib/components/taxonomy-menu-item/use-taxonomy-menu-item-keyboard.js +100 -0
  39. package/dist/esm/lib/constants.js +2 -0
  40. package/dist/esm/lib/hooks/messages.js +16 -0
  41. package/dist/esm/lib/hooks/use-taxonomy-picker-controller.js +261 -0
  42. package/dist/esm/lib/metadata-taxonomy-picker.js +10 -0
  43. package/dist/esm/lib/state/reducer.js +147 -0
  44. package/dist/esm/lib/state/transitions.js +22 -0
  45. package/dist/i18n/bn-IN.js +24 -0
  46. package/dist/i18n/bn-IN.properties +44 -0
  47. package/dist/i18n/da-DK.js +24 -0
  48. package/dist/i18n/da-DK.properties +44 -0
  49. package/dist/i18n/de-DE.js +24 -0
  50. package/dist/i18n/de-DE.properties +44 -0
  51. package/dist/i18n/en-AU.js +24 -0
  52. package/dist/i18n/en-AU.properties +44 -0
  53. package/dist/i18n/en-CA.js +24 -0
  54. package/dist/i18n/en-CA.properties +44 -0
  55. package/dist/i18n/en-GB.js +24 -0
  56. package/dist/i18n/en-GB.properties +44 -0
  57. package/dist/i18n/en-US.js +24 -0
  58. package/dist/i18n/en-US.properties +44 -0
  59. package/dist/i18n/en-x-pseudo.js +24 -0
  60. package/dist/i18n/en-x-pseudo.properties +44 -0
  61. package/dist/i18n/es-419.js +24 -0
  62. package/dist/i18n/es-419.properties +44 -0
  63. package/dist/i18n/es-ES.js +24 -0
  64. package/dist/i18n/es-ES.properties +44 -0
  65. package/dist/i18n/fi-FI.js +24 -0
  66. package/dist/i18n/fi-FI.properties +44 -0
  67. package/dist/i18n/fr-CA.js +24 -0
  68. package/dist/i18n/fr-CA.properties +44 -0
  69. package/dist/i18n/fr-FR.js +24 -0
  70. package/dist/i18n/fr-FR.properties +44 -0
  71. package/dist/i18n/hi-IN.js +24 -0
  72. package/dist/i18n/hi-IN.properties +44 -0
  73. package/dist/i18n/it-IT.js +24 -0
  74. package/dist/i18n/it-IT.properties +44 -0
  75. package/dist/i18n/ja-JP.js +24 -0
  76. package/dist/i18n/ja-JP.properties +44 -0
  77. package/dist/i18n/json/src/lib/components/metadata-taxonomy-picker-shell/messages.json +1 -0
  78. package/dist/i18n/json/src/lib/components/taxonomy-items-list/load-more-feedback/messages.json +1 -0
  79. package/dist/i18n/json/src/lib/components/taxonomy-items-list/messages.json +1 -0
  80. package/dist/i18n/json/src/lib/components/taxonomy-level-filter/messages.json +1 -0
  81. package/dist/i18n/json/src/lib/components/taxonomy-menu-item/messages.json +1 -0
  82. package/dist/i18n/json/src/lib/hooks/messages.json +1 -0
  83. package/dist/i18n/ko-KR.js +24 -0
  84. package/dist/i18n/ko-KR.properties +44 -0
  85. package/dist/i18n/nb-NO.js +24 -0
  86. package/dist/i18n/nb-NO.properties +44 -0
  87. package/dist/i18n/nl-NL.js +24 -0
  88. package/dist/i18n/nl-NL.properties +44 -0
  89. package/dist/i18n/pl-PL.js +24 -0
  90. package/dist/i18n/pl-PL.properties +44 -0
  91. package/dist/i18n/pt-BR.js +24 -0
  92. package/dist/i18n/pt-BR.properties +44 -0
  93. package/dist/i18n/ru-RU.js +24 -0
  94. package/dist/i18n/ru-RU.properties +44 -0
  95. package/dist/i18n/sv-SE.js +24 -0
  96. package/dist/i18n/sv-SE.properties +44 -0
  97. package/dist/i18n/tr-TR.js +24 -0
  98. package/dist/i18n/tr-TR.properties +44 -0
  99. package/dist/i18n/zh-CN.js +24 -0
  100. package/dist/i18n/zh-CN.properties +44 -0
  101. package/dist/i18n/zh-TW.js +24 -0
  102. package/dist/i18n/zh-TW.properties +44 -0
  103. package/dist/styles/empty-state.css +1 -0
  104. package/dist/styles/error-state.css +1 -0
  105. package/dist/styles/load-more-error-row.css +1 -0
  106. package/dist/styles/load-more-loading-row.css +1 -0
  107. package/dist/styles/loading-state.css +1 -0
  108. package/dist/styles/metadata-taxonomy-picker-shell.css +1 -0
  109. package/dist/styles/taxonomy-ancestor-breadcrumb.css +1 -0
  110. package/dist/styles/taxonomy-items-list.css +1 -0
  111. package/dist/styles/taxonomy-level-filter.css +1 -0
  112. package/dist/styles/taxonomy-menu-item.css +1 -0
  113. package/dist/types/index.d.ts +4 -0
  114. package/dist/types/lib/components/metadata-taxonomy-picker-shell/index.d.ts +1 -0
  115. package/dist/types/lib/components/metadata-taxonomy-picker-shell/messages.d.ts +27 -0
  116. package/dist/types/lib/components/metadata-taxonomy-picker-shell/metadata-taxonomy-picker-shell.d.ts +2 -0
  117. package/dist/types/lib/components/taxonomy-ancestor-breadcrumb/index.d.ts +1 -0
  118. package/dist/types/lib/components/taxonomy-ancestor-breadcrumb/taxonomy-ancestor-breadcrumb.d.ts +16 -0
  119. package/dist/types/lib/components/taxonomy-items-list/empty-state/empty-state.d.ts +10 -0
  120. package/dist/types/lib/components/taxonomy-items-list/empty-state/index.d.ts +1 -0
  121. package/dist/types/lib/components/taxonomy-items-list/error-state/error-state.d.ts +9 -0
  122. package/dist/types/lib/components/taxonomy-items-list/error-state/index.d.ts +1 -0
  123. package/dist/types/lib/components/taxonomy-items-list/index.d.ts +5 -0
  124. package/dist/types/lib/components/taxonomy-items-list/load-more-feedback/index.d.ts +2 -0
  125. package/dist/types/lib/components/taxonomy-items-list/load-more-feedback/load-more-error-row.d.ts +10 -0
  126. package/dist/types/lib/components/taxonomy-items-list/load-more-feedback/load-more-loading-row.d.ts +7 -0
  127. package/dist/types/lib/components/taxonomy-items-list/load-more-feedback/messages.d.ts +22 -0
  128. package/dist/types/lib/components/taxonomy-items-list/loading-state/index.d.ts +1 -0
  129. package/dist/types/lib/components/taxonomy-items-list/loading-state/loading-state.d.ts +6 -0
  130. package/dist/types/lib/components/taxonomy-items-list/messages.d.ts +42 -0
  131. package/dist/types/lib/components/taxonomy-items-list/taxonomy-items-list.d.ts +82 -0
  132. package/dist/types/lib/components/taxonomy-level-filter/index.d.ts +1 -0
  133. package/dist/types/lib/components/taxonomy-level-filter/messages.d.ts +7 -0
  134. package/dist/types/lib/components/taxonomy-level-filter/taxonomy-level-filter.d.ts +11 -0
  135. package/dist/types/lib/components/taxonomy-menu-item/index.d.ts +1 -0
  136. package/dist/types/lib/components/taxonomy-menu-item/messages.d.ts +7 -0
  137. package/dist/types/lib/components/taxonomy-menu-item/taxonomy-menu-item.d.ts +20 -0
  138. package/dist/types/lib/components/taxonomy-menu-item/use-taxonomy-menu-item-keyboard.d.ts +47 -0
  139. package/dist/types/lib/constants.d.ts +49 -0
  140. package/dist/types/lib/hooks/messages.d.ts +17 -0
  141. package/dist/types/lib/hooks/use-taxonomy-picker-controller.d.ts +22 -0
  142. package/dist/types/lib/metadata-taxonomy-picker.d.ts +8 -0
  143. package/dist/types/lib/state/reducer.d.ts +180 -0
  144. package/dist/types/lib/state/transitions.d.ts +4 -0
  145. package/dist/types/lib/stories/metadata-taxonomy-picker.stories.d.ts +136 -0
  146. package/dist/types/lib/stories/shared/build-taxonomy-items.d.ts +10 -0
  147. package/dist/types/lib/stories/shared/create-mock-items-service.d.ts +35 -0
  148. package/dist/types/lib/stories/shared/generate-deep-nodes.d.ts +39 -0
  149. package/dist/types/lib/stories/shared/generate-hierarchical-nodes.d.ts +3 -0
  150. package/dist/types/lib/stories/shared/generate-nodes.d.ts +2 -0
  151. package/dist/types/lib/stories/shared/generate-search-results.d.ts +10 -0
  152. package/dist/types/lib/stories/shared/story-container.d.ts +5 -0
  153. package/dist/types/lib/stories/shared/taxonomy-items-list-fixtures.d.ts +7 -0
  154. package/dist/types/lib/stories/taxonomy-ancestor-breadcrumb.stories.d.ts +28 -0
  155. package/dist/types/lib/stories/taxonomy-items-list.stories.d.ts +77 -0
  156. package/dist/types/lib/stories/taxonomy-menu-item.stories.d.ts +67 -0
  157. package/dist/types/lib/stories/tests/breadcrumb-navigation.interaction-tests.stories.d.ts +78 -0
  158. package/dist/types/lib/stories/tests/error-handling.interaction-tests.stories.d.ts +50 -0
  159. package/dist/types/lib/stories/tests/interaction-tests.stories.d.ts +47 -0
  160. package/dist/types/lib/stories/tests/level-filter-interaction-tests.stories.d.ts +99 -0
  161. package/dist/types/lib/stories/tests/level-transitions.interaction-tests.stories.d.ts +60 -0
  162. package/dist/types/lib/stories/tests/pagination.interaction-tests.stories.d.ts +90 -0
  163. package/dist/types/lib/stories/tests/portal-and-ref.interaction-tests.stories.d.ts +39 -0
  164. package/dist/types/lib/stories/tests/search-interaction-tests.stories.d.ts +124 -0
  165. package/dist/types/lib/stories/tests/shell-selection.interaction-tests.stories.d.ts +56 -0
  166. package/dist/types/lib/stories/tests/single-level-mode.interaction-tests.stories.d.ts +50 -0
  167. package/dist/types/lib/stories/tests/taxonomy-menu-item.interaction-tests.stories.d.ts +70 -0
  168. package/dist/types/lib/stories/tests/visual-regression-tests.stories.d.ts +38 -0
  169. package/dist/types/lib/types.d.ts +105 -0
  170. package/package.json +51 -0
@@ -0,0 +1,39 @@
1
+ import { TaxonomyNode } from '../../types';
2
+ declare const ROOT_KEY = "__root__";
3
+ export interface DeepTreeOptions {
4
+ /** Total depth of the tree (number of drillable levels). */
5
+ depth: number;
6
+ /** How many children each non-leaf level holds. Defaults to 3. */
7
+ branching?: number;
8
+ /**
9
+ * Optional per-level display name template applied as `${prefix} ${index}`.
10
+ * If not provided, levels are labelled as `L1`, `L2`, … with the row index.
11
+ */
12
+ levelLabels?: string[];
13
+ /**
14
+ * Render long, sentence-style names that force the breadcrumb to truncate
15
+ * even at moderate depths. Useful for visualizing the folder-tree dropdown.
16
+ */
17
+ longNames?: boolean;
18
+ }
19
+ /**
20
+ * Build a synthetic taxonomy tree with arbitrary depth for breadcrumb-truncation
21
+ * stories. The first child of every level is the only one whose subtree continues
22
+ * deeper, which guarantees a single deterministic deep path while still giving
23
+ * each level enough siblings to look realistic in the items list.
24
+ *
25
+ * Example for `depth: 4`, `branching: 3`:
26
+ *
27
+ * root → L1 01, L1 02, L1 03
28
+ * L1 01 → L2 01, L2 02, L2 03
29
+ * L2 01 → L3 01, L3 02, L3 03
30
+ * L3 01 → L4 01, L4 02, L4 03 (leaves)
31
+ */
32
+ export declare function buildDeepTree({ depth, branching, levelLabels, longNames, }: DeepTreeOptions): Record<string, TaxonomyNode[]>;
33
+ /**
34
+ * Returns the deterministic deep path produced by `buildDeepTree` — the chain
35
+ * of ids the caller must drill through to reach the deepest level. The first
36
+ * id is the root-level row, the last id is the deepest level reachable.
37
+ */
38
+ export declare function getDeepPath(depth: number): string[];
39
+ export { ROOT_KEY };
@@ -0,0 +1,3 @@
1
+ import { TaxonomyNode } from '../../types';
2
+ /** Three-level fixture (Region -> Country -> State) for drill-down stories. */
3
+ export declare function buildTwoLevelTree(): Record<string, TaxonomyNode[]>;
@@ -0,0 +1,2 @@
1
+ import { TaxonomyNode } from '../../types';
2
+ export declare function generateNodes(count: number, options?: Partial<TaxonomyNode>): TaxonomyNode[];
@@ -0,0 +1,10 @@
1
+ import { TaxonomySearchResult } from '../../types';
2
+ /**
3
+ * Builds an array of `TaxonomySearchResult` fixtures for use in stories and
4
+ * interaction tests. Each result has an `ancestors` array by default so that
5
+ * the ancestor-breadcrumb subtitle is rendered in the row.
6
+ *
7
+ * Pass `options` to override any field across all generated items, e.g.
8
+ * `{ hasChildren: true }` to verify drill-down chevrons in search results.
9
+ */
10
+ export declare function generateSearchResults(count: number, options?: Partial<TaxonomySearchResult>): TaxonomySearchResult[];
@@ -0,0 +1,5 @@
1
+ import { ReactNode } from 'react';
2
+ /** Fixed-width framed wrapper used by TaxonomyItemsList stories. */
3
+ export declare function StoryContainer({ children }: {
4
+ children: ReactNode;
5
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import { TaxonomyAncestor } from '../../types';
2
+ /** Realistic single-line names for browse-mode rows. */
3
+ export declare const BROWSE_NAMES: string[];
4
+ /** Realistic names for search-mode rows (paired with `ANCESTOR_PATHS`). */
5
+ export declare const SEARCH_NAMES: string[];
6
+ /** Ancestor breadcrumb paths from depth 1 to depth 7, used to vary search-row height. */
7
+ export declare const ANCESTOR_PATHS: TaxonomyAncestor[][];
@@ -0,0 +1,28 @@
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { TaxonomyAncestorBreadcrumb } from '../components/taxonomy-ancestor-breadcrumb';
3
+ import { TaxonomyAncestor } from '../types';
4
+ declare const _default: {
5
+ title: string;
6
+ component: import('react').NamedExoticComponent<import('../components/taxonomy-ancestor-breadcrumb').TaxonomyAncestorBreadcrumbProps>;
7
+ decorators: ((Story: import('storybook/internal/csf').PartialStoryFn<import('@storybook/react').ReactRenderer, {
8
+ ancestors: TaxonomyAncestor[];
9
+ }>) => import("react/jsx-runtime").JSX.Element)[];
10
+ parameters: {
11
+ docs: {
12
+ description: {
13
+ component: string;
14
+ };
15
+ };
16
+ layout: string;
17
+ };
18
+ };
19
+ export default _default;
20
+ type Story = StoryObj<typeof TaxonomyAncestorBreadcrumb>;
21
+ export declare const SingleAncestor: Story;
22
+ export declare const TwoAncestors: Story;
23
+ /** Plenty of width — full trail fits without truncation. */
24
+ export declare const FullTrailFits: Story;
25
+ /** Narrow container — the trail collapses to `first / … / last`. */
26
+ export declare const TruncatedToFirstAndLast: Story;
27
+ /** Long segment names — truncated form still applies CSS ellipsis on the leaf segment. */
28
+ export declare const VeryLongSegments: Story;
@@ -0,0 +1,77 @@
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { TaxonomyItemsList } from '../components/taxonomy-items-list';
3
+ declare const _default: {
4
+ title: string;
5
+ component: import('react').ForwardRefExoticComponent<import('../components/taxonomy-items-list').TaxonomyItemsListProps & import('react').RefAttributes<import('../components/taxonomy-items-list').TaxonomyItemsListRef>>;
6
+ decorators: ((Story: import('storybook/internal/csf').PartialStoryFn<import('@storybook/react').ReactRenderer, {
7
+ items: import('../components/taxonomy-menu-item').TaxonomyMenuItemProps[];
8
+ multiSelect: boolean;
9
+ selectedValue: string;
10
+ estimatedRowHeight?: number | undefined;
11
+ hasVariableRowHeight?: boolean | undefined;
12
+ isSearchMode?: boolean | undefined;
13
+ isFetching: boolean;
14
+ error: string | null;
15
+ loadMoreError?: string | null | undefined;
16
+ onRetry: () => void;
17
+ listboxId?: string | undefined;
18
+ onFocusExit?: (() => void) | undefined;
19
+ hasMore?: boolean | undefined;
20
+ isFetchingMore?: boolean | undefined;
21
+ onLoadMore?: (() => void) | undefined;
22
+ ref?: import('react').LegacyRef<import('../components/taxonomy-items-list').TaxonomyItemsListRef> | undefined;
23
+ key?: import('react').Key | null | undefined;
24
+ }>) => import("react/jsx-runtime").JSX.Element)[];
25
+ parameters: {
26
+ docs: {
27
+ description: {
28
+ component: string;
29
+ };
30
+ };
31
+ layout: string;
32
+ modernizedComponents: boolean;
33
+ };
34
+ };
35
+ export default _default;
36
+ type Story = StoryObj<typeof TaxonomyItemsList>;
37
+ /** 1 000 single-select browse items — validates scrolling and virtualization at scale. */
38
+ export declare const BrowseLargeDataset: Story;
39
+ /** 3 000 multi-select browse items with checkboxes. */
40
+ export declare const BrowseLargeDatasetMultiSelect: Story;
41
+ /** Small browse list — 5 items, no scrollbar. */
42
+ export declare const BrowseFewItems: Story;
43
+ /** 1 000 search results with 1–7 level ancestor breadcrumbs. Rows vary in height. */
44
+ export declare const SearchLargeDataset: Story;
45
+ /** 3 000 multi-select search results with breadcrumbs and checkboxes. */
46
+ export declare const SearchLargeDatasetMultiSelect: Story;
47
+ /** Search results with drill-down chevrons — results that have children. */
48
+ export declare const SearchWithDrillDown: Story;
49
+ /**
50
+ * Browse rows where only deeper levels are selectable. Rows render the
51
+ * display name and drill-down chevron only — no radio or checkbox.
52
+ */
53
+ export declare const BrowseNonSelectableParentLevel: Story;
54
+ /**
55
+ * Search results matching a parent-only level — breadcrumbs are shown,
56
+ * the row exposes no selection control, but the drill-down chevron
57
+ * remains so users can navigate into selectable children.
58
+ */
59
+ export declare const SearchNonSelectableResults: Story;
60
+ /** Full-area skeleton while data is loading. */
61
+ export declare const Loading: Story;
62
+ /** Error state with a retry button. */
63
+ export declare const Error: Story;
64
+ /** Empty state when the level contains no items. */
65
+ export declare const Empty: Story;
66
+ /** Items already loaded with ghost rows shown at the bottom while the next page loads. */
67
+ export declare const LoadingMore: Story;
68
+ /**
69
+ * Load-more error: already-loaded items remain visible while an inline
70
+ * "Loading failed" notice with a Reload action sits at the bottom of the list.
71
+ */
72
+ export declare const LoadMoreError: Story;
73
+ /**
74
+ * Same load-more error variant, but in search mode — verifies the inline
75
+ * error renders at the bottom of variable-height search rows too.
76
+ */
77
+ export declare const SearchLoadMoreError: Story;
@@ -0,0 +1,67 @@
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { TaxonomyMenuItem, TaxonomyMenuItemProps } from '../components/taxonomy-menu-item';
3
+ declare const _default: {
4
+ title: string;
5
+ component: import('react').NamedExoticComponent<TaxonomyMenuItemProps>;
6
+ render: (props: TaxonomyMenuItemProps) => import("react/jsx-runtime").JSX.Element;
7
+ args: {
8
+ id: string;
9
+ displayName: string;
10
+ selectable: true;
11
+ multiSelect: false;
12
+ isSelected: false;
13
+ showDrillDown: false;
14
+ onSelect: import('storybook/actions').HandlerFunction;
15
+ onDrillDown: import('storybook/actions').HandlerFunction;
16
+ };
17
+ decorators: ((Story: import('storybook/internal/csf').PartialStoryFn<import('@storybook/react').ReactRenderer, {
18
+ id: string;
19
+ displayName: string;
20
+ isSearchMode?: boolean | undefined;
21
+ selectable: boolean;
22
+ multiSelect: boolean;
23
+ isSelected: boolean;
24
+ showDrillDown: boolean;
25
+ ancestors?: import('../types').TaxonomyAncestor[] | undefined;
26
+ onSelect: (id: string, closeAfterSelect?: boolean) => void;
27
+ onDrillDown?: ((id: string) => void) | undefined;
28
+ onFocusExit?: (() => void) | undefined;
29
+ }>) => import("react/jsx-runtime").JSX.Element)[];
30
+ parameters: {
31
+ docs: {
32
+ description: {
33
+ component: string;
34
+ };
35
+ };
36
+ viewport: {
37
+ defaultViewport: string;
38
+ };
39
+ layout: string;
40
+ };
41
+ };
42
+ export default _default;
43
+ type Story = StoryObj<typeof TaxonomyMenuItem>;
44
+ /** Radio selection control, unselected. */
45
+ export declare const RadioUnselected: Story;
46
+ /** Radio selection control, selected. */
47
+ export declare const RadioSelected: Story;
48
+ /** Checkbox selection control, unselected (multi-select mode). */
49
+ export declare const CheckboxUnselected: Story;
50
+ /** Checkbox selection control, selected (multi-select mode). */
51
+ export declare const CheckboxSelected: Story;
52
+ /** Non-selectable item rendered as a plain label — no radio or checkbox. */
53
+ export declare const NonSelectablePlainLabel: Story;
54
+ /** Radio item with drill-down chevron for navigating into child levels. */
55
+ export declare const WithDrillDownChevron: Story;
56
+ /** Non-selectable item with drill-down chevron — acts as a navigation-only row. */
57
+ export declare const NonSelectableWithDrillDown: Story;
58
+ /** Item with a single ancestor in the breadcrumb subtitle. */
59
+ export declare const WithSingleAncestor: Story;
60
+ /** Item with multiple ancestors forming a breadcrumb path (Region > Country > State). */
61
+ export declare const WithMultipleAncestors: Story;
62
+ /** Checkbox item with ancestors and drill-down chevron — full combined variant. */
63
+ export declare const CheckboxWithAncestorsAndDrillDown: Story;
64
+ /** Selected radio with ancestors and drill-down — the other full combined variant. */
65
+ export declare const RadioWithAncestorsAndDrillDown: Story;
66
+ /** Long display name and long ancestor path — verifies text truncation. */
67
+ export declare const LongTextTruncation: Story;
@@ -0,0 +1,78 @@
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { MetadataTaxonomyPicker } from '../../../index';
3
+ import { MetadataTaxonomyPickerProps, TaxonomyPickerMode, TaxonomyValue } from '../../types';
4
+ declare const _default: {
5
+ parameters: {
6
+ docs: {
7
+ page: () => import("react/jsx-runtime").JSX.Element;
8
+ };
9
+ controls: {
10
+ exclude: RegExp;
11
+ };
12
+ };
13
+ title: string;
14
+ component: import('react').ForwardRefExoticComponent<MetadataTaxonomyPickerProps & import('react').RefAttributes<HTMLInputElement>>;
15
+ decorators: ((Story: import('storybook/internal/csf').PartialStoryFn<import('@storybook/react').ReactRenderer, {
16
+ mode: TaxonomyPickerMode;
17
+ multiSelect: boolean;
18
+ value: TaxonomyValue[];
19
+ onValueChange: (values: TaxonomyValue[]) => void;
20
+ itemsService: import('../../types').TaxonomyItemsService;
21
+ eventService?: import('../../types').TaxonomyPickerEventService | undefined;
22
+ levels?: import('../../types').TaxonomyLevel[] | undefined;
23
+ placeholder?: string | undefined;
24
+ disabled?: boolean | undefined;
25
+ label?: string | undefined;
26
+ containerClassName?: string | undefined;
27
+ portalElement?: (HTMLElement | (() => HTMLElement | null) | null) | undefined;
28
+ ref?: import('react').LegacyRef<HTMLInputElement> | undefined;
29
+ key?: import('react').Key | null | undefined;
30
+ }>) => import("react/jsx-runtime").JSX.Element)[];
31
+ };
32
+ export default _default;
33
+ type Story = StoryObj<typeof MetadataTaxonomyPicker>;
34
+ /**
35
+ * At the root level the breadcrumb is intentionally absent — there is nowhere
36
+ * to navigate "back" to. The popover shows only the items list.
37
+ */
38
+ export declare const HidesBreadcrumbAtRootLevel: Story;
39
+ /**
40
+ * After drilling into a child level the breadcrumb appears inside the popover
41
+ * and the current page (the level the user is browsing) is shown as the
42
+ * trailing, non-interactive crumb.
43
+ */
44
+ export declare const RendersBreadcrumbAfterDrillDown: Story;
45
+ /**
46
+ * Drilling deeper appends the new level to the breadcrumb trail and the
47
+ * previously-current crumb becomes a clickable button.
48
+ */
49
+ export declare const AppendsCrumbsAsTheUserDrillsDeeper: Story;
50
+ /**
51
+ * Clicking an ancestor crumb navigates the picker back to that level and the
52
+ * children of the chosen ancestor reappear in the items list.
53
+ */
54
+ export declare const NavigatesBackToAncestorWhenCrumbClicked: Story;
55
+ /**
56
+ * Clicking the synthetic root crumb ("All") returns the picker to the
57
+ * top-level list and removes the breadcrumb entirely.
58
+ */
59
+ export declare const NavigatesBackToRootWhenRootCrumbClicked: Story;
60
+ /**
61
+ * Eight-level drill-down. The current page reflects the deepest level the user
62
+ * navigated into, and the synthetic root crumb is still reachable through the
63
+ * folder-tree dropdown (the trail is too long to render every crumb inline).
64
+ */
65
+ export declare const NavigatesThroughEightLevelsAndReportsCurrentPage: Story;
66
+ /**
67
+ * From a deep level the user can jump straight back to any ancestor in a single
68
+ * click — even when that ancestor lives inside the folder-tree truncation
69
+ * dropdown. The trail trims to that ancestor and its children reappear in the
70
+ * list.
71
+ */
72
+ export declare const JumpsToMidTrailAncestorFromDeepLevel: Story;
73
+ /**
74
+ * In a narrow popover with long display names, the folder-tree truncation
75
+ * collapses older ancestors into a dropdown that the user can open to surface
76
+ * the hidden ancestors.
77
+ */
78
+ export declare const FolderTreeTruncationExposesHiddenAncestors: Story;
@@ -0,0 +1,50 @@
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { MetadataTaxonomyPicker } from '../../../index';
3
+ declare const _default: {
4
+ parameters: {
5
+ docs: {
6
+ page: () => import("react/jsx-runtime").JSX.Element;
7
+ };
8
+ controls: {
9
+ exclude: RegExp;
10
+ };
11
+ };
12
+ title: string;
13
+ component: import('react').ForwardRefExoticComponent<import('../../types').MetadataTaxonomyPickerProps & import('react').RefAttributes<HTMLInputElement>>;
14
+ };
15
+ export default _default;
16
+ type Story = StoryObj<typeof MetadataTaxonomyPicker>;
17
+ /**
18
+ * Acceptance: clicking retry on the initial load error calls `actions.retry()`,
19
+ * which re-runs `initialLoad`. The full-area error is replaced by the items
20
+ * once the retry succeeds.
21
+ */
22
+ export declare const InitialLoadErrorRecoversOnRetry: Story;
23
+ /**
24
+ * Acceptance: load-more error displays as an inline row at the bottom of the
25
+ * existing list, already-loaded items remain visible, and clicking retry
26
+ * re-attempts from the current marker.
27
+ */
28
+ export declare const BrowseLoadMoreErrorRecoversOnRetry: Story;
29
+ /**
30
+ * Acceptance: search error fills the search results area with a retry button,
31
+ * and clicking retry re-runs the last committed query.
32
+ */
33
+ export declare const SearchErrorRecoversOnRetry: Story;
34
+ /**
35
+ * Acceptance: search load-more error shows an inline error row at the bottom
36
+ * of the search results, already-loaded results remain visible, and clicking
37
+ * retry re-attempts from the current marker.
38
+ */
39
+ export declare const SearchLoadMoreErrorRecoversOnRetry: Story;
40
+ /**
41
+ * Acceptance: `lastFailedOp` is set on each error action and cleared on the
42
+ * corresponding success — so retry is always unambiguous, even if the user
43
+ * has changed the search input between the failure and the retry click.
44
+ *
45
+ * Scenario: initial browse load fails → user types into the search input
46
+ * (committing a search) → user clears the search → user clicks retry. The
47
+ * retry must re-run the initial browse load (the only operation still in
48
+ * the failed state) and not get confused by the intermediate search.
49
+ */
50
+ export declare const RetryRemainsUnambiguousAcrossStateDrift: Story;
@@ -0,0 +1,47 @@
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { MetadataTaxonomyPicker } from '../../../index';
3
+ import { MetadataTaxonomyPickerProps, TaxonomyPickerMode, TaxonomyValue } from '../../types';
4
+ declare const _default: {
5
+ parameters: {
6
+ docs: {
7
+ page: () => import("react/jsx-runtime").JSX.Element;
8
+ };
9
+ controls: {
10
+ exclude: RegExp;
11
+ };
12
+ };
13
+ title: string;
14
+ component: import('react').ForwardRefExoticComponent<MetadataTaxonomyPickerProps & import('react').RefAttributes<HTMLInputElement>>;
15
+ decorators: ((Story: import('storybook/internal/csf').PartialStoryFn<import('@storybook/react').ReactRenderer, {
16
+ mode: TaxonomyPickerMode;
17
+ multiSelect: boolean;
18
+ value: TaxonomyValue[];
19
+ onValueChange: (values: TaxonomyValue[]) => void;
20
+ itemsService: import('../../types').TaxonomyItemsService;
21
+ eventService?: import('../../types').TaxonomyPickerEventService | undefined;
22
+ levels?: import('../../types').TaxonomyLevel[] | undefined;
23
+ placeholder?: string | undefined;
24
+ disabled?: boolean | undefined;
25
+ label?: string | undefined;
26
+ containerClassName?: string | undefined;
27
+ portalElement?: (HTMLElement | (() => HTMLElement | null) | null) | undefined;
28
+ ref?: import('react').LegacyRef<HTMLInputElement> | undefined;
29
+ key?: import('react').Key | null | undefined;
30
+ }>) => import("react/jsx-runtime").JSX.Element)[];
31
+ };
32
+ export default _default;
33
+ type Story = StoryObj<typeof MetadataTaxonomyPicker>;
34
+ export declare const OpensPopoverOnClick: Story;
35
+ export declare const ClosesOnEscape: Story;
36
+ export declare const ClosesOnClickOutside: Story;
37
+ export declare const ShowsSkeletonWhileLoading: Story;
38
+ export declare const ShowsEmptyStateWhenNoData: Story;
39
+ export declare const SingleSelectPicksItemAndClosesPopover: Story;
40
+ export declare const MultiSelectTogglesItemsWithoutClosingPopover: Story;
41
+ export declare const SingleSelectArrowNavigationKeepsPopoverOpen: Story;
42
+ export declare const MultiSelectDeselectsAlreadySelectedItem: Story;
43
+ export declare const NonSelectableItemRendersWithoutSelectionControl: Story;
44
+ export declare const DrillsDownMultipleLevels: Story;
45
+ export declare const DrillDownShowsLoadingSkeleton: Story;
46
+ export declare const RightArrowAndSpacebarKeyboardDrillDown: Story;
47
+ export declare const ChipDismiss: Story;
@@ -0,0 +1,99 @@
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { MetadataTaxonomyPickerProps, TaxonomyLevel, TaxonomyPickerMode, TaxonomyValue } from '../../types';
3
+ interface ControlledPickerProps extends Omit<MetadataTaxonomyPickerProps, 'value' | 'onValueChange'> {
4
+ initialValue?: TaxonomyValue[];
5
+ }
6
+ declare function ControlledPicker({ initialValue, ...props }: ControlledPickerProps): import("react/jsx-runtime").JSX.Element;
7
+ declare const _default: {
8
+ parameters: {
9
+ docs: {
10
+ page: () => import("react/jsx-runtime").JSX.Element;
11
+ };
12
+ controls: {
13
+ exclude: RegExp;
14
+ };
15
+ };
16
+ title: string;
17
+ component: import('react').ForwardRefExoticComponent<MetadataTaxonomyPickerProps & import('react').RefAttributes<HTMLInputElement>>;
18
+ render: (args: MetadataTaxonomyPickerProps & import('react').RefAttributes<HTMLInputElement>) => import("react/jsx-runtime").JSX.Element;
19
+ args: {
20
+ itemsService: import('../../types').TaxonomyItemsService;
21
+ levels: TaxonomyLevel[];
22
+ mode: TaxonomyPickerMode.MultiLevel;
23
+ multiSelect: false;
24
+ placeholder: string;
25
+ };
26
+ decorators: ((Story: import('storybook/internal/csf').PartialStoryFn<import('@storybook/react').ReactRenderer, {
27
+ mode: TaxonomyPickerMode;
28
+ multiSelect: boolean;
29
+ value: TaxonomyValue[];
30
+ onValueChange: (values: TaxonomyValue[]) => void;
31
+ itemsService: import('../../types').TaxonomyItemsService;
32
+ eventService?: import('../../types').TaxonomyPickerEventService | undefined;
33
+ levels?: TaxonomyLevel[] | undefined;
34
+ placeholder?: string | undefined;
35
+ disabled?: boolean | undefined;
36
+ label?: string | undefined;
37
+ containerClassName?: string | undefined;
38
+ portalElement?: (HTMLElement | (() => HTMLElement | null) | null) | undefined;
39
+ ref?: import('react').LegacyRef<HTMLInputElement> | undefined;
40
+ key?: import('react').Key | null | undefined;
41
+ }>) => import("react/jsx-runtime").JSX.Element)[];
42
+ };
43
+ export default _default;
44
+ type Story = StoryObj<typeof ControlledPicker>;
45
+ /**
46
+ * The level filter only appears once the user starts typing — it is invisible
47
+ * in browse mode.
48
+ */
49
+ export declare const LevelFilterHiddenInBrowseMode: Story;
50
+ /**
51
+ * Once any character is typed the level filter becomes visible, even before
52
+ * the debounced search request completes.
53
+ */
54
+ export declare const LevelFilterAppearsImmediatelyOnFirstKeystroke: Story;
55
+ /**
56
+ * Taxonomies with only one level do not display the level filter — there is
57
+ * nothing meaningful to filter by.
58
+ */
59
+ export declare const LevelFilterHiddenForSingleLevelTaxonomy: Story;
60
+ /**
61
+ * When the search input is cleared, the picker returns to browse mode and the
62
+ * level filter disappears.
63
+ */
64
+ export declare const LevelFilterHiddenAfterClearingSearch: Story;
65
+ /**
66
+ * When the user starts typing from the root level (no drill-down), the filter
67
+ * defaults to "All levels" — no level is pre-selected.
68
+ */
69
+ export declare const LevelFilterDefaultsToAllLevelsAtRoot: Story;
70
+ /**
71
+ * When the user is one level deep (drilled into a Region) and then types,
72
+ * the filter automatically pre-selects the child level ("Country").
73
+ */
74
+ export declare const LevelFilterAutoSelectsChildLevelAfterDrillDown: Story;
75
+ /**
76
+ * The dropdown lists "All levels" first, then a separator, then one item per
77
+ * available taxonomy level.
78
+ */
79
+ export declare const LevelFilterDropdownListsAllLevels: Story;
80
+ /**
81
+ * Selecting a level from the dropdown re-runs the search restricted to that
82
+ * level, so only matching nodes from that level appear.
83
+ */
84
+ export declare const SelectingALevelFiltersSearchResults: Story;
85
+ /**
86
+ * After selecting a level, the trigger button updates its label to reflect the
87
+ * active filter.
88
+ */
89
+ export declare const LevelFilterTriggerReflectsActiveSelection: Story;
90
+ /**
91
+ * With no `levels`, the filter dropdown is hidden and a drill-down search
92
+ * must not silently apply a synthetic filter — results span every level.
93
+ */
94
+ export declare const SearchAfterDrillDownWithNoAvailableLevelsIsUnfiltered: Story;
95
+ /**
96
+ * Selecting "All levels" removes the level restriction, causing results from
97
+ * every level to appear again.
98
+ */
99
+ export declare const SelectingAllLevelsRemovesFilter: Story;
@@ -0,0 +1,60 @@
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { TaxonomyItemsService } from '../../types';
3
+ declare function LevelTransitionsHarness({ itemsService }: {
4
+ itemsService: TaxonomyItemsService;
5
+ }): import("react/jsx-runtime").JSX.Element;
6
+ declare const _default: {
7
+ parameters: {
8
+ docs: {
9
+ page: () => import("react/jsx-runtime").JSX.Element;
10
+ };
11
+ controls: {
12
+ exclude: RegExp;
13
+ };
14
+ };
15
+ title: string;
16
+ component: typeof LevelTransitionsHarness;
17
+ decorators: ((Story: import('storybook/internal/csf').PartialStoryFn<import('@storybook/react').ReactRenderer, {
18
+ itemsService: TaxonomyItemsService;
19
+ }>) => import("react/jsx-runtime").JSX.Element)[];
20
+ };
21
+ export default _default;
22
+ type Story = StoryObj<typeof LevelTransitionsHarness>;
23
+ /**
24
+ * Cache-hit path: after drilling into a level whose parent level was previously
25
+ * fetched, navigating back rehydrates from cache without issuing a new request.
26
+ */
27
+ export declare const NavigatesBackFromCacheWithoutRefetch: Story;
28
+ /**
29
+ * Cache-miss path: when the user lands on a deep level via a search result
30
+ * (whose ancestor level was never browsed), navigating back to that ancestor
31
+ * has no cached snapshot to seed from. The reducer transitions the level via
32
+ * `transitionToLevel` (clears items, shows the skeleton), and the controller
33
+ * issues a fresh `getNodes(region-a)` request.
34
+ */
35
+ export declare const NavigatesBackWithRefetchWhenCacheMisses: Story;
36
+ /**
37
+ * Reset-on-close: closing the popover wipes the per-level cache and reducer
38
+ * state, so the next open re-fetches the root.
39
+ */
40
+ export declare const ResetsStateOnCloseAndRefetchesRootOnReopen: Story;
41
+ /**
42
+ * Stale-response guard: drilling into one level and then immediately drilling
43
+ * into a different level must show the second level's data even though the
44
+ * first level's response resolves first (with the longer delay it would
45
+ * otherwise overwrite it).
46
+ */
47
+ export declare const DropsStaleFetchResponseAfterRapidDrillDown: Story;
48
+ /**
49
+ * Happy-path error reporting: when the network request for the current level
50
+ * fails, the reducer surfaces the message via `initialLoadError`, stops the
51
+ * fetching spinner, and tags the last failed op as `browse` so retry UI can
52
+ * target the right operation.
53
+ */
54
+ export declare const SurfacesFetchErrorForCurrentLevel: Story;
55
+ /**
56
+ * Stale-response guard for errors: drilling into a slow-failing level and
57
+ * immediately navigating back must NOT pollute the root level with the late
58
+ * Region A error. The reducer's `forParentId` guard drops the stale failure.
59
+ */
60
+ export declare const DropsStaleFetchErrorAfterRapidNavigateBack: Story;