@jobber/components-native 0.108.1 → 0.109.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/AtlantisThemeContext/AtlantisThemeContext.md +40 -0
- package/dist/docs/Icon/Icon.md +60 -53
- package/dist/docs/Select/Select.md +987 -0
- package/dist/docs/index.md +1 -0
- package/dist/package.json +3 -3
- package/dist/src/Select/Select.composable.test.js +38 -0
- package/dist/src/Select/Select.js +26 -0
- package/dist/src/Select/SelectComposableTypes.js +1 -0
- package/dist/src/Select/SelectRoot.js +85 -0
- package/dist/src/Select/SelectRoot.style.js +9 -0
- package/dist/src/Select/SelectRoot.test.js +157 -0
- package/dist/src/Select/components/SelectContent.js +51 -0
- package/dist/src/Select/components/SelectContent.test.js +51 -0
- package/dist/src/Select/components/SelectFieldContext.js +10 -0
- package/dist/src/Select/components/SelectItem.js +29 -0
- package/dist/src/Select/components/SelectItem.style.js +6 -0
- package/dist/src/Select/components/SelectItem.test.js +98 -0
- package/dist/src/Select/components/SelectLabel.js +29 -0
- package/dist/src/Select/components/SelectTrigger.js +40 -0
- package/dist/src/Select/components/SelectTrigger.style.js +26 -0
- package/dist/src/Select/index.js +2 -0
- package/dist/src/primitives/Portal/index.js +3 -1
- package/dist/src/primitives/Select/SelectPrimitive.js +4 -12
- package/dist/src/primitives/Select/SelectPrimitive.style.js +14 -9
- package/dist/src/primitives/Select/SelectPrimitive.test.js +2 -2
- package/dist/src/primitives/Select/index.js +1 -1
- package/dist/src/utils/meta/meta.json +11 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/src/Select/Select.composable.test.d.ts +1 -0
- package/dist/types/src/Select/Select.d.ts +18 -0
- package/dist/types/src/Select/SelectComposableTypes.d.ts +50 -0
- package/dist/types/src/Select/SelectRoot.d.ts +12 -0
- package/dist/types/src/Select/SelectRoot.style.d.ts +8 -0
- package/dist/types/src/Select/SelectRoot.test.d.ts +1 -0
- package/dist/types/src/Select/components/SelectContent.d.ts +8 -0
- package/dist/types/src/Select/components/SelectContent.test.d.ts +1 -0
- package/dist/types/src/Select/components/SelectFieldContext.d.ts +27 -0
- package/dist/types/src/Select/components/SelectItem.d.ts +32 -0
- package/dist/types/src/Select/components/SelectItem.style.d.ts +5 -0
- package/dist/types/src/Select/components/SelectItem.test.d.ts +1 -0
- package/dist/types/src/Select/components/SelectLabel.d.ts +22 -0
- package/dist/types/src/Select/components/SelectTrigger.d.ts +20 -0
- package/dist/types/src/Select/components/SelectTrigger.style.d.ts +21 -0
- package/dist/types/src/Select/index.d.ts +2 -1
- package/dist/types/src/primitives/Select/SelectPrimitive.d.ts +3 -1
- package/dist/types/src/primitives/Select/SelectPrimitive.style.d.ts +6 -3
- package/dist/types/src/primitives/Select/index.d.ts +1 -1
- package/dist/types/src/primitives/Select/types.d.ts +1 -1
- package/package.json +3 -3
- package/src/Select/Select.composable.stories.tsx +93 -0
- package/src/Select/Select.composable.test.tsx +56 -0
- package/src/Select/Select.guide.md +197 -0
- package/src/Select/Select.tsx +31 -0
- package/src/Select/SelectComposableTypes.ts +57 -0
- package/src/Select/SelectRoot.style.ts +10 -0
- package/src/Select/SelectRoot.test.tsx +245 -0
- package/src/Select/SelectRoot.tsx +120 -0
- package/src/Select/components/SelectContent.test.tsx +67 -0
- package/src/Select/components/SelectContent.tsx +75 -0
- package/src/Select/components/SelectFieldContext.tsx +46 -0
- package/src/Select/components/SelectItem.style.ts +7 -0
- package/src/Select/components/SelectItem.test.tsx +166 -0
- package/src/Select/components/SelectItem.tsx +78 -0
- package/src/Select/components/SelectLabel.tsx +57 -0
- package/src/Select/components/SelectTrigger.style.ts +29 -0
- package/src/Select/components/SelectTrigger.tsx +98 -0
- package/src/Select/docs/SelectComposableBasic.tsx +18 -0
- package/src/Select/docs/SelectComposableControlledWithRef.tsx +28 -0
- package/src/Select/docs/SelectComposableCustomMarker.tsx +25 -0
- package/src/Select/docs/SelectComposableDescription.tsx +18 -0
- package/src/Select/docs/SelectComposableDisabled.tsx +18 -0
- package/src/Select/docs/SelectComposableDisabledOptions.tsx +20 -0
- package/src/Select/docs/SelectComposableGroupedOptions.tsx +29 -0
- package/src/Select/docs/SelectComposableItemPrefixSuffix.tsx +34 -0
- package/src/Select/docs/SelectComposableLabelAbove.tsx +18 -0
- package/src/Select/docs/SelectComposableLabelInside.tsx +18 -0
- package/src/Select/docs/SelectComposableProvinces.tsx +36 -0
- package/src/Select/docs/SelectComposableReadOnly.tsx +18 -0
- package/src/Select/docs/SelectComposableValidationFlow.tsx +27 -0
- package/src/Select/docs/index.ts +14 -0
- package/src/Select/index.ts +10 -1
- package/src/primitives/Portal/index.ts +3 -1
- package/src/primitives/Select/SelectPrimitive.style.ts +18 -11
- package/src/primitives/Select/SelectPrimitive.test.tsx +2 -2
- package/src/primitives/Select/SelectPrimitive.tsx +6 -18
- package/src/primitives/Select/index.ts +4 -1
- package/src/primitives/Select/types.ts +1 -1
- package/src/utils/meta/meta.json +11 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Keyboard, View } from "react-native";
|
|
3
|
+
import { useRootContext } from "@rn-primitives/select";
|
|
4
|
+
import { useStyles } from "./SelectTrigger.style";
|
|
5
|
+
import { useSelectFieldState } from "./SelectFieldContext";
|
|
6
|
+
import { FieldLabel } from "./SelectLabel";
|
|
7
|
+
import { SELECT_TRIGGER_DEFAULT_TEST_ID, SelectPrimitive, } from "../../primitives/Select";
|
|
8
|
+
import { Icon } from "../../Icon";
|
|
9
|
+
/**
|
|
10
|
+
* The styled field trigger: composes the chevron, the resolved `invalid` styling,
|
|
11
|
+
* the accessible name, the inside label placement, and the static `readOnly`
|
|
12
|
+
* presentation over `SelectPrimitive.Trigger`. State comes from `Select.Root`
|
|
13
|
+
* (field context) and the primitive root context.
|
|
14
|
+
*/
|
|
15
|
+
export function SelectTrigger({ children, testID, ref, }) {
|
|
16
|
+
const styles = useStyles();
|
|
17
|
+
const { invalid, readOnly, accessibilityLabel, labelPlacement } = useSelectFieldState();
|
|
18
|
+
const { open, value, disabled } = useRootContext();
|
|
19
|
+
const isDisabled = disabled !== null && disabled !== void 0 ? disabled : false;
|
|
20
|
+
// `disabled` wins over `readOnly`.
|
|
21
|
+
const isReadOnly = !isDisabled && (readOnly !== null && readOnly !== void 0 ? readOnly : false);
|
|
22
|
+
const isInsideLabel = labelPlacement === "inside";
|
|
23
|
+
const content = (React.createElement(View, { style: [styles.content, isInsideLabel && styles.contentInside] },
|
|
24
|
+
isInsideLabel && React.createElement(FieldLabel, null),
|
|
25
|
+
children));
|
|
26
|
+
if (isReadOnly) {
|
|
27
|
+
return (React.createElement(View, { testID: testID !== null && testID !== void 0 ? testID : SELECT_TRIGGER_DEFAULT_TEST_ID, accessible: true, accessibilityLabel: accessibilityLabel, accessibilityValue: (value === null || value === void 0 ? void 0 : value.label) ? { text: value.label } : undefined, style: styles.readOnly }, content));
|
|
28
|
+
}
|
|
29
|
+
return (React.createElement(SelectPrimitive.Trigger, { ref: ref, testID: testID, invalid: invalid, accessibilityLabel: accessibilityLabel,
|
|
30
|
+
// Dismiss any open keyboard so it doesn't cover the dropdown (matches the
|
|
31
|
+
// native picker's on-device behaviour; rn-primitives doesn't do this).
|
|
32
|
+
onPressIn: () => Keyboard.dismiss() },
|
|
33
|
+
content,
|
|
34
|
+
React.createElement(Chevron, { open: open, disabled: isDisabled })));
|
|
35
|
+
}
|
|
36
|
+
/** Trailing chevron: tinted `iconSecondary`, greyed when disabled, rotated when open. */
|
|
37
|
+
function Chevron({ open, disabled, }) {
|
|
38
|
+
return (React.createElement(View, { style: { transform: [{ rotate: open ? "180deg" : "0deg" }] } },
|
|
39
|
+
React.createElement(Icon, { name: "arrowDown", color: disabled ? "disabled" : "iconSecondary" })));
|
|
40
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { buildThemedStyles } from "../../AtlantisThemeContext";
|
|
2
|
+
export const useStyles = buildThemedStyles(tokens => ({
|
|
3
|
+
content: {
|
|
4
|
+
flex: 1,
|
|
5
|
+
justifyContent: "center",
|
|
6
|
+
},
|
|
7
|
+
// Inside-label placement: the Value's flex fills the column vertically and
|
|
8
|
+
// would otherwise pin the label flush to the top. This top inset gives the
|
|
9
|
+
// label the same breathing room as the shared input chrome's mini-label.
|
|
10
|
+
contentInside: {
|
|
11
|
+
paddingTop: tokens["space-small"] - tokens["space-smallest"],
|
|
12
|
+
},
|
|
13
|
+
// Static read-only surface — mirrors the trigger shape with a subtle fill, no chevron.
|
|
14
|
+
readOnly: {
|
|
15
|
+
flexDirection: "row",
|
|
16
|
+
alignItems: "center",
|
|
17
|
+
gap: tokens["space-small"],
|
|
18
|
+
minHeight: tokens["space-largest"] + tokens["space-small"],
|
|
19
|
+
paddingLeft: tokens["space-base"],
|
|
20
|
+
paddingRight: tokens["space-small"],
|
|
21
|
+
backgroundColor: tokens["color-surface--background--subtle"],
|
|
22
|
+
borderWidth: tokens["border-base"],
|
|
23
|
+
borderColor: tokens["color-border"],
|
|
24
|
+
borderRadius: tokens["radius-base"],
|
|
25
|
+
},
|
|
26
|
+
}));
|
package/dist/src/Select/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// The portal host that backs every portal-based primitive (e.g. the Select
|
|
2
2
|
// dropdown). Apps mount one <AtlantisPortalHost/> at their root; it shares this
|
|
3
3
|
// package's bundled @rn-primitives/portal instance with the primitives' Portal,
|
|
4
|
-
// so registered overlays render in the host.
|
|
4
|
+
// so registered overlays render in the host. On iOS, `Select.Content` lifts the
|
|
5
|
+
// dropdown above native-stack modals with `FullWindowOverlay` (react-native-
|
|
6
|
+
// screens), so this single root host is sufficient on both platforms.
|
|
5
7
|
export { PortalHost as AtlantisPortalHost } from "@rn-primitives/portal";
|
|
@@ -15,6 +15,8 @@ import * as Primitive from "@rn-primitives/select";
|
|
|
15
15
|
import { SafeAreaInsetsContext } from "react-native-safe-area-context";
|
|
16
16
|
import { useStyles } from "./SelectPrimitive.style";
|
|
17
17
|
import { tokens as staticTokens } from "../../utils/design";
|
|
18
|
+
/** Default trigger testID. Consumer-supplied `testID`s are used verbatim. */
|
|
19
|
+
export const SELECT_TRIGGER_DEFAULT_TEST_ID = "ATL-Select-Trigger";
|
|
18
20
|
function SelectPrimitiveRoot(_a) {
|
|
19
21
|
var props = __rest(_a, []);
|
|
20
22
|
return React.createElement(Primitive.Root, Object.assign({}, props));
|
|
@@ -25,23 +27,16 @@ function SelectPrimitiveRoot(_a) {
|
|
|
25
27
|
* primitive provides no chevron of its own.
|
|
26
28
|
*/
|
|
27
29
|
function SelectPrimitiveTrigger(_a) {
|
|
28
|
-
var { children, style, testID
|
|
30
|
+
var { children, style, testID = SELECT_TRIGGER_DEFAULT_TEST_ID, invalid, ref } = _a, props = __rest(_a, ["children", "style", "testID", "invalid", "ref"]);
|
|
29
31
|
const styles = useStyles();
|
|
30
32
|
const { open, value, disabled: rootDisabled } = Primitive.useRootContext();
|
|
31
|
-
const [pressed, setPressed] = React.useState(false);
|
|
32
33
|
// `disabled` is Root-level; the primitive's Trigger won't read it from
|
|
33
34
|
// context, so resolve it here and pass it down to block interaction.
|
|
34
35
|
const isDisabled = rootDisabled !== null && rootDisabled !== void 0 ? rootDisabled : false;
|
|
35
36
|
const isInvalid = !isDisabled && (invalid !== null && invalid !== void 0 ? invalid : false);
|
|
36
37
|
// Announce the selected option as the trigger's value.
|
|
37
38
|
const accessibilityValue = (value === null || value === void 0 ? void 0 : value.label) ? { text: value.label } : undefined;
|
|
38
|
-
return (React.createElement(Primitive.Trigger, Object.assign({ ref: ref, testID:
|
|
39
|
-
setPressed(true);
|
|
40
|
-
onPressIn === null || onPressIn === void 0 ? void 0 : onPressIn(event);
|
|
41
|
-
}, onPressOut: event => {
|
|
42
|
-
setPressed(false);
|
|
43
|
-
onPressOut === null || onPressOut === void 0 ? void 0 : onPressOut(event);
|
|
44
|
-
}, style: [
|
|
39
|
+
return (React.createElement(Primitive.Trigger, Object.assign({ ref: ref, testID: testID, disabled: isDisabled, accessibilityValue: accessibilityValue, style: ({ pressed }) => [
|
|
45
40
|
styles.trigger,
|
|
46
41
|
pressed && !open && styles.triggerPressed,
|
|
47
42
|
open && styles.triggerOpen,
|
|
@@ -50,9 +45,6 @@ function SelectPrimitiveTrigger(_a) {
|
|
|
50
45
|
style,
|
|
51
46
|
] }, props), children));
|
|
52
47
|
}
|
|
53
|
-
function computeTriggerTestID(testID) {
|
|
54
|
-
return testID ? `ATL-${testID}-Select-Trigger` : "ATL-Select-Trigger";
|
|
55
|
-
}
|
|
56
48
|
function SelectPrimitiveValue(_a) {
|
|
57
49
|
var { style } = _a, props = __rest(_a, ["style"]);
|
|
58
50
|
const styles = useStyles();
|
|
@@ -4,10 +4,6 @@ import { tokens as staticTokens } from "../../utils/design";
|
|
|
4
4
|
const baseLineHeight = staticTokens["typography--lineHeight-base"];
|
|
5
5
|
export const useStyles = buildThemedStyles(tokens => {
|
|
6
6
|
const typographyStyles = getTypographyStyles(tokens);
|
|
7
|
-
// The dark theme merges a web CSS-string `shadow-base` over the native object
|
|
8
|
-
// shadow, leaving stray indexed keys on the value. Pick only the React Native
|
|
9
|
-
// shadow properties so those keys never reach the style (spreading them
|
|
10
|
-
// breaks style application through the dropdown's portal on react-native-web).
|
|
11
7
|
const shadowBase = tokens["shadow-base"];
|
|
12
8
|
const contentShadow = {
|
|
13
9
|
shadowColor: shadowBase.shadowColor,
|
|
@@ -22,7 +18,8 @@ export const useStyles = buildThemedStyles(tokens => {
|
|
|
22
18
|
alignItems: "center",
|
|
23
19
|
gap: tokens["space-small"],
|
|
24
20
|
minHeight: tokens["space-largest"] + tokens["space-small"],
|
|
25
|
-
|
|
21
|
+
paddingLeft: tokens["space-base"],
|
|
22
|
+
paddingRight: tokens["space-small"],
|
|
26
23
|
backgroundColor: tokens["color-surface"],
|
|
27
24
|
borderWidth: tokens["border-base"],
|
|
28
25
|
borderColor: tokens["color-border--interactive"],
|
|
@@ -31,15 +28,23 @@ export const useStyles = buildThemedStyles(tokens => {
|
|
|
31
28
|
triggerOpen: {
|
|
32
29
|
borderWidth: tokens["border-thick"],
|
|
33
30
|
borderColor: tokens["color-interactive--subtle"],
|
|
34
|
-
//
|
|
35
|
-
|
|
31
|
+
// On open the border grows from `border-base` to `border-thick`, which
|
|
32
|
+
// would push the content inward by that width delta on each side.
|
|
33
|
+
// Subtract the delta from the horizontal padding so the total inset
|
|
34
|
+
// (border + padding) — and thus the label/value/chevron position — stays
|
|
35
|
+
// constant.
|
|
36
|
+
paddingLeft: tokens["space-base"] - (tokens["border-thick"] - tokens["border-base"]),
|
|
37
|
+
paddingRight: tokens["space-small"] -
|
|
38
|
+
(tokens["border-thick"] - tokens["border-base"]),
|
|
36
39
|
},
|
|
37
40
|
triggerPressed: {
|
|
38
41
|
borderWidth: tokens["border-thick"],
|
|
39
42
|
borderColor: tokens["color-border--interactive"],
|
|
40
|
-
|
|
43
|
+
// Same border-thickness compensation as `triggerOpen` above.
|
|
44
|
+
paddingLeft: tokens["space-base"] - (tokens["border-thick"] - tokens["border-base"]),
|
|
45
|
+
paddingRight: tokens["space-small"] -
|
|
46
|
+
(tokens["border-thick"] - tokens["border-base"]),
|
|
41
47
|
},
|
|
42
|
-
// Critical sets only the colour; width follows the open/pressed state.
|
|
43
48
|
triggerInvalid: {
|
|
44
49
|
borderColor: tokens["color-critical"],
|
|
45
50
|
},
|
|
@@ -32,9 +32,9 @@ describe("SelectPrimitive.Trigger", () => {
|
|
|
32
32
|
renderSelect();
|
|
33
33
|
expect(screen.getByTestId("ATL-Select-Trigger")).toBeDefined();
|
|
34
34
|
});
|
|
35
|
-
it("
|
|
35
|
+
it("uses a provided testID verbatim", () => {
|
|
36
36
|
renderSelect({ testID: "city" });
|
|
37
|
-
expect(screen.getByTestId("
|
|
37
|
+
expect(screen.getByTestId("city")).toBeDefined();
|
|
38
38
|
expect(screen.queryByTestId("ATL-Select-Trigger")).toBeNull();
|
|
39
39
|
});
|
|
40
40
|
it("fires onOpenChange and applies open styling when pressed", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { SelectPrimitive } from "./SelectPrimitive";
|
|
1
|
+
export { SelectPrimitive, SELECT_TRIGGER_DEFAULT_TEST_ID, } from "./SelectPrimitive";
|
|
@@ -60,6 +60,17 @@
|
|
|
60
60
|
"Option",
|
|
61
61
|
"ProgressBar",
|
|
62
62
|
"Select",
|
|
63
|
+
"Select.Content",
|
|
64
|
+
"Select.Group",
|
|
65
|
+
"Select.GroupLabel",
|
|
66
|
+
"Select.Item",
|
|
67
|
+
"Select.ItemPrefix",
|
|
68
|
+
"Select.ItemSuffix",
|
|
69
|
+
"Select.Label",
|
|
70
|
+
"Select.Root",
|
|
71
|
+
"Select.Separator",
|
|
72
|
+
"Select.Trigger",
|
|
73
|
+
"Select.Value",
|
|
63
74
|
"SelectPressable",
|
|
64
75
|
"StatusLabel",
|
|
65
76
|
"Switch",
|