@crowdstrike/glide-core 0.32.0 → 0.32.2

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
@@ -65,6 +65,9 @@ let Accordion = class Accordion extends LitElement {
65
65
  return;
66
66
  }
67
67
  if (isOpen && hasChanged) {
68
+ // Used in a conditional below to avoid dispatching a "toggle" event on first
69
+ // render when Accordion is open initially.
70
+ const hasUpdated = this.hasUpdated;
68
71
  // Wait for `.summary` to re-render after the "active" class addition to
69
72
  // prevent animation jank, especially in Firefox and Safari.
70
73
  this.updateComplete.then(() => {
@@ -87,7 +90,7 @@ let Accordion = class Accordion extends LitElement {
87
90
  easing: getComputedStyle(this.#defaultSlotElementRef.value).getPropertyValue('--private-easing'),
88
91
  })
89
92
  .addEventListener('finish', () => {
90
- if (this.#detailsElementRef.value) {
93
+ if (this.#detailsElementRef.value && hasUpdated) {
91
94
  this.dispatchEvent(new Event('toggle', { bubbles: true, composed: true }));
92
95
  }
93
96
  });
@@ -132,7 +135,6 @@ let Accordion = class Accordion extends LitElement {
132
135
  active: this.open || this.isClosing,
133
136
  open: this.open,
134
137
  })}
135
- data-test="summary"
136
138
  @click=${this.#onSummaryClick}
137
139
  ${ref(this.#summaryElementRef)}
138
140
  >
@@ -178,7 +180,6 @@ let Accordion = class Accordion extends LitElement {
178
180
  'default-slot': true,
179
181
  indented: this.hasPrefixIcon,
180
182
  })}
181
- data-test="default-slot"
182
183
  style=${styleMap({
183
184
  '--private-close-duration': 'var(--glide-core-duration-fast-02)',
184
185
  '--private-easing': 'var(--glide-core-animation-swoop)',
@@ -202,14 +203,18 @@ let Accordion = class Accordion extends LitElement {
202
203
  #prefixIconSlotElementRef;
203
204
  #suffixIconsSlotElementRef;
204
205
  #summaryElementRef;
206
+ /* v8 ignore start */
205
207
  #onPrefixIconSlotChange() {
206
208
  const assignedNodes = this.#prefixIconSlotElementRef.value?.assignedNodes();
207
209
  this.hasPrefixIcon = Boolean(assignedNodes && assignedNodes.length > 0);
208
210
  }
211
+ /* v8 ignore end */
212
+ /* v8 ignore start */
209
213
  #onSuffixIconsSlotChange() {
210
214
  const assignedNodes = this.#suffixIconsSlotElementRef.value?.assignedNodes();
211
215
  this.hasSuffixIcons = Boolean(assignedNodes && assignedNodes.length > 0);
212
216
  }
217
+ /* v8 ignore end */
213
218
  #onSummaryClick(event) {
214
219
  // Canceling it prevents `details` from immediately showing and hiding
215
220
  // the default slot on open and close, letting us animate it when we're ready.
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]
@@ -80,18 +80,22 @@ let Button = class Button extends LitElement {
80
80
  primary: this.variant === 'primary',
81
81
  secondary: this.variant === 'secondary',
82
82
  tertiary: this.variant === 'tertiary',
83
+ link: this.variant === 'link',
83
84
  large: this.size === 'large',
84
85
  small: this.size === 'small',
85
86
  disabled: this.disabled,
86
87
  'prefix-icon': this.hasPrefixIcon,
87
88
  'suffix-icon': this.hasSuffixIcon,
88
89
  })}
89
- data-test="button"
90
90
  slot="target"
91
91
  @click=${this.#onClick}
92
92
  ${ref(this.#buttonElementRef)}
93
93
  >
94
94
  <slot
95
+ class=${classMap({
96
+ 'prefix-icon-slot': true,
97
+ hidden: this.variant === 'link',
98
+ })}
95
99
  name="prefix-icon"
96
100
  @slotchange=${this.#onPrefixIconSlotChange}
97
101
  ${ref(this.#prefixIconSlotElementRef)}
@@ -105,6 +109,10 @@ let Button = class Button extends LitElement {
105
109
  ${this.label}
106
110
 
107
111
  <slot
112
+ class=${classMap({
113
+ 'suffix-icon-slot': true,
114
+ hidden: this.variant === 'link',
115
+ })}
108
116
  name="suffix-icon"
109
117
  @slotchange=${this.#onSuffixIconSlotChange}
110
118
  ${ref(this.#suffixIconSlotElementRef)}
@@ -153,10 +161,13 @@ let Button = class Button extends LitElement {
153
161
  return;
154
162
  }
155
163
  }
164
+ /* v8 ignore start */
156
165
  #onPrefixIconSlotChange() {
157
166
  const assignedNodes = this.#prefixIconSlotElementRef.value?.assignedNodes();
158
167
  this.hasPrefixIcon = Boolean(assignedNodes && assignedNodes.length > 0);
159
168
  }
169
+ /* v8 ignore end */
170
+ /* v8 ignore start */
160
171
  #onSuffixIconSlotChange() {
161
172
  const assignedNodes = this.#suffixIconSlotElementRef.value?.assignedNodes();
162
173
  this.hasSuffixIcon = Boolean(assignedNodes && assignedNodes.length > 0);
@@ -135,17 +135,48 @@ export default [
135
135
  }
136
136
  }
137
137
 
138
- &.large {
138
+ &.link {
139
+ background-color: initial;
140
+ border: none;
141
+ border-radius: var(--glide-core-rounding-base-radius-xxs);
142
+ color: var(--glide-core-color-interactive-text-link);
143
+ font-size: var(--glide-core-typography-size-body-default);
144
+ font-weight: var(--glide-core-typography-weight-regular);
145
+ padding: 0;
146
+
147
+ &.disabled {
148
+ color: var(--glide-core-color-interactive-text-link--disabled);
149
+ }
150
+
151
+ &:not(:active):hover:not(.disabled) {
152
+ color: var(--glide-core-color-interactive-text-link--hover);
153
+ text-decoration: underline;
154
+ }
155
+ }
156
+
157
+ &.large:not(.link) {
139
158
  block-size: 2.125rem;
140
159
  font-size: var(--glide-core-typography-size-body-large);
141
160
  min-inline-size: 2.75rem;
142
161
  }
143
162
 
144
- &.small {
163
+ &.small:not(.link) {
145
164
  block-size: 1.75rem;
146
165
  font-size: var(--glide-core-typography-size-body-small);
147
166
  min-inline-size: 2.5625rem;
148
167
  }
149
168
  }
169
+
170
+ .prefix-icon-slot {
171
+ &.hidden {
172
+ display: none;
173
+ }
174
+ }
175
+
176
+ .suffix-icon-slot {
177
+ &.hidden {
178
+ display: none;
179
+ }
180
+ }
150
181
  `,
151
182
  ];
package/dist/checkbox.js CHANGED
@@ -158,11 +158,13 @@ let Checkbox = class Checkbox extends LitElement {
158
158
  });
159
159
  this.#intersectionObserver.observe(this);
160
160
  }
161
+ /* v8 ignore start */
161
162
  disconnectedCallback() {
162
163
  super.disconnectedCallback();
163
164
  this.form?.removeEventListener('formdata', this.#onFormdata);
164
165
  this.#intersectionObserver?.disconnect();
165
166
  }
167
+ /* v8 ignore end */
166
168
  get validity() {
167
169
  // If we're in a Checkbox Group, `disabled`, `required`, and whether or not
168
170
  // the form has been submitted don't apply because Checkbox Group handles those
@@ -201,7 +203,7 @@ let Checkbox = class Checkbox extends LitElement {
201
203
  this.indeterminate = this.getAttribute('indeterminate') === '';
202
204
  }
203
205
  render() {
204
- return html `<div class="component" data-test="component">
206
+ return html `<div class="component">
205
207
  ${when(this.privateVariant === 'minimal', () => html `
206
208
  <label
207
209
  class="label-and-input-and-checkbox"
@@ -289,7 +291,6 @@ let Checkbox = class Checkbox extends LitElement {
289
291
  aria-describedby="summary description"
290
292
  aria-invalid=${this.#isShowValidationFeedback}
291
293
  class="input"
292
- data-test="input"
293
294
  id="input"
294
295
  type="checkbox"
295
296
  .checked=${this.checked}
@@ -343,8 +344,9 @@ let Checkbox = class Checkbox extends LitElement {
343
344
  ${when(this.#isShowValidationFeedback && this.validityMessage, () => html `<span
344
345
  class="validity-message"
345
346
  data-test="validity-message"
346
- >${unsafeHTML(this.validityMessage)}</span
347
- >`)}
347
+ >
348
+ ${unsafeHTML(this.validityMessage)}
349
+ </span>`)}
348
350
  </div>
349
351
  </glide-core-private-label>`)}
350
352
  </div>`;
@@ -500,7 +502,7 @@ let Checkbox = class Checkbox extends LitElement {
500
502
  if (event.target instanceof HTMLInputElement) {
501
503
  this.checked = event.target.checked;
502
504
  }
503
- // If the input is interacted with it's no longer indeterminate.
505
+ // If the input has been interacted with it's no longer indeterminate.
504
506
  this.indeterminate = false;
505
507
  if (event.type === 'change') {
506
508
  // Unlike "input" events, "change" events aren't composed. So we have to
@@ -54,8 +54,12 @@ export default [
54
54
  padding-inline: var(--glide-core-spacing-base-sm);
55
55
  text-align: start;
56
56
  transition:
57
- background-color 200ms ease-in-out,
58
- border-color 200ms ease-in-out;
57
+ background-color var(--glide-core-duration-moderate-02)
58
+ var(--glide-core-animation-swoop),
59
+ border-color var(--glide-core-duration-moderate-02)
60
+ var(--glide-core-animation-swoop),
61
+ box-shadow var(--glide-core-duration-moderate-02)
62
+ var(--glide-core-animation-swoop);
59
63
  user-select: none;
60
64
 
61
65
  &.quiet:not(.multiple) {
@@ -67,6 +71,10 @@ export default [
67
71
  min-inline-size: 3.75rem;
68
72
  padding-block: 0;
69
73
  padding-inline: var(--glide-core-spacing-base-sm);
74
+
75
+ .error {
76
+ border-color: var(--glide-core-color-advisory-stroke-error-primary);
77
+ }
70
78
  }
71
79
 
72
80
  &.disabled {
@@ -110,9 +118,21 @@ export default [
110
118
  border-color: var(--glide-core-color-interactive-stroke-focus);
111
119
  }
112
120
 
113
- &:has(.primary-button:focus-visible, .input:focus-visible) {
114
- &.quiet {
121
+ &:has(.primary-button:focus-visible, .input:focus-visible):not(
122
+ .readonly
123
+ ) {
124
+ &:not(.error) {
115
125
  border-color: var(--glide-core-color-interactive-stroke-focus);
126
+ box-shadow:
127
+ 0 0 0 1px var(--glide-core-color-interactive-stroke-focus),
128
+ 1px 1px 4px -1px var(--glide-core-color-interactive-stroke-focus);
129
+ }
130
+
131
+ &.error {
132
+ box-shadow:
133
+ 0 0 0 1px var(--glide-core-color-advisory-stroke-error-primary),
134
+ 1px 1px 4px -1px
135
+ var(--glide-core-color-advisory-stroke-error-primary);
116
136
  }
117
137
  }
118
138
  }
@@ -359,7 +379,8 @@ export default [
359
379
  inline-size: 100%;
360
380
  max-inline-size: 21.875rem;
361
381
  padding-inline: 0.625rem;
362
- transition: background-color 100ms ease-in-out;
382
+ transition: background-color var(--glide-core-duration-fast-02)
383
+ var(--glide-core-animation-swoop);
363
384
  user-select: none;
364
385
  white-space: nowrap;
365
386
 
@@ -46,11 +46,11 @@ export default [
46
46
  display: flex;
47
47
  min-inline-size: 3.75rem;
48
48
  padding-inline: var(--glide-core-spacing-base-sm);
49
- transition: border-color 200ms ease-in-out;
50
-
51
- &.focused {
52
- border-color: var(--glide-core-color-interactive-stroke-focus);
53
- }
49
+ transition:
50
+ border-color var(--glide-core-duration-moderate-02)
51
+ var(--glide-core-animation-swoop),
52
+ box-shadow var(--glide-core-duration-moderate-02)
53
+ var(--glide-core-animation-swoop);
54
54
 
55
55
  &:not(.disabled, .error, .readonly) {
56
56
  &:hover,
@@ -65,6 +65,22 @@ export default [
65
65
  border-color: var(--glide-core-color-advisory-stroke-error-primary);
66
66
  }
67
67
 
68
+ &.focused:not(.readonly) {
69
+ &:not(.error) {
70
+ border-color: var(--glide-core-color-interactive-stroke-focus);
71
+ box-shadow:
72
+ 0 0 0 1px var(--glide-core-color-interactive-stroke-focus),
73
+ 1px 1px 4px -1px var(--glide-core-color-interactive-stroke-focus);
74
+ }
75
+
76
+ &.error {
77
+ box-shadow:
78
+ 0 0 0 1px var(--glide-core-color-advisory-stroke-error-primary),
79
+ 1px 1px 4px -1px
80
+ var(--glide-core-color-advisory-stroke-error-primary);
81
+ }
82
+ }
83
+
68
84
  /*
69
85
  We had to resort to a class selector because there may be a bug in Chrome and Safari
70
86
  with ":read-only": https://bugs.chromium.org/p/chromium/issues/detail?id=1519649
package/dist/link.d.ts CHANGED
@@ -9,6 +9,7 @@ declare global {
9
9
  * @attr {boolean} [disabled=false]
10
10
  * @attr {string} [download]
11
11
  * @attr {string} [href]
12
+ * @attr {string} [rel]
12
13
  * @attr {'_blank'|'_parent'|'_self'|'_top'} [target]
13
14
  *
14
15
  * @readonly
@@ -22,6 +23,7 @@ export default class Link extends LitElement {
22
23
  disabled: boolean;
23
24
  download?: string;
24
25
  href?: string;
26
+ rel?: string;
25
27
  target?: '_blank' | '_parent' | '_self' | '_top';
26
28
  readonly version: string;
27
29
  click(): void;
package/dist/link.js CHANGED
@@ -19,6 +19,7 @@ import required from './library/required.js';
19
19
  * @attr {boolean} [disabled=false]
20
20
  * @attr {string} [download]
21
21
  * @attr {string} [href]
22
+ * @attr {string} [rel]
22
23
  * @attr {'_blank'|'_parent'|'_self'|'_top'} [target]
23
24
  *
24
25
  * @readonly
@@ -69,6 +70,7 @@ let Link = class Link extends LitElement {
69
70
  data-test="component"
70
71
  download=${ifDefined(this.download)}
71
72
  href=${ifDefined(this.href)}
73
+ rel=${ifDefined(this.rel)}
72
74
  target=${ifDefined(this.target)}
73
75
  @click=${this.#onClick}
74
76
  ${ref(this.#componentElementRef)}
@@ -97,6 +99,9 @@ __decorate([
97
99
  __decorate([
98
100
  property({ reflect: true })
99
101
  ], Link.prototype, "href", void 0);
102
+ __decorate([
103
+ property({ reflect: true })
104
+ ], Link.prototype, "rel", void 0);
100
105
  __decorate([
101
106
  property({ reflect: true })
102
107
  ], Link.prototype, "target", void 0);
@@ -35,7 +35,9 @@ export default [
35
35
  );
36
36
  border: none;
37
37
  border-radius: var(--glide-core-rounding-base-radius-sm);
38
- box-shadow: var(--glide-core-effect-floating);
38
+ box-shadow: 0 var(--glide-core-color-effect-position-elevation-floating-y)
39
+ var(--glide-core-color-effect-blur-elevation-floating-blur)
40
+ var(--glide-core-color-effect-color-elevation-dialog);
39
41
  font-family: var(--glide-core-typography-family-primary);
40
42
  opacity: 0;
41
43
  padding: 0;
@@ -70,7 +72,9 @@ export default [
70
72
 
71
73
  &::backdrop {
72
74
  backdrop-filter: blur(3px);
73
- background-color: rgba(0 0 0 / 40%);
75
+ background-color: var(
76
+ --glide-core-private-color-dialog-and-modal-surface-overlay
77
+ );
74
78
 
75
79
  @media (prefers-reduced-motion: no-preference) {
76
80
  animation: backdrop-fade-in 250ms;
@@ -137,6 +137,7 @@
137
137
  --glide-core-color-effect-color-elevation-raised-1: #0000000d;
138
138
  --glide-core-color-effect-color-elevation-raised-2: #00000026;
139
139
  --glide-core-color-effect-color-elevation-floating: #00000040;
140
+ --glide-core-color-effect-color-elevation-dialog: #00000040;
140
141
  --glide-core-color-effect-color-elevation-detail-panel: #adadad;
141
142
  --glide-core-color-effect-color-scroll-shadow: #0000001a;
142
143
  --glide-core-color-effect-position-elevation-floating-y: 0.25rem;
@@ -149,6 +150,7 @@
149
150
  --glide-core-private-color-checkbox-icon-default--disabled: #d9d9d9;
150
151
  --glide-core-private-color-radio-icon-default--disabled: #d9d9d9;
151
152
  --glide-core-private-color-dialog-and-modal-surface-container: #ffffff;
153
+ --glide-core-private-color-dialog-and-modal-surface-overlay: #0000008c;
152
154
  --glide-core-private-color-skeleton-loader-surface-linear-gradient-sides: #0000000d;
153
155
  --glide-core-private-color-skeleton-loader-surface-linear-gradient-middle: #0000001a;
154
156
  --glide-core-private-color-slider-and-scrollbar-surface-handle: #f0f0f0;
@@ -296,6 +298,7 @@
296
298
  --glide-core-color-effect-color-elevation-raised-1: #ffffff00;
297
299
  --glide-core-color-effect-color-elevation-raised-2: #ffffff00;
298
300
  --glide-core-color-effect-color-elevation-floating: #14141459;
301
+ --glide-core-color-effect-color-elevation-dialog: #000000f2;
299
302
  --glide-core-color-effect-color-elevation-detail-panel: #000000f2;
300
303
  --glide-core-color-effect-color-scroll-shadow: #ffffff0d;
301
304
  --glide-core-color-effect-position-elevation-floating-y: 0.75rem;
@@ -308,6 +311,7 @@
308
311
  --glide-core-private-color-checkbox-icon-default--disabled: #434343;
309
312
  --glide-core-private-color-radio-icon-default--disabled: #434343;
310
313
  --glide-core-private-color-dialog-and-modal-surface-container: #292929;
314
+ --glide-core-private-color-dialog-and-modal-surface-overlay: #141414d9;
311
315
  --glide-core-private-color-skeleton-loader-surface-linear-gradient-sides: #ffffff0d;
312
316
  --glide-core-private-color-skeleton-loader-surface-linear-gradient-middle: #ffffff1a;
313
317
  --glide-core-private-color-slider-and-scrollbar-surface-handle: #2c2c2c;
@@ -58,7 +58,11 @@ export default [
58
58
  padding: var(--glide-core-spacing-base-xs)
59
59
  var(--glide-core-spacing-base-sm);
60
60
  resize: vertical;
61
- transition: border-color 200ms ease-in-out;
61
+ transition:
62
+ border-color var(--glide-core-duration-moderate-02)
63
+ var(--glide-core-animation-swoop),
64
+ box-shadow var(--glide-core-duration-moderate-02)
65
+ var(--glide-core-animation-swoop);
62
66
 
63
67
  /*
64
68
  Because 'field-sizing: content' is used, it allows the
@@ -81,7 +85,22 @@ export default [
81
85
  outline: none;
82
86
  }
83
87
 
84
- &:focus-visible,
88
+ &:focus-visible:not([readonly]) {
89
+ &:not(.error) {
90
+ border-color: var(--glide-core-color-interactive-stroke-focus);
91
+ box-shadow:
92
+ 0 0 0 1px var(--glide-core-color-interactive-stroke-focus),
93
+ 1px 1px 4px -1px var(--glide-core-color-interactive-stroke-focus);
94
+ }
95
+
96
+ &.error {
97
+ box-shadow:
98
+ 0 0 0 1px var(--glide-core-color-advisory-stroke-error-primary),
99
+ 1px 1px 4px -1px
100
+ var(--glide-core-color-advisory-stroke-error-primary);
101
+ }
102
+ }
103
+
85
104
  &:hover {
86
105
  border-color: var(--glide-core-color-interactive-stroke-primary--hover);
87
106
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdstrike/glide-core",
3
- "version": "0.32.0",
3
+ "version": "0.32.2",
4
4
  "description": "A Web Component design system",
5
5
  "author": "CrowdStrike UX Team",
6
6
  "license": "Apache-2.0",
@@ -29,6 +29,7 @@
29
29
  "!dist/eslint",
30
30
  "!dist/figma",
31
31
  "!dist/icons/storybook.*",
32
+ "!dist/playwright",
32
33
  "!dist/storybook",
33
34
  "!dist/stylelint",
34
35
  "!dist/ts-morph"
@@ -58,6 +59,7 @@
58
59
  "lit": "^3.2.1"
59
60
  },
60
61
  "devDependencies": {
62
+ "@axe-core/playwright": "^4.10.2",
61
63
  "@changesets/changelog-github": "^0.5.0",
62
64
  "@changesets/cli": "^2.27.10",
63
65
  "@custom-elements-manifest/analyzer": "^0.10.4",
@@ -65,21 +67,28 @@
65
67
  "@eslint/js": "^9.28.0",
66
68
  "@figma/rest-api-spec": "^0.32.0",
67
69
  "@html-eslint/eslint-plugin": "^0.41.0",
70
+ "@jridgewell/trace-mapping": "^0.3.29",
71
+ "@lit-labs/ssr": "^3.3.1",
68
72
  "@open-wc/testing": "^4.0.0",
69
- "@playwright/test": "^1.52.0",
73
+ "@playwright/test": "^1.54.2",
70
74
  "@rollup/plugin-commonjs": "^28.0.2",
71
- "@storybook/addon-actions": "^8.6.3",
72
- "@storybook/addon-controls": "^8.6.3",
73
- "@storybook/addon-docs": "^8.6.3",
74
- "@storybook/addon-toolbars": "^8.6.3",
75
- "@storybook/core-events": "^8.6.3",
76
- "@storybook/manager-api": "^8.6.3",
77
- "@storybook/preview-api": "^8.6.3",
78
- "@storybook/theming": "^8.6.3",
79
- "@storybook/web-components": "^8.6.3",
80
- "@storybook/web-components-vite": "^8.6.3",
75
+ "@storybook/addon-actions": "^8.6.14",
76
+ "@storybook/addon-controls": "^8.6.14",
77
+ "@storybook/addon-docs": "^8.6.14",
78
+ "@storybook/addon-toolbars": "^8.6.14",
79
+ "@storybook/core-events": "^8.6.14",
80
+ "@storybook/manager-api": "^8.6.14",
81
+ "@storybook/preview-api": "^8.6.14",
82
+ "@storybook/theming": "^8.6.14",
83
+ "@storybook/types": "^8.6.14",
84
+ "@storybook/web-components": "^8.6.14",
85
+ "@storybook/web-components-vite": "^8.6.14",
81
86
  "@stylistic/eslint-plugin": "^2.13.0",
87
+ "@types/convert-source-map": "^2.0.3",
82
88
  "@types/eslint": "^8.56.12",
89
+ "@types/istanbul-lib-coverage": "^2.0.6",
90
+ "@types/istanbul-lib-report": "^3.0.3",
91
+ "@types/istanbul-reports": "^3.0.4",
83
92
  "@types/mocha": "^10.0.10",
84
93
  "@types/sinon": "^17.0.3",
85
94
  "@typescript-eslint/rule-tester": "^8.33.0",
@@ -92,6 +101,7 @@
92
101
  "@web/test-runner-playwright": "^0.11.0",
93
102
  "chokidar-cli": "^3.0.0",
94
103
  "comment-parser": "^1.4.1",
104
+ "convert-source-map": "^2.0.0",
95
105
  "custom-elements-manifest": "^2.1.0",
96
106
  "esbuild": "^0.25.0",
97
107
  "eslint": "^9.31.0",
@@ -99,20 +109,26 @@
99
109
  "eslint-plugin-import": "^2.31.0",
100
110
  "eslint-plugin-lit": "^1.15.0",
101
111
  "eslint-plugin-lit-a11y": "^4.1.4",
112
+ "eslint-plugin-playwright": "^2.2.2",
102
113
  "eslint-plugin-sort-class-members": "^1.21.0",
103
114
  "eslint-plugin-unicorn": "^60.0.0",
104
115
  "globals": "^15.13.0",
105
116
  "globby": "^14.0.2",
117
+ "http-server": "^14.1.1",
106
118
  "husky": "^8.0.3",
107
119
  "is-ci": "^4.1.0",
120
+ "istanbul-lib-coverage": "^3.2.2",
121
+ "istanbul-lib-report": "^3.0.1",
122
+ "istanbul-reports": "^3.1.7",
108
123
  "lint-staged": "^15.2.11",
109
124
  "lit": "^3.3.0",
110
125
  "lit-analyzer": "^2.0.3",
126
+ "matcher": "^5.0.0",
111
127
  "minify-literals": "^1.0.10",
112
128
  "node-html-parser": "^7.0.1",
113
129
  "npm-run-all2": "^7.0.2",
114
130
  "per-env": "^1.0.2",
115
- "playwright": "^1.52.0",
131
+ "playwright": "^1.54.2",
116
132
  "postcss": "^8.5.6",
117
133
  "postcss-lit": "^1.2.0",
118
134
  "prettier": "^3.5.3",
@@ -120,10 +136,10 @@
120
136
  "react-dom": "^19.1.0",
121
137
  "rimraf": "^6.0.1",
122
138
  "sinon": "^19.0.2",
123
- "storybook": "^8.6.3",
139
+ "storybook": "^8.6.14",
124
140
  "stylelint": "^16.21.1",
125
141
  "stylelint-config-standard": "^36.0.1",
126
- "stylelint-order": "^6.0.4",
142
+ "stylelint-order": "^7.0.0",
127
143
  "stylelint-prettier": "^5.0.2",
128
144
  "stylelint-use-logical": "^2.1.2",
129
145
  "stylelint-use-nesting": "^6.0.0",
@@ -132,8 +148,8 @@
132
148
  "tsx": "^4.19.2",
133
149
  "typescript": "^5.8.3",
134
150
  "typescript-eslint": "^8.33.0",
151
+ "v8-to-istanbul": "^9.3.0",
135
152
  "vite": "^6.3.2",
136
- "vitest": "^3.0.8",
137
153
  "yocto-spinner": "^0.2.0"
138
154
  },
139
155
  "engines": {
@@ -150,7 +166,7 @@
150
166
  "start:development:ts-morph:comment:tsx": "Remove `tsx` once Node.js type stripping is available.",
151
167
  "start:production": "rimraf ./dist && pnpm start:production:cem-analyze && pnpm start:production:ts-morph && npm-run-all --aggregate-output --print-label --parallel start:production:typescript start:production:storybook start:production:esbuild",
152
168
  "start:production:esbuild": "node ./esbuild.js",
153
- "start:production:cem-analyze": "tsc --noCheck --outDir ./dist && NODE_OPTIONS=--no-warnings=ExperimentalWarning cem analyze --config ./custom-elements.config.js --quiet && git diff --quiet -- || { echo ERROR: Uncommitted elements manifest changes. Run this command locally and commit the changes.; exit 1; }",
169
+ "start:production:cem-analyze": "tsc --noCheck --outDir ./dist && NODE_OPTIONS=--no-warnings=ExperimentalWarning cem analyze --config ./custom-elements.config.js --quiet && git diff --quiet ./custom-elements.json || { echo ERROR: Uncommitted elements manifest changes. Run this command locally and commit the changes.; exit 1; }",
154
170
  "start:production:figma:dev-resources": "tsx ./src/figma/dev-resources/run.ts",
155
171
  "start:production:figma:variables": "tsx ./src/figma/variables/run.ts",
156
172
  "start:production:storybook": "storybook build --config-dir .storybook --disable-telemetry --output-dir ./dist/storybook",
@@ -170,22 +186,19 @@
170
186
  "lint:production:stylelint": "tsc --noCheck --outDir ./dist && stylelint '**/*.styles.ts' --custom-syntax postcss-lit --no-color",
171
187
  "test": "per-env",
172
188
  "test:development": "pnpm test:development:web-test-runner",
173
- "test:development:playwright": "playwright test --quiet --ui-port 6007 --update-snapshots --update-source-method=overwrite",
174
- "test:development:playwright:update": "rimraf ./src/aria-snapshots && playwright test --quiet --project aria --update-snapshots --update-source-method=overwrite --workers 100%",
175
- "test:development:vitest": "vitest --config ./vitest.config.js & chokidar './src/eslint/**' './src/stylelint/**' --ignore './src/eslint/rules/*.test.ts' './src/stylelint/*.test.ts' --initial --silent --command 'tsc --noCheck --outDir ./dist'",
176
- "test:development:vitest:comment": "Excluded from `test:development` because Vitest muddies the console when running alongside Web Test Runner.",
189
+ "test:development:playwright": "npm-run-all --parallel test:development:playwright:coverage test:development:playwright:ui",
190
+ "test:development:playwright:coverage": "http-server ./dist/playwright/coverage-report --port 6008 --silent",
191
+ "test:development:playwright:ui": "playwright test --config ./src/playwright/playwright.config.ts --ui-port 6007 --update-snapshots --update-source-method=overwrite",
192
+ "test:development:playwright:update": "PLAYWRIGHT_SKIP_COVERAGE=true playwright test --config ./src/playwright/playwright.config.ts --quiet --project accessibility --update-snapshots --update-source-method=overwrite --workers 100%",
177
193
  "test:development:web-test-runner": "web-test-runner --watch",
178
194
  "test:production": "pnpm start:production:esbuild && npm-run-all --aggregate-output --print-label --parallel test:production:*",
179
- "test:production:playwright:aria": "playwright test --quiet --only-changed origin/main",
180
- "test:production:playwright:visuals": "playwright test --ignore-snapshots --quiet --only-changed origin/main",
181
- "test:production:playwright:visuals:comment": "Snapshots are ignored because this is meant to be only a quick smoke test telling us when we've written a test incorrectly.",
182
- "test:production:vitest": "tsc --noCheck --outDir ./dist && vitest run --config ./vitest.config.js",
195
+ "test:production:playwright": "playwright test --config ./src/playwright/playwright.config.ts --grep 'is accessible|@eslint|@events|@forms|@keyboard|@miscellaneous|@mouse|@stylelint'",
196
+ "test:production:playwright:comment": "Used locally by developers and as a pre-push hook. Running every '@accessibility' test would take too long. So we only run the 'is accessible' test, which in many cases completes code coverage.",
183
197
  "test:production:web-test-runner": "web-test-runner",
184
198
  "typecheck": "per-env",
185
199
  "typecheck:development": "tsc --erasableSyntaxOnly --outDir ./dist -w",
186
200
  "typecheck:production": "tsc --erasableSyntaxOnly --outDir ./dist",
187
- "postinstall": "is-ci || pnpm dlx playwright@1.52.0 install --only-shell --with-deps chromium",
188
- "postinstall:comment": "Not installing Chromium in CI every time we run `pnpm install` speeds up builds at the cost of having to also update Playwright's version in our workflows whenever we update Playwright here.",
201
+ "postinstall": "is-ci || pnpm dlx playwright@1.54.2 install --no-shell --with-deps chromium firefox webkit",
189
202
  "release": "changeset publish"
190
203
  }
191
204
  }
@@ -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
- });