panelui-native 0.44.0 → 0.49.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 (108) hide show
  1. package/README.md +6 -1
  2. package/lib/module/components/accordion/index.js +32 -4
  3. package/lib/module/components/accordion/index.js.map +1 -1
  4. package/lib/module/components/button/index.js +83 -15
  5. package/lib/module/components/button/index.js.map +1 -1
  6. package/lib/module/components/button-group/index.js +186 -0
  7. package/lib/module/components/button-group/index.js.map +1 -0
  8. package/lib/module/components/color-picker/index.js +110 -1
  9. package/lib/module/components/color-picker/index.js.map +1 -1
  10. package/lib/module/components/combobox/index.js +7 -1
  11. package/lib/module/components/combobox/index.js.map +1 -1
  12. package/lib/module/components/date-time-picker/index.js +272 -0
  13. package/lib/module/components/date-time-picker/index.js.map +1 -0
  14. package/lib/module/components/fab/index.js +514 -0
  15. package/lib/module/components/fab/index.js.map +1 -0
  16. package/lib/module/components/grid-item/index.js +486 -0
  17. package/lib/module/components/grid-item/index.js.map +1 -0
  18. package/lib/module/components/{kpi-chart → kpi}/index.js +62 -62
  19. package/lib/module/components/kpi/index.js.map +1 -0
  20. package/lib/module/components/line-chart/index.js +92 -10
  21. package/lib/module/components/line-chart/index.js.map +1 -1
  22. package/lib/module/components/markdown-editor/index.js +406 -0
  23. package/lib/module/components/markdown-editor/index.js.map +1 -0
  24. package/lib/module/components/markdown-editor/markdown-transforms.js +243 -0
  25. package/lib/module/components/markdown-editor/markdown-transforms.js.map +1 -0
  26. package/lib/module/components/pie-chart/index.js +625 -0
  27. package/lib/module/components/pie-chart/index.js.map +1 -0
  28. package/lib/module/components/questionnaire/index.js +1312 -0
  29. package/lib/module/components/questionnaire/index.js.map +1 -0
  30. package/lib/module/components/scatter-chart/index.js +1173 -0
  31. package/lib/module/components/scatter-chart/index.js.map +1 -0
  32. package/lib/module/components/tabs/index.js +359 -41
  33. package/lib/module/components/tabs/index.js.map +1 -1
  34. package/lib/module/components/time-picker/index.js +34 -6
  35. package/lib/module/components/time-picker/index.js.map +1 -1
  36. package/lib/module/components/tree/index.js +500 -0
  37. package/lib/module/components/tree/index.js.map +1 -0
  38. package/lib/module/icons/index.js +217 -0
  39. package/lib/module/icons/index.js.map +1 -1
  40. package/lib/module/index.js +11 -2
  41. package/lib/module/index.js.map +1 -1
  42. package/lib/module/utils/chart.js +81 -0
  43. package/lib/module/utils/chart.js.map +1 -1
  44. package/lib/typescript/src/components/accordion/index.d.ts +21 -0
  45. package/lib/typescript/src/components/accordion/index.d.ts.map +1 -1
  46. package/lib/typescript/src/components/button/index.d.ts +21 -0
  47. package/lib/typescript/src/components/button/index.d.ts.map +1 -1
  48. package/lib/typescript/src/components/button-group/index.d.ts +212 -0
  49. package/lib/typescript/src/components/button-group/index.d.ts.map +1 -0
  50. package/lib/typescript/src/components/color-picker/index.d.ts +82 -1
  51. package/lib/typescript/src/components/color-picker/index.d.ts.map +1 -1
  52. package/lib/typescript/src/components/combobox/index.d.ts.map +1 -1
  53. package/lib/typescript/src/components/date-time-picker/index.d.ts +127 -0
  54. package/lib/typescript/src/components/date-time-picker/index.d.ts.map +1 -0
  55. package/lib/typescript/src/components/fab/index.d.ts +285 -0
  56. package/lib/typescript/src/components/fab/index.d.ts.map +1 -0
  57. package/lib/typescript/src/components/grid-item/index.d.ts +292 -0
  58. package/lib/typescript/src/components/grid-item/index.d.ts.map +1 -0
  59. package/lib/typescript/src/components/{kpi-chart → kpi}/index.d.ts +65 -65
  60. package/lib/typescript/src/components/kpi/index.d.ts.map +1 -0
  61. package/lib/typescript/src/components/line-chart/index.d.ts +25 -1
  62. package/lib/typescript/src/components/line-chart/index.d.ts.map +1 -1
  63. package/lib/typescript/src/components/markdown-editor/index.d.ts +102 -0
  64. package/lib/typescript/src/components/markdown-editor/index.d.ts.map +1 -0
  65. package/lib/typescript/src/components/markdown-editor/markdown-transforms.d.ts +76 -0
  66. package/lib/typescript/src/components/markdown-editor/markdown-transforms.d.ts.map +1 -0
  67. package/lib/typescript/src/components/pie-chart/index.d.ts +245 -0
  68. package/lib/typescript/src/components/pie-chart/index.d.ts.map +1 -0
  69. package/lib/typescript/src/components/questionnaire/index.d.ts +336 -0
  70. package/lib/typescript/src/components/questionnaire/index.d.ts.map +1 -0
  71. package/lib/typescript/src/components/scatter-chart/index.d.ts +309 -0
  72. package/lib/typescript/src/components/scatter-chart/index.d.ts.map +1 -0
  73. package/lib/typescript/src/components/tabs/index.d.ts +29 -2
  74. package/lib/typescript/src/components/tabs/index.d.ts.map +1 -1
  75. package/lib/typescript/src/components/time-picker/index.d.ts +19 -1
  76. package/lib/typescript/src/components/time-picker/index.d.ts.map +1 -1
  77. package/lib/typescript/src/components/tree/index.d.ts +125 -0
  78. package/lib/typescript/src/components/tree/index.d.ts.map +1 -0
  79. package/lib/typescript/src/icons/index.d.ts +22 -0
  80. package/lib/typescript/src/icons/index.d.ts.map +1 -1
  81. package/lib/typescript/src/index.d.ts +14 -5
  82. package/lib/typescript/src/index.d.ts.map +1 -1
  83. package/lib/typescript/src/utils/chart.d.ts +34 -0
  84. package/lib/typescript/src/utils/chart.d.ts.map +1 -1
  85. package/package.json +1 -1
  86. package/src/components/accordion/index.tsx +48 -6
  87. package/src/components/button/index.tsx +97 -15
  88. package/src/components/button-group/index.tsx +199 -0
  89. package/src/components/color-picker/index.tsx +140 -3
  90. package/src/components/combobox/index.tsx +7 -1
  91. package/src/components/date-time-picker/index.tsx +411 -0
  92. package/src/components/fab/index.tsx +583 -0
  93. package/src/components/grid-item/index.tsx +515 -0
  94. package/src/components/{kpi-chart → kpi}/index.tsx +85 -85
  95. package/src/components/line-chart/index.tsx +98 -8
  96. package/src/components/markdown-editor/index.tsx +526 -0
  97. package/src/components/markdown-editor/markdown-transforms.ts +228 -0
  98. package/src/components/pie-chart/index.tsx +863 -0
  99. package/src/components/questionnaire/index.tsx +1615 -0
  100. package/src/components/scatter-chart/index.tsx +1401 -0
  101. package/src/components/tabs/index.tsx +392 -50
  102. package/src/components/time-picker/index.tsx +42 -6
  103. package/src/components/tree/index.tsx +564 -0
  104. package/src/icons/index.tsx +154 -0
  105. package/src/index.ts +142 -18
  106. package/src/utils/chart.ts +110 -0
  107. package/lib/module/components/kpi-chart/index.js.map +0 -1
  108. package/lib/typescript/src/components/kpi-chart/index.d.ts.map +0 -1
@@ -0,0 +1,406 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * MarkdownEditor — a field for writing markdown, and a way to see it rendered.
5
+ *
6
+ * ```tsx
7
+ * const [draft, setDraft] = useState('');
8
+ *
9
+ * <MarkdownEditor value={draft} onValueChange={setDraft} rows={12} />
10
+ * ```
11
+ *
12
+ * ## Writing and reading are two modes, not two panes
13
+ *
14
+ * Side by side is how this is done on a desktop, and it does not survive the
15
+ * trip to a phone: two columns of a phone's width are two columns too narrow to
16
+ * read, and the keyboard covers the bottom half of the screen exactly when the
17
+ * writer is using it. So there is one pane and a switch — write, or read what
18
+ * you wrote. The toolbar carries the switch, because the toolbar is the one
19
+ * thing on screen in both modes.
20
+ *
21
+ * ## The toolbar edits the selection
22
+ *
23
+ * Every button here is a function of the text and where the caret is in it, and
24
+ * the answer that matters is not which characters get inserted but where the
25
+ * caret lands afterwards. Bolding a selected phrase leaves it selected, so it
26
+ * can be italicised next; bolding nothing puts the caret between the new
27
+ * markers, where the writing is about to go; and pressing the same button again
28
+ * takes the markers off. Those rules live in `markdown-transforms.ts` as pure
29
+ * functions over `(text, selection)`, away from anything to do with a field.
30
+ *
31
+ * ## Why it renders through Response
32
+ *
33
+ * The preview is `Response`, the same reader that renders a model's answer, so
34
+ * markdown means the same thing everywhere in the library and there is one
35
+ * parser to be right rather than two to keep in step. It renders through
36
+ * `Typography`, `CodeBlock` and `Table`, which is to say through the app's own
37
+ * type and colours — a preview that looked like a document viewer would be
38
+ * showing the writer something they are not going to ship.
39
+ *
40
+ * Nothing here reaches for a platform markdown renderer. `Text` in SwiftUI can
41
+ * parse markdown and Jetpack Compose's cannot, so a platform-backed editor
42
+ * would render on one of the two and be a plain string on the other.
43
+ *
44
+ * Works controlled (`value` + `onValueChange`) or uncontrolled (`defaultValue`).
45
+ */
46
+ import { createContext, forwardRef, useCallback, useContext, useMemo, useRef, useState } from 'react';
47
+ import { View } from 'react-native';
48
+ import { tv } from 'tailwind-variants';
49
+ import { BoldIcon, CodeIcon, EyeIcon, HeadingIcon, ItalicIcon, LinkIcon, ListIcon, ListOrderedIcon, PencilIcon, QuoteIcon } from "../../icons/index.js";
50
+ import { Text } from "../../primitives/text.js";
51
+ import { cn } from "../../utils/cn.js";
52
+ import { Button } from "../button/index.js";
53
+ import { ButtonGroup } from "../button-group/index.js";
54
+ import { Response } from "../response/index.js";
55
+ import { Textarea } from "../textarea/index.js";
56
+ import { insertLink, toggleFence, toggleLinePrefix, toggleOrderedList, toggleWrap } from "./markdown-transforms.js";
57
+
58
+ /** Which pane the editor is showing. */
59
+
60
+ /** A formatting action the toolbar can offer. */
61
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
62
+ /** The actions a toolbar shows when it is not told which to show. */
63
+ const DEFAULT_ACTIONS = ['bold', 'italic', 'heading', 'bulletList', 'orderedList', 'quote', 'code', 'link'];
64
+
65
+ /**
66
+ * What each action does, what it is called, and what it looks like.
67
+ *
68
+ * One table rather than a switch in the toolbar and another in the context:
69
+ * adding an action should be adding a row here, and nowhere else.
70
+ */
71
+ const ACTIONS = {
72
+ bold: {
73
+ label: 'Bold',
74
+ icon: size => /*#__PURE__*/_jsx(BoldIcon, {
75
+ size: size
76
+ }),
77
+ apply: (text, selection) => toggleWrap(text, selection, '**')
78
+ },
79
+ italic: {
80
+ label: 'Italic',
81
+ icon: size => /*#__PURE__*/_jsx(ItalicIcon, {
82
+ size: size
83
+ }),
84
+ apply: (text, selection) => toggleWrap(text, selection, '_')
85
+ },
86
+ heading: {
87
+ label: 'Heading',
88
+ icon: size => /*#__PURE__*/_jsx(HeadingIcon, {
89
+ size: size
90
+ }),
91
+ apply: (text, selection) => toggleLinePrefix(text, selection, '## ')
92
+ },
93
+ quote: {
94
+ label: 'Quote',
95
+ icon: size => /*#__PURE__*/_jsx(QuoteIcon, {
96
+ size: size
97
+ }),
98
+ apply: (text, selection) => toggleLinePrefix(text, selection, '> ')
99
+ },
100
+ code: {
101
+ label: 'Code block',
102
+ icon: size => /*#__PURE__*/_jsx(CodeIcon, {
103
+ size: size
104
+ }),
105
+ apply: toggleFence
106
+ },
107
+ bulletList: {
108
+ label: 'Bulleted list',
109
+ icon: size => /*#__PURE__*/_jsx(ListIcon, {
110
+ size: size
111
+ }),
112
+ apply: (text, selection) => toggleLinePrefix(text, selection, '- ')
113
+ },
114
+ orderedList: {
115
+ label: 'Numbered list',
116
+ icon: size => /*#__PURE__*/_jsx(ListOrderedIcon, {
117
+ size: size
118
+ }),
119
+ apply: toggleOrderedList
120
+ },
121
+ link: {
122
+ label: 'Link',
123
+ icon: size => /*#__PURE__*/_jsx(LinkIcon, {
124
+ size: size
125
+ }),
126
+ apply: insertLink
127
+ }
128
+ };
129
+ const markdownEditorVariants = tv({
130
+ slots: {
131
+ root: 'w-full gap-2',
132
+ toolbar: 'flex-row items-center justify-between gap-2',
133
+ // The preview stands in the field's place, so it takes the field's shape.
134
+ // A rendered draft that sat on the page with no edge around it would not
135
+ // read as the same object the writing was in.
136
+ preview: 'w-full rounded-xl border border-input bg-popover px-3 py-2.5',
137
+ empty: 'py-6 text-center'
138
+ }
139
+ });
140
+ const MarkdownEditorContext = /*#__PURE__*/createContext(null);
141
+ function useMarkdownEditor(part) {
142
+ const ctx = useContext(MarkdownEditorContext);
143
+ if (!ctx) throw new Error(`${part} must be used inside <MarkdownEditor>.`);
144
+ return ctx;
145
+ }
146
+ const MarkdownEditorRoot = /*#__PURE__*/forwardRef(({
147
+ className,
148
+ value: valueProp,
149
+ defaultValue = '',
150
+ onValueChange,
151
+ mode: modeProp,
152
+ defaultMode = 'write',
153
+ onModeChange,
154
+ disabled = false,
155
+ children,
156
+ placeholder,
157
+ rows,
158
+ ...props
159
+ }, ref) => {
160
+ const slots = markdownEditorVariants();
161
+ const [internalValue, setInternalValue] = useState(defaultValue);
162
+ const value = valueProp ?? internalValue;
163
+ const [internalMode, setInternalMode] = useState(defaultMode);
164
+ const mode = modeProp ?? internalMode;
165
+
166
+ /*
167
+ * The live selection is a ref rather than state.
168
+ *
169
+ * It changes on every caret move — every keystroke, every tap in the text —
170
+ * and nothing on screen depends on it. Holding it in state would re-render
171
+ * the field, and therefore the preview under it, once per character typed.
172
+ */
173
+ const selectionRef = useRef({
174
+ start: 0,
175
+ end: 0
176
+ });
177
+
178
+ /*
179
+ * What the field should show as selected after a toolbar edit, held for
180
+ * exactly one render.
181
+ *
182
+ * A `selection` prop that stays set is a field the writer cannot move the
183
+ * caret in — every tap would be pulled back to wherever the last edit put
184
+ * it. So it is set once, applied, and cleared by the very selection change
185
+ * it causes.
186
+ */
187
+ const [pending, setPending] = useState(undefined);
188
+ const valueRef = useRef(value);
189
+ valueRef.current = value;
190
+ const commit = useCallback(next => {
191
+ if (valueProp === undefined) setInternalValue(next);
192
+ onValueChange?.(next);
193
+ }, [valueProp, onValueChange]);
194
+ const setMode = useCallback(next => {
195
+ if (modeProp === undefined) setInternalMode(next);
196
+ onModeChange?.(next);
197
+ }, [modeProp, onModeChange]);
198
+ const run = useCallback(action => {
199
+ const result = ACTIONS[action].apply(valueRef.current, selectionRef.current);
200
+ // Kept locally too: the parent may be slow to hand the new text back,
201
+ // and the next press must not be computed against the old string.
202
+ valueRef.current = result.text;
203
+ selectionRef.current = result.selection;
204
+ commit(result.text);
205
+ setPending(result.selection);
206
+ }, [commit]);
207
+ const context = useMemo(() => ({
208
+ value,
209
+ mode,
210
+ setMode,
211
+ run,
212
+ pending,
213
+ setSelection: selection => {
214
+ selectionRef.current = selection;
215
+ },
216
+ clearPending: () => setPending(undefined),
217
+ onChangeText: next => {
218
+ valueRef.current = next;
219
+ commit(next);
220
+ },
221
+ disabled
222
+ }), [value, mode, setMode, run, pending, commit, disabled]);
223
+ return /*#__PURE__*/_jsx(MarkdownEditorContext.Provider, {
224
+ value: context,
225
+ children: /*#__PURE__*/_jsx(View, {
226
+ ref: ref,
227
+ className: slots.root({
228
+ className
229
+ }),
230
+ ...props,
231
+ children: children ?? /*#__PURE__*/_jsxs(_Fragment, {
232
+ children: [/*#__PURE__*/_jsx(MarkdownEditorToolbar, {}), /*#__PURE__*/_jsx(MarkdownEditorInput, {
233
+ placeholder: placeholder,
234
+ rows: rows
235
+ }), /*#__PURE__*/_jsx(MarkdownEditorPreview, {})]
236
+ })
237
+ })
238
+ });
239
+ });
240
+ MarkdownEditorRoot.displayName = 'MarkdownEditor';
241
+
242
+ /* -------------------------------------------------------------------------- *
243
+ * Toolbar
244
+ * -------------------------------------------------------------------------- */
245
+
246
+ /**
247
+ * The formatting actions, and the switch between writing and reading.
248
+ *
249
+ * The formatting run is hidden rather than disabled while previewing. Its
250
+ * buttons act on a selection, and in the preview there is no selection for them
251
+ * to act on — a row of controls that are present but inert is a row that has to
252
+ * be tried before it can be understood.
253
+ */
254
+ const MarkdownEditorToolbar = /*#__PURE__*/forwardRef(({
255
+ className,
256
+ actions = DEFAULT_ACTIONS,
257
+ showModeSwitch = true,
258
+ children,
259
+ ...props
260
+ }, ref) => {
261
+ const {
262
+ mode,
263
+ setMode,
264
+ run,
265
+ disabled
266
+ } = useMarkdownEditor('MarkdownEditor.Toolbar');
267
+ const slots = markdownEditorVariants();
268
+ return /*#__PURE__*/_jsxs(View, {
269
+ ref: ref,
270
+ className: slots.toolbar({
271
+ className
272
+ }),
273
+ ...props,
274
+ children: [mode === 'write' ? /*#__PURE__*/_jsx(ButtonGroup, {
275
+ variant: "ghost",
276
+ size: "sm",
277
+ className: "shrink",
278
+ children: actions.map(action => /*#__PURE__*/_jsx(Button, {
279
+ accessibilityLabel: ACTIONS[action].label,
280
+ disabled: disabled,
281
+ onPress: () => run(action),
282
+ className: "px-2",
283
+ children: ACTIONS[action].icon(16)
284
+ }, action))
285
+ }) : /*#__PURE__*/_jsx(View, {
286
+ className: "shrink"
287
+ }), /*#__PURE__*/_jsxs(View, {
288
+ className: "flex-row items-center gap-2",
289
+ children: [children, showModeSwitch ? /*#__PURE__*/_jsxs(ButtonGroup, {
290
+ size: "sm",
291
+ children: [/*#__PURE__*/_jsx(Button, {
292
+ variant: mode === 'write' ? 'secondary' : 'ghost',
293
+ startContent: /*#__PURE__*/_jsx(PencilIcon, {
294
+ size: 14
295
+ }),
296
+ onPress: () => setMode('write'),
297
+ children: "Write"
298
+ }), /*#__PURE__*/_jsx(Button, {
299
+ variant: mode === 'preview' ? 'secondary' : 'ghost',
300
+ startContent: /*#__PURE__*/_jsx(EyeIcon, {
301
+ size: 14
302
+ }),
303
+ onPress: () => setMode('preview'),
304
+ children: "Preview"
305
+ })]
306
+ }) : null]
307
+ })]
308
+ });
309
+ });
310
+ MarkdownEditorToolbar.displayName = 'MarkdownEditor.Toolbar';
311
+
312
+ /* -------------------------------------------------------------------------- *
313
+ * Input
314
+ * -------------------------------------------------------------------------- */
315
+
316
+ /**
317
+ * The field the markdown is written in — a `Textarea`, tracking its selection.
318
+ *
319
+ * Renders nothing while the preview is up. Unmounted rather than hidden: a
320
+ * field kept alive behind the preview keeps the keyboard up with it.
321
+ */
322
+ const MarkdownEditorInput = /*#__PURE__*/forwardRef(({
323
+ className,
324
+ rows = 8,
325
+ ...props
326
+ }, ref) => {
327
+ const {
328
+ value,
329
+ mode,
330
+ pending,
331
+ setSelection,
332
+ clearPending,
333
+ onChangeText,
334
+ disabled
335
+ } = useMarkdownEditor('MarkdownEditor.Input');
336
+ const handleSelectionChange = useCallback(event => {
337
+ setSelection(event.nativeEvent.selection);
338
+ // The edit's own selection has now landed, so stop forcing it and give
339
+ // the caret back to whoever is holding the phone.
340
+ clearPending();
341
+ }, [setSelection, clearPending]);
342
+ if (mode !== 'write') return null;
343
+ return /*#__PURE__*/_jsx(Textarea, {
344
+ ref: ref,
345
+ value: value,
346
+ onChangeText: onChangeText,
347
+ selection: pending,
348
+ onSelectionChange: handleSelectionChange,
349
+ disabled: disabled,
350
+ rows: rows,
351
+ autoCapitalize: "none",
352
+ autoCorrect: false
353
+ // A markdown source is code as much as it is prose: an editor that
354
+ // capitalises the word after a fence, or rewrites a dash into an
355
+ // en dash, is an editor that changes what the document renders as.
356
+ ,
357
+ className: cn('font-mono', className),
358
+ ...props
359
+ });
360
+ });
361
+ MarkdownEditorInput.displayName = 'MarkdownEditor.Input';
362
+
363
+ /* -------------------------------------------------------------------------- *
364
+ * Preview
365
+ * -------------------------------------------------------------------------- */
366
+
367
+ /**
368
+ * The draft, rendered.
369
+ *
370
+ * Renders nothing while the field is up, which is what makes the two one pane
371
+ * rather than two.
372
+ */
373
+ const MarkdownEditorPreview = /*#__PURE__*/forwardRef(({
374
+ className,
375
+ emptyText = 'Nothing to preview yet.',
376
+ ...props
377
+ }, ref) => {
378
+ const {
379
+ value,
380
+ mode
381
+ } = useMarkdownEditor('MarkdownEditor.Preview');
382
+ const slots = markdownEditorVariants();
383
+ if (mode !== 'preview') return null;
384
+ return /*#__PURE__*/_jsx(View, {
385
+ ref: ref,
386
+ className: slots.preview({
387
+ className
388
+ }),
389
+ ...props,
390
+ children: value.trim() ? /*#__PURE__*/_jsx(Response, {
391
+ children: value
392
+ }) : /*#__PURE__*/_jsx(Text, {
393
+ size: "sm",
394
+ muted: true,
395
+ className: slots.empty(),
396
+ children: emptyText
397
+ })
398
+ });
399
+ });
400
+ MarkdownEditorPreview.displayName = 'MarkdownEditor.Preview';
401
+ export const MarkdownEditor = Object.assign(MarkdownEditorRoot, {
402
+ Toolbar: MarkdownEditorToolbar,
403
+ Input: MarkdownEditorInput,
404
+ Preview: MarkdownEditorPreview
405
+ });
406
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["createContext","forwardRef","useCallback","useContext","useMemo","useRef","useState","View","tv","BoldIcon","CodeIcon","EyeIcon","HeadingIcon","ItalicIcon","LinkIcon","ListIcon","ListOrderedIcon","PencilIcon","QuoteIcon","Text","cn","Button","ButtonGroup","Response","Textarea","insertLink","toggleFence","toggleLinePrefix","toggleOrderedList","toggleWrap","jsx","_jsx","Fragment","_Fragment","jsxs","_jsxs","DEFAULT_ACTIONS","ACTIONS","bold","label","icon","size","apply","text","selection","italic","heading","quote","code","bulletList","orderedList","link","markdownEditorVariants","slots","root","toolbar","preview","empty","MarkdownEditorContext","useMarkdownEditor","part","ctx","Error","MarkdownEditorRoot","className","value","valueProp","defaultValue","onValueChange","mode","modeProp","defaultMode","onModeChange","disabled","children","placeholder","rows","props","ref","internalValue","setInternalValue","internalMode","setInternalMode","selectionRef","start","end","pending","setPending","undefined","valueRef","current","commit","next","setMode","run","action","result","context","setSelection","clearPending","onChangeText","Provider","MarkdownEditorToolbar","MarkdownEditorInput","MarkdownEditorPreview","displayName","actions","showModeSwitch","variant","map","accessibilityLabel","onPress","startContent","handleSelectionChange","event","nativeEvent","onSelectionChange","autoCapitalize","autoCorrect","emptyText","trim","muted","MarkdownEditor","Object","assign","Toolbar","Input","Preview"],"sourceRoot":"../../../../src","sources":["components/markdown-editor/index.tsx"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * The edits a formatting toolbar makes, as functions of the text and where the
5
+ * caret is in it.
6
+ *
7
+ * Pure, and deliberately so. Every one of these takes `(text, selection)` and
8
+ * returns the text that should replace it together with where the selection
9
+ * should end up — no component, no ref, no input. What makes a formatting
10
+ * toolbar feel broken is never the characters it inserts; it is where the caret
11
+ * lands afterwards, and that is a property of these functions rather than of
12
+ * the field they are wired to.
13
+ *
14
+ * Three rules they all keep:
15
+ *
16
+ * - **Applying twice undoes it.** A toolbar button that only ever adds is a
17
+ * button you can press once, and every press after that damages the text.
18
+ * - **A selection stays selected.** Bolding three words and then italicising
19
+ * the same three has to be two presses, not a press and a re-selection.
20
+ * - **With nothing selected, the caret lands where the writing goes** — between
21
+ * the new markers rather than after them.
22
+ */
23
+
24
+ /** Clamps a selection to the text it belongs to, and puts it the right way round. */
25
+ function normalise(text, selection) {
26
+ const a = Math.max(0, Math.min(text.length, selection.start));
27
+ const b = Math.max(0, Math.min(text.length, selection.end));
28
+ return {
29
+ start: Math.min(a, b),
30
+ end: Math.max(a, b)
31
+ };
32
+ }
33
+
34
+ /* -------------------------------------------------------------------------- *
35
+ * Inline markers — bold, italic, inline code
36
+ * -------------------------------------------------------------------------- */
37
+
38
+ /**
39
+ * Wraps the selection in `marker`, or unwraps it if it is already wrapped.
40
+ *
41
+ * "Already wrapped" is checked both ways round: the markers may be inside the
42
+ * selection (the writer selected `**bold**`) or immediately outside it (they
43
+ * selected `bold` in the middle of `**bold**`). Both are the same intent, and a
44
+ * toolbar that only recognised one of them would add a second pair of asterisks
45
+ * to text that already had them.
46
+ */
47
+ export function toggleWrap(text, selection, marker) {
48
+ const {
49
+ start,
50
+ end
51
+ } = normalise(text, selection);
52
+ const selected = text.slice(start, end);
53
+ const len = marker.length;
54
+
55
+ // The markers are inside the selection.
56
+ if (selected.length >= len * 2 && selected.startsWith(marker) && selected.endsWith(marker)) {
57
+ const inner = selected.slice(len, selected.length - len);
58
+ return {
59
+ text: text.slice(0, start) + inner + text.slice(end),
60
+ selection: {
61
+ start,
62
+ end: start + inner.length
63
+ }
64
+ };
65
+ }
66
+
67
+ // The markers are just outside it.
68
+ const before = text.slice(Math.max(0, start - len), start);
69
+ const after = text.slice(end, end + len);
70
+ if (before === marker && after === marker) {
71
+ return {
72
+ text: text.slice(0, start - len) + selected + text.slice(end + len),
73
+ selection: {
74
+ start: start - len,
75
+ end: end - len + selected.length
76
+ }
77
+ };
78
+ }
79
+ const next = text.slice(0, start) + marker + selected + marker + text.slice(end);
80
+
81
+ // Nothing selected: the caret goes between the markers, which is where the
82
+ // writer is about to type. Something selected: it stays selected.
83
+ return selected ? {
84
+ text: next,
85
+ selection: {
86
+ start: start + len,
87
+ end: end + len
88
+ }
89
+ } : {
90
+ text: next,
91
+ selection: {
92
+ start: start + len,
93
+ end: start + len
94
+ }
95
+ };
96
+ }
97
+
98
+ /* -------------------------------------------------------------------------- *
99
+ * Line prefixes — headings, lists, quotes
100
+ * -------------------------------------------------------------------------- */
101
+
102
+ /** The span of whole lines the selection touches, even partly. */
103
+ function lineRange(text, selection) {
104
+ const {
105
+ start,
106
+ end
107
+ } = normalise(text, selection);
108
+ const from = text.lastIndexOf('\n', start - 1) + 1;
109
+ const lineEnd = text.indexOf('\n', end);
110
+ return {
111
+ start: from,
112
+ end: lineEnd === -1 ? text.length : lineEnd
113
+ };
114
+ }
115
+
116
+ /**
117
+ * Replaces the text between two offsets and reports where the selection goes.
118
+ *
119
+ * The selection is kept over the same *lines* rather than the same character
120
+ * offsets — prefixing four lines moves everything after the first one along,
121
+ * and a selection that did not move with them would end up covering a different
122
+ * four lines than the ones just changed.
123
+ */
124
+ function replaceBlock(text, range, replacement) {
125
+ return {
126
+ text: text.slice(0, range.start) + replacement + text.slice(range.end),
127
+ selection: {
128
+ start: range.start,
129
+ end: range.start + replacement.length
130
+ }
131
+ };
132
+ }
133
+
134
+ /**
135
+ * Puts `prefix` on the front of every line the selection touches, or takes it
136
+ * off if every one of them already has it.
137
+ *
138
+ * Every one, not any one: a mixed block is a block the writer is trying to make
139
+ * uniform, so the useful answer there is to add rather than to remove.
140
+ */
141
+ export function toggleLinePrefix(text, selection, prefix) {
142
+ const range = lineRange(text, selection);
143
+ const lines = text.slice(range.start, range.end).split('\n');
144
+ const has = line => line.startsWith(prefix);
145
+ const next = lines.every(has) ? lines.map(line => line.slice(prefix.length)) : lines.map(line => has(line) ? line : prefix + line);
146
+ return replaceBlock(text, range, next.join('\n'));
147
+ }
148
+
149
+ /** How an ordered-list line starts, so it can be recognised and removed. */
150
+ const ORDERED = /^\d+\.\s/;
151
+
152
+ /**
153
+ * Numbers the lines the selection touches, or unnumbers them.
154
+ *
155
+ * Counted from one within the block rather than continuing whatever came above
156
+ * it: the numbers a writer types are not the numbers that get rendered — every
157
+ * markdown reader renumbers an ordered list from its first item — so the useful
158
+ * thing is for the source to read the way the output will.
159
+ */
160
+ export function toggleOrderedList(text, selection) {
161
+ const range = lineRange(text, selection);
162
+ const lines = text.slice(range.start, range.end).split('\n');
163
+ const next = lines.every(line => ORDERED.test(line)) ? lines.map(line => line.replace(ORDERED, '')) : lines.map((line, i) => `${i + 1}. ${line.replace(ORDERED, '')}`);
164
+ return replaceBlock(text, range, next.join('\n'));
165
+ }
166
+
167
+ /* -------------------------------------------------------------------------- *
168
+ * Links
169
+ * -------------------------------------------------------------------------- */
170
+
171
+ /** Placeholder left where a link's target goes. */
172
+ export const LINK_PLACEHOLDER = 'url';
173
+
174
+ /**
175
+ * Turns the selection into a link, and selects the part that still needs
176
+ * filling in.
177
+ *
178
+ * Which part that is depends on what was selected. With text selected, the
179
+ * label is written and the target is not, so the placeholder target is left
180
+ * selected and typing replaces it. With nothing selected there is neither, and
181
+ * the label comes first because it is the half the writer is thinking about.
182
+ */
183
+ export function insertLink(text, selection) {
184
+ const {
185
+ start,
186
+ end
187
+ } = normalise(text, selection);
188
+ const label = text.slice(start, end);
189
+ const inserted = `[${label}](${LINK_PLACEHOLDER})`;
190
+ const next = text.slice(0, start) + inserted + text.slice(end);
191
+ if (label) {
192
+ const from = start + label.length + 3; // `[` + label + `](`
193
+ return {
194
+ text: next,
195
+ selection: {
196
+ start: from,
197
+ end: from + LINK_PLACEHOLDER.length
198
+ }
199
+ };
200
+ }
201
+ return {
202
+ text: next,
203
+ selection: {
204
+ start: start + 1,
205
+ end: start + 1
206
+ }
207
+ };
208
+ }
209
+
210
+ /* -------------------------------------------------------------------------- *
211
+ * Fenced code
212
+ * -------------------------------------------------------------------------- */
213
+
214
+ /**
215
+ * Puts the selected lines in a fence, or takes them out of one.
216
+ *
217
+ * A fence is the one construct that has to sit on lines of its own, so this
218
+ * makes room for itself: a blank line before it when it is not already at the
219
+ * start of a paragraph, and one after it at the end.
220
+ */
221
+ export function toggleFence(text, selection) {
222
+ const range = lineRange(text, selection);
223
+ const block = text.slice(range.start, range.end);
224
+ const lines = block.split('\n');
225
+ if (lines.length >= 2 && lines[0]?.startsWith('```') && lines.at(-1) === '```') {
226
+ return replaceBlock(text, range, lines.slice(1, -1).join('\n'));
227
+ }
228
+ const leadIn = range.start > 0 && text[range.start - 1] !== '\n' ? '\n' : '';
229
+ const fenced = `${leadIn}\`\`\`\n${block}\n\`\`\``;
230
+ const result = replaceBlock(text, range, fenced);
231
+
232
+ // Inside the fence, on the line the code goes on — not around the whole
233
+ // block, which would be selecting the markers along with the content.
234
+ const inner = range.start + leadIn.length + 4;
235
+ return {
236
+ text: result.text,
237
+ selection: {
238
+ start: inner,
239
+ end: inner + block.length
240
+ }
241
+ };
242
+ }
243
+ //# sourceMappingURL=markdown-transforms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["normalise","text","selection","a","Math","max","min","length","start","b","end","toggleWrap","marker","selected","slice","len","startsWith","endsWith","inner","before","after","next","lineRange","from","lastIndexOf","lineEnd","indexOf","replaceBlock","range","replacement","toggleLinePrefix","prefix","lines","split","has","line","every","map","join","ORDERED","toggleOrderedList","test","replace","i","LINK_PLACEHOLDER","insertLink","label","inserted","toggleFence","block","at","leadIn","fenced","result"],"sourceRoot":"../../../../src","sources":["components/markdown-editor/markdown-transforms.ts"],"mappings":"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","ignoreList":[]}