@proyecto-viviana/solidaria-components 0.2.2 → 0.2.3

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 (64) hide show
  1. package/dist/Color.d.ts +2 -6
  2. package/dist/Color.d.ts.map +1 -1
  3. package/dist/ComboBox.d.ts +3 -3
  4. package/dist/ComboBox.d.ts.map +1 -1
  5. package/dist/GridList.d.ts +2 -2
  6. package/dist/GridList.d.ts.map +1 -1
  7. package/dist/ListBox.d.ts +5 -5
  8. package/dist/ListBox.d.ts.map +1 -1
  9. package/dist/Menu.d.ts +3 -3
  10. package/dist/Menu.d.ts.map +1 -1
  11. package/dist/Select.d.ts +3 -3
  12. package/dist/Select.d.ts.map +1 -1
  13. package/dist/Table.d.ts +2 -2
  14. package/dist/Table.d.ts.map +1 -1
  15. package/dist/Tabs.d.ts +1 -1
  16. package/dist/Tabs.d.ts.map +1 -1
  17. package/dist/index.js +56 -56
  18. package/dist/index.js.map +2 -2
  19. package/dist/index.ssr.js +56 -56
  20. package/dist/index.ssr.js.map +2 -2
  21. package/package.json +10 -8
  22. package/src/Autocomplete.tsx +174 -0
  23. package/src/Breadcrumbs.tsx +264 -0
  24. package/src/Button.tsx +238 -0
  25. package/src/Calendar.tsx +471 -0
  26. package/src/Checkbox.tsx +387 -0
  27. package/src/Color.tsx +1370 -0
  28. package/src/ComboBox.tsx +824 -0
  29. package/src/DateField.tsx +337 -0
  30. package/src/DatePicker.tsx +367 -0
  31. package/src/Dialog.tsx +262 -0
  32. package/src/Disclosure.tsx +439 -0
  33. package/src/GridList.tsx +511 -0
  34. package/src/Landmark.tsx +203 -0
  35. package/src/Link.tsx +201 -0
  36. package/src/ListBox.tsx +346 -0
  37. package/src/Menu.tsx +544 -0
  38. package/src/Meter.tsx +157 -0
  39. package/src/Modal.tsx +433 -0
  40. package/src/NumberField.tsx +542 -0
  41. package/src/Popover.tsx +540 -0
  42. package/src/ProgressBar.tsx +162 -0
  43. package/src/RadioGroup.tsx +356 -0
  44. package/src/RangeCalendar.tsx +462 -0
  45. package/src/SearchField.tsx +479 -0
  46. package/src/Select.tsx +734 -0
  47. package/src/Separator.tsx +130 -0
  48. package/src/Slider.tsx +500 -0
  49. package/src/Switch.tsx +213 -0
  50. package/src/Table.tsx +857 -0
  51. package/src/Tabs.tsx +552 -0
  52. package/src/TagGroup.tsx +421 -0
  53. package/src/TextField.tsx +271 -0
  54. package/src/TimeField.tsx +455 -0
  55. package/src/Toast.tsx +503 -0
  56. package/src/Toolbar.tsx +160 -0
  57. package/src/Tooltip.tsx +423 -0
  58. package/src/Tree.tsx +551 -0
  59. package/src/VisuallyHidden.tsx +60 -0
  60. package/src/contexts.ts +74 -0
  61. package/src/index.ts +620 -0
  62. package/src/utils.tsx +329 -0
  63. package/dist/index.jsx +0 -9056
  64. package/dist/index.jsx.map +0 -7
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Separator component for solidaria-components
3
+ *
4
+ * Pre-wired headless separator component that combines aria hooks.
5
+ * Port of react-aria-components/src/Separator.tsx
6
+ */
7
+
8
+ import {
9
+ type JSX,
10
+ createContext,
11
+ createMemo,
12
+ splitProps,
13
+ } from 'solid-js';
14
+ import { Dynamic } from 'solid-js/web';
15
+ import {
16
+ createSeparator,
17
+ type AriaSeparatorProps,
18
+ type Orientation,
19
+ } from '@proyecto-viviana/solidaria';
20
+ import {
21
+ type SlotProps,
22
+ filterDOMProps,
23
+ } from './utils';
24
+
25
+ // ============================================
26
+ // TYPES
27
+ // ============================================
28
+
29
+ export interface SeparatorRenderProps {
30
+ /** The orientation of the separator. */
31
+ orientation: Orientation;
32
+ }
33
+
34
+ export interface SeparatorProps
35
+ extends AriaSeparatorProps,
36
+ SlotProps {
37
+ /** The CSS className for the element. A function may be provided to receive render props. */
38
+ class?: string | ((renderProps: SeparatorRenderProps) => string);
39
+ /** The inline style for the element. A function may be provided to receive render props. */
40
+ style?: JSX.CSSProperties | ((renderProps: SeparatorRenderProps) => JSX.CSSProperties);
41
+ }
42
+
43
+ // ============================================
44
+ // CONTEXT
45
+ // ============================================
46
+
47
+ export const SeparatorContext = createContext<SeparatorProps | null>(null);
48
+
49
+ // ============================================
50
+ // SEPARATOR COMPONENT
51
+ // ============================================
52
+
53
+ /**
54
+ * A separator is a visual divider between two groups of content,
55
+ * e.g. groups of menu items or sections of a page.
56
+ *
57
+ * @example
58
+ * ```tsx
59
+ * <Separator />
60
+ *
61
+ * // Vertical separator
62
+ * <Separator orientation="vertical" />
63
+ *
64
+ * // Custom element type
65
+ * <Separator elementType="div" />
66
+ * ```
67
+ */
68
+ export function Separator(props: SeparatorProps): JSX.Element {
69
+ const [local, ariaProps] = splitProps(props, [
70
+ 'class',
71
+ 'style',
72
+ 'slot',
73
+ ]);
74
+
75
+ // Determine the element type
76
+ const elementType = createMemo(() => {
77
+ let element = ariaProps.elementType || 'hr';
78
+ // If vertical and using hr, switch to div since hr is inherently horizontal
79
+ if (element === 'hr' && ariaProps.orientation === 'vertical') {
80
+ element = 'div';
81
+ }
82
+ return element;
83
+ });
84
+
85
+ // Create separator aria props
86
+ const separatorAria = createSeparator({
87
+ get orientation() { return ariaProps.orientation; },
88
+ get elementType() { return elementType(); },
89
+ get 'aria-label'() { return ariaProps['aria-label']; },
90
+ get 'aria-labelledby'() { return ariaProps['aria-labelledby']; },
91
+ get id() { return ariaProps.id; },
92
+ });
93
+
94
+ // Render props values
95
+ const renderValues = createMemo<SeparatorRenderProps>(() => ({
96
+ orientation: ariaProps.orientation ?? 'horizontal',
97
+ }));
98
+
99
+ // Resolve class
100
+ const resolvedClass = createMemo(() => {
101
+ const cls = local.class;
102
+ if (typeof cls === 'function') {
103
+ return cls(renderValues());
104
+ }
105
+ return cls ?? 'solidaria-Separator';
106
+ });
107
+
108
+ // Resolve style
109
+ const resolvedStyle = createMemo(() => {
110
+ const style = local.style;
111
+ if (typeof style === 'function') {
112
+ return style(renderValues());
113
+ }
114
+ return style;
115
+ });
116
+
117
+ // Filter DOM props
118
+ const domProps = createMemo(() => filterDOMProps(ariaProps, { global: true }));
119
+
120
+ return (
121
+ <Dynamic
122
+ component={elementType()}
123
+ {...domProps()}
124
+ {...separatorAria.separatorProps}
125
+ class={resolvedClass()}
126
+ style={resolvedStyle()}
127
+ slot={local.slot}
128
+ />
129
+ );
130
+ }
package/src/Slider.tsx ADDED
@@ -0,0 +1,500 @@
1
+ /**
2
+ * Slider component for solidaria-components
3
+ *
4
+ * A pre-wired headless slider that combines state + aria hooks.
5
+ * Port of react-aria-components/src/Slider.tsx
6
+ */
7
+
8
+ import {
9
+ type JSX,
10
+ createContext,
11
+ createMemo,
12
+ splitProps,
13
+ useContext,
14
+ Show,
15
+ } from 'solid-js';
16
+ import {
17
+ createSlider,
18
+ createFocusRing,
19
+ createHover,
20
+ type AriaSliderProps,
21
+ } from '@proyecto-viviana/solidaria';
22
+ import {
23
+ createSliderState,
24
+ type SliderState,
25
+ type SliderOrientation,
26
+ } from '@proyecto-viviana/solid-stately';
27
+ import {
28
+ type RenderChildren,
29
+ type ClassNameOrFunction,
30
+ type StyleOrFunction,
31
+ type SlotProps,
32
+ useRenderProps,
33
+ filterDOMProps,
34
+ } from './utils';
35
+
36
+ // ============================================
37
+ // TYPES
38
+ // ============================================
39
+
40
+ export interface SliderRenderProps {
41
+ /** Whether the slider is disabled. */
42
+ isDisabled: boolean;
43
+ /** Whether the slider is being dragged. */
44
+ isDragging: boolean;
45
+ /** Whether the slider is focused. */
46
+ isFocused: boolean;
47
+ /** The current value. */
48
+ value: number;
49
+ /** The value as a percent (0-1). */
50
+ valuePercent: number;
51
+ /** The orientation. */
52
+ orientation: SliderOrientation;
53
+ }
54
+
55
+ export interface SliderProps extends Omit<AriaSliderProps, 'label'>, SlotProps {
56
+ /** The current value (controlled). */
57
+ value?: number;
58
+ /** The default value (uncontrolled). */
59
+ defaultValue?: number;
60
+ /** Handler called when the value changes. */
61
+ onChange?: (value: number) => void;
62
+ /** Handler called when dragging ends. */
63
+ onChangeEnd?: (value: number) => void;
64
+ /** The minimum value. */
65
+ minValue?: number;
66
+ /** The maximum value. */
67
+ maxValue?: number;
68
+ /** The step value. */
69
+ step?: number;
70
+ /** The orientation of the slider. */
71
+ orientation?: SliderOrientation;
72
+ /** The locale for number formatting. */
73
+ locale?: string;
74
+ /** Number format options. */
75
+ formatOptions?: Intl.NumberFormatOptions;
76
+ /** A visible label for the slider. */
77
+ label?: JSX.Element;
78
+ /** The children of the component. */
79
+ children?: RenderChildren<SliderRenderProps>;
80
+ /** The CSS className for the element. */
81
+ class?: ClassNameOrFunction<SliderRenderProps>;
82
+ /** The inline style for the element. */
83
+ style?: StyleOrFunction<SliderRenderProps>;
84
+ }
85
+
86
+ export interface SliderTrackRenderProps {
87
+ /** Whether the slider is disabled. */
88
+ isDisabled: boolean;
89
+ /** Whether the slider is being dragged. */
90
+ isDragging: boolean;
91
+ /** The value as a percent (0-1). */
92
+ valuePercent: number;
93
+ /** The orientation. */
94
+ orientation: SliderOrientation;
95
+ }
96
+
97
+ export interface SliderTrackProps extends SlotProps {
98
+ /** The children of the track. */
99
+ children?: RenderChildren<SliderTrackRenderProps>;
100
+ /** The CSS className for the element. */
101
+ class?: ClassNameOrFunction<SliderTrackRenderProps>;
102
+ /** The inline style for the element. */
103
+ style?: StyleOrFunction<SliderTrackRenderProps>;
104
+ }
105
+
106
+ export interface SliderThumbRenderProps {
107
+ /** Whether the slider is disabled. */
108
+ isDisabled: boolean;
109
+ /** Whether the thumb is being dragged. */
110
+ isDragging: boolean;
111
+ /** Whether the thumb is focused. */
112
+ isFocused: boolean;
113
+ /** Whether the thumb has keyboard focus. */
114
+ isFocusVisible: boolean;
115
+ /** Whether the thumb is hovered. */
116
+ isHovered: boolean;
117
+ /** The current value. */
118
+ value: number;
119
+ /** The value as a percent (0-1). */
120
+ valuePercent: number;
121
+ }
122
+
123
+ export interface SliderThumbProps extends SlotProps {
124
+ /** The children of the thumb. */
125
+ children?: RenderChildren<SliderThumbRenderProps>;
126
+ /** The CSS className for the element. */
127
+ class?: ClassNameOrFunction<SliderThumbRenderProps>;
128
+ /** The inline style for the element. */
129
+ style?: StyleOrFunction<SliderThumbRenderProps>;
130
+ }
131
+
132
+ export interface SliderOutputRenderProps {
133
+ /** The current value. */
134
+ value: number;
135
+ /** The formatted value string. */
136
+ formattedValue: string;
137
+ }
138
+
139
+ export interface SliderOutputProps extends SlotProps {
140
+ /** The children of the output. */
141
+ children?: RenderChildren<SliderOutputRenderProps>;
142
+ /** The CSS className for the element. */
143
+ class?: ClassNameOrFunction<SliderOutputRenderProps>;
144
+ /** The inline style for the element. */
145
+ style?: StyleOrFunction<SliderOutputRenderProps>;
146
+ }
147
+
148
+ // ============================================
149
+ // CONTEXT
150
+ // ============================================
151
+
152
+ interface SliderContextValue {
153
+ state: SliderState;
154
+ trackProps: JSX.HTMLAttributes<HTMLElement>;
155
+ thumbProps: JSX.HTMLAttributes<HTMLElement>;
156
+ outputProps: JSX.HTMLAttributes<HTMLElement>;
157
+ inputProps: JSX.InputHTMLAttributes<HTMLInputElement>;
158
+ trackRef: HTMLElement | undefined;
159
+ setTrackRef: (el: HTMLElement) => void;
160
+ }
161
+
162
+ export const SliderContext = createContext<SliderContextValue | null>(null);
163
+
164
+ // ============================================
165
+ // COMPONENTS
166
+ // ============================================
167
+
168
+ /**
169
+ * A slider allows users to select a value from a range.
170
+ */
171
+ export function Slider(props: SliderProps): JSX.Element {
172
+ const [local, stateProps, ariaProps, rest] = splitProps(
173
+ props,
174
+ ['class', 'style', 'slot'],
175
+ ['value', 'defaultValue', 'onChange', 'onChangeEnd', 'minValue', 'maxValue', 'step', 'orientation', 'locale', 'formatOptions'],
176
+ ['label', 'aria-label', 'aria-labelledby', 'aria-describedby', 'isDisabled', 'id']
177
+ );
178
+
179
+ // Create slider state
180
+ const state = createSliderState({
181
+ get value() {
182
+ return stateProps.value;
183
+ },
184
+ get defaultValue() {
185
+ return stateProps.defaultValue;
186
+ },
187
+ get onChange() {
188
+ return stateProps.onChange;
189
+ },
190
+ get onChangeEnd() {
191
+ return stateProps.onChangeEnd;
192
+ },
193
+ get minValue() {
194
+ return stateProps.minValue;
195
+ },
196
+ get maxValue() {
197
+ return stateProps.maxValue;
198
+ },
199
+ get step() {
200
+ return stateProps.step;
201
+ },
202
+ get orientation() {
203
+ return stateProps.orientation;
204
+ },
205
+ get locale() {
206
+ return stateProps.locale;
207
+ },
208
+ get formatOptions() {
209
+ return stateProps.formatOptions;
210
+ },
211
+ get isDisabled() {
212
+ return ariaProps.isDisabled;
213
+ },
214
+ });
215
+
216
+ // Track ref for pointer handling
217
+ let trackRef: HTMLElement | undefined;
218
+ const setTrackRef = (el: HTMLElement) => {
219
+ trackRef = el;
220
+ };
221
+
222
+ // Create slider aria props
223
+ const {
224
+ labelProps,
225
+ groupProps,
226
+ trackProps,
227
+ thumbProps,
228
+ inputProps,
229
+ outputProps,
230
+ } = createSlider(ariaProps, state, () => trackRef ?? null);
231
+
232
+ // Render props values
233
+ const renderValues = createMemo<SliderRenderProps>(() => ({
234
+ isDisabled: state.isDisabled,
235
+ isDragging: state.isDragging(),
236
+ isFocused: state.isFocused(),
237
+ value: state.value(),
238
+ valuePercent: state.getValuePercent(),
239
+ orientation: state.orientation,
240
+ }));
241
+
242
+ // Resolve render props
243
+ const renderProps = useRenderProps(
244
+ {
245
+ children: props.children,
246
+ class: local.class,
247
+ style: local.style,
248
+ defaultClassName: 'solidaria-Slider',
249
+ },
250
+ renderValues
251
+ );
252
+
253
+ // Filter DOM props
254
+ const domProps = createMemo(() => filterDOMProps(rest as Record<string, unknown>, { global: true }));
255
+
256
+ // Clean props helpers
257
+ const cleanGroupProps = () => {
258
+ const { ref: _ref, ...rest } = groupProps as Record<string, unknown>;
259
+ return rest;
260
+ };
261
+
262
+ return (
263
+ <SliderContext.Provider
264
+ value={{
265
+ state,
266
+ trackProps,
267
+ thumbProps,
268
+ outputProps,
269
+ inputProps,
270
+ trackRef,
271
+ setTrackRef,
272
+ }}
273
+ >
274
+ <div
275
+ {...domProps()}
276
+ {...cleanGroupProps()}
277
+ class={renderProps.class()}
278
+ style={renderProps.style()}
279
+ data-disabled={state.isDisabled || undefined}
280
+ data-orientation={state.orientation}
281
+ data-dragging={state.isDragging() || undefined}
282
+ >
283
+ {/* Label */}
284
+ <Show when={ariaProps.label}>
285
+ <span {...labelProps}>{ariaProps.label}</span>
286
+ </Show>
287
+
288
+ {renderProps.renderChildren()}
289
+
290
+ {/* Hidden input for form submission */}
291
+ <input {...inputProps} />
292
+ </div>
293
+ </SliderContext.Provider>
294
+ );
295
+ }
296
+
297
+ /**
298
+ * The track element of a slider.
299
+ */
300
+ export function SliderTrack(props: SliderTrackProps): JSX.Element {
301
+ const [local] = splitProps(props, ['class', 'style', 'slot']);
302
+
303
+ const context = useContext(SliderContext);
304
+ if (!context) {
305
+ throw new Error('SliderTrack must be used within a Slider');
306
+ }
307
+
308
+ const { state, trackProps, setTrackRef } = context;
309
+
310
+ // Render props values
311
+ const renderValues = createMemo<SliderTrackRenderProps>(() => ({
312
+ isDisabled: state.isDisabled,
313
+ isDragging: state.isDragging(),
314
+ valuePercent: state.getValuePercent(),
315
+ orientation: state.orientation,
316
+ }));
317
+
318
+ // Resolve render props
319
+ const renderProps = useRenderProps(
320
+ {
321
+ children: props.children,
322
+ class: local.class,
323
+ style: local.style,
324
+ defaultClassName: 'solidaria-Slider-track',
325
+ },
326
+ renderValues
327
+ );
328
+
329
+ // Clean props
330
+ const cleanTrackProps = () => {
331
+ const { ref: _ref, style: trackStyle, ...rest } = trackProps as Record<string, unknown>;
332
+ return rest;
333
+ };
334
+
335
+ // Merge styles
336
+ const mergedStyle = () => {
337
+ const trackStyle = (trackProps as { style?: Record<string, string> }).style || {};
338
+ const renderStyle = renderProps.style() || {};
339
+ return { ...trackStyle, ...renderStyle };
340
+ };
341
+
342
+ return (
343
+ <div
344
+ ref={setTrackRef}
345
+ {...cleanTrackProps()}
346
+ class={renderProps.class()}
347
+ style={mergedStyle()}
348
+ data-disabled={state.isDisabled || undefined}
349
+ data-orientation={state.orientation}
350
+ data-dragging={state.isDragging() || undefined}
351
+ >
352
+ {renderProps.renderChildren()}
353
+ </div>
354
+ );
355
+ }
356
+
357
+ /**
358
+ * The thumb element of a slider.
359
+ */
360
+ export function SliderThumb(props: SliderThumbProps): JSX.Element {
361
+ const [local] = splitProps(props, ['class', 'style', 'slot']);
362
+
363
+ const context = useContext(SliderContext);
364
+ if (!context) {
365
+ throw new Error('SliderFill must be used within a Slider');
366
+ }
367
+
368
+ const { state, thumbProps } = context;
369
+
370
+ // Create focus ring
371
+ const { isFocused, isFocusVisible, focusProps } = createFocusRing();
372
+
373
+ // Create hover
374
+ const { isHovered, hoverProps } = createHover({
375
+ get isDisabled() {
376
+ return state.isDisabled;
377
+ },
378
+ });
379
+
380
+ // Render props values
381
+ const renderValues = createMemo<SliderThumbRenderProps>(() => ({
382
+ isDisabled: state.isDisabled,
383
+ isDragging: state.isDragging(),
384
+ isFocused: isFocused() || state.isFocused(),
385
+ isFocusVisible: isFocusVisible(),
386
+ isHovered: isHovered(),
387
+ value: state.value(),
388
+ valuePercent: state.getValuePercent(),
389
+ }));
390
+
391
+ // Resolve render props
392
+ const renderProps = useRenderProps(
393
+ {
394
+ children: props.children,
395
+ class: local.class,
396
+ style: local.style,
397
+ defaultClassName: 'solidaria-Slider-thumb',
398
+ },
399
+ renderValues
400
+ );
401
+
402
+ // Clean props
403
+ const cleanThumbProps = () => {
404
+ const { ref: _ref, style: thumbStyle, ...rest } = thumbProps as Record<string, unknown>;
405
+ return rest;
406
+ };
407
+ const cleanFocusProps = () => {
408
+ const { ref: _ref, ...rest } = focusProps as Record<string, unknown>;
409
+ return rest;
410
+ };
411
+ const cleanHoverProps = () => {
412
+ const { ref: _ref, ...rest } = hoverProps as Record<string, unknown>;
413
+ return rest;
414
+ };
415
+
416
+ // Merge styles
417
+ const mergedStyle = () => {
418
+ const thumbStyle = (thumbProps as { style?: Record<string, string> }).style || {};
419
+ const renderStyle = renderProps.style() || {};
420
+ return { ...thumbStyle, ...renderStyle };
421
+ };
422
+
423
+ return (
424
+ <div
425
+ {...cleanThumbProps()}
426
+ {...cleanFocusProps()}
427
+ {...cleanHoverProps()}
428
+ class={renderProps.class()}
429
+ style={mergedStyle()}
430
+ data-disabled={state.isDisabled || undefined}
431
+ data-dragging={state.isDragging() || undefined}
432
+ data-focused={isFocused() || undefined}
433
+ data-focus-visible={isFocusVisible() || undefined}
434
+ data-hovered={isHovered() || undefined}
435
+ >
436
+ {renderProps.renderChildren()}
437
+ </div>
438
+ );
439
+ }
440
+
441
+ /**
442
+ * The output element of a slider, displaying the current value.
443
+ */
444
+ export function SliderOutput(props: SliderOutputProps): JSX.Element {
445
+ const [local] = splitProps(props, ['class', 'style', 'slot']);
446
+
447
+ const context = useContext(SliderContext);
448
+ if (!context) {
449
+ throw new Error('SliderThumb must be used within a Slider');
450
+ }
451
+
452
+ const { state, outputProps } = context;
453
+
454
+ // Render props values
455
+ const renderValues = createMemo<SliderOutputRenderProps>(() => ({
456
+ value: state.value(),
457
+ formattedValue: state.getFormattedValue(),
458
+ }));
459
+
460
+ // Resolve render props
461
+ const renderProps = useRenderProps(
462
+ {
463
+ children: props.children,
464
+ class: local.class,
465
+ style: local.style,
466
+ defaultClassName: 'solidaria-Slider-output',
467
+ },
468
+ renderValues
469
+ );
470
+
471
+ // Clean props
472
+ const cleanOutputProps = () => {
473
+ const { ref: _ref, ...rest } = outputProps as Record<string, unknown>;
474
+ return rest;
475
+ };
476
+
477
+ // Default children shows formatted value
478
+ const renderedChildren = () => {
479
+ // Check if raw children prop exists before calling renderChildren
480
+ if (renderProps.children === undefined || renderProps.children === null) {
481
+ return state.getFormattedValue();
482
+ }
483
+ return renderProps.renderChildren();
484
+ };
485
+
486
+ return (
487
+ <output
488
+ {...cleanOutputProps()}
489
+ class={renderProps.class()}
490
+ style={renderProps.style()}
491
+ >
492
+ {renderedChildren()}
493
+ </output>
494
+ );
495
+ }
496
+
497
+ // Attach sub-components
498
+ Slider.Track = SliderTrack;
499
+ Slider.Thumb = SliderThumb;
500
+ Slider.Output = SliderOutput;