@noxlovette/material 0.4.8 → 0.5.1

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.
Files changed (144) hide show
  1. package/dist/animation/Shapes.stories.svelte +56 -0
  2. package/dist/animation/Shapes.stories.svelte.d.ts +3 -0
  3. package/dist/animation/TransitionPatterns.stories.svelte +359 -0
  4. package/dist/animation/TransitionPatterns.stories.svelte.d.ts +3 -0
  5. package/dist/animation/containerTransform.d.ts +35 -12
  6. package/dist/animation/containerTransform.js +31 -138
  7. package/dist/animation/enterExit.d.ts +30 -3
  8. package/dist/animation/enterExit.js +69 -22
  9. package/dist/animation/index.d.ts +2 -1
  10. package/dist/animation/index.js +2 -1
  11. package/dist/animation/presence.svelte.d.ts +47 -0
  12. package/dist/animation/presence.svelte.js +84 -0
  13. package/dist/animation/shapeMorph.svelte.d.ts +52 -0
  14. package/dist/animation/shapeMorph.svelte.js +112 -0
  15. package/dist/animation/shapesAnimatableSmall.d.ts +28 -22
  16. package/dist/animation/shapesAnimatableSmall.js +32 -23
  17. package/dist/animation/sharedAxisTransition.d.ts +57 -37
  18. package/dist/animation/sharedAxisTransition.js +74 -22
  19. package/dist/animation/skeleton.d.ts +16 -0
  20. package/dist/animation/skeleton.js +28 -0
  21. package/dist/animation/spring.d.ts +61 -0
  22. package/dist/animation/spring.js +53 -0
  23. package/dist/animation/springValue.svelte.d.ts +22 -0
  24. package/dist/animation/springValue.svelte.js +42 -0
  25. package/dist/animation/transition.d.ts +3 -1
  26. package/dist/animation/transition.js +3 -1
  27. package/dist/attachments/clickOutside.d.ts +13 -0
  28. package/dist/attachments/clickOutside.js +18 -0
  29. package/dist/attachments/index.d.ts +1 -0
  30. package/dist/attachments/index.js +1 -0
  31. package/dist/components/buttons/FAB.svelte +23 -16
  32. package/dist/components/buttons/FABMenu.svelte +24 -29
  33. package/dist/components/buttons/FABMenu.svelte.d.ts +2 -1
  34. package/dist/components/buttons/FABMenuItem.svelte +23 -20
  35. package/dist/components/buttons/FABMenuItem.svelte.d.ts +5 -1
  36. package/dist/components/buttons/split-button/SplitButton.svelte +10 -17
  37. package/dist/components/buttons/split-button/theme.js +1 -1
  38. package/dist/components/buttons/types.d.ts +3 -3
  39. package/dist/components/cards/theme.js +1 -1
  40. package/dist/components/containers/bottom-sheet/BottomSheet.stories.svelte +8 -12
  41. package/dist/components/containers/bottom-sheet/BottomSheet.svelte +67 -55
  42. package/dist/components/containers/bottom-sheet/BottomSheet.svelte.d.ts +1 -1
  43. package/dist/components/containers/bottom-sheet/types.d.ts +8 -2
  44. package/dist/components/containers/context-menu/ContextMenu.svelte +23 -36
  45. package/dist/components/containers/context-menu/theme.js +2 -2
  46. package/dist/components/containers/dialogue/Dialogue.svelte +49 -65
  47. package/dist/components/containers/link-preview/LinkPreview.svelte +12 -23
  48. package/dist/components/containers/link-preview/theme.d.ts +3 -3
  49. package/dist/components/containers/menu/Menu.svelte +14 -21
  50. package/dist/components/containers/menu/MenuSub.svelte +10 -17
  51. package/dist/components/containers/pane/DraggablePane.svelte +90 -5
  52. package/dist/components/containers/pane/DraggablePane.svelte.d.ts +1 -1
  53. package/dist/components/containers/pane/theme.js +2 -2
  54. package/dist/components/containers/popover/Popover.svelte +31 -42
  55. package/dist/components/containers/popover/theme.d.ts +3 -3
  56. package/dist/components/containers/scroll-area/theme.js +2 -2
  57. package/dist/components/containers/side-sheet/SideSheet.stories.svelte +10 -15
  58. package/dist/components/containers/side-sheet/SideSheet.svelte +44 -44
  59. package/dist/components/containers/side-sheet/SideSheet.svelte.d.ts +4 -3
  60. package/dist/components/containers/side-sheet/types.d.ts +8 -2
  61. package/dist/components/date/DateField.svelte +99 -92
  62. package/dist/components/date/DateField.svelte.d.ts +4 -5
  63. package/dist/components/date/DateRangeField.svelte +127 -155
  64. package/dist/components/date/DateRangeField.svelte.d.ts +4 -5
  65. package/dist/components/date/calendarMotion.d.ts +9 -0
  66. package/dist/components/date/calendarMotion.js +23 -0
  67. package/dist/components/date/theme.d.ts +95 -0
  68. package/dist/components/date/theme.js +103 -14
  69. package/dist/components/date/types.d.ts +13 -0
  70. package/dist/components/forms/checkbox/theme.js +2 -2
  71. package/dist/components/forms/command/theme.d.ts +3 -3
  72. package/dist/components/forms/command/theme.js +1 -1
  73. package/dist/components/forms/pin/theme.js +2 -2
  74. package/dist/components/forms/radio-group/theme.js +2 -2
  75. package/dist/components/forms/select/Select.svelte +42 -54
  76. package/dist/components/forms/select/theme.js +4 -4
  77. package/dist/components/forms/slider/Slider.svelte +144 -126
  78. package/dist/components/forms/slider/Slider.svelte.d.ts +3 -0
  79. package/dist/components/forms/slider/theme.d.ts +154 -48
  80. package/dist/components/forms/slider/theme.js +60 -20
  81. package/dist/components/forms/slider/types.d.ts +1 -1
  82. package/dist/components/forms/switch/theme.js +4 -4
  83. package/dist/components/forms/textfield/Textfield.svelte +1 -1
  84. package/dist/components/forms/textfield/theme.d.ts +12 -0
  85. package/dist/components/forms/textfield/theme.js +30 -10
  86. package/dist/components/forms/toggle-group/theme.js +1 -1
  87. package/dist/components/forms/tooltip/Tooltip.svelte +24 -35
  88. package/dist/components/nav/breadcrumb/theme.js +1 -1
  89. package/dist/components/nav/navbar/theme.js +2 -2
  90. package/dist/components/nav/rail/Rail.svelte +4 -5
  91. package/dist/components/nav/rail/theme.js +7 -7
  92. package/dist/components/nav/tabs/TabHolder.svelte +29 -3
  93. package/dist/components/nav/tabs/TabHolder.svelte.d.ts +3 -1
  94. package/dist/components/nav/tabs/theme.js +1 -1
  95. package/dist/components/progress/CircularProgress.svelte +78 -4
  96. package/dist/components/progress/CircularProgress.svelte.d.ts +5 -0
  97. package/dist/components/progress/LinearProgress.svelte +70 -7
  98. package/dist/components/progress/LinearProgress.svelte.d.ts +5 -0
  99. package/dist/components/progress/WavyLinearProgress.svelte +27 -3
  100. package/dist/components/progress/WavyLinearProgress.svelte.d.ts +3 -0
  101. package/dist/components/progress/_wavy.d.ts +2 -0
  102. package/dist/components/progress/_wavy.js +3 -1
  103. package/dist/components/snackbar/Snackbar.svelte +13 -17
  104. package/dist/components/table/TableBody.svelte +3 -16
  105. package/dist/components/table/TableBody.svelte.d.ts +1 -5
  106. package/dist/components/table/TableHeader.svelte +1 -1
  107. package/dist/components/table/theme.js +1 -1
  108. package/dist/components/table/types.d.ts +0 -7
  109. package/dist/components/time/TimeField.stories.svelte +41 -0
  110. package/dist/components/time/TimeField.stories.svelte.d.ts +19 -0
  111. package/dist/components/time/TimeField.svelte +69 -62
  112. package/dist/components/time/TimeField.svelte.d.ts +6 -0
  113. package/dist/components/time/TimepickerInput.svelte +8 -4
  114. package/dist/components/time/types.d.ts +11 -1
  115. package/dist/components/toolbar/theme.js +2 -2
  116. package/dist/index.d.ts +1 -1
  117. package/dist/index.js +1 -1
  118. package/dist/styles/component.css +21 -22
  119. package/dist/styles/motion.css +317 -38
  120. package/dist/utils/Layer.svelte +16 -29
  121. package/dist/utils/icon/LoadingIndicator.svelte +61 -22
  122. package/dist/utils/icon/loadingShapes.d.ts +1 -0
  123. package/dist/utils/icon/loadingShapes.js +16 -0
  124. package/package.json +5 -2
  125. package/dist/actions/clickOutside.d.ts +0 -3
  126. package/dist/actions/clickOutside.js +0 -13
  127. package/dist/actions/floating.d.ts +0 -20
  128. package/dist/actions/floating.js +0 -87
  129. package/dist/actions/index.d.ts +0 -6
  130. package/dist/actions/index.js +0 -6
  131. package/dist/actions/keyboard.d.ts +0 -3
  132. package/dist/actions/keyboard.js +0 -14
  133. package/dist/actions/portal.d.ts +0 -3
  134. package/dist/actions/portal.js +0 -8
  135. package/dist/actions/positionFloating.d.ts +0 -10
  136. package/dist/actions/positionFloating.js +0 -59
  137. package/dist/actions/rovingFocusGroup.d.ts +0 -20
  138. package/dist/actions/rovingFocusGroup.js +0 -82
  139. package/dist/animation/easing.d.ts +0 -6
  140. package/dist/animation/easing.js +0 -78
  141. package/dist/animation/outroClass.d.ts +0 -3
  142. package/dist/animation/outroClass.js +0 -20
  143. package/dist/animation/transitionTypes.d.ts +0 -8
  144. package/dist/animation/transitionTypes.js +0 -1
@@ -4,11 +4,17 @@ Material 3 Slider.
4
4
 
5
5
  Sliders allow users to make selections from a range of values.
6
6
 
7
+ The handle follows the pointer 1:1 while dragged; any other change (a keyboard step, a click on
8
+ the track, a new `value` from outside) springs to it on the fast spatial spring.
9
+
7
10
  @see https://m3.material.io/components/sliders/overview
8
11
  -->
9
12
  <script lang="ts">
10
13
  import { Slider } from 'bits-ui';
11
14
  import clsx from 'clsx';
15
+ import type { Attachment } from 'svelte/attachments';
16
+ import { springTokens } from '../../../animation/spring.js';
17
+ import { SpringValue } from '../../../animation/springValue.svelte.js';
12
18
  import { Icon } from '../../../utils/index.js';
13
19
  import { slider } from './theme.js';
14
20
  import type { SliderProps } from './types.js';
@@ -26,58 +32,120 @@ Sliders allow users to make selections from a range of values.
26
32
  stops = false,
27
33
  endStops = true,
28
34
  vertical = false,
29
- format = (n: number) => {
30
- return n.toFixed(0);
31
- },
35
+ format = (n: number) => n.toFixed(0),
32
36
  class: className,
33
37
  dir,
34
38
  id,
35
39
  ...extra
36
40
  }: SliderProps = $props();
37
41
 
38
- const {
39
- root,
40
- leadingIcon,
41
- leadingIconPop,
42
- trailingIcon,
43
- trailingIconPop,
44
- trackFill,
45
- trackRest,
46
- stopBase,
47
- stopFill,
48
- stopRest,
49
- handle: handleCls,
50
- value: valueCls
51
- } = $derived(slider({ size, vertical }));
52
-
53
- const sliderDir = $derived(dir === null || dir === 'auto' ? undefined : dir);
54
- const sliderId = $derived(id === null ? undefined : id);
42
+ /* M3 slider geometry, in px. */
43
+ const HANDLE_PX = 4;
44
+ const GAP_PX = 6;
45
+ const ICON_PADDING_PX = 8;
46
+ /* Stops closer than this to the handle's center are hidden under its gap. */
47
+ const STOP_CLEARANCE_PX = HANDLE_PX / 2 + GAP_PX;
55
48
 
56
- let offsetWidth = $state(600);
57
- let offsetHeight = $state(600);
58
- let inlineSize = $derived(vertical ? offsetHeight : offsetWidth);
49
+ const iconSize = $derived(size === 'xl' ? 'lg' : 'md');
50
+ const iconPx = $derived(size === 'xl' ? 40 : 24);
59
51
 
52
+ const stepValue = $derived(typeof step === 'number' ? step : undefined);
60
53
  const range = $derived(max - min);
61
- const handlePosition = $derived((value - min) / (range || 1));
62
- const stopList = $derived.by(() => {
63
- const output: number[] = [];
64
- const add = (stopValue: number) => {
65
- if (leadingIconProps && stopValue == 0) return;
66
- if (trailingIconProps && stopValue == 1) return;
67
- output.push(stopValue);
54
+ const toFraction = (v: number) => (range > 0 ? (v - min) / range : 0);
55
+
56
+ /* ---- motion ---------------------------------------------------------------------------- */
57
+
58
+ /*
59
+ A press that jumps the value (a click on the track) springs; once the pointer moves while
60
+ pressed, the handle is being dragged and tracks it directly.
61
+ */
62
+ let dragging = $state(false);
63
+
64
+ const trackDrag: Attachment<HTMLElement> = (node) => {
65
+ const move = () => (dragging = true);
66
+ const release = () => {
67
+ dragging = false;
68
+ window.removeEventListener('pointermove', move);
69
+ window.removeEventListener('pointerup', release);
70
+ window.removeEventListener('pointercancel', release);
71
+ };
72
+ const press = () => {
73
+ if (disabled) return;
74
+ window.addEventListener('pointermove', move);
75
+ window.addEventListener('pointerup', release);
76
+ window.addEventListener('pointercancel', release);
77
+ };
78
+ node.addEventListener('pointerdown', press);
79
+ return () => {
80
+ node.removeEventListener('pointerdown', press);
81
+ release();
68
82
  };
83
+ };
69
84
 
70
- if (stops && typeof step == 'number' && range > 0) {
71
- for (let i = 0; i <= range; i += step) add(i / range);
72
- }
73
- if (endStops && !output.includes(1)) {
74
- add(1);
75
- }
85
+ /** The rendered position as a 0–1 fraction; springs towards `value` unless dragging. */
86
+ const fraction = new SpringValue(
87
+ () => toFraction(value),
88
+ springTokens.fastSpatial,
89
+ () => dragging
90
+ );
76
91
 
77
- return output;
92
+ /* The spring may overshoot the ends; the track can't. */
93
+ const pos = $derived(Math.min(1, Math.max(0, fraction.current)));
94
+
95
+ /* ---- geometry -------------------------------------------------------------------------- */
96
+
97
+ let trackWidth = $state(0);
98
+ let trackHeight = $state(0);
99
+ const length = $derived(vertical ? trackHeight : trackWidth);
100
+
101
+ const start = $derived(vertical ? 'bottom' : 'left');
102
+ const extent = $derived(vertical ? 'height' : 'width');
103
+
104
+ /** Handle center: travels the track inset by half a handle so it never overhangs the ends. */
105
+ const center = (f: number) => `calc(${HANDLE_PX / 2}px + ${f} * (100% - ${HANDLE_PX}px))`;
106
+ const centerPx = $derived(HANDLE_PX / 2 + pos * (length - HANDLE_PX));
107
+
108
+ const activePx = $derived(centerPx - HANDLE_PX / 2 - GAP_PX);
109
+ const inactivePx = $derived(length - centerPx - HANDLE_PX / 2 - GAP_PX);
110
+
111
+ const activeStyle = $derived(
112
+ `${extent}: max(0px, calc(${pos} * (100% - ${HANDLE_PX}px) - ${GAP_PX}px))`
113
+ );
114
+ const inactiveStyle = $derived(
115
+ `${extent}: max(0px, calc(${1 - pos} * (100% - ${HANDLE_PX}px) - ${GAP_PX}px))`
116
+ );
117
+
118
+ /* Stops sit inset by half the track thickness so the end stops land in the rounded caps. */
119
+ const stopList = $derived.by(() => {
120
+ const output: number[] = [];
121
+ if (stops && stepValue && range > 0) {
122
+ for (let v = min; v <= max; v += stepValue) output.push(toFraction(v));
123
+ } else if (endStops) {
124
+ output.push(1);
125
+ }
126
+ return output.filter((s) => {
127
+ if (leadingIconProps && s === 0) return false;
128
+ if (trailingIconProps && s === 1) return false;
129
+ return !length || Math.abs(s - pos) * length > STOP_CLEARANCE_PX;
130
+ });
78
131
  });
79
132
 
80
- const stepValue = $derived(typeof step === 'number' ? step : undefined);
133
+ /* Icons ride inside their track; when it gets too short they hop across the handle. */
134
+ const iconFits = (trackPx: number) => trackPx >= iconPx + ICON_PADDING_PX * 2;
135
+ const leadingOnActive = $derived(!length || iconFits(activePx));
136
+ const trailingOnInactive = $derived(!length || iconFits(inactivePx));
137
+
138
+ const leadingOffset = $derived(
139
+ leadingOnActive ? ICON_PADDING_PX : centerPx + HANDLE_PX / 2 + GAP_PX + ICON_PADDING_PX
140
+ );
141
+ const trailingOffset = $derived(
142
+ trailingOnInactive
143
+ ? length - ICON_PADDING_PX - iconPx
144
+ : centerPx - HANDLE_PX / 2 - GAP_PX - ICON_PADDING_PX - iconPx
145
+ );
146
+
147
+ const sliderDir = $derived(dir === null || dir === 'auto' ? undefined : dir);
148
+ const sliderId = $derived(id === null ? undefined : id);
81
149
  </script>
82
150
 
83
151
  <Slider.Root
@@ -93,109 +161,59 @@ Sliders allow users to make selections from a range of values.
93
161
  {...extra}
94
162
  >
95
163
  {#snippet child({ props })}
164
+ {@const cls = slider({ size, vertical, active: dragging })}
96
165
  <div
97
166
  {...props}
98
- class={root({ class: clsx(className) })}
99
- style="--handle: {handlePosition - 0.5}; {props.style ?? ''}"
167
+ class={cls.root({ class: clsx(className) })}
168
+ bind:clientWidth={trackWidth}
169
+ bind:clientHeight={trackHeight}
170
+ {@attach trackDrag}
100
171
  >
101
- <div
102
- class="pointer-events-none absolute inset-0"
103
- bind:offsetWidth
104
- bind:offsetHeight
105
- aria-hidden="true"
106
- ></div>
107
-
108
- <div
109
- class={trackFill({
110
- class: clsx(
111
- vertical &&
112
- '[clip-path:inset(calc(100%-var(--handle-left))_0_0_0_round_var(--m3-slider-track-in-shape)_var(--m3-slider-track-in-shape)_var(--track-radius)_var(--track-radius))]'
113
- )
114
- })}
115
- >
116
- {#each stopList as stop}
117
- <div
118
- class={clsx(
119
- stopBase(),
120
- stopFill(),
121
- vertical ? '-translate-x-1/2 translate-y-1/2' : '-translate-x-1/2 -translate-y-1/2'
122
- )}
123
- style:--x={stop - 0.5}
124
- ></div>
125
- {/each}
126
- </div>
127
-
128
- <div
129
- class={trackRest({
130
- class: clsx(
131
- vertical &&
132
- '[clip-path:inset(0_0_var(--handle-right)_0_round_var(--track-radius)_var(--track-radius)_var(--m3-slider-track-in-shape)_var(--m3-slider-track-in-shape))]'
133
- )
134
- })}
135
- >
136
- {#each stopList as stop}
137
- <div
138
- class={clsx(
139
- stopBase(),
140
- stopRest(),
141
- vertical ? '-translate-x-1/2 translate-y-1/2' : '-translate-x-1/2 -translate-y-1/2'
142
- )}
143
- style:--x={stop - 0.5}
144
- ></div>
145
- {/each}
146
- </div>
172
+ <div class={cls.track({ class: cls.activeTrack() })} style={activeStyle}></div>
173
+ <div class={cls.track({ class: cls.inactiveTrack() })} style={inactiveStyle}></div>
174
+
175
+ {#each stopList as s (s)}
176
+ <div
177
+ class={cls.stop({ class: s < pos ? cls.stopOnActive() : cls.stopOnInactive() })}
178
+ style="{start}: calc(var(--track) / 2 + {s} * (100% - var(--track)))"
179
+ ></div>
180
+ {/each}
147
181
 
148
182
  {#if leadingIconProps}
149
- <Icon
150
- class={leadingIcon({
151
- class: clsx(
152
- leadingIconProps.class,
153
- inlineSize * handlePosition < (size == 'xl' ? 48 : 40) && leadingIconPop(),
154
- vertical && 'translate-x-[-50%] translate-y-0'
155
- )
156
- })}
157
- {...leadingIconProps}
158
- />
183
+ <span
184
+ class={cls.icon({ class: leadingOnActive ? cls.iconOnActive() : cls.iconOnInactive() })}
185
+ style="{start}: {leadingOffset}px"
186
+ >
187
+ <Icon size={iconSize} {...leadingIconProps} />
188
+ </span>
159
189
  {/if}
160
190
  {#if trailingIconProps}
161
- <Icon
162
- class={trailingIcon({
163
- class: clsx(
164
- trailingIconProps.class,
165
- inlineSize * (1 - handlePosition) < (size == 'xl' ? 48 : 40) && trailingIconPop(),
166
- vertical && 'translate-x-[-50%] translate-y-0'
167
- )
191
+ <span
192
+ class={cls.icon({
193
+ class: trailingOnInactive ? cls.iconOnInactive() : cls.iconOnActive()
168
194
  })}
169
- {...trailingIconProps}
170
- />
195
+ style="{start}: {trailingOffset}px"
196
+ >
197
+ <Icon size={iconSize} {...trailingIconProps} />
198
+ </span>
171
199
  {/if}
172
200
 
173
- <Slider.Thumb
174
- index={0}
175
- class={handleCls({
176
- class: clsx(vertical ? 'translate-y-1/2' : '-translate-x-1/2')
177
- })}
178
- />
201
+ <Slider.Thumb index={0}>
202
+ {#snippet child({ props: thumbProps, active })}
203
+ <div
204
+ {...thumbProps}
205
+ class={cls.handle()}
206
+ data-active={active || undefined}
207
+ style="{start}: {center(pos)}"
208
+ ></div>
209
+ {/snippet}
210
+ </Slider.Thumb>
179
211
 
180
212
  {#if showValue}
181
- <div
182
- class={valueCls({
183
- class: clsx(vertical ? 'translate-x-0 translate-y-1/2 rotate-90' : '-translate-x-1/2')
184
- })}
185
- >
213
+ <div class={cls.value()} style="{start}: {center(pos)}" aria-hidden="true">
186
214
  {format(value)}
187
215
  </div>
188
216
  {/if}
189
217
  </div>
190
218
  {/snippet}
191
219
  </Slider.Root>
192
-
193
- <style>
194
- @layer tokens {
195
- :root {
196
- --m3-slider-track-out-shape: 0.5rem;
197
- --m3-slider-track-in-shape: 0.125rem;
198
- --m3-slider-handle-shape: calc(infinity * 1px);
199
- }
200
- }
201
- </style>
@@ -5,6 +5,9 @@ import type { SliderProps } from './types.js';
5
5
  *
6
6
  * Sliders allow users to make selections from a range of values.
7
7
  *
8
+ * The handle follows the pointer 1:1 while dragged; any other change (a keyboard step, a click on
9
+ * the track, a new `value` from outside) springs to it on the fast spatial spring.
10
+ *
8
11
  * @see https://m3.material.io/components/sliders/overview
9
12
  */
10
13
  declare const Slider: import("svelte").Component<SliderProps, {}, "value">;
@@ -1,77 +1,183 @@
1
1
  import { type VariantProps } from 'tailwind-variants';
2
+ /**
3
+ * M3 Expressive slider: an active and an inactive track separated from a bar handle by a 6dp gap.
4
+ * Track/handle positions are set inline by `Slider.svelte` from one animated value; these slots
5
+ * only carry size, shape and color.
6
+ *
7
+ * https://m3.material.io/components/sliders/specs
8
+ */
2
9
  export declare const slider: import("tailwind-variants").TVReturnType<{
3
10
  size: {
4
- xs: "[--track-height:1rem] [--handle-height:2.75rem] [--track-radius:var(--m3-shape-small)] [--icon-size:0]";
5
- s: "[--track-height:1.5rem] [--handle-height:2.75rem] [--track-radius:var(--m3-shape-small)] [--icon-size:0]";
6
- m: "[--track-height:2.5rem] [--handle-height:3.25rem] [--track-radius:var(--m3-shape-medium)] [--icon-size:1.5rem]";
7
- l: "[--track-height:3.5rem] [--handle-height:4.25rem] [--track-radius:var(--m3-shape-large)] [--icon-size:1.5rem]";
8
- xl: "[--track-height:6rem] [--handle-height:6.75rem] [--track-radius:var(--m3-shape-extra-large)] [--icon-size:2rem]";
11
+ xs: {
12
+ root: string;
13
+ };
14
+ s: {
15
+ root: string;
16
+ };
17
+ m: {
18
+ root: string;
19
+ };
20
+ l: {
21
+ root: string;
22
+ };
23
+ xl: {
24
+ root: string;
25
+ };
9
26
  };
10
27
  vertical: {
11
- true: "[writing-mode:sideways-lr]";
28
+ false: {
29
+ root: string;
30
+ track: string;
31
+ activeTrack: string;
32
+ inactiveTrack: string;
33
+ stop: string;
34
+ icon: string;
35
+ handle: string;
36
+ value: string;
37
+ };
38
+ true: {
39
+ root: string;
40
+ track: string;
41
+ activeTrack: string;
42
+ inactiveTrack: string;
43
+ stop: string;
44
+ icon: string;
45
+ handle: string;
46
+ value: string;
47
+ };
48
+ };
49
+ active: {
50
+ true: {
51
+ value: string;
52
+ };
12
53
  };
13
54
  }, {
14
55
  root: string;
15
- input: string;
16
- leadingIcon: string;
17
- leadingIconPop: string;
18
- trailingIcon: string;
19
- trailingIconPop: string;
20
- trackFill: string;
21
- trackRest: string;
22
- stopBase: string;
23
- stopFill: string;
24
- stopRest: string;
56
+ track: string;
57
+ activeTrack: string;
58
+ inactiveTrack: string;
59
+ stop: string;
60
+ stopOnActive: string;
61
+ stopOnInactive: string;
62
+ icon: string;
63
+ iconOnActive: string;
64
+ iconOnInactive: string;
25
65
  handle: string;
26
66
  value: string;
27
67
  }, undefined, {
28
68
  size: {
29
- xs: "[--track-height:1rem] [--handle-height:2.75rem] [--track-radius:var(--m3-shape-small)] [--icon-size:0]";
30
- s: "[--track-height:1.5rem] [--handle-height:2.75rem] [--track-radius:var(--m3-shape-small)] [--icon-size:0]";
31
- m: "[--track-height:2.5rem] [--handle-height:3.25rem] [--track-radius:var(--m3-shape-medium)] [--icon-size:1.5rem]";
32
- l: "[--track-height:3.5rem] [--handle-height:4.25rem] [--track-radius:var(--m3-shape-large)] [--icon-size:1.5rem]";
33
- xl: "[--track-height:6rem] [--handle-height:6.75rem] [--track-radius:var(--m3-shape-extra-large)] [--icon-size:2rem]";
69
+ xs: {
70
+ root: string;
71
+ };
72
+ s: {
73
+ root: string;
74
+ };
75
+ m: {
76
+ root: string;
77
+ };
78
+ l: {
79
+ root: string;
80
+ };
81
+ xl: {
82
+ root: string;
83
+ };
34
84
  };
35
85
  vertical: {
36
- true: "[writing-mode:sideways-lr]";
86
+ false: {
87
+ root: string;
88
+ track: string;
89
+ activeTrack: string;
90
+ inactiveTrack: string;
91
+ stop: string;
92
+ icon: string;
93
+ handle: string;
94
+ value: string;
95
+ };
96
+ true: {
97
+ root: string;
98
+ track: string;
99
+ activeTrack: string;
100
+ inactiveTrack: string;
101
+ stop: string;
102
+ icon: string;
103
+ handle: string;
104
+ value: string;
105
+ };
106
+ };
107
+ active: {
108
+ true: {
109
+ value: string;
110
+ };
37
111
  };
38
112
  }, {
39
113
  root: string;
40
- input: string;
41
- leadingIcon: string;
42
- leadingIconPop: string;
43
- trailingIcon: string;
44
- trailingIconPop: string;
45
- trackFill: string;
46
- trackRest: string;
47
- stopBase: string;
48
- stopFill: string;
49
- stopRest: string;
114
+ track: string;
115
+ activeTrack: string;
116
+ inactiveTrack: string;
117
+ stop: string;
118
+ stopOnActive: string;
119
+ stopOnInactive: string;
120
+ icon: string;
121
+ iconOnActive: string;
122
+ iconOnInactive: string;
50
123
  handle: string;
51
124
  value: string;
52
125
  }, import("tailwind-variants").TVReturnTypeLike<{
53
126
  size: {
54
- xs: "[--track-height:1rem] [--handle-height:2.75rem] [--track-radius:var(--m3-shape-small)] [--icon-size:0]";
55
- s: "[--track-height:1.5rem] [--handle-height:2.75rem] [--track-radius:var(--m3-shape-small)] [--icon-size:0]";
56
- m: "[--track-height:2.5rem] [--handle-height:3.25rem] [--track-radius:var(--m3-shape-medium)] [--icon-size:1.5rem]";
57
- l: "[--track-height:3.5rem] [--handle-height:4.25rem] [--track-radius:var(--m3-shape-large)] [--icon-size:1.5rem]";
58
- xl: "[--track-height:6rem] [--handle-height:6.75rem] [--track-radius:var(--m3-shape-extra-large)] [--icon-size:2rem]";
127
+ xs: {
128
+ root: string;
129
+ };
130
+ s: {
131
+ root: string;
132
+ };
133
+ m: {
134
+ root: string;
135
+ };
136
+ l: {
137
+ root: string;
138
+ };
139
+ xl: {
140
+ root: string;
141
+ };
59
142
  };
60
143
  vertical: {
61
- true: "[writing-mode:sideways-lr]";
144
+ false: {
145
+ root: string;
146
+ track: string;
147
+ activeTrack: string;
148
+ inactiveTrack: string;
149
+ stop: string;
150
+ icon: string;
151
+ handle: string;
152
+ value: string;
153
+ };
154
+ true: {
155
+ root: string;
156
+ track: string;
157
+ activeTrack: string;
158
+ inactiveTrack: string;
159
+ stop: string;
160
+ icon: string;
161
+ handle: string;
162
+ value: string;
163
+ };
164
+ };
165
+ active: {
166
+ true: {
167
+ value: string;
168
+ };
62
169
  };
63
170
  }, {
64
171
  root: string;
65
- input: string;
66
- leadingIcon: string;
67
- leadingIconPop: string;
68
- trailingIcon: string;
69
- trailingIconPop: string;
70
- trackFill: string;
71
- trackRest: string;
72
- stopBase: string;
73
- stopFill: string;
74
- stopRest: string;
172
+ track: string;
173
+ activeTrack: string;
174
+ inactiveTrack: string;
175
+ stop: string;
176
+ stopOnActive: string;
177
+ stopOnInactive: string;
178
+ icon: string;
179
+ iconOnActive: string;
180
+ iconOnInactive: string;
75
181
  handle: string;
76
182
  value: string;
77
183
  }>>;
@@ -1,33 +1,73 @@
1
1
  import { tv } from 'tailwind-variants';
2
+ /**
3
+ * M3 Expressive slider: an active and an inactive track separated from a bar handle by a 6dp gap.
4
+ * Track/handle positions are set inline by `Slider.svelte` from one animated value; these slots
5
+ * only carry size, shape and color.
6
+ *
7
+ * https://m3.material.io/components/sliders/specs
8
+ */
2
9
  export const slider = tv({
3
10
  slots: {
4
- root: 'slider-root group relative block min-w-40 [block-size:var(--handle-height)] [print-color-adjust:exact] [--m3-slider-track-out-shape:0.5rem] [--m3-slider-track-in-shape:0.125rem] [--m3-slider-handle-shape:var(--m3-shape-full)] [--functional-width:calc(100%-2*(0.25rem+0.125rem))] [--handle-left:calc(50%+var(--functional-width)*var(--handle)-0.125rem-0.375rem)] [--handle-center:calc(50%+var(--functional-width)*var(--handle))] [--handle-right:calc(50%+var(--functional-width)*var(--handle)+0.125rem+0.375rem)] cursor-pointer data-[disabled]:cursor-not-allowed',
5
- input: 'peer absolute left-1/2 [inline-size:calc(var(--functional-width)+1rem)] [block-size:100%] -translate-x-1/2 appearance-none opacity-0 m-0 enabled:cursor-pointer',
6
- leadingIcon: 'absolute top-1/2 left-1 h-[var(--icon-size)] w-[var(--icon-size)] -translate-y-1/2 text-[var(--m3c-secondary-container)] pointer-events-none',
7
- leadingIconPop: 'left-[var(--handle-right)] text-[var(--m3c-primary)]',
8
- trailingIcon: 'absolute top-1/2 right-1 h-[var(--icon-size)] w-[var(--icon-size)] -translate-y-1/2 text-[var(--m3c-primary)] pointer-events-none',
9
- trailingIconPop: 'right-[calc(100%-var(--handle-left))] text-[var(--m3c-secondary-container)]',
10
- trackFill: 'absolute inset-x-0 [inset-block:calc((var(--handle-height)-var(--track-height))/2)] pointer-events-none bg-[var(--m3c-primary)] [clip-path:inset(0_calc(100%-var(--handle-left))_0_0_round_var(--track-radius)_var(--m3-slider-track-in-shape)_var(--m3-slider-track-in-shape)_var(--track-radius))] group-data-[disabled]:bg-[--translucent(var(--m3c-on-surface),0.38)] [@media(forced-colors:active)]:bg-[selecteditem] group-data-[disabled]:[@media(forced-colors:active)]:bg-[canvastext]',
11
- trackRest: 'absolute inset-x-0 [inset-block:calc((var(--handle-height)-var(--track-height))/2)] pointer-events-none bg-[var(--m3c-secondary-container)] [clip-path:inset(0_0_0_var(--handle-right)_round_var(--m3-slider-track-in-shape)_var(--track-radius)_var(--track-radius)_var(--m3-slider-track-in-shape))] group-data-[disabled]:bg-[--translucent(var(--m3c-on-surface),0.12)] [@media(forced-colors:active)]:bg-[canvastext] group-data-[disabled]:[@media(forced-colors:active)]:bg-[graytext]',
12
- stopBase: 'absolute top-1/2 h-1 w-1 rounded-full [inset-inline-start:calc(50%+(100%-0.5rem-0.25rem)*var(--x))] pointer-events-none',
13
- stopFill: 'bg-[var(--m3c-on-primary)] group-data-[disabled]:bg-[var(--m3c-inverse-on-surface)]',
14
- stopRest: 'bg-[var(--m3c-primary)] group-data-[disabled]:bg-[--translucent(var(--m3c-on-surface),0.38)]',
15
- handle: 'absolute inset-y-0 left-[var(--handle-center)] w-1 rounded-[1.25rem] bg-[var(--m3c-primary)] pointer-events-none group-focus-within:outline group-focus-within:outline-[4px] group-focus-within:outline-[var(--m3c-on-secondary-container)] group-focus-within:outline-offset-[5px] group-focus-within:z-[2] group-focus-within:w-0.5 group-active:w-0.5 group-data-[disabled]:bg-[--translucent(var(--m3c-on-surface),0.38)] [@media(forced-colors:active)]:bg-[selecteditem] group-data-[disabled]:[@media(forced-colors:active)]:bg-[graytext]',
16
- value: 'absolute flex min-w-12 items-center justify-center rounded-[var(--m3-slider-handle-shape)] bg-[var(--m3c-inverse-surface)] px-4 py-3 text-[var(--m3c-inverse-on-surface)] md-sys-typescale-label-large [inset-inline-start:var(--handle-center)] [inset-block-end:calc(var(--handle-height)+4px)] opacity-0 pointer-events-none select-none z-[1] group-hover:opacity-100 group-focus-within:opacity-100 group-active:opacity-100 [@media(forced-colors:active)]:border-2 [@media(forced-colors:active)]:border-[selecteditem] [@media(forced-colors:active)]:overflow-hidden'
11
+ root: 'group relative flex shrink-0 cursor-pointer touch-none select-none data-[disabled]:cursor-not-allowed',
12
+ track: 'pointer-events-none absolute',
13
+ activeTrack: 'bg-md-sys-color-primary group-data-[disabled]:bg-md-sys-color-on-surface/38',
14
+ inactiveTrack: 'bg-md-sys-color-secondary-container group-data-[disabled]:bg-md-sys-color-on-surface/12',
15
+ stop: 'pointer-events-none absolute size-1 rounded-full',
16
+ stopOnActive: 'bg-md-sys-color-on-primary group-data-[disabled]:bg-md-sys-color-inverse-on-surface',
17
+ stopOnInactive: 'bg-md-sys-color-on-secondary-container group-data-[disabled]:bg-md-sys-color-on-surface/38',
18
+ icon: 'pointer-events-none absolute',
19
+ iconOnActive: 'text-md-sys-color-on-primary',
20
+ iconOnInactive: 'text-md-sys-color-on-secondary-container',
21
+ handle: `
22
+ absolute rounded-full bg-md-sys-color-primary outline-none
23
+ transition-[width,height] md-sys-motion-fast-spatial
24
+ focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-md-sys-color-secondary
25
+ group-data-[disabled]:bg-md-sys-color-on-surface/38
26
+ `,
27
+ value: `
28
+ pointer-events-none absolute z-10 flex min-w-12 items-center justify-center rounded-full
29
+ bg-md-sys-color-inverse-surface px-4 py-3
30
+ md-sys-typescale-label-large text-md-sys-color-inverse-on-surface
31
+ opacity-0 transition-opacity md-sys-motion-effects
32
+ group-has-[[data-slider-thumb]:focus-visible]:opacity-100
33
+ `
17
34
  },
18
35
  variants: {
19
36
  size: {
20
- xs: '[--track-height:1rem] [--handle-height:2.75rem] [--track-radius:var(--m3-shape-small)] [--icon-size:0]',
21
- s: '[--track-height:1.5rem] [--handle-height:2.75rem] [--track-radius:var(--m3-shape-small)] [--icon-size:0]',
22
- m: '[--track-height:2.5rem] [--handle-height:3.25rem] [--track-radius:var(--m3-shape-medium)] [--icon-size:1.5rem]',
23
- l: '[--track-height:3.5rem] [--handle-height:4.25rem] [--track-radius:var(--m3-shape-large)] [--icon-size:1.5rem]',
24
- xl: '[--track-height:6rem] [--handle-height:6.75rem] [--track-radius:var(--m3-shape-extra-large)] [--icon-size:2rem]'
37
+ xs: { root: '[--track:1rem] [--handle:2.75rem] [--outer:var(--radius-sm)]' },
38
+ s: { root: '[--track:1.5rem] [--handle:2.75rem] [--outer:var(--radius-sm)]' },
39
+ m: { root: '[--track:2.5rem] [--handle:3.25rem] [--outer:var(--radius-md)]' },
40
+ l: { root: '[--track:3.5rem] [--handle:4.25rem] [--outer:var(--radius-lg)]' },
41
+ xl: { root: '[--track:6rem] [--handle:6.75rem] [--outer:var(--radius-xl)]' }
25
42
  },
26
43
  vertical: {
27
- true: '[writing-mode:sideways-lr]'
44
+ false: {
45
+ root: 'h-[var(--handle)] w-full min-w-40',
46
+ track: 'top-1/2 h-[var(--track)] -translate-y-1/2',
47
+ activeTrack: 'left-0 rounded-l-[var(--outer)] rounded-r-[2px]',
48
+ inactiveTrack: 'right-0 rounded-l-[2px] rounded-r-[var(--outer)]',
49
+ stop: 'top-1/2 -translate-x-1/2 -translate-y-1/2',
50
+ icon: 'top-1/2 -translate-y-1/2',
51
+ handle: 'top-0 h-full w-1 -translate-x-1/2 data-[active]:w-0.5',
52
+ value: 'bottom-[calc(100%+4px)] -translate-x-1/2'
53
+ },
54
+ true: {
55
+ root: 'h-full min-h-40 w-[var(--handle)]',
56
+ track: 'left-1/2 w-[var(--track)] -translate-x-1/2',
57
+ activeTrack: 'bottom-0 rounded-t-[2px] rounded-b-[var(--outer)]',
58
+ inactiveTrack: 'top-0 rounded-t-[var(--outer)] rounded-b-[2px]',
59
+ stop: 'left-1/2 -translate-x-1/2 translate-y-1/2',
60
+ icon: 'left-1/2 -translate-x-1/2',
61
+ handle: 'left-0 h-1 w-full translate-y-1/2 data-[active]:h-0.5',
62
+ value: 'left-[calc(100%+4px)] translate-y-1/2'
63
+ }
64
+ },
65
+ active: {
66
+ true: { value: 'opacity-100' }
28
67
  }
29
68
  },
30
69
  defaultVariants: {
31
- size: 'xs'
70
+ size: 'xs',
71
+ vertical: false
32
72
  }
33
73
  });