@crowdstrike/glide-core 0.5.1 → 0.6.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 (242) hide show
  1. package/README.md +11 -1
  2. package/dist/accordion.js +1 -1
  3. package/dist/accordion.styles.js +5 -4
  4. package/dist/accordion.test.basics.js +109 -0
  5. package/dist/accordion.test.events.js +39 -0
  6. package/dist/button-group.button.js +1 -1
  7. package/dist/button-group.button.styles.js +6 -5
  8. package/dist/button-group.button.test.basics.js +169 -0
  9. package/dist/button-group.button.test.events.js +73 -0
  10. package/dist/button-group.js +1 -1
  11. package/dist/button-group.styles.js +3 -3
  12. package/dist/button-group.test.basics.js +268 -0
  13. package/dist/button-group.test.events.js +291 -0
  14. package/dist/button.d.ts +3 -2
  15. package/dist/button.js +1 -1
  16. package/dist/button.styles.js +5 -5
  17. package/dist/button.test.basics.js +202 -0
  18. package/dist/button.test.events.js +25 -0
  19. package/dist/button.test.form.js +49 -0
  20. package/dist/checkbox-group.js +1 -1
  21. package/dist/checkbox-group.styles.js +2 -2
  22. package/dist/checkbox-group.test.basics.js +119 -0
  23. package/dist/checkbox-group.test.events.js +110 -0
  24. package/dist/checkbox-group.test.focus.js +45 -0
  25. package/dist/checkbox-group.test.form.js +130 -0
  26. package/dist/checkbox-group.test.validity.js +75 -0
  27. package/dist/checkbox.js +1 -1
  28. package/dist/checkbox.styles.js +7 -4
  29. package/dist/checkbox.test.basics.js +89 -0
  30. package/dist/checkbox.test.events.js +87 -0
  31. package/dist/checkbox.test.focus.js +38 -0
  32. package/dist/checkbox.test.form.js +115 -0
  33. package/dist/checkbox.test.states.js +62 -0
  34. package/dist/checkbox.test.validity.js +51 -0
  35. package/dist/drawer.d.ts +2 -2
  36. package/dist/drawer.js +1 -15
  37. package/dist/drawer.styles.js +14 -4
  38. package/dist/drawer.test.accessibility.js +22 -0
  39. package/dist/drawer.test.basics.js +43 -0
  40. package/dist/drawer.test.closing.js +37 -0
  41. package/dist/drawer.test.events.js +52 -0
  42. package/dist/drawer.test.floating-components.d.ts +1 -0
  43. package/dist/drawer.test.floating-components.js +51 -0
  44. package/dist/drawer.test.methods.js +34 -0
  45. package/dist/dropdown.d.ts +4 -2
  46. package/dist/dropdown.js +1 -1
  47. package/dist/dropdown.option.d.ts +0 -2
  48. package/dist/dropdown.option.js +1 -1
  49. package/dist/dropdown.option.styles.js +2 -2
  50. package/dist/dropdown.option.test.basics.js +59 -0
  51. package/dist/dropdown.option.test.basics.multiple.js +26 -0
  52. package/dist/dropdown.option.test.basics.single.js +20 -0
  53. package/dist/dropdown.option.test.events.js +27 -0
  54. package/dist/dropdown.option.test.focus.js +11 -0
  55. package/dist/dropdown.option.test.interactions.multiple.js +82 -0
  56. package/dist/dropdown.option.test.interactions.single.js +22 -0
  57. package/dist/dropdown.styles.js +26 -6
  58. package/dist/dropdown.test.basics.filterable.js +84 -0
  59. package/dist/dropdown.test.basics.js +233 -0
  60. package/dist/dropdown.test.basics.multiple.js +270 -0
  61. package/dist/dropdown.test.basics.single.js +79 -0
  62. package/dist/dropdown.test.events.js +268 -0
  63. package/dist/dropdown.test.events.multiple.js +130 -0
  64. package/dist/dropdown.test.focus.d.ts +1 -0
  65. package/dist/dropdown.test.focus.filterable.js +154 -0
  66. package/dist/dropdown.test.focus.js +28 -0
  67. package/dist/dropdown.test.focus.multiple.js +181 -0
  68. package/dist/dropdown.test.focus.single.js +53 -0
  69. package/dist/dropdown.test.form.js +140 -0
  70. package/dist/dropdown.test.form.multiple.js +149 -0
  71. package/dist/dropdown.test.form.single.js +128 -0
  72. package/dist/dropdown.test.interactions.filterable.js +449 -0
  73. package/dist/dropdown.test.interactions.js +446 -0
  74. package/dist/dropdown.test.interactions.multiple.js +908 -0
  75. package/dist/dropdown.test.interactions.single.js +466 -0
  76. package/dist/dropdown.test.validity.js +46 -0
  77. package/dist/icon-button.d.ts +3 -2
  78. package/dist/icon-button.js +1 -1
  79. package/dist/icon-button.styles.js +12 -12
  80. package/dist/icon-button.test.basics.js +110 -0
  81. package/dist/icons/checked.js +1 -1
  82. package/dist/icons/magnifying-glass.js +1 -1
  83. package/dist/input.js +1 -1
  84. package/dist/input.styles.js +4 -3
  85. package/dist/input.test.basics.js +169 -0
  86. package/dist/input.test.events.js +97 -0
  87. package/dist/input.test.focus.js +54 -0
  88. package/dist/input.test.form.js +56 -0
  89. package/dist/input.test.validity.js +50 -0
  90. package/dist/label.js +1 -1
  91. package/dist/label.styles.js +13 -15
  92. package/dist/label.test.basics.js +129 -0
  93. package/dist/library/expect-argument-error.js +1 -1
  94. package/dist/library/localize.d.ts +17 -0
  95. package/dist/library/localize.js +1 -0
  96. package/dist/library/ow.js +1 -1
  97. package/dist/library/ow.test.js +55 -0
  98. package/dist/library/set-containing-block.d.ts +15 -0
  99. package/dist/library/set-containing-block.js +1 -0
  100. package/dist/menu.button.d.ts +1 -2
  101. package/dist/menu.button.js +1 -1
  102. package/dist/menu.button.styles.js +3 -3
  103. package/dist/menu.button.test.basics.js +42 -0
  104. package/dist/menu.d.ts +7 -2
  105. package/dist/menu.js +1 -1
  106. package/dist/menu.link.d.ts +1 -2
  107. package/dist/menu.link.js +1 -1
  108. package/dist/menu.link.styles.js +3 -3
  109. package/dist/menu.link.test.basics.js +46 -0
  110. package/dist/menu.options.d.ts +22 -0
  111. package/dist/menu.options.js +1 -0
  112. package/dist/menu.options.styles.d.ts +2 -0
  113. package/dist/menu.options.styles.js +33 -0
  114. package/dist/menu.options.test.basics.d.ts +2 -0
  115. package/dist/menu.options.test.basics.js +43 -0
  116. package/dist/menu.stories.d.ts +1 -0
  117. package/dist/menu.styles.js +7 -31
  118. package/dist/menu.test.basics.d.ts +1 -0
  119. package/dist/menu.test.basics.js +183 -0
  120. package/dist/menu.test.focus.d.ts +0 -1
  121. package/dist/menu.test.focus.js +84 -0
  122. package/dist/menu.test.interactions.d.ts +1 -1
  123. package/dist/menu.test.interactions.js +664 -0
  124. package/dist/modal.icon-button.js +1 -1
  125. package/dist/modal.icon-button.styles.js +2 -2
  126. package/dist/modal.icon-button.test.basics.js +45 -0
  127. package/dist/modal.js +1 -15
  128. package/dist/modal.styles.js +4 -7
  129. package/dist/modal.tertiary-icon.d.ts +1 -0
  130. package/dist/modal.tertiary-icon.js +1 -1
  131. package/dist/modal.tertiary-icon.test.basics.js +59 -0
  132. package/dist/modal.test.accessibility.js +48 -0
  133. package/dist/modal.test.basics.js +203 -0
  134. package/dist/modal.test.close.js +38 -0
  135. package/dist/modal.test.events.js +110 -0
  136. package/dist/modal.test.floating-components.d.ts +1 -0
  137. package/dist/modal.test.floating-components.js +62 -0
  138. package/dist/modal.test.lock-scroll.js +76 -0
  139. package/dist/modal.test.methods.js +23 -0
  140. package/dist/modal.test.scrollbars.js +19 -0
  141. package/dist/radio-group.js +1 -1
  142. package/dist/radio-group.styles.js +20 -24
  143. package/dist/radio-group.test.basics.js +323 -0
  144. package/dist/radio-group.test.events.js +277 -0
  145. package/dist/radio-group.test.focus.js +75 -0
  146. package/dist/radio-group.test.form.js +104 -0
  147. package/dist/radio-group.test.validity.js +228 -0
  148. package/dist/radio.js +1 -1
  149. package/dist/radio.styles.js +14 -31
  150. package/dist/split-button.d.ts +27 -0
  151. package/dist/split-button.js +1 -0
  152. package/dist/split-button.stories.d.ts +17 -0
  153. package/dist/split-button.styles.d.ts +2 -0
  154. package/dist/split-button.styles.js +102 -0
  155. package/dist/split-button.test.basics.d.ts +1 -0
  156. package/dist/split-button.test.basics.js +99 -0
  157. package/dist/split-container.d.ts +31 -0
  158. package/dist/split-container.js +1 -0
  159. package/dist/split-container.styles.d.ts +2 -0
  160. package/dist/split-container.styles.js +134 -0
  161. package/dist/split-container.test.basics.d.ts +3 -0
  162. package/dist/split-container.test.basics.js +440 -0
  163. package/dist/split-container.test.interactions.d.ts +1 -0
  164. package/dist/split-container.test.interactions.js +20 -0
  165. package/dist/split-link.d.ts +25 -0
  166. package/dist/split-link.js +1 -0
  167. package/dist/split-link.test.basics.d.ts +1 -0
  168. package/dist/split-link.test.basics.js +92 -0
  169. package/dist/split-link.test.interactions.d.ts +1 -0
  170. package/dist/split-link.test.interactions.js +19 -0
  171. package/dist/status-indicator.js +1 -1
  172. package/dist/status-indicator.styles.js +2 -2
  173. package/dist/status-indicator.test.basics.js +102 -0
  174. package/dist/styles/focus-outline.js +1 -4
  175. package/dist/styles/variables.css +1 -1
  176. package/dist/styles/visually-hidden.js +1 -11
  177. package/dist/tab.group.js +1 -1
  178. package/dist/tab.group.styles.js +2 -2
  179. package/dist/tab.group.test.basics.js +185 -0
  180. package/dist/tab.js +1 -1
  181. package/dist/tab.panel.js +1 -1
  182. package/dist/tab.panel.styles.js +3 -3
  183. package/dist/tab.styles.js +80 -55
  184. package/dist/tab.test.basics.js +71 -0
  185. package/dist/tag.js +1 -1
  186. package/dist/tag.styles.js +4 -3
  187. package/dist/tag.test.basics.js +118 -0
  188. package/dist/tag.test.events.js +16 -0
  189. package/dist/tag.test.focus.js +11 -0
  190. package/dist/tag.test.translations.d.ts +1 -0
  191. package/dist/tag.test.translations.js +25 -0
  192. package/dist/textarea.js +2 -2
  193. package/dist/textarea.styles.js +5 -4
  194. package/dist/textarea.test.basics.js +140 -0
  195. package/dist/textarea.test.events.js +204 -0
  196. package/dist/textarea.test.form.js +70 -0
  197. package/dist/textarea.test.validity.js +83 -0
  198. package/dist/toasts.js +1 -1
  199. package/dist/toasts.styles.js +2 -2
  200. package/dist/toasts.test.basics.js +94 -0
  201. package/dist/toasts.toast.js +1 -1
  202. package/dist/toasts.toast.styles.js +5 -2
  203. package/dist/toasts.toast.test.basics.js +139 -0
  204. package/dist/toggle.js +1 -1
  205. package/dist/toggle.styles.js +3 -3
  206. package/dist/toggle.test.basics.js +68 -0
  207. package/dist/toggle.test.events.js +29 -0
  208. package/dist/toggle.test.focus.js +9 -0
  209. package/dist/toggle.test.states.js +43 -0
  210. package/dist/tooltip.d.ts +2 -0
  211. package/dist/tooltip.js +1 -1
  212. package/dist/tooltip.styles.js +5 -3
  213. package/dist/tooltip.test.basics.js +64 -0
  214. package/dist/tooltip.test.interactions.js +78 -0
  215. package/dist/translations/en.d.ts +3 -0
  216. package/dist/translations/en.js +1 -0
  217. package/dist/translations/fr.d.ts +3 -0
  218. package/dist/translations/fr.js +1 -0
  219. package/dist/translations/ja.d.ts +3 -0
  220. package/dist/translations/ja.js +1 -0
  221. package/dist/tree.d.ts +1 -0
  222. package/dist/tree.item.d.ts +3 -1
  223. package/dist/tree.item.icon-button.js +1 -1
  224. package/dist/tree.item.icon-button.styles.js +2 -2
  225. package/dist/tree.item.icon-button.test.basics.js +13 -0
  226. package/dist/tree.item.js +1 -1
  227. package/dist/tree.item.menu.d.ts +2 -0
  228. package/dist/tree.item.menu.js +1 -1
  229. package/dist/tree.item.menu.styles.js +2 -2
  230. package/dist/tree.item.menu.test.basics.js +33 -0
  231. package/dist/tree.item.styles.js +23 -8
  232. package/dist/tree.item.test.basics.js +102 -0
  233. package/dist/tree.js +1 -1
  234. package/dist/tree.stories.d.ts +1 -0
  235. package/dist/tree.styles.js +2 -2
  236. package/dist/tree.test.aria.js +86 -0
  237. package/dist/tree.test.basics.js +123 -0
  238. package/dist/tree.test.events.js +19 -0
  239. package/dist/tree.test.focus.js +261 -0
  240. package/package.json +25 -18
  241. /package/dist/{dropdown.option.test.focus.multiple.d.ts → dropdown.option.test.focus.d.ts} +0 -0
  242. /package/dist/{dropdown.option.test.focus.single.d.ts → dropdown.test.events.multiple.d.ts} +0 -0
@@ -0,0 +1,62 @@
1
+ import { expect, fixture, html } from '@open-wc/testing';
2
+ import GlideCoreModal from './modal.js';
3
+ import GlideCoreModalTertiaryIcon from './modal.tertiary-icon.js';
4
+ import GlideCoreTreeItemMenu from './tree.item.menu.js';
5
+ GlideCoreModal.shadowRootOptions.mode = 'open';
6
+ GlideCoreModalTertiaryIcon.shadowRootOptions.mode = 'open';
7
+ GlideCoreTreeItemMenu.shadowRootOptions.mode = 'open';
8
+ it('sets containing block for tooltips', async () => {
9
+ const element = await fixture(html `<glide-core-modal label="Modal title">
10
+ <glide-core-tooltip>
11
+ Tooltip
12
+ <span slot="target">Target</span>
13
+ </glide-core-tooltip>
14
+ <glide-core-modal-tertiary-icon
15
+ slot="tertiary"
16
+ label="Information"
17
+ tooltip-placement="right"
18
+ >
19
+ Icon
20
+ </glide-core-modal-tertiary-icon>
21
+ </glide-core-modal>`);
22
+ const containingBlock = element.shadowRoot?.querySelector('dialog');
23
+ element.showModal();
24
+ const tooltip = element.querySelector('glide-core-tooltip');
25
+ expect(tooltip?.containingBlock === containingBlock).to.be.true;
26
+ const tertiaryIconTooltip = element
27
+ .querySelector('glide-core-modal-tertiary-icon')
28
+ ?.shadowRoot?.querySelector('glide-core-tooltip');
29
+ expect(tertiaryIconTooltip?.containingBlock === containingBlock).to.be.true;
30
+ });
31
+ it('sets containing block for menus', async () => {
32
+ const element = await fixture(html `<glide-core-modal label="Modal title">
33
+ <glide-core-menu>
34
+ <glide-core-menu-options>
35
+ <glide-core-menu-link label="One" url="/one"> </glide-core-menu-link>
36
+ </glide-core-menu-options>
37
+
38
+ <div slot="target">Target</div>
39
+ </glide-core-menu>
40
+ </glide-core-modal>`);
41
+ const containingBlock = element.shadowRoot?.querySelector('dialog');
42
+ element.showModal();
43
+ const menu = element.querySelector('glide-core-menu');
44
+ expect(menu?.containingBlock === containingBlock).to.be.true;
45
+ });
46
+ it('sets containing block for tree item menu', async () => {
47
+ const element = await fixture(html `<glide-core-modal label="Modal title">
48
+ <glide-core-tree>
49
+ <glide-core-tree-item label="yup">
50
+ <glide-core-tree-item-menu slot="menu">
51
+ <glide-core-menu-link label="Edit" url="/edit">
52
+ </glide-core-menu-link>
53
+ </glide-core-tree-item-menu>
54
+ </glide-core-tree-item>
55
+ </glide-core-tree>
56
+ </glide-core-modal>`);
57
+ const containingBlock = element.shadowRoot?.querySelector('dialog');
58
+ element.showModal();
59
+ const treeItemMenu = element.querySelector('glide-core-tree-item-menu');
60
+ const menu = treeItemMenu?.shadowRoot?.querySelector('glide-core-menu');
61
+ expect(menu?.containingBlock === containingBlock).to.be.true;
62
+ });
@@ -0,0 +1,76 @@
1
+ import * as sinon from 'sinon';
2
+ import { expect, fixture, html } from '@open-wc/testing';
3
+ import { sendKeys, sendMouse } from '@web/test-runner-commands';
4
+ import GlideCoreModal from './modal.js';
5
+ GlideCoreModal.shadowRootOptions.mode = 'open';
6
+ const addSpy = sinon.spy(document.documentElement.classList, 'add');
7
+ const removeSpy = sinon.spy(document.documentElement.classList, 'remove');
8
+ afterEach(() => {
9
+ addSpy.resetHistory();
10
+ removeSpy.resetHistory();
11
+ });
12
+ after(() => {
13
+ addSpy.restore();
14
+ removeSpy.restore();
15
+ });
16
+ it('adds the "private-glide-core-modal-lock-scroll" class to the documentElement when opened and removes it when closed', async () => {
17
+ const element = await fixture(html `<glide-core-modal label="Modal title"
18
+ >Modal Content</glide-core-modal
19
+ >`);
20
+ element.showModal();
21
+ expect(addSpy.callCount).to.equal(1);
22
+ expect(addSpy.calledWith('private-glide-core-modal-lock-scroll')).to.be.ok;
23
+ expect(removeSpy.callCount).to.equal(0);
24
+ element.close();
25
+ expect(removeSpy.callCount).to.equal(1);
26
+ expect(removeSpy.calledWith('private-glide-core-modal-lock-scroll')).to.be.ok;
27
+ // Verify `add` was not called again for some reason
28
+ expect(addSpy.callCount).to.equal(1);
29
+ });
30
+ it('removes the "private-glide-core-modal-lock-scroll" class when the close button is clicked', async () => {
31
+ const element = await fixture(html `<glide-core-modal label="Modal title"
32
+ >Modal Content</glide-core-modal
33
+ >`);
34
+ element.showModal();
35
+ expect(removeSpy.callCount).to.equal(0);
36
+ const button = element.shadowRoot.querySelector('[data-test="close-button"]');
37
+ expect(button).to.be.ok;
38
+ button?.click();
39
+ expect(removeSpy.callCount).to.equal(1);
40
+ });
41
+ it('removes the "private-glide-core-modal-lock-scroll" class when the "close" method is called', async () => {
42
+ const element = await fixture(html `<glide-core-modal label="Modal title"
43
+ >Modal Content</glide-core-modal
44
+ >`);
45
+ element.showModal();
46
+ expect(removeSpy.callCount).to.equal(0);
47
+ const dialogElement = element.shadowRoot.querySelector('dialog');
48
+ expect(dialogElement?.hasAttribute('open')).to.be.true;
49
+ element.close();
50
+ expect(removeSpy.callCount).to.equal(1);
51
+ });
52
+ it('removes the "private-glide-core-modal-lock-scroll" class when the escape key is pressed', async () => {
53
+ const element = await fixture(html `<glide-core-modal label="Modal title"
54
+ >Modal Content</glide-core-modal
55
+ >`);
56
+ element.showModal();
57
+ expect(removeSpy.callCount).to.equal(0);
58
+ await sendKeys({ press: 'Escape' });
59
+ expect(removeSpy.callCount).to.equal(1);
60
+ });
61
+ it('removes class "private-glide-core-modal-lock-scroll" from document when click is outside dialog', async () => {
62
+ const element = await fixture(html `<glide-core-modal label="Modal title"
63
+ >Modal Content</glide-core-modal
64
+ >`);
65
+ element.showModal();
66
+ const dialogElement = element?.shadowRoot?.querySelector('dialog');
67
+ const boundingRectangle = dialogElement?.getBoundingClientRect();
68
+ expect(boundingRectangle).is.not.null;
69
+ expect(document.documentElement.classList.contains('private-glide-core-modal-lock-scroll')).to.be.true;
70
+ const { top, left } = boundingRectangle;
71
+ await sendMouse({
72
+ type: 'click',
73
+ position: [Math.floor(left - 1), Math.floor(top - 1)],
74
+ });
75
+ expect(document.documentElement.classList.contains('private-glide-core-modal-lock-scroll')).to.be.false;
76
+ });
@@ -0,0 +1,23 @@
1
+ import { expect, fixture, html } from '@open-wc/testing';
2
+ import GlideCoreModal from './modal.js';
3
+ GlideCoreModal.shadowRootOptions.mode = 'open';
4
+ it('opens the modal when the "showModal" method is called and closes it when "close" is called', async () => {
5
+ const element = await fixture(html `<glide-core-modal label="Modal title">
6
+ Modal Content
7
+ </glide-core-modal>`);
8
+ element.showModal();
9
+ const dialogElement = element.shadowRoot?.querySelector('dialog');
10
+ expect(dialogElement?.hasAttribute('open')).to.be.true;
11
+ element.close();
12
+ expect(dialogElement?.hasAttribute('open')).to.be.false;
13
+ });
14
+ it('remains open when the "showModal" method is called twice', async () => {
15
+ const element = await fixture(html `<glide-core-modal label="Modal title">
16
+ Modal Content
17
+ </glide-core-modal>`);
18
+ element.showModal();
19
+ const dialogElement = element.shadowRoot?.querySelector('dialog');
20
+ expect(dialogElement?.hasAttribute('open')).to.be.true;
21
+ element.showModal();
22
+ expect(dialogElement?.hasAttribute('open')).to.be.true;
23
+ });
@@ -0,0 +1,19 @@
1
+ import './modal.js';
2
+ import * as sinon from 'sinon';
3
+ import { expect, fixture, html } from '@open-wc/testing';
4
+ import GlideCoreModal from './modal.js';
5
+ GlideCoreModal.shadowRootOptions.mode = 'open';
6
+ const cssSupportsStub = sinon.stub(window.CSS, 'supports').returns(false);
7
+ const setPropertySpy = sinon.spy(document.documentElement.style, 'setProperty');
8
+ afterEach(() => {
9
+ cssSupportsStub.restore();
10
+ setPropertySpy.restore();
11
+ });
12
+ it('sets the "--glide-scroll-size" variable when the browser does not support scrollbar-gutter', async () => {
13
+ const element = await fixture(html `<glide-core-modal label="Modal title">
14
+ Modal Content
15
+ </glide-core-modal>`);
16
+ element.showModal();
17
+ expect(cssSupportsStub.calledWith('scrollbar-gutter')).to.be.ok;
18
+ expect(setPropertySpy.callCount).to.equal(1);
19
+ });
@@ -1 +1 @@
1
- "use strict";var tt=Object.defineProperty;var et=Object.getOwnPropertyDescriptor;var m=(n,d,t,e)=>{for(var i=e>1?void 0:e?et(d,t):d,b=n.length-1,A;b>=0;b--)(A=n[b])&&(i=(e?A(d,t,i):A(i))||i);return e&&i&&tt(d,t,i),i};var O=(n,d,t)=>{if(!d.has(n))throw TypeError("Cannot "+t)};var s=(n,d,t)=>(O(n,d,"read from private field"),t?t.call(n):d.get(n)),o=(n,d,t)=>{if(d.has(n))throw TypeError("Cannot add the same private member more than once");d instanceof WeakSet?d.add(n):d.set(n,t)},E=(n,d,t,e)=>(O(n,d,"write to private field"),e?e.call(n,t):d.set(n,t),t);var a=(n,d,t)=>(O(n,d,"access private method"),t);var R,g,p,c,y,I,V,F,S,B,$,X,x,Y,C,Z,D,_,U,G,l,r,u,v,w,T,q,H,L,z,M,K;import"./label.js";import"./tooltip.js";import{LitElement as N,html as it}from"lit";import{classMap as st}from"lit/directives/class-map.js";import{createRef as j,ref as J}from"lit/directives/ref.js";import{customElement as at,property as k,state as P}from"lit/decorators.js";import{owSlot as Q,owSlotType as W}from"./library/ow.js";import f from"./radio.js";import lt from"./radio-group.styles.js";let h=class extends N{constructor(){super();o(this,V);o(this,S);o(this,$);o(this,x);o(this,C);o(this,D);o(this,U);o(this,l);o(this,u);o(this,w);o(this,q);o(this,L);o(this,M);this.description="";this.disabled=!1;this.label="";this.hideLabel=!1;this.name="";this.required=!1;this.value="";this.isCheckingValidity=!1;this.isReportValidityOrSubmit=!1;o(this,R,j());o(this,g,j());o(this,p,void 0);o(this,c,void 0);o(this,y,void 0);o(this,I,({formData:t})=>{this.name&&this.value.length>0&&!this.disabled&&t.append(this.name,this.value)});E(this,c,this.attachInternals()),this.addEventListener("invalid",a(this,C,Z))}checkValidity(){return this.isCheckingValidity=!0,s(this,c).checkValidity()}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",s(this,I)),E(this,p,void 0)}firstUpdated(){Q(s(this,g).value),W(s(this,g).value,[f]),E(this,p,s(this,l,r).find(t=>t.checked)),a(this,V,F).call(this)}focus(t){let e=s(this,l,r).find(i=>i.checked);e||(e=s(this,l,r).find(i=>i.tabIndex===0)),e?.focus(t)}get form(){return s(this,c).form}get validity(){return s(this,c).validity}get willValidate(){return s(this,c).willValidate}formAssociatedCallback(){this.form?.addEventListener("formdata",s(this,I))}formResetCallback(){if(s(this,p)&&this.contains(s(this,p)))for(const t of s(this,l,r))a(this,u,v).call(this,t===s(this,p),t)}render(){return it`<div class="component" @click="${a(this,$,X)}" @keydown="${a(this,D,_)}" ${J(s(this,R))}><glide-core-label orientation="horizontal" ?error="${s(this,S,B)}" ?hide="${this.hideLabel}" ?required="${this.required}"><label id="label" data-test="label">${this.label}</label><div class="${st({"radio-container":!0,vertical:!0,invalid:s(this,S,B)})}" role="radiogroup" slot="control" aria-labelledby="label description"><slot ${J(s(this,g))} @slotchange="${a(this,x,Y)}"></slot></div><slot name="tooltip" slot="tooltip"></slot><slot id="description" name="description" slot="description"></slot></glide-core-label></div>`}reportValidity(){return s(this,c).reportValidity()}updated(t){this.hasUpdated&&(t.has("value")||t.has("required"))&&(a(this,U,G).call(this),a(this,q,H).call(this,!s(this,c).validity.valid),this.requestUpdate())}willUpdate(t){if(this.hasUpdated){if(t.has("required")&&a(this,M,K).call(this),t.has("disabled")){for(const e of s(this,l,r))a(this,w,T).call(this,this.disabled,e);!this.disabled&&a(this,L,z).call(this)}if(t.has("value"))for(const e of s(this,l,r))e.checked=e.value===this.value}}};R=new WeakMap,g=new WeakMap,p=new WeakMap,c=new WeakMap,y=new WeakMap,I=new WeakMap,V=new WeakSet,F=function(){const t=s(this,l,r).find(e=>e.checked);this.value=t?.value??s(this,p)?.value??"",E(this,y,t??s(this,p)),this.required&&a(this,M,K).call(this);for(const e of s(this,l,r))this.disabled?a(this,w,T).call(this,this.disabled,e):a(this,w,T).call(this,e.disabled,e);!this.disabled&&a(this,L,z).call(this)},S=new WeakSet,B=function(){const t=!this.disabled&&!this.validity.valid&&this.isReportValidityOrSubmit;return a(this,q,H).call(this,t),t},$=new WeakSet,X=function(t){if(this.disabled)return;if(t.target instanceof f&&t.target.disabled&&s(this,y)&&!s(this,y).disabled){s(this,y)?.focus();return}const e=t.target;if(e instanceof f&&e&&!e.disabled){a(this,u,v).call(this,!0,e);for(const i of s(this,l,r))i!==e&&a(this,u,v).call(this,!1,i)}},x=new WeakSet,Y=function(){Q(s(this,g).value),W(s(this,g).value,[f]),a(this,V,F).call(this)},C=new WeakSet,Z=function(t){t.preventDefault(),this.isCheckingValidity||(this.isReportValidityOrSubmit=!0,this.focus())},D=new WeakSet,_=function(t){if(!(this.disabled||t.target instanceof f&&t.target?.disabled)&&t.target instanceof f){const e=t.target;switch(t.key){case"ArrowUp":case"ArrowLeft":{t.preventDefault();let i=e.previousElementSibling;for(;(!i||i instanceof f&&i.disabled||!(i instanceof f))&&i!==e;)if(i===null){const b=s(this,l,r).at(-1);b&&(i=b)}else i=i.previousElementSibling;i&&i instanceof f&&!i.disabled&&i!==e&&(a(this,u,v).call(this,!1,e),a(this,u,v).call(this,!0,i));break}case"ArrowDown":case"ArrowRight":{t.preventDefault();let i=e.nextElementSibling;for(;(!i||i instanceof f&&i.disabled||!(i instanceof f))&&i!==e;)if(i===null){const b=s(this,l,r).at(0);b&&(i=b)}else i=i.nextElementSibling;i&&i instanceof f&&!i.disabled&&i!==e&&(a(this,u,v).call(this,!1,e),a(this,u,v).call(this,!0,i));break}case" ":{if(t.preventDefault(),!e.disabled&&!e.checked){a(this,u,v).call(this,!0,e);for(const i of s(this,l,r))i!==e&&a(this,u,v).call(this,!1,i)}break}}}},U=new WeakSet,G=function(){const t=s(this,l,r).find(e=>e.checked);this.required&&!t?s(this,c).setValidity({valueMissing:!0}," ",s(this,R).value):s(this,c).setValidity({})},l=new WeakSet,r=function(){return s(this,g).value?.assignedElements().filter(t=>t instanceof f)??[]},u=new WeakSet,v=function(t,e){e.checked=t,e.tabIndex=t?0:-1,t&&(E(this,y,e),this.value=e.value,e.focus(),e.dispatchEvent(new Event("change",{bubbles:!0})),e.dispatchEvent(new Event("input",{bubbles:!0})))},w=new WeakSet,T=function(t,e){e.disabled=t,t&&(e.tabIndex=-1)},q=new WeakSet,H=function(t){for(const e of s(this,l,r))e.invalid=t},L=new WeakSet,z=function(){if(this.disabled||s(this,l,r).every(i=>i.disabled))return;let t=null;const e=s(this,l,r).find(i=>!i.disabled&&i.checked);if(e)t=e;else{const i=s(this,l,r).find(b=>!b.disabled);i&&(t=i)}if(t)for(const i of s(this,l,r))i.tabIndex=i===t?0:-1},M=new WeakSet,K=function(){for(const t of s(this,l,r))t.required=this.required},h.formAssociated=!0,h.shadowRootOptions={...N.shadowRootOptions,mode:"closed"},h.styles=lt,m([k()],h.prototype,"description",2),m([k({type:Boolean,reflect:!0})],h.prototype,"disabled",2),m([k()],h.prototype,"label",2),m([k({attribute:"hide-label",type:Boolean})],h.prototype,"hideLabel",2),m([k()],h.prototype,"name",2),m([k({type:Boolean,reflect:!0})],h.prototype,"required",2),m([k({reflect:!0})],h.prototype,"value",2),m([P()],h.prototype,"isCheckingValidity",2),m([P()],h.prototype,"isReportValidityOrSubmit",2),h=m([at("glide-core-radio-group")],h);export{h as default};
1
+ var __decorate=this&&this.__decorate||function(e,i,t,o){var s,a=arguments.length,d=a<3?i:null===o?o=Object.getOwnPropertyDescriptor(i,t):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)d=Reflect.decorate(e,i,t,o);else for(var l=e.length-1;l>=0;l--)(s=e[l])&&(d=(a<3?s(d):a>3?s(i,t,d):s(i,t))||d);return a>3&&d&&Object.defineProperty(i,t,d),d};import"./label.js";import"./tooltip.js";import{LitElement,html}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{owSlot,owSlotType}from"./library/ow.js";import GlideCoreRadio from"./radio.js";import styles from"./radio-group.styles.js";let GlideCoreRadioGroup=class GlideCoreRadioGroup extends LitElement{static{this.formAssociated=!0}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}checkValidity(){return this.isCheckingValidity=!0,this.#e.checkValidity()}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",this.#i),this.#t=void 0}firstUpdated(){owSlot(this.#o.value),owSlotType(this.#o.value,[GlideCoreRadio]),this.#t=this.#s.find((e=>e.checked)),this.#a()}focus(e){let i=this.#s.find((e=>e.checked));i||(i=this.#s.find((e=>0===e.tabIndex))),i?.focus(e)}get form(){return this.#e.form}get validity(){return this.#e.validity}get willValidate(){return this.#e.willValidate}formAssociatedCallback(){this.form?.addEventListener("formdata",this.#i)}formResetCallback(){if(this.#t&&this.contains(this.#t))for(const e of this.#s)this.#d(e===this.#t,e)}render(){return html`<div class="component" @click="${this.#l}" @keydown="${this.#r}" ${ref(this.#n)}><glide-core-label orientation="horizontal" ?disabled="${this.disabled}" ?error="${this.#h}" ?hide="${this.hideLabel}" ?required="${this.required}"><label id="label" data-test="label">${this.label}</label><div class="${classMap({"radio-container":!0,vertical:!0,invalid:this.#h})}" role="radiogroup" slot="control" aria-labelledby="label description"><slot ${ref(this.#o)} @slotchange="${this.#c}"></slot></div><slot name="tooltip" slot="tooltip"></slot><slot id="description" name="description" slot="description"></slot></glide-core-label></div>`}reportValidity(){return this.#e.reportValidity()}updated(e){this.hasUpdated&&(e.has("value")||e.has("required"))&&(this.#p(),this.#f(!this.#e.validity.valid),this.requestUpdate())}willUpdate(e){if(this.hasUpdated){if(e.has("required")&&this.#u(),e.has("disabled")){for(const e of this.#s)this.#R(this.disabled,e);!this.disabled&&this.#m()}if(e.has("value"))for(const e of this.#s)e.checked=e.value===this.value}}constructor(){super(),this.description="",this.disabled=!1,this.label="",this.hideLabel=!1,this.name="",this.required=!1,this.value="",this.isCheckingValidity=!1,this.isReportValidityOrSubmit=!1,this.#n=createRef(),this.#o=createRef(),this.#t=void 0,this.#i=({formData:e})=>{this.name&&this.value.length>0&&!this.disabled&&e.append(this.name,this.value)},this.#e=this.attachInternals(),this.addEventListener("invalid",this.#b)}#n;#o;#t;#e;#v;#i;#a(){const e=this.#s.find((e=>e.checked));this.value=e?.value??this.#t?.value??"",this.#v=e??this.#t,this.required&&this.#u();for(const e of this.#s)this.disabled?this.#R(this.disabled,e):this.#R(e.disabled,e);!this.disabled&&this.#m()}get#h(){const e=!this.disabled&&!this.validity.valid&&this.isReportValidityOrSubmit;return this.#f(e),e}#l(e){if(this.disabled)return;if(e.target instanceof GlideCoreRadio&&e.target.disabled&&this.#v&&!this.#v.disabled)return void this.#v?.focus();const i=e.target;if(i instanceof GlideCoreRadio&&i&&!i.disabled){this.#d(!0,i);for(const e of this.#s)e!==i&&this.#d(!1,e)}}#c(){owSlot(this.#o.value),owSlotType(this.#o.value,[GlideCoreRadio]),this.#a()}#b(e){e.preventDefault(),this.isCheckingValidity||(this.isReportValidityOrSubmit=!0,this.focus())}#r(e){if(!(this.disabled||e.target instanceof GlideCoreRadio&&e.target?.disabled)&&e.target instanceof GlideCoreRadio){const i=e.target;switch(e.key){case"ArrowUp":case"ArrowLeft":{e.preventDefault();let t=i.previousElementSibling;for(;(!t||t instanceof GlideCoreRadio&&t.disabled||!(t instanceof GlideCoreRadio))&&t!==i;)if(null===t){const e=this.#s.at(-1);e&&(t=e)}else t=t.previousElementSibling;t&&t instanceof GlideCoreRadio&&!t.disabled&&t!==i&&(this.#d(!1,i),this.#d(!0,t));break}case"ArrowDown":case"ArrowRight":{e.preventDefault();let t=i.nextElementSibling;for(;(!t||t instanceof GlideCoreRadio&&t.disabled||!(t instanceof GlideCoreRadio))&&t!==i;)if(null===t){const e=this.#s.at(0);e&&(t=e)}else t=t.nextElementSibling;t&&t instanceof GlideCoreRadio&&!t.disabled&&t!==i&&(this.#d(!1,i),this.#d(!0,t));break}case" ":if(e.preventDefault(),!i.disabled&&!i.checked){this.#d(!0,i);for(const e of this.#s)e!==i&&this.#d(!1,e)}}}}#p(){const e=this.#s.find((e=>e.checked));this.required&&!e?this.#e.setValidity({valueMissing:!0}," ",this.#n.value):this.#e.setValidity({})}get#s(){return this.#o.value?.assignedElements().filter((e=>e instanceof GlideCoreRadio))??[]}#d(e,i){i.checked=e,i.tabIndex=e?0:-1,e&&(this.#v=i,this.value=i.value,i.focus(),i.dispatchEvent(new Event("change",{bubbles:!0})),i.dispatchEvent(new Event("input",{bubbles:!0})))}#R(e,i){i.disabled=e,e&&(i.tabIndex=-1)}#f(e){for(const i of this.#s)i.invalid=e}#m(){if(this.disabled||this.#s.every((e=>e.disabled)))return;let e=null;const i=this.#s.find((e=>!e.disabled&&e.checked));if(i)e=i;else{const i=this.#s.find((e=>!e.disabled));i&&(e=i)}if(e)for(const i of this.#s)i.tabIndex=i===e?0:-1}#u(){for(const e of this.#s)e.required=this.required}};__decorate([property()],GlideCoreRadioGroup.prototype,"description",void 0),__decorate([property({type:Boolean,reflect:!0})],GlideCoreRadioGroup.prototype,"disabled",void 0),__decorate([property()],GlideCoreRadioGroup.prototype,"label",void 0),__decorate([property({attribute:"hide-label",type:Boolean})],GlideCoreRadioGroup.prototype,"hideLabel",void 0),__decorate([property()],GlideCoreRadioGroup.prototype,"name",void 0),__decorate([property({type:Boolean,reflect:!0})],GlideCoreRadioGroup.prototype,"required",void 0),__decorate([property({reflect:!0})],GlideCoreRadioGroup.prototype,"value",void 0),__decorate([state()],GlideCoreRadioGroup.prototype,"isCheckingValidity",void 0),__decorate([state()],GlideCoreRadioGroup.prototype,"isReportValidityOrSubmit",void 0),GlideCoreRadioGroup=__decorate([customElement("glide-core-radio-group")],GlideCoreRadioGroup);export default GlideCoreRadioGroup;
@@ -1,4 +1,4 @@
1
- "use strict";import{css as e}from"lit";export default[e`
1
+ import{css}from"lit";export default[css`
2
2
  .component {
3
3
  color: var(--glide-core-text-body-1);
4
4
  display: inline-flex;
@@ -8,33 +8,29 @@
8
8
  font-variant: var(--glide-core-heading-xxxs-font-variant);
9
9
  font-weight: var(--glide-core-heading-xxxs-font-weight);
10
10
  line-height: 1;
11
+ }
11
12
 
12
- & .vertical {
13
- appearance: none;
14
- border: none;
15
- display: flex;
16
- flex-direction: column;
17
- margin: 0;
18
- padding: 0;
13
+ .radio-container {
14
+ display: flex;
15
+ gap: 0.375rem;
16
+ inline-size: min-content;
17
+
18
+ &.invalid {
19
+ border: 1px solid var(--glide-core-status-error);
20
+ border-radius: 0.5rem;
21
+ color: var(--glide-core-status-error);
22
+ margin-block-end: -0.0625rem;
23
+ margin-inline-start: -0.0625rem;
24
+ padding: var(--glide-core-spacing-xxs) 0.375rem;
19
25
  }
20
26
 
21
- & .radio-container {
27
+ &.vertical {
22
28
  display: flex;
23
- gap: var(--glide-core-spacing-xs);
24
- inline-size: min-content;
25
-
26
- &.invalid {
27
- border: 1px solid var(--glide-core-status-error);
28
- border-radius: 0.5rem;
29
- color: var(--glide-core-status-error);
30
- margin-block-end: -0.0625rem;
31
- margin-inline-start: -0.0625rem;
32
- padding: var(--glide-core-spacing-xxs) 0.375rem;
33
- }
29
+ flex-direction: column;
34
30
  }
31
+ }
35
32
 
36
- glide-core-label::part(tooltip-and-label-container) {
37
- align-items: flex-start;
38
- }
33
+ glide-core-label::part(tooltip-and-label-container) {
34
+ align-items: flex-start;
39
35
  }
40
- `];
36
+ `];
@@ -0,0 +1,323 @@
1
+ import './radio-group.js';
2
+ import './radio.js';
3
+ import { elementUpdated, expect, fixture, html } from '@open-wc/testing';
4
+ import GlideCoreRadio from './radio.js';
5
+ import GlideCoreRadioGroup from './radio-group.js';
6
+ import expectArgumentError from './library/expect-argument-error.js';
7
+ GlideCoreRadio.shadowRootOptions.mode = 'open';
8
+ GlideCoreRadioGroup.shadowRootOptions.mode = 'open';
9
+ it('registers', async () => {
10
+ expect(window.customElements.get('glide-core-radio-group')).to.equal(GlideCoreRadioGroup);
11
+ expect(window.customElements.get('glide-core-radio')).to.equal(GlideCoreRadio);
12
+ });
13
+ it('is accessible', async () => {
14
+ const element = await fixture(html `
15
+ <glide-core-radio-group label="label" name="name" value="value-1">
16
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
17
+ <glide-core-radio value="value-2" label="Two"></glide-core-radio>
18
+ <glide-core-radio value="value-3" label="Three"></glide-core-radio>
19
+ <span slot="tooltip">Tooltip</span>
20
+ <div slot="description">Description</div>
21
+ </glide-core-radio-group>
22
+ `);
23
+ await expect(element).to.be.accessible();
24
+ });
25
+ it('renders appropriate attributes on glide-core-radio', async () => {
26
+ await fixture(html `
27
+ <glide-core-radio-group label="label" name="name">
28
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
29
+ <glide-core-radio value="value-2" label="Two" checked></glide-core-radio>
30
+ </glide-core-radio-group>
31
+ `);
32
+ const radios = document.querySelectorAll('glide-core-radio');
33
+ expect(radios[0]).to.have.attribute('value', 'value-1');
34
+ expect(radios[0]).to.have.attribute('tabindex', '-1');
35
+ expect(radios[0]).to.not.have.attribute('checked');
36
+ expect(radios[0]).to.have.attribute('role', 'radio');
37
+ expect(radios[0]).to.have.attribute('aria-checked', 'false');
38
+ expect(radios[0]).to.have.attribute('aria-disabled', 'false');
39
+ expect(radios[0]).to.have.attribute('aria-invalid', 'false');
40
+ expect(radios[0]).to.have.attribute('aria-required', 'false');
41
+ expect(radios[1]).to.have.attribute('value', 'value-2');
42
+ expect(radios[1]).to.have.attribute('tabindex', '0');
43
+ expect(radios[1]).to.have.attribute('checked');
44
+ expect(radios[1]).to.have.attribute('role', 'radio');
45
+ expect(radios[1]).to.have.attribute('aria-checked', 'true');
46
+ expect(radios[1]).to.have.attribute('aria-disabled', 'false');
47
+ expect(radios[1]).to.have.attribute('aria-invalid', 'false');
48
+ expect(radios[1]).to.have.attribute('aria-required', 'false');
49
+ });
50
+ it('renders a label, radio group, description, and tooltip when given', async () => {
51
+ const group = await fixture(html `
52
+ <glide-core-radio-group label="label" name="name" value="value-1">
53
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
54
+ <span slot="tooltip" data-test="tooltip">Tooltip</span>
55
+ <div slot="description" data-test="description">Description</div>
56
+ </glide-core-radio-group>
57
+ `);
58
+ const label = group.shadowRoot?.querySelector('[data-test="label"]');
59
+ const radioGroup = group?.shadowRoot?.querySelector('[role="radiogroup"]');
60
+ const tooltip = document.querySelector('[data-test="tooltip"]');
61
+ const description = document?.querySelector('[data-test="description"]');
62
+ expect(group).to.not.be.null;
63
+ expect(label).to.not.be.null;
64
+ expect(radioGroup).to.not.be.null;
65
+ expect(tooltip).to.not.be.null;
66
+ expect(description).to.not.be.null;
67
+ });
68
+ it('does not render a required symbol when a "label" is given and "required" is not set', async () => {
69
+ await fixture(html `
70
+ <glide-core-radio-group label="label" name="name" value="value-1">
71
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
72
+ </glide-core-radio-group>
73
+ `);
74
+ const group = document.querySelector('glide-core-radio-group');
75
+ const requiredSymbol = group?.shadowRoot?.querySelector('[data-test="label-required"]');
76
+ expect(requiredSymbol).to.be.null;
77
+ });
78
+ it('sets "required" attributes on radios when "required" is set on the group', async () => {
79
+ await fixture(html `
80
+ <glide-core-radio-group label="label" name="name" value="value-1" required>
81
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
82
+ <glide-core-radio value="value-2" label="Two"></glide-core-radio>
83
+ </glide-core-radio-group>
84
+ `);
85
+ const radios = document.querySelectorAll('glide-core-radio');
86
+ expect(radios[0]).to.have.attribute('required');
87
+ expect(radios[0]).to.have.attribute('aria-required', 'true');
88
+ expect(radios[1]).to.have.attribute('required');
89
+ expect(radios[1]).to.have.attribute('aria-required', 'true');
90
+ });
91
+ it('does not set "required" attributes on radios when "required" is not set on the group', async () => {
92
+ await fixture(html `
93
+ <glide-core-radio-group label="label" name="name" value="value-1">
94
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
95
+ <glide-core-radio value="value-2" label="Two"></glide-core-radio>
96
+ </glide-core-radio-group>
97
+ `);
98
+ const radios = document.querySelectorAll('glide-core-radio');
99
+ expect(radios[0]).to.not.have.attribute('required');
100
+ expect(radios[0]).to.have.attribute('aria-required', 'false');
101
+ expect(radios[1]).to.not.have.attribute('required');
102
+ expect(radios[1]).to.have.attribute('aria-required', 'false');
103
+ });
104
+ it('renders radios as "disabled" when "disabled" is set on the group', async () => {
105
+ await fixture(html `
106
+ <glide-core-radio-group label="label" name="name" value="value-1" disabled>
107
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
108
+ </glide-core-radio-group>
109
+ `);
110
+ const radio = document.querySelector('glide-core-radio');
111
+ expect(radio).to.have.attribute('disabled');
112
+ expect(radio).to.have.attribute('aria-disabled', 'true');
113
+ expect(radio?.shadowRoot?.querySelector('.disabled')).to.be.not.null;
114
+ });
115
+ it('does not render radios as "disabled" when "disabled" is not set on the group', async () => {
116
+ await fixture(html `
117
+ <glide-core-radio-group label="label" name="name" value="value-1">
118
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
119
+ </glide-core-radio-group>
120
+ `);
121
+ const radio = document.querySelector('glide-core-radio');
122
+ expect(radio).to.not.have.attribute('disabled');
123
+ expect(radio).to.have.attribute('aria-disabled', 'false');
124
+ expect(radio?.shadowRoot?.querySelector('.disabled')).to.be.null;
125
+ });
126
+ it('renders radios as "disabled" when "disabled" is dynamically set and removed on the group', async () => {
127
+ const component = await fixture(html `
128
+ <glide-core-radio-group label="label" name="name" value="value-1">
129
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
130
+ </glide-core-radio-group>
131
+ `);
132
+ const radio = document.querySelector('glide-core-radio');
133
+ expect(radio).to.not.have.attribute('disabled');
134
+ expect(radio).to.have.attribute('aria-disabled', 'false');
135
+ expect(radio?.shadowRoot?.querySelector('.disabled')).to.be.null;
136
+ component.disabled = true;
137
+ await elementUpdated(component);
138
+ expect(radio).to.have.attribute('disabled');
139
+ expect(radio).to.have.attribute('aria-disabled', 'true');
140
+ expect(radio?.shadowRoot?.querySelector('.disabled')).to.be.not.null;
141
+ component.disabled = false;
142
+ await elementUpdated(component);
143
+ expect(radio).to.not.have.attribute('disabled');
144
+ expect(radio).to.have.attribute('aria-disabled', 'false');
145
+ expect(radio?.shadowRoot?.querySelector('.disabled')).to.be.null;
146
+ });
147
+ it('sets the radio group to an empty value when no radio is "checked"', async () => {
148
+ const component = await fixture(html `
149
+ <glide-core-radio-group label="label" name="name">
150
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
151
+ <glide-core-radio value="value-2" label="Two"></glide-core-radio>
152
+ </glide-core-radio-group>
153
+ `);
154
+ const radios = document.querySelectorAll('glide-core-radio');
155
+ expect(component.value).to.equal('');
156
+ expect(radios.length).to.equal(2);
157
+ expect(radios[0]).to.not.have.attribute('checked');
158
+ expect(radios[0]).to.have.attribute('aria-checked', 'false');
159
+ expect(radios[1]).to.not.have.attribute('checked');
160
+ expect(radios[1]).to.have.attribute('aria-checked', 'false');
161
+ });
162
+ it('sets the group "value" when a radio is set as "checked"', async () => {
163
+ await fixture(html `
164
+ <glide-core-radio-group label="label" name="name">
165
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
166
+ <glide-core-radio value="value-2" checked label="Two"></glide-core-radio>
167
+ </glide-core-radio-group>
168
+ `);
169
+ const group = document.querySelector('glide-core-radio-group');
170
+ expect(group).to.have.attribute('value', 'value-2');
171
+ });
172
+ it('throws an error when an element other than `glide-core-radio` is a child of the default slot', async () => {
173
+ await expectArgumentError(() => {
174
+ return fixture(html `
175
+ <glide-core-radio-group label="label" name="name">
176
+ <div>Option 1</div>
177
+ <glide-core-radio value="value-2" label="Two"></glide-core-radio>
178
+ </glide-core-radio-group>
179
+ `);
180
+ });
181
+ });
182
+ it('throws an error when the group has no children', async () => {
183
+ await expectArgumentError(() => {
184
+ return fixture(html `<glide-core-radio-group label="label" name="name">
185
+ </glide-core-radio-group>`);
186
+ });
187
+ });
188
+ it('sets the first radio to be tabbable when none are checked', async () => {
189
+ await fixture(html `<glide-core-radio-group name="name">
190
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
191
+ <glide-core-radio value="value-2" label="Two"></glide-core-radio>
192
+ <glide-core-radio value="value-3" label="Three"></glide-core-radio>
193
+ </glide-core-radio-group>`);
194
+ const radios = document.querySelectorAll('glide-core-radio');
195
+ expect(radios.length).to.equal(3);
196
+ expect(radios[0]).to.have.attribute('tabindex', '0');
197
+ expect(radios[1]).to.have.attribute('tabindex', '-1');
198
+ expect(radios[2]).to.have.attribute('tabindex', '-1');
199
+ });
200
+ it('sets the first non-disabled radio as tabbable when none are checked', async () => {
201
+ await fixture(html `<glide-core-radio-group name="name">
202
+ <glide-core-radio value="value-1" disabled label="One"></glide-core-radio>
203
+ <glide-core-radio value="value-2" label="Two"></glide-core-radio>
204
+ <glide-core-radio value="value-3" label="Three"></glide-core-radio>
205
+ </glide-core-radio-group>`);
206
+ const radios = document.querySelectorAll('glide-core-radio');
207
+ expect(radios.length).to.equal(3);
208
+ expect(radios[0]).to.have.attribute('tabindex', '-1');
209
+ expect(radios[1]).to.have.attribute('tabindex', '0');
210
+ expect(radios[2]).to.have.attribute('tabindex', '-1');
211
+ });
212
+ it('no radios are tabbable when the group is "disabled"', async () => {
213
+ await fixture(html `<glide-core-radio-group name="name" disabled>
214
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
215
+ <glide-core-radio value="value-2" label="Two"></glide-core-radio>
216
+ <glide-core-radio
217
+ value="value-3"
218
+ checked
219
+ label="Three"
220
+ ></glide-core-radio>
221
+ </glide-core-radio-group>`);
222
+ const radios = document.querySelectorAll('glide-core-radio');
223
+ expect(radios.length).to.equal(3);
224
+ expect(radios[0]).to.have.attribute('tabindex', '-1');
225
+ expect(radios[1]).to.have.attribute('tabindex', '-1');
226
+ expect(radios[2]).to.have.attribute('tabindex', '-1');
227
+ });
228
+ it('disabled radios are not tabbable', async () => {
229
+ await fixture(html `<glide-core-radio-group name="name">
230
+ <glide-core-radio value="value-1" disabled label="One"></glide-core-radio>
231
+ <glide-core-radio value="value-2" disabled label="Two"></glide-core-radio>
232
+ </glide-core-radio-group>`);
233
+ const radios = document.querySelectorAll('glide-core-radio');
234
+ expect(radios.length).to.equal(2);
235
+ expect(radios[0]).to.have.attribute('tabindex', '-1');
236
+ expect(radios[1]).to.have.attribute('tabindex', '-1');
237
+ });
238
+ it('sets only the "checked" radio as tabbable', async () => {
239
+ await fixture(html `<glide-core-radio-group name="name">
240
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
241
+ <glide-core-radio value="value-2" label="Two"></glide-core-radio>
242
+ <glide-core-radio
243
+ value="value-3"
244
+ label="Three"
245
+ checked
246
+ ></glide-core-radio>
247
+ </glide-core-radio-group>`);
248
+ const radios = document.querySelectorAll('glide-core-radio');
249
+ expect(radios.length).to.equal(3);
250
+ expect(radios[0]).to.have.attribute('tabindex', '-1');
251
+ expect(radios[1]).to.have.attribute('tabindex', '-1');
252
+ expect(radios[2]).to.have.attribute('tabindex', '0');
253
+ });
254
+ it('has reactive radio attribute "aria-checked"', async () => {
255
+ await fixture(html `<glide-core-radio-group name="name">
256
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
257
+ </glide-core-radio-group>`);
258
+ const radio = document.querySelector('glide-core-radio');
259
+ expect(radio).to.not.be.null;
260
+ expect(radio).to.have.attribute('aria-checked', 'false');
261
+ radio?.setAttribute('checked', '');
262
+ await elementUpdated(radio);
263
+ expect(radio).to.have.attribute('aria-checked', 'true');
264
+ radio?.removeAttribute('checked');
265
+ await elementUpdated(radio);
266
+ expect(radio).to.have.attribute('aria-checked', 'false');
267
+ });
268
+ it('has reactive radio attribute "aria-disabled"', async () => {
269
+ await fixture(html `<glide-core-radio-group name="name">
270
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
271
+ </glide-core-radio-group>`);
272
+ const radio = document.querySelector('glide-core-radio');
273
+ expect(radio).to.not.be.null;
274
+ expect(radio).to.have.attribute('aria-disabled', 'false');
275
+ radio?.setAttribute('disabled', '');
276
+ await elementUpdated(radio);
277
+ expect(radio).to.have.attribute('aria-disabled', 'true');
278
+ radio?.removeAttribute('disabled');
279
+ await elementUpdated(radio);
280
+ expect(radio).to.have.attribute('aria-disabled', 'false');
281
+ });
282
+ it('has reactive radio attribute "aria-required"', async () => {
283
+ await fixture(html `<glide-core-radio-group name="name">
284
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
285
+ </glide-core-radio-group>`);
286
+ const radio = document.querySelector('glide-core-radio');
287
+ expect(radio).to.not.be.null;
288
+ expect(radio).to.have.attribute('aria-required', 'false');
289
+ radio?.setAttribute('required', '');
290
+ await elementUpdated(radio);
291
+ expect(radio).to.have.attribute('aria-required', 'true');
292
+ radio?.removeAttribute('required');
293
+ await elementUpdated(radio);
294
+ expect(radio).to.have.attribute('aria-required', 'false');
295
+ });
296
+ it('has reactive radio attribute "aria-invalid"', async () => {
297
+ await fixture(html `<glide-core-radio-group name="name">
298
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
299
+ </glide-core-radio-group>`);
300
+ const radio = document.querySelector('glide-core-radio');
301
+ expect(radio).to.not.be.null;
302
+ expect(radio).to.have.attribute('aria-invalid', 'false');
303
+ radio?.setAttribute('invalid', '');
304
+ await elementUpdated(radio);
305
+ expect(radio).to.have.attribute('aria-invalid', 'true');
306
+ radio?.removeAttribute('invalid');
307
+ await elementUpdated(radio);
308
+ expect(radio).to.have.attribute('aria-invalid', 'false');
309
+ });
310
+ it('adds a label to radio when given', async () => {
311
+ const component = await fixture(html `<glide-core-radio value="value-1" label="One"></glide-core-radio>`);
312
+ const label = component.shadowRoot.querySelector('.component')?.textContent;
313
+ expect(label).to.contain('One');
314
+ expect(component.ariaLabel).to.equal('One');
315
+ });
316
+ it('changes the radio label dynamically as when given', async () => {
317
+ const component = await fixture(html `<glide-core-radio value="value-1" label="One"></glide-core-radio>`);
318
+ component.label = 'Two';
319
+ await elementUpdated(component);
320
+ const label = component.shadowRoot.querySelector('.component')?.textContent;
321
+ expect(label).to.contain('Two');
322
+ expect(component.ariaLabel).to.equal('Two');
323
+ });