panelui-native 0.97.0 → 0.98.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.
- package/README.md +1 -0
- package/lib/module/components/stack-card/index.js +1204 -0
- package/lib/module/components/stack-card/index.js.map +1 -0
- package/lib/module/components/stack-card/stack-card-geometry.js +261 -0
- package/lib/module/components/stack-card/stack-card-geometry.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/components/stack-card/index.d.ts +472 -0
- package/lib/typescript/src/components/stack-card/index.d.ts.map +1 -0
- package/lib/typescript/src/components/stack-card/stack-card-geometry.d.ts +126 -0
- package/lib/typescript/src/components/stack-card/stack-card-geometry.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +8 -1
- package/src/components/stack-card/index.tsx +1423 -0
- package/src/components/stack-card/stack-card-geometry.ts +279 -0
- package/src/index.ts +14 -0
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StackCard — a pile of cards, taken one at a time by throwing the top one off.
|
|
3
|
+
*
|
|
4
|
+
* ```tsx
|
|
5
|
+
* <StackCard className="h-[460px]" onSwipe={(direction, index) => decide(people[index], direction)}>
|
|
6
|
+
* <StackCard.Stamp direction="right" color="success">Yes</StackCard.Stamp>
|
|
7
|
+
* <StackCard.Stamp direction="left" color="destructive">No</StackCard.Stamp>
|
|
8
|
+
* {people.map((person) => (
|
|
9
|
+
* <StackCard.Card key={person.id}>
|
|
10
|
+
* <Text>{person.name}</Text>
|
|
11
|
+
* </StackCard.Card>
|
|
12
|
+
* ))}
|
|
13
|
+
* <StackCard.Empty>
|
|
14
|
+
* <Text muted>Nobody left</Text>
|
|
15
|
+
* </StackCard.Empty>
|
|
16
|
+
* </StackCard>
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* For a queue of things each answered with one decision and then gone: a
|
|
20
|
+
* review queue, a set of flashcards, an inbox of suggestions. The gesture is
|
|
21
|
+
* the answer, which is what makes it quicker than a list of rows with buttons
|
|
22
|
+
* on them — and what makes it wrong for anything the reader has to compare,
|
|
23
|
+
* skim or come back to. A deck shows one card and hides the rest.
|
|
24
|
+
*
|
|
25
|
+
* For a run of slides the reader browses rather than disposes of, use
|
|
26
|
+
* [Carousel](../carousel); for one row's actions in a list, [Swipe](../swipe).
|
|
27
|
+
*
|
|
28
|
+
* ## The pile is one drag, read by everything
|
|
29
|
+
*
|
|
30
|
+
* The top card's `x` and `y` are the only values a gesture writes, and every
|
|
31
|
+
* other moving part is derived from them: each stamp fades in on how far the
|
|
32
|
+
* drag has carried the card toward its own direction, and the cards behind
|
|
33
|
+
* climb toward the top position on the furthest of those.
|
|
34
|
+
*
|
|
35
|
+
* That derivation is also what makes a dismissal seamless. By the time the top
|
|
36
|
+
* card has been carried far enough to leave, the second card is already
|
|
37
|
+
* exactly where the top card sits — so when the deck advances there is nothing
|
|
38
|
+
* left for it to move, and no frame in which the pile re-arranges itself.
|
|
39
|
+
*
|
|
40
|
+
* ## The deck moves on the UI thread, and React catches up
|
|
41
|
+
*
|
|
42
|
+
* Which card is on top is held twice: as React state, for what is mounted and
|
|
43
|
+
* for the callbacks, and as a shared value, for what is drawn. A throw is
|
|
44
|
+
* handled entirely on the UI thread — the card leaves on the frame the finger
|
|
45
|
+
* lets go, and once it is off the screen the top card, the offset and the fade
|
|
46
|
+
* all move in one step — and only then is the new index requested from React.
|
|
47
|
+
*
|
|
48
|
+
* Nothing on the screen waits for a render, so a busy JavaScript thread cannot
|
|
49
|
+
* stall a throw or leave a frame where the two halves disagree. What React
|
|
50
|
+
* renders afterwards is kept from showing before the UI thread agrees with it:
|
|
51
|
+
* a stamp is only drawn on the card the UI thread has on top.
|
|
52
|
+
*
|
|
53
|
+
* A controlled deck is still the owner's to decide. An owner that declines the
|
|
54
|
+
* new index gets the card back, flown in from the way it went; one that
|
|
55
|
+
* accepts it sees nothing move at all, because it already has.
|
|
56
|
+
*
|
|
57
|
+
* One card behind the pile's stated depth stays mounted so it can fade in as
|
|
58
|
+
* it takes the last visible place, and one card ahead of the top stays mounted
|
|
59
|
+
* so `undo` has something to fly back in. The rest are unmounted, which is
|
|
60
|
+
* what makes a deck of five hundred cost what a deck of five costs.
|
|
61
|
+
*
|
|
62
|
+
* ## A deck is not reachable by a gesture alone
|
|
63
|
+
*
|
|
64
|
+
* A throw is not available to a screen reader, and neither is a card that can
|
|
65
|
+
* only be answered by throwing it. So the top card publishes an accessibility
|
|
66
|
+
* action for every direction the deck accepts, and `StackCard.Action` renders
|
|
67
|
+
* the same decisions as ordinary buttons — which sighted people reach for too,
|
|
68
|
+
* on the card they are not sure about.
|
|
69
|
+
*/
|
|
70
|
+
import { type ReactNode } from 'react';
|
|
71
|
+
import { View, type ViewProps } from 'react-native';
|
|
72
|
+
import { type SharedValue } from 'react-native-reanimated';
|
|
73
|
+
import { type VariantProps } from 'tailwind-variants';
|
|
74
|
+
import { type StackCardDirection } from './stack-card-geometry.js';
|
|
75
|
+
export type { StackCardDirection } from './stack-card-geometry.js';
|
|
76
|
+
/**
|
|
77
|
+
* The deck's state, for a control that lives outside the pile — a counter, a
|
|
78
|
+
* progress bar, a button in a toolbar.
|
|
79
|
+
*
|
|
80
|
+
* `release` is a shared value running 0 to 1 as the top card is carried toward
|
|
81
|
+
* leaving, so something beside the deck can move with the drag rather than
|
|
82
|
+
* starting a second animation next to it.
|
|
83
|
+
*/
|
|
84
|
+
export declare function useStackCard(): {
|
|
85
|
+
/** How many cards have been answered, which is also the top card's index. */
|
|
86
|
+
index: number;
|
|
87
|
+
/** How many cards the deck was given. */
|
|
88
|
+
count: number;
|
|
89
|
+
/** How many are left, the top one included. */
|
|
90
|
+
remaining: number;
|
|
91
|
+
/** Whether there is a card to bring back. */
|
|
92
|
+
canUndo: boolean;
|
|
93
|
+
release: SharedValue<number>;
|
|
94
|
+
send: (direction: StackCardDirection) => void;
|
|
95
|
+
undo: () => void;
|
|
96
|
+
reset: () => void;
|
|
97
|
+
};
|
|
98
|
+
/** How the cards behind the top one are arranged. */
|
|
99
|
+
export type StackCardLayout = 'stack' | 'fan' | 'flat';
|
|
100
|
+
export interface StackCardHandle {
|
|
101
|
+
/** Send the top card away as though it had been thrown that way. */
|
|
102
|
+
swipe: (direction: StackCardDirection) => void;
|
|
103
|
+
/** Bring the last card back, and with it the decision that removed it. */
|
|
104
|
+
undo: () => void;
|
|
105
|
+
/** Put every card back. */
|
|
106
|
+
reset: () => void;
|
|
107
|
+
}
|
|
108
|
+
export interface StackCardProps extends Omit<ViewProps, 'children'> {
|
|
109
|
+
/**
|
|
110
|
+
* A `StackCard.Card` for each card, plus any of `StackCard.Stamp`,
|
|
111
|
+
* `StackCard.Empty` and `StackCard.Actions`, in any order. Anything else is
|
|
112
|
+
* laid out under the pile.
|
|
113
|
+
*/
|
|
114
|
+
children?: ReactNode;
|
|
115
|
+
/**
|
|
116
|
+
* Which card is on top, when the caller holds it. Leave unset to let the
|
|
117
|
+
* deck keep its own. A controlled deck that declines a request stays where
|
|
118
|
+
* it is and the thrown card comes back, so this is also how a decision is
|
|
119
|
+
* confirmed before it is taken.
|
|
120
|
+
*/
|
|
121
|
+
index?: number;
|
|
122
|
+
/** Which card an uncontrolled deck starts on. */
|
|
123
|
+
defaultIndex?: number;
|
|
124
|
+
/** Fires whenever the deck asks to move, with the index it is asking for. */
|
|
125
|
+
onIndexChange?: (index: number) => void;
|
|
126
|
+
/**
|
|
127
|
+
* Fires when a card leaves, with the way it went and the index it was at.
|
|
128
|
+
* It fires before `onIndexChange` asks for the next index. Not called by
|
|
129
|
+
* `undo` — the index going back is what reports that.
|
|
130
|
+
*/
|
|
131
|
+
onSwipe?: (direction: StackCardDirection, index: number) => void;
|
|
132
|
+
/** Fires once when the last card leaves. */
|
|
133
|
+
onEmpty?: () => void;
|
|
134
|
+
/**
|
|
135
|
+
* Which ways a card may be thrown. Left and right by default.
|
|
136
|
+
*
|
|
137
|
+
* A direction left out still follows the finger a little and then comes
|
|
138
|
+
* back, rather than refusing to move at all — a card that does not budge
|
|
139
|
+
* reads as a frozen screen.
|
|
140
|
+
*/
|
|
141
|
+
directions?: readonly StackCardDirection[];
|
|
142
|
+
/**
|
|
143
|
+
* How the cards behind the top one are arranged. `stack` steps them down and
|
|
144
|
+
* back; `fan` turns them alternately, like a hand of cards; `flat` hides them
|
|
145
|
+
* entirely, for full-bleed cards where a peeking edge is only clutter.
|
|
146
|
+
*/
|
|
147
|
+
layout?: StackCardLayout;
|
|
148
|
+
/** How many cards are drawn behind the top one. Two is a pile; five is a mess. */
|
|
149
|
+
depth?: number;
|
|
150
|
+
/**
|
|
151
|
+
* How far a card has to be taken for a release to send it away, as a
|
|
152
|
+
* fraction of the card. Momentum counts toward it, so a flick clears it
|
|
153
|
+
* without travelling.
|
|
154
|
+
*/
|
|
155
|
+
threshold?: number;
|
|
156
|
+
/** Stop the deck taking a gesture, without changing how it looks. */
|
|
157
|
+
disabled?: boolean;
|
|
158
|
+
/** A tick when a drag first reaches the point of no return, and a knock as the card goes. */
|
|
159
|
+
haptics?: boolean;
|
|
160
|
+
/**
|
|
161
|
+
* What a screen reader is offered for each direction, in place of "Swipe
|
|
162
|
+
* left". Name the decision — `{ left: 'Skip', right: 'Save' }`.
|
|
163
|
+
*/
|
|
164
|
+
directionLabels?: Partial<Record<StackCardDirection, string>>;
|
|
165
|
+
/** Classes for the whole control. Give it a height; the pile fills what is left. */
|
|
166
|
+
className?: string;
|
|
167
|
+
/** Classes for the box the cards are laid out in. */
|
|
168
|
+
pileClassName?: string;
|
|
169
|
+
}
|
|
170
|
+
export interface StackCardCardProps extends ViewProps {
|
|
171
|
+
className?: string;
|
|
172
|
+
children?: ReactNode;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* A stamp is a filled block of colour with a word on it, turned a few degrees
|
|
176
|
+
* so it reads as pressed onto the card rather than laid out on it.
|
|
177
|
+
*
|
|
178
|
+
* The fill is the status colour at full strength rather than a tint of it: a
|
|
179
|
+
* stamp exists only for the moment it appears, and a six-per-cent wash of the
|
|
180
|
+
* card's own surface is a smudge rather than an answer. The word is carried in
|
|
181
|
+
* white, which is what the status colours are chosen to take — a status's
|
|
182
|
+
* `-foreground` token is its darker text form, meant for a neutral surface,
|
|
183
|
+
* and over the fill it is the same hue twice.
|
|
184
|
+
*
|
|
185
|
+
* It sits in the corner the card is being pulled away from, which is also the
|
|
186
|
+
* corner the thumb is not over.
|
|
187
|
+
*/
|
|
188
|
+
declare const stampVariants: import("tailwind-variants").TVReturnType<{
|
|
189
|
+
color: {
|
|
190
|
+
default: {
|
|
191
|
+
pill: string;
|
|
192
|
+
label: string;
|
|
193
|
+
};
|
|
194
|
+
primary: {
|
|
195
|
+
pill: string;
|
|
196
|
+
label: string;
|
|
197
|
+
};
|
|
198
|
+
success: {
|
|
199
|
+
pill: string;
|
|
200
|
+
label: string;
|
|
201
|
+
};
|
|
202
|
+
warning: {
|
|
203
|
+
pill: string;
|
|
204
|
+
label: string;
|
|
205
|
+
};
|
|
206
|
+
info: {
|
|
207
|
+
pill: string;
|
|
208
|
+
label: string;
|
|
209
|
+
};
|
|
210
|
+
destructive: {
|
|
211
|
+
pill: string;
|
|
212
|
+
label: string;
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
direction: {
|
|
216
|
+
left: {
|
|
217
|
+
root: string;
|
|
218
|
+
pill: string;
|
|
219
|
+
};
|
|
220
|
+
right: {
|
|
221
|
+
root: string;
|
|
222
|
+
pill: string;
|
|
223
|
+
};
|
|
224
|
+
up: {
|
|
225
|
+
root: string;
|
|
226
|
+
};
|
|
227
|
+
down: {
|
|
228
|
+
root: string;
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
}, {
|
|
232
|
+
root: string;
|
|
233
|
+
pill: string;
|
|
234
|
+
label: string;
|
|
235
|
+
}, undefined, {
|
|
236
|
+
color: {
|
|
237
|
+
default: {
|
|
238
|
+
pill: string;
|
|
239
|
+
label: string;
|
|
240
|
+
};
|
|
241
|
+
primary: {
|
|
242
|
+
pill: string;
|
|
243
|
+
label: string;
|
|
244
|
+
};
|
|
245
|
+
success: {
|
|
246
|
+
pill: string;
|
|
247
|
+
label: string;
|
|
248
|
+
};
|
|
249
|
+
warning: {
|
|
250
|
+
pill: string;
|
|
251
|
+
label: string;
|
|
252
|
+
};
|
|
253
|
+
info: {
|
|
254
|
+
pill: string;
|
|
255
|
+
label: string;
|
|
256
|
+
};
|
|
257
|
+
destructive: {
|
|
258
|
+
pill: string;
|
|
259
|
+
label: string;
|
|
260
|
+
};
|
|
261
|
+
};
|
|
262
|
+
direction: {
|
|
263
|
+
left: {
|
|
264
|
+
root: string;
|
|
265
|
+
pill: string;
|
|
266
|
+
};
|
|
267
|
+
right: {
|
|
268
|
+
root: string;
|
|
269
|
+
pill: string;
|
|
270
|
+
};
|
|
271
|
+
up: {
|
|
272
|
+
root: string;
|
|
273
|
+
};
|
|
274
|
+
down: {
|
|
275
|
+
root: string;
|
|
276
|
+
};
|
|
277
|
+
};
|
|
278
|
+
}, {
|
|
279
|
+
root: string;
|
|
280
|
+
pill: string;
|
|
281
|
+
label: string;
|
|
282
|
+
}, import("tailwind-variants").TVReturnType<{
|
|
283
|
+
color: {
|
|
284
|
+
default: {
|
|
285
|
+
pill: string;
|
|
286
|
+
label: string;
|
|
287
|
+
};
|
|
288
|
+
primary: {
|
|
289
|
+
pill: string;
|
|
290
|
+
label: string;
|
|
291
|
+
};
|
|
292
|
+
success: {
|
|
293
|
+
pill: string;
|
|
294
|
+
label: string;
|
|
295
|
+
};
|
|
296
|
+
warning: {
|
|
297
|
+
pill: string;
|
|
298
|
+
label: string;
|
|
299
|
+
};
|
|
300
|
+
info: {
|
|
301
|
+
pill: string;
|
|
302
|
+
label: string;
|
|
303
|
+
};
|
|
304
|
+
destructive: {
|
|
305
|
+
pill: string;
|
|
306
|
+
label: string;
|
|
307
|
+
};
|
|
308
|
+
};
|
|
309
|
+
direction: {
|
|
310
|
+
left: {
|
|
311
|
+
root: string;
|
|
312
|
+
pill: string;
|
|
313
|
+
};
|
|
314
|
+
right: {
|
|
315
|
+
root: string;
|
|
316
|
+
pill: string;
|
|
317
|
+
};
|
|
318
|
+
up: {
|
|
319
|
+
root: string;
|
|
320
|
+
};
|
|
321
|
+
down: {
|
|
322
|
+
root: string;
|
|
323
|
+
};
|
|
324
|
+
};
|
|
325
|
+
}, {
|
|
326
|
+
root: string;
|
|
327
|
+
pill: string;
|
|
328
|
+
label: string;
|
|
329
|
+
}, undefined, unknown, unknown, undefined>>;
|
|
330
|
+
export type StackCardStampColor = 'default' | 'primary' | 'success' | 'warning' | 'info' | 'destructive';
|
|
331
|
+
export interface StackCardStampProps extends Omit<ViewProps, 'children'>, VariantProps<typeof stampVariants> {
|
|
332
|
+
className?: string;
|
|
333
|
+
/** The word, or anything else to draw on the stamp. */
|
|
334
|
+
children?: ReactNode;
|
|
335
|
+
/** Which direction the stamp answers for. Also where on the card it goes. */
|
|
336
|
+
direction?: StackCardDirection;
|
|
337
|
+
/** Extra classes for the label, when the stamp is given a string. */
|
|
338
|
+
labelClassName?: string;
|
|
339
|
+
}
|
|
340
|
+
export interface StackCardEmptyProps extends ViewProps {
|
|
341
|
+
className?: string;
|
|
342
|
+
children?: ReactNode;
|
|
343
|
+
}
|
|
344
|
+
export interface StackCardActionsProps extends ViewProps {
|
|
345
|
+
className?: string;
|
|
346
|
+
children?: ReactNode;
|
|
347
|
+
}
|
|
348
|
+
declare const actionVariants: import("tailwind-variants").TVReturnType<{
|
|
349
|
+
color: {
|
|
350
|
+
default: {
|
|
351
|
+
root: string;
|
|
352
|
+
};
|
|
353
|
+
primary: {
|
|
354
|
+
root: string;
|
|
355
|
+
};
|
|
356
|
+
success: {
|
|
357
|
+
root: string;
|
|
358
|
+
};
|
|
359
|
+
warning: {
|
|
360
|
+
root: string;
|
|
361
|
+
};
|
|
362
|
+
info: {
|
|
363
|
+
root: string;
|
|
364
|
+
};
|
|
365
|
+
destructive: {
|
|
366
|
+
root: string;
|
|
367
|
+
};
|
|
368
|
+
};
|
|
369
|
+
size: {
|
|
370
|
+
sm: {
|
|
371
|
+
root: string;
|
|
372
|
+
};
|
|
373
|
+
md: {
|
|
374
|
+
root: string;
|
|
375
|
+
};
|
|
376
|
+
lg: {
|
|
377
|
+
root: string;
|
|
378
|
+
};
|
|
379
|
+
};
|
|
380
|
+
}, {
|
|
381
|
+
root: string;
|
|
382
|
+
}, undefined, {
|
|
383
|
+
color: {
|
|
384
|
+
default: {
|
|
385
|
+
root: string;
|
|
386
|
+
};
|
|
387
|
+
primary: {
|
|
388
|
+
root: string;
|
|
389
|
+
};
|
|
390
|
+
success: {
|
|
391
|
+
root: string;
|
|
392
|
+
};
|
|
393
|
+
warning: {
|
|
394
|
+
root: string;
|
|
395
|
+
};
|
|
396
|
+
info: {
|
|
397
|
+
root: string;
|
|
398
|
+
};
|
|
399
|
+
destructive: {
|
|
400
|
+
root: string;
|
|
401
|
+
};
|
|
402
|
+
};
|
|
403
|
+
size: {
|
|
404
|
+
sm: {
|
|
405
|
+
root: string;
|
|
406
|
+
};
|
|
407
|
+
md: {
|
|
408
|
+
root: string;
|
|
409
|
+
};
|
|
410
|
+
lg: {
|
|
411
|
+
root: string;
|
|
412
|
+
};
|
|
413
|
+
};
|
|
414
|
+
}, {
|
|
415
|
+
root: string;
|
|
416
|
+
}, import("tailwind-variants").TVReturnType<{
|
|
417
|
+
color: {
|
|
418
|
+
default: {
|
|
419
|
+
root: string;
|
|
420
|
+
};
|
|
421
|
+
primary: {
|
|
422
|
+
root: string;
|
|
423
|
+
};
|
|
424
|
+
success: {
|
|
425
|
+
root: string;
|
|
426
|
+
};
|
|
427
|
+
warning: {
|
|
428
|
+
root: string;
|
|
429
|
+
};
|
|
430
|
+
info: {
|
|
431
|
+
root: string;
|
|
432
|
+
};
|
|
433
|
+
destructive: {
|
|
434
|
+
root: string;
|
|
435
|
+
};
|
|
436
|
+
};
|
|
437
|
+
size: {
|
|
438
|
+
sm: {
|
|
439
|
+
root: string;
|
|
440
|
+
};
|
|
441
|
+
md: {
|
|
442
|
+
root: string;
|
|
443
|
+
};
|
|
444
|
+
lg: {
|
|
445
|
+
root: string;
|
|
446
|
+
};
|
|
447
|
+
};
|
|
448
|
+
}, {
|
|
449
|
+
root: string;
|
|
450
|
+
}, undefined, unknown, unknown, undefined>>;
|
|
451
|
+
export interface StackCardActionProps extends Omit<ViewProps, 'children'>, VariantProps<typeof actionVariants> {
|
|
452
|
+
className?: string;
|
|
453
|
+
/** What pressing it does: send the top card that way, or bring the last one back. */
|
|
454
|
+
action: StackCardDirection | 'undo';
|
|
455
|
+
/** The glyph. Sized and tinted by the button — pass neither. */
|
|
456
|
+
icon?: ReactNode;
|
|
457
|
+
/**
|
|
458
|
+
* What a screen reader is offered. Falls back to "Undo", or to the plain
|
|
459
|
+
* name of the direction.
|
|
460
|
+
*/
|
|
461
|
+
label?: string;
|
|
462
|
+
/** Run after the deck has been told, for a sound or a log. */
|
|
463
|
+
onPress?: () => void;
|
|
464
|
+
}
|
|
465
|
+
export declare const StackCard: import("react").ForwardRefExoticComponent<StackCardProps & import("react").RefAttributes<StackCardHandle>> & {
|
|
466
|
+
Card: import("react").ForwardRefExoticComponent<StackCardCardProps & import("react").RefAttributes<View>>;
|
|
467
|
+
Stamp: import("react").ForwardRefExoticComponent<StackCardStampProps & import("react").RefAttributes<View>>;
|
|
468
|
+
Empty: import("react").ForwardRefExoticComponent<StackCardEmptyProps & import("react").RefAttributes<View>>;
|
|
469
|
+
Actions: import("react").ForwardRefExoticComponent<StackCardActionsProps & import("react").RefAttributes<View>>;
|
|
470
|
+
Action: import("react").ForwardRefExoticComponent<StackCardActionProps & import("react").RefAttributes<View>>;
|
|
471
|
+
};
|
|
472
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/stack-card/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The numbers a deck is made of, kept apart from the views that draw them so
|
|
3
|
+
* each rule can be checked on its own.
|
|
4
|
+
*
|
|
5
|
+
* Every function here is a worklet: they run inside the pan handler and the
|
|
6
|
+
* animated styles, on the UI thread, and none of them touches anything but
|
|
7
|
+
* its arguments.
|
|
8
|
+
*/
|
|
9
|
+
/** Which way a card leaves the deck. */
|
|
10
|
+
export type StackCardDirection = 'left' | 'right' | 'up' | 'down';
|
|
11
|
+
/**
|
|
12
|
+
* iOS's scroll deceleration, and the constant behind `project`.
|
|
13
|
+
*
|
|
14
|
+
* Momentum is what lets a short fast flick count and a long slow drag not.
|
|
15
|
+
* Without it the only question a release can answer is how far the finger
|
|
16
|
+
* travelled, and a deck read that way feels heavy in the hand.
|
|
17
|
+
*/
|
|
18
|
+
export declare const DECELERATION = 0.998;
|
|
19
|
+
/**
|
|
20
|
+
* Where a flick would come to rest if it kept decelerating, in points.
|
|
21
|
+
*
|
|
22
|
+
* The exponential-decay form the platform uses, not the `v² / 2a` from
|
|
23
|
+
* physics: the two disagree most at exactly the speeds a thumb produces.
|
|
24
|
+
*/
|
|
25
|
+
export declare function project(velocity: number, deceleration?: number): number;
|
|
26
|
+
/**
|
|
27
|
+
* How far a finger gets on an axis the deck does not accept, given how far it
|
|
28
|
+
* pushed.
|
|
29
|
+
*
|
|
30
|
+
* Asymptotic rather than clamped. A card that stops dead at a limit reads as
|
|
31
|
+
* broken; one that keeps moving a little further for a lot more travel reads
|
|
32
|
+
* as held.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resist(travel: number, span: number, give: number): number;
|
|
35
|
+
/** How far a card has to be taken for a release to send it away, in points. */
|
|
36
|
+
export declare function commitReach(span: number, threshold: number): number;
|
|
37
|
+
/**
|
|
38
|
+
* How far a drag has carried a card toward leaving in one direction, 0 to 1.
|
|
39
|
+
*
|
|
40
|
+
* One number, and three things read it: the stamp for that direction fades in
|
|
41
|
+
* on it, the card behind climbs into place on it, and the haptic fires when it
|
|
42
|
+
* first reaches 1.
|
|
43
|
+
*/
|
|
44
|
+
export declare function directionProgress(direction: StackCardDirection, x: number, y: number, width: number, height: number, threshold: number): number;
|
|
45
|
+
/** The furthest any accepted direction has been carried, 0 to 1. */
|
|
46
|
+
export declare function releaseProgress(allowed: readonly StackCardDirection[], x: number, y: number, width: number, height: number, threshold: number): number;
|
|
47
|
+
/**
|
|
48
|
+
* Which way a lifted finger sent the card, or `null` to put it back.
|
|
49
|
+
*
|
|
50
|
+
* Distance and momentum are added before the comparison rather than tested one
|
|
51
|
+
* after the other, so there is a single rule: a card leaves when the finger
|
|
52
|
+
* was going to take it past the reach, whether it got there or not.
|
|
53
|
+
*
|
|
54
|
+
* Where two directions both qualify — a diagonal fling in a deck that takes
|
|
55
|
+
* all four — the one carried furthest wins, so the card goes where it was
|
|
56
|
+
* actually thrown.
|
|
57
|
+
*/
|
|
58
|
+
export declare function releasedDirection(allowed: readonly StackCardDirection[], x: number, y: number, velocityX: number, velocityY: number, width: number, height: number, threshold: number): StackCardDirection | null;
|
|
59
|
+
/**
|
|
60
|
+
* Where a card is animated to on its way off.
|
|
61
|
+
*
|
|
62
|
+
* The off-axis is carried rather than zeroed, so a card thrown up and to the
|
|
63
|
+
* right leaves up and to the right. Zeroing it straightens the throw out
|
|
64
|
+
* mid-flight, which is the one moment the animation is most obviously not the
|
|
65
|
+
* finger any more.
|
|
66
|
+
*/
|
|
67
|
+
export declare function exitTarget(direction: StackCardDirection, width: number, height: number, x: number, y: number): {
|
|
68
|
+
x: number;
|
|
69
|
+
y: number;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* How long a card takes to leave, in milliseconds.
|
|
73
|
+
*
|
|
74
|
+
* Long enough that the card starts out at the speed the finger let go of it.
|
|
75
|
+
* An ease-out starts `slope` times faster than its average, so covering
|
|
76
|
+
* `distance` from `speed` takes `slope × distance / speed`. Faster than that
|
|
77
|
+
* and the card leaps ahead of the finger; slower, and it drags as though it
|
|
78
|
+
* had caught on something.
|
|
79
|
+
*
|
|
80
|
+
* Clamped both ways. A hard flick would otherwise be gone in a frame or two,
|
|
81
|
+
* which reads as the card vanishing rather than being thrown; and a card
|
|
82
|
+
* released barely moving would drift off for a second. `speed` is only what
|
|
83
|
+
* was travelling toward the way out — none at all, for a card sent by a
|
|
84
|
+
* button, gives the longest.
|
|
85
|
+
*/
|
|
86
|
+
export declare function exitDuration(distance: number, speed: number, slope: number, shortest: number, longest: number): number;
|
|
87
|
+
/**
|
|
88
|
+
* Which way the card pivots, from where it was taken hold of.
|
|
89
|
+
*
|
|
90
|
+
* A card pulled by its top corner turns one way and one pulled by its bottom
|
|
91
|
+
* corner turns the other, because that is what a piece of card on a table
|
|
92
|
+
* does. Read once when the finger lands and held for the whole gesture: a
|
|
93
|
+
* lever that changed sign mid-drag would flip the card over in the hand.
|
|
94
|
+
*/
|
|
95
|
+
export declare function lever(grabY: number, height: number): number;
|
|
96
|
+
/**
|
|
97
|
+
* The card's tilt, in degrees.
|
|
98
|
+
*
|
|
99
|
+
* Measured against half the card rather than all of it: a card commits at
|
|
100
|
+
* roughly a third of its width, and scaled across the full width the tilt at
|
|
101
|
+
* the moment of release would be a couple of degrees — present in the numbers
|
|
102
|
+
* and invisible on the screen.
|
|
103
|
+
*/
|
|
104
|
+
export declare function tiltAngle(x: number, width: number, maxTilt: number, pivot: number): number;
|
|
105
|
+
/**
|
|
106
|
+
* Where a card sits in the pile, counting the top one as 0, once the drag on
|
|
107
|
+
* the card in front of it is taken into account.
|
|
108
|
+
*
|
|
109
|
+
* This is what makes the pile continuous across a dismissal. By the time the
|
|
110
|
+
* top card has been carried far enough to leave, the one behind it has already
|
|
111
|
+
* arrived at the top position — so when it becomes the top card there is
|
|
112
|
+
* nothing left to move.
|
|
113
|
+
*/
|
|
114
|
+
export declare function effectiveDepth(depth: number, release: number): number;
|
|
115
|
+
/**
|
|
116
|
+
* How opaque a card at a given depth is drawn, where `visible` is how many the
|
|
117
|
+
* pile shows behind its top card.
|
|
118
|
+
*
|
|
119
|
+
* One more card is kept than the pile shows, and this is what fades it in: one
|
|
120
|
+
* place further back than the pile goes it is invisible, and it reaches full
|
|
121
|
+
* strength exactly as it takes the last visible place. Without it a card
|
|
122
|
+
* appears out of nothing at the bottom of the pile every time one leaves the
|
|
123
|
+
* top.
|
|
124
|
+
*/
|
|
125
|
+
export declare function depthOpacity(depth: number, visible: number): number;
|
|
126
|
+
//# sourceMappingURL=stack-card-geometry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stack-card-geometry.d.ts","sourceRoot":"","sources":["../../../../../src/components/stack-card/stack-card-geometry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,wCAAwC;AACxC,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC;AAElE;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,QAAQ,CAAC;AAElC;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAcvE;AAED;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAIzE;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGnE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,kBAAkB,EAC7B,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,MAAM,CAOR;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAC7B,OAAO,EAAE,SAAS,kBAAkB,EAAE,EACtC,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,MAAM,CAUR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,SAAS,kBAAkB,EAAE,EACtC,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,kBAAkB,GAAG,IAAI,CAgC3B;AAQD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,kBAAkB,EAC7B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAY1B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,MAAM,CAKR;AAED;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAI3D;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAK1F;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAGrE;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAGnE"}
|
|
@@ -126,6 +126,7 @@ export { Sortable, reorderItems, useSortableItem, type SortableProps, type Sorta
|
|
|
126
126
|
export { Spinner, type SpinnerProps } from './components/spinner/index.js';
|
|
127
127
|
export { Splitter, type SplitterProps, type SplitterPanelProps, type SplitterHandleProps, type SplitterOrientation, type SplitterConstraint, } from './components/splitter/index.js';
|
|
128
128
|
export { SplitView, useSplitView, type SplitViewProps, type SplitViewPaneProps, type SplitViewDragAreaProps, type SplitViewHandleProps, type SplitViewVariant, } from './components/split-view/index.js';
|
|
129
|
+
export { StackCard, useStackCard, type StackCardProps, type StackCardHandle, type StackCardCardProps, type StackCardStampProps, type StackCardEmptyProps, type StackCardActionsProps, type StackCardActionProps, type StackCardDirection, type StackCardLayout, type StackCardStampColor, } from './components/stack-card/index.js';
|
|
129
130
|
export { Steps, type StepsProps, type StepsItemProps, type StepsTriggerProps, type StepsIndicatorProps, type StepsSeparatorProps, type StepState, type StepsOrientation, } from './components/steps/index.js';
|
|
130
131
|
export { Surface, type SurfaceProps } from './components/surface/index.js';
|
|
131
132
|
export { Swipe, useSwipeGroup, type SwipeProps, type SwipeGroupProps, type SwipePanelProps, type SwipeActionProps, type SwipeActionColor, type SwipeOpenSide, type SwipeHandle, } from './components/swipe/index.js';
|