@crowdstrike/glide-core 0.32.1 → 0.32.3

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/accordion.js CHANGED
@@ -135,7 +135,6 @@ let Accordion = class Accordion extends LitElement {
135
135
  active: this.open || this.isClosing,
136
136
  open: this.open,
137
137
  })}
138
- data-test="summary"
139
138
  @click=${this.#onSummaryClick}
140
139
  ${ref(this.#summaryElementRef)}
141
140
  >
@@ -181,7 +180,6 @@ let Accordion = class Accordion extends LitElement {
181
180
  'default-slot': true,
182
181
  indented: this.hasPrefixIcon,
183
182
  })}
184
- data-test="default-slot"
185
183
  style=${styleMap({
186
184
  '--private-close-duration': 'var(--glide-core-duration-fast-02)',
187
185
  '--private-easing': 'var(--glide-core-animation-swoop)',
package/dist/button.d.ts CHANGED
@@ -14,7 +14,7 @@ declare global {
14
14
  * @attr {string} [tooltip]
15
15
  * @attr {'button'|'submit'|'reset'} [type='button']
16
16
  * @attr {string} [value='']
17
- * @attr {'primary'|'secondary'|'tertiary'} [variant='primary']
17
+ * @attr {'primary'|'secondary'|'tertiary'|'link'} [variant='primary']
18
18
  *
19
19
  * @readonly
20
20
  * @attr {string} [version]
@@ -42,7 +42,7 @@ export default class Button extends LitElement {
42
42
  tooltip?: string;
43
43
  type: 'button' | 'submit' | 'reset';
44
44
  value: string;
45
- variant: 'primary' | 'secondary' | 'tertiary';
45
+ variant: 'primary' | 'secondary' | 'tertiary' | 'link';
46
46
  readonly version: string;
47
47
  get form(): HTMLFormElement | null;
48
48
  click(): void;
package/dist/button.js CHANGED
@@ -23,7 +23,7 @@ import required from './library/required.js';
23
23
  * @attr {string} [tooltip]
24
24
  * @attr {'button'|'submit'|'reset'} [type='button']
25
25
  * @attr {string} [value='']
26
- * @attr {'primary'|'secondary'|'tertiary'} [variant='primary']
26
+ * @attr {'primary'|'secondary'|'tertiary'|'link'} [variant='primary']
27
27
  *
28
28
  * @readonly
29
29
  * @attr {string} [version]
@@ -70,6 +70,7 @@ let Button = class Button extends LitElement {
70
70
  }
71
71
  render() {
72
72
  return html `<glide-core-tooltip
73
+ class="tooltip"
73
74
  label=${this.tooltip ?? ''}
74
75
  ?disabled=${!this.disabled || !this.tooltip}
75
76
  >
@@ -80,18 +81,22 @@ let Button = class Button extends LitElement {
80
81
  primary: this.variant === 'primary',
81
82
  secondary: this.variant === 'secondary',
82
83
  tertiary: this.variant === 'tertiary',
84
+ link: this.variant === 'link',
83
85
  large: this.size === 'large',
84
86
  small: this.size === 'small',
85
87
  disabled: this.disabled,
86
88
  'prefix-icon': this.hasPrefixIcon,
87
89
  'suffix-icon': this.hasSuffixIcon,
88
90
  })}
89
- data-test="button"
90
91
  slot="target"
91
92
  @click=${this.#onClick}
92
93
  ${ref(this.#buttonElementRef)}
93
94
  >
94
95
  <slot
96
+ class=${classMap({
97
+ 'prefix-icon-slot': true,
98
+ hidden: this.variant === 'link',
99
+ })}
95
100
  name="prefix-icon"
96
101
  @slotchange=${this.#onPrefixIconSlotChange}
97
102
  ${ref(this.#prefixIconSlotElementRef)}
@@ -102,9 +107,13 @@ let Button = class Button extends LitElement {
102
107
  -->
103
108
  </slot>
104
109
 
105
- ${this.label}
110
+ <span class="label">${this.label}</span>
106
111
 
107
112
  <slot
113
+ class=${classMap({
114
+ 'suffix-icon-slot': true,
115
+ hidden: this.variant === 'link',
116
+ })}
108
117
  name="suffix-icon"
109
118
  @slotchange=${this.#onSuffixIconSlotChange}
110
119
  ${ref(this.#suffixIconSlotElementRef)}
@@ -22,6 +22,7 @@ export default [
22
22
  font-weight: var(--glide-core-typography-weight-bold);
23
23
  gap: var(--glide-core-spacing-base-xs);
24
24
  justify-content: center;
25
+ max-inline-size: 100%;
25
26
  padding-block: var(--glide-core-spacing-base-xs);
26
27
  padding-inline: var(--glide-core-spacing-base-md);
27
28
  transition-duration: var(--glide-core-duration-moderate-02);
@@ -135,17 +136,61 @@ export default [
135
136
  }
136
137
  }
137
138
 
138
- &.large {
139
+ &.link {
140
+ background-color: initial;
141
+ border: none;
142
+ border-radius: var(--glide-core-rounding-base-radius-xxs);
143
+ color: var(--glide-core-color-interactive-text-link);
144
+ font-size: var(--glide-core-typography-size-body-default);
145
+ font-weight: var(--glide-core-typography-weight-regular);
146
+ padding: 0;
147
+ text-align: start;
148
+
149
+ &.disabled {
150
+ color: var(--glide-core-color-interactive-text-link--disabled);
151
+ }
152
+
153
+ &:not(:active):hover:not(.disabled) {
154
+ color: var(--glide-core-color-interactive-text-link--hover);
155
+ text-decoration: underline;
156
+ }
157
+ }
158
+
159
+ &.large:not(.link) {
139
160
  block-size: 2.125rem;
140
161
  font-size: var(--glide-core-typography-size-body-large);
141
162
  min-inline-size: 2.75rem;
142
163
  }
143
164
 
144
- &.small {
165
+ &.small:not(.link) {
145
166
  block-size: 1.75rem;
146
167
  font-size: var(--glide-core-typography-size-body-small);
147
168
  min-inline-size: 2.5625rem;
148
169
  }
149
170
  }
171
+
172
+ .tooltip {
173
+ max-inline-size: 100%;
174
+ white-space: inherit;
175
+ }
176
+
177
+ .prefix-icon-slot {
178
+ &.hidden {
179
+ display: none;
180
+ }
181
+ }
182
+
183
+ .label {
184
+ min-inline-size: 3ch;
185
+ overflow: hidden;
186
+ text-overflow: ellipsis;
187
+ white-space: inherit;
188
+ }
189
+
190
+ .suffix-icon-slot {
191
+ &.hidden {
192
+ display: none;
193
+ }
194
+ }
150
195
  `,
151
196
  ];
@@ -27,6 +27,7 @@ declare global {
27
27
  * @slot {Element} [private-icon]
28
28
  *
29
29
  * @fires {Event} change
30
+ * @fires {Event} input
30
31
  * @fires {Event} invalid
31
32
  *
32
33
  * @readonly
package/dist/checkbox.js CHANGED
@@ -40,6 +40,7 @@ import required from './library/required.js';
40
40
  * @slot {Element} [private-icon]
41
41
  *
42
42
  * @fires {Event} change
43
+ * @fires {Event} input
43
44
  * @fires {Event} invalid
44
45
  *
45
46
  * @readonly
@@ -158,11 +159,13 @@ let Checkbox = class Checkbox extends LitElement {
158
159
  });
159
160
  this.#intersectionObserver.observe(this);
160
161
  }
162
+ /* v8 ignore start */
161
163
  disconnectedCallback() {
162
164
  super.disconnectedCallback();
163
165
  this.form?.removeEventListener('formdata', this.#onFormdata);
164
166
  this.#intersectionObserver?.disconnect();
165
167
  }
168
+ /* v8 ignore end */
166
169
  get validity() {
167
170
  // If we're in a Checkbox Group, `disabled`, `required`, and whether or not
168
171
  // the form has been submitted don't apply because Checkbox Group handles those
@@ -201,7 +204,7 @@ let Checkbox = class Checkbox extends LitElement {
201
204
  this.indeterminate = this.getAttribute('indeterminate') === '';
202
205
  }
203
206
  render() {
204
- return html `<div class="component" data-test="component">
207
+ return html `<div class="component">
205
208
  ${when(this.privateVariant === 'minimal', () => html `
206
209
  <label
207
210
  class="label-and-input-and-checkbox"
@@ -289,7 +292,6 @@ let Checkbox = class Checkbox extends LitElement {
289
292
  aria-describedby="summary description"
290
293
  aria-invalid=${this.#isShowValidationFeedback}
291
294
  class="input"
292
- data-test="input"
293
295
  id="input"
294
296
  type="checkbox"
295
297
  .checked=${this.checked}
@@ -343,8 +345,9 @@ let Checkbox = class Checkbox extends LitElement {
343
345
  ${when(this.#isShowValidationFeedback && this.validityMessage, () => html `<span
344
346
  class="validity-message"
345
347
  data-test="validity-message"
346
- >${unsafeHTML(this.validityMessage)}</span
347
- >`)}
348
+ >
349
+ ${unsafeHTML(this.validityMessage)}
350
+ </span>`)}
348
351
  </div>
349
352
  </glide-core-private-label>`)}
350
353
  </div>`;
@@ -478,12 +481,12 @@ let Checkbox = class Checkbox extends LitElement {
478
481
  this.reportValidity();
479
482
  this.isBlurring = false;
480
483
  }
481
- // Only "change" would need to be handled if not for some consumers needing
482
- // to force Checkbox checked or unchecked until the user has completed some action.
484
+ // Only "change" would need to be handled if not for some consumers needing to
485
+ // force Checkbox checked or unchecked until the user has completed some action.
483
486
  //
484
- // The way to force Checkbox checked or unchecked is to add an "input" or
485
- // "change" handler and then immediately set `checked` back to its desired
486
- // state inside that handler.
487
+ // The way they can force Checkbox to be checked or unchecked is to add an "input"
488
+ // or "change" handler and then immediately set `checked` back to its desired state
489
+ // inside that handler.
487
490
  //
488
491
  // To do that, consumers need to await `this.updateComplete` so `checked` isn't
489
492
  // immediately reverted after Checkbox updates, which happens asynchronously and
@@ -493,18 +496,25 @@ let Checkbox = class Checkbox extends LitElement {
493
496
  // why we're handling "input" as well: so that "input", like "change", results
494
497
  // in an update that can be awaited.
495
498
  //
496
- // If "input" events were dispatched after "change" events, only handling
497
- // "change" here would suffice because an update from "change" would already
498
- // be pending by the time "input" is dispatched.
499
+ // If "input" events were dispatched after "change" events, only handling "change"
500
+ // here would suffice because an update from "change" would already be pending by
501
+ // the time "input" is dispatched.
499
502
  #onInputChangeOrInput(event) {
500
503
  if (event.target instanceof HTMLInputElement) {
501
504
  this.checked = event.target.checked;
502
505
  }
503
- // If the input is interacted with it's no longer indeterminate.
506
+ // If the input has been interacted with it's no longer indeterminate.
504
507
  this.indeterminate = false;
508
+ // Our analyzer plugin (`add-events.ts`) doesn't and can't account for events that
509
+ // are implicitly dispatched by a native form control in a component. So we stop
510
+ // the original event and dispatch our own.
511
+ if (event.type === 'input') {
512
+ event.stopPropagation();
513
+ this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
514
+ }
505
515
  if (event.type === 'change') {
506
- // Unlike "input" events, "change" events aren't composed. So we have to
507
- // manually dispatch them.
516
+ // Unlike "input" events, "change" events aren't composed. So we have to manually
517
+ // dispatch them.
508
518
  this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
509
519
  }
510
520
  }
package/dist/input.js CHANGED
@@ -453,8 +453,8 @@ let Input = class Input extends LitElement {
453
453
  if (this.#inputElementRef.value?.value) {
454
454
  this.value = this.#inputElementRef.value?.value;
455
455
  }
456
- // Unlike "input" events, "change" events aren't composed. So we have to
457
- // manually dispatch them.
456
+ // Unlike "input" events, "change" events aren't composed. So we have to manually
457
+ // dispatch them.
458
458
  this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
459
459
  }
460
460
  #onInputFocus() {
package/dist/menu.js CHANGED
@@ -416,20 +416,28 @@ let Menu = class Menu extends LitElement {
416
416
  return this.closest('glide-core-option');
417
417
  }
418
418
  get #subMenus() {
419
- return [
420
- ...this.querySelectorAll(
421
- // The "content" slot case.
422
- ':scope > glide-core-options > glide-core-option > [slot="content"] > glide-core-menu'),
423
- ...this.querySelectorAll(
424
- // The "content" slot and Options Group case.
425
- ':scope > glide-core-options > glide-core-options-group > glide-core-option > [slot="content"] > glide-core-menu'),
426
- ...this.querySelectorAll(
427
- // The "content" slot fallback case.
428
- ':scope > glide-core-options > glide-core-option > [slot="submenu"]'),
429
- ...this.querySelectorAll(
430
- // The "content" slot fallback and Options Group case.
431
- ':scope > glide-core-options > glide-core-options-group > glide-core-option > [slot="submenu"]'),
432
- ];
419
+ const assignedElements = this.#defaultSlotElementRef.value?.assignedElements({ flatten: true });
420
+ if (!assignedElements) {
421
+ return [];
422
+ }
423
+ return assignedElements
424
+ .filter((element) => element instanceof Options)
425
+ .flatMap((element) => {
426
+ return [
427
+ ...element.querySelectorAll(
428
+ // The "content" slot case.
429
+ ':scope > glide-core-option > [slot="content"] > glide-core-menu'),
430
+ ...element.querySelectorAll(
431
+ // The "content" slot and Options Group case.
432
+ ':scope > glide-core-options-group > glide-core-option > [slot="content"] > glide-core-menu'),
433
+ ...element.querySelectorAll(
434
+ // The "content" slot fallback case.
435
+ ':scope > glide-core-option > [slot="submenu"]'),
436
+ ...element.querySelectorAll(
437
+ // The "content" slot fallback and Options Group case.
438
+ ':scope > glide-core-options-group > glide-core-option > [slot="submenu"]'),
439
+ ];
440
+ });
433
441
  }
434
442
  get #targetElement() {
435
443
  const element = this.#targetSlotElementRef.value
package/dist/slider.js CHANGED
@@ -801,8 +801,8 @@ let Slider = class Slider extends LitElement {
801
801
  const normalizedValue = Math.round(inputValue / this.step) * this.step;
802
802
  this.maximumValue = Math.min(Math.max(normalizedValue, this.minimumValue + this.step), this.max);
803
803
  this.#updateHandlesAndTrack();
804
- // Unlike "input" events, "change" events aren't composed. So
805
- // we have to manually dispatch them.
804
+ // Unlike "input" events, "change" events aren't composed. So we have to manually
805
+ // dispatch them.
806
806
  this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
807
807
  }
808
808
  }
@@ -842,8 +842,8 @@ let Slider = class Slider extends LitElement {
842
842
  // can't go higher than 70 (75-5).
843
843
  this.maximumValue - this.step);
844
844
  this.#updateHandlesAndTrack();
845
- // Unlike "input" events, "change" events aren't composed. So
846
- // we have to manually dispatch them.
845
+ // Unlike "input" events, "change" events aren't composed. So we have to manually
846
+ // dispatch them.
847
847
  this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
848
848
  }
849
849
  }
@@ -28,6 +28,7 @@ declare global {
28
28
  * @slot {Element | string} [description] - Additional information or context
29
29
  *
30
30
  * @fires {Event} change
31
+ * @fires {Event} input
31
32
  * @fires {Event} invalid
32
33
  *
33
34
  * @readonly
package/dist/textarea.js CHANGED
@@ -40,6 +40,7 @@ import required from './library/required.js';
40
40
  * @slot {Element | string} [description] - Additional information or context
41
41
  *
42
42
  * @fires {Event} change
43
+ * @fires {Event} input
43
44
  * @fires {Event} invalid
44
45
  *
45
46
  * @readonly
@@ -310,14 +311,21 @@ let Textarea = class Textarea extends LitElement {
310
311
  if (this.#textareaElementRef.value) {
311
312
  this.value = this.#textareaElementRef.value.value;
312
313
  }
313
- // Unlike "input" events, "change" events aren't composed. So we have to
314
- // manually dispatch them.
314
+ // Unlike "input" events, "change" events aren't composed. So we have to manually
315
+ // dispatch them.
315
316
  this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
316
317
  }
317
- #onTextareaInput() {
318
+ #onTextareaInput(event) {
318
319
  if (this.#textareaElementRef.value) {
319
320
  this.value = this.#textareaElementRef.value.value;
320
321
  }
322
+ // Our analyzer plugin (`add-events.ts`) doesn't and can't account for events that
323
+ // are implicitly dispatched by a native form control in a component. So we stop
324
+ // the original event and dispatch our own.
325
+ if (event.type === 'input') {
326
+ event.stopPropagation();
327
+ this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
328
+ }
321
329
  }
322
330
  #onTextareaKeydown(event) {
323
331
  if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {
package/dist/toggle.d.ts CHANGED
@@ -20,6 +20,7 @@ declare global {
20
20
  * @slot {Element | string} [description] - Additional information or context
21
21
  *
22
22
  * @fires {Event} change
23
+ * @fires {Event} input
23
24
  */
24
25
  export default class Toggle extends LitElement {
25
26
  #private;
package/dist/toggle.js CHANGED
@@ -30,6 +30,7 @@ import required from './library/required.js';
30
30
  * @slot {Element | string} [description] - Additional information or context
31
31
  *
32
32
  * @fires {Event} change
33
+ * @fires {Event} input
33
34
  */
34
35
  let Toggle = class Toggle extends LitElement {
35
36
  constructor() {
@@ -136,9 +137,16 @@ let Toggle = class Toggle extends LitElement {
136
137
  if (event.target instanceof HTMLInputElement) {
137
138
  this.checked = event.target.checked;
138
139
  }
140
+ // Our analyzer plugin (`add-events.ts`) doesn't and can't account for events that
141
+ // are implicitly dispatched by a native form control in a component. So we stop
142
+ // the original event and dispatch our own.
143
+ if (event.type === 'input') {
144
+ event.stopPropagation();
145
+ this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
146
+ }
139
147
  if (event.type === 'change') {
140
- // Unlike "input" events, "change" events aren't composed. So we have to
141
- // manually dispatch them.
148
+ // Unlike "input" events, "change" events aren't composed. So we have to manually
149
+ // dispatch them.
142
150
  this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
143
151
  }
144
152
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdstrike/glide-core",
3
- "version": "0.32.1",
3
+ "version": "0.32.3",
4
4
  "description": "A Web Component design system",
5
5
  "author": "CrowdStrike UX Team",
6
6
  "license": "Apache-2.0",
@@ -1 +0,0 @@
1
- export {};
@@ -1,38 +0,0 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- import { LitElement } from 'lit';
8
- import { customElement } from 'lit/decorators.js';
9
- import { expect, fixture, html } from '@open-wc/testing';
10
- import en from '../translations/en.js';
11
- import { LocalizeController } from './localize.js';
12
- let Component = class Component extends LitElement {
13
- constructor() {
14
- super(...arguments);
15
- this.localize = new LocalizeController(this);
16
- }
17
- };
18
- Component = __decorate([
19
- customElement('glide-core-component')
20
- ], Component);
21
- it('can call any term from en translation if locale is Japanese', async () => {
22
- const host = await fixture(html `<glide-core-component></glide-core-component>`);
23
- host.lang = 'ja';
24
- expect(host.localize.lang()).to.equal('ja');
25
- const keys = Object.keys(en);
26
- for (const key of keys) {
27
- expect(host.localize.term(key)).to.be.ok;
28
- }
29
- });
30
- it('can call any term from en translation if locale is French', async () => {
31
- const host = await fixture(html `<glide-core-component></glide-core-component>`);
32
- host.lang = 'fr';
33
- expect(host.localize.lang()).to.equal('fr');
34
- const keys = Object.keys(en);
35
- for (const key of keys) {
36
- expect(host.localize.term(key)).to.be.ok;
37
- }
38
- });