lapikit 0.7.2 → 0.7.4
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/@types/components.d.ts +1 -7
- package/dist/@types/dom.d.ts +4 -3
- package/dist/@types/props.d.ts +3 -3
- package/dist/animations/ripple.js +33 -17
- package/dist/components/accordion/accordion.svelte +192 -228
- package/dist/components/accordion/accordion.types.d.ts +5 -7
- package/dist/components/accordion/modules/accordion-item.svelte +144 -140
- package/dist/components/alert/alert.svelte +246 -293
- package/dist/components/alert/alert.types.d.ts +5 -5
- package/dist/components/app/app.svelte +29 -44
- package/dist/components/appbar/appbar.svelte +205 -190
- package/dist/components/appbar/appbar.types.d.ts +6 -6
- package/dist/components/aspect-ratio/aspect-ratio.svelte +43 -63
- package/dist/components/avatar/avatar.svelte +169 -161
- package/dist/components/avatar/avatar.types.d.ts +3 -4
- package/dist/components/btn/btn.svelte +431 -465
- package/dist/components/btn/btn.types.d.ts +5 -6
- package/dist/components/card/card.svelte +214 -176
- package/dist/components/card/card.types.d.ts +6 -3
- package/dist/components/card/modules/card-actions.svelte +11 -35
- package/dist/components/card/modules/card-container.svelte +9 -33
- package/dist/components/card/modules/card-content.svelte +18 -44
- package/dist/components/card/modules/card-media.svelte +10 -34
- package/dist/components/card/modules/card-title.svelte +22 -48
- package/dist/components/chip/chip.svelte +416 -464
- package/dist/components/chip/chip.types.d.ts +5 -5
- package/dist/components/dialog/dialog.svelte +174 -171
- package/dist/components/dialog/dialog.types.d.ts +6 -6
- package/dist/components/dropdown/dropdown.svelte +149 -144
- package/dist/components/dropdown/dropdown.types.d.ts +4 -11
- package/dist/components/field/field.svelte +474 -0
- package/dist/components/field/field.svelte.d.ts +4 -0
- package/dist/components/field/field.types.d.ts +46 -0
- package/dist/components/field/field.types.js +1 -0
- package/dist/components/icon/icon.svelte +67 -96
- package/dist/components/icon/icon.types.d.ts +2 -1
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +1 -0
- package/dist/components/list/list.svelte +193 -194
- package/dist/components/list/list.types.d.ts +5 -7
- package/dist/components/list/modules/list-item.svelte +134 -147
- package/dist/components/modal/modal.svelte +239 -222
- package/dist/components/modal/modal.types.d.ts +6 -6
- package/dist/components/popover/popover.svelte +125 -127
- package/dist/components/popover/popover.types.d.ts +4 -11
- package/dist/components/separator/separator.svelte +56 -87
- package/dist/components/separator/separator.types.d.ts +1 -1
- package/dist/components/spacer/spacer.svelte +6 -25
- package/dist/components/textfield/textfield.svelte +94 -543
- package/dist/components/textfield/textfield.types.d.ts +13 -33
- package/dist/components/toolbar/toolbar.svelte +216 -211
- package/dist/components/toolbar/toolbar.types.d.ts +8 -9
- package/dist/components/tooltip/tooltip.svelte +201 -266
- package/dist/components/tooltip/tooltip.types.d.ts +3 -10
- package/dist/constants.js +1 -0
- package/dist/html-mapped.d.ts +1 -15
- package/dist/html-mapped.js +0 -19
- package/dist/labs/sheet/sheet.svelte +145 -19
- package/dist/labs/sheet/sheet.svelte.d.ts +2 -10
- package/dist/labs/sheet/sheet.types.d.ts +16 -0
- package/dist/labs/sheet/sheet.types.js +1 -0
- package/dist/utils/color.d.ts +2 -2
- package/dist/utils/color.js +2 -1
- package/dist/utils/components.d.ts +10 -10
- package/dist/utils/components.js +16 -75
- package/dist/utils/floating.d.ts +58 -0
- package/dist/utils/floating.js +131 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/package.json +3 -3
- package/dist/components/dropdown/dropdown.svelte.js +0 -148
- package/dist/components/popover/popover.svelte.js +0 -134
- package/dist/components/tooltip/tooltip.svelte.js +0 -131
|
@@ -3,9 +3,15 @@
|
|
|
3
3
|
* Sheet component
|
|
4
4
|
* @description A simple sheet component for experimentation for developers Lapikit. Please don't use it in production.
|
|
5
5
|
*/
|
|
6
|
-
import { useComponentAttrs, useElevation } from '../../utils';
|
|
6
|
+
import { useComponentAttrs, useElevation, useIsInteractive } from '../../utils';
|
|
7
|
+
import { ripple } from '../../animations';
|
|
8
|
+
import type { SheetProps } from './sheet.types.js';
|
|
7
9
|
|
|
8
10
|
let {
|
|
11
|
+
ref = $bindable(),
|
|
12
|
+
is = 'div',
|
|
13
|
+
href,
|
|
14
|
+
type,
|
|
9
15
|
class: className,
|
|
10
16
|
style: styleAttr,
|
|
11
17
|
children,
|
|
@@ -13,38 +19,66 @@
|
|
|
13
19
|
's-style': sStyle,
|
|
14
20
|
elevation,
|
|
15
21
|
rounded,
|
|
22
|
+
density = 'default',
|
|
16
23
|
variant = 'filled',
|
|
17
24
|
active,
|
|
18
25
|
color,
|
|
26
|
+
interactive,
|
|
27
|
+
disabled = false,
|
|
28
|
+
noRipple,
|
|
19
29
|
...rest
|
|
20
|
-
} = $props();
|
|
30
|
+
}: SheetProps = $props();
|
|
21
31
|
|
|
22
32
|
// states
|
|
23
33
|
let attrs = $derived(
|
|
24
34
|
useComponentAttrs('kit-sheet', { className, sClass, styleAttr, sStyle, color, active }, rest)
|
|
25
35
|
);
|
|
26
36
|
let elevationState = $derived(useElevation(elevation));
|
|
37
|
+
let tag = $derived((href && 'a') || is);
|
|
38
|
+
// undefined: detected (a, button, onclick...), true: forced, false: no visual feedback (still clickable)
|
|
39
|
+
let isInteractive = $derived(interactive ?? useIsInteractive(rest, tag, ['a', 'button']));
|
|
40
|
+
let isDisabled = $derived(!!disabled);
|
|
41
|
+
let resolvedHref = $derived(tag === 'a' && !isDisabled ? href : undefined);
|
|
42
|
+
let resolvedType = $derived(tag === 'button' ? (type ?? 'button') : undefined);
|
|
43
|
+
let resolvedDisabled = $derived(tag === 'button' ? isDisabled : undefined);
|
|
44
|
+
let resolvedTabIndex = $derived(tag === 'a' && isDisabled ? -1 : undefined);
|
|
27
45
|
</script>
|
|
28
46
|
|
|
29
|
-
<
|
|
47
|
+
<svelte:element
|
|
48
|
+
this={tag}
|
|
49
|
+
bind:this={ref}
|
|
30
50
|
class={attrs.class}
|
|
31
51
|
style={attrs.style}
|
|
52
|
+
href={resolvedHref}
|
|
53
|
+
type={resolvedType}
|
|
54
|
+
disabled={resolvedDisabled}
|
|
55
|
+
tabindex={resolvedTabIndex}
|
|
32
56
|
data-rounded={rounded}
|
|
57
|
+
data-density={density}
|
|
33
58
|
data-variant={variant}
|
|
34
59
|
data-elevation={elevationState.base}
|
|
35
60
|
data-elevation-hover={elevationState.hover}
|
|
36
61
|
data-elevation-active={elevationState.active}
|
|
37
62
|
data-active={active}
|
|
63
|
+
data-interactive={isInteractive}
|
|
64
|
+
data-disabled={isDisabled}
|
|
65
|
+
aria-disabled={isDisabled || undefined}
|
|
66
|
+
use:ripple={{
|
|
67
|
+
component: 'sheet',
|
|
68
|
+
disabled: noRipple || isDisabled || !isInteractive
|
|
69
|
+
}}
|
|
38
70
|
{...attrs.rest}
|
|
39
71
|
>
|
|
40
72
|
{@render children?.()}
|
|
41
|
-
</
|
|
73
|
+
</svelte:element>
|
|
42
74
|
|
|
43
|
-
<style
|
|
75
|
+
<style>:where(.kit-sheet) {
|
|
44
76
|
--kit-sheet-color: initial;
|
|
45
77
|
--kit-sheet-on-color: initial;
|
|
46
78
|
--kit-sheet-active-fg: initial;
|
|
47
79
|
--kit-sheet-active-shade: initial;
|
|
80
|
+
--kit-sheet-hover-fg: initial;
|
|
81
|
+
--kit-sheet-pressed-fg: initial;
|
|
48
82
|
--kit-sheet-bg: var(--kit-sheet-color, var(--kit-color-surface-1));
|
|
49
83
|
--kit-sheet-fg: var(--kit-sheet-on-color, var(--kit-sheet-contrast, var(--kit-color-text)));
|
|
50
84
|
--kit-sheet-ink: var(--kit-sheet-color, var(--kit-color-text));
|
|
@@ -59,12 +93,19 @@
|
|
|
59
93
|
);
|
|
60
94
|
}
|
|
61
95
|
@supports (color: color(from red srgb-linear r g b)) {
|
|
62
|
-
.kit-sheet {
|
|
96
|
+
:where(.kit-sheet) {
|
|
63
97
|
--kit-sheet-contrast: color(from var(--kit-sheet-color) srgb-linear clamp(0, (0.1791 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * 100000, 1) clamp(0, (0.1791 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * 100000, 1) clamp(0, (0.1791 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * 100000, 1)/1);
|
|
64
98
|
}
|
|
65
99
|
}
|
|
100
|
+
:where(.kit-sheet) {
|
|
101
|
+
--kit-sheet-p: 12px;
|
|
102
|
+
}
|
|
103
|
+
|
|
66
104
|
.kit-sheet {
|
|
67
105
|
display: flex;
|
|
106
|
+
position: relative;
|
|
107
|
+
gap: calc(var(--kit-space-default) + var(--kit-sheet-density-offset) / 2);
|
|
108
|
+
padding: calc(var(--kit-sheet-p) + var(--kit-sheet-density-offset) / 2);
|
|
68
109
|
background-color: var(--kit-sheet-bg);
|
|
69
110
|
color: var(--kit-sheet-fg);
|
|
70
111
|
border-radius: var(--kit-sheet-radius);
|
|
@@ -78,7 +119,20 @@
|
|
|
78
119
|
}
|
|
79
120
|
}
|
|
80
121
|
|
|
81
|
-
.kit-sheet
|
|
122
|
+
/* native resets: no background here, it would beat the background of .kit-sheet */
|
|
123
|
+
a.kit-sheet {
|
|
124
|
+
text-decoration: none;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
button.kit-sheet {
|
|
128
|
+
appearance: none;
|
|
129
|
+
border: 0;
|
|
130
|
+
padding: 0;
|
|
131
|
+
font: inherit;
|
|
132
|
+
text-align: inherit;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
:where(.kit-sheet[data-variant=tonal]) {
|
|
82
136
|
--kit-sheet-bg: color-mix(in oklab, var(--kit-sheet-ink) 16%, transparent);
|
|
83
137
|
--kit-sheet-fg: var(--kit-sheet-ink);
|
|
84
138
|
--kit-sheet-border: transparent;
|
|
@@ -86,25 +140,47 @@
|
|
|
86
140
|
--kit-sheet-active-fg: var(--kit-sheet-ink);
|
|
87
141
|
}
|
|
88
142
|
|
|
89
|
-
.kit-sheet[data-variant=
|
|
143
|
+
:where(.kit-sheet[data-variant=text]) {
|
|
144
|
+
--kit-sheet-bg: transparent;
|
|
145
|
+
--kit-sheet-fg: var(--kit-sheet-ink);
|
|
146
|
+
--kit-sheet-border: transparent;
|
|
147
|
+
--kit-sheet-active: color-mix(in oklab, var(--kit-sheet-ink) 14%, transparent);
|
|
148
|
+
--kit-sheet-active-fg: var(--kit-sheet-ink);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
:where(.kit-sheet[data-variant=plain]) {
|
|
152
|
+
--kit-sheet-bg: transparent;
|
|
153
|
+
--kit-sheet-fg: var(--kit-sheet-ink);
|
|
154
|
+
--kit-sheet-border: transparent;
|
|
155
|
+
--kit-sheet-hover: transparent;
|
|
156
|
+
--kit-sheet-pressed: transparent;
|
|
157
|
+
--kit-sheet-hover-fg: color-mix(in oklab, var(--kit-sheet-fg) 72%, transparent);
|
|
158
|
+
--kit-sheet-pressed-fg: color-mix(in oklab, var(--kit-sheet-fg) 56%, transparent);
|
|
159
|
+
--kit-sheet-active: transparent;
|
|
160
|
+
--kit-sheet-active-fg: var(--kit-sheet-color, var(--kit-color-accent));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
:where(.kit-sheet[data-variant=outline]) {
|
|
90
164
|
--kit-sheet-bg: transparent;
|
|
91
165
|
--kit-sheet-fg: var(--kit-sheet-ink);
|
|
92
166
|
--kit-sheet-border: var(--kit-sheet-color, var(--kit-color-border));
|
|
93
167
|
--kit-sheet-active: color-mix(in oklab, var(--kit-sheet-ink) 14%, transparent);
|
|
94
168
|
--kit-sheet-active-fg: var(--kit-sheet-ink);
|
|
95
|
-
border: 1px solid var(--kit-sheet-border);
|
|
96
169
|
}
|
|
97
170
|
|
|
98
|
-
.kit-sheet[data-variant=surface] {
|
|
171
|
+
:where(.kit-sheet[data-variant=surface]) {
|
|
99
172
|
--kit-sheet-bg: color-mix(in oklab, var(--kit-sheet-ink) 8%, transparent);
|
|
100
173
|
--kit-sheet-fg: var(--kit-sheet-ink);
|
|
101
174
|
--kit-sheet-border: color-mix(in oklab, var(--kit-sheet-ink) 35%, transparent);
|
|
102
175
|
--kit-sheet-active: color-mix(in oklab, var(--kit-sheet-ink) 18%, transparent);
|
|
103
176
|
--kit-sheet-active-fg: var(--kit-sheet-ink);
|
|
104
|
-
border: 1px solid var(--kit-sheet-border);
|
|
105
177
|
}
|
|
106
178
|
|
|
107
|
-
.kit-sheet[data-
|
|
179
|
+
.kit-sheet:is([data-variant=outline], [data-variant=surface]) {
|
|
180
|
+
border: var(--kit-outline-weight) solid var(--kit-sheet-border);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
:where(.kit-sheet[data-active=true]) {
|
|
108
184
|
--kit-sheet-bg: var(--kit-sheet-active, var(--kit-color-accent));
|
|
109
185
|
--kit-sheet-fg: var(
|
|
110
186
|
--kit-sheet-active-fg,
|
|
@@ -112,34 +188,84 @@
|
|
|
112
188
|
);
|
|
113
189
|
}
|
|
114
190
|
|
|
191
|
+
/**
|
|
192
|
+
* interactive: hover, pressed, focus-visible and disabled
|
|
193
|
+
*/
|
|
194
|
+
.kit-sheet[data-interactive=true]:not([data-disabled=true]) {
|
|
195
|
+
cursor: pointer;
|
|
196
|
+
}
|
|
197
|
+
.kit-sheet[data-interactive=true]:not([data-disabled=true]):hover {
|
|
198
|
+
background-color: var(--kit-sheet-hover);
|
|
199
|
+
color: var(--kit-sheet-hover-fg, var(--kit-sheet-fg));
|
|
200
|
+
}
|
|
201
|
+
.kit-sheet[data-interactive=true]:not([data-disabled=true]):active {
|
|
202
|
+
background-color: var(--kit-sheet-pressed);
|
|
203
|
+
color: var(--kit-sheet-pressed-fg, var(--kit-sheet-fg));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.kit-sheet:not([data-disabled=true]):focus-visible {
|
|
207
|
+
outline: 2px solid var(--kit-color-focus);
|
|
208
|
+
outline-offset: 2px;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.kit-sheet[data-disabled=true] {
|
|
212
|
+
opacity: var(--kit-disabled-opacity, 0.55);
|
|
213
|
+
pointer-events: none;
|
|
214
|
+
user-select: none;
|
|
215
|
+
}
|
|
216
|
+
|
|
115
217
|
/**
|
|
116
218
|
* rounded
|
|
117
219
|
* @link https://lapikit.dev/docs/customize
|
|
118
220
|
*/
|
|
119
|
-
.kit-sheet[data-rounded=
|
|
221
|
+
:where(.kit-sheet[data-rounded="0"]) {
|
|
120
222
|
--kit-sheet-radius: var(--kit-shape-none);
|
|
121
223
|
}
|
|
122
224
|
|
|
123
|
-
.kit-sheet[data-rounded=xs] {
|
|
225
|
+
:where(.kit-sheet[data-rounded=xs]) {
|
|
124
226
|
--kit-sheet-radius: var(--kit-shape-xs);
|
|
125
227
|
}
|
|
126
228
|
|
|
127
|
-
.kit-sheet[data-rounded=sm] {
|
|
229
|
+
:where(.kit-sheet[data-rounded=sm]) {
|
|
128
230
|
--kit-sheet-radius: var(--kit-shape-sm);
|
|
129
231
|
}
|
|
130
232
|
|
|
131
|
-
.kit-sheet[data-rounded=md] {
|
|
233
|
+
:where(.kit-sheet[data-rounded=md]) {
|
|
132
234
|
--kit-sheet-radius: var(--kit-shape-md);
|
|
133
235
|
}
|
|
134
236
|
|
|
135
|
-
.kit-sheet[data-rounded=lg] {
|
|
237
|
+
:where(.kit-sheet[data-rounded=lg]) {
|
|
136
238
|
--kit-sheet-radius: var(--kit-shape-lg);
|
|
137
239
|
}
|
|
138
240
|
|
|
139
|
-
.kit-sheet[data-rounded=xl] {
|
|
241
|
+
:where(.kit-sheet[data-rounded=xl]) {
|
|
140
242
|
--kit-sheet-radius: var(--kit-shape-xl);
|
|
141
243
|
}
|
|
142
244
|
|
|
143
|
-
.kit-sheet[data-rounded=full] {
|
|
245
|
+
:where(.kit-sheet[data-rounded=full]) {
|
|
144
246
|
--kit-sheet-radius: var(--kit-shape-full);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* density
|
|
251
|
+
* @link https://lapikit.dev/docs/customize
|
|
252
|
+
*/
|
|
253
|
+
:where(.kit-sheet[data-density=dense]) {
|
|
254
|
+
--kit-sheet-density-offset: var(--kit-density-dense);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
:where(.kit-sheet[data-density=compact]) {
|
|
258
|
+
--kit-sheet-density-offset: var(--kit-density-compact);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
:where(.kit-sheet[data-density=default]) {
|
|
262
|
+
--kit-sheet-density-offset: var(--kit-density-default);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
:where(.kit-sheet[data-density=comfortable]) {
|
|
266
|
+
--kit-sheet-density-offset: var(--kit-density-comfortable);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
:where(.kit-sheet[data-density=spacious]) {
|
|
270
|
+
--kit-sheet-density-offset: var(--kit-density-spacious);
|
|
145
271
|
}</style>
|
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
style: any;
|
|
4
|
-
children: any;
|
|
5
|
-
elevation: any;
|
|
6
|
-
rounded: any;
|
|
7
|
-
variant?: string;
|
|
8
|
-
active: any;
|
|
9
|
-
color: any;
|
|
10
|
-
} & Record<string, any>, {}, "">;
|
|
1
|
+
import type { SheetProps } from './sheet.types.ts';
|
|
2
|
+
declare const Sheet: import("svelte").Component<SheetProps, {}, "ref">;
|
|
11
3
|
type Sheet = ReturnType<typeof Sheet>;
|
|
12
4
|
export default Sheet;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ColorProps, Component, ElevationProps, RoundedType } from '../../@types';
|
|
2
|
+
export interface SheetProps extends Component {
|
|
3
|
+
ref?: HTMLElement | null;
|
|
4
|
+
is?: 'div' | 'article' | 'section' | 'aside' | 'a' | 'button';
|
|
5
|
+
href?: string;
|
|
6
|
+
type?: 'button' | 'submit' | 'reset';
|
|
7
|
+
variant?: 'filled' | 'tonal' | 'outline' | 'text' | 'plain' | 'surface';
|
|
8
|
+
rounded?: RoundedType | 'full';
|
|
9
|
+
density?: 'dense' | 'compact' | 'default' | 'comfortable' | 'spacious';
|
|
10
|
+
elevation?: ElevationProps;
|
|
11
|
+
active?: boolean;
|
|
12
|
+
color?: ColorProps;
|
|
13
|
+
interactive?: boolean;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
noRipple?: boolean;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/utils/color.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ColorProps } from '../@types';
|
|
2
|
-
export declare function resolveColor(color: string | null | undefined): string | undefined;
|
|
3
|
-
export declare function resolveOnColor(color: string | null | undefined): string | undefined;
|
|
2
|
+
export declare function resolveColor(color: string | false | null | undefined): string | undefined;
|
|
3
|
+
export declare function resolveOnColor(color: string | false | null | undefined): string | undefined;
|
|
4
4
|
export declare function colorStyle(name: string, color: ColorProps | null | undefined, active?: boolean): string;
|
package/dist/utils/color.js
CHANGED
|
@@ -2,7 +2,8 @@ import { DEV } from 'esm-env';
|
|
|
2
2
|
const paletteName = /^[a-zA-Z][\w-]*$/;
|
|
3
3
|
const unsafe = /[;{}]/;
|
|
4
4
|
function clean(color) {
|
|
5
|
-
|
|
5
|
+
// color={isActive && 'accent'} gives false: only a string is a color
|
|
6
|
+
const value = typeof color === 'string' ? color.trim() : undefined;
|
|
6
7
|
if (!value)
|
|
7
8
|
return undefined;
|
|
8
9
|
if (unsafe.test(value)) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ColorProps, ComponentAttrs, ElevationProps, ElevationState, PropValue, SStyleProp,
|
|
1
|
+
import type { ColorProps, ComponentAttrs, ElevationProps, ElevationState, PropValue, SStyleProp, useStylesProps } from '../@types';
|
|
2
2
|
import type { ClassValue } from 'svelte/elements';
|
|
3
3
|
/**
|
|
4
4
|
* The classes of the s-class_xxx directives (class:xxx on a kit tag):
|
|
@@ -9,15 +9,6 @@ import type { ClassValue } from 'svelte/elements';
|
|
|
9
9
|
* - false, null, undefined and '' give nothing.
|
|
10
10
|
*/
|
|
11
11
|
export declare function directiveClasses(classProps: Record<string, PropValue> | undefined): string[];
|
|
12
|
-
/**
|
|
13
|
-
* useClassName - Utility to compute class names for a component.
|
|
14
|
-
* @param baseClass - The base class name for the component.
|
|
15
|
-
* @param className - Additional class names: a string or an array of strings.
|
|
16
|
-
* @param sClass - The s-class property which can be a string, array, or object.
|
|
17
|
-
* @param classProps - An object containing s-class_xxx directives.
|
|
18
|
-
* @returns A computed class string: no extra spaces, no duplicates, in the order of the inputs.
|
|
19
|
-
*/
|
|
20
|
-
export declare function useClassName({ baseClass, className, sClass, classProps }?: useClassNameProps): string;
|
|
21
12
|
export declare function useIsInteractive(props: Record<string, unknown>, tag: string, interactiveTags: readonly string[], interactive?: boolean): boolean;
|
|
22
13
|
/**
|
|
23
14
|
* useStyles - Utility to compute style declarations for a component (pure function).
|
|
@@ -58,3 +49,12 @@ export declare function useComponentAttrs(baseClass: string, { className, sClass
|
|
|
58
49
|
color?: ColorProps | null;
|
|
59
50
|
active?: boolean;
|
|
60
51
|
}, rest: Record<string, unknown>): ComponentAttrs;
|
|
52
|
+
/**
|
|
53
|
+
* splitAriaAttrs - Separates the aria-* attributes from the other attributes, for a component whose
|
|
54
|
+
* role is on another element than its content (dialog, modal).
|
|
55
|
+
* @param rest - The rest of the props of the component.
|
|
56
|
+
*/
|
|
57
|
+
export declare function splitAriaAttrs(rest: Record<string, unknown>): {
|
|
58
|
+
aria: Record<string, unknown>;
|
|
59
|
+
others: Record<string, unknown>;
|
|
60
|
+
};
|
package/dist/utils/components.js
CHANGED
|
@@ -3,8 +3,6 @@ import { makeComponentProps } from '../html-mapped';
|
|
|
3
3
|
import { colorStyle } from './color.js';
|
|
4
4
|
const endsWithSeparator = /[^a-zA-Z0-9]$/;
|
|
5
5
|
const startsWithSeparator = /^[^a-zA-Z0-9]/;
|
|
6
|
-
const whitespace = /\s/;
|
|
7
|
-
const whitespaces = /\s+/;
|
|
8
6
|
const propertyCache = new Map();
|
|
9
7
|
function hasKeys(value) {
|
|
10
8
|
if (!value || typeof value !== 'object')
|
|
@@ -15,39 +13,6 @@ function hasKeys(value) {
|
|
|
15
13
|
}
|
|
16
14
|
return false;
|
|
17
15
|
}
|
|
18
|
-
/**
|
|
19
|
-
* Adds the classes of a value (one or several, separated by spaces) to the set.
|
|
20
|
-
* The set keeps the first position of each class and drops the duplicates.
|
|
21
|
-
*/
|
|
22
|
-
function addClasses(classes, value) {
|
|
23
|
-
if (!whitespace.test(value)) {
|
|
24
|
-
if (value)
|
|
25
|
-
classes.add(value);
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
for (const name of value.split(whitespaces)) {
|
|
29
|
-
if (name)
|
|
30
|
-
classes.add(name);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Adds a class value with the rules of clsx (class on an element): a string, an array (nested too),
|
|
35
|
-
* or an object whose keys are added when their value is truthy. Joining an array would give "a,b"
|
|
36
|
-
*/
|
|
37
|
-
function addClassValue(classes, value) {
|
|
38
|
-
if (typeof value === 'string')
|
|
39
|
-
addClasses(classes, value);
|
|
40
|
-
else if (Array.isArray(value)) {
|
|
41
|
-
for (const item of value)
|
|
42
|
-
addClassValue(classes, item);
|
|
43
|
-
}
|
|
44
|
-
else if (value && typeof value === 'object') {
|
|
45
|
-
for (const key in value) {
|
|
46
|
-
if (value[key])
|
|
47
|
-
addClasses(classes, key);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
16
|
/**
|
|
52
17
|
* The classes of the s-class_xxx directives (class:xxx on a kit tag):
|
|
53
18
|
* - true gives the name (class:active -> active);
|
|
@@ -74,46 +39,6 @@ export function directiveClasses(classProps) {
|
|
|
74
39
|
}
|
|
75
40
|
return classes;
|
|
76
41
|
}
|
|
77
|
-
/**
|
|
78
|
-
* useClassName - Utility to compute class names for a component.
|
|
79
|
-
* @param baseClass - The base class name for the component.
|
|
80
|
-
* @param className - Additional class names: a string or an array of strings.
|
|
81
|
-
* @param sClass - The s-class property which can be a string, array, or object.
|
|
82
|
-
* @param classProps - An object containing s-class_xxx directives.
|
|
83
|
-
* @returns A computed class string: no extra spaces, no duplicates, in the order of the inputs.
|
|
84
|
-
*/
|
|
85
|
-
export function useClassName({ baseClass = '', className, sClass, classProps } = {}) {
|
|
86
|
-
if (!sClass && !className && !hasKeys(classProps))
|
|
87
|
-
return baseClass;
|
|
88
|
-
const classes = new Set();
|
|
89
|
-
if (baseClass)
|
|
90
|
-
addClasses(classes, baseClass);
|
|
91
|
-
if (typeof sClass === 'string') {
|
|
92
|
-
addClasses(classes, sClass);
|
|
93
|
-
}
|
|
94
|
-
else if (Array.isArray(sClass)) {
|
|
95
|
-
for (const value of sClass) {
|
|
96
|
-
if (typeof value === 'string')
|
|
97
|
-
addClasses(classes, value);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
else if (sClass && typeof sClass === 'object') {
|
|
101
|
-
for (const key in sClass) {
|
|
102
|
-
const value = sClass[key];
|
|
103
|
-
if (value === true)
|
|
104
|
-
addClasses(classes, key);
|
|
105
|
-
else if (typeof value === 'string')
|
|
106
|
-
addClasses(classes, value);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
if (classProps) {
|
|
110
|
-
for (const name of directiveClasses(classProps))
|
|
111
|
-
addClasses(classes, name);
|
|
112
|
-
}
|
|
113
|
-
if (className)
|
|
114
|
-
addClassValue(classes, className);
|
|
115
|
-
return [...classes].join(' ');
|
|
116
|
-
}
|
|
117
42
|
/**
|
|
118
43
|
* useIsInteractive - Utility to determine whether a component should behave as interactive:
|
|
119
44
|
* either explicitly flagged, rendered as an interactive tag (e.g. 'a', 'button'), or given
|
|
@@ -243,3 +168,19 @@ export function useComponentAttrs(baseClass, { className, sClass, styleAttr, sSt
|
|
|
243
168
|
rest: restProps
|
|
244
169
|
};
|
|
245
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* splitAriaAttrs - Separates the aria-* attributes from the other attributes, for a component whose
|
|
173
|
+
* role is on another element than its content (dialog, modal).
|
|
174
|
+
* @param rest - The rest of the props of the component.
|
|
175
|
+
*/
|
|
176
|
+
export function splitAriaAttrs(rest) {
|
|
177
|
+
const aria = {};
|
|
178
|
+
const others = {};
|
|
179
|
+
for (const key in rest) {
|
|
180
|
+
if (key.startsWith('aria-'))
|
|
181
|
+
aria[key] = rest[key];
|
|
182
|
+
else
|
|
183
|
+
others[key] = rest[key];
|
|
184
|
+
}
|
|
185
|
+
return { aria, others };
|
|
186
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export type FloatingSide = 'top' | 'bottom' | 'left' | 'right';
|
|
2
|
+
export type FloatingAlign = 'start' | 'center' | 'end';
|
|
3
|
+
/** An element, or a point of the viewport (the position of a pointer event) */
|
|
4
|
+
export type FloatingAnchor = HTMLElement | {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
};
|
|
8
|
+
export interface FloatingOptions {
|
|
9
|
+
anchor: FloatingAnchor | null | undefined;
|
|
10
|
+
/** false hides the element without removing it (default true) */
|
|
11
|
+
open?: boolean;
|
|
12
|
+
side?: FloatingSide;
|
|
13
|
+
align?: FloatingAlign;
|
|
14
|
+
/** space between the anchor and the floating element, in px */
|
|
15
|
+
offset?: number;
|
|
16
|
+
/** minimal space between the floating element and the edges of the viewport, in px */
|
|
17
|
+
padding?: number;
|
|
18
|
+
/** moves to the opposite side when there is not enough space */
|
|
19
|
+
flip?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface FloatingRect {
|
|
22
|
+
top: number;
|
|
23
|
+
right: number;
|
|
24
|
+
bottom: number;
|
|
25
|
+
left: number;
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
}
|
|
29
|
+
export interface FloatingPosition {
|
|
30
|
+
x: number;
|
|
31
|
+
y: number;
|
|
32
|
+
side: FloatingSide;
|
|
33
|
+
/** position of the center of the anchor along the floating element, for an arrow */
|
|
34
|
+
arrow: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* computeFloating - The position of a floating element next to an anchor (pure function).
|
|
38
|
+
* @param anchor - The rect of the anchor, in the viewport.
|
|
39
|
+
* @param size - The size of the floating element (offsetWidth / offsetHeight: not affected by a transform).
|
|
40
|
+
* @param viewport - The size of the viewport, without the scrollbars.
|
|
41
|
+
*/
|
|
42
|
+
export declare function computeFloating(anchor: FloatingRect, size: {
|
|
43
|
+
width: number;
|
|
44
|
+
height: number;
|
|
45
|
+
}, viewport: {
|
|
46
|
+
width: number;
|
|
47
|
+
height: number;
|
|
48
|
+
}, { side, align, offset, padding, flip }?: Omit<FloatingOptions, 'anchor'>): FloatingPosition;
|
|
49
|
+
/**
|
|
50
|
+
* floating - Shows an element in the top layer (Popover API) next to its anchor, and keeps it there.
|
|
51
|
+
* The element needs the popover attribute. It gets its position (left / top), its side (data-side)
|
|
52
|
+
* and the position of the arrow (--kit-floating-arrow).
|
|
53
|
+
* It follows the scroll of every ancestor, the resize of the viewport and the size of both elements.
|
|
54
|
+
*/
|
|
55
|
+
export declare function floating(node: HTMLElement, options: FloatingOptions): {
|
|
56
|
+
update(next: FloatingOptions): void;
|
|
57
|
+
destroy(): void;
|
|
58
|
+
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
const opposite = {
|
|
2
|
+
top: 'bottom',
|
|
3
|
+
bottom: 'top',
|
|
4
|
+
left: 'right',
|
|
5
|
+
right: 'left'
|
|
6
|
+
};
|
|
7
|
+
function clamp(value, min, max) {
|
|
8
|
+
return Math.min(Math.max(value, min), Math.max(min, max));
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* computeFloating - The position of a floating element next to an anchor (pure function).
|
|
12
|
+
* @param anchor - The rect of the anchor, in the viewport.
|
|
13
|
+
* @param size - The size of the floating element (offsetWidth / offsetHeight: not affected by a transform).
|
|
14
|
+
* @param viewport - The size of the viewport, without the scrollbars.
|
|
15
|
+
*/
|
|
16
|
+
export function computeFloating(anchor, size, viewport, { side = 'bottom', align = 'start', offset = 6, padding = 8, flip = true } = {}) {
|
|
17
|
+
const space = {
|
|
18
|
+
top: anchor.top - offset - padding,
|
|
19
|
+
bottom: viewport.height - anchor.bottom - offset - padding,
|
|
20
|
+
left: anchor.left - offset - padding,
|
|
21
|
+
right: viewport.width - anchor.right - offset - padding
|
|
22
|
+
};
|
|
23
|
+
const vertical = side === 'top' || side === 'bottom';
|
|
24
|
+
const needed = vertical ? size.height : size.width;
|
|
25
|
+
let resolvedSide = side;
|
|
26
|
+
if (flip && space[side] < needed && space[opposite[side]] > space[side]) {
|
|
27
|
+
resolvedSide = opposite[side];
|
|
28
|
+
}
|
|
29
|
+
let x;
|
|
30
|
+
let y;
|
|
31
|
+
if (vertical) {
|
|
32
|
+
y = resolvedSide === 'top' ? anchor.top - offset - size.height : anchor.bottom + offset;
|
|
33
|
+
x =
|
|
34
|
+
align === 'start'
|
|
35
|
+
? anchor.left
|
|
36
|
+
: align === 'end'
|
|
37
|
+
? anchor.right - size.width
|
|
38
|
+
: anchor.left + (anchor.width - size.width) / 2;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
x = resolvedSide === 'left' ? anchor.left - offset - size.width : anchor.right + offset;
|
|
42
|
+
y =
|
|
43
|
+
align === 'start'
|
|
44
|
+
? anchor.top
|
|
45
|
+
: align === 'end'
|
|
46
|
+
? anchor.bottom - size.height
|
|
47
|
+
: anchor.top + (anchor.height - size.height) / 2;
|
|
48
|
+
}
|
|
49
|
+
// shift: the floating element stays in the viewport
|
|
50
|
+
x = clamp(x, padding, viewport.width - size.width - padding);
|
|
51
|
+
y = clamp(y, padding, viewport.height - size.height - padding);
|
|
52
|
+
const arrow = vertical
|
|
53
|
+
? clamp(anchor.left + anchor.width / 2 - x, 8, size.width - 8)
|
|
54
|
+
: clamp(anchor.top + anchor.height / 2 - y, 8, size.height - 8);
|
|
55
|
+
return { x, y, side: resolvedSide, arrow };
|
|
56
|
+
}
|
|
57
|
+
function anchorRect(anchor) {
|
|
58
|
+
if (anchor instanceof HTMLElement)
|
|
59
|
+
return anchor.getBoundingClientRect();
|
|
60
|
+
return { top: anchor.y, right: anchor.x, bottom: anchor.y, left: anchor.x, width: 0, height: 0 };
|
|
61
|
+
}
|
|
62
|
+
function supportsPopover(node) {
|
|
63
|
+
return typeof node.showPopover === 'function';
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* floating - Shows an element in the top layer (Popover API) next to its anchor, and keeps it there.
|
|
67
|
+
* The element needs the popover attribute. It gets its position (left / top), its side (data-side)
|
|
68
|
+
* and the position of the arrow (--kit-floating-arrow).
|
|
69
|
+
* It follows the scroll of every ancestor, the resize of the viewport and the size of both elements.
|
|
70
|
+
*/
|
|
71
|
+
export function floating(node, options) {
|
|
72
|
+
let frame = 0;
|
|
73
|
+
function toggle() {
|
|
74
|
+
if (!supportsPopover(node))
|
|
75
|
+
return;
|
|
76
|
+
const shown = node.matches(':popover-open');
|
|
77
|
+
if (options.open !== false && !shown)
|
|
78
|
+
node.showPopover();
|
|
79
|
+
if (options.open === false && shown)
|
|
80
|
+
node.hidePopover();
|
|
81
|
+
}
|
|
82
|
+
function update() {
|
|
83
|
+
const { anchor, open, ...rest } = options;
|
|
84
|
+
if (open === false || !anchor || !node.isConnected)
|
|
85
|
+
return;
|
|
86
|
+
if (anchor instanceof HTMLElement && !anchor.isConnected)
|
|
87
|
+
return;
|
|
88
|
+
const position = computeFloating(anchorRect(anchor), { width: node.offsetWidth, height: node.offsetHeight }, {
|
|
89
|
+
width: document.documentElement.clientWidth,
|
|
90
|
+
height: document.documentElement.clientHeight
|
|
91
|
+
}, rest);
|
|
92
|
+
node.style.left = `${position.x}px`;
|
|
93
|
+
node.style.top = `${position.y}px`;
|
|
94
|
+
node.style.setProperty('--kit-floating-arrow', `${position.arrow}px`);
|
|
95
|
+
node.dataset.side = position.side;
|
|
96
|
+
}
|
|
97
|
+
function schedule() {
|
|
98
|
+
cancelAnimationFrame(frame);
|
|
99
|
+
frame = requestAnimationFrame(update);
|
|
100
|
+
}
|
|
101
|
+
toggle();
|
|
102
|
+
update();
|
|
103
|
+
// capture: the scroll of any ancestor, not only the window
|
|
104
|
+
window.addEventListener('scroll', schedule, { capture: true, passive: true });
|
|
105
|
+
window.addEventListener('resize', schedule, { passive: true });
|
|
106
|
+
const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(schedule);
|
|
107
|
+
observer?.observe(node);
|
|
108
|
+
if (options.anchor instanceof HTMLElement)
|
|
109
|
+
observer?.observe(options.anchor);
|
|
110
|
+
return {
|
|
111
|
+
update(next) {
|
|
112
|
+
if (next.anchor !== options.anchor) {
|
|
113
|
+
if (options.anchor instanceof HTMLElement)
|
|
114
|
+
observer?.unobserve(options.anchor);
|
|
115
|
+
if (next.anchor instanceof HTMLElement)
|
|
116
|
+
observer?.observe(next.anchor);
|
|
117
|
+
}
|
|
118
|
+
options = next;
|
|
119
|
+
toggle();
|
|
120
|
+
schedule();
|
|
121
|
+
},
|
|
122
|
+
destroy() {
|
|
123
|
+
cancelAnimationFrame(frame);
|
|
124
|
+
window.removeEventListener('scroll', schedule, { capture: true });
|
|
125
|
+
window.removeEventListener('resize', schedule);
|
|
126
|
+
observer?.disconnect();
|
|
127
|
+
if (supportsPopover(node) && node.matches(':popover-open'))
|
|
128
|
+
node.hidePopover();
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED