panelui-native 0.46.0 → 0.51.1

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 (87) hide show
  1. package/README.md +12 -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/date-time-picker/index.js +23 -5
  11. package/lib/module/components/date-time-picker/index.js.map +1 -1
  12. package/lib/module/components/fab/index.js +514 -0
  13. package/lib/module/components/fab/index.js.map +1 -0
  14. package/lib/module/components/markdown-editor/index.js +406 -0
  15. package/lib/module/components/markdown-editor/index.js.map +1 -0
  16. package/lib/module/components/markdown-editor/markdown-transforms.js +243 -0
  17. package/lib/module/components/markdown-editor/markdown-transforms.js.map +1 -0
  18. package/lib/module/components/questionnaire/index.js +1312 -0
  19. package/lib/module/components/questionnaire/index.js.map +1 -0
  20. package/lib/module/components/sortable/index.js +806 -0
  21. package/lib/module/components/sortable/index.js.map +1 -0
  22. package/lib/module/components/swipe/index.js +140 -5
  23. package/lib/module/components/swipe/index.js.map +1 -1
  24. package/lib/module/components/tabs/index.js +94 -18
  25. package/lib/module/components/tabs/index.js.map +1 -1
  26. package/lib/module/components/time-picker/index.js +34 -6
  27. package/lib/module/components/time-picker/index.js.map +1 -1
  28. package/lib/module/components/tree/index.js +500 -0
  29. package/lib/module/components/tree/index.js.map +1 -0
  30. package/lib/module/icons/index.js +246 -0
  31. package/lib/module/icons/index.js.map +1 -1
  32. package/lib/module/index.js +8 -2
  33. package/lib/module/index.js.map +1 -1
  34. package/lib/module/utils/haptics.js +19 -0
  35. package/lib/module/utils/haptics.js.map +1 -1
  36. package/lib/typescript/src/components/accordion/index.d.ts +21 -0
  37. package/lib/typescript/src/components/accordion/index.d.ts.map +1 -1
  38. package/lib/typescript/src/components/button/index.d.ts +21 -0
  39. package/lib/typescript/src/components/button/index.d.ts.map +1 -1
  40. package/lib/typescript/src/components/button-group/index.d.ts +212 -0
  41. package/lib/typescript/src/components/button-group/index.d.ts.map +1 -0
  42. package/lib/typescript/src/components/color-picker/index.d.ts +82 -1
  43. package/lib/typescript/src/components/color-picker/index.d.ts.map +1 -1
  44. package/lib/typescript/src/components/date-time-picker/index.d.ts +7 -1
  45. package/lib/typescript/src/components/date-time-picker/index.d.ts.map +1 -1
  46. package/lib/typescript/src/components/fab/index.d.ts +285 -0
  47. package/lib/typescript/src/components/fab/index.d.ts.map +1 -0
  48. package/lib/typescript/src/components/markdown-editor/index.d.ts +102 -0
  49. package/lib/typescript/src/components/markdown-editor/index.d.ts.map +1 -0
  50. package/lib/typescript/src/components/markdown-editor/markdown-transforms.d.ts +76 -0
  51. package/lib/typescript/src/components/markdown-editor/markdown-transforms.d.ts.map +1 -0
  52. package/lib/typescript/src/components/questionnaire/index.d.ts +336 -0
  53. package/lib/typescript/src/components/questionnaire/index.d.ts.map +1 -0
  54. package/lib/typescript/src/components/sortable/index.d.ts +238 -0
  55. package/lib/typescript/src/components/sortable/index.d.ts.map +1 -0
  56. package/lib/typescript/src/components/swipe/index.d.ts +35 -0
  57. package/lib/typescript/src/components/swipe/index.d.ts.map +1 -1
  58. package/lib/typescript/src/components/tabs/index.d.ts +9 -0
  59. package/lib/typescript/src/components/tabs/index.d.ts.map +1 -1
  60. package/lib/typescript/src/components/time-picker/index.d.ts +19 -1
  61. package/lib/typescript/src/components/time-picker/index.d.ts.map +1 -1
  62. package/lib/typescript/src/components/tree/index.d.ts +125 -0
  63. package/lib/typescript/src/components/tree/index.d.ts.map +1 -0
  64. package/lib/typescript/src/icons/index.d.ts +30 -0
  65. package/lib/typescript/src/icons/index.d.ts.map +1 -1
  66. package/lib/typescript/src/index.d.ts +10 -4
  67. package/lib/typescript/src/index.d.ts.map +1 -1
  68. package/lib/typescript/src/utils/haptics.d.ts +14 -0
  69. package/lib/typescript/src/utils/haptics.d.ts.map +1 -1
  70. package/package.json +1 -1
  71. package/src/components/accordion/index.tsx +48 -6
  72. package/src/components/button/index.tsx +97 -15
  73. package/src/components/button-group/index.tsx +199 -0
  74. package/src/components/color-picker/index.tsx +140 -3
  75. package/src/components/date-time-picker/index.tsx +39 -3
  76. package/src/components/fab/index.tsx +583 -0
  77. package/src/components/markdown-editor/index.tsx +526 -0
  78. package/src/components/markdown-editor/markdown-transforms.ts +228 -0
  79. package/src/components/questionnaire/index.tsx +1615 -0
  80. package/src/components/sortable/index.tsx +1080 -0
  81. package/src/components/swipe/index.tsx +165 -3
  82. package/src/components/tabs/index.tsx +100 -28
  83. package/src/components/time-picker/index.tsx +42 -6
  84. package/src/components/tree/index.tsx +564 -0
  85. package/src/icons/index.tsx +176 -0
  86. package/src/index.ts +89 -1
  87. package/src/utils/haptics.ts +21 -0
@@ -0,0 +1,336 @@
1
+ /**
2
+ * Questionnaire — one question at a time, with progress, validation and a way
3
+ * back.
4
+ *
5
+ * Unlike `Steps`, which reflects a flow the app owns, Questionnaire *owns* the
6
+ * flow: it holds the answers, decides which question is current, gates the way
7
+ * forward on the current one being answered, and reports the whole set back
8
+ * when it is done. The caller supplies the questions and does something with
9
+ * the answers; everything between those two points belongs here.
10
+ *
11
+ * ```tsx
12
+ * <Questionnaire items={items} onSubmit={(answers) => save(answers)}>
13
+ * <Questionnaire.Title>Project setup</Questionnaire.Title>
14
+ * <Questionnaire.Progress />
15
+ * <Questionnaire.Item name="direction" required>
16
+ * <Questionnaire.Question>What should we build next?</Questionnaire.Question>
17
+ * <Questionnaire.Description>Choose one, or write your own.</Questionnaire.Description>
18
+ * <Questionnaire.Choices>
19
+ * <Questionnaire.Choice value="delegation" label="Delegation" />
20
+ * <Questionnaire.Choice value="prompts" label="Question prompts" />
21
+ * <Questionnaire.Input placeholder="Type another answer…" />
22
+ * </Questionnaire.Choices>
23
+ * <Questionnaire.Error />
24
+ * </Questionnaire.Item>
25
+ * <Questionnaire.Footer>
26
+ * <Questionnaire.Back />
27
+ * <Questionnaire.Next />
28
+ * <Questionnaire.Submit />
29
+ * </Questionnaire.Footer>
30
+ * </Questionnaire>
31
+ * ```
32
+ *
33
+ * ## Why it draws its own Frame
34
+ *
35
+ * A survey is a widget, not a paragraph: it wants a boundary, a title strip and
36
+ * a footer that stays put while the middle changes. That is exactly `Frame`, so
37
+ * the root renders one rather than leaving every caller to assemble the same
38
+ * shell. `Frame.Panel`'s `overflow-hidden` also does the clipping the sliding
39
+ * question needs, for free. Pass `frame={false}` to drop it — for a
40
+ * questionnaire inside a `BottomSheet` or a card that already draws a border.
41
+ *
42
+ * ## Why the root reads its children instead of collecting registrations
43
+ *
44
+ * Only the active question is mounted, so an unmounted one cannot report that
45
+ * it exists — and without knowing the full set there is no total to count
46
+ * against, no "is this the last one", and no way to disable a question the
47
+ * user has not reached. So the root inspects its children once per render and
48
+ * reads `name`, `required`, `multiple` and `disabled` straight off the
49
+ * elements. React elements carry their props before anything renders them,
50
+ * which makes the whole set knowable without mounting any of it.
51
+ *
52
+ * That same pass sorts the parts into the shell: the title and progress go to
53
+ * the header strip, the footer to a section at the bottom of the panel, and
54
+ * everything else is a question.
55
+ *
56
+ * ## Answers are one record, the way a form would submit them
57
+ *
58
+ * `answers[name]` is a string for a single-answer question and an array for a
59
+ * `multiple` one. A freeform answer lands under the same name — it is another
60
+ * answer to the same question, not a separate field — which is why the text
61
+ * input shows whatever value does not match one of the question's own choices.
62
+ * Picking a choice and typing therefore replace each other, without either one
63
+ * having to know the other exists.
64
+ *
65
+ * ## What blocks the way forward
66
+ *
67
+ * A required question blocks until it has an answer. An optional one never
68
+ * blocks. `Questionnaire.Skip` does not unblock anything, then — it *records*
69
+ * that the question was deliberately left out, moving its status from
70
+ * `unanswered` to `skipped` so the app can tell the two apart. Making an
71
+ * optional question demand an explicit skip would trap anyone who did not
72
+ * render the Skip button, and a question that cannot be ignored is not
73
+ * optional.
74
+ */
75
+ import { type ReactNode } from 'react';
76
+ import { View, type TextInput, type ViewProps } from 'react-native';
77
+ import { type ButtonProps } from '../button/index.js';
78
+ import { type InputProps } from '../input/index.js';
79
+ /** Where a question stands: never touched, answered, or deliberately left out. */
80
+ export type QuestionnaireItemStatus = 'unanswered' | 'answered' | 'skipped';
81
+ /** Which key each answer is badged with. */
82
+ export type QuestionnaireShortcutMode = 'letters' | 'numbers';
83
+ /** Every answer given so far, keyed by question name. */
84
+ export type QuestionnaireAnswers = Record<string, string | string[]>;
85
+ /**
86
+ * A question, described rather than rendered. Pass these as `items` so the
87
+ * questionnaire knows its full set before any of it mounts — which is what
88
+ * makes a conditional question countable and a total meaningful.
89
+ */
90
+ export interface QuestionnaireItemDefinition {
91
+ /** Unique name — the key this question's answer is stored under. */
92
+ name: string;
93
+ /** Blocks the way forward until it has an answer. */
94
+ required?: boolean;
95
+ /** Accepts more than one answer, so its answer is an array. */
96
+ multiple?: boolean;
97
+ /** Left out of the count and never navigated to. */
98
+ disabled?: boolean;
99
+ }
100
+ export interface QuestionnaireProps extends Omit<ViewProps, 'children'> {
101
+ className?: string;
102
+ /**
103
+ * The full set of questions, in order. Optional: without it the order and
104
+ * the totals come from the `Questionnaire.Item` children instead. Pass it
105
+ * when a question is conditional, since a question the user has not reached
106
+ * still has to be counted — or not counted, if it no longer applies.
107
+ */
108
+ items?: readonly QuestionnaireItemDefinition[];
109
+ /** Controlled active question, by name. */
110
+ item?: string;
111
+ /** Which question to open on. Defaults to the first enabled one. */
112
+ defaultItem?: string;
113
+ /** Called with the name of the question being moved to. */
114
+ onItemChange?: (name: string) => void;
115
+ /** Controlled answers. */
116
+ answers?: QuestionnaireAnswers;
117
+ /** Answers to start with — for resuming a part-finished questionnaire. */
118
+ defaultAnswers?: QuestionnaireAnswers;
119
+ /** Called with the whole set every time any answer changes. */
120
+ onAnswersChange?: (answers: QuestionnaireAnswers) => void;
121
+ /** Called with every answer once the last question validates. */
122
+ onSubmit?: (answers: QuestionnaireAnswers) => void;
123
+ /**
124
+ * Badge every answer with a letter (`A`, `B`, `C`) or a number (`1`, `2`,
125
+ * `3`). Disabled answers are skipped rather than taking a badge with them.
126
+ *
127
+ * The badge is an affordance, not a binding: React Native surfaces hardware
128
+ * key events only to a focused text field, so nothing here can listen for
129
+ * the key itself.
130
+ */
131
+ shortcuts?: QuestionnaireShortcutMode;
132
+ /**
133
+ * Let a horizontal drag move between questions. Going forward is gated on
134
+ * the same answer the button is, so a swipe off an unanswered required
135
+ * question springs back and shows its error.
136
+ */
137
+ swipeable?: boolean;
138
+ /**
139
+ * Draw the surrounding `Frame`. Turn it off to place the questionnaire in a
140
+ * sheet, a dialog or a card that already draws its own boundary.
141
+ */
142
+ frame?: boolean;
143
+ children?: ReactNode;
144
+ }
145
+ declare function QuestionnaireRoot({ className, items, item: itemProp, defaultItem, onItemChange, answers: answersProp, defaultAnswers, onAnswersChange, onSubmit, shortcuts, swipeable, frame, children, ...props }: QuestionnaireProps): import("react").JSX.Element;
146
+ declare namespace QuestionnaireRoot {
147
+ var displayName: string;
148
+ }
149
+ export interface QuestionnaireTitleProps extends ViewProps {
150
+ className?: string;
151
+ children?: ReactNode;
152
+ }
153
+ /**
154
+ * Names the questionnaire as a whole, in the frame's header strip. The
155
+ * current question's own prompt is `Questionnaire.Question`.
156
+ */
157
+ declare function QuestionnaireTitle({ className, children, ...props }: QuestionnaireTitleProps): import("react").JSX.Element;
158
+ declare namespace QuestionnaireTitle {
159
+ var displayName: string;
160
+ }
161
+ /** What a custom progress indicator is told about where the reader is. */
162
+ export interface QuestionnaireProgressState {
163
+ /** One-based position of the active question. */
164
+ current: number;
165
+ /** How many questions are enabled. */
166
+ total: number;
167
+ first: boolean;
168
+ last: boolean;
169
+ }
170
+ /** How the position is drawn. */
171
+ export type QuestionnaireProgressVariant = 'pips' | 'numbers' | 'count';
172
+ export interface QuestionnaireProgressProps {
173
+ className?: string;
174
+ /**
175
+ * `pips` is a bar per question, filled up to the one being asked and widened
176
+ * on it. `numbers` counts them out instead, which is what you want when the
177
+ * reader will be sent back to a particular question. `count` is the plain
178
+ * `Question 2 of 5`.
179
+ *
180
+ * `pips` and `numbers` fall back to `count` past eight questions, where
181
+ * neither is countable at a glance any more.
182
+ */
183
+ variant?: QuestionnaireProgressVariant;
184
+ /**
185
+ * Replace the indicator entirely. Given a function, it is called with the
186
+ * position — for a bar, a row of dots, or a percentage.
187
+ */
188
+ children?: ReactNode | ((state: QuestionnaireProgressState) => ReactNode);
189
+ }
190
+ /** Where the reader is in the set, announced as a progress bar. */
191
+ declare function QuestionnaireProgress({ className, variant, children, }: QuestionnaireProgressProps): import("react").JSX.Element;
192
+ declare namespace QuestionnaireProgress {
193
+ var displayName: string;
194
+ }
195
+ export interface QuestionnaireItemProps extends Omit<ViewProps, 'children'> {
196
+ className?: string;
197
+ /** Unique name — the key this question's answer is stored under. */
198
+ name: string;
199
+ /** Blocks the way forward until it has an answer. */
200
+ required?: boolean;
201
+ /** Accepts more than one answer, so its answer is an array. */
202
+ multiple?: boolean;
203
+ /** Left out of the count and never navigated to. */
204
+ disabled?: boolean;
205
+ /** Mark the question at fault from a validator of your own. */
206
+ invalid?: boolean;
207
+ /** Called whenever this question moves between unanswered, answered and skipped. */
208
+ onStatusChange?: (status: QuestionnaireItemStatus) => void;
209
+ children?: ReactNode;
210
+ }
211
+ /**
212
+ * One question. Only the active one is mounted, so anything it holds is built
213
+ * when it is reached and thrown away when it is left.
214
+ */
215
+ declare function QuestionnaireItem({ className, name, required, multiple, invalid: invalidProp, children, disabled: _disabled, onStatusChange: _onStatusChange, ...props }: QuestionnaireItemProps): import("react").JSX.Element;
216
+ declare namespace QuestionnaireItem {
217
+ var displayName: string;
218
+ }
219
+ export interface QuestionnaireQuestionProps extends ViewProps {
220
+ className?: string;
221
+ children?: ReactNode;
222
+ }
223
+ /** The question being asked. */
224
+ declare function QuestionnaireQuestion({ className, children, ...props }: QuestionnaireQuestionProps): import("react").JSX.Element;
225
+ declare namespace QuestionnaireQuestion {
226
+ var displayName: string;
227
+ }
228
+ export interface QuestionnaireDescriptionProps extends ViewProps {
229
+ className?: string;
230
+ children?: ReactNode;
231
+ }
232
+ /** A line under the question — what to consider, or that it can be skipped. */
233
+ declare function QuestionnaireDescription({ className, children, ...props }: QuestionnaireDescriptionProps): import("react").JSX.Element;
234
+ declare namespace QuestionnaireDescription {
235
+ var displayName: string;
236
+ }
237
+ export interface QuestionnaireChoicesProps extends Omit<ViewProps, 'children'> {
238
+ className?: string;
239
+ children?: ReactNode;
240
+ }
241
+ /**
242
+ * The answers to a question. It hands each choice its shortcut badge, counting
243
+ * only the ones that can be picked so a disabled answer does not take a letter
244
+ * out of the sequence with it.
245
+ */
246
+ declare function QuestionnaireChoices({ className, children, ...props }: QuestionnaireChoicesProps): import("react").JSX.Element;
247
+ declare namespace QuestionnaireChoices {
248
+ var displayName: string;
249
+ }
250
+ export interface QuestionnaireChoiceProps {
251
+ className?: string;
252
+ /** The value recorded when this answer is picked. */
253
+ value: string;
254
+ /** The answer itself. */
255
+ label?: string;
256
+ /** A line under the label, for an answer that needs explaining. */
257
+ description?: string;
258
+ disabled?: boolean;
259
+ children?: ReactNode;
260
+ }
261
+ export interface QuestionnaireInputProps extends Omit<InputProps, 'value' | 'onChangeText' | 'errorMessage'> {
262
+ className?: string;
263
+ }
264
+ export interface QuestionnaireErrorProps extends ViewProps {
265
+ className?: string;
266
+ /** Replace the default message. */
267
+ children?: ReactNode;
268
+ }
269
+ /** Why the way forward is closed. Nothing until the question fails to pass. */
270
+ declare function QuestionnaireError({ className, children, ...props }: QuestionnaireErrorProps): import("react").JSX.Element | null;
271
+ declare namespace QuestionnaireError {
272
+ var displayName: string;
273
+ }
274
+ export interface QuestionnaireFooterProps extends ViewProps {
275
+ className?: string;
276
+ children?: ReactNode;
277
+ }
278
+ /**
279
+ * The action row, in its own section at the foot of the panel. It stays put
280
+ * while the question above it changes, which is what keeps the button under
281
+ * the thumb where it was.
282
+ */
283
+ declare function QuestionnaireFooter({ className, children, ...props }: QuestionnaireFooterProps): import("react").JSX.Element;
284
+ declare namespace QuestionnaireFooter {
285
+ var displayName: string;
286
+ }
287
+ /** What a navigation button is told about the question it is acting on. */
288
+ export interface QuestionnaireActionState {
289
+ /** Whether the action applies to the active question at all. */
290
+ visible: boolean;
291
+ /** Where the active question stands. */
292
+ status: QuestionnaireItemStatus;
293
+ }
294
+ export interface QuestionnaireActionProps extends Omit<ButtonProps, 'children'> {
295
+ /** Replace the label. Given a function, it is called with the question's state. */
296
+ children?: ReactNode | ((state: QuestionnaireActionState) => ReactNode);
297
+ }
298
+ /**
299
+ * A flexible gap for the footer, so the trailing buttons sit against the
300
+ * trailing edge whether or not `Questionnaire.Back` is showing.
301
+ */
302
+ declare function QuestionnaireSpacer({ className, ...props }: ViewProps): import("react").JSX.Element;
303
+ declare namespace QuestionnaireSpacer {
304
+ var displayName: string;
305
+ }
306
+ export declare const Questionnaire: typeof QuestionnaireRoot & {
307
+ Title: typeof QuestionnaireTitle;
308
+ Progress: typeof QuestionnaireProgress;
309
+ Item: typeof QuestionnaireItem;
310
+ Question: typeof QuestionnaireQuestion;
311
+ Description: typeof QuestionnaireDescription;
312
+ Choices: typeof QuestionnaireChoices;
313
+ Choice: import("react").ForwardRefExoticComponent<QuestionnaireChoiceProps & import("react").RefAttributes<View>>;
314
+ Input: import("react").ForwardRefExoticComponent<QuestionnaireInputProps & import("react").RefAttributes<TextInput>>;
315
+ Error: typeof QuestionnaireError;
316
+ Footer: typeof QuestionnaireFooter;
317
+ Spacer: typeof QuestionnaireSpacer;
318
+ Back: {
319
+ ({ children, variant, className, ...props }: QuestionnaireActionProps): import("react").JSX.Element | null;
320
+ displayName: string;
321
+ };
322
+ Skip: {
323
+ ({ children, variant, className, ...props }: QuestionnaireActionProps): import("react").JSX.Element | null;
324
+ displayName: string;
325
+ };
326
+ Next: {
327
+ ({ children, variant, className, ...props }: QuestionnaireActionProps): import("react").JSX.Element | null;
328
+ displayName: string;
329
+ };
330
+ Submit: {
331
+ ({ children, variant, className, ...props }: QuestionnaireActionProps): import("react").JSX.Element | null;
332
+ displayName: string;
333
+ };
334
+ };
335
+ export {};
336
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/questionnaire/index.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Sortable — a list whose rows can be dragged into a different order.
3
+ *
4
+ * The one list interaction nothing else in the library covers. `Swipe` acts on
5
+ * a row, `Tree` opens one, `Table` sorts every row at once by a column — none
6
+ * of them let a person say *this one goes above that one*, which is how a
7
+ * playlist, a task list, a set of form fields or a run of dashboard tiles is
8
+ * actually arranged.
9
+ *
10
+ * ```tsx
11
+ * const [tasks, setTasks] = useState(TASKS);
12
+ *
13
+ * <Sortable
14
+ * value={tasks.map((task) => task.id)}
15
+ * onReorder={(_, { from, to }) => setTasks((t) => reorderItems(t, from, to))}
16
+ * gap={8}
17
+ * >
18
+ * {tasks.map((task) => (
19
+ * <Sortable.Item key={task.id} id={task.id}>
20
+ * <Item variant="outline">
21
+ * <Item.Content>
22
+ * <Item.Title>{task.title}</Item.Title>
23
+ * </Item.Content>
24
+ * <Sortable.Handle />
25
+ * </Item>
26
+ * </Sortable.Item>
27
+ * ))}
28
+ * </Sortable>
29
+ * ```
30
+ *
31
+ * ## Nothing is ever moved in the tree
32
+ *
33
+ * The rows stay exactly where they were laid out and are pushed around with
34
+ * transforms. A row's offset is the difference between where its slot sits in
35
+ * the order being dragged and where it sits in the order that was rendered —
36
+ * one subtraction, on the UI thread, per row per frame. Reordering the
37
+ * children instead would mean React reconciling the whole list on every slot
38
+ * the finger crosses, which is the one thing a drag cannot afford.
39
+ *
40
+ * It also means the component never owns the order. It reports where a row was
41
+ * dropped and the list is the caller's to rearrange, because the caller is the
42
+ * only one who knows what the ids stand for — a `value` that disagreed with
43
+ * the children would put rows in places their content had not moved to.
44
+ *
45
+ * ## Heights are measured, not assumed
46
+ *
47
+ * Every row reports its own height, so a list of rows of different sizes lands
48
+ * in the right slots. A fixed row height would be one number to get wrong in
49
+ * every list that has a two-line row in it, and the measurement costs one
50
+ * layout pass on mount.
51
+ *
52
+ * ## Where the drop is reported
53
+ *
54
+ * `onReorder` fires when the row has finished settling, not when the finger
55
+ * lifts. Between those two moments the row is animating into a slot that the
56
+ * layout does not know about yet; re-rendering the list in the middle of that
57
+ * would relayout every row underneath it and the settling row would jump. By
58
+ * the time the callback runs the rows are already where the new order puts
59
+ * them, so the re-render that follows changes nothing on screen.
60
+ */
61
+ import { type ReactNode } from 'react';
62
+ import { type ViewProps } from 'react-native';
63
+ import Animated, { type AnimatedRef } from 'react-native-reanimated';
64
+ /** What starts a drag. */
65
+ export type SortableActivation = 'handle' | 'longPress';
66
+ /** Where a row ended up, alongside the order it produced. */
67
+ export interface SortableReorderDetails {
68
+ /** The row that was dragged. */
69
+ id: string;
70
+ /** Its index before the drag. */
71
+ from: number;
72
+ /** Its index after it. */
73
+ to: number;
74
+ }
75
+ /**
76
+ * The same move applied to a list of your own.
77
+ *
78
+ * `onReorder` hands back the new order of the ids, but a list is rarely a list
79
+ * of ids — it is a list of the things they name. This does the move on that
80
+ * list, and returns a new array rather than sorting in place, because the one
81
+ * that mutated would be the one React had already decided was unchanged.
82
+ *
83
+ * ```tsx
84
+ * onReorder={(_, { from, to }) => setTasks((tasks) => reorderItems(tasks, from, to))}
85
+ * ```
86
+ *
87
+ * Indices outside the list are returned unchanged rather than throwing: a
88
+ * reorder is not worth crashing a screen over, and a list that did not move is
89
+ * the honest result of a move that had nowhere to go.
90
+ */
91
+ export declare function reorderItems<T>(items: readonly T[], from: number, to: number): T[];
92
+ /**
93
+ * What the row being rendered knows about itself.
94
+ *
95
+ * For a handle of your own, or for a row that looks different while it is
96
+ * being carried — dimmed neighbours, a border, a shadow. `isActive` is a plain
97
+ * boolean and changes twice in a drag rather than sixty times a second: it is
98
+ * set when the row is lifted and cleared when it lands, and nothing between
99
+ * those two moments touches React at all.
100
+ */
101
+ export declare function useSortableItem(): {
102
+ id: string;
103
+ index: number;
104
+ isActive: boolean;
105
+ disabled: boolean;
106
+ };
107
+ export interface SortableProps extends Omit<ViewProps, 'children'> {
108
+ className?: string;
109
+ /**
110
+ * The ids of the rows, in the order they are rendered below. It is the
111
+ * caller's array rather than the component's, because only the caller knows
112
+ * what an id stands for — an order held here that disagreed with the
113
+ * children would put rows in places their content had not moved to.
114
+ */
115
+ value: string[];
116
+ /**
117
+ * The rows, one `Sortable.Item` per id in `value` and in the same order.
118
+ * They may be wrapped in anything; each row registers itself.
119
+ */
120
+ children?: ReactNode;
121
+ /**
122
+ * Told the new order once the dropped row has settled, and where it came
123
+ * from and went. Rearrange your own list from `details` — `reorderItems`
124
+ * does exactly this move.
125
+ */
126
+ onReorder?: (order: string[], details: SortableReorderDetails) => void;
127
+ /**
128
+ * Space between rows, in points. A prop rather than a `gap` class because
129
+ * the drag has to know it: the slot a row lands in is measured, and a gap
130
+ * the component cannot read is a gap it drops rows into the middle of.
131
+ */
132
+ gap?: number;
133
+ /**
134
+ * What lifts a row. `handle` is the default and the safer one — the rest of
135
+ * the row stays free to be pressed, and a list of rows with buttons on them
136
+ * still works. `longPress` gives the whole row to the drag.
137
+ */
138
+ activation?: SortableActivation;
139
+ /** How long `longPress` activation waits, in milliseconds. */
140
+ longPressDelay?: number;
141
+ /**
142
+ * Knock when a row is lifted, tick as it passes each slot. On by default:
143
+ * a drag with no feedback under the finger is the interaction people give up
144
+ * on halfway through, unsure whether anything is happening.
145
+ */
146
+ haptics?: boolean;
147
+ /** Turn every row's drag off and leave the list static. */
148
+ disabled?: boolean;
149
+ /**
150
+ * The scroller the list sits in, from `useAnimatedRef`. Given one, a drag
151
+ * carried to the top or bottom edge scrolls it, so a list longer than the
152
+ * screen can be reordered end to end. Without it a drag stops at the edge,
153
+ * which is correct for a list that fits.
154
+ */
155
+ scrollRef?: AnimatedRef<Animated.ScrollView>;
156
+ /** Points from the scroller's edge at which the scrolling begins. */
157
+ autoscrollThreshold?: number;
158
+ /** Points per frame at the very edge, tapering to nothing at the threshold. */
159
+ autoscrollSpeed?: number;
160
+ /** Told which row was lifted, the moment it is. */
161
+ onDragStart?: (id: string) => void;
162
+ /** Told when it lands, whether or not the order changed. */
163
+ onDragEnd?: (id: string) => void;
164
+ }
165
+ /**
166
+ * The list, and everything the rows share.
167
+ *
168
+ * It renders one plain `View` in a column and nothing else. The rows are the
169
+ * caller's, laid out by flexbox in the order they were written; the component
170
+ * only ever adds a transform to them.
171
+ */
172
+ declare function SortableRoot({ className, value, children, onReorder, gap, activation, longPressDelay, haptics, disabled, scrollRef, autoscrollThreshold, autoscrollSpeed, onDragStart, onDragEnd, ...props }: SortableProps): import("react").JSX.Element;
173
+ declare namespace SortableRoot {
174
+ var displayName: string;
175
+ }
176
+ export interface SortableItemProps extends Omit<ViewProps, 'children'> {
177
+ className?: string;
178
+ /**
179
+ * What this row is, and the id that appears in `value` and in the order
180
+ * handed back. Stable across renders — an id derived from the index changes
181
+ * the moment the list is reordered, and the rows lose track of themselves.
182
+ */
183
+ id: string;
184
+ children?: ReactNode;
185
+ /**
186
+ * Stop this row being picked up. The others still move past it, because a
187
+ * row that cannot be dragged is not the same as a row that cannot be
188
+ * displaced — a pinned row is a different feature, and pretending this one
189
+ * is it would mean silently refusing drops that look like they worked.
190
+ */
191
+ disabled?: boolean;
192
+ /**
193
+ * Extra classes for the row while it is being carried, applied last. A
194
+ * lifted row is given an opaque surface and a shadow so it is never drawn
195
+ * see-through over the rows it is passing; this is what overrides that.
196
+ */
197
+ activeClassName?: string;
198
+ }
199
+ /**
200
+ * One row.
201
+ *
202
+ * It measures itself, carries its own transform, and holds the pan — which is
203
+ * either wrapped around the whole row or handed to a `Sortable.Handle` inside
204
+ * it, depending on what lifts a row in this list.
205
+ */
206
+ declare function SortableItem({ className, activeClassName, id, children, disabled, ...props }: SortableItemProps): import("react").JSX.Element;
207
+ declare namespace SortableItem {
208
+ var displayName: string;
209
+ }
210
+ export interface SortableHandleProps extends Omit<ViewProps, 'children'> {
211
+ className?: string;
212
+ /** Replaces the grip glyph. Anything at all — the drag is on the box. */
213
+ children?: ReactNode;
214
+ /** What a screen reader calls the grip. */
215
+ accessibilityLabel?: string;
216
+ }
217
+ /**
218
+ * The part of a row that lifts it.
219
+ *
220
+ * A grip exists so the rest of the row does not have to be given up to the
221
+ * drag: a row with a button, a checkbox or a link on it needs those to stay
222
+ * pressable, and a long press on the whole row takes all of them. It is sized
223
+ * to be hit rather than to be seen, which is why the box around the glyph is
224
+ * larger than the glyph.
225
+ *
226
+ * Inert in a list that lifts on a long press — the whole row already carries
227
+ * the gesture there, and a second one inside it would fight the first.
228
+ */
229
+ declare function SortableHandle({ className, children, accessibilityLabel, ...props }: SortableHandleProps): import("react").JSX.Element;
230
+ declare namespace SortableHandle {
231
+ var displayName: string;
232
+ }
233
+ export declare const Sortable: typeof SortableRoot & {
234
+ Item: typeof SortableItem;
235
+ Handle: typeof SortableHandle;
236
+ };
237
+ export {};
238
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/sortable/index.tsx"],"names":[],"mappings":"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"}
@@ -27,6 +27,11 @@
27
27
  *
28
28
  * Everything that moves runs on the UI thread. A row being dragged does not
29
29
  * re-render — the only React work in a swipe is the callback at the end of it.
30
+ *
31
+ * Rows in a `Swipe.Group` close each other, so only one of them is ever open.
32
+ * That is the behaviour of every list on the phone that has this gesture, and
33
+ * a row cannot arrange it alone: it knows when it opens and has no way to hear
34
+ * that a sibling did.
30
35
  */
31
36
  import { type ReactNode } from 'react';
32
37
  import { View, type ViewProps } from 'react-native';
@@ -40,6 +45,35 @@ export interface SwipeHandle {
40
45
  /** Put the row back. */
41
46
  close: () => void;
42
47
  }
48
+ export interface SwipeGroupProps extends ViewProps {
49
+ className?: string;
50
+ children?: ReactNode;
51
+ /**
52
+ * Close the other rows when one opens. On by default — that is the whole
53
+ * reason to reach for a group. Turning it off keeps the container and the
54
+ * `useSwipeGroup` handle while letting several rows stand open at once.
55
+ */
56
+ exclusive?: boolean;
57
+ }
58
+ /**
59
+ * Shut every row in the enclosing `Swipe.Group`.
60
+ *
61
+ * The one thing a group knows that a single row cannot: a list that scrolls,
62
+ * navigates away, or has just deleted the row that was open wants all of them
63
+ * put back, and holding a ref to each row to do it by hand is bookkeeping the
64
+ * group is already doing.
65
+ *
66
+ * ```tsx
67
+ * const { closeAll } = useSwipeGroup();
68
+ * <ScrollView onScrollBeginDrag={closeAll}>…</ScrollView>
69
+ * ```
70
+ *
71
+ * Outside a group it is inert rather than an error, so a row that is sometimes
72
+ * grouped and sometimes not does not need two versions of its parent.
73
+ */
74
+ export declare function useSwipeGroup(): {
75
+ closeAll: () => void;
76
+ };
43
77
  /**
44
78
  * A tile is a filled block of colour with its content laid over it, which
45
79
  * settles both halves of how it is coloured:
@@ -198,6 +232,7 @@ export interface SwipeProps extends Omit<ViewProps, 'children'> {
198
232
  contentClassName?: string;
199
233
  }
200
234
  export declare const Swipe: import("react").ForwardRefExoticComponent<SwipeProps & import("react").RefAttributes<SwipeHandle>> & {
235
+ Group: import("react").ForwardRefExoticComponent<SwipeGroupProps & import("react").RefAttributes<View>>;
201
236
  Start: import("react").ForwardRefExoticComponent<SwipePanelProps & import("react").RefAttributes<View>>;
202
237
  End: import("react").ForwardRefExoticComponent<SwipePanelProps & import("react").RefAttributes<View>>;
203
238
  Action: import("react").ForwardRefExoticComponent<SwipeActionProps & import("react").RefAttributes<View>>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/swipe/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAYL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,IAAI,EAA0B,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAU5E,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AA0B1D,KAAK,SAAS,GAAG,OAAO,GAAG,KAAK,CAAC;AAEjC,+DAA+D;AAC/D,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,IAAI,CAAC;AAE7C,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,IAAI,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IAChC,wBAAwB;IACxB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAYD;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CAkBlB,CAAC;AAEH,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,MAAM,GACN,aAAa,CAAC;AAelB,MAAM,WAAW,gBACf,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EACjC,YAAY,CAAC,OAAO,cAAc,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mCAAmC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AA0FD,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AA+CD,MAAM,WAAW,UAAW,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C,wCAAwC;IACxC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAkVD,eAAO,MAAM,KAAK;;;;CAIhB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/swipe/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,EAaL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,IAAI,EAA0B,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAU5E,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AA0B1D,KAAK,SAAS,GAAG,OAAO,GAAG,KAAK,CAAC;AAEjC,+DAA+D;AAC/D,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,IAAI,CAAC;AAE7C,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,IAAI,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IAChC,wBAAwB;IACxB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AA2BD,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AA2ED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,IAAI;IAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;CAAE,CAIxD;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CAkBlB,CAAC;AAEH,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,MAAM,GACN,aAAa,CAAC;AAelB,MAAM,WAAW,gBACf,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EACjC,YAAY,CAAC,OAAO,cAAc,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mCAAmC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AA0FD,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AA+CD,MAAM,WAAW,UAAW,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C,wCAAwC;IACxC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAgXD,eAAO,MAAM,KAAK;;;;;CAKhB,CAAC"}