@lion/ui 0.14.3 → 0.15.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 (235) hide show
  1. package/README.md +38 -12
  2. package/components/combobox/test/lion-combobox.test.js +50 -2
  3. package/components/core/src/SlotMixin.js +52 -0
  4. package/components/core/test/SlotMixin.test.js +85 -0
  5. package/components/icon/src/icons.js +14 -2
  6. package/components/icon/test/hammer.svg.js +5 -2
  7. package/components/icon/test/heart.svg.js +5 -2
  8. package/components/icon/test/lion-icon.test.js +10 -4
  9. package/components/input-stepper/src/LionInputStepper.js +10 -10
  10. package/components/listbox/src/ListboxMixin.js +3 -35
  11. package/components/localize/src/getLocalizeManager.js +16 -10
  12. package/components/localize/test/getLocalizeManager.test.js +15 -7
  13. package/components/localize/test/side-effect-free-entrypoint.test.js +9 -3
  14. package/components/overlays/src/ArrowMixin.js +10 -4
  15. package/components/overlays/src/singleton.js +14 -4
  16. package/components/overlays/test/OverlayController.test.js +4 -1
  17. package/custom-elements.json +3014 -220
  18. package/dist-types/components/core/src/ScopedElementsMixin.d.ts.map +1 -1
  19. package/dist-types/components/core/src/SlotMixin.d.ts +35 -0
  20. package/dist-types/components/core/src/SlotMixin.d.ts.map +1 -1
  21. package/dist-types/components/core/test/SlotMixin.test.d.ts.map +1 -1
  22. package/dist-types/components/icon/src/LionIcon.d.ts +1 -1
  23. package/dist-types/components/icon/src/LionIcon.d.ts.map +1 -1
  24. package/dist-types/components/icon/src/icons.d.ts +2 -1
  25. package/dist-types/components/icon/src/icons.d.ts.map +1 -1
  26. package/dist-types/components/icon/test/hammer.svg.d.ts +1 -1
  27. package/dist-types/components/icon/test/hammer.svg.d.ts.map +1 -1
  28. package/dist-types/components/icon/test/heart.svg.d.ts +1 -1
  29. package/dist-types/components/icon/test/heart.svg.d.ts.map +1 -1
  30. package/dist-types/components/input-stepper/src/LionInputStepper.d.ts +4 -4
  31. package/dist-types/components/input-stepper/src/LionInputStepper.d.ts.map +1 -1
  32. package/dist-types/components/listbox/src/ListboxMixin.d.ts.map +1 -1
  33. package/dist-types/components/localize/src/getLocalizeManager.d.ts +2 -58
  34. package/dist-types/components/localize/src/getLocalizeManager.d.ts.map +1 -1
  35. package/dist-types/components/localize/test/getLocalizeManager.test.d.ts +4 -1
  36. package/dist-types/components/localize/test/getLocalizeManager.test.d.ts.map +1 -1
  37. package/dist-types/components/localize/test/side-effect-free-entrypoint.test.d.ts +4 -0
  38. package/dist-types/components/localize/test/side-effect-free-entrypoint.test.d.ts.map +1 -1
  39. package/dist-types/components/overlays/src/ArrowMixin.d.ts.map +1 -1
  40. package/dist-types/components/overlays/src/singleton.d.ts.map +1 -1
  41. package/dist-types/tsconfig.tsbuildinfo +1 -1
  42. package/docs/components/accordion/index.md +1 -1
  43. package/docs/components/accordion/overview.md +1 -1
  44. package/docs/components/accordion/reference.md +1 -1
  45. package/docs/components/accordion/use-cases.md +1 -1
  46. package/docs/components/button/{extensions/bootstrap-button.mjs → assets/bootstrap-button.js} +10 -5
  47. package/docs/components/button/examples.md +1 -1
  48. package/docs/components/button/extensions.md +2 -2
  49. package/docs/components/button/index.md +2 -2
  50. package/docs/components/button/overview.md +4 -4
  51. package/docs/components/button/use-cases.md +6 -6
  52. package/docs/components/calendar/index.md +1 -1
  53. package/docs/components/calendar/overview.md +1 -1
  54. package/docs/components/calendar/use-cases.md +2 -2
  55. package/docs/components/checkbox-group/index.md +1 -1
  56. package/docs/components/checkbox-group/overview.md +3 -3
  57. package/docs/components/checkbox-group/use-cases.md +1 -1
  58. package/docs/components/collapsible/examples.md +1 -1
  59. package/docs/components/collapsible/index.md +1 -1
  60. package/docs/components/collapsible/overview.md +2 -2
  61. package/docs/components/collapsible/use-cases.md +1 -1
  62. package/docs/components/combobox/extensions.md +2 -1
  63. package/docs/components/combobox/index.md +1 -1
  64. package/docs/components/combobox/overview.md +2 -2
  65. package/docs/components/combobox/use-cases.md +2 -2
  66. package/docs/components/dialog/index.md +1 -1
  67. package/docs/components/dialog/overview.md +2 -2
  68. package/docs/components/dialog/use-cases.md +1 -1
  69. package/docs/components/drawer/index.md +1 -1
  70. package/docs/components/drawer/overview.md +1 -1
  71. package/docs/components/drawer/use-cases.md +1 -1
  72. package/docs/components/fieldset/index.md +1 -1
  73. package/docs/components/fieldset/overview.md +6 -6
  74. package/docs/components/fieldset/use-cases.md +1 -1
  75. package/docs/components/form/index.md +1 -1
  76. package/docs/components/form/overview.md +4 -4
  77. package/docs/components/form/use-cases.md +3 -3
  78. package/docs/components/icon/index.md +1 -1
  79. package/docs/components/icon/overview.md +1 -1
  80. package/docs/components/icon/use-cases.md +2 -15
  81. package/docs/components/index.md +1 -1
  82. package/docs/components/input/index.md +1 -1
  83. package/docs/components/input/overview.md +2 -2
  84. package/docs/components/input/use-cases.md +1 -1
  85. package/docs/components/input-amount/index.md +1 -1
  86. package/docs/components/input-amount/overview.md +4 -4
  87. package/docs/components/input-amount/use-cases.md +1 -1
  88. package/docs/components/input-amount-dropdown/index.md +1 -1
  89. package/docs/components/input-amount-dropdown/use-cases.md +1 -1
  90. package/docs/components/input-date/index.md +1 -1
  91. package/docs/components/input-date/overview.md +4 -4
  92. package/docs/components/input-date/use-cases.md +1 -1
  93. package/docs/components/input-datepicker/index.md +1 -1
  94. package/docs/components/input-datepicker/overview.md +6 -6
  95. package/docs/components/input-datepicker/use-cases.md +1 -1
  96. package/docs/components/input-email/index.md +1 -1
  97. package/docs/components/input-email/overview.md +3 -3
  98. package/docs/components/input-email/use-cases.md +1 -1
  99. package/docs/components/input-file/index.md +1 -1
  100. package/docs/components/input-file/overview.md +2 -2
  101. package/docs/components/input-file/use-cases.md +1 -1
  102. package/docs/components/input-iban/index.md +1 -1
  103. package/docs/components/input-iban/overview.md +3 -3
  104. package/docs/components/input-iban/use-cases.md +1 -1
  105. package/docs/components/input-range/index.md +1 -1
  106. package/docs/components/input-range/overview.md +3 -3
  107. package/docs/components/input-range/use-cases.md +1 -1
  108. package/docs/components/input-stepper/api-table.md +2 -0
  109. package/docs/components/input-stepper/index.md +1 -1
  110. package/docs/components/input-stepper/overview.md +2 -2
  111. package/docs/components/input-stepper/use-cases.md +1 -1
  112. package/docs/components/input-tel/index.md +1 -1
  113. package/docs/components/input-tel/overview.md +2 -2
  114. package/docs/components/input-tel/use-cases.md +7 -7
  115. package/docs/components/input-tel-dropdown/extensions.md +1 -1
  116. package/docs/components/input-tel-dropdown/index.md +1 -1
  117. package/docs/components/input-tel-dropdown/overview.md +2 -2
  118. package/docs/components/input-tel-dropdown/use-cases.md +1 -1
  119. package/docs/components/listbox/index.md +1 -1
  120. package/docs/components/listbox/overview.md +1 -1
  121. package/docs/components/listbox/use-cases.md +2 -2
  122. package/docs/components/pagination/index.md +1 -1
  123. package/docs/components/pagination/overview.md +1 -1
  124. package/docs/components/pagination/use-cases.md +1 -1
  125. package/docs/components/progress-indicator/examples.md +1 -1
  126. package/docs/components/progress-indicator/index.md +1 -1
  127. package/docs/components/progress-indicator/overview.md +1 -1
  128. package/docs/components/radio-group/index.md +1 -1
  129. package/docs/components/radio-group/overview.md +4 -4
  130. package/docs/components/radio-group/use-cases.md +1 -1
  131. package/docs/components/select/index.md +1 -1
  132. package/docs/components/select/overview.md +1 -1
  133. package/docs/components/select/use-cases.md +2 -2
  134. package/docs/components/select-rich/examples.md +1 -1
  135. package/docs/components/select-rich/index.md +1 -1
  136. package/docs/components/select-rich/overview.md +1 -1
  137. package/docs/components/select-rich/use-cases.md +3 -3
  138. package/docs/components/steps/index.md +1 -1
  139. package/docs/components/steps/overview.md +1 -1
  140. package/docs/components/steps/use-cases.md +1 -1
  141. package/docs/components/switch/index.md +1 -1
  142. package/docs/components/switch/overview.md +1 -1
  143. package/docs/components/switch/reference.md +1 -1
  144. package/docs/components/switch/use-cases.md +1 -1
  145. package/docs/components/tabs/examples.md +2 -2
  146. package/docs/components/tabs/index.md +1 -1
  147. package/docs/components/tabs/overview.md +1 -1
  148. package/docs/components/tabs/use-cases.md +1 -1
  149. package/docs/components/textarea/index.md +1 -1
  150. package/docs/components/textarea/overview.md +1 -1
  151. package/docs/components/textarea/use-cases.md +1 -1
  152. package/docs/components/tooltip/examples.md +1 -1
  153. package/docs/components/tooltip/index.md +1 -1
  154. package/docs/components/tooltip/overview.md +1 -1
  155. package/docs/components/tooltip/use-cases.md +1 -1
  156. package/docs/fundamentals/index.md +4 -4
  157. package/docs/fundamentals/node-tools/babel-plugin-extend-docs/index.md +1 -1
  158. package/docs/fundamentals/node-tools/babel-plugin-extend-docs/overview.md +1 -1
  159. package/docs/fundamentals/node-tools/index.md +1 -1
  160. package/docs/fundamentals/node-tools/providence-analytics/index.md +1 -1
  161. package/docs/fundamentals/node-tools/providence-analytics/overview.md +1 -1
  162. package/docs/fundamentals/node-tools/publish-docs/index.md +1 -1
  163. package/docs/fundamentals/node-tools/publish-docs/overview.md +4 -4
  164. package/docs/fundamentals/node-tools/remark-extend/index.md +1 -1
  165. package/docs/fundamentals/node-tools/remark-extend/overview.md +1 -1
  166. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/index.md +1 -1
  167. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +3 -3
  168. package/docs/fundamentals/rationales/TypeScript.md +1 -1
  169. package/docs/fundamentals/rationales/accessibility.md +2 -2
  170. package/docs/fundamentals/rationales/index.md +1 -1
  171. package/docs/fundamentals/rationales/side-effects.md +1 -1
  172. package/docs/fundamentals/rationales/versioning.md +1 -1
  173. package/docs/fundamentals/systems/core/SlotMixin.md +2 -2
  174. package/docs/fundamentals/systems/core/index.md +1 -1
  175. package/docs/fundamentals/systems/core/overview.md +2 -2
  176. package/docs/fundamentals/systems/form/formatting-and-parsing.md +5 -5
  177. package/docs/fundamentals/systems/form/index.md +1 -1
  178. package/docs/fundamentals/systems/form/interaction-states.md +1 -1
  179. package/docs/fundamentals/systems/form/model-value.md +2 -2
  180. package/docs/fundamentals/systems/form/overview.md +29 -29
  181. package/docs/fundamentals/systems/form/styling.md +1 -1
  182. package/docs/fundamentals/systems/form/use-cases.md +1 -1
  183. package/docs/fundamentals/systems/form/validate.md +3 -3
  184. package/docs/fundamentals/systems/icon/index.md +1 -1
  185. package/docs/fundamentals/systems/icon/overview.md +1 -1
  186. package/docs/fundamentals/systems/index.md +1 -1
  187. package/docs/fundamentals/systems/localize/api-table.md +3 -0
  188. package/docs/fundamentals/systems/localize/dates.md +1 -1
  189. package/docs/fundamentals/systems/localize/index.md +1 -1
  190. package/docs/fundamentals/systems/localize/numbers.md +1 -1
  191. package/docs/fundamentals/systems/localize/overview.md +5 -5
  192. package/docs/fundamentals/systems/localize/rationale.md +1 -1
  193. package/docs/fundamentals/systems/localize/text.md +5 -4
  194. package/docs/fundamentals/systems/localize/use-cases.md +1 -1
  195. package/docs/fundamentals/systems/overlays/_configuration-positioning.md +3 -3
  196. package/docs/fundamentals/systems/overlays/_edge-cases.md +3 -3
  197. package/docs/fundamentals/systems/overlays/api-table.md +3 -0
  198. package/docs/fundamentals/systems/overlays/assets/demo-overlay-positioning.mjs +1 -1
  199. package/docs/fundamentals/systems/overlays/configuration.md +5 -5
  200. package/docs/fundamentals/systems/overlays/index.md +1 -1
  201. package/docs/fundamentals/systems/overlays/overview.md +6 -6
  202. package/docs/fundamentals/systems/overlays/rationale.md +1 -1
  203. package/docs/fundamentals/systems/overlays/use-cases.md +6 -6
  204. package/docs/fundamentals/tools/ajax/index.md +1 -1
  205. package/docs/fundamentals/tools/ajax/overview.md +2 -2
  206. package/docs/fundamentals/tools/ajax/use-cases.md +3 -3
  207. package/docs/fundamentals/tools/helpers/action-logger.md +1 -1
  208. package/docs/fundamentals/tools/helpers/index.md +2 -2
  209. package/docs/fundamentals/tools/helpers/overview.md +2 -2
  210. package/docs/fundamentals/tools/index.md +1 -1
  211. package/docs/fundamentals/tools/singleton-manager/example-complex/index.md +1 -1
  212. package/docs/fundamentals/tools/singleton-manager/example-fail/demo-app.js +4 -4
  213. package/docs/fundamentals/tools/singleton-manager/example-fail/index.md +2 -2
  214. package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/{page-a/page-a.js → page-c/page-c.js} +2 -2
  215. package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/{page-b/page-b.js → page-d/page-d.js} +2 -2
  216. package/docs/fundamentals/tools/singleton-manager/example-success/demo-app.js +4 -4
  217. package/docs/fundamentals/tools/singleton-manager/example-success/index.md +2 -2
  218. package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/{page-a/page-a.js → page-e/page-e.js} +2 -3
  219. package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/{page-b/page-b.js → page-f/page-f.js} +2 -2
  220. package/docs/fundamentals/tools/singleton-manager/index.md +2 -2
  221. package/docs/fundamentals/tools/singleton-manager/overview.md +5 -5
  222. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  223. package/docs/guides/how-to/create-a-form.md +4 -4
  224. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  225. package/docs/guides/index.md +8 -8
  226. package/docs/guides/principles/index.md +5 -5
  227. package/docs/guides/principles/styling.md +1 -1
  228. package/package.json +2 -2
  229. /package/docs/fundamentals/systems/overlays/assets/{applyDemoOverlayStyles.mjs → applyDemoOverlayStyles.js} +0 -0
  230. /package/docs/fundamentals/systems/overlays/assets/{demo-el-using-overlaymixin.mjs → demo-el-using-overlaymixin.js} +0 -0
  231. /package/docs/fundamentals/systems/overlays/assets/{demo-overlay-backdrop.mjs → demo-overlay-backdrop.js} +0 -0
  232. /package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/{page-b → page-d}/node_modules/overlays/index.js +0 -0
  233. /package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/{page-b → page-d}/node_modules/overlays/instance.js +0 -0
  234. /package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/{page-b → page-f}/node_modules/overlays/index.js +0 -0
  235. /package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/{page-b → page-f}/node_modules/overlays/instance.js +0 -0
package/README.md CHANGED
@@ -26,33 +26,59 @@
26
26
  </p>
27
27
 
28
28
  <p align="center">
29
- <a href="https://lion.js.org">Website</a>
29
+ <a href="https://lion-web.netlify.app">Website</a>
30
30
  ·
31
- <a href="https://lion.js.org/fundamentals/">Fundamentals</a>
31
+ <a href="https://lion-web.netlify.app/fundamentals/">Fundamentals</a>
32
32
  ·
33
- <a href="https://lion.js.org/guides/">Guides</a>
33
+ <a href="https://lion-web.netlify.app/guides/">Guides</a>
34
34
  ·
35
- <a href="https://lion.js.org/components/">Components</a>
35
+ <a href="https://lion-web.netlify.app/components/">Components</a>
36
36
  ·
37
- <a href="https://lion.js.org/blog/">Blog</a>
37
+ <a href="https://lion-web.netlify.app/blog/">Blog</a>
38
38
  </p>
39
39
 
40
- **Lion is a set of highly performant, accessible, and flexible Web Components.**
40
+ **Lion is a set of highly performant, accessible and flexible Web Components.!**
41
41
 
42
42
  They provide an unopinionated, white-label layer that can be extended to your own layer of components.
43
43
 
44
44
  - **High Performance:** Focused on great performance in all relevant browsers with a minimal number of dependencies.
45
45
  - **Accessibility:** Aimed at compliance with the WCAG 2.2 AA standard to create components that are accessible for everybody.
46
46
  - **Flexibility:** Provides solutions through Web Components and JavaScript classes which can be used, adopted and extended to fit all needs.
47
- - **Modern Code:** Lion is distributed as pure ES modules.
48
- - **Exposes functions/classes and Web Components:** Ships a functionality in its most appropriate form.
47
+ - **Modern Code:** Lion is distributes as pure es modules.
48
+ - **Exposes functions/classes and Web Components:** Ships a functionality in it's most appropriate form.
49
49
 
50
- > Note: Our demo examples might look simple and not very stylish. This is on purpose. They are designed to be basic so you can easily add your own styles to them to match your intended design, without dealing with styles that are already there.
50
+ > Note: Our demos may look a little bland but that is on purpose. They only come with functional stylings.
51
+ > This makes sense as the main use case is to extend those components and if you do you do not want to override existing stylings.
51
52
 
52
53
  <p align="center">
53
- <a href="https://lion.js.org/guides/"><strong>Explore the Lion Guides&nbsp;&nbsp;▶</strong></a>
54
+ <a href="https://lion-web.netlify.app/guides/"><strong>Explore the Lion Guides&nbsp;&nbsp;▶</strong></a>
54
55
  </p>
55
56
 
57
+ ## Astro migration
58
+
59
+ - Keep using `/docs` on the root level as we used it in the `master` branch. The documentation is copied into Astro related directories on `npm run start` and when when anything in `/docs` is updated.
60
+ - Replace manually all references to assets in all `md` files so that we imply that the path is produced from the directory where the md file is located. F.e. `new URL('../src/wa-combobox/assets/obama.jpeg', import.meta.url).href;` should `new URL('./src/wa-combobox/assets/obama.jpeg', import.meta.url).href;`. Note double dot is replaced with one dot. See [this PR](https://github.com/ing-bank/lion/pull/2125/files#diff-403b1e0ab54d51dcfe54248e847498e492da00383d8b33a4087994ab9035a22c) for the reference.
61
+ - Rename all `*.mjs` files to `*.js` ones if they are used by `mdjs` examples
62
+
63
+ ### Astro how to
64
+
65
+ - To start in dev mode run `nmm run start`
66
+ - To start in production mode:
67
+ - Run `npm run build`
68
+ - Run `npm run preview`
69
+
70
+ ### Issues which are not caused by the migration (not to be fixed now)
71
+
72
+ - There is a browser console error on [collapsible page](http://localhost:4321/components/collapsible):
73
+
74
+ ```
75
+ __mdjs-stories--use-cases.js:40 Uncaught TypeError: shadowRoot.getElementById is not a function
76
+ ```
77
+
78
+ Note. There is the same error on master. This issue is not caused by the migration
79
+
80
+ ### TODO
81
+
56
82
  ## How to install
57
83
 
58
84
  ```bash
@@ -113,7 +139,7 @@ You can also use the lion elements directly, although this is likely not a commo
113
139
 
114
140
  ## Issues
115
141
 
116
- If you encounter an issue with any of the packages we are offering please open a [new bug issue](https://github.com/ing-bank/lion/issues/new?assignees=&labels=&template=bug_report.md&title=). Be sure to include a description of the expected and the current behavior - additionally adding a [reproduction](https://webcomponents.dev/edit/kpZmz1CJN580OaXsk56f?pm=1) always helps.
142
+ If you encounter an issue with any of the packages we are offering please open a [new bug issue](https://github.com/ing-bank/lion/issues/new?assignees=&labels=&template=bug_report.md&title=). Be sure to include a description of the expected and the current behavior - additional adding a [reproduction](https://webcomponents.dev/edit/kpZmz1CJN580OaXsk56f?pm=1) always helps.
117
143
 
118
144
  ## Feature requests
119
145
 
@@ -158,7 +184,7 @@ This means you only have to apply your own Design System: by delivering styles,
158
184
 
159
185
  ## Coding guidelines
160
186
 
161
- Check out our [coding guidelines](https://lion.js.org/guides/principles/definitions-and-terms/) for more detailed information.
187
+ Check out our [coding guidelines](https://lion-web.netlify.app/guides/principles/definitions-and-terms/) for more detailed information.
162
188
 
163
189
  ## How to contribute
164
190
 
@@ -2,11 +2,11 @@ import { defineCE, expect, fixture, html, unsafeStatic, waitUntil } from '@open-
2
2
  import { Required, Unparseable } from '@lion/ui/form-core.js';
3
3
  import { sendKeys } from '@web/test-runner-commands';
4
4
  import { LionCombobox } from '@lion/ui/combobox.js';
5
- import { browserDetection } from '@lion/ui/core.js';
5
+ import { browserDetection, SlotMixin } from '@lion/ui/core.js';
6
6
  import '@lion/ui/define/lion-combobox.js';
7
7
  import '@lion/ui/define/lion-listbox.js';
8
8
  import '@lion/ui/define/lion-option.js';
9
- import { LitElement } from 'lit';
9
+ import { LitElement, nothing } from 'lit';
10
10
  import sinon from 'sinon';
11
11
  import {
12
12
  getFilteredOptionValues,
@@ -413,6 +413,54 @@ describe('lion-combobox', () => {
413
413
  expect(el.validationStates).to.have.property('error');
414
414
  expect(el.validationStates.error).to.have.property('MatchesOption');
415
415
  });
416
+
417
+ it('keeps slottable provided in `slots` getter as direct host child', async () => {
418
+ class MyEl extends SlotMixin(LionCombobox) {
419
+ // @ts-ignore
420
+ get slots() {
421
+ return {
422
+ ...super.slots,
423
+ _lazyRenderedSlot: () => ({
424
+ template: this.renderSlot
425
+ ? html`<span id="lazyRenderedSlotId">(Optional)</span>`
426
+ : html`${nothing}`,
427
+ renderAsDirectHostChild: true,
428
+ }),
429
+ };
430
+ }
431
+
432
+ _labelTemplate() {
433
+ return html`
434
+ <div class="form-field__label">
435
+ <slot name="label"></slot>
436
+ <slot name="_lazyRenderedSlot"></slot>
437
+ <slot></slot>
438
+ </div>
439
+ `;
440
+ }
441
+
442
+ constructor() {
443
+ super();
444
+ this.renderSlot = false;
445
+ }
446
+ }
447
+ const tagName = defineCE(MyEl);
448
+ const wrappingTag = unsafeStatic(tagName);
449
+
450
+ const el = /** @type {MyEl} */ (
451
+ await fixture(html`
452
+ <${wrappingTag} label="my label">
453
+ <lion-option .choiceValue="${'1'}">${'one'}</lion-option>
454
+ </${wrappingTag}>
455
+ `)
456
+ );
457
+ await el.registrationComplete;
458
+
459
+ el.renderSlot = true;
460
+ await el.updateComplete;
461
+ const lazyRenderedSlot = el.querySelector('#lazyRenderedSlotId');
462
+ expect(lazyRenderedSlot?.parentElement === el).to.be.true;
463
+ });
416
464
  });
417
465
 
418
466
  describe('Values', () => {
@@ -12,6 +12,58 @@ import { render } from 'lit';
12
12
  * @typedef {import('lit').LitElement} LitElement
13
13
  */
14
14
 
15
+ /**
16
+ * Sometimes, we want to provide best DX (direct slottables) and be accessible
17
+ * at the same time.
18
+ * In the first example below, we need to wrap our options in light dom in an element with
19
+ * [role=listbox]. We could achieve this via the second example, but it would affect our
20
+ * public api negatively. not allowing us to be forward compatible with the AOM spec:
21
+ * https://wicg.github.io/aom/explainer.html
22
+ * With this method, it's possible to watch elements in the default slot and move them
23
+ * to the desired target (the element with [role=listbox]) in light dom.
24
+ *
25
+ * @example
26
+ * # desired api
27
+ * <sel-ect>
28
+ * <opt-ion></opt-ion>
29
+ * </sel-ect>
30
+ * # desired end state
31
+ * <sel-ect>
32
+ * <div role="listbox" slot="lisbox">
33
+ * <opt-ion></opt-ion>
34
+ * </div>
35
+ * </sel-ect>
36
+ *
37
+ * Note, the function does not move the nodes specified by a subclasser in the `slots` getter
38
+ * @param {HTMLElement} source host of ShadowRoot with default <slot>
39
+ * @param {HTMLElement} target the desired target in light dom
40
+ */
41
+ export function moveUserProvidedDefaultSlottablesToTarget(source, target) {
42
+ /**
43
+ * Nodes injected via `slots` getter are going to be added as host's children
44
+ * starting by a comment node like <!--_start_slot_*-->
45
+ * and ending by a comment node like <!--_end_slot_*-->
46
+ * So we ignore everything that comes between those `start_slot` and `end_slot` comments
47
+ */
48
+ let isInsideSlotSection = false;
49
+ Array.from(source.childNodes).forEach((/** @type {* & Element} */ c) => {
50
+ const isNamedSlottable = c.hasAttribute && c.hasAttribute('slot');
51
+ const isComment = c.nodeType === Node.COMMENT_NODE;
52
+ if (isComment && !isInsideSlotSection) {
53
+ isInsideSlotSection = c.textContent.includes('_start_slot_');
54
+ }
55
+ if (isInsideSlotSection) {
56
+ if (c.textContent.includes('_end_slot_')) {
57
+ isInsideSlotSection = false;
58
+ }
59
+ return;
60
+ }
61
+ if (!isNamedSlottable) {
62
+ target.appendChild(c);
63
+ }
64
+ });
65
+ }
66
+
15
67
  /**
16
68
  * @param {SlotFunctionResult} slotFunctionResult
17
69
  * @returns {'template-result'|'node'|'slot-rerender-object'|null}
@@ -2,6 +2,7 @@ import { defineCE, expect, fixture, fixtureSync, unsafeStatic, html } from '@ope
2
2
  import { SlotMixin } from '@lion/ui/core.js';
3
3
  import { LitElement } from 'lit';
4
4
  import sinon from 'sinon';
5
+ import { moveUserProvidedDefaultSlottablesToTarget } from '../src/SlotMixin.js';
5
6
 
6
7
  import { ScopedElementsMixin, supportsScopedRegistry } from '../src/ScopedElementsMixin.js';
7
8
  import { isActiveElement } from '../test-helpers/isActiveElement.js';
@@ -134,6 +135,90 @@ describe('SlotMixin', () => {
134
135
  expect(elNoSlot.didCreateConditionalSlot()).to.be.false;
135
136
  });
136
137
 
138
+ it('should move default slots to target', async () => {
139
+ const target = document.createElement('div');
140
+ const source = document.createElement('div');
141
+ /**
142
+ * Exmple of usage:
143
+ * get slots() {
144
+ * return {
145
+ * _nothing: () => ({
146
+ * template: html`${nothing}`,
147
+ * renderAsDirectHostChild: true,
148
+ * }),
149
+ * }
150
+ * }
151
+ */
152
+ const variableNothing = `
153
+ <!--_start_slot_lit-el-->
154
+ <!-- {lit-el} -->
155
+ <!--_end_slot_lit-el-->`;
156
+
157
+ /**
158
+ * Exmple of usage:
159
+ * get slots() {
160
+ * return {
161
+ * '': () => ({
162
+ * template: html`<div>text<div>`,
163
+ * renderAsDirectHostChild: true,
164
+ * }),
165
+ * }
166
+ * }
167
+ */
168
+ const defaultSlottableProvidedViaSlotsGetter = `
169
+ <!--_start_slot_-->
170
+ <div>text</div>
171
+ <!--_end_slot_-->
172
+ `;
173
+
174
+ /**
175
+ * Exmple of usage:
176
+ * get slots() {
177
+ * return {
178
+ * label: () => ({
179
+ * template: html`<div>text<div>`,
180
+ * renderAsDirectHostChild: true,
181
+ * }),
182
+ * }
183
+ * }
184
+ */
185
+ const namedSlottable = `
186
+ <!--_start_slot_label-->
187
+ <div slot="label">text</div>
188
+ <!--_end_slot_label-->
189
+ `;
190
+
191
+ /**
192
+ * Here we assume .test1, .test2 and .test3 are the ones provided as content projection f.e.:
193
+ * <my-comp>
194
+ * <div class="test1"><div>
195
+ * <div class="test2"><div>
196
+ * <div class="test3"><div>
197
+ * </my-comp>
198
+ *
199
+ * And the rest of content is added via `slots` getter by SlotMixin
200
+ * The function should move only content projection and ignore the rest
201
+ * */
202
+
203
+ source.innerHTML = `
204
+ <div class="test1"></div>
205
+ ${variableNothing}
206
+ <div class="test2"></div>
207
+ ${defaultSlottableProvidedViaSlotsGetter}
208
+ <div class="test3"></div>
209
+ ${namedSlottable}
210
+ `;
211
+
212
+ moveUserProvidedDefaultSlottablesToTarget(source, target);
213
+ expect(target.children.length).to.equal(3);
214
+ const test1Element = target.querySelector('.test1');
215
+ const test2Element = target.querySelector('.test2');
216
+ const test3Element = target.querySelector('.test3');
217
+ expect(test1Element?.parentElement === target).to.equal(true);
218
+ expect(test2Element?.parentElement === target).to.equal(true);
219
+ expect(test3Element?.parentElement === target).to.equal(true);
220
+ });
221
+
137
222
  describe('Rerender', () => {
138
223
  it('supports rerender when SlotRerenderObject provided', async () => {
139
224
  const tag = defineCE(
@@ -1,4 +1,16 @@
1
- import { singletonManager } from 'singleton-manager';
1
+ import { singletonManager, lazifyInstantiation } from 'singleton-manager';
2
2
  import { IconManager } from './IconManager.js';
3
3
 
4
- export const icons = singletonManager.get('@lion/ui::icons::0.x') || new IconManager();
4
+ /**
5
+ * @returns {IconManager}
6
+ */
7
+ function getIconManager() {
8
+ if (!singletonManager.has('@lion/ui::icons::0.x')) {
9
+ const iconManager = new IconManager();
10
+ singletonManager.set('@lion/ui::icons::0.x', iconManager);
11
+ }
12
+
13
+ return singletonManager.get('@lion/ui::icons::0.x');
14
+ }
15
+
16
+ export const icons = lazifyInstantiation(getIconManager);
@@ -1,2 +1,5 @@
1
- export default /** @param {(strings: TemplateStringsArray, ... expr: string[]) => string} tag */ tag =>
2
- tag`<svg focusable="false" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" data-test-id="svg-hammer"><path d="M.476 12.915L6.7 6 9 8.556l-6.223 6.915a1.542 1.542 0 0 1-1.15.529 1.54 1.54 0 0 1-1.15-.53c-.636-.706-.636-1.85 0-2.555zm12.638-9.031L16 6.863 12.866 10 4 .919 9.35 0l1.912 1.972.251-.251c.52-.52 2.4 1.363 1.88 1.882l-.279.28z"></path></svg>`;
1
+ // @ts-nocheck
2
+ export default /** @type {import("lit").TemplateResult} */ (
3
+ tag =>
4
+ tag`<svg focusable="false" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" data-test-id="svg-hammer"><path d="M.476 12.915L6.7 6 9 8.556l-6.223 6.915a1.542 1.542 0 0 1-1.15.529 1.54 1.54 0 0 1-1.15-.53c-.636-.706-.636-1.85 0-2.555zm12.638-9.031L16 6.863 12.866 10 4 .919 9.35 0l1.912 1.972.251-.251c.52-.52 2.4 1.363 1.88 1.882l-.279.28z"></path></svg>`
5
+ );
@@ -1,2 +1,5 @@
1
- export default /** @param {(strings: TemplateStringsArray, ... expr: string[]) => string} tag */ tag =>
2
- tag`<svg focusable="false" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" data-test-id="svg-heart"><path d="M8.002 14.867a.828.828 0 0 1-.324-.066C7.36 14.665 0 11.466 0 6.153 0 3.592 1.543.825 4.98 1.01c1.465.077 2.437.828 3.018 1.491.581-.667 1.553-1.414 3.023-1.491.107-.008.207-.008.31-.008C13.58 1.001 16 2.614 16 6.153c0 5.313-7.36 8.512-7.671 8.644a.787.787 0 0 1-.327.07z"></path></svg>`;
1
+ // @ts-nocheck
2
+ export default /** @type {import("lit").TemplateResult} */ (
3
+ tag =>
4
+ tag`<svg focusable="false" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" data-test-id="svg-heart"><path d="M8.002 14.867a.828.828 0 0 1-.324-.066C7.36 14.665 0 11.466 0 6.153 0 3.592 1.543.825 4.98 1.01c1.465.077 2.437.828 3.018 1.491.581-.667 1.553-1.414 3.023-1.491.107-.008.207-.008.31-.008C13.58 1.001 16 2.614 16 6.153c0 5.313-7.36 8.512-7.671 8.644a.787.787 0 0 1-.327.07z"></path></svg>`
5
+ );
@@ -183,13 +183,19 @@ describe('lion-icon', () => {
183
183
  try {
184
184
  icons.addIconResolver(
185
185
  'foo',
186
- // eslint-disable-next-line no-promise-executor-return
187
- () => new Promise(resolve => setTimeout(() => resolve(heartSvg), 10)),
186
+ () =>
187
+ /** @type {Promise<TemplateResult>} */ (
188
+ // eslint-disable-next-line no-promise-executor-return
189
+ new Promise(resolve => setTimeout(() => resolve(heartSvg)))
190
+ ),
188
191
  );
189
192
  icons.addIconResolver(
190
193
  'bar',
191
- // eslint-disable-next-line no-promise-executor-return
192
- () => new Promise(resolve => setTimeout(() => resolve(hammerSvg), 4)),
194
+ () =>
195
+ /** @type {Promise<TemplateResult>} */ (
196
+ // eslint-disable-next-line no-promise-executor-return
197
+ new Promise(resolve => setTimeout(() => resolve(hammerSvg)))
198
+ ),
193
199
  );
194
200
  const el = await fixture(html`<lion-icon icon-id="foo:lorem:ipsum"></lion-icon>`);
195
201
 
@@ -94,8 +94,8 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
94
94
  step: this.step,
95
95
  };
96
96
 
97
- this.__increment = this.__increment.bind(this);
98
- this.__decrement = this.__decrement.bind(this);
97
+ this._increment = this._increment.bind(this);
98
+ this._decrement = this._decrement.bind(this);
99
99
  this._onEnterButton = this._onEnterButton.bind(this);
100
100
  this._onLeaveButton = this._onLeaveButton.bind(this);
101
101
  }
@@ -192,11 +192,11 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
192
192
  */
193
193
  __keyDownHandler(ev) {
194
194
  if (ev.key === 'ArrowUp') {
195
- this.__increment();
195
+ this._increment();
196
196
  }
197
197
 
198
198
  if (ev.key === 'ArrowDown') {
199
- this.__decrement();
199
+ this._decrement();
200
200
  }
201
201
  }
202
202
 
@@ -262,9 +262,9 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
262
262
 
263
263
  /**
264
264
  * Increment the value based on given step or default step value is 1
265
- * @private
265
+ * @protected
266
266
  */
267
- __increment() {
267
+ _increment() {
268
268
  const { step, min, max } = this.values;
269
269
  const stepMin = min !== Infinity ? min : 0;
270
270
 
@@ -284,9 +284,9 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
284
284
 
285
285
  /**
286
286
  * Decrement the value based on given step or default step value is 1
287
- * @private
287
+ * @protected
288
288
  */
289
- __decrement() {
289
+ _decrement() {
290
290
  const { step, max, min } = this.values;
291
291
  const stepMin = min !== Infinity ? min : 0;
292
292
 
@@ -379,7 +379,7 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
379
379
  return html`
380
380
  <button
381
381
  ?disabled=${this.disabled || this.readOnly}
382
- @click=${this.__decrement}
382
+ @click=${this._decrement}
383
383
  @focus=${this._onEnterButton}
384
384
  @blur=${this._onLeaveButton}
385
385
  type="button"
@@ -399,7 +399,7 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
399
399
  return html`
400
400
  <button
401
401
  ?disabled=${this.disabled || this.readOnly}
402
- @click=${this.__increment}
402
+ @click=${this._increment}
403
403
  @focus=${this._onEnterButton}
404
404
  @blur=${this._onLeaveButton}
405
405
  type="button"
@@ -4,6 +4,7 @@ import { dedupeMixin } from '@open-wc/dedupe-mixin';
4
4
  import { ChoiceGroupMixin, FormControlMixin, FormRegistrarMixin } from '@lion/ui/form-core.js';
5
5
  import { ScopedElementsMixin } from '../../core/src/ScopedElementsMixin.js';
6
6
  import { LionOptions } from './LionOptions.js';
7
+ import { moveUserProvidedDefaultSlottablesToTarget } from '../../core/src/SlotMixin.js';
7
8
 
8
9
  // TODO: extract ListNavigationWithActiveDescendantMixin that can be reused in [role="menu"]
9
10
  // having children with [role="menuitem|menuitemcheckbox|menuitemradio|option"] and
@@ -21,39 +22,6 @@ import { LionOptions } from './LionOptions.js';
21
22
 
22
23
  // TODO: consider adding methods below to @lion/helpers
23
24
 
24
- /**
25
- * Sometimes, we want to provide best DX (direct slottables) and be accessible
26
- * at the same time.
27
- * In the first example below, we need to wrap our options in light dom in an element with
28
- * [role=listbox]. We could achieve this via the second example, but it would affect our
29
- * public api negatively. not allowing us to be forward compatible with the AOM spec:
30
- * https://wicg.github.io/aom/explainer.html
31
- * With this method, it's possible to watch elements in the default slot and move them
32
- * to the desired target (the element with [role=listbox]) in light dom.
33
- *
34
- * @example
35
- * # desired api
36
- * <sel-ect>
37
- * <opt-ion></opt-ion>
38
- * </sel-ect>
39
- * # desired end state
40
- * <sel-ect>
41
- * <div role="listbox" slot="lisbox">
42
- * <opt-ion></opt-ion>
43
- * </div>
44
- * </sel-ect>
45
- * @param {HTMLElement} source host of ShadowRoot with default <slot>
46
- * @param {HTMLElement} target the desired target in light dom
47
- */
48
- function moveDefaultSlottablesToTarget(source, target) {
49
- Array.from(source.childNodes).forEach((/** @type {* & Element} */ c) => {
50
- const isNamedSlottable = c.hasAttribute && c.hasAttribute('slot');
51
- if (!isNamedSlottable) {
52
- target.appendChild(c);
53
- }
54
- });
55
- }
56
-
57
25
  /**
58
26
  * @type {ListboxMixin}
59
27
  * @param {import('@open-wc/dedupe-mixin').Constructor<import('lit').LitElement>} superclass
@@ -899,9 +867,9 @@ const ListboxMixinImplementation = superclass =>
899
867
  );
900
868
 
901
869
  if (slot) {
902
- moveDefaultSlottablesToTarget(this, this._listboxNode);
870
+ moveUserProvidedDefaultSlottablesToTarget(this, this._listboxNode);
903
871
  slot.addEventListener('slotchange', () => {
904
- moveDefaultSlottablesToTarget(this, this._listboxNode);
872
+ moveUserProvidedDefaultSlottablesToTarget(this, this._listboxNode);
905
873
  });
906
874
  }
907
875
  }
@@ -1,5 +1,5 @@
1
1
  // @ts-ignore
2
- import { singletonManager } from 'singleton-manager';
2
+ import { singletonManager, lazifyInstantiation } from 'singleton-manager';
3
3
  import { LocalizeManager } from './LocalizeManager.js';
4
4
 
5
5
  /**
@@ -57,18 +57,24 @@ import { LocalizeManager } from './LocalizeManager.js';
57
57
  * }
58
58
  * ```
59
59
  *
60
+ * @deprecated Use `localize` directly instead (as this is always side-effect free now)
61
+ *
60
62
  * @returns {LocalizeManager}
61
63
  */
62
- export function getLocalizeManager() {
63
- if (singletonManager.has('@lion/ui::localize::0.x')) {
64
- return singletonManager.get('@lion/ui::localize::0.x');
64
+ function getLocalizeManager() {
65
+ if (!singletonManager.has('@lion/ui::localize::0.x')) {
66
+ const localizeManager = new LocalizeManager({
67
+ autoLoadOnLocaleChange: true,
68
+ fallbackLocale: 'en-GB',
69
+ });
70
+ singletonManager.set('@lion/ui::localize::0.x', localizeManager);
65
71
  }
66
72
 
67
- const localizeManager = new LocalizeManager({
68
- autoLoadOnLocaleChange: true,
69
- fallbackLocale: 'en-GB',
70
- });
71
- singletonManager.set('@lion/ui::localize::0.x', localizeManager);
73
+ return singletonManager.get('@lion/ui::localize::0.x');
74
+ }
72
75
 
73
- return localizeManager;
76
+ function getLocalizeManagerLazily() {
77
+ return lazifyInstantiation(getLocalizeManager);
74
78
  }
79
+
80
+ export { getLocalizeManagerLazily as getLocalizeManager };
@@ -1,8 +1,10 @@
1
1
  import { expect } from '@open-wc/testing';
2
+ import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js';
2
3
  // @ts-ignore
3
4
  import { singletonManager } from 'singleton-manager';
4
5
  import { LocalizeManager } from '../src/LocalizeManager.js';
5
- import { getLocalizeManager } from '../src/getLocalizeManager.js';
6
+
7
+ /** @typedef {LocalizeManager & { __instance_for_testing?: LocalizeManager }} LocalizeManagerForTesting */
6
8
 
7
9
  describe('getLocalizeManager', () => {
8
10
  beforeEach(() => {
@@ -12,20 +14,26 @@ describe('getLocalizeManager', () => {
12
14
 
13
15
  it('gets a default instance when nothing registered on singletonManager with "@lion/ui::localize::0.x"', () => {
14
16
  expect(singletonManager.get('@lion/ui::localize::0.x')).to.be.undefined;
15
- const localizeManager = getLocalizeManager();
16
- expect(localizeManager).to.equal(singletonManager.get('@lion/ui::localize::0.x'));
17
+ const /** @type {LocalizeManagerForTesting} */ localizeManager = getLocalizeManager();
18
+ expect(localizeManager.__instance_for_testing).to.equal(
19
+ singletonManager.get('@lion/ui::localize::0.x'),
20
+ );
17
21
  });
18
22
 
19
23
  it('gets the same instance when called multiple times', () => {
20
- const localizeManager = getLocalizeManager();
21
- const localizeManagerSecondCall = getLocalizeManager();
22
- expect(localizeManager).to.equal(localizeManagerSecondCall);
24
+ const /** @type {LocalizeManagerForTesting} */ localizeManager = getLocalizeManager();
25
+ const /** @type {LocalizeManagerForTesting} */ localizeManagerSecondCall = getLocalizeManager();
26
+ expect(localizeManager.__instance_for_testing).not.to.be.undefined;
27
+ expect(localizeManager.__instance_for_testing).to.equal(
28
+ localizeManagerSecondCall.__instance_for_testing,
29
+ );
23
30
  });
24
31
 
25
32
  it('gets the instance that was registered on singletonManager with "@lion/ui::localize::0.x"', () => {
26
33
  // Set your own for custom behavior or for deduping purposes
27
34
  class MyLocalizeManager extends LocalizeManager {}
28
35
  singletonManager.set('@lion/ui::localize::0.x', MyLocalizeManager);
29
- expect(getLocalizeManager()).to.equal(MyLocalizeManager);
36
+ const /** @type {LocalizeManagerForTesting} */ localizeManager = getLocalizeManager();
37
+ expect(localizeManager.__instance_for_testing).to.equal(MyLocalizeManager);
30
38
  });
31
39
  });
@@ -5,6 +5,7 @@ import { singletonManager } from 'singleton-manager';
5
5
 
6
6
  /**
7
7
  * @typedef {import('../types/LocalizeMixinTypes.js').LocalizeMixin} LocalizeMixinHost
8
+ * @typedef {import('../../validate-messages/src/getLocalizedMessage.js').LocalizeManager & { __instance_for_testing?: import('../../validate-messages/src/getLocalizedMessage.js').LocalizeManager, aCallToRegisterLazilyLoadedInstance?: () => void }} LocalizeManagerForTesting
8
9
  */
9
10
 
10
11
  describe('Entrypoints localize', () => {
@@ -24,15 +25,20 @@ describe('Entrypoints localize', () => {
24
25
  });
25
26
 
26
27
  it('"@lion/ui/localize.js" has side effects (c.q. registers itself on singletonManager)', async () => {
27
- await import('@lion/ui/localize.js');
28
+ const /** @type {{ localize: LocalizeManagerForTesting }} */ { localize } = await import(
29
+ '@lion/ui/localize.js'
30
+ );
31
+ localize.aCallToRegisterLazilyLoadedInstance?.();
28
32
 
29
33
  expect(singletonManagerSetSpy).to.have.been.calledOnce;
30
34
 
31
- const { getLocalizeManager } = await import('@lion/ui/localize-no-side-effects.js');
35
+ const /** @type {{ getLocalizeManager: () => LocalizeManagerForTesting }} */ {
36
+ getLocalizeManager,
37
+ } = await import('@lion/ui/localize-no-side-effects.js');
32
38
 
33
39
  expect(singletonManagerSetSpy).to.have.been.calledWith(
34
40
  '@lion/ui::localize::0.x',
35
- getLocalizeManager(),
41
+ getLocalizeManager().__instance_for_testing,
36
42
  );
37
43
  });
38
44
  });
@@ -64,8 +64,11 @@ export const ArrowMixinImplementation = superclass =>
64
64
 
65
65
  [data-popper-placement^='left'] .arrow {
66
66
  right: calc(
67
- -1 * (var(--tooltip-arrow-height) +
68
- (var(--tooltip-arrow-width) - var(--tooltip-arrow-height)) / 2)
67
+ -1 *
68
+ (
69
+ var(--tooltip-arrow-height) +
70
+ (var(--tooltip-arrow-width) - var(--tooltip-arrow-height)) / 2
71
+ )
69
72
  );
70
73
  }
71
74
 
@@ -75,8 +78,11 @@ export const ArrowMixinImplementation = superclass =>
75
78
 
76
79
  [data-popper-placement^='right'] .arrow {
77
80
  left: calc(
78
- -1 * (var(--tooltip-arrow-height) +
79
- (var(--tooltip-arrow-width) - var(--tooltip-arrow-height)) / 2)
81
+ -1 *
82
+ (
83
+ var(--tooltip-arrow-height) +
84
+ (var(--tooltip-arrow-width) - var(--tooltip-arrow-height)) / 2
85
+ )
80
86
  );
81
87
  }
82
88