@jobber/components-native 0.111.1 → 0.112.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.
- package/dist/docs/ActivityIndicator/ActivityIndicator.md +11 -11
- package/dist/docs/Icon/Icon.md +19 -1
- package/dist/docs/empty-states/empty-states.md +13 -5
- package/dist/package.json +3 -3
- package/dist/src/BottomSheet/BottomSheet.js +1 -1
- package/dist/src/Chip/Chip.js +1 -1
- package/dist/src/Chip/Chip.test.js +1 -1
- package/dist/src/Icon/Icon.js +6 -2
- package/dist/src/Icon/Icon.test.js +14 -0
- package/dist/src/Toast/Toast.js +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/BottomSheet/BottomSheet.tsx +1 -1
- package/src/Chip/Chip.test.tsx +1 -1
- package/src/Chip/Chip.tsx +1 -1
- package/src/Glimmer/Glimmer.stories.tsx +3 -3
- package/src/Icon/Icon.test.tsx +24 -0
- package/src/Icon/Icon.tsx +12 -3
- package/src/Icon/__snapshots__/Icon.test.tsx.snap +1 -13
- package/src/IconButton/IconButton.stories.tsx +1 -1
- package/src/IconButton/docs/IconButtonBasic.tsx +1 -1
- package/src/InputDate/docs/InputDateBasic.tsx +2 -1
- package/src/InputDate/docs/InputDateEmptyValueLabel.tsx +2 -1
- package/src/InputDate/docs/InputDateInvalid.tsx +2 -1
- package/src/Toast/Toast.stories.tsx +4 -4
- package/src/Toast/Toast.tsx +1 -1
|
@@ -65,19 +65,19 @@ cases. The `small` size (16px) should be used on individual elements of an
|
|
|
65
65
|
interface (e.g. inside a `Button` or `Card`) or when sitting next to short
|
|
66
66
|
inline text.
|
|
67
67
|
|
|
68
|
-
Layout is the consumer's responsibility — `ActivityIndicator` does not expose
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
Layout is the consumer's responsibility — `ActivityIndicator` does not expose an
|
|
69
|
+
`inline` prop. Place it inside your own flex / inline-block container, or pass a
|
|
70
|
+
`className` / `style`, to control surrounding layout.
|
|
71
71
|
|
|
72
72
|
## Accessibility
|
|
73
73
|
|
|
74
74
|
`ActivityIndicator` announces itself politely to assistive technology:
|
|
75
75
|
|
|
76
|
-
* `role="status"` marks the element as a polite live region, appropriate for
|
|
77
|
-
|
|
78
|
-
* `aria-label` defaults to the literal English string `"Loading"`. Pass a
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
* `role="status"` marks the element as a polite live region, appropriate for a
|
|
77
|
+
non-urgent loading state.
|
|
78
|
+
* `aria-label` defaults to the literal English string `"Loading"`. Pass a custom
|
|
79
|
+
`ariaLabel` to localize or to describe the specific activity (e.g.
|
|
80
|
+
`ariaLabel="Uploading file"`).
|
|
81
81
|
|
|
82
82
|
The indicator does not participate in the keyboard tab order.
|
|
83
83
|
|
|
@@ -85,9 +85,9 @@ The indicator does not participate in the keyboard tab order.
|
|
|
85
85
|
|
|
86
86
|
When the user's operating system reports
|
|
87
87
|
[`prefers-reduced-motion: reduce`](https://developer.mozilla.org/docs/Web/CSS/@media/prefers-reduced-motion),
|
|
88
|
-
the indicator hides its rocking and rotating layers, repaints a single
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
the indicator hides its rocking and rotating layers, repaints a single static
|
|
89
|
+
ring in the icon foreground colour, and gently pulses its opacity so the
|
|
90
|
+
indicator still reads as "busy" without rotational motion.
|
|
91
91
|
|
|
92
92
|
## Relationship to Spinner
|
|
93
93
|
|
package/dist/docs/Icon/Icon.md
CHANGED
|
@@ -427,7 +427,6 @@ export function IconSizesExample() {
|
|
|
427
427
|
| | `import` |
|
|
428
428
|
| | `merge` |
|
|
429
429
|
| | `redo` |
|
|
430
|
-
| | `remove` |
|
|
431
430
|
| | `search` |
|
|
432
431
|
| | `sort` |
|
|
433
432
|
| | `sync` |
|
|
@@ -512,6 +511,25 @@ export function IconSizesExample() {
|
|
|
512
511
|
| | `plus2` |
|
|
513
512
|
|
|
514
513
|
|
|
514
|
+
## Validating icon names at runtime
|
|
515
|
+
|
|
516
|
+
When icon names arrive as runtime data (API responses, configuration, user
|
|
517
|
+
input), validate them before rendering with the exports from
|
|
518
|
+
`@jobber/components` (also available from `@jobber/design`):
|
|
519
|
+
|
|
520
|
+
* `iconNames`: a readonly array of every valid icon name
|
|
521
|
+
* `isIconName(value)`: a type guard that narrows a value to `IconNames`
|
|
522
|
+
|
|
523
|
+
```tsx
|
|
524
|
+
import { Icon, isIconName } from "@jobber/components";
|
|
525
|
+
|
|
526
|
+
function StatusIcon({ iconName }: { readonly iconName: string }) {
|
|
527
|
+
if (!isIconName(iconName)) return null;
|
|
528
|
+
|
|
529
|
+
return <Icon name={iconName} />;
|
|
530
|
+
}
|
|
531
|
+
```
|
|
532
|
+
|
|
515
533
|
## Component customization
|
|
516
534
|
|
|
517
535
|
### UNSAFE\_ props (advanced usage)
|
|
@@ -21,7 +21,8 @@ for the “emptiness” may include, but are not limited to…
|
|
|
21
21
|
* Search results with no match
|
|
22
22
|
* An error has resulted in the user not being able to access content they
|
|
23
23
|
otherwise could
|
|
24
|
-
* A specific field doesn't have a value (for example, a custom field that the
|
|
24
|
+
* A specific field doesn't have a value (for example, a custom field that the
|
|
25
|
+
user hasn't populated)
|
|
25
26
|
|
|
26
27
|
## Solution
|
|
27
28
|
|
|
@@ -70,22 +71,29 @@ When a field doesn't have a value, use a dash to indicate the lack of a value.
|
|
|
70
71
|
This provides:
|
|
71
72
|
|
|
72
73
|
* confirmation that nothing was entered
|
|
73
|
-
* confirmation that something *can* be entered there should the information
|
|
74
|
+
* confirmation that something *can* be entered there should the information
|
|
75
|
+
require an update
|
|
74
76
|
|
|
75
77
|
```tsx
|
|
76
78
|
<Card>
|
|
77
79
|
<Content>
|
|
78
80
|
<Heading level={4}>Additional details</Heading>
|
|
79
81
|
<Stack gap="smallest">
|
|
80
|
-
<Text size="small" variation="subdued">
|
|
82
|
+
<Text size="small" variation="subdued">
|
|
83
|
+
Preferred service date
|
|
84
|
+
</Text>
|
|
81
85
|
<Text>June 25, 2026</Text>
|
|
82
86
|
</Stack>
|
|
83
87
|
<Stack gap="smallest">
|
|
84
|
-
<Text size="small" variation="subdued">
|
|
88
|
+
<Text size="small" variation="subdued">
|
|
89
|
+
Gate code
|
|
90
|
+
</Text>
|
|
85
91
|
<Text>—</Text>
|
|
86
92
|
</Stack>
|
|
87
93
|
<Stack gap="smallest">
|
|
88
|
-
<Text size="small" variation="subdued">
|
|
94
|
+
<Text size="small" variation="subdued">
|
|
95
|
+
Additional requests
|
|
96
|
+
</Text>
|
|
89
97
|
<Text>—</Text>
|
|
90
98
|
</Stack>
|
|
91
99
|
</Content>
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jobber/components-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.112.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "React Native implementation of Atlantis",
|
|
6
6
|
"repository": {
|
|
@@ -73,7 +73,7 @@
|
|
|
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.111.0",
|
|
77
77
|
"@jobber/hooks": "2.21.0",
|
|
78
78
|
"@react-native-community/datetimepicker": "^8.4.5",
|
|
79
79
|
"@react-native/babel-preset": "^0.82.1",
|
|
@@ -124,5 +124,5 @@
|
|
|
124
124
|
"react-native-screens": ">=4.18.0",
|
|
125
125
|
"react-native-svg": ">=12.0.0"
|
|
126
126
|
},
|
|
127
|
-
"gitHead": "
|
|
127
|
+
"gitHead": "71ed27026cd539889c5ce6c627bd74a8d283112e"
|
|
128
128
|
}
|
|
@@ -64,7 +64,7 @@ function Footer({ styles, close, cancelLabel, }) {
|
|
|
64
64
|
return (React.createElement(View, null,
|
|
65
65
|
React.createElement(View, { style: styles.footerDivider },
|
|
66
66
|
React.createElement(Divider, null)),
|
|
67
|
-
React.createElement(BottomSheetOption, { text: cancelLabel, icon: "
|
|
67
|
+
React.createElement(BottomSheetOption, { text: cancelLabel, icon: "cross", onPress: close })));
|
|
68
68
|
}
|
|
69
69
|
function dismissKeyboard() {
|
|
70
70
|
//Dismisses the keyboard before opening the bottom sheet.
|
package/dist/src/Chip/Chip.js
CHANGED
|
@@ -42,7 +42,7 @@ export function Chip({ icon, label, onPress, isDismissible, isActive, inactiveBa
|
|
|
42
42
|
label && (React.createElement(View, { style: styles.chipText },
|
|
43
43
|
React.createElement(Typography, { color: "base", fontWeight: "medium", maxFontScaleSize: tokens["typography--fontSize-large"], maxLines: "single", reverseTheme: isActive }, label))),
|
|
44
44
|
isDismissible && (React.createElement(View, { style: [styles.dismissIcon, dismissColor] },
|
|
45
|
-
React.createElement(Icon, { name: "
|
|
45
|
+
React.createElement(Icon, { name: "cross", size: "small" })))));
|
|
46
46
|
}
|
|
47
47
|
function getBorderStyle(inactiveBackgroundColor, tokens) {
|
|
48
48
|
let borderColor = "transparent";
|
|
@@ -38,7 +38,7 @@ it("renders an inactive Chip with icon", () => {
|
|
|
38
38
|
});
|
|
39
39
|
it("renders a Chip with the dismiss icon", () => {
|
|
40
40
|
const { getByTestId } = render(React.createElement(Chip, { label: "Foo", onPress: jest.fn(), isActive: true, isDismissible: true }));
|
|
41
|
-
expect(getByTestId("
|
|
41
|
+
expect(getByTestId("cross")).toBeDefined();
|
|
42
42
|
});
|
|
43
43
|
it("should call the handler with the new value", () => {
|
|
44
44
|
const pressHandler = jest.fn();
|
package/dist/src/Icon/Icon.js
CHANGED
|
@@ -7,14 +7,18 @@ export function Icon({ name, color, size = "base", customColor, testID, }) {
|
|
|
7
7
|
const { svgStyle, paths, viewBox } = getIcon({
|
|
8
8
|
name,
|
|
9
9
|
color,
|
|
10
|
+
customColor,
|
|
10
11
|
size,
|
|
11
12
|
platform: "mobile",
|
|
12
13
|
format: "js",
|
|
13
14
|
tokens,
|
|
14
15
|
});
|
|
16
|
+
// Paths with their own fill are static artwork; only unfilled paths take
|
|
17
|
+
// the themed color and customColor.
|
|
15
18
|
// getIcon returns undefined paths for an unknown icon name; render nothing rather than crash.
|
|
16
|
-
const icon = (paths !== null && paths !== void 0 ? paths : []).map(
|
|
17
|
-
|
|
19
|
+
const icon = (paths !== null && paths !== void 0 ? paths : []).map(path => {
|
|
20
|
+
var _a;
|
|
21
|
+
return (React.createElement(Path, { key: path.d, d: path.d, fill: (_a = path.fill) !== null && _a !== void 0 ? _a : (customColor || svgStyle.fill), fillOpacity: path.fillOpacity, opacity: path.opacity }));
|
|
18
22
|
});
|
|
19
23
|
return (React.createElement(Svg, { style: Object.assign(Object.assign({}, svgStyle), { display: "flex" }), testID: testID || name, viewBox: viewBox }, icon));
|
|
20
24
|
}
|
|
@@ -45,6 +45,20 @@ it("renders an empty svg without throwing for an unknown icon name", () => {
|
|
|
45
45
|
const svg = render(React.createElement(Icon, { name: "someNonexistentIcon" }));
|
|
46
46
|
expect(svg.UNSAFE_root.findAllByType(Path)).toHaveLength(0);
|
|
47
47
|
});
|
|
48
|
+
it("renders the multi-color truck icon with its static fills", () => {
|
|
49
|
+
const svg = render(React.createElement(Icon, { name: "truck" }));
|
|
50
|
+
const fills = svg.UNSAFE_root.findAllByType(Path).map(path => path.props.fill);
|
|
51
|
+
expect(fills).toHaveLength(5);
|
|
52
|
+
expect(fills).toContain("#2B2B2B");
|
|
53
|
+
expect(fills.filter(fill => fill.startsWith("#"))).toHaveLength(4);
|
|
54
|
+
});
|
|
55
|
+
it("applies customColor to the truck body path but not its static artwork", () => {
|
|
56
|
+
const svg = render(React.createElement(Icon, { name: "truck", customColor: "#abc123" }));
|
|
57
|
+
const fills = svg.UNSAFE_root.findAllByType(Path).map(path => path.props.fill);
|
|
58
|
+
expect(fills).toHaveLength(5);
|
|
59
|
+
expect(fills.filter(fill => fill === "#abc123")).toHaveLength(1);
|
|
60
|
+
expect(fills).toEqual(expect.arrayContaining(["#2B2B2B", "#000000", "#FFFFFF", "#2A2A2A"]));
|
|
61
|
+
});
|
|
48
62
|
describe("theme-aware fill", () => {
|
|
49
63
|
function getPathFills(svg) {
|
|
50
64
|
return svg.UNSAFE_root.findAllByType(Path).map(p => p.props.fill);
|
package/dist/src/Toast/Toast.js
CHANGED
|
@@ -21,7 +21,7 @@ function DefaultToast({ text1 }) {
|
|
|
21
21
|
React.createElement(TouchableOpacity, { style: styles.toastMessage, accessibilityRole: "alert" },
|
|
22
22
|
React.createElement(Text, { reverseTheme: true }, text1)),
|
|
23
23
|
React.createElement(View, { style: styles.toastIcon },
|
|
24
|
-
React.createElement(IconButton, { onPress: Toast.hide, name: "
|
|
24
|
+
React.createElement(IconButton, { onPress: Toast.hide, name: "cross", customColor: tokens["color-greyBlue--light"], accessibilityLabel: t("dismiss") })))));
|
|
25
25
|
}
|
|
26
26
|
const toastConfig = {
|
|
27
27
|
default: DefaultToast,
|