ember-primitives 0.59.0 → 0.60.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.
@@ -0,0 +1,239 @@
1
+ import { tracked } from '@glimmer/tracking';
2
+ import { htmlSafe } from '@ember/template';
3
+ import { g, i } from 'decorator-transforms/runtime';
4
+
5
+ const DEFAULT_MIN = 0;
6
+ const DEFAULT_MAX = 100;
7
+ const DEFAULT_STEP = 1;
8
+ function clamp(value, min, max) {
9
+ return Math.min(Math.max(value, min), max);
10
+ }
11
+ function roundToStep(value, step) {
12
+ if (!Number.isFinite(step) || step <= 0) return value;
13
+ return Math.round(value / step) * step;
14
+ }
15
+ function getPercentage(value, min, max) {
16
+ const range = max - min;
17
+ if (!Number.isFinite(range) || range === 0) return 0;
18
+ return (value - min) / range * 100;
19
+ }
20
+ function normalizeTickValues(values) {
21
+ const uniques = new Set();
22
+ for (const value of values) {
23
+ if (Number.isFinite(value)) uniques.add(value);
24
+ }
25
+ return Array.from(uniques).sort((a, b) => a - b);
26
+ }
27
+ function findNearestIndex(values, target) {
28
+ if (values.length === 0) return 0;
29
+ const first = values[0];
30
+ if (first === undefined) return 0;
31
+ let nearestIndex = 0;
32
+ let nearestDistance = Math.abs(first - target);
33
+ for (let index = 1; index < values.length; index++) {
34
+ const candidate = values[index];
35
+ if (candidate === undefined) continue;
36
+ const distance = Math.abs(candidate - target);
37
+ if (distance < nearestDistance) {
38
+ nearestIndex = index;
39
+ nearestDistance = distance;
40
+ }
41
+ }
42
+ return nearestIndex;
43
+ }
44
+ class ThumbState {
45
+ #slider;
46
+ constructor(slider, index) {
47
+ this.index = index;
48
+ this.#slider = slider;
49
+ }
50
+ get value() {
51
+ return this.#slider.values[this.index] ?? this.#slider.min;
52
+ }
53
+ get inputValue() {
54
+ const ticks = this.#slider.tickValues;
55
+ if (!ticks) return this.value;
56
+ return clamp(findNearestIndex(ticks, this.value), 0, Math.max(0, ticks.length - 1));
57
+ }
58
+ get percent() {
59
+ return this.#slider.thumbPercents[this.index] ?? 0;
60
+ }
61
+ get active() {
62
+ return this.#slider.activeThumbIndex === this.index;
63
+ }
64
+ get positionStyle() {
65
+ return this.#slider.thumbPositionStyle(this.percent);
66
+ }
67
+ }
68
+ class SliderStore {
69
+ #thumbStates = [];
70
+ #getArgs;
71
+ static {
72
+ g(this.prototype, "activeThumbIndex", [tracked], function () {
73
+ return null;
74
+ });
75
+ }
76
+ #activeThumbIndex = (i(this, "activeThumbIndex"), void 0);
77
+ constructor(getArgs) {
78
+ this.#getArgs = getArgs;
79
+ const args = this.#getArgs();
80
+ const initialCount = Array.isArray(args.value) ? Math.max(1, args.value.length) : 1;
81
+ this.#thumbStates = Array.from({
82
+ length: initialCount
83
+ }, (_, index) => new ThumbState(this, index));
84
+ }
85
+ get #args() {
86
+ return this.#getArgs();
87
+ }
88
+ get min() {
89
+ return this.#args.min ?? DEFAULT_MIN;
90
+ }
91
+ get max() {
92
+ return this.#args.max ?? DEFAULT_MAX;
93
+ }
94
+ get step() {
95
+ return typeof this.#args.step === 'number' ? this.#args.step : DEFAULT_STEP;
96
+ }
97
+ get tickValues() {
98
+ const fromStep = Array.isArray(this.#args.step) ? this.#args.step : undefined;
99
+ const raw = fromStep;
100
+ if (!raw) return null;
101
+ const normalized = normalizeTickValues(raw);
102
+ return normalized.length === 0 ? null : normalized;
103
+ }
104
+ get orientation() {
105
+ return this.#args.orientation ?? 'horizontal';
106
+ }
107
+ get disabled() {
108
+ return this.#args.disabled ?? false;
109
+ }
110
+ get internalMin() {
111
+ const ticks = this.tickValues;
112
+ if (ticks) return 0;
113
+ return this.min;
114
+ }
115
+ get internalMax() {
116
+ const ticks = this.tickValues;
117
+ if (ticks) return Math.max(0, ticks.length - 1);
118
+ return this.max;
119
+ }
120
+ get internalStep() {
121
+ const ticks = this.tickValues;
122
+ if (ticks) return 1;
123
+ return this.step;
124
+ }
125
+ get internalValues() {
126
+ const ticks = this.tickValues;
127
+ const normalized = Array.isArray(this.#args.value) ? this.#args.value.length === 0 ? [ticks?.[0] ?? this.min] : this.#args.value : [this.#args.value ?? ticks?.[0] ?? this.min];
128
+ if (ticks) {
129
+ return normalized.map(v => {
130
+ const index = findNearestIndex(ticks, v);
131
+ return clamp(index, this.internalMin, this.internalMax);
132
+ });
133
+ }
134
+ return normalized.map(v => clamp(roundToStep(v, this.step), this.min, this.max));
135
+ }
136
+ outputValuesFromInternal(internalValues) {
137
+ const ticks = this.tickValues;
138
+ if (!ticks) return internalValues;
139
+ return internalValues.map(internal => {
140
+ const index = clamp(Math.round(internal), 0, ticks.length - 1);
141
+ return ticks[index] ?? ticks[0] ?? this.min;
142
+ });
143
+ }
144
+ get values() {
145
+ return this.outputValuesFromInternal(this.internalValues);
146
+ }
147
+ get thumbs() {
148
+ this.#ensureThumbCount(this.internalValues.length);
149
+ return this.#thumbStates;
150
+ }
151
+ get thumbPercents() {
152
+ return this.internalValues.map(value => getPercentage(value, this.internalMin, this.internalMax));
153
+ }
154
+ get isMulti() {
155
+ return this.internalValues.length > 1;
156
+ }
157
+ thumbPositionStyle = percent => {
158
+ const property = this.orientation === 'horizontal' ? 'left' : 'bottom';
159
+ return htmlSafe(`${property}: ${percent}%`);
160
+ };
161
+ get rangeStyle() {
162
+ const internalValues = this.internalValues;
163
+
164
+ // For a single-thumb slider, the "range" should fill from the start to the
165
+ // thumb. For multi-thumb, it fills between the min/max thumbs.
166
+ const internalRangeMin = internalValues.length <= 1 ? this.internalMin : Math.min(...internalValues);
167
+ const internalRangeMax = internalValues[0] === undefined ? this.internalMin : Math.max(...internalValues);
168
+ const startPercent = getPercentage(internalRangeMin, this.internalMin, this.internalMax);
169
+ const endPercent = getPercentage(internalRangeMax, this.internalMin, this.internalMax);
170
+ if (this.orientation === 'horizontal') {
171
+ return htmlSafe(`left: ${startPercent}%; right: ${100 - endPercent}%`);
172
+ } else {
173
+ return htmlSafe(`bottom: ${startPercent}%; top: ${100 - endPercent}%`);
174
+ }
175
+ }
176
+ updateValue = newValues => {
177
+ if (this.#args.onValueChange) {
178
+ this.#args.onValueChange(this.coerceOutput(newValues));
179
+ }
180
+ };
181
+ commitValue = newValues => {
182
+ if (this.#args.onValueCommit) {
183
+ this.#args.onValueCommit(this.coerceOutput(newValues));
184
+ }
185
+ };
186
+ coerceOutput(values) {
187
+ if (Array.isArray(this.#args.value)) return values;
188
+ return values[0] ?? this.min;
189
+ }
190
+ #ensureThumbCount(count) {
191
+ if (count === this.#thumbStates.length) return;
192
+ if (count < this.#thumbStates.length) {
193
+ this.#thumbStates = this.#thumbStates.slice(0, count);
194
+ return;
195
+ }
196
+ const startIndex = this.#thumbStates.length;
197
+ for (let index = startIndex; index < count; index++) {
198
+ this.#thumbStates.push(new ThumbState(this, index));
199
+ }
200
+ }
201
+ #applyThumbInternalValue(index, rawValue) {
202
+ const nextValues = [...this.internalValues];
203
+ const stepped = clamp(roundToStep(rawValue, this.internalStep), this.internalMin, this.internalMax);
204
+ let constrained = stepped;
205
+ if (nextValues.length > 1) {
206
+ const prev = nextValues[index - 1];
207
+ const next = nextValues[index + 1];
208
+ if (prev !== undefined) constrained = Math.max(constrained, prev);
209
+ if (next !== undefined) constrained = Math.min(constrained, next);
210
+ }
211
+ nextValues[index] = constrained;
212
+ return nextValues;
213
+ }
214
+ handleThumbInput = (index, value) => {
215
+ if (this.disabled) return;
216
+ const internalValues = this.#applyThumbInternalValue(index, value);
217
+ const newValues = this.outputValuesFromInternal(internalValues);
218
+ this.updateValue(newValues);
219
+ };
220
+ handleThumbChange = (index, value) => {
221
+ if (this.disabled) return;
222
+ const internalValues = this.#applyThumbInternalValue(index, value);
223
+ const newValues = this.outputValuesFromInternal(internalValues);
224
+ this.updateValue(newValues);
225
+ this.commitValue(newValues);
226
+ };
227
+ handleThumbActivate = index => {
228
+ this.activeThumbIndex = index;
229
+ };
230
+ defaultThumbLabel = index => {
231
+ const count = this.internalValues.length;
232
+ if (count <= 1) return 'Value';
233
+ if (count === 2) return index === 0 ? 'Minimum' : 'Maximum';
234
+ return `Value ${index + 1}`;
235
+ };
236
+ }
237
+
238
+ export { SliderStore };
239
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sources":["../../../src/components/slider/store.ts"],"sourcesContent":["import { tracked } from '@glimmer/tracking';\nimport { htmlSafe } from '@ember/template';\n\n/**\n * `style` attribute values need to be SafeStrings to avoid Ember's\n * style-binding warning.\n */\nexport type StyleString = ReturnType<typeof htmlSafe>;\n\nexport interface SliderStoreArgs {\n value?: number | number[];\n min?: number;\n max?: number;\n step?: number | number[];\n orientation?: 'horizontal' | 'vertical';\n disabled?: boolean;\n onValueChange?: (value: number | number[]) => void;\n onValueCommit?: (value: number | number[]) => void;\n}\n\nexport interface SliderThumb {\n index: number;\n value: number;\n /**\n * The value to pass to `<input type=\"range\">`.\n *\n * When using an array `step`, this is the internal index (0..n-1).\n * Otherwise it's the same as `value`.\n */\n inputValue: number;\n percent: number;\n active: boolean;\n /**\n * Inline style positioning this thumb along the track\n * (`left: x%` or `bottom: x%`, depending on orientation).\n */\n positionStyle: StyleString;\n}\n\nconst DEFAULT_MIN = 0;\nconst DEFAULT_MAX = 100;\nconst DEFAULT_STEP = 1;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction roundToStep(value: number, step: number): number {\n if (!Number.isFinite(step) || step <= 0) return value;\n\n return Math.round(value / step) * step;\n}\n\nfunction getPercentage(value: number, min: number, max: number): number {\n const range = max - min;\n\n if (!Number.isFinite(range) || range === 0) return 0;\n\n return ((value - min) / range) * 100;\n}\n\nfunction normalizeTickValues(values: number[]): number[] {\n const uniques = new Set<number>();\n\n for (const value of values) {\n if (Number.isFinite(value)) uniques.add(value);\n }\n\n return Array.from(uniques).sort((a, b) => a - b);\n}\n\nfunction findNearestIndex(values: number[], target: number): number {\n if (values.length === 0) return 0;\n\n const first = values[0];\n\n if (first === undefined) return 0;\n\n let nearestIndex = 0;\n let nearestDistance = Math.abs(first - target);\n\n for (let index = 1; index < values.length; index++) {\n const candidate = values[index];\n\n if (candidate === undefined) continue;\n\n const distance = Math.abs(candidate - target);\n\n if (distance < nearestDistance) {\n nearestIndex = index;\n nearestDistance = distance;\n }\n }\n\n return nearestIndex;\n}\n\nclass ThumbState implements SliderThumb {\n #slider: SliderStore;\n\n constructor(\n slider: SliderStore,\n public index: number\n ) {\n this.#slider = slider;\n }\n\n get value(): number {\n return this.#slider.values[this.index] ?? this.#slider.min;\n }\n\n get inputValue(): number {\n const ticks = this.#slider.tickValues;\n\n if (!ticks) return this.value;\n\n return clamp(findNearestIndex(ticks, this.value), 0, Math.max(0, ticks.length - 1));\n }\n\n get percent(): number {\n return this.#slider.thumbPercents[this.index] ?? 0;\n }\n\n get active(): boolean {\n return this.#slider.activeThumbIndex === this.index;\n }\n\n get positionStyle(): StyleString {\n return this.#slider.thumbPositionStyle(this.percent);\n }\n}\n\nexport class SliderStore {\n #thumbStates: ThumbState[] = [];\n #getArgs: () => SliderStoreArgs;\n\n @tracked activeThumbIndex: number | null = null;\n\n constructor(getArgs: () => SliderStoreArgs) {\n this.#getArgs = getArgs;\n\n const args = this.#getArgs();\n const initialCount = Array.isArray(args.value) ? Math.max(1, args.value.length) : 1;\n\n this.#thumbStates = Array.from(\n { length: initialCount },\n (_, index) => new ThumbState(this, index)\n );\n }\n\n get #args(): SliderStoreArgs {\n return this.#getArgs();\n }\n\n get min(): number {\n return this.#args.min ?? DEFAULT_MIN;\n }\n\n get max(): number {\n return this.#args.max ?? DEFAULT_MAX;\n }\n\n get step(): number {\n return typeof this.#args.step === 'number' ? this.#args.step : DEFAULT_STEP;\n }\n\n get tickValues(): number[] | null {\n const fromStep = Array.isArray(this.#args.step) ? this.#args.step : undefined;\n const raw = fromStep;\n\n if (!raw) return null;\n\n const normalized = normalizeTickValues(raw);\n\n return normalized.length === 0 ? null : normalized;\n }\n\n get orientation(): 'horizontal' | 'vertical' {\n return this.#args.orientation ?? 'horizontal';\n }\n\n get disabled(): boolean {\n return this.#args.disabled ?? false;\n }\n\n get internalMin(): number {\n const ticks = this.tickValues;\n\n if (ticks) return 0;\n\n return this.min;\n }\n\n get internalMax(): number {\n const ticks = this.tickValues;\n\n if (ticks) return Math.max(0, ticks.length - 1);\n\n return this.max;\n }\n\n get internalStep(): number {\n const ticks = this.tickValues;\n\n if (ticks) return 1;\n\n return this.step;\n }\n\n get internalValues(): number[] {\n const ticks = this.tickValues;\n const normalized = Array.isArray(this.#args.value)\n ? this.#args.value.length === 0\n ? [ticks?.[0] ?? this.min]\n : this.#args.value\n : [this.#args.value ?? ticks?.[0] ?? this.min];\n\n if (ticks) {\n return normalized.map((v) => {\n const index = findNearestIndex(ticks, v);\n\n return clamp(index, this.internalMin, this.internalMax);\n });\n }\n\n return normalized.map((v) => clamp(roundToStep(v, this.step), this.min, this.max));\n }\n\n outputValuesFromInternal(internalValues: number[]): number[] {\n const ticks = this.tickValues;\n\n if (!ticks) return internalValues;\n\n return internalValues.map((internal) => {\n const index = clamp(Math.round(internal), 0, ticks.length - 1);\n\n return ticks[index] ?? ticks[0] ?? this.min;\n });\n }\n\n get values(): number[] {\n return this.outputValuesFromInternal(this.internalValues);\n }\n\n get thumbs(): SliderThumb[] {\n this.#ensureThumbCount(this.internalValues.length);\n\n return this.#thumbStates;\n }\n\n get thumbPercents(): number[] {\n return this.internalValues.map((value) =>\n getPercentage(value, this.internalMin, this.internalMax)\n );\n }\n\n get isMulti(): boolean {\n return this.internalValues.length > 1;\n }\n\n thumbPositionStyle = (percent: number): StyleString => {\n const property = this.orientation === 'horizontal' ? 'left' : 'bottom';\n\n return htmlSafe(`${property}: ${percent}%`);\n };\n\n get rangeStyle(): StyleString {\n const internalValues = this.internalValues;\n\n // For a single-thumb slider, the \"range\" should fill from the start to the\n // thumb. For multi-thumb, it fills between the min/max thumbs.\n const internalRangeMin =\n internalValues.length <= 1 ? this.internalMin : Math.min(...internalValues);\n const internalRangeMax =\n internalValues[0] === undefined ? this.internalMin : Math.max(...internalValues);\n const startPercent = getPercentage(internalRangeMin, this.internalMin, this.internalMax);\n const endPercent = getPercentage(internalRangeMax, this.internalMin, this.internalMax);\n\n if (this.orientation === 'horizontal') {\n return htmlSafe(`left: ${startPercent}%; right: ${100 - endPercent}%`);\n } else {\n return htmlSafe(`bottom: ${startPercent}%; top: ${100 - endPercent}%`);\n }\n }\n\n updateValue = (newValues: number[]) => {\n if (this.#args.onValueChange) {\n this.#args.onValueChange(this.coerceOutput(newValues));\n }\n };\n\n commitValue = (newValues: number[]) => {\n if (this.#args.onValueCommit) {\n this.#args.onValueCommit(this.coerceOutput(newValues));\n }\n };\n\n coerceOutput(values: number[]): number | number[] {\n if (Array.isArray(this.#args.value)) return values;\n\n return values[0] ?? this.min;\n }\n\n #ensureThumbCount(count: number) {\n if (count === this.#thumbStates.length) return;\n\n if (count < this.#thumbStates.length) {\n this.#thumbStates = this.#thumbStates.slice(0, count);\n\n return;\n }\n\n const startIndex = this.#thumbStates.length;\n\n for (let index = startIndex; index < count; index++) {\n this.#thumbStates.push(new ThumbState(this, index));\n }\n }\n\n #applyThumbInternalValue(index: number, rawValue: number): number[] {\n const nextValues = [...this.internalValues];\n const stepped = clamp(\n roundToStep(rawValue, this.internalStep),\n this.internalMin,\n this.internalMax\n );\n\n let constrained = stepped;\n\n if (nextValues.length > 1) {\n const prev = nextValues[index - 1];\n const next = nextValues[index + 1];\n\n if (prev !== undefined) constrained = Math.max(constrained, prev);\n if (next !== undefined) constrained = Math.min(constrained, next);\n }\n\n nextValues[index] = constrained;\n\n return nextValues;\n }\n\n handleThumbInput = (index: number, value: number) => {\n if (this.disabled) return;\n\n const internalValues = this.#applyThumbInternalValue(index, value);\n const newValues = this.outputValuesFromInternal(internalValues);\n\n this.updateValue(newValues);\n };\n\n handleThumbChange = (index: number, value: number) => {\n if (this.disabled) return;\n\n const internalValues = this.#applyThumbInternalValue(index, value);\n const newValues = this.outputValuesFromInternal(internalValues);\n\n this.updateValue(newValues);\n this.commitValue(newValues);\n };\n\n handleThumbActivate = (index: number) => {\n this.activeThumbIndex = index;\n };\n\n defaultThumbLabel = (index: number): string => {\n const count = this.internalValues.length;\n\n if (count <= 1) return 'Value';\n if (count === 2) return index === 0 ? 'Minimum' : 'Maximum';\n\n return `Value ${index + 1}`;\n };\n}\n"],"names":["DEFAULT_MIN","DEFAULT_MAX","DEFAULT_STEP","clamp","value","min","max","Math","roundToStep","step","Number","isFinite","round","getPercentage","range","normalizeTickValues","values","uniques","Set","add","Array","from","sort","a","b","findNearestIndex","target","length","first","undefined","nearestIndex","nearestDistance","abs","index","candidate","distance","ThumbState","constructor","slider","inputValue","ticks","tickValues","percent","thumbPercents","active","activeThumbIndex","positionStyle","thumbPositionStyle","SliderStore","g","prototype","tracked","i","getArgs","args","initialCount","isArray","_","#args","fromStep","raw","normalized","orientation","disabled","internalMin","internalMax","internalStep","internalValues","map","v","outputValuesFromInternal","internal","thumbs","isMulti","property","htmlSafe","rangeStyle","internalRangeMin","internalRangeMax","startPercent","endPercent","updateValue","newValues","onValueChange","coerceOutput","commitValue","onValueCommit","#ensureThumbCount","count","slice","startIndex","push","#applyThumbInternalValue","rawValue","nextValues","stepped","constrained","prev","next","handleThumbInput","handleThumbChange","handleThumbActivate","defaultThumbLabel"],"mappings":"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"}
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Structural styles for <Slider>.
3
+ *
4
+ * These handle the annoying parts of building a custom slider on top of
5
+ * native <input type="range"> elements:
6
+ * - stretching an invisible native input over the track (so keyboard,
7
+ * pointer, and assistive-tech behavior all come from the platform)
8
+ * - letting multiple overlapping inputs coexist (multi-thumb / range
9
+ * sliders) by routing pointer events through the native thumb only
10
+ * - vertical orientation (via `writing-mode`, no rotation hacks)
11
+ * - positioning the visual thumb and keeping the active thumb on top
12
+ *
13
+ * Appearance (colors, exact sizes) is left to the consumer.
14
+ *
15
+ * Everything is wrapped in `@layer ember-primitives`, so *any* unlayered
16
+ * consumer rule overrides these -- regardless of specificity or order.
17
+ *
18
+ * This is a plain stylesheet (bundled like any other CSS), so styles are
19
+ * present at first layout -- no waiting on a render cycle. If you render
20
+ * the slider inside a shadow root, bring this stylesheet into that root
21
+ * yourself (e.g. adopt it, or @import it in the shadow tree).
22
+ *
23
+ * Knobs:
24
+ * --ember-primitives__slider__hit-area pointer target size (default 24px)
25
+ * --ember-primitives__slider__thumb-size visual thumb size (default 16px)
26
+ * --ember-primitives__slider__track-thickness rail thickness (default 4px)
27
+ * --ember-primitives__slider__vertical-size length of a vertical slider (default 10rem)
28
+ */
29
+ @layer ember-primitives {
30
+ .ember-primitives__slider {
31
+ position: relative;
32
+ display: flex;
33
+ align-items: center;
34
+ min-height: var(--ember-primitives__slider__hit-area, 24px);
35
+ }
36
+
37
+ .ember-primitives__slider[data-orientation="vertical"] {
38
+ flex-direction: column;
39
+ min-height: 0;
40
+ min-width: var(--ember-primitives__slider__hit-area, 24px);
41
+ height: var(--ember-primitives__slider__vertical-size, 10rem);
42
+ }
43
+
44
+ .ember-primitives__slider__track {
45
+ position: relative;
46
+ flex: 1;
47
+ height: var(--ember-primitives__slider__track-thickness, 4px);
48
+ }
49
+
50
+ .ember-primitives__slider[data-orientation="vertical"] .ember-primitives__slider__track {
51
+ height: auto;
52
+ width: var(--ember-primitives__slider__track-thickness, 4px);
53
+ }
54
+
55
+ .ember-primitives__slider__range {
56
+ position: absolute;
57
+ top: 0;
58
+ bottom: 0;
59
+ }
60
+
61
+ .ember-primitives__slider[data-orientation="vertical"] .ember-primitives__slider__range {
62
+ top: auto;
63
+ bottom: auto;
64
+ left: 0;
65
+ right: 0;
66
+ }
67
+
68
+ /*
69
+ The native input is stretched across the whole track, invisible, and only
70
+ used for interaction. The visual thumb (a sibling) is what users see.
71
+ */
72
+ .ember-primitives__slider__thumb-input {
73
+ position: absolute;
74
+ left: 0;
75
+ top: 50%;
76
+ translate: 0 -50%;
77
+ width: 100%;
78
+ height: var(--ember-primitives__slider__hit-area, 24px);
79
+ margin: 0;
80
+ opacity: 0;
81
+ appearance: none;
82
+ background: transparent;
83
+ cursor: pointer;
84
+ }
85
+
86
+ .ember-primitives__slider__thumb-input:disabled {
87
+ cursor: not-allowed;
88
+ }
89
+
90
+ .ember-primitives__slider__thumb-input[data-active] {
91
+ z-index: 2;
92
+ }
93
+
94
+ /*
95
+ Size the (invisible) native thumb to the hit area, so grabbing "the thumb"
96
+ feels right. These cannot be comma-combined: an unknown pseudo-element
97
+ invalidates the whole selector list in the other engine.
98
+ */
99
+ .ember-primitives__slider__thumb-input::-webkit-slider-thumb {
100
+ appearance: none;
101
+ width: var(--ember-primitives__slider__hit-area, 24px);
102
+ height: var(--ember-primitives__slider__hit-area, 24px);
103
+ }
104
+
105
+ .ember-primitives__slider__thumb-input::-moz-range-thumb {
106
+ border: none;
107
+ width: var(--ember-primitives__slider__hit-area, 24px);
108
+ height: var(--ember-primitives__slider__hit-area, 24px);
109
+ }
110
+
111
+ /*
112
+ Multi-thumb sliders overlap multiple full-width range inputs. If the
113
+ inputs themselves receive pointer events, the top-most input steals
114
+ clicks/drags from the other thumbs. Disable pointer events on the
115
+ track-sized input and re-enable them on the native thumb only.
116
+
117
+ Single-thumb sliders keep the whole input interactive, so clicking
118
+ anywhere on the track jumps to that value.
119
+ */
120
+ .ember-primitives__slider[data-multi] .ember-primitives__slider__thumb-input {
121
+ pointer-events: none;
122
+ }
123
+
124
+ .ember-primitives__slider[data-multi]
125
+ .ember-primitives__slider__thumb-input::-webkit-slider-thumb {
126
+ pointer-events: auto;
127
+ }
128
+
129
+ .ember-primitives__slider[data-multi] .ember-primitives__slider__thumb-input::-moz-range-thumb {
130
+ pointer-events: auto;
131
+ }
132
+
133
+ /*
134
+ Vertical orientation: modern engines render a native vertical range input
135
+ with `writing-mode`. `direction: rtl` puts the minimum at the bottom.
136
+ */
137
+ .ember-primitives__slider[data-orientation="vertical"] .ember-primitives__slider__thumb-input {
138
+ writing-mode: vertical-lr;
139
+ direction: rtl;
140
+ top: 0;
141
+ left: 50%;
142
+ translate: -50% 0;
143
+ width: var(--ember-primitives__slider__hit-area, 24px);
144
+ height: 100%;
145
+ }
146
+
147
+ /*
148
+ The visual thumb. The component positions it with an inline
149
+ `left`/`bottom` percentage; centering uses the `translate` property
150
+ (not `transform`) so consumer hover/active effects like
151
+ `transform: scale(1.4)` or `scale: 1.4` compose with it instead of
152
+ clobbering it.
153
+ */
154
+ .ember-primitives__slider__thumb {
155
+ position: absolute;
156
+ top: 50%;
157
+ translate: -50% -50%;
158
+ pointer-events: none;
159
+ z-index: 1;
160
+ }
161
+
162
+ .ember-primitives__slider__thumb[data-active] {
163
+ z-index: 3;
164
+ }
165
+
166
+ .ember-primitives__slider[data-orientation="vertical"] .ember-primitives__slider__thumb {
167
+ top: auto;
168
+ left: 50%;
169
+ translate: -50% 50%;
170
+ }
171
+
172
+ /*
173
+ Default appearance -- zero specificity via :where(), so any consumer rule
174
+ wins (even a layered one). Colors derive from currentColor so the slider
175
+ adapts to its context.
176
+ */
177
+ :where(.ember-primitives__slider__track) {
178
+ border-radius: calc(var(--ember-primitives__slider__track-thickness, 4px) / 2);
179
+ background: color-mix(in srgb, currentColor 20%, transparent);
180
+ }
181
+
182
+ :where(.ember-primitives__slider__range) {
183
+ border-radius: inherit;
184
+ background: currentColor;
185
+ }
186
+
187
+ :where(.ember-primitives__slider__thumb) {
188
+ width: var(--ember-primitives__slider__thumb-size, 16px);
189
+ height: var(--ember-primitives__slider__thumb-size, 16px);
190
+ border-radius: 50%;
191
+ background: currentColor;
192
+ }
193
+
194
+ :where(.ember-primitives__slider__thumb[data-disabled]) {
195
+ opacity: 0.5;
196
+ }
197
+
198
+ /* Keyboard focus is on the (invisible) input; reflect it on the visual thumb. */
199
+ :where(.ember-primitives__slider__thumb-input:focus-visible + .ember-primitives__slider__thumb) {
200
+ outline: 2px solid currentColor;
201
+ outline-offset: 2px;
202
+ }
203
+ }
@@ -0,0 +1,88 @@
1
+ import "./slider.css"
2
+ import Component from '@glimmer/component';
3
+ import { hash } from '@ember/helper';
4
+ import { on } from '@ember/modifier';
5
+ import { SliderStore } from './slider/store.js';
6
+ import { precompileTemplate } from '@ember/template-compilation';
7
+ import { setComponentTemplate } from '@ember/component';
8
+ import templateOnly from '@ember/component/template-only';
9
+
10
+ ;
11
+
12
+ const Track = setComponentTemplate(precompileTemplate("<span ...attributes class=\"ember-primitives__slider__track\">\n {{yield}}\n</span>", {
13
+ strictMode: true
14
+ }), templateOnly());
15
+ const Range = setComponentTemplate(precompileTemplate("<span ...attributes class=\"ember-primitives__slider__range\" style={{@rangeStyle}} />", {
16
+ strictMode: true
17
+ }), templateOnly());
18
+ class ThumbComponent extends Component {
19
+ get index() {
20
+ return this.args.thumb?.index ?? this.args.index ?? 0;
21
+ }
22
+ get value() {
23
+ // When using tick values, the `input` needs the internal index.
24
+ return this.args.thumb?.inputValue ?? this.args.value ?? this.args.store.internalMin;
25
+ }
26
+ get isActive() {
27
+ return this.args.store.activeThumbIndex === this.index;
28
+ }
29
+ get positionStyle() {
30
+ const percent = this.args.thumb?.percent ?? this.args.store.thumbPercents[this.index] ?? 0;
31
+ return this.args.store.thumbPositionStyle(percent);
32
+ }
33
+ readValue(event) {
34
+ // In docs live previews the component may run in an iframe/shadow realm,
35
+ // where `instanceof HTMLInputElement` is not reliable. `currentTarget` is
36
+ // the element the handler is attached to.
37
+ const el = event.currentTarget;
38
+ const raw = el?.value;
39
+ const parsed = raw === undefined ? NaN : Number.parseFloat(raw);
40
+ return Number.isFinite(parsed) ? parsed : this.value;
41
+ }
42
+ onInput = event => {
43
+ this.args.store.handleThumbActivate(this.index);
44
+ this.args.store.handleThumbInput(this.index, this.readValue(event));
45
+ };
46
+ onChange = event => {
47
+ this.args.store.handleThumbActivate(this.index);
48
+ this.args.store.handleThumbChange(this.index, this.readValue(event));
49
+ };
50
+ onPointerUp = () => {
51
+ this.args.store.handleThumbActivate(this.index);
52
+ };
53
+ onGotPointerCapture = () => {
54
+ this.args.store.handleThumbActivate(this.index);
55
+ };
56
+ onFocus = () => {
57
+ this.args.store.handleThumbActivate(this.index);
58
+ };
59
+ static {
60
+ setComponentTemplate(precompileTemplate("<input ...attributes class=\"ember-primitives__slider__thumb-input\" type=\"range\" min={{@store.internalMin}} max={{@store.internalMax}} step={{@store.internalStep}} value={{this.value}} disabled={{@store.disabled}} data-active={{if this.isActive \"\"}} {{on \"gotpointercapture\" this.onGotPointerCapture}} {{on \"pointerup\" this.onPointerUp}} {{on \"focus\" this.onFocus}} {{on \"input\" this.onInput}} {{on \"change\" this.onChange}} />\n<span class=\"ember-primitives__slider__thumb\" style={{this.positionStyle}} data-active={{if this.isActive \"\"}} data-disabled={{if @store.disabled \"\"}} aria-hidden=\"true\">{{yield}}</span>", {
61
+ strictMode: true,
62
+ scope: () => ({
63
+ on
64
+ })
65
+ }), this);
66
+ }
67
+ }
68
+ class Slider extends Component {
69
+ store;
70
+ constructor(owner, args) {
71
+ super(owner, args);
72
+ this.store = new SliderStore(() => this.args);
73
+ }
74
+ static {
75
+ setComponentTemplate(precompileTemplate("<span ...attributes class=\"ember-primitives__slider\" data-orientation={{this.store.orientation}} data-disabled={{if this.store.disabled \"\"}} data-multi={{if this.store.isMulti \"\"}}>\n {{#if (has-block)}}\n {{yield (hash Track=Track Range=(component Range rangeStyle=this.store.rangeStyle) Thumb=(component ThumbComponent store=this.store) values=this.store.values tickValues=this.store.tickValues thumbs=this.store.thumbs min=this.store.min max=this.store.max step=this.store.step)}}\n {{else}}\n <Track>\n <Range @rangeStyle={{this.store.rangeStyle}} />\n\n {{#each this.store.thumbs as |thumb|}}\n <ThumbComponent @store={{this.store}} @thumb={{thumb}} aria-label={{this.store.defaultThumbLabel thumb.index}} />\n {{/each}}\n </Track>\n {{/if}}\n</span>", {
76
+ strictMode: true,
77
+ scope: () => ({
78
+ hash,
79
+ Track,
80
+ Range,
81
+ ThumbComponent
82
+ })
83
+ }), this);
84
+ }
85
+ }
86
+
87
+ export { Slider, Slider as default };
88
+ //# sourceMappingURL=slider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slider.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ export { R as Rating } from './rating-BrIiwDLw.js';
20
20
  export { Scroller } from './components/scroller.js';
21
21
  export { Separator } from './components/separator.js';
22
22
  export { Shadowed } from './components/shadowed.js';
23
+ export { Slider } from './components/slider.js';
23
24
  export { Switch } from './components/switch.js';
24
25
  export { Toggle } from './components/toggle.js';
25
26
  export { ToggleGroup } from './components/toggle-group.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * DANGER: this is a *barrel file*\n *\n * It forces the whole library to be loaded and all dependencies.\n *\n * If you have a small app, you probably don't want to import from here -- instead import from each sub-path.\n */\nimport { importSync, isDevelopingApp, macroCondition } from '@embroider/macros';\n\nif (macroCondition(isDevelopingApp())) {\n importSync('./components/violations.css');\n}\n\nexport { Accordion } from './components/accordion.gts';\nexport type {\n AccordionContentExternalSignature,\n AccordionHeaderExternalSignature,\n AccordionItemExternalSignature,\n AccordionTriggerExternalSignature,\n} from './components/accordion/public.ts';\nexport { Avatar } from './components/avatar.gts';\nexport { Breadcrumb } from './components/breadcrumb.gts';\nexport { Dialog, Dialog as Modal } from './components/dialog.gts';\nexport { Drawer } from './components/drawer.gts';\nexport { ExternalLink } from './components/external-link.gts';\nexport { Form } from './components/form.gts';\nexport { IncrementalEach } from './components/incremental-each.gts';\nexport { Key, KeyCombo } from './components/keys.gts';\nexport { StickyFooter } from './components/layout/sticky-footer.gts';\nexport { Link } from './components/link.gts';\nexport { Menu } from './components/menu.gts';\nexport { OTP, OTPInput } from './components/one-time-password.gts';\nexport { Popover } from './components/popover.gts';\nexport { Portal } from './components/portal.gts';\nexport { PortalTargets } from './components/portal-targets.gts';\nexport { TARGETS as PORTALS } from './components/portal-targets.gts';\nexport { Progress } from './components/progress.gts';\nexport { Rating } from './components/rating.gts';\nexport { Scroller } from './components/scroller.gts';\nexport { Separator } from './components/separator.gts';\nexport { Shadowed } from './components/shadowed.gts';\nexport { Switch } from './components/switch.gts';\nexport { Toggle } from './components/toggle.gts';\nexport { ToggleGroup } from './components/toggle-group.gts';\nexport { VisuallyHidden } from './components/visually-hidden.gts';\nexport { Zoetrope } from './components/zoetrope.ts';\nexport * from './helpers.ts';\n"],"names":["macroCondition","isDevelopingApp","importSync"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA,IAAIA,cAAc,CAACC,eAAe,EAAE,CAAC,EAAE;EACrCC,UAAU,CAAC,6BAA6B,CAAC;AAC3C"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * DANGER: this is a *barrel file*\n *\n * It forces the whole library to be loaded and all dependencies.\n *\n * If you have a small app, you probably don't want to import from here -- instead import from each sub-path.\n */\nimport { importSync, isDevelopingApp, macroCondition } from '@embroider/macros';\n\nif (macroCondition(isDevelopingApp())) {\n importSync('./components/violations.css');\n}\n\nexport { Accordion } from './components/accordion.gts';\nexport type {\n AccordionContentExternalSignature,\n AccordionHeaderExternalSignature,\n AccordionItemExternalSignature,\n AccordionTriggerExternalSignature,\n} from './components/accordion/public.ts';\nexport { Avatar } from './components/avatar.gts';\nexport { Breadcrumb } from './components/breadcrumb.gts';\nexport { Dialog, Dialog as Modal } from './components/dialog.gts';\nexport { Drawer } from './components/drawer.gts';\nexport { ExternalLink } from './components/external-link.gts';\nexport { Form } from './components/form.gts';\nexport { IncrementalEach } from './components/incremental-each.gts';\nexport { Key, KeyCombo } from './components/keys.gts';\nexport { StickyFooter } from './components/layout/sticky-footer.gts';\nexport { Link } from './components/link.gts';\nexport { Menu } from './components/menu.gts';\nexport { OTP, OTPInput } from './components/one-time-password.gts';\nexport { Popover } from './components/popover.gts';\nexport { Portal } from './components/portal.gts';\nexport { PortalTargets } from './components/portal-targets.gts';\nexport { TARGETS as PORTALS } from './components/portal-targets.gts';\nexport { Progress } from './components/progress.gts';\nexport { Rating } from './components/rating.gts';\nexport { Scroller } from './components/scroller.gts';\nexport { Separator } from './components/separator.gts';\nexport { Shadowed } from './components/shadowed.gts';\nexport { Slider } from './components/slider.gts';\nexport { Switch } from './components/switch.gts';\nexport { Toggle } from './components/toggle.gts';\nexport { ToggleGroup } from './components/toggle-group.gts';\nexport { VisuallyHidden } from './components/visually-hidden.gts';\nexport { Zoetrope } from './components/zoetrope.ts';\nexport * from './helpers.ts';\n"],"names":["macroCondition","isDevelopingApp","importSync"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA,IAAIA,cAAc,CAACC,eAAe,EAAE,CAAC,EAAE;EACrCC,UAAU,CAAC,6BAA6B,CAAC;AAC3C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-primitives",
3
- "version": "0.59.0",
3
+ "version": "0.60.0",
4
4
  "description": "Making apps easier to build",
5
5
  "keywords": [
6
6
  "ember-addon"
@@ -20,7 +20,7 @@
20
20
  "@babel/runtime": "^7.28.6",
21
21
  "@embroider/addon-shim": "^1.10.2",
22
22
  "@floating-ui/dom": "^1.7.5",
23
- "decorator-transforms": "2.3.1",
23
+ "decorator-transforms": "2.3.2",
24
24
  "ember-element-helper": "^0.8.8",
25
25
  "form-data-utils": "^0.6.0",
26
26
  "reactiveweb": "^1.9.1",
@@ -28,7 +28,7 @@
28
28
  "tabster": "^8.7.0",
29
29
  "tracked-built-ins": "^4.1.0",
30
30
  "tracked-toolbox": "^3.0.0",
31
- "which-heading-do-i-need": "0.2.7"
31
+ "which-heading-do-i-need": "0.4.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@arethetypeswrong/cli": "^0.18.0",
@@ -61,6 +61,7 @@
61
61
  "ember-source": "^6.10.1",
62
62
  "ember-template-lint": "^7.9.3",
63
63
  "eslint": "^9.39.2",
64
+ "eslint-plugin-compat": "^7.0.2",
64
65
  "execa": "^9.6.0",
65
66
  "fix-bad-declaration-output": "^1.1.5",
66
67
  "prettier": "^3.8.1",
@@ -121,6 +122,12 @@
121
122
  "ember-modifier": ">= 4.1.0",
122
123
  "ember-resources": ">= 6.1.0"
123
124
  },
125
+ "browserslist": [
126
+ "last 2 Chrome versions",
127
+ "last 2 Firefox versions",
128
+ "last 2 Safari versions",
129
+ "last 2 Edge versions"
130
+ ],
124
131
  "peerDependenciesMeta": {
125
132
  "@ember/test-helpers": {
126
133
  "optional": true