@jobber/components 8.20.1 → 8.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/LegacySelect.d.ts +1 -0
  2. package/{Select.js → LegacySelect.js} +3 -3
  3. package/dist/BottomSheet-cjs.js +9 -58
  4. package/dist/BottomSheet-es.js +2 -47
  5. package/dist/Card/index.cjs +4 -0
  6. package/dist/Card/index.mjs +4 -0
  7. package/dist/ComboboxChipRemove-cjs.js +3418 -0
  8. package/dist/ComboboxChipRemove-es.js +3366 -0
  9. package/dist/ComboboxPrimitive-cjs.js +170 -0
  10. package/dist/ComboboxPrimitive-es.js +168 -0
  11. package/dist/DataDump/index.cjs +4 -0
  12. package/dist/DataDump/index.mjs +4 -0
  13. package/dist/DataTable/index.cjs +1 -1
  14. package/dist/DataTable/index.mjs +1 -1
  15. package/dist/DataTable-cjs.js +3 -3
  16. package/dist/DataTable-es.js +2 -2
  17. package/dist/InputNumberExperimental-cjs.js +45 -44
  18. package/dist/InputNumberExperimental-es.js +3 -2
  19. package/dist/InternalBackdrop-cjs.js +4278 -0
  20. package/dist/InternalBackdrop-es.js +4204 -0
  21. package/dist/LegacySelect/LegacySelect.d.ts +7 -0
  22. package/dist/{Select/Select.types.d.ts → LegacySelect/LegacySelect.types.d.ts} +1 -1
  23. package/dist/{Select → LegacySelect}/index.cjs +3 -3
  24. package/dist/LegacySelect/index.d.ts +3 -0
  25. package/dist/{Select → LegacySelect}/index.mjs +1 -1
  26. package/dist/{Select-cjs.js → LegacySelect-cjs.js} +5 -5
  27. package/dist/{Select-es.js → LegacySelect-es.js} +5 -5
  28. package/dist/Menu/index.cjs +4 -0
  29. package/dist/Menu/index.mjs +4 -0
  30. package/dist/Menu-cjs.js +9 -8
  31. package/dist/Menu-es.js +2 -1
  32. package/dist/MenuSubmenuTrigger-cjs.js +208 -1969
  33. package/dist/MenuSubmenuTrigger-es.js +7 -1759
  34. package/dist/NumberFieldInput-cjs.js +56 -439
  35. package/dist/NumberFieldInput-es.js +6 -376
  36. package/dist/Page/index.cjs +4 -0
  37. package/dist/Page/index.mjs +4 -0
  38. package/dist/ScrollAreaViewport-cjs.js +108 -4356
  39. package/dist/ScrollAreaViewport-es.js +6 -4201
  40. package/dist/buttonRenderAdapter-cjs.js +56 -0
  41. package/dist/buttonRenderAdapter-es.js +51 -0
  42. package/dist/clamp-cjs.js +0 -1194
  43. package/dist/clamp-es.js +1 -1091
  44. package/dist/docs/Autocomplete/Autocomplete.md +1 -1
  45. package/dist/docs/Chip/Chip.md +2 -2
  46. package/dist/docs/{Select/Select.md → LegacySelect/LegacySelect.md} +67 -62
  47. package/dist/docs/Menu/Menu.md +1 -1
  48. package/dist/docs/MultiSelect/MultiSelect.md +1 -1
  49. package/dist/docs/Tabs/Tabs.md +2 -1
  50. package/dist/docs/empty-states/empty-states.md +29 -0
  51. package/dist/docs/index.md +1 -1
  52. package/dist/index.cjs +7 -3
  53. package/dist/index.d.mts +1 -1
  54. package/dist/index.d.ts +1 -1
  55. package/dist/index.mjs +5 -1
  56. package/dist/primitives/BottomSheet/index.cjs +5 -2
  57. package/dist/primitives/BottomSheet/index.mjs +5 -2
  58. package/dist/primitives/ComboboxPrimitive/ComboboxPrimitive.d.ts +32 -0
  59. package/dist/primitives/ComboboxPrimitive/ComboboxPrimitive.types.d.ts +30 -0
  60. package/dist/primitives/ComboboxPrimitive/index.cjs +28 -0
  61. package/dist/primitives/ComboboxPrimitive/index.d.ts +2 -0
  62. package/dist/primitives/ComboboxPrimitive/index.mjs +22 -0
  63. package/dist/primitives/InputNumberExperimental/index.cjs +4 -2
  64. package/dist/primitives/InputNumberExperimental/index.mjs +4 -2
  65. package/dist/primitives/index.cjs +11 -2
  66. package/dist/primitives/index.d.ts +1 -0
  67. package/dist/primitives/index.mjs +10 -2
  68. package/dist/styles.css +793 -26
  69. package/dist/unstyledPrimitives/index.cjs +237 -3588
  70. package/dist/unstyledPrimitives/index.mjs +96 -3447
  71. package/dist/useButton-cjs.js +1196 -0
  72. package/dist/useButton-es.js +1091 -0
  73. package/dist/useCompositeListItem-cjs.js +1792 -0
  74. package/dist/useCompositeListItem-es.js +1762 -0
  75. package/dist/useLabel-cjs.js +411 -0
  76. package/dist/useLabel-es.js +378 -0
  77. package/dist/utils/meta/meta.json +3 -3
  78. package/package.json +7 -7
  79. package/Select.d.ts +0 -1
  80. package/dist/Select/Select.d.ts +0 -7
  81. package/dist/Select/index.d.ts +0 -3
  82. /package/dist/{Select → LegacySelect}/Option.d.ts +0 -0
  83. /package/dist/{Select → LegacySelect}/OptionGroup.d.ts +0 -0
  84. /package/dist/{Select → LegacySelect}/hooks/useSelectActions.d.ts +0 -0
@@ -0,0 +1,378 @@
1
+ import * as ReactDOM from 'react-dom';
2
+ import { a as useStableCallback, d as useIsoLayoutEffect, u as useBaseUiId, g as getTarget, o as ownerDocument } from './useButton-es.js';
3
+ import * as React from 'react';
4
+ import { N as NOOP, f as formatErrorMessage, E as EMPTY_OBJECT, a as useRefWithInit } from './useRenderElement-es.js';
5
+ import { b as isElement, a as isHTMLElement } from './floating-ui.utils.dom-es.js';
6
+
7
+ let FieldControlDataAttributes = /*#__PURE__*/function (FieldControlDataAttributes) {
8
+ /**
9
+ * Present when the field is disabled.
10
+ */
11
+ FieldControlDataAttributes["disabled"] = "data-disabled";
12
+ /**
13
+ * Present when the field is in valid state.
14
+ */
15
+ FieldControlDataAttributes["valid"] = "data-valid";
16
+ /**
17
+ * Present when the field is in invalid state.
18
+ */
19
+ FieldControlDataAttributes["invalid"] = "data-invalid";
20
+ /**
21
+ * Present when the field has been touched.
22
+ */
23
+ FieldControlDataAttributes["touched"] = "data-touched";
24
+ /**
25
+ * Present when the field's value has changed.
26
+ */
27
+ FieldControlDataAttributes["dirty"] = "data-dirty";
28
+ /**
29
+ * Present when the field is filled.
30
+ */
31
+ FieldControlDataAttributes["filled"] = "data-filled";
32
+ /**
33
+ * Present when the field control is focused.
34
+ */
35
+ FieldControlDataAttributes["focused"] = "data-focused";
36
+ return FieldControlDataAttributes;
37
+ }({});
38
+
39
+ const DEFAULT_VALIDITY_STATE = {
40
+ badInput: false,
41
+ customError: false,
42
+ patternMismatch: false,
43
+ rangeOverflow: false,
44
+ rangeUnderflow: false,
45
+ stepMismatch: false,
46
+ tooLong: false,
47
+ tooShort: false,
48
+ typeMismatch: false,
49
+ valid: null,
50
+ valueMissing: false
51
+ };
52
+ const DEFAULT_FIELD_STATE_ATTRIBUTES = {
53
+ valid: null,
54
+ touched: false,
55
+ dirty: false,
56
+ filled: false,
57
+ focused: false
58
+ };
59
+ const DEFAULT_FIELD_ROOT_STATE = {
60
+ disabled: false,
61
+ ...DEFAULT_FIELD_STATE_ATTRIBUTES
62
+ };
63
+ const fieldValidityMapping = {
64
+ valid(value) {
65
+ if (value === null) {
66
+ return null;
67
+ }
68
+ if (value) {
69
+ return {
70
+ [FieldControlDataAttributes.valid]: ''
71
+ };
72
+ }
73
+ return {
74
+ [FieldControlDataAttributes.invalid]: ''
75
+ };
76
+ }
77
+ };
78
+
79
+ const FieldRootContext = /*#__PURE__*/React.createContext({
80
+ invalid: undefined,
81
+ name: undefined,
82
+ validityData: {
83
+ state: DEFAULT_VALIDITY_STATE,
84
+ errors: [],
85
+ error: '',
86
+ value: '',
87
+ initialValue: null
88
+ },
89
+ setValidityData: NOOP,
90
+ disabled: undefined,
91
+ touched: DEFAULT_FIELD_STATE_ATTRIBUTES.touched,
92
+ setTouched: NOOP,
93
+ dirty: DEFAULT_FIELD_STATE_ATTRIBUTES.dirty,
94
+ setDirty: NOOP,
95
+ filled: DEFAULT_FIELD_STATE_ATTRIBUTES.filled,
96
+ setFilled: NOOP,
97
+ focused: DEFAULT_FIELD_STATE_ATTRIBUTES.focused,
98
+ setFocused: NOOP,
99
+ validate: () => null,
100
+ validationMode: 'onSubmit',
101
+ validationDebounceTime: 0,
102
+ shouldValidateOnChange: () => false,
103
+ state: DEFAULT_FIELD_ROOT_STATE,
104
+ markedDirtyRef: {
105
+ current: false
106
+ },
107
+ validation: {
108
+ getValidationProps: (props = EMPTY_OBJECT) => props,
109
+ getInputValidationProps: (props = EMPTY_OBJECT) => props,
110
+ inputRef: {
111
+ current: null
112
+ },
113
+ commit: async () => {}
114
+ }
115
+ });
116
+ if (process.env.NODE_ENV !== "production") FieldRootContext.displayName = "FieldRootContext";
117
+ function useFieldRootContext(optional = true) {
118
+ const context = React.useContext(FieldRootContext);
119
+ if (context.setValidityData === NOOP && !optional) {
120
+ throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: FieldRootContext is missing. Field parts must be placed within <Field.Root>.' : formatErrorMessage(28));
121
+ }
122
+ return context;
123
+ }
124
+
125
+ /**
126
+ * Combines the field's client-side, stateful validity data with the external invalid state to
127
+ * determine the field's true validity.
128
+ */
129
+ function getCombinedFieldValidityData(validityData, invalid) {
130
+ return {
131
+ ...validityData,
132
+ state: {
133
+ ...validityData.state,
134
+ valid: !invalid && validityData.state.valid
135
+ }
136
+ };
137
+ }
138
+
139
+ const FormContext = /*#__PURE__*/React.createContext({
140
+ formRef: {
141
+ current: {
142
+ fields: new Map()
143
+ }
144
+ },
145
+ errors: {},
146
+ clearErrors: NOOP,
147
+ validationMode: 'onSubmit',
148
+ submitAttemptedRef: {
149
+ current: false
150
+ }
151
+ });
152
+ if (process.env.NODE_ENV !== "production") FormContext.displayName = "FormContext";
153
+ function useFormContext() {
154
+ return React.useContext(FormContext);
155
+ }
156
+
157
+ function useField(params) {
158
+ const {
159
+ enabled = true,
160
+ value,
161
+ id,
162
+ name,
163
+ controlRef,
164
+ commit
165
+ } = params;
166
+ const {
167
+ formRef
168
+ } = useFormContext();
169
+ const {
170
+ invalid,
171
+ markedDirtyRef,
172
+ validityData,
173
+ setValidityData
174
+ } = useFieldRootContext();
175
+ const getValue = useStableCallback(params.getValue);
176
+ useIsoLayoutEffect(() => {
177
+ if (!enabled) {
178
+ return;
179
+ }
180
+ let initialValue = value;
181
+ if (initialValue === undefined) {
182
+ initialValue = getValue();
183
+ }
184
+ if (validityData.initialValue === null && initialValue !== null) {
185
+ setValidityData(prev => ({
186
+ ...prev,
187
+ initialValue
188
+ }));
189
+ }
190
+ }, [enabled, setValidityData, value, validityData.initialValue, getValue]);
191
+ useIsoLayoutEffect(() => {
192
+ if (!enabled || !id) {
193
+ return;
194
+ }
195
+ formRef.current.fields.set(id, {
196
+ getValue,
197
+ name,
198
+ controlRef,
199
+ validityData: getCombinedFieldValidityData(validityData, invalid),
200
+ validate(flushSync = true) {
201
+ let nextValue = value;
202
+ if (nextValue === undefined) {
203
+ nextValue = getValue();
204
+ }
205
+ markedDirtyRef.current = true;
206
+ if (!flushSync) {
207
+ commit(nextValue);
208
+ } else {
209
+ // Synchronously update the validity state so the submit event can be prevented.
210
+ ReactDOM.flushSync(() => commit(nextValue));
211
+ }
212
+ }
213
+ });
214
+ }, [commit, controlRef, enabled, formRef, getValue, id, invalid, markedDirtyRef, name, validityData, value]);
215
+ useIsoLayoutEffect(() => {
216
+ const fields = formRef.current.fields;
217
+ return () => {
218
+ if (id) {
219
+ fields.delete(id);
220
+ }
221
+ };
222
+ }, [formRef, id]);
223
+ }
224
+
225
+ /**
226
+ * A context for providing [labelable elements](https://html.spec.whatwg.org/multipage/forms.html#category-label)\
227
+ * with an accessible name (label) and description.
228
+ */
229
+ const LabelableContext = /*#__PURE__*/React.createContext({
230
+ controlId: undefined,
231
+ registerControlId: NOOP,
232
+ labelId: undefined,
233
+ setLabelId: NOOP,
234
+ messageIds: [],
235
+ setMessageIds: NOOP,
236
+ getDescriptionProps: externalProps => externalProps
237
+ });
238
+ if (process.env.NODE_ENV !== "production") LabelableContext.displayName = "LabelableContext";
239
+ function useLabelableContext() {
240
+ return React.useContext(LabelableContext);
241
+ }
242
+
243
+ function useLabelableId(params = {}) {
244
+ const {
245
+ id,
246
+ implicit = false,
247
+ controlRef
248
+ } = params;
249
+ const {
250
+ controlId,
251
+ registerControlId
252
+ } = useLabelableContext();
253
+ const defaultId = useBaseUiId(id);
254
+ const controlIdForEffect = implicit ? controlId : undefined;
255
+ const controlSourceRef = useRefWithInit(() => Symbol('labelable-control'));
256
+ const hasRegisteredRef = React.useRef(false);
257
+ const hadExplicitIdRef = React.useRef(id != null);
258
+ const unregisterControlId = useStableCallback(() => {
259
+ if (!hasRegisteredRef.current || registerControlId === NOOP) {
260
+ return;
261
+ }
262
+ hasRegisteredRef.current = false;
263
+ registerControlId(controlSourceRef.current, undefined);
264
+ });
265
+ useIsoLayoutEffect(() => {
266
+ if (registerControlId === NOOP) {
267
+ return undefined;
268
+ }
269
+ let nextId;
270
+ if (implicit) {
271
+ const elem = controlRef?.current;
272
+ if (isElement(elem) && elem.closest('label') != null) {
273
+ nextId = id ?? null;
274
+ } else {
275
+ nextId = controlIdForEffect ?? defaultId;
276
+ }
277
+ } else if (id != null) {
278
+ hadExplicitIdRef.current = true;
279
+ nextId = id;
280
+ } else if (hadExplicitIdRef.current) {
281
+ nextId = defaultId;
282
+ } else {
283
+ unregisterControlId();
284
+ return undefined;
285
+ }
286
+ if (nextId === undefined) {
287
+ unregisterControlId();
288
+ return undefined;
289
+ }
290
+ hasRegisteredRef.current = true;
291
+ registerControlId(controlSourceRef.current, nextId);
292
+ return undefined;
293
+ }, [id, controlRef, controlIdForEffect, registerControlId, implicit, defaultId, controlSourceRef, unregisterControlId]);
294
+ React.useEffect(() => {
295
+ return unregisterControlId;
296
+ }, [unregisterControlId]);
297
+ return controlId ?? defaultId;
298
+ }
299
+
300
+ function useRegisteredLabelId(idProp, setLabelId) {
301
+ const id = useBaseUiId(idProp);
302
+ useIsoLayoutEffect(() => {
303
+ setLabelId(id);
304
+ return () => {
305
+ setLabelId(undefined);
306
+ };
307
+ }, [id, setLabelId]);
308
+ return id;
309
+ }
310
+
311
+ function useLabel(params = {}) {
312
+ const {
313
+ id: idProp,
314
+ fallbackControlId,
315
+ native = false,
316
+ setLabelId: setLabelIdProp,
317
+ focusControl: focusControlProp
318
+ } = params;
319
+ const {
320
+ controlId: contextControlId,
321
+ setLabelId: setContextLabelId
322
+ } = useLabelableContext();
323
+ const syncLabelId = useStableCallback(nextLabelId => {
324
+ setContextLabelId(nextLabelId);
325
+ setLabelIdProp?.(nextLabelId);
326
+ });
327
+ const id = useRegisteredLabelId(idProp, syncLabelId);
328
+ const resolvedControlId = contextControlId ?? fallbackControlId;
329
+ function focusControl(event) {
330
+ if (focusControlProp) {
331
+ focusControlProp(event, resolvedControlId);
332
+ return;
333
+ }
334
+ if (!resolvedControlId) {
335
+ return;
336
+ }
337
+ const controlElement = ownerDocument(event.currentTarget).getElementById(resolvedControlId);
338
+ if (isHTMLElement(controlElement)) {
339
+ focusElementWithVisible(controlElement);
340
+ }
341
+ }
342
+ function handleInteraction(event) {
343
+ const target = getTarget(event.nativeEvent);
344
+ if (target?.closest('button,input,select,textarea')) {
345
+ return;
346
+ }
347
+
348
+ // Prevent text selection when double clicking label.
349
+ if (!event.defaultPrevented && event.detail > 1) {
350
+ event.preventDefault();
351
+ }
352
+ if (native) {
353
+ return;
354
+ }
355
+ focusControl(event);
356
+ }
357
+ return native ? {
358
+ id,
359
+ htmlFor: resolvedControlId ?? undefined,
360
+ onMouseDown: handleInteraction
361
+ } : {
362
+ id,
363
+ onClick: handleInteraction,
364
+ onPointerDown(event) {
365
+ event.preventDefault();
366
+ }
367
+ };
368
+ }
369
+ function focusElementWithVisible(element) {
370
+ element.focus({
371
+ // Available from Chrome 144+ (January 2026).
372
+ // Safari and Firefox already support it.
373
+ // @ts-expect-error not available in types yet
374
+ focusVisible: true
375
+ });
376
+ }
377
+
378
+ export { DEFAULT_VALIDITY_STATE as D, FieldRootContext as F, LabelableContext as L, useFormContext as a, useFieldRootContext as b, useLabel as c, useLabelableId as d, useField as e, fieldValidityMapping as f, getCombinedFieldValidityData as g, DEFAULT_FIELD_STATE_ATTRIBUTES as h, useLabelableContext as u };
@@ -125,6 +125,9 @@
125
125
  "InputText",
126
126
  "InputTime",
127
127
  "InputValidation",
128
+ "LegacySelect",
129
+ "LegacySelect.Option",
130
+ "LegacySelect.OptionGroup",
128
131
  "LightBox",
129
132
  "LightBox.Background",
130
133
  "LightBox.Caption",
@@ -200,9 +203,6 @@
200
203
  "SegmentedControlContext.Consumer",
201
204
  "SegmentedControlContext.Provider",
202
205
  "SegmentedControlProvider",
203
- "Select",
204
- "Select.Option",
205
- "Select.OptionGroup",
206
206
  "SideDrawer",
207
207
  "SideDrawer.Actions",
208
208
  "SideDrawer.BackButton",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components",
3
- "version": "8.20.1",
3
+ "version": "8.21.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -340,10 +340,10 @@
340
340
  "import": "./dist/ResponsiveSwitcher/index.mjs",
341
341
  "require": "./dist/ResponsiveSwitcher/index.cjs"
342
342
  },
343
- "./Select": {
344
- "types": "./dist/Select/index.d.ts",
345
- "import": "./dist/Select/index.mjs",
346
- "require": "./dist/Select/index.cjs"
343
+ "./LegacySelect": {
344
+ "types": "./dist/LegacySelect/index.d.ts",
345
+ "import": "./dist/LegacySelect/index.mjs",
346
+ "require": "./dist/LegacySelect/index.cjs"
347
347
  },
348
348
  "./SideDrawer": {
349
349
  "types": "./dist/SideDrawer/index.d.ts",
@@ -487,7 +487,7 @@
487
487
  "devDependencies": {
488
488
  "@apollo/client": "^3.7.10",
489
489
  "@csstools/postcss-global-data": "^1.0.3",
490
- "@jobber/design": "0.106.0",
490
+ "@jobber/design": "0.106.1",
491
491
  "@jobber/hooks": "2.21.0",
492
492
  "@rollup/plugin-alias": "^5.1.0",
493
493
  "@rollup/plugin-commonjs": "^25.0.7",
@@ -541,5 +541,5 @@
541
541
  "> 1%",
542
542
  "IE 10"
543
543
  ],
544
- "gitHead": "c5da7c5d3db964c4803ccf359bc4e59ed63f668d"
544
+ "gitHead": "8b1aaf0160310df30d09ba5f3dd9b12a008970cc"
545
545
  }
package/Select.d.ts DELETED
@@ -1 +0,0 @@
1
- export * from "./dist/Select";
@@ -1,7 +0,0 @@
1
- import React from "react";
2
- import type { SelectProps } from "./Select.types";
3
- export declare function Select(props: SelectProps): React.JSX.Element;
4
- export declare namespace Select {
5
- var Option: typeof import("./Option").Option;
6
- var OptionGroup: typeof import("./OptionGroup").OptionGroup;
7
- }
@@ -1,3 +0,0 @@
1
- export { Option } from "./Option";
2
- export { Select } from "./Select";
3
- export type { SelectProps } from "./Select.types";
File without changes
File without changes