@proyecto-viviana/solidaria-components 0.1.3 → 0.2.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.
- package/dist/Color.d.ts +6 -2
- 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 +15 -15
- package/dist/index.js.map +2 -2
- package/dist/index.ssr.js +15 -15
- package/dist/index.ssr.js.map +2 -2
- package/package.json +8 -10
- package/src/Autocomplete.tsx +0 -174
- package/src/Breadcrumbs.tsx +0 -264
- package/src/Button.tsx +0 -238
- package/src/Calendar.tsx +0 -471
- package/src/Checkbox.tsx +0 -387
- package/src/Color.tsx +0 -1370
- package/src/ComboBox.tsx +0 -824
- package/src/DateField.tsx +0 -337
- package/src/DatePicker.tsx +0 -367
- package/src/Dialog.tsx +0 -262
- package/src/Disclosure.tsx +0 -439
- package/src/GridList.tsx +0 -511
- package/src/Landmark.tsx +0 -203
- package/src/Link.tsx +0 -201
- package/src/ListBox.tsx +0 -346
- package/src/Menu.tsx +0 -544
- package/src/Meter.tsx +0 -157
- package/src/Modal.tsx +0 -433
- package/src/NumberField.tsx +0 -542
- package/src/Popover.tsx +0 -540
- package/src/ProgressBar.tsx +0 -162
- package/src/RadioGroup.tsx +0 -356
- package/src/RangeCalendar.tsx +0 -462
- package/src/SearchField.tsx +0 -479
- package/src/Select.tsx +0 -734
- package/src/Separator.tsx +0 -130
- package/src/Slider.tsx +0 -500
- package/src/Switch.tsx +0 -213
- package/src/Table.tsx +0 -857
- package/src/Tabs.tsx +0 -552
- package/src/TagGroup.tsx +0 -421
- package/src/TextField.tsx +0 -271
- package/src/TimeField.tsx +0 -455
- package/src/Toast.tsx +0 -503
- package/src/Toolbar.tsx +0 -160
- package/src/Tooltip.tsx +0 -423
- package/src/Tree.tsx +0 -551
- package/src/VisuallyHidden.tsx +0 -60
- package/src/contexts.ts +0 -74
- package/src/index.ts +0 -620
- package/src/utils.tsx +0 -329
package/src/Color.tsx
DELETED
|
@@ -1,1370 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Color components for solidaria-components
|
|
3
|
-
*
|
|
4
|
-
* Pre-wired headless color picker components that combine state + aria hooks.
|
|
5
|
-
* Port of react-aria-components color components.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
type JSX,
|
|
10
|
-
createContext,
|
|
11
|
-
createMemo,
|
|
12
|
-
splitProps,
|
|
13
|
-
useContext,
|
|
14
|
-
Show,
|
|
15
|
-
} from 'solid-js';
|
|
16
|
-
import {
|
|
17
|
-
createColorSlider,
|
|
18
|
-
createColorArea,
|
|
19
|
-
createColorWheel,
|
|
20
|
-
createColorField,
|
|
21
|
-
createColorSwatch,
|
|
22
|
-
createFocusRing,
|
|
23
|
-
createHover,
|
|
24
|
-
type AriaColorSliderOptions,
|
|
25
|
-
type AriaColorAreaOptions,
|
|
26
|
-
type AriaColorWheelOptions,
|
|
27
|
-
type AriaColorFieldOptions,
|
|
28
|
-
} from '@proyecto-viviana/solidaria';
|
|
29
|
-
import {
|
|
30
|
-
createColorSliderState,
|
|
31
|
-
createColorAreaState,
|
|
32
|
-
createColorWheelState,
|
|
33
|
-
createColorFieldState,
|
|
34
|
-
normalizeColor,
|
|
35
|
-
type Color,
|
|
36
|
-
type ColorChannel,
|
|
37
|
-
type ColorFormat,
|
|
38
|
-
type ColorSliderState,
|
|
39
|
-
type ColorAreaState,
|
|
40
|
-
type ColorWheelState,
|
|
41
|
-
type ColorFieldState,
|
|
42
|
-
} from '@proyecto-viviana/solid-stately';
|
|
43
|
-
import {
|
|
44
|
-
type RenderChildren,
|
|
45
|
-
type ClassNameOrFunction,
|
|
46
|
-
type StyleOrFunction,
|
|
47
|
-
type SlotProps,
|
|
48
|
-
useRenderProps,
|
|
49
|
-
filterDOMProps,
|
|
50
|
-
} from './utils';
|
|
51
|
-
|
|
52
|
-
// ============================================
|
|
53
|
-
// COLOR SLIDER
|
|
54
|
-
// ============================================
|
|
55
|
-
|
|
56
|
-
export interface ColorSliderRenderProps {
|
|
57
|
-
/** Whether the slider is disabled. */
|
|
58
|
-
isDisabled: boolean;
|
|
59
|
-
/** Whether the slider is being dragged. */
|
|
60
|
-
isDragging: boolean;
|
|
61
|
-
/** The color channel being controlled. */
|
|
62
|
-
channel: ColorChannel;
|
|
63
|
-
/** The current value. */
|
|
64
|
-
value: number;
|
|
65
|
-
/** The current color. */
|
|
66
|
-
color: Color;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export interface ColorSliderProps extends Omit<AriaColorSliderOptions, 'channel'>, SlotProps {
|
|
70
|
-
/** The current color value (controlled). */
|
|
71
|
-
value?: Color | string;
|
|
72
|
-
/** The default color value (uncontrolled). */
|
|
73
|
-
defaultValue?: Color | string;
|
|
74
|
-
/** Handler called when the color changes. */
|
|
75
|
-
onChange?: (color: Color) => void;
|
|
76
|
-
/** Handler called when dragging ends. */
|
|
77
|
-
onChangeEnd?: (color: Color) => void;
|
|
78
|
-
/** The color channel to control. */
|
|
79
|
-
channel: ColorChannel;
|
|
80
|
-
/** A visible label for the slider. */
|
|
81
|
-
label?: JSX.Element;
|
|
82
|
-
/** The children of the component. */
|
|
83
|
-
children?: RenderChildren<ColorSliderRenderProps>;
|
|
84
|
-
/** The CSS className for the element. */
|
|
85
|
-
class?: ClassNameOrFunction<ColorSliderRenderProps>;
|
|
86
|
-
/** The inline style for the element. */
|
|
87
|
-
style?: StyleOrFunction<ColorSliderRenderProps>;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export interface ColorSliderTrackRenderProps {
|
|
91
|
-
/** Whether the slider is disabled. */
|
|
92
|
-
isDisabled: boolean;
|
|
93
|
-
/** Whether the slider is being dragged. */
|
|
94
|
-
isDragging: boolean;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export interface ColorSliderTrackProps extends SlotProps {
|
|
98
|
-
/** The children of the track. */
|
|
99
|
-
children?: RenderChildren<ColorSliderTrackRenderProps>;
|
|
100
|
-
/** The CSS className for the element. */
|
|
101
|
-
class?: ClassNameOrFunction<ColorSliderTrackRenderProps>;
|
|
102
|
-
/** The inline style for the element. */
|
|
103
|
-
style?: StyleOrFunction<ColorSliderTrackRenderProps>;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export interface ColorSliderThumbRenderProps {
|
|
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
|
-
}
|
|
118
|
-
|
|
119
|
-
export interface ColorSliderThumbProps extends SlotProps {
|
|
120
|
-
/** The children of the thumb. */
|
|
121
|
-
children?: RenderChildren<ColorSliderThumbRenderProps>;
|
|
122
|
-
/** The CSS className for the element. */
|
|
123
|
-
class?: ClassNameOrFunction<ColorSliderThumbRenderProps>;
|
|
124
|
-
/** The inline style for the element. */
|
|
125
|
-
style?: StyleOrFunction<ColorSliderThumbRenderProps>;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Context
|
|
129
|
-
interface ColorSliderContextValue {
|
|
130
|
-
state: ColorSliderState;
|
|
131
|
-
trackProps: JSX.HTMLAttributes<HTMLDivElement>;
|
|
132
|
-
thumbProps: JSX.HTMLAttributes<HTMLDivElement>;
|
|
133
|
-
inputProps: JSX.InputHTMLAttributes<HTMLInputElement>;
|
|
134
|
-
trackRef: HTMLDivElement | undefined;
|
|
135
|
-
setTrackRef: (el: HTMLDivElement) => void;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export const ColorSliderContext = createContext<ColorSliderContextValue | null>(null);
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* A color slider allows users to adjust a single color channel.
|
|
142
|
-
*/
|
|
143
|
-
export function ColorSlider(props: ColorSliderProps): JSX.Element {
|
|
144
|
-
const [local, stateProps, ariaProps, rest] = splitProps(
|
|
145
|
-
props,
|
|
146
|
-
['children', 'class', 'style', 'slot', 'label'],
|
|
147
|
-
['value', 'defaultValue', 'onChange', 'onChangeEnd', 'channel'],
|
|
148
|
-
['aria-label', 'aria-labelledby', 'aria-describedby', 'isDisabled', 'channelName']
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
// Create color slider state
|
|
152
|
-
const state = createColorSliderState(() => ({
|
|
153
|
-
value: stateProps.value,
|
|
154
|
-
defaultValue: stateProps.defaultValue,
|
|
155
|
-
onChange: stateProps.onChange,
|
|
156
|
-
onChangeEnd: stateProps.onChangeEnd,
|
|
157
|
-
channel: stateProps.channel,
|
|
158
|
-
isDisabled: ariaProps.isDisabled,
|
|
159
|
-
}));
|
|
160
|
-
|
|
161
|
-
// Track ref
|
|
162
|
-
let trackRef: HTMLDivElement | undefined;
|
|
163
|
-
const setTrackRef = (el: HTMLDivElement) => {
|
|
164
|
-
trackRef = el;
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
// Create color slider aria props
|
|
168
|
-
const {
|
|
169
|
-
trackProps,
|
|
170
|
-
thumbProps,
|
|
171
|
-
inputProps,
|
|
172
|
-
labelProps,
|
|
173
|
-
} = createColorSlider(
|
|
174
|
-
() => ({
|
|
175
|
-
channel: stateProps.channel,
|
|
176
|
-
'aria-label': ariaProps['aria-label'],
|
|
177
|
-
'aria-labelledby': ariaProps['aria-labelledby'],
|
|
178
|
-
'aria-describedby': ariaProps['aria-describedby'],
|
|
179
|
-
isDisabled: ariaProps.isDisabled,
|
|
180
|
-
channelName: ariaProps.channelName,
|
|
181
|
-
}),
|
|
182
|
-
() => state,
|
|
183
|
-
() => trackRef ?? null
|
|
184
|
-
);
|
|
185
|
-
|
|
186
|
-
// Render props values
|
|
187
|
-
const renderValues = createMemo<ColorSliderRenderProps>(() => ({
|
|
188
|
-
isDisabled: state.isDisabled,
|
|
189
|
-
isDragging: state.isDragging,
|
|
190
|
-
channel: state.channel,
|
|
191
|
-
value: state.getThumbValue(),
|
|
192
|
-
color: state.value,
|
|
193
|
-
}));
|
|
194
|
-
|
|
195
|
-
// Resolve render props
|
|
196
|
-
const renderProps = useRenderProps(
|
|
197
|
-
{
|
|
198
|
-
children: props.children,
|
|
199
|
-
class: local.class,
|
|
200
|
-
style: local.style,
|
|
201
|
-
defaultClassName: 'solidaria-ColorSlider',
|
|
202
|
-
},
|
|
203
|
-
renderValues
|
|
204
|
-
);
|
|
205
|
-
|
|
206
|
-
// Filter DOM props
|
|
207
|
-
const domProps = createMemo(() => filterDOMProps(rest as Record<string, unknown>, { global: true }));
|
|
208
|
-
|
|
209
|
-
return (
|
|
210
|
-
<ColorSliderContext.Provider
|
|
211
|
-
value={{
|
|
212
|
-
state,
|
|
213
|
-
trackProps,
|
|
214
|
-
thumbProps,
|
|
215
|
-
inputProps,
|
|
216
|
-
trackRef,
|
|
217
|
-
setTrackRef,
|
|
218
|
-
}}
|
|
219
|
-
>
|
|
220
|
-
<div
|
|
221
|
-
{...domProps()}
|
|
222
|
-
class={renderProps.class()}
|
|
223
|
-
style={renderProps.style()}
|
|
224
|
-
data-disabled={state.isDisabled || undefined}
|
|
225
|
-
data-dragging={state.isDragging || undefined}
|
|
226
|
-
data-channel={state.channel}
|
|
227
|
-
>
|
|
228
|
-
{/* Label */}
|
|
229
|
-
<Show when={local.label}>
|
|
230
|
-
<label {...labelProps}>{local.label}</label>
|
|
231
|
-
</Show>
|
|
232
|
-
|
|
233
|
-
{renderProps.renderChildren()}
|
|
234
|
-
|
|
235
|
-
{/* Hidden input for accessibility */}
|
|
236
|
-
<input {...inputProps} />
|
|
237
|
-
</div>
|
|
238
|
-
</ColorSliderContext.Provider>
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* The track element of a color slider.
|
|
244
|
-
*/
|
|
245
|
-
export function ColorSliderTrack(props: ColorSliderTrackProps): JSX.Element {
|
|
246
|
-
const [local] = splitProps(props, ['class', 'style', 'slot']);
|
|
247
|
-
|
|
248
|
-
const context = useContext(ColorSliderContext);
|
|
249
|
-
if (!context) {
|
|
250
|
-
throw new Error('ColorSliderTrack must be used within a ColorSlider');
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const { state, trackProps, setTrackRef } = context;
|
|
254
|
-
|
|
255
|
-
// Render props values
|
|
256
|
-
const renderValues = createMemo<ColorSliderTrackRenderProps>(() => ({
|
|
257
|
-
isDisabled: state.isDisabled,
|
|
258
|
-
isDragging: state.isDragging,
|
|
259
|
-
}));
|
|
260
|
-
|
|
261
|
-
// Resolve render props
|
|
262
|
-
const renderProps = useRenderProps(
|
|
263
|
-
{
|
|
264
|
-
children: props.children,
|
|
265
|
-
class: local.class,
|
|
266
|
-
style: local.style,
|
|
267
|
-
defaultClassName: 'solidaria-ColorSlider-track',
|
|
268
|
-
},
|
|
269
|
-
renderValues
|
|
270
|
-
);
|
|
271
|
-
|
|
272
|
-
// Clean props
|
|
273
|
-
const cleanTrackProps = () => {
|
|
274
|
-
const { ref: _ref, style: _trackStyle, ...rest } = trackProps as Record<string, unknown>;
|
|
275
|
-
return rest;
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
// Merge styles
|
|
279
|
-
const mergedStyle = () => {
|
|
280
|
-
const trackStyle = (trackProps as { style?: Record<string, string> }).style || {};
|
|
281
|
-
const renderStyle = renderProps.style() || {};
|
|
282
|
-
return { ...trackStyle, ...renderStyle };
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
return (
|
|
286
|
-
<div
|
|
287
|
-
ref={setTrackRef}
|
|
288
|
-
{...cleanTrackProps()}
|
|
289
|
-
class={renderProps.class()}
|
|
290
|
-
style={mergedStyle()}
|
|
291
|
-
data-disabled={state.isDisabled || undefined}
|
|
292
|
-
data-dragging={state.isDragging || undefined}
|
|
293
|
-
>
|
|
294
|
-
{renderProps.renderChildren()}
|
|
295
|
-
</div>
|
|
296
|
-
);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* The thumb element of a color slider.
|
|
301
|
-
*/
|
|
302
|
-
export function ColorSliderThumb(props: ColorSliderThumbProps): JSX.Element {
|
|
303
|
-
const [local] = splitProps(props, ['class', 'style', 'slot']);
|
|
304
|
-
|
|
305
|
-
const context = useContext(ColorSliderContext);
|
|
306
|
-
if (!context) {
|
|
307
|
-
throw new Error('ColorSliderThumb must be used within a ColorSlider');
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
const { state, thumbProps } = context;
|
|
311
|
-
|
|
312
|
-
// Create focus ring
|
|
313
|
-
const { isFocused, isFocusVisible, focusProps } = createFocusRing();
|
|
314
|
-
|
|
315
|
-
// Create hover
|
|
316
|
-
const { isHovered, hoverProps } = createHover({
|
|
317
|
-
get isDisabled() {
|
|
318
|
-
return state.isDisabled;
|
|
319
|
-
},
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
// Render props values
|
|
323
|
-
const renderValues = createMemo<ColorSliderThumbRenderProps>(() => ({
|
|
324
|
-
isDisabled: state.isDisabled,
|
|
325
|
-
isDragging: state.isDragging,
|
|
326
|
-
isFocused: isFocused(),
|
|
327
|
-
isFocusVisible: isFocusVisible(),
|
|
328
|
-
isHovered: isHovered(),
|
|
329
|
-
}));
|
|
330
|
-
|
|
331
|
-
// Resolve render props
|
|
332
|
-
const renderProps = useRenderProps(
|
|
333
|
-
{
|
|
334
|
-
children: props.children,
|
|
335
|
-
class: local.class,
|
|
336
|
-
style: local.style,
|
|
337
|
-
defaultClassName: 'solidaria-ColorSlider-thumb',
|
|
338
|
-
},
|
|
339
|
-
renderValues
|
|
340
|
-
);
|
|
341
|
-
|
|
342
|
-
// Clean props
|
|
343
|
-
const cleanThumbProps = () => {
|
|
344
|
-
const { ref: _ref, style: _thumbStyle, ...rest } = thumbProps as Record<string, unknown>;
|
|
345
|
-
return rest;
|
|
346
|
-
};
|
|
347
|
-
const cleanFocusProps = () => {
|
|
348
|
-
const { ref: _ref, ...rest } = focusProps as Record<string, unknown>;
|
|
349
|
-
return rest;
|
|
350
|
-
};
|
|
351
|
-
const cleanHoverProps = () => {
|
|
352
|
-
const { ref: _ref, ...rest } = hoverProps as Record<string, unknown>;
|
|
353
|
-
return rest;
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
// Merge styles
|
|
357
|
-
const mergedStyle = () => {
|
|
358
|
-
const thumbStyle = (thumbProps as { style?: Record<string, string> }).style || {};
|
|
359
|
-
const renderStyle = renderProps.style() || {};
|
|
360
|
-
return { ...thumbStyle, ...renderStyle };
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
return (
|
|
364
|
-
<div
|
|
365
|
-
{...cleanThumbProps()}
|
|
366
|
-
{...cleanFocusProps()}
|
|
367
|
-
{...cleanHoverProps()}
|
|
368
|
-
class={renderProps.class()}
|
|
369
|
-
style={mergedStyle()}
|
|
370
|
-
data-disabled={state.isDisabled || undefined}
|
|
371
|
-
data-dragging={state.isDragging || undefined}
|
|
372
|
-
data-focused={isFocused() || undefined}
|
|
373
|
-
data-focus-visible={isFocusVisible() || undefined}
|
|
374
|
-
data-hovered={isHovered() || undefined}
|
|
375
|
-
>
|
|
376
|
-
{renderProps.renderChildren()}
|
|
377
|
-
</div>
|
|
378
|
-
);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// Attach sub-components
|
|
382
|
-
ColorSlider.Track = ColorSliderTrack;
|
|
383
|
-
ColorSlider.Thumb = ColorSliderThumb;
|
|
384
|
-
|
|
385
|
-
// ============================================
|
|
386
|
-
// COLOR AREA
|
|
387
|
-
// ============================================
|
|
388
|
-
|
|
389
|
-
export interface ColorAreaRenderProps {
|
|
390
|
-
/** Whether the area is disabled. */
|
|
391
|
-
isDisabled: boolean;
|
|
392
|
-
/** Whether the area is being dragged. */
|
|
393
|
-
isDragging: boolean;
|
|
394
|
-
/** The X channel. */
|
|
395
|
-
xChannel: ColorChannel;
|
|
396
|
-
/** The Y channel. */
|
|
397
|
-
yChannel: ColorChannel;
|
|
398
|
-
/** The current color. */
|
|
399
|
-
color: Color;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
export interface ColorAreaProps extends AriaColorAreaOptions, SlotProps {
|
|
403
|
-
/** The current color value (controlled). */
|
|
404
|
-
value?: Color | string;
|
|
405
|
-
/** The default color value (uncontrolled). */
|
|
406
|
-
defaultValue?: Color | string;
|
|
407
|
-
/** Handler called when the color changes. */
|
|
408
|
-
onChange?: (color: Color) => void;
|
|
409
|
-
/** Handler called when dragging ends. */
|
|
410
|
-
onChangeEnd?: (color: Color) => void;
|
|
411
|
-
/** The X channel to control. */
|
|
412
|
-
xChannel?: ColorChannel;
|
|
413
|
-
/** The Y channel to control. */
|
|
414
|
-
yChannel?: ColorChannel;
|
|
415
|
-
/** The children of the component. */
|
|
416
|
-
children?: RenderChildren<ColorAreaRenderProps>;
|
|
417
|
-
/** The CSS className for the element. */
|
|
418
|
-
class?: ClassNameOrFunction<ColorAreaRenderProps>;
|
|
419
|
-
/** The inline style for the element. */
|
|
420
|
-
style?: StyleOrFunction<ColorAreaRenderProps>;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
export interface ColorAreaGradientRenderProps {
|
|
424
|
-
/** Whether the area is disabled. */
|
|
425
|
-
isDisabled: boolean;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
export interface ColorAreaGradientProps extends SlotProps {
|
|
429
|
-
/** The children of the gradient. */
|
|
430
|
-
children?: RenderChildren<ColorAreaGradientRenderProps>;
|
|
431
|
-
/** The CSS className for the element. */
|
|
432
|
-
class?: ClassNameOrFunction<ColorAreaGradientRenderProps>;
|
|
433
|
-
/** The inline style for the element. */
|
|
434
|
-
style?: StyleOrFunction<ColorAreaGradientRenderProps>;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
export interface ColorAreaThumbRenderProps {
|
|
438
|
-
/** Whether the area is disabled. */
|
|
439
|
-
isDisabled: boolean;
|
|
440
|
-
/** Whether the thumb is being dragged. */
|
|
441
|
-
isDragging: boolean;
|
|
442
|
-
/** Whether the thumb is focused. */
|
|
443
|
-
isFocused: boolean;
|
|
444
|
-
/** Whether the thumb has keyboard focus. */
|
|
445
|
-
isFocusVisible: boolean;
|
|
446
|
-
/** Whether the thumb is hovered. */
|
|
447
|
-
isHovered: boolean;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
export interface ColorAreaThumbProps extends SlotProps {
|
|
451
|
-
/** The children of the thumb. */
|
|
452
|
-
children?: RenderChildren<ColorAreaThumbRenderProps>;
|
|
453
|
-
/** The CSS className for the element. */
|
|
454
|
-
class?: ClassNameOrFunction<ColorAreaThumbRenderProps>;
|
|
455
|
-
/** The inline style for the element. */
|
|
456
|
-
style?: StyleOrFunction<ColorAreaThumbRenderProps>;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// Context
|
|
460
|
-
interface ColorAreaContextValue {
|
|
461
|
-
state: ColorAreaState;
|
|
462
|
-
colorAreaProps: JSX.HTMLAttributes<HTMLDivElement>;
|
|
463
|
-
gradientProps: JSX.HTMLAttributes<HTMLDivElement>;
|
|
464
|
-
thumbProps: JSX.HTMLAttributes<HTMLDivElement>;
|
|
465
|
-
xInputProps: JSX.InputHTMLAttributes<HTMLInputElement>;
|
|
466
|
-
yInputProps: JSX.InputHTMLAttributes<HTMLInputElement>;
|
|
467
|
-
areaRef: HTMLDivElement | undefined;
|
|
468
|
-
setAreaRef: (el: HTMLDivElement) => void;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
export const ColorAreaContext = createContext<ColorAreaContextValue | null>(null);
|
|
472
|
-
|
|
473
|
-
/**
|
|
474
|
-
* A color area allows users to select a color using a 2D gradient.
|
|
475
|
-
*/
|
|
476
|
-
export function ColorArea(props: ColorAreaProps): JSX.Element {
|
|
477
|
-
const [local, stateProps, ariaProps, rest] = splitProps(
|
|
478
|
-
props,
|
|
479
|
-
['children', 'class', 'style', 'slot'],
|
|
480
|
-
['value', 'defaultValue', 'onChange', 'onChangeEnd', 'xChannel', 'yChannel'],
|
|
481
|
-
['aria-label', 'aria-labelledby', 'aria-describedby', 'isDisabled']
|
|
482
|
-
);
|
|
483
|
-
|
|
484
|
-
// Create color area state
|
|
485
|
-
const state = createColorAreaState(() => ({
|
|
486
|
-
value: stateProps.value,
|
|
487
|
-
defaultValue: stateProps.defaultValue,
|
|
488
|
-
onChange: stateProps.onChange,
|
|
489
|
-
onChangeEnd: stateProps.onChangeEnd,
|
|
490
|
-
xChannel: stateProps.xChannel,
|
|
491
|
-
yChannel: stateProps.yChannel,
|
|
492
|
-
isDisabled: ariaProps.isDisabled,
|
|
493
|
-
}));
|
|
494
|
-
|
|
495
|
-
// Area ref
|
|
496
|
-
let areaRef: HTMLDivElement | undefined;
|
|
497
|
-
const setAreaRef = (el: HTMLDivElement) => {
|
|
498
|
-
areaRef = el;
|
|
499
|
-
};
|
|
500
|
-
|
|
501
|
-
// Create color area aria props
|
|
502
|
-
const {
|
|
503
|
-
colorAreaProps,
|
|
504
|
-
gradientProps,
|
|
505
|
-
thumbProps,
|
|
506
|
-
xInputProps,
|
|
507
|
-
yInputProps,
|
|
508
|
-
} = createColorArea(
|
|
509
|
-
() => ({
|
|
510
|
-
'aria-label': ariaProps['aria-label'],
|
|
511
|
-
'aria-labelledby': ariaProps['aria-labelledby'],
|
|
512
|
-
'aria-describedby': ariaProps['aria-describedby'],
|
|
513
|
-
isDisabled: ariaProps.isDisabled,
|
|
514
|
-
}),
|
|
515
|
-
() => state,
|
|
516
|
-
() => areaRef ?? null
|
|
517
|
-
);
|
|
518
|
-
|
|
519
|
-
// Render props values
|
|
520
|
-
const renderValues = createMemo<ColorAreaRenderProps>(() => ({
|
|
521
|
-
isDisabled: state.isDisabled,
|
|
522
|
-
isDragging: state.isDragging,
|
|
523
|
-
xChannel: state.xChannel,
|
|
524
|
-
yChannel: state.yChannel,
|
|
525
|
-
color: state.value,
|
|
526
|
-
}));
|
|
527
|
-
|
|
528
|
-
// Resolve render props
|
|
529
|
-
const renderProps = useRenderProps(
|
|
530
|
-
{
|
|
531
|
-
children: props.children,
|
|
532
|
-
class: local.class,
|
|
533
|
-
style: local.style,
|
|
534
|
-
defaultClassName: 'solidaria-ColorArea',
|
|
535
|
-
},
|
|
536
|
-
renderValues
|
|
537
|
-
);
|
|
538
|
-
|
|
539
|
-
// Filter DOM props
|
|
540
|
-
const domProps = createMemo(() => filterDOMProps(rest as Record<string, unknown>, { global: true }));
|
|
541
|
-
|
|
542
|
-
// Clean props
|
|
543
|
-
const cleanColorAreaProps = () => {
|
|
544
|
-
const { ref: _ref, style: _areaStyle, ...rest } = colorAreaProps as Record<string, unknown>;
|
|
545
|
-
return rest;
|
|
546
|
-
};
|
|
547
|
-
|
|
548
|
-
// Merge styles
|
|
549
|
-
const mergedStyle = () => {
|
|
550
|
-
const areaStyle = (colorAreaProps as { style?: Record<string, string> }).style || {};
|
|
551
|
-
const renderStyle = renderProps.style() || {};
|
|
552
|
-
return { ...areaStyle, ...renderStyle };
|
|
553
|
-
};
|
|
554
|
-
|
|
555
|
-
return (
|
|
556
|
-
<ColorAreaContext.Provider
|
|
557
|
-
value={{
|
|
558
|
-
state,
|
|
559
|
-
colorAreaProps,
|
|
560
|
-
gradientProps,
|
|
561
|
-
thumbProps,
|
|
562
|
-
xInputProps,
|
|
563
|
-
yInputProps,
|
|
564
|
-
areaRef,
|
|
565
|
-
setAreaRef,
|
|
566
|
-
}}
|
|
567
|
-
>
|
|
568
|
-
<div
|
|
569
|
-
ref={setAreaRef}
|
|
570
|
-
{...domProps()}
|
|
571
|
-
{...cleanColorAreaProps()}
|
|
572
|
-
class={renderProps.class()}
|
|
573
|
-
style={mergedStyle()}
|
|
574
|
-
data-disabled={state.isDisabled || undefined}
|
|
575
|
-
data-dragging={state.isDragging || undefined}
|
|
576
|
-
>
|
|
577
|
-
{renderProps.renderChildren()}
|
|
578
|
-
|
|
579
|
-
{/* Hidden inputs for accessibility */}
|
|
580
|
-
<input {...xInputProps} />
|
|
581
|
-
<input {...yInputProps} />
|
|
582
|
-
</div>
|
|
583
|
-
</ColorAreaContext.Provider>
|
|
584
|
-
);
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
* The gradient background of a color area.
|
|
589
|
-
*/
|
|
590
|
-
export function ColorAreaGradient(props: ColorAreaGradientProps): JSX.Element {
|
|
591
|
-
const [local] = splitProps(props, ['class', 'style', 'slot']);
|
|
592
|
-
|
|
593
|
-
const context = useContext(ColorAreaContext);
|
|
594
|
-
if (!context) {
|
|
595
|
-
throw new Error('ColorAreaGradient must be used within a ColorArea');
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
const { state, gradientProps } = context;
|
|
599
|
-
|
|
600
|
-
// Render props values
|
|
601
|
-
const renderValues = createMemo<ColorAreaGradientRenderProps>(() => ({
|
|
602
|
-
isDisabled: state.isDisabled,
|
|
603
|
-
}));
|
|
604
|
-
|
|
605
|
-
// Resolve render props
|
|
606
|
-
const renderProps = useRenderProps(
|
|
607
|
-
{
|
|
608
|
-
children: props.children,
|
|
609
|
-
class: local.class,
|
|
610
|
-
style: local.style,
|
|
611
|
-
defaultClassName: 'solidaria-ColorArea-gradient',
|
|
612
|
-
},
|
|
613
|
-
renderValues
|
|
614
|
-
);
|
|
615
|
-
|
|
616
|
-
// Clean props
|
|
617
|
-
const cleanGradientProps = () => {
|
|
618
|
-
const { ref: _ref, style: _gradStyle, ...rest } = gradientProps as Record<string, unknown>;
|
|
619
|
-
return rest;
|
|
620
|
-
};
|
|
621
|
-
|
|
622
|
-
// Merge styles
|
|
623
|
-
const mergedStyle = () => {
|
|
624
|
-
const gradStyle = (gradientProps as { style?: Record<string, string> }).style || {};
|
|
625
|
-
const renderStyle = renderProps.style() || {};
|
|
626
|
-
return { ...gradStyle, ...renderStyle };
|
|
627
|
-
};
|
|
628
|
-
|
|
629
|
-
return (
|
|
630
|
-
<div
|
|
631
|
-
{...cleanGradientProps()}
|
|
632
|
-
class={renderProps.class()}
|
|
633
|
-
style={mergedStyle()}
|
|
634
|
-
data-disabled={state.isDisabled || undefined}
|
|
635
|
-
>
|
|
636
|
-
{renderProps.renderChildren()}
|
|
637
|
-
</div>
|
|
638
|
-
);
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
/**
|
|
642
|
-
* The thumb element of a color area.
|
|
643
|
-
*/
|
|
644
|
-
export function ColorAreaThumb(props: ColorAreaThumbProps): JSX.Element {
|
|
645
|
-
const [local] = splitProps(props, ['class', 'style', 'slot']);
|
|
646
|
-
|
|
647
|
-
const context = useContext(ColorAreaContext);
|
|
648
|
-
if (!context) {
|
|
649
|
-
throw new Error('ColorAreaThumb must be used within a ColorArea');
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
const { state, thumbProps } = context;
|
|
653
|
-
|
|
654
|
-
// Create focus ring
|
|
655
|
-
const { isFocused, isFocusVisible, focusProps } = createFocusRing();
|
|
656
|
-
|
|
657
|
-
// Create hover
|
|
658
|
-
const { isHovered, hoverProps } = createHover({
|
|
659
|
-
get isDisabled() {
|
|
660
|
-
return state.isDisabled;
|
|
661
|
-
},
|
|
662
|
-
});
|
|
663
|
-
|
|
664
|
-
// Render props values
|
|
665
|
-
const renderValues = createMemo<ColorAreaThumbRenderProps>(() => ({
|
|
666
|
-
isDisabled: state.isDisabled,
|
|
667
|
-
isDragging: state.isDragging,
|
|
668
|
-
isFocused: isFocused(),
|
|
669
|
-
isFocusVisible: isFocusVisible(),
|
|
670
|
-
isHovered: isHovered(),
|
|
671
|
-
}));
|
|
672
|
-
|
|
673
|
-
// Resolve render props
|
|
674
|
-
const renderProps = useRenderProps(
|
|
675
|
-
{
|
|
676
|
-
children: props.children,
|
|
677
|
-
class: local.class,
|
|
678
|
-
style: local.style,
|
|
679
|
-
defaultClassName: 'solidaria-ColorArea-thumb',
|
|
680
|
-
},
|
|
681
|
-
renderValues
|
|
682
|
-
);
|
|
683
|
-
|
|
684
|
-
// Clean props
|
|
685
|
-
const cleanThumbProps = () => {
|
|
686
|
-
const { ref: _ref, style: _thumbStyle, ...rest } = thumbProps as Record<string, unknown>;
|
|
687
|
-
return rest;
|
|
688
|
-
};
|
|
689
|
-
const cleanFocusProps = () => {
|
|
690
|
-
const { ref: _ref, ...rest } = focusProps as Record<string, unknown>;
|
|
691
|
-
return rest;
|
|
692
|
-
};
|
|
693
|
-
const cleanHoverProps = () => {
|
|
694
|
-
const { ref: _ref, ...rest } = hoverProps as Record<string, unknown>;
|
|
695
|
-
return rest;
|
|
696
|
-
};
|
|
697
|
-
|
|
698
|
-
// Merge styles
|
|
699
|
-
const mergedStyle = () => {
|
|
700
|
-
const thumbStyle = (thumbProps as { style?: Record<string, string> }).style || {};
|
|
701
|
-
const renderStyle = renderProps.style() || {};
|
|
702
|
-
return { ...thumbStyle, ...renderStyle };
|
|
703
|
-
};
|
|
704
|
-
|
|
705
|
-
return (
|
|
706
|
-
<div
|
|
707
|
-
{...cleanThumbProps()}
|
|
708
|
-
{...cleanFocusProps()}
|
|
709
|
-
{...cleanHoverProps()}
|
|
710
|
-
class={renderProps.class()}
|
|
711
|
-
style={mergedStyle()}
|
|
712
|
-
data-disabled={state.isDisabled || undefined}
|
|
713
|
-
data-dragging={state.isDragging || undefined}
|
|
714
|
-
data-focused={isFocused() || undefined}
|
|
715
|
-
data-focus-visible={isFocusVisible() || undefined}
|
|
716
|
-
data-hovered={isHovered() || undefined}
|
|
717
|
-
>
|
|
718
|
-
{renderProps.renderChildren()}
|
|
719
|
-
</div>
|
|
720
|
-
);
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
// Attach sub-components
|
|
724
|
-
ColorArea.Gradient = ColorAreaGradient;
|
|
725
|
-
ColorArea.Thumb = ColorAreaThumb;
|
|
726
|
-
|
|
727
|
-
// ============================================
|
|
728
|
-
// COLOR WHEEL
|
|
729
|
-
// ============================================
|
|
730
|
-
|
|
731
|
-
export interface ColorWheelRenderProps {
|
|
732
|
-
/** Whether the wheel is disabled. */
|
|
733
|
-
isDisabled: boolean;
|
|
734
|
-
/** Whether the wheel is being dragged. */
|
|
735
|
-
isDragging: boolean;
|
|
736
|
-
/** The current hue value (0-360). */
|
|
737
|
-
hue: number;
|
|
738
|
-
/** The current color. */
|
|
739
|
-
color: Color;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
export interface ColorWheelProps extends AriaColorWheelOptions, SlotProps {
|
|
743
|
-
/** The current color value (controlled). */
|
|
744
|
-
value?: Color | string;
|
|
745
|
-
/** The default color value (uncontrolled). */
|
|
746
|
-
defaultValue?: Color | string;
|
|
747
|
-
/** Handler called when the color changes. */
|
|
748
|
-
onChange?: (color: Color) => void;
|
|
749
|
-
/** Handler called when dragging ends. */
|
|
750
|
-
onChangeEnd?: (color: Color) => void;
|
|
751
|
-
/** The children of the component. */
|
|
752
|
-
children?: RenderChildren<ColorWheelRenderProps>;
|
|
753
|
-
/** The CSS className for the element. */
|
|
754
|
-
class?: ClassNameOrFunction<ColorWheelRenderProps>;
|
|
755
|
-
/** The inline style for the element. */
|
|
756
|
-
style?: StyleOrFunction<ColorWheelRenderProps>;
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
export interface ColorWheelTrackRenderProps {
|
|
760
|
-
/** Whether the wheel is disabled. */
|
|
761
|
-
isDisabled: boolean;
|
|
762
|
-
/** Whether the wheel is being dragged. */
|
|
763
|
-
isDragging: boolean;
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
export interface ColorWheelTrackProps extends SlotProps {
|
|
767
|
-
/** The children of the track. */
|
|
768
|
-
children?: RenderChildren<ColorWheelTrackRenderProps>;
|
|
769
|
-
/** The CSS className for the element. */
|
|
770
|
-
class?: ClassNameOrFunction<ColorWheelTrackRenderProps>;
|
|
771
|
-
/** The inline style for the element. */
|
|
772
|
-
style?: StyleOrFunction<ColorWheelTrackRenderProps>;
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
export interface ColorWheelThumbRenderProps {
|
|
776
|
-
/** Whether the wheel is disabled. */
|
|
777
|
-
isDisabled: boolean;
|
|
778
|
-
/** Whether the thumb is being dragged. */
|
|
779
|
-
isDragging: boolean;
|
|
780
|
-
/** Whether the thumb is focused. */
|
|
781
|
-
isFocused: boolean;
|
|
782
|
-
/** Whether the thumb has keyboard focus. */
|
|
783
|
-
isFocusVisible: boolean;
|
|
784
|
-
/** Whether the thumb is hovered. */
|
|
785
|
-
isHovered: boolean;
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
export interface ColorWheelThumbProps extends SlotProps {
|
|
789
|
-
/** The children of the thumb. */
|
|
790
|
-
children?: RenderChildren<ColorWheelThumbRenderProps>;
|
|
791
|
-
/** The CSS className for the element. */
|
|
792
|
-
class?: ClassNameOrFunction<ColorWheelThumbRenderProps>;
|
|
793
|
-
/** The inline style for the element. */
|
|
794
|
-
style?: StyleOrFunction<ColorWheelThumbRenderProps>;
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
// Context
|
|
798
|
-
interface ColorWheelContextValue {
|
|
799
|
-
state: ColorWheelState;
|
|
800
|
-
trackProps: JSX.HTMLAttributes<HTMLDivElement>;
|
|
801
|
-
thumbProps: JSX.HTMLAttributes<HTMLDivElement>;
|
|
802
|
-
inputProps: JSX.InputHTMLAttributes<HTMLInputElement>;
|
|
803
|
-
wheelRef: HTMLDivElement | undefined;
|
|
804
|
-
setWheelRef: (el: HTMLDivElement) => void;
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
export const ColorWheelContext = createContext<ColorWheelContextValue | null>(null);
|
|
808
|
-
|
|
809
|
-
/**
|
|
810
|
-
* A color wheel allows users to select a hue using a circular control.
|
|
811
|
-
*/
|
|
812
|
-
export function ColorWheel(props: ColorWheelProps): JSX.Element {
|
|
813
|
-
const [local, stateProps, ariaProps, rest] = splitProps(
|
|
814
|
-
props,
|
|
815
|
-
['children', 'class', 'style', 'slot'],
|
|
816
|
-
['value', 'defaultValue', 'onChange', 'onChangeEnd'],
|
|
817
|
-
['aria-label', 'aria-labelledby', 'aria-describedby', 'isDisabled']
|
|
818
|
-
);
|
|
819
|
-
|
|
820
|
-
// Create color wheel state
|
|
821
|
-
const state = createColorWheelState(() => ({
|
|
822
|
-
value: stateProps.value,
|
|
823
|
-
defaultValue: stateProps.defaultValue,
|
|
824
|
-
onChange: stateProps.onChange,
|
|
825
|
-
onChangeEnd: stateProps.onChangeEnd,
|
|
826
|
-
isDisabled: ariaProps.isDisabled,
|
|
827
|
-
}));
|
|
828
|
-
|
|
829
|
-
// Wheel ref
|
|
830
|
-
let wheelRef: HTMLDivElement | undefined;
|
|
831
|
-
const setWheelRef = (el: HTMLDivElement) => {
|
|
832
|
-
wheelRef = el;
|
|
833
|
-
};
|
|
834
|
-
|
|
835
|
-
// Create color wheel aria props
|
|
836
|
-
const {
|
|
837
|
-
trackProps,
|
|
838
|
-
thumbProps,
|
|
839
|
-
inputProps,
|
|
840
|
-
} = createColorWheel(
|
|
841
|
-
() => ({
|
|
842
|
-
'aria-label': ariaProps['aria-label'],
|
|
843
|
-
'aria-labelledby': ariaProps['aria-labelledby'],
|
|
844
|
-
'aria-describedby': ariaProps['aria-describedby'],
|
|
845
|
-
isDisabled: ariaProps.isDisabled,
|
|
846
|
-
}),
|
|
847
|
-
() => state,
|
|
848
|
-
() => wheelRef ?? null
|
|
849
|
-
);
|
|
850
|
-
|
|
851
|
-
// Render props values
|
|
852
|
-
const renderValues = createMemo<ColorWheelRenderProps>(() => ({
|
|
853
|
-
isDisabled: state.isDisabled,
|
|
854
|
-
isDragging: state.isDragging,
|
|
855
|
-
hue: state.getHue(),
|
|
856
|
-
color: state.value,
|
|
857
|
-
}));
|
|
858
|
-
|
|
859
|
-
// Resolve render props
|
|
860
|
-
const renderProps = useRenderProps(
|
|
861
|
-
{
|
|
862
|
-
children: props.children,
|
|
863
|
-
class: local.class,
|
|
864
|
-
style: local.style,
|
|
865
|
-
defaultClassName: 'solidaria-ColorWheel',
|
|
866
|
-
},
|
|
867
|
-
renderValues
|
|
868
|
-
);
|
|
869
|
-
|
|
870
|
-
// Filter DOM props
|
|
871
|
-
const domProps = createMemo(() => filterDOMProps(rest as Record<string, unknown>, { global: true }));
|
|
872
|
-
|
|
873
|
-
return (
|
|
874
|
-
<ColorWheelContext.Provider
|
|
875
|
-
value={{
|
|
876
|
-
state,
|
|
877
|
-
trackProps,
|
|
878
|
-
thumbProps,
|
|
879
|
-
inputProps,
|
|
880
|
-
wheelRef,
|
|
881
|
-
setWheelRef,
|
|
882
|
-
}}
|
|
883
|
-
>
|
|
884
|
-
<div
|
|
885
|
-
{...domProps()}
|
|
886
|
-
class={renderProps.class()}
|
|
887
|
-
style={renderProps.style()}
|
|
888
|
-
data-disabled={state.isDisabled || undefined}
|
|
889
|
-
data-dragging={state.isDragging || undefined}
|
|
890
|
-
>
|
|
891
|
-
{renderProps.renderChildren()}
|
|
892
|
-
|
|
893
|
-
{/* Hidden input for accessibility */}
|
|
894
|
-
<input {...inputProps} />
|
|
895
|
-
</div>
|
|
896
|
-
</ColorWheelContext.Provider>
|
|
897
|
-
);
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
/**
|
|
901
|
-
* The track element of a color wheel.
|
|
902
|
-
*/
|
|
903
|
-
export function ColorWheelTrack(props: ColorWheelTrackProps): JSX.Element {
|
|
904
|
-
const [local] = splitProps(props, ['class', 'style', 'slot']);
|
|
905
|
-
|
|
906
|
-
const context = useContext(ColorWheelContext);
|
|
907
|
-
if (!context) {
|
|
908
|
-
throw new Error('ColorWheelTrack must be used within a ColorWheel');
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
const { state, trackProps, setWheelRef } = context;
|
|
912
|
-
|
|
913
|
-
// Render props values
|
|
914
|
-
const renderValues = createMemo<ColorWheelTrackRenderProps>(() => ({
|
|
915
|
-
isDisabled: state.isDisabled,
|
|
916
|
-
isDragging: state.isDragging,
|
|
917
|
-
}));
|
|
918
|
-
|
|
919
|
-
// Resolve render props
|
|
920
|
-
const renderProps = useRenderProps(
|
|
921
|
-
{
|
|
922
|
-
children: props.children,
|
|
923
|
-
class: local.class,
|
|
924
|
-
style: local.style,
|
|
925
|
-
defaultClassName: 'solidaria-ColorWheel-track',
|
|
926
|
-
},
|
|
927
|
-
renderValues
|
|
928
|
-
);
|
|
929
|
-
|
|
930
|
-
// Clean props
|
|
931
|
-
const cleanTrackProps = () => {
|
|
932
|
-
const { ref: _ref, style: _trackStyle, ...rest } = trackProps as Record<string, unknown>;
|
|
933
|
-
return rest;
|
|
934
|
-
};
|
|
935
|
-
|
|
936
|
-
// Merge styles
|
|
937
|
-
const mergedStyle = () => {
|
|
938
|
-
const trackStyle = (trackProps as { style?: Record<string, string> }).style || {};
|
|
939
|
-
const renderStyle = renderProps.style() || {};
|
|
940
|
-
return { ...trackStyle, ...renderStyle };
|
|
941
|
-
};
|
|
942
|
-
|
|
943
|
-
return (
|
|
944
|
-
<div
|
|
945
|
-
ref={setWheelRef}
|
|
946
|
-
{...cleanTrackProps()}
|
|
947
|
-
class={renderProps.class()}
|
|
948
|
-
style={mergedStyle()}
|
|
949
|
-
data-disabled={state.isDisabled || undefined}
|
|
950
|
-
data-dragging={state.isDragging || undefined}
|
|
951
|
-
>
|
|
952
|
-
{renderProps.renderChildren()}
|
|
953
|
-
</div>
|
|
954
|
-
);
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
/**
|
|
958
|
-
* The thumb element of a color wheel.
|
|
959
|
-
*/
|
|
960
|
-
export function ColorWheelThumb(props: ColorWheelThumbProps): JSX.Element {
|
|
961
|
-
const [local] = splitProps(props, ['class', 'style', 'slot']);
|
|
962
|
-
|
|
963
|
-
const context = useContext(ColorWheelContext);
|
|
964
|
-
if (!context) {
|
|
965
|
-
throw new Error('ColorWheelThumb must be used within a ColorWheel');
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
const { state, thumbProps } = context;
|
|
969
|
-
|
|
970
|
-
// Create focus ring
|
|
971
|
-
const { isFocused, isFocusVisible, focusProps } = createFocusRing();
|
|
972
|
-
|
|
973
|
-
// Create hover
|
|
974
|
-
const { isHovered, hoverProps } = createHover({
|
|
975
|
-
get isDisabled() {
|
|
976
|
-
return state.isDisabled;
|
|
977
|
-
},
|
|
978
|
-
});
|
|
979
|
-
|
|
980
|
-
// Render props values
|
|
981
|
-
const renderValues = createMemo<ColorWheelThumbRenderProps>(() => ({
|
|
982
|
-
isDisabled: state.isDisabled,
|
|
983
|
-
isDragging: state.isDragging,
|
|
984
|
-
isFocused: isFocused(),
|
|
985
|
-
isFocusVisible: isFocusVisible(),
|
|
986
|
-
isHovered: isHovered(),
|
|
987
|
-
}));
|
|
988
|
-
|
|
989
|
-
// Resolve render props
|
|
990
|
-
const renderProps = useRenderProps(
|
|
991
|
-
{
|
|
992
|
-
children: props.children,
|
|
993
|
-
class: local.class,
|
|
994
|
-
style: local.style,
|
|
995
|
-
defaultClassName: 'solidaria-ColorWheel-thumb',
|
|
996
|
-
},
|
|
997
|
-
renderValues
|
|
998
|
-
);
|
|
999
|
-
|
|
1000
|
-
// Clean props
|
|
1001
|
-
const cleanThumbProps = () => {
|
|
1002
|
-
const { ref: _ref, style: _thumbStyle, ...rest } = thumbProps as Record<string, unknown>;
|
|
1003
|
-
return rest;
|
|
1004
|
-
};
|
|
1005
|
-
const cleanFocusProps = () => {
|
|
1006
|
-
const { ref: _ref, ...rest } = focusProps as Record<string, unknown>;
|
|
1007
|
-
return rest;
|
|
1008
|
-
};
|
|
1009
|
-
const cleanHoverProps = () => {
|
|
1010
|
-
const { ref: _ref, ...rest } = hoverProps as Record<string, unknown>;
|
|
1011
|
-
return rest;
|
|
1012
|
-
};
|
|
1013
|
-
|
|
1014
|
-
// Merge styles
|
|
1015
|
-
const mergedStyle = () => {
|
|
1016
|
-
const thumbStyle = (thumbProps as { style?: Record<string, string> }).style || {};
|
|
1017
|
-
const renderStyle = renderProps.style() || {};
|
|
1018
|
-
return { ...thumbStyle, ...renderStyle };
|
|
1019
|
-
};
|
|
1020
|
-
|
|
1021
|
-
return (
|
|
1022
|
-
<div
|
|
1023
|
-
{...cleanThumbProps()}
|
|
1024
|
-
{...cleanFocusProps()}
|
|
1025
|
-
{...cleanHoverProps()}
|
|
1026
|
-
class={renderProps.class()}
|
|
1027
|
-
style={mergedStyle()}
|
|
1028
|
-
data-disabled={state.isDisabled || undefined}
|
|
1029
|
-
data-dragging={state.isDragging || undefined}
|
|
1030
|
-
data-focused={isFocused() || undefined}
|
|
1031
|
-
data-focus-visible={isFocusVisible() || undefined}
|
|
1032
|
-
data-hovered={isHovered() || undefined}
|
|
1033
|
-
>
|
|
1034
|
-
{renderProps.renderChildren()}
|
|
1035
|
-
</div>
|
|
1036
|
-
);
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
// Attach sub-components
|
|
1040
|
-
ColorWheel.Track = ColorWheelTrack;
|
|
1041
|
-
ColorWheel.Thumb = ColorWheelThumb;
|
|
1042
|
-
|
|
1043
|
-
// ============================================
|
|
1044
|
-
// COLOR FIELD
|
|
1045
|
-
// ============================================
|
|
1046
|
-
|
|
1047
|
-
export interface ColorFieldRenderProps {
|
|
1048
|
-
/** Whether the field is disabled. */
|
|
1049
|
-
isDisabled: boolean;
|
|
1050
|
-
/** Whether the field is read-only. */
|
|
1051
|
-
isReadOnly: boolean;
|
|
1052
|
-
/** Whether the input value is invalid. */
|
|
1053
|
-
isInvalid: boolean;
|
|
1054
|
-
/** The current color value (null if invalid). */
|
|
1055
|
-
color: Color | null;
|
|
1056
|
-
/** The color channel being edited (if single channel mode). */
|
|
1057
|
-
channel: ColorChannel | undefined;
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
export interface ColorFieldProps extends AriaColorFieldOptions, SlotProps {
|
|
1061
|
-
/** The current color value (controlled). */
|
|
1062
|
-
value?: Color | string | null;
|
|
1063
|
-
/** The default color value (uncontrolled). */
|
|
1064
|
-
defaultValue?: Color | string;
|
|
1065
|
-
/** Handler called when the color changes. */
|
|
1066
|
-
onChange?: (color: Color | null) => void;
|
|
1067
|
-
/** The color channel to edit (for single channel mode). */
|
|
1068
|
-
channel?: ColorChannel;
|
|
1069
|
-
/** The color format for parsing/displaying. */
|
|
1070
|
-
colorFormat?: ColorFormat;
|
|
1071
|
-
/** A visible label for the field. */
|
|
1072
|
-
label?: JSX.Element;
|
|
1073
|
-
/** The children of the component. */
|
|
1074
|
-
children?: RenderChildren<ColorFieldRenderProps>;
|
|
1075
|
-
/** The CSS className for the element. */
|
|
1076
|
-
class?: ClassNameOrFunction<ColorFieldRenderProps>;
|
|
1077
|
-
/** The inline style for the element. */
|
|
1078
|
-
style?: StyleOrFunction<ColorFieldRenderProps>;
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
export interface ColorFieldInputRenderProps {
|
|
1082
|
-
/** Whether the field is disabled. */
|
|
1083
|
-
isDisabled: boolean;
|
|
1084
|
-
/** Whether the field is read-only. */
|
|
1085
|
-
isReadOnly: boolean;
|
|
1086
|
-
/** Whether the input value is invalid. */
|
|
1087
|
-
isInvalid: boolean;
|
|
1088
|
-
/** Whether the input is focused. */
|
|
1089
|
-
isFocused: boolean;
|
|
1090
|
-
/** Whether the input has keyboard focus. */
|
|
1091
|
-
isFocusVisible: boolean;
|
|
1092
|
-
/** Whether the input is hovered. */
|
|
1093
|
-
isHovered: boolean;
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
export interface ColorFieldInputProps extends SlotProps {
|
|
1097
|
-
/** The children of the input (usually not used). */
|
|
1098
|
-
children?: RenderChildren<ColorFieldInputRenderProps>;
|
|
1099
|
-
/** The CSS className for the element. */
|
|
1100
|
-
class?: ClassNameOrFunction<ColorFieldInputRenderProps>;
|
|
1101
|
-
/** The inline style for the element. */
|
|
1102
|
-
style?: StyleOrFunction<ColorFieldInputRenderProps>;
|
|
1103
|
-
}
|
|
1104
|
-
|
|
1105
|
-
// Context
|
|
1106
|
-
interface ColorFieldContextValue {
|
|
1107
|
-
state: ColorFieldState;
|
|
1108
|
-
inputProps: JSX.InputHTMLAttributes<HTMLInputElement>;
|
|
1109
|
-
labelProps: JSX.LabelHTMLAttributes<HTMLLabelElement>;
|
|
1110
|
-
}
|
|
1111
|
-
|
|
1112
|
-
export const ColorFieldContext = createContext<ColorFieldContextValue | null>(null);
|
|
1113
|
-
|
|
1114
|
-
/**
|
|
1115
|
-
* A color field allows users to enter a color value as text.
|
|
1116
|
-
*/
|
|
1117
|
-
export function ColorField(props: ColorFieldProps): JSX.Element {
|
|
1118
|
-
const [local, stateProps, ariaProps, rest] = splitProps(
|
|
1119
|
-
props,
|
|
1120
|
-
['children', 'class', 'style', 'slot', 'label'],
|
|
1121
|
-
['value', 'defaultValue', 'onChange', 'channel', 'colorFormat'],
|
|
1122
|
-
['aria-label', 'aria-labelledby', 'aria-describedby', 'isDisabled', 'isReadOnly']
|
|
1123
|
-
);
|
|
1124
|
-
|
|
1125
|
-
// Create color field state
|
|
1126
|
-
const state = createColorFieldState(() => ({
|
|
1127
|
-
value: stateProps.value,
|
|
1128
|
-
defaultValue: stateProps.defaultValue,
|
|
1129
|
-
onChange: stateProps.onChange,
|
|
1130
|
-
channel: stateProps.channel,
|
|
1131
|
-
colorFormat: stateProps.colorFormat,
|
|
1132
|
-
isDisabled: ariaProps.isDisabled,
|
|
1133
|
-
isReadOnly: ariaProps.isReadOnly,
|
|
1134
|
-
}));
|
|
1135
|
-
|
|
1136
|
-
// Input ref
|
|
1137
|
-
let inputRef: HTMLInputElement | undefined;
|
|
1138
|
-
|
|
1139
|
-
// Create color field aria props
|
|
1140
|
-
const {
|
|
1141
|
-
inputProps,
|
|
1142
|
-
labelProps,
|
|
1143
|
-
} = createColorField(
|
|
1144
|
-
() => ({
|
|
1145
|
-
'aria-label': ariaProps['aria-label'],
|
|
1146
|
-
'aria-labelledby': ariaProps['aria-labelledby'],
|
|
1147
|
-
'aria-describedby': ariaProps['aria-describedby'],
|
|
1148
|
-
isDisabled: ariaProps.isDisabled,
|
|
1149
|
-
isReadOnly: ariaProps.isReadOnly,
|
|
1150
|
-
channel: stateProps.channel,
|
|
1151
|
-
}),
|
|
1152
|
-
() => state,
|
|
1153
|
-
() => inputRef ?? null
|
|
1154
|
-
);
|
|
1155
|
-
|
|
1156
|
-
// Render props values
|
|
1157
|
-
const renderValues = createMemo<ColorFieldRenderProps>(() => ({
|
|
1158
|
-
isDisabled: state.isDisabled,
|
|
1159
|
-
isReadOnly: state.isReadOnly,
|
|
1160
|
-
isInvalid: state.isInvalid,
|
|
1161
|
-
color: state.value,
|
|
1162
|
-
channel: state.channel,
|
|
1163
|
-
}));
|
|
1164
|
-
|
|
1165
|
-
// Resolve render props
|
|
1166
|
-
const renderProps = useRenderProps(
|
|
1167
|
-
{
|
|
1168
|
-
children: props.children,
|
|
1169
|
-
class: local.class,
|
|
1170
|
-
style: local.style,
|
|
1171
|
-
defaultClassName: 'solidaria-ColorField',
|
|
1172
|
-
},
|
|
1173
|
-
renderValues
|
|
1174
|
-
);
|
|
1175
|
-
|
|
1176
|
-
// Filter DOM props
|
|
1177
|
-
const domProps = createMemo(() => filterDOMProps(rest as Record<string, unknown>, { global: true }));
|
|
1178
|
-
|
|
1179
|
-
return (
|
|
1180
|
-
<ColorFieldContext.Provider
|
|
1181
|
-
value={{
|
|
1182
|
-
state,
|
|
1183
|
-
inputProps,
|
|
1184
|
-
labelProps,
|
|
1185
|
-
}}
|
|
1186
|
-
>
|
|
1187
|
-
<div
|
|
1188
|
-
{...domProps()}
|
|
1189
|
-
class={renderProps.class()}
|
|
1190
|
-
style={renderProps.style()}
|
|
1191
|
-
data-disabled={state.isDisabled || undefined}
|
|
1192
|
-
data-readonly={state.isReadOnly || undefined}
|
|
1193
|
-
data-invalid={state.isInvalid || undefined}
|
|
1194
|
-
>
|
|
1195
|
-
{/* Label */}
|
|
1196
|
-
<Show when={local.label}>
|
|
1197
|
-
<label {...labelProps}>{local.label}</label>
|
|
1198
|
-
</Show>
|
|
1199
|
-
|
|
1200
|
-
{renderProps.renderChildren()}
|
|
1201
|
-
</div>
|
|
1202
|
-
</ColorFieldContext.Provider>
|
|
1203
|
-
);
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
/**
|
|
1207
|
-
* The input element of a color field.
|
|
1208
|
-
*/
|
|
1209
|
-
export function ColorFieldInput(props: ColorFieldInputProps): JSX.Element {
|
|
1210
|
-
const [local] = splitProps(props, ['class', 'style', 'slot']);
|
|
1211
|
-
|
|
1212
|
-
const context = useContext(ColorFieldContext);
|
|
1213
|
-
if (!context) {
|
|
1214
|
-
throw new Error('ColorFieldInput must be used within a ColorField');
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
const { state, inputProps } = context;
|
|
1218
|
-
|
|
1219
|
-
// Create focus ring
|
|
1220
|
-
const { isFocused, isFocusVisible, focusProps } = createFocusRing();
|
|
1221
|
-
|
|
1222
|
-
// Create hover
|
|
1223
|
-
const { isHovered, hoverProps } = createHover({
|
|
1224
|
-
get isDisabled() {
|
|
1225
|
-
return state.isDisabled;
|
|
1226
|
-
},
|
|
1227
|
-
});
|
|
1228
|
-
|
|
1229
|
-
// Render props values
|
|
1230
|
-
const renderValues = createMemo<ColorFieldInputRenderProps>(() => ({
|
|
1231
|
-
isDisabled: state.isDisabled,
|
|
1232
|
-
isReadOnly: state.isReadOnly,
|
|
1233
|
-
isInvalid: state.isInvalid,
|
|
1234
|
-
isFocused: isFocused(),
|
|
1235
|
-
isFocusVisible: isFocusVisible(),
|
|
1236
|
-
isHovered: isHovered(),
|
|
1237
|
-
}));
|
|
1238
|
-
|
|
1239
|
-
// Resolve render props
|
|
1240
|
-
const renderProps = useRenderProps(
|
|
1241
|
-
{
|
|
1242
|
-
children: props.children,
|
|
1243
|
-
class: local.class,
|
|
1244
|
-
style: local.style,
|
|
1245
|
-
defaultClassName: 'solidaria-ColorField-input',
|
|
1246
|
-
},
|
|
1247
|
-
renderValues
|
|
1248
|
-
);
|
|
1249
|
-
|
|
1250
|
-
// Clean props
|
|
1251
|
-
const cleanInputProps = () => {
|
|
1252
|
-
const { ref: _ref, style: _inputStyle, ...rest } = inputProps as Record<string, unknown>;
|
|
1253
|
-
return rest;
|
|
1254
|
-
};
|
|
1255
|
-
const cleanFocusProps = () => {
|
|
1256
|
-
const { ref: _ref, ...rest } = focusProps as Record<string, unknown>;
|
|
1257
|
-
return rest;
|
|
1258
|
-
};
|
|
1259
|
-
const cleanHoverProps = () => {
|
|
1260
|
-
const { ref: _ref, ...rest } = hoverProps as Record<string, unknown>;
|
|
1261
|
-
return rest;
|
|
1262
|
-
};
|
|
1263
|
-
|
|
1264
|
-
return (
|
|
1265
|
-
<input
|
|
1266
|
-
{...cleanInputProps()}
|
|
1267
|
-
{...cleanFocusProps()}
|
|
1268
|
-
{...cleanHoverProps()}
|
|
1269
|
-
class={renderProps.class()}
|
|
1270
|
-
style={renderProps.style()}
|
|
1271
|
-
data-disabled={state.isDisabled || undefined}
|
|
1272
|
-
data-readonly={state.isReadOnly || undefined}
|
|
1273
|
-
data-invalid={state.isInvalid || undefined}
|
|
1274
|
-
data-focused={isFocused() || undefined}
|
|
1275
|
-
data-focus-visible={isFocusVisible() || undefined}
|
|
1276
|
-
data-hovered={isHovered() || undefined}
|
|
1277
|
-
/>
|
|
1278
|
-
);
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
|
-
// Attach sub-components
|
|
1282
|
-
ColorField.Input = ColorFieldInput;
|
|
1283
|
-
|
|
1284
|
-
// ============================================
|
|
1285
|
-
// COLOR SWATCH
|
|
1286
|
-
// ============================================
|
|
1287
|
-
|
|
1288
|
-
export interface ColorSwatchRenderProps {
|
|
1289
|
-
/** The color being displayed. */
|
|
1290
|
-
color: Color;
|
|
1291
|
-
/** The color as a CSS string. */
|
|
1292
|
-
colorValue: string;
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
export interface ColorSwatchProps extends SlotProps {
|
|
1296
|
-
/** The color to display. */
|
|
1297
|
-
color: Color | string;
|
|
1298
|
-
/** Accessible label for the swatch. */
|
|
1299
|
-
'aria-label'?: string;
|
|
1300
|
-
/** The children of the component. */
|
|
1301
|
-
children?: RenderChildren<ColorSwatchRenderProps>;
|
|
1302
|
-
/** The CSS className for the element. */
|
|
1303
|
-
class?: ClassNameOrFunction<ColorSwatchRenderProps>;
|
|
1304
|
-
/** The inline style for the element. */
|
|
1305
|
-
style?: StyleOrFunction<ColorSwatchRenderProps>;
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
/**
|
|
1309
|
-
* A color swatch displays a preview of a color.
|
|
1310
|
-
*/
|
|
1311
|
-
export function ColorSwatch(props: ColorSwatchProps): JSX.Element {
|
|
1312
|
-
const [local, ariaProps, rest] = splitProps(
|
|
1313
|
-
props,
|
|
1314
|
-
['children', 'class', 'style', 'slot', 'color'],
|
|
1315
|
-
['aria-label']
|
|
1316
|
-
);
|
|
1317
|
-
|
|
1318
|
-
// Create color swatch aria props
|
|
1319
|
-
const { swatchProps } = createColorSwatch(() => ({
|
|
1320
|
-
color: local.color,
|
|
1321
|
-
'aria-label': ariaProps['aria-label'],
|
|
1322
|
-
}));
|
|
1323
|
-
|
|
1324
|
-
// Normalize color
|
|
1325
|
-
const color = createMemo(() => normalizeColor(local.color));
|
|
1326
|
-
|
|
1327
|
-
// Render props values
|
|
1328
|
-
const renderValues = createMemo<ColorSwatchRenderProps>(() => ({
|
|
1329
|
-
color: color(),
|
|
1330
|
-
colorValue: color().toString('css'),
|
|
1331
|
-
}));
|
|
1332
|
-
|
|
1333
|
-
// Resolve render props
|
|
1334
|
-
const renderProps = useRenderProps(
|
|
1335
|
-
{
|
|
1336
|
-
children: props.children,
|
|
1337
|
-
class: local.class,
|
|
1338
|
-
style: local.style,
|
|
1339
|
-
defaultClassName: 'solidaria-ColorSwatch',
|
|
1340
|
-
},
|
|
1341
|
-
renderValues
|
|
1342
|
-
);
|
|
1343
|
-
|
|
1344
|
-
// Filter DOM props
|
|
1345
|
-
const domProps = createMemo(() => filterDOMProps(rest as Record<string, unknown>, { global: true }));
|
|
1346
|
-
|
|
1347
|
-
// Clean props
|
|
1348
|
-
const cleanSwatchProps = () => {
|
|
1349
|
-
const { ref: _ref, style: _swatchStyle, ...rest } = swatchProps as Record<string, unknown>;
|
|
1350
|
-
return rest;
|
|
1351
|
-
};
|
|
1352
|
-
|
|
1353
|
-
// Merge styles
|
|
1354
|
-
const mergedStyle = () => {
|
|
1355
|
-
const swatchStyle = (swatchProps as { style?: Record<string, string> }).style || {};
|
|
1356
|
-
const renderStyle = renderProps.style() || {};
|
|
1357
|
-
return { ...swatchStyle, ...renderStyle };
|
|
1358
|
-
};
|
|
1359
|
-
|
|
1360
|
-
return (
|
|
1361
|
-
<div
|
|
1362
|
-
{...domProps()}
|
|
1363
|
-
{...cleanSwatchProps()}
|
|
1364
|
-
class={renderProps.class()}
|
|
1365
|
-
style={mergedStyle()}
|
|
1366
|
-
>
|
|
1367
|
-
{renderProps.renderChildren()}
|
|
1368
|
-
</div>
|
|
1369
|
-
);
|
|
1370
|
-
}
|