@studio-piot/native-ui 0.2.3 → 0.2.4

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 (100) hide show
  1. package/README.md +2 -1
  2. package/dist/components/ErrorBanner/ErrorBanner.d.ts +8 -0
  3. package/dist/components/ErrorBanner/ErrorBanner.d.ts.map +1 -0
  4. package/dist/components/ErrorBanner/ErrorBanner.js +136 -0
  5. package/dist/components/ErrorBanner/ErrorBanner.js.map +1 -0
  6. package/dist/components/ErrorBanner/errorBannerContext.d.ts +36 -0
  7. package/dist/components/ErrorBanner/errorBannerContext.d.ts.map +1 -0
  8. package/dist/components/ErrorBanner/errorBannerContext.js +78 -0
  9. package/dist/components/ErrorBanner/errorBannerContext.js.map +1 -0
  10. package/dist/components/ErrorBanner/errorBannerCopy.d.ts +7 -0
  11. package/dist/components/ErrorBanner/errorBannerCopy.d.ts.map +1 -0
  12. package/dist/components/ErrorBanner/errorBannerCopy.js +22 -0
  13. package/dist/components/ErrorBanner/errorBannerCopy.js.map +1 -0
  14. package/dist/components/ErrorBanner/errorBannerThemeRoles.d.ts +9 -0
  15. package/dist/components/ErrorBanner/errorBannerThemeRoles.d.ts.map +1 -0
  16. package/dist/components/ErrorBanner/errorBannerThemeRoles.js +11 -0
  17. package/dist/components/ErrorBanner/errorBannerThemeRoles.js.map +1 -0
  18. package/dist/components/ErrorBanner/icons.d.ts +7 -0
  19. package/dist/components/ErrorBanner/icons.d.ts.map +1 -0
  20. package/dist/components/ErrorBanner/icons.js +46 -0
  21. package/dist/components/ErrorBanner/icons.js.map +1 -0
  22. package/dist/components/ErrorBanner/index.d.ts +6 -0
  23. package/dist/components/ErrorBanner/index.d.ts.map +1 -0
  24. package/dist/components/ErrorBanner/index.js +16 -0
  25. package/dist/components/ErrorBanner/index.js.map +1 -0
  26. package/dist/components/ErrorBanner/types.d.ts +31 -0
  27. package/dist/components/ErrorBanner/types.d.ts.map +1 -0
  28. package/dist/components/ErrorBanner/types.js +3 -0
  29. package/dist/components/ErrorBanner/types.js.map +1 -0
  30. package/dist/components/ErrorBanner/useErrorBanner.d.ts +13 -0
  31. package/dist/components/ErrorBanner/useErrorBanner.d.ts.map +1 -0
  32. package/dist/components/ErrorBanner/useErrorBanner.js +31 -0
  33. package/dist/components/ErrorBanner/useErrorBanner.js.map +1 -0
  34. package/dist/components/Field/fieldChrome.d.ts +1 -1
  35. package/dist/components/Field/fieldChrome.d.ts.map +1 -1
  36. package/dist/components/Field/fieldChrome.js +20 -4
  37. package/dist/components/Field/fieldChrome.js.map +1 -1
  38. package/dist/components/Field/types.d.ts +2 -0
  39. package/dist/components/Field/types.d.ts.map +1 -1
  40. package/dist/components/Form/Form.d.ts +1 -1
  41. package/dist/components/Form/Form.d.ts.map +1 -1
  42. package/dist/components/Form/Form.js +36 -23
  43. package/dist/components/Form/Form.js.map +1 -1
  44. package/dist/components/Form/types.d.ts +7 -0
  45. package/dist/components/Form/types.d.ts.map +1 -1
  46. package/dist/components/RadioField/RadioField.d.ts.map +1 -1
  47. package/dist/components/RadioField/RadioField.js +6 -1
  48. package/dist/components/RadioField/RadioField.js.map +1 -1
  49. package/dist/components/SegmentedControl/SegmentedControl.d.ts +1 -1
  50. package/dist/components/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  51. package/dist/components/SegmentedControl/SegmentedControl.js +8 -8
  52. package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
  53. package/dist/components/SegmentedControl/segmentThemeRoles.d.ts +5 -6
  54. package/dist/components/SegmentedControl/segmentThemeRoles.d.ts.map +1 -1
  55. package/dist/components/SegmentedControl/segmentThemeRoles.js +5 -6
  56. package/dist/components/SegmentedControl/segmentThemeRoles.js.map +1 -1
  57. package/dist/components/Select/Select.d.ts +1 -1
  58. package/dist/components/Select/Select.d.ts.map +1 -1
  59. package/dist/components/Select/Select.js +11 -4
  60. package/dist/components/Select/Select.js.map +1 -1
  61. package/dist/components/Select/types.d.ts +2 -0
  62. package/dist/components/Select/types.d.ts.map +1 -1
  63. package/dist/components/Slider/Slider.d.ts.map +1 -1
  64. package/dist/components/Slider/Slider.js +6 -1
  65. package/dist/components/Slider/Slider.js.map +1 -1
  66. package/dist/components/index.d.ts +1 -0
  67. package/dist/components/index.d.ts.map +1 -1
  68. package/dist/components/index.js +10 -1
  69. package/dist/components/index.js.map +1 -1
  70. package/dist/index.d.ts +2 -1
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +11 -2
  73. package/dist/index.js.map +1 -1
  74. package/docs/components/error-banner.md +85 -0
  75. package/docs/components/form.md +2 -1
  76. package/docs/components/segmented-control.md +23 -13
  77. package/package.json +4 -2
  78. package/src/components/ErrorBanner/ErrorBanner.tsx +232 -0
  79. package/src/components/ErrorBanner/errorBannerContext.tsx +140 -0
  80. package/src/components/ErrorBanner/errorBannerCopy.test.ts +41 -0
  81. package/src/components/ErrorBanner/errorBannerCopy.ts +22 -0
  82. package/src/components/ErrorBanner/errorBannerThemeRoles.test.ts +19 -0
  83. package/src/components/ErrorBanner/errorBannerThemeRoles.ts +9 -0
  84. package/src/components/ErrorBanner/icons.tsx +38 -0
  85. package/src/components/ErrorBanner/index.ts +14 -0
  86. package/src/components/ErrorBanner/types.ts +31 -0
  87. package/src/components/ErrorBanner/useErrorBanner.ts +33 -0
  88. package/src/components/Field/fieldChrome.tsx +33 -7
  89. package/src/components/Field/types.ts +2 -0
  90. package/src/components/Form/Form.tsx +56 -2
  91. package/src/components/Form/types.ts +7 -0
  92. package/src/components/RadioField/RadioField.tsx +6 -1
  93. package/src/components/SegmentedControl/SegmentedControl.tsx +7 -11
  94. package/src/components/SegmentedControl/segmentThemeRoles.test.ts +9 -7
  95. package/src/components/SegmentedControl/segmentThemeRoles.ts +5 -6
  96. package/src/components/Select/Select.tsx +20 -5
  97. package/src/components/Select/types.ts +2 -0
  98. package/src/components/Slider/Slider.tsx +6 -1
  99. package/src/components/index.ts +13 -0
  100. package/src/index.ts +14 -1
@@ -3,15 +3,17 @@ import { describe, it } from "node:test";
3
3
  import { SEGMENTED_THEME_ROLES } from "./segmentThemeRoles.ts";
4
4
 
5
5
  describe("SEGMENTED_THEME_ROLES", () => {
6
- it("maps colour props onto existing Field and radio roles", () => {
7
- assert.equal(SEGMENTED_THEME_ROLES.backgroundColor, "fieldBackground");
8
- assert.equal(SEGMENTED_THEME_ROLES.borderColor, "fieldBorder");
6
+ it("maps colour props to dedicated segment roles", () => {
7
+ assert.equal(SEGMENTED_THEME_ROLES.backgroundColor, "segmentBackground");
9
8
  assert.equal(
10
9
  SEGMENTED_THEME_ROLES.selectedBackgroundColor,
11
- "fieldRadioSelected",
10
+ "segmentSelectedBackground",
12
11
  );
13
- assert.equal(SEGMENTED_THEME_ROLES.labelColor, "fieldText");
14
- assert.equal(SEGMENTED_THEME_ROLES.selectedLabelColor, "fieldBackground");
15
- assert.equal(SEGMENTED_THEME_ROLES.titleColor, "fieldLabel");
12
+ assert.equal(SEGMENTED_THEME_ROLES.labelColor, "segmentLabel");
13
+ assert.equal(
14
+ SEGMENTED_THEME_ROLES.selectedLabelColor,
15
+ "segmentSelectedLabel",
16
+ );
17
+ assert.equal(SEGMENTED_THEME_ROLES.titleColor, "segmentTitle");
16
18
  });
17
19
  });
@@ -1,10 +1,9 @@
1
1
  export const SEGMENTED_THEME_ROLES = {
2
- backgroundColor: "fieldBackground",
3
- borderColor: "fieldBorder",
4
- selectedBackgroundColor: "fieldRadioSelected",
5
- labelColor: "fieldText",
6
- selectedLabelColor: "fieldBackground",
7
- titleColor: "fieldLabel",
2
+ backgroundColor: "segmentBackground",
3
+ selectedBackgroundColor: "segmentSelectedBackground",
4
+ labelColor: "segmentLabel",
5
+ selectedLabelColor: "segmentSelectedLabel",
6
+ titleColor: "segmentTitle",
8
7
  } as const;
9
8
 
10
9
  export type SegmentedThemeColorProp = keyof typeof SEGMENTED_THEME_ROLES;
@@ -23,6 +23,10 @@ import {
23
23
  } from "@gorhom/bottom-sheet";
24
24
  import { FullWindowOverlay } from "react-native-screens";
25
25
  import { buttonRadiusValue } from "../Button/buttonRadius";
26
+ import {
27
+ useErrorBannerDismiss,
28
+ useErrorBannerField,
29
+ } from "../ErrorBanner";
26
30
  import { useResolvedFieldColor } from "../Field/useResolvedFieldColor";
27
31
  import { useThemeColor } from "../../theme/useThemeColor";
28
32
  import { DEFAULT_SELECT_DETENTS } from "./resolveSelectDetentIndex";
@@ -42,6 +46,7 @@ function SheetContainer({ children }: { children?: ReactNode }) {
42
46
  }
43
47
 
44
48
  export function Select({
49
+ name,
45
50
  value,
46
51
  onChange,
47
52
  options,
@@ -105,7 +110,12 @@ export function Select({
105
110
  const closeDiscColor = useThemeColor("text");
106
111
  const closeIconColor = useThemeColor("background");
107
112
 
108
- const hasError = Boolean(error);
113
+ const dismissBanner = useErrorBannerDismiss();
114
+ const { viewRef, listed } = useErrorBannerField(name, () => {
115
+ modalRef.current?.present();
116
+ });
117
+ const hasError = Boolean(error) || Boolean(listed);
118
+ const inlineError = listed ? undefined : error;
109
119
  const selected = options.find((option) => option.value === value);
110
120
  const display = selected?.label ?? placeholder;
111
121
  const isPlaceholder = selected == null;
@@ -192,16 +202,21 @@ export function Select({
192
202
  const onSelect = (option: SelectOption) => {
193
203
  if (option.disabled) return;
194
204
  onChange(option.value);
205
+ dismissBanner();
195
206
  dismiss();
196
207
  };
197
208
 
198
209
  return (
199
- <View style={[styles.column, !editable && styles.blocked, style]}>
210
+ <View
211
+ ref={viewRef}
212
+ collapsable={false}
213
+ style={[styles.column, !editable && styles.blocked, style]}
214
+ >
200
215
  {label ? (
201
216
  <Text style={[styles.label, { color: labelColor }]}>{label}</Text>
202
217
  ) : null}
203
218
  <Pressable
204
- accessibilityHint="Opens a list of options"
219
+ accessibilityHint={listed?.message ?? "Opens a list of options"}
205
220
  accessibilityLabel={label ? `${label}. ${display}` : display}
206
221
  accessibilityRole="button"
207
222
  accessibilityState={{ disabled: !editable }}
@@ -233,8 +248,8 @@ export function Select({
233
248
  ›
234
249
  </Text>
235
250
  </Pressable>
236
- {error ? (
237
- <Text style={[styles.helper, { color: errorColor }]}>{error}</Text>
251
+ {inlineError ? (
252
+ <Text style={[styles.helper, { color: errorColor }]}>{inlineError}</Text>
238
253
  ) : description ? (
239
254
  <Text style={[styles.helper, { color: descriptionColor }]}>
240
255
  {description}
@@ -13,6 +13,8 @@ export type SelectCloseButton =
13
13
  | ((dismiss: () => void) => ReactNode);
14
14
 
15
15
  export type SelectProps = {
16
+ /** Registers the field with `Form` / `ErrorBannerProvider` for banner rows. */
17
+ name?: string;
16
18
  value: string | null;
17
19
  onChange: (value: string) => void;
18
20
  options: SelectOption[];
@@ -1,5 +1,6 @@
1
1
  import { StyleSheet, Text, View } from "react-native";
2
2
  import CommunitySlider from "@react-native-community/slider";
3
+ import { useErrorBannerDismiss } from "../ErrorBanner";
3
4
  import { useResolvedFieldColor } from "../Field/useResolvedFieldColor";
4
5
  import { SLIDER_THEME_ROLES } from "./sliderThemeRoles";
5
6
  import type { SliderProps } from "./types";
@@ -36,6 +37,7 @@ export function Slider({
36
37
  SLIDER_THEME_ROLES.trackColor,
37
38
  );
38
39
 
40
+ const dismissBanner = useErrorBannerDismiss();
39
41
  const display = formatValue(value);
40
42
  const accessibilityLabel = label ? `${label}. ${display}` : display;
41
43
 
@@ -58,7 +60,10 @@ export function Slider({
58
60
  maximumValue={maximumValue}
59
61
  minimumTrackTintColor={highlightColor}
60
62
  minimumValue={minimumValue}
61
- onValueChange={onChange}
63
+ onValueChange={(next) => {
64
+ onChange(next);
65
+ dismissBanner();
66
+ }}
62
67
  step={step}
63
68
  style={styles.track}
64
69
  thumbTintColor={highlightColor}
@@ -21,6 +21,19 @@ export {
21
21
  type FieldTextareaProps,
22
22
  } from "./Field";
23
23
  export { Form, FormCloseButton, type FormProps } from "./Form";
24
+ export {
25
+ ErrorBanner,
26
+ ErrorBannerField,
27
+ ErrorBannerProvider,
28
+ ERROR_BANNER_THEME_ROLES,
29
+ useErrorBanner,
30
+ useErrorBannerContext,
31
+ useErrorBannerDismiss,
32
+ useErrorBannerField,
33
+ type ErrorBannerThemeColorProp,
34
+ type ErrorBannerProps,
35
+ type FieldError,
36
+ } from "./ErrorBanner";
24
37
  export {
25
38
  RadioField,
26
39
  RADIO_THEME_ROLES,
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export const version = "0.2.3";
1
+ export const version = "0.2.4";
2
2
 
3
3
  export * from "./theme";
4
4
  export {
@@ -28,6 +28,19 @@ export {
28
28
  FormCloseButton,
29
29
  type FormProps,
30
30
  } from "./components/Form";
31
+ export {
32
+ ErrorBanner,
33
+ ErrorBannerField,
34
+ ErrorBannerProvider,
35
+ ERROR_BANNER_THEME_ROLES,
36
+ useErrorBanner,
37
+ useErrorBannerContext,
38
+ useErrorBannerDismiss,
39
+ useErrorBannerField,
40
+ type ErrorBannerThemeColorProp,
41
+ type ErrorBannerProps,
42
+ type FieldError,
43
+ } from "./components/ErrorBanner";
31
44
  export {
32
45
  RadioField,
33
46
  RADIO_THEME_ROLES,