@box/metadata-view 1.59.15 → 1.60.1

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.
@@ -1,31 +1,39 @@
1
1
  import { useAdvancedFilterContext as e } from "./advanced-filter-context.js";
2
- import { MetadataDateField as t, MetadataFloatField as n, MetadataMultiSelectField as r, MetadataStringField as i } from "@box/metadata-filter";
3
- import { jsx as a } from "react/jsx-runtime";
4
- var o = ({ fieldNamePrefix: t, filterOptionsMap: n, label: r }) => {
5
- let i = e();
2
+ import { useFilterChipPopoverPortalElement as t } from "./filter-chip-popover-context.js";
3
+ import { MetadataDateField as n, MetadataFloatField as r, MetadataMultiSelectField as i, MetadataStringField as a, MetadataTaxonomyFieldAdvanced as o } from "@box/metadata-filter";
4
+ import { jsx as s } from "react/jsx-runtime";
5
+ var c = ({ fieldNamePrefix: t, filterOptionsMap: n, label: r, portalElement: i }) => {
6
+ let a = e();
6
7
  return {
7
- key: i?.resetKey,
8
- fieldAdvancedFilterOptions: i?.currentOption,
8
+ key: a?.resetKey,
9
+ fieldAdvancedFilterOptions: a?.currentOption,
9
10
  fieldNamePrefix: t,
10
11
  filterOptionsMap: n,
11
12
  isAdvancedFilterEnabled: !0,
12
13
  label: r,
13
- onAdvancedFilterOptionChange: i ? (e, t) => i.onOptionChange(t) : void 0
14
+ onAdvancedFilterOptionChange: a ? (e, t) => a.onOptionChange(t) : void 0,
15
+ portalElement: i ?? void 0
14
16
  };
15
- }, s = ({ fieldType: e, fieldNamePrefix: s, filterOptionsMap: c, label: l, locale: u }) => {
16
- let d = o({
17
- fieldNamePrefix: s,
18
- filterOptionsMap: c,
19
- label: l
17
+ }, l = ({ fieldType: e, fieldNamePrefix: l, filterOptionsMap: u, isMultilevelTaxonomyFieldEnabled: d, label: f, locale: p, portalElement: m, taxonomyOptionsFetcher: h }) => {
18
+ let g = c({
19
+ fieldNamePrefix: l,
20
+ filterOptionsMap: u,
21
+ label: f,
22
+ portalElement: t() ?? m
20
23
  });
21
24
  switch (e) {
22
- case "date": return /* @__PURE__ */ a(t, {
23
- ...d,
24
- locale: u
25
+ case "date": return /* @__PURE__ */ s(n, {
26
+ ...g,
27
+ locale: p
25
28
  });
26
- case "float": return /* @__PURE__ */ a(n, { ...d });
27
- case "string": return /* @__PURE__ */ a(i, { ...d });
28
- default: return /* @__PURE__ */ a(r, { ...d });
29
+ case "float": return /* @__PURE__ */ s(r, { ...g });
30
+ case "string": return /* @__PURE__ */ s(a, { ...g });
31
+ case "taxonomy": return /* @__PURE__ */ s(o, {
32
+ ...g,
33
+ isMultilevelTaxonomyFieldEnabled: d,
34
+ taxonomyOptionsFetcher: h
35
+ });
36
+ default: return /* @__PURE__ */ s(i, { ...g });
29
37
  }
30
38
  };
31
- export { s as AdvancedFieldContent };
39
+ export { l as AdvancedFieldContent };
@@ -0,0 +1,3 @@
1
+ import { createContext as e, useContext as t } from "react";
2
+ var n = /* @__PURE__ */ e(null), r = n.Provider, i = () => t(n);
3
+ export { r as FilterChipPopoverPortalProvider, i as useFilterChipPopoverPortalElement };
@@ -7,31 +7,40 @@ import { FilterChip as a } from "@box/blueprint-web";
7
7
  import { useMemo as o, useRef as s } from "react";
8
8
  import { Form as c, Formik as l } from "formik";
9
9
  import { jsx as u, jsxs as d } from "react/jsx-runtime";
10
- var f = ({ dataTargetPrefix: f, predefinedFilterOptions: p, containerRef: m, filterGroups: h = [], initialFilterValues: g, isAllFiltersDisabled: _, onAllFiltersClick: v, onFilterSubmit: y }) => {
11
- let b = i(p), x = ({ metadata: { fields: e } }) => {
12
- y && y(e);
13
- }, S = [...b, ...h], C = S.flatMap(({ filters: e }) => e).sort((e, t) => (e.position ?? 0) - (t.position ?? 0)), w = o(() => e(C, g), [C.map((e) => `${e.id}:${e.fieldType}`).sort().join("|"), g]), T = s(null);
10
+ var f = (e) => {
11
+ let t = e.fieldType === "taxonomy" ? [
12
+ e.key,
13
+ JSON.stringify(e.optionsRules),
14
+ JSON.stringify(e.levels),
15
+ e.scope,
16
+ e.templateKey
17
+ ].join(":") : "";
18
+ return `${e.id}:${e.fieldType}:${t}`;
19
+ }, p = ({ dataTargetPrefix: p, predefinedFilterOptions: m, containerRef: h, filterGroups: g = [], initialFilterValues: _, isAllFiltersDisabled: v, onAllFiltersClick: y, onFilterSubmit: b }) => {
20
+ let x = i(m), S = ({ metadata: { fields: e } }) => {
21
+ b && b(e);
22
+ }, C = [...x, ...g], w = C.flatMap(({ filters: e }) => e).sort((e, t) => (e.position ?? 0) - (t.position ?? 0)), T = o(() => e(w, _), [w.map((e) => f(e)).sort().join("|"), _]), E = s(null);
14
23
  return /* @__PURE__ */ u(l, {
15
24
  enableReinitialize: !0,
16
- initialValues: w,
17
- onSubmit: x,
25
+ initialValues: T,
26
+ onSubmit: S,
18
27
  children: /* @__PURE__ */ u(c, {
19
- ref: T,
28
+ ref: E,
20
29
  children: /* @__PURE__ */ d(a.Group, {
21
30
  className: t.filterChipGroup,
22
31
  name: "metadata-view-filters",
23
32
  type: "multiple",
24
- children: [_ ? null : /* @__PURE__ */ u(n, {
25
- containerRef: m,
26
- dataTargetPrefix: f,
27
- filterGroups: S,
28
- onAllFiltersClick: v
29
- }), C.filter((e) => e.shouldRenderChip).map((e) => /* @__PURE__ */ u(r, {
33
+ children: [v ? null : /* @__PURE__ */ u(n, {
34
+ containerRef: h,
35
+ dataTargetPrefix: p,
36
+ filterGroups: C,
37
+ onAllFiltersClick: y
38
+ }), w.filter((e) => e.shouldRenderChip).map((e) => /* @__PURE__ */ u(r, {
30
39
  filterOption: e,
31
- formRef: T
40
+ formRef: E
32
41
  }, e.id))]
33
42
  })
34
43
  })
35
44
  });
36
45
  };
37
- export { f as FilterRow };
46
+ export { p as FilterRow };
@@ -4,82 +4,96 @@ import { extractAdvancedFilterOption as n, isFilterSelected as r } from "./is-fi
4
4
  import i from "./messages.js";
5
5
  import { t as a } from "../../../../chunks/filter-row.module.js";
6
6
  import { AdvancedFilterContext as o } from "./advanced-filter-context.js";
7
- import { useFormFilterChip as s } from "./use-form-filter-chip.js";
8
- import { Button as c, FilterChip as l, Popover as u } from "@box/blueprint-web";
9
- import { useMemo as d, useState as f } from "react";
10
- import { useIntl as p } from "react-intl";
11
- import { getIn as m, useFormikContext as h } from "formik";
12
- import { jsx as g, jsxs as _ } from "react/jsx-runtime";
13
- var v = ({ children: v, formRef: y, icon: b, id: x, name: S = "", isAdvancedFilterEnabled: C, advancedFilterOptionsMap: w }) => {
14
- let { formatMessage: T } = p(), [E, D] = f(!1), { handleSubmit: O, setFieldValue: k, resetForm: A, values: j } = h(), M = m(j, `metadata.fields.${x}.fieldType`), N = m(j, `metadata.fields.${x}.value`), { appliedAdvancedFilterOption: P, currentAdvancedFilterOption: F, dynamicDisplayName: I, handleAdvancedFilterOptionChange: L, handleApply: R, handleCancel: z, handleClear: B } = s({
15
- name: S,
16
- advancedFilterOptionsMap: w,
17
- initialAdvancedFilterOption: C && N ? n(N) : void 0
18
- }), [V, H] = f(0), U = () => {
19
- C && R(), O(), D(!1);
20
- }, [W, G] = f(j), K = (e) => {
21
- D(e), e ? (G(j), C && H((e) => e + 1)) : (A({ values: W }), C && z());
22
- }, q = () => {
23
- k(`metadata.fields.${x}.value`, e({
24
- fieldType: M,
25
- isAdvancedFilterEnabled: C
26
- })), C && B();
27
- }, J = d(() => {
28
- if (C && t(P)) return !0;
29
- let e = m(j, `metadata.fields.${x}.value`);
7
+ import { FilterChipPopoverPortalProvider as s } from "./filter-chip-popover-context.js";
8
+ import { useFormFilterChip as c } from "./use-form-filter-chip.js";
9
+ import { useNestedOverlayPopoverOpenChange as l } from "./use-nested-overlay-popover-open-change.js";
10
+ import { Button as u, FilterChip as d, Popover as f } from "@box/blueprint-web";
11
+ import { useMemo as p, useState as m } from "react";
12
+ import { useIntl as h } from "react-intl";
13
+ import { getIn as g, useFormikContext as _ } from "formik";
14
+ import { jsx as v, jsxs as y } from "react/jsx-runtime";
15
+ var b = ({ children: b, formRef: x, icon: S, id: C, name: w = "", isAdvancedFilterEnabled: T, advancedFilterOptionsMap: E }) => {
16
+ let { formatMessage: D } = h(), [O, k] = m(!1), { handleSubmit: A, setFieldValue: j, resetForm: M, values: N } = _(), P = g(N, `metadata.fields.${C}.fieldType`), F = g(N, `metadata.fields.${C}.value`), { appliedAdvancedFilterOption: I, currentAdvancedFilterOption: L, dynamicDisplayName: R, handleAdvancedFilterOptionChange: z, handleApply: B, handleCancel: V, handleClear: H } = c({
17
+ name: w,
18
+ advancedFilterOptionsMap: E,
19
+ initialAdvancedFilterOption: T && F ? n(F) : void 0
20
+ }), [U, W] = m(0), G = () => {
21
+ T && B(), A(), k(!1);
22
+ }, [K, q] = m(N), { handlePopoverOpenChange: J, portalElement: Y, setPopoverContentRef: X } = l({
23
+ onOpenChange: (e) => {
24
+ k(e), e ? (q(N), T && W((e) => e + 1)) : (M({ values: K }), T && V());
25
+ },
26
+ popoverOpen: O
27
+ }), Z = () => {
28
+ j(`metadata.fields.${C}.value`, e({
29
+ fieldType: P,
30
+ isAdvancedFilterEnabled: T
31
+ })), T && H();
32
+ }, Q = p(() => {
33
+ if (T && t(I)) return !0;
34
+ let e = g(N, `metadata.fields.${C}.value`);
30
35
  return e ? r(e) : !1;
31
36
  }, [
32
- j,
33
- x,
37
+ N,
34
38
  C,
35
- P
36
- ]), Y = () => {
37
- if (M === "date") {
38
- let e = m(j, `metadata.fields.${x}.value.customType`), t = e && e !== "anyTime" && e !== "customRange", n = m(j, `metadata.fields.${x}.value.relativeType`);
39
- return (t || n && n !== "customRange") && !J;
39
+ T,
40
+ I
41
+ ]), $ = () => {
42
+ if (P === "date") {
43
+ let e = g(N, `metadata.fields.${C}.value.customType`), t = e && e !== "anyTime" && e !== "customRange", n = g(N, `metadata.fields.${C}.value.relativeType`);
44
+ return (t || n && n !== "customRange") && !Q;
40
45
  }
41
46
  return !1;
42
- }, X = C && J ? I : S, Z = C ? /* @__PURE__ */ g(o.Provider, {
43
- value: {
44
- currentOption: F,
45
- onOptionChange: L,
46
- resetKey: V
47
- },
48
- children: v
49
- }) : v;
50
- return /* @__PURE__ */ g("div", { children: /* @__PURE__ */ _(u.Root, {
51
- onOpenChange: K,
52
- open: E,
53
- children: [/* @__PURE__ */ g(u.Trigger, { children: /* @__PURE__ */ _(l.TriggerChip, {
54
- selected: J,
55
- value: x,
47
+ }, ee = T && Q ? R : w, te = p(() => ({
48
+ currentOption: L,
49
+ onOptionChange: z,
50
+ resetKey: U
51
+ }), [
52
+ L,
53
+ z,
54
+ U
55
+ ]), ne = T ? /* @__PURE__ */ v(o.Provider, {
56
+ value: te,
57
+ children: b
58
+ }) : b;
59
+ return /* @__PURE__ */ v("div", { children: /* @__PURE__ */ y(f.Root, {
60
+ modal: !1,
61
+ onOpenChange: J,
62
+ open: O,
63
+ children: [/* @__PURE__ */ v(f.Trigger, { children: /* @__PURE__ */ y(d.TriggerChip, {
64
+ selected: Q,
65
+ value: C,
56
66
  children: [
57
- b && /* @__PURE__ */ g(l.Icon, { icon: b }),
58
- /* @__PURE__ */ g(l.Label, { children: X }),
59
- /* @__PURE__ */ g(l.DropdownIndicator, {})
67
+ S && /* @__PURE__ */ v(d.Icon, { icon: S }),
68
+ /* @__PURE__ */ v(d.Label, { children: ee }),
69
+ /* @__PURE__ */ v(d.DropdownIndicator, {})
60
70
  ]
61
- }, x) }), /* @__PURE__ */ _(u.ContentContainer, {
71
+ }, C) }), /* @__PURE__ */ v(f.ContentContainer, {
72
+ ref: X,
62
73
  align: "start",
63
74
  className: a.popoverContent,
64
- container: y.current,
75
+ container: x.current,
65
76
  "data-testid": "form-filter-chip-popover",
66
- children: [/* @__PURE__ */ g(u.MainContent, { children: Z }), /* @__PURE__ */ _(u.Footer, {
67
- className: a.popoverFooter,
68
- children: [/* @__PURE__ */ g(c, {
69
- onClick: q,
70
- size: "small",
71
- variant: "secondary",
72
- children: T(i.clearButton)
73
- }), /* @__PURE__ */ g(c, {
74
- disabled: Y(),
75
- onClick: U,
76
- size: "small",
77
- type: "submit",
78
- variant: "primary",
79
- children: T(i.applyButton)
77
+ children: /* @__PURE__ */ y(s, {
78
+ value: Y,
79
+ children: [/* @__PURE__ */ v(f.MainContent, { children: ne }), /* @__PURE__ */ y(f.Footer, {
80
+ className: a.popoverFooter,
81
+ children: [/* @__PURE__ */ v(u, {
82
+ onClick: Z,
83
+ size: "small",
84
+ variant: "secondary",
85
+ children: D(i.clearButton)
86
+ }), /* @__PURE__ */ v(u, {
87
+ disabled: $(),
88
+ onClick: G,
89
+ size: "small",
90
+ type: "submit",
91
+ variant: "primary",
92
+ children: D(i.applyButton)
93
+ })]
80
94
  })]
81
- })]
95
+ })
82
96
  })]
83
97
  }) });
84
98
  };
85
- export { v as FormFilterChip };
99
+ export { b as FormFilterChip };
@@ -1,32 +1,47 @@
1
- var e = (e) => ({
1
+ import { FilterKeyTypes as e } from "@box/metadata-filter";
2
+ var t = (e) => ({
2
3
  key: e,
3
4
  id: e
4
- }), t = ({ fieldType: t, options: n }) => ["enum", "multiSelect"].includes(t) ? (n || []).map(e) : [], n = ({ fieldType: e, isAdvancedFilterEnabled: t }) => e === "date" ? {
5
+ }), n = ({ fieldType: e, options: n }) => ["enum", "multiSelect"].includes(e) ? (n || []).map(t) : [], r = ({ fieldType: t, isAdvancedFilterEnabled: n }) => t === "taxonomy" ? n ? {
6
+ value: [],
7
+ advancedFilterOption: e.MATCH_ANY
8
+ } : [] : t === "date" ? {
5
9
  customType: "anyTime",
6
10
  range: {
7
11
  gt: "",
8
12
  lt: ""
9
13
  }
10
- } : e === "float" ? t ? { enum: [] } : { range: {
14
+ } : t === "float" ? n ? { enum: [] } : { range: {
11
15
  gt: "",
12
16
  lt: ""
13
- } } : { enum: [] }, r = (e) => Array.isArray(e) ? e.length > 1 ? "multiSelect" : "enum" : !e || typeof e != "object" ? "enum" : "customDays" in e || "relativeDays" in e || "customType" in e || "relativeType" in e ? "date" : "range" in e ? "float" : "enum" in e && e.enum.length > 1 ? "multiSelect" : "enum", i = (e, i) => {
14
- let a = e.reduce((e, r) => {
15
- let a = i?.[r.id]?.value, o = n({
16
- fieldType: r.fieldType,
17
- isAdvancedFilterEnabled: r.isAdvancedFilterEnabled
18
- });
19
- return e[r.id] = {
17
+ } } : { enum: [] }, i = (e) => Array.isArray(e) ? e.length > 1 ? "multiSelect" : "enum" : !e || typeof e != "object" ? "enum" : "customDays" in e || "relativeDays" in e || "customType" in e || "relativeType" in e ? "date" : "range" in e ? "float" : "value" in e && Array.isArray(e.value) ? "taxonomy" : "enum" in e && e.enum.length > 1 ? "multiSelect" : "enum", a = (e, t) => {
18
+ let a = e.reduce((e, i) => {
19
+ let a = t?.[i.id]?.value, o = r({
20
+ fieldType: i.fieldType,
21
+ isAdvancedFilterEnabled: i.isAdvancedFilterEnabled
22
+ }), s = {
20
23
  value: a ?? o,
21
- fieldType: r.fieldType,
22
- options: t(r)
23
- }, e;
24
+ fieldType: i.fieldType,
25
+ options: n(i)
26
+ };
27
+ return e[i.id] = i.fieldType === "taxonomy" ? {
28
+ ...s,
29
+ key: i.key ?? i.id,
30
+ levels: i.levels,
31
+ optionsRules: i.optionsRules
32
+ } : s, e;
24
33
  }, {});
25
- return i && Object.keys(i).filter((e) => !a[e]).forEach((e) => {
34
+ t && Object.keys(t).filter((e) => !a[e]).forEach((e) => {
26
35
  a[e] = {
27
- value: i[e].value,
28
- fieldType: r(i[e].value)
36
+ value: t[e].value,
37
+ fieldType: i(t[e].value)
29
38
  };
30
- }), { metadata: { fields: a } };
39
+ });
40
+ let o = e.find((e) => e.fieldType === "taxonomy");
41
+ return { metadata: {
42
+ fields: a,
43
+ scope: o?.scope,
44
+ templateKey: o?.templateKey
45
+ } };
31
46
  };
32
- export { n as getDefaultFieldValue, i as getInitialFieldValues, r as inferFieldType };
47
+ export { r as getDefaultFieldValue, a as getInitialFieldValues, i as inferFieldType };
@@ -20,7 +20,9 @@ var n = (e) => !!e && typeof e == "object" && !Array.isArray(e) && "advancedFilt
20
20
  let n = o(e);
21
21
  return n && n !== t.SELECT_FILTER_TYPE ? n : void 0;
22
22
  }, c = (t) => {
23
+ if (Array.isArray(t)) return t.length > 0;
23
24
  if ("advancedFilterOption" in t && e(t.advancedFilterOption)) return !0;
25
+ if ("value" in t && Array.isArray(t.value)) return t.value.length > 0;
24
26
  if ("range" in t) {
25
27
  let { range: e } = t;
26
28
  return !!(e && (e.gt || e.lt));
@@ -6,21 +6,24 @@ import { useIntl as i } from "react-intl";
6
6
  import { MetadataDateField as a, MetadataFloatField as o, MetadataStringField as s } from "@box/metadata-filter";
7
7
  import { jsx as c } from "react/jsx-runtime";
8
8
  var l = ({ filterOption: l, formRef: u }) => {
9
- let { advancedFilterOptionsMap: d, canUseRelativeDates: f, customDateFilterOptions: p, fieldType: m, icon: h, id: g, isAdvancedFilterEnabled: _, name: v, options: y, placeholder: b, variant: x } = l, { locale: S } = i(), C = `metadata.fields.${g}`, w = v ?? "";
10
- if (m === "multiSelect" && x === "file") return /* @__PURE__ */ c(e, { id: g });
9
+ let { advancedFilterOptionsMap: d, canUseRelativeDates: f, customDateFilterOptions: p, fieldType: m, icon: h, id: g, isAdvancedFilterEnabled: _, isMultilevelTaxonomyFieldEnabled: v, name: y, options: b, placeholder: x, taxonomyOptionsFetcher: S, variant: C } = l, { locale: w } = i(), T = `metadata.fields.${g}`, E = y ?? "";
10
+ if (m === "multiSelect" && C === "file") return /* @__PURE__ */ c(e, { id: g });
11
11
  if (_) return /* @__PURE__ */ c(n, {
12
12
  advancedFilterOptionsMap: d,
13
13
  formRef: u,
14
14
  icon: h,
15
15
  id: g,
16
16
  isAdvancedFilterEnabled: !0,
17
- name: v,
17
+ name: y,
18
18
  children: /* @__PURE__ */ c(t, {
19
19
  fieldType: m,
20
- fieldNamePrefix: C,
20
+ fieldNamePrefix: T,
21
21
  filterOptionsMap: d,
22
- label: w,
23
- locale: S
22
+ isMultilevelTaxonomyFieldEnabled: v,
23
+ label: E,
24
+ locale: w,
25
+ portalElement: u.current,
26
+ taxonomyOptionsFetcher: S
24
27
  })
25
28
  }, g);
26
29
  switch (m) {
@@ -28,45 +31,45 @@ var l = ({ filterOption: l, formRef: u }) => {
28
31
  formRef: u,
29
32
  icon: h,
30
33
  id: g,
31
- name: v,
34
+ name: y,
32
35
  children: /* @__PURE__ */ c(a, {
33
36
  canUseRelativeDates: f,
34
37
  customDateFilterOptions: p,
35
38
  direction: "vertical",
36
- fieldNamePrefix: C,
37
- label: w,
38
- locale: S
39
+ fieldNamePrefix: T,
40
+ label: E,
41
+ locale: w
39
42
  })
40
43
  }, g);
41
44
  case "float": return /* @__PURE__ */ c(n, {
42
45
  formRef: u,
43
46
  icon: h,
44
47
  id: g,
45
- name: v,
48
+ name: y,
46
49
  children: /* @__PURE__ */ c(o, {
47
- fieldNamePrefix: C,
48
- label: w
50
+ fieldNamePrefix: T,
51
+ label: E
49
52
  })
50
53
  }, g);
51
54
  case "string": return /* @__PURE__ */ c(n, {
52
55
  formRef: u,
53
56
  icon: h,
54
57
  id: g,
55
- name: v,
58
+ name: y,
56
59
  children: /* @__PURE__ */ c(s, {
57
- fieldNamePrefix: C,
58
- label: w
60
+ fieldNamePrefix: T,
61
+ label: E
59
62
  })
60
63
  }, g);
61
64
  case "multiSelect":
62
65
  case "enum": return /* @__PURE__ */ c(r, {
63
- fieldNamePrefix: C,
66
+ fieldNamePrefix: T,
64
67
  formRef: u,
65
68
  icon: h,
66
69
  id: g,
67
- name: v,
68
- options: y,
69
- placeholder: b,
70
+ name: y,
71
+ options: b,
72
+ placeholder: x,
70
73
  type: m
71
74
  });
72
75
  default: return null;
@@ -0,0 +1,30 @@
1
+ import { useCallback as e, useEffect as t, useRef as n, useState as r } from "react";
2
+ var i = ({ onOpenChange: i, popoverOpen: a }) => {
3
+ let o = n(null), s = n(!1), [c, l] = r(null);
4
+ return t(() => {
5
+ if (!a) return;
6
+ let e = () => {
7
+ let e = o.current;
8
+ return e ? !!(e.querySelector("[role=\"combobox\"][aria-expanded=\"true\"]") ?? e.querySelector("[aria-haspopup=\"tree\"][aria-expanded=\"true\"]")) : !1;
9
+ }, t = (t) => {
10
+ if (t.key !== "Escape") return;
11
+ let n = o.current;
12
+ !n || !(t.target instanceof Node) || !n.contains(t.target) || (s.current = e());
13
+ }, n = (t) => {
14
+ let n = o.current;
15
+ n && t.target instanceof Node && n.contains(t.target) || (s.current = e());
16
+ };
17
+ return document.addEventListener("keydown", t, !0), document.addEventListener("pointerdown", n, !0), () => {
18
+ document.removeEventListener("keydown", t, !0), document.removeEventListener("pointerdown", n, !0);
19
+ };
20
+ }, [a]), {
21
+ handlePopoverOpenChange: e((e) => {
22
+ e ? i(!0) : s.current ? s.current = !1 : i(!1);
23
+ }, [i]),
24
+ portalElement: c,
25
+ setPopoverContentRef: e((e) => {
26
+ o.current = e, l(e);
27
+ }, [])
28
+ };
29
+ };
30
+ export { i as useNestedOverlayPopoverOpenChange };
@@ -1,12 +1,15 @@
1
- import { AdvancedFilterOptionsMap, FilterOption } from './types';
1
+ import { AdvancedFilterOptionsMap, FilterOption, TaxonomyOptionsFetcher } from './types';
2
2
  type BaseAdvancedFieldProps = {
3
3
  fieldNamePrefix: string;
4
4
  filterOptionsMap?: AdvancedFilterOptionsMap;
5
5
  label: string;
6
+ portalElement?: HTMLElement | null;
6
7
  };
7
8
  type AdvancedFieldContentProps = BaseAdvancedFieldProps & {
8
9
  fieldType: FilterOption['fieldType'];
10
+ isMultilevelTaxonomyFieldEnabled?: boolean;
9
11
  locale: string;
12
+ taxonomyOptionsFetcher?: TaxonomyOptionsFetcher;
10
13
  };
11
- export declare const AdvancedFieldContent: ({ fieldType, fieldNamePrefix, filterOptionsMap, label, locale, }: AdvancedFieldContentProps) => import("react/jsx-runtime").JSX.Element;
14
+ export declare const AdvancedFieldContent: ({ fieldType, fieldNamePrefix, filterOptionsMap, isMultilevelTaxonomyFieldEnabled, label, locale, portalElement, taxonomyOptionsFetcher, }: AdvancedFieldContentProps) => import("react/jsx-runtime").JSX.Element;
12
15
  export {};
@@ -0,0 +1,2 @@
1
+ export declare const FilterChipPopoverPortalProvider: import('react').Provider<HTMLElement>;
2
+ export declare const useFilterChipPopoverPortalElement: () => HTMLElement | null;
@@ -1,9 +1,8 @@
1
- import { MetadataFormFieldValue } from '@box/metadata-filter';
2
1
  import { MetadataFieldType } from '../../types';
3
- import { FilterOption, InitialFilterValues, MetadataFormValues } from './types';
2
+ import { FilterFieldValue, FilterOption, InitialFilterValues, MetadataFormValues } from './types';
4
3
  export declare const getDefaultFieldValue: ({ fieldType, isAdvancedFilterEnabled, }: {
5
4
  fieldType?: MetadataFieldType;
6
5
  isAdvancedFilterEnabled?: boolean;
7
- }) => MetadataFormFieldValue;
8
- export declare const inferFieldType: (value: MetadataFormFieldValue) => MetadataFieldType;
6
+ }) => FilterFieldValue;
7
+ export declare const inferFieldType: (value: FilterFieldValue) => MetadataFieldType;
9
8
  export declare const getInitialFieldValues: (filterOptions: FilterOption[], customFieldValues?: InitialFilterValues) => MetadataFormValues;
@@ -1,8 +1,14 @@
1
1
  import { FilterKey, MetadataFormFieldValue } from '@box/metadata-filter';
2
- export declare const extractAdvancedFilterOption: (value: MetadataFormFieldValue) => FilterKey | undefined;
2
+ type TaxonomyFieldValue = {
3
+ value?: unknown[];
4
+ advancedFilterOption?: FilterKey;
5
+ };
6
+ type FilterFieldValue = MetadataFormFieldValue | TaxonomyFieldValue;
7
+ export declare const extractAdvancedFilterOption: (value: FilterFieldValue) => FilterKey | undefined;
3
8
  /**
4
9
  * Returns true if the given field value is considered "selected" (i.e., not empty).
5
10
  * Also returns true when an isBlank/isNotBlank advanced filter option is applied,
6
11
  * since those filters are active even when the field value itself is empty.
7
12
  */
8
- export declare const isFilterSelected: (value: MetadataFormFieldValue) => boolean;
13
+ export declare const isFilterSelected: (value: FilterFieldValue) => boolean;
14
+ export {};
@@ -1,4 +1,4 @@
1
- import { FilterKey, MetadataFormFieldValue, MetadataTemplateFieldOption } from '@box/metadata-filter';
1
+ import { FetcherResponse, FilterKey, Level, MetadataFormFieldValue, MetadataTemplateFieldOption, TaxonomyOptionsRules, TreeOptionType, TreeQueryInput } from '@box/metadata-filter';
2
2
  import { ReactNode } from 'react';
3
3
  import { FilterVariant, MetadataFieldType } from '../../types';
4
4
  export interface CustomDateFilterOption {
@@ -19,17 +19,28 @@ export interface FilterGroup {
19
19
  toggleable: boolean;
20
20
  }
21
21
  export type AdvancedFilterOptionsMap = [FilterKey, string][];
22
- export interface FilterOption {
22
+ export type TaxonomyOptionsFetcher = (scope: string, templateKey: string, fieldKey: string, level: number, options: TreeQueryInput) => Promise<FetcherResponse<TreeOptionType>>;
23
+ export type TaxonomyFilterValue = TreeOptionType[] | {
24
+ value: TreeOptionType[];
25
+ advancedFilterOption: FilterKey;
26
+ };
27
+ export type FilterFieldValue = MetadataFormFieldValue | TaxonomyFilterValue;
28
+ interface BaseFilterOption {
23
29
  customLabels?: string[];
24
- fieldType: MetadataFieldType;
25
30
  icon?: React.ForwardRefExoticComponent<Omit<React.SVGProps<SVGSVGElement>, 'ref'> & React.RefAttributes<SVGSVGElement>>;
26
31
  id: string;
27
- isAdvancedFilterEnabled?: boolean;
28
32
  advancedFilterOptionsMap?: AdvancedFilterOptionsMap;
33
+ isMultilevelTaxonomyFieldEnabled?: boolean;
29
34
  isItemMetadata?: boolean;
35
+ key?: string;
36
+ levels?: Level[];
30
37
  name?: string;
31
38
  options?: string[];
39
+ optionsRules?: TaxonomyOptionsRules;
32
40
  placeholder?: string;
41
+ scope?: string;
42
+ taxonomyOptionsFetcher?: TaxonomyOptionsFetcher;
43
+ templateKey?: string;
33
44
  canUseRelativeDates?: boolean;
34
45
  customDateFilterOptions?: Array<CustomDateFilterOptionsProps>;
35
46
  selected: boolean;
@@ -43,6 +54,15 @@ export interface FilterOption {
43
54
  */
44
55
  position?: number;
45
56
  }
57
+ interface TaxonomyFilterOption extends BaseFilterOption {
58
+ fieldType: 'taxonomy';
59
+ isAdvancedFilterEnabled: true;
60
+ }
61
+ interface NonTaxonomyFilterOption extends BaseFilterOption {
62
+ fieldType: Exclude<MetadataFieldType, 'taxonomy'>;
63
+ isAdvancedFilterEnabled?: boolean;
64
+ }
65
+ export type FilterOption = TaxonomyFilterOption | NonTaxonomyFilterOption;
46
66
  export interface FilterChipProps {
47
67
  formRef: React.RefObject<HTMLFormElement>;
48
68
  icon?: React.ForwardRefExoticComponent<Omit<React.SVGProps<SVGSVGElement>, 'ref'> & React.RefAttributes<SVGSVGElement>>;
@@ -52,14 +72,20 @@ export interface FilterChipProps {
52
72
  }
53
73
  export type FilterValues = Record<string, {
54
74
  fieldType: MetadataFieldType;
75
+ key?: string;
76
+ levels?: Level[];
55
77
  options?: Array<MetadataTemplateFieldOption>;
56
- value: MetadataFormFieldValue;
78
+ optionsRules?: TaxonomyOptionsRules;
79
+ value: FilterFieldValue;
57
80
  }>;
58
81
  export type InitialFilterValues = Record<string, {
59
- value: MetadataFormFieldValue;
82
+ value: FilterFieldValue;
60
83
  }>;
61
84
  export type MetadataFormValues = {
62
85
  metadata: {
63
86
  fields: FilterValues;
87
+ scope?: string;
88
+ templateKey?: string;
64
89
  };
65
90
  };
91
+ export {};
@@ -0,0 +1,15 @@
1
+ type UseNestedOverlayPopoverOpenChangeProps = {
2
+ onOpenChange: (open: boolean) => void;
3
+ popoverOpen: boolean;
4
+ };
5
+ /**
6
+ * Default Popover dismissal treats Escape or outside pointer events from nested combobox/tree
7
+ * overlays as a parent close too. Taxonomy/combobox filters need that first dismiss to close
8
+ * only the nested overlay while keeping the filter popover open.
9
+ */
10
+ export declare const useNestedOverlayPopoverOpenChange: ({ onOpenChange, popoverOpen, }: UseNestedOverlayPopoverOpenChangeProps) => {
11
+ handlePopoverOpenChange: (open: boolean) => void;
12
+ portalElement: HTMLElement;
13
+ setPopoverContentRef: (node: HTMLDivElement | null) => void;
14
+ };
15
+ export {};
@@ -1,6 +1,6 @@
1
1
  import { FilterOption } from '../filter-row/types';
2
- interface FilterProps extends FilterOption {
2
+ type FilterProps = FilterOption & {
3
3
  parentRef: HTMLElement;
4
- }
4
+ };
5
5
  export declare const Filter: ({ ...props }: FilterProps) => import("react/jsx-runtime").JSX.Element;
6
6
  export {};
@@ -30,6 +30,7 @@ export declare const ADVANCED_FILTER_IDS: {
30
30
  readonly fileSize: "file-size-filter";
31
31
  readonly phoneNumber: "phone-number-filter";
32
32
  readonly roleAdvanced: "role-advanced-filter";
33
+ readonly taxonomyAdvanced: "taxonomy-advanced-filter";
33
34
  };
34
35
  export declare const mockAdvancedFilterOptions: FilterOption[];
35
36
  export declare const mockFilterOptionsWithEnumPlaceholder: FilterOption[];
@@ -4,7 +4,7 @@ import { Selection } from 'react-aria-components';
4
4
  import { ActionBarProps, MetadataTableProps, PaginationProps } from './components';
5
5
  import { ItemActionMenuProps } from './components/item-action-menu';
6
6
  export declare const SELECT_ALL: "all";
7
- export type MetadataFieldType = 'date' | 'enum' | 'float' | 'multiSelect' | 'string';
7
+ export type MetadataFieldType = 'date' | 'enum' | 'float' | 'multiSelect' | 'string' | 'taxonomy';
8
8
  export type FilterVariant = 'default' | 'search' | 'file' | 'radio' | 'relative' | 'checkbox';
9
9
  export interface Column extends Partial<ColumnProps> {
10
10
  cellRenderer?: (item: Item, column: Column) => React.ReactNode | undefined;
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@box/metadata-view",
3
- "version": "1.59.15",
3
+ "version": "1.60.1",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "peerDependencies": {
6
- "@box/blueprint-web": "^14.36.0",
7
- "@box/blueprint-web-assets": "^4.120.2",
8
- "@box/box-item-type-selector": "^1.41.24",
9
- "@box/content-field": "^1.42.24",
10
- "@box/item-icon": "^2.35.24",
11
- "@box/metadata-filter": "^1.83.24",
12
- "@box/types": "2.2.3",
6
+ "@box/blueprint-web": "^14.36.1",
7
+ "@box/blueprint-web-assets": "^4.120.3",
8
+ "@box/box-item-type-selector": "^1.41.25",
9
+ "@box/content-field": "^1.42.25",
10
+ "@box/item-icon": "^2.35.25",
11
+ "@box/metadata-filter": "^1.83.26",
12
+ "@box/types": "2.2.4",
13
13
  "@tanstack/react-virtual": "^3.10.8",
14
14
  "formik": "^2.4.5",
15
15
  "lodash": "^4.17.15",
@@ -19,15 +19,15 @@
19
19
  "react-intl": "^6.4.2"
20
20
  },
21
21
  "devDependencies": {
22
- "@box/blueprint-web": "^14.36.0",
23
- "@box/blueprint-web-assets": "^4.120.2",
24
- "@box/box-item-type-selector": "^1.41.24",
25
- "@box/content-field": "^1.42.24",
26
- "@box/eslint-plugin-blueprint": "1.2.3",
27
- "@box/item-icon": "^2.35.24",
28
- "@box/metadata-filter": "^1.83.24",
29
- "@box/storybook-utils": "0.19.17",
30
- "@box/types": "2.2.3",
22
+ "@box/blueprint-web": "^14.36.1",
23
+ "@box/blueprint-web-assets": "^4.120.3",
24
+ "@box/box-item-type-selector": "^1.41.25",
25
+ "@box/content-field": "^1.42.25",
26
+ "@box/eslint-plugin-blueprint": "1.2.4",
27
+ "@box/item-icon": "^2.35.25",
28
+ "@box/metadata-filter": "^1.83.26",
29
+ "@box/storybook-utils": "0.19.18",
30
+ "@box/types": "2.2.4",
31
31
  "@tanstack/react-virtual": "^3.10.8",
32
32
  "react-intl": "^6.4.2"
33
33
  },