@kanso-labs/react-native-kanso-ui 0.0.0-stage → 0.1.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 (145) hide show
  1. package/LICENSE.md +20 -0
  2. package/README.md +205 -2
  3. package/dist/button/index.d.ts +56 -0
  4. package/dist/button/index.js +169 -0
  5. package/dist/button/index.js.map +1 -0
  6. package/dist/button/palettes.js +47 -0
  7. package/dist/button/palettes.js.map +1 -0
  8. package/dist/chip/index.js +194 -0
  9. package/dist/chip/index.js.map +1 -0
  10. package/dist/chip/styles.js +36 -0
  11. package/dist/chip/styles.js.map +1 -0
  12. package/dist/clipboard/index.js +58 -0
  13. package/dist/clipboard/index.js.map +1 -0
  14. package/dist/components/avatar/index.d.ts +82 -0
  15. package/dist/components/avatar/index.js +62 -0
  16. package/dist/components/avatar/index.js.map +1 -0
  17. package/dist/components/button/index.d.ts +87 -0
  18. package/dist/components/button/index.js +377 -0
  19. package/dist/components/button/index.js.map +1 -0
  20. package/dist/components/card/index.d.ts +78 -0
  21. package/dist/components/card/index.js +315 -0
  22. package/dist/components/card/index.js.map +1 -0
  23. package/dist/components/checkbox/index.d.ts +76 -0
  24. package/dist/components/checkbox/index.js +360 -0
  25. package/dist/components/checkbox/index.js.map +1 -0
  26. package/dist/components/chip/index.d.ts +84 -0
  27. package/dist/components/chip/index.js +257 -0
  28. package/dist/components/chip/index.js.map +1 -0
  29. package/dist/components/chip-group/index.d.ts +143 -0
  30. package/dist/components/chip-group/index.js +669 -0
  31. package/dist/components/chip-group/index.js.map +1 -0
  32. package/dist/components/copy-field/index.d.ts +60 -0
  33. package/dist/components/copy-field/index.js +277 -0
  34. package/dist/components/copy-field/index.js.map +1 -0
  35. package/dist/components/currency/index.d.ts +69 -0
  36. package/dist/components/currency/index.js +162 -0
  37. package/dist/components/currency/index.js.map +1 -0
  38. package/dist/components/form/index.d.ts +84 -0
  39. package/dist/components/form/index.js +95 -0
  40. package/dist/components/form/index.js.map +1 -0
  41. package/dist/components/icon-button/index.d.ts +68 -0
  42. package/dist/components/icon-button/index.js +289 -0
  43. package/dist/components/icon-button/index.js.map +1 -0
  44. package/dist/components/link/index.d.ts +59 -0
  45. package/dist/components/link/index.js +191 -0
  46. package/dist/components/link/index.js.map +1 -0
  47. package/dist/components/number-field/index.d.ts +151 -0
  48. package/dist/components/number-field/index.js +832 -0
  49. package/dist/components/number-field/index.js.map +1 -0
  50. package/dist/components/product-icon/index.d.ts +70 -0
  51. package/dist/components/product-icon/index.js +60 -0
  52. package/dist/components/product-icon/index.js.map +1 -0
  53. package/dist/components/radio-group/index.d.ts +105 -0
  54. package/dist/components/radio-group/index.js +597 -0
  55. package/dist/components/radio-group/index.js.map +1 -0
  56. package/dist/components/search-field/index.d.ts +98 -0
  57. package/dist/components/search-field/index.js +521 -0
  58. package/dist/components/search-field/index.js.map +1 -0
  59. package/dist/components/segmented-button/index.d.ts +113 -0
  60. package/dist/components/segmented-button/index.js +937 -0
  61. package/dist/components/segmented-button/index.js.map +1 -0
  62. package/dist/components/separator/index.d.ts +45 -0
  63. package/dist/components/separator/index.js +109 -0
  64. package/dist/components/separator/index.js.map +1 -0
  65. package/dist/components/stack/index.d.ts +70 -0
  66. package/dist/components/stack/index.js +107 -0
  67. package/dist/components/stack/index.js.map +1 -0
  68. package/dist/components/switch/index.d.ts +76 -0
  69. package/dist/components/switch/index.js +591 -0
  70. package/dist/components/switch/index.js.map +1 -0
  71. package/dist/components/text/index.d.ts +44 -0
  72. package/dist/components/text/index.js +78 -0
  73. package/dist/components/text/index.js.map +1 -0
  74. package/dist/components/text-field/index.d.ts +146 -0
  75. package/dist/components/text-field/index.js +228 -0
  76. package/dist/components/text-field/index.js.map +1 -0
  77. package/dist/control/index.js +117 -0
  78. package/dist/control/index.js.map +1 -0
  79. package/dist/control/styles.js +36 -0
  80. package/dist/control/styles.js.map +1 -0
  81. package/dist/field/index.d.ts +13 -0
  82. package/dist/field/index.js +1007 -0
  83. package/dist/field/index.js.map +1 -0
  84. package/dist/field/styles.js +131 -0
  85. package/dist/field/styles.js.map +1 -0
  86. package/dist/form/index.d.ts +24 -0
  87. package/dist/form/index.js +209 -0
  88. package/dist/form/index.js.map +1 -0
  89. package/dist/glyphs/icon-style.d.ts +25 -0
  90. package/dist/glyphs/icon-style.js +22 -0
  91. package/dist/glyphs/icon-style.js.map +1 -0
  92. package/dist/glyphs/index.js +170 -0
  93. package/dist/glyphs/index.js.map +1 -0
  94. package/dist/glyphs/styles.js +7 -0
  95. package/dist/glyphs/styles.js.map +1 -0
  96. package/dist/hooks/useWindowSizeClass.d.ts +25 -0
  97. package/dist/hooks/useWindowSizeClass.js +39 -0
  98. package/dist/hooks/useWindowSizeClass.js.map +1 -0
  99. package/dist/index.d.ts +31 -0
  100. package/dist/index.js +27 -0
  101. package/dist/mark/image.js +61 -0
  102. package/dist/mark/image.js.map +1 -0
  103. package/dist/mark/index.d.ts +9 -0
  104. package/dist/mark/index.js +234 -0
  105. package/dist/mark/index.js.map +1 -0
  106. package/dist/mark/initials.js +65 -0
  107. package/dist/mark/initials.js.map +1 -0
  108. package/dist/mark/styles.d.ts +1 -0
  109. package/dist/mark/styles.js +73 -0
  110. package/dist/mark/styles.js.map +1 -0
  111. package/dist/number/parser.js +321 -0
  112. package/dist/number/parser.js.map +1 -0
  113. package/dist/number/state.js +235 -0
  114. package/dist/number/state.js.map +1 -0
  115. package/dist/overlay/host.js +111 -0
  116. package/dist/overlay/host.js.map +1 -0
  117. package/dist/press/index.js +350 -0
  118. package/dist/press/index.js.map +1 -0
  119. package/dist/press/styles.js +31 -0
  120. package/dist/press/styles.js.map +1 -0
  121. package/dist/router/index.d.ts +28 -0
  122. package/dist/router/index.js +82 -0
  123. package/dist/router/index.js.map +1 -0
  124. package/dist/theme/color.js +25 -0
  125. package/dist/theme/color.js.map +1 -0
  126. package/dist/theme/resolve.d.ts +6 -0
  127. package/dist/theme/resolve.js +310 -0
  128. package/dist/theme/resolve.js.map +1 -0
  129. package/dist/theme/scope.d.ts +42 -0
  130. package/dist/theme/scope.js +80 -0
  131. package/dist/theme/scope.js.map +1 -0
  132. package/dist/theme/styles.js +39 -0
  133. package/dist/theme/styles.js.map +1 -0
  134. package/dist/theme-scope.d.ts +56 -0
  135. package/dist/theme-scope.js +127 -0
  136. package/dist/theme-scope.js.map +1 -0
  137. package/dist/tokens/defaults.d.ts +407 -0
  138. package/dist/tokens/defaults.js +403 -0
  139. package/dist/tokens/defaults.js.map +1 -0
  140. package/dist/typography/fonts.js +84 -0
  141. package/dist/typography/fonts.js.map +1 -0
  142. package/dist/typography/roles.d.ts +10 -0
  143. package/dist/typography/roles.js +82 -0
  144. package/dist/typography/roles.js.map +1 -0
  145. package/package.json +132 -4
@@ -0,0 +1,44 @@
1
+ import { TypeRole } from "../../typography/roles.js";
2
+ import { Text, TextProps } from "react-native";
3
+ import { ComponentRef, Ref } from "react";
4
+ //#region src/components/text/index.d.ts
5
+ type TextProps$1 = TextProps & {
6
+ readonly ref?: Ref<ComponentRef<typeof Text>>;
7
+ /**
8
+ * The colour role to draw in. `neutral` is the on-surface role, as it is on
9
+ * web; `inherit` takes the colour of the Text around it instead of setting
10
+ * one.
11
+ * @default 'neutral'
12
+ */
13
+ readonly tone?: 'error' | 'inherit' | 'muted' | 'negative' | 'neutral' | 'positive' | 'primary';
14
+ /**
15
+ * Which role of the type scale to draw in.
16
+ * @default 'bodyMedium'
17
+ */
18
+ readonly variant?: TypeRole;
19
+ };
20
+ /**
21
+ * A run of text in one role of Material Design's type scale and one colour
22
+ * role, with web's props and values.
23
+ *
24
+ * ```tsx
25
+ * <Text accessibilityRole="header" variant="titleLarge">
26
+ * Headline
27
+ * </Text>
28
+ * ```
29
+ *
30
+ * Each role reads its family, size, line height, weight and tracking from the
31
+ * theme, so an override of the plain or brand family reaches every role drawn
32
+ * in it. The family is the token's first when the app has registered it with
33
+ * expo-font, and the system font otherwise. The OS text size scales every
34
+ * role, as `allowFontScaling` leaves it.
35
+ *
36
+ * Web's `render` and `block` have no counterpart: a native Text is a block
37
+ * unless it sits inside another, and a heading is an `accessibilityRole`
38
+ * rather than an element. `style`, `ref` and `testID` land on React Native's
39
+ * own Text.
40
+ */
41
+ declare function Text$1({ style, tone, variant, ...props }: TextProps$1): import("react").JSX.Element;
42
+ //#endregion
43
+ export { Text$1 as Text, type TextProps$1 as TextProps };
44
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,78 @@
1
+ import { useTheme } from "../../theme/scope.js";
2
+ import { composeStyles, themedStyles } from "../../theme/styles.js";
3
+ import { useTypeRole } from "../../typography/roles.js";
4
+ import { c } from "react/compiler-runtime";
5
+ import { StyleSheet, Text } from "react-native";
6
+ import { jsx } from "react/jsx-runtime";
7
+ //#region src/components/text/index.tsx
8
+ const stylesOf = themedStyles(({ colors }) => StyleSheet.create({
9
+ error: { color: colors.error },
10
+ inherit: {},
11
+ muted: { color: colors.onSurfaceVariant },
12
+ negative: { color: colors.negative },
13
+ neutral: { color: colors.onSurface },
14
+ positive: { color: colors.positive },
15
+ primary: { color: colors.primary }
16
+ }));
17
+ /**
18
+ * A run of text in one role of Material Design's type scale and one colour
19
+ * role, with web's props and values.
20
+ *
21
+ * ```tsx
22
+ * <Text accessibilityRole="header" variant="titleLarge">
23
+ * Headline
24
+ * </Text>
25
+ * ```
26
+ *
27
+ * Each role reads its family, size, line height, weight and tracking from the
28
+ * theme, so an override of the plain or brand family reaches every role drawn
29
+ * in it. The family is the token's first when the app has registered it with
30
+ * expo-font, and the system font otherwise. The OS text size scales every
31
+ * role, as `allowFontScaling` leaves it.
32
+ *
33
+ * Web's `render` and `block` have no counterpart: a native Text is a block
34
+ * unless it sits inside another, and a heading is an `accessibilityRole`
35
+ * rather than an element. `style`, `ref` and `testID` land on React Native's
36
+ * own Text.
37
+ */
38
+ function Text$1(t0) {
39
+ const $ = c(9);
40
+ let props;
41
+ let style;
42
+ let t1;
43
+ let t2;
44
+ if ($[0] !== t0) {
45
+ ({style, tone: t1, variant: t2, ...props} = t0);
46
+ $[0] = t0;
47
+ $[1] = props;
48
+ $[2] = style;
49
+ $[3] = t1;
50
+ $[4] = t2;
51
+ } else {
52
+ props = $[1];
53
+ style = $[2];
54
+ t1 = $[3];
55
+ t2 = $[4];
56
+ }
57
+ const tone = t1 === void 0 ? "neutral" : t1;
58
+ const role = useTypeRole(t2 === void 0 ? "bodyMedium" : t2);
59
+ const tones = stylesOf(useTheme());
60
+ const T0 = Text;
61
+ const t3 = composeStyles(role, tones[tone], style);
62
+ let t4;
63
+ if ($[5] !== T0 || $[6] !== props || $[7] !== t3) {
64
+ t4 = /* @__PURE__ */ jsx(T0, {
65
+ ...props,
66
+ style: t3
67
+ });
68
+ $[5] = T0;
69
+ $[6] = props;
70
+ $[7] = t3;
71
+ $[8] = t4;
72
+ } else t4 = $[8];
73
+ return t4;
74
+ }
75
+ //#endregion
76
+ export { Text$1 as Text };
77
+
78
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["ComponentRef","Ref","TextProps","NativeTextProps","Text","NativeText","StyleSheet","TypeRole","useTheme","composeStyles","themedStyles","useTypeRole","stylesOf","colors","create","error","color","inherit","muted","onSurfaceVariant","negative","neutral","onSurface","positive","primary","ref","tone","variant","t0","$","_c","props","style","t1","t2","undefined","role","tones","T0","t3","t4","Text","_c","NativeText"],"sources":["../../../src/components/text/index.tsx"],"sourcesContent":["import type { ComponentRef, Ref } from 'react'\nimport type { TextProps as NativeTextProps } from 'react-native'\n\nimport { Text as NativeText, StyleSheet } from 'react-native'\n\nimport type { TypeRole } from '../../typography/roles'\n\nimport { useTheme } from '../../theme/scope'\nimport { composeStyles, themedStyles } from '../../theme/styles'\nimport { useTypeRole } from '../../typography/roles'\n\n// Tone is a separate axis from variant so the two compose freely: any of the\n// fifteen roles in any of these colours, the same set web's Text takes.\n// `inherit` sets no colour, so a Text inside another takes the outer one's.\nconst stylesOf = themedStyles(({ colors }) =>\n StyleSheet.create({\n error: { color: colors.error },\n inherit: {},\n muted: { color: colors.onSurfaceVariant },\n negative: { color: colors.negative },\n neutral: { color: colors.onSurface },\n positive: { color: colors.positive },\n primary: { color: colors.primary },\n }),\n)\n\ntype TextProps = NativeTextProps & {\n readonly ref?: Ref<ComponentRef<typeof NativeText>>\n /**\n * The colour role to draw in. `neutral` is the on-surface role, as it is on\n * web; `inherit` takes the colour of the Text around it instead of setting\n * one.\n * @default 'neutral'\n */\n readonly tone?:\n | 'error'\n | 'inherit'\n | 'muted'\n | 'negative'\n | 'neutral'\n | 'positive'\n | 'primary'\n /**\n * Which role of the type scale to draw in.\n * @default 'bodyMedium'\n */\n readonly variant?: TypeRole\n}\n\n/**\n * A run of text in one role of Material Design's type scale and one colour\n * role, with web's props and values.\n *\n * ```tsx\n * <Text accessibilityRole=\"header\" variant=\"titleLarge\">\n * Headline\n * </Text>\n * ```\n *\n * Each role reads its family, size, line height, weight and tracking from the\n * theme, so an override of the plain or brand family reaches every role drawn\n * in it. The family is the token's first when the app has registered it with\n * expo-font, and the system font otherwise. The OS text size scales every\n * role, as `allowFontScaling` leaves it.\n *\n * Web's `render` and `block` have no counterpart: a native Text is a block\n * unless it sits inside another, and a heading is an `accessibilityRole`\n * rather than an element. `style`, `ref` and `testID` land on React Native's\n * own Text.\n */\nfunction Text({\n style,\n tone = 'neutral',\n variant = 'bodyMedium',\n ...props\n}: TextProps) {\n const role = useTypeRole(variant)\n const tones = stylesOf(useTheme())\n\n return (\n <NativeText {...props} style={composeStyles(role, tones[tone], style)} />\n )\n}\n\nexport type { TextProps }\n\nexport { Text }\n"],"mappings":";;;;;;;AAcA,MAAMY,WAAWF,cAAc,EAAEG,aAC/BP,WAAWQ,OAAO;CAChBC,OAAO,EAAEC,OAAOH,OAAOE,MAAM;CAC7BE,SAAS,CAAC;CACVC,OAAO,EAAEF,OAAOH,OAAOM,iBAAiB;CACxCC,UAAU,EAAEJ,OAAOH,OAAOO,SAAS;CACnCC,SAAS,EAAEL,OAAOH,OAAOS,UAAU;CACnCC,UAAU,EAAEP,OAAOH,OAAOU,SAAS;CACnCC,SAAS,EAAER,OAAOH,OAAOW,QAAQ;AACnC,CAAC,CACH;;;;;;;;;;;;;;;;;;;;;;AA8CA,SAAApB,OAAAwB,IAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CAAA,IAAAC;CAAA,IAAAC;CAAA,IAAAC;CAAA,IAAAC;CAAA,IAAAL,EAAA,OAAAD,IAAA;EAAc,CAAA,CAAAI,OAAAN,MAAAO,IAAAN,SAAAO,IAAA,GAAAH,SAAAH;EAKFC,EAAA,KAAAD;EAAAC,EAAA,KAAAE;EAAAF,EAAA,KAAAG;EAAAH,EAAA,KAAAI;EAAAJ,EAAA,KAAAK;CAAA,OAAA;EAAAH,QAAAF,EAAA;EAAAG,QAAAH,EAAA;EAAAI,KAAAJ,EAAA;EAAAK,KAAAL,EAAA;CAAA;CAHV,MAAAH,OAAAO,OAAAE,KAAAA,IAAA,YAAAF;CAIA,MAAAG,OAAazB,YAHbuB,OAAAC,KAAAA,IAAA,eAAAD,EAGgC;CAChC,MAAAG,QAAczB,SAASJ,SAAS,CAAC;CAG9B,MAAA8B,KAAAjC;CAA6B,MAAAkC,KAAA9B,cAAc2B,MAAMC,MAAMX,OAAOM,KAAK;CAAC,IAAAQ;CAAA,IAAAX,EAAA,OAAAS,MAAAT,EAAA,OAAAE,SAAAF,EAAA,OAAAU,IAAA;EAArEC,KAAA,oBAAC,IAAD;GAAW,GAAKT;GAAc,OAAAQ;EAAuC,CAAA;EAAIV,EAAA,KAAAS;EAAAT,EAAA,KAAAE;EAAAF,EAAA,KAAAU;EAAAV,EAAA,KAAAW;CAAA,OAAAA,KAAAX,EAAA;CAAA,OAAzEW;AAAyE"}
@@ -0,0 +1,146 @@
1
+ import { ValidationResult } from "../../form/index.js";
2
+ import { FieldVariant } from "../../field/index.js";
3
+ import { StyleProp, TextInput, TextInputProps, View, ViewStyle } from "react-native";
4
+ import { ReactNode, Ref } from "react";
5
+ //#region src/components/text-field/index.d.ts
6
+ type TextFieldProps = Omit<TextInputProps, 'accessibilityHint' | 'accessibilityLabel' | 'aria-disabled' | 'aria-label' | 'children' | 'cursorColor' | 'defaultValue' | 'editable' | 'multiline' | 'numberOfLines' | 'onChange' | 'onChangeText' | 'placeholder' | 'placeholderTextColor' | 'readOnly' | 'selectionColor' | 'style' | 'underlineColorAndroid' | 'value'> & {
7
+ /**
8
+ * Counts the characters the field holds at the end of the supporting line,
9
+ * against `maxLength` where there is one, as the text fields page's
10
+ * character counter does. The count is written in the device's digits.
11
+ * @default false
12
+ */
13
+ readonly characterCount?: boolean;
14
+ /**
15
+ * How the limit is said to a screen reader, where there is a `maxLength`.
16
+ * Read with the field rather than as the value changes, so it names the
17
+ * limit and not what is left of it; the visible count is hidden from
18
+ * screen readers, which is what this replaces. Left out, it is the English
19
+ * sentence, "Up to 20 characters", singular for a limit of one.
20
+ */
21
+ readonly characterLimitLabel?: string;
22
+ /** The value the field opens with, when it keeps its own. */
23
+ readonly defaultValue?: string;
24
+ /**
25
+ * A hint shown under the field. Replaced by `error` when there is one, so
26
+ * the two never stack.
27
+ */
28
+ readonly description?: string;
29
+ /**
30
+ * The problem with the current value, in words. Its presence is what puts
31
+ * the field in its error state: the message, the error colours, and the
32
+ * invalid state a screen reader reads all follow from it. The line under
33
+ * the field arrives with the message, so the field grows when this does,
34
+ * unless it is inside a `Form`, which keeps the line drawn. It wins over
35
+ * what `validate` and the form say, and holds a `native` form back.
36
+ */
37
+ readonly error?: string;
38
+ /**
39
+ * Whether the label sits in the empty box and floats to the top once the
40
+ * field is focused or holds a value, as the text fields page draws it.
41
+ * `false` keeps it small at the top in every state.
42
+ * @default true
43
+ */
44
+ readonly floatingLabel?: boolean;
45
+ /**
46
+ * A ref to the field's own `TextInput`, which is what a call site moves
47
+ * focus to, after a server's error, say. `ref` is the field as a whole.
48
+ */
49
+ readonly inputRef?: Ref<TextInput>;
50
+ /**
51
+ * Draws the field disabled: it takes no focus and no input.
52
+ * @default false
53
+ */
54
+ readonly isDisabled?: boolean;
55
+ /**
56
+ * Shows the value and takes focus, but takes no input.
57
+ * @default false
58
+ */
59
+ readonly isReadOnly?: boolean;
60
+ /**
61
+ * Marks the label with an asterisk, as the text fields page marks a field
62
+ * that must be filled.
63
+ * @default false
64
+ */
65
+ readonly isRequired?: boolean;
66
+ /**
67
+ * What the field is for, and the name a screen reader reads for it.
68
+ * Required, since a text field with no label is a box nobody can name.
69
+ */
70
+ readonly label: string;
71
+ /**
72
+ * An icon at the start of the box, before the label and the value: the
73
+ * page's 24dp leading icon, in the muted role. The slot hands it that
74
+ * colour and size through `useIconStyle()`.
75
+ */
76
+ readonly leadingIcon?: ReactNode;
77
+ /**
78
+ * The name the value is submitted under by the `Form` around the field,
79
+ * and the key its `validationErrors` reach the field by.
80
+ */
81
+ readonly name?: string;
82
+ /**
83
+ * Renders the value in the mono face with tabular figures, for amounts and
84
+ * other numbers meant to be compared down a column.
85
+ * @default false
86
+ */
87
+ readonly numeric?: boolean;
88
+ /** Called with the new value as it is edited. */
89
+ readonly onChange?: (value: string) => void;
90
+ /**
91
+ * Text before the value on its line, in the muted role, shown while the
92
+ * field is focused or holds a value.
93
+ */
94
+ readonly prefix?: ReactNode;
95
+ readonly ref?: Ref<View>;
96
+ /** Positions and sizes the field as a whole. */
97
+ readonly style?: StyleProp<ViewStyle>;
98
+ /**
99
+ * Text after the value on its line, in the muted role, shown while the
100
+ * field is focused or holds a value.
101
+ */
102
+ readonly suffix?: ReactNode;
103
+ /**
104
+ * An icon at the end of the box, after the value: the page's 24dp trailing
105
+ * icon, in the muted role and the error role while the field has an
106
+ * error. The slot hands it that colour and size through `useIconStyle()`.
107
+ */
108
+ readonly trailingIcon?: ReactNode;
109
+ /**
110
+ * Checks the value, and returns its problem in words, or several, where
111
+ * there is one, and `true`, `null` or `undefined` where there is none.
112
+ * Under the default `aria` validation the error shows as the value
113
+ * changes; inside a `native` form it shows once a submission is tried, or
114
+ * once the field loses focus after an edit, and holds the form back.
115
+ */
116
+ readonly validate?: (value: string) => ValidationResult;
117
+ /** The value, when the call site keeps it. */
118
+ readonly value?: string;
119
+ /**
120
+ * The filled box, or the outlined one: no fill, an outline that thickens
121
+ * and takes the primary role while focused, and the label cutting it once
122
+ * it floats, the text fields page's two fields.
123
+ * @default 'filled'
124
+ */
125
+ readonly variant?: FieldVariant;
126
+ };
127
+ /**
128
+ * A labelled single-line input, the text fields page's filled or outlined
129
+ * field. Pass `value` with `onChange` to control it, or `defaultValue` to let
130
+ * it keep its own; `onChange` is handed the string.
131
+ *
132
+ * The page's configurations are props: `leadingIcon` and `trailingIcon` at
133
+ * the box's ends, `prefix` and `suffix` on the value's line, and
134
+ * `characterCount` opposite the supporting text, counting against
135
+ * `maxLength`. React Native's own `TextInput` props, the keyboard and the
136
+ * return key among them, reach the control; `style` and `ref` are the field
137
+ * as a whole, and `inputRef` the control.
138
+ *
139
+ * ```tsx
140
+ * <TextField label="Label" description="Supporting line" />
141
+ * ```
142
+ */
143
+ declare function TextField({ characterCount, characterLimitLabel, defaultValue, description, error, floatingLabel, inputRef, isDisabled, isReadOnly, isRequired, label, leadingIcon, name, numeric, onBlur, onChange, onFocus, prefix, ref, style, suffix, trailingIcon, validate, value, variant, ...props }: TextFieldProps): import("react").JSX.Element;
144
+ //#endregion
145
+ export { TextField, type TextFieldProps };
146
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,228 @@
1
+ import { useFieldValidation } from "../../form/index.js";
2
+ import { FieldBox, FieldInput, FieldMessage, describedBy, useFieldFocus } from "../../field/index.js";
3
+ import { c } from "react/compiler-runtime";
4
+ import { View } from "react-native";
5
+ import { useId, useImperativeHandle, useRef, useState } from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/components/text-field/index.tsx
8
+ function blurThen(onBlur, then) {
9
+ return (event) => {
10
+ onBlur();
11
+ then?.(event);
12
+ };
13
+ }
14
+ function editInto(setOwn, onChange, onEdit) {
15
+ return (text) => {
16
+ setOwn(text);
17
+ onEdit();
18
+ onChange?.(text);
19
+ };
20
+ }
21
+ /**
22
+ * A labelled single-line input, the text fields page's filled or outlined
23
+ * field. Pass `value` with `onChange` to control it, or `defaultValue` to let
24
+ * it keep its own; `onChange` is handed the string.
25
+ *
26
+ * The page's configurations are props: `leadingIcon` and `trailingIcon` at
27
+ * the box's ends, `prefix` and `suffix` on the value's line, and
28
+ * `characterCount` opposite the supporting text, counting against
29
+ * `maxLength`. React Native's own `TextInput` props, the keyboard and the
30
+ * return key among them, reach the control; `style` and `ref` are the field
31
+ * as a whole, and `inputRef` the control.
32
+ *
33
+ * ```tsx
34
+ * <TextField label="Label" description="Supporting line" />
35
+ * ```
36
+ */
37
+ function TextField(t0) {
38
+ const $ = c(60);
39
+ const { characterCount: t1, characterLimitLabel, defaultValue: t2, description, error, floatingLabel: t3, inputRef, isDisabled: t4, isReadOnly: t5, isRequired: t6, label, leadingIcon, name, numeric: t7, onBlur, onChange, onFocus, prefix, ref, style, suffix, trailingIcon, validate, value, variant: t8, ...props } = t0;
40
+ const characterCount = t1 === void 0 ? false : t1;
41
+ const defaultValue = t2 === void 0 ? "" : t2;
42
+ const floatingLabel = t3 === void 0 ? true : t3;
43
+ const isDisabled = t4 === void 0 ? false : t4;
44
+ const isReadOnly = t5 === void 0 ? false : t5;
45
+ const isRequired = t6 === void 0 ? false : t6;
46
+ const numeric = t7 === void 0 ? false : t7;
47
+ const variant = t8 === void 0 ? "filled" : t8;
48
+ const id = useId();
49
+ const control = useRef(null);
50
+ const [own, setOwn] = useState(defaultValue);
51
+ const current = value ?? own;
52
+ const t9 = current === "";
53
+ let t10;
54
+ if ($[0] !== current || $[1] !== error || $[2] !== isDisabled || $[3] !== isReadOnly || $[4] !== isRequired || $[5] !== name || $[6] !== t9 || $[7] !== validate) {
55
+ t10 = {
56
+ control,
57
+ error,
58
+ isDisabled,
59
+ isEmpty: t9,
60
+ isReadOnly,
61
+ isRequired,
62
+ name,
63
+ submitted: current,
64
+ validate,
65
+ value: current
66
+ };
67
+ $[0] = current;
68
+ $[1] = error;
69
+ $[2] = isDisabled;
70
+ $[3] = isReadOnly;
71
+ $[4] = isRequired;
72
+ $[5] = name;
73
+ $[6] = t9;
74
+ $[7] = validate;
75
+ $[8] = t10;
76
+ } else t10 = $[8];
77
+ const validation = useFieldValidation(t10);
78
+ let t11;
79
+ if ($[9] !== onBlur || $[10] !== validation.onBlur) {
80
+ t11 = blurThen(validation.onBlur, onBlur);
81
+ $[9] = onBlur;
82
+ $[10] = validation.onBlur;
83
+ $[11] = t11;
84
+ } else t11 = $[11];
85
+ let t12;
86
+ if ($[12] !== onFocus || $[13] !== t11) {
87
+ t12 = {
88
+ onBlur: t11,
89
+ onFocus
90
+ };
91
+ $[12] = onFocus;
92
+ $[13] = t11;
93
+ $[14] = t12;
94
+ } else t12 = $[14];
95
+ const focus = useFieldFocus(t12);
96
+ const shownError = validation.error;
97
+ let t13;
98
+ let t14;
99
+ if ($[15] === Symbol.for("react.memo_cache_sentinel")) {
100
+ t13 = () => control.current;
101
+ t14 = [];
102
+ $[15] = t13;
103
+ $[16] = t14;
104
+ } else {
105
+ t13 = $[15];
106
+ t14 = $[16];
107
+ }
108
+ useImperativeHandle(inputRef, t13, t14);
109
+ const T0 = View;
110
+ const T1 = FieldBox;
111
+ const t15 = focus.focused;
112
+ const t16 = shownError !== void 0;
113
+ const t17 = current !== "";
114
+ const T2 = FieldInput;
115
+ const t18 = focus.handlers;
116
+ const t19 = describedBy(id, {
117
+ characterLimitLabel,
118
+ description,
119
+ error: shownError,
120
+ maxLength: props.maxLength
121
+ });
122
+ const t20 = !isDisabled && !isReadOnly;
123
+ let t21;
124
+ if ($[17] !== onChange || $[18] !== setOwn || $[19] !== validation.onEdit) {
125
+ t21 = editInto(setOwn, onChange, validation.onEdit);
126
+ $[17] = onChange;
127
+ $[18] = setOwn;
128
+ $[19] = validation.onEdit;
129
+ $[20] = t21;
130
+ } else t21 = $[20];
131
+ let t22;
132
+ if ($[21] !== T2 || $[22] !== current || $[23] !== focus.handlers || $[24] !== label || $[25] !== numeric || $[26] !== prefix || $[27] !== props || $[28] !== suffix || $[29] !== t19 || $[30] !== t20 || $[31] !== t21) {
133
+ t22 = /* @__PURE__ */ jsx(T2, {
134
+ ...props,
135
+ ...t18,
136
+ "aria-label": label,
137
+ described: t19,
138
+ editable: t20,
139
+ numeric,
140
+ onChangeText: t21,
141
+ prefix,
142
+ ref: control,
143
+ suffix,
144
+ value: current
145
+ });
146
+ $[21] = T2;
147
+ $[22] = current;
148
+ $[23] = focus.handlers;
149
+ $[24] = label;
150
+ $[25] = numeric;
151
+ $[26] = prefix;
152
+ $[27] = props;
153
+ $[28] = suffix;
154
+ $[29] = t19;
155
+ $[30] = t20;
156
+ $[31] = t21;
157
+ $[32] = t22;
158
+ } else t22 = $[32];
159
+ let t23;
160
+ if ($[33] !== T1 || $[34] !== floatingLabel || $[35] !== focus.focused || $[36] !== isDisabled || $[37] !== isRequired || $[38] !== label || $[39] !== leadingIcon || $[40] !== t16 || $[41] !== t17 || $[42] !== t22 || $[43] !== trailingIcon || $[44] !== variant) {
161
+ t23 = /* @__PURE__ */ jsx(T1, {
162
+ control,
163
+ floatingLabel,
164
+ isDisabled,
165
+ isFocused: t15,
166
+ isInvalid: t16,
167
+ isPopulated: t17,
168
+ isRequired,
169
+ label,
170
+ leading: leadingIcon,
171
+ trailing: trailingIcon,
172
+ variant,
173
+ children: t22
174
+ });
175
+ $[33] = T1;
176
+ $[34] = floatingLabel;
177
+ $[35] = focus.focused;
178
+ $[36] = isDisabled;
179
+ $[37] = isRequired;
180
+ $[38] = label;
181
+ $[39] = leadingIcon;
182
+ $[40] = t16;
183
+ $[41] = t17;
184
+ $[42] = t22;
185
+ $[43] = trailingIcon;
186
+ $[44] = variant;
187
+ $[45] = t23;
188
+ } else t23 = $[45];
189
+ let t24;
190
+ if ($[46] !== characterCount || $[47] !== characterLimitLabel || $[48] !== current.length || $[49] !== description || $[50] !== id || $[51] !== props.maxLength || $[52] !== shownError) {
191
+ t24 = /* @__PURE__ */ jsx(FieldMessage, {
192
+ characterCount,
193
+ characterLimitLabel,
194
+ description,
195
+ error: shownError,
196
+ id,
197
+ length: current.length,
198
+ maxLength: props.maxLength
199
+ });
200
+ $[46] = characterCount;
201
+ $[47] = characterLimitLabel;
202
+ $[48] = current.length;
203
+ $[49] = description;
204
+ $[50] = id;
205
+ $[51] = props.maxLength;
206
+ $[52] = shownError;
207
+ $[53] = t24;
208
+ } else t24 = $[53];
209
+ let t25;
210
+ if ($[54] !== T0 || $[55] !== ref || $[56] !== style || $[57] !== t23 || $[58] !== t24) {
211
+ t25 = /* @__PURE__ */ jsxs(T0, {
212
+ ref,
213
+ style,
214
+ children: [t23, t24]
215
+ });
216
+ $[54] = T0;
217
+ $[55] = ref;
218
+ $[56] = style;
219
+ $[57] = t23;
220
+ $[58] = t24;
221
+ $[59] = t25;
222
+ } else t25 = $[59];
223
+ return t25;
224
+ }
225
+ //#endregion
226
+ export { TextField };
227
+
228
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["ReactNode","Ref","StyleProp","TextInput","TextInputProps","ViewStyle","useId","useImperativeHandle","useRef","useState","View","FieldVariant","ValidationResult","describedBy","FieldBox","FieldInput","FieldMessage","useFieldFocus","useFieldValidation","TextFieldProps","Omit","characterCount","characterLimitLabel","defaultValue","description","error","floatingLabel","inputRef","isDisabled","isReadOnly","isRequired","label","leadingIcon","name","numeric","onChange","value","prefix","ref","style","suffix","trailingIcon","validate","variant","blurThen","onBlur","then","event","editInto","setOwn","onEdit","text","TextField","t0","$","_c","t1","t2","t3","t4","t5","t6","t7","onFocus","t8","props","undefined","id","control","own","current","t9","t10","isEmpty","submitted","validation","t11","t12","focus","shownError","t13","t14","Symbol","for","T0","T1","t15","focused","t16","t17","T2","t18","handlers","t19","maxLength","t20","t21","t22","t23","t24","length","t25","_c"],"sources":["../../../src/components/text-field/index.tsx"],"sourcesContent":["import type { ReactNode, Ref } from 'react'\nimport type {\n StyleProp,\n TextInput,\n TextInputProps,\n ViewStyle,\n} from 'react-native'\n\nimport { useId, useImperativeHandle, useRef, useState } from 'react'\nimport { View } from 'react-native'\n\nimport type { FieldVariant } from '../../field'\nimport type { ValidationResult } from '../../form'\n\nimport {\n describedBy,\n FieldBox,\n FieldInput,\n FieldMessage,\n useFieldFocus,\n} from '../../field'\nimport { useFieldValidation } from '../../form'\n\n// kanso-ui's TextField, drawn through the field chrome in src/field: the box\n// with its label and icons, the control on the value's line with its prefix\n// and suffix, and the supporting line under it with the count. What the\n// chrome draws, and how it draws it, is written there.\n//\n// The value is the field's own or the call site's. Given `value` it shows\n// that and reports edits through `onChange`; given `defaultValue`, or\n// nothing, it keeps what is typed itself. `onChange` is handed the string, as\n// web's is, rather than React Native's event.\n//\n// **Web's `isInvalid` is not a prop here either.** The error is what puts the\n// field in its error state, the message and the colours and the invalid\n// state a screen reader reads following from it, so a field cannot be\n// invalid with nothing to say why. The error shown is `error`, or what the\n// field's `validate` and the `Form` around it say, which src/form decides.\n\ntype TextFieldProps = Omit<\n TextInputProps,\n | 'accessibilityHint'\n | 'accessibilityLabel'\n | 'aria-disabled'\n | 'aria-label'\n | 'children'\n | 'cursorColor'\n | 'defaultValue'\n | 'editable'\n | 'multiline'\n | 'numberOfLines'\n | 'onChange'\n | 'onChangeText'\n | 'placeholder'\n | 'placeholderTextColor'\n | 'readOnly'\n | 'selectionColor'\n | 'style'\n | 'underlineColorAndroid'\n | 'value'\n> & {\n /**\n * Counts the characters the field holds at the end of the supporting line,\n * against `maxLength` where there is one, as the text fields page's\n * character counter does. The count is written in the device's digits.\n * @default false\n */\n readonly characterCount?: boolean\n /**\n * How the limit is said to a screen reader, where there is a `maxLength`.\n * Read with the field rather than as the value changes, so it names the\n * limit and not what is left of it; the visible count is hidden from\n * screen readers, which is what this replaces. Left out, it is the English\n * sentence, \"Up to 20 characters\", singular for a limit of one.\n */\n readonly characterLimitLabel?: string\n /** The value the field opens with, when it keeps its own. */\n readonly defaultValue?: string\n /**\n * A hint shown under the field. Replaced by `error` when there is one, so\n * the two never stack.\n */\n readonly description?: string\n /**\n * The problem with the current value, in words. Its presence is what puts\n * the field in its error state: the message, the error colours, and the\n * invalid state a screen reader reads all follow from it. The line under\n * the field arrives with the message, so the field grows when this does,\n * unless it is inside a `Form`, which keeps the line drawn. It wins over\n * what `validate` and the form say, and holds a `native` form back.\n */\n readonly error?: string\n /**\n * Whether the label sits in the empty box and floats to the top once the\n * field is focused or holds a value, as the text fields page draws it.\n * `false` keeps it small at the top in every state.\n * @default true\n */\n readonly floatingLabel?: boolean\n /**\n * A ref to the field's own `TextInput`, which is what a call site moves\n * focus to, after a server's error, say. `ref` is the field as a whole.\n */\n readonly inputRef?: Ref<TextInput>\n /**\n * Draws the field disabled: it takes no focus and no input.\n * @default false\n */\n readonly isDisabled?: boolean\n /**\n * Shows the value and takes focus, but takes no input.\n * @default false\n */\n readonly isReadOnly?: boolean\n /**\n * Marks the label with an asterisk, as the text fields page marks a field\n * that must be filled.\n * @default false\n */\n readonly isRequired?: boolean\n /**\n * What the field is for, and the name a screen reader reads for it.\n * Required, since a text field with no label is a box nobody can name.\n */\n readonly label: string\n /**\n * An icon at the start of the box, before the label and the value: the\n * page's 24dp leading icon, in the muted role. The slot hands it that\n * colour and size through `useIconStyle()`.\n */\n readonly leadingIcon?: ReactNode\n /**\n * The name the value is submitted under by the `Form` around the field,\n * and the key its `validationErrors` reach the field by.\n */\n readonly name?: string\n /**\n * Renders the value in the mono face with tabular figures, for amounts and\n * other numbers meant to be compared down a column.\n * @default false\n */\n readonly numeric?: boolean\n /** Called with the new value as it is edited. */\n readonly onChange?: (value: string) => void\n /**\n * Text before the value on its line, in the muted role, shown while the\n * field is focused or holds a value.\n */\n readonly prefix?: ReactNode\n readonly ref?: Ref<View>\n /** Positions and sizes the field as a whole. */\n readonly style?: StyleProp<ViewStyle>\n /**\n * Text after the value on its line, in the muted role, shown while the\n * field is focused or holds a value.\n */\n readonly suffix?: ReactNode\n /**\n * An icon at the end of the box, after the value: the page's 24dp trailing\n * icon, in the muted role and the error role while the field has an\n * error. The slot hands it that colour and size through `useIconStyle()`.\n */\n readonly trailingIcon?: ReactNode\n /**\n * Checks the value, and returns its problem in words, or several, where\n * there is one, and `true`, `null` or `undefined` where there is none.\n * Under the default `aria` validation the error shows as the value\n * changes; inside a `native` form it shows once a submission is tried, or\n * once the field loses focus after an edit, and holds the form back.\n */\n readonly validate?: (value: string) => ValidationResult\n /** The value, when the call site keeps it. */\n readonly value?: string\n /**\n * The filled box, or the outlined one: no fill, an outline that thickens\n * and takes the primary role while focused, and the label cutting it once\n * it floats, the text fields page's two fields.\n * @default 'filled'\n */\n readonly variant?: FieldVariant\n}\n\n// The field's own blur handling, then the call site's.\nfunction blurThen(\n onBlur: () => void,\n then: TextInputProps['onBlur'],\n): TextInputProps['onBlur'] {\n return (event) => {\n onBlur()\n then?.(event)\n }\n}\n\n// Keeps an edit as the field's own value and reports it, so a field the call\n// site controls is told and one it does not still shows what was typed, and\n// tells the field's validation it was edited.\nfunction editInto(\n setOwn: (value: string) => void,\n onChange: ((value: string) => void) | undefined,\n onEdit: () => void,\n) {\n return (text: string) => {\n setOwn(text)\n onEdit()\n onChange?.(text)\n }\n}\n\n/**\n * A labelled single-line input, the text fields page's filled or outlined\n * field. Pass `value` with `onChange` to control it, or `defaultValue` to let\n * it keep its own; `onChange` is handed the string.\n *\n * The page's configurations are props: `leadingIcon` and `trailingIcon` at\n * the box's ends, `prefix` and `suffix` on the value's line, and\n * `characterCount` opposite the supporting text, counting against\n * `maxLength`. React Native's own `TextInput` props, the keyboard and the\n * return key among them, reach the control; `style` and `ref` are the field\n * as a whole, and `inputRef` the control.\n *\n * ```tsx\n * <TextField label=\"Label\" description=\"Supporting line\" />\n * ```\n */\nfunction TextField({\n characterCount = false,\n characterLimitLabel,\n defaultValue = '',\n description,\n error,\n floatingLabel = true,\n inputRef,\n isDisabled = false,\n isReadOnly = false,\n isRequired = false,\n label,\n leadingIcon,\n name,\n numeric = false,\n onBlur,\n onChange,\n onFocus,\n prefix,\n ref,\n style,\n suffix,\n trailingIcon,\n validate,\n value,\n variant = 'filled',\n ...props\n}: TextFieldProps) {\n const id = useId()\n const control = useRef<TextInput>(null)\n const [own, setOwn] = useState(defaultValue)\n const current = value ?? own\n const validation = useFieldValidation({\n control,\n error,\n isDisabled,\n isEmpty: current === '',\n isReadOnly,\n isRequired,\n name,\n submitted: current,\n validate,\n value: current,\n })\n const focus = useFieldFocus({\n onBlur: blurThen(validation.onBlur, onBlur),\n onFocus,\n })\n const shownError = validation.error\n\n useImperativeHandle<null | TextInput, null | TextInput>(\n inputRef,\n () => control.current,\n [],\n )\n\n return (\n <View ref={ref} style={style}>\n <FieldBox\n control={control}\n floatingLabel={floatingLabel}\n isDisabled={isDisabled}\n isFocused={focus.focused}\n isInvalid={shownError !== undefined}\n isPopulated={current !== ''}\n isRequired={isRequired}\n label={label}\n leading={leadingIcon}\n trailing={trailingIcon}\n variant={variant}\n >\n <FieldInput\n {...props}\n {...focus.handlers}\n aria-label={label}\n described={describedBy(id, {\n characterLimitLabel,\n description,\n error: shownError,\n maxLength: props.maxLength,\n })}\n editable={!isDisabled && !isReadOnly}\n numeric={numeric}\n onChangeText={editInto(setOwn, onChange, validation.onEdit)}\n prefix={prefix}\n ref={control}\n suffix={suffix}\n value={current}\n />\n </FieldBox>\n <FieldMessage\n characterCount={characterCount}\n characterLimitLabel={characterLimitLabel}\n description={description}\n error={shownError}\n id={id}\n length={current.length}\n maxLength={props.maxLength}\n />\n </View>\n )\n}\n\nexport { TextField }\nexport type { TextFieldProps }\n"],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ import { useTheme } from "../theme/scope.js";
2
+ import { composeStyles } from "../theme/styles.js";
3
+ import { useTypeRole } from "../typography/roles.js";
4
+ import { controlStylesOf } from "./styles.js";
5
+ import { c } from "react/compiler-runtime";
6
+ import { Platform, Text, View } from "react-native";
7
+ import { jsx } from "react/jsx-runtime";
8
+ //#region src/control/index.tsx
9
+ const HIDDEN = {
10
+ accessibilityElementsHidden: true,
11
+ importantForAccessibility: "no-hide-descendants"
12
+ };
13
+ /**
14
+ * The label beside a selection control, set in body large. Renders nothing
15
+ * without children, which is what a control labelled some other way, by
16
+ * `aria-label` or a group's label, needs.
17
+ */
18
+ function ControlLabel(t0) {
19
+ const $ = c(4);
20
+ const { children, isDisabled: t1 } = t0;
21
+ const isDisabled = t1 === void 0 ? false : t1;
22
+ const theme = useTheme();
23
+ const own = controlStylesOf(theme);
24
+ const role = useTypeRole("bodyLarge");
25
+ if (children === void 0) return null;
26
+ const T0 = Text;
27
+ const t2 = composeStyles(role, own.label, isDisabled ? own.labelDisabled : void 0);
28
+ let t3;
29
+ if ($[0] !== T0 || $[1] !== children || $[2] !== t2) {
30
+ t3 = /* @__PURE__ */ jsx(T0, {
31
+ style: t2,
32
+ children
33
+ });
34
+ $[0] = T0;
35
+ $[1] = children;
36
+ $[2] = t2;
37
+ $[3] = t3;
38
+ } else t3 = $[3];
39
+ return t3;
40
+ }
41
+ /**
42
+ * The line under a selection control's label: the error while there is one,
43
+ * otherwise the description, so the two never stack. Renders nothing when
44
+ * there is neither. Hand the control `describedBy(id, message)` with the same
45
+ * `id`, so a screen reader reads the line with the control.
46
+ */
47
+ function ControlMessage(t0) {
48
+ const $ = c(13);
49
+ const { description, error, id, style } = t0;
50
+ const theme = useTheme();
51
+ const own = controlStylesOf(theme);
52
+ const role = useTypeRole("bodySmall");
53
+ let t1;
54
+ if ($[0] !== description || $[1] !== error) {
55
+ t1 = messageOf(description, error);
56
+ $[0] = description;
57
+ $[1] = error;
58
+ $[2] = t1;
59
+ } else t1 = $[2];
60
+ const message = t1;
61
+ if (message === void 0) return null;
62
+ const T0 = View;
63
+ const t2 = Platform.OS === "web" ? void 0 : HIDDEN;
64
+ const t3 = composeStyles(own.messages, style);
65
+ const T1 = Text;
66
+ const t4 = composeStyles(role, own.message, error === void 0 ? void 0 : own.messageError);
67
+ let t5;
68
+ if ($[3] !== T1 || $[4] !== id || $[5] !== message || $[6] !== t4) {
69
+ t5 = /* @__PURE__ */ jsx(T1, {
70
+ id,
71
+ style: t4,
72
+ children: message
73
+ });
74
+ $[3] = T1;
75
+ $[4] = id;
76
+ $[5] = message;
77
+ $[6] = t4;
78
+ $[7] = t5;
79
+ } else t5 = $[7];
80
+ let t6;
81
+ if ($[8] !== T0 || $[9] !== t2 || $[10] !== t3 || $[11] !== t5) {
82
+ t6 = /* @__PURE__ */ jsx(T0, {
83
+ ...t2,
84
+ style: t3,
85
+ children: t5
86
+ });
87
+ $[8] = T0;
88
+ $[9] = t2;
89
+ $[10] = t3;
90
+ $[11] = t5;
91
+ $[12] = t6;
92
+ } else t6 = $[12];
93
+ return t6;
94
+ }
95
+ /**
96
+ * How a control is described by the line under it, to spread onto the
97
+ * control. On iOS and Android the message is the control's accessibility
98
+ * hint, which VoiceOver and TalkBack read after its name and state, and
99
+ * `ControlMessage` hides the line itself from them so it is not read twice.
100
+ * React Native Web drops the hint, so there the control points at the line
101
+ * with `aria-describedby`, as web's controls do.
102
+ */
103
+ function describedBy(id, message) {
104
+ return Platform.OS === "web" ? { "aria-describedby": message === void 0 ? void 0 : id } : { accessibilityHint: message };
105
+ }
106
+ /**
107
+ * What the line under a control says: the error while there is one,
108
+ * otherwise the description, and nothing for an empty string.
109
+ */
110
+ function messageOf(description, error) {
111
+ const message = error ?? description;
112
+ return message === "" ? void 0 : message;
113
+ }
114
+ //#endregion
115
+ export { ControlLabel, ControlMessage, describedBy, messageOf };
116
+
117
+ //# sourceMappingURL=index.js.map