@crowdstrike/glide-core 0.29.2 → 0.30.1

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 (122) hide show
  1. package/dist/accordion.js +240 -1
  2. package/dist/accordion.styles.js +13 -7
  3. package/dist/button-group.button.js +143 -1
  4. package/dist/button-group.button.styles.js +43 -15
  5. package/dist/button-group.js +249 -1
  6. package/dist/button-group.styles.js +10 -5
  7. package/dist/button.js +206 -1
  8. package/dist/button.styles.js +12 -7
  9. package/dist/checkbox-group.js +479 -14
  10. package/dist/checkbox-group.styles.js +5 -2
  11. package/dist/checkbox.js +519 -32
  12. package/dist/checkbox.styles.js +10 -5
  13. package/dist/drawer.js +168 -1
  14. package/dist/drawer.styles.js +5 -2
  15. package/dist/dropdown.js +2423 -123
  16. package/dist/dropdown.option.js +536 -1
  17. package/dist/dropdown.option.styles.js +5 -2
  18. package/dist/dropdown.styles.js +15 -8
  19. package/dist/form-controls-layout.js +102 -1
  20. package/dist/form-controls-layout.styles.js +5 -2
  21. package/dist/icon-button.js +139 -1
  22. package/dist/icon-button.styles.js +19 -7
  23. package/dist/icons/checked.js +28 -1
  24. package/dist/icons/chevron.js +21 -1
  25. package/dist/icons/magnifying-glass.js +23 -1
  26. package/dist/icons/pencil.js +21 -1
  27. package/dist/icons/severity-critical.js +20 -1
  28. package/dist/icons/severity-informational.js +20 -1
  29. package/dist/icons/severity-medium.js +20 -1
  30. package/dist/icons/x.js +21 -1
  31. package/dist/inline-alert.js +118 -1
  32. package/dist/inline-alert.styles.js +5 -2
  33. package/dist/input.d.ts +8 -2
  34. package/dist/input.js +505 -41
  35. package/dist/input.styles.js +25 -4
  36. package/dist/label.js +303 -1
  37. package/dist/label.styles.js +11 -5
  38. package/dist/library/assert-slot.js +136 -1
  39. package/dist/library/expect-unhandled-rejection.js +14 -1
  40. package/dist/library/expect-window-error.js +26 -1
  41. package/dist/library/final.js +18 -1
  42. package/dist/library/form-control.js +1 -1
  43. package/dist/library/localize.js +10 -1
  44. package/dist/library/mouse.js +35 -1
  45. package/dist/library/on-resize.js +24 -1
  46. package/dist/library/required.js +35 -1
  47. package/dist/library/shadow-root-mode.js +4 -1
  48. package/dist/library/unique-id.js +3 -1
  49. package/dist/link.js +92 -1
  50. package/dist/link.styles.js +10 -5
  51. package/dist/menu.d.ts +3 -2
  52. package/dist/menu.js +1259 -1
  53. package/dist/menu.styles.js +35 -19
  54. package/dist/modal.d.ts +4 -0
  55. package/dist/modal.icon-button.js +60 -1
  56. package/dist/modal.icon-button.styles.js +5 -2
  57. package/dist/modal.js +473 -1
  58. package/dist/modal.styles.js +71 -22
  59. package/dist/option.d.ts +74 -0
  60. package/dist/option.js +498 -0
  61. package/dist/option.styles.js +140 -0
  62. package/dist/{menu.options.d.ts → options.d.ts} +5 -6
  63. package/dist/options.js +130 -0
  64. package/dist/options.styles.js +21 -0
  65. package/dist/popover.js +620 -1
  66. package/dist/popover.styles.js +11 -5
  67. package/dist/radio-group.js +624 -17
  68. package/dist/radio-group.radio.js +211 -1
  69. package/dist/radio-group.radio.styles.js +9 -4
  70. package/dist/radio-group.styles.js +5 -2
  71. package/dist/slider.js +1040 -61
  72. package/dist/slider.styles.js +9 -4
  73. package/dist/spinner.js +60 -1
  74. package/dist/spinner.styles.js +5 -2
  75. package/dist/split-button.js +116 -1
  76. package/dist/split-button.primary-button.js +100 -1
  77. package/dist/split-button.primary-button.styles.js +13 -6
  78. package/dist/split-button.primary-link.js +102 -1
  79. package/dist/split-button.secondary-button.d.ts +2 -3
  80. package/dist/split-button.secondary-button.js +121 -1
  81. package/dist/split-button.secondary-button.styles.js +12 -7
  82. package/dist/split-button.styles.js +9 -4
  83. package/dist/styles/focus-outline.js +9 -3
  84. package/dist/styles/fonts.css +6 -1
  85. package/dist/styles/opacity-and-scale-animation.js +6 -3
  86. package/dist/styles/skeleton.js +6 -3
  87. package/dist/styles/variables.css +410 -1
  88. package/dist/styles/visually-hidden.js +6 -3
  89. package/dist/tab.group.js +386 -1
  90. package/dist/tab.group.styles.js +5 -2
  91. package/dist/tab.js +133 -1
  92. package/dist/tab.panel.js +93 -1
  93. package/dist/tab.panel.styles.js +11 -5
  94. package/dist/tab.styles.js +9 -4
  95. package/dist/tag.js +207 -1
  96. package/dist/tag.styles.js +10 -5
  97. package/dist/textarea.js +353 -19
  98. package/dist/textarea.styles.js +23 -4
  99. package/dist/toast.js +130 -1
  100. package/dist/toast.toasts.js +248 -25
  101. package/dist/toast.toasts.styles.js +9 -4
  102. package/dist/toggle.js +178 -1
  103. package/dist/toggle.styles.js +25 -5
  104. package/dist/tooltip.container.js +130 -1
  105. package/dist/tooltip.container.styles.js +5 -2
  106. package/dist/tooltip.js +484 -1
  107. package/dist/tooltip.styles.js +21 -5
  108. package/dist/translations/en.js +36 -1
  109. package/dist/translations/fr.js +37 -1
  110. package/dist/translations/ja.js +37 -1
  111. package/package.json +8 -12
  112. package/dist/menu.button.d.ts +0 -42
  113. package/dist/menu.button.js +0 -1
  114. package/dist/menu.button.styles.js +0 -32
  115. package/dist/menu.link.d.ts +0 -44
  116. package/dist/menu.link.js +0 -1
  117. package/dist/menu.link.styles.js +0 -35
  118. package/dist/menu.options.js +0 -1
  119. package/dist/menu.options.styles.d.ts +0 -2
  120. package/dist/menu.options.styles.js +0 -20
  121. /package/dist/{menu.button.styles.d.ts → option.styles.d.ts} +0 -0
  122. /package/dist/{menu.link.styles.d.ts → options.styles.d.ts} +0 -0
package/dist/tab.group.js CHANGED
@@ -1 +1,386 @@
1
- var __decorate=this&&this.__decorate||function(t,e,s,a){var o,i=arguments.length,l=i<3?e:null===a?a=Object.getOwnPropertyDescriptor(e,s):a;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)l=Reflect.decorate(t,e,s,a);else for(var n=t.length-1;n>=0;n--)(o=t[n])&&(l=(i<3?o(l):i>3?o(e,s,l):o(e,s))||l);return i>3&&l&&Object.defineProperty(e,s,l),l};import"./icon-button.js";import{html,LitElement}from"lit";import{classMap}from"lit/directives/class-map.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property,state}from"lit/decorators.js";import{when}from"lit/directives/when.js";import packageJson from"../package.json"with{type:"json"};import{LocalizeController}from"./library/localize.js";import Tab from"./tab.js";import TabPanel from"./tab.panel.js";import chevronIcon from"./icons/chevron.js";import onResize from"./library/on-resize.js";import styles from"./tab.group.styles.js";import assertSlot from"./library/assert-slot.js";import shadowRootMode from"./library/shadow-root-mode.js";import final from"./library/final.js";let TabGroup=class TabGroup extends LitElement{constructor(){super(...arguments),this.version=packageJson.version,this.isDisableOverflowEndButton=!1,this.isDisableOverflowStartButton=!1,this.isShowOverflowButtons=!1,this.#t=createRef(),this.#e=new LocalizeController(this),this.#s=createRef(),this.#a=createRef(),this.#o=null,this.#i=createRef(),this.#l=createRef()}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:shadowRootMode}}static{this.styles=styles}render(){return html`<div class="component" @click="${this.#n}" @keydown="${this.#r}" ${ref(this.#t)}><div class="tab-container" data-test="tab-container">${when(this.isShowOverflowButtons,(()=>html`<button aria-label="${this.#e.term("previousTab")}" class="${classMap({"overflow-button":!0,start:!0,disabled:this.isDisableOverflowStartButton})}" data-test="overflow-start-button" tabindex="-1" ?disabled="${this.isDisableOverflowStartButton}" @click="${this.#c.bind(this,"start")}" ${ref(this.#a)}>${chevronIcon}</button>`))}<div class="tab-group" data-test="tablist" role="tablist" tabindex="-1" @focusout="${this.#d}" @scroll="${this.#b}" ${onResize(this.#h.bind(this))} ${ref(this.#l)}><slot name="nav" @private-selected="${this.#f}" @slotchange="${this.#m}" ${assertSlot([Tab])}></slot><div class="${classMap({"selected-tab-indicator":!0,animated:this.hasUpdated})}" data-test="selected-tab-indicator" ${ref(this.#i)}></div></div>${when(this.isShowOverflowButtons,(()=>html`<button aria-label="${this.#e.term("nextTab")}" class="${classMap({"overflow-button":!0,end:!0,disabled:this.isDisableOverflowEndButton})}" data-test="overflow-end-button" tabindex="-1" @click="${this.#c.bind(this,"end")}" ?disabled="${this.isDisableOverflowEndButton}" ${ref(this.#s)}>${chevronIcon}</button>`))}</div><slot @slotchange="${this.#u}" ${assertSlot([TabPanel])}></slot></div>`}#t;#e;#s;#a;#o;#i;#l;get#p(){return this.#v.at(0)}get#E(){return this.#v.findLast((({selected:t})=>t))}get#T(){return[...this.querySelectorAll(":scope > glide-core-tab-panel")]}get#v(){return[...this.querySelectorAll(":scope > glide-core-tab")]}#n(t){const e=t.target.closest("glide-core-tab");e instanceof Tab&&!e.disabled&&this.#v.includes(e)&&(e.selected=!0)}#r(t){const e=t.target instanceof HTMLElement&&t.target.closest("glide-core-tab");if(["Enter"," "].includes(t.key)&&e instanceof Tab&&!e.disabled&&(e.selected=!0,t.preventDefault()),["ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home","End"].includes(t.key)){const e=this.#v.find((t=>t.matches(":focus")));if(e instanceof Tab){let s=this.#v.indexOf(e);switch(t.key){case"Home":s=0;break;case"End":s=this.#v.length-1;break;case"ArrowLeft":s--;break;case"ArrowRight":s++}s<0&&(s=this.#v.length-1),s>this.#v.length-1&&(s=0),this.#v[s]?.focus({preventScroll:!1});for(const[,t]of this.#v.entries())t.tabIndex=this.#v[s]===t?0:-1;this.#b(),t.preventDefault()}}}#u(){this.#w()}#m(){if(this.#E){this.#E.tabIndex=0;for(const t of this.#v)t.selected&&t!==this.#E&&(t.selected=!1,t.tabIndex=-1)}else this.#p&&(this.#p.selected=!0,this.#p.tabIndex=0);for(const t of this.#T)t.privateIsSelected=t.name===this.#E?.panel,t.tabIndex=t.name===this.#E?.panel?0:-1;this.#w(),this.#b()}#c(t){const e="end"===t?1:-1;this.#l.value&&this.#l.value.scrollBy({left:e*this.#l.value.clientWidth*.5,top:0})}#d(){for(const[,t]of this.#v.entries())t.tabIndex=t===this.#E?0:-1}#h(){this.#o&&clearTimeout(this.#o),this.#S(),this.#o=setTimeout((()=>{this.#b()}))}#f(t){if(t.target instanceof Tab&&t.target.selected){t.target.privateSelect(),t.target.tabIndex=0;for(const e of this.#v)e!==t.target&&(e.selected=!1,e.tabIndex=-1)}else this.#p&&!this.#E&&(this.#p.privateSelect(),this.#p.tabIndex=0);this.#S();for(const t of this.#T)t.privateIsSelected=t.name===this.#E?.panel,t.tabIndex=t.name===this.#E?.panel?0:-1}#w(){for(const t of this.#v){const e=this.#T.filter((e=>e.name===t.panel))?.at(0);e?.id&&(t.setAttribute("aria-controls",e.id),e.setAttribute("aria-labelledby",t.id))}}#b(){this.#l.value&&(this.isShowOverflowButtons=this.#l.value.scrollWidth>this.#l.value.clientWidth,this.isDisableOverflowStartButton=this.#l.value.scrollLeft<=0,this.isDisableOverflowEndButton=Math.round(this.#l.value.scrollLeft)+this.#l.value.clientWidth>=this.#l.value.scrollWidth)}#S(){if(this.#E&&this.#v.length>0&&this.#i.value){const t=this.#E===this.#v.at(0),e=this.#E===this.#v.at(-1),s=t?Number.parseInt(window.getComputedStyle(this.#E).getPropertyValue("padding-inline-start")):e?Number.parseInt(window.getComputedStyle(this.#E).getPropertyValue("padding-inline-end")):0,a=this.#E===this.#v.at(0)?s:this.#E.offsetLeft-this.#v.at(0).offsetLeft;this.#i.value.style.setProperty("--private-selected-tab-indicator-translate",`${a}px`);const{width:o}=this.#E.getBoundingClientRect();this.#i.value.style.setProperty("--private-selected-tab-indicator-width",o-s+"px")}}};__decorate([property({reflect:!0})],TabGroup.prototype,"version",void 0),__decorate([state()],TabGroup.prototype,"isDisableOverflowEndButton",void 0),__decorate([state()],TabGroup.prototype,"isDisableOverflowStartButton",void 0),__decorate([state()],TabGroup.prototype,"isShowOverflowButtons",void 0),TabGroup=__decorate([customElement("glide-core-tab-group"),final],TabGroup);export default TabGroup;
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 './icon-button.js';
8
+ import { html, LitElement } from 'lit';
9
+ import { classMap } from 'lit/directives/class-map.js';
10
+ import { createRef, ref } from 'lit/directives/ref.js';
11
+ import { customElement, property, state } from 'lit/decorators.js';
12
+ import { when } from 'lit/directives/when.js';
13
+ import packageJson from '../package.json' with { type: 'json' };
14
+ import { LocalizeController } from './library/localize.js';
15
+ import Tab from './tab.js';
16
+ import TabPanel from './tab.panel.js';
17
+ import chevronIcon from './icons/chevron.js';
18
+ import onResize from './library/on-resize.js';
19
+ import styles from './tab.group.styles.js';
20
+ import assertSlot from './library/assert-slot.js';
21
+ import shadowRootMode from './library/shadow-root-mode.js';
22
+ import final from './library/final.js';
23
+ /**
24
+ * @readonly
25
+ * @attr {string} [version]
26
+ *
27
+ * @slot {TabPanel}
28
+ * @slot {Tab} [nav]
29
+ *
30
+ * @cssprop [--tabs-padding-block-end=0rem]
31
+ * @cssprop [--tabs-padding-block-start=0rem]
32
+ * @cssprop [--tabs-padding-inline-end=0rem]
33
+ * @cssprop [--tabs-padding-inline-start=0rem]
34
+ */
35
+ let TabGroup = class TabGroup extends LitElement {
36
+ constructor() {
37
+ super(...arguments);
38
+ this.version = packageJson.version;
39
+ this.isDisableOverflowEndButton = false;
40
+ this.isDisableOverflowStartButton = false;
41
+ this.isShowOverflowButtons = false;
42
+ this.#componentElementRef = createRef();
43
+ this.#localize = new LocalizeController(this);
44
+ this.#overflowEndButtonElementRef = createRef();
45
+ this.#overflowStartButtonElementRef = createRef();
46
+ this.#resizeTimeout = null;
47
+ this.#selectedTabIndicatorElementRef = createRef();
48
+ this.#tabListElementRef = createRef();
49
+ }
50
+ static { this.shadowRootOptions = {
51
+ ...LitElement.shadowRootOptions,
52
+ mode: shadowRootMode,
53
+ }; }
54
+ static { this.styles = styles; }
55
+ render() {
56
+ return html `<div
57
+ class="component"
58
+ @click=${this.#onComponentClick}
59
+ @keydown=${this.#onComponentKeydown}
60
+ ${ref(this.#componentElementRef)}
61
+ >
62
+ <div class="tab-container" data-test="tab-container">
63
+ ${when(this.isShowOverflowButtons, () => html `
64
+ <button
65
+ aria-label=${this.#localize.term('previousTab')}
66
+ class=${classMap({
67
+ 'overflow-button': true,
68
+ start: true,
69
+ disabled: this.isDisableOverflowStartButton,
70
+ })}
71
+ data-test="overflow-start-button"
72
+ tabindex="-1"
73
+ ?disabled=${this.isDisableOverflowStartButton}
74
+ @click=${this.#onOverflowButtonClick.bind(this, 'start')}
75
+ ${ref(this.#overflowStartButtonElementRef)}
76
+ >
77
+ ${chevronIcon}
78
+ </button>
79
+ `)}
80
+ <div
81
+ class="tab-group"
82
+ data-test="tablist"
83
+ role="tablist"
84
+ tabindex="-1"
85
+ @focusout=${this.#onTabListFocusout}
86
+ @scroll=${this.#setOverflowButtonsState}
87
+ ${onResize(this.#onTabListResize.bind(this))}
88
+ ${ref(this.#tabListElementRef)}
89
+ >
90
+ <slot
91
+ name="nav"
92
+ @private-selected=${this.#onTabSelected}
93
+ @slotchange=${this.#onNavSlotChange}
94
+ ${assertSlot([Tab])}
95
+ >
96
+ <!-- @type {Tab} -->
97
+ </slot>
98
+
99
+ <div
100
+ class=${classMap({
101
+ 'selected-tab-indicator': true,
102
+ animated: this.hasUpdated,
103
+ })}
104
+ data-test="selected-tab-indicator"
105
+ ${ref(this.#selectedTabIndicatorElementRef)}
106
+ ></div>
107
+ </div>
108
+
109
+ ${when(this.isShowOverflowButtons, () => html `
110
+ <button
111
+ aria-label=${this.#localize.term('nextTab')}
112
+ class=${classMap({
113
+ 'overflow-button': true,
114
+ end: true,
115
+ disabled: this.isDisableOverflowEndButton,
116
+ })}
117
+ data-test="overflow-end-button"
118
+ tabindex="-1"
119
+ @click=${this.#onOverflowButtonClick.bind(this, 'end')}
120
+ ?disabled=${this.isDisableOverflowEndButton}
121
+ ${ref(this.#overflowEndButtonElementRef)}
122
+ >
123
+ ${chevronIcon}
124
+ </button>
125
+ `)}
126
+ </div>
127
+
128
+ <slot @slotchange=${this.#onDefaultSlotChange} ${assertSlot([TabPanel])}>
129
+ <!-- @type {TabPanel} -->
130
+ </slot>
131
+ </div>`;
132
+ }
133
+ #componentElementRef;
134
+ #localize;
135
+ #overflowEndButtonElementRef;
136
+ #overflowStartButtonElementRef;
137
+ #resizeTimeout;
138
+ #selectedTabIndicatorElementRef;
139
+ #tabListElementRef;
140
+ get #firstTab() {
141
+ return this.#tabElements.at(0);
142
+ }
143
+ get #lastSelectedTab() {
144
+ return this.#tabElements.findLast(({ selected }) => selected);
145
+ }
146
+ get #panelElements() {
147
+ return [
148
+ ...this.querySelectorAll(':scope > glide-core-tab-panel'),
149
+ ];
150
+ }
151
+ get #tabElements() {
152
+ return [...this.querySelectorAll(':scope > glide-core-tab')];
153
+ }
154
+ #onComponentClick(event) {
155
+ const target = event.target;
156
+ const clickedTab = target.closest('glide-core-tab');
157
+ if (clickedTab instanceof Tab &&
158
+ !clickedTab.disabled &&
159
+ // Tab Panels can themselves include a Tab Group. We want to ensure
160
+ // we're dealing with one of this instance's Tabs and not a Tab in
161
+ // a Tab Panel.
162
+ this.#tabElements.includes(clickedTab)) {
163
+ clickedTab.selected = true;
164
+ }
165
+ }
166
+ #onComponentKeydown(event) {
167
+ const tab = event.target instanceof HTMLElement &&
168
+ event.target.closest('glide-core-tab');
169
+ if (['Enter', ' '].includes(event.key) &&
170
+ tab instanceof Tab &&
171
+ !tab.disabled) {
172
+ tab.selected = true;
173
+ event.preventDefault(); // Prevent page scroll when Space is pressed
174
+ }
175
+ if ([
176
+ 'ArrowLeft',
177
+ 'ArrowRight',
178
+ 'ArrowUp',
179
+ 'ArrowDown',
180
+ 'Home',
181
+ 'End',
182
+ ].includes(event.key)) {
183
+ const focusedElement = this.#tabElements.find((tab) => tab.matches(':focus'));
184
+ if (focusedElement instanceof Tab) {
185
+ let index = this.#tabElements.indexOf(focusedElement);
186
+ switch (event.key) {
187
+ case 'Home': {
188
+ index = 0;
189
+ break;
190
+ }
191
+ case 'End': {
192
+ index = this.#tabElements.length - 1;
193
+ break;
194
+ }
195
+ case 'ArrowLeft': {
196
+ index--;
197
+ break;
198
+ }
199
+ case 'ArrowRight': {
200
+ index++;
201
+ break;
202
+ }
203
+ }
204
+ if (index < 0) {
205
+ index = this.#tabElements.length - 1;
206
+ }
207
+ if (index > this.#tabElements.length - 1) {
208
+ index = 0;
209
+ }
210
+ this.#tabElements[index]?.focus({
211
+ preventScroll: false,
212
+ });
213
+ // Set the last tab navigated to as tabbable so that, if the tab button
214
+ // is pressed, focus moves to the tab's panel and not back to the
215
+ // last selected tab. This is particularly noticeable when the selected
216
+ // tab is to the left of the tab navigated to by keyboard.
217
+ for (const [, tabElement] of this.#tabElements.entries()) {
218
+ tabElement.tabIndex =
219
+ this.#tabElements[index] === tabElement ? 0 : -1;
220
+ }
221
+ this.#setOverflowButtonsState();
222
+ event.preventDefault(); // Prevent page scroll
223
+ }
224
+ }
225
+ }
226
+ #onDefaultSlotChange() {
227
+ this.#setAriaAttributes();
228
+ }
229
+ #onNavSlotChange() {
230
+ if (this.#lastSelectedTab) {
231
+ this.#lastSelectedTab.tabIndex = 0;
232
+ for (const tab of this.#tabElements) {
233
+ if (tab.selected && tab !== this.#lastSelectedTab) {
234
+ tab.selected = false;
235
+ tab.tabIndex = -1;
236
+ }
237
+ }
238
+ }
239
+ else if (this.#firstTab) {
240
+ this.#firstTab.selected = true;
241
+ this.#firstTab.tabIndex = 0;
242
+ }
243
+ for (const panel of this.#panelElements) {
244
+ panel.privateIsSelected = panel.name === this.#lastSelectedTab?.panel;
245
+ panel.tabIndex = panel.name === this.#lastSelectedTab?.panel ? 0 : -1;
246
+ }
247
+ this.#setAriaAttributes();
248
+ this.#setOverflowButtonsState();
249
+ }
250
+ #onOverflowButtonClick(button) {
251
+ const directionFactor = button === 'end' ? 1 : -1;
252
+ const percentageFactor = 0.5;
253
+ if (this.#tabListElementRef.value) {
254
+ this.#tabListElementRef.value.scrollBy({
255
+ left: directionFactor *
256
+ this.#tabListElementRef.value.clientWidth *
257
+ percentageFactor,
258
+ top: 0,
259
+ });
260
+ }
261
+ }
262
+ #onTabListFocusout() {
263
+ // Set the last selected tab as tabbable so that when pressing Shift + Tab on the
264
+ // Tab Panel focus goes back to the last selected tab.
265
+ for (const [, tabElement] of this.#tabElements.entries()) {
266
+ tabElement.tabIndex = tabElement === this.#lastSelectedTab ? 0 : -1;
267
+ }
268
+ }
269
+ #onTabListResize() {
270
+ if (this.#resizeTimeout) {
271
+ clearTimeout(this.#resizeTimeout);
272
+ }
273
+ // TODO
274
+ //
275
+ // This only needs to be called here so the indicator is updated when the content
276
+ // of Tab's slots changes.
277
+ //
278
+ // Tab's default slot will soon be replaced by a `label` attribute. When that
279
+ // happens, this call can be removed, and `#updateSelectedTabIndicator()` can be
280
+ // instead called when Tab dispatches "private-label-change" and
281
+ // "private-icon-slotchange" events.
282
+ //
283
+ // Those changes will certainly require slightly more code. But they'll make it
284
+ // much clearer why `#updateSelectedTabIndicator()` is being called. Additionally,
285
+ // Tab Group will no longer be doing unncessary work every time the viewport is
286
+ // resized.
287
+ this.#updateSelectedTabIndicator();
288
+ // Toggling the overflow buttons will itself cause a resize. So we
289
+ // wait a tick to avoid a loop.
290
+ this.#resizeTimeout = setTimeout(() => {
291
+ this.#setOverflowButtonsState();
292
+ });
293
+ }
294
+ #onTabSelected(event) {
295
+ if (event.target instanceof Tab && event.target.selected) {
296
+ event.target.privateSelect();
297
+ event.target.tabIndex = 0;
298
+ for (const tab of this.#tabElements) {
299
+ if (tab !== event.target) {
300
+ tab.selected = false;
301
+ tab.tabIndex = -1;
302
+ }
303
+ }
304
+ }
305
+ else if (this.#firstTab && !this.#lastSelectedTab) {
306
+ this.#firstTab.privateSelect();
307
+ this.#firstTab.tabIndex = 0;
308
+ }
309
+ this.#updateSelectedTabIndicator();
310
+ for (const panel of this.#panelElements) {
311
+ panel.privateIsSelected = panel.name === this.#lastSelectedTab?.panel;
312
+ panel.tabIndex = panel.name === this.#lastSelectedTab?.panel ? 0 : -1;
313
+ }
314
+ }
315
+ #setAriaAttributes() {
316
+ for (const tab of this.#tabElements) {
317
+ const relatedPanel = this.#panelElements
318
+ .filter((panel) => panel.name === tab.panel)
319
+ ?.at(0);
320
+ if (relatedPanel?.id) {
321
+ tab.setAttribute('aria-controls', relatedPanel.id);
322
+ relatedPanel.setAttribute('aria-labelledby', tab.id);
323
+ }
324
+ }
325
+ }
326
+ #setOverflowButtonsState() {
327
+ if (this.#tabListElementRef.value) {
328
+ this.isShowOverflowButtons =
329
+ this.#tabListElementRef.value.scrollWidth >
330
+ this.#tabListElementRef.value.clientWidth;
331
+ this.isDisableOverflowStartButton =
332
+ this.#tabListElementRef.value.scrollLeft <= 0;
333
+ this.isDisableOverflowEndButton =
334
+ // Rounded because `scrollLeft` is a float and `clientWidth` and `scrollWidth`
335
+ // are integers rounded up.
336
+ Math.round(this.#tabListElementRef.value.scrollLeft) +
337
+ this.#tabListElementRef.value.clientWidth >=
338
+ this.#tabListElementRef.value.scrollWidth;
339
+ }
340
+ }
341
+ #updateSelectedTabIndicator() {
342
+ if (this.#lastSelectedTab &&
343
+ this.#tabElements.length > 0 &&
344
+ this.#selectedTabIndicatorElementRef.value) {
345
+ const isFirstTab = this.#lastSelectedTab === this.#tabElements.at(0);
346
+ const isLastTab = this.#lastSelectedTab === this.#tabElements.at(-1);
347
+ const selectedTabInlinePadding = isFirstTab
348
+ ? Number.parseInt(window
349
+ .getComputedStyle(this.#lastSelectedTab)
350
+ .getPropertyValue('padding-inline-start'))
351
+ : isLastTab
352
+ ? Number.parseInt(window
353
+ .getComputedStyle(this.#lastSelectedTab)
354
+ .getPropertyValue('padding-inline-end'))
355
+ : 0;
356
+ const selectedTabIndicatorTranslateLeft = this.#lastSelectedTab === this.#tabElements.at(0)
357
+ ? selectedTabInlinePadding
358
+ : this.#lastSelectedTab.offsetLeft -
359
+ // `this.#tabElements.at(0)` is guaranteed to be defined by the guard at the
360
+ // top of this function.
361
+ //
362
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
363
+ this.#tabElements.at(0).offsetLeft;
364
+ this.#selectedTabIndicatorElementRef.value.style.setProperty('--private-selected-tab-indicator-translate', `${selectedTabIndicatorTranslateLeft}px`);
365
+ const { width: selectedTabWidth } = this.#lastSelectedTab.getBoundingClientRect();
366
+ this.#selectedTabIndicatorElementRef.value.style.setProperty('--private-selected-tab-indicator-width', `${selectedTabWidth - selectedTabInlinePadding}px`);
367
+ }
368
+ }
369
+ };
370
+ __decorate([
371
+ property({ reflect: true })
372
+ ], TabGroup.prototype, "version", void 0);
373
+ __decorate([
374
+ state()
375
+ ], TabGroup.prototype, "isDisableOverflowEndButton", void 0);
376
+ __decorate([
377
+ state()
378
+ ], TabGroup.prototype, "isDisableOverflowStartButton", void 0);
379
+ __decorate([
380
+ state()
381
+ ], TabGroup.prototype, "isShowOverflowButtons", void 0);
382
+ TabGroup = __decorate([
383
+ customElement('glide-core-tab-group'),
384
+ final
385
+ ], TabGroup);
386
+ export default TabGroup;
@@ -1,4 +1,6 @@
1
- import{css}from"lit";export default[css`
1
+ import { css } from 'lit';
2
+ export default [
3
+ css `
2
4
  :host {
3
5
  --tabs-padding-block-end: 0rem;
4
6
  --tabs-padding-block-start: 0rem;
@@ -102,4 +104,5 @@ import{css}from"lit";export default[css`
102
104
  ::slotted([slot='nav']:last-of-type) {
103
105
  padding-inline-end: 0.1875rem;
104
106
  }
105
- `];
107
+ `,
108
+ ];
package/dist/tab.js CHANGED
@@ -1 +1,133 @@
1
- var __decorate=this&&this.__decorate||function(e,t,o,s){var r,i=arguments.length,a=i<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,o):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,o,s);else for(var l=e.length-1;l>=0;l--)(r=e[l])&&(a=(i<3?r(a):i>3?r(t,o,a):r(t,o))||a);return i>3&&a&&Object.defineProperty(t,o,a),a};import{html,LitElement}from"lit";import{classMap}from"lit/directives/class-map.js";import{customElement,property}from"lit/decorators.js";import packageJson from"../package.json"with{type:"json"};import styles from"./tab.styles.js";import shadowRootMode from"./library/shadow-root-mode.js";import final from"./library/final.js";import required from"./library/required.js";import uniqueId from"./library/unique-id.js";let Tab=class Tab extends LitElement{constructor(){super(...arguments),this.disabled=!1,this.version=packageJson.version,this.id=uniqueId(),this.role="tab",this.#e=!1}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:shadowRootMode}}static{this.styles=styles}get selected(){return this.#e}set selected(e){const t=e!==this.#e;this.#e=e,t&&this.dispatchEvent(new Event("private-selected",{bubbles:!0}))}privateSelect(){this.selected=!0,this.dispatchEvent(new Event("selected",{bubbles:!0,composed:!0}))}render(){return html`<div class="${classMap({component:!0,disabled:this.disabled,selected:this.selected})}" data-test="component"><div class="container"><slot name="icon"></slot><slot></slot></div></div>`}updated(e){e.has("selected")&&this.setAttribute("aria-selected",this.selected?"true":"false"),e.has("disabled")&&(this.disabled?(this.setAttribute("aria-disabled","true"),this.setAttribute("tabindex","-1")):this.removeAttribute("aria-disabled"))}#e};__decorate([property({reflect:!0}),required],Tab.prototype,"panel",void 0),__decorate([property({type:Boolean,reflect:!0})],Tab.prototype,"disabled",void 0),__decorate([property({type:Boolean,reflect:!0})],Tab.prototype,"selected",null),__decorate([property({reflect:!0})],Tab.prototype,"version",void 0),__decorate([property({reflect:!0})],Tab.prototype,"id",void 0),__decorate([property({reflect:!0})],Tab.prototype,"role",void 0),Tab=__decorate([customElement("glide-core-tab"),final],Tab);export default Tab;
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 { html, LitElement } from 'lit';
8
+ import { classMap } from 'lit/directives/class-map.js';
9
+ import { customElement, property } from 'lit/decorators.js';
10
+ import packageJson from '../package.json' with { type: 'json' };
11
+ import styles from './tab.styles.js';
12
+ import shadowRootMode from './library/shadow-root-mode.js';
13
+ import final from './library/final.js';
14
+ import required from './library/required.js';
15
+ import uniqueId from './library/unique-id.js';
16
+ /**
17
+ * @attr {string} panel
18
+ * @attr {boolean} [disabled=false]
19
+ *
20
+ * @readonly
21
+ * @attr {string} [id]
22
+ *
23
+ * @readonly
24
+ * @attr {string} [role='tab']
25
+ *
26
+ * @attr {boolean} [selected=false]
27
+ *
28
+ * @readonly
29
+ * @attr {string} [version]
30
+ *
31
+ * @slot {Element | string} - A label
32
+ * @slot {Element} [icon]
33
+ *
34
+ * @fires {Event} selected
35
+ */
36
+ let Tab = class Tab extends LitElement {
37
+ constructor() {
38
+ super(...arguments);
39
+ this.disabled = false;
40
+ this.version = packageJson.version;
41
+ this.id = uniqueId();
42
+ this.role = 'tab';
43
+ this.#isSelected = false;
44
+ }
45
+ static { this.shadowRootOptions = {
46
+ ...LitElement.shadowRootOptions,
47
+ mode: shadowRootMode,
48
+ }; }
49
+ static { this.styles = styles; }
50
+ /**
51
+ * @default false
52
+ */
53
+ get selected() {
54
+ return this.#isSelected;
55
+ }
56
+ set selected(isSelected) {
57
+ const hasChanged = isSelected !== this.#isSelected;
58
+ this.#isSelected = isSelected;
59
+ if (hasChanged) {
60
+ this.dispatchEvent(new Event('private-selected', {
61
+ bubbles: true,
62
+ }));
63
+ }
64
+ }
65
+ privateSelect() {
66
+ this.selected = true;
67
+ this.dispatchEvent(new Event('selected', { bubbles: true, composed: true }));
68
+ }
69
+ render() {
70
+ return html `<div
71
+ class=${classMap({
72
+ component: true,
73
+ disabled: this.disabled,
74
+ selected: this.selected,
75
+ })}
76
+ data-test="component"
77
+ >
78
+ <div class="container">
79
+ <slot name="icon">
80
+ <!--
81
+ @type {Element}
82
+ -->
83
+ </slot>
84
+
85
+ <slot>
86
+ <!--
87
+ A label
88
+ @type {Element | string}
89
+ -->
90
+ </slot>
91
+ </div>
92
+ </div>`;
93
+ }
94
+ updated(changes) {
95
+ if (changes.has('selected')) {
96
+ this.setAttribute('aria-selected', this.selected ? 'true' : 'false');
97
+ }
98
+ if (changes.has('disabled')) {
99
+ if (this.disabled) {
100
+ this.setAttribute('aria-disabled', 'true');
101
+ this.setAttribute('tabindex', '-1');
102
+ }
103
+ else {
104
+ this.removeAttribute('aria-disabled');
105
+ }
106
+ }
107
+ }
108
+ #isSelected;
109
+ };
110
+ __decorate([
111
+ property({ reflect: true }),
112
+ required
113
+ ], Tab.prototype, "panel", void 0);
114
+ __decorate([
115
+ property({ type: Boolean, reflect: true })
116
+ ], Tab.prototype, "disabled", void 0);
117
+ __decorate([
118
+ property({ type: Boolean, reflect: true })
119
+ ], Tab.prototype, "selected", null);
120
+ __decorate([
121
+ property({ reflect: true })
122
+ ], Tab.prototype, "version", void 0);
123
+ __decorate([
124
+ property({ reflect: true })
125
+ ], Tab.prototype, "id", void 0);
126
+ __decorate([
127
+ property({ reflect: true })
128
+ ], Tab.prototype, "role", void 0);
129
+ Tab = __decorate([
130
+ customElement('glide-core-tab'),
131
+ final
132
+ ], Tab);
133
+ export default Tab;
package/dist/tab.panel.js CHANGED
@@ -1 +1,93 @@
1
- var __decorate=this&&this.__decorate||function(e,t,r,o){var a,i=arguments.length,s=i<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,r):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,o);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(s=(i<3?a(s):i>3?a(t,r,s):a(t,r))||s);return i>3&&s&&Object.defineProperty(t,r,s),s};import{html,LitElement}from"lit";import{classMap}from"lit/directives/class-map.js";import{customElement,property}from"lit/decorators.js";import packageJson from"../package.json"with{type:"json"};import styles from"./tab.panel.styles.js";import shadowRootMode from"./library/shadow-root-mode.js";import final from"./library/final.js";import required from"./library/required.js";import uniqueId from"./library/unique-id.js";let TabPanel=class TabPanel extends LitElement{constructor(){super(...arguments),this.version=packageJson.version,this.role="tabpanel",this.id=uniqueId(),this.#e=!1}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:shadowRootMode}}static{this.styles=styles}get privateIsSelected(){return this.#e}set privateIsSelected(e){this.setAttribute("aria-hidden",e?"false":"true"),this.#e=e}render(){return html`<div class="${classMap({component:!0,hidden:!this.privateIsSelected,selected:this.privateIsSelected})}" data-test="tab-panel"><slot></slot></div>`}#e};__decorate([property({reflect:!0}),required],TabPanel.prototype,"name",void 0),__decorate([property({type:Boolean})],TabPanel.prototype,"privateIsSelected",null),__decorate([property({reflect:!0})],TabPanel.prototype,"version",void 0),__decorate([property({reflect:!0})],TabPanel.prototype,"role",void 0),__decorate([property({reflect:!0})],TabPanel.prototype,"id",void 0),TabPanel=__decorate([customElement("glide-core-tab-panel"),final],TabPanel);export default TabPanel;
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 { html, LitElement } from 'lit';
8
+ import { classMap } from 'lit/directives/class-map.js';
9
+ import { customElement, property } from 'lit/decorators.js';
10
+ import packageJson from '../package.json' with { type: 'json' };
11
+ import styles from './tab.panel.styles.js';
12
+ import shadowRootMode from './library/shadow-root-mode.js';
13
+ import final from './library/final.js';
14
+ import required from './library/required.js';
15
+ import uniqueId from './library/unique-id.js';
16
+ /**
17
+ * @attr {string} name - The corresponding Tab should have a `panel` attribute with this name
18
+ *
19
+ * @readonly
20
+ * @attr {string} [id]
21
+ *
22
+ * @readonly
23
+ * @attr {string} [role='tabpanel']
24
+ *
25
+ * @readonly
26
+ * @attr {string} [version]
27
+ *
28
+ * @slot {Element | string} - The content of the panel
29
+ *
30
+ * @cssprop [--padding-inline-end=0rem]
31
+ * @cssprop [--padding-inline-start=0rem]
32
+ */
33
+ let TabPanel = class TabPanel extends LitElement {
34
+ constructor() {
35
+ super(...arguments);
36
+ this.version = packageJson.version;
37
+ this.role = 'tabpanel';
38
+ this.id = uniqueId();
39
+ this.#isSelected = false;
40
+ }
41
+ static { this.shadowRootOptions = {
42
+ ...LitElement.shadowRootOptions,
43
+ mode: shadowRootMode,
44
+ }; }
45
+ static { this.styles = styles; }
46
+ // Private because it's only meant to be used by Tab Group.
47
+ get privateIsSelected() {
48
+ return this.#isSelected;
49
+ }
50
+ set privateIsSelected(isSelected) {
51
+ this.setAttribute('aria-hidden', isSelected ? 'false' : 'true');
52
+ this.#isSelected = isSelected;
53
+ }
54
+ render() {
55
+ return html `<div
56
+ class=${classMap({
57
+ component: true,
58
+ hidden: !this.privateIsSelected,
59
+ selected: this.privateIsSelected,
60
+ })}
61
+ data-test="tab-panel"
62
+ >
63
+ <slot>
64
+ <!--
65
+ The content of the panel
66
+ @type {Element | string}
67
+ -->
68
+ </slot>
69
+ </div>`;
70
+ }
71
+ #isSelected;
72
+ };
73
+ __decorate([
74
+ property({ reflect: true }),
75
+ required
76
+ ], TabPanel.prototype, "name", void 0);
77
+ __decorate([
78
+ property({ type: Boolean })
79
+ ], TabPanel.prototype, "privateIsSelected", null);
80
+ __decorate([
81
+ property({ reflect: true })
82
+ ], TabPanel.prototype, "version", void 0);
83
+ __decorate([
84
+ property({ reflect: true })
85
+ ], TabPanel.prototype, "role", void 0);
86
+ __decorate([
87
+ property({ reflect: true })
88
+ ], TabPanel.prototype, "id", void 0);
89
+ TabPanel = __decorate([
90
+ customElement('glide-core-tab-panel'),
91
+ final
92
+ ], TabPanel);
93
+ export default TabPanel;
@@ -1,7 +1,12 @@
1
- import{css}from"lit";import focusOutline from"./styles/focus-outline.js";import visuallyHidden from"./styles/visually-hidden.js";export default[css`
2
- ${focusOutline(":host(:focus-visible) .component")}
3
- ${visuallyHidden(".hidden")}
4
- `,css`
1
+ import { css } from 'lit';
2
+ import focusOutline from './styles/focus-outline.js';
3
+ import visuallyHidden from './styles/visually-hidden.js';
4
+ export default [
5
+ css `
6
+ ${focusOutline(':host(:focus-visible) .component')}
7
+ ${visuallyHidden('.hidden')}
8
+ `,
9
+ css `
5
10
  :host {
6
11
  --padding-inline-end: 0rem;
7
12
  --padding-inline-start: 0rem;
@@ -33,4 +38,5 @@ import{css}from"lit";import focusOutline from"./styles/focus-outline.js";import
33
38
  block-size: 100%;
34
39
  }
35
40
  }
36
- `];
41
+ `,
42
+ ];