vira 33.5.1 → 33.6.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/dist/elements/index.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ export * from './vira-link.element.js';
|
|
|
33
33
|
export * from './vira-modal.element.js';
|
|
34
34
|
export * from './vira-progress.element.js';
|
|
35
35
|
export * from './vira-relative-time.element.js';
|
|
36
|
+
export * from './vira-slider.element.js';
|
|
36
37
|
export * from './vira-tabs.element.js';
|
|
37
38
|
export * from './vira-tag.element.js';
|
|
38
39
|
export * from './vira-text-area.element.js';
|
package/dist/elements/index.js
CHANGED
|
@@ -33,6 +33,7 @@ export * from './vira-link.element.js';
|
|
|
33
33
|
export * from './vira-modal.element.js';
|
|
34
34
|
export * from './vira-progress.element.js';
|
|
35
35
|
export * from './vira-relative-time.element.js';
|
|
36
|
+
export * from './vira-slider.element.js';
|
|
36
37
|
export * from './vira-tabs.element.js';
|
|
37
38
|
export * from './vira-tag.element.js';
|
|
38
39
|
export * from './vira-text-area.element.js';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type PartialWithUndefined } from '@augment-vir/common';
|
|
2
|
+
/**
|
|
3
|
+
* Inputs for {@link ViraSlider}.
|
|
4
|
+
*
|
|
5
|
+
* @category Internal
|
|
6
|
+
*/
|
|
7
|
+
export type ViraSliderInputs = {
|
|
8
|
+
value: number;
|
|
9
|
+
} & PartialWithUndefined<{
|
|
10
|
+
/** Defaults to `0`. */
|
|
11
|
+
min: number;
|
|
12
|
+
/** Defaults to `100`. */
|
|
13
|
+
max: number;
|
|
14
|
+
/** Defaults to `1`. */
|
|
15
|
+
step: number;
|
|
16
|
+
isDisabled: boolean;
|
|
17
|
+
/** The slider's accessible name. It is not rendered visibly. */
|
|
18
|
+
label: string;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* A themed replacement for `<input type="range">`. The track, fill, and thumb are drawn with Vira's
|
|
22
|
+
* form colors, so they follow the current theme (including dark mode) where a browser's native
|
|
23
|
+
* range styling does not. An invisible native range input sits on top, so keyboard, pointer, and
|
|
24
|
+
* screen reader behavior are the browser's own.
|
|
25
|
+
*
|
|
26
|
+
* `valueChange` fires on every change while dragging. The slider is controlled: it only moves when
|
|
27
|
+
* `value` is updated in response.
|
|
28
|
+
*
|
|
29
|
+
* @category Input
|
|
30
|
+
* @category Elements
|
|
31
|
+
* @see https://electrovir.github.io/vira/book/elements/vira-slider
|
|
32
|
+
*/
|
|
33
|
+
export declare const ViraSlider: import("element-vir").DeclarativeElementDefinition<"vira-slider", Readonly<ViraSliderInputs>, {}, {
|
|
34
|
+
valueChange: import("element-vir").DefineElementEvent<number>;
|
|
35
|
+
}, "vira-slider-", "vira-slider-track-height" | "vira-slider-thumb-size" | "vira-slider-track-color" | "vira-slider-fill-color" | "vira-slider-thumb-color" | "vira-slider-thumb-hover-color" | "vira-slider-thumb-active-color", readonly [], readonly []>;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { extractEventTarget } from '@augment-vir/web';
|
|
2
|
+
import { classMap, css, defineElementEvent, html, ifDefined, listen } from 'element-vir';
|
|
3
|
+
import { viraDisabledStyles } from '../styles/disabled.js';
|
|
4
|
+
import { createFocusStyles } from '../styles/focus.js';
|
|
5
|
+
import { viraFormCssVars } from '../styles/form-styles.js';
|
|
6
|
+
import { defineViraElement } from '../util/define-vira-element.js';
|
|
7
|
+
/**
|
|
8
|
+
* A themed replacement for `<input type="range">`. The track, fill, and thumb are drawn with Vira's
|
|
9
|
+
* form colors, so they follow the current theme (including dark mode) where a browser's native
|
|
10
|
+
* range styling does not. An invisible native range input sits on top, so keyboard, pointer, and
|
|
11
|
+
* screen reader behavior are the browser's own.
|
|
12
|
+
*
|
|
13
|
+
* `valueChange` fires on every change while dragging. The slider is controlled: it only moves when
|
|
14
|
+
* `value` is updated in response.
|
|
15
|
+
*
|
|
16
|
+
* @category Input
|
|
17
|
+
* @category Elements
|
|
18
|
+
* @see https://electrovir.github.io/vira/book/elements/vira-slider
|
|
19
|
+
*/
|
|
20
|
+
export const ViraSlider = defineViraElement()({
|
|
21
|
+
tagName: 'vira-slider',
|
|
22
|
+
cssVars: {
|
|
23
|
+
'vira-slider-track-height': '4px',
|
|
24
|
+
'vira-slider-thumb-size': '16px',
|
|
25
|
+
'vira-slider-track-color': viraFormCssVars['vira-form-border-color'].value,
|
|
26
|
+
'vira-slider-fill-color': viraFormCssVars['vira-form-accent-primary-color'].value,
|
|
27
|
+
'vira-slider-thumb-color': viraFormCssVars['vira-form-accent-primary-color'].value,
|
|
28
|
+
'vira-slider-thumb-hover-color': viraFormCssVars['vira-form-accent-primary-hover-color'].value,
|
|
29
|
+
'vira-slider-thumb-active-color': viraFormCssVars['vira-form-accent-primary-active-color'].value,
|
|
30
|
+
},
|
|
31
|
+
styles({ cssVars }) {
|
|
32
|
+
return css `
|
|
33
|
+
:host {
|
|
34
|
+
display: inline-flex;
|
|
35
|
+
width: 160px;
|
|
36
|
+
vertical-align: middle;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.slider {
|
|
40
|
+
position: relative;
|
|
41
|
+
flex-grow: 1;
|
|
42
|
+
height: ${cssVars['vira-slider-thumb-size'].value};
|
|
43
|
+
|
|
44
|
+
&.disabled {
|
|
45
|
+
${viraDisabledStyles};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.track,
|
|
50
|
+
.fill {
|
|
51
|
+
position: absolute;
|
|
52
|
+
top: 50%;
|
|
53
|
+
left: 0;
|
|
54
|
+
height: ${cssVars['vira-slider-track-height'].value};
|
|
55
|
+
transform: translateY(-50%);
|
|
56
|
+
border-radius: ${cssVars['vira-slider-track-height'].value};
|
|
57
|
+
pointer-events: none;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.track {
|
|
61
|
+
width: 100%;
|
|
62
|
+
background-color: ${cssVars['vira-slider-track-color'].value};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.fill {
|
|
66
|
+
background-color: ${cssVars['vira-slider-fill-color'].value};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.thumb {
|
|
70
|
+
position: absolute;
|
|
71
|
+
top: 0;
|
|
72
|
+
width: ${cssVars['vira-slider-thumb-size'].value};
|
|
73
|
+
height: ${cssVars['vira-slider-thumb-size'].value};
|
|
74
|
+
box-sizing: border-box;
|
|
75
|
+
border-radius: 50%;
|
|
76
|
+
border: 2px solid ${viraFormCssVars['vira-form-background-color'].value};
|
|
77
|
+
background-color: ${cssVars['vira-slider-thumb-color'].value};
|
|
78
|
+
pointer-events: none;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
input {
|
|
82
|
+
position: absolute;
|
|
83
|
+
inset: 0;
|
|
84
|
+
width: 100%;
|
|
85
|
+
height: 100%;
|
|
86
|
+
margin: 0;
|
|
87
|
+
padding: 0;
|
|
88
|
+
appearance: none;
|
|
89
|
+
background: transparent;
|
|
90
|
+
opacity: 0;
|
|
91
|
+
cursor: pointer;
|
|
92
|
+
|
|
93
|
+
/*
|
|
94
|
+
The invisible native thumb must match the drawn thumb's width so the browser
|
|
95
|
+
maps pointer positions to the same values the drawn thumb shows.
|
|
96
|
+
*/
|
|
97
|
+
&::-webkit-slider-thumb {
|
|
98
|
+
appearance: none;
|
|
99
|
+
width: ${cssVars['vira-slider-thumb-size'].value};
|
|
100
|
+
height: ${cssVars['vira-slider-thumb-size'].value};
|
|
101
|
+
}
|
|
102
|
+
&::-moz-range-thumb {
|
|
103
|
+
width: ${cssVars['vira-slider-thumb-size'].value};
|
|
104
|
+
height: ${cssVars['vira-slider-thumb-size'].value};
|
|
105
|
+
border: none;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
&:hover ~ .thumb {
|
|
109
|
+
background-color: ${cssVars['vira-slider-thumb-hover-color'].value};
|
|
110
|
+
}
|
|
111
|
+
&:active ~ .thumb {
|
|
112
|
+
background-color: ${cssVars['vira-slider-thumb-active-color'].value};
|
|
113
|
+
}
|
|
114
|
+
&:focus-visible:not(:active) ~ .thumb::after {
|
|
115
|
+
${createFocusStyles({
|
|
116
|
+
elementBorderSize: '2px',
|
|
117
|
+
borderRadius: '50%',
|
|
118
|
+
noNesting: true,
|
|
119
|
+
})}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
`;
|
|
123
|
+
},
|
|
124
|
+
events: {
|
|
125
|
+
valueChange: defineElementEvent(),
|
|
126
|
+
},
|
|
127
|
+
render({ inputs, dispatch, events, cssVars }) {
|
|
128
|
+
const min = inputs.min ?? 0;
|
|
129
|
+
const max = inputs.max ?? 100;
|
|
130
|
+
const fraction = max > min ? Math.min(1, Math.max(0, (inputs.value - min) / (max - min))) : 0;
|
|
131
|
+
const thumbOffset = css `calc((100% - ${cssVars['vira-slider-thumb-size'].value}) * ${fraction})`;
|
|
132
|
+
return html `
|
|
133
|
+
<div
|
|
134
|
+
class="slider ${classMap({
|
|
135
|
+
disabled: !!inputs.isDisabled,
|
|
136
|
+
})}"
|
|
137
|
+
>
|
|
138
|
+
<div class="track"></div>
|
|
139
|
+
<div
|
|
140
|
+
class="fill"
|
|
141
|
+
style=${css `
|
|
142
|
+
width: calc(
|
|
143
|
+
${thumbOffset} + ${cssVars['vira-slider-thumb-size'].value} / 2
|
|
144
|
+
);
|
|
145
|
+
`}
|
|
146
|
+
></div>
|
|
147
|
+
<input
|
|
148
|
+
type="range"
|
|
149
|
+
min=${min}
|
|
150
|
+
max=${max}
|
|
151
|
+
step=${inputs.step ?? 1}
|
|
152
|
+
aria-label=${ifDefined(inputs.label || undefined)}
|
|
153
|
+
?disabled=${inputs.isDisabled}
|
|
154
|
+
.value=${String(inputs.value)}
|
|
155
|
+
${listen('input', (event) => {
|
|
156
|
+
const inputElement = extractEventTarget(event, HTMLInputElement);
|
|
157
|
+
const newValue = Number(inputElement.value);
|
|
158
|
+
/**
|
|
159
|
+
* Snap the native input back to the controlled value; it only moves once
|
|
160
|
+
* the new value is assigned back in.
|
|
161
|
+
*/
|
|
162
|
+
inputElement.value = String(inputs.value);
|
|
163
|
+
if (newValue !== inputs.value) {
|
|
164
|
+
dispatch(new events.valueChange({
|
|
165
|
+
detail: newValue,
|
|
166
|
+
}));
|
|
167
|
+
}
|
|
168
|
+
})}
|
|
169
|
+
/>
|
|
170
|
+
<div
|
|
171
|
+
class="thumb"
|
|
172
|
+
style=${css `
|
|
173
|
+
left: ${thumbOffset};
|
|
174
|
+
`}
|
|
175
|
+
></div>
|
|
176
|
+
</div>
|
|
177
|
+
`;
|
|
178
|
+
},
|
|
179
|
+
});
|