@box/metadata-taxonomy-picker 2.18.1 → 2.18.3

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 (19) hide show
  1. package/dist/chunks/metadata-taxonomy-picker-shell.js +11 -11
  2. package/dist/chunks/taxonomy-menu-item.js +6 -6
  3. package/dist/esm/lib/state/reducer.js +6 -1
  4. package/dist/styles/metadata-taxonomy-picker-shell.css +1 -1
  5. package/dist/styles/taxonomy-menu-item.css +1 -1
  6. package/dist/types/index.d.ts +1 -2
  7. package/dist/types/lib/metadata-taxonomy-picker.d.ts +0 -1
  8. package/dist/types/lib/stories/metadata-taxonomy-picker.stories.d.ts +5 -69
  9. package/dist/types/lib/stories/shared/generate-nodes.d.ts +12 -1
  10. package/dist/types/lib/stories/shared/metadata-taxonomy-picker-fixtures.d.ts +12 -0
  11. package/dist/types/lib/stories/tests/{breadcrumb-navigation.interaction-tests.stories.d.ts → navigation.interaction-tests.stories.d.ts} +51 -2
  12. package/dist/types/lib/stories/tests/{shell-selection.interaction-tests.stories.d.ts → selection.interaction-tests.stories.d.ts} +11 -0
  13. package/dist/types/lib/stories/tests/taxonomy-menu-item.interaction-tests.stories.d.ts +0 -5
  14. package/dist/types/lib/stories/tests/visual-regression-tests.stories.d.ts +8 -0
  15. package/package.json +6 -6
  16. package/dist/types/lib/stories/tests/interaction-tests.stories.d.ts +0 -47
  17. package/dist/types/lib/stories/tests/level-transitions.interaction-tests.stories.d.ts +0 -60
  18. /package/dist/types/lib/stories/tests/{level-filter-interaction-tests.stories.d.ts → level-filter.interaction-tests.stories.d.ts} +0 -0
  19. /package/dist/types/lib/stories/tests/{search-interaction-tests.stories.d.ts → search.interaction-tests.stories.d.ts} +0 -0
@@ -12,16 +12,16 @@ import { jsx as f, jsxs as p } from "react/jsx-runtime";
12
12
  import '../styles/metadata-taxonomy-picker-shell.css';var m = /* @__PURE__ */ function(e) {
13
13
  return e.SingleLevel = "single-level", e.MultiLevel = "multi-level", e;
14
14
  }({}), h = {
15
- container: "_container_1uu1w_1",
16
- label: "_label_1uu1w_8",
17
- trigger: "_trigger_1uu1w_16",
18
- searchInput: "_searchInput_1uu1w_34",
19
- chips: "_chips_1uu1w_47",
20
- searchIcon: "_searchIcon_1uu1w_73",
21
- emptyState: "_emptyState_1uu1w_81",
22
- popover: "_popover_1uu1w_87",
23
- clearButton: "_clearButton_1uu1w_92",
24
- breadcrumbContainer: "_breadcrumbContainer_1uu1w_96"
15
+ container: "_container_bnccr_1",
16
+ label: "_label_bnccr_8",
17
+ trigger: "_trigger_bnccr_16",
18
+ searchInput: "_searchInput_bnccr_34",
19
+ chips: "_chips_bnccr_47",
20
+ searchIcon: "_searchIcon_bnccr_73",
21
+ emptyState: "_emptyState_bnccr_81",
22
+ popover: "_popover_bnccr_87",
23
+ clearButton: "_clearButton_bnccr_92",
24
+ breadcrumbContainer: "_breadcrumbContainer_bnccr_96"
25
25
  };
26
26
  function de(e) {
27
27
  let t = null;
@@ -30,7 +30,7 @@ function de(e) {
30
30
  }
31
31
  var fe = [];
32
32
  function pe(e) {
33
- if (e != null) return typeof e == "function" ? e() : e;
33
+ if (e != null) return (typeof e == "function" ? e() : e) ?? void 0;
34
34
  }
35
35
  var g = /* @__PURE__ */ a(function({ itemsService: a, eventService: g, levels: _ = fe, mode: me, multiSelect: v, value: y, onValueChange: b, placeholder: he, disabled: x = !1, label: S, containerClassName: ge, portalElement: _e }, ve) {
36
36
  let { formatMessage: C } = ue(), w = te(), T = `${w}-listbox`, E = l(null), ye = oe(E, ve), D = l(null), O = l(null), k = l(0), A = l(!1), be = pe(_e), j = me === m.SingleLevel, { state: M, isOpen: N, handleOpenChange: P, handleInputValueChange: F, actions: I } = t(a, _, g), { items: L, levelStack: R } = M, { drillDown: z, navigateBack: B, loadMore: xe, setSearchScopeOverride: V } = I, H = M.searchInputValue !== "", U = c(() => de(M.availableLevels), [M.availableLevels]);
@@ -9,12 +9,12 @@ import { jsx as f, jsxs as p } from "react/jsx-runtime";
9
9
  import { CompositeItem as m } from "@ariakit/react";
10
10
  import { ChevronRight as h } from "@box/blueprint-web-assets/icons/Medium";
11
11
  import '../styles/taxonomy-menu-item.css';var g = {
12
- row: "_row_1y44c_2",
13
- rowWithAncestors: "_rowWithAncestors_1y44c_19",
14
- nonSelectable: "_nonSelectable_1y44c_24",
15
- selectionControl: "_selectionControl_1y44c_31",
16
- content: "_content_1y44c_41",
17
- drillDown: "_drillDown_1y44c_48"
12
+ row: "_row_1a4ve_2",
13
+ rowWithAncestors: "_rowWithAncestors_1a4ve_19",
14
+ nonSelectable: "_nonSelectable_1a4ve_24",
15
+ selectionControl: "_selectionControl_1a4ve_31",
16
+ content: "_content_1a4ve_41",
17
+ drillDown: "_drillDown_1a4ve_48"
18
18
  }, _ = /* @__PURE__ */ r(function({ id: r, displayName: _, isSearchMode: v = !1, selectable: y, multiSelect: b, isSelected: x, showDrillDown: S, ancestors: C, onSelect: w, onDrillDown: T, onFocusExit: E }) {
19
19
  let { formatMessage: D } = d(), O = C != null && C.length > 0 && v, k = a(null), A = a(null), j = a(null), { handleSelectionControlFocus: M, handleRowKeyDown: N, handleRowKeyDownCapture: P, handleSelectionControlKeyDown: F, handleDrillDownKeyDown: I } = n({
20
20
  id: r,
@@ -102,14 +102,19 @@ function i(i, a) {
102
102
  searchInputValue: a.value,
103
103
  levelFilter: a.value === "" ? null : e,
104
104
  availableLevels: [...a.availableLevels],
105
- isFetchingSearch: a.value !== ""
105
+ isFetchingSearch: a.value !== "",
106
+ isFetchingSearchMore: !1,
107
+ searchLoadMoreError: null,
108
+ lastFailedOp: i.lastFailedOp === t.SearchMore ? null : i.lastFailedOp
106
109
  };
107
110
  }
108
111
  case n.SearchFetchStart: return {
109
112
  ...i,
110
113
  isFetchingSearch: !0,
114
+ isFetchingSearchMore: !1,
111
115
  searchError: null,
112
116
  searchLoadMoreError: null,
117
+ searchNextMarker: void 0,
113
118
  searchQuery: a.query,
114
119
  lastFailedOp: i.lastFailedOp === t.Search || i.lastFailedOp === t.SearchMore ? null : i.lastFailedOp
115
120
  };
@@ -1 +1 @@
1
- ._container_1uu1w_1{gap:var(--bp-space-020,.5rem);flex-direction:column;width:100%;display:flex}._label_1uu1w_8{color:var(--bp-text-text-on-light);font-size:var(--bp-font-size-040,1rem);font-weight:var(--bp-font-weight-bold,600);line-height:var(--bp-line-height-040,1.5rem);cursor:pointer}._trigger_1uu1w_16{box-sizing:border-box;align-items:center;gap:var(--space-2);width:100%;min-height:var(--bp-size-090,2.25rem);padding-block:var(--bp-space-020,.5rem);padding-inline:var(--bp-space-030,.75rem);color:var(--bp-text-text-on-light);background-color:var(--surface-dropdown-surface);border:var(--bp-border-01,.0625rem) solid var(--bp-border-input-border);border-radius:var(--bp-radius-06,.75rem);font:inherit;cursor:pointer;outline:none;flex-wrap:wrap;display:flex}._trigger_1uu1w_16:has(._searchInput_1uu1w_34:focus){background-color:var(--surface-dropdown-surface-focus);border-color:var(--outline-focus-on-light);border-width:var(--bp-border-02,.125rem)}._trigger_1uu1w_16[data-disabled=true]{opacity:.6;cursor:not-allowed}._trigger_1uu1w_16[data-disabled=true] button{pointer-events:none}._chips_1uu1w_47{gap:var(--space-2);flex-wrap:wrap;display:flex}._trigger_1uu1w_16[data-disabled=true] ._chips_1uu1w_47{pointer-events:none}._searchInput_1uu1w_34{min-width:var(--size-12);color:var(--bp-text-text-on-light);font:inherit;cursor:inherit;background:0 0;border:none;outline:none;flex:1;padding:0}._searchInput_1uu1w_34::placeholder{color:var(--bp-text-text-on-light-secondary);font-size:var(--bp-font-size-05,.9375rem);font-weight:var(--bp-font-weight-regular,400)}._searchIcon_1uu1w_73{width:var(--bp-size-040,1rem);height:var(--bp-size-040,1rem);color:var(--bp-icon-icon-on-light-secondary);pointer-events:none;flex-shrink:0}._emptyState_1uu1w_81{padding-block:var(--space-3);padding-inline:var(--space-3);text-align:center}._popover_1uu1w_87{width:var(--radix-popover-trigger-width);max-width:none}._clearButton_1uu1w_92{flex-shrink:0}._breadcrumbContainer_1uu1w_96{min-width:0;padding-block:var(--bp-space-020,.5rem);padding-inline:var(--bp-space-020,.5rem);border-bottom:var(--bp-border-01,.0625rem) solid var(--bp-border-divider);align-items:center;display:flex}
1
+ ._container_bnccr_1{gap:var(--bp-space-020,.5rem);flex-direction:column;width:100%;display:flex}._label_bnccr_8{color:var(--bp-text-text-on-light);font-size:var(--bp-font-size-040,1rem);font-weight:var(--bp-font-weight-bold,600);line-height:var(--bp-line-height-040,1.5rem);cursor:pointer}._trigger_bnccr_16{box-sizing:border-box;align-items:center;gap:var(--space-2);width:100%;min-height:var(--bp-size-090,2.25rem);padding-block:var(--bp-space-020,.5rem);padding-inline:var(--bp-space-030,.75rem);color:var(--bp-text-text-on-light);background-color:var(--surface-dropdown-surface);border:var(--bp-border-01,.0625rem) solid var(--bp-border-input-border);border-radius:var(--bp-radius-06,.75rem);font:inherit;cursor:pointer;outline:none;flex-wrap:wrap;display:flex}._trigger_bnccr_16:has(._searchInput_bnccr_34:focus){background-color:var(--surface-dropdown-surface-focus);border-color:var(--outline-focus-on-light);border-width:var(--bp-border-02,.125rem)}._trigger_bnccr_16[data-disabled=true]{opacity:.6;cursor:not-allowed}._trigger_bnccr_16[data-disabled=true] button{pointer-events:none}._chips_bnccr_47{gap:var(--space-2);flex-wrap:wrap;display:flex}._trigger_bnccr_16[data-disabled=true] ._chips_bnccr_47{pointer-events:none}._searchInput_bnccr_34{min-width:var(--size-12);color:var(--bp-text-text-on-light);font:inherit;cursor:inherit;background:0 0;border:none;outline:none;flex:1;padding:0}._searchInput_bnccr_34::placeholder{color:var(--bp-text-text-on-light-secondary);font-size:var(--bp-font-size-05,.9375rem);font-weight:var(--bp-font-weight-regular,400)}._searchIcon_bnccr_73{width:var(--bp-size-040,1rem);height:var(--bp-size-040,1rem);color:var(--bp-icon-icon-on-light-secondary);pointer-events:none;flex-shrink:0}._emptyState_bnccr_81{padding-block:var(--space-3);padding-inline:var(--space-3);text-align:center}._popover_bnccr_87{width:var(--radix-popover-trigger-width);max-width:none}._clearButton_bnccr_92{flex-shrink:0}._breadcrumbContainer_bnccr_96{min-width:0;padding-block:var(--bp-space-020,.5rem);padding-inline:var(--bp-space-020,.5rem);border-bottom:var(--bp-border-01,.0625rem) solid var(--bp-border-divider);align-items:center;display:flex}._breadcrumbContainer_bnccr_96 li:first-child:has(button){margin-inline-start:calc(-1 * var(--bp-space-010,.25rem))}
@@ -1 +1 @@
1
- ._row_1y44c_2{box-sizing:border-box;align-items:center;gap:var(--bp-space-030,.75rem);height:var(--bp-size-090,2.25rem);padding:0 var(--bp-space-020,.5rem);border-radius:var(--bp-radius-04,.5rem);cursor:pointer;border:var(--bp-border-01) transparent;background:0 0;display:flex;overflow:visible}._row_1y44c_2:hover{background-color:var(--surface-menu-surface-hover)}._rowWithAncestors_1y44c_19{height:auto;padding:var(--bp-space-010,.25rem) var(--bp-space-020,.5rem)}._nonSelectable_1y44c_24{cursor:default}._selectionControl_1y44c_31{width:var(--bp-size-040,1rem);height:var(--bp-size-040,1rem);flex-shrink:0;overflow:visible}._selectionControl_1y44c_31 button{margin-top:0}._content_1y44c_41{flex-direction:column;flex:1;min-width:0;display:flex}._drillDown_1y44c_48{flex-shrink:0}
1
+ ._row_1a4ve_2{box-sizing:border-box;align-items:center;gap:var(--bp-space-030,.75rem);height:var(--bp-size-090,2.25rem);padding:0 var(--bp-space-020,.5rem);border-radius:var(--bp-radius-04,.5rem);cursor:pointer;border:var(--bp-border-01) transparent;background:0 0;display:flex;overflow:visible}._row_1a4ve_2:hover{background-color:var(--surface-menu-surface-hover)}._rowWithAncestors_1a4ve_19{height:auto;padding:var(--bp-space-010,.25rem) var(--bp-space-020,.5rem)}._nonSelectable_1a4ve_24{cursor:default}._selectionControl_1a4ve_31{width:var(--bp-size-040,1rem);height:var(--bp-size-040,1rem);flex-shrink:0;overflow:visible}._selectionControl_1a4ve_31 label{margin-top:-2px}._content_1a4ve_41{flex-direction:column;flex:1;min-width:0;display:flex}._drillDown_1a4ve_48{flex-shrink:0}
@@ -1,4 +1,3 @@
1
1
  export { MetadataTaxonomyPicker } from './lib/metadata-taxonomy-picker';
2
- export type { MetadataTaxonomyPickerProps } from './lib/metadata-taxonomy-picker';
3
2
  export { TaxonomyPickerMode } from './lib/types';
4
- export type { BreadcrumbEntry, FetchParams, FetchResponse, SearchParams, TaxonomyAncestor, TaxonomyItemsService, TaxonomyLevel, TaxonomyNode, TaxonomyPickerEventService, TaxonomySearchResult, TaxonomyValue, } from './lib/types';
3
+ export type { BreadcrumbEntry, FetchParams, FetchResponse, MetadataTaxonomyPickerProps, SearchParams, TaxonomyAncestor, TaxonomyItemsService, TaxonomyLevel, TaxonomyNode, TaxonomyPickerEventService, TaxonomySearchResult, TaxonomyValue, } from './lib/types';
@@ -1,5 +1,4 @@
1
1
  import { MetadataTaxonomyPickerProps } from './types';
2
- export type { MetadataTaxonomyPickerProps } from './types';
3
2
  /**
4
3
  * Forwards the ref to the picker's trigger input so consumers can manage
5
4
  * focus or other imperative interactions on the input element directly.
@@ -32,93 +32,35 @@ declare const _default: {
32
32
  };
33
33
  export default _default;
34
34
  type Story = StoryObj<typeof MetadataTaxonomyPicker>;
35
- /** The popover shows the initial data when the initial fetch is successful. */
36
- export declare const InitialData: Story;
37
- /**
38
- * The popover shows a skeleton loading state while the initial fetch is in progress.
39
- */
40
- export declare const LoadingState: Story;
41
- /**
42
- * The popover shows an empty state when there is no data after loading completes.
43
- */
44
- export declare const EmptyState: Story;
35
+ /** Main picker showcase: all four mode permutations plus empty and error/retry. */
36
+ export declare const Default: Story;
45
37
  /** 1 000 items rendered in a virtualized list — validates performance at scale. */
46
38
  export declare const LargeDataset: Story;
47
- /** 1 000 items in multi-select mode — checkboxes with large dataset. */
48
- export declare const LargeDatasetMultiSelect: Story;
49
- /** Error state — the fetch fails and a retry button is shown. */
50
- export declare const ErrorState: Story;
51
- /**
52
- * Disabled state — the trigger cannot be interacted with.
53
- */
54
- export declare const Disabled: Story;
55
- /**
56
- * No selection — only the placeholder text is visible inside the trigger.
57
- */
58
- export declare const NoSelection: Story;
59
- /**
60
- * A single chip is shown inside the trigger when one value is selected.
61
- */
62
- export declare const SingleChip: Story;
63
- /**
64
- * Multiple chips are shown when several values are selected.
65
- */
66
- export declare const MultipleChips: Story;
67
- /**
68
- * When many values are selected the chips wrap across multiple lines inside the trigger.
69
- */
70
- export declare const OverflowChips: Story;
71
- /** Click a row's chevron (or press Right Arrow on a focused row) to drill in. */
72
- export declare const DrillDownNavigation: Story;
73
- /**
74
- * Eight-level hierarchy (Region → Block) with four siblings per level. Drill all
75
- * the way down to see the Blueprint Breadcrumb collapse the older ancestors into
76
- * the folder-tree dropdown while keeping the last few levels and the current
77
- * page visible.
78
- */
79
- export declare const DeepDrillDownNavigation: Story;
80
39
  /**
81
40
  * Six-level hierarchy with intentionally long display names, rendered in a
82
41
  * narrow popover. Forces the folder-tree truncation to engage early so the
83
42
  * breadcrumb dropdown trigger is visible even mid-way through the trail.
84
43
  */
85
- export declare const DeepDrillDownNavigationWithLongLabels: Story;
44
+ export declare const BreadcrumbOverflow: Story;
86
45
  /**
87
46
  * Picker with real search filtering: typing a substring shows all matching
88
47
  * nodes with their ancestor breadcrumbs. Try `region`, `country`, `state`, or
89
48
  * `01` to see results across all levels. Use the level filter dropdown to
90
49
  * restrict results to a specific level.
91
50
  */
92
- export declare const WithSearch: Story;
93
- /**
94
- * Disabled state with selected values — chips are visible but not interactive (no dismiss button).
95
- */
96
- export declare const DisabledWithChips: Story;
51
+ export declare const SearchAndLevelFilter: Story;
97
52
  /**
98
53
  * Cursor-paginated browse list (450 items, page size 100). Scroll near the bottom
99
54
  * to auto-fetch the next page: ghost rows appear while the request is in flight
100
55
  * and new rows append below the already-loaded ones, preserving scroll position.
101
56
  */
102
57
  export declare const Pagination: Story;
103
- /**
104
- * Pagination + drill-down: scroll through several pages at the root, drill into
105
- * a node, then navigate back. All pages loaded before drilling down are restored
106
- * from cache, so the user lands back at the same scroll-loaded state without
107
- * having to re-scroll or re-fetch.
108
- */
109
- export declare const PaginationWithDrillDownCacheRestore: Story;
110
- /** Multi-level × multi-select: drill down at every level, pick many values across levels. */
111
- export declare const MultiLevelMultiSelect: Story;
112
- /** Multi-level × single-select: drill down, pick one value; popover closes on selection. */
113
- export declare const MultiLevelSingleSelect: Story;
114
58
  /**
115
59
  * Single-level × multi-select with non-selectable parents. Drill through
116
60
  * Country → State (no radios) to reach selectable Cities; search is locked
117
61
  * to the City level regardless of browse position.
118
62
  */
119
- export declare const SingleLevelMultiSelectWithNonSelectableParents: Story;
120
- /** Single-level × single-select with non-selectable parents — closes on City pick. */
121
- export declare const SingleLevelSingleSelectWithNonSelectableParents: Story;
63
+ export declare const SingleLevelCityPicker: Story;
122
64
  /**
123
65
  * Browse load-more error: the first page loads successfully, but the next page
124
66
  * (triggered by scrolling to the bottom) fails. Already-loaded items stay
@@ -126,11 +68,5 @@ export declare const SingleLevelSingleSelectWithNonSelectableParents: Story;
126
68
  * the bottom of the list. Clicking Reload re-attempts from the current marker.
127
69
  */
128
70
  export declare const LoadMoreError: Story;
129
- /**
130
- * Search error: the initial search request fails, replacing the result area
131
- * with the full-area error and retry button. Clicking retry re-runs the last
132
- * committed query.
133
- */
134
- export declare const SearchErrorState: Story;
135
71
  export declare const PortalElementInScrollableContainer: Story;
136
72
  export declare const ForwardedRefFocus: Story;
@@ -1,2 +1,13 @@
1
1
  import { TaxonomyNode } from '../../types';
2
- export declare function generateNodes(count: number, options?: Partial<TaxonomyNode>): TaxonomyNode[];
2
+ interface GenerateNodesOptions extends Partial<TaxonomyNode> {
3
+ /**
4
+ * Optional namespace prepended to the default `node-` / `Item ` strings so
5
+ * fixtures used by multiple services in the same story don't collide on
6
+ * `node-1`, `node-2`, etc. The display name uses the prefix verbatim
7
+ * (e.g. `idPrefix: 'flat'` → ids `flat-1`, names `Flat 1`); pass a
8
+ * single-word prefix for the cleanest results.
9
+ */
10
+ idPrefix?: string;
11
+ }
12
+ export declare function generateNodes(count: number, options?: GenerateNodesOptions): TaxonomyNode[];
13
+ export {};
@@ -0,0 +1,12 @@
1
+ import { TaxonomyLevel, TaxonomyValue } from '../../types';
2
+ export declare const defaultService: import('../../types').TaxonomyItemsService;
3
+ export declare const largeDatasetService: import('../../types').TaxonomyItemsService;
4
+ export declare const emptyService: import('../../types').TaxonomyItemsService;
5
+ export declare const errorService: import('../../types').TaxonomyItemsService;
6
+ export declare const paginatedService: import('../../types').TaxonomyItemsService;
7
+ export declare const mixedSelectabilityService: import('../../types').TaxonomyItemsService;
8
+ export declare const searchableHierarchyService: import('../../types').TaxonomyItemsService;
9
+ export declare const longLabelDeepHierarchyService: import('../../types').TaxonomyItemsService;
10
+ export declare const defaultLevels: TaxonomyLevel[];
11
+ /** Real root-level items from `buildDeepTree` so chips aren't orphaned synthetic values. */
12
+ export declare const defaultMultiSelectInitialValue: TaxonomyValue[];
@@ -1,6 +1,6 @@
1
1
  import { StoryObj } from '@storybook/react-vite';
2
2
  import { MetadataTaxonomyPicker } from '../../../index';
3
- import { MetadataTaxonomyPickerProps, TaxonomyPickerMode, TaxonomyValue } from '../../types';
3
+ import { MetadataTaxonomyPickerProps, TaxonomyItemsService, TaxonomyPickerMode, TaxonomyValue } from '../../types';
4
4
  declare const _default: {
5
5
  parameters: {
6
6
  docs: {
@@ -17,7 +17,7 @@ declare const _default: {
17
17
  multiSelect: boolean;
18
18
  value: TaxonomyValue[];
19
19
  onValueChange: (values: TaxonomyValue[]) => void;
20
- itemsService: import('../../types').TaxonomyItemsService;
20
+ itemsService: TaxonomyItemsService;
21
21
  eventService?: import('../../types').TaxonomyPickerEventService | undefined;
22
22
  levels?: import('../../types').TaxonomyLevel[] | undefined;
23
23
  placeholder?: string | undefined;
@@ -31,6 +31,17 @@ declare const _default: {
31
31
  };
32
32
  export default _default;
33
33
  type Story = StoryObj<typeof MetadataTaxonomyPicker>;
34
+ /**
35
+ * Clicking the chevron on a row replaces the current items list with the
36
+ * children of the chosen row; repeating it walks the user further down the tree.
37
+ */
38
+ export declare const DrillsDownMultipleLevels: Story;
39
+ /**
40
+ * While a drill-down request is in flight the items list is replaced by the
41
+ * loading skeleton so the user knows the previous level's items are no longer
42
+ * accurate.
43
+ */
44
+ export declare const DrillDownShowsLoadingSkeleton: Story;
34
45
  /**
35
46
  * At the root level the breadcrumb is intentionally absent — there is nowhere
36
47
  * to navigate "back" to. The popover shows only the items list.
@@ -76,3 +87,41 @@ export declare const JumpsToMidTrailAncestorFromDeepLevel: Story;
76
87
  * the hidden ancestors.
77
88
  */
78
89
  export declare const FolderTreeTruncationExposesHiddenAncestors: Story;
90
+ /**
91
+ * Cache-hit path: after drilling into a level whose parent level was previously
92
+ * fetched, navigating back rehydrates from cache without issuing a new request.
93
+ */
94
+ export declare const NavigatesBackFromCacheWithoutRefetch: Story;
95
+ /**
96
+ * Cache-miss path: when the user lands on a deep level via a search result
97
+ * (whose ancestor level was never browsed), navigating back to that ancestor
98
+ * has no cached snapshot to seed from. The reducer transitions the level via
99
+ * `transitionToLevel` (clears items, shows the skeleton), and the controller
100
+ * issues a fresh `getNodes(region-a)` request.
101
+ */
102
+ export declare const NavigatesBackWithRefetchWhenCacheMisses: Story;
103
+ /**
104
+ * Reset-on-close: closing the popover wipes the per-level cache and reducer
105
+ * state, so the next open re-fetches the root.
106
+ */
107
+ export declare const ResetsStateOnCloseAndRefetchesRootOnReopen: Story;
108
+ /**
109
+ * Stale-response guard: drilling into one level and then immediately drilling
110
+ * into a different level must show the second level's data even though the
111
+ * first level's response resolves first (with the longer delay it would
112
+ * otherwise overwrite it).
113
+ */
114
+ export declare const DropsStaleFetchResponseAfterRapidDrillDown: Story;
115
+ /**
116
+ * Happy-path error reporting: when the network request for the current level
117
+ * fails, the reducer surfaces the message via `initialLoadError`, stops the
118
+ * fetching spinner, and tags the last failed op as `browse` so retry UI can
119
+ * target the right operation.
120
+ */
121
+ export declare const SurfacesFetchErrorForCurrentLevel: Story;
122
+ /**
123
+ * Stale-response guard for errors: drilling into a slow-failing level and
124
+ * immediately navigating back must NOT pollute the root level with the late
125
+ * Region A error. The reducer's `forParentId` guard drops the stale failure.
126
+ */
127
+ export declare const DropsStaleFetchErrorAfterRapidNavigateBack: Story;
@@ -42,9 +42,18 @@ declare const _default: {
42
42
  };
43
43
  export default _default;
44
44
  type Story = StoryObj<typeof ControlledPicker>;
45
+ export declare const PopoverOpensOnTriggerClick: Story;
46
+ export declare const PopoverClosesOnEscape: Story;
47
+ export declare const PopoverClosesOnClickOutside: Story;
45
48
  export declare const SingleSelectClickEmitsValueWithFullNodeShape: Story;
46
49
  export declare const SingleSelectRadioClickEmitsValue: Story;
47
50
  export declare const SingleSelectReplacesPreviousValue: Story;
51
+ /**
52
+ * Arrow navigation between rows must not commit a selection or close the
53
+ * popover — only Space/Enter or a click do that. This guards against
54
+ * accidental selection-on-focus regressions in roving-tabindex code paths.
55
+ */
56
+ export declare const SingleSelectArrowKeepsPopoverOpen: Story;
48
57
  export declare const MultiSelectAppendsValuesAcrossClicks: Story;
49
58
  export declare const MultiSelectTogglesOffWhenAlreadySelected: Story;
50
59
  export declare const SingleSelectShowsChipForSelectedValue: Story;
@@ -53,4 +62,6 @@ export declare const SingleSelectClearButtonClearsValue: Story;
53
62
  export declare const SingleSelectClearButtonDoesNothingWhenDisabled: Story;
54
63
  export declare const SingleSelectChipHasNoDeleteButton: Story;
55
64
  export declare const MultiSelectDoesNotShowSingleClearButton: Story;
65
+ export declare const MultiSelectChipDismissRemovesValue: Story;
66
+ export declare const NonSelectableRowRendersWithoutSelectionControl: Story;
56
67
  export declare const TypingInTriggerUpdatesControlledValue: Story;
@@ -51,7 +51,6 @@ export declare const CheckboxClickCallsOnSelectOnce: Story;
51
51
  export declare const ArrowRightFromRowFocusesDrillDownButton: Story;
52
52
  export declare const ArrowRightNoOpWithoutDrillDown: Story;
53
53
  export declare const ArrowLeftFromRowFocusesSelectionControl: Story;
54
- export declare const ArrowRightFromRowFocusesDrillDownWhenNonSelectable: Story;
55
54
  export declare const EnterOnDrillDownButtonCallsOnDrillDown: Story;
56
55
  export declare const SpaceOnDrillDownButtonCallsOnDrillDown: Story;
57
56
  export declare const ArrowLeftFromDrillDownFocusesSelectionControl: Story;
@@ -59,12 +58,8 @@ export declare const ArrowRightFromSelectionControlFocusesDrillDown: Story;
59
58
  export declare const ArrowLeftFromSelectionControlFocusesRow: Story;
60
59
  export declare const SubControlsAreNotInTabOrder: Story;
61
60
  export declare const TabOnSelectionControlNavigatesToNextRow: Story;
62
- export declare const TabOnDrillDownNavigatesToNextRow: Story;
63
61
  export declare const TabOnRowMovesToNextRow: Story;
64
62
  export declare const ShiftTabOnRowMovesToPrevRow: Story;
65
63
  export declare const ArrowDownFromSelectionControlFocusesNextRow: Story;
66
- export declare const ArrowDownFromDrillDownFocusesNextRow: Story;
67
64
  export declare const ArrowUpFromSelectionControlFocusesPrevRow: Story;
68
65
  export declare const ShiftTabOnFirstRowFocusesInput: Story;
69
- export declare const ShiftTabOnFirstRowSelectionControlFocusesInput: Story;
70
- export declare const ShiftTabOnFirstRowDrillDownFocusesInput: Story;
@@ -36,3 +36,11 @@ export default _default;
36
36
  type Story = StoryObj<typeof MetadataTaxonomyPicker>;
37
37
  export declare const DefaultClosed: Story;
38
38
  export declare const DisabledState: Story;
39
+ export declare const SelectedChipsClosed: Story;
40
+ export declare const OpenBrowseList: Story;
41
+ export declare const OpenMultiSelectList: Story;
42
+ export declare const LoadingState: Story;
43
+ export declare const EmptyState: Story;
44
+ export declare const ErrorState: Story;
45
+ export declare const BreadcrumbAfterDrillDown: Story;
46
+ export declare const SearchResults: Story;
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@box/metadata-taxonomy-picker",
3
- "version": "2.18.1",
3
+ "version": "2.18.3",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "peerDependencies": {
6
6
  "@ariakit/react": "^0.4.21",
7
- "@box/blueprint-web": "^15.5.2",
8
- "@box/blueprint-web-assets": "^4.123.0",
7
+ "@box/blueprint-web": "^15.6.0",
8
+ "@box/blueprint-web-assets": "^4.123.2",
9
9
  "@tanstack/react-virtual": "^3.10.8",
10
10
  "react": "^18.0.0",
11
11
  "react-dom": "^18.0.0",
@@ -13,10 +13,10 @@
13
13
  },
14
14
  "devDependencies": {
15
15
  "@ariakit/react": "^0.4.21",
16
- "@box/blueprint-web": "^15.5.2",
17
- "@box/blueprint-web-assets": "^4.123.0",
16
+ "@box/blueprint-web": "^15.6.0",
17
+ "@box/blueprint-web-assets": "^4.123.2",
18
18
  "@box/eslint-plugin-blueprint": "1.2.5",
19
- "@box/storybook-utils": "0.20.10",
19
+ "@box/storybook-utils": "0.20.12",
20
20
  "@tanstack/react-virtual": "^3.10.8",
21
21
  "react-intl": "^6.4.2"
22
22
  },
@@ -1,47 +0,0 @@
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;
@@ -1,60 +0,0 @@
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;