kemet-ui 0.2.0 → 1.0.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 (66) hide show
  1. package/custom-elements.json +5546 -855
  2. package/dist/components/kemet-accordion-panel.js +178 -0
  3. package/dist/components/kemet-accordion.js +105 -72
  4. package/dist/components/kemet-badge.js +102 -0
  5. package/dist/components/kemet-button.js +230 -0
  6. package/dist/components/kemet-checkbox.js +298 -0
  7. package/dist/components/kemet-combo.js +207 -0
  8. package/dist/components/kemet-count.js +112 -0
  9. package/dist/components/kemet-draggable.js +19 -6
  10. package/dist/components/kemet-drawer.js +38 -15
  11. package/dist/components/kemet-drawer.styles.js +6 -0
  12. package/dist/components/kemet-field.js +233 -0
  13. package/dist/components/kemet-flipcard-trigger.js +4 -5
  14. package/dist/components/kemet-flipcard.js +26 -3
  15. package/dist/components/kemet-icon.js +19 -3
  16. package/dist/components/kemet-input.js +650 -0
  17. package/dist/components/kemet-modal-close.js +23 -4
  18. package/dist/components/kemet-modal.js +78 -13
  19. package/dist/components/kemet-modal.styles.js +14 -2
  20. package/dist/components/kemet-option.js +45 -0
  21. package/dist/components/kemet-popover-close.js +1 -1
  22. package/dist/components/kemet-popover.js +75 -12
  23. package/dist/components/kemet-radio.js +214 -0
  24. package/dist/components/kemet-radios.js +218 -0
  25. package/dist/components/kemet-rotator.js +23 -4
  26. package/dist/components/kemet-scroll-link.js +21 -2
  27. package/dist/components/kemet-scroll-nav.js +25 -2
  28. package/dist/components/kemet-scroll-snap-paginator.js +68 -26
  29. package/dist/components/kemet-scroll-snap-slide.js +23 -13
  30. package/dist/components/kemet-scroll-snap.js +31 -16
  31. package/dist/components/kemet-select.js +365 -0
  32. package/dist/components/kemet-svg.js +18 -2
  33. package/dist/components/kemet-svgs.js +7 -3
  34. package/dist/components/kemet-tab-panel.js +15 -1
  35. package/dist/components/kemet-tab.js +48 -1
  36. package/dist/components/kemet-tabs.js +289 -83
  37. package/dist/components/kemet-tabs.styles.js +200 -0
  38. package/dist/components/kemet-textarea.js +395 -0
  39. package/dist/components/kemet-toggle.js +225 -0
  40. package/dist/kemet-components.cjs +5128 -1200
  41. package/dist/kemet-components.js +5117 -1173
  42. package/dist/kemet-components.min.js +1536 -421
  43. package/dist/styles/kemet.components.css +12 -260
  44. package/dist/styles/kemet.components.css.map +1 -1
  45. package/dist/styles/kemet.core.css +2371 -503
  46. package/dist/styles/kemet.core.css.map +1 -1
  47. package/dist/styles/scss/components/_config.scss +0 -25
  48. package/dist/styles/scss/components/accordion.scss +4 -53
  49. package/dist/styles/scss/components/modal.scss +5 -9
  50. package/dist/styles/scss/components/scrollsnap.scss +0 -57
  51. package/dist/styles/scss/core/_config.scss +160 -3
  52. package/dist/styles/scss/core/_helpers.scss +109 -2
  53. package/dist/styles/scss/core/attributes.scss +16 -0
  54. package/dist/styles/scss/core/base.scss +38 -0
  55. package/dist/styles/scss/core/layout.scss +6 -5
  56. package/dist/styles/scss/kemet.components.scss +0 -2
  57. package/dist/styles/scss/kemet.core.scss +1 -2
  58. package/package.json +34 -56
  59. package/dist/components/kemet-carousel-link.js +0 -54
  60. package/dist/components/kemet-carousel-next.js +0 -46
  61. package/dist/components/kemet-carousel-prev.js +0 -46
  62. package/dist/components/kemet-carousel-slide.js +0 -83
  63. package/dist/components/kemet-carousel.js +0 -236
  64. package/dist/components/kemet-ratio.js +0 -61
  65. package/dist/styles/scss/components/flipcard.scss +0 -14
  66. package/dist/styles/scss/components/tabs.scss +0 -73
@@ -1,7 +1,7 @@
1
1
  import { html, LitElement } from 'lit';
2
2
  import { stylesBase, stylesEffects } from './kemet-modal.styles.js';
3
3
 
4
- export class KemetModal extends LitElement {
4
+ export default class KemetModal extends LitElement {
5
5
  static get styles() {
6
6
  return [
7
7
  stylesBase,
@@ -23,33 +23,87 @@ export class KemetModal extends LitElement {
23
23
  type: Boolean,
24
24
  attribute: 'close-on-click',
25
25
  },
26
+ breakpoint: {
27
+ type: String,
28
+ },
29
+ mobile: {
30
+ type: Boolean,
31
+ reflect: true,
32
+ },
26
33
  };
27
34
  }
28
35
 
29
36
  constructor() {
30
37
  super();
38
+
39
+ // managed properties
31
40
  this.opened = false;
32
41
  this.closeOnClick = false;
42
+ this.breakpoint = '600px';
33
43
 
34
- this.addEventListener('kemet-modal-close-btn', () => { this.opened = false; });
44
+ // bindings
45
+ this.addEventListener('kemet-modal-close-pressed', () => { this.opened = false; });
35
46
  }
36
47
 
37
48
  firstUpdated() {
49
+ // standard properties
50
+ this.focusableSelector = 'body, a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]';
51
+ this.focusableElements = this.querySelectorAll(this.focusableSelector);
52
+
53
+ // events
54
+ this.addEventListener('keyup', (event) => {
55
+ if (event.key === 'Escape') {
56
+ this.opened = false;
57
+ }
58
+ });
59
+
38
60
  this.addEventListener('click', (event) => {
39
61
  if (this.opened && this.closeOnClick && event.target.tagName.toLowerCase() === 'kemet-modal') {
40
62
  this.opened = false;
41
63
  }
42
64
  });
65
+
66
+ window.addEventListener('resize', () => {
67
+ this.isMobile();
68
+ });
69
+
70
+ this.focusableElements.forEach((element) => {
71
+ element.addEventListener('keydown', event => this.handleFocusableDown(event));
72
+ });
43
73
  }
44
74
 
45
75
  updated(prevProps) {
46
76
  if (!prevProps.get('opened') && this.opened === true) {
47
- this.makeEvent('opened');
77
+ setTimeout(() => {
78
+ this.focusableElements[0].focus();
79
+ }, 100);
80
+
81
+ /**
82
+ * Fires when the modal opens
83
+ */
84
+ this.dispatchEvent(
85
+ new CustomEvent('kemet-modal-opened', {
86
+ bubbles: true,
87
+ composed: true,
88
+ detail: this,
89
+ }),
90
+ );
48
91
  }
49
92
 
50
93
  if (prevProps.get('opened') && this.opened === false) {
51
- this.makeEvent('closed');
94
+ /**
95
+ * Fires when the modal closes
96
+ */
97
+ this.dispatchEvent(
98
+ new CustomEvent('kemet-modal-closed', {
99
+ bubbles: true,
100
+ composed: true,
101
+ detail: this,
102
+ }),
103
+ );
52
104
  }
105
+
106
+ this.isMobile();
53
107
  }
54
108
 
55
109
  render() {
@@ -61,15 +115,26 @@ export class KemetModal extends LitElement {
61
115
  `;
62
116
  }
63
117
 
64
- makeEvent(type) {
65
- this.dispatchEvent(
66
- new CustomEvent(`kemet-modal-${type}`, {
67
- bubbles: true,
68
- composed: true,
69
- detail: this,
70
- }),
71
- );
118
+ isMobile() {
119
+ const mediaQuery = window.matchMedia(`(max-width: ${this.breakpoint})`);
120
+ this.mobile = mediaQuery.matches;
121
+ }
122
+
123
+ handleFocusableDown(event) {
124
+ const firstFocusable = this.focusableElements[0];
125
+ const lastFocusable = this.focusableElements[this.focusableElements.length - 1];
126
+
127
+ if (event.key === 'Tab') {
128
+ if (event.shiftKey && document.activeElement === firstFocusable) {
129
+ event.preventDefault();
130
+ lastFocusable.focus();
131
+ } else if (!event.shiftKey && document.activeElement === lastFocusable) {
132
+ event.preventDefault();
133
+ firstFocusable.focus();
134
+ }
135
+ }
72
136
  }
73
137
  }
74
138
 
75
- window.customElements.define('kemet-modal', KemetModal);
139
+ // eslint-disable-next-line no-unused-expressions
140
+ customElements.get('kemet-modal') || customElements.define('kemet-modal', KemetModal);
@@ -1,6 +1,12 @@
1
1
  import { css } from 'lit';
2
2
 
3
3
  export const stylesBase = css`
4
+ *,
5
+ *::before,
6
+ *::after {
7
+ box-sizing: border-box;
8
+ }
9
+
4
10
  :host {
5
11
  position: fixed;
6
12
  display: flex;
@@ -21,8 +27,14 @@ export const stylesBase = css`
21
27
  position: relative;
22
28
  z-index: 3;
23
29
  margin: auto;
24
- min-width: var(--kemet-modal-min-width, 0);
25
- max-width: var(--kemet-modal-max-width, none);
30
+ min-width: var(--kemet-modal-content-min-width, 0);
31
+ max-width: var(--kemet-modal-content-max-width, none);
32
+ }
33
+
34
+ :host([mobile]) .content {
35
+ min-width: var(--kemet-modal-content-mobile-min-width, 100%);
36
+ min-height: var(--kemet-modal-content-mobile-min-height, 80vh);
37
+ padding: var(--kemet-modal-content-mobile-padding, 1rem);
26
38
  }
27
39
 
28
40
  .overlay {
@@ -0,0 +1,45 @@
1
+ import { html, LitElement } from 'lit';
2
+
3
+ export default class KemetOption extends LitElement {
4
+ static get properties() {
5
+ return {
6
+ /**
7
+ * The label of the option
8
+ */
9
+ label: {
10
+ type: String,
11
+ },
12
+ /**
13
+ * The value of the options
14
+ */
15
+ value: {
16
+ type: String,
17
+ },
18
+ /**
19
+ * Determines whether to disable the option
20
+ */
21
+ disabled: {
22
+ type: Boolean,
23
+ },
24
+ /**
25
+ * Selects the option if true
26
+ */
27
+ selected: {
28
+ type: Boolean,
29
+ },
30
+ };
31
+ }
32
+
33
+ constructor() {
34
+ super();
35
+
36
+ this.value = '';
37
+ }
38
+
39
+ render() {
40
+ return html`<slot></slot>`;
41
+ }
42
+ }
43
+
44
+ // eslint-disable-next-line no-unused-expressions
45
+ customElements.get('kemet-option') || customElements.define('kemet-option', KemetOption);
@@ -6,7 +6,7 @@ const keyCodes = {
6
6
  ESC: 27,
7
7
  };
8
8
 
9
- export class KemetPopoverClose extends LitElement {
9
+ export default class KemetPopoverClose extends LitElement {
10
10
  static get styles() {
11
11
  return [
12
12
  css`
@@ -17,7 +17,7 @@ const keyCodes = {
17
17
  ESC: 27,
18
18
  };
19
19
 
20
- export class KemetPopover extends LitElement {
20
+ export default class KemetPopover extends LitElement {
21
21
  static get styles() {
22
22
  return [
23
23
  css`
@@ -121,33 +121,62 @@ export class KemetPopover extends LitElement {
121
121
 
122
122
  static get properties() {
123
123
  return {
124
+ /**
125
+ * Determines whether or not the popover displays.
126
+ */
124
127
  opened: {
125
128
  type: Boolean,
126
129
  reflect: true,
127
130
  },
131
+ /**
132
+ * The opening and closing effect of the popover. Is optional.
133
+ * Values include:
134
+ * (fade | scale | slide | fall | flip horizontal | flip vertical | sign | super scaled)
135
+ */
128
136
  effect: {
129
137
  string: String,
130
138
  reflect: true,
131
139
  },
140
+ /**
141
+ * Determines the placement of the popover.
142
+ * Values include: (top | right | bottom | left)
143
+ */
132
144
  position: {
133
145
  type: String,
134
146
  reflect: true,
135
147
  },
148
+ /**
149
+ * Adds a built in tooltip to the popover.
150
+ */
136
151
  tooltip: {
137
152
  type: Boolean,
138
153
  },
154
+ /**
155
+ * Adds a custom tooltip to the popover.
156
+ * Use the custom-tooltip slot to specify the custom tooltip.
157
+ */
139
158
  customTooltip: {
140
159
  type: Boolean,
141
160
  attribute: 'custom-tooltip',
142
161
  },
162
+ /**
163
+ * Controls how the trigger should activate the popover.
164
+ * Values include: (click | hover)
165
+ */
143
166
  fireOn: {
144
167
  type: String,
145
168
  attribute: 'fire-on',
146
169
  },
170
+ /**
171
+ * Allows the popover to be closed by clicking outside of its content.
172
+ */
147
173
  clickOutside: {
148
174
  type: Boolean,
149
175
  attribute: 'click-outside',
150
176
  },
177
+ /**
178
+ * Intelligently positions the popover.
179
+ */
151
180
  smart: {
152
181
  type: Boolean,
153
182
  },
@@ -170,6 +199,10 @@ export class KemetPopover extends LitElement {
170
199
  }
171
200
 
172
201
  firstUpdated() {
202
+ // standard properties
203
+ this.focusableSelector = 'body, a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable], kemet-popover-close';
204
+ this.focusableElements = this.querySelectorAll(this.focusableSelector);
205
+
173
206
  // eslint-disable-next-line prefer-destructuring
174
207
  this.contentElement = this.shadowRoot
175
208
  .querySelector('slot[name="content"]')
@@ -178,15 +211,39 @@ export class KemetPopover extends LitElement {
178
211
  window.addEventListener('resize', () => {
179
212
  this.smartContent();
180
213
  });
214
+
215
+ if (this.fireOn === 'click') {
216
+ this.focusableElements.forEach((element) => {
217
+ element.addEventListener('keydown', event => this.handleFocusableDown(event));
218
+ });
219
+ }
181
220
  }
182
221
 
183
222
  updated(prevProps) {
184
223
  if (!prevProps.get('opened') && this.opened === true) {
185
- this.makeEvent('opened');
224
+ /**
225
+ * Fires when the popover opens.
226
+ */
227
+ this.dispatchEvent(
228
+ new CustomEvent('kemet-popover-opened', {
229
+ bubbles: true,
230
+ composed: true,
231
+ detail: this,
232
+ }),
233
+ );
186
234
  }
187
235
 
188
236
  if (prevProps.get('opened') && this.opened === false) {
189
- this.makeEvent('closed');
237
+ /**
238
+ * Fires when the popover closes.
239
+ */
240
+ this.dispatchEvent(
241
+ new CustomEvent('kemet-popover-closed', {
242
+ bubbles: true,
243
+ composed: true,
244
+ detail: this,
245
+ }),
246
+ );
190
247
  }
191
248
 
192
249
  this.smartContent();
@@ -247,14 +304,19 @@ export class KemetPopover extends LitElement {
247
304
  }
248
305
  }
249
306
 
250
- makeEvent(type) {
251
- this.dispatchEvent(
252
- new CustomEvent(`kemet-popover-${type}`, {
253
- bubbles: true,
254
- composed: true,
255
- detail: this,
256
- }),
257
- );
307
+ handleFocusableDown(event) {
308
+ const firstFocusable = this.focusableElements[0];
309
+ const lastFocusable = this.focusableElements[this.focusableElements.length - 1];
310
+
311
+ if (event.key === 'Tab') {
312
+ if (event.shiftKey && document.activeElement === firstFocusable) {
313
+ event.preventDefault();
314
+ lastFocusable.focus();
315
+ } else if (!event.shiftKey && document.activeElement === lastFocusable) {
316
+ event.preventDefault();
317
+ firstFocusable.focus();
318
+ }
319
+ }
258
320
  }
259
321
 
260
322
  makeTooltip() {
@@ -361,4 +423,5 @@ export class KemetPopover extends LitElement {
361
423
  }
362
424
  }
363
425
 
364
- window.customElements.define('kemet-popover', KemetPopover);
426
+ // eslint-disable-next-line no-unused-expressions
427
+ customElements.get('kemet-popover') || customElements.define('kemet-popover', KemetPopover);
@@ -0,0 +1,214 @@
1
+ import { html, css, LitElement } from 'lit';
2
+ import { ifDefined } from 'lit/directives/if-defined.js';
3
+ import { live } from 'lit/directives/live.js';
4
+
5
+ export default class KemetRadio extends LitElement {
6
+ static get styles() {
7
+ return [
8
+ css`
9
+ *,
10
+ *::before,
11
+ *::after {
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ :host {
16
+ display: inline-block;
17
+ }
18
+
19
+ :host([disabled]) {
20
+ opacity: 0.5;
21
+ }
22
+
23
+ label {
24
+ cursor: pointer;
25
+ display: inline-flex;
26
+ gap: 0.5rem;
27
+ align-items: center;
28
+ margin-right: 0.5rem;
29
+ }
30
+
31
+ input {
32
+ cursor: pointer;
33
+ margin: 0;
34
+ padding: 0;
35
+ width: var(--kemet-radio-size, 18px);
36
+ height: var(--kemet-radio-size, 18px);
37
+ position: absolute;
38
+ opacity: 0;
39
+ }
40
+
41
+ button {
42
+ display: inline-flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ width: var(--kemet-radio-size, 18px);
46
+ height: var(--kemet-radio-size, 18px);
47
+ padding: 0;
48
+ border-radius: 50%;
49
+ background: none;
50
+ border: var(--kemet-radio-border, 1px solid var(--kemet-color-primary));
51
+ }
52
+
53
+ [part='dot'] {
54
+ display: inline-flex;
55
+ border-radius: 50%;
56
+ width: var(--kemet-radio-size, 18px);
57
+ height: var(--kemet-radio-size, 18px);
58
+ background: var(--kemet-radio-dot-color, var(--kemet-color-primary));
59
+ border: var(--kemet-radio-border, 1px solid var(--kemet-color-primary));
60
+ box-shadow: inset 0px 0px 0px var(--kemet-radio-dot-border-width, 3px) var(--kemet-radio-dot-border-color, var(--kemet-color-white));
61
+ }
62
+
63
+ :host([filled]) [part='dot'] {
64
+ background: var(--kemet-radio-dot-color-filled, var(--kemet-color-white));
65
+ box-shadow: inset 0px 0px 0px var(--kemet-radio-dot-border-width, 4px) var(--kemet-radio-dot-border-color, var(--kemet-color-primary));
66
+ }
67
+ `,
68
+ ];
69
+ }
70
+
71
+ static get properties() {
72
+ return {
73
+ /**
74
+ * The text next to the radio button
75
+ */
76
+ label: {
77
+ type: String,
78
+ },
79
+ /**
80
+ * Determines whether or not the button is checked
81
+ */
82
+ checked: {
83
+ type: Boolean,
84
+ reflect: true,
85
+ },
86
+ /**
87
+ * The name of the field
88
+ */
89
+ name: {
90
+ type: String,
91
+ },
92
+ /**
93
+ * The value of the radio button
94
+ */
95
+ value: {
96
+ type: String,
97
+ },
98
+ /**
99
+ * Determines if the button should be disabled
100
+ */
101
+ disabled: {
102
+ type: Boolean,
103
+ reflect: true,
104
+ },
105
+ /**
106
+ * Is true when the button is focused on
107
+ */
108
+ focused: {
109
+ type: Boolean,
110
+ reflect: true,
111
+ },
112
+ /**
113
+ * Displayed the button as a filled button
114
+ */
115
+ filled: {
116
+ type: Boolean,
117
+ reflect: true,
118
+ },
119
+ };
120
+ }
121
+
122
+ constructor() {
123
+ super();
124
+
125
+ // managed properties
126
+ this.label = '';
127
+ this.name = this.closest('kemet-radios').name || 'radio-button';
128
+ this.disabled = false;
129
+ }
130
+
131
+ firstUpdated() {
132
+ this.input = this.shadowRoot.querySelector('input');
133
+ this.setAttribute('role', 'radio');
134
+
135
+ if (this.checked) {
136
+ this.setAttribute('aria-checked', 'true');
137
+ } else {
138
+ this.setAttribute('aria-checked', 'false');
139
+ }
140
+ }
141
+
142
+ render() {
143
+ return html`
144
+ <label part="label">
145
+ <input
146
+ type="radio"
147
+ name=${ifDefined(this.name)}
148
+ .value=${this.value}
149
+ .checked=${live(this.checked)}
150
+ .disabled=${this.disabled}
151
+ @blur=${() => this.handleBlur()}
152
+ @focus=${() => this.handleFocus()}
153
+ />
154
+ <button part="button" aria-label=${this.label}>${this.makeDot()}</button>
155
+ <span part="text">${this.label}</span>
156
+ </label>
157
+ `;
158
+ }
159
+
160
+ click() {
161
+ this.input.click();
162
+ }
163
+
164
+ blur() {
165
+ this.input.blur();
166
+ }
167
+
168
+ focus() {
169
+ this.input.focus();
170
+ }
171
+
172
+ handleBlur() {
173
+ this.focused = false;
174
+
175
+ /**
176
+ * Fires when the checkbox loses or receives focus
177
+ */
178
+ this.dispatchEvent(
179
+ new CustomEvent('kemet-radio-focused', {
180
+ bubbles: true,
181
+ composed: true,
182
+ detail: false,
183
+ }),
184
+ );
185
+ }
186
+
187
+ handleFocus() {
188
+ this.focused = true;
189
+
190
+ /**
191
+ * Fires when the checkbox loses or receives focus
192
+ */
193
+ this.dispatchEvent(
194
+ new CustomEvent('kemet-radio-focused', {
195
+ bubbles: true,
196
+ composed: true,
197
+ detail: true,
198
+ }),
199
+ );
200
+ }
201
+
202
+ makeDot() {
203
+ if (this.checked) {
204
+ return html`
205
+ <span part="dot"></span>
206
+ `;
207
+ }
208
+
209
+ return null;
210
+ }
211
+ }
212
+
213
+ // eslint-disable-next-line no-unused-expressions
214
+ customElements.get('kemet-radio') || customElements.define('kemet-radio', KemetRadio);