@rtzll/reflow 0.3.0 → 0.5.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/dist/basic.js +3 -8
- package/dist/breadcrumb.css +10 -0
- package/dist/breadcrumb.js +38 -40
- package/dist/compositions.css +3 -3
- package/dist/drawer.css +240 -0
- package/dist/drawer.d.ts +45 -0
- package/dist/drawer.js +228 -0
- package/dist/foundations.css +27 -14
- package/dist/hover-card.d.ts +32 -0
- package/dist/hover-card.js +119 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/overlays.js +14 -2
- package/dist/popover.css +69 -0
- package/dist/popover.d.ts +38 -0
- package/dist/popover.js +57 -0
- package/dist/segmented-control.css +172 -0
- package/dist/segmented-control.d.ts +34 -0
- package/dist/segmented-control.js +38 -0
- package/dist/sidebar.css +14 -57
- package/dist/sidebar.js +9 -13
- package/dist/status-icon.d.ts +3 -0
- package/dist/status-icon.js +7 -0
- package/dist/styles.css +4 -0
- package/dist/systems.js +5 -1
- package/dist/toaster.css +268 -0
- package/dist/toaster.d.ts +79 -0
- package/dist/toaster.js +418 -0
- package/package.json +1 -1
package/dist/toaster.css
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/* Toaster: a pile of toasts fixed to one corner or edge of the viewport.
|
|
2
|
+
The newest toast sits in front; the ones behind peek out and narrow on
|
|
3
|
+
QueuedStack's stacking values. Pointed at or focused, the pile spreads
|
|
4
|
+
out a gap apart. The script writes each toast's depth, height and spread
|
|
5
|
+
offset; the lift turns offsets upward for the bottom positions. */
|
|
6
|
+
.rf-toaster-region {
|
|
7
|
+
display: block;
|
|
8
|
+
outline: none;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.rf-toaster {
|
|
12
|
+
--rf-toaster-offset: 24px;
|
|
13
|
+
--rf-toast-width: 356px;
|
|
14
|
+
--rf-toast-lift: -1;
|
|
15
|
+
position: fixed;
|
|
16
|
+
z-index: 2147483000;
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
inline-size: var(--rf-toast-width);
|
|
19
|
+
max-inline-size: calc(100vw - 2 * var(--rf-toaster-offset));
|
|
20
|
+
block-size: var(--rf-toaster-piled-height, 0px);
|
|
21
|
+
margin: 0;
|
|
22
|
+
padding: 0;
|
|
23
|
+
list-style: none;
|
|
24
|
+
color: var(--rf-fg);
|
|
25
|
+
font: var(--rf-text-body) / var(--rf-leading-body) var(--rf-font);
|
|
26
|
+
-webkit-font-smoothing: antialiased;
|
|
27
|
+
}
|
|
28
|
+
.rf-toaster[data-expanded] {
|
|
29
|
+
block-size: var(--rf-toaster-spread-height, 0px);
|
|
30
|
+
}
|
|
31
|
+
.rf-toaster[data-position^='top'] {
|
|
32
|
+
--rf-toast-lift: 1;
|
|
33
|
+
top: var(--rf-toaster-offset);
|
|
34
|
+
}
|
|
35
|
+
.rf-toaster[data-position^='bottom'] {
|
|
36
|
+
bottom: var(--rf-toaster-offset);
|
|
37
|
+
}
|
|
38
|
+
.rf-toaster[data-position$='left'] {
|
|
39
|
+
left: var(--rf-toaster-offset);
|
|
40
|
+
}
|
|
41
|
+
.rf-toaster[data-position$='right'] {
|
|
42
|
+
right: var(--rf-toaster-offset);
|
|
43
|
+
}
|
|
44
|
+
.rf-toaster[data-position$='center'] {
|
|
45
|
+
left: 50%;
|
|
46
|
+
translate: -50% 0;
|
|
47
|
+
}
|
|
48
|
+
@media (max-width: 600px) {
|
|
49
|
+
.rf-toaster {
|
|
50
|
+
--rf-toaster-offset: 16px;
|
|
51
|
+
inset-inline: var(--rf-toaster-offset);
|
|
52
|
+
inline-size: auto;
|
|
53
|
+
translate: none;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.rf-toast {
|
|
58
|
+
--rf-status-color: var(--rf-fg);
|
|
59
|
+
--rf-toast-y: calc(var(--rf-toast-lift) * var(--rf-toast-depth, 0) * var(--rf-stack-peek));
|
|
60
|
+
position: absolute;
|
|
61
|
+
inset-inline: 0;
|
|
62
|
+
z-index: calc(100 - var(--rf-toast-depth, 0));
|
|
63
|
+
box-sizing: border-box;
|
|
64
|
+
block-size: var(--rf-toast-front-height, auto);
|
|
65
|
+
overflow: hidden;
|
|
66
|
+
border-radius: var(--rf-panel-radius);
|
|
67
|
+
outline: none;
|
|
68
|
+
background: var(--rf-surface-3, white);
|
|
69
|
+
box-shadow:
|
|
70
|
+
inset 0 1px light-dark(transparent, rgb(255 255 255 / 2%)),
|
|
71
|
+
inset 0 0 0 1px light-dark(transparent, rgb(255 255 255 / 2%)),
|
|
72
|
+
0 0 0 1px light-dark(rgb(0 0 0 / 6%), rgb(0 0 0 / 12%)),
|
|
73
|
+
0 1px 1px -0.5px light-dark(rgb(0 0 0 / 6%), rgb(0 0 0 / 18%)),
|
|
74
|
+
0 3px 3px -1.5px light-dark(rgb(0 0 0 / 6%), rgb(0 0 0 / 18%)),
|
|
75
|
+
0 12px 28px light-dark(rgb(0 0 0 / 10%), rgb(0 0 0 / 24%));
|
|
76
|
+
translate: var(--rf-swipe-x, 0px) calc(var(--rf-toast-y) + var(--rf-swipe-y, 0px));
|
|
77
|
+
scale: calc(1 - var(--rf-toast-depth, 0) * var(--rf-stack-scale-step)) 1;
|
|
78
|
+
touch-action: none;
|
|
79
|
+
transition:
|
|
80
|
+
translate var(--rf-spring-moderate),
|
|
81
|
+
scale var(--rf-spring-moderate),
|
|
82
|
+
block-size var(--rf-spring-moderate),
|
|
83
|
+
opacity var(--rf-spring-moderate);
|
|
84
|
+
}
|
|
85
|
+
.rf-toaster[data-position^='top'] > .rf-toast {
|
|
86
|
+
top: 0;
|
|
87
|
+
}
|
|
88
|
+
.rf-toaster[data-position^='bottom'] > .rf-toast {
|
|
89
|
+
bottom: 0;
|
|
90
|
+
}
|
|
91
|
+
.rf-toast[data-front] {
|
|
92
|
+
block-size: var(--rf-toast-height, auto);
|
|
93
|
+
}
|
|
94
|
+
.rf-toast:focus-visible {
|
|
95
|
+
outline: 2px solid var(--rf-accent);
|
|
96
|
+
outline-offset: 2px;
|
|
97
|
+
}
|
|
98
|
+
/* A new toast slides in from the edge. */
|
|
99
|
+
@starting-style {
|
|
100
|
+
.rf-toast {
|
|
101
|
+
--rf-toast-y: calc(var(--rf-toast-lift) * -100%);
|
|
102
|
+
opacity: 0;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.rf-toaster[data-expanded] > .rf-toast {
|
|
107
|
+
--rf-toast-y: calc(var(--rf-toast-lift) * var(--rf-toast-offset, 0px));
|
|
108
|
+
block-size: var(--rf-toast-height, auto);
|
|
109
|
+
scale: 1;
|
|
110
|
+
}
|
|
111
|
+
.rf-toast[data-hidden] {
|
|
112
|
+
visibility: hidden;
|
|
113
|
+
opacity: 0;
|
|
114
|
+
pointer-events: none;
|
|
115
|
+
}
|
|
116
|
+
.rf-toast[data-swiping] {
|
|
117
|
+
cursor: grabbing;
|
|
118
|
+
user-select: none;
|
|
119
|
+
transition: none;
|
|
120
|
+
}
|
|
121
|
+
/* Leaving, the front toast drops back to its edge; a swiped one carries on
|
|
122
|
+
the way it was thrown; the others fade where they are. */
|
|
123
|
+
.rf-toast[data-removed] {
|
|
124
|
+
opacity: 0;
|
|
125
|
+
pointer-events: none;
|
|
126
|
+
transition:
|
|
127
|
+
translate var(--rf-exit-slow),
|
|
128
|
+
scale var(--rf-exit-slow),
|
|
129
|
+
opacity var(--rf-exit-moderate);
|
|
130
|
+
}
|
|
131
|
+
.rf-toast[data-removed][data-front]:not([data-swipe-out]) {
|
|
132
|
+
--rf-toast-y: calc(var(--rf-toast-lift) * -100%);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.rf-toast-inner {
|
|
136
|
+
display: flex;
|
|
137
|
+
align-items: flex-start;
|
|
138
|
+
gap: 12px;
|
|
139
|
+
padding: 16px;
|
|
140
|
+
transition: opacity var(--rf-spring-moderate);
|
|
141
|
+
}
|
|
142
|
+
/* Piled, only the front toast shows its content. */
|
|
143
|
+
.rf-toaster:not([data-expanded]) > .rf-toast:not([data-front]) > .rf-toast-inner {
|
|
144
|
+
opacity: 0;
|
|
145
|
+
}
|
|
146
|
+
.rf-toast[data-status='info'] {
|
|
147
|
+
--rf-status-color: light-dark(#3b82f6, var(--rf-info));
|
|
148
|
+
}
|
|
149
|
+
.rf-toast[data-status='success'] {
|
|
150
|
+
--rf-status-color: light-dark(#22c55e, var(--rf-success));
|
|
151
|
+
}
|
|
152
|
+
.rf-toast[data-status='warning'] {
|
|
153
|
+
--rf-status-color: light-dark(#f59e0b, var(--rf-warning));
|
|
154
|
+
}
|
|
155
|
+
.rf-toast[data-status='error'] {
|
|
156
|
+
--rf-status-color: light-dark(#ef4444, var(--rf-danger));
|
|
157
|
+
}
|
|
158
|
+
.rf-toast[data-status='loading'] {
|
|
159
|
+
--rf-status-color: var(--rf-muted);
|
|
160
|
+
}
|
|
161
|
+
.rf-toast-icon {
|
|
162
|
+
display: grid;
|
|
163
|
+
flex: none;
|
|
164
|
+
place-items: center;
|
|
165
|
+
inline-size: 20px;
|
|
166
|
+
block-size: var(--rf-leading-subtitle);
|
|
167
|
+
color: var(--rf-status-color);
|
|
168
|
+
}
|
|
169
|
+
.rf-toast-icon > svg {
|
|
170
|
+
inline-size: 20px;
|
|
171
|
+
block-size: 20px;
|
|
172
|
+
}
|
|
173
|
+
.rf-toast-spinner g {
|
|
174
|
+
transform-box: fill-box;
|
|
175
|
+
transform-origin: center;
|
|
176
|
+
animation: rf-button-spinner-turn 1s cubic-bezier(0.65, 0, 0.35, 1) infinite;
|
|
177
|
+
}
|
|
178
|
+
.rf-toast-spinner circle {
|
|
179
|
+
stroke-dasharray: 0.01 49.99;
|
|
180
|
+
stroke-dashoffset: -25;
|
|
181
|
+
animation: rf-button-spinner-breathe 1s cubic-bezier(0.65, 0, 0.35, 1) infinite;
|
|
182
|
+
}
|
|
183
|
+
.rf-toast-content {
|
|
184
|
+
display: flex;
|
|
185
|
+
flex: 1;
|
|
186
|
+
flex-direction: column;
|
|
187
|
+
gap: 2px;
|
|
188
|
+
min-inline-size: 0;
|
|
189
|
+
}
|
|
190
|
+
.rf-toast-title {
|
|
191
|
+
font-size: var(--rf-text-subtitle);
|
|
192
|
+
line-height: var(--rf-leading-subtitle);
|
|
193
|
+
font-variation-settings: var(--rf-weight-strong);
|
|
194
|
+
overflow-wrap: anywhere;
|
|
195
|
+
}
|
|
196
|
+
.rf-toast-description {
|
|
197
|
+
color: var(--rf-muted);
|
|
198
|
+
overflow-wrap: anywhere;
|
|
199
|
+
}
|
|
200
|
+
.rf-toast-action {
|
|
201
|
+
flex: none;
|
|
202
|
+
margin-block: calc((var(--rf-leading-subtitle) - 28px) / 2);
|
|
203
|
+
}
|
|
204
|
+
.rf-toast-close {
|
|
205
|
+
display: flex;
|
|
206
|
+
flex: none;
|
|
207
|
+
align-items: center;
|
|
208
|
+
justify-content: center;
|
|
209
|
+
box-sizing: border-box;
|
|
210
|
+
inline-size: 28px;
|
|
211
|
+
block-size: 28px;
|
|
212
|
+
margin-block: calc((var(--rf-leading-subtitle) - 28px) / 2);
|
|
213
|
+
margin-inline: -4px -6px;
|
|
214
|
+
padding: 0;
|
|
215
|
+
border: 0;
|
|
216
|
+
border-radius: var(--rf-radius);
|
|
217
|
+
outline: none;
|
|
218
|
+
background: transparent;
|
|
219
|
+
color: var(--rf-muted);
|
|
220
|
+
cursor: pointer;
|
|
221
|
+
transition:
|
|
222
|
+
color var(--rf-fast),
|
|
223
|
+
background-color var(--rf-fast);
|
|
224
|
+
}
|
|
225
|
+
.rf-toast-close:focus-visible {
|
|
226
|
+
box-shadow: 0 0 0 1px var(--rf-accent);
|
|
227
|
+
}
|
|
228
|
+
@media (hover: hover) {
|
|
229
|
+
.rf-toast-close:hover {
|
|
230
|
+
background: var(--rf-hover);
|
|
231
|
+
color: var(--rf-fg);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
.rf-toast-close > svg {
|
|
235
|
+
inline-size: 15px;
|
|
236
|
+
block-size: 15px;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
[data-density='compact'] .rf-toast-inner {
|
|
240
|
+
gap: 10px;
|
|
241
|
+
padding: 12px;
|
|
242
|
+
}
|
|
243
|
+
[data-density='compact'] .rf-toast-icon,
|
|
244
|
+
[data-density='compact'] .rf-toast-icon > svg {
|
|
245
|
+
inline-size: 16px;
|
|
246
|
+
}
|
|
247
|
+
[data-density='compact'] .rf-toast-icon > svg {
|
|
248
|
+
block-size: 16px;
|
|
249
|
+
}
|
|
250
|
+
[data-density='compact'] .rf-toast-close > svg {
|
|
251
|
+
inline-size: 13px;
|
|
252
|
+
block-size: 13px;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
@media (prefers-reduced-motion: reduce) {
|
|
256
|
+
.rf-toast,
|
|
257
|
+
.rf-toast[data-removed] {
|
|
258
|
+
transition: opacity var(--rf-spring-moderate);
|
|
259
|
+
}
|
|
260
|
+
.rf-toast-spinner :is(g, circle) {
|
|
261
|
+
animation: none;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
@media (forced-colors: active) {
|
|
265
|
+
.rf-toast {
|
|
266
|
+
border: 1px solid CanvasText;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { type Handle, type RemixNode } from 'remix/component';
|
|
2
|
+
export type ToastStatus = 'default' | 'info' | 'success' | 'warning' | 'error' | 'loading';
|
|
3
|
+
export type ToasterPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
|
|
4
|
+
export interface ToastAction {
|
|
5
|
+
label: string;
|
|
6
|
+
/** Runs on click. The toast then closes, unless the handler calls `event.preventDefault()`. */
|
|
7
|
+
onClick: (event: MouseEvent) => void;
|
|
8
|
+
}
|
|
9
|
+
export interface ToastOptions {
|
|
10
|
+
/** Reuse an id to update a toast in place instead of adding another. */
|
|
11
|
+
id?: string;
|
|
12
|
+
description?: RemixNode;
|
|
13
|
+
/** Milliseconds before it closes on its own. `Infinity` keeps it until dismissed. Defaults to the Toaster's duration. */
|
|
14
|
+
duration?: number;
|
|
15
|
+
action?: ToastAction;
|
|
16
|
+
/** Whether a swipe, Escape or the close button can close it. Default true. */
|
|
17
|
+
dismissible?: boolean;
|
|
18
|
+
/** Replaces the status icon. */
|
|
19
|
+
icon?: RemixNode;
|
|
20
|
+
/** Called when the toast is closed by a swipe, Escape, the close button, an action or `toast.dismiss`. */
|
|
21
|
+
onDismiss?: (toast: Toast) => void;
|
|
22
|
+
/** Called when the toast closes on its own after its duration. */
|
|
23
|
+
onAutoClose?: (toast: Toast) => void;
|
|
24
|
+
}
|
|
25
|
+
export interface Toast extends ToastOptions {
|
|
26
|
+
id: string;
|
|
27
|
+
title: RemixNode;
|
|
28
|
+
status: ToastStatus;
|
|
29
|
+
}
|
|
30
|
+
export interface ToastPromiseMessages<T> {
|
|
31
|
+
loading: RemixNode;
|
|
32
|
+
success: RemixNode | ((value: T) => RemixNode);
|
|
33
|
+
error: RemixNode | ((error: unknown) => RemixNode);
|
|
34
|
+
description?: RemixNode;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Raises a toast in the app's `<Toaster>` and returns its id. `toast.success`,
|
|
38
|
+
* `toast.info`, `toast.warning`, `toast.error` and `toast.loading` set its
|
|
39
|
+
* status; `toast.promise` follows a promise from loading to its outcome;
|
|
40
|
+
* `toast.dismiss` closes one toast, or all of them.
|
|
41
|
+
*/
|
|
42
|
+
export declare const toast: ((title: RemixNode, options?: ToastOptions) => string) & {
|
|
43
|
+
success: (title: RemixNode, options?: ToastOptions) => string;
|
|
44
|
+
info: (title: RemixNode, options?: ToastOptions) => string;
|
|
45
|
+
warning: (title: RemixNode, options?: ToastOptions) => string;
|
|
46
|
+
error: (title: RemixNode, options?: ToastOptions) => string;
|
|
47
|
+
loading: (title: RemixNode, options?: ToastOptions) => string;
|
|
48
|
+
promise<T>(promise: Promise<T> | (() => Promise<T>), messages: ToastPromiseMessages<T>, options?: ToastOptions): string;
|
|
49
|
+
dismiss: (id?: string) => void;
|
|
50
|
+
};
|
|
51
|
+
export interface ToasterProps {
|
|
52
|
+
/** Where the stack sits. Default bottom-right. */
|
|
53
|
+
position?: ToasterPosition;
|
|
54
|
+
/** Show the stack spread out instead of piled. Default false. */
|
|
55
|
+
expand?: boolean;
|
|
56
|
+
/** How many toasts stay in view; older ones wait behind them. Default 3. */
|
|
57
|
+
visibleToasts?: number;
|
|
58
|
+
/** Milliseconds each toast stays before closing on its own. Default 4000. */
|
|
59
|
+
duration?: number;
|
|
60
|
+
/** Give every dismissible toast a close button. Default false. */
|
|
61
|
+
closeButton?: boolean;
|
|
62
|
+
/** Moves focus to the newest toast. Default alt+t. */
|
|
63
|
+
hotkey?: string;
|
|
64
|
+
/** Names the notifications region. Default "Notifications". */
|
|
65
|
+
label?: string;
|
|
66
|
+
/** Distance from the viewport's edges in pixels. Default 24, or 16 on narrow screens. */
|
|
67
|
+
offset?: number;
|
|
68
|
+
size?: 'default' | 'compact';
|
|
69
|
+
class?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Shows the toasts raised with `toast()`. Place one in the app, outside
|
|
73
|
+
* anything that scrolls. The newest toast sits in front with up to two
|
|
74
|
+
* peeking behind it, on QueuedStack's stacking values; pointing at or
|
|
75
|
+
* focusing the stack spreads it out and pauses the timers. A swipe toward
|
|
76
|
+
* the nearest edge, Escape, or the close button dismisses a toast, and the
|
|
77
|
+
* hotkey moves focus to the newest one.
|
|
78
|
+
*/
|
|
79
|
+
export declare function Toaster(handle: Handle<ToasterProps>): () => import("remix/component").RemixElement;
|