@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.
- package/dist/Color.d.ts +2 -6
- package/dist/Color.d.ts.map +1 -1
- package/dist/ComboBox.d.ts +3 -3
- package/dist/ComboBox.d.ts.map +1 -1
- package/dist/GridList.d.ts +2 -2
- package/dist/GridList.d.ts.map +1 -1
- package/dist/ListBox.d.ts +5 -5
- package/dist/ListBox.d.ts.map +1 -1
- package/dist/Menu.d.ts +3 -3
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Select.d.ts +3 -3
- package/dist/Select.d.ts.map +1 -1
- package/dist/Table.d.ts +2 -2
- package/dist/Table.d.ts.map +1 -1
- package/dist/Tabs.d.ts +1 -1
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/index.js +56 -56
- package/dist/index.js.map +2 -2
- package/dist/index.ssr.js +56 -56
- package/dist/index.ssr.js.map +2 -2
- package/package.json +10 -8
- package/src/Autocomplete.tsx +174 -0
- package/src/Breadcrumbs.tsx +264 -0
- package/src/Button.tsx +238 -0
- package/src/Calendar.tsx +471 -0
- package/src/Checkbox.tsx +387 -0
- package/src/Color.tsx +1370 -0
- package/src/ComboBox.tsx +824 -0
- package/src/DateField.tsx +337 -0
- package/src/DatePicker.tsx +367 -0
- package/src/Dialog.tsx +262 -0
- package/src/Disclosure.tsx +439 -0
- package/src/GridList.tsx +511 -0
- package/src/Landmark.tsx +203 -0
- package/src/Link.tsx +201 -0
- package/src/ListBox.tsx +346 -0
- package/src/Menu.tsx +544 -0
- package/src/Meter.tsx +157 -0
- package/src/Modal.tsx +433 -0
- package/src/NumberField.tsx +542 -0
- package/src/Popover.tsx +540 -0
- package/src/ProgressBar.tsx +162 -0
- package/src/RadioGroup.tsx +356 -0
- package/src/RangeCalendar.tsx +462 -0
- package/src/SearchField.tsx +479 -0
- package/src/Select.tsx +734 -0
- package/src/Separator.tsx +130 -0
- package/src/Slider.tsx +500 -0
- package/src/Switch.tsx +213 -0
- package/src/Table.tsx +857 -0
- package/src/Tabs.tsx +552 -0
- package/src/TagGroup.tsx +421 -0
- package/src/TextField.tsx +271 -0
- package/src/TimeField.tsx +455 -0
- package/src/Toast.tsx +503 -0
- package/src/Toolbar.tsx +160 -0
- package/src/Tooltip.tsx +423 -0
- package/src/Tree.tsx +551 -0
- package/src/VisuallyHidden.tsx +60 -0
- package/src/contexts.ts +74 -0
- package/src/index.ts +620 -0
- package/src/utils.tsx +329 -0
- package/dist/index.jsx +0 -9056
- 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;
|