@x33025/sveltely 0.1.17 → 0.1.19

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 (153) hide show
  1. package/dist/actions/LoaderOverlay.svelte +33 -8
  2. package/dist/actions/LoaderOverlay.svelte.d.ts +3 -0
  3. package/dist/actions/loader.d.ts +3 -0
  4. package/dist/actions/loader.js +20 -7
  5. package/dist/components/Library/AnimatedNumber/AnimatedNumber.demo.svelte +3 -9
  6. package/dist/components/Library/ArticleEditor/ArticleEditor.svelte +3 -3
  7. package/dist/components/Library/ArticleEditor/ArticleEditorBody.svelte +59 -74
  8. package/dist/components/Library/ArticleEditor/ArticleEditorHeader.svelte +21 -31
  9. package/dist/components/Library/ArticleEditor/{ArticleBlockCode.svelte → Blocks/Code.svelte} +2 -3
  10. package/dist/components/Library/ArticleEditor/Blocks/Code.svelte.d.ts +8 -0
  11. package/dist/components/Library/ArticleEditor/{ArticleBlockFAQ.svelte → Blocks/FAQ.svelte} +3 -3
  12. package/dist/components/Library/ArticleEditor/Blocks/FAQ.svelte.d.ts +8 -0
  13. package/dist/components/Library/ArticleEditor/{ArticleBlockHeading.svelte → Blocks/Heading.svelte} +9 -9
  14. package/dist/components/Library/ArticleEditor/{ArticleBlockHeading.svelte.d.ts → Blocks/Heading.svelte.d.ts} +4 -4
  15. package/dist/components/Library/ArticleEditor/Blocks/Image.svelte +32 -0
  16. package/dist/components/Library/ArticleEditor/Blocks/Image.svelte.d.ts +10 -0
  17. package/dist/components/Library/ArticleEditor/{ArticleBlockList.svelte → Blocks/List.svelte} +4 -4
  18. package/dist/components/Library/ArticleEditor/{ArticleBlockList.svelte.d.ts → Blocks/List.svelte.d.ts} +4 -4
  19. package/dist/components/Library/ArticleEditor/{ArticleBlockParagraph.svelte → Blocks/Paragraph.svelte} +3 -3
  20. package/dist/components/Library/ArticleEditor/{ArticleBlockFallback.svelte.d.ts → Blocks/Paragraph.svelte.d.ts} +4 -4
  21. package/dist/components/Library/ArticleEditor/{ArticleBlockTable.svelte → Blocks/Table.svelte} +1 -1
  22. package/dist/components/Library/ArticleEditor/{ArticleBlockTable.svelte.d.ts → Blocks/Table.svelte.d.ts} +4 -4
  23. package/dist/components/Library/ArticleEditor/Blocks/index.d.ts +7 -0
  24. package/dist/components/Library/ArticleEditor/Blocks/index.js +7 -0
  25. package/dist/components/Library/ArticleEditor/index.d.ts +1 -9
  26. package/dist/components/Library/ArticleEditor/index.js +1 -9
  27. package/dist/components/Library/AsyncButton/AsyncButton.demo.svelte +2 -6
  28. package/dist/components/Library/AsyncButton/AsyncButton.svelte +9 -5
  29. package/dist/components/Library/AsyncButton/AsyncButton.svelte.d.ts +2 -1
  30. package/dist/components/Library/Button/Button.demo.svelte +2 -17
  31. package/dist/components/Library/Button/Button.demo.svelte.d.ts +0 -1
  32. package/dist/components/Library/Button/Button.svelte +15 -16
  33. package/dist/components/Library/Button/Button.svelte.d.ts +2 -1
  34. package/dist/components/Library/Calendar/Calendar.svelte +17 -27
  35. package/dist/components/Library/Checkbox/Checkbox.demo.svelte +7 -4
  36. package/dist/components/Library/Checkbox/Checkbox.svelte +24 -61
  37. package/dist/components/Library/Checkbox/Checkbox.svelte.d.ts +2 -4
  38. package/dist/components/Library/ChipInput/ChipInput.demo.svelte +2 -2
  39. package/dist/components/Library/ChipInput/ChipInput.svelte +7 -11
  40. package/dist/components/Library/ChipInput/ChipInput.svelte.d.ts +3 -2
  41. package/dist/components/Library/Dropdown/Action.svelte +1 -1
  42. package/dist/components/Library/Dropdown/Dropdown.demo.svelte +10 -10
  43. package/dist/components/Library/Dropdown/Dropdown.svelte +2 -6
  44. package/dist/components/Library/Dropdown/Item.svelte +2 -2
  45. package/dist/components/Library/Dropdown/Section.svelte +1 -1
  46. package/dist/components/Library/Dropdown/Trigger.svelte +3 -7
  47. package/dist/components/Library/Image/Image.demo.svelte +3 -3
  48. package/dist/components/Library/Image/Image.svelte +57 -12
  49. package/dist/components/Library/Image/Image.svelte.d.ts +1 -2
  50. package/dist/components/Library/Image/ImagePlaceholder.demo.svelte +12 -0
  51. package/dist/components/Library/Image/ImagePlaceholder.demo.svelte.d.ts +23 -0
  52. package/dist/components/Library/Image/ImagePlaceholder.svelte +28 -4
  53. package/dist/components/Library/Image/ImagePlaceholder.svelte.d.ts +1 -1
  54. package/dist/components/Library/Image/index.d.ts +1 -0
  55. package/dist/components/Library/Image/index.js +1 -0
  56. package/dist/components/Library/ImageMask/BrushPreview.svelte +6 -6
  57. package/dist/components/Library/ImageMask/ImageMask.demo.svelte +10 -8
  58. package/dist/components/Library/ImageMask/ImageMask.svelte +14 -6
  59. package/dist/components/Library/ImageMask/ImageMask.svelte.d.ts +1 -2
  60. package/dist/components/Library/ImageMask/MaskLayer.svelte +12 -6
  61. package/dist/components/Library/Label/Label.demo.svelte +9 -3
  62. package/dist/components/Library/Label/Label.svelte +8 -2
  63. package/dist/components/Library/Link/Link.svelte +10 -22
  64. package/dist/components/Library/Link/Link.svelte.d.ts +2 -3
  65. package/dist/components/Library/Loader/Loader.demo.svelte +9 -3
  66. package/dist/components/Library/NavigationStack/Link.svelte +8 -12
  67. package/dist/components/Library/NavigationStack/Link.svelte.d.ts +1 -3
  68. package/dist/components/Library/NavigationStack/SidebarToggle.svelte +8 -2
  69. package/dist/components/Library/NumberField/NumberField.svelte +21 -17
  70. package/dist/components/Library/NumberField/NumberField.svelte.d.ts +4 -2
  71. package/dist/components/Library/Pagination/Pagination.svelte +3 -3
  72. package/dist/components/Library/Popover/Popover.svelte +2 -7
  73. package/dist/components/Library/ScrollView/ScrollView.demo.svelte +50 -0
  74. package/dist/components/Library/ScrollView/ScrollView.demo.svelte.d.ts +10 -0
  75. package/dist/components/Library/ScrollView/ScrollView.svelte +414 -67
  76. package/dist/components/Library/ScrollView/ScrollView.svelte.d.ts +17 -1
  77. package/dist/components/Library/ScrollView/index.d.ts +1 -1
  78. package/dist/components/Library/SearchField/SearchField.demo.svelte +2 -2
  79. package/dist/components/Library/SearchField/SearchField.svelte +9 -4
  80. package/dist/components/Library/SearchField/SearchField.svelte.d.ts +2 -1
  81. package/dist/components/Library/SegmentedPicker/SegmentedPicker.demo.svelte +2 -2
  82. package/dist/components/Library/SegmentedPicker/SegmentedPicker.svelte +7 -7
  83. package/dist/components/Library/Sheet/Sheet.demo.svelte +1 -1
  84. package/dist/components/Library/Sheet/Sheet.svelte +2 -7
  85. package/dist/components/Library/Slider/Slider.demo.svelte +1 -1
  86. package/dist/components/Library/Slider/Slider.svelte +11 -7
  87. package/dist/components/Library/Slider/Slider.svelte.d.ts +2 -1
  88. package/dist/components/Library/Spinner/Spinner.demo.svelte +1 -1
  89. package/dist/components/Library/Switch/Switch.demo.svelte +7 -4
  90. package/dist/components/Library/Switch/Switch.svelte +28 -68
  91. package/dist/components/Library/Switch/Switch.svelte.d.ts +2 -4
  92. package/dist/components/Library/Table/Column.svelte +81 -0
  93. package/dist/components/Library/Table/Column.svelte.d.ts +39 -0
  94. package/dist/components/Library/Table/Table.demo.svelte +148 -0
  95. package/dist/components/Library/Table/Table.demo.svelte.d.ts +10 -0
  96. package/dist/components/Library/Table/Table.svelte +624 -0
  97. package/dist/components/Library/Table/Table.svelte.d.ts +42 -0
  98. package/dist/components/Library/Table/context.d.ts +5 -0
  99. package/dist/components/Library/Table/context.js +2 -0
  100. package/dist/components/Library/Table/index.js +5 -0
  101. package/dist/components/Library/Table/types.d.ts +37 -0
  102. package/dist/components/Library/Table/types.js +1 -0
  103. package/dist/components/Library/Text/Text.demo.svelte +21 -0
  104. package/dist/components/Library/Text/Text.demo.svelte.d.ts +24 -0
  105. package/dist/components/Library/Text/Text.svelte +41 -0
  106. package/dist/components/Library/Text/Text.svelte.d.ts +9 -0
  107. package/dist/components/Library/Text/index.d.ts +1 -0
  108. package/dist/components/Library/Text/index.js +1 -0
  109. package/dist/components/Library/TextEditor/TextEditor.svelte +15 -9
  110. package/dist/components/Library/TextEditor/TextEditor.svelte.d.ts +2 -4
  111. package/dist/components/Library/TextField/TextField.demo.svelte +1 -1
  112. package/dist/components/Library/TextField/TextField.svelte +21 -18
  113. package/dist/components/Library/TextField/TextField.svelte.d.ts +4 -2
  114. package/dist/components/Library/TextShimmer/TextShimmer.demo.svelte +1 -1
  115. package/dist/components/Library/TimePicker/TimePicker.demo.svelte +10 -2
  116. package/dist/components/Library/TimePicker/TimePicker.svelte +10 -5
  117. package/dist/components/Library/TokenSearchField/TokenSearchField.demo.svelte +4 -2
  118. package/dist/components/Library/TokenSearchField/TokenSearchField.svelte +11 -11
  119. package/dist/components/Library/TokenSearchField/TokenSearchField.svelte.d.ts +2 -1
  120. package/dist/components/Library/WheelPicker/WheelColumn.svelte +183 -126
  121. package/dist/components/Library/WheelPicker/WheelPicker.svelte +4 -4
  122. package/dist/components/Library/WheelPicker/WheelPicker.svelte.d.ts +2 -2
  123. package/dist/components/Library/WheelPicker/index.d.ts +1 -1
  124. package/dist/components/Library/WheelPicker/types.d.ts +6 -0
  125. package/dist/components/Local/ColorStyleControls.svelte +201 -0
  126. package/dist/components/Local/ColorStyleControls.svelte.d.ts +13 -0
  127. package/dist/components/Local/HeroCard.svelte +3 -3
  128. package/dist/components/Local/LayoutStyleControls.svelte +67 -0
  129. package/dist/components/Local/LayoutStyleControls.svelte.d.ts +11 -0
  130. package/dist/components/Local/StyleControls.svelte +48 -124
  131. package/dist/components/Local/StyleControls.svelte.d.ts +7 -5
  132. package/dist/index.d.ts +9 -2
  133. package/dist/index.js +5 -1
  134. package/dist/style/index.css +7 -12
  135. package/dist/style/label.d.ts +2 -1
  136. package/dist/style/label.js +2 -1
  137. package/dist/style/surface.js +4 -0
  138. package/dist/style/text-editor.d.ts +2 -13
  139. package/dist/style/text-editor.js +1 -12
  140. package/dist/style/text.d.ts +26 -0
  141. package/dist/style/text.js +69 -0
  142. package/dist/style/tooltip.d.ts +4 -0
  143. package/dist/style/tooltip.js +1 -0
  144. package/dist/style.css +41 -114
  145. package/package.json +1 -1
  146. package/dist/components/Library/ArticleEditor/ArticleBlockCode.svelte.d.ts +0 -8
  147. package/dist/components/Library/ArticleEditor/ArticleBlockFAQ.svelte.d.ts +0 -8
  148. package/dist/components/Library/ArticleEditor/ArticleBlockFallback.svelte +0 -79
  149. package/dist/components/Library/ArticleEditor/ArticleBlockImage.svelte +0 -48
  150. package/dist/components/Library/ArticleEditor/ArticleBlockImage.svelte.d.ts +0 -9
  151. package/dist/components/Library/ArticleEditor/ArticleBlockParagraph.svelte.d.ts +0 -15
  152. package/dist/components/Library/ArticleEditor/ArticleImagePreview.svelte +0 -71
  153. package/dist/components/Library/ArticleEditor/ArticleImagePreview.svelte.d.ts +0 -8
@@ -1,5 +1,9 @@
1
1
  <script lang="ts" generics="T extends string | number">
2
- import { tick } from 'svelte';
2
+ import { tick, untrack } from 'svelte';
3
+ import ScrollView, {
4
+ type ScrollGeometry,
5
+ type ScrollViewHandle
6
+ } from '../ScrollView';
3
7
  import type { WheelOption } from './types';
4
8
 
5
9
  type Props = {
@@ -10,17 +14,49 @@
10
14
 
11
15
  let { options, value = $bindable<T>(), onChange }: Props = $props();
12
16
 
13
- let viewport = $state<HTMLDivElement | null>(null);
17
+ let viewport = $state<ScrollViewHandle | null>(null);
14
18
  let optionRefs = $state<(HTMLButtonElement | null)[]>([]);
15
19
  let scrollTimeout = $state<ReturnType<typeof setTimeout> | null>(null);
16
- let scrollingLockTimeout = $state<ReturnType<typeof setTimeout> | null>(null);
17
20
  let isUserScrolling = $state(false);
18
21
  let scrollAnimationFrame = $state<number | null>(null);
19
- let visualUpdateFrame = $state<number | null>(null);
22
+ let spacerSize = $state(0);
23
+ let optionHeight = $state(0);
24
+ let scrollOffsetY = $state(0);
25
+ let optionPointer: { id: number; x: number; y: number; moved: boolean } | null = null;
20
26
 
21
27
  const easeOutCubic = (t: number) => 1 - Math.pow(1 - t, 3);
22
28
 
23
- const animateScrollTo = (nextViewport: HTMLDivElement, targetTop: number, duration = 220) => {
29
+ const resolveOptionHeight = (nextViewport = viewport) => {
30
+ const measuredOptionHeight = optionRefs.find((element) => element !== null)?.clientHeight;
31
+ const cssOptionHeight =
32
+ typeof document === 'undefined'
33
+ ? 0
34
+ : parseFloat(
35
+ getComputedStyle(nextViewport?.element ?? document.documentElement).getPropertyValue(
36
+ '--wheel-picker-option-height'
37
+ )
38
+ );
39
+
40
+ return measuredOptionHeight && measuredOptionHeight > 0
41
+ ? measuredOptionHeight
42
+ : Number.isFinite(cssOptionHeight)
43
+ ? cssOptionHeight
44
+ : 0;
45
+ };
46
+
47
+ const measureSpacerSize = (nextViewport = viewport) => {
48
+ if (!nextViewport) return;
49
+ const nextOptionHeight = resolveOptionHeight(nextViewport);
50
+ const nextSpacerSize = Math.max(0, (nextViewport.clientHeight - nextOptionHeight) / 2);
51
+ if (Math.abs(optionHeight - nextOptionHeight) > 0.5) {
52
+ optionHeight = nextOptionHeight;
53
+ }
54
+ if (Math.abs(spacerSize - nextSpacerSize) > 0.5) {
55
+ spacerSize = nextSpacerSize;
56
+ }
57
+ };
58
+
59
+ const animateScrollTo = (nextViewport: ScrollViewHandle, targetTop: number, duration = 220) => {
24
60
  if (scrollAnimationFrame) cancelAnimationFrame(scrollAnimationFrame);
25
61
 
26
62
  const startTop = nextViewport.scrollTop;
@@ -47,7 +83,7 @@
47
83
  };
48
84
 
49
85
  const scrollSelectedIntoView = async (
50
- nextViewport: HTMLDivElement | null,
86
+ nextViewport: ScrollViewHandle | null,
51
87
  element: HTMLButtonElement | null
52
88
  ) => {
53
89
  if (!nextViewport || !element) return;
@@ -63,7 +99,7 @@
63
99
  };
64
100
 
65
101
  const getCenteredIndex = (
66
- nextViewport: HTMLDivElement | null,
102
+ nextViewport: ScrollViewHandle | null,
67
103
  elements: Array<HTMLButtonElement | null>
68
104
  ) => {
69
105
  if (!nextViewport) return -1;
@@ -87,7 +123,7 @@
87
123
  };
88
124
 
89
125
  const getCenterDistance = (
90
- nextViewport: HTMLDivElement | null,
126
+ nextViewport: ScrollViewHandle | null,
91
127
  element: HTMLButtonElement | null
92
128
  ) => {
93
129
  if (!nextViewport || !element) return Number.POSITIVE_INFINITY;
@@ -98,30 +134,6 @@
98
134
  return Math.abs(elementCenter - viewportCenter);
99
135
  };
100
136
 
101
- const updateVisualDepth = () => {
102
- if (!viewport) return;
103
- const viewportRect = viewport.getBoundingClientRect();
104
- const viewportCenter = viewportRect.top + viewportRect.height / 2;
105
- const maxDistance = Math.max(viewportRect.height / 2, 1);
106
-
107
- for (const element of optionRefs) {
108
- if (!element) continue;
109
- const rect = element.getBoundingClientRect();
110
- const center = rect.top + rect.height / 2;
111
- const ratio = Math.min(1, Math.abs(center - viewportCenter) / maxDistance);
112
- const emphasis = Math.pow(Math.cos(ratio * (Math.PI / 2)), 2);
113
- element.style.setProperty('--wheel-column-emphasis', emphasis.toFixed(3));
114
- }
115
- };
116
-
117
- const scheduleVisualDepthUpdate = () => {
118
- if (visualUpdateFrame) cancelAnimationFrame(visualUpdateFrame);
119
- visualUpdateFrame = requestAnimationFrame(() => {
120
- visualUpdateFrame = null;
121
- updateVisualDepth();
122
- });
123
- };
124
-
125
137
  const applyValue = (nextValue: T) => {
126
138
  if (value === nextValue) return;
127
139
  value = nextValue;
@@ -129,13 +141,39 @@
129
141
  };
130
142
 
131
143
  const selectOption = (option: WheelOption<T>, index: number) => {
144
+ if (scrollTimeout) clearTimeout(scrollTimeout);
145
+ isUserScrolling = false;
132
146
  applyValue(option.value);
133
147
  void scrollSelectedIntoView(viewport, optionRefs[index] ?? null);
134
- scheduleVisualDepthUpdate();
148
+ };
149
+
150
+ const handleOptionPointerdown = (event: PointerEvent) => {
151
+ optionPointer = {
152
+ id: event.pointerId,
153
+ x: event.clientX,
154
+ y: event.clientY,
155
+ moved: false
156
+ };
157
+ };
158
+
159
+ const handleOptionPointermove = (event: PointerEvent) => {
160
+ if (!optionPointer || optionPointer.id !== event.pointerId) return;
161
+ const distance = Math.hypot(event.clientX - optionPointer.x, event.clientY - optionPointer.y);
162
+ if (distance > 6) optionPointer.moved = true;
163
+ };
164
+
165
+ const handleOptionClick = (option: WheelOption<T>, index: number) => {
166
+ if (optionPointer?.moved) {
167
+ optionPointer = null;
168
+ return;
169
+ }
170
+ optionPointer = null;
171
+ selectOption(option, index);
135
172
  };
136
173
 
137
174
  const syncToCurrentValue = () => {
138
175
  if (isUserScrolling || !viewport) return;
176
+ measureSpacerSize(viewport);
139
177
  const index = options.findIndex((option) => option.value === value);
140
178
  if (index < 0) return;
141
179
  const element = optionRefs[index] ?? null;
@@ -143,67 +181,70 @@
143
181
  if (getCenterDistance(viewport, element) > 1) {
144
182
  void scrollSelectedIntoView(viewport, element);
145
183
  }
146
- scheduleVisualDepthUpdate();
147
184
  };
148
185
 
149
- const handleScroll = () => {
150
- scheduleVisualDepthUpdate();
186
+ const settleScroll = () => {
187
+ isUserScrolling = false;
188
+ const centeredIndex = getCenteredIndex(viewport, optionRefs);
189
+ if (centeredIndex < 0) return;
190
+ const centeredOption = options[centeredIndex];
191
+ const centeredElement = optionRefs[centeredIndex] ?? null;
192
+ if (!centeredOption || !centeredElement) return;
193
+
194
+ const centerDistance = getCenterDistance(viewport, centeredElement);
195
+ if (centerDistance > 1) {
196
+ void scrollSelectedIntoView(viewport, centeredElement);
197
+ }
198
+
199
+ applyValue(centeredOption.value);
200
+ };
201
+
202
+ const handleScroll = (geometry: ScrollGeometry) => {
203
+ scrollOffsetY = geometry.offset.y;
204
+ measureSpacerSize();
151
205
  isUserScrolling = true;
152
- if (scrollingLockTimeout) clearTimeout(scrollingLockTimeout);
153
- scrollingLockTimeout = setTimeout(() => {
154
- isUserScrolling = false;
155
- }, 180);
156
206
 
157
207
  if (scrollTimeout) clearTimeout(scrollTimeout);
158
- scrollTimeout = setTimeout(() => {
159
- const centeredIndex = getCenteredIndex(viewport, optionRefs);
160
- if (centeredIndex < 0) return;
161
- const centeredOption = options[centeredIndex];
162
- const centeredElement = optionRefs[centeredIndex] ?? null;
163
- if (!centeredOption || !centeredElement) return;
164
-
165
- const centerDistance = getCenterDistance(viewport, centeredElement);
166
- if (centerDistance > 1) {
167
- void scrollSelectedIntoView(viewport, centeredElement);
168
- }
169
-
170
- applyValue(centeredOption.value);
171
- scheduleVisualDepthUpdate();
172
- }, 140);
208
+ scrollTimeout = setTimeout(settleScroll, 240);
173
209
  };
174
210
 
175
- const viewportSync = (node: HTMLDivElement) => {
176
- viewport = node;
177
- void tick().then(() => {
178
- syncToCurrentValue();
179
- scheduleVisualDepthUpdate();
211
+ $effect(() => {
212
+ const nextViewport = viewport;
213
+ const nextValue = value;
214
+ const nextOptions = options;
215
+ if (!nextViewport) return;
216
+
217
+ void tick().then(async () => {
218
+ if (viewport !== nextViewport || value !== nextValue || options !== nextOptions) return;
219
+ untrack(() => {
220
+ measureSpacerSize(nextViewport);
221
+ });
222
+ await tick();
223
+ if (viewport !== nextViewport || value !== nextValue || options !== nextOptions) return;
224
+ untrack(() => {
225
+ syncToCurrentValue();
226
+ });
180
227
  });
228
+ });
181
229
 
182
- return {
183
- update() {
184
- void tick().then(() => {
185
- syncToCurrentValue();
186
- scheduleVisualDepthUpdate();
187
- });
188
- },
189
- destroy() {
190
- if (scrollTimeout) clearTimeout(scrollTimeout);
191
- if (scrollingLockTimeout) clearTimeout(scrollingLockTimeout);
192
- if (scrollAnimationFrame) cancelAnimationFrame(scrollAnimationFrame);
193
- if (visualUpdateFrame) cancelAnimationFrame(visualUpdateFrame);
194
- viewport = null;
195
- }
230
+ $effect(() => {
231
+ return () => {
232
+ if (scrollTimeout) clearTimeout(scrollTimeout);
233
+ if (scrollAnimationFrame) cancelAnimationFrame(scrollAnimationFrame);
196
234
  };
197
- };
235
+ });
198
236
  </script>
199
237
 
200
- <div
201
- class="wheel-column-viewport"
202
- bind:this={viewport}
203
- use:viewportSync={{ value, options }}
204
- onscroll={handleScroll}
238
+ <ScrollView
239
+ axis="vertical"
240
+ bind:viewport
241
+ scrollGradient={false}
242
+ showIndicators={false}
243
+ contentStyles={{ paddingX: 0, paddingY: 0 }}
244
+ onScroll={handleScroll}
205
245
  >
206
246
  <div class="wheel-column-options vstack">
247
+ <div class="wheel-column-spacer" style:height={`${spacerSize}px`} aria-hidden="true"></div>
207
248
  {#each options as option, index (option.value)}
208
249
  <button
209
250
  bind:this={optionRefs[index]}
@@ -211,47 +252,58 @@
211
252
  class="wheel-column-option"
212
253
  class:wheel-column-option-selected={option.value === value}
213
254
  aria-pressed={option.value === value}
214
- onclick={() => selectOption(option, index)}
255
+ onpointerdown={handleOptionPointerdown}
256
+ onpointermove={handleOptionPointermove}
257
+ onpointercancel={() => {
258
+ optionPointer = null;
259
+ }}
260
+ onclick={() => handleOptionClick(option, index)}
215
261
  >
216
262
  {option.label}
217
263
  </button>
218
264
  {/each}
265
+ <div class="wheel-column-spacer" style:height={`${spacerSize}px`} aria-hidden="true"></div>
266
+ </div>
267
+ </ScrollView>
268
+
269
+ <div
270
+ class="wheel-column-active-layer"
271
+ style:top={`${spacerSize}px`}
272
+ style:height={`${optionHeight}px`}
273
+ aria-hidden="true"
274
+ >
275
+ <div
276
+ class="wheel-column-active-options"
277
+ style:transform={`translateY(${-scrollOffsetY - spacerSize}px)`}
278
+ >
279
+ <div class="wheel-column-spacer" style:height={`${spacerSize}px`}></div>
280
+ {#each options as option (option.value)}
281
+ <div class="wheel-column-active-option">{option.label}</div>
282
+ {/each}
283
+ <div class="wheel-column-spacer" style:height={`${spacerSize}px`}></div>
219
284
  </div>
220
285
  </div>
221
286
 
222
287
  <style>
223
- .wheel-column-viewport {
224
- height: 100%;
225
- display: flex;
226
- flex-direction: column;
227
- min-height: 0;
288
+ :global(.wheel-picker-column) {
228
289
  position: relative;
229
- overflow-y: auto;
230
- overflow-x: hidden;
231
- overscroll-behavior-y: contain;
232
- scrollbar-width: none;
233
- -ms-overflow-style: none;
234
- z-index: 1;
290
+ overflow: hidden;
235
291
  }
236
292
 
237
- .wheel-column-viewport::-webkit-scrollbar {
238
- display: none;
293
+ :global(.wheel-picker-column > .scroll-view) {
294
+ z-index: 1;
239
295
  }
240
296
 
241
- .wheel-column-viewport::before,
242
- .wheel-column-viewport::after {
243
- content: '';
244
- display: block;
245
- flex: 0 0 calc(50% - (var(--wheel-picker-option-height) / 2));
297
+ .wheel-column-options {
298
+ gap: 0;
246
299
  }
247
300
 
248
- .wheel-column-options {
301
+ .wheel-column-spacer {
249
302
  flex: 0 0 auto;
250
- gap: 0;
303
+ min-height: 0;
251
304
  }
252
305
 
253
306
  .wheel-column-option {
254
- --wheel-column-emphasis: 0;
255
307
  width: 100%;
256
308
  height: var(--wheel-picker-option-height);
257
309
  border: none;
@@ -260,37 +312,42 @@
260
312
  display: flex;
261
313
  align-items: center;
262
314
  justify-content: center;
263
- padding: 0 calc(var(--sveltely-padding-x) * 0.67 * var(--wheel-picker-scale));
315
+ padding: calc(var(--sveltely-padding-y) * 0.67 * var(--wheel-picker-scale))
316
+ calc(var(--sveltely-padding-x) * 0.67 * var(--wheel-picker-scale));
264
317
  font-size: calc(var(--wheel-picker-font-size) * 0.875);
265
- line-height: 1;
266
- color: var(--sveltely-primary-color);
267
- text-align: center;
268
- appearance: none;
269
- position: relative;
270
- z-index: 1;
271
- opacity: calc(0.3 + (var(--wheel-column-emphasis) * 0.7));
272
- transform: scale(calc(0.84 + (var(--wheel-column-emphasis) * 0.16)));
273
- transform-origin: center;
318
+ font-variant-numeric: tabular-nums;
319
+ line-height: 1.2;
320
+ color: var(--sveltely-text-secondary-color);
321
+ font-weight: 400;
274
322
  transition:
275
- color 160ms,
276
- background-color 160ms,
277
- opacity 160ms,
278
- transform 160ms;
323
+ color 120ms,
324
+ font-weight 120ms;
279
325
  }
280
326
 
281
- .wheel-column-option:hover {
282
- background: var(--sveltely-hover-color);
327
+ .wheel-column-active-layer {
328
+ position: absolute;
329
+ inset-inline: 0;
330
+ z-index: 2;
331
+ overflow: hidden;
332
+ pointer-events: none;
283
333
  }
284
334
 
285
- .wheel-column-option:focus-visible {
286
- outline: 2px solid color-mix(in oklab, var(--sveltely-active-color) 24%, white);
287
- outline-offset: 2px;
335
+ .wheel-column-active-options {
336
+ will-change: transform;
288
337
  }
289
338
 
290
- .wheel-column-option-selected {
291
- background: transparent;
292
- color: var(--sveltely-primary-color);
293
- opacity: 1;
294
- transform: scale(1);
339
+ .wheel-column-active-option {
340
+ display: flex;
341
+ width: 100%;
342
+ height: var(--wheel-picker-option-height);
343
+ align-items: center;
344
+ justify-content: center;
345
+ padding: calc(var(--sveltely-padding-y) * 0.67 * var(--wheel-picker-scale))
346
+ calc(var(--sveltely-padding-x) * 0.67 * var(--wheel-picker-scale));
347
+ font-size: calc(var(--wheel-picker-font-size) * 0.875);
348
+ font-variant-numeric: tabular-nums;
349
+ line-height: 1.2;
350
+ color: var(--sveltely-text-primary-color);
351
+ font-weight: 600;
295
352
  }
296
353
  </style>
@@ -1,10 +1,10 @@
1
1
  <script lang="ts">
2
2
  import WheelColumn from './WheelColumn.svelte';
3
3
  import { extractStyleProps, surfaceStyle, type StyleProps } from '../../../style/surface';
4
- import type { WheelColumn as WheelColumnData } from './types';
4
+ import type { AnyWheelColumn } from './types';
5
5
 
6
6
  type Props = {
7
- columns: WheelColumnData[];
7
+ columns: AnyWheelColumn[];
8
8
  height?: number | string;
9
9
  } & StyleProps &
10
10
  Record<string, unknown>;
@@ -95,7 +95,7 @@
95
95
  height: var(--wheel-picker-option-height);
96
96
  transform: translateY(-50%);
97
97
  border-radius: var(--sveltely-border-radius);
98
- background: color-mix(in oklab, var(--sveltely-inactive-color) 85%, white);
98
+ background: color-mix(in oklab, var(--sveltely-control-inactive-color) 85%, white);
99
99
  pointer-events: none;
100
100
  z-index: 0;
101
101
  }
@@ -105,6 +105,6 @@
105
105
  font-size: calc(var(--wheel-picker-font-size) * 0.75);
106
106
  line-height: 1;
107
107
  font-weight: 500;
108
- color: var(--sveltely-secondary-color);
108
+ color: var(--sveltely-text-secondary-color);
109
109
  }
110
110
  </style>
@@ -1,7 +1,7 @@
1
1
  import { type StyleProps } from '../../../style/surface';
2
- import type { WheelColumn as WheelColumnData } from './types';
2
+ import type { AnyWheelColumn } from './types';
3
3
  type Props = {
4
- columns: WheelColumnData[];
4
+ columns: AnyWheelColumn[];
5
5
  height?: number | string;
6
6
  } & StyleProps & Record<string, unknown>;
7
7
  declare const WheelPicker: import("svelte").Component<Props, {}, "">;
@@ -1,2 +1,2 @@
1
1
  export { default } from './WheelPicker.svelte';
2
- export type { WheelColumn, WheelOption } from './types';
2
+ export type { AnyWheelColumn, WheelColumn, WheelOption } from './types';
@@ -8,3 +8,9 @@ export type WheelColumn<TValue extends string | number = string> = {
8
8
  options: WheelOption<TValue>[];
9
9
  onChange?: (value: TValue) => void;
10
10
  };
11
+ export type AnyWheelColumn = {
12
+ label?: string;
13
+ value: string | number;
14
+ options: WheelOption<string | number>[];
15
+ onChange?: (value: string | number) => void;
16
+ };
@@ -0,0 +1,201 @@
1
+ <script lang="ts">
2
+ import Divider from '../Library/Divider';
3
+ import HStack from '../Library/HStack';
4
+ import Label from '../Library/Label';
5
+ import VStack from '../Library/VStack';
6
+
7
+ type Props = {
8
+ borderColor?: string;
9
+ textPrimaryColor?: string;
10
+ textSecondaryColor?: string;
11
+ textTertiaryColor?: string;
12
+ backgroundColor?: string;
13
+ controlActiveColor?: string;
14
+ controlInactiveColor?: string;
15
+ controlBackgroundColor?: string;
16
+ };
17
+
18
+ let {
19
+ borderColor = $bindable('#e4e4e7'),
20
+ textPrimaryColor = $bindable('#18181b'),
21
+ textSecondaryColor = $bindable('#71717a'),
22
+ textTertiaryColor = $bindable('#a1a1aa'),
23
+ backgroundColor = $bindable('#ffffff'),
24
+ controlActiveColor = $bindable('#18181b'),
25
+ controlInactiveColor = $bindable('#f4f4f5'),
26
+ controlBackgroundColor = $bindable('#fafafa')
27
+ }: Props = $props();
28
+ </script>
29
+
30
+ <VStack gap={5}>
31
+ <Label label="Text colors" color="var(--sveltely-text-tertiary-color)" fontSize={7.5} />
32
+ <Label
33
+ label="Text primary"
34
+ orientation="leading"
35
+ width="100%"
36
+ align="center"
37
+ justify="between"
38
+ gap={5}
39
+ >
40
+ <HStack width="100%" align="center" justify="end" gap={5}>
41
+ <span class="text-[var(--sveltely-text-secondary-color)]">{textPrimaryColor}</span>
42
+ <input
43
+ bind:value={textPrimaryColor}
44
+ type="color"
45
+ aria-label="Text primary"
46
+ class="color-input"
47
+ />
48
+ </HStack>
49
+ </Label>
50
+ <Label
51
+ label="Text secondary"
52
+ orientation="leading"
53
+ width="100%"
54
+ align="center"
55
+ justify="between"
56
+ gap={5}
57
+ >
58
+ <HStack width="100%" align="center" justify="end" gap={5}>
59
+ <span class="text-[var(--sveltely-text-secondary-color)]">{textSecondaryColor}</span>
60
+ <input
61
+ bind:value={textSecondaryColor}
62
+ type="color"
63
+ aria-label="Text secondary"
64
+ class="color-input"
65
+ />
66
+ </HStack>
67
+ </Label>
68
+ <Label
69
+ label="Text tertiary"
70
+ orientation="leading"
71
+ width="100%"
72
+ align="center"
73
+ justify="between"
74
+ gap={5}
75
+ >
76
+ <HStack width="100%" align="center" justify="end" gap={5}>
77
+ <span class="text-[var(--sveltely-text-secondary-color)]">{textTertiaryColor}</span>
78
+ <input
79
+ bind:value={textTertiaryColor}
80
+ type="color"
81
+ aria-label="Text tertiary"
82
+ class="color-input"
83
+ />
84
+ </HStack>
85
+ </Label>
86
+ <Divider />
87
+ <Label label="Surface colors" color="var(--sveltely-text-tertiary-color)" fontSize={7.5} />
88
+ <Label
89
+ label="Background color"
90
+ orientation="leading"
91
+ width="100%"
92
+ align="center"
93
+ justify="between"
94
+ gap={5}
95
+ >
96
+ <HStack width="100%" align="center" justify="end" gap={5}>
97
+ <span class="text-[var(--sveltely-text-secondary-color)]">{backgroundColor}</span>
98
+ <input
99
+ bind:value={backgroundColor}
100
+ type="color"
101
+ aria-label="Background color"
102
+ class="color-input"
103
+ />
104
+ </HStack>
105
+ </Label>
106
+ <Label
107
+ label="Border color"
108
+ orientation="leading"
109
+ width="100%"
110
+ align="center"
111
+ justify="between"
112
+ gap={5}
113
+ >
114
+ <HStack width="100%" align="center" justify="end" gap={5}>
115
+ <span class="text-[var(--sveltely-text-secondary-color)]">{borderColor}</span>
116
+ <input bind:value={borderColor} type="color" aria-label="Border color" class="color-input" />
117
+ </HStack>
118
+ </Label>
119
+ <Divider />
120
+ <Label label="Control colors" color="var(--sveltely-text-tertiary-color)" fontSize={7.5} />
121
+ <Label
122
+ label="Control active"
123
+ orientation="leading"
124
+ width="100%"
125
+ align="center"
126
+ justify="between"
127
+ gap={5}
128
+ >
129
+ <HStack width="100%" align="center" justify="end" gap={5}>
130
+ <span class="text-[var(--sveltely-text-secondary-color)]">{controlActiveColor}</span>
131
+ <input
132
+ bind:value={controlActiveColor}
133
+ type="color"
134
+ aria-label="Control active"
135
+ class="color-input"
136
+ />
137
+ </HStack>
138
+ </Label>
139
+ <Label
140
+ label="Control background"
141
+ orientation="leading"
142
+ width="100%"
143
+ align="center"
144
+ justify="between"
145
+ gap={5}
146
+ >
147
+ <HStack width="100%" align="center" justify="end" gap={5}>
148
+ <span class="text-[var(--sveltely-text-secondary-color)]">{controlBackgroundColor}</span>
149
+ <input
150
+ bind:value={controlBackgroundColor}
151
+ type="color"
152
+ aria-label="Control background"
153
+ class="color-input"
154
+ />
155
+ </HStack>
156
+ </Label>
157
+ <Label
158
+ label="Control inactive"
159
+ orientation="leading"
160
+ width="100%"
161
+ align="center"
162
+ justify="between"
163
+ gap={5}
164
+ >
165
+ <HStack width="100%" align="center" justify="end" gap={5}>
166
+ <span class="text-[var(--sveltely-text-secondary-color)]">{controlInactiveColor}</span>
167
+ <input
168
+ bind:value={controlInactiveColor}
169
+ type="color"
170
+ aria-label="Control inactive"
171
+ class="color-input"
172
+ />
173
+ </HStack>
174
+ </Label>
175
+ </VStack>
176
+
177
+ <style>
178
+ .color-input {
179
+ width: 2.5rem;
180
+ height: 2.5rem;
181
+ flex: 0 0 2.5rem;
182
+ border: 1px solid var(--sveltely-border-color);
183
+ border-radius: 0.375rem;
184
+ background: white;
185
+ padding: 0.1875rem;
186
+ }
187
+
188
+ .color-input::-webkit-color-swatch-wrapper {
189
+ padding: 0;
190
+ }
191
+
192
+ .color-input::-webkit-color-swatch {
193
+ border: 0;
194
+ border-radius: 0.25rem;
195
+ }
196
+
197
+ .color-input::-moz-color-swatch {
198
+ border: 0;
199
+ border-radius: 0.25rem;
200
+ }
201
+ </style>
@@ -0,0 +1,13 @@
1
+ type Props = {
2
+ borderColor?: string;
3
+ textPrimaryColor?: string;
4
+ textSecondaryColor?: string;
5
+ textTertiaryColor?: string;
6
+ backgroundColor?: string;
7
+ controlActiveColor?: string;
8
+ controlInactiveColor?: string;
9
+ controlBackgroundColor?: string;
10
+ };
11
+ declare const ColorStyleControls: import("svelte").Component<Props, {}, "backgroundColor" | "borderColor" | "textPrimaryColor" | "textSecondaryColor" | "textTertiaryColor" | "controlActiveColor" | "controlInactiveColor" | "controlBackgroundColor">;
12
+ type ColorStyleControls = ReturnType<typeof ColorStyleControls>;
13
+ export default ColorStyleControls;