@kubex/zinc 1.1.91 → 1.1.94
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/custom-elements.json +1738 -110
- package/dist/vscode.html-custom-data.json +136 -4
- package/dist/web-types.json +307 -4
- package/dist/zn.d.ts +298 -2
- package/dist/zn.min.js +708 -516
- package/docs/pages/components/page-builder.md +22 -0
- package/docs/pages/components/schedule-builder.md +345 -0
- package/package.json +1 -1
- package/src/components/alert/alert.scss +9 -13
- package/src/components/chip/chip.scss +1 -1
- package/src/components/content-block/content-block.component.ts +3 -2
- package/src/components/icon-picker/icon-picker.component.ts +1 -1
- package/src/components/linked-select/linked-select.component.ts +22 -5
- package/src/components/page/page.scss +13 -7
- package/src/components/page-builder/page-builder.component.ts +52 -7
- package/src/components/page-builder/page-builder.scss +166 -9
- package/src/components/page-builder/page-builder.test.ts +134 -0
- package/src/components/page-builder/page.types.ts +23 -3
- package/src/components/page-nav/page-nav.scss +9 -1
- package/src/components/panel/panel.component.ts +5 -1
- package/src/components/priority-list/priority-list.component.ts +1 -0
- package/src/components/priority-list/priority-list.scss +2 -1
- package/src/components/schedule-builder/index.ts +12 -0
- package/src/components/schedule-builder/schedule-builder.component.ts +1543 -0
- package/src/components/schedule-builder/schedule-builder.scss +448 -0
- package/src/components/schedule-builder/schedule-builder.test.ts +344 -0
- package/src/components/toggle/toggle.component.ts +2 -1
- package/src/zinc.ts +1 -0
- package/docs/superpowers/plans/2026-08-03-theme-editor.md +0 -1536
- package/docs/superpowers/specs/2026-08-03-theme-editor-design.md +0 -327
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import '../../../dist/zn.min.js';
|
|
2
|
+
import {expect, fixture, html} from '@open-wc/testing';
|
|
3
|
+
import type {ScheduleValue} from './schedule-builder.component';
|
|
4
|
+
import type ZnScheduleBuilder from './schedule-builder.component';
|
|
5
|
+
|
|
6
|
+
const parseSchedule = (value: string): ScheduleValue => JSON.parse(value) as ScheduleValue;
|
|
7
|
+
|
|
8
|
+
const scheduleValue = JSON.stringify({
|
|
9
|
+
days: {
|
|
10
|
+
mon: [{start: '08:00', end: '18:00'}],
|
|
11
|
+
tue: [], wed: [], thu: [], fri: [], sat: [], sun: []
|
|
12
|
+
},
|
|
13
|
+
exceptions: []
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('<zn-schedule-builder>', () => {
|
|
17
|
+
it('should render a component', async () => {
|
|
18
|
+
const el = await fixture(html`
|
|
19
|
+
<zn-schedule-builder></zn-schedule-builder>`);
|
|
20
|
+
|
|
21
|
+
expect(el).to.exist;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should expose an empty schedule by default', async () => {
|
|
25
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
26
|
+
<zn-schedule-builder></zn-schedule-builder>`);
|
|
27
|
+
|
|
28
|
+
expect(el.schedule.days.mon).to.deep.equal([]);
|
|
29
|
+
expect(el.schedule.exceptions).to.deep.equal([]);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should parse a JSON value into the schedule', async () => {
|
|
33
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
34
|
+
<zn-schedule-builder value="${scheduleValue}"></zn-schedule-builder>`);
|
|
35
|
+
|
|
36
|
+
expect(el.getDay('mon')).to.deep.equal([{start: '08:00', end: '18:00'}]);
|
|
37
|
+
expect(el.getDay('sun')).to.deep.equal([]);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should accept the shorthand range syntax', async () => {
|
|
41
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
42
|
+
<zn-schedule-builder value='{"mon":["09:00-17:00"]}'></zn-schedule-builder>`);
|
|
43
|
+
|
|
44
|
+
expect(el.getDay('mon')).to.deep.equal([{start: '09:00', end: '17:00'}]);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should serialise assignments back into the value', async () => {
|
|
48
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
49
|
+
<zn-schedule-builder></zn-schedule-builder>`);
|
|
50
|
+
|
|
51
|
+
el.setDay('tue', [{start: '10:00', end: '12:00'}]);
|
|
52
|
+
await el.updateComplete;
|
|
53
|
+
|
|
54
|
+
expect(parseSchedule(el.value).days.tue).to.deep.equal([{start: '10:00', end: '12:00'}]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should merge overlapping and touching ranges', async () => {
|
|
58
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
59
|
+
<zn-schedule-builder></zn-schedule-builder>`);
|
|
60
|
+
|
|
61
|
+
el.setDay('wed', [{start: '13:00', end: '18:00'}, {start: '08:00', end: '13:00'}]);
|
|
62
|
+
await el.updateComplete;
|
|
63
|
+
|
|
64
|
+
expect(el.getDay('wed')).to.deep.equal([{start: '08:00', end: '18:00'}]);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should drop invalid ranges', async () => {
|
|
68
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
69
|
+
<zn-schedule-builder></zn-schedule-builder>`);
|
|
70
|
+
|
|
71
|
+
el.setDay('thu', [{start: '18:00', end: '09:00'}, {start: 'nope', end: '10:00'}]);
|
|
72
|
+
await el.updateComplete;
|
|
73
|
+
|
|
74
|
+
expect(el.getDay('thu')).to.deep.equal([]);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should emit zn-change when the schedule changes', async () => {
|
|
78
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
79
|
+
<zn-schedule-builder></zn-schedule-builder>`);
|
|
80
|
+
|
|
81
|
+
let changed = false;
|
|
82
|
+
el.addEventListener('zn-change', () => (changed = true));
|
|
83
|
+
|
|
84
|
+
el.setDay('fri', [{start: '09:00', end: '17:00'}]);
|
|
85
|
+
await el.updateComplete;
|
|
86
|
+
|
|
87
|
+
expect(changed).to.be.true;
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should render the list view when view is form', async () => {
|
|
91
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
92
|
+
<zn-schedule-builder view="form" value="${scheduleValue}"></zn-schedule-builder>`);
|
|
93
|
+
|
|
94
|
+
expect(el.shadowRoot?.querySelector('.list')).to.exist;
|
|
95
|
+
expect(el.shadowRoot?.querySelector('.calendar')).to.not.exist;
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should render the calendar view by default', async () => {
|
|
99
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
100
|
+
<zn-schedule-builder value="${scheduleValue}"></zn-schedule-builder>`);
|
|
101
|
+
|
|
102
|
+
expect(el.shadowRoot?.querySelector('.calendar')).to.exist;
|
|
103
|
+
expect(el.shadowRoot?.querySelectorAll('.calendar__col').length).to.equal(7);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should shade hours a weekday exception removes', async () => {
|
|
107
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
108
|
+
<zn-schedule-builder value='{
|
|
109
|
+
"days": {"fri": ["08:00-18:00"]},
|
|
110
|
+
"exceptions": [{"label": "Summer Fridays", "days": ["fri"], "ranges": ["08:00-16:00"]}]
|
|
111
|
+
}'></zn-schedule-builder>`);
|
|
112
|
+
|
|
113
|
+
const friday = el.shadowRoot?.querySelectorAll('.calendar__col')[4];
|
|
114
|
+
expect(friday?.querySelectorAll('.calendar__slot--open').length).to.be.greaterThan(0);
|
|
115
|
+
expect(friday?.querySelectorAll('.calendar__slot--reduced').length).to.equal(4); // 16:00–18:00
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('should not shade the weekly grid for a one-off dated exception', async () => {
|
|
119
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
120
|
+
<zn-schedule-builder value='{
|
|
121
|
+
"days": {"mon": ["08:00-18:00"]},
|
|
122
|
+
"exceptions": [{"label": "Offsite", "date": "2026-09-14", "ranges": ["08:00-13:00"]}]
|
|
123
|
+
}'></zn-schedule-builder>`);
|
|
124
|
+
|
|
125
|
+
expect(el.shadowRoot?.querySelectorAll('.calendar__slot--reduced').length).to.equal(0);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe('timezones', () => {
|
|
129
|
+
it('should not convert anything when no timezone is configured', async () => {
|
|
130
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
131
|
+
<zn-schedule-builder value='{"mon":["09:00-17:00"]}'></zn-schedule-builder>`);
|
|
132
|
+
|
|
133
|
+
expect(el.displayedDays.mon).to.deep.equal([{start: '09:00', end: '17:00'}]);
|
|
134
|
+
expect(parseSchedule(el.value).timezone).to.be.undefined;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should default to storing in UTC once a timezone is in play', async () => {
|
|
138
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
139
|
+
<zn-schedule-builder show-timezone value='{"mon":["09:00-17:00"]}'></zn-schedule-builder>`);
|
|
140
|
+
|
|
141
|
+
expect(parseSchedule(el.value).timezone).to.equal('UTC');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should show stored hours in the display timezone without changing the value', async () => {
|
|
145
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
146
|
+
<zn-schedule-builder
|
|
147
|
+
display-timezone="Europe/London"
|
|
148
|
+
reference-date="2026-07-15"
|
|
149
|
+
value='{"timezone":"UTC","days":{"mon":["09:00-17:00"]}}'></zn-schedule-builder>`);
|
|
150
|
+
|
|
151
|
+
// London is UTC+1 in July.
|
|
152
|
+
expect(el.displayedDays.mon).to.deep.equal([{start: '10:00', end: '18:00'}]);
|
|
153
|
+
expect(el.getDay('mon')).to.deep.equal([{start: '09:00', end: '17:00'}]);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should follow daylight saving via the reference date', async () => {
|
|
157
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
158
|
+
<zn-schedule-builder
|
|
159
|
+
display-timezone="Europe/London"
|
|
160
|
+
reference-date="2026-01-15"
|
|
161
|
+
value='{"timezone":"UTC","days":{"mon":["09:00-17:00"]}}'></zn-schedule-builder>`);
|
|
162
|
+
|
|
163
|
+
// London is UTC+0 in January.
|
|
164
|
+
expect(el.displayedDays.mon).to.deep.equal([{start: '09:00', end: '17:00'}]);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should roll hours onto the next day when the offset pushes them past midnight', async () => {
|
|
168
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
169
|
+
<zn-schedule-builder
|
|
170
|
+
display-timezone="Asia/Tokyo"
|
|
171
|
+
value='{"timezone":"UTC","days":{"mon":["23:00-24:00"]}}'></zn-schedule-builder>`);
|
|
172
|
+
|
|
173
|
+
expect(el.displayedDays.mon).to.deep.equal([]);
|
|
174
|
+
expect(el.displayedDays.tue).to.deep.equal([{start: '08:00', end: '09:00'}]);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should wrap Sunday hours around to Monday', async () => {
|
|
178
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
179
|
+
<zn-schedule-builder
|
|
180
|
+
display-timezone="Asia/Tokyo"
|
|
181
|
+
value='{"timezone":"UTC","days":{"sun":["20:00-22:00"]}}'></zn-schedule-builder>`);
|
|
182
|
+
|
|
183
|
+
expect(el.displayedDays.mon).to.deep.equal([{start: '05:00', end: '07:00'}]);
|
|
184
|
+
expect(el.displayedDays.sun).to.deep.equal([]);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('should convert edits made in the display timezone back to UTC', async () => {
|
|
188
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
189
|
+
<zn-schedule-builder display-timezone="Asia/Tokyo" save-timezone="UTC"></zn-schedule-builder>`);
|
|
190
|
+
|
|
191
|
+
el.setDisplayDay('tue', [{start: '09:00', end: '17:00'}]);
|
|
192
|
+
await el.updateComplete;
|
|
193
|
+
|
|
194
|
+
expect(el.getDay('tue')).to.deep.equal([{start: '00:00', end: '08:00'}]);
|
|
195
|
+
expect(el.displayedDays.tue).to.deep.equal([{start: '09:00', end: '17:00'}]);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('should convert incoming data expressed in another timezone', async () => {
|
|
199
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
200
|
+
<zn-schedule-builder
|
|
201
|
+
save-timezone="UTC"
|
|
202
|
+
reference-date="2026-07-15"
|
|
203
|
+
value='{"timezone":"Europe/London","days":{"mon":["09:00-17:00"]}}'></zn-schedule-builder>`);
|
|
204
|
+
|
|
205
|
+
expect(el.getDay('mon')).to.deep.equal([{start: '08:00', end: '16:00'}]);
|
|
206
|
+
expect(parseSchedule(el.value).timezone).to.equal('UTC');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('should adopt the value timezone when none is configured', async () => {
|
|
210
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
211
|
+
<zn-schedule-builder value='{"timezone":"Europe/London","days":{"mon":["09:00-17:00"]}}'></zn-schedule-builder>`);
|
|
212
|
+
|
|
213
|
+
expect(el.getDay('mon')).to.deep.equal([{start: '09:00', end: '17:00'}]);
|
|
214
|
+
expect(parseSchedule(el.value).timezone).to.equal('Europe/London');
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('should render the timezone picker only when asked', async () => {
|
|
218
|
+
const without: ZnScheduleBuilder = await fixture(html`
|
|
219
|
+
<zn-schedule-builder></zn-schedule-builder>`);
|
|
220
|
+
expect(without.shadowRoot?.querySelector('zn-select')).to.not.exist;
|
|
221
|
+
|
|
222
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
223
|
+
<zn-schedule-builder show-timezone display-timezone="Europe/London"></zn-schedule-builder>`);
|
|
224
|
+
const select = el.shadowRoot?.querySelector('zn-select');
|
|
225
|
+
|
|
226
|
+
expect(select).to.exist;
|
|
227
|
+
expect(el.shadowRoot?.querySelectorAll('zn-option').length).to.be.greaterThan(1);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const optionValues = (el: ZnScheduleBuilder) =>
|
|
231
|
+
[...(el.shadowRoot?.querySelectorAll('zn-option') ?? [])].map(option => option.getAttribute('value') ?? '');
|
|
232
|
+
|
|
233
|
+
it('should expand the named timezone sets', async () => {
|
|
234
|
+
const offsets: ZnScheduleBuilder = await fixture(html`
|
|
235
|
+
<zn-schedule-builder show-timezone timezones="offsets"></zn-schedule-builder>`);
|
|
236
|
+
const common: ZnScheduleBuilder = await fixture(html`
|
|
237
|
+
<zn-schedule-builder show-timezone timezones="common"></zn-schedule-builder>`);
|
|
238
|
+
const all: ZnScheduleBuilder = await fixture(html`
|
|
239
|
+
<zn-schedule-builder show-timezone timezones="all"></zn-schedule-builder>`);
|
|
240
|
+
|
|
241
|
+
expect(optionValues(offsets).length).to.be.greaterThan(20);
|
|
242
|
+
expect(optionValues(common).length).to.be.greaterThan(optionValues(offsets).length);
|
|
243
|
+
expect(optionValues(all).length).to.be.greaterThan(optionValues(common).length);
|
|
244
|
+
expect(optionValues(common)).to.include('Asia/Kathmandu');
|
|
245
|
+
expect(optionValues(offsets)).to.not.include('Asia/Kathmandu');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should cover every offset in the offsets set from the common set', async () => {
|
|
249
|
+
const offsets: ZnScheduleBuilder = await fixture(html`
|
|
250
|
+
<zn-schedule-builder show-timezone timezones="offsets"></zn-schedule-builder>`);
|
|
251
|
+
const common: ZnScheduleBuilder = await fixture(html`
|
|
252
|
+
<zn-schedule-builder show-timezone timezones="common"></zn-schedule-builder>`);
|
|
253
|
+
|
|
254
|
+
const offsetsOf = (zones: string[]) => new Set(zones.flatMap(zone =>
|
|
255
|
+
['2026-01-15T12:00:00Z', '2026-07-15T12:00:00Z'].map(when => {
|
|
256
|
+
const parts = new Intl.DateTimeFormat('en-US', {
|
|
257
|
+
timeZone: zone, hour12: false,
|
|
258
|
+
year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit'
|
|
259
|
+
}).formatToParts(new Date(when));
|
|
260
|
+
const read = (type: string) => Number(parts.find(part => part.type === type)?.value);
|
|
261
|
+
const utc = Date.UTC(read('year'), read('month') - 1, read('day'), read('hour') % 24, read('minute'));
|
|
262
|
+
return Math.round((utc - new Date(when).getTime()) / 60000);
|
|
263
|
+
})));
|
|
264
|
+
|
|
265
|
+
const covered = offsetsOf(optionValues(common));
|
|
266
|
+
[...offsetsOf(optionValues(offsets))].forEach(offset => expect(covered).to.include(offset));
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('should offer the English-speaking set under friendly names', async () => {
|
|
270
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
271
|
+
<zn-schedule-builder show-timezone timezones="en" display-timezone="Europe/London"></zn-schedule-builder>`);
|
|
272
|
+
|
|
273
|
+
expect(optionValues(el)).to.include.members([
|
|
274
|
+
'America/New_York', 'America/Chicago', 'America/Denver', 'America/Los_Angeles',
|
|
275
|
+
'Europe/London', 'Australia/Sydney'
|
|
276
|
+
]);
|
|
277
|
+
|
|
278
|
+
const labels = [...(el.shadowRoot?.querySelectorAll('zn-option') ?? [])].map(o => o.textContent?.trim() ?? '');
|
|
279
|
+
expect(labels.some(label => label.startsWith('US Eastern ('))).to.be.true;
|
|
280
|
+
expect(labels.some(label => label.startsWith('US Mountain ('))).to.be.true;
|
|
281
|
+
expect(labels.some(label => label.startsWith('UK ('))).to.be.true;
|
|
282
|
+
expect(labels.some(label => label.startsWith('Australia ('))).to.be.true;
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('should keep the friendly label when a set is combined with plain zones', async () => {
|
|
286
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
287
|
+
<zn-schedule-builder show-timezone
|
|
288
|
+
timezones="en America/New_York Asia/Tokyo"
|
|
289
|
+
display-timezone="Europe/London"></zn-schedule-builder>`);
|
|
290
|
+
|
|
291
|
+
const newYork = [...(el.shadowRoot?.querySelectorAll('zn-option') ?? [])]
|
|
292
|
+
.filter(option => option.getAttribute('value') === 'America/New_York');
|
|
293
|
+
|
|
294
|
+
expect(newYork).to.have.lengthOf(1);
|
|
295
|
+
expect(newYork[0].textContent?.trim()).to.match(/^US Eastern \(/);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('should mix named sets with explicit zones', async () => {
|
|
299
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
300
|
+
<zn-schedule-builder show-timezone timezones="UTC Europe/London Asia/Tokyo"></zn-schedule-builder>`);
|
|
301
|
+
|
|
302
|
+
// The viewer's own zone is always added so the current selection is never unreachable.
|
|
303
|
+
expect(optionValues(el)).to.include.members(['UTC', 'Europe/London', 'Asia/Tokyo']);
|
|
304
|
+
expect(optionValues(el).length).to.be.lessThan(10);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('should not emit zn-change when only the display timezone changes', async () => {
|
|
308
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
309
|
+
<zn-schedule-builder show-timezone value='{"mon":["09:00-17:00"]}'></zn-schedule-builder>`);
|
|
310
|
+
|
|
311
|
+
const before = el.value;
|
|
312
|
+
let changed = false;
|
|
313
|
+
el.addEventListener('zn-change', () => (changed = true));
|
|
314
|
+
|
|
315
|
+
el.displayTimezone = 'Asia/Tokyo';
|
|
316
|
+
await el.updateComplete;
|
|
317
|
+
|
|
318
|
+
expect(changed).to.be.false;
|
|
319
|
+
expect(el.value).to.equal(before);
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it('should be invalid when required and empty', async () => {
|
|
324
|
+
const el: ZnScheduleBuilder = await fixture(html`
|
|
325
|
+
<zn-schedule-builder required></zn-schedule-builder>`);
|
|
326
|
+
|
|
327
|
+
expect(el.checkValidity()).to.be.false;
|
|
328
|
+
|
|
329
|
+
el.setDay('mon', [{start: '09:00', end: '17:00'}]);
|
|
330
|
+
await el.updateComplete;
|
|
331
|
+
|
|
332
|
+
expect(el.checkValidity()).to.be.true;
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('should submit the schedule as JSON with the form', async () => {
|
|
336
|
+
const form: HTMLFormElement = await fixture(html`
|
|
337
|
+
<form>
|
|
338
|
+
<zn-schedule-builder name="hours" value="${scheduleValue}"></zn-schedule-builder>
|
|
339
|
+
</form>`);
|
|
340
|
+
|
|
341
|
+
const data = new FormData(form);
|
|
342
|
+
expect(parseSchedule(String(data.get('hours'))).days.mon).to.deep.equal([{start: '08:00', end: '18:00'}]);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
@@ -26,6 +26,7 @@ import styles from './toggle.scss';
|
|
|
26
26
|
*
|
|
27
27
|
* @csspart base - The component's base wrapper containing the toggle switch.
|
|
28
28
|
* @csspart control - The toggle switch control (the circular button that slides).
|
|
29
|
+
* @csspart label - The toggle's label.
|
|
29
30
|
* @csspart description - The container that wraps the toggle's description.
|
|
30
31
|
*
|
|
31
32
|
* @cssproperty --zn-toggle-margin - The margin around the toggle switch. Defaults to `8px 0`.
|
|
@@ -218,7 +219,7 @@ export default class ZnToggle extends ZincElement implements ZincFormControl {
|
|
|
218
219
|
<label>
|
|
219
220
|
${this.label || hasDescription ? html`
|
|
220
221
|
<div class="switch__label-wrapper">
|
|
221
|
-
${this.label ? html`<p class="switch-label">${this.label}</p>` : ''}
|
|
222
|
+
${this.label ? html`<p part="label" class="switch-label">${this.label}</p>` : ''}
|
|
222
223
|
<div part="description"
|
|
223
224
|
id="description"
|
|
224
225
|
class="switch__description"
|
package/src/zinc.ts
CHANGED
|
@@ -114,6 +114,7 @@ export { default as PreviewFrame } from './components/preview-frame';
|
|
|
114
114
|
export { default as ThemeEditor } from './components/theme-editor';
|
|
115
115
|
export { default as SlashMenu } from './components/slash-menu';
|
|
116
116
|
export { default as SlashItem } from './components/slash-item';
|
|
117
|
+
export { default as ScheduleBuilder } from './components/schedule-builder';
|
|
117
118
|
/* plop:component */
|
|
118
119
|
|
|
119
120
|
// Base Component
|