@design.estate/dees-catalog 3.33.0 → 3.34.1
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_bundle/bundle.js +860 -447
- package/dist_bundle/bundle.js.map +4 -4
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-form/dees-form/dees-form.d.ts +2 -1
- package/dist_ts_web/elements/00group-form/dees-form/dees-form.js +3 -1
- package/dist_ts_web/elements/00group-input/dees-input-toggle/dees-input-toggle.d.ts +58 -0
- package/dist_ts_web/elements/00group-input/dees-input-toggle/dees-input-toggle.demo.d.ts +3 -0
- package/dist_ts_web/elements/00group-input/dees-input-toggle/dees-input-toggle.demo.js +307 -0
- package/dist_ts_web/elements/00group-input/dees-input-toggle/dees-input-toggle.js +381 -0
- package/dist_ts_web/elements/00group-input/dees-input-toggle/index.d.ts +1 -0
- package/dist_ts_web/elements/00group-input/dees-input-toggle/index.js +2 -0
- package/dist_ts_web/elements/00group-input/index.d.ts +1 -0
- package/dist_ts_web/elements/00group-input/index.js +2 -1
- package/package.json +2 -2
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-form/dees-form/dees-form.ts +3 -0
- package/ts_web/elements/00group-input/dees-input-toggle/dees-input-toggle.demo.ts +310 -0
- package/ts_web/elements/00group-input/dees-input-toggle/dees-input-toggle.ts +372 -0
- package/ts_web/elements/00group-input/dees-input-toggle/index.ts +1 -0
- package/ts_web/elements/00group-input/index.ts +1 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { html, css, cssManager } from '@design.estate/dees-element';
|
|
2
|
+
import '@design.estate/dees-wcctools/demotools';
|
|
3
|
+
import '../../dees-panel/dees-panel.js';
|
|
4
|
+
import type { DeesInputToggle } from './dees-input-toggle.js';
|
|
5
|
+
|
|
6
|
+
export const demoFunc = () => html`
|
|
7
|
+
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
|
8
|
+
// Example of programmatic interaction
|
|
9
|
+
const toggleAllOnBtn = elementArg.querySelector('#toggle-all-on');
|
|
10
|
+
const toggleAllOffBtn = elementArg.querySelector('#toggle-all-off');
|
|
11
|
+
const featureToggles = elementArg.querySelectorAll('.feature-toggles dees-input-toggle');
|
|
12
|
+
|
|
13
|
+
if (toggleAllOnBtn && toggleAllOffBtn) {
|
|
14
|
+
toggleAllOnBtn.addEventListener('click', () => {
|
|
15
|
+
featureToggles.forEach((toggle: DeesInputToggle) => {
|
|
16
|
+
if (!toggle.disabled && !toggle.required) {
|
|
17
|
+
toggle.value = true;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
toggleAllOffBtn.addEventListener('click', () => {
|
|
23
|
+
featureToggles.forEach((toggle: DeesInputToggle) => {
|
|
24
|
+
if (!toggle.disabled && !toggle.required) {
|
|
25
|
+
toggle.value = false;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}}>
|
|
31
|
+
<style>
|
|
32
|
+
${css`
|
|
33
|
+
.demo-container {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
gap: 24px;
|
|
37
|
+
padding: 24px;
|
|
38
|
+
max-width: 1200px;
|
|
39
|
+
margin: 0 auto;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
dees-panel {
|
|
43
|
+
margin-bottom: 24px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
dees-panel:last-child {
|
|
47
|
+
margin-bottom: 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.toggle-group {
|
|
51
|
+
display: flex;
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
gap: 16px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.horizontal-toggles {
|
|
57
|
+
display: flex;
|
|
58
|
+
gap: 32px;
|
|
59
|
+
flex-wrap: wrap;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.interactive-section {
|
|
63
|
+
background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 16.8%)')};
|
|
64
|
+
border-radius: 8px;
|
|
65
|
+
padding: 16px;
|
|
66
|
+
margin-top: 16px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.output-text {
|
|
70
|
+
font-family: monospace;
|
|
71
|
+
font-size: 13px;
|
|
72
|
+
color: ${cssManager.bdTheme('hsl(215.3 25% 26.7%)', 'hsl(210 40% 80%)')};
|
|
73
|
+
padding: 8px;
|
|
74
|
+
background: ${cssManager.bdTheme('hsl(210 40% 98%)', 'hsl(215 20.2% 11.8%)')};
|
|
75
|
+
border-radius: 4px;
|
|
76
|
+
min-height: 24px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.settings-section {
|
|
80
|
+
background: ${cssManager.bdTheme('hsl(0 0% 97%)', 'hsl(0 0% 7%)')};
|
|
81
|
+
border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
|
|
82
|
+
border-radius: 8px;
|
|
83
|
+
padding: 20px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.button-group {
|
|
87
|
+
display: flex;
|
|
88
|
+
gap: 8px;
|
|
89
|
+
margin-bottom: 16px;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.feature-toggles {
|
|
93
|
+
background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 11.8%)')};
|
|
94
|
+
border: 1px solid ${cssManager.bdTheme('hsl(214.3 31.8% 91.4%)', 'hsl(215 20.2% 16.8%)')};
|
|
95
|
+
border-radius: 6px;
|
|
96
|
+
padding: 16px;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.section-title {
|
|
100
|
+
font-size: 16px;
|
|
101
|
+
font-weight: 600;
|
|
102
|
+
margin-bottom: 16px;
|
|
103
|
+
color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.drag-hint {
|
|
107
|
+
font-size: 12px;
|
|
108
|
+
color: ${cssManager.bdTheme('hsl(0 0% 45.1%)', 'hsl(0 0% 63.9%)')};
|
|
109
|
+
margin-top: 8px;
|
|
110
|
+
font-style: italic;
|
|
111
|
+
}
|
|
112
|
+
`}
|
|
113
|
+
</style>
|
|
114
|
+
|
|
115
|
+
<div class="demo-container">
|
|
116
|
+
<dees-panel .title=${'Basic Toggle'} .subtitle=${'Simple on/off toggle switch with drag support'}>
|
|
117
|
+
<div class="toggle-group">
|
|
118
|
+
<dees-input-toggle
|
|
119
|
+
.label=${'Enable feature'}
|
|
120
|
+
.value=${false}
|
|
121
|
+
.key=${'basic'}
|
|
122
|
+
></dees-input-toggle>
|
|
123
|
+
|
|
124
|
+
<dees-input-toggle
|
|
125
|
+
.label=${'Active toggle'}
|
|
126
|
+
.value=${true}
|
|
127
|
+
.key=${'active'}
|
|
128
|
+
></dees-input-toggle>
|
|
129
|
+
|
|
130
|
+
<dees-input-toggle
|
|
131
|
+
.label=${'With description'}
|
|
132
|
+
.value=${false}
|
|
133
|
+
.description=${'This toggle has additional helper text explaining its purpose'}
|
|
134
|
+
.key=${'withDesc'}
|
|
135
|
+
></dees-input-toggle>
|
|
136
|
+
</div>
|
|
137
|
+
<p class="drag-hint">Tip: You can drag the toggle knob to switch states</p>
|
|
138
|
+
</dees-panel>
|
|
139
|
+
|
|
140
|
+
<dees-panel .title=${'Toggle States'} .subtitle=${'Different toggle states and configurations'}>
|
|
141
|
+
<div class="toggle-group">
|
|
142
|
+
<dees-input-toggle
|
|
143
|
+
.label=${'Default (off)'}
|
|
144
|
+
.value=${false}
|
|
145
|
+
></dees-input-toggle>
|
|
146
|
+
|
|
147
|
+
<dees-input-toggle
|
|
148
|
+
.label=${'Enabled (on)'}
|
|
149
|
+
.value=${true}
|
|
150
|
+
></dees-input-toggle>
|
|
151
|
+
|
|
152
|
+
<dees-input-toggle
|
|
153
|
+
.label=${'Disabled (off)'}
|
|
154
|
+
.value=${false}
|
|
155
|
+
.disabled=${true}
|
|
156
|
+
></dees-input-toggle>
|
|
157
|
+
|
|
158
|
+
<dees-input-toggle
|
|
159
|
+
.label=${'Disabled (on)'}
|
|
160
|
+
.value=${true}
|
|
161
|
+
.disabled=${true}
|
|
162
|
+
></dees-input-toggle>
|
|
163
|
+
|
|
164
|
+
<dees-input-toggle
|
|
165
|
+
.label=${'Required (always on)'}
|
|
166
|
+
.value=${true}
|
|
167
|
+
.required=${true}
|
|
168
|
+
.description=${'This toggle cannot be turned off'}
|
|
169
|
+
></dees-input-toggle>
|
|
170
|
+
</div>
|
|
171
|
+
</dees-panel>
|
|
172
|
+
|
|
173
|
+
<dees-panel .title=${'Horizontal Layout'} .subtitle=${'Toggles arranged horizontally for compact interfaces'}>
|
|
174
|
+
<div class="horizontal-toggles">
|
|
175
|
+
<dees-input-toggle
|
|
176
|
+
.label=${'WiFi'}
|
|
177
|
+
.value=${true}
|
|
178
|
+
.layoutMode=${'horizontal'}
|
|
179
|
+
></dees-input-toggle>
|
|
180
|
+
|
|
181
|
+
<dees-input-toggle
|
|
182
|
+
.label=${'Bluetooth'}
|
|
183
|
+
.value=${false}
|
|
184
|
+
.layoutMode=${'horizontal'}
|
|
185
|
+
></dees-input-toggle>
|
|
186
|
+
|
|
187
|
+
<dees-input-toggle
|
|
188
|
+
.label=${'GPS'}
|
|
189
|
+
.value=${true}
|
|
190
|
+
.layoutMode=${'horizontal'}
|
|
191
|
+
></dees-input-toggle>
|
|
192
|
+
|
|
193
|
+
<dees-input-toggle
|
|
194
|
+
.label=${'NFC'}
|
|
195
|
+
.value=${false}
|
|
196
|
+
.layoutMode=${'horizontal'}
|
|
197
|
+
></dees-input-toggle>
|
|
198
|
+
</div>
|
|
199
|
+
</dees-panel>
|
|
200
|
+
|
|
201
|
+
<dees-panel .title=${'Settings Example'} .subtitle=${'Toggles in a typical settings context'}>
|
|
202
|
+
<div class="settings-section">
|
|
203
|
+
<h4 class="section-title">Notification Settings</h4>
|
|
204
|
+
|
|
205
|
+
<div class="toggle-group">
|
|
206
|
+
<dees-input-toggle
|
|
207
|
+
.label=${'Push notifications'}
|
|
208
|
+
.value=${true}
|
|
209
|
+
.description=${'Receive push notifications on your device'}
|
|
210
|
+
.key=${'push'}
|
|
211
|
+
></dees-input-toggle>
|
|
212
|
+
|
|
213
|
+
<dees-input-toggle
|
|
214
|
+
.label=${'Email notifications'}
|
|
215
|
+
.value=${true}
|
|
216
|
+
.description=${'Get important updates via email'}
|
|
217
|
+
.key=${'email'}
|
|
218
|
+
></dees-input-toggle>
|
|
219
|
+
|
|
220
|
+
<dees-input-toggle
|
|
221
|
+
.label=${'Sound'}
|
|
222
|
+
.value=${false}
|
|
223
|
+
.description=${'Play a sound for notifications'}
|
|
224
|
+
.key=${'sound'}
|
|
225
|
+
></dees-input-toggle>
|
|
226
|
+
|
|
227
|
+
<dees-input-toggle
|
|
228
|
+
.label=${'Vibration'}
|
|
229
|
+
.value=${true}
|
|
230
|
+
.description=${'Vibrate for notifications'}
|
|
231
|
+
.key=${'vibration'}
|
|
232
|
+
></dees-input-toggle>
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
</dees-panel>
|
|
236
|
+
|
|
237
|
+
<dees-panel .title=${'Feature Toggles'} .subtitle=${'Batch operations on multiple toggles'}>
|
|
238
|
+
<div class="button-group">
|
|
239
|
+
<dees-button id="toggle-all-on" type="secondary">Enable All</dees-button>
|
|
240
|
+
<dees-button id="toggle-all-off" type="secondary">Disable All</dees-button>
|
|
241
|
+
</div>
|
|
242
|
+
|
|
243
|
+
<div class="feature-toggles">
|
|
244
|
+
<div class="toggle-group">
|
|
245
|
+
<dees-input-toggle
|
|
246
|
+
.label=${'Dark Mode'}
|
|
247
|
+
.value=${true}
|
|
248
|
+
.key=${'darkMode'}
|
|
249
|
+
></dees-input-toggle>
|
|
250
|
+
|
|
251
|
+
<dees-input-toggle
|
|
252
|
+
.label=${'Auto-save'}
|
|
253
|
+
.value=${true}
|
|
254
|
+
.key=${'autoSave'}
|
|
255
|
+
></dees-input-toggle>
|
|
256
|
+
|
|
257
|
+
<dees-input-toggle
|
|
258
|
+
.label=${'Spell check'}
|
|
259
|
+
.value=${false}
|
|
260
|
+
.key=${'spellCheck'}
|
|
261
|
+
></dees-input-toggle>
|
|
262
|
+
|
|
263
|
+
<dees-input-toggle
|
|
264
|
+
.label=${'Developer mode'}
|
|
265
|
+
.value=${false}
|
|
266
|
+
.key=${'devMode'}
|
|
267
|
+
></dees-input-toggle>
|
|
268
|
+
|
|
269
|
+
<dees-input-toggle
|
|
270
|
+
.label=${'Beta features'}
|
|
271
|
+
.value=${false}
|
|
272
|
+
.key=${'beta'}
|
|
273
|
+
></dees-input-toggle>
|
|
274
|
+
</div>
|
|
275
|
+
</div>
|
|
276
|
+
</dees-panel>
|
|
277
|
+
|
|
278
|
+
<dees-panel .title=${'Interactive Example'} .subtitle=${'Toggle to see value changes in real-time'}>
|
|
279
|
+
<div class="toggle-group">
|
|
280
|
+
<dees-input-toggle
|
|
281
|
+
.label=${'Airplane mode'}
|
|
282
|
+
.value=${false}
|
|
283
|
+
@newValue=${(event: CustomEvent) => {
|
|
284
|
+
const output = document.querySelector('#airplane-output');
|
|
285
|
+
if (output) {
|
|
286
|
+
output.textContent = `Airplane mode: ${event.detail ? 'ON' : 'OFF'}`;
|
|
287
|
+
}
|
|
288
|
+
}}
|
|
289
|
+
></dees-input-toggle>
|
|
290
|
+
|
|
291
|
+
<dees-input-toggle
|
|
292
|
+
.label=${'Do not disturb'}
|
|
293
|
+
.value=${false}
|
|
294
|
+
@newValue=${(event: CustomEvent) => {
|
|
295
|
+
const output = document.querySelector('#dnd-output');
|
|
296
|
+
if (output) {
|
|
297
|
+
output.textContent = `Do not disturb: ${event.detail ? 'ENABLED' : 'DISABLED'}`;
|
|
298
|
+
}
|
|
299
|
+
}}
|
|
300
|
+
></dees-input-toggle>
|
|
301
|
+
</div>
|
|
302
|
+
|
|
303
|
+
<div class="interactive-section">
|
|
304
|
+
<div id="airplane-output" class="output-text">Airplane mode: OFF</div>
|
|
305
|
+
<div id="dnd-output" class="output-text" style="margin-top: 8px;">Do not disturb: DISABLED</div>
|
|
306
|
+
</div>
|
|
307
|
+
</dees-panel>
|
|
308
|
+
</div>
|
|
309
|
+
</dees-demowrapper>
|
|
310
|
+
`;
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import {
|
|
2
|
+
customElement,
|
|
3
|
+
type TemplateResult,
|
|
4
|
+
property,
|
|
5
|
+
html,
|
|
6
|
+
css,
|
|
7
|
+
cssManager,
|
|
8
|
+
} from '@design.estate/dees-element';
|
|
9
|
+
import * as domtools from '@design.estate/dees-domtools';
|
|
10
|
+
import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
|
|
11
|
+
import { demoFunc } from './dees-input-toggle.demo.js';
|
|
12
|
+
import { cssGeistFontFamily } from '../../00fonts.js';
|
|
13
|
+
import { themeDefaultStyles } from '../../00theme.js';
|
|
14
|
+
|
|
15
|
+
declare global {
|
|
16
|
+
interface HTMLElementTagNameMap {
|
|
17
|
+
'dees-input-toggle': DeesInputToggle;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@customElement('dees-input-toggle')
|
|
22
|
+
export class DeesInputToggle extends DeesInputBase<DeesInputToggle> {
|
|
23
|
+
// STATIC
|
|
24
|
+
public static demo = demoFunc;
|
|
25
|
+
public static demoGroup = 'Input';
|
|
26
|
+
|
|
27
|
+
// INSTANCE
|
|
28
|
+
|
|
29
|
+
@property({ type: Boolean, reflect: true })
|
|
30
|
+
accessor value: boolean = false;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Knob position tracking (0 = off, maxTravel = on)
|
|
34
|
+
*/
|
|
35
|
+
private currentX = 0;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Drag state
|
|
39
|
+
*/
|
|
40
|
+
private isDragging = false;
|
|
41
|
+
private hasDragged = false;
|
|
42
|
+
private startX = 0;
|
|
43
|
+
|
|
44
|
+
// Toggle dimensions
|
|
45
|
+
private readonly trackWidth = 36;
|
|
46
|
+
private readonly trackHeight = 20;
|
|
47
|
+
private readonly knobSize = 14;
|
|
48
|
+
private readonly padding = 2;
|
|
49
|
+
private readonly maxTravel = 16; // trackWidth - knobSize - (padding * 2) - border
|
|
50
|
+
|
|
51
|
+
constructor() {
|
|
52
|
+
super();
|
|
53
|
+
this.labelPosition = 'right'; // Toggle defaults to label on the right
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public static styles = [
|
|
57
|
+
themeDefaultStyles,
|
|
58
|
+
...DeesInputBase.baseStyles,
|
|
59
|
+
cssManager.defaultStyles,
|
|
60
|
+
css`
|
|
61
|
+
* {
|
|
62
|
+
box-sizing: border-box;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
:host {
|
|
66
|
+
position: relative;
|
|
67
|
+
cursor: default;
|
|
68
|
+
font-family: ${cssGeistFontFamily};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.maincontainer {
|
|
72
|
+
display: inline-flex;
|
|
73
|
+
align-items: flex-start;
|
|
74
|
+
gap: 8px;
|
|
75
|
+
cursor: pointer;
|
|
76
|
+
user-select: none;
|
|
77
|
+
transition: all 0.15s ease;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.toggle-track {
|
|
81
|
+
position: relative;
|
|
82
|
+
flex-shrink: 0;
|
|
83
|
+
height: 20px;
|
|
84
|
+
width: 36px;
|
|
85
|
+
border-radius: 10px;
|
|
86
|
+
background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 3.9%)')};
|
|
87
|
+
border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
|
|
88
|
+
overflow: hidden;
|
|
89
|
+
transition: all 0.15s ease;
|
|
90
|
+
margin-top: 1px;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.maincontainer:hover .toggle-track {
|
|
94
|
+
border-color: ${cssManager.bdTheme('hsl(0 0% 79.8%)', 'hsl(0 0% 20.9%)')};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
:host([value]) .toggle-track {
|
|
98
|
+
background: ${cssManager.bdTheme('hsl(222.2 47.4% 51.2%)', 'hsl(217.2 91.2% 59.8%)')};
|
|
99
|
+
border-color: ${cssManager.bdTheme('hsl(222.2 47.4% 51.2%)', 'hsl(217.2 91.2% 59.8%)')};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.toggle-track:focus-visible {
|
|
103
|
+
outline: none;
|
|
104
|
+
box-shadow: 0 0 0 3px ${cssManager.bdTheme('hsl(222.2 47.4% 51.2% / 0.1)', 'hsl(217.2 91.2% 59.8% / 0.1)')};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.toggle-knob {
|
|
108
|
+
position: absolute;
|
|
109
|
+
top: 2px;
|
|
110
|
+
width: 14px;
|
|
111
|
+
height: 14px;
|
|
112
|
+
border-radius: 7px;
|
|
113
|
+
background: ${cssManager.bdTheme('hsl(0 0% 63.9%)', 'hsl(0 0% 45.1%)')};
|
|
114
|
+
transition: left 0.15s ease, background 0.15s ease;
|
|
115
|
+
touch-action: none;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.toggle-knob.dragging {
|
|
119
|
+
transition: background 0.15s ease;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
:host([value]) .toggle-knob {
|
|
123
|
+
background: white;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* Disabled state */
|
|
127
|
+
.maincontainer.disabled {
|
|
128
|
+
cursor: not-allowed;
|
|
129
|
+
opacity: 0.5;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.toggle-track.disabled {
|
|
133
|
+
background: ${cssManager.bdTheme('hsl(0 0% 95.1%)', 'hsl(0 0% 14.9%)')};
|
|
134
|
+
border-color: ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* Required state (locked on) */
|
|
138
|
+
:host([required][value]) .toggle-track {
|
|
139
|
+
background: ${cssManager.bdTheme('hsl(222.2 47.4% 61.2%)', 'hsl(217.2 91.2% 49.8%)')};
|
|
140
|
+
border-color: ${cssManager.bdTheme('hsl(222.2 47.4% 61.2%)', 'hsl(217.2 91.2% 49.8%)')};
|
|
141
|
+
cursor: not-allowed;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
:host([required][value]) .toggle-knob {
|
|
145
|
+
background: ${cssManager.bdTheme('hsl(0 0% 85%)', 'hsl(0 0% 70%)')};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* Label */
|
|
149
|
+
.label-container {
|
|
150
|
+
display: flex;
|
|
151
|
+
flex-direction: column;
|
|
152
|
+
gap: 2px;
|
|
153
|
+
flex: 1;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.toggle-label {
|
|
157
|
+
font-size: 14px;
|
|
158
|
+
font-weight: 500;
|
|
159
|
+
line-height: 20px;
|
|
160
|
+
color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')};
|
|
161
|
+
transition: color 0.15s ease;
|
|
162
|
+
letter-spacing: -0.01em;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.maincontainer:hover .toggle-label {
|
|
166
|
+
color: ${cssManager.bdTheme('hsl(0 0% 9%)', 'hsl(0 0% 95%)')};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.maincontainer.disabled:hover .toggle-label {
|
|
170
|
+
color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* Description */
|
|
174
|
+
.description-text {
|
|
175
|
+
font-size: 12px;
|
|
176
|
+
color: ${cssManager.bdTheme('hsl(0 0% 45.1%)', 'hsl(0 0% 63.9%)')};
|
|
177
|
+
line-height: 1.5;
|
|
178
|
+
}
|
|
179
|
+
`,
|
|
180
|
+
];
|
|
181
|
+
|
|
182
|
+
public render(): TemplateResult {
|
|
183
|
+
return html`
|
|
184
|
+
<div class="input-wrapper">
|
|
185
|
+
<div class="maincontainer ${this.disabled ? 'disabled' : ''}" @click="${this.handleClick}">
|
|
186
|
+
<div
|
|
187
|
+
class="toggle-track ${this.disabled ? 'disabled' : ''}"
|
|
188
|
+
tabindex="${this.disabled ? '-1' : '0'}"
|
|
189
|
+
@keydown="${this.handleKeydown}"
|
|
190
|
+
>
|
|
191
|
+
<div
|
|
192
|
+
class="toggle-knob"
|
|
193
|
+
style="left: ${this.padding + this.currentX}px;"
|
|
194
|
+
@pointerdown="${this.onPointerDown}"
|
|
195
|
+
@pointermove="${this.onPointerMove}"
|
|
196
|
+
@pointerup="${this.onPointerUp}"
|
|
197
|
+
@pointercancel="${this.onPointerUp}"
|
|
198
|
+
></div>
|
|
199
|
+
</div>
|
|
200
|
+
<div class="label-container">
|
|
201
|
+
${this.label ? html`<div class="toggle-label">${this.label}</div>` : ''}
|
|
202
|
+
${this.description ? html`<div class="description-text">${this.description}</div>` : ''}
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
`;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
public async firstUpdated(_changedProperties: Map<PropertyKey, unknown>) {
|
|
210
|
+
await super.firstUpdated(_changedProperties);
|
|
211
|
+
// Initialize knob position based on initial value
|
|
212
|
+
if (this.required && !this.value) {
|
|
213
|
+
this.value = true;
|
|
214
|
+
}
|
|
215
|
+
this.currentX = this.value ? this.maxTravel : 0;
|
|
216
|
+
this.requestUpdate();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Click handler - toggles the value
|
|
221
|
+
*/
|
|
222
|
+
private async handleClick(event: MouseEvent) {
|
|
223
|
+
if (this.isDragging || this.hasDragged) {
|
|
224
|
+
event.stopPropagation();
|
|
225
|
+
event.preventDefault();
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (this.disabled) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (this.required) {
|
|
234
|
+
// Bounce animation for required toggles
|
|
235
|
+
this.currentX = this.maxTravel;
|
|
236
|
+
this.requestUpdate();
|
|
237
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
238
|
+
this.currentX = this.maxTravel - 3;
|
|
239
|
+
this.requestUpdate();
|
|
240
|
+
await domtools.plugins.smartdelay.delayFor(150);
|
|
241
|
+
this.currentX = this.maxTravel;
|
|
242
|
+
this.requestUpdate();
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
event.stopPropagation();
|
|
247
|
+
event.preventDefault();
|
|
248
|
+
|
|
249
|
+
this.value = !this.value;
|
|
250
|
+
this.currentX = this.value ? this.maxTravel : 0;
|
|
251
|
+
this.requestUpdate();
|
|
252
|
+
|
|
253
|
+
this.dispatchEvent(
|
|
254
|
+
new CustomEvent('newValue', {
|
|
255
|
+
detail: this.value,
|
|
256
|
+
bubbles: true,
|
|
257
|
+
})
|
|
258
|
+
);
|
|
259
|
+
this.changeSubject.next(this);
|
|
260
|
+
|
|
261
|
+
domtools.plugins.smartdelay.delayFor(0).then(() => {
|
|
262
|
+
this.hasDragged = false;
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Pointer down - start dragging
|
|
268
|
+
*/
|
|
269
|
+
private onPointerDown(event: PointerEvent) {
|
|
270
|
+
if (this.required || this.disabled) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
this.isDragging = true;
|
|
275
|
+
this.startX = event.clientX - this.currentX;
|
|
276
|
+
(event.target as HTMLElement).setPointerCapture(event.pointerId);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Pointer move - track drag position
|
|
281
|
+
*/
|
|
282
|
+
private onPointerMove(event: PointerEvent) {
|
|
283
|
+
if (!this.isDragging) return;
|
|
284
|
+
const newX = event.clientX - this.startX;
|
|
285
|
+
this.hasDragged = true;
|
|
286
|
+
|
|
287
|
+
const toggleKnob = this.shadowRoot?.querySelector('.toggle-knob') as HTMLDivElement;
|
|
288
|
+
if (toggleKnob) {
|
|
289
|
+
toggleKnob.classList.add('dragging');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
this.currentX = Math.max(0, Math.min(newX, this.maxTravel));
|
|
293
|
+
this.requestUpdate();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Pointer up - complete drag and snap to nearest side
|
|
298
|
+
*/
|
|
299
|
+
private onPointerUp(event: PointerEvent) {
|
|
300
|
+
if (!this.isDragging) return;
|
|
301
|
+
(event.target as HTMLElement).releasePointerCapture(event.pointerId);
|
|
302
|
+
this.isDragging = false;
|
|
303
|
+
|
|
304
|
+
if (!this.hasDragged) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const toggleKnob = this.shadowRoot?.querySelector('.toggle-knob') as HTMLDivElement;
|
|
309
|
+
if (toggleKnob) {
|
|
310
|
+
toggleKnob.classList.remove('dragging');
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Snap to nearest side based on midpoint
|
|
314
|
+
const midpoint = this.maxTravel / 2;
|
|
315
|
+
this.value = this.currentX > midpoint;
|
|
316
|
+
this.currentX = this.value ? this.maxTravel : 0;
|
|
317
|
+
this.requestUpdate();
|
|
318
|
+
|
|
319
|
+
this.dispatchEvent(
|
|
320
|
+
new CustomEvent('newValue', {
|
|
321
|
+
detail: this.value,
|
|
322
|
+
bubbles: true,
|
|
323
|
+
})
|
|
324
|
+
);
|
|
325
|
+
this.changeSubject.next(this);
|
|
326
|
+
|
|
327
|
+
domtools.plugins.smartdelay.delayFor(0).then(() => {
|
|
328
|
+
this.hasDragged = false;
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Sync knob position when value is changed externally
|
|
334
|
+
*/
|
|
335
|
+
updated(changedProperties: Map<string, any>): void {
|
|
336
|
+
super.updated(changedProperties);
|
|
337
|
+
if (
|
|
338
|
+
changedProperties.has('value') &&
|
|
339
|
+
!this.isDragging &&
|
|
340
|
+
!this.hasDragged
|
|
341
|
+
) {
|
|
342
|
+
this.currentX = this.value ? this.maxTravel : 0;
|
|
343
|
+
this.requestUpdate();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Keyboard support
|
|
349
|
+
*/
|
|
350
|
+
private handleKeydown(event: KeyboardEvent) {
|
|
351
|
+
if (event.key === ' ' || event.key === 'Enter') {
|
|
352
|
+
event.preventDefault();
|
|
353
|
+
this.handleClick(event as unknown as MouseEvent);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// DeesInputBase interface implementation
|
|
358
|
+
public getValue(): boolean {
|
|
359
|
+
return this.value;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
public setValue(valueArg: boolean): void {
|
|
363
|
+
this.value = valueArg;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
public focus(): void {
|
|
367
|
+
const track = this.shadowRoot?.querySelector('.toggle-track');
|
|
368
|
+
if (track) {
|
|
369
|
+
(track as HTMLElement).focus();
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dees-input-toggle.js';
|
|
@@ -15,6 +15,7 @@ export * from './dees-input-richtext/index.js';
|
|
|
15
15
|
export * from './dees-input-searchselect/index.js';
|
|
16
16
|
export * from './dees-input-tags/index.js';
|
|
17
17
|
export * from './dees-input-text/index.js';
|
|
18
|
+
export * from './dees-input-toggle/index.js';
|
|
18
19
|
export * from './dees-input-typelist/index.js';
|
|
19
20
|
export * from './dees-input-wysiwyg.js';
|
|
20
21
|
export * from './profilepicture/dees-input-profilepicture.js';
|