@yelison/forma-ui 0.0.0-stage → 0.1.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/CHANGELOG.md +19 -0
- package/LICENSE +21 -0
- package/README.md +243 -2
- package/dist/base.css +25 -0
- package/dist/components/Badge/Badge.d.ts +14 -0
- package/dist/components/Badge/Badge.js +12 -0
- package/dist/components/Badge/Badge.module.css.js +11 -0
- package/dist/components/Badge/index.d.ts +1 -0
- package/dist/components/Button/Button.d.ts +23 -0
- package/dist/components/Button/Button.js +34 -0
- package/dist/components/Button/Button.module.css.js +13 -0
- package/dist/components/Button/IconButton.d.ts +17 -0
- package/dist/components/Button/IconButton.js +20 -0
- package/dist/components/Button/IconButton.module.css.js +8 -0
- package/dist/components/Button/buttonClassName.d.ts +17 -0
- package/dist/components/Button/buttonClassName.js +8 -0
- package/dist/components/Button/index.d.ts +3 -0
- package/dist/components/Dialog/Dialog.d.ts +51 -0
- package/dist/components/Dialog/Dialog.js +38 -0
- package/dist/components/Dialog/Dialog.module.css.js +12 -0
- package/dist/components/Dialog/index.d.ts +1 -0
- package/dist/components/Field/Field.d.ts +42 -0
- package/dist/components/Field/Field.js +40 -0
- package/dist/components/Field/Field.module.css.js +9 -0
- package/dist/components/Field/control.module.css.js +4 -0
- package/dist/components/Field/index.d.ts +1 -0
- package/dist/components/Icon/Icon.d.ts +19 -0
- package/dist/components/Icon/Icon.js +27 -0
- package/dist/components/Icon/index.d.ts +1 -0
- package/dist/components/Icon/paths.d.ts +26 -0
- package/dist/components/Icon/paths.js +32 -0
- package/dist/components/Input/Input.d.ts +24 -0
- package/dist/components/Input/Input.js +23 -0
- package/dist/components/Input/index.d.ts +1 -0
- package/dist/components/Tooltip/Tooltip.d.ts +65 -0
- package/dist/components/Tooltip/Tooltip.js +51 -0
- package/dist/components/Tooltip/Tooltip.module.css.js +4 -0
- package/dist/components/Tooltip/activeTooltip.d.ts +4 -0
- package/dist/components/Tooltip/activeTooltip.js +10 -0
- package/dist/components/Tooltip/index.d.ts +1 -0
- package/dist/contrast-pairs.json +368 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +19 -0
- package/dist/lib/cx.d.ts +4 -0
- package/dist/lib/cx.js +6 -0
- package/dist/lib/position.d.ts +22 -0
- package/dist/lib/position.js +21 -0
- package/dist/lib/scrollLock.d.ts +13 -0
- package/dist/lib/scrollLock.js +22 -0
- package/dist/lib/useFloating.d.ts +25 -0
- package/dist/lib/useFloating.js +48 -0
- package/dist/lib/useModalDialog.d.ts +15 -0
- package/dist/lib/useModalDialog.js +42 -0
- package/dist/provider/FormaProvider.d.ts +17 -0
- package/dist/provider/FormaProvider.js +16 -0
- package/dist/provider/index.d.ts +3 -0
- package/dist/provider/strings.d.ts +14 -0
- package/dist/provider/strings.js +7 -0
- package/dist/provider/stringsContext.d.ts +6 -0
- package/dist/provider/stringsContext.js +6 -0
- package/dist/provider/useFormaStrings.d.ts +3 -0
- package/dist/provider/useFormaStrings.js +8 -0
- package/dist/styles.css +2 -0
- package/dist/theme/index.d.ts +5 -0
- package/dist/theme/themeScript.d.ts +21 -0
- package/dist/theme/themeScript.js +7 -0
- package/dist/theme/themeStore.d.ts +42 -0
- package/dist/theme/themeStore.js +55 -0
- package/dist/theme/useTheme.d.ts +21 -0
- package/dist/theme/useTheme.js +16 -0
- package/dist/tokens/contrast.d.ts +12 -0
- package/dist/tokens/contrast.js +25 -0
- package/dist/tokens/tokens.d.ts +2 -0
- package/dist/tokens/tokens.js +4 -0
- package/dist/tokens.css +156 -0
- package/dist/tokens.json +154 -0
- package/package.json +95 -4
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
{
|
|
2
|
+
"thresholds": {
|
|
3
|
+
"text": 4.5,
|
|
4
|
+
"nonText": 3
|
|
5
|
+
},
|
|
6
|
+
"pairs": [
|
|
7
|
+
{
|
|
8
|
+
"foreground": "ink",
|
|
9
|
+
"background": "bg",
|
|
10
|
+
"kind": "text",
|
|
11
|
+
"themes": [
|
|
12
|
+
"light",
|
|
13
|
+
"dark"
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"foreground": "ink",
|
|
18
|
+
"background": "surface",
|
|
19
|
+
"kind": "text",
|
|
20
|
+
"themes": [
|
|
21
|
+
"light",
|
|
22
|
+
"dark"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"foreground": "ink",
|
|
27
|
+
"background": "surface-hover",
|
|
28
|
+
"kind": "text",
|
|
29
|
+
"themes": [
|
|
30
|
+
"light",
|
|
31
|
+
"dark"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"foreground": "ink",
|
|
36
|
+
"background": "blue-bg",
|
|
37
|
+
"kind": "text",
|
|
38
|
+
"themes": [
|
|
39
|
+
"light",
|
|
40
|
+
"dark"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"foreground": "muted",
|
|
45
|
+
"background": "bg",
|
|
46
|
+
"kind": "text",
|
|
47
|
+
"themes": [
|
|
48
|
+
"light",
|
|
49
|
+
"dark"
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"foreground": "muted",
|
|
54
|
+
"background": "surface",
|
|
55
|
+
"kind": "text",
|
|
56
|
+
"themes": [
|
|
57
|
+
"light",
|
|
58
|
+
"dark"
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"foreground": "muted",
|
|
63
|
+
"background": "surface-hover",
|
|
64
|
+
"kind": "text",
|
|
65
|
+
"themes": [
|
|
66
|
+
"light",
|
|
67
|
+
"dark"
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"foreground": "muted",
|
|
72
|
+
"background": "blue-bg",
|
|
73
|
+
"kind": "text",
|
|
74
|
+
"themes": [
|
|
75
|
+
"light",
|
|
76
|
+
"dark"
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"foreground": "blue-ink",
|
|
81
|
+
"background": "bg",
|
|
82
|
+
"kind": "text",
|
|
83
|
+
"themes": [
|
|
84
|
+
"light",
|
|
85
|
+
"dark"
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"foreground": "blue-ink",
|
|
90
|
+
"background": "surface",
|
|
91
|
+
"kind": "text",
|
|
92
|
+
"themes": [
|
|
93
|
+
"light",
|
|
94
|
+
"dark"
|
|
95
|
+
]
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"foreground": "blue-ink",
|
|
99
|
+
"background": "surface-hover",
|
|
100
|
+
"kind": "text",
|
|
101
|
+
"themes": [
|
|
102
|
+
"light",
|
|
103
|
+
"dark"
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"foreground": "green-ink",
|
|
108
|
+
"background": "bg",
|
|
109
|
+
"kind": "text",
|
|
110
|
+
"themes": [
|
|
111
|
+
"light",
|
|
112
|
+
"dark"
|
|
113
|
+
]
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"foreground": "green-ink",
|
|
117
|
+
"background": "surface",
|
|
118
|
+
"kind": "text",
|
|
119
|
+
"themes": [
|
|
120
|
+
"light",
|
|
121
|
+
"dark"
|
|
122
|
+
]
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"foreground": "green-ink",
|
|
126
|
+
"background": "surface-hover",
|
|
127
|
+
"kind": "text",
|
|
128
|
+
"themes": [
|
|
129
|
+
"light",
|
|
130
|
+
"dark"
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"foreground": "amber-ink",
|
|
135
|
+
"background": "bg",
|
|
136
|
+
"kind": "text",
|
|
137
|
+
"themes": [
|
|
138
|
+
"light",
|
|
139
|
+
"dark"
|
|
140
|
+
]
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"foreground": "amber-ink",
|
|
144
|
+
"background": "surface",
|
|
145
|
+
"kind": "text",
|
|
146
|
+
"themes": [
|
|
147
|
+
"light",
|
|
148
|
+
"dark"
|
|
149
|
+
]
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"foreground": "amber-ink",
|
|
153
|
+
"background": "surface-hover",
|
|
154
|
+
"kind": "text",
|
|
155
|
+
"themes": [
|
|
156
|
+
"light",
|
|
157
|
+
"dark"
|
|
158
|
+
]
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"foreground": "red-ink",
|
|
162
|
+
"background": "bg",
|
|
163
|
+
"kind": "text",
|
|
164
|
+
"themes": [
|
|
165
|
+
"light",
|
|
166
|
+
"dark"
|
|
167
|
+
]
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"foreground": "red-ink",
|
|
171
|
+
"background": "surface",
|
|
172
|
+
"kind": "text",
|
|
173
|
+
"themes": [
|
|
174
|
+
"light",
|
|
175
|
+
"dark"
|
|
176
|
+
]
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"foreground": "red-ink",
|
|
180
|
+
"background": "surface-hover",
|
|
181
|
+
"kind": "text",
|
|
182
|
+
"themes": [
|
|
183
|
+
"light",
|
|
184
|
+
"dark"
|
|
185
|
+
]
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"foreground": "green-ink",
|
|
189
|
+
"background": "blue-bg",
|
|
190
|
+
"kind": "text",
|
|
191
|
+
"themes": [
|
|
192
|
+
"light",
|
|
193
|
+
"dark"
|
|
194
|
+
]
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"foreground": "amber-ink",
|
|
198
|
+
"background": "blue-bg",
|
|
199
|
+
"kind": "text",
|
|
200
|
+
"themes": [
|
|
201
|
+
"light",
|
|
202
|
+
"dark"
|
|
203
|
+
]
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"foreground": "red-ink",
|
|
207
|
+
"background": "blue-bg",
|
|
208
|
+
"kind": "text",
|
|
209
|
+
"themes": [
|
|
210
|
+
"light",
|
|
211
|
+
"dark"
|
|
212
|
+
]
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"foreground": "blue-ink",
|
|
216
|
+
"background": "blue-bg",
|
|
217
|
+
"kind": "text",
|
|
218
|
+
"themes": [
|
|
219
|
+
"light",
|
|
220
|
+
"dark"
|
|
221
|
+
]
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"foreground": "green-ink",
|
|
225
|
+
"background": "green-bg",
|
|
226
|
+
"kind": "text",
|
|
227
|
+
"themes": [
|
|
228
|
+
"light",
|
|
229
|
+
"dark"
|
|
230
|
+
]
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
"foreground": "amber-ink",
|
|
234
|
+
"background": "amber-bg",
|
|
235
|
+
"kind": "text",
|
|
236
|
+
"themes": [
|
|
237
|
+
"light",
|
|
238
|
+
"dark"
|
|
239
|
+
]
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"foreground": "red-ink",
|
|
243
|
+
"background": "red-bg",
|
|
244
|
+
"kind": "text",
|
|
245
|
+
"themes": [
|
|
246
|
+
"light",
|
|
247
|
+
"dark"
|
|
248
|
+
]
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"foreground": "ink",
|
|
252
|
+
"background": "amber-bg",
|
|
253
|
+
"kind": "text",
|
|
254
|
+
"themes": [
|
|
255
|
+
"light",
|
|
256
|
+
"dark"
|
|
257
|
+
]
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"foreground": "muted",
|
|
261
|
+
"background": "amber-bg",
|
|
262
|
+
"kind": "text",
|
|
263
|
+
"themes": [
|
|
264
|
+
"light",
|
|
265
|
+
"dark"
|
|
266
|
+
]
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
"foreground": "link",
|
|
270
|
+
"background": "surface",
|
|
271
|
+
"kind": "text",
|
|
272
|
+
"themes": [
|
|
273
|
+
"light",
|
|
274
|
+
"dark"
|
|
275
|
+
]
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"foreground": "link",
|
|
279
|
+
"background": "bg",
|
|
280
|
+
"kind": "text",
|
|
281
|
+
"themes": [
|
|
282
|
+
"light",
|
|
283
|
+
"dark"
|
|
284
|
+
]
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
"foreground": "nav-text",
|
|
288
|
+
"background": "nav",
|
|
289
|
+
"kind": "text",
|
|
290
|
+
"themes": [
|
|
291
|
+
"light",
|
|
292
|
+
"dark"
|
|
293
|
+
]
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"foreground": "nav-text",
|
|
297
|
+
"background": "nav-active",
|
|
298
|
+
"kind": "text",
|
|
299
|
+
"themes": [
|
|
300
|
+
"light",
|
|
301
|
+
"dark"
|
|
302
|
+
]
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
"foreground": "nav-ink",
|
|
306
|
+
"background": "nav",
|
|
307
|
+
"kind": "text",
|
|
308
|
+
"themes": [
|
|
309
|
+
"light",
|
|
310
|
+
"dark"
|
|
311
|
+
]
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"foreground": "nav-ink",
|
|
315
|
+
"background": "nav-active",
|
|
316
|
+
"kind": "text",
|
|
317
|
+
"themes": [
|
|
318
|
+
"light",
|
|
319
|
+
"dark"
|
|
320
|
+
]
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
"foreground": "on-brand",
|
|
324
|
+
"background": "brand",
|
|
325
|
+
"kind": "text",
|
|
326
|
+
"themes": [
|
|
327
|
+
"light",
|
|
328
|
+
"dark"
|
|
329
|
+
]
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
"foreground": "on-brand",
|
|
333
|
+
"background": "brand-hover",
|
|
334
|
+
"kind": "text",
|
|
335
|
+
"themes": [
|
|
336
|
+
"light",
|
|
337
|
+
"dark"
|
|
338
|
+
]
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
"foreground": "brand",
|
|
342
|
+
"background": "surface",
|
|
343
|
+
"kind": "nonText",
|
|
344
|
+
"themes": [
|
|
345
|
+
"light",
|
|
346
|
+
"dark"
|
|
347
|
+
]
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
"foreground": "brand",
|
|
351
|
+
"background": "bg",
|
|
352
|
+
"kind": "nonText",
|
|
353
|
+
"themes": [
|
|
354
|
+
"light",
|
|
355
|
+
"dark"
|
|
356
|
+
]
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
"foreground": "brand",
|
|
360
|
+
"background": "progress-track",
|
|
361
|
+
"kind": "nonText",
|
|
362
|
+
"themes": [
|
|
363
|
+
"light",
|
|
364
|
+
"dark"
|
|
365
|
+
]
|
|
366
|
+
}
|
|
367
|
+
]
|
|
368
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { contrastRatio, relativeLuminance } from './tokens/contrast.js';
|
|
2
|
+
export { tokenNames, type TokenName } from './tokens/tokens.js';
|
|
3
|
+
export { createThemeStore, themeScript, useTheme } from './theme/index.js';
|
|
4
|
+
export type { ResolvedTheme, ThemePreference, ThemeStore, ThemeStoreOptions, UseThemeResult } from './theme/index.js';
|
|
5
|
+
export { FormaProvider, useFormaStrings, defaultStrings, type FormaProviderProps, type FormaStrings, } from './provider/index.js';
|
|
6
|
+
export { Badge, type BadgeProps, type BadgeTone } from './components/Badge/index.js';
|
|
7
|
+
export { Icon, type IconName, type IconProps } from './components/Icon/index.js';
|
|
8
|
+
export { Field, type FieldControlProps, type FieldProps } from './components/Field/index.js';
|
|
9
|
+
export { Input, type InputProps } from './components/Input/index.js';
|
|
10
|
+
export { Button, IconButton, buttonClassName, type ButtonProps, type IconButtonProps, type ButtonStyleOptions, type ButtonVariant, } from './components/Button/index.js';
|
|
11
|
+
export { Tooltip, type TooltipPlacement, type TooltipProps, type TooltipTriggerProps, } from './components/Tooltip/index.js';
|
|
12
|
+
export { Dialog, Modal, type DialogProps, type ModalProps } from './components/Dialog/index.js';
|
|
13
|
+
export { useScrollLock } from './lib/scrollLock.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { contrastRatio as e, relativeLuminance as t } from "./tokens/contrast.js";
|
|
2
|
+
import { tokenNames as n } from "./tokens/tokens.js";
|
|
3
|
+
import { createThemeStore as r } from "./theme/themeStore.js";
|
|
4
|
+
import { themeScript as i } from "./theme/themeScript.js";
|
|
5
|
+
import { useTheme as a } from "./theme/useTheme.js";
|
|
6
|
+
import { defaultStrings as o } from "./provider/strings.js";
|
|
7
|
+
import { FormaProvider as s } from "./provider/FormaProvider.js";
|
|
8
|
+
import { useFormaStrings as c } from "./provider/useFormaStrings.js";
|
|
9
|
+
import { Badge as l } from "./components/Badge/Badge.js";
|
|
10
|
+
import { Icon as u } from "./components/Icon/Icon.js";
|
|
11
|
+
import { Field as d } from "./components/Field/Field.js";
|
|
12
|
+
import { Input as f } from "./components/Input/Input.js";
|
|
13
|
+
import { buttonClassName as p } from "./components/Button/buttonClassName.js";
|
|
14
|
+
import { Button as m } from "./components/Button/Button.js";
|
|
15
|
+
import { IconButton as h } from "./components/Button/IconButton.js";
|
|
16
|
+
import { Tooltip as g } from "./components/Tooltip/Tooltip.js";
|
|
17
|
+
import { useScrollLock as _ } from "./lib/scrollLock.js";
|
|
18
|
+
import { Dialog as v, Modal as y } from "./components/Dialog/Dialog.js";
|
|
19
|
+
export { l as Badge, m as Button, v as Dialog, d as Field, s as FormaProvider, u as Icon, h as IconButton, f as Input, y as Modal, g as Tooltip, p as buttonClassName, e as contrastRatio, r as createThemeStore, o as defaultStrings, t as relativeLuminance, i as themeScript, n as tokenNames, c as useFormaStrings, _ as useScrollLock, a as useTheme };
|
package/dist/lib/cx.d.ts
ADDED
package/dist/lib/cx.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type Placement = 'right' | 'bottom-start' | 'bottom-end';
|
|
2
|
+
export interface Size {
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
}
|
|
6
|
+
export interface Rect extends Size {
|
|
7
|
+
top: number;
|
|
8
|
+
left: number;
|
|
9
|
+
}
|
|
10
|
+
export interface Position {
|
|
11
|
+
top: number;
|
|
12
|
+
left: number;
|
|
13
|
+
placement: Placement | 'left' | 'top-start' | 'top-end';
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Places a floating element next to its anchor without leaving the viewport.
|
|
17
|
+
* If it does not fit on the requested side it flips (right → left, below → above) and then clamps to the edges.
|
|
18
|
+
*/
|
|
19
|
+
export declare function computePosition(anchor: Rect, floating: Size, placement: Placement, viewport: Size, { gap, margin }?: {
|
|
20
|
+
gap?: number | undefined;
|
|
21
|
+
margin?: number | undefined;
|
|
22
|
+
}): Position;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/lib/position.ts
|
|
2
|
+
var e = (e, t, n) => Math.min(Math.max(e, t), Math.max(t, n));
|
|
3
|
+
function t(t, n, r, i, { gap: a = 8, margin: o = 8 } = {}) {
|
|
4
|
+
let s = i.width - n.width - o, c = i.height - n.height - o;
|
|
5
|
+
if (r === "right") {
|
|
6
|
+
let r = t.top + t.height / 2 - n.height / 2, l = t.left + t.width + a, u = l + n.width + o <= i.width, d = u ? l : t.left - a - n.width;
|
|
7
|
+
return {
|
|
8
|
+
top: e(r, o, c),
|
|
9
|
+
left: e(d, o, s),
|
|
10
|
+
placement: u ? "right" : "left"
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
let l = t.top + t.height + a, u = l + n.height + o <= i.height, d = t.top - a - n.height, f = !u && d >= o, p = r === "bottom-start" ? t.left : t.left + t.width - n.width, m = r === "bottom-start" ? "start" : "end";
|
|
14
|
+
return {
|
|
15
|
+
top: e(f ? d : l, o, c),
|
|
16
|
+
left: e(p, o, s),
|
|
17
|
+
placement: f ? `top-${m}` : `bottom-${m}`
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { t as computePosition };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locks the document scroll while at least one modal overlay is open.
|
|
3
|
+
* The lock is a counter: the returned function releases one lock, and only the last release unlocks the page.
|
|
4
|
+
*/
|
|
5
|
+
export declare function lockScroll(): () => void;
|
|
6
|
+
/**
|
|
7
|
+
* Locks the document scroll while `active` is `true`, for an overlay of your own such as a drawer.
|
|
8
|
+
*
|
|
9
|
+
* Every overlay of the library shares one counter, so two overlays open at once keep the page locked until the last of
|
|
10
|
+
* them closes. The lock is the `forma-scroll-locked` class on `<html>`, which `@yelison/forma-ui/base.css` defines:
|
|
11
|
+
* without that stylesheet the hook still counts, but the page keeps scrolling.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useScrollLock(active: boolean): void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useEffect as e } from "react";
|
|
2
|
+
//#region src/lib/scrollLock.ts
|
|
3
|
+
var t = 0;
|
|
4
|
+
function n() {
|
|
5
|
+
let e = document.documentElement;
|
|
6
|
+
if (t === 0) {
|
|
7
|
+
let t = window.innerWidth - e.clientWidth;
|
|
8
|
+
t > 0 && (e.style.paddingRight = `${t}px`);
|
|
9
|
+
}
|
|
10
|
+
t += 1, e.classList.add("forma-scroll-locked");
|
|
11
|
+
let n = !1;
|
|
12
|
+
return () => {
|
|
13
|
+
n || (n = !0, --t, t === 0 && (e.classList.remove("forma-scroll-locked"), e.style.removeProperty("padding-right")));
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function r(t) {
|
|
17
|
+
e(() => {
|
|
18
|
+
if (t) return n();
|
|
19
|
+
}, [t]);
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { n as lockScroll, r as useScrollLock };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Placement } from './position.js';
|
|
2
|
+
/**
|
|
3
|
+
* Positions a floating element (fixed, in a portal) next to its anchor and places it again on scroll and window
|
|
4
|
+
* resize while it is open.
|
|
5
|
+
* The anchor and the floating element are kept in state: `setAnchor` and `setFloating` work as callback refs.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useFloating<TAnchor extends HTMLElement, TFloating extends HTMLElement>(open: boolean, placement: Placement): {
|
|
8
|
+
anchor: TAnchor | null;
|
|
9
|
+
setAnchor: import("react").Dispatch<import("react").SetStateAction<TAnchor | null>>;
|
|
10
|
+
floating: TFloating | null;
|
|
11
|
+
setFloating: import("react").Dispatch<import("react").SetStateAction<TFloating | null>>;
|
|
12
|
+
style: {
|
|
13
|
+
position: "fixed";
|
|
14
|
+
top: number;
|
|
15
|
+
left: number;
|
|
16
|
+
visibility?: undefined;
|
|
17
|
+
} | {
|
|
18
|
+
position: "fixed";
|
|
19
|
+
top: number;
|
|
20
|
+
left: number;
|
|
21
|
+
visibility: "hidden";
|
|
22
|
+
};
|
|
23
|
+
positioned: boolean;
|
|
24
|
+
portalContainer: HTMLElement;
|
|
25
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { computePosition as e } from "./position.js";
|
|
2
|
+
import { useCallback as t, useLayoutEffect as n, useState as r } from "react";
|
|
3
|
+
//#region src/lib/useFloating.ts
|
|
4
|
+
function i(i, a) {
|
|
5
|
+
let [o, s] = r(null), [c, l] = r(null), [u, d] = r(null), f = t(() => {
|
|
6
|
+
o && c && d(e(o.getBoundingClientRect(), {
|
|
7
|
+
width: c.offsetWidth,
|
|
8
|
+
height: c.offsetHeight
|
|
9
|
+
}, a, {
|
|
10
|
+
width: document.documentElement.clientWidth,
|
|
11
|
+
height: window.innerHeight
|
|
12
|
+
}));
|
|
13
|
+
}, [
|
|
14
|
+
o,
|
|
15
|
+
c,
|
|
16
|
+
a
|
|
17
|
+
]);
|
|
18
|
+
n(() => {
|
|
19
|
+
if (i && c) return f(), window.addEventListener("resize", f), window.addEventListener("scroll", f, !0), () => {
|
|
20
|
+
window.removeEventListener("resize", f), window.removeEventListener("scroll", f, !0);
|
|
21
|
+
};
|
|
22
|
+
}, [
|
|
23
|
+
i,
|
|
24
|
+
c,
|
|
25
|
+
f
|
|
26
|
+
]);
|
|
27
|
+
let p = i && u ? {
|
|
28
|
+
position: "fixed",
|
|
29
|
+
top: u.top,
|
|
30
|
+
left: u.left
|
|
31
|
+
} : {
|
|
32
|
+
position: "fixed",
|
|
33
|
+
top: 0,
|
|
34
|
+
left: 0,
|
|
35
|
+
visibility: "hidden"
|
|
36
|
+
}, m = o?.closest("dialog") ?? globalThis.document?.body;
|
|
37
|
+
return {
|
|
38
|
+
anchor: o,
|
|
39
|
+
setAnchor: s,
|
|
40
|
+
floating: c,
|
|
41
|
+
setFloating: l,
|
|
42
|
+
style: p,
|
|
43
|
+
positioned: i && u !== null,
|
|
44
|
+
portalContainer: m
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
export { i as useFloating };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type MouseEvent, type PointerEvent, type SyntheticEvent } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Manages a controlled native <dialog>: it opens it as a modal (focus trapped, background inert), locks the scroll,
|
|
4
|
+
* closes on Escape or a click on the backdrop, and returns the focus to the element that had it before.
|
|
5
|
+
* The content must go in a child that fills the whole dialog, so that a click on the backdrop can be told apart.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useModalDialog(open: boolean, onClose: () => void): {
|
|
8
|
+
ref: import("react").RefObject<HTMLDialogElement | null>;
|
|
9
|
+
onCancel(event: SyntheticEvent<HTMLDialogElement>): void;
|
|
10
|
+
/** Native closes that do not go through cancel, such as a form with method="dialog". */
|
|
11
|
+
onClose(): void;
|
|
12
|
+
onPointerDown(event: PointerEvent<HTMLDialogElement>): void;
|
|
13
|
+
onPointerUp(event: PointerEvent<HTMLDialogElement>): void;
|
|
14
|
+
onClick(event: MouseEvent<HTMLDialogElement>): void;
|
|
15
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { lockScroll as e } from "./scrollLock.js";
|
|
2
|
+
import { useEffect as t, useRef as n } from "react";
|
|
3
|
+
//#region src/lib/useModalDialog.ts
|
|
4
|
+
function r(r, i) {
|
|
5
|
+
let a = n(null), o = n(i), s = n(!1), c = n(!1);
|
|
6
|
+
return t(() => {
|
|
7
|
+
o.current = i;
|
|
8
|
+
}), t(() => {
|
|
9
|
+
let t = a.current;
|
|
10
|
+
if (!r || !t) return;
|
|
11
|
+
let n = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
12
|
+
t.showModal();
|
|
13
|
+
let i = e();
|
|
14
|
+
return () => {
|
|
15
|
+
t.open && (s.current = !0, t.close()), i(), n?.focus();
|
|
16
|
+
};
|
|
17
|
+
}, [r]), {
|
|
18
|
+
ref: a,
|
|
19
|
+
onCancel(e) {
|
|
20
|
+
e.preventDefault(), o.current();
|
|
21
|
+
},
|
|
22
|
+
onClose() {
|
|
23
|
+
if (s.current) {
|
|
24
|
+
s.current = !1;
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
o.current();
|
|
28
|
+
},
|
|
29
|
+
onPointerDown(e) {
|
|
30
|
+
c.current = e.target === e.currentTarget;
|
|
31
|
+
},
|
|
32
|
+
onPointerUp(e) {
|
|
33
|
+
e.target !== e.currentTarget && (c.current = !1);
|
|
34
|
+
},
|
|
35
|
+
onClick(e) {
|
|
36
|
+
let t = c.current;
|
|
37
|
+
c.current = !1, t && e.target === e.currentTarget && o.current();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { r as useModalDialog };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { FormaStrings } from './strings.js';
|
|
3
|
+
/** The props of `FormaProvider`. */
|
|
4
|
+
export interface FormaProviderProps {
|
|
5
|
+
/**
|
|
6
|
+
* Replaces the library's built-in text, for example `{ buttonLoading: 'Enviando…' }`. Entries left out keep the
|
|
7
|
+
* value of the closest provider above, or the English default.
|
|
8
|
+
*/
|
|
9
|
+
strings?: Partial<FormaStrings>;
|
|
10
|
+
/** The part of the application whose components read these strings. */
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Supplies the text that the components show on their own. A prop on a component wins over the provider, and the
|
|
15
|
+
* provider over the English default. Nothing else is needed for an application in English.
|
|
16
|
+
*/
|
|
17
|
+
export declare function FormaProvider({ strings, children }: FormaProviderProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { StringsContext as e } from "./stringsContext.js";
|
|
2
|
+
import { useContext as t, useMemo as n } from "react";
|
|
3
|
+
import { jsx as r } from "react/jsx-runtime";
|
|
4
|
+
//#region src/provider/FormaProvider.tsx
|
|
5
|
+
function i({ strings: i, children: a }) {
|
|
6
|
+
let o = t(e), s = i?.buttonLoading ?? o.buttonLoading, c = i?.dialogClose ?? o.dialogClose, l = n(() => ({
|
|
7
|
+
buttonLoading: s,
|
|
8
|
+
dialogClose: c
|
|
9
|
+
}), [s, c]);
|
|
10
|
+
return /* @__PURE__ */ r(e, {
|
|
11
|
+
value: l,
|
|
12
|
+
children: a
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { i as FormaProvider };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** The text the library shows on its own, one entry per string. Components also accept a prop that wins over it. */
|
|
2
|
+
export interface FormaStrings {
|
|
3
|
+
/** The accessible name of a button while it is loading. */
|
|
4
|
+
buttonLoading: string;
|
|
5
|
+
/** The accessible name of a dialog's close button, for a dialog that opts into one. */
|
|
6
|
+
dialogClose: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The English text that `FormaProvider` replaces and `useFormaStrings` returns without a provider.
|
|
10
|
+
* It is frozen: a consumer that changed it would change the default of every component at once.
|
|
11
|
+
* The pure annotation lets a bundler drop the object when nothing imports it: it cannot know that `Object.freeze`
|
|
12
|
+
* has no side effect.
|
|
13
|
+
*/
|
|
14
|
+
export declare const defaultStrings: Readonly<FormaStrings>;
|