@jobber/components 9.6.2 → 9.6.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.
@@ -5,6 +5,7 @@ import { ComboboxClearSelection, ComboboxSelectAll, ComboboxSelectedCount } from
5
5
  import { ComboboxAction, ComboboxCollection, ComboboxGroup, ComboboxGroupLabel, ComboboxItem, ComboboxList, ComboboxRow, ComboboxSeparator } from "./Combobox.items";
6
6
  import { ComboboxPrimitive } from "../primitives/ComboboxPrimitive";
7
7
  declare function useFilter(options?: ComboboxFilterOptions): import("@base-ui/react").AutocompleteFilter;
8
+ declare function useFilteredItems<Value = unknown>(): Value[];
8
9
  declare function ComboboxRoot<Value, Multiple extends boolean | undefined = false>({ children, className, description, disabled, error, invalid, label, modal, style, multiple, readOnly, size, ...rootProps }: ComboboxRootProps<Value, Multiple>): React.JSX.Element;
9
10
  declare function ComboboxLabel({ className, ...labelProps }: ComboboxLabelProps): React.JSX.Element;
10
11
  declare function ComboboxLabelNote({ className, ...labelNoteProps }: ComboboxLabelNoteProps): React.JSX.Element;
@@ -63,6 +64,7 @@ declare const Combobox: typeof ComboboxRoot & {
63
64
  ClearSelection: typeof ComboboxClearSelection;
64
65
  SelectAll: typeof ComboboxSelectAll;
65
66
  useFilter: typeof useFilter;
67
+ useFilteredItems: typeof useFilteredItems;
66
68
  getSelectAllState: typeof getSelectAllState;
67
69
  getNextSelectAllValues: typeof getNextSelectAllValues;
68
70
  };
@@ -19,7 +19,7 @@ export declare const DEFAULT_COMBOBOX_RESPONSIVE_CONFIG: {
19
19
  positionerProps: {};
20
20
  showChipRemove: true;
21
21
  };
22
- export declare function getComboboxResponsiveConfig(width: number | undefined): {
22
+ export declare function getComboboxResponsiveConfig(isSmallScreen: boolean): {
23
23
  defaultModal: false;
24
24
  footerActionButtonRecipe: {
25
25
  size: "small";
@@ -3,9 +3,7 @@
3
3
  var Combobox = require('../Combobox-cjs.js');
4
4
  require('../tslib.es6-cjs.js');
5
5
  require('react');
6
- require('@jobber/hooks');
7
6
  require('classnames');
8
- require('../getMappedBreakpointWidth-cjs.js');
9
7
  require('../Button-cjs.js');
10
8
  require('react-router-dom');
11
9
  require('../Icon-cjs.js');
@@ -1,9 +1,7 @@
1
1
  export { C as Combobox } from '../Combobox-es.js';
2
2
  import '../tslib.es6-es.js';
3
3
  import 'react';
4
- import '@jobber/hooks';
5
4
  import 'classnames';
6
- import '../getMappedBreakpointWidth-es.js';
7
5
  import '../Button-es.js';
8
6
  import 'react-router-dom';
9
7
  import '../Icon-es.js';
@@ -2,9 +2,7 @@
2
2
 
3
3
  var tslib_es6 = require('./tslib.es6-cjs.js');
4
4
  var React = require('react');
5
- var jobberHooks = require('@jobber/hooks');
6
5
  var classnames = require('classnames');
7
- var getMappedBreakpointWidth = require('./getMappedBreakpointWidth-cjs.js');
8
6
  var Button = require('./Button-cjs.js');
9
7
  var buttonRenderAdapter = require('./buttonRenderAdapter-cjs.js');
10
8
  var ComboboxPrimitive = require('./ComboboxPrimitive-cjs.js');
@@ -16,6 +14,56 @@ var Glimmer = require('./Glimmer-cjs.js');
16
14
  var HelperText = require('./HelperText-cjs.js');
17
15
  var FieldDescription = require('./FieldDescription-cjs.js');
18
16
 
17
+ function getWindowDimensions() {
18
+ if (!(globalThis === null || globalThis === void 0 ? void 0 : globalThis.document)) {
19
+ return {
20
+ width: undefined,
21
+ height: undefined,
22
+ };
23
+ }
24
+ const { innerWidth: width, innerHeight: height } = window;
25
+ return {
26
+ width,
27
+ height,
28
+ };
29
+ }
30
+ function useWindowDimensions() {
31
+ const [windowDimensions, setWindowDimensions] = React.useState(getWindowDimensions());
32
+ React.useEffect(() => {
33
+ function handleResize() {
34
+ setWindowDimensions(getWindowDimensions());
35
+ }
36
+ window === null || window === void 0 ? void 0 : window.addEventListener("resize", handleResize);
37
+ return () => window === null || window === void 0 ? void 0 : window.removeEventListener("resize", handleResize);
38
+ }, []);
39
+ return windowDimensions;
40
+ }
41
+
42
+ const BREAKPOINT_SIZES = { sm: 490, md: 768, lg: 1080, xl: 1440 };
43
+
44
+ /**
45
+ * SSR-safe check for whether the viewport is a small ("mobile") web screen,
46
+ * i.e. at or below the `sm` breakpoint.
47
+ *
48
+ * Returns `false` on the server and on the client's first (hydration) render —
49
+ * regardless of the real viewport — so the two renders agree and React can
50
+ * hydrate without a mismatch. After mount an effect re-renders with the value
51
+ * derived from the real viewport width, and it stays in sync on resize via
52
+ * `useWindowDimensions`.
53
+ *
54
+ * Prefer this over reading `useWindowDimensions` directly whenever the viewport
55
+ * size decides which DOM is rendered (e.g. an anchored dropdown vs. a
56
+ * `BottomSheet`). Reading the width directly re-introduces the hydration
57
+ * mismatch, because the client's first render sees the real width while the
58
+ * server saw `undefined`.
59
+ */
60
+ function useIsSmallScreen() {
61
+ const [hasMounted, setHasMounted] = React.useState(false);
62
+ const { width } = useWindowDimensions();
63
+ React.useEffect(() => setHasMounted(true), []);
64
+ return hasMounted && width !== undefined && width <= BREAKPOINT_SIZES.sm;
65
+ }
66
+
19
67
  function defaultIsItemEqual(candidateValue, selectedValue) {
20
68
  return Object.is(candidateValue, selectedValue);
21
69
  }
@@ -75,11 +123,10 @@ const MOBILE_COMBOBOX_RESPONSIVE_CONFIG = {
75
123
  },
76
124
  showChipRemove: false,
77
125
  };
78
- function getComboboxResponsiveConfig(width) {
79
- if (width !== undefined && width <= getMappedBreakpointWidth.AtlantisBreakpoints.sm) {
80
- return MOBILE_COMBOBOX_RESPONSIVE_CONFIG;
81
- }
82
- return DEFAULT_COMBOBOX_RESPONSIVE_CONFIG;
126
+ function getComboboxResponsiveConfig(isSmallScreen) {
127
+ return isSmallScreen
128
+ ? MOBILE_COMBOBOX_RESPONSIVE_CONFIG
129
+ : DEFAULT_COMBOBOX_RESPONSIVE_CONFIG;
83
130
  }
84
131
 
85
132
  const ComboboxContext = React.createContext(null);
@@ -370,6 +417,9 @@ function useFilter(options) {
370
417
  const { locale } = AtlantisContext.useAtlantisContext();
371
418
  return ComboboxPrimitive.useFilter(Object.assign({ locale }, options));
372
419
  }
420
+ function useFilteredItems() {
421
+ return ComboboxPrimitive.useFilteredItems();
422
+ }
373
423
  function getIconSize(size) {
374
424
  if (size === "small")
375
425
  return "small";
@@ -426,8 +476,8 @@ function getDefaultEmptyChildren({ empty, hasLoading }, emptyContent) {
426
476
  }
427
477
  function ComboboxRoot(_a) {
428
478
  var { children, className, description, disabled, error, invalid, label, modal, style, multiple, readOnly, size = DEFAULT_SIZE } = _a, rootProps = tslib_es6.__rest(_a, ["children", "className", "description", "disabled", "error", "invalid", "label", "modal", "style", "multiple", "readOnly", "size"]);
429
- const { width } = jobberHooks.useWindowDimensions();
430
- const responsive = getComboboxResponsiveConfig(width);
479
+ const isSmallScreen = useIsSmallScreen();
480
+ const responsive = getComboboxResponsiveConfig(isSmallScreen);
431
481
  const [positionerAnchor, setPositionerAnchor] = React.useState(null);
432
482
  const contextValue = React.useMemo(() => ({
433
483
  disabled: Boolean(disabled),
@@ -668,6 +718,7 @@ const Combobox = Object.assign(ComboboxRoot, {
668
718
  ClearSelection: ComboboxClearSelection,
669
719
  SelectAll: ComboboxSelectAll,
670
720
  useFilter,
721
+ useFilteredItems,
671
722
  getSelectAllState,
672
723
  getNextSelectAllValues,
673
724
  });
@@ -1,11 +1,9 @@
1
1
  import { _ as __rest } from './tslib.es6-es.js';
2
- import React__default from 'react';
3
- import { useWindowDimensions } from '@jobber/hooks';
2
+ import React__default, { useState, useEffect } from 'react';
4
3
  import classnames from 'classnames';
5
- import { A as AtlantisBreakpoints } from './getMappedBreakpointWidth-es.js';
6
4
  import { B as Button } from './Button-es.js';
7
5
  import { n as normalizeBaseUiButtonProps } from './buttonRenderAdapter-es.js';
8
- import { a as ComboboxValue, b as ComboboxClear$1, c as ComboboxList$1, d as ComboboxItem$1, e as ComboboxItemIndicator$1, f as ComboboxRow$1, g as ComboboxCollection$1, h as ComboboxGroup$1, i as ComboboxGroupLabel$1, j as ComboboxSeparator$1, k as ComboboxIcon, l as ComboboxChip, m as ComboboxChipRemove, n as ComboboxStatus, u as useFilter$1, o as ComboboxRoot$1, p as ComboboxInputGroup$1, q as ComboboxInput$1, r as ComboboxTrigger$1, s as ComboboxPortal, t as ComboboxBackdrop, v as ComboboxPositioner, w as ComboboxPopup, x as ComboboxChips$1, y as ComboboxEmpty$1 } from './ComboboxPrimitive-es.js';
6
+ import { a as ComboboxValue, b as ComboboxClear$1, c as ComboboxList$1, d as ComboboxItem$1, e as ComboboxItemIndicator$1, f as ComboboxRow$1, g as ComboboxCollection$1, h as ComboboxGroup$1, i as ComboboxGroupLabel$1, j as ComboboxSeparator$1, k as ComboboxIcon, l as ComboboxChip, m as ComboboxChipRemove, n as ComboboxStatus, u as useFilter$1, o as useFilteredItems$1, p as ComboboxRoot$1, q as ComboboxInputGroup$1, r as ComboboxInput$1, s as ComboboxTrigger$1, t as ComboboxPortal, v as ComboboxBackdrop, w as ComboboxPositioner, x as ComboboxPopup, y as ComboboxChips$1, z as ComboboxEmpty$1 } from './ComboboxPrimitive-es.js';
9
7
  import { m as mergeProps } from './useRenderElement-es.js';
10
8
  import { I as Icon } from './Icon-es.js';
11
9
  import { m as mergeClassName } from './mergeClassName-es.js';
@@ -14,6 +12,56 @@ import { G as Glimmer } from './Glimmer-es.js';
14
12
  import { H as HelperText } from './HelperText-es.js';
15
13
  import { F as FieldRoot, a as FieldLabel, b as FieldDescription, c as FieldError } from './FieldDescription-es.js';
16
14
 
15
+ function getWindowDimensions() {
16
+ if (!(globalThis === null || globalThis === void 0 ? void 0 : globalThis.document)) {
17
+ return {
18
+ width: undefined,
19
+ height: undefined,
20
+ };
21
+ }
22
+ const { innerWidth: width, innerHeight: height } = window;
23
+ return {
24
+ width,
25
+ height,
26
+ };
27
+ }
28
+ function useWindowDimensions() {
29
+ const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());
30
+ useEffect(() => {
31
+ function handleResize() {
32
+ setWindowDimensions(getWindowDimensions());
33
+ }
34
+ window === null || window === void 0 ? void 0 : window.addEventListener("resize", handleResize);
35
+ return () => window === null || window === void 0 ? void 0 : window.removeEventListener("resize", handleResize);
36
+ }, []);
37
+ return windowDimensions;
38
+ }
39
+
40
+ const BREAKPOINT_SIZES = { sm: 490, md: 768, lg: 1080, xl: 1440 };
41
+
42
+ /**
43
+ * SSR-safe check for whether the viewport is a small ("mobile") web screen,
44
+ * i.e. at or below the `sm` breakpoint.
45
+ *
46
+ * Returns `false` on the server and on the client's first (hydration) render —
47
+ * regardless of the real viewport — so the two renders agree and React can
48
+ * hydrate without a mismatch. After mount an effect re-renders with the value
49
+ * derived from the real viewport width, and it stays in sync on resize via
50
+ * `useWindowDimensions`.
51
+ *
52
+ * Prefer this over reading `useWindowDimensions` directly whenever the viewport
53
+ * size decides which DOM is rendered (e.g. an anchored dropdown vs. a
54
+ * `BottomSheet`). Reading the width directly re-introduces the hydration
55
+ * mismatch, because the client's first render sees the real width while the
56
+ * server saw `undefined`.
57
+ */
58
+ function useIsSmallScreen() {
59
+ const [hasMounted, setHasMounted] = useState(false);
60
+ const { width } = useWindowDimensions();
61
+ useEffect(() => setHasMounted(true), []);
62
+ return hasMounted && width !== undefined && width <= BREAKPOINT_SIZES.sm;
63
+ }
64
+
17
65
  function defaultIsItemEqual(candidateValue, selectedValue) {
18
66
  return Object.is(candidateValue, selectedValue);
19
67
  }
@@ -73,11 +121,10 @@ const MOBILE_COMBOBOX_RESPONSIVE_CONFIG = {
73
121
  },
74
122
  showChipRemove: false,
75
123
  };
76
- function getComboboxResponsiveConfig(width) {
77
- if (width !== undefined && width <= AtlantisBreakpoints.sm) {
78
- return MOBILE_COMBOBOX_RESPONSIVE_CONFIG;
79
- }
80
- return DEFAULT_COMBOBOX_RESPONSIVE_CONFIG;
124
+ function getComboboxResponsiveConfig(isSmallScreen) {
125
+ return isSmallScreen
126
+ ? MOBILE_COMBOBOX_RESPONSIVE_CONFIG
127
+ : DEFAULT_COMBOBOX_RESPONSIVE_CONFIG;
81
128
  }
82
129
 
83
130
  const ComboboxContext = React__default.createContext(null);
@@ -368,6 +415,9 @@ function useFilter(options) {
368
415
  const { locale } = useAtlantisContext();
369
416
  return useFilter$1(Object.assign({ locale }, options));
370
417
  }
418
+ function useFilteredItems() {
419
+ return useFilteredItems$1();
420
+ }
371
421
  function getIconSize(size) {
372
422
  if (size === "small")
373
423
  return "small";
@@ -424,8 +474,8 @@ function getDefaultEmptyChildren({ empty, hasLoading }, emptyContent) {
424
474
  }
425
475
  function ComboboxRoot(_a) {
426
476
  var { children, className, description, disabled, error, invalid, label, modal, style, multiple, readOnly, size = DEFAULT_SIZE } = _a, rootProps = __rest(_a, ["children", "className", "description", "disabled", "error", "invalid", "label", "modal", "style", "multiple", "readOnly", "size"]);
427
- const { width } = useWindowDimensions();
428
- const responsive = getComboboxResponsiveConfig(width);
477
+ const isSmallScreen = useIsSmallScreen();
478
+ const responsive = getComboboxResponsiveConfig(isSmallScreen);
429
479
  const [positionerAnchor, setPositionerAnchor] = React__default.useState(null);
430
480
  const contextValue = React__default.useMemo(() => ({
431
481
  disabled: Boolean(disabled),
@@ -666,6 +716,7 @@ const Combobox = Object.assign(ComboboxRoot, {
666
716
  ClearSelection: ComboboxClearSelection,
667
717
  SelectAll: ComboboxSelectAll,
668
718
  useFilter,
719
+ useFilteredItems,
669
720
  getSelectAllState,
670
721
  getNextSelectAllValues,
671
722
  });
@@ -92,7 +92,7 @@ function ComboboxPositioner(_a) {
92
92
  }
93
93
  function ComboboxPopup(_a) {
94
94
  var { className } = _a, popupProps = tslib_es6.__rest(_a, ["className"]);
95
- return (React.createElement(ComboboxChipRemove$1.ComboboxPopup, Object.assign({}, popupProps, { className: mergeClassName.mergeClassName(styles.popup, className) })));
95
+ return (React.createElement(ComboboxChipRemove$1.ComboboxPopup, Object.assign({}, popupProps, { className: mergeClassName.mergeClassName(styles.popup, className), "data-elevation": "elevated" })));
96
96
  }
97
97
  function ComboboxArrow(_a) {
98
98
  var { className } = _a, arrowProps = tslib_es6.__rest(_a, ["className"]);
@@ -150,7 +150,9 @@ function ComboboxSeparator(_a) {
150
150
  return (React.createElement(Separator.Separator, Object.assign({}, separatorProps, { className: mergeClassName.mergeClassName(styles.separator, className) })));
151
151
  }
152
152
  const useFilter = ComboboxChipRemove$1.useComboboxFilter;
153
- const useFilteredItems = ComboboxChipRemove$1.useFilteredItems;
153
+ function useFilteredItems() {
154
+ return ComboboxChipRemove$1.useFilteredItems();
155
+ }
154
156
 
155
157
  var ComboboxPrimitive = /*#__PURE__*/Object.freeze({
156
158
  __proto__: null,
@@ -210,3 +212,4 @@ exports.ComboboxStatus = ComboboxStatus;
210
212
  exports.ComboboxTrigger = ComboboxTrigger;
211
213
  exports.ComboboxValue = ComboboxValue;
212
214
  exports.useFilter = useFilter;
215
+ exports.useFilteredItems = useFilteredItems;
@@ -90,7 +90,7 @@ function ComboboxPositioner(_a) {
90
90
  }
91
91
  function ComboboxPopup(_a) {
92
92
  var { className } = _a, popupProps = __rest(_a, ["className"]);
93
- return (React__default.createElement(ComboboxPopup$1, Object.assign({}, popupProps, { className: mergeClassName(styles.popup, className) })));
93
+ return (React__default.createElement(ComboboxPopup$1, Object.assign({}, popupProps, { className: mergeClassName(styles.popup, className), "data-elevation": "elevated" })));
94
94
  }
95
95
  function ComboboxArrow(_a) {
96
96
  var { className } = _a, arrowProps = __rest(_a, ["className"]);
@@ -148,7 +148,9 @@ function ComboboxSeparator(_a) {
148
148
  return (React__default.createElement(Separator, Object.assign({}, separatorProps, { className: mergeClassName(styles.separator, className) })));
149
149
  }
150
150
  const useFilter = useComboboxFilter;
151
- const useFilteredItems = useFilteredItems$1;
151
+ function useFilteredItems() {
152
+ return useFilteredItems$1();
153
+ }
152
154
 
153
155
  var ComboboxPrimitive = /*#__PURE__*/Object.freeze({
154
156
  __proto__: null,
@@ -182,4 +184,4 @@ var ComboboxPrimitive = /*#__PURE__*/Object.freeze({
182
184
  useFilteredItems: useFilteredItems
183
185
  });
184
186
 
185
- export { ComboboxPrimitive as C, ComboboxValue as a, ComboboxClear as b, ComboboxList as c, ComboboxItem as d, ComboboxItemIndicator as e, ComboboxRow as f, ComboboxCollection as g, ComboboxGroup as h, ComboboxGroupLabel as i, ComboboxSeparator as j, ComboboxIcon as k, ComboboxChip as l, ComboboxChipRemove as m, ComboboxStatus as n, ComboboxRoot as o, ComboboxInputGroup as p, ComboboxInput as q, ComboboxTrigger as r, ComboboxPortal as s, ComboboxBackdrop as t, useFilter as u, ComboboxPositioner as v, ComboboxPopup as w, ComboboxChips as x, ComboboxEmpty as y };
187
+ export { ComboboxPrimitive as C, ComboboxValue as a, ComboboxClear as b, ComboboxList as c, ComboboxItem as d, ComboboxItemIndicator as e, ComboboxRow as f, ComboboxCollection as g, ComboboxGroup as h, ComboboxGroupLabel as i, ComboboxSeparator as j, ComboboxIcon as k, ComboboxChip as l, ComboboxChipRemove as m, ComboboxStatus as n, useFilteredItems as o, ComboboxRoot as p, ComboboxInputGroup as q, ComboboxInput as r, ComboboxTrigger as s, ComboboxPortal as t, useFilter as u, ComboboxBackdrop as v, ComboboxPositioner as w, ComboboxPopup as x, ComboboxChips as y, ComboboxEmpty as z };
@@ -5,7 +5,6 @@ require('react');
5
5
  require('classnames');
6
6
  require('@jobber/hooks');
7
7
  require('../getMappedAtlantisSpaceToken-cjs.js');
8
- require('../getMappedBreakpointWidth-cjs.js');
9
8
 
10
9
 
11
10
 
@@ -3,4 +3,3 @@ import 'react';
3
3
  import 'classnames';
4
4
  import '@jobber/hooks';
5
5
  import '../getMappedAtlantisSpaceToken-es.js';
6
- import '../getMappedBreakpointWidth-es.js';
@@ -4,12 +4,28 @@ var React = require('react');
4
4
  var classnames = require('classnames');
5
5
  var jobberHooks = require('@jobber/hooks');
6
6
  var getMappedAtlantisSpaceToken = require('./getMappedAtlantisSpaceToken-cjs.js');
7
- var getMappedBreakpointWidth = require('./getMappedBreakpointWidth-cjs.js');
8
7
 
9
8
  var styles = {"contentBlock":"rJamQZ6fRes-","left":"bqjXV8MRO-4-","right":"sCMxIxKkFe0-","center":"_2pIQVKvVL1I-","andText":"_6dF2no3aTxw-","gutters":"_8k8YLsatGag-","spinning":"sjMwRWFdKeo-"};
10
9
 
10
+ const AtlantisBreakpoints = {
11
+ xs: 0,
12
+ sm: 490,
13
+ md: 768,
14
+ lg: 1080,
15
+ xl: 1440,
16
+ };
17
+ const getMappedBreakpointWidth = (maxWidth) => {
18
+ if (typeof maxWidth === "number") {
19
+ return `${maxWidth}px`;
20
+ }
21
+ if (AtlantisBreakpoints[maxWidth]) {
22
+ return (AtlantisBreakpoints[maxWidth] + "px");
23
+ }
24
+ return maxWidth;
25
+ };
26
+
11
27
  function ContentBlock({ children, maxWidth = jobberHooks.Breakpoints.smaller, andText, gutters, justify = "left", as: Tag = "div", dataAttributes, ariaAttributes, role, id, UNSAFE_className, UNSAFE_style, }) {
12
- return (React.createElement(Tag, Object.assign({ role: role, id: id }, dataAttributes, ariaAttributes, { style: Object.assign({ "--content-block-max-width": getMappedBreakpointWidth.getMappedBreakpointWidth(maxWidth), "--content-block-gutters": getMappedAtlantisSpaceToken.getMappedAtlantisSpaceToken(gutters) }, UNSAFE_style === null || UNSAFE_style === void 0 ? void 0 : UNSAFE_style.container), className: classnames(styles.contentBlock, andText && styles.andText, gutters && styles.gutters, justify === "left" && styles.left, justify === "right" && styles.right, justify === "center" && styles.center, UNSAFE_className === null || UNSAFE_className === void 0 ? void 0 : UNSAFE_className.container) }), children));
28
+ return (React.createElement(Tag, Object.assign({ role: role, id: id }, dataAttributes, ariaAttributes, { style: Object.assign({ "--content-block-max-width": getMappedBreakpointWidth(maxWidth), "--content-block-gutters": getMappedAtlantisSpaceToken.getMappedAtlantisSpaceToken(gutters) }, UNSAFE_style === null || UNSAFE_style === void 0 ? void 0 : UNSAFE_style.container), className: classnames(styles.contentBlock, andText && styles.andText, gutters && styles.gutters, justify === "left" && styles.left, justify === "right" && styles.right, justify === "center" && styles.center, UNSAFE_className === null || UNSAFE_className === void 0 ? void 0 : UNSAFE_className.container) }), children));
13
29
  }
14
30
 
15
31
  exports.ContentBlock = ContentBlock;
@@ -2,10 +2,26 @@ import React__default from 'react';
2
2
  import classnames from 'classnames';
3
3
  import { Breakpoints } from '@jobber/hooks';
4
4
  import { g as getMappedAtlantisSpaceToken } from './getMappedAtlantisSpaceToken-es.js';
5
- import { g as getMappedBreakpointWidth } from './getMappedBreakpointWidth-es.js';
6
5
 
7
6
  var styles = {"contentBlock":"rJamQZ6fRes-","left":"bqjXV8MRO-4-","right":"sCMxIxKkFe0-","center":"_2pIQVKvVL1I-","andText":"_6dF2no3aTxw-","gutters":"_8k8YLsatGag-","spinning":"sjMwRWFdKeo-"};
8
7
 
8
+ const AtlantisBreakpoints = {
9
+ xs: 0,
10
+ sm: 490,
11
+ md: 768,
12
+ lg: 1080,
13
+ xl: 1440,
14
+ };
15
+ const getMappedBreakpointWidth = (maxWidth) => {
16
+ if (typeof maxWidth === "number") {
17
+ return `${maxWidth}px`;
18
+ }
19
+ if (AtlantisBreakpoints[maxWidth]) {
20
+ return (AtlantisBreakpoints[maxWidth] + "px");
21
+ }
22
+ return maxWidth;
23
+ };
24
+
9
25
  function ContentBlock({ children, maxWidth = Breakpoints.smaller, andText, gutters, justify = "left", as: Tag = "div", dataAttributes, ariaAttributes, role, id, UNSAFE_className, UNSAFE_style, }) {
10
26
  return (React__default.createElement(Tag, Object.assign({ role: role, id: id }, dataAttributes, ariaAttributes, { style: Object.assign({ "--content-block-max-width": getMappedBreakpointWidth(maxWidth), "--content-block-gutters": getMappedAtlantisSpaceToken(gutters) }, UNSAFE_style === null || UNSAFE_style === void 0 ? void 0 : UNSAFE_style.container), className: classnames(styles.contentBlock, andText && styles.andText, gutters && styles.gutters, justify === "left" && styles.left, justify === "right" && styles.right, justify === "center" && styles.center, UNSAFE_className === null || UNSAFE_className === void 0 ? void 0 : UNSAFE_className.container) }), children));
11
27
  }
@@ -0,0 +1,563 @@
1
+ # Combobox
2
+
3
+ ## Summary
4
+
5
+ Combobox lets a user search and select one or more values from a list. Use it
6
+ when the list benefits from filtering, when the selected values need to appear
7
+ in the field, or when the popup needs supporting actions such as creating a new
8
+ option.
9
+
10
+ Use Combobox when the selected value is saved, submitted, assigned, or otherwise
11
+ becomes part of the user's work.
12
+
13
+ ## Anatomy
14
+
15
+ | Part | Description |
16
+ | ----------- | ----------------------------------------------------------------- |
17
+ | Field | Label, optional note, description, and error treatment |
18
+ | Trigger | Visible field that opens the popup and displays the current value |
19
+ | Search | Input used to filter options, either in the trigger or popup |
20
+ | Content | Popup or mobile sheet that contains options and affordances |
21
+ | Item | Selectable option with optional prefix, description, and suffix |
22
+ | Empty state | Message shown when search has no matching options |
23
+ | Actions | Sticky action rows below the option list |
24
+ | Footer | Sticky region for multiple-selection affordances |
25
+
26
+ ## Behavior
27
+
28
+ #### Opening and closing
29
+
30
+ Combobox opens when the trigger is clicked, tapped, or activated by keyboard. It
31
+ closes when the user selects a single-select option, clicks or taps outside the
32
+ popup, or presses Esc.
33
+
34
+ Multiple-selection comboboxes stay open while values are selected so users can
35
+ choose more than one option.
36
+
37
+ #### Search
38
+
39
+ Search filters the option list as the user types. Search can happen directly in
40
+ the trigger or inside the popup, depending on the trigger pattern.
41
+
42
+ #### Empty state
43
+
44
+ When no options match, the empty state appears above actions and footer content.
45
+ This keeps creation actions and multiple-selection controls in predictable
46
+ locations.
47
+
48
+ #### Actions and footer
49
+
50
+ Actions are anchored below the option list. The multiple-selection footer is
51
+ anchored below options and actions when present.
52
+
53
+ #### Small screens
54
+
55
+ On small screens, Combobox automatically presents the popup as a bottom-anchored
56
+ sheet. Consumers use the same Combobox API across desktop and mobile web.
57
+
58
+ ## Trigger patterns
59
+
60
+ Use `Combobox.TriggerInput` when the user searches directly in the field.
61
+
62
+ Use `Combobox.TriggerValue` when the closed field should behave more like a
63
+ Select and search belongs inside the popup.
64
+
65
+ Use `Combobox.TriggerMultipleValue` for multi-select fields that show selected
66
+ chips in the closed field and keep search inside the popup.
67
+
68
+ ## Variants
69
+
70
+ #### Single select
71
+
72
+ Use single select when the user can choose one value.
73
+
74
+ #### Multiple select
75
+
76
+ Use multiple select when the user can choose several values and needs selected
77
+ values to remain visible in the field.
78
+
79
+ #### Popup search
80
+
81
+ Use popup search when the trigger should display the current value and search
82
+ should happen after the popup opens.
83
+
84
+ ## Item content
85
+
86
+ Items can be plain text for the default row treatment, or composed with
87
+ `Combobox.ItemPrefix`, `Combobox.ItemLabel`, `Combobox.ItemDescription`, and
88
+ `Combobox.ItemSuffix` for richer option content. The selected checkmark is
89
+ included by default.
90
+
91
+ ## Empty and loading states
92
+
93
+ Combobox includes a default empty state so search results always resolve in the
94
+ right place, above actions and footer content. Customize the message through
95
+ `Combobox.Content`, render your own `Combobox.Empty`, or opt out when the
96
+ experience needs to own that region.
97
+
98
+ Loading uses four glimmer rows by default. The row count and loading content can
99
+ be customized when a product needs a different loading treatment.
100
+
101
+ ## Actions
102
+
103
+ Actions are for work outside option selection, such as creating or inviting an
104
+ item. The default action row uses the leading add icon shown in Figma, while
105
+ `Combobox.ActionPrefix` and `Combobox.ActionLabel` are available when the row
106
+ needs custom content.
107
+
108
+ ## Multiple-selection footer
109
+
110
+ Use `Combobox.SelectionFooter` for the opinionated multiple-select footer. It
111
+ keeps selected count, clear, and select-all controls in a consistent order.
112
+
113
+ Select-all behavior is product-owned: the app decides whether "all" means
114
+ visible, filtered, loaded, paginated, or server-known results.
115
+
116
+ ## Content Guidelines
117
+
118
+ #### Labels
119
+
120
+ Use a short noun label that names the value being selected.
121
+
122
+ | ✅ Do | ❌ Don't |
123
+ | ------------ | -------------------------------- |
124
+ | Team member | Choose which team member to use |
125
+ | Job type | Select one of these job types |
126
+ | Service area | Search and pick a service region |
127
+
128
+ #### Search placeholder
129
+
130
+ Use placeholder text that describes what can be searched. Keep it short.
131
+
132
+ | ✅ Do | ❌ Don't |
133
+ | ------------------- | ----------------------------------------- |
134
+ | Search team members | Start typing to search all team members |
135
+ | Search clients | Enter the name of the client to find them |
136
+ | Search job types | Filter the dropdown |
137
+
138
+ #### Item text
139
+
140
+ Use the item label for the selectable value. Use descriptions only when they
141
+ help distinguish similar options.
142
+
143
+ | ✅ Do | ❌ Don't |
144
+ | ---------------------------- | ---------------------------------------- |
145
+ | Ryan Clearwater | Select Ryan Clearwater |
146
+ | Ryan Clearwater + Sales lead | Ryan Clearwater, who is the sales lead |
147
+ | Downtown + Service area | Downtown service area available for jobs |
148
+
149
+ #### Actions
150
+
151
+ Use actions for work outside option selection, such as creating or inviting an
152
+ item. Action labels should be verb-first and sentence-cased.
153
+
154
+ | ✅ Do | ❌ Don't |
155
+ | ------------------ | ------------------------ |
156
+ | Create team member | Team member creation |
157
+ | Invite team member | Send invitation to staff |
158
+ | Add client | Client |
159
+
160
+ ## Do's and Don'ts
161
+
162
+ #### Do
163
+
164
+ * ✅ Use Combobox when the list benefits from search or filtering
165
+ * ✅ Use enough item context to distinguish similar values
166
+ * ✅ Keep empty state above actions and footer controls
167
+ * ✅ Use the multiple-selection footer for clear and select-all affordances
168
+ * ✅ Define what "select all" means before including it
169
+
170
+ #### Don't
171
+
172
+ * ❌ Don't use Combobox for a tiny static list where Select is simpler
173
+ * ❌ Don't hide empty state behind actions or footer controls
174
+ * ❌ Don't assume "select all" means every server result
175
+ * ❌ Don't mix unrelated actions into the popup
176
+ * ❌ Don't overload item rows with content that slows scanning
177
+
178
+ ## Rich item data
179
+
180
+ Options can include more than a primary label when extra context helps users
181
+ choose confidently. Use descriptions, prefixes, or suffixes when similar options
182
+ need to be distinguished at a glance. Those fields can also be made filterable,
183
+ so search can match the details users naturally type.
184
+
185
+ ## Accessibility
186
+
187
+ Combobox should have a clear accessible label. Keyboard behavior and active item
188
+ management are provided by Base UI.
189
+
190
+ #### Keyboard navigation
191
+
192
+ | Key | Behavior |
193
+ | ------------------ | ------------------------------------------------------ |
194
+ | Tab | Moves focus to the trigger, actions, or footer buttons |
195
+ | Up and Down arrows | Moves through available options |
196
+ | Enter | Selects the highlighted option or activates an action |
197
+ | Esc | Closes the popup |
198
+
199
+ ## Related components
200
+
201
+ * To choose one value from a small static list, use [Select](../Select/Select.md)
202
+ * To present actions that do not filter or select form values, use
203
+ [Menu](../Menu/Menu.md)
204
+
205
+
206
+ ## Composition
207
+
208
+ Combobox is a composable field built on `ComboboxPrimitive`. The sugared
209
+ component provides common recipes while preserving access to lower-level pieces
210
+ when a product flow needs more control.
211
+
212
+ ### Trigger recipes
213
+
214
+ Most implementations should start with one of the trigger recipes.
215
+
216
+ #### `Combobox.TriggerInput`
217
+
218
+ Use `Combobox.TriggerInput` when the user should search directly in the field.
219
+
220
+ ```tsx
221
+ <Combobox label="Team member" items={teamMembers}>
222
+ <Combobox.TriggerInput placeholder="Search team members" />
223
+ <Combobox.Content>
224
+ <Combobox.List>
225
+ {member => (
226
+ <Combobox.Item key={member.id} value={member}>
227
+ {member.name}
228
+ </Combobox.Item>
229
+ )}
230
+ </Combobox.List>
231
+ </Combobox.Content>
232
+ </Combobox>
233
+ ```
234
+
235
+ #### `Combobox.TriggerValue`
236
+
237
+ Use `Combobox.TriggerValue` when the closed field should display the selected
238
+ value and the search input should live inside the popup.
239
+
240
+ ```tsx
241
+ <Combobox label="Team member" items={teamMembers}>
242
+ <Combobox.TriggerValue placeholder="Select team member" />
243
+ <Combobox.Content>
244
+ <Combobox.Input placeholder="Search team members" />
245
+ <Combobox.List>
246
+ {member => (
247
+ <Combobox.Item key={member.id} value={member}>
248
+ {member.name}
249
+ </Combobox.Item>
250
+ )}
251
+ </Combobox.List>
252
+ </Combobox.Content>
253
+ </Combobox>
254
+ ```
255
+
256
+ #### `Combobox.TriggerMultipleValue`
257
+
258
+ Use `Combobox.TriggerMultipleValue` when the closed field should display
259
+ selected chips and the search input should live inside the popup.
260
+
261
+ ```tsx
262
+ <Combobox multiple label="Assigned team" items={teamMembers}>
263
+ <Combobox.TriggerMultipleValue getItemLabel={member => member.name} />
264
+ <Combobox.Content>
265
+ <Combobox.Input placeholder="Search team members" />
266
+ <Combobox.List>
267
+ {member => (
268
+ <Combobox.Item key={member.id} value={member}>
269
+ {member.name}
270
+ </Combobox.Item>
271
+ )}
272
+ </Combobox.List>
273
+ </Combobox.Content>
274
+ </Combobox>
275
+ ```
276
+
277
+ #### `Combobox.TriggerMultipleWithInput`
278
+
279
+ Use `Combobox.TriggerMultipleWithInput` when multi-select chips and search
280
+ should both live in the trigger.
281
+
282
+ ```tsx
283
+ <Combobox multiple label="Assigned team" items={teamMembers}>
284
+ <Combobox.TriggerMultipleWithInput getItemLabel={member => member.name} />
285
+ <Combobox.Content>
286
+ <Combobox.List>
287
+ {member => (
288
+ <Combobox.Item key={member.id} value={member}>
289
+ {member.name}
290
+ </Combobox.Item>
291
+ )}
292
+ </Combobox.List>
293
+ </Combobox.Content>
294
+ </Combobox>
295
+ ```
296
+
297
+ ### Field text
298
+
299
+ Pass `label`, `description`, and `error` on `Combobox` for the default Atlantis
300
+ field treatment. If the layout needs different placement, compose
301
+ `Combobox.Label`, `Combobox.Description`, and `Combobox.Error` manually.
302
+
303
+ ```tsx
304
+ <Combobox
305
+ label="Team member"
306
+ description="Search by name"
307
+ error="Choose a team member"
308
+ items={teamMembers}
309
+ >
310
+ {/* trigger and content */}
311
+ </Combobox>
312
+ ```
313
+
314
+ ### Empty state
315
+
316
+ `Combobox.Content` renders `"No results found"` by default when search has no
317
+ matches. The empty state is placed after options and before actions or footer
318
+ content.
319
+
320
+ Use the `empty` prop to customize the default message:
321
+
322
+ ```tsx
323
+ <Combobox.Content empty="No team members found">
324
+ {/* options */}
325
+ </Combobox.Content>
326
+ ```
327
+
328
+ When the empty state needs custom markup, omit the automatic empty state and
329
+ render `Combobox.Empty` directly:
330
+
331
+ ```tsx
332
+ <Combobox.Content empty={null}>
333
+ <Combobox.List>{/* options */}</Combobox.List>
334
+ <Combobox.Empty>No team members match this search.</Combobox.Empty>
335
+ </Combobox.Content>
336
+ ```
337
+
338
+ ### Actions
339
+
340
+ Use `Combobox.Action` for interactive rows that are not selectable options, such
341
+ as creating a new customer or inviting a team member. Use `Combobox.Item` when
342
+ the row represents a value the Combobox can select.
343
+
344
+ ```tsx
345
+ <Combobox.Content empty={`No matches for "${query}"`}>
346
+ <Combobox.List>{/* options */}</Combobox.List>
347
+ <Combobox.Actions>
348
+ <Combobox.Action onClick={() => createTeamMember(query)}>
349
+ Create team member
350
+ </Combobox.Action>
351
+ </Combobox.Actions>
352
+ </Combobox.Content>
353
+ ```
354
+
355
+ Clicking an action runs the action's handler and leaves the popup open. If an
356
+ action should close the popup, control `open` from product state and set it to
357
+ `false` in the action handler. If the action opens another overlay, such as a
358
+ Dialog, also coordinate that from product state so focus and closing behavior
359
+ match the product flow.
360
+
361
+ ```tsx
362
+ const [open, setOpen] = useState(false);
363
+
364
+ <Combobox open={open} onOpenChange={setOpen}>
365
+ <Combobox.TriggerInput />
366
+ <Combobox.Content>
367
+ <Combobox.List>{/* options */}</Combobox.List>
368
+ <Combobox.Actions>
369
+ <Combobox.Action
370
+ onClick={() => {
371
+ createTeamMember();
372
+ setOpen(false);
373
+ }}
374
+ >
375
+ Create team member
376
+ </Combobox.Action>
377
+ </Combobox.Actions>
378
+ </Combobox.Content>
379
+ </Combobox>;
380
+ ```
381
+
382
+ ### Footer and select all
383
+
384
+ `Combobox.SelectionFooter` is the default multiple-select footer. It owns the
385
+ visual ordering for selected count, clear, and select all. Use
386
+ `showSelectedCount={false}` when the count should be omitted.
387
+
388
+ Select-all behavior is intentionally not automatic. Products must decide the
389
+ candidate set and pass `onSelectAll`.
390
+
391
+ ```tsx
392
+ const selectAllState = Combobox.getSelectAllState({
393
+ selectedValues,
394
+ candidateValues: visibleValues,
395
+ });
396
+ ```
397
+
398
+ The candidate set can be visible results, filtered results, loaded results, the
399
+ current page, or another product-defined set.
400
+
401
+ ```tsx
402
+ const [selectedMembers, setSelectedMembers] = useState([]);
403
+ const selectAllState = Combobox.getSelectAllState({
404
+ selectedValues: selectedMembers,
405
+ candidateValues: visibleMembers,
406
+ });
407
+
408
+ <Combobox
409
+ multiple
410
+ value={selectedMembers}
411
+ onValueChange={setSelectedMembers}
412
+ items={visibleMembers}
413
+ >
414
+ <Combobox.TriggerMultipleValue getItemLabel={member => member.name} />
415
+ <Combobox.Content>
416
+ <Combobox.Input placeholder="Search team members" />
417
+ <Combobox.List>{/* options */}</Combobox.List>
418
+ <Combobox.SelectionFooter
419
+ selectAllState={selectAllState}
420
+ onSelectAll={() =>
421
+ setSelectedMembers(
422
+ Combobox.getNextSelectAllValues({
423
+ selectedValues: selectedMembers,
424
+ candidateValues: visibleMembers,
425
+ })
426
+ )
427
+ }
428
+ />
429
+ </Combobox.Content>
430
+ </Combobox>;
431
+ ```
432
+
433
+ ## Controlled and uncontrolled usage
434
+
435
+ Combobox follows Base UI's value model. Use `value` and `onValueChange` when the
436
+ app owns selection state, or `defaultValue` for uncontrolled selection.
437
+
438
+ Single-select values are one item or `null`. Multi-select values are arrays.
439
+ When values are objects, use `itemToString` for display and `itemToValue` for
440
+ form submission.
441
+
442
+ ```tsx
443
+ <Combobox
444
+ value={selectedMember}
445
+ onValueChange={setSelectedMember}
446
+ itemToString={member => member?.name ?? ""}
447
+ itemToValue={member => member.id}
448
+ items={teamMembers}
449
+ >
450
+ {/* trigger and content */}
451
+ </Combobox>
452
+ ```
453
+
454
+ ## Filtering and data strategy
455
+
456
+ For local data, pass `items` and optionally customize the root `filter` prop.
457
+ `Combobox.useFilter` exposes Base UI's filter helper with Atlantis locale wired
458
+ in, so matching handles locale-sensitive text consistently.
459
+
460
+ ```tsx
461
+ const filter = Combobox.useFilter();
462
+
463
+ <Combobox
464
+ items={teamMembers}
465
+ filter={(member, query) =>
466
+ filter.contains(member.name, query) ||
467
+ filter.contains(member.department, query) ||
468
+ filter.contains(member.role, query)
469
+ }
470
+ >
471
+ {/* trigger and content */}
472
+ </Combobox>;
473
+ ```
474
+
475
+ `Combobox.useFilteredItems` exposes Base UI's filtered item collection for
476
+ custom list rendering, virtualization, or pagination affordances. It does not
477
+ load additional data on its own; it only reads the filtered items currently
478
+ known to Combobox.
479
+
480
+ Combobox does not own pagination, but it gives products the pieces to build it.
481
+ Pass the currently loaded items into `items`, load additional pages from product
482
+ state or an API call, and compose loading UI inside the popup with
483
+ `Combobox.Status` and `ActivityIndicator` when needed. For local large lists,
484
+ use `Combobox.useFilteredItems` when custom rendering or virtualization needs
485
+ access to the current filtered collection.
486
+
487
+ ```tsx
488
+ <Combobox.Content>
489
+ <Combobox.Input placeholder="Search team members" />
490
+ <Combobox.List>{/* loaded options */}</Combobox.List>
491
+ {isLoadingMore && (
492
+ <Combobox.Status>
493
+ <ActivityIndicator aria-label="Loading more team members" />
494
+ </Combobox.Status>
495
+ )}
496
+ </Combobox.Content>
497
+ ```
498
+
499
+ For async, paginated, virtualized, or server-filtered data, keep the data
500
+ strategy in product code. Fetch from input changes, pass the current loaded or
501
+ windowed items to Combobox, and disable client filtering when the server already
502
+ returned filtered results.
503
+
504
+ > **NOTICE:** Combobox does not infer total result sets, page boundaries, or select-all
505
+ > semantics for server-backed data.
506
+
507
+ ## Mobile web
508
+
509
+ Combobox automatically switches to a bottom-anchored sheet at the Atlantis small
510
+ breakpoint. This uses Base UI's Combobox modal and backdrop behavior, not
511
+ Atlantis `BottomSheet`, so consumers do not need a separate mobile API.
512
+
513
+
514
+ ## Props
515
+
516
+ ### Web
517
+
518
+ | Prop | Type | Required | Default | Description |
519
+ |------|------|----------|---------|-------------|
520
+ | `actionsRef` | `RefObject<Actions>` | No | — | A ref to imperative actions. - `unmount`: Manually unmounts the combobox. Call this after any externally controlled c... |
521
+ | `autoComplete` | `string` | No | — | Provides a hint to the browser for autofill. @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attribu... |
522
+ | `autoHighlight` | `boolean` | No | `false` | Whether the first matching item is highlighted automatically while filtering. |
523
+ | `className` | `string` | No | — | |
524
+ | `defaultInputValue` | `string | number | readonly string[]` | No | — | The uncontrolled input value when initially rendered. To render a controlled input, use the `inputValue` prop instead. |
525
+ | `defaultOpen` | `boolean` | No | `false` | Whether the popup is initially open. To render a controlled popup, use the `open` prop instead. |
526
+ | `defaultValue` | `ComboboxValueType<Value, Multiple>` | No | — | The uncontrolled selected value of the combobox when it's initially rendered. To render a controlled combobox, use t... |
527
+ | `description` | `string` | No | — | |
528
+ | `disabled` | `boolean` | No | `false` | Whether the component should ignore user interaction. |
529
+ | `error` | `string` | No | — | |
530
+ | `filter` | `(itemValue: Value, query: string, itemToString?: (itemValue: Value) => string) => boolean` | No | — | Filter function used to match items vs input query. |
531
+ | `filteredItems` | `readonly any[] | readonly Group<any>[]` | No | — | Filtered items to display in the list. When provided, the list will use these items instead of filtering the `items` ... |
532
+ | `form` | `string` | No | — | Identifies the form that owns the internal input. Useful when the combobox is rendered outside the form. |
533
+ | `grid` | `boolean` | No | `false` | Whether list items are presented in a grid layout. When enabled, arrow keys navigate across rows and columns inferred... |
534
+ | `highlightItemOnHover` | `boolean` | No | `true` | Whether moving the pointer over items should highlight them. Disabling this prop allows CSS `:hover` to be differenti... |
535
+ | `id` | `string` | No | — | The id of the component. |
536
+ | `inline` | `boolean` | No | `false` | Whether the list is rendered inline without using the component's own popup. Specify `open` unconditionally in conju... |
537
+ | `inputRef` | `Ref<HTMLInputElement>` | No | — | A ref to the hidden input element. |
538
+ | `inputValue` | `string | number | readonly string[]` | No | — | The input value of the combobox. Use when controlled. |
539
+ | `invalid` | `boolean` | No | — | |
540
+ | `isItemEqualToValue` | `(itemValue: Value, value: Value) => boolean` | No | — | Custom comparison logic used to determine if a combobox item value matches the current selected value. Useful when it... |
541
+ | `items` | `readonly any[] | readonly Group<any>[]` | No | — | The items to be displayed in the list. Can be either a flat array of items or an array of groups with items. |
542
+ | `itemToStringLabel` | `(itemValue: Value) => string` | No | — | When the item values are objects (`<Combobox.Item value={object}>`), this function converts the object value to a str... |
543
+ | `itemToStringValue` | `(itemValue: Value) => string` | No | — | When the item values are objects (`<Combobox.Item value={object}>`), this function converts the object value to a str... |
544
+ | `label` | `ReactNode` | No | — | |
545
+ | `limit` | `number` | No | `-1` | The maximum number of items to display in the list. |
546
+ | `locale` | `LocalesArgument` | No | — | The locale to use for string comparison. Defaults to the user's runtime locale. |
547
+ | `loopFocus` | `boolean` | No | `true` | Whether to loop keyboard focus back to the input when the end of the list is reached while using the arrow keys. The ... |
548
+ | `modal` | `boolean` | No | `false` | Determines if the popup enters a modal state when open. - `true`: user interaction is limited to the popup: document ... |
549
+ | `multiple` | `boolean` | No | `false` | Whether multiple items can be selected. |
550
+ | `name` | `string` | No | — | Identifies the field when a form is submitted. |
551
+ | `onInputValueChange` | `(inputValue: string, eventDetails: ChangeEventDetails) => void` | No | — | Event handler called when the input value changes. |
552
+ | `onItemHighlighted` | `(highlightedValue: Value, eventDetails: HighlightEventDetails) => void` | No | — | Callback fired when an item is highlighted or unhighlighted. Receives the highlighted item value (or `undefined` if n... |
553
+ | `onOpenChange` | `(open: boolean, eventDetails: ChangeEventDetails) => void` | No | — | Event handler called when the popup is opened or closed. |
554
+ | `onOpenChangeComplete` | `(open: boolean) => void` | No | — | Event handler called after any animations complete when the popup is opened or closed. |
555
+ | `onValueChange` | `(value: ComboboxValueType<Value, Multiple> | (Multiple extends true ? never : null), eventDetails: ChangeEventDetails) => void` | No | — | Event handler called when the selected value of the combobox changes. |
556
+ | `open` | `boolean` | No | — | Whether the popup is currently open. Use when controlled. |
557
+ | `openOnInputClick` | `boolean` | No | `true` | Whether the popup opens when clicking the input. |
558
+ | `readOnly` | `boolean` | No | `false` | Whether the user should be unable to choose a different option from the popup. |
559
+ | `required` | `boolean` | No | `false` | Whether the user must choose a value before submitting a form. |
560
+ | `size` | `ComboboxSize` | No | — | |
561
+ | `style` | `CSSProperties` | No | — | |
562
+ | `value` | `ComboboxValueType<Value, Multiple>` | No | — | The selected value of the combobox. Use when controlled. |
563
+ | `virtualized` | `boolean` | No | `false` | Whether the items are being externally virtualized. |
@@ -1,20 +1,18 @@
1
1
  # FilterPicker
2
2
 
3
- > **NOTICE:** This component was previously named `Combobox`. Use `FilterPicker` as the
4
- > direct replacement.
3
+ > **NOTICE:** This component was previously named `Combobox`. Use `FilterPicker` for
4
+ > filtering existing content. For searchable field selection, use the new Base
5
+ > UI-backed [Combobox](../Combobox/Combobox.md).
5
6
 
6
- The FilterPicker is designed to provide a versatile and accessible interface for
7
- selecting one or more options from a list. FilterPicker can be used for a
8
- variety of scenarios, such as selecting items from a predefined list, filtering
9
- and searching through data.
7
+ FilterPicker lets users narrow an existing list, table, report, or page of
8
+ records. Use it when selected options act as filters for nearby content.
10
9
 
11
- ## Design & usage guidelines
10
+ If the user is choosing a value to save, submit, assign, or display in a form
11
+ field, use [Combobox](../Combobox/Combobox.md) instead.
12
12
 
13
- The FilterPicker component's primary function is to facilitate option selection
14
- and searching within a list of items.
13
+ ## Design & usage guidelines
15
14
 
16
- It should be used in scenarios where users need to choose from a set of options,
17
- with the added benefit of filtering.
15
+ FilterPicker's primary function is to apply filter criteria to existing content.
18
16
 
19
17
  The FilterPicker also has the flexibility to allow for custom actions, such as
20
18
  adding a new item to the list of options or managing a selection.
@@ -15,6 +15,7 @@
15
15
  [choosing-components](./choosing-components/choosing-components.md)
16
16
  [Cluster](./Cluster/Cluster.md)
17
17
  [Colors](./Colors/Colors.md)
18
+ [Combobox](./Combobox/Combobox.md)
18
19
  [ConfirmationModal](./ConfirmationModal/ConfirmationModal.md)
19
20
  [Container](./Container/Container.md)
20
21
  [Content](./Content/Content.md)
package/dist/index.cjs CHANGED
@@ -115,7 +115,6 @@ require('color');
115
115
  require('./tslib.es6-cjs.js');
116
116
  require('react-router-dom');
117
117
  require('./getMappedAtlantisSpaceToken-cjs.js');
118
- require('./getMappedBreakpointWidth-cjs.js');
119
118
  require('./buttonRenderAdapter-cjs.js');
120
119
  require('./useRenderElement-cjs.js');
121
120
  require('./ComboboxPrimitive-cjs.js');
package/dist/index.mjs CHANGED
@@ -113,7 +113,6 @@ import 'color';
113
113
  import './tslib.es6-es.js';
114
114
  import 'react-router-dom';
115
115
  import './getMappedAtlantisSpaceToken-es.js';
116
- import './getMappedBreakpointWidth-es.js';
117
116
  import './buttonRenderAdapter-es.js';
118
117
  import './useRenderElement-es.js';
119
118
  import './ComboboxPrimitive-es.js';
@@ -28,5 +28,5 @@ declare function ComboboxEmpty({ className, ...emptyProps }: ComboboxPrimitiveEm
28
28
  declare function ComboboxClear({ className, render, ...clearProps }: ComboboxPrimitiveClearProps): React.JSX.Element;
29
29
  declare function ComboboxSeparator({ className, ...separatorProps }: ComboboxPrimitiveSeparatorProps): React.JSX.Element;
30
30
  declare const useFilter: typeof BaseCombobox.useFilter;
31
- declare const useFilteredItems: typeof BaseCombobox.useFilteredItems;
31
+ declare function useFilteredItems<Value = unknown>(): Value[];
32
32
  export { ComboboxRoot as Root, ComboboxLabel as Label, ComboboxValue as Value, ComboboxInput as Input, ComboboxInputGroup as InputGroup, ComboboxTrigger as Trigger, ComboboxList as List, ComboboxStatus as Status, ComboboxPortal as Portal, ComboboxBackdrop as Backdrop, ComboboxPositioner as Positioner, ComboboxPopup as Popup, ComboboxArrow as Arrow, ComboboxIcon as Icon, ComboboxGroup as Group, ComboboxGroupLabel as GroupLabel, ComboboxItem as Item, ComboboxItemIndicator as ItemIndicator, ComboboxChips as Chips, ComboboxChip as Chip, ComboboxChipRemove as ChipRemove, ComboboxRow as Row, ComboboxCollection as Collection, ComboboxEmpty as Empty, ComboboxClear as Clear, ComboboxSeparator as Separator, useFilter, useFilteredItems, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components",
3
- "version": "9.6.2",
3
+ "version": "9.6.3",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -549,5 +549,5 @@
549
549
  "> 1%",
550
550
  "IE 10"
551
551
  ],
552
- "gitHead": "a3e6d42140c69289bcda7f63dadfc2d47688b5d5"
552
+ "gitHead": "2ea35aba9020c49cabbece42af65fb007281284e"
553
553
  }
@@ -1,21 +0,0 @@
1
- 'use strict';
2
-
3
- const AtlantisBreakpoints = {
4
- xs: 0,
5
- sm: 490,
6
- md: 768,
7
- lg: 1080,
8
- xl: 1440,
9
- };
10
- const getMappedBreakpointWidth = (maxWidth) => {
11
- if (typeof maxWidth === "number") {
12
- return `${maxWidth}px`;
13
- }
14
- if (AtlantisBreakpoints[maxWidth]) {
15
- return (AtlantisBreakpoints[maxWidth] + "px");
16
- }
17
- return maxWidth;
18
- };
19
-
20
- exports.AtlantisBreakpoints = AtlantisBreakpoints;
21
- exports.getMappedBreakpointWidth = getMappedBreakpointWidth;
@@ -1,18 +0,0 @@
1
- const AtlantisBreakpoints = {
2
- xs: 0,
3
- sm: 490,
4
- md: 768,
5
- lg: 1080,
6
- xl: 1440,
7
- };
8
- const getMappedBreakpointWidth = (maxWidth) => {
9
- if (typeof maxWidth === "number") {
10
- return `${maxWidth}px`;
11
- }
12
- if (AtlantisBreakpoints[maxWidth]) {
13
- return (AtlantisBreakpoints[maxWidth] + "px");
14
- }
15
- return maxWidth;
16
- };
17
-
18
- export { AtlantisBreakpoints as A, getMappedBreakpointWidth as g };