@jobber/components-native 0.105.4 → 0.107.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 (42) hide show
  1. package/dist/docs/ActionItem/ActionItem.md +1 -1
  2. package/dist/docs/ButtonGroup/ButtonGroup.md +2 -2
  3. package/dist/docs/Chip/Chip.md +4 -4
  4. package/dist/docs/EmptyState/EmptyState.md +1 -1
  5. package/dist/docs/Icon/Icon.md +1 -1
  6. package/dist/docs/IconButton/IconButton.md +1 -1
  7. package/dist/docs/usage-guidelines/usage-guidelines.md +5 -5
  8. package/dist/package.json +5 -3
  9. package/dist/src/ActivityIndicator/ActivityIndicator.js +1 -1
  10. package/dist/src/primitives/Portal/index.js +5 -0
  11. package/dist/src/primitives/Select/SelectPrimitive.js +173 -0
  12. package/dist/src/primitives/Select/SelectPrimitive.style.js +112 -0
  13. package/dist/src/primitives/Select/SelectPrimitive.test.js +243 -0
  14. package/dist/src/primitives/Select/index.js +1 -0
  15. package/dist/src/primitives/Select/types.js +1 -0
  16. package/dist/src/primitives/index.js +2 -0
  17. package/dist/src/utils/test/PortalHostWrapper.js +11 -0
  18. package/dist/src/utils/test/index.js +1 -0
  19. package/dist/tsconfig.build.tsbuildinfo +1 -1
  20. package/dist/types/src/primitives/Portal/index.d.ts +1 -0
  21. package/dist/types/src/primitives/Select/SelectPrimitive.d.ts +67 -0
  22. package/dist/types/src/primitives/Select/SelectPrimitive.style.d.ts +105 -0
  23. package/dist/types/src/primitives/Select/SelectPrimitive.test.d.ts +1 -0
  24. package/dist/types/src/primitives/Select/index.d.ts +2 -0
  25. package/dist/types/src/primitives/Select/types.d.ts +41 -0
  26. package/dist/types/src/primitives/index.d.ts +2 -0
  27. package/dist/types/src/utils/test/PortalHostWrapper.d.ts +10 -0
  28. package/dist/types/src/utils/test/index.d.ts +1 -0
  29. package/package.json +5 -3
  30. package/src/ActivityIndicator/ActivityIndicator.stories.tsx +46 -1
  31. package/src/ActivityIndicator/ActivityIndicator.tsx +1 -1
  32. package/src/ActivityIndicator/guide.md +6 -4
  33. package/src/primitives/Portal/index.ts +5 -0
  34. package/src/primitives/Select/SelectPrimitive.stories.tsx +221 -0
  35. package/src/primitives/Select/SelectPrimitive.style.ts +141 -0
  36. package/src/primitives/Select/SelectPrimitive.test.tsx +372 -0
  37. package/src/primitives/Select/SelectPrimitive.tsx +292 -0
  38. package/src/primitives/Select/index.ts +17 -0
  39. package/src/primitives/Select/types.ts +96 -0
  40. package/src/primitives/index.ts +2 -0
  41. package/src/utils/test/PortalHostWrapper.tsx +19 -0
  42. package/src/utils/test/index.ts +1 -0
@@ -0,0 +1,292 @@
1
+ import React from "react";
2
+ import { StyleSheet } from "react-native";
3
+ import * as Primitive from "@rn-primitives/select";
4
+ import { SafeAreaInsetsContext } from "react-native-safe-area-context";
5
+ import { useStyles } from "./SelectPrimitive.style";
6
+ import type {
7
+ SelectPrimitiveContentProps,
8
+ SelectPrimitiveGroupProps,
9
+ SelectPrimitiveItemIndicatorProps,
10
+ SelectPrimitiveItemProps,
11
+ SelectPrimitiveItemTextProps,
12
+ SelectPrimitiveLabelProps,
13
+ SelectPrimitiveOverlayProps,
14
+ SelectPrimitivePortalProps,
15
+ SelectPrimitiveRootProps,
16
+ SelectPrimitiveSeparatorProps,
17
+ SelectPrimitiveTriggerProps,
18
+ SelectPrimitiveValueProps,
19
+ SelectPrimitiveViewportProps,
20
+ } from "./types";
21
+ import { tokens as staticTokens } from "../../utils/design";
22
+
23
+ function SelectPrimitiveRoot({ ...props }: SelectPrimitiveRootProps) {
24
+ return <Primitive.Root {...props} />;
25
+ }
26
+
27
+ /**
28
+ * Styled trigger field. Renders only its `children` — compose
29
+ * `SelectPrimitive.Value` and any trailing icon (e.g. a chevron) here; the
30
+ * primitive provides no chevron of its own.
31
+ */
32
+ function SelectPrimitiveTrigger({
33
+ children,
34
+ style,
35
+ testID,
36
+ invalid,
37
+ onPressIn,
38
+ onPressOut,
39
+ ref,
40
+ ...props
41
+ }: SelectPrimitiveTriggerProps) {
42
+ const styles = useStyles();
43
+ const { open, value, disabled: rootDisabled } = Primitive.useRootContext();
44
+ const [pressed, setPressed] = React.useState(false);
45
+
46
+ // `disabled` is Root-level; the primitive's Trigger won't read it from
47
+ // context, so resolve it here and pass it down to block interaction.
48
+ const isDisabled = rootDisabled ?? false;
49
+ const isInvalid = !isDisabled && (invalid ?? false);
50
+
51
+ // Announce the selected option as the trigger's value.
52
+ const accessibilityValue = value?.label ? { text: value.label } : undefined;
53
+
54
+ return (
55
+ <Primitive.Trigger
56
+ ref={ref}
57
+ testID={computeTriggerTestID(testID)}
58
+ disabled={isDisabled}
59
+ accessibilityValue={accessibilityValue}
60
+ onPressIn={event => {
61
+ setPressed(true);
62
+ onPressIn?.(event);
63
+ }}
64
+ onPressOut={event => {
65
+ setPressed(false);
66
+ onPressOut?.(event);
67
+ }}
68
+ style={[
69
+ styles.trigger,
70
+ pressed && !open && styles.triggerPressed,
71
+ open && styles.triggerOpen,
72
+ isInvalid && styles.triggerInvalid,
73
+ isDisabled && styles.triggerDisabled,
74
+ style,
75
+ ]}
76
+ {...props}
77
+ >
78
+ {children}
79
+ </Primitive.Trigger>
80
+ );
81
+ }
82
+
83
+ function computeTriggerTestID(testID?: string): string {
84
+ return testID ? `ATL-${testID}-Select-Trigger` : "ATL-Select-Trigger";
85
+ }
86
+
87
+ function SelectPrimitiveValue({ style, ...props }: SelectPrimitiveValueProps) {
88
+ const styles = useStyles();
89
+ const { value, disabled } = Primitive.useRootContext();
90
+ const isEmpty = value?.value === undefined;
91
+
92
+ return (
93
+ <Primitive.Value
94
+ style={[
95
+ styles.value,
96
+ isEmpty && styles.valuePlaceholder,
97
+ disabled && styles.valueDisabled,
98
+ style,
99
+ ]}
100
+ {...props}
101
+ />
102
+ );
103
+ }
104
+
105
+ /** Portals the dropdown into the mounted `AtlantisPortalHost`. */
106
+ function SelectPrimitivePortal({ ...props }: SelectPrimitivePortalProps) {
107
+ return <Primitive.Portal {...props} />;
108
+ }
109
+
110
+ /** Tap-outside dismiss surface behind the dropdown (no scrim). */
111
+ function SelectPrimitiveOverlay({
112
+ style,
113
+ testID = "ATL-Select-Overlay",
114
+ ...props
115
+ }: SelectPrimitiveOverlayProps) {
116
+ const styles = useStyles();
117
+
118
+ return (
119
+ <Primitive.Overlay
120
+ testID={testID}
121
+ style={StyleSheet.flatten([styles.overlay, style])}
122
+ {...props}
123
+ />
124
+ );
125
+ }
126
+
127
+ /**
128
+ * Anchored dropdown surface: matches the trigger width, applies safe-area
129
+ * insets, and flips above the trigger when space is tight. Compose it inside
130
+ * `Portal`, alongside `Overlay`, wrapping the items in a `Viewport`.
131
+ */
132
+ function SelectPrimitiveContent({
133
+ children,
134
+ style,
135
+ sideOffset = staticTokens["space-smaller"],
136
+ insets,
137
+ ref,
138
+ ...props
139
+ }: SelectPrimitiveContentProps) {
140
+ const styles = useStyles();
141
+ // Read the context directly, not `useSafeAreaInsets` (which throws without a
142
+ // provider): `Content` renders at the portal host, which may sit outside one.
143
+ const safeAreaInsets = React.useContext(SafeAreaInsetsContext) ?? undefined;
144
+ const { triggerPosition } = Primitive.useRootContext();
145
+
146
+ return (
147
+ <Primitive.Content
148
+ ref={ref}
149
+ sideOffset={sideOffset}
150
+ insets={insets ?? safeAreaInsets}
151
+ style={StyleSheet.flatten([
152
+ styles.content,
153
+ triggerPosition ? { width: triggerPosition.width } : undefined,
154
+ style,
155
+ ])}
156
+ {...props}
157
+ >
158
+ {children}
159
+ </Primitive.Content>
160
+ );
161
+ }
162
+
163
+ /** Scroll container for the items (a no-op passthrough on native). */
164
+ function SelectPrimitiveViewport({ ...props }: SelectPrimitiveViewportProps) {
165
+ return <Primitive.Viewport {...props} />;
166
+ }
167
+
168
+ /**
169
+ * Styled, pressable option row. Compose its content from `SelectPrimitive.ItemText`
170
+ * and `SelectPrimitive.ItemIndicator` (and anything else) as `children`.
171
+ */
172
+ function SelectPrimitiveItem({
173
+ style,
174
+ disabled,
175
+ ref,
176
+ ...props
177
+ }: SelectPrimitiveItemProps) {
178
+ const styles = useStyles();
179
+
180
+ return (
181
+ <Primitive.Item
182
+ ref={ref}
183
+ disabled={disabled}
184
+ style={({ pressed }) => [
185
+ styles.item,
186
+ pressed && styles.itemPressed,
187
+ style,
188
+ ]}
189
+ {...props}
190
+ />
191
+ );
192
+ }
193
+
194
+ /**
195
+ * The option label as styled text (reads the label from the item context). The
196
+ * `disabled` flag is explicit — the composing layer (e.g. the sugared
197
+ * `Select.Item`) forwards the row's disabled state to grey the text.
198
+ */
199
+ function SelectPrimitiveItemText({
200
+ style,
201
+ disabled,
202
+ ref,
203
+ ...props
204
+ }: SelectPrimitiveItemTextProps) {
205
+ const styles = useStyles();
206
+
207
+ return (
208
+ <Primitive.ItemText
209
+ ref={ref}
210
+ style={[styles.itemText, disabled && styles.itemTextDisabled, style]}
211
+ {...props}
212
+ />
213
+ );
214
+ }
215
+
216
+ /**
217
+ * The selected-state marker slot. Renders its `children` (the marker, e.g. a
218
+ * checkmark) on the selected row only — it self-hides on unselected rows. The
219
+ * marker glyph is supplied by the composing layer, not defaulted here.
220
+ */
221
+ function SelectPrimitiveItemIndicator({
222
+ style,
223
+ ref,
224
+ ...props
225
+ }: SelectPrimitiveItemIndicatorProps) {
226
+ const styles = useStyles();
227
+
228
+ return (
229
+ <Primitive.ItemIndicator
230
+ ref={ref}
231
+ style={[styles.itemIndicator, style]}
232
+ {...props}
233
+ />
234
+ );
235
+ }
236
+
237
+ /**
238
+ * Groups related options, typically with a `SelectPrimitive.Label` heading.
239
+ */
240
+ function SelectPrimitiveGroup({ ...props }: SelectPrimitiveGroupProps) {
241
+ return <Primitive.Group {...props} />;
242
+ }
243
+
244
+ /**
245
+ * A styled group heading rendered inside `SelectPrimitive.Group`.
246
+ */
247
+ function SelectPrimitiveLabel({
248
+ style,
249
+ ref,
250
+ ...props
251
+ }: SelectPrimitiveLabelProps) {
252
+ const styles = useStyles();
253
+
254
+ return (
255
+ <Primitive.Label ref={ref} style={[styles.groupLabel, style]} {...props} />
256
+ );
257
+ }
258
+
259
+ /**
260
+ * A styled divider between groups or options.
261
+ */
262
+ function SelectPrimitiveSeparator({
263
+ style,
264
+ ref,
265
+ ...props
266
+ }: SelectPrimitiveSeparatorProps) {
267
+ const styles = useStyles();
268
+
269
+ return (
270
+ <Primitive.Separator
271
+ ref={ref}
272
+ style={[styles.separator, style]}
273
+ {...props}
274
+ />
275
+ );
276
+ }
277
+
278
+ export const SelectPrimitive = {
279
+ Root: SelectPrimitiveRoot,
280
+ Trigger: SelectPrimitiveTrigger,
281
+ Value: SelectPrimitiveValue,
282
+ Portal: SelectPrimitivePortal,
283
+ Overlay: SelectPrimitiveOverlay,
284
+ Content: SelectPrimitiveContent,
285
+ Viewport: SelectPrimitiveViewport,
286
+ Item: SelectPrimitiveItem,
287
+ ItemText: SelectPrimitiveItemText,
288
+ ItemIndicator: SelectPrimitiveItemIndicator,
289
+ Group: SelectPrimitiveGroup,
290
+ Label: SelectPrimitiveLabel,
291
+ Separator: SelectPrimitiveSeparator,
292
+ };
@@ -0,0 +1,17 @@
1
+ export { SelectPrimitive } from "./SelectPrimitive";
2
+ export type {
3
+ SelectPrimitiveContentProps,
4
+ SelectPrimitiveGroupProps,
5
+ SelectPrimitiveItemIndicatorProps,
6
+ SelectPrimitiveItemProps,
7
+ SelectPrimitiveItemTextProps,
8
+ SelectPrimitiveLabelProps,
9
+ SelectPrimitiveOption,
10
+ SelectPrimitiveOverlayProps,
11
+ SelectPrimitivePortalProps,
12
+ SelectPrimitiveRootProps,
13
+ SelectPrimitiveSeparatorProps,
14
+ SelectPrimitiveTriggerProps,
15
+ SelectPrimitiveValueProps,
16
+ SelectPrimitiveViewportProps,
17
+ } from "./types";
@@ -0,0 +1,96 @@
1
+ import type React from "react";
2
+ import type { StyleProp, ViewStyle } from "react-native";
3
+ import type {
4
+ ContentProps,
5
+ ContentRef,
6
+ GroupProps,
7
+ GroupRef,
8
+ ItemIndicatorProps,
9
+ ItemIndicatorRef,
10
+ ItemProps,
11
+ ItemRef,
12
+ ItemTextProps,
13
+ ItemTextRef,
14
+ LabelProps,
15
+ LabelRef,
16
+ Option,
17
+ OverlayProps,
18
+ OverlayRef,
19
+ PortalProps,
20
+ RootProps,
21
+ SeparatorProps,
22
+ SeparatorRef,
23
+ TriggerProps,
24
+ TriggerRef,
25
+ ValueProps,
26
+ ViewportProps,
27
+ } from "@rn-primitives/select";
28
+
29
+ export type { Option as SelectPrimitiveOption };
30
+
31
+ export type SelectPrimitiveRootProps = RootProps;
32
+
33
+ export interface SelectPrimitiveTriggerProps
34
+ extends Omit<TriggerProps, "style" | "children" | "disabled" | "asChild">,
35
+ React.RefAttributes<TriggerRef> {
36
+ /** Renders as `ATL-<testID>-Select-Trigger`, or `ATL-Select-Trigger` when omitted. */
37
+ readonly testID?: string;
38
+
39
+ /** Critical (error) border styling. Style-only — no field/validation logic. */
40
+ readonly invalid?: boolean;
41
+
42
+ /** Callback styles are not supported; state styling is composed internally. */
43
+ readonly style?: StyleProp<ViewStyle>;
44
+
45
+ readonly children?: React.ReactNode;
46
+ }
47
+
48
+ export type SelectPrimitiveValueProps = ValueProps;
49
+
50
+ export type SelectPrimitivePortalProps = PortalProps;
51
+
52
+ export interface SelectPrimitiveOverlayProps
53
+ extends Omit<OverlayProps, "style" | "asChild">,
54
+ React.RefAttributes<OverlayRef> {
55
+ readonly style?: StyleProp<ViewStyle>;
56
+ }
57
+
58
+ export interface SelectPrimitiveContentProps
59
+ extends ContentProps,
60
+ React.RefAttributes<ContentRef> {}
61
+
62
+ export type SelectPrimitiveViewportProps = ViewportProps;
63
+
64
+ export interface SelectPrimitiveItemProps
65
+ extends Omit<ItemProps, "style" | "asChild">,
66
+ React.RefAttributes<ItemRef> {
67
+ /** Callback styles are not supported; pressed styling is composed internally. */
68
+ readonly style?: StyleProp<ViewStyle>;
69
+
70
+ /** Compose `ItemText` / `ItemIndicator` (and any other content) as children. */
71
+ readonly children?: React.ReactNode;
72
+ }
73
+
74
+ export interface SelectPrimitiveItemTextProps
75
+ extends Omit<ItemTextProps, "asChild">,
76
+ React.RefAttributes<ItemTextRef> {
77
+ /** Greys the label; the composing layer forwards the row's disabled state. */
78
+ readonly disabled?: boolean;
79
+ }
80
+
81
+ /** The default selected-item checkmark; overridable via `children`. */
82
+ export interface SelectPrimitiveItemIndicatorProps
83
+ extends ItemIndicatorProps,
84
+ React.RefAttributes<ItemIndicatorRef> {}
85
+
86
+ export interface SelectPrimitiveGroupProps
87
+ extends GroupProps,
88
+ React.RefAttributes<GroupRef> {}
89
+
90
+ export interface SelectPrimitiveLabelProps
91
+ extends LabelProps,
92
+ React.RefAttributes<LabelRef> {}
93
+
94
+ export interface SelectPrimitiveSeparatorProps
95
+ extends SeparatorProps,
96
+ React.RefAttributes<SeparatorRef> {}
@@ -2,3 +2,5 @@
2
2
  * This file exports styled components-native primitives.
3
3
  */
4
4
  export * from "./HelperText";
5
+ export * from "./Portal";
6
+ export * from "./Select";
@@ -0,0 +1,19 @@
1
+ import React from "react";
2
+ import { PortalHost } from "@rn-primitives/portal";
3
+
4
+ interface PortalHostWrapperProps {
5
+ readonly children: React.ReactNode;
6
+ }
7
+
8
+ /**
9
+ * Test wrapper that mounts a `PortalHost` so portal-based overlays (e.g. the
10
+ * Select dropdown) render: `render(ui, { wrapper: PortalHostWrapper })`.
11
+ */
12
+ export function PortalHostWrapper({ children }: PortalHostWrapperProps) {
13
+ return (
14
+ <>
15
+ {children}
16
+ <PortalHost />
17
+ </>
18
+ );
19
+ }
@@ -1 +1,2 @@
1
1
  export { MockSafeAreaProvider } from "./MockSafeAreaProvider";
2
+ export { PortalHostWrapper } from "./PortalHostWrapper";