@jobber/components-native 0.113.5 → 0.113.7
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.
- package/dist/docs/Button/Button.md +1 -1
- package/dist/docs/Chip/Chip.md +1 -1
- package/dist/docs/Colors/Colors.md +1 -1
- package/dist/docs/Icon/Icon.md +23 -16
- package/dist/docs/InputNumber/InputNumber.md +131 -17
- package/dist/docs/InputText/InputText.md +9 -1
- package/dist/docs/Spacing/Spacing.md +1 -1
- package/dist/docs/page-layouts/page-layouts.md +29 -0
- package/dist/docs/settings/settings.md +3 -3
- package/dist/docs/usage-guidelines/usage-guidelines.md +16 -24
- package/dist/package.json +4 -5
- package/dist/src/AutoLink/hooks/useTokenGenerator.js +2 -2
- package/dist/src/ErrorMessageWrapper/ErrorMessageWrapper.js +5 -5
- package/dist/src/FormatFile/components/_mocks/mockFiles.js +4 -4
- package/dist/src/InputText/context/InputAccessoriesProvider.js +2 -2
- package/dist/src/hooks/useFormController.js +2 -2
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -5
- package/src/AutoLink/hooks/useTokenGenerator.ts +2 -2
- package/src/ErrorMessageWrapper/ErrorMessageWrapper.tsx +5 -5
- package/src/FormatFile/components/_mocks/mockFiles.ts +4 -4
- package/src/InputText/context/InputAccessoriesProvider.tsx +2 -2
- package/src/hooks/useFormController.ts +2 -2
|
@@ -388,7 +388,7 @@ A key distinction between subtle buttons and the other variations is that the
|
|
|
388
388
|
primary/secondary/tertiary scale is styled differently, but the conceptual
|
|
389
389
|
hierarchy is the same. Notably, the tertiary subtle button has a transparent
|
|
390
390
|
background, allowing it to be *extra* subtle when placed overtop
|
|
391
|
-
`surface--background` elements such as a
|
|
391
|
+
`surface--background` elements such as a Dialog header.
|
|
392
392
|
|
|
393
393
|
```tsx
|
|
394
394
|
import React from "react";
|
package/dist/docs/Chip/Chip.md
CHANGED
|
@@ -22,7 +22,7 @@ export function ChipWithAvatarExample(
|
|
|
22
22
|
<Chip.Prefix>
|
|
23
23
|
<Avatar
|
|
24
24
|
size="small"
|
|
25
|
-
|
|
25
|
+
src="https://images.unsplash.com/photo-1669475535925-a011d7c31d45?q=80&w=1886&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
|
|
26
26
|
/>
|
|
27
27
|
</Chip.Prefix>
|
|
28
28
|
<Chip.Suffix>
|
|
@@ -156,7 +156,7 @@ application.
|
|
|
156
156
|
#### Overlay
|
|
157
157
|
|
|
158
158
|
Use to mask an area of the interface to promote focus to a foreground action,
|
|
159
|
-
such as a [
|
|
159
|
+
such as a [Dialog](/components/Dialog)'s appearance. Overlay includes built-in
|
|
160
160
|
opacity values.
|
|
161
161
|
|
|
162
162
|
#### Overlay--Dimmed
|
package/dist/docs/Icon/Icon.md
CHANGED
|
@@ -192,6 +192,7 @@ export function IconSizesExample() {
|
|
|
192
192
|
|
|
193
193
|
| Icon | `Name` |
|
|
194
194
|
| :--- | :----------------- |
|
|
195
|
+
| | `arrow` |
|
|
195
196
|
| | `arrowDown` |
|
|
196
197
|
| | `arrowLeft` |
|
|
197
198
|
| | `arrowRight` |
|
|
@@ -244,22 +245,23 @@ export function IconSizesExample() {
|
|
|
244
245
|
|
|
245
246
|
### Forms
|
|
246
247
|
|
|
247
|
-
| Icon | `Name`
|
|
248
|
-
| :--- |
|
|
249
|
-
| | `checkbox`
|
|
250
|
-
| | `checklist`
|
|
251
|
-
| | `
|
|
252
|
-
| | `
|
|
253
|
-
| | `
|
|
254
|
-
| | `
|
|
255
|
-
| | `
|
|
256
|
-
| | `
|
|
257
|
-
| | `
|
|
258
|
-
| | `
|
|
259
|
-
| | `
|
|
260
|
-
| | `
|
|
261
|
-
| | `
|
|
262
|
-
| | `
|
|
248
|
+
| Icon | `Name` |
|
|
249
|
+
| :--- | :---------------- |
|
|
250
|
+
| | `checkbox` |
|
|
251
|
+
| | `checklist` |
|
|
252
|
+
| | `digestChecklist` |
|
|
253
|
+
| | `edit` |
|
|
254
|
+
| | `editDisabled` |
|
|
255
|
+
| | `radioButton` |
|
|
256
|
+
| | `star` |
|
|
257
|
+
| | `starHalf` |
|
|
258
|
+
| | `starFill` |
|
|
259
|
+
| | `text` |
|
|
260
|
+
| | `textBox` |
|
|
261
|
+
| | `textField` |
|
|
262
|
+
| | `toggle` |
|
|
263
|
+
| | `dropdown` |
|
|
264
|
+
| | `trash` |
|
|
263
265
|
|
|
264
266
|
### Status and support
|
|
265
267
|
|
|
@@ -346,6 +348,8 @@ export function IconSizesExample() {
|
|
|
346
348
|
| | `contactlessPayment` |
|
|
347
349
|
| | `cheque` |
|
|
348
350
|
| | `cash` |
|
|
351
|
+
| | `coin` |
|
|
352
|
+
| | `handDollarSign` |
|
|
349
353
|
|
|
350
354
|
### Work
|
|
351
355
|
|
|
@@ -425,7 +429,9 @@ export function IconSizesExample() {
|
|
|
425
429
|
| | `future` |
|
|
426
430
|
| | `history` |
|
|
427
431
|
| | `import` |
|
|
432
|
+
| | `maximize` |
|
|
428
433
|
| | `merge` |
|
|
434
|
+
| | `minimize` |
|
|
429
435
|
| | `redo` |
|
|
430
436
|
| | `search` |
|
|
431
437
|
| | `sort` |
|
|
@@ -477,6 +483,7 @@ export function IconSizesExample() {
|
|
|
477
483
|
| | `phoneEnd` |
|
|
478
484
|
| | `phoneIncoming` |
|
|
479
485
|
| | `phoneOutgoing` |
|
|
486
|
+
| | `pieChart` |
|
|
480
487
|
| | `pinned` |
|
|
481
488
|
| | `presentation` |
|
|
482
489
|
| | `priceTag` |
|
|
@@ -339,17 +339,17 @@ the **Design** tab.
|
|
|
339
339
|
| `Description` | Helper text below the field |
|
|
340
340
|
| `Error` | Styled error message below the field |
|
|
341
341
|
|
|
342
|
-
## Composition
|
|
343
|
-
|
|
344
|
-
The prop-driven component is sugar: it renders exactly the tree you would write
|
|
345
|
-
by hand with `<InputNumber.Wrapper>` and the parts. To customize a single piece,
|
|
346
|
-
compose the tree yourself and swap that one part — the other parts keep their
|
|
347
|
-
defaults. The sugar does not merge consumer-provided parts into its render, so
|
|
348
|
-
there is no per-slot precedence to reason about.
|
|
349
|
-
|
|
350
342
|
`Wrapper` owns the field state and shares it with the parts through context, so
|
|
351
343
|
every part must be rendered inside a `Wrapper` (a part used outside one throws).
|
|
352
344
|
|
|
345
|
+
## Customize one part
|
|
346
|
+
|
|
347
|
+
Pass the content parts you want — `Label`, `Affix`, `Stepper`, `Loading`,
|
|
348
|
+
`Description`, `Error` — straight to `Wrapper`. It builds `Group`, `Input`, and
|
|
349
|
+
`Footer` around them and places each part at the right depth, so you never
|
|
350
|
+
reproduce the skeleton to change one piece. `Wrapper` renders only the parts you
|
|
351
|
+
gave it: leave one out and it is not there.
|
|
352
|
+
|
|
353
353
|
The example below replaces the default stepper icons with `+` / `−` and leaves
|
|
354
354
|
everything else as the default:
|
|
355
355
|
|
|
@@ -361,25 +361,139 @@ export function InputNumberCompositionExample() {
|
|
|
361
361
|
const [value, setValue] = useState<number | null>(3);
|
|
362
362
|
|
|
363
363
|
return (
|
|
364
|
-
<InputNumber.Wrapper
|
|
364
|
+
<InputNumber.Wrapper onValueCommitted={setValue} value={value}>
|
|
365
|
+
<InputNumber.Label>Quantity</InputNumber.Label>
|
|
366
|
+
<InputNumber.Stepper>
|
|
367
|
+
<InputNumber.Increment ariaLabel="Increase Quantity">
|
|
368
|
+
+
|
|
369
|
+
</InputNumber.Increment>
|
|
370
|
+
<InputNumber.Decrement ariaLabel="Decrease Quantity">
|
|
371
|
+
−
|
|
372
|
+
</InputNumber.Decrement>
|
|
373
|
+
</InputNumber.Stepper>
|
|
374
|
+
</InputNumber.Wrapper>
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Omit a part
|
|
380
|
+
|
|
381
|
+
A field with no stepper is the same composition minus the `Stepper`:
|
|
382
|
+
|
|
383
|
+
```tsx
|
|
384
|
+
import React, { useState } from "react";
|
|
385
|
+
import { InputNumber } from "@jobber/components";
|
|
386
|
+
|
|
387
|
+
export function InputNumberCompositionStepperlessExample() {
|
|
388
|
+
const [value, setValue] = useState<number | null>(15);
|
|
389
|
+
|
|
390
|
+
return (
|
|
391
|
+
<InputNumber.Wrapper
|
|
392
|
+
format={{ style: "unit", unit: "percent" }}
|
|
393
|
+
onValueCommitted={setValue}
|
|
394
|
+
value={value}
|
|
395
|
+
>
|
|
396
|
+
<InputNumber.Label>Tax rate</InputNumber.Label>
|
|
397
|
+
</InputNumber.Wrapper>
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Show a part conditionally
|
|
403
|
+
|
|
404
|
+
Presence is ordinary conditional JSX; there is no `show*` prop to reach for:
|
|
405
|
+
|
|
406
|
+
```tsx
|
|
407
|
+
import React, { useState } from "react";
|
|
408
|
+
import { InputNumber } from "@jobber/components";
|
|
409
|
+
|
|
410
|
+
export function InputNumberCompositionConditionalStepperExample() {
|
|
411
|
+
const [unitCost, setUnitCost] = useState<number | null>(0);
|
|
412
|
+
const [markup, setMarkup] = useState<number | null>(20);
|
|
413
|
+
|
|
414
|
+
return (
|
|
415
|
+
<>
|
|
416
|
+
<InputNumber
|
|
417
|
+
label="Unit cost"
|
|
418
|
+
onValueCommitted={setUnitCost}
|
|
419
|
+
prefix={{ label: "$" }}
|
|
420
|
+
value={unitCost}
|
|
421
|
+
/>
|
|
422
|
+
<InputNumber.Wrapper onValueCommitted={setMarkup} value={markup}>
|
|
423
|
+
<InputNumber.Label>Markup</InputNumber.Label>
|
|
424
|
+
<InputNumber.Affix label="%" variation="suffix" />
|
|
425
|
+
{Boolean(unitCost) && <InputNumber.Stepper />}
|
|
426
|
+
</InputNumber.Wrapper>
|
|
427
|
+
</>
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Below-field content
|
|
433
|
+
|
|
434
|
+
`Description` and `Error` route into the footer row, which exists only while one
|
|
435
|
+
of them is rendered. The two are never shown together: when both are present the
|
|
436
|
+
error replaces the description, since a description hints at what the field
|
|
437
|
+
wants and the error already restates it.
|
|
438
|
+
|
|
439
|
+
```tsx
|
|
440
|
+
import React, { useState } from "react";
|
|
441
|
+
import { InputNumber } from "@jobber/components";
|
|
442
|
+
|
|
443
|
+
export function InputNumberCompositionFooterExample() {
|
|
444
|
+
const [value, setValue] = useState<number | null>(50);
|
|
445
|
+
const error = (value ?? 0) > 99 ? "Enter a value between 1 and 99" : "";
|
|
446
|
+
|
|
447
|
+
return (
|
|
448
|
+
<InputNumber.Wrapper
|
|
449
|
+
invalid={Boolean(error)}
|
|
450
|
+
max={99}
|
|
451
|
+
min={1}
|
|
452
|
+
onValueChange={setValue}
|
|
453
|
+
value={value}
|
|
454
|
+
>
|
|
455
|
+
<InputNumber.Label>Quantity</InputNumber.Label>
|
|
456
|
+
<InputNumber.Description>Per visit</InputNumber.Description>
|
|
457
|
+
{error && <InputNumber.Error>{error}</InputNumber.Error>}
|
|
458
|
+
</InputNumber.Wrapper>
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
## Custom layouts
|
|
464
|
+
|
|
465
|
+
For an arrangement the standard skeleton does not produce, compose the
|
|
466
|
+
structural parts (`Group`, `Input`, `Footer`) yourself. `Wrapper` then renders
|
|
467
|
+
your tree exactly as written and adds nothing:
|
|
468
|
+
|
|
469
|
+
```tsx
|
|
470
|
+
import React, { useState } from "react";
|
|
471
|
+
import { InputNumber } from "@jobber/components";
|
|
472
|
+
|
|
473
|
+
export function InputNumberCompositionCustomLayoutExample() {
|
|
474
|
+
const [value, setValue] = useState<number | null>(3);
|
|
475
|
+
|
|
476
|
+
return (
|
|
477
|
+
<InputNumber.Wrapper inline onValueCommitted={setValue} value={value}>
|
|
365
478
|
<InputNumber.Group>
|
|
479
|
+
<InputNumber.Decrement ariaLabel="Decrease quantity" />
|
|
366
480
|
<InputNumber.Input>
|
|
367
481
|
<InputNumber.Label>Quantity</InputNumber.Label>
|
|
368
|
-
<InputNumber.Stepper>
|
|
369
|
-
<InputNumber.Increment ariaLabel="Increase Quantity">
|
|
370
|
-
+
|
|
371
|
-
</InputNumber.Increment>
|
|
372
|
-
<InputNumber.Decrement ariaLabel="Decrease Quantity">
|
|
373
|
-
−
|
|
374
|
-
</InputNumber.Decrement>
|
|
375
|
-
</InputNumber.Stepper>
|
|
376
482
|
</InputNumber.Input>
|
|
483
|
+
<InputNumber.Increment ariaLabel="Increase quantity" />
|
|
377
484
|
</InputNumber.Group>
|
|
378
485
|
</InputNumber.Wrapper>
|
|
379
486
|
);
|
|
380
487
|
}
|
|
381
488
|
```
|
|
382
489
|
|
|
490
|
+
Pick one path per `Wrapper`. Mixing structural parts with loose content parts
|
|
491
|
+
throws, rather than guessing where the loose parts belong.
|
|
492
|
+
|
|
493
|
+
The sugar does not merge consumer-provided parts into its render, so there is no
|
|
494
|
+
per-slot precedence to reason about — children passed to `<InputNumber>` are
|
|
495
|
+
ignored. Compose on `Wrapper` instead.
|
|
496
|
+
|
|
383
497
|
## Controlled usage
|
|
384
498
|
|
|
385
499
|
The field is controlled: pass `value` (a `number`, or `null` for empty) and read
|
|
@@ -86,6 +86,10 @@ and align the input with
|
|
|
86
86
|
With clearer guidance around the purpose of inputs, the user is able to better
|
|
87
87
|
focus on the task at hand.
|
|
88
88
|
|
|
89
|
+
Either affix can be given an `onClick` to make it an action, which renders the
|
|
90
|
+
affix icon as a button. An actioned affix requires both an `icon` and an
|
|
91
|
+
`ariaLabel` to name the button — affix labels are not actionable.
|
|
92
|
+
|
|
89
93
|
```tsx
|
|
90
94
|
import React, { useState } from "react";
|
|
91
95
|
import type { InputTextProps } from "@jobber/components/InputText";
|
|
@@ -128,7 +132,11 @@ export function InputTextPrefixSuffixExample(
|
|
|
128
132
|
/>
|
|
129
133
|
<InputText
|
|
130
134
|
placeholder="Search"
|
|
131
|
-
prefix={{
|
|
135
|
+
prefix={{
|
|
136
|
+
icon: "search",
|
|
137
|
+
ariaLabel: "submit search",
|
|
138
|
+
onClick: () => alert("This could submit a search"),
|
|
139
|
+
}}
|
|
132
140
|
value={search}
|
|
133
141
|
onChange={handleSearchChange}
|
|
134
142
|
suffix={{
|
|
@@ -48,7 +48,7 @@ form elements.
|
|
|
48
48
|
### Large
|
|
49
49
|
|
|
50
50
|
Use `large` spacing for higher-level "parent" containers.
|
|
51
|
-
[
|
|
51
|
+
[Dialog](/components/Dialog) uses `large` spacing in its header and around the
|
|
52
52
|
edges to give itself a bit more prominence as a standalone view, in a similar
|
|
53
53
|
manner to [Page](/components/Page).
|
|
54
54
|
|
|
@@ -43,6 +43,35 @@ More complex full-page scaffolding can be found on the [Scaffolding](../scaffold
|
|
|
43
43
|
</Stack>
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
+
```tsx
|
|
47
|
+
<Stack>
|
|
48
|
+
<Heading level={2}>Stack Dialog Layouts</Heading>
|
|
49
|
+
<Text>Stacks are a great way to layout content in a dialog format. They are responsive and easy to read.</Text>
|
|
50
|
+
<Dialog>
|
|
51
|
+
<Dialog.Trigger>
|
|
52
|
+
<Button label="Open Dialog" />
|
|
53
|
+
</Dialog.Trigger>
|
|
54
|
+
<Dialog.Content>
|
|
55
|
+
<Dialog.Header>
|
|
56
|
+
<Dialog.Title>Dialog Layout</Dialog.Title>
|
|
57
|
+
<Dialog.Close />
|
|
58
|
+
</Dialog.Header>
|
|
59
|
+
<Dialog.Body>
|
|
60
|
+
<Stack>
|
|
61
|
+
<Text>A dialog with a header, body text, and footer</Text>
|
|
62
|
+
<Text>And they're all stacked vertically with equal spacing</Text>
|
|
63
|
+
</Stack>
|
|
64
|
+
</Dialog.Body>
|
|
65
|
+
<Dialog.Footer>
|
|
66
|
+
<Dialog.Actions
|
|
67
|
+
primary={<Dialog.Close render={<Button label="Close the Dialog" />} />}
|
|
68
|
+
/>
|
|
69
|
+
</Dialog.Footer>
|
|
70
|
+
</Dialog.Content>
|
|
71
|
+
</Dialog>
|
|
72
|
+
</Stack>
|
|
73
|
+
```
|
|
74
|
+
|
|
46
75
|
```tsx
|
|
47
76
|
<Stack>
|
|
48
77
|
<Heading level={1}>Cluster</Heading>
|
|
@@ -26,7 +26,7 @@ Most settings can be managed with the
|
|
|
26
26
|
[FeatureSwitch](../components/FeatureSwitch) component, which allows:
|
|
27
27
|
|
|
28
28
|
* turning functionality on and off
|
|
29
|
-
* editing aspects of the feature via a [
|
|
29
|
+
* editing aspects of the feature via a [Dialog](../components/Dialog)
|
|
30
30
|
* if the page supports it, live updates to the setting
|
|
31
31
|
|
|
32
32
|
### Grouping settings
|
|
@@ -37,7 +37,7 @@ Use a [Card](../Card/Card.md) to group related settings together.
|
|
|
37
37
|
|
|
38
38
|
The [FeatureSwitch](../components/FeatureSwitch) component is a good starting
|
|
39
39
|
point for most settings. If the setting is more complex, you can trigger a
|
|
40
|
-
[
|
|
40
|
+
[Dialog](../components/Dialog) to edit the setting.
|
|
41
41
|
|
|
42
42
|
For cases where you don't need the full functionality of the `FeatureSwitch`,
|
|
43
43
|
you can either opt out of props like `onSwitch` or `onEdit`, or compose a layout
|
|
@@ -49,7 +49,7 @@ of the pieces you do need.
|
|
|
49
49
|
|
|
50
50
|
* [FeatureSwitch](../components/FeatureSwitch)
|
|
51
51
|
* [Card](../Card/Card.md)
|
|
52
|
-
* [
|
|
52
|
+
* [Dialog](../components/Dialog)
|
|
53
53
|
* [Switch](../Switch/Switch.md)
|
|
54
54
|
|
|
55
55
|
## Principles
|
|
@@ -5,22 +5,13 @@ before generating any Atlantis code.
|
|
|
5
5
|
|
|
6
6
|
***
|
|
7
7
|
|
|
8
|
-
## Always use version= for migrated components
|
|
9
|
-
|
|
10
|
-
The following components have a v2 implementation. **Always pass
|
|
11
|
-
`version={2}`**. Never generate v1 usage for these components — v1 is
|
|
12
|
-
deprecated.
|
|
13
|
-
|
|
14
|
-
| Component | Import | v2 prop |
|
|
15
|
-
| --------- | -------------------------------------------------- | ------------------------------------------------- |
|
|
16
|
-
| Modal | `import { Modal } from "@jobber/components/Modal"` | `version={2}` — uses `Modal.Provider` composition |
|
|
17
|
-
|
|
18
8
|
## Deprecated components — do not use
|
|
19
9
|
|
|
20
|
-
| Deprecated | Replacement | Notes
|
|
21
|
-
| --------------------- | ------------------------------------------------------ |
|
|
22
|
-
| `
|
|
23
|
-
| `
|
|
10
|
+
| Deprecated | Replacement | Notes |
|
|
11
|
+
| --------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
12
|
+
| `Modal` | `Dialog` | Includes `Modal.Provider` and the `Modal.*` subcomponents. See [migrating to Dialog](/components/Dialog/implement#component-view-migrating-to-dialog). |
|
|
13
|
+
| `MultiSelect` | `Autocomplete` with `multiple` prop, or `FilterPicker` | Fully deprecated, no longer supported. |
|
|
14
|
+
| `Chips` (dismissible) | `Autocomplete` with `multiple` prop | Dismissible Chips variant is deprecated. |
|
|
24
15
|
|
|
25
16
|
### Deprecated props on still-supported components
|
|
26
17
|
|
|
@@ -74,7 +65,7 @@ parent reads its compound children to wire up state, accessibility, and styling.
|
|
|
74
65
|
|
|
75
66
|
| Component | Subcomponents | Usage |
|
|
76
67
|
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
77
|
-
| `
|
|
68
|
+
| `Dialog` | `Dialog.Trigger`, `Dialog.Content`, `Dialog.Header`, `Dialog.Title`, `Dialog.Close`, `Dialog.Body`, `Dialog.Footer`, `Dialog.Actions`, `Dialog.ScrollArea` | `Dialog` > `Dialog.Trigger` + `Dialog.Content` containing `Dialog.Header` (with `Dialog.Title` and `Dialog.Close`), `Dialog.Body`, and `Dialog.Footer` (wrapping `Dialog.Actions`). `Dialog.Header` and `Dialog.Footer` are layout-only slots. Use `finalFocus` to control focus return when the trigger unmounts. |
|
|
78
69
|
| `Banner` | `Banner.Provider`, `Banner.Content`, `Banner.Icon`, `Banner.DismissButton`, `Banner.Action` | Either the simple `<Banner type="...">children</Banner>` form, or the Provider form: `Banner.Provider` > `Banner.Content` (+ optional `Banner.Icon` / `Banner.Action` / `Banner.DismissButton`). |
|
|
79
70
|
| `Card` | `Card.Header`, `Card.Body` | `Card` > `Card.Header` + `Card.Body`. The legacy `header` string/element prop still works for simple cases. Use composition for any header that needs richer markup. |
|
|
80
71
|
| `FilterPicker` | `FilterPicker.Activator`, `FilterPicker.Option`, `FilterPicker.Action` | `FilterPicker` > optional `FilterPicker.Activator`, one or more `FilterPicker.Option`, optional `FilterPicker.Action`. Omitting `FilterPicker.Activator` renders the default activator. |
|
|
@@ -100,10 +91,9 @@ parent reads its compound children to wire up state, accessibility, and styling.
|
|
|
100
91
|
returns a translated label per state (e.g. `"Next page"`, `"Previous page"`).
|
|
101
92
|
* **`RadioGroup` options whose `children` aren't text** must provide
|
|
102
93
|
`aria-label` on the option so it has an accessible name.
|
|
103
|
-
* **`
|
|
104
|
-
`
|
|
105
|
-
|
|
106
|
-
over `ariaLabel` when both are provided.
|
|
94
|
+
* **`Dialog` must include a `Dialog.Title`** so the dialog has an accessible
|
|
95
|
+
name. `Dialog.Title` is wired to `aria-labelledby` automatically, and
|
|
96
|
+
`Dialog.Body` to `aria-describedby` — do not wire these by hand.
|
|
107
97
|
|
|
108
98
|
## UNSAFE\_ props
|
|
109
99
|
|
|
@@ -123,12 +113,14 @@ prefer design tokens inside any custom styles you do write. See
|
|
|
123
113
|
* If using two cards next to each other horizontally, ensure they have a gap
|
|
124
114
|
between them
|
|
125
115
|
|
|
126
|
-
###
|
|
116
|
+
### Dialog
|
|
127
117
|
|
|
128
|
-
*
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
118
|
+
* Use `Dialog` for overlay content. `Modal` is deprecated — do not generate new
|
|
119
|
+
`Modal` or `Modal.Provider` usage.
|
|
120
|
+
* Put the dialog's inner content in `Dialog.Body`, which supplies the padding
|
|
121
|
+
from the edges of the dialog and the gap between fields.
|
|
122
|
+
* Put action buttons in a `Dialog.Actions` inside a `Dialog.Footer` rather than
|
|
123
|
+
placing bare buttons in the body.
|
|
132
124
|
|
|
133
125
|
### Color
|
|
134
126
|
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jobber/components-native",
|
|
3
|
-
"version": "0.113.
|
|
3
|
+
"version": "0.113.7",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "React Native implementation of Atlantis",
|
|
6
6
|
"repository": {
|
|
@@ -67,13 +67,13 @@
|
|
|
67
67
|
"react-intl": "^7.1.11",
|
|
68
68
|
"react-native-keyboard-controller": "^1.20.7",
|
|
69
69
|
"react-native-toast-message": "^2.1.6",
|
|
70
|
-
"react-native-uuid": "^
|
|
70
|
+
"react-native-uuid": "^2.0.4",
|
|
71
71
|
"ts-xor": "^1.1.0"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@babel/runtime": "^7.29.2",
|
|
75
75
|
"@gorhom/bottom-sheet": "^5.2.8",
|
|
76
|
-
"@jobber/design": "0.
|
|
76
|
+
"@jobber/design": "0.113.0",
|
|
77
77
|
"@jobber/hooks": "2.21.1",
|
|
78
78
|
"@react-native-community/datetimepicker": "^8.4.5",
|
|
79
79
|
"@react-native/babel-preset": "^0.82.1",
|
|
@@ -86,7 +86,6 @@
|
|
|
86
86
|
"@types/lodash.debounce": "^4.0.7",
|
|
87
87
|
"@types/lodash.identity": "^3.0.7",
|
|
88
88
|
"@types/node": "^22.19.17",
|
|
89
|
-
"@types/react-native-uuid": "^1.4.0",
|
|
90
89
|
"@types/react-test-renderer": "19.1.0",
|
|
91
90
|
"date-fns": "^2.30.0",
|
|
92
91
|
"date-fns-tz": "^2.0.0",
|
|
@@ -124,5 +123,5 @@
|
|
|
124
123
|
"react-native-screens": ">=4.18.0",
|
|
125
124
|
"react-native-svg": ">=12.0.0"
|
|
126
125
|
},
|
|
127
|
-
"gitHead": "
|
|
126
|
+
"gitHead": "a4a24e9df170032a2d37c2b72e855d95281fafcd"
|
|
128
127
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
|
-
import
|
|
2
|
+
import uuid from "react-native-uuid";
|
|
3
3
|
export function useTokenGenerator() {
|
|
4
4
|
let counter = 0;
|
|
5
|
-
const [identifier] = useState(v1());
|
|
5
|
+
const [identifier] = useState(uuid.v1());
|
|
6
6
|
return [
|
|
7
7
|
() => `@__ELEMENT-${identifier}-${counter++}__@`,
|
|
8
8
|
new RegExp(`(@__ELEMENT-${identifier}-\\d+__@)`, "g"),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useRef } from "react";
|
|
2
2
|
import { View } from "react-native";
|
|
3
|
-
import
|
|
3
|
+
import uuid from "react-native-uuid";
|
|
4
4
|
import { useErrorMessageContext } from "./context";
|
|
5
5
|
import { useStyles } from "./ErrorMessageWrapper.style";
|
|
6
6
|
import { Icon } from "../Icon";
|
|
@@ -16,7 +16,7 @@ export function ErrorMessageWrapper({ message, wrapFor = "default", children, })
|
|
|
16
16
|
const register = errorMessageContext === null || errorMessageContext === void 0 ? void 0 : errorMessageContext.register;
|
|
17
17
|
const unregister = errorMessageContext === null || errorMessageContext === void 0 ? void 0 : errorMessageContext.unregister;
|
|
18
18
|
const a11yMessageRef = useRef(null);
|
|
19
|
-
const { current:
|
|
19
|
+
const { current: id } = useRef(uuid.v4());
|
|
20
20
|
const hasErrorMessage = Boolean(message);
|
|
21
21
|
const styles = useStyles();
|
|
22
22
|
const wrapForStyle = {
|
|
@@ -25,12 +25,12 @@ export function ErrorMessageWrapper({ message, wrapFor = "default", children, })
|
|
|
25
25
|
};
|
|
26
26
|
useEffect(() => {
|
|
27
27
|
if (register) {
|
|
28
|
-
register({ id
|
|
28
|
+
register({ id, ref: a11yMessageRef, hasErrorMessage });
|
|
29
29
|
}
|
|
30
30
|
if (unregister) {
|
|
31
|
-
return () => unregister(
|
|
31
|
+
return () => unregister(id);
|
|
32
32
|
}
|
|
33
|
-
}, [
|
|
33
|
+
}, [id, hasErrorMessage, register, unregister]);
|
|
34
34
|
return (React.createElement(View, { style: [styles.wrapper] },
|
|
35
35
|
hasErrorMessage && (React.createElement(View, { ref: a11yMessageRef, accessible: true, accessibilityRole: "text", accessibilityLabel: message, pointerEvents: "none", style: styles.screenReaderMessage })),
|
|
36
36
|
children,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import uuid from "react-native-uuid";
|
|
2
2
|
import { StatusCode } from "../../types";
|
|
3
3
|
export const FILE_UPLOAD_MOCK_FILE = ({ progress, status = StatusCode.InProgress, }) => ({
|
|
4
4
|
batchContext: {
|
|
5
5
|
batchCount: 1,
|
|
6
6
|
batchId: "FILES",
|
|
7
7
|
},
|
|
8
|
-
uuid: v4(),
|
|
8
|
+
uuid: uuid.v4(),
|
|
9
9
|
key: "path/test.txt",
|
|
10
10
|
name: "test.txt",
|
|
11
11
|
size: 1,
|
|
@@ -21,7 +21,7 @@ export const FILE_UPLOAD_MOCK_IMAGE = ({ progress, size, status = StatusCode.InP
|
|
|
21
21
|
batchCount: 1,
|
|
22
22
|
batchId: "IMAGES",
|
|
23
23
|
},
|
|
24
|
-
uuid: v4(),
|
|
24
|
+
uuid: uuid.v4(),
|
|
25
25
|
key: "path/test.png",
|
|
26
26
|
name: "test.png",
|
|
27
27
|
size: size || 1,
|
|
@@ -37,7 +37,7 @@ export const FILE_UPLOAD_MOCK_PDF = ({ progress, status = StatusCode.InProgress,
|
|
|
37
37
|
batchCount: 1,
|
|
38
38
|
batchId: "FILES",
|
|
39
39
|
},
|
|
40
|
-
uuid: v4(),
|
|
40
|
+
uuid: uuid.v4(),
|
|
41
41
|
key: "path/test.pdf",
|
|
42
42
|
name: "test.pdf",
|
|
43
43
|
size: 1,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from "react";
|
|
2
2
|
import { InputAccessoryView, Keyboard, Platform, Button as RNButton, View, useColorScheme, } from "react-native";
|
|
3
|
-
import
|
|
3
|
+
import uuid from "react-native-uuid";
|
|
4
4
|
import { InputAccessoriesContext } from "./InputAccessoriesContext";
|
|
5
5
|
import { useStyles } from "./InputAccessoriesProvider.style";
|
|
6
6
|
export function InputAccessoriesProvider({ children, }) {
|
|
7
|
-
const inputAccessoryID = useRef(v4()).current;
|
|
7
|
+
const inputAccessoryID = useRef(uuid.v4()).current;
|
|
8
8
|
const { focusedInput, setFocusedInput, canFocusNext, canFocusPrevious, elements, setElements, previousKey, nextKey, } = useInputAccessoriesProviderState();
|
|
9
9
|
const colorScheme = useColorScheme();
|
|
10
10
|
const styles = useStyles();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import uuid from "react-native-uuid";
|
|
2
2
|
import { get, useController, useForm, useFormContext } from "react-hook-form";
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
export function useFormController({ name, value, validations, }) {
|
|
@@ -23,7 +23,7 @@ export function useFormController({ name, value, validations, }) {
|
|
|
23
23
|
return { error, field };
|
|
24
24
|
}
|
|
25
25
|
function useControlName(name) {
|
|
26
|
-
const [identifier] = useState(v1());
|
|
26
|
+
const [identifier] = useState(uuid.v1());
|
|
27
27
|
const prefix = `generatedName--${identifier}`;
|
|
28
28
|
return `${name || prefix}`;
|
|
29
29
|
}
|