@lion/ui 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. package/components/core/test/SlotMixin.test.js +28 -21
  2. package/components/drawer/src/LionDrawer.js +217 -0
  3. package/components/drawer/src/drawerStyle.js +59 -0
  4. package/components/drawer/test/lion-drawer.test.js +109 -0
  5. package/components/localize/src/number/parseNumber.js +15 -36
  6. package/components/localize/test/number/parseNumber.test.js +3 -12
  7. package/custom-elements.json +743 -0
  8. package/dist-types/components/drawer/src/LionDrawer.d.ts +67 -0
  9. package/dist-types/components/drawer/src/LionDrawer.d.ts.map +1 -0
  10. package/dist-types/components/drawer/src/drawerStyle.d.ts +2 -0
  11. package/dist-types/components/drawer/src/drawerStyle.d.ts.map +1 -0
  12. package/dist-types/components/drawer/test/lion-drawer.test.d.ts +3 -0
  13. package/dist-types/components/drawer/test/lion-drawer.test.d.ts.map +1 -0
  14. package/dist-types/components/localize/src/number/parseNumber.d.ts.map +1 -1
  15. package/dist-types/exports/define/lion-drawer.d.ts +2 -0
  16. package/dist-types/exports/define/lion-drawer.d.ts.map +1 -0
  17. package/dist-types/exports/drawer.d.ts +2 -0
  18. package/dist-types/exports/drawer.d.ts.map +1 -0
  19. package/dist-types/tsconfig.tsbuildinfo +1 -1
  20. package/docs/components/accordion/index.md +3 -0
  21. package/docs/components/accordion/overview.md +129 -0
  22. package/docs/components/accordion/reference.md +47 -0
  23. package/docs/components/accordion/use-cases.md +252 -0
  24. package/docs/components/button/examples.md +30 -0
  25. package/docs/components/button/index.md +3 -0
  26. package/docs/components/button/overview.md +30 -0
  27. package/docs/components/button/src/icon.svg.js +5 -0
  28. package/docs/components/button/use-cases.md +106 -0
  29. package/docs/components/calendar/index.md +3 -0
  30. package/docs/components/calendar/overview.md +49 -0
  31. package/docs/components/calendar/use-cases.md +192 -0
  32. package/docs/components/checkbox-group/index.md +3 -0
  33. package/docs/components/checkbox-group/overview.md +40 -0
  34. package/docs/components/checkbox-group/use-cases.md +256 -0
  35. package/docs/components/collapsible/assets/CustomCollapsible.js +113 -0
  36. package/docs/components/collapsible/assets/applyDemoCollapsibleStyles.js +37 -0
  37. package/docs/components/collapsible/examples.md +83 -0
  38. package/docs/components/collapsible/index.md +3 -0
  39. package/docs/components/collapsible/overview.md +39 -0
  40. package/docs/components/collapsible/use-cases.md +79 -0
  41. package/docs/components/combobox/examples.md +153 -0
  42. package/docs/components/combobox/index.md +3 -0
  43. package/docs/components/combobox/overview.md +51 -0
  44. package/docs/components/combobox/src/LinkMixin.js +60 -0
  45. package/docs/components/combobox/src/demo-selection-display.js +191 -0
  46. package/docs/components/combobox/src/gh-combobox/gh-button.js +69 -0
  47. package/docs/components/combobox/src/gh-combobox/gh-combobox.js +508 -0
  48. package/docs/components/combobox/src/google-combobox/assets/google-clear-icon.js +9 -0
  49. package/docs/components/combobox/src/google-combobox/assets/google-search-icon.js +9 -0
  50. package/docs/components/combobox/src/google-combobox/assets/google-voice-search-icon.js +19 -0
  51. package/docs/components/combobox/src/google-combobox/assets/googlelogo_color_272x92dp.png +0 -0
  52. package/docs/components/combobox/src/google-combobox/google-combobox.js +460 -0
  53. package/docs/components/combobox/src/lazyRender.js +29 -0
  54. package/docs/components/combobox/src/levenshtein.js +95 -0
  55. package/docs/components/combobox/src/md-combobox/MdFieldMixin.js +341 -0
  56. package/docs/components/combobox/src/md-combobox/md-combobox.js +89 -0
  57. package/docs/components/combobox/src/md-combobox/md-input.js +5 -0
  58. package/docs/components/combobox/src/md-combobox/style/load-roboto.js +6 -0
  59. package/docs/components/combobox/src/md-combobox/style/md-ripple.js +81 -0
  60. package/docs/components/combobox/src/wa-combobox/wa-combobox.js +368 -0
  61. package/docs/components/combobox/use-cases.md +377 -0
  62. package/docs/components/dialog/index.md +3 -0
  63. package/docs/components/dialog/overview.md +63 -0
  64. package/docs/components/dialog/src/demo-dialog-style.js +3 -0
  65. package/docs/components/dialog/src/demoStyle.js +39 -0
  66. package/docs/components/dialog/src/slots-dialog-content.js +32 -0
  67. package/docs/components/dialog/src/styled-dialog-content.js +38 -0
  68. package/docs/components/dialog/use-cases.md +154 -0
  69. package/docs/components/drawer/index.md +3 -0
  70. package/docs/components/drawer/overview.md +68 -0
  71. package/docs/components/drawer/src/demoStyle.js +71 -0
  72. package/docs/components/drawer/use-cases.md +194 -0
  73. package/docs/components/fieldset/index.md +3 -0
  74. package/docs/components/fieldset/overview.md +49 -0
  75. package/docs/components/fieldset/use-cases.md +185 -0
  76. package/docs/components/form/index.md +3 -0
  77. package/docs/components/form/overview.md +43 -0
  78. package/docs/components/form/use-cases.md +72 -0
  79. package/docs/components/icon/assets/bugs/bug01.svg.js +2 -0
  80. package/docs/components/icon/assets/bugs/bug02.svg.js +2 -0
  81. package/docs/components/icon/assets/bugs/bug05.svg.js +2 -0
  82. package/docs/components/icon/assets/bugs/bug06.svg.js +2 -0
  83. package/docs/components/icon/assets/bugs/bug08.svg.js +2 -0
  84. package/docs/components/icon/assets/bugs/bug12.svg.js +2 -0
  85. package/docs/components/icon/assets/bugs/bug19.svg.js +2 -0
  86. package/docs/components/icon/assets/bugs/bug23.svg.js +2 -0
  87. package/docs/components/icon/assets/bugs/bug24.svg.js +2 -0
  88. package/docs/components/icon/assets/iconset-bugs.js +11 -0
  89. package/docs/components/icon/assets/iconset-misc.js +3 -0
  90. package/docs/components/icon/assets/iconset-space.js +31 -0
  91. package/docs/components/icon/assets/misc/arrowLeft.svg.js +6 -0
  92. package/docs/components/icon/assets/space/aliens-spaceship.svg.js +2 -0
  93. package/docs/components/icon/assets/space/meteor.svg.js +2 -0
  94. package/docs/components/icon/assets/space/moon-flag.svg.js +2 -0
  95. package/docs/components/icon/assets/space/moon.svg.js +2 -0
  96. package/docs/components/icon/assets/space/night.svg.js +2 -0
  97. package/docs/components/icon/assets/space/orbit.svg.js +2 -0
  98. package/docs/components/icon/assets/space/planet.svg.js +2 -0
  99. package/docs/components/icon/assets/space/robot.svg.js +2 -0
  100. package/docs/components/icon/assets/space/rocket.svg.js +2 -0
  101. package/docs/components/icon/assets/space/satellite.svg.js +2 -0
  102. package/docs/components/icon/assets/space/signal.svg.js +2 -0
  103. package/docs/components/icon/assets/space/space-helmet.svg.js +2 -0
  104. package/docs/components/icon/assets/space/sun.svg.js +2 -0
  105. package/docs/components/icon/assets/space/telescope.svg.js +2 -0
  106. package/docs/components/icon/index.md +3 -0
  107. package/docs/components/icon/overview.md +40 -0
  108. package/docs/components/icon/use-cases.md +93 -0
  109. package/docs/components/index.md +7 -0
  110. package/docs/components/input/index.md +3 -0
  111. package/docs/components/input/overview.md +36 -0
  112. package/docs/components/input/use-cases.md +77 -0
  113. package/docs/components/input-amount/index.md +3 -0
  114. package/docs/components/input-amount/overview.md +49 -0
  115. package/docs/components/input-amount/use-cases.md +122 -0
  116. package/docs/components/input-date/index.md +3 -0
  117. package/docs/components/input-date/overview.md +39 -0
  118. package/docs/components/input-date/use-cases.md +83 -0
  119. package/docs/components/input-datepicker/index.md +3 -0
  120. package/docs/components/input-datepicker/overview.md +42 -0
  121. package/docs/components/input-datepicker/use-cases.md +78 -0
  122. package/docs/components/input-email/index.md +3 -0
  123. package/docs/components/input-email/overview.md +32 -0
  124. package/docs/components/input-email/use-cases.md +48 -0
  125. package/docs/components/input-iban/index.md +3 -0
  126. package/docs/components/input-iban/overview.md +37 -0
  127. package/docs/components/input-iban/use-cases.md +102 -0
  128. package/docs/components/input-range/index.md +3 -0
  129. package/docs/components/input-range/overview.md +34 -0
  130. package/docs/components/input-range/use-cases.md +108 -0
  131. package/docs/components/input-stepper/index.md +3 -0
  132. package/docs/components/input-stepper/overview.md +36 -0
  133. package/docs/components/input-stepper/use-cases.md +41 -0
  134. package/docs/components/input-tel/index.md +3 -0
  135. package/docs/components/input-tel/overview.md +62 -0
  136. package/docs/components/input-tel/src/h-region-code-table.js +109 -0
  137. package/docs/components/input-tel/use-cases.md +307 -0
  138. package/docs/components/input-tel-dropdown/examples.md +32 -0
  139. package/docs/components/input-tel-dropdown/index.md +3 -0
  140. package/docs/components/input-tel-dropdown/overview.md +38 -0
  141. package/docs/components/input-tel-dropdown/src/intl-input-tel-dropdown.js +127 -0
  142. package/docs/components/input-tel-dropdown/use-cases.md +159 -0
  143. package/docs/components/listbox/index.md +3 -0
  144. package/docs/components/listbox/overview.md +42 -0
  145. package/docs/components/listbox/src/listboxData.js +65 -0
  146. package/docs/components/listbox/use-cases.md +147 -0
  147. package/docs/components/pagination/index.md +3 -0
  148. package/docs/components/pagination/overview.md +29 -0
  149. package/docs/components/pagination/use-cases.md +99 -0
  150. package/docs/components/progress-indicator/assets/my-determinate-progress-bar.js +30 -0
  151. package/docs/components/progress-indicator/assets/my-indeterminate-progress-spinner.js +55 -0
  152. package/docs/components/progress-indicator/examples.md +125 -0
  153. package/docs/components/progress-indicator/index.md +3 -0
  154. package/docs/components/progress-indicator/overview.md +36 -0
  155. package/docs/components/radio-group/index.md +3 -0
  156. package/docs/components/radio-group/overview.md +46 -0
  157. package/docs/components/radio-group/use-cases.md +140 -0
  158. package/docs/components/select/index.md +3 -0
  159. package/docs/components/select/overview.md +44 -0
  160. package/docs/components/select/use-cases.md +55 -0
  161. package/docs/components/select-rich/examples.md +31 -0
  162. package/docs/components/select-rich/index.md +3 -0
  163. package/docs/components/select-rich/overview.md +46 -0
  164. package/docs/components/select-rich/src/flagStyles.js +1250 -0
  165. package/docs/components/select-rich/src/flags.png +0 -0
  166. package/docs/components/select-rich/src/flags@2x.png +0 -0
  167. package/docs/components/select-rich/src/intl-select-rich.js +194 -0
  168. package/docs/components/select-rich/src/regionMetaList.js +1717 -0
  169. package/docs/components/select-rich/use-cases.md +370 -0
  170. package/docs/components/steps/index.md +3 -0
  171. package/docs/components/steps/overview.md +63 -0
  172. package/docs/components/steps/use-cases.md +163 -0
  173. package/docs/components/switch/index.md +3 -0
  174. package/docs/components/switch/overview.md +75 -0
  175. package/docs/components/switch/reference.md +39 -0
  176. package/docs/components/switch/use-cases.md +76 -0
  177. package/docs/components/tabs/examples.md +23 -0
  178. package/docs/components/tabs/index.md +3 -0
  179. package/docs/components/tabs/overview.md +48 -0
  180. package/docs/components/tabs/src/lea-tab-panel.js +24 -0
  181. package/docs/components/tabs/src/lea-tab.js +45 -0
  182. package/docs/components/tabs/src/lea-tabs.js +28 -0
  183. package/docs/components/tabs/use-cases.md +219 -0
  184. package/docs/components/textarea/index.md +3 -0
  185. package/docs/components/textarea/overview.md +35 -0
  186. package/docs/components/textarea/use-cases.md +95 -0
  187. package/docs/components/tooltip/examples.md +39 -0
  188. package/docs/components/tooltip/index.md +3 -0
  189. package/docs/components/tooltip/overview.md +44 -0
  190. package/docs/components/tooltip/use-cases.md +208 -0
  191. package/docs/fundamentals/index.md +19 -0
  192. package/docs/fundamentals/node-tools/babel-plugin-extend-docs/index.md +1 -0
  193. package/docs/fundamentals/node-tools/babel-plugin-extend-docs/overview.md +233 -0
  194. package/docs/fundamentals/node-tools/index.md +1 -0
  195. package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +68 -0
  196. package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +111 -0
  197. package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +69 -0
  198. package/docs/fundamentals/node-tools/providence-analytics/assets/_mermaid.svg.js +1202 -0
  199. package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +22 -0
  200. package/docs/fundamentals/node-tools/providence-analytics/index.md +1 -0
  201. package/docs/fundamentals/node-tools/providence-analytics/overview.md +192 -0
  202. package/docs/fundamentals/node-tools/publish-docs/index.md +1 -0
  203. package/docs/fundamentals/node-tools/publish-docs/overview.md +136 -0
  204. package/docs/fundamentals/node-tools/remark-extend/index.md +1 -0
  205. package/docs/fundamentals/node-tools/remark-extend/overview.md +274 -0
  206. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/index.md +1 -0
  207. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +285 -0
  208. package/docs/fundamentals/rationales/TypeScript.md +18 -0
  209. package/docs/fundamentals/rationales/index.md +1 -0
  210. package/docs/fundamentals/rationales/side-effects.md +203 -0
  211. package/docs/fundamentals/rationales/versioning.md +35 -0
  212. package/docs/fundamentals/systems/core/index.md +3 -0
  213. package/docs/fundamentals/systems/core/overview.md +85 -0
  214. package/docs/fundamentals/systems/form/assets/FormatMixinDiagram-1.svg +1 -0
  215. package/docs/fundamentals/systems/form/assets/FormatMixinDiagram-2.svg +1 -0
  216. package/docs/fundamentals/systems/form/assets/FormatMixinDiagram-3.svg +84 -0
  217. package/docs/fundamentals/systems/form/assets/h-output.js +155 -0
  218. package/docs/fundamentals/systems/form/formatting-and-parsing.md +245 -0
  219. package/docs/fundamentals/systems/form/index.md +3 -0
  220. package/docs/fundamentals/systems/form/interaction-states.md +177 -0
  221. package/docs/fundamentals/systems/form/model-value.md +35 -0
  222. package/docs/fundamentals/systems/form/overview.md +82 -0
  223. package/docs/fundamentals/systems/form/styling.md +101 -0
  224. package/docs/fundamentals/systems/form/use-cases.md +156 -0
  225. package/docs/fundamentals/systems/form/validate.md +929 -0
  226. package/docs/fundamentals/systems/icon/index.md +3 -0
  227. package/docs/fundamentals/systems/icon/overview.md +124 -0
  228. package/docs/fundamentals/systems/index.md +1 -0
  229. package/docs/fundamentals/systems/localize/assets/all-locales.js +437 -0
  230. package/docs/fundamentals/systems/localize/assets/en-AU.js +6 -0
  231. package/docs/fundamentals/systems/localize/assets/en-GB.js +6 -0
  232. package/docs/fundamentals/systems/localize/assets/en-US.js +6 -0
  233. package/docs/fundamentals/systems/localize/assets/en.js +4 -0
  234. package/docs/fundamentals/systems/localize/assets/nl-BE.js +6 -0
  235. package/docs/fundamentals/systems/localize/assets/nl-NL.js +6 -0
  236. package/docs/fundamentals/systems/localize/assets/nl.js +4 -0
  237. package/docs/fundamentals/systems/localize/dates.md +195 -0
  238. package/docs/fundamentals/systems/localize/index.md +3 -0
  239. package/docs/fundamentals/systems/localize/numbers.md +217 -0
  240. package/docs/fundamentals/systems/localize/overview.md +48 -0
  241. package/docs/fundamentals/systems/localize/rationale.md +62 -0
  242. package/docs/fundamentals/systems/localize/text.md +125 -0
  243. package/docs/fundamentals/systems/localize/use-cases.md +319 -0
  244. package/docs/fundamentals/systems/overlays/assets/applyDemoOverlayStyles.js +22 -0
  245. package/docs/fundamentals/systems/overlays/assets/demo-overlay-backdrop.js +48 -0
  246. package/docs/fundamentals/systems/overlays/assets/demo-overlay-system.js +42 -0
  247. package/docs/fundamentals/systems/overlays/assets/umbrella-form.js +133 -0
  248. package/docs/fundamentals/systems/overlays/configuration.md +453 -0
  249. package/docs/fundamentals/systems/overlays/form-integration.md +65 -0
  250. package/docs/fundamentals/systems/overlays/index.md +3 -0
  251. package/docs/fundamentals/systems/overlays/overview.md +118 -0
  252. package/docs/fundamentals/systems/overlays/rationale.md +232 -0
  253. package/docs/fundamentals/systems/overlays/scope.md +176 -0
  254. package/docs/fundamentals/systems/overlays/use-cases.md +699 -0
  255. package/docs/fundamentals/tools/ajax/assets/naga.json +9 -0
  256. package/docs/fundamentals/tools/ajax/assets/pabu.json +9 -0
  257. package/docs/fundamentals/tools/ajax/index.md +3 -0
  258. package/docs/fundamentals/tools/ajax/overview.md +128 -0
  259. package/docs/fundamentals/tools/ajax/use-cases.md +456 -0
  260. package/docs/fundamentals/tools/helpers/action-logger.md +165 -0
  261. package/docs/fundamentals/tools/helpers/index.md +3 -0
  262. package/docs/fundamentals/tools/helpers/overview.md +30 -0
  263. package/docs/fundamentals/tools/index.md +1 -0
  264. package/docs/fundamentals/tools/singleton-manager/index.md +3 -0
  265. package/docs/fundamentals/tools/singleton-manager/overview.md +304 -0
  266. package/docs/guides/how-to/create-a-custom-field.md +200 -0
  267. package/docs/guides/how-to/extend-a-native-input.md +66 -0
  268. package/docs/guides/how-to/get-started.md +77 -0
  269. package/docs/guides/how-to/index.md +1 -0
  270. package/docs/guides/index.md +34 -0
  271. package/docs/guides/principles/definitions-and-terms.md +41 -0
  272. package/docs/guides/principles/index.md +26 -0
  273. package/docs/guides/principles/scoped-elements.md +103 -0
  274. package/docs/guides/principles/styling.md +32 -0
  275. package/docs/guides/principles/subclasser-apis.md +28 -0
  276. package/docs/override.js +15 -0
  277. package/exports/define/lion-drawer.js +3 -0
  278. package/exports/drawer.js +1 -0
  279. package/package.json +2 -2
@@ -1,14 +1,21 @@
1
1
  import sinon from 'sinon';
2
- import { defineCE, expect, fixture } from '@open-wc/testing';
2
+ import { defineCE, expect, fixture, unsafeStatic, html } from '@open-wc/testing';
3
3
  import { ScopedElementsMixin } from '@open-wc/scoped-elements';
4
4
  import { SlotMixin } from '@lion/ui/core.js';
5
- import { LitElement, html } from 'lit';
5
+ import { LitElement } from 'lit';
6
6
 
7
+ const mockedRenderTarget = document.createElement('div');
7
8
  function mockScopedRegistry() {
9
+ const outputObj = { createElementCallCount: 0 };
8
10
  // @ts-expect-error wait for browser support
9
- ShadowRoot.prototype.createElement = () => {};
11
+ ShadowRoot.prototype.createElement = () => {
12
+ outputObj.createElementCallCount += 1;
13
+ // Return an element that lit can use as render target
14
+ return mockedRenderTarget;
15
+ };
10
16
  // @ts-expect-error wait for browser support
11
17
  window.CustomElementRegistry = class {};
18
+ return outputObj;
12
19
  }
13
20
 
14
21
  function unMockScopedRegistry() {
@@ -211,13 +218,12 @@ describe('SlotMixin', () => {
211
218
  expect(slot.tagName).to.equal('SPAN');
212
219
  });
213
220
 
214
- // TODO: @Thijs is this still needed?
215
- it.skip('supports scoped elements when polyfill loaded', async () => {
216
- mockScopedRegistry();
221
+ it('supports scoped elements when polyfill loaded', async () => {
222
+ const outputObj = mockScopedRegistry();
217
223
 
218
224
  class ScopedEl extends LitElement {}
219
225
 
220
- const tag = defineCE(
226
+ const tagName = defineCE(
221
227
  class extends ScopedElementsMixin(SlotMixin(LitElement)) {
222
228
  static get scopedElements() {
223
229
  return {
@@ -240,16 +246,10 @@ describe('SlotMixin', () => {
240
246
  },
241
247
  );
242
248
 
243
- let error = '';
244
- try {
245
- // @ts-ignore
246
- await fixture(html`<${tag}></${tag}>`, { scopedElements: true });
247
- } catch (e) {
248
- // @ts-ignore
249
- error = e.toString();
250
- }
251
- // it throws when it uses our temp mock (error is browser specific, so we check overlapping part)
252
- expect(error).to.include('.importNode is not a function');
249
+ const tag = unsafeStatic(tagName);
250
+ await fixture(html`<${tag}></${tag}>`);
251
+
252
+ expect(outputObj.createElementCallCount).to.equal(1);
253
253
 
254
254
  unMockScopedRegistry();
255
255
  });
@@ -257,7 +257,7 @@ describe('SlotMixin', () => {
257
257
  it('does not scope elements when polyfill not loaded', async () => {
258
258
  class ScopedEl extends LitElement {}
259
259
 
260
- const tag = defineCE(
260
+ const tagName = defineCE(
261
261
  class extends ScopedElementsMixin(SlotMixin(LitElement)) {
262
262
  static get scopedElements() {
263
263
  return {
@@ -280,10 +280,17 @@ describe('SlotMixin', () => {
280
280
  },
281
281
  );
282
282
 
283
+ const renderTarget = document.createElement('div');
284
+ const el = document.createElement(tagName);
285
+
286
+ // We don't use fixture, so we limit the amount of calls to document.createElement
283
287
  const docSpy = sinon.spy(document, 'createElement');
284
- await fixture(html`<${tag}></${tag}>`);
285
- // one for the fixture, one for the scoped slot
286
- expect(docSpy).to.have.been.calledTwice;
288
+ document.body.appendChild(renderTarget);
289
+ renderTarget.appendChild(el);
290
+
291
+ expect(docSpy.callCount).to.equal(2);
292
+
293
+ document.body.removeChild(renderTarget);
287
294
  docSpy.restore();
288
295
  });
289
296
  });
@@ -0,0 +1,217 @@
1
+ import { html } from 'lit';
2
+ import { LionCollapsible } from '@lion/ui/collapsible.js';
3
+ import { drawerStyle } from './drawerStyle.js';
4
+
5
+ const EVENT = {
6
+ TRANSITION_END: 'transitionend',
7
+ TRANSITION_START: 'transitionstart',
8
+ };
9
+
10
+ export class LionDrawer extends LionCollapsible {
11
+ static get properties() {
12
+ return {
13
+ transitioning: {
14
+ type: Boolean,
15
+ reflect: true,
16
+ },
17
+ opened: {
18
+ type: Boolean,
19
+ reflect: true,
20
+ },
21
+ position: {
22
+ type: String,
23
+ reflect: true,
24
+ },
25
+ };
26
+ }
27
+
28
+ constructor() {
29
+ super();
30
+
31
+ /** @private */
32
+ this.__toggle = () => {
33
+ this.opened = !this.opened;
34
+ };
35
+ }
36
+
37
+ connectedCallback() {
38
+ super.connectedCallback();
39
+
40
+ if (!this.hasAttribute('position')) {
41
+ this.position = 'left';
42
+ }
43
+
44
+ if (this._contentNode) {
45
+ this._contentNode.style.setProperty('display', '');
46
+ }
47
+
48
+ this.__setBoundaries();
49
+ }
50
+
51
+ /**
52
+ * Update aria labels on state change.
53
+ * @param {import('lit').PropertyValues } changedProperties
54
+ */
55
+ updated(changedProperties) {
56
+ if (changedProperties.has('opened')) {
57
+ this._openedChanged();
58
+ }
59
+ }
60
+
61
+ static get styles() {
62
+ return [drawerStyle];
63
+ }
64
+
65
+ __setBoundaries() {
66
+ const host = this.shadowRoot?.host;
67
+
68
+ if (this.position === 'top') {
69
+ this.minHeight = host ? getComputedStyle(host).getPropertyValue('--min-height') : '0px';
70
+ this.maxHeight = host ? getComputedStyle(host).getPropertyValue('--max-height') : '0px';
71
+ this.minWidth = '0px';
72
+ this.maxWidth = 'none';
73
+ } else {
74
+ this.minWidth = host ? getComputedStyle(host).getPropertyValue('--min-width') : '0px';
75
+ this.maxWidth = host ? getComputedStyle(host).getPropertyValue('--max-width') : '0px';
76
+ this.minHeight = 'auto';
77
+ this.maxHeight = 'fit-content';
78
+ }
79
+
80
+ setTimeout(() => {
81
+ const prop = this.position === 'top' ? 'width' : 'height';
82
+
83
+ if (this.__contentNode) {
84
+ this.__contentNode.style.setProperty(prop, '');
85
+ }
86
+ });
87
+ }
88
+
89
+ /**
90
+ * Setter for position property, available values are 'top', 'left' and 'right'
91
+ * @param {String} position
92
+ */
93
+ set position(position) {
94
+ const stale = this.position;
95
+ this._position = position;
96
+ this.setAttribute('position', position);
97
+
98
+ this.__setBoundaries();
99
+ this.requestUpdate('position', stale);
100
+ }
101
+
102
+ get position() {
103
+ return this._position ?? 'left';
104
+ }
105
+
106
+ /**
107
+ * Trigger show animation and wait for transition to be finished.
108
+ * @param {Object} options - element node and its options
109
+ * @param {HTMLElement} options.contentNode
110
+ * @override
111
+ */
112
+ async _showAnimation({ contentNode }) {
113
+ const min = this.position === 'top' ? this.minHeight : this.minWidth;
114
+ const max = this.position === 'top' ? this.maxHeight : this.maxWidth;
115
+ const prop = this.position === 'top' ? 'height' : 'width';
116
+
117
+ contentNode.style.setProperty(prop, /** @type {string} */ (min));
118
+ await new Promise(resolve => requestAnimationFrame(() => resolve(true)));
119
+ contentNode.style.setProperty(prop, /** @type {string} */ (max));
120
+ await this._waitForTransition({ contentNode });
121
+ }
122
+
123
+ /**
124
+ * Trigger hide animation and wait for transition to be finished.
125
+ * @param {Object} options - element node and its options
126
+ * @param {HTMLElement} options.contentNode
127
+ * @override
128
+ */
129
+ async _hideAnimation({ contentNode }) {
130
+ if (
131
+ ((this.position === 'left' || this.position === 'right') &&
132
+ this._contentWidth === this.minWidth) ||
133
+ (this.position === 'top' && this._contentHeight === this.minHeight)
134
+ ) {
135
+ return;
136
+ }
137
+
138
+ const min = this.position === 'top' ? this.minHeight : this.minWidth;
139
+ const prop = this.position === 'top' ? 'height' : 'width';
140
+
141
+ contentNode.style.setProperty(prop, /** @type {string} */ (min));
142
+ await this._waitForTransition({ contentNode });
143
+ }
144
+
145
+ /**
146
+ * Wait until the transition event is finished.
147
+ * @param {Object} options - element node and its options
148
+ * @param {HTMLElement} options.contentNode
149
+ * @returns {Promise<void>} transition event
150
+ */
151
+ _waitForTransition({ contentNode }) {
152
+ return new Promise(resolve => {
153
+ const transitionStarted = () => {
154
+ contentNode.removeEventListener(EVENT.TRANSITION_START, transitionStarted);
155
+ this.transitioning = true;
156
+ };
157
+ contentNode.addEventListener(EVENT.TRANSITION_START, transitionStarted);
158
+
159
+ const transitionEnded = () => {
160
+ contentNode.removeEventListener(EVENT.TRANSITION_END, transitionEnded);
161
+ this.transitioning = false;
162
+ resolve();
163
+ };
164
+ contentNode.addEventListener(EVENT.TRANSITION_END, transitionEnded);
165
+ });
166
+ }
167
+
168
+ /**
169
+ * @protected
170
+ */
171
+ get __contentNode() {
172
+ return /** @type {HTMLElement} */ (this.shadowRoot?.querySelector('.container'));
173
+ }
174
+
175
+ get _contentWidth() {
176
+ const size = this.__contentNode?.getBoundingClientRect().width || 0;
177
+ return `${size}px`;
178
+ }
179
+
180
+ get _contentHeight() {
181
+ const size = this.__contentNode?.getBoundingClientRect().height || 0;
182
+ return `${size}px`;
183
+ }
184
+
185
+ _openedChanged() {
186
+ this._updateContentSize();
187
+ if (this._invokerNode) {
188
+ this._invokerNode.setAttribute('aria-expanded', `${this.opened}`);
189
+ }
190
+
191
+ this.dispatchEvent(new CustomEvent('opened-changed'));
192
+ }
193
+
194
+ async _updateContentSize() {
195
+ if (this.__contentNode) {
196
+ if (this.opened) {
197
+ await this._showAnimation({ contentNode: this.__contentNode });
198
+ } else {
199
+ await this._hideAnimation({ contentNode: this.__contentNode });
200
+ }
201
+ }
202
+ }
203
+
204
+ render() {
205
+ return html`
206
+ <div class="container">
207
+ <div class="headline-container">
208
+ <slot name="invoker"></slot>
209
+ <slot name="headline"></slot>
210
+ </div>
211
+ <div class="content-container">
212
+ <slot name="content"></slot>
213
+ </div>
214
+ </div>
215
+ `;
216
+ }
217
+ }
@@ -0,0 +1,59 @@
1
+ import { css } from 'lit';
2
+
3
+ export const drawerStyle = css`
4
+ :host {
5
+ display: block;
6
+ height: 100%;
7
+ --min-width: 72px;
8
+ --max-width: 320px;
9
+ --min-height: auto;
10
+ --max-height: fit-content;
11
+ --start-width: var(--min-width);
12
+ --start-height: 100%;
13
+ --transition-property: width;
14
+ }
15
+
16
+ :host([position='top']) {
17
+ width: 100%;
18
+ --min-width: 0px;
19
+ --max-width: none;
20
+ --min-height: 50px;
21
+ --max-height: 200px;
22
+ --start-width: 100%;
23
+ --start-height: var(--min-height);
24
+ --transition-property: height;
25
+ }
26
+
27
+ .container {
28
+ display: flex;
29
+ flex-direction: column;
30
+ width: var(--start-width);
31
+ height: var(--start-height);
32
+ min-width: var(--min-width);
33
+ max-width: var(--max-width);
34
+ min-height: var(--min-height);
35
+ max-height: var(--max-height);
36
+ overflow: hidden;
37
+ box-sizing: border-box;
38
+ transition: var(--transition-property) 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
39
+ }
40
+
41
+ .headline-container {
42
+ display: flex;
43
+ align-items: center;
44
+ flex-wrap: nowrap;
45
+ }
46
+
47
+ :host([position='right']) .headline-container {
48
+ flex-direction: row-reverse;
49
+ }
50
+
51
+ .content-container {
52
+ overflow: hidden;
53
+ flex-grow: 1;
54
+ }
55
+
56
+ ::slotted([slot='content']) {
57
+ width: var(--max-width);
58
+ }
59
+ `;
@@ -0,0 +1,109 @@
1
+ import { expect, fixture as _fixture } from '@open-wc/testing';
2
+ import { html } from 'lit/static-html.js';
3
+ import '@lion/ui/define/lion-drawer.js';
4
+
5
+ /**
6
+ * @typedef {import('../src/LionDrawer.js').LionDrawer} LionDrawer
7
+ * @typedef {import('lit').TemplateResult} TemplateResult
8
+ */
9
+ const fixture = /** @type {(arg: TemplateResult) => Promise<LionDrawer>} */ (_fixture);
10
+
11
+ const template = html`
12
+ <lion-drawer>
13
+ <button slot="invoker">Open</button>
14
+ <p slot="headline">Headline</p>
15
+ <div slot="content" class="drawer">This is the content of the drawer</div>
16
+ </lion-drawer>
17
+ `;
18
+
19
+ describe('<lion-drawer>', () => {
20
+ describe('Drawer', () => {
21
+ it('sets position to "left" by default', async () => {
22
+ const drawer = await fixture(template);
23
+ expect(drawer.position).to.equal('left');
24
+ });
25
+
26
+ it('has [position] attribute which serves as styling hook', async () => {
27
+ const drawer = await fixture(template);
28
+ expect(drawer).to.have.attribute('position').equal('left');
29
+ });
30
+
31
+ it('sets the minimum and maximum width when position=left', async () => {
32
+ const drawer = await fixture(template);
33
+ const minWidth = getComputedStyle(drawer).getPropertyValue('--min-width');
34
+ const maxWidth = getComputedStyle(drawer).getPropertyValue('--max-width');
35
+
36
+ expect(drawer.minWidth).to.equal(minWidth);
37
+ expect(drawer.maxWidth).to.equal(maxWidth);
38
+ });
39
+
40
+ it('sets the minimum and maximum width when position=right', async () => {
41
+ const drawer = await fixture(template);
42
+ drawer.position = 'right';
43
+ await drawer.updateComplete;
44
+
45
+ const minWidth = getComputedStyle(drawer).getPropertyValue('--min-width');
46
+ const maxWidth = getComputedStyle(drawer).getPropertyValue('--max-width');
47
+
48
+ expect(drawer.minWidth).to.equal(minWidth);
49
+ expect(drawer.maxWidth).to.equal(maxWidth);
50
+ });
51
+
52
+ it('sets the minimum and maximum height when position=top', async () => {
53
+ const drawer = await fixture(template);
54
+ drawer.position = 'top';
55
+ await drawer.updateComplete;
56
+
57
+ const minHeight = getComputedStyle(drawer).getPropertyValue('--min-height');
58
+ const maxHeight = getComputedStyle(drawer).getPropertyValue('--max-height');
59
+
60
+ expect(drawer.minHeight).to.equal(minHeight);
61
+ expect(drawer.maxHeight).to.equal(maxHeight);
62
+ });
63
+ });
64
+
65
+ describe('Accessibility', () => {
66
+ it('[collapsed] is a11y AXE accessible', async () => {
67
+ const drawer = await fixture(template);
68
+ await expect(drawer).to.be.accessible();
69
+ });
70
+
71
+ it('[opened] is a11y AXE accessible', async () => {
72
+ const drawer = await fixture(template);
73
+ drawer.opened = true;
74
+ await expect(drawer).to.be.accessible();
75
+ });
76
+
77
+ describe('Invoker', () => {
78
+ it('links id of content items to invoker via [aria-controls]', async () => {
79
+ const drawerElement = await fixture(template);
80
+ const invoker = drawerElement.querySelector('[slot=invoker]');
81
+ const content = drawerElement.querySelector('[slot=content]');
82
+ expect(invoker?.getAttribute('aria-controls')).to.equal(content?.id);
83
+ });
84
+
85
+ it('adds aria-expanded="false" to invoker when its content is not expanded', async () => {
86
+ const drawerElement = await fixture(template);
87
+ const invoker = drawerElement.querySelector('[slot=invoker]');
88
+ expect(invoker).to.have.attribute('aria-expanded', 'false');
89
+ });
90
+
91
+ it('adds aria-expanded="true" to invoker when its content is expanded', async () => {
92
+ const drawerElement = await fixture(template);
93
+ const invoker = drawerElement.querySelector('[slot=invoker]');
94
+ drawerElement.opened = true;
95
+ await drawerElement.updateComplete;
96
+ expect(invoker).to.have.attribute('aria-expanded', 'true');
97
+ });
98
+ });
99
+
100
+ describe('Contents', () => {
101
+ it('adds aria-labelledby referring to invoker id', async () => {
102
+ const drawerElement = await fixture(template);
103
+ const invoker = drawerElement.querySelector('[slot=invoker]');
104
+ const content = drawerElement.querySelector('[slot=content]');
105
+ expect(content).to.have.attribute('aria-labelledby', invoker?.id);
106
+ });
107
+ });
108
+ });
109
+ });
@@ -1,56 +1,35 @@
1
1
  import { getDecimalSeparator } from './getDecimalSeparator.js';
2
2
 
3
- /**
4
- * @param {string} value to evaluate
5
- * @return {boolean} true if value equal . or ,
6
- */
7
- function isDecimalSeparator(value) {
8
- return value === '.' || value === ',';
9
- }
10
-
11
3
  /**
12
4
  * Determines the best possible parsing mode.
13
5
  *
14
- * - If there is only one separator (withLocale)
15
- * - 1,23 => xxx1.23 (heuristic)
16
- * - else parse mode depends mostly on the last 4 chars
17
- * - 1234 => xxx1234 (heuristic)
18
- * - [space]123 => xxx123 (heuristic)
19
- * - ,123 => unclear
20
- * - if 1.000,123 (we find a different separator) => 1000.123 (heuristic)
21
- * - if 1,000,123 (we find only same separators) => 1000123 (unparseable)
22
- * - if 100,123 (we find no more separators) => unclear
23
- * - if en => 100123 (withLocale)
24
- * - if nl => 100.123 (withLocale)
25
- *
26
- * See also {@link parseAmount}
6
+ * It has 3 "methods" of returning numbers
7
+ * - 'unparseable': becomes just numbers
8
+ * - 'withLocale': result depends on given or global locale
9
+ * - 'heuristic': result depends on considering separators
27
10
  *
28
11
  * @example
29
- * getParseMode('1.234') => 'withLocale'
12
+ * parseNumber('1.234.567'); // method: unparseable => 1234567
13
+ * parseNumber('1.234'); // method: withLocale => depending on locale 1234 or 1.234
14
+ * parseNumber('1.234,56'); // method: heuristic => 1234.56
15
+ * parseNumber('1 234.56'); // method: heuristic => 1234.56
16
+ * parseNumber('1,234.56'); // method: heuristic => 1234.56
30
17
  *
31
18
  * @param {string} value Clean number (only [0-9 ,.]) to be parsed
19
+ * @param {object} options
20
+ * @param {string?} [options.mode] auto|pasted
32
21
  * @return {string} unparseable|withLocale|heuristic
33
22
  */
34
23
  function getParseMode(value, { mode = 'auto' } = {}) {
35
24
  const separators = value.match(/[., ]/g);
36
25
 
37
- if (mode === 'auto' && separators && separators.length === 1) {
26
+ if (!separators || (mode === 'auto' && separators.length === 1)) {
38
27
  return 'withLocale';
39
28
  }
40
-
41
- if (value.length > 4) {
42
- const charAtLastSeparatorPosition = value[value.length - 4];
43
- if (isDecimalSeparator(charAtLastSeparatorPosition)) {
44
- const firstPart = value.substring(0, value.length - 4);
45
- const otherSeparators = firstPart.match(/[., ]/g);
46
- if (otherSeparators) {
47
- const lastSeparator = charAtLastSeparatorPosition;
48
- return otherSeparators.indexOf(lastSeparator) === -1 ? 'heuristic' : 'unparseable';
49
- }
50
- return 'withLocale';
51
- }
29
+ if (separators.length === 1 || separators[0] !== separators[separators.length - 1]) {
30
+ return 'heuristic';
52
31
  }
53
- return 'heuristic';
32
+ return 'unparseable';
54
33
  }
55
34
 
56
35
  /**
@@ -72,19 +72,10 @@ describe('parseNumber()', () => {
72
72
  expect(parseNumber('123456.78', { mode: 'pasted' })).to.equal(123456.78);
73
73
  });
74
74
 
75
- it('detects separators heuristically when there are 2 same ones e.g. 1.234.56', () => {
76
- expect(parseNumber('1.234.5')).to.equal(1234.5);
77
- expect(parseNumber('1,234,5')).to.equal(1234.5);
78
-
79
- expect(parseNumber('1.234.56')).to.equal(1234.56);
80
- expect(parseNumber('1,234,56')).to.equal(1234.56);
75
+ it('detects separators unparseable when there are 2 same ones e.g. 1.234.56', () => {
76
+ expect(parseNumber('1.234.56')).to.equal(123456);
77
+ expect(parseNumber('1,234,56')).to.equal(123456);
81
78
  expect(parseNumber('1 234 56')).to.equal(123456);
82
-
83
- expect(parseNumber('1.234.5678')).to.equal(1234.5678);
84
- expect(parseNumber('1,234,5678')).to.equal(1234.5678);
85
-
86
- expect(parseNumber('1.234.56789')).to.equal(1234.56789);
87
- expect(parseNumber('1,234,56789')).to.equal(1234.56789);
88
79
  });
89
80
 
90
81
  it('uses locale to parse amount if there is only one separator e.g. 1.234', () => {