@webority-technologies/mobile-ui 0.0.1 → 0.0.3

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 (134) hide show
  1. package/README.md +2 -1
  2. package/lib/commonjs/components/AuthedImage/AuthedImage.js +225 -0
  3. package/lib/commonjs/components/AuthedImage/authedImageCache.js +253 -0
  4. package/lib/commonjs/components/AuthedImage/index.js +45 -0
  5. package/lib/commonjs/components/BottomSheet/BottomSheet.js +10 -4
  6. package/lib/commonjs/components/Drawer/Drawer.js +6 -3
  7. package/lib/commonjs/components/ErrorBoundary/ErrorBoundary.js +136 -0
  8. package/lib/commonjs/components/ErrorBoundary/index.js +27 -0
  9. package/lib/commonjs/components/ErrorBoundary/useErrorHandler.js +24 -0
  10. package/lib/commonjs/components/ErrorBoundary/withErrorBoundary.js +28 -0
  11. package/lib/commonjs/components/FilePicker/FilePicker.js +1 -1
  12. package/lib/commonjs/components/FloatingActionButton/FloatingActionButton.js +14 -1
  13. package/lib/commonjs/components/ImageGallery/ImageGallery.js +13 -0
  14. package/lib/commonjs/components/InlineSelect/InlineSelect.js +1 -1
  15. package/lib/commonjs/components/Input/Input.js +6 -0
  16. package/lib/commonjs/components/KeyboardAwareScrollView/KeyboardAwareScrollView.js +62 -13
  17. package/lib/commonjs/components/LoaderOverlay/LoaderOverlay.js +203 -0
  18. package/lib/commonjs/components/LoaderOverlay/index.js +25 -0
  19. package/lib/commonjs/components/Markdown/Markdown.js +274 -0
  20. package/lib/commonjs/components/Markdown/index.js +13 -0
  21. package/lib/commonjs/components/Markdown/parse.js +229 -0
  22. package/lib/commonjs/components/OTPInput/OTPInput.js +5 -0
  23. package/lib/commonjs/components/OptionSheet/OptionSheet.js +3 -3
  24. package/lib/commonjs/components/PhoneNumberInput/PhoneNumberInput.js +1 -1
  25. package/lib/commonjs/components/Radio/Radio.js +9 -0
  26. package/lib/commonjs/components/Rating/Rating.js +5 -0
  27. package/lib/commonjs/components/RichTextEditor/RichTextEditor.js +311 -0
  28. package/lib/commonjs/components/RichTextEditor/index.js +20 -0
  29. package/lib/commonjs/components/RichTextEditor/markdownActions.js +213 -0
  30. package/lib/commonjs/components/SearchBar/SearchBar.js +7 -0
  31. package/lib/commonjs/components/Select/Select.js +1 -1
  32. package/lib/commonjs/components/Skeleton/Skeleton.js +17 -36
  33. package/lib/commonjs/components/Slider/Slider.js +21 -5
  34. package/lib/commonjs/components/Swipeable/Swipeable.js +5 -2
  35. package/lib/commonjs/components/TimePicker/TimePicker.js +11 -0
  36. package/lib/commonjs/components/index.js +230 -141
  37. package/lib/commonjs/form/FormContext.js +13 -1
  38. package/lib/commonjs/form/useField.js +13 -1
  39. package/lib/commonjs/theme/Gradient.js +44 -41
  40. package/lib/commonjs/theme/index.js +24 -2
  41. package/lib/commonjs/utils/hapticUtils.js +38 -18
  42. package/lib/module/components/AuthedImage/AuthedImage.js +221 -0
  43. package/lib/module/components/AuthedImage/authedImageCache.js +239 -0
  44. package/lib/module/components/AuthedImage/index.js +5 -0
  45. package/lib/module/components/BottomSheet/BottomSheet.js +10 -4
  46. package/lib/module/components/Drawer/Drawer.js +6 -3
  47. package/lib/module/components/ErrorBoundary/ErrorBoundary.js +130 -0
  48. package/lib/module/components/ErrorBoundary/index.js +6 -0
  49. package/lib/module/components/ErrorBoundary/useErrorHandler.js +20 -0
  50. package/lib/module/components/ErrorBoundary/withErrorBoundary.js +23 -0
  51. package/lib/module/components/FilePicker/FilePicker.js +1 -1
  52. package/lib/module/components/FloatingActionButton/FloatingActionButton.js +14 -1
  53. package/lib/module/components/ImageGallery/ImageGallery.js +13 -0
  54. package/lib/module/components/InlineSelect/InlineSelect.js +1 -1
  55. package/lib/module/components/Input/Input.js +6 -0
  56. package/lib/module/components/KeyboardAwareScrollView/KeyboardAwareScrollView.js +63 -14
  57. package/lib/module/components/LoaderOverlay/LoaderOverlay.js +196 -0
  58. package/lib/module/components/LoaderOverlay/index.js +4 -0
  59. package/lib/module/components/Markdown/Markdown.js +268 -0
  60. package/lib/module/components/Markdown/index.js +4 -0
  61. package/lib/module/components/Markdown/parse.js +223 -0
  62. package/lib/module/components/OTPInput/OTPInput.js +5 -0
  63. package/lib/module/components/OptionSheet/OptionSheet.js +3 -3
  64. package/lib/module/components/PhoneNumberInput/PhoneNumberInput.js +1 -1
  65. package/lib/module/components/Radio/Radio.js +9 -0
  66. package/lib/module/components/Rating/Rating.js +5 -0
  67. package/lib/module/components/RichTextEditor/RichTextEditor.js +306 -0
  68. package/lib/module/components/RichTextEditor/index.js +5 -0
  69. package/lib/module/components/RichTextEditor/markdownActions.js +207 -0
  70. package/lib/module/components/SearchBar/SearchBar.js +7 -0
  71. package/lib/module/components/Select/Select.js +1 -1
  72. package/lib/module/components/Skeleton/Skeleton.js +17 -36
  73. package/lib/module/components/Slider/Slider.js +21 -5
  74. package/lib/module/components/Swipeable/Swipeable.js +5 -2
  75. package/lib/module/components/TimePicker/TimePicker.js +11 -0
  76. package/lib/module/components/index.js +5 -0
  77. package/lib/module/form/FormContext.js +13 -1
  78. package/lib/module/form/useField.js +13 -1
  79. package/lib/module/theme/Gradient.js +41 -38
  80. package/lib/module/theme/index.js +17 -1
  81. package/lib/module/utils/hapticUtils.js +37 -18
  82. package/lib/typescript/commonjs/components/AuthedImage/AuthedImage.d.ts +22 -0
  83. package/lib/typescript/commonjs/components/AuthedImage/authedImageCache.d.ts +48 -0
  84. package/lib/typescript/commonjs/components/AuthedImage/index.d.ts +5 -0
  85. package/lib/typescript/commonjs/components/Button/Button.d.ts +1 -3
  86. package/lib/typescript/commonjs/components/Card/Card.d.ts +1 -2
  87. package/lib/typescript/commonjs/components/ErrorBoundary/ErrorBoundary.d.ts +38 -0
  88. package/lib/typescript/commonjs/components/ErrorBoundary/index.d.ts +5 -0
  89. package/lib/typescript/commonjs/components/ErrorBoundary/useErrorHandler.d.ts +9 -0
  90. package/lib/typescript/commonjs/components/ErrorBoundary/withErrorBoundary.d.ts +9 -0
  91. package/lib/typescript/commonjs/components/KeyboardAwareScrollView/KeyboardAwareScrollView.d.ts +15 -0
  92. package/lib/typescript/commonjs/components/LoaderOverlay/LoaderOverlay.d.ts +25 -0
  93. package/lib/typescript/commonjs/components/LoaderOverlay/index.d.ts +3 -0
  94. package/lib/typescript/commonjs/components/Markdown/Markdown.d.ts +29 -0
  95. package/lib/typescript/commonjs/components/Markdown/index.d.ts +3 -0
  96. package/lib/typescript/commonjs/components/Markdown/parse.d.ts +58 -0
  97. package/lib/typescript/commonjs/components/OptionSheet/OptionSheet.d.ts +8 -1
  98. package/lib/typescript/commonjs/components/RichTextEditor/RichTextEditor.d.ts +48 -0
  99. package/lib/typescript/commonjs/components/RichTextEditor/index.d.ts +5 -0
  100. package/lib/typescript/commonjs/components/RichTextEditor/markdownActions.d.ts +35 -0
  101. package/lib/typescript/commonjs/components/Skeleton/Skeleton.d.ts +1 -1
  102. package/lib/typescript/commonjs/components/index.d.ts +10 -0
  103. package/lib/typescript/commonjs/form/FormContext.d.ts +13 -3
  104. package/lib/typescript/commonjs/theme/Gradient.d.ts +18 -3
  105. package/lib/typescript/commonjs/theme/index.d.ts +16 -1
  106. package/lib/typescript/commonjs/theme/types.d.ts +2 -2
  107. package/lib/typescript/commonjs/utils/hapticUtils.d.ts +4 -0
  108. package/lib/typescript/module/components/AuthedImage/AuthedImage.d.ts +22 -0
  109. package/lib/typescript/module/components/AuthedImage/authedImageCache.d.ts +48 -0
  110. package/lib/typescript/module/components/AuthedImage/index.d.ts +5 -0
  111. package/lib/typescript/module/components/Button/Button.d.ts +1 -3
  112. package/lib/typescript/module/components/Card/Card.d.ts +1 -2
  113. package/lib/typescript/module/components/ErrorBoundary/ErrorBoundary.d.ts +38 -0
  114. package/lib/typescript/module/components/ErrorBoundary/index.d.ts +5 -0
  115. package/lib/typescript/module/components/ErrorBoundary/useErrorHandler.d.ts +9 -0
  116. package/lib/typescript/module/components/ErrorBoundary/withErrorBoundary.d.ts +9 -0
  117. package/lib/typescript/module/components/KeyboardAwareScrollView/KeyboardAwareScrollView.d.ts +15 -0
  118. package/lib/typescript/module/components/LoaderOverlay/LoaderOverlay.d.ts +25 -0
  119. package/lib/typescript/module/components/LoaderOverlay/index.d.ts +3 -0
  120. package/lib/typescript/module/components/Markdown/Markdown.d.ts +29 -0
  121. package/lib/typescript/module/components/Markdown/index.d.ts +3 -0
  122. package/lib/typescript/module/components/Markdown/parse.d.ts +58 -0
  123. package/lib/typescript/module/components/OptionSheet/OptionSheet.d.ts +8 -1
  124. package/lib/typescript/module/components/RichTextEditor/RichTextEditor.d.ts +48 -0
  125. package/lib/typescript/module/components/RichTextEditor/index.d.ts +5 -0
  126. package/lib/typescript/module/components/RichTextEditor/markdownActions.d.ts +35 -0
  127. package/lib/typescript/module/components/Skeleton/Skeleton.d.ts +1 -1
  128. package/lib/typescript/module/components/index.d.ts +10 -0
  129. package/lib/typescript/module/form/FormContext.d.ts +13 -3
  130. package/lib/typescript/module/theme/Gradient.d.ts +18 -3
  131. package/lib/typescript/module/theme/index.d.ts +16 -1
  132. package/lib/typescript/module/theme/types.d.ts +2 -2
  133. package/lib/typescript/module/utils/hapticUtils.d.ts +4 -0
  134. package/package.json +20 -13
@@ -0,0 +1,311 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.RichTextEditor = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _index = require("../../theme/index.js");
10
+ var _index2 = require("../../utils/index.js");
11
+ var _index3 = require("../Skeleton/index.js");
12
+ var _markdownActions = require("./markdownActions.js");
13
+ var _jsxRuntime = require("react/jsx-runtime");
14
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
15
+ /** Glyph + spoken name per action. The glyph IS the markdown marker wherever one reads as itself. */
16
+ const ACTION_META = {
17
+ bold: {
18
+ glyph: 'B',
19
+ label: 'Bold'
20
+ },
21
+ italic: {
22
+ glyph: 'I',
23
+ label: 'Italic'
24
+ },
25
+ strikethrough: {
26
+ glyph: 'S',
27
+ label: 'Strikethrough'
28
+ },
29
+ code: {
30
+ glyph: '</>',
31
+ label: 'Inline code'
32
+ },
33
+ link: {
34
+ glyph: 'link',
35
+ label: 'Link'
36
+ },
37
+ heading1: {
38
+ glyph: 'H1',
39
+ label: 'Heading 1'
40
+ },
41
+ heading2: {
42
+ glyph: 'H2',
43
+ label: 'Heading 2'
44
+ },
45
+ bulletList: {
46
+ glyph: '•',
47
+ label: 'Bulleted list'
48
+ },
49
+ numberedList: {
50
+ glyph: '1.',
51
+ label: 'Numbered list'
52
+ },
53
+ quote: {
54
+ glyph: '>',
55
+ label: 'Quote'
56
+ }
57
+ };
58
+ const DEFAULT_ACTIONS = ['bold', 'italic', 'strikethrough', 'code', 'link', 'heading1', 'heading2', 'bulletList', 'numberedList', 'quote'];
59
+ const DEFAULT_MIN_HEIGHT = 160;
60
+
61
+ /**
62
+ * A markdown editor: a themed multiline field plus a toolbar that wraps the
63
+ * current selection in the markers our own `<Markdown>` renderer reads back.
64
+ *
65
+ * Deliberately NOT a WYSIWYG surface. Rich-text-on-RN means a WebView, which is
66
+ * exactly what replacing the stale `react-native-pell-rich-editor` was meant to
67
+ * escape: markdown in, markdown out, one plain TextInput, no bridge.
68
+ */
69
+ const RichTextEditor = exports.RichTextEditor = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
70
+ const {
71
+ value,
72
+ onChangeText,
73
+ placeholder,
74
+ actions = DEFAULT_ACTIONS,
75
+ disabled = false,
76
+ loading = false,
77
+ minHeight = DEFAULT_MIN_HEIGHT,
78
+ autoFocus = false,
79
+ accessibilityLabel,
80
+ haptic,
81
+ style,
82
+ toolbarStyle,
83
+ inputStyle,
84
+ testID
85
+ } = props;
86
+ const theme = (0, _index.useTheme)();
87
+ const styles = (0, _react.useMemo)(() => buildStyles(theme), [theme]);
88
+ const text = value ?? '';
89
+ const [selection, setSelection] = (0, _react.useState)({
90
+ start: 0,
91
+ end: 0
92
+ });
93
+ const [focused, setFocused] = (0, _react.useState)(false);
94
+ /**
95
+ * Only set for the render immediately after a toolbar action. Holding the
96
+ * TextInput's `selection` permanently fights the platform keyboard on
97
+ * Android, so it is released as soon as the field reports the caret moved.
98
+ */
99
+ const [forcedSelection, setForcedSelection] = (0, _react.useState)(null);
100
+ const handleSelectionChange = (0, _react.useCallback)(event => {
101
+ setSelection(event.nativeEvent.selection);
102
+ setForcedSelection(null);
103
+ }, []);
104
+ const handleChangeText = (0, _react.useCallback)(next => {
105
+ setForcedSelection(null);
106
+ onChangeText?.(next);
107
+ }, [onChangeText]);
108
+ const runAction = (0, _react.useCallback)(action => {
109
+ if (disabled) {
110
+ return;
111
+ }
112
+ const h = (0, _index2.resolveHaptic)(haptic, 'selection');
113
+ if (h) {
114
+ (0, _index2.triggerHaptic)(h);
115
+ }
116
+ const result = (0, _markdownActions.applyMarkdownAction)({
117
+ text,
118
+ selection: (0, _markdownActions.normalizeSelection)(selection, text.length)
119
+ }, action);
120
+ setSelection(result.selection);
121
+ setForcedSelection(result.selection);
122
+ onChangeText?.(result.text);
123
+ }, [disabled, haptic, onChangeText, selection, text]);
124
+ if (loading) {
125
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(RichTextEditorSkeleton, {
126
+ actionCount: actions.length,
127
+ minHeight: minHeight,
128
+ style: style,
129
+ testID: testID
130
+ });
131
+ }
132
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
133
+ testID: testID,
134
+ style: [styles.container, {
135
+ borderColor: focused ? theme.colors.border.focus : theme.colors.border.primary,
136
+ opacity: disabled ? 0.55 : 1
137
+ }, style],
138
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
139
+ style: [styles.toolbar, toolbarStyle],
140
+ children: actions.map(action => /*#__PURE__*/(0, _jsxRuntime.jsx)(ToolbarButton, {
141
+ action: action,
142
+ disabled: disabled,
143
+ onPress: runAction,
144
+ styles: styles,
145
+ theme: theme,
146
+ testID: testID ? `${testID}-${action}` : undefined
147
+ }, action))
148
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
149
+ ref: ref,
150
+ value: text,
151
+ onChangeText: handleChangeText,
152
+ onSelectionChange: handleSelectionChange,
153
+ onFocus: () => setFocused(true),
154
+ onBlur: () => setFocused(false),
155
+ selection: forcedSelection ?? undefined,
156
+ editable: !disabled,
157
+ autoFocus: autoFocus,
158
+ multiline: true,
159
+ textAlignVertical: "top",
160
+ placeholder: placeholder,
161
+ placeholderTextColor: theme.colors.text.tertiary,
162
+ accessibilityLabel: accessibilityLabel,
163
+ style: [styles.input, {
164
+ minHeight
165
+ }, inputStyle],
166
+ testID: testID ? `${testID}-input` : undefined
167
+ })]
168
+ });
169
+ });
170
+ RichTextEditor.displayName = 'RichTextEditor';
171
+ const ToolbarButton = ({
172
+ action,
173
+ disabled,
174
+ onPress,
175
+ styles,
176
+ theme,
177
+ testID
178
+ }) => {
179
+ const meta = ACTION_META[action];
180
+ // Each glyph carries its own formatting, so the button reads as what it does.
181
+ // Built as one object rather than an array entry per rule: a `fontWeight:
182
+ // undefined` in a style array wipes the family weight `fontFor` just set.
183
+ const glyphStyle = {
184
+ color: disabled ? theme.colors.text.disabled : theme.colors.text.primary
185
+ };
186
+ if (action === 'bold') {
187
+ glyphStyle.fontWeight = theme.typography.fontWeight.bold;
188
+ }
189
+ if (action === 'italic') {
190
+ glyphStyle.fontStyle = 'italic';
191
+ }
192
+ if (action === 'strikethrough') {
193
+ glyphStyle.textDecorationLine = 'line-through';
194
+ }
195
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
196
+ onPress: () => onPress(action),
197
+ disabled: disabled,
198
+ accessibilityRole: "button",
199
+ accessibilityLabel: meta.label,
200
+ accessibilityState: {
201
+ disabled
202
+ },
203
+ hitSlop: 4,
204
+ testID: testID,
205
+ style: ({
206
+ pressed
207
+ }) => [styles.button, {
208
+ backgroundColor: pressed ? theme.colors.surface.pressed : theme.colors.background.secondary
209
+ }],
210
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
211
+ allowFontScaling: false,
212
+ style: [styles.buttonLabel, glyphStyle],
213
+ children: meta.glyph
214
+ })
215
+ });
216
+ };
217
+ ToolbarButton.displayName = 'RichTextEditorToolbarButton';
218
+
219
+ /**
220
+ * Placeholder shape for `<RichTextEditor>`: the same bordered box, a row of
221
+ * button-sized blocks where the toolbar sits, and text lines filling the body,
222
+ * so nothing reflows when the draft arrives.
223
+ */
224
+ const RichTextEditorSkeleton = ({
225
+ actionCount,
226
+ minHeight,
227
+ style,
228
+ testID
229
+ }) => {
230
+ const theme = (0, _index.useTheme)();
231
+ const styles = (0, _react.useMemo)(() => buildStyles(theme), [theme]);
232
+ const buttons = Array.from({
233
+ length: Math.max(1, actionCount)
234
+ }, (_, index) => index);
235
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
236
+ testID: testID,
237
+ style: [styles.container, style],
238
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
239
+ style: styles.toolbar,
240
+ children: buttons.map(index => /*#__PURE__*/(0, _jsxRuntime.jsx)(_index3.Skeleton, {
241
+ width: 34,
242
+ height: 30,
243
+ radius: "sm"
244
+ }, index))
245
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
246
+ style: [styles.skeletonBody, {
247
+ minHeight
248
+ }],
249
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_index3.Skeleton, {
250
+ shape: "text",
251
+ width: "94%",
252
+ height: 14
253
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_index3.Skeleton, {
254
+ shape: "text",
255
+ width: "100%",
256
+ height: 14
257
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_index3.Skeleton, {
258
+ shape: "text",
259
+ width: "72%",
260
+ height: 14
261
+ })]
262
+ })]
263
+ });
264
+ };
265
+ RichTextEditorSkeleton.displayName = 'RichTextEditorSkeleton';
266
+ const buildStyles = theme => _reactNative.StyleSheet.create({
267
+ container: {
268
+ borderWidth: theme.colors.border.width,
269
+ borderColor: theme.colors.border.primary,
270
+ borderRadius: theme.radius.md,
271
+ backgroundColor: theme.colors.background.primary,
272
+ overflow: 'hidden'
273
+ },
274
+ toolbar: {
275
+ flexDirection: 'row',
276
+ flexWrap: 'wrap',
277
+ alignItems: 'center',
278
+ gap: theme.spacing.xs,
279
+ padding: theme.spacing.xs,
280
+ borderBottomWidth: _reactNative.StyleSheet.hairlineWidth,
281
+ borderBottomColor: theme.colors.border.secondary,
282
+ backgroundColor: theme.colors.background.secondary
283
+ },
284
+ button: {
285
+ minWidth: 34,
286
+ height: 30,
287
+ paddingHorizontal: theme.spacing.xs,
288
+ borderRadius: theme.radius.sm,
289
+ alignItems: 'center',
290
+ justifyContent: 'center'
291
+ },
292
+ buttonLabel: {
293
+ ...(0, _index.fontFor)(theme, 'medium'),
294
+ fontSize: theme.typography.fontSize.sm
295
+ },
296
+ input: {
297
+ ...(0, _index.fontFor)(theme, 'normal'),
298
+ color: theme.colors.text.primary,
299
+ fontSize: theme.typography.fontSize.base,
300
+ lineHeight: theme.typography.fontSize.base * 1.5,
301
+ paddingHorizontal: theme.spacing.md,
302
+ paddingVertical: theme.spacing.sm
303
+ },
304
+ skeletonBody: {
305
+ paddingHorizontal: theme.spacing.md,
306
+ paddingVertical: theme.spacing.sm,
307
+ gap: theme.spacing.sm
308
+ }
309
+ });
310
+ var _default = exports.default = RichTextEditor;
311
+ //# sourceMappingURL=RichTextEditor.js.map
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "RichTextEditor", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _RichTextEditor.RichTextEditor;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "applyMarkdownAction", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _markdownActions.applyMarkdownAction;
16
+ }
17
+ });
18
+ var _markdownActions = require("./markdownActions.js");
19
+ var _RichTextEditor = require("./RichTextEditor.js");
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.normalizeSelection = exports.applyMarkdownAction = void 0;
7
+ /**
8
+ * The text transforms behind the editor's toolbar, kept out of the component so
9
+ * the behaviour people actually notice — toggling bold OFF again, and where the
10
+ * caret lands when nothing is selected — can be tested as data, with no
11
+ * rendering involved. Same split as Markdown/parse.ts.
12
+ *
13
+ * The output targets our own `<Markdown>` renderer, so the vocabulary is the
14
+ * subset that parser reads: `**`, `*`, `~~`, backtick, `[](…)`, `#`, `##`,
15
+ * `- `, `1. `, `> `. Nothing here emits anything that renderer would show as
16
+ * literal text.
17
+ */
18
+
19
+ const INLINE_MARKERS = {
20
+ bold: '**',
21
+ italic: '*',
22
+ strikethrough: '~~',
23
+ code: '`'
24
+ };
25
+
26
+ /** A whole link, and only a whole link — used to decide "is this already one?". */
27
+ const WHOLE_LINK = /^\[([^\]]*)\]\(([^)\s]*)\)$/;
28
+ const LINK_URL_PLACEHOLDER = 'url';
29
+ const BLOCK_RULES = {
30
+ heading1: {
31
+ has: l => /^#\s/.test(l),
32
+ prefix: () => '# '
33
+ },
34
+ heading2: {
35
+ has: l => /^##\s/.test(l),
36
+ prefix: () => '## '
37
+ },
38
+ bulletList: {
39
+ has: l => /^[-*+]\s/.test(l),
40
+ prefix: () => '- '
41
+ },
42
+ numberedList: {
43
+ has: l => /^\d+[.)]\s/.test(l),
44
+ prefix: index => `${index + 1}. `
45
+ },
46
+ quote: {
47
+ has: l => /^>\s?/.test(l),
48
+ prefix: () => '> '
49
+ }
50
+ };
51
+
52
+ /** Every block marker this editor writes, so switching kinds replaces rather than stacks. */
53
+ const ANY_BLOCK_PREFIX = /^(?:#{1,6}\s+|[-*+]\s+|\d+[.)]\s+|>\s?)/;
54
+ const isBlockAction = action => action in BLOCK_RULES;
55
+ const clamp = (value, max) => {
56
+ // React Native reports -1 for "no selection yet" on some Android builds.
57
+ if (!Number.isFinite(value) || value < 0) {
58
+ return 0;
59
+ }
60
+ return Math.min(Math.trunc(value), max);
61
+ };
62
+
63
+ /** Selection as given can be reversed, unset, or past the end after an edit. */
64
+ const normalizeSelection = (selection, length) => {
65
+ const a = clamp(selection.start, length);
66
+ const b = clamp(selection.end, length);
67
+ return {
68
+ start: Math.min(a, b),
69
+ end: Math.max(a, b)
70
+ };
71
+ };
72
+ exports.normalizeSelection = normalizeSelection;
73
+ const caret = at => ({
74
+ start: at,
75
+ end: at
76
+ });
77
+ const applyInlineMarker = (text, selection, marker) => {
78
+ const {
79
+ start,
80
+ end
81
+ } = selection;
82
+ const selected = text.slice(start, end);
83
+ const size = marker.length;
84
+
85
+ // `*` is a prefix of `**`, so italic must never mistake bold for itself:
86
+ // unwrapping one star per side would silently downgrade bold to italic.
87
+ const boldCollision = marker === '*';
88
+ const wrappedInside = selected.length >= size * 2 && selected.startsWith(marker) && selected.endsWith(marker);
89
+ if (wrappedInside && !(boldCollision && selected.startsWith('**') && selected.endsWith('**'))) {
90
+ const inner = selected.slice(size, selected.length - size);
91
+ return {
92
+ text: text.slice(0, start) + inner + text.slice(end),
93
+ selection: {
94
+ start,
95
+ end: start + inner.length
96
+ }
97
+ };
98
+ }
99
+ const before = text.slice(Math.max(0, start - size), start);
100
+ const after = text.slice(end, end + size);
101
+ const wrappedOutside = start >= size && before === marker && after === marker && !(boldCollision && text.slice(Math.max(0, start - 2), start) === '**');
102
+ if (wrappedOutside) {
103
+ return {
104
+ text: text.slice(0, start - size) + selected + text.slice(end + size),
105
+ selection: {
106
+ start: start - size,
107
+ end: end - size
108
+ }
109
+ };
110
+ }
111
+ const next = text.slice(0, start) + marker + selected + marker + text.slice(end);
112
+ return {
113
+ text: next,
114
+ selection: start === end ? caret(start + size) : {
115
+ start: start + size,
116
+ end: end + size
117
+ }
118
+ };
119
+ };
120
+ const applyLink = (text, selection) => {
121
+ const {
122
+ start,
123
+ end
124
+ } = selection;
125
+ const selected = text.slice(start, end);
126
+ const existing = WHOLE_LINK.exec(selected);
127
+ if (existing) {
128
+ const label = existing[1];
129
+ return {
130
+ text: text.slice(0, start) + label + text.slice(end),
131
+ selection: {
132
+ start,
133
+ end: start + label.length
134
+ }
135
+ };
136
+ }
137
+ const inserted = `[${selected}](${LINK_URL_PLACEHOLDER})`;
138
+ const next = text.slice(0, start) + inserted + text.slice(end);
139
+ if (start === end) {
140
+ // Nothing selected: the label is what the user types first, so the caret
141
+ // goes between the brackets rather than onto the URL placeholder.
142
+ return {
143
+ text: next,
144
+ selection: caret(start + 1)
145
+ };
146
+ }
147
+ const urlStart = start + selected.length + 3;
148
+ return {
149
+ text: next,
150
+ selection: {
151
+ start: urlStart,
152
+ end: urlStart + LINK_URL_PLACEHOLDER.length
153
+ }
154
+ };
155
+ };
156
+ const applyBlockPrefix = (text, selection, action) => {
157
+ const rule = BLOCK_RULES[action];
158
+ const lines = text.split('\n');
159
+ const offsets = [];
160
+ let cursor = 0;
161
+ for (const line of lines) {
162
+ offsets.push(cursor);
163
+ cursor += line.length + 1;
164
+ }
165
+ const lineIndexAt = position => {
166
+ let index = 0;
167
+ for (let i = 0; i < lines.length; i += 1) {
168
+ if (offsets[i] <= position) {
169
+ index = i;
170
+ }
171
+ }
172
+ return index;
173
+ };
174
+ const first = lineIndexAt(selection.start);
175
+ const last = lineIndexAt(selection.end);
176
+ const affected = lines.slice(first, last + 1);
177
+ const allHave = affected.every(line => rule.has(line));
178
+ const rewritten = affected.map((line, index) => allHave ? line.replace(ANY_BLOCK_PREFIX, '') : rule.prefix(index) + line.replace(ANY_BLOCK_PREFIX, ''));
179
+ const firstDelta = rewritten[0].length - affected[0].length;
180
+ const totalDelta = rewritten.reduce((sum, line, index) => sum + (line.length - affected[index].length), 0);
181
+ const nextLines = [...lines.slice(0, first), ...rewritten, ...lines.slice(last + 1)];
182
+ const nextText = nextLines.join('\n');
183
+ return {
184
+ text: nextText,
185
+ selection: normalizeSelection({
186
+ start: Math.max(offsets[first], selection.start + firstDelta),
187
+ end: selection.end + totalDelta
188
+ }, nextText.length)
189
+ };
190
+ };
191
+
192
+ /**
193
+ * Applies one toolbar action to the current text + selection and returns the
194
+ * next pair. Pure: the caller owns the state.
195
+ *
196
+ * Wrapping applies to the selection; with nothing selected the markers are
197
+ * inserted and the caret lands between them. Applying an action to text that
198
+ * already carries it removes it instead of stacking a second copy — which is
199
+ * the half people notice immediately when it is missing.
200
+ */
201
+ const applyMarkdownAction = (state, action) => {
202
+ const text = state.text ?? '';
203
+ const selection = normalizeSelection(state.selection, text.length);
204
+ if (isBlockAction(action)) {
205
+ return applyBlockPrefix(text, selection, action);
206
+ }
207
+ if (action === 'link') {
208
+ return applyLink(text, selection);
209
+ }
210
+ return applyInlineMarker(text, selection, INLINE_MARKERS[action]);
211
+ };
212
+ exports.applyMarkdownAction = applyMarkdownAction;
213
+ //# sourceMappingURL=markdownActions.js.map
@@ -68,6 +68,13 @@ const SearchBar = exports.SearchBar = /*#__PURE__*/(0, _react.forwardRef)((props
68
68
  const debouncedValue = (0, _useDebounce.useDebounce)(internalValue, debounceMs ?? 0);
69
69
  const cancelAnim = (0, _react.useRef)((0, _index.createAnimatedValue)(0)).current;
70
70
 
71
+ // Equivalent-mutant note: removing the `debounceMs === undefined` guard
72
+ // below cannot change observable behaviour. `internalValue` is only ever
73
+ // read (via `displayValue`) when `debounceMs !== undefined`; without the
74
+ // guard, a non-debounced instance would keep resyncing `internalValue`
75
+ // from `value` on every prop change, but that resynced value is never
76
+ // displayed or sent anywhere while non-debounced, so no test can observe
77
+ // the difference.
71
78
  // biome-ignore lint/correctness/useExhaustiveDependencies: syncs the internal draft FROM the `value` prop; adding `internalValue` would revert every keystroke while the debounce is still pending
72
79
  (0, _react.useEffect)(() => {
73
80
  if (debounceMs === undefined) {
@@ -231,7 +231,7 @@ const Select = exports.Select = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
231
231
  accessibilityLabel: label ?? placeholder ?? 'Options',
232
232
  options: options,
233
233
  labelOf: labelOf,
234
- valueOf: valueOf,
234
+ getValue: valueOf,
235
235
  disabledOf: disabledOf,
236
236
  descriptionOf: descriptionOf,
237
237
  iconOf: iconOf,
@@ -7,6 +7,7 @@ exports.default = exports.SkeletonText = exports.SkeletonCircle = exports.Skelet
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _index = require("../../theme/index.js");
10
+ var _Gradient = require("../../theme/Gradient.js");
10
11
  var _index2 = require("../../utils/index.js");
11
12
  var _SkeletonClock = require("./SkeletonClock.js");
12
13
  var _SkeletonProvider = require("./SkeletonProvider.js");
@@ -24,7 +25,7 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
24
25
  * - A View with the base color and `overflow: hidden` + radius gives the
25
26
  * placeholder its shape.
26
27
  * - For `animation: 'shimmer'`, an Animated.View carrying a 3-stop
27
- * `LinearGradient` (transparent → highlight → transparent) translates
28
+ * linear gradient (transparent → highlight → transparent) translates
28
29
  * across the box. The radius clips it to the right outline automatically.
29
30
  * - For `animation: 'pulse'`, a full-fill Animated.View fades its opacity
30
31
  * between 0 and 0.6. Cheap and useful for tiny shapes where a sweep
@@ -37,17 +38,6 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
37
38
  * height directly for full control.
38
39
  */
39
40
 
40
- // `react-native-linear-gradient` is an OPTIONAL peer dep. When it's installed
41
- // we sweep a real gradient band across the shimmer. When it isn't, we fall
42
- // back to a solid-color band — still works, just less polished. This keeps
43
- // the library deployable in apps that don't need gradients elsewhere.
44
- let LinearGradientImpl = null;
45
- try {
46
- LinearGradientImpl = require('react-native-linear-gradient').default;
47
- } catch {
48
- // Optional peer; resolved lazily by consumers that need shimmer polish.
49
- }
50
-
51
41
  /** Animation pattern. */
52
42
 
53
43
  /** Sweep speed for the shimmer band. Ignored for pulse / none. */
@@ -165,36 +155,27 @@ const Skeleton = ({
165
155
  }
166
156
 
167
157
  // 3-stop gradient: transparent → highlight → transparent. Feathered
168
- // edges feel premium; a solid band looks like a bug. When the optional
169
- // gradient package isn't installed we render the band as a solid
170
- // highlight rectangle — visibly different but still recognizably a
171
- // shimmer effect.
158
+ // edges feel premium; a solid band looks like a bug.
172
159
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Animated.View, {
173
160
  pointerEvents: "none",
174
161
  style: [styles.shimmerBand, {
175
162
  width: bandWidth,
176
163
  transform: [{
177
164
  translateX
178
- }]
179
- }],
180
- children: LinearGradientImpl ? /*#__PURE__*/(0, _jsxRuntime.jsx)(LinearGradientImpl, {
181
- colors: ['transparent', highlightColor, 'transparent'],
182
- locations: [0, 0.5, 1],
183
- start: {
184
- x: 0,
185
- y: 0.5
186
- },
187
- end: {
188
- x: 1,
189
- y: 0.5
190
- },
191
- style: _reactNative.StyleSheet.absoluteFill
192
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
193
- style: [_reactNative.StyleSheet.absoluteFill, {
194
- backgroundColor: highlightColor,
195
- opacity: 0.55
196
- }]
197
- })
165
+ }],
166
+ experimental_backgroundImage: [(0, _Gradient.toBackgroundImage)({
167
+ colors: ['transparent', highlightColor, 'transparent'],
168
+ locations: [0, 0.5, 1],
169
+ start: {
170
+ x: 0,
171
+ y: 0.5
172
+ },
173
+ end: {
174
+ x: 1,
175
+ y: 0.5
176
+ }
177
+ })]
178
+ }]
198
179
  });
199
180
  }, [effectiveVariant, highlightColor, clock.pulse, containerWidth, styles.shimmerBand, bandWidth, translateX]);
200
181
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {