Skip to content

Commit 8139eee

Browse files
keithamusvdepizzol
andcommitted
initial implementation
Co-authored-by: Vinicius Depizzol <[email protected]>
1 parent 263f453 commit 8139eee

File tree

3 files changed

+140
-33
lines changed

3 files changed

+140
-33
lines changed

examples/index.html

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@
22
<html lang="en">
33
<head>
44
<meta charset="utf-8" />
5-
<title>custom-element demo</title>
5+
<title>slider-input demo</title>
66
</head>
77
<body>
8-
<custom-element></custom-element>
9-
8+
<slider-input value="50" max="100" min="0"></slider-input>
109
<script type="module">
11-
// import 'https://unpkg.com/@github/custom-element-boilerplate@latest/dist/custom-element.js'
12-
import '../src/custom-element.ts'
10+
// import 'https://unpkg.com/@github/slider-input-boilerplate@latest/dist/slider-input.js'
11+
import '../src/slider-input-element.ts'
1312
</script>
1413
</body>
1514
</html>

src/custom-element.ts

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/slider-input-element.ts

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
const html = String.raw
2+
const css = String.raw
3+
const sliderInputStyles = new CSSStyleSheet()
4+
sliderInputStyles.replaceSync(css`
5+
:host {
6+
cursor: ew-resize;
7+
}
8+
input {
9+
cursor: inherit;
10+
background-image: linear-gradient(to right, rgba(0, 0, 0, 0.25) 0% var(--value-filled, 0%), transparent var(--value-filled, 0%) 100%);
11+
}
12+
input::-webkit-inner-spin-button {
13+
display: none;
14+
}
15+
`)
16+
/**
17+
* An example Custom Element. This documentation ends up in the
18+
* README so describe how this elements works here.
19+
*
20+
* You can event add examples on the element is used with Markdown.
21+
*
22+
* ```
23+
* <slider-input></slider-input>
24+
* ```
25+
*/
26+
class SliderInputElement extends HTMLElement {
27+
static observedAttributes = ['value', 'min', 'max']
28+
29+
#renderRoot!: ShadowRoot
30+
#initialX = 0
31+
#initialValue = 0
32+
#valueChanged = false
33+
#sliderAbortController: AbortController | null
34+
#stylesheet = new CSSStyleSheet()
35+
36+
get value() {
37+
return Number(this.#input.value) || 0
38+
}
39+
40+
set value(value: number) {
41+
this.#stylesheet.replaceSync(`:host {
42+
--value-filled: ${100 * value / (this.max - this.min)}%
43+
}`)
44+
this.#input.value = `${value}`
45+
}
46+
47+
get max() {
48+
return Number(this.#input.max) || 0
49+
}
50+
51+
set max(value: number) {
52+
this.#input.max = `${value}`
53+
}
54+
55+
get min() {
56+
return Number(this.#input.min) || 0
57+
}
58+
59+
set min(value: number) {
60+
this.#input.min = `${value}`
61+
}
62+
63+
get #input() {
64+
return this.#renderRoot?.querySelector('input')!
65+
}
66+
67+
attributeChangedCallback(name: 'value', oldValue: string | null, newValue: string | null) {
68+
if (!this.#renderRoot) return
69+
if (name === 'value') {
70+
console.log(name, newValue)
71+
this.#input.value = newValue
72+
} else if (name === 'min') {
73+
this.#input.min = newValue
74+
} else if (name === 'max') {
75+
this.#input.max = newValue
76+
}
77+
}
78+
79+
connectedCallback(): void {
80+
this.#renderRoot = this.attachShadow({mode: 'open'})
81+
this.#renderRoot.adoptedStyleSheets = [sliderInputStyles, this.#stylesheet]
82+
this.#renderRoot.innerHTML = html`<input type="number" />`
83+
this.addEventListener('mousedown', this)
84+
this.#input.addEventListener('input', this)
85+
this.#input.value = this.getAttribute('value')
86+
this.#input.min = this.getAttribute('min')
87+
this.#input.max = this.getAttribute('max')
88+
}
89+
90+
handleEvent(event: Event) {
91+
if (event.type === 'mousedown' && event.which === 1) {
92+
this.#activateSlider(event)
93+
} else if (event.type === 'mouseup') {
94+
this.#sliderAbortController?.abort()
95+
if (!this.#valueChanged) {
96+
this.#input.focus()
97+
this.#input.select()
98+
}
99+
this.#valueChanged = false
100+
} else if (event.type === 'mousemove') {
101+
const delta = event.screenX - this.#initialX
102+
const newValue = this.#initialValue + delta
103+
this.value = Math.max(this.min, Math.min(this.max, newValue))
104+
this.#valueChanged = true
105+
} else if (event.type === 'input') {
106+
this.value = this.#input.value
107+
} else {
108+
console.log(event.screenX, event.clientX, event.pageX)
109+
}
110+
}
111+
112+
#activateSlider(event: Event) {
113+
this.#initialX = event.screenX
114+
this.#initialValue = this.value
115+
console.log(this.#initialX)
116+
this.#sliderAbortController?.abort()
117+
const {signal} = (this.#sliderAbortController = new AbortController())
118+
this.ownerDocument.addEventListener('mousemove', this, {signal})
119+
this.ownerDocument.addEventListener('mouseup', this, {signal})
120+
}
121+
122+
trackCusorPosition() {}
123+
}
124+
125+
declare global {
126+
interface Window {
127+
SliderInputElement: typeof SliderInputElement
128+
}
129+
}
130+
131+
export default SliderInputElement
132+
133+
if (!window.customElements.get('slider-input')) {
134+
window.SliderInputElement = SliderInputElement
135+
window.customElements.define('slider-input', SliderInputElement)
136+
}

0 commit comments

Comments
 (0)