kemet-ui 1.0.1 → 1.3.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.
Files changed (31) hide show
  1. package/custom-elements.json +5673 -3259
  2. package/dist/components/kemet-carousel/kemet-carousel-current.js +36 -0
  3. package/dist/components/kemet-carousel/kemet-carousel-first.js +47 -0
  4. package/dist/components/kemet-carousel/kemet-carousel-last.js +47 -0
  5. package/dist/components/kemet-carousel/kemet-carousel-link.js +59 -0
  6. package/dist/components/kemet-carousel/kemet-carousel-next.js +47 -0
  7. package/dist/components/kemet-carousel/kemet-carousel-prev.js +47 -0
  8. package/dist/components/kemet-carousel/kemet-carousel-slide.js +51 -0
  9. package/dist/components/kemet-carousel/kemet-carousel-total.js +36 -0
  10. package/dist/components/kemet-carousel/kemet-carousel.js +492 -0
  11. package/dist/components/kemet-combo/kemet-combo.js +7 -3
  12. package/dist/components/kemet-fab/kemet-fab.js +209 -0
  13. package/dist/components/kemet-input/kemet-input.js +15 -4
  14. package/dist/components/kemet-modal/kemet-modal.js +1 -1
  15. package/dist/components/kemet-password/kemet-password.js +278 -0
  16. package/dist/components/kemet-sortable/kemet-sortable-item.js +42 -0
  17. package/dist/components/kemet-sortable/kemet-sortable.js +93 -0
  18. package/dist/components/kemet-tracker/kemet-tracker-step.js +239 -0
  19. package/dist/components/kemet-tracker/kemet-tracker.js +76 -0
  20. package/dist/components/kemet-upload/kemet-upload-file.js +167 -0
  21. package/dist/components/kemet-upload/kemet-upload-file.loaders.styles.js +53 -0
  22. package/dist/components/kemet-upload/kemet-upload.js +260 -0
  23. package/dist/kemet-components.cjs +7377 -5085
  24. package/dist/kemet-components.js +7372 -5086
  25. package/dist/kemet-components.min.js +889 -190
  26. package/dist/styles/kemet.components.css +1 -80
  27. package/dist/styles/kemet.components.css.map +1 -1
  28. package/dist/styles/kemet.components.scss +0 -1
  29. package/dist/utilities/controllers/forms.js +4 -2
  30. package/package.json +19 -15
  31. package/dist/styles/components/carousel.scss +0 -64
@@ -0,0 +1,492 @@
1
+ import { html, css, LitElement } from 'lit';
2
+
3
+ export default class KemetCarousel extends LitElement {
4
+ static get styles() {
5
+ return css`
6
+ :host,
7
+ *,
8
+ *::before,
9
+ *::after {
10
+ box-sizing: border-box;
11
+ }
12
+
13
+ :host {
14
+ position: relative;
15
+ display: grid;
16
+ grid-template-columns: minmax(0, 1fr);
17
+ align-items: center;
18
+ width: var(--kemet-carousel-width, 100%);
19
+ height: var(--kemet-carousel-height, auto);
20
+ overflow: visible;
21
+ }
22
+
23
+ :host([arrows]) {
24
+ grid-template-columns: auto minmax(0, 1fr) auto;
25
+ }
26
+
27
+ .toolbar {
28
+ display: flex;
29
+ gap: var(--kemet-carousel-toolbar-gap, 1rem);
30
+ align-items: center;
31
+ justify-content: var(--kemet-carousel-toolbar-justify-content, center);
32
+ line-height: 1;
33
+ padding: var(--kemet-carousel-toolbar-padding, 1rem);
34
+ }
35
+
36
+ :host([inner]) .toolbar {
37
+ width: var(--kemet-carousel-toolbar-inner-width, 100%);
38
+ position: absolute;
39
+ bottom: var(--kemet-carousel-toolbar-inner-bottom, 0);
40
+ top: var(--kemet-carousel-toolbar-inner-top, auto);
41
+ color: var(--kemet-carousel-toolbar-inner-color, var(--kemet-color-white));
42
+ background-color: var(--kemet-carousel-toolbar-inner-background-color, rgba(0, 0, 0, 0.4));
43
+ }
44
+
45
+ .slides {
46
+ overflow: hidden;
47
+ position: relative;
48
+ padding: 1rem 0;
49
+ border: var(--kemet-carousel-slides-border, 1px solid var(--kemet-color-gray1));
50
+ }
51
+
52
+ .slider {
53
+ display: flex;
54
+ flex-wrap: nowrap;
55
+ transition: transform var(--kemet-carousel-transition-speed, 300ms) ease;
56
+ }
57
+
58
+ ::slotted([slot='next']),
59
+ ::slotted([slot='prev']) {
60
+ opacity: var(--kemet-carousel-arrows-opacity, 0.25);
61
+ transition: opacity var(--kemet-carousel-arrows-transition-speed, 300ms) ease-in-out;
62
+ }
63
+
64
+ :host(:hover) ::slotted([slot='next']),
65
+ :host(:hover) ::slotted([slot='prev']) {
66
+ opacity: var(--kemet-carousel-arrows-opacity-hover, 1);
67
+ }
68
+ `;
69
+ }
70
+
71
+ static get properties() {
72
+ return {
73
+ /**
74
+ * The current slide index.
75
+ */
76
+ index: {
77
+ type: Number,
78
+ reflect: true,
79
+ },
80
+ /**
81
+ * The total amount of slides
82
+ */
83
+ total: {
84
+ type: Number,
85
+ },
86
+ /**
87
+ * The width of the slider
88
+ */
89
+ sliderWidth: {
90
+ type: String,
91
+ },
92
+ /**
93
+ * The X position of the slider
94
+ */
95
+ sliderTranslateX: {
96
+ type: String,
97
+ },
98
+ /**
99
+ * Displays the toolbar inside the carousel container
100
+ */
101
+ inner: {
102
+ type: Boolean,
103
+ reflect: true,
104
+ },
105
+ /**
106
+ * Determines whether or not to display arrows
107
+ */
108
+ arrows: {
109
+ type: Boolean,
110
+ reflect: true,
111
+ },
112
+ /**
113
+ * Default options for the carousel
114
+ */
115
+ options: {
116
+ type: Object,
117
+ },
118
+ /**
119
+ * Options are different breakpoints for the carousel. Is mobile first.
120
+ */
121
+ breakpoints: {
122
+ type: Object,
123
+ },
124
+ };
125
+ }
126
+
127
+ constructor() {
128
+ super();
129
+
130
+ // managed properties
131
+ this.index = 0;
132
+ this.total = 0;
133
+ this.sliderWidth = 'auto';
134
+ this.sliderTranslateX = '0';
135
+ this.inner = false;
136
+ this.arrows = false;
137
+ this.options = {
138
+ perView: 1,
139
+ perMove: 1,
140
+ gap: 12,
141
+ slideshow: 0,
142
+ rewind: true,
143
+ center: false,
144
+ };
145
+ this.breakpoints = {
146
+ 768: {
147
+ perView: 2,
148
+ gap: 24,
149
+ rewind: false,
150
+ },
151
+ 1280: {
152
+ perView: 2.5,
153
+ center: true,
154
+ },
155
+ };
156
+
157
+ // bindings
158
+ this.addEventListener('kemet-carousel-first', this.handleFirst.bind(this));
159
+ this.addEventListener('kemet-carousel-last', this.handleLast.bind(this));
160
+ this.addEventListener('kemet-carousel-next', this.handleNext.bind(this));
161
+ this.addEventListener('kemet-carousel-prev', this.handlePrev.bind(this));
162
+ this.addEventListener('kemet-carousel-link', this.handleLink.bind(this));
163
+ }
164
+
165
+ firstUpdated() {
166
+ // standard properties
167
+ this.slides = [];
168
+ this.links = [];
169
+
170
+ // elements
171
+ this.containerElement = this.shadowRoot.querySelector('[part="container"]');
172
+ this.slidesElement = this.shadowRoot.querySelector('[part="slides"]');
173
+ this.sliderElement = this.shadowRoot.querySelector('[part="slider"]');
174
+ this.toolbarElement = this.shadowRoot.querySelector('[part="toolbar"]');
175
+ this.toolbarSlotElement = this.querySelector('[slot="toolbar"]');
176
+ this.informationElement = this.querySelector('kemet-carousel-information');
177
+
178
+ // events
179
+ window.addEventListener('resize', () => {
180
+ this.setSlideSize();
181
+ this.setToolbarSize();
182
+ this.updateIndex(this.index);
183
+ });
184
+
185
+ this.sliderElement.addEventListener('transitionend', this.handleTransitionEnd.bind(this));
186
+
187
+ // methods
188
+ this.swipeMove = (event) => {
189
+ event.preventDefault();
190
+
191
+ const pageX = event.touches ? event.touches[0].pageX : event.pageX;
192
+ const currentSlide = this.slides[this.index];
193
+
194
+ this.sliderTranslateX = `${pageX - this.startX - currentSlide.offsetLeft}px`;
195
+ };
196
+
197
+ this.handleSlideShow = () => {
198
+ if (this.getOption('slideshow') > 0) {
199
+ this.updateIndex(this.index + 1);
200
+ clearTimeout(this.handleSlideShow);
201
+ }
202
+ };
203
+
204
+ // setup
205
+ this.setSlideSize();
206
+ this.goToSlide(this.index);
207
+ }
208
+
209
+ updated(prevProps) {
210
+ this.setSlideSize();
211
+ this.setToolbarSize();
212
+
213
+ if (prevProps.has('index')) {
214
+ this.updateIndex(this.index);
215
+ setTimeout(this.handleSlideShow, this.getOption('slideshow') * 1000);
216
+ }
217
+ }
218
+
219
+ render() {
220
+ return html`
221
+ <slot name="prev" @slotchange=${this.handleArrows}></slot>
222
+ <div class="container" part="container">
223
+ <section
224
+ class="slides"
225
+ part="slides"
226
+ @mousedown=${this.swipeStart}
227
+ @mouseup=${this.swipeEnd}
228
+ @touchstart=${this.swipeStart}
229
+ @touchend=${this.swipeEnd}
230
+ @mouseleave=${this.swipeLeave}
231
+ >
232
+ <div class="slider" part="slider" style="width:${this.sliderWidth}; transform:translateX(${this.sliderTranslateX});">
233
+ <slot name="slides" @slotchange="${this.handleSlotChange}"></slot>
234
+ </div>
235
+ </section>
236
+ ${this.makeToolbar()}
237
+ </div>
238
+ <slot name="next" @slotchange=${this.handleArrows}></slot>
239
+ `;
240
+ }
241
+
242
+ swipeStart(event) {
243
+ this.startX = event.touches ? event.touches[0].pageX : event.pageX;
244
+
245
+ this.addEventListener('mousemove', this.swipeMove);
246
+ this.addEventListener('touchmove', this.swipeMove);
247
+ }
248
+
249
+ swipeEnd(event) {
250
+ this.updateIndex(this.swipeUpdate(event));
251
+ this.removeEventListener('mousemove', this.swipeMove, false);
252
+ this.removeEventListener('touchmove', this.swipeMove, false);
253
+ }
254
+
255
+ swipeUpdate(event) {
256
+ const pageX = event.changedTouches ? event.changedTouches[0].pageX : event.pageX;
257
+ const direction = this.startX > pageX ? 'right' : 'left';
258
+ const threshold = this.slidesElement.offsetWidth / 3;
259
+ const diff = this.startX - pageX;
260
+ const shouldUpdate = Math.abs(diff) > threshold;
261
+
262
+ let { index } = this;
263
+
264
+ if (shouldUpdate && direction === 'right') {
265
+ index = this.index >= this.slides.length - 1 ? this.index : this.index + 1;
266
+ }
267
+
268
+ if (shouldUpdate && direction === 'left') {
269
+ index = this.index < 1 ? 0 : this.index - 1;
270
+ }
271
+
272
+ return index;
273
+ }
274
+
275
+ swipeLeave() {
276
+ this.updateIndex(this.index);
277
+ this.removeEventListener('mousemove', this.swipeMove, false);
278
+ this.removeEventListener('touchmove', this.swipeMove, false);
279
+ }
280
+
281
+ setSlideSize() {
282
+ this.slideWidth = this.containerElement.offsetWidth / this.getOption('perView');
283
+
284
+ this.slides.forEach((slide) => {
285
+ slide.style.marginLeft = `${this.getOption('gap') / 2}px`;
286
+ slide.style.marginRight = `${this.getOption('gap') / 2}px`;
287
+ slide.style.width = `${this.slideWidth - this.getOption('gap')}px`;
288
+ });
289
+
290
+ this.sliderWidth = `${this.slideWidth * this.slides.length}px`;
291
+ }
292
+
293
+ setToolbarSize() {
294
+ if (this.inner && this.toolbarElement) {
295
+ const width = this.slidesElement.offsetWidth;
296
+ this.toolbarElement.style.width = `${width}px`;
297
+ }
298
+ }
299
+
300
+ makeToolbar() {
301
+ if (this.toolbarSlotElement) {
302
+ return html`
303
+ <section class="toolbar" part="toolbar">
304
+ <slot name="toolbar"></slot>
305
+ </section>
306
+ `;
307
+ }
308
+
309
+ return null;
310
+ }
311
+
312
+ handleSlotChange() {
313
+ const slides = this.querySelectorAll('kemet-carousel-slide');
314
+ const links = this.querySelectorAll('kemet-carousel-link');
315
+
316
+ // handle slides
317
+ slides.forEach((slide) => {
318
+ this.slides.push(slide);
319
+ });
320
+
321
+ this.updateInformation();
322
+ this.total = slides.length;
323
+ slides[this.index].selected = true;
324
+
325
+ // handle links
326
+ links.forEach((link) => {
327
+ this.links.push(link);
328
+ });
329
+ }
330
+
331
+ handleArrows() {
332
+ this.arrows = true;
333
+ }
334
+
335
+ handleFirst() {
336
+ this.updateIndex(0);
337
+ }
338
+
339
+ handleLast() {
340
+ this.updateIndex(this.slides.length - 1);
341
+ }
342
+
343
+ handleNext() {
344
+ let newIndex = this.index + this.getOption('perMove');
345
+
346
+ if (newIndex >= this.slides.length) {
347
+ if (this.getOption('rewind')) {
348
+ newIndex = 0;
349
+ } else {
350
+ newIndex = this.index;
351
+ }
352
+ }
353
+
354
+ this.updateIndex(newIndex);
355
+ }
356
+
357
+ handlePrev() {
358
+ let newIndex = this.index - this.getOption('perMove');
359
+
360
+ // send them to the last slide
361
+ if (newIndex < 0) {
362
+ if (this.getOption('rewind')) {
363
+ newIndex = this.slides.length - 1;
364
+ } else {
365
+ newIndex = this.index;
366
+ }
367
+ }
368
+
369
+ this.updateIndex(newIndex);
370
+ }
371
+
372
+ updateIndex(newIndex) {
373
+ let currentSlide = this.slides[this.index];
374
+ let currentLink = this.links[newIndex];
375
+
376
+ // remove selected from all links
377
+ this.links.forEach((link) => {
378
+ link.selected = false;
379
+ });
380
+
381
+ // if current link is invalid assume it's the first link
382
+ if (!currentLink) {
383
+ [currentLink] = this.links;
384
+ }
385
+
386
+ // add selected to current link
387
+ if (currentLink) {
388
+ currentLink.selected = true;
389
+ }
390
+
391
+ if (currentSlide) {
392
+ currentSlide.setAttribute('aria-hidden', 'true');
393
+
394
+ // correct for invalid indexes
395
+ if (newIndex > -1 && newIndex < this.slides.length) {
396
+ this.index = newIndex;
397
+ } else {
398
+ // eslint-disable-next-line no-console
399
+ console.warn('An invalid index number was entered. The kemet-carousel has been reset to the first slide.');
400
+ this.index = 0;
401
+ }
402
+
403
+ // move
404
+ this.goToSlide(this.index);
405
+
406
+ // update new slide
407
+ currentSlide = this.slides[this.index];
408
+ currentSlide.setAttribute('aria-hidden', 'false');
409
+
410
+ this.slides.forEach((slide) => {
411
+ slide.selected = false;
412
+ });
413
+
414
+ currentSlide.selected = true;
415
+
416
+ // notify consumers of slide change
417
+
418
+ /**
419
+ * Fires with the a slide has begun to change
420
+ */
421
+ this.dispatchEvent(new CustomEvent('kemet-carousel-change-start', {
422
+ bubbles: true,
423
+ composed: true,
424
+ detail: this,
425
+ }));
426
+
427
+ // update information element
428
+ this.updateInformation();
429
+ }
430
+ }
431
+
432
+ updateInformation() {
433
+ this.informationSlot = this.slides[this.index].querySelector('[slot="information"]');
434
+
435
+ if (this.informationElement) {
436
+ if (this.informationSlot) {
437
+ this.informationElement.innerHTML = this.informationSlot.outerHTML;
438
+ } else {
439
+ this.informationElement.innerHTML = '';
440
+ }
441
+ }
442
+ }
443
+
444
+ goToSlide(index) {
445
+ if (this.getOption('center') === true) {
446
+ const slidesCenter = this.slidesElement.offsetWidth / 2;
447
+ const slideX = this.slideWidth * index;
448
+ this.sliderTranslateX = `${slideX - (slideX - slidesCenter) - this.slideWidth / 2 - slideX}px`;
449
+ } else {
450
+ this.sliderTranslateX = `${(this.slideWidth * index) * -1}px`;
451
+ }
452
+ }
453
+
454
+ handleTransitionEnd() {
455
+ const currentElement = this.querySelector('kemet-carousel-current');
456
+
457
+ if (currentElement) {
458
+ currentElement.current = this.index + 1;
459
+ }
460
+
461
+ /**
462
+ * Fires when a slide has changed and finished animating
463
+ */
464
+ this.dispatchEvent(new CustomEvent('kemet-carousel-change-finished', {
465
+ bubbles: true,
466
+ composed: true,
467
+ detail: this,
468
+ }));
469
+ }
470
+
471
+ handleLink(event) {
472
+ this.updateIndex(event.detail.slide);
473
+ }
474
+
475
+ getOption(option) {
476
+ const breakpoints = Object.keys(this.breakpoints);
477
+ let value = this.options[option];
478
+
479
+ breakpoints.forEach((breakpoint) => {
480
+ if (window.matchMedia(`(min-width: ${breakpoint}px)`).matches && this.breakpoints[breakpoint][option] !== undefined) {
481
+ value = this.breakpoints[breakpoint][option];
482
+ }
483
+
484
+ return value;
485
+ });
486
+
487
+ return value;
488
+ }
489
+ }
490
+
491
+ // eslint-disable-next-line no-unused-expressions
492
+ customElements.get('kemet-carousel') || customElements.define('kemet-carousel', KemetCarousel);
@@ -84,7 +84,7 @@ export default class KemetCombo extends LitElement {
84
84
  this.input = this.field.querySelector('[slot="input"]');
85
85
 
86
86
  // managed properties
87
- this.slug = this.field.slug;
87
+ this.slug = this.field.slug || 'slug';
88
88
 
89
89
  // events listeners
90
90
  this.input.addEventListener('kemet-input-input', this.handleInput.bind(this));
@@ -99,7 +99,7 @@ export default class KemetCombo extends LitElement {
99
99
  aria-controls="${this.slug}-listbox"
100
100
  aria-haspopup="listbox"
101
101
  id="${this.slug}-combobox"
102
- aria-label="${this.field.label}"
102
+ aria-label="${this.field?.label}"
103
103
  >
104
104
  <ul role="listbox" aria-labelledby="${this.slug}-label" id="${this.slug}-listbox">
105
105
  ${this.makeOptions()}
@@ -154,7 +154,11 @@ export default class KemetCombo extends LitElement {
154
154
  new CustomEvent('kemet-combo-selection', {
155
155
  bubbles: true,
156
156
  composed: true,
157
- detail: event.target.getAttribute('id'),
157
+ detail: {
158
+ element: event.target,
159
+ text: event.target.innerText,
160
+ id: event.target.getAttribute('id'),
161
+ },
158
162
  }),
159
163
  );
160
164
  }