@spectrum-web-components/slider 0.12.6 → 0.12.7-express.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/package.json +3 -3
- package/sp-slider-handle.d.ts +6 -0
- package/sp-slider-handle.js +14 -0
- package/sp-slider-handle.js.map +1 -0
- package/sp-slider.d.ts +7 -0
- package/sp-slider.js +15 -0
- package/sp-slider.js.map +1 -0
- package/src/HandleController.d.ts +110 -0
- package/src/HandleController.js +470 -0
- package/src/HandleController.js.map +1 -0
- package/src/Slider.d.ts +68 -0
- package/src/Slider.js +370 -0
- package/src/Slider.js.map +1 -0
- package/src/SliderHandle.d.ts +57 -0
- package/src/SliderHandle.js +192 -0
- package/src/SliderHandle.js.map +1 -0
- package/src/index.d.ts +3 -0
- package/src/index.js +15 -0
- package/src/index.js.map +1 -0
- package/src/slider.css.d.ts +2 -0
- package/src/slider.css.js +203 -0
- package/src/slider.css.js.map +1 -0
- package/src/spectrum-slider.css.d.ts +2 -0
- package/src/spectrum-slider.css.js +189 -0
- package/src/spectrum-slider.css.js.map +1 -0
- package/stories/slider.stories.js +699 -0
- package/stories/slider.stories.js.map +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spectrum-web-components/slider",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.7-express.0+7a2be85d7",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@spectrum-web-components/field-label": "^0.7.5",
|
|
54
54
|
"@spectrum-web-components/number-field": "^0.3.6",
|
|
55
55
|
"@spectrum-web-components/shared": "^0.13.5",
|
|
56
|
-
"@spectrum-web-components/theme": "^0.10.0",
|
|
56
|
+
"@spectrum-web-components/theme": "^0.10.1-express.0+7a2be85d7",
|
|
57
57
|
"tslib": "^2.0.0"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"./sp-*.js",
|
|
66
66
|
"./sync/sp-*.js"
|
|
67
67
|
],
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "7a2be85d7e231dcf4141a86b7056f6c139a43851"
|
|
69
69
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2021 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
import { SliderHandle } from './src/SliderHandle.js';
|
|
13
|
+
customElements.define('sp-slider-handle', SliderHandle);
|
|
14
|
+
//# sourceMappingURL=sp-slider-handle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sp-slider-handle.js","sourceRoot":"","sources":["sp-slider-handle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;EAUE;AACF,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,cAAc,CAAC,MAAM,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC","sourcesContent":["/*\nCopyright 2021 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\nimport { SliderHandle } from './src/SliderHandle.js';\n\ncustomElements.define('sp-slider-handle', SliderHandle);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sp-slider-handle': SliderHandle;\n }\n}\n"]}
|
package/sp-slider.d.ts
ADDED
package/sp-slider.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
import './sp-slider-handle.js'; // codify sp-slider's implicit dependency on sp-slider-handle
|
|
13
|
+
import { Slider } from './src/Slider.js';
|
|
14
|
+
customElements.define('sp-slider', Slider);
|
|
15
|
+
//# sourceMappingURL=sp-slider.js.map
|
package/sp-slider.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sp-slider.js","sourceRoot":"","sources":["sp-slider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;EAUE;AACF,OAAO,uBAAuB,CAAC,CAAC,6DAA6D;AAC7F,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,cAAc,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC","sourcesContent":["/*\nCopyright 2020 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\nimport './sp-slider-handle.js'; // codify sp-slider's implicit dependency on sp-slider-handle\nimport { Slider } from './src/Slider.js';\n\ncustomElements.define('sp-slider', Slider);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sp-slider': Slider;\n }\n}\n"]}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { TemplateResult } from '@spectrum-web-components/base';
|
|
2
|
+
import { Slider } from './Slider.js';
|
|
3
|
+
import { Controller, SliderHandle, SliderNormalization } from './SliderHandle.js';
|
|
4
|
+
interface RangeAndClamp {
|
|
5
|
+
range: {
|
|
6
|
+
min: number;
|
|
7
|
+
max: number;
|
|
8
|
+
};
|
|
9
|
+
clamp: {
|
|
10
|
+
min: number;
|
|
11
|
+
max: number;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
interface ModelValue extends RangeAndClamp {
|
|
15
|
+
name: string;
|
|
16
|
+
value: number;
|
|
17
|
+
normalizedValue: number;
|
|
18
|
+
step: number;
|
|
19
|
+
highlight: boolean;
|
|
20
|
+
ariaLabel?: string;
|
|
21
|
+
normalization: SliderNormalization;
|
|
22
|
+
handle: SliderHandle;
|
|
23
|
+
}
|
|
24
|
+
interface InputWithModel extends HTMLInputElement {
|
|
25
|
+
model: ModelValue;
|
|
26
|
+
}
|
|
27
|
+
interface DataFromPointerEvent {
|
|
28
|
+
resolvedInput: boolean;
|
|
29
|
+
input: InputWithModel;
|
|
30
|
+
model?: ModelValue;
|
|
31
|
+
}
|
|
32
|
+
export interface HandleValueDictionary {
|
|
33
|
+
[key: string]: number;
|
|
34
|
+
}
|
|
35
|
+
export declare class HandleController implements Controller {
|
|
36
|
+
private observer;
|
|
37
|
+
private host;
|
|
38
|
+
private handles;
|
|
39
|
+
private model;
|
|
40
|
+
private handleOrder;
|
|
41
|
+
private draggingHandle?;
|
|
42
|
+
private handleRefMap?;
|
|
43
|
+
constructor(host: Slider);
|
|
44
|
+
get values(): HandleValueDictionary;
|
|
45
|
+
get size(): number;
|
|
46
|
+
inputForHandle(handle: SliderHandle): HTMLInputElement | undefined;
|
|
47
|
+
requestUpdate(): void;
|
|
48
|
+
/**
|
|
49
|
+
* It is possible for value attributes to be set programmatically. The <input>
|
|
50
|
+
* for a particular slider needs to have an opportunity to validate any such
|
|
51
|
+
* values
|
|
52
|
+
*
|
|
53
|
+
* @param handle Handle who's value needs validation
|
|
54
|
+
*/
|
|
55
|
+
setValueFromHandle(handle: SliderHandle): void;
|
|
56
|
+
handleHasChanged(handle: SliderHandle): void;
|
|
57
|
+
formattedValueForHandle(model: ModelValue): string;
|
|
58
|
+
get formattedValues(): Map<string, string>;
|
|
59
|
+
get focusElement(): HTMLElement;
|
|
60
|
+
protected handleOrientation: () => void;
|
|
61
|
+
hostConnected(): void;
|
|
62
|
+
hostDisconnected(): void;
|
|
63
|
+
hostUpdate(): void;
|
|
64
|
+
private waitForUpgrade;
|
|
65
|
+
private extractModelFromLightDom;
|
|
66
|
+
get activeHandle(): string;
|
|
67
|
+
get activeHandleInputId(): string;
|
|
68
|
+
activateHandle(name: string): void;
|
|
69
|
+
private getActiveHandleElements;
|
|
70
|
+
private getHandleElements;
|
|
71
|
+
private clearHandleComponentCache;
|
|
72
|
+
private _boundingClientRect?;
|
|
73
|
+
private get boundingClientRect();
|
|
74
|
+
private updateBoundingRect;
|
|
75
|
+
/**
|
|
76
|
+
* Return the `input` and `model` associated with the event and
|
|
77
|
+
* whether the `input` is a `resolvedInput` meaning it was acquired
|
|
78
|
+
* from the `model` rather than the event.
|
|
79
|
+
*/
|
|
80
|
+
protected extractDataFromEvent(event: PointerEvent): DataFromPointerEvent;
|
|
81
|
+
private _activePointerEventData;
|
|
82
|
+
handlePointerdown(event: PointerEvent): void;
|
|
83
|
+
handlePointerup(event: PointerEvent): void;
|
|
84
|
+
handlePointermove(event: PointerEvent): void;
|
|
85
|
+
/**
|
|
86
|
+
* Keep the slider value property in sync with the input element's value
|
|
87
|
+
*/
|
|
88
|
+
private onInputChange;
|
|
89
|
+
private onInputFocus;
|
|
90
|
+
private onInputBlur;
|
|
91
|
+
private onInputKeydown;
|
|
92
|
+
private dispatchChangeEvent;
|
|
93
|
+
/**
|
|
94
|
+
* Returns the value under the cursor
|
|
95
|
+
* @param: PointerEvent on slider
|
|
96
|
+
* @return: Slider value that correlates to the position under the pointer
|
|
97
|
+
*/
|
|
98
|
+
private calculateHandlePosition;
|
|
99
|
+
renderHandle(model: ModelValue, index: number, zIndex: number, isMultiHandle: boolean): TemplateResult;
|
|
100
|
+
render(): TemplateResult[];
|
|
101
|
+
/**
|
|
102
|
+
* Returns a list of track segment [start, end] tuples where the values are
|
|
103
|
+
* normalized to be between 0 and 1.
|
|
104
|
+
* @returns A list of track segment tuples [start, end]
|
|
105
|
+
*/
|
|
106
|
+
trackSegments(): [number, number][];
|
|
107
|
+
private updateModel;
|
|
108
|
+
handleUpdatesComplete(): Promise<void>;
|
|
109
|
+
}
|
|
110
|
+
export {};
|
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2021 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
import { html } from '@spectrum-web-components/base';
|
|
13
|
+
import { classMap, ifDefined, styleMap, } from '@spectrum-web-components/base/src/directives.js';
|
|
14
|
+
import { SliderHandle, } from './SliderHandle.js';
|
|
15
|
+
export class HandleController {
|
|
16
|
+
constructor(host) {
|
|
17
|
+
this.handles = new Map();
|
|
18
|
+
this.model = [];
|
|
19
|
+
this.handleOrder = [];
|
|
20
|
+
this.handleOrientation = () => {
|
|
21
|
+
this.updateBoundingRect();
|
|
22
|
+
};
|
|
23
|
+
this.extractModelFromLightDom = () => {
|
|
24
|
+
let handles = [
|
|
25
|
+
...this.host.querySelectorAll('[slot="handle"]'),
|
|
26
|
+
];
|
|
27
|
+
if (handles.length === 0) {
|
|
28
|
+
handles = [this.host];
|
|
29
|
+
}
|
|
30
|
+
// extractModelFromLightDom depends on slotted handles already having been upgraded
|
|
31
|
+
if (handles.some((h) => this.waitForUpgrade(h))) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
this.handles = new Map();
|
|
35
|
+
this.handleOrder = [];
|
|
36
|
+
handles.forEach((handle, index) => {
|
|
37
|
+
var _a;
|
|
38
|
+
/* c8 ignore next */
|
|
39
|
+
if (!((_a = handle.handleName) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
40
|
+
handle.name = `handle${index + 1}`;
|
|
41
|
+
}
|
|
42
|
+
this.handles.set(handle.handleName, handle);
|
|
43
|
+
this.handleOrder.push(handle.handleName);
|
|
44
|
+
handle.handleController = this;
|
|
45
|
+
});
|
|
46
|
+
this.requestUpdate();
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Keep the slider value property in sync with the input element's value
|
|
50
|
+
*/
|
|
51
|
+
this.onInputChange = (event) => {
|
|
52
|
+
const input = event.target;
|
|
53
|
+
input.model.handle.value = input.valueAsNumber;
|
|
54
|
+
this.requestUpdate();
|
|
55
|
+
this.dispatchChangeEvent(input, input.model.handle);
|
|
56
|
+
};
|
|
57
|
+
this.onInputFocus = (event) => {
|
|
58
|
+
const input = event.target;
|
|
59
|
+
let isFocusVisible;
|
|
60
|
+
try {
|
|
61
|
+
isFocusVisible =
|
|
62
|
+
input.matches(':focus-visible') ||
|
|
63
|
+
this.host.matches('.focus-visible');
|
|
64
|
+
/* c8 ignore next 3 */
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
isFocusVisible = this.host.matches('.focus-visible');
|
|
68
|
+
}
|
|
69
|
+
input.model.handle.highlight = isFocusVisible;
|
|
70
|
+
this.requestUpdate();
|
|
71
|
+
};
|
|
72
|
+
this.onInputBlur = (event) => {
|
|
73
|
+
const input = event.target;
|
|
74
|
+
input.model.handle.highlight = false;
|
|
75
|
+
this.requestUpdate();
|
|
76
|
+
};
|
|
77
|
+
this.onInputKeydown = (event) => {
|
|
78
|
+
const input = event.target;
|
|
79
|
+
input.model.handle.highlight = true;
|
|
80
|
+
this.requestUpdate();
|
|
81
|
+
};
|
|
82
|
+
this.host = host;
|
|
83
|
+
}
|
|
84
|
+
get values() {
|
|
85
|
+
const result = {};
|
|
86
|
+
for (const model of this.handles.values()) {
|
|
87
|
+
result[model.handleName] = model.value;
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
get size() {
|
|
92
|
+
return this.handles.size;
|
|
93
|
+
}
|
|
94
|
+
inputForHandle(handle) {
|
|
95
|
+
if (this.handles.has(handle.handleName)) {
|
|
96
|
+
const { input } = this.getHandleElements(handle);
|
|
97
|
+
return input;
|
|
98
|
+
}
|
|
99
|
+
/* c8 ignore next 2 */
|
|
100
|
+
throw new Error(`No input for handle "${handle.name}"`);
|
|
101
|
+
}
|
|
102
|
+
requestUpdate() {
|
|
103
|
+
this.host.requestUpdate();
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* It is possible for value attributes to be set programmatically. The <input>
|
|
107
|
+
* for a particular slider needs to have an opportunity to validate any such
|
|
108
|
+
* values
|
|
109
|
+
*
|
|
110
|
+
* @param handle Handle who's value needs validation
|
|
111
|
+
*/
|
|
112
|
+
setValueFromHandle(handle) {
|
|
113
|
+
const elements = this.getHandleElements(handle);
|
|
114
|
+
/* c8 ignore next */
|
|
115
|
+
if (!elements)
|
|
116
|
+
return;
|
|
117
|
+
const { input } = elements;
|
|
118
|
+
if (input.valueAsNumber === handle.value) {
|
|
119
|
+
if (handle.dragging) {
|
|
120
|
+
handle.dispatchInputEvent();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
input.valueAsNumber = handle.value;
|
|
125
|
+
handle.value = input.valueAsNumber;
|
|
126
|
+
this.requestUpdate();
|
|
127
|
+
}
|
|
128
|
+
handle.value = input.valueAsNumber;
|
|
129
|
+
}
|
|
130
|
+
handleHasChanged(handle) {
|
|
131
|
+
if (handle !== this.host) {
|
|
132
|
+
this.requestUpdate();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
formattedValueForHandle(model) {
|
|
136
|
+
var _a;
|
|
137
|
+
const { handle } = model;
|
|
138
|
+
const numberFormat = (_a = handle.numberFormat) !== null && _a !== void 0 ? _a : this.host.numberFormat;
|
|
139
|
+
return handle.getAriaHandleText(model.value, numberFormat);
|
|
140
|
+
}
|
|
141
|
+
get formattedValues() {
|
|
142
|
+
const result = new Map();
|
|
143
|
+
for (const model of this.model) {
|
|
144
|
+
result.set(model.name, this.formattedValueForHandle(model));
|
|
145
|
+
}
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
get focusElement() {
|
|
149
|
+
const { input } = this.getActiveHandleElements();
|
|
150
|
+
if (this.host.editable &&
|
|
151
|
+
!input.model.handle.dragging) {
|
|
152
|
+
return this.host.numberField;
|
|
153
|
+
}
|
|
154
|
+
return input;
|
|
155
|
+
}
|
|
156
|
+
hostConnected() {
|
|
157
|
+
if (!this.observer) {
|
|
158
|
+
this.observer = new MutationObserver(this.extractModelFromLightDom);
|
|
159
|
+
}
|
|
160
|
+
this.observer.observe(this.host, { subtree: true, childList: true });
|
|
161
|
+
this.extractModelFromLightDom();
|
|
162
|
+
if ('orientation' in screen) {
|
|
163
|
+
screen.orientation.addEventListener('change', this.handleOrientation);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
window.addEventListener('orientationchange', this.handleOrientation);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
hostDisconnected() {
|
|
170
|
+
this.observer.disconnect();
|
|
171
|
+
if ('orientation' in screen) {
|
|
172
|
+
screen.orientation.removeEventListener('change', this.handleOrientation);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
window.removeEventListener('orientationchange', this.handleOrientation);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
hostUpdate() {
|
|
179
|
+
this.updateModel();
|
|
180
|
+
}
|
|
181
|
+
// Since extractModelFromLightDom bails on the first un-upgraded handle,
|
|
182
|
+
// a maximum of one listener will be set up per extraction attempt.
|
|
183
|
+
waitForUpgrade(handle) {
|
|
184
|
+
if (handle instanceof SliderHandle) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
handle.addEventListener('sp-slider-handle-ready', () => this.extractModelFromLightDom(), { once: true, passive: true });
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
get activeHandle() {
|
|
191
|
+
return this.handleOrder[this.handleOrder.length - 1];
|
|
192
|
+
}
|
|
193
|
+
get activeHandleInputId() {
|
|
194
|
+
const active = this.activeHandle;
|
|
195
|
+
const index = this.model.findIndex((model) => model.name === active);
|
|
196
|
+
return `input-${index}`;
|
|
197
|
+
}
|
|
198
|
+
activateHandle(name) {
|
|
199
|
+
const index = this.handleOrder.findIndex((item) => item === name);
|
|
200
|
+
if (index >= 0) {
|
|
201
|
+
this.handleOrder.splice(index, 1);
|
|
202
|
+
}
|
|
203
|
+
this.handleOrder.push(name);
|
|
204
|
+
}
|
|
205
|
+
getActiveHandleElements() {
|
|
206
|
+
const name = this.activeHandle;
|
|
207
|
+
const handleSlider = this.handles.get(name);
|
|
208
|
+
const elements = this.getHandleElements(handleSlider);
|
|
209
|
+
return Object.assign({ model: handleSlider }, elements);
|
|
210
|
+
}
|
|
211
|
+
getHandleElements(sliderHandle) {
|
|
212
|
+
if (!this.handleRefMap) {
|
|
213
|
+
this.handleRefMap = new WeakMap();
|
|
214
|
+
const inputNodes = this.host.shadowRoot.querySelectorAll('.handle > input');
|
|
215
|
+
for (const inputNode of inputNodes) {
|
|
216
|
+
const input = inputNode;
|
|
217
|
+
const handle = input.parentElement;
|
|
218
|
+
const model = this.handles.get(handle.getAttribute('name'));
|
|
219
|
+
if (model) {
|
|
220
|
+
this.handleRefMap.set(model, { input, handle });
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const components = this.handleRefMap.get(sliderHandle);
|
|
225
|
+
return components;
|
|
226
|
+
}
|
|
227
|
+
clearHandleComponentCache() {
|
|
228
|
+
delete this.handleRefMap;
|
|
229
|
+
}
|
|
230
|
+
get boundingClientRect() {
|
|
231
|
+
if (!this._boundingClientRect) {
|
|
232
|
+
this._boundingClientRect = this.host.track.getBoundingClientRect();
|
|
233
|
+
}
|
|
234
|
+
return this._boundingClientRect;
|
|
235
|
+
}
|
|
236
|
+
updateBoundingRect() {
|
|
237
|
+
delete this._boundingClientRect;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Return the `input` and `model` associated with the event and
|
|
241
|
+
* whether the `input` is a `resolvedInput` meaning it was acquired
|
|
242
|
+
* from the `model` rather than the event.
|
|
243
|
+
*/
|
|
244
|
+
extractDataFromEvent(event) {
|
|
245
|
+
if (!this._activePointerEventData) {
|
|
246
|
+
let input = event.target.querySelector(':scope > .input');
|
|
247
|
+
const resolvedInput = !input;
|
|
248
|
+
const model = input
|
|
249
|
+
? input.model
|
|
250
|
+
: this.model.find((item) => item.name === this.activeHandle);
|
|
251
|
+
if (!input && !!model) {
|
|
252
|
+
input = model.handle.focusElement;
|
|
253
|
+
}
|
|
254
|
+
this._activePointerEventData = {
|
|
255
|
+
input,
|
|
256
|
+
model,
|
|
257
|
+
resolvedInput,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
return this._activePointerEventData;
|
|
261
|
+
}
|
|
262
|
+
handlePointerdown(event) {
|
|
263
|
+
const { resolvedInput, model } = this.extractDataFromEvent(event);
|
|
264
|
+
if (!model || this.host.disabled || event.button !== 0) {
|
|
265
|
+
event.preventDefault();
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
this.host.track.setPointerCapture(event.pointerId);
|
|
269
|
+
this.updateBoundingRect();
|
|
270
|
+
this.host.labelEl.click();
|
|
271
|
+
this.draggingHandle = model.handle;
|
|
272
|
+
model.handle.dragging = true;
|
|
273
|
+
this.activateHandle(model.name);
|
|
274
|
+
if (resolvedInput) {
|
|
275
|
+
// When the input is resolved forward the pointer event to
|
|
276
|
+
// `handlePointermove` in order to update the value/UI becuase
|
|
277
|
+
// the pointer event was on the track not a handle
|
|
278
|
+
this.handlePointermove(event);
|
|
279
|
+
}
|
|
280
|
+
this.requestUpdate();
|
|
281
|
+
}
|
|
282
|
+
handlePointerup(event) {
|
|
283
|
+
const { input, model } = this.extractDataFromEvent(event);
|
|
284
|
+
delete this._activePointerEventData;
|
|
285
|
+
if (!model)
|
|
286
|
+
return;
|
|
287
|
+
this.host.labelEl.click();
|
|
288
|
+
model.handle.highlight = false;
|
|
289
|
+
delete this.draggingHandle;
|
|
290
|
+
model.handle.dragging = false;
|
|
291
|
+
this.requestUpdate();
|
|
292
|
+
this.host.track.releasePointerCapture(event.pointerId);
|
|
293
|
+
this.dispatchChangeEvent(input, model.handle);
|
|
294
|
+
}
|
|
295
|
+
handlePointermove(event) {
|
|
296
|
+
const { input, model } = this.extractDataFromEvent(event);
|
|
297
|
+
if (!model)
|
|
298
|
+
return;
|
|
299
|
+
/* c8 ignore next 3 */
|
|
300
|
+
if (!this.draggingHandle) {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
event.stopPropagation();
|
|
304
|
+
input.value = this.calculateHandlePosition(event, model).toString();
|
|
305
|
+
model.handle.value = parseFloat(input.value);
|
|
306
|
+
this.requestUpdate();
|
|
307
|
+
}
|
|
308
|
+
dispatchChangeEvent(input, handle) {
|
|
309
|
+
input.valueAsNumber = handle.value;
|
|
310
|
+
const changeEvent = new Event('change', {
|
|
311
|
+
bubbles: true,
|
|
312
|
+
composed: true,
|
|
313
|
+
});
|
|
314
|
+
handle.dispatchEvent(changeEvent);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Returns the value under the cursor
|
|
318
|
+
* @param: PointerEvent on slider
|
|
319
|
+
* @return: Slider value that correlates to the position under the pointer
|
|
320
|
+
*/
|
|
321
|
+
calculateHandlePosition(event, model) {
|
|
322
|
+
const rect = this.boundingClientRect;
|
|
323
|
+
const minOffset = rect.left;
|
|
324
|
+
const offset = event.clientX;
|
|
325
|
+
const size = rect.width;
|
|
326
|
+
const normalized = (offset - minOffset) / size;
|
|
327
|
+
const value = model.normalization.fromNormalized(normalized, model.range.min, model.range.max);
|
|
328
|
+
/* c8 ignore next */
|
|
329
|
+
return this.host.isLTR ? value : model.range.max - value;
|
|
330
|
+
}
|
|
331
|
+
renderHandle(model, index, zIndex, isMultiHandle) {
|
|
332
|
+
var _a;
|
|
333
|
+
const classes = {
|
|
334
|
+
handle: true,
|
|
335
|
+
dragging: ((_a = this.draggingHandle) === null || _a === void 0 ? void 0 : _a.handleName) === model.name,
|
|
336
|
+
'handle-highlight': model.highlight,
|
|
337
|
+
};
|
|
338
|
+
const style = {
|
|
339
|
+
[this.host.isLTR ? 'left' : 'right']: `${model.normalizedValue * 100}%`,
|
|
340
|
+
'z-index': zIndex.toString(),
|
|
341
|
+
// Allow setting background per-handle
|
|
342
|
+
'background-color': `var(--spectrum-slider-handle-background-color-${index}, var(--spectrum-slider-handle-default-background-color))`,
|
|
343
|
+
'border-color': `var(--spectrum-slider-handle-border-color-${index}, var(-spectrum-slider-handle-default-border-color))`,
|
|
344
|
+
};
|
|
345
|
+
const ariaLabelledBy = isMultiHandle ? `label input-${index}` : 'label';
|
|
346
|
+
return html `
|
|
347
|
+
<div
|
|
348
|
+
class=${classMap(classes)}
|
|
349
|
+
name=${model.name}
|
|
350
|
+
style=${styleMap(style)}
|
|
351
|
+
role="presentation"
|
|
352
|
+
>
|
|
353
|
+
<input
|
|
354
|
+
type="range"
|
|
355
|
+
class="input"
|
|
356
|
+
id="input-${index}"
|
|
357
|
+
min=${model.clamp.min}
|
|
358
|
+
max=${model.clamp.max}
|
|
359
|
+
step=${model.step}
|
|
360
|
+
value=${model.value}
|
|
361
|
+
aria-disabled=${ifDefined(this.host.disabled ? 'true' : undefined)}
|
|
362
|
+
tabindex=${ifDefined(this.host.editable ? -1 : undefined)}
|
|
363
|
+
aria-label=${ifDefined(model.ariaLabel)}
|
|
364
|
+
aria-labelledby=${ariaLabelledBy}
|
|
365
|
+
aria-valuetext=${this.formattedValueForHandle(model)}
|
|
366
|
+
@change=${this.onInputChange}
|
|
367
|
+
@focus=${this.onInputFocus}
|
|
368
|
+
@blur=${this.onInputBlur}
|
|
369
|
+
@keydown=${this.onInputKeydown}
|
|
370
|
+
.model=${model}
|
|
371
|
+
/>
|
|
372
|
+
</div>
|
|
373
|
+
`;
|
|
374
|
+
}
|
|
375
|
+
render() {
|
|
376
|
+
this.clearHandleComponentCache();
|
|
377
|
+
return this.model.map((model, index) => {
|
|
378
|
+
const zIndex = this.handleOrder.indexOf(model.name) + 1;
|
|
379
|
+
return this.renderHandle(model, index, zIndex, this.model.length > 1);
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Returns a list of track segment [start, end] tuples where the values are
|
|
384
|
+
* normalized to be between 0 and 1.
|
|
385
|
+
* @returns A list of track segment tuples [start, end]
|
|
386
|
+
*/
|
|
387
|
+
trackSegments() {
|
|
388
|
+
const values = this.model.map((model) => model.normalizedValue);
|
|
389
|
+
values.sort((a, b) => a - b);
|
|
390
|
+
// The first segment always starts at 0
|
|
391
|
+
values.unshift(0);
|
|
392
|
+
return values.map((value, index, array) => {
|
|
393
|
+
var _a;
|
|
394
|
+
return [
|
|
395
|
+
value,
|
|
396
|
+
(_a = array[index + 1]) !== null && _a !== void 0 ? _a : 1,
|
|
397
|
+
];
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
updateModel() {
|
|
401
|
+
const handles = [...this.handles.values()];
|
|
402
|
+
const getRangeAndClamp = (index) => {
|
|
403
|
+
const handle = handles[index];
|
|
404
|
+
const previous = handles[index - 1];
|
|
405
|
+
const next = handles[index + 1];
|
|
406
|
+
const min = typeof handle.min === 'number'
|
|
407
|
+
? handle.min
|
|
408
|
+
: this.host.min;
|
|
409
|
+
const max = typeof handle.max === 'number'
|
|
410
|
+
? handle.max
|
|
411
|
+
: this.host.max;
|
|
412
|
+
const result = {
|
|
413
|
+
range: { min: min, max: max },
|
|
414
|
+
clamp: { min: min, max: max },
|
|
415
|
+
};
|
|
416
|
+
if (handle.min === 'previous') {
|
|
417
|
+
if (previous) {
|
|
418
|
+
for (let j = index - 1; j >= 0; j--) {
|
|
419
|
+
const item = handles[j];
|
|
420
|
+
if (typeof item.min === 'number') {
|
|
421
|
+
result.range.min = item.min;
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
result.clamp.min = Math.max(previous.value, result.range.min);
|
|
426
|
+
/* c8 ignore next 5 */
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
console.warn('First slider handle cannot have attribute min="previous"');
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
if (handle.max === 'next') {
|
|
433
|
+
if (next) {
|
|
434
|
+
for (let j = index + 1; j < handles.length; j++) {
|
|
435
|
+
const item = handles[j];
|
|
436
|
+
if (typeof item.max === 'number') {
|
|
437
|
+
result.range.max = item.max;
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
result.clamp.max = Math.min(next.value, result.range.max);
|
|
442
|
+
/* c8 ignore next 5 */
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
console.warn('Last slider handle cannot have attribute max="next"');
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return result;
|
|
449
|
+
};
|
|
450
|
+
const modelValues = handles.map((handle, index) => {
|
|
451
|
+
var _a;
|
|
452
|
+
const rangeAndClamp = getRangeAndClamp(index);
|
|
453
|
+
const { toNormalized } = handle.normalization;
|
|
454
|
+
const clampedValue = Math.max(Math.min(handle.value, rangeAndClamp.clamp.max), rangeAndClamp.clamp.min);
|
|
455
|
+
const normalizedValue = toNormalized(clampedValue, rangeAndClamp.range.min, rangeAndClamp.range.max);
|
|
456
|
+
const model = Object.assign({ name: handle.handleName, value: clampedValue, normalizedValue, highlight: handle.highlight, step: (_a = handle.step) !== null && _a !== void 0 ? _a : this.host.step, normalization: handle.normalization, handle, ariaLabel: handle !== this.host && (handle === null || handle === void 0 ? void 0 : handle.label.length) > 0
|
|
457
|
+
? handle.label
|
|
458
|
+
: undefined }, rangeAndClamp);
|
|
459
|
+
return model;
|
|
460
|
+
});
|
|
461
|
+
this.model = modelValues;
|
|
462
|
+
}
|
|
463
|
+
async handleUpdatesComplete() {
|
|
464
|
+
const updates = [...this.handles.values()]
|
|
465
|
+
.filter((handle) => handle !== this.host)
|
|
466
|
+
.map((handle) => handle.updateComplete);
|
|
467
|
+
await Promise.all(updates);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
//# sourceMappingURL=HandleController.js.map
|