draft-components 2.8.0 → 2.9.0
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/css/draft-components.css +233 -0
- package/dist/components/index.d.ts +3 -2
- package/dist/components/index.js +3 -2
- package/dist/components/slider-range/index.d.ts +2 -0
- package/dist/components/slider-range/index.js +1 -0
- package/dist/components/slider-range/slider-range-data-list.d.ts +10 -0
- package/dist/components/slider-range/slider-range-data-list.js +12 -0
- package/dist/components/slider-range/slider-range-label.d.ts +9 -0
- package/dist/components/slider-range/slider-range-label.js +5 -0
- package/dist/components/slider-range/slider-range.d.ts +20 -0
- package/dist/components/slider-range/slider-range.js +147 -0
- package/dist/hooks/use-callback-ref.d.ts +1 -1
- package/dist/lib/helpers.d.ts +2 -0
- package/dist/lib/helpers.js +6 -0
- package/dist/lib/react-helpers.d.ts +1 -0
- package/dist/lib/react-helpers.js +3 -0
- package/package.json +30 -32
package/css/draft-components.css
CHANGED
|
@@ -2123,6 +2123,239 @@
|
|
|
2123
2123
|
padding-top: 4px;
|
|
2124
2124
|
}
|
|
2125
2125
|
|
|
2126
|
+
.dc-slider-range {
|
|
2127
|
+
--dc-slider-range-active-track-left: 0%;
|
|
2128
|
+
--dc-slider-range-active-track-right: 0%;
|
|
2129
|
+
--dc-slider-range-labels-margin-bottom: 12px;
|
|
2130
|
+
--dc-slider-range-tick-marks-margin-top: 2px;
|
|
2131
|
+
|
|
2132
|
+
/* Label properties */
|
|
2133
|
+
--dc-slider-range-label-height: 24px;
|
|
2134
|
+
--dc-slider-range-label-padding-x: 8px;
|
|
2135
|
+
--dc-slider-range-label-radius: 6px;
|
|
2136
|
+
--dc-slider-range-label-text-color: var(--dc-white);
|
|
2137
|
+
--dc-slider-range-label-bg: var(--dc-gray-800);
|
|
2138
|
+
|
|
2139
|
+
/* Track properties */
|
|
2140
|
+
--dc-slider-range-track-width: 100%;
|
|
2141
|
+
--dc-slider-range-track-height: 4px;
|
|
2142
|
+
--dc-slider-range-track-radius: 0;
|
|
2143
|
+
--dc-slider-range-track-border-color: transparent;
|
|
2144
|
+
--dc-slider-range-track-bg: var(--dc-control-bg-inset);
|
|
2145
|
+
--dc-slider-range-active-track-bg: var(--dc-control-primary-color);
|
|
2146
|
+
|
|
2147
|
+
/* Thumb properties */
|
|
2148
|
+
--dc-slider-range-thumb-width: 20px;
|
|
2149
|
+
--dc-slider-range-thumb-height: 20px;
|
|
2150
|
+
--dc-slider-range-thumb-border: 4px solid var(--dc-control-primary-color);
|
|
2151
|
+
--dc-slider-range-thumb-radius: 50%;
|
|
2152
|
+
--dc-slider-range-thumb-bg: var(--dc-control-bg);
|
|
2153
|
+
--dc-slider-range-thumb-shadow: 0 0 0 transparent;
|
|
2154
|
+
--dc-slider-focus-ring:
|
|
2155
|
+
var(--dc-slider-range-thumb-shadow),
|
|
2156
|
+
0 0 0 1px white,
|
|
2157
|
+
0 0 0 4px var(--dc-focus-ring-color);
|
|
2158
|
+
|
|
2159
|
+
/* Tick mark properties */
|
|
2160
|
+
--dc-slider-range-tick-mark-font: var(--dc-text-xs);
|
|
2161
|
+
--dc-slider-range-tick-mark-gap: 4px;
|
|
2162
|
+
--dc-slider-range-tick-mark-width: 2px;
|
|
2163
|
+
--dc-slider-range-tick-mark-height: 8px;
|
|
2164
|
+
--dc-slider-range-tick-mark-color: var(--dc-control-border-color);
|
|
2165
|
+
--dc-slider-range-tick-mark-label-color: var(--dc-control-secondary-text-color);
|
|
2166
|
+
|
|
2167
|
+
color-scheme: light;
|
|
2168
|
+
font-family: var(--dc-primary-font);
|
|
2169
|
+
position: relative;
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
.dc-slider-range__labels-container {
|
|
2173
|
+
position: relative;
|
|
2174
|
+
width: 100%;
|
|
2175
|
+
height: var(--dc-slider-range-thumb-height);
|
|
2176
|
+
margin-bottom: var(--dc-slider-range-labels-margin-bottom);
|
|
2177
|
+
border: none;
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
.dc-slider-range__label {
|
|
2181
|
+
font: var(--dc-text-xs);
|
|
2182
|
+
color: var(--dc-slider-range-label-text-color);
|
|
2183
|
+
position: absolute;
|
|
2184
|
+
top: 0;
|
|
2185
|
+
left: 0;
|
|
2186
|
+
display: inline-flex;
|
|
2187
|
+
align-items: center;
|
|
2188
|
+
box-sizing: border-box;
|
|
2189
|
+
height: var(--dc-slider-range-label-height);
|
|
2190
|
+
max-width: 100%;
|
|
2191
|
+
padding: 0 var(--dc-slider-range-label-padding-x);
|
|
2192
|
+
text-align: center;
|
|
2193
|
+
border-radius: var(--dc-slider-range-label-radius);
|
|
2194
|
+
background: var(--dc-slider-range-label-bg);
|
|
2195
|
+
font-variant-numeric: tabular-nums;
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
.dc-slider-range__label[hidden] {
|
|
2199
|
+
opacity: 0;
|
|
2200
|
+
pointer-events: none;
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
.dc-slider-range__label-text {
|
|
2204
|
+
overflow: hidden;
|
|
2205
|
+
white-space: nowrap;
|
|
2206
|
+
text-overflow: ellipsis;
|
|
2207
|
+
}
|
|
2208
|
+
|
|
2209
|
+
.dc-slider-range__track {
|
|
2210
|
+
position: relative;
|
|
2211
|
+
display: block;
|
|
2212
|
+
width: var(--dc-slider-range-track-width);
|
|
2213
|
+
height: max(var(--dc-slider-range-track-height), var(--dc-slider-range-thumb-height));
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2216
|
+
.dc-slider-range__track::before,
|
|
2217
|
+
.dc-slider-range__track::after {
|
|
2218
|
+
content: "";
|
|
2219
|
+
position: absolute;
|
|
2220
|
+
z-index: -1;
|
|
2221
|
+
top: 50%;
|
|
2222
|
+
display: block;
|
|
2223
|
+
box-sizing: border-box;
|
|
2224
|
+
height: var(--dc-slider-range-track-height);
|
|
2225
|
+
transform: translateY(-50%);
|
|
2226
|
+
border-radius: var(--dc-slider-range-track-radius);
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2229
|
+
.dc-slider-range__track::before {
|
|
2230
|
+
width: 100%;
|
|
2231
|
+
background: var(--dc-slider-range-track-bg);
|
|
2232
|
+
box-shadow: inset 0 0 0 1px var(--dc-slider-range-track-border-color);
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
.dc-slider-range__track::after {
|
|
2236
|
+
right: var(--dc-slider-range-active-track-right);
|
|
2237
|
+
left: var(--dc-slider-range-active-track-left);
|
|
2238
|
+
background: var(--dc-slider-range-active-track-bg);
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
.dc-slider-range_disabled .dc-slider-range__track {
|
|
2242
|
+
opacity: var(--dc-disabled-state-opacity);
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
.dc-slider-range__input {
|
|
2246
|
+
-webkit-appearance: none;
|
|
2247
|
+
-moz-appearance: none;
|
|
2248
|
+
appearance: none;
|
|
2249
|
+
position: absolute;
|
|
2250
|
+
top: 0;
|
|
2251
|
+
left: 0;
|
|
2252
|
+
cursor: default;
|
|
2253
|
+
width: 100%;
|
|
2254
|
+
height: 100%;
|
|
2255
|
+
margin: 0;
|
|
2256
|
+
padding: 0;
|
|
2257
|
+
pointer-events: none;
|
|
2258
|
+
background: none;
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
.dc-slider-range__input_active {
|
|
2262
|
+
z-index: 1;
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
.dc-slider-range__input:focus {
|
|
2266
|
+
outline: none;
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
.dc-slider-range__input::-webkit-slider-runnable-track {
|
|
2270
|
+
-webkit-appearance: none;
|
|
2271
|
+
appearance: none;
|
|
2272
|
+
width: 100%;
|
|
2273
|
+
height: 100%;
|
|
2274
|
+
background: none;
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
.dc-slider-range__input::-moz-range-track {
|
|
2278
|
+
-moz-appearance: none;
|
|
2279
|
+
appearance: none;
|
|
2280
|
+
width: 100%;
|
|
2281
|
+
height: 100%;
|
|
2282
|
+
background: none;
|
|
2283
|
+
}
|
|
2284
|
+
|
|
2285
|
+
.dc-slider-range__input::-webkit-slider-thumb {
|
|
2286
|
+
-webkit-appearance: none;
|
|
2287
|
+
appearance: none;
|
|
2288
|
+
display: inline-block;
|
|
2289
|
+
box-sizing: border-box;
|
|
2290
|
+
width: var(--dc-slider-range-thumb-width);
|
|
2291
|
+
height: var(--dc-slider-range-thumb-height);
|
|
2292
|
+
margin: 0;
|
|
2293
|
+
padding: 0;
|
|
2294
|
+
pointer-events: all;
|
|
2295
|
+
border: var(--dc-slider-range-thumb-border);
|
|
2296
|
+
border-radius: var(--dc-slider-range-thumb-radius);
|
|
2297
|
+
background: var(--dc-slider-range-thumb-bg);
|
|
2298
|
+
box-shadow: var(--dc-slider-range-thumb-shadow);
|
|
2299
|
+
}
|
|
2300
|
+
|
|
2301
|
+
.dc-slider-range__input:focus::-webkit-slider-thumb {
|
|
2302
|
+
box-shadow: var(--dc-slider-focus-ring);
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
.dc-slider-range input::-moz-range-thumb {
|
|
2306
|
+
-moz-appearance: none;
|
|
2307
|
+
appearance: none;
|
|
2308
|
+
display: inline-block;
|
|
2309
|
+
box-sizing: border-box;
|
|
2310
|
+
width: var(--dc-slider-range-thumb-width);
|
|
2311
|
+
height: var(--dc-slider-range-thumb-height);
|
|
2312
|
+
margin: 0;
|
|
2313
|
+
padding: 0;
|
|
2314
|
+
pointer-events: all;
|
|
2315
|
+
border: var(--dc-slider-range-thumb-border);
|
|
2316
|
+
border-radius: var(--dc-slider-range-thumb-radius);
|
|
2317
|
+
background: var(--dc-slider-range-thumb-bg);
|
|
2318
|
+
box-shadow: var(--dc-slider-range-thumb-shadow);
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
.dc-slider-range__input:focus::-moz-range-thumb {
|
|
2322
|
+
box-shadow: var(--dc-slider-focus-ring);
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
.dc-slider-range__tick-marks {
|
|
2326
|
+
display: flex;
|
|
2327
|
+
justify-content: space-between;
|
|
2328
|
+
width: 100%;
|
|
2329
|
+
margin: var(--dc-slider-range-tick-marks-margin-top) 0 0;
|
|
2330
|
+
padding: 0;
|
|
2331
|
+
list-style: none;
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
.dc-slider-range__tick-marks > li {
|
|
2335
|
+
font: var(--dc-slider-range-tick-mark-font);
|
|
2336
|
+
color: var(--dc-slider-range-tick-mark-label-color);
|
|
2337
|
+
display: inline-flex;
|
|
2338
|
+
cursor: default;
|
|
2339
|
+
-webkit-user-select: none;
|
|
2340
|
+
-moz-user-select: none;
|
|
2341
|
+
user-select: none;
|
|
2342
|
+
flex-direction: column;
|
|
2343
|
+
gap: var(--dc-slider-range-tick-mark-gap);
|
|
2344
|
+
align-items: center;
|
|
2345
|
+
width: var(--dc-slider-range-thumb-width);
|
|
2346
|
+
min-width: var(--dc-slider-range-thumb-width);
|
|
2347
|
+
white-space: nowrap;
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
.dc-slider-range__tick-marks > li::before {
|
|
2351
|
+
content: "";
|
|
2352
|
+
display: inline-flex;
|
|
2353
|
+
flex-shrink: 0;
|
|
2354
|
+
width: var(--dc-slider-range-tick-mark-width);
|
|
2355
|
+
height: var(--dc-slider-range-tick-mark-height);
|
|
2356
|
+
background: var(--dc-slider-range-tick-mark-color);
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2126
2359
|
.dc-file-picker {
|
|
2127
2360
|
--dc-file-picker-label-color: var(--dc-control-primary-text-color);
|
|
2128
2361
|
--dc-file-picker-icon-color: var(--dc-control-secondary-text-color);
|
|
@@ -2,13 +2,13 @@ export * from './alert/index.js';
|
|
|
2
2
|
export * from './avatar/index.js';
|
|
3
3
|
export * from './badge/index.js';
|
|
4
4
|
export * from './breadcrumbs/index.js';
|
|
5
|
-
export * from './button/index.js';
|
|
6
5
|
export * from './button-group/index.js';
|
|
6
|
+
export * from './button/index.js';
|
|
7
7
|
export * from './caption/index.js';
|
|
8
8
|
export * from './checkbox/index.js';
|
|
9
9
|
export * from './color-picker/index.js';
|
|
10
|
-
export * from './date-picker/index.js';
|
|
11
10
|
export * from './date-picker-popover/index.js';
|
|
11
|
+
export * from './date-picker/index.js';
|
|
12
12
|
export * from './date-range-picker-popover/index.js';
|
|
13
13
|
export * from './dialog/index.js';
|
|
14
14
|
export * from './empty-state/index.js';
|
|
@@ -28,6 +28,7 @@ export * from './segmented-control/index.js';
|
|
|
28
28
|
export * from './select/index.js';
|
|
29
29
|
export * from './selection-control/index.js';
|
|
30
30
|
export * from './slide-over/index.js';
|
|
31
|
+
export * from './slider-range/index.js';
|
|
31
32
|
export * from './slider/index.js';
|
|
32
33
|
export * from './spinner/index.js';
|
|
33
34
|
export * from './switch/index.js';
|
package/dist/components/index.js
CHANGED
|
@@ -2,13 +2,13 @@ export * from './alert/index.js';
|
|
|
2
2
|
export * from './avatar/index.js';
|
|
3
3
|
export * from './badge/index.js';
|
|
4
4
|
export * from './breadcrumbs/index.js';
|
|
5
|
-
export * from './button/index.js';
|
|
6
5
|
export * from './button-group/index.js';
|
|
6
|
+
export * from './button/index.js';
|
|
7
7
|
export * from './caption/index.js';
|
|
8
8
|
export * from './checkbox/index.js';
|
|
9
9
|
export * from './color-picker/index.js';
|
|
10
|
-
export * from './date-picker/index.js';
|
|
11
10
|
export * from './date-picker-popover/index.js';
|
|
11
|
+
export * from './date-picker/index.js';
|
|
12
12
|
export * from './date-range-picker-popover/index.js';
|
|
13
13
|
export * from './dialog/index.js';
|
|
14
14
|
export * from './empty-state/index.js';
|
|
@@ -28,6 +28,7 @@ export * from './segmented-control/index.js';
|
|
|
28
28
|
export * from './select/index.js';
|
|
29
29
|
export * from './selection-control/index.js';
|
|
30
30
|
export * from './slide-over/index.js';
|
|
31
|
+
export * from './slider-range/index.js';
|
|
31
32
|
export * from './slider/index.js';
|
|
32
33
|
export * from './spinner/index.js';
|
|
33
34
|
export * from './switch/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './slider-range.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export type SliderRangeTickMarkDescriptor = {
|
|
3
|
+
value: number;
|
|
4
|
+
label?: ReactNode;
|
|
5
|
+
};
|
|
6
|
+
export declare function SliderRangeDataList({ className, id, tickMarks, }: {
|
|
7
|
+
className?: string;
|
|
8
|
+
id: string;
|
|
9
|
+
tickMarks: SliderRangeTickMarkDescriptor[];
|
|
10
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { classNames } from '../../lib/index.js';
|
|
3
|
+
export function SliderRangeDataList({ className, id, tickMarks, }) {
|
|
4
|
+
const renderedOptions = [];
|
|
5
|
+
const renderedTickMarks = [];
|
|
6
|
+
for (const { value, label } of tickMarks) {
|
|
7
|
+
const key = `${value}-tick-mark`;
|
|
8
|
+
renderedOptions.push(_jsx("option", { value: value }, key));
|
|
9
|
+
renderedTickMarks.push(_jsx("li", { children: label }, key));
|
|
10
|
+
}
|
|
11
|
+
return (_jsxs(_Fragment, { children: [_jsx("datalist", { id: id, children: renderedOptions }), _jsx("ol", { className: classNames('dc-slider-range__tick-marks', className), children: renderedTickMarks })] }));
|
|
12
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
type SliderRangeLabelProps = {
|
|
3
|
+
className?: string;
|
|
4
|
+
hidden?: boolean;
|
|
5
|
+
htmlFor: string | string[];
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
};
|
|
8
|
+
export declare const SliderRangeLabel: import("react").ForwardRefExoticComponent<SliderRangeLabelProps & import("react").RefAttributes<HTMLOutputElement>>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
import { classNames } from '../../lib/index.js';
|
|
4
|
+
export const SliderRangeLabel = forwardRef(({ className, hidden, htmlFor, children, }, ref) => (_jsx("output", { ref: ref, hidden: hidden, htmlFor: Array.isArray(htmlFor) ? htmlFor.join(' ') : htmlFor, className: classNames('dc-slider-range__label', className), children: _jsx("span", { className: "dc-slider-range__label-text", children: children }) })));
|
|
5
|
+
SliderRangeLabel.displayName = 'SliderRangeLabel';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
import { SliderRangeTickMarkDescriptor } from './slider-range-data-list.js';
|
|
3
|
+
export type SliderRangeValue = {
|
|
4
|
+
readonly min: number;
|
|
5
|
+
readonly max: number;
|
|
6
|
+
};
|
|
7
|
+
export type SliderRangeProps = {
|
|
8
|
+
style?: CSSProperties;
|
|
9
|
+
className?: string;
|
|
10
|
+
tickMarks?: SliderRangeTickMarkDescriptor[];
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
min?: number;
|
|
13
|
+
max?: number;
|
|
14
|
+
step?: number;
|
|
15
|
+
name?: string;
|
|
16
|
+
value: SliderRangeValue;
|
|
17
|
+
onChange: (value: SliderRangeValue) => void;
|
|
18
|
+
renderValue?: (value: number) => ReactNode;
|
|
19
|
+
};
|
|
20
|
+
export declare function SliderRange({ style, className, tickMarks, disabled, min, max, step, name, value: range, onChange: onChangeRange, renderValue, }: SliderRangeProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useId, useLayoutEffect, useRef, useState, } from 'react';
|
|
3
|
+
import { classNames, formatNumber, formatPercent, getCustomPropertyValue } from '../../lib/index.js';
|
|
4
|
+
import { SliderRangeLabel } from './slider-range-label.js';
|
|
5
|
+
import { SliderRangeDataList } from './slider-range-data-list.js';
|
|
6
|
+
const inputKeys = ['min', 'max'];
|
|
7
|
+
const numberFormatter = new Intl.NumberFormat();
|
|
8
|
+
export function SliderRange({ style, className, tickMarks, disabled, min = 0, max = 100, step = 1, name, value: range, onChange: onChangeRange, renderValue = numberFormatter.format, }) {
|
|
9
|
+
const id = useId();
|
|
10
|
+
const containerRef = useRef(null);
|
|
11
|
+
const labelsContainerRef = useRef(null);
|
|
12
|
+
const minValueLabelRef = useRef(null);
|
|
13
|
+
const maxValueLabelRef = useRef(null);
|
|
14
|
+
const rangeLabelRef = useRef(null);
|
|
15
|
+
const [focusedInputKey, setFocusedInputKey] = useState('min');
|
|
16
|
+
let dataListId;
|
|
17
|
+
let dataList;
|
|
18
|
+
if (tickMarks && tickMarks.length > 0) {
|
|
19
|
+
dataListId = `${id}data-list`;
|
|
20
|
+
dataList = _jsx(SliderRangeDataList, { id: dataListId, tickMarks: tickMarks });
|
|
21
|
+
}
|
|
22
|
+
const handleFocus = (key) => () => {
|
|
23
|
+
setFocusedInputKey(key);
|
|
24
|
+
};
|
|
25
|
+
const handleChange = (key) => (event) => {
|
|
26
|
+
const value = Number(event.target.value);
|
|
27
|
+
const { min, max } = range;
|
|
28
|
+
if (key === 'min') {
|
|
29
|
+
onChangeRange({ max, min: Math.min(max, value) });
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
onChangeRange({ min, max: Math.max(min, value) });
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const activeTrackLeft = calcTrackOffsetInPercent(range.min, {
|
|
36
|
+
min,
|
|
37
|
+
max,
|
|
38
|
+
step,
|
|
39
|
+
});
|
|
40
|
+
const activeTrackRight = calcTrackOffsetInPercent(range.max, {
|
|
41
|
+
min,
|
|
42
|
+
max,
|
|
43
|
+
step,
|
|
44
|
+
});
|
|
45
|
+
useLayoutEffect(() => {
|
|
46
|
+
const container = containerRef.current;
|
|
47
|
+
if (!container) {
|
|
48
|
+
throw new Error('container ref is not set');
|
|
49
|
+
}
|
|
50
|
+
const labelsContainer = labelsContainerRef.current;
|
|
51
|
+
if (!labelsContainer) {
|
|
52
|
+
throw new Error('labelsContainer ref is not set');
|
|
53
|
+
}
|
|
54
|
+
const minLabel = minValueLabelRef.current;
|
|
55
|
+
if (!minLabel) {
|
|
56
|
+
throw new Error('minValueLabel ref is not set');
|
|
57
|
+
}
|
|
58
|
+
const maxLabel = maxValueLabelRef.current;
|
|
59
|
+
if (!maxLabel) {
|
|
60
|
+
throw new Error('maxValueLabel ref is not set');
|
|
61
|
+
}
|
|
62
|
+
const rangeLabel = rangeLabelRef.current;
|
|
63
|
+
if (!rangeLabel) {
|
|
64
|
+
throw new Error('rangeLabel ref is not set');
|
|
65
|
+
}
|
|
66
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
67
|
+
const thumbWidth = parseFloat(getCustomPropertyValue(container, '--dc-slider-range-thumb-width'));
|
|
68
|
+
const labelsContainerWidth = getElementWidth(labelsContainer);
|
|
69
|
+
const minLabelWidth = getElementWidth(minLabel);
|
|
70
|
+
const maxLabelWidth = getElementWidth(maxLabel);
|
|
71
|
+
const rangeLabelWidth = getElementWidth(rangeLabel);
|
|
72
|
+
const minLabelOffset = calcLabelOffsetInPixels(minLabelWidth, {
|
|
73
|
+
thumbWidth,
|
|
74
|
+
containerWidth: labelsContainerWidth,
|
|
75
|
+
offsetInPercent: activeTrackLeft,
|
|
76
|
+
});
|
|
77
|
+
setElementTranslateX(minLabel, minLabelOffset);
|
|
78
|
+
const maxLabelOffset = calcLabelOffsetInPixels(maxLabelWidth, {
|
|
79
|
+
thumbWidth,
|
|
80
|
+
containerWidth: labelsContainerWidth,
|
|
81
|
+
offsetInPercent: activeTrackRight,
|
|
82
|
+
});
|
|
83
|
+
setElementTranslateX(maxLabel, maxLabelOffset);
|
|
84
|
+
let rangeLabelOffset;
|
|
85
|
+
if (focusedInputKey === 'max') {
|
|
86
|
+
rangeLabelOffset = minLabelOffset;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
rangeLabelOffset = (maxLabelOffset + maxLabelWidth) - rangeLabelWidth;
|
|
90
|
+
}
|
|
91
|
+
setElementTranslateX(rangeLabel, rangeLabelOffset);
|
|
92
|
+
const shouldShowRangeLabel = (minLabelOffset + minLabelWidth) >= maxLabelOffset;
|
|
93
|
+
if (shouldShowRangeLabel) {
|
|
94
|
+
minLabel.hidden = true;
|
|
95
|
+
maxLabel.hidden = true;
|
|
96
|
+
rangeLabel.hidden = false;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
minLabel.hidden = false;
|
|
100
|
+
maxLabel.hidden = false;
|
|
101
|
+
rangeLabel.hidden = true;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
resizeObserver.observe(labelsContainer);
|
|
105
|
+
return () => resizeObserver.unobserve(labelsContainer);
|
|
106
|
+
}, [focusedInputKey, activeTrackLeft, activeTrackRight]);
|
|
107
|
+
return (_jsxs("div", { ref: containerRef, style: {
|
|
108
|
+
...style,
|
|
109
|
+
'--dc-slider-range-active-track-left': formatPercent(activeTrackLeft),
|
|
110
|
+
'--dc-slider-range-active-track-right': formatPercent(1 - activeTrackRight),
|
|
111
|
+
}, className: classNames(className, {
|
|
112
|
+
'dc-slider-range': true,
|
|
113
|
+
'dc-slider-range_disabled': disabled,
|
|
114
|
+
}), children: [_jsxs("div", { ref: labelsContainerRef, className: "dc-slider-range__labels-container", children: [_jsx(SliderRangeLabel, { ref: minValueLabelRef, htmlFor: generateInputId(id, 'min'), children: renderValue(range.min) }), _jsx(SliderRangeLabel, { ref: maxValueLabelRef, htmlFor: generateInputId(id, 'max'), children: renderValue(range.max) }), _jsx(SliderRangeLabel, { ref: rangeLabelRef, hidden: true, htmlFor: [generateInputId(id, 'min'), generateInputId(id, 'max')], children: range.min === range.max
|
|
115
|
+
? _jsx(_Fragment, { children: renderValue(range.min) })
|
|
116
|
+
: _jsxs(_Fragment, { children: [renderValue(range.min), " - ", renderValue(range.max)] }) })] }), _jsx("div", { className: "dc-slider-range__track", children: inputKeys.map((inputKey) => (_jsx("input", { id: generateInputId(id, inputKey), className: classNames({
|
|
117
|
+
'dc-slider-range__input': true,
|
|
118
|
+
'dc-slider-range__input_active': focusedInputKey === inputKey,
|
|
119
|
+
}), type: "range", min: min, max: max, step: step, list: dataListId, name: name ? `${name}[${inputKey}]` : undefined, value: range[inputKey], disabled: disabled, onChange: handleChange(inputKey), onFocus: handleFocus(inputKey) }, inputKey))) }), dataList] }));
|
|
120
|
+
}
|
|
121
|
+
function generateInputId(id, inputKey) {
|
|
122
|
+
return `${id}input-range-${inputKey}`;
|
|
123
|
+
}
|
|
124
|
+
function calcTrackOffsetInPercent(value, opts) {
|
|
125
|
+
return Math.round(value / opts.step) * opts.step / (opts.max - opts.min);
|
|
126
|
+
}
|
|
127
|
+
function calcLabelOffsetInPixels(labelWidth, opts) {
|
|
128
|
+
let offset = ((opts.offsetInPercent * opts.containerWidth) -
|
|
129
|
+
(opts.offsetInPercent * opts.thumbWidth) -
|
|
130
|
+
((labelWidth - opts.thumbWidth) / 2));
|
|
131
|
+
const min = 0;
|
|
132
|
+
const max = opts.containerWidth - labelWidth;
|
|
133
|
+
if (offset < min) {
|
|
134
|
+
offset = min;
|
|
135
|
+
}
|
|
136
|
+
if (offset > max) {
|
|
137
|
+
offset = max;
|
|
138
|
+
}
|
|
139
|
+
return offset;
|
|
140
|
+
}
|
|
141
|
+
function getElementWidth(element) {
|
|
142
|
+
const rect = element.getBoundingClientRect();
|
|
143
|
+
return rect.width;
|
|
144
|
+
}
|
|
145
|
+
function setElementTranslateX(element, offsetX) {
|
|
146
|
+
element.style.transform = `translateX(${formatNumber(offsetX)}px)`;
|
|
147
|
+
}
|
package/dist/lib/helpers.d.ts
CHANGED
|
@@ -3,4 +3,6 @@ export declare function once<T extends AnyFunction>(fn: T): (...args: Parameters
|
|
|
3
3
|
export declare function assertIfNullable<T>(value: T, message?: string): asserts value is NonNullable<T>;
|
|
4
4
|
export declare function exhaustiveCheck(value: never, message?: string): never;
|
|
5
5
|
export declare function noop(): undefined;
|
|
6
|
+
export declare function formatNumber(num: number, fractionDigits?: number): number;
|
|
7
|
+
export declare function formatPercent(percent: number): string;
|
|
6
8
|
export {};
|
package/dist/lib/helpers.js
CHANGED
|
@@ -20,3 +20,9 @@ export function exhaustiveCheck(value, message) {
|
|
|
20
20
|
export function noop() {
|
|
21
21
|
return undefined;
|
|
22
22
|
}
|
|
23
|
+
export function formatNumber(num, fractionDigits = 5) {
|
|
24
|
+
return Number(num.toFixed(fractionDigits));
|
|
25
|
+
}
|
|
26
|
+
export function formatPercent(percent) {
|
|
27
|
+
return `${formatNumber(percent * 100)}%`;
|
|
28
|
+
}
|
|
@@ -12,3 +12,4 @@ export type ReactElementWithRef = ReactElement & {
|
|
|
12
12
|
export declare function isReactElementWithRef(element: unknown): element is ReactElementWithRef;
|
|
13
13
|
export declare function focusElement(element: EventTarget | null | undefined): void;
|
|
14
14
|
export declare function getRefElement<T extends HTMLElement>(ref: RefObject<T> | MutableRefObject<T>, message?: string): NonNullable<T>;
|
|
15
|
+
export declare function getCustomPropertyValue(element: HTMLElement, property: string): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "draft-components",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"description": "The React based UI components library.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -53,49 +53,47 @@
|
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@alexzimakov/eslint-config": "1.8.0",
|
|
56
|
-
"@heroicons/react": "2.
|
|
57
|
-
"@storybook/addon-actions": "7.
|
|
58
|
-
"@storybook/addon-essentials": "7.
|
|
59
|
-
"@storybook/addon-links": "7.
|
|
60
|
-
"@storybook/addon-themes": "7.
|
|
61
|
-
"@storybook/react": "7.
|
|
62
|
-
"@storybook/react-vite": "7.
|
|
56
|
+
"@heroicons/react": "2.1.1",
|
|
57
|
+
"@storybook/addon-actions": "7.6.7",
|
|
58
|
+
"@storybook/addon-essentials": "7.6.7",
|
|
59
|
+
"@storybook/addon-links": "7.6.7",
|
|
60
|
+
"@storybook/addon-themes": "7.6.7",
|
|
61
|
+
"@storybook/react": "7.6.7",
|
|
62
|
+
"@storybook/react-vite": "7.6.7",
|
|
63
63
|
"@testing-library/dom": "9.3.3",
|
|
64
|
-
"@testing-library/jest-dom": "6.
|
|
65
|
-
"@testing-library/react": "14.
|
|
66
|
-
"@testing-library/user-event": "14.5.
|
|
67
|
-
"@types/node": "20.
|
|
68
|
-
"@types/react": "18.2.
|
|
69
|
-
"@types/react-dom": "18.2.
|
|
70
|
-
"@typescript-eslint/eslint-plugin": "6.
|
|
71
|
-
"@
|
|
64
|
+
"@testing-library/jest-dom": "6.2.0",
|
|
65
|
+
"@testing-library/react": "14.1.2",
|
|
66
|
+
"@testing-library/user-event": "14.5.2",
|
|
67
|
+
"@types/node": "20.10.6",
|
|
68
|
+
"@types/react": "18.2.46",
|
|
69
|
+
"@types/react-dom": "18.2.18",
|
|
70
|
+
"@typescript-eslint/eslint-plugin": "6.17.0",
|
|
71
|
+
"@typescript-eslint/parser": "6.17.0",
|
|
72
|
+
"@vitest/coverage-istanbul": "1.1.2",
|
|
72
73
|
"autoprefixer": "10.4.16",
|
|
73
|
-
"eslint": "8.
|
|
74
|
+
"eslint": "8.56.0",
|
|
74
75
|
"eslint-plugin-jsx-a11y": "6.8.0",
|
|
75
76
|
"eslint-plugin-react": "7.33.2",
|
|
76
77
|
"eslint-plugin-react-hooks": "4.6.0",
|
|
77
78
|
"eslint-plugin-storybook": "0.6.15",
|
|
78
|
-
"eslint-plugin-testing-library": "6.
|
|
79
|
+
"eslint-plugin-testing-library": "6.2.0",
|
|
79
80
|
"husky": "8.0.3",
|
|
80
|
-
"jsdom": "
|
|
81
|
-
"lint-staged": "15.0
|
|
82
|
-
"postcss": "8.4.
|
|
83
|
-
"postcss-import": "
|
|
81
|
+
"jsdom": "23.0.1",
|
|
82
|
+
"lint-staged": "15.2.0",
|
|
83
|
+
"postcss": "8.4.32",
|
|
84
|
+
"postcss-import": "16.0.0",
|
|
84
85
|
"react": "18.2.0",
|
|
85
86
|
"react-dom": "18.2.0",
|
|
86
|
-
"storybook": "7.
|
|
87
|
-
"stylelint": "
|
|
88
|
-
"stylelint-config-standard": "
|
|
89
|
-
"stylelint-order": "6.0.
|
|
90
|
-
"typescript": "5.
|
|
91
|
-
"vite": "
|
|
92
|
-
"vitest": "
|
|
87
|
+
"storybook": "7.6.7",
|
|
88
|
+
"stylelint": "16.1.0",
|
|
89
|
+
"stylelint-config-standard": "36.0.0",
|
|
90
|
+
"stylelint-order": "6.0.4",
|
|
91
|
+
"typescript": "5.3.3",
|
|
92
|
+
"vite": "5.0.10",
|
|
93
|
+
"vitest": "1.1.2"
|
|
93
94
|
},
|
|
94
95
|
"lint-staged": {
|
|
95
96
|
"*.ts?(x)": "npm run lint-js",
|
|
96
97
|
"*.css": "npm run lint-css"
|
|
97
|
-
},
|
|
98
|
-
"dependencies": {
|
|
99
|
-
"@typescript-eslint/parser": "6.10.0"
|
|
100
98
|
}
|
|
101
99
|
}
|