@noxlovette/material 0.4.8 → 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/animation/TransitionPatterns.stories.svelte +357 -0
- package/dist/animation/TransitionPatterns.stories.svelte.d.ts +3 -0
- package/dist/animation/containerTransform.d.ts +26 -12
- package/dist/animation/containerTransform.js +22 -138
- package/dist/animation/enterExit.d.ts +21 -3
- package/dist/animation/enterExit.js +69 -22
- package/dist/animation/index.d.ts +1 -1
- package/dist/animation/index.js +1 -1
- package/dist/animation/presence.svelte.d.ts +47 -0
- package/dist/animation/presence.svelte.js +84 -0
- package/dist/animation/sharedAxisTransition.d.ts +35 -37
- package/dist/animation/sharedAxisTransition.js +50 -22
- package/dist/animation/skeleton.d.ts +11 -0
- package/dist/animation/skeleton.js +23 -0
- package/dist/animation/spring.d.ts +61 -0
- package/dist/animation/spring.js +53 -0
- package/dist/animation/springValue.svelte.d.ts +22 -0
- package/dist/animation/springValue.svelte.js +42 -0
- package/dist/animation/transition.d.ts +3 -1
- package/dist/animation/transition.js +3 -1
- package/dist/attachments/clickOutside.d.ts +13 -0
- package/dist/attachments/clickOutside.js +18 -0
- package/dist/attachments/index.d.ts +1 -0
- package/dist/attachments/index.js +1 -0
- package/dist/components/buttons/FAB.svelte +23 -16
- package/dist/components/buttons/FABMenu.svelte +24 -29
- package/dist/components/buttons/FABMenu.svelte.d.ts +2 -1
- package/dist/components/buttons/FABMenuItem.svelte +23 -20
- package/dist/components/buttons/FABMenuItem.svelte.d.ts +5 -1
- package/dist/components/buttons/split-button/SplitButton.svelte +10 -17
- package/dist/components/buttons/split-button/theme.js +1 -1
- package/dist/components/buttons/types.d.ts +3 -3
- package/dist/components/cards/theme.js +1 -1
- package/dist/components/containers/bottom-sheet/BottomSheet.stories.svelte +8 -12
- package/dist/components/containers/bottom-sheet/BottomSheet.svelte +67 -55
- package/dist/components/containers/bottom-sheet/BottomSheet.svelte.d.ts +1 -1
- package/dist/components/containers/bottom-sheet/types.d.ts +8 -2
- package/dist/components/containers/context-menu/ContextMenu.svelte +23 -36
- package/dist/components/containers/context-menu/theme.js +2 -2
- package/dist/components/containers/dialogue/Dialogue.svelte +49 -65
- package/dist/components/containers/link-preview/LinkPreview.svelte +12 -23
- package/dist/components/containers/link-preview/theme.d.ts +3 -3
- package/dist/components/containers/menu/Menu.svelte +14 -21
- package/dist/components/containers/menu/MenuSub.svelte +10 -17
- package/dist/components/containers/pane/DraggablePane.svelte +90 -5
- package/dist/components/containers/pane/DraggablePane.svelte.d.ts +1 -1
- package/dist/components/containers/pane/theme.js +2 -2
- package/dist/components/containers/popover/Popover.svelte +31 -42
- package/dist/components/containers/popover/theme.d.ts +3 -3
- package/dist/components/containers/scroll-area/theme.js +2 -2
- package/dist/components/containers/side-sheet/SideSheet.stories.svelte +10 -15
- package/dist/components/containers/side-sheet/SideSheet.svelte +44 -44
- package/dist/components/containers/side-sheet/SideSheet.svelte.d.ts +4 -3
- package/dist/components/containers/side-sheet/types.d.ts +8 -2
- package/dist/components/date/DateField.svelte +85 -92
- package/dist/components/date/DateField.svelte.d.ts +2 -5
- package/dist/components/date/DateRangeField.svelte +113 -155
- package/dist/components/date/DateRangeField.svelte.d.ts +2 -5
- package/dist/components/date/theme.d.ts +95 -0
- package/dist/components/date/theme.js +99 -14
- package/dist/components/date/types.d.ts +13 -0
- package/dist/components/forms/checkbox/theme.js +2 -2
- package/dist/components/forms/command/theme.d.ts +3 -3
- package/dist/components/forms/command/theme.js +1 -1
- package/dist/components/forms/pin/theme.js +2 -2
- package/dist/components/forms/radio-group/theme.js +2 -2
- package/dist/components/forms/select/Select.svelte +42 -54
- package/dist/components/forms/select/theme.js +4 -4
- package/dist/components/forms/slider/Slider.svelte +144 -126
- package/dist/components/forms/slider/Slider.svelte.d.ts +3 -0
- package/dist/components/forms/slider/theme.d.ts +154 -48
- package/dist/components/forms/slider/theme.js +60 -20
- package/dist/components/forms/slider/types.d.ts +1 -1
- package/dist/components/forms/switch/theme.js +4 -4
- package/dist/components/forms/textfield/Textfield.svelte +1 -1
- package/dist/components/forms/textfield/theme.d.ts +9 -0
- package/dist/components/forms/textfield/theme.js +26 -9
- package/dist/components/forms/toggle-group/theme.js +1 -1
- package/dist/components/forms/tooltip/Tooltip.svelte +24 -35
- package/dist/components/nav/breadcrumb/theme.js +1 -1
- package/dist/components/nav/navbar/theme.js +2 -2
- package/dist/components/nav/rail/Rail.svelte +4 -5
- package/dist/components/nav/rail/theme.js +7 -7
- package/dist/components/nav/tabs/theme.js +1 -1
- package/dist/components/progress/CircularProgress.svelte +78 -4
- package/dist/components/progress/CircularProgress.svelte.d.ts +5 -0
- package/dist/components/progress/LinearProgress.svelte +70 -7
- package/dist/components/progress/LinearProgress.svelte.d.ts +5 -0
- package/dist/components/progress/WavyLinearProgress.svelte +27 -3
- package/dist/components/progress/WavyLinearProgress.svelte.d.ts +3 -0
- package/dist/components/progress/_wavy.d.ts +2 -0
- package/dist/components/progress/_wavy.js +3 -1
- package/dist/components/snackbar/Snackbar.svelte +13 -17
- package/dist/components/table/TableBody.svelte +3 -16
- package/dist/components/table/TableBody.svelte.d.ts +1 -5
- package/dist/components/table/TableHeader.svelte +1 -1
- package/dist/components/table/theme.js +1 -1
- package/dist/components/table/types.d.ts +0 -7
- package/dist/components/time/TimeField.stories.svelte +41 -0
- package/dist/components/time/TimeField.stories.svelte.d.ts +19 -0
- package/dist/components/time/TimeField.svelte +62 -61
- package/dist/components/toolbar/theme.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/styles/component.css +21 -22
- package/dist/styles/motion.css +317 -38
- package/dist/utils/Layer.svelte +16 -29
- package/dist/utils/icon/LoadingIndicator.svelte +61 -22
- package/dist/utils/icon/loadingShapes.d.ts +1 -0
- package/dist/utils/icon/loadingShapes.js +15 -0
- package/package.json +5 -2
- package/dist/actions/clickOutside.d.ts +0 -3
- package/dist/actions/clickOutside.js +0 -13
- package/dist/actions/floating.d.ts +0 -20
- package/dist/actions/floating.js +0 -87
- package/dist/actions/index.d.ts +0 -6
- package/dist/actions/index.js +0 -6
- package/dist/actions/keyboard.d.ts +0 -3
- package/dist/actions/keyboard.js +0 -14
- package/dist/actions/portal.d.ts +0 -3
- package/dist/actions/portal.js +0 -8
- package/dist/actions/positionFloating.d.ts +0 -10
- package/dist/actions/positionFloating.js +0 -59
- package/dist/actions/rovingFocusGroup.d.ts +0 -20
- package/dist/actions/rovingFocusGroup.js +0 -82
- package/dist/animation/easing.d.ts +0 -6
- package/dist/animation/easing.js +0 -78
- package/dist/animation/outroClass.d.ts +0 -3
- package/dist/animation/outroClass.js +0 -20
- package/dist/animation/transitionTypes.d.ts +0 -8
- package/dist/animation/transitionTypes.js +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { tv } from 'tailwind-variants';
|
|
2
2
|
export const rail = tv({
|
|
3
3
|
slots: {
|
|
4
|
-
base: 'py-12 hidden bg-md-sys-color-surface-container z-40 flex-col md:flex gap-6 transition-[width,padding,background-color]
|
|
4
|
+
base: 'py-12 hidden bg-md-sys-color-surface-container z-40 flex-col md:flex gap-6 transition-[width,padding,background-color] md-sys-motion-spatial',
|
|
5
5
|
items: 'flex flex-col gap-3 pt-6 scrollbar-none w-full overflow-x-hidden',
|
|
6
|
-
ghost: 'hidden md:block shrink-0 transition-[width]
|
|
6
|
+
ghost: 'hidden md:block shrink-0 transition-[width] md-sys-motion-spatial',
|
|
7
7
|
scrim: 'hidden md:block lg:hidden inset-0'
|
|
8
8
|
},
|
|
9
9
|
variants: {
|
|
@@ -41,11 +41,11 @@ export const rail = tv({
|
|
|
41
41
|
});
|
|
42
42
|
export const railElement = tv({
|
|
43
43
|
slots: {
|
|
44
|
-
base: 'group relative z-30 flex w-full transition-all
|
|
45
|
-
content: 'flex items-center min-w-0 rounded-full gap-0.5 py-1.5 transition-all
|
|
46
|
-
iconContainer: 'relative rounded-full items-center justify-center inline-flex transition-all
|
|
47
|
-
icon: 'text-[24px] transition-all
|
|
48
|
-
label: 'transition-all
|
|
44
|
+
base: 'group relative z-30 flex w-full transition-all md-sys-motion-spatial',
|
|
45
|
+
content: 'flex items-center min-w-0 rounded-full gap-0.5 py-1.5 transition-all md-sys-motion-spatial',
|
|
46
|
+
iconContainer: 'relative rounded-full items-center justify-center inline-flex transition-all md-sys-motion-spatial',
|
|
47
|
+
icon: 'text-[24px] transition-all md-sys-motion-spatial',
|
|
48
|
+
label: 'transition-all md-sys-motion-spatial whitespace-nowrap'
|
|
49
49
|
},
|
|
50
50
|
variants: {
|
|
51
51
|
active: {
|
|
@@ -2,7 +2,7 @@ import { tv } from 'tailwind-variants';
|
|
|
2
2
|
export const tabHolder = tv({
|
|
3
3
|
slots: {
|
|
4
4
|
base: 'relative flex w-full bg-md-sys-color-surface',
|
|
5
|
-
bar: 'absolute bottom-0 h-[3px] rounded-t-full bg-md-sys-color-primary transition-transform
|
|
5
|
+
bar: 'absolute bottom-0 h-[3px] rounded-t-full bg-md-sys-color-primary transition-transform md-sys-motion-fast-spatial'
|
|
6
6
|
},
|
|
7
7
|
variants: {
|
|
8
8
|
rounded: {
|
|
@@ -2,10 +2,18 @@
|
|
|
2
2
|
@component
|
|
3
3
|
Material 3 Circular Progress Indicator.
|
|
4
4
|
|
|
5
|
+
Determinate: the arc springs to each new `percent` on the slow effects spring (critically damped,
|
|
6
|
+
so progress never visibly runs backwards), with a gap separating it from the track.
|
|
7
|
+
Indeterminate: the arc's head and tail take turns springing ahead, so it grows, shrinks and
|
|
8
|
+
travels around the circle.
|
|
9
|
+
|
|
5
10
|
@see https://m3.material.io/components/progress-indicators/overview#circular-progress-indicators
|
|
6
11
|
-->
|
|
7
12
|
<script lang="ts">
|
|
8
13
|
import { Progress } from 'bits-ui';
|
|
14
|
+
import { animate, type AnimationPlaybackControls } from 'motion';
|
|
15
|
+
import { springTokens, springTransition } from '../../animation/spring.js';
|
|
16
|
+
import { SpringValue } from '../../animation/springValue.svelte.js';
|
|
9
17
|
|
|
10
18
|
let {
|
|
11
19
|
percent,
|
|
@@ -20,8 +28,69 @@ Material 3 Circular Progress Indicator.
|
|
|
20
28
|
thickness?: number;
|
|
21
29
|
} = $props();
|
|
22
30
|
|
|
23
|
-
|
|
24
|
-
|
|
31
|
+
/* M3: 4dp between the indicator and the track, measured between the rounded caps. */
|
|
32
|
+
const GAP_PX = 4;
|
|
33
|
+
/* Indeterminate arc lengths it grows to and shrinks back to. Not M3 values: tune by eye. */
|
|
34
|
+
const MIN_SWEEP_DEG = 20;
|
|
35
|
+
const MAX_SWEEP_DEG = 270;
|
|
36
|
+
|
|
37
|
+
const r = $derived(size / 2 - thickness / 2);
|
|
38
|
+
const circumference = $derived(Math.PI * r * 2);
|
|
39
|
+
/* Round caps overhang each end by half the stroke; the gap sits between those caps. */
|
|
40
|
+
const gapDeg = $derived((((GAP_PX + thickness) / r) * 180) / Math.PI);
|
|
41
|
+
|
|
42
|
+
const shown = new SpringValue(() => percent ?? 0, springTokens.slowEffects);
|
|
43
|
+
|
|
44
|
+
let head = $state(0);
|
|
45
|
+
let tail = $state(0);
|
|
46
|
+
|
|
47
|
+
$effect(() => {
|
|
48
|
+
if (percent != null) return;
|
|
49
|
+
let running = true;
|
|
50
|
+
let controls: AnimationPlaybackControls | undefined;
|
|
51
|
+
const spring = springTransition(springTokens.spatial);
|
|
52
|
+
|
|
53
|
+
(async () => {
|
|
54
|
+
let h = 0;
|
|
55
|
+
let t = 0;
|
|
56
|
+
while (running) {
|
|
57
|
+
controls = animate(h, t + MAX_SWEEP_DEG, { ...spring, onUpdate: (v) => (head = v) });
|
|
58
|
+
await controls;
|
|
59
|
+
h = t + MAX_SWEEP_DEG;
|
|
60
|
+
if (!running) break;
|
|
61
|
+
controls = animate(t, h - MIN_SWEEP_DEG, { ...spring, onUpdate: (v) => (tail = v) });
|
|
62
|
+
await controls;
|
|
63
|
+
t = h - MIN_SWEEP_DEG;
|
|
64
|
+
}
|
|
65
|
+
})();
|
|
66
|
+
|
|
67
|
+
return () => {
|
|
68
|
+
running = false;
|
|
69
|
+
controls?.stop();
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
/** An arc from `fromDeg`, `sweepDeg` long, as stroke-dash values (0° = 12 o'clock). */
|
|
74
|
+
const arc = (fromDeg: number, sweepDeg: number) => ({
|
|
75
|
+
dasharray: `${(Math.max(0, sweepDeg) / 360) * circumference} ${circumference}`,
|
|
76
|
+
dashoffset: (-(fromDeg % 360) / 360) * circumference,
|
|
77
|
+
// A zero-length dash with round caps still paints a dot.
|
|
78
|
+
opacity: sweepDeg > 0.5 ? 1 : 0
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const from = $derived(percent != null ? 0 : tail);
|
|
82
|
+
const sweep = $derived(percent != null ? (shown.current / 100) * 360 : head - tail);
|
|
83
|
+
|
|
84
|
+
const indicator = $derived(arc(from, sweep));
|
|
85
|
+
/* The track fills the rest of the circle, keeping a gap either side of the indicator. M3 draws
|
|
86
|
+
no track while indeterminate. */
|
|
87
|
+
const track = $derived(
|
|
88
|
+
percent == null
|
|
89
|
+
? arc(0, 0)
|
|
90
|
+
: indicator.opacity
|
|
91
|
+
? arc(from + sweep + gapDeg, 360 - sweep - gapDeg * 2)
|
|
92
|
+
: arc(0, 360)
|
|
93
|
+
);
|
|
25
94
|
</script>
|
|
26
95
|
|
|
27
96
|
<Progress.Root value={percent ?? null} max={100} data-cy="m3-circular-progress">
|
|
@@ -40,6 +109,10 @@ Material 3 Circular Progress Indicator.
|
|
|
40
109
|
{r}
|
|
41
110
|
stroke="var(--color-md-sys-color-secondary-container)"
|
|
42
111
|
stroke-width={thickness}
|
|
112
|
+
stroke-dasharray={track.dasharray}
|
|
113
|
+
stroke-dashoffset={track.dashoffset}
|
|
114
|
+
opacity={track.opacity}
|
|
115
|
+
stroke-linecap="round"
|
|
43
116
|
fill="none"
|
|
44
117
|
/>
|
|
45
118
|
<circle
|
|
@@ -48,8 +121,9 @@ Material 3 Circular Progress Indicator.
|
|
|
48
121
|
{r}
|
|
49
122
|
stroke="var(--color-md-sys-color-primary)"
|
|
50
123
|
stroke-width={thickness}
|
|
51
|
-
stroke-dasharray=
|
|
52
|
-
stroke-dashoffset={
|
|
124
|
+
stroke-dasharray={indicator.dasharray}
|
|
125
|
+
stroke-dashoffset={indicator.dashoffset}
|
|
126
|
+
opacity={indicator.opacity}
|
|
53
127
|
stroke-linecap="round"
|
|
54
128
|
fill="none"
|
|
55
129
|
/>
|
|
@@ -9,6 +9,11 @@ type $$ComponentProps = {
|
|
|
9
9
|
/**
|
|
10
10
|
* Material 3 Circular Progress Indicator.
|
|
11
11
|
*
|
|
12
|
+
* Determinate: the arc springs to each new `percent` on the slow effects spring (critically damped,
|
|
13
|
+
* so progress never visibly runs backwards), with a gap separating it from the track.
|
|
14
|
+
* Indeterminate: the arc's head and tail take turns springing ahead, so it grows, shrinks and
|
|
15
|
+
* travels around the circle.
|
|
16
|
+
*
|
|
12
17
|
* @see https://m3.material.io/components/progress-indicators/overview#circular-progress-indicators
|
|
13
18
|
*/
|
|
14
19
|
declare const CircularProgress: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
@@ -2,12 +2,20 @@
|
|
|
2
2
|
@component
|
|
3
3
|
Material 3 Linear Progress Indicator.
|
|
4
4
|
|
|
5
|
+
Determinate: the bar springs to each new `percent` on the slow effects spring (critically damped,
|
|
6
|
+
so progress never visibly runs backwards). Indeterminate: the bar's head and tail spring across
|
|
7
|
+
the track on springs of different stiffness, so it stretches out and catches up on every pass.
|
|
8
|
+
The track always keeps a gap either side of the bar.
|
|
9
|
+
|
|
5
10
|
@see https://m3.material.io/components/progress-indicators/overview#linear-progress-indicators
|
|
6
11
|
-->
|
|
7
12
|
<script lang="ts">
|
|
8
13
|
import clsx from 'clsx';
|
|
9
14
|
import { tv } from 'tailwind-variants';
|
|
10
15
|
import { Progress } from 'bits-ui';
|
|
16
|
+
import { animate, type AnimationPlaybackControls } from 'motion';
|
|
17
|
+
import { springTokens, springTransition } from '../../animation/spring.js';
|
|
18
|
+
import { SpringValue } from '../../animation/springValue.svelte.js';
|
|
11
19
|
|
|
12
20
|
let {
|
|
13
21
|
percent,
|
|
@@ -21,15 +29,58 @@ Material 3 Linear Progress Indicator.
|
|
|
21
29
|
class?: string;
|
|
22
30
|
} = $props();
|
|
23
31
|
|
|
32
|
+
/* M3: 4dp between the indicator and the track. */
|
|
33
|
+
const GAP_PX = 4;
|
|
34
|
+
|
|
24
35
|
const linearProgress = tv({
|
|
25
36
|
slots: {
|
|
26
|
-
container: '
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
container: 'relative overflow-hidden',
|
|
38
|
+
segment: 'absolute inset-y-0 rounded-full',
|
|
39
|
+
bar: 'bg-md-sys-color-primary',
|
|
40
|
+
track: 'bg-md-sys-color-secondary-container'
|
|
29
41
|
}
|
|
30
42
|
});
|
|
31
43
|
|
|
32
|
-
const { container,
|
|
44
|
+
const { container, segment, bar, track } = linearProgress();
|
|
45
|
+
|
|
46
|
+
const shown = new SpringValue(() => (percent ?? 0) / 100, springTokens.slowEffects);
|
|
47
|
+
|
|
48
|
+
/* Indeterminate pass: the head leads on the spatial spring, the tail trails on the slower one. */
|
|
49
|
+
let head = $state(0);
|
|
50
|
+
let tail = $state(0);
|
|
51
|
+
|
|
52
|
+
$effect(() => {
|
|
53
|
+
if (percent != null) return;
|
|
54
|
+
let running = true;
|
|
55
|
+
let controls: AnimationPlaybackControls[] = [];
|
|
56
|
+
|
|
57
|
+
(async () => {
|
|
58
|
+
while (running) {
|
|
59
|
+
head = 0;
|
|
60
|
+
tail = 0;
|
|
61
|
+
controls = [
|
|
62
|
+
animate(0, 1, {
|
|
63
|
+
...springTransition(springTokens.spatial),
|
|
64
|
+
onUpdate: (v) => (head = v)
|
|
65
|
+
}),
|
|
66
|
+
animate(0, 1, {
|
|
67
|
+
...springTransition(springTokens.slowSpatial),
|
|
68
|
+
onUpdate: (v) => (tail = v)
|
|
69
|
+
})
|
|
70
|
+
];
|
|
71
|
+
await Promise.all(controls);
|
|
72
|
+
}
|
|
73
|
+
})();
|
|
74
|
+
|
|
75
|
+
return () => {
|
|
76
|
+
running = false;
|
|
77
|
+
controls.forEach((c) => c.stop());
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const clamp01 = (v: number) => Math.min(1, Math.max(0, v));
|
|
82
|
+
const start = $derived(percent != null ? 0 : clamp01(tail));
|
|
83
|
+
const end = $derived(percent != null ? clamp01(shown.current) : clamp01(head));
|
|
33
84
|
</script>
|
|
34
85
|
|
|
35
86
|
<Progress.Root
|
|
@@ -39,8 +90,20 @@ Material 3 Linear Progress Indicator.
|
|
|
39
90
|
style="height: {height / 16}rem"
|
|
40
91
|
data-cy="m3-linear-progress"
|
|
41
92
|
>
|
|
42
|
-
{#if
|
|
43
|
-
<div
|
|
93
|
+
{#if start > 0}
|
|
94
|
+
<div
|
|
95
|
+
class={segment({ class: track() })}
|
|
96
|
+
style="left: 0; width: max(0px, calc({start} * 100% - {GAP_PX}px))"
|
|
97
|
+
></div>
|
|
98
|
+
{/if}
|
|
99
|
+
{#if end > start}
|
|
100
|
+
<div
|
|
101
|
+
class={segment({ class: bar() })}
|
|
102
|
+
style="left: calc({start} * 100%); width: calc({end - start} * 100%)"
|
|
103
|
+
></div>
|
|
44
104
|
{/if}
|
|
45
|
-
<div
|
|
105
|
+
<div
|
|
106
|
+
class={segment({ class: track() })}
|
|
107
|
+
style="right: 0; width: max(0px, calc({1 - end} * 100% - {end > start ? GAP_PX : 0}px))"
|
|
108
|
+
></div>
|
|
46
109
|
</Progress.Root>
|
|
@@ -8,6 +8,11 @@ type $$ComponentProps = {
|
|
|
8
8
|
/**
|
|
9
9
|
* Material 3 Linear Progress Indicator.
|
|
10
10
|
*
|
|
11
|
+
* Determinate: the bar springs to each new `percent` on the slow effects spring (critically damped,
|
|
12
|
+
* so progress never visibly runs backwards). Indeterminate: the bar's head and tail spring across
|
|
13
|
+
* the track on springs of different stiffness, so it stretches out and catches up on every pass.
|
|
14
|
+
* The track always keeps a gap either side of the bar.
|
|
15
|
+
*
|
|
11
16
|
* @see https://m3.material.io/components/progress-indicators/overview#linear-progress-indicators
|
|
12
17
|
*/
|
|
13
18
|
declare const LinearProgress: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
@component
|
|
3
3
|
Wavy linear progress indicator — a custom M3-inspired variant.
|
|
4
4
|
|
|
5
|
+
The wave travels continuously; the filled length springs to each new `percent` on the slow
|
|
6
|
+
effects spring (critically damped, so progress never visibly runs backwards).
|
|
7
|
+
|
|
5
8
|
@see https://m3.material.io/components/progress-indicators/overview
|
|
6
9
|
-->
|
|
7
10
|
<script lang="ts">
|
|
8
11
|
import { Progress } from 'bits-ui';
|
|
9
|
-
import {
|
|
12
|
+
import { animate } from 'motion';
|
|
13
|
+
import { springTokens } from '../../animation/spring.js';
|
|
14
|
+
import { SpringValue } from '../../animation/springValue.svelte.js';
|
|
15
|
+
import { linear, trackOpacity, WAVE_PERIOD_MS } from './_wavy.js';
|
|
10
16
|
|
|
11
17
|
let {
|
|
12
18
|
width = 600,
|
|
@@ -26,10 +32,28 @@ Wavy linear progress indicator — a custom M3-inspired variant.
|
|
|
26
32
|
class?: string;
|
|
27
33
|
} = $props();
|
|
28
34
|
|
|
35
|
+
const shown = new SpringValue(() => percent ?? 0, springTokens.slowEffects);
|
|
36
|
+
|
|
37
|
+
/* The wave's phase: a travelling wave moves at constant speed, one wavelength per period. */
|
|
38
|
+
let time = $state(0);
|
|
39
|
+
$effect(() => {
|
|
40
|
+
const controls = animate(0, WAVE_PERIOD_MS, {
|
|
41
|
+
duration: WAVE_PERIOD_MS / 1000,
|
|
42
|
+
ease: 'linear',
|
|
43
|
+
repeat: Infinity,
|
|
44
|
+
onUpdate: (v) => (time = v)
|
|
45
|
+
});
|
|
46
|
+
return () => controls.stop();
|
|
47
|
+
});
|
|
48
|
+
|
|
29
49
|
let left = $derived(thickness * 0.5);
|
|
30
50
|
let right = $derived(width - thickness * 0.5);
|
|
31
|
-
let percentX = $derived(
|
|
32
|
-
|
|
51
|
+
let percentX = $derived(
|
|
52
|
+
percent != null
|
|
53
|
+
? (Math.min(100, Math.max(0, shown.current)) / 100) * (right - left) + left
|
|
54
|
+
: left
|
|
55
|
+
);
|
|
56
|
+
let wavePath = $derived(linear(height / 2 - thickness / 2, height / 2, left, percentX, time));
|
|
33
57
|
</script>
|
|
34
58
|
|
|
35
59
|
<Progress.Root value={percent ?? null} max={100}>
|
|
@@ -12,6 +12,9 @@ type $$ComponentProps = {
|
|
|
12
12
|
/**
|
|
13
13
|
* Wavy linear progress indicator — a custom M3-inspired variant.
|
|
14
14
|
*
|
|
15
|
+
* The wave travels continuously; the filled length springs to each new `percent` on the slow
|
|
16
|
+
* effects spring (critically damped, so progress never visibly runs backwards).
|
|
17
|
+
*
|
|
15
18
|
* @see https://m3.material.io/components/progress-indicators/overview
|
|
16
19
|
*/
|
|
17
20
|
declare const WavyLinearProgress: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
/** One full wave cycle, in ms. */
|
|
2
|
+
export declare const WAVE_PERIOD_MS = 1000;
|
|
1
3
|
export declare const linear: (amp: number, center: number, from: number, to: number, time: number, cutoffTo?: number) => string;
|
|
2
4
|
export declare const trackOpacity: (right: number, x: number) => number;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/** One full wave cycle, in ms. */
|
|
2
|
+
export const WAVE_PERIOD_MS = 1000;
|
|
3
|
+
const frequencyT = (Math.PI * 2) / WAVE_PERIOD_MS;
|
|
2
4
|
const frequencyX = (Math.PI * 2) / 40;
|
|
3
5
|
const round2 = (x) => Math.round(x * 100) / 100;
|
|
4
6
|
const round1 = (x) => Math.round(x * 10) / 10;
|
|
@@ -9,8 +9,7 @@ Snackbars provide brief messages about app processes at the bottom of the screen
|
|
|
9
9
|
import type { SnackBarProps } from './types.js';
|
|
10
10
|
import Icon from '../../utils/icon/Icon.svelte';
|
|
11
11
|
import { Layer } from '../../utils/index.js';
|
|
12
|
-
import { enterExit } from '../../animation/
|
|
13
|
-
import { easeEmphasizedDecel, easeEmphasizedAccel } from '../../animation/easing.js';
|
|
12
|
+
import { enterExit, Presence } from '../../animation/index.js';
|
|
14
13
|
|
|
15
14
|
let {
|
|
16
15
|
message = $bindable(''),
|
|
@@ -49,6 +48,12 @@ Snackbars provide brief messages about app processes at the bottom of the screen
|
|
|
49
48
|
};
|
|
50
49
|
});
|
|
51
50
|
|
|
51
|
+
const snack = new Presence(() => Boolean(message) && !dismissed);
|
|
52
|
+
|
|
53
|
+
// Dismissing clears `message`; keep rendering the last one while the exit animation plays.
|
|
54
|
+
let lastMessage: SnackBarProps['message'] = '';
|
|
55
|
+
const shownMessage = $derived.by(() => (message ? (lastMessage = message) : lastMessage));
|
|
56
|
+
|
|
52
57
|
const {
|
|
53
58
|
base,
|
|
54
59
|
icon,
|
|
@@ -58,27 +63,18 @@ Snackbars provide brief messages about app processes at the bottom of the screen
|
|
|
58
63
|
} = $derived(snackbar({ fixed }));
|
|
59
64
|
</script>
|
|
60
65
|
|
|
61
|
-
{#if
|
|
66
|
+
{#if snack.mounted}
|
|
62
67
|
<div
|
|
63
68
|
class={base()}
|
|
64
69
|
data-cy="m3-snackbar"
|
|
65
70
|
{...restProps}
|
|
66
|
-
|
|
67
|
-
duration: 400,
|
|
68
|
-
easing: easeEmphasizedDecel,
|
|
69
|
-
mode: 'slide-up'
|
|
70
|
-
}}
|
|
71
|
-
out:enterExit={{
|
|
72
|
-
duration: 200,
|
|
73
|
-
easing: easeEmphasizedAccel,
|
|
74
|
-
mode: 'slide-up'
|
|
75
|
-
}}
|
|
71
|
+
{@attach snack.attach(enterExit.slideUp)}
|
|
76
72
|
>
|
|
77
|
-
{#if typeof
|
|
78
|
-
<p class={supportingText()}>{
|
|
79
|
-
{:else}
|
|
73
|
+
{#if typeof shownMessage === 'string'}
|
|
74
|
+
<p class={supportingText()}>{shownMessage}</p>
|
|
75
|
+
{:else if shownMessage}
|
|
80
76
|
<p class={supportingText()}>
|
|
81
|
-
{@render
|
|
77
|
+
{@render shownMessage()}
|
|
82
78
|
</p>
|
|
83
79
|
{/if}
|
|
84
80
|
|
|
@@ -1,30 +1,17 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
@component
|
|
3
|
-
Wraps the data rows of a Table.
|
|
4
|
-
stop on the table once (roving tabindex), and ArrowUp/ArrowDown or k/j move focus
|
|
5
|
-
between rows. Set `navigable={false}` to opt a purely presentational table out.
|
|
3
|
+
Wraps the data rows of a Table.
|
|
6
4
|
-->
|
|
7
5
|
<script lang="ts">
|
|
8
6
|
import type { TableBodyProps } from './types.js';
|
|
9
7
|
import { table } from './theme.js';
|
|
10
|
-
import { rovingFocusGroup } from '../../actions/index.js';
|
|
11
8
|
import clsx from 'clsx';
|
|
12
9
|
|
|
13
|
-
let {
|
|
14
|
-
children,
|
|
15
|
-
navigable = true,
|
|
16
|
-
loop = false,
|
|
17
|
-
class: className,
|
|
18
|
-
...restProps
|
|
19
|
-
}: TableBodyProps = $props();
|
|
10
|
+
let { children, class: className, ...restProps }: TableBodyProps = $props();
|
|
20
11
|
|
|
21
12
|
const { body } = table();
|
|
22
13
|
</script>
|
|
23
14
|
|
|
24
|
-
<tbody
|
|
25
|
-
class={body({ class: clsx(className) })}
|
|
26
|
-
use:rovingFocusGroup={{ candidateSelector: '[data-table-row]', loop, enabled: navigable }}
|
|
27
|
-
{...restProps}
|
|
28
|
-
>
|
|
15
|
+
<tbody class={body({ class: clsx(className) })} {...restProps}>
|
|
29
16
|
{@render children()}
|
|
30
17
|
</tbody>
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import type { TableBodyProps } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Wraps the data rows of a Table. Rows are keyboard-navigable by default: Tab/Shift+Tab
|
|
4
|
-
* stop on the table once (roving tabindex), and ArrowUp/ArrowDown or k/j move focus
|
|
5
|
-
* between rows. Set `navigable={false}` to opt a purely presentational table out.
|
|
6
|
-
*/
|
|
2
|
+
/** Wraps the data rows of a Table. */
|
|
7
3
|
declare const TableBody: import("svelte").Component<TableBodyProps, {}, "">;
|
|
8
4
|
type TableBody = ReturnType<typeof TableBody>;
|
|
9
5
|
export default TableBody;
|
|
@@ -30,7 +30,7 @@ and `sortDirection` props. Defaults to `scope="col"`.
|
|
|
30
30
|
{#if sortable}
|
|
31
31
|
<span
|
|
32
32
|
class={[
|
|
33
|
-
'transition-[opacity,transform]
|
|
33
|
+
'md-sys-motion-fast-spatial transition-[opacity,transform]',
|
|
34
34
|
sorted ? 'opacity-100' : 'opacity-0 group-hover:opacity-40',
|
|
35
35
|
sortDirection === 'desc' ? 'rotate-180' : 'rotate-0'
|
|
36
36
|
].join(' ')}
|
|
@@ -5,7 +5,7 @@ export const table = tv({
|
|
|
5
5
|
head: '',
|
|
6
6
|
body: '[&_tr:last-child]:border-b-0',
|
|
7
7
|
foot: 'border-t border-md-sys-color-outline-variant',
|
|
8
|
-
row: 'border-b border-md-sys-color-outline-variant transition-colors focus-visible:outline focus-visible:-outline-offset-2 focus-visible:outline-md-sys-color-primary',
|
|
8
|
+
row: 'border-b border-md-sys-color-outline-variant transition-colors md-sys-motion-fast-effects focus-visible:outline focus-visible:-outline-offset-2 focus-visible:outline-md-sys-color-primary',
|
|
9
9
|
cell: 'px-4 py-3 align-middle',
|
|
10
10
|
header: 'px-4 py-4 align-middle md-sys-typescale-label-large text-md-sys-color-on-surface font-medium whitespace-nowrap'
|
|
11
11
|
},
|
|
@@ -13,13 +13,6 @@ export type TableHeadProps = HTMLAttributes<HTMLTableSectionElement> & {
|
|
|
13
13
|
};
|
|
14
14
|
export type TableBodyProps = HTMLAttributes<HTMLTableSectionElement> & {
|
|
15
15
|
children: Snippet;
|
|
16
|
-
/**
|
|
17
|
-
* Make rows keyboard-navigable: roving tabindex so Tab/Shift+Tab stop on the table
|
|
18
|
-
* once, and ArrowUp/ArrowDown (or k/j) move focus between rows. Default `true`.
|
|
19
|
-
*/
|
|
20
|
-
navigable?: boolean;
|
|
21
|
-
/** Loop focus from the last row back to the first (and vice versa). Default `false`. */
|
|
22
|
-
loop?: boolean;
|
|
23
16
|
};
|
|
24
17
|
export type TableFootProps = HTMLAttributes<HTMLTableSectionElement> & {
|
|
25
18
|
children: Snippet;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
TimeField anchors its TimepickerInput overlay to the whole field via a bits-ui Popover
|
|
3
|
+
(`customAnchor`), so the panel is portaled, flips above the field when there's no room below,
|
|
4
|
+
and dismisses on outside click / Escape.
|
|
5
|
+
-->
|
|
6
|
+
<script module lang="ts">
|
|
7
|
+
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
8
|
+
import TimeField from './TimeField.svelte';
|
|
9
|
+
|
|
10
|
+
const { Story } = defineMeta({
|
|
11
|
+
title: 'Time/TimeField',
|
|
12
|
+
component: TimeField,
|
|
13
|
+
argTypes: {
|
|
14
|
+
label: { control: 'text' },
|
|
15
|
+
disabled: { control: 'boolean' },
|
|
16
|
+
error: { control: 'boolean' },
|
|
17
|
+
required: { control: 'boolean' }
|
|
18
|
+
},
|
|
19
|
+
args: {
|
|
20
|
+
label: 'Time',
|
|
21
|
+
value: '09:30',
|
|
22
|
+
disabled: false,
|
|
23
|
+
error: false,
|
|
24
|
+
required: false
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<Story name="Playground">
|
|
30
|
+
{#snippet template(args)}
|
|
31
|
+
<div class="max-w-xs p-8">
|
|
32
|
+
<TimeField {...args} />
|
|
33
|
+
</div>
|
|
34
|
+
{/snippet}
|
|
35
|
+
</Story>
|
|
36
|
+
|
|
37
|
+
<Story name="Near Bottom Edge" asChild>
|
|
38
|
+
<div class="flex min-h-dvh max-w-xs flex-col justify-end p-8">
|
|
39
|
+
<TimeField label="Time" value="18:45" />
|
|
40
|
+
</div>
|
|
41
|
+
</Story>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import TimeField from './TimeField.svelte';
|
|
2
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
+
$$bindings?: Bindings;
|
|
5
|
+
} & Exports;
|
|
6
|
+
(internal: unknown, props: {
|
|
7
|
+
$$events?: Events;
|
|
8
|
+
$$slots?: Slots;
|
|
9
|
+
}): Exports & {
|
|
10
|
+
$set?: any;
|
|
11
|
+
$on?: any;
|
|
12
|
+
};
|
|
13
|
+
z_$$bindings?: Bindings;
|
|
14
|
+
}
|
|
15
|
+
declare const TimeField: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
16
|
+
[evt: string]: CustomEvent<any>;
|
|
17
|
+
}, {}, {}, string>;
|
|
18
|
+
type TimeField = InstanceType<typeof TimeField>;
|
|
19
|
+
export default TimeField;
|