@fusion.dev/helix-headless 0.143.0 → 0.145.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 (314) hide show
  1. package/custom-elements.json +16990 -1383
  2. package/dist/accordion/item/accordion-item.d.ts +48 -12
  3. package/dist/accordion/item/accordion-item.js +26 -5
  4. package/dist/accordion/root/accordion-root.d.ts +6 -0
  5. package/dist/accordion/root/accordion-root.js +7 -1
  6. package/dist/announcement/root/announcement-root.d.ts +21 -1
  7. package/dist/announcement/root/announcement-root.js +36 -1
  8. package/dist/app-header/root/app-header-root.d.ts +7 -0
  9. package/dist/app-header/root/app-header-root.js +5 -1
  10. package/dist/app-header/sectioning.d.ts +7 -0
  11. package/dist/app-header/sectioning.js +26 -0
  12. package/dist/area-chart/root/area-chart-root.d.ts +12 -4
  13. package/dist/area-chart/root/area-chart-root.js +24 -7
  14. package/dist/avatar/root/avatar-root.d.ts +14 -0
  15. package/dist/avatar/root/avatar-root.js +23 -9
  16. package/dist/badge/root/badge-root.d.ts +11 -7
  17. package/dist/badge/root/badge-root.js +1 -1
  18. package/dist/bar-chart/root/bar-chart-root.d.ts +12 -3
  19. package/dist/bar-chart/root/bar-chart-root.js +17 -10
  20. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +32 -1
  21. package/dist/breadcrumbs/root/breadcrumbs-root.js +25 -2
  22. package/dist/button/root/button-root.d.ts +47 -1
  23. package/dist/button/root/button-root.js +38 -4
  24. package/dist/callout/root/callout-root.d.ts +18 -1
  25. package/dist/callout/root/callout-root.js +15 -4
  26. package/dist/canvas/root/canvas-root.d.ts +38 -3
  27. package/dist/canvas/root/canvas-root.js +121 -40
  28. package/dist/card/root/card-root.d.ts +30 -1
  29. package/dist/card/root/card-root.js +38 -5
  30. package/dist/carousel/root/carousel-root.d.ts +90 -0
  31. package/dist/carousel/root/carousel-root.js +134 -12
  32. package/dist/chat/composer/chat-composer.d.ts +38 -6
  33. package/dist/chat/composer/chat-composer.js +42 -9
  34. package/dist/chat/message/chat-message.d.ts +32 -1
  35. package/dist/chat/message/chat-message.js +25 -9
  36. package/dist/chat/naming.d.ts +22 -0
  37. package/dist/chat/naming.js +12 -0
  38. package/dist/chat/relative-clock.d.ts +39 -0
  39. package/dist/chat/relative-clock.js +31 -0
  40. package/dist/chat/root/chat-root.d.ts +36 -0
  41. package/dist/chat/root/chat-root.js +24 -1
  42. package/dist/checkbox/root/checkbox-root.js +2 -0
  43. package/dist/checkbox-group/root/checkbox-group-root.d.ts +53 -3
  44. package/dist/checkbox-group/root/checkbox-group-root.js +71 -22
  45. package/dist/code-block/lines.d.ts +13 -0
  46. package/dist/code-block/lines.js +2 -0
  47. package/dist/code-block/root/code-block-root.d.ts +38 -1
  48. package/dist/code-block/root/code-block-root.js +28 -7
  49. package/dist/color-input/root/color-input-root.d.ts +34 -1
  50. package/dist/color-input/root/color-input-root.js +23 -4
  51. package/dist/color-picker/channels.d.ts +26 -0
  52. package/dist/color-picker/channels.js +84 -0
  53. package/dist/color-picker/root/color-picker-root.d.ts +81 -5
  54. package/dist/color-picker/root/color-picker-root.js +103 -10
  55. package/dist/combobox/root/combobox-root.d.ts +38 -3
  56. package/dist/combobox/root/combobox-root.js +64 -2
  57. package/dist/command/root/command-root.d.ts +30 -4
  58. package/dist/command/root/command-root.js +33 -3
  59. package/dist/copy-button/from.d.ts +22 -0
  60. package/dist/copy-button/from.js +28 -0
  61. package/dist/copy-button/root/copy-button-root.d.ts +47 -1
  62. package/dist/copy-button/root/copy-button-root.js +44 -8
  63. package/dist/data-table/root/data-table-root.d.ts +150 -2
  64. package/dist/data-table/root/data-table-root.js +303 -29
  65. package/dist/data-table/tree.d.ts +40 -0
  66. package/dist/data-table/tree.js +55 -0
  67. package/dist/date-input/root/date-input-root.d.ts +73 -4
  68. package/dist/date-input/root/date-input-root.js +93 -43
  69. package/dist/date-picker/root/date-picker-root.d.ts +145 -1
  70. package/dist/date-picker/root/date-picker-root.js +239 -48
  71. package/dist/description-list/item/description-list-item.d.ts +17 -2
  72. package/dist/description-list/item/description-list-item.js +15 -2
  73. package/dist/description-list/root/description-list-root.d.ts +27 -1
  74. package/dist/description-list/root/description-list-root.js +26 -1
  75. package/dist/dialog/description.d.ts +9 -0
  76. package/dist/dialog/description.js +14 -0
  77. package/dist/dialog/root/dialog-root.d.ts +64 -1
  78. package/dist/dialog/root/dialog-root.js +49 -23
  79. package/dist/donut-chart/root/donut-chart-root.d.ts +25 -4
  80. package/dist/donut-chart/root/donut-chart-root.js +21 -6
  81. package/dist/drawer/root/drawer-root.d.ts +63 -2
  82. package/dist/drawer/root/drawer-root.js +95 -19
  83. package/dist/drawer/swipe-start.d.ts +9 -0
  84. package/dist/drawer/swipe-start.js +12 -0
  85. package/dist/drilldown/item/drilldown-item.d.ts +11 -6
  86. package/dist/drilldown/item/drilldown-item.js +8 -5
  87. package/dist/drilldown/root/drilldown-root.d.ts +11 -0
  88. package/dist/drilldown/root/drilldown-root.js +8 -3
  89. package/dist/element-events.generated.js +61 -13
  90. package/dist/empty/root/empty-root.d.ts +1 -1
  91. package/dist/file-input/root/file-input-root.d.ts +47 -0
  92. package/dist/file-input/root/file-input-root.js +60 -22
  93. package/dist/file-input/screen.d.ts +35 -0
  94. package/dist/file-input/screen.js +49 -0
  95. package/dist/filter-input/menu/filter-menu.d.ts +3 -0
  96. package/dist/filter-input/menu/filter-menu.js +8 -4
  97. package/dist/filter-input/root/filter-input-root.d.ts +38 -4
  98. package/dist/filter-input/root/filter-input-root.js +67 -3
  99. package/dist/filter-input/suggest.d.ts +17 -0
  100. package/dist/filter-input/suggest.js +23 -0
  101. package/dist/format-date/options.d.ts +33 -0
  102. package/dist/format-date/options.js +42 -0
  103. package/dist/format-date/root/format-date-root.d.ts +51 -0
  104. package/dist/format-date/root/format-date-root.js +58 -38
  105. package/dist/heatmap/root/heatmap-root.d.ts +23 -6
  106. package/dist/heatmap/root/heatmap-root.js +24 -13
  107. package/dist/icon/index.d.ts +2 -0
  108. package/dist/icon/index.js +2 -0
  109. package/dist/icon/registry.d.ts +37 -0
  110. package/dist/icon/registry.js +83 -0
  111. package/dist/icon/root/icon-root.d.ts +30 -4
  112. package/dist/icon/root/icon-root.js +41 -6
  113. package/dist/icon/root/index.d.ts +2 -0
  114. package/dist/icon/root/index.js +2 -0
  115. package/dist/icon/set.d.ts +1 -0
  116. package/dist/icon/set.js +3 -0
  117. package/dist/image/root/image-root.d.ts +14 -0
  118. package/dist/image/root/image-root.js +23 -2
  119. package/dist/input/root/input-root.d.ts +11 -0
  120. package/dist/input/root/input-root.js +16 -1
  121. package/dist/kbd/root/kbd-root.d.ts +20 -13
  122. package/dist/kbd/root/kbd-root.js +35 -37
  123. package/dist/kbd/shortcut.d.ts +18 -0
  124. package/dist/kbd/shortcut.js +35 -0
  125. package/dist/legend/hidden-series.d.ts +8 -0
  126. package/dist/legend/hidden-series.js +13 -0
  127. package/dist/legend/root/legend-root.d.ts +56 -0
  128. package/dist/legend/root/legend-root.js +54 -5
  129. package/dist/lightbox/item/lightbox-item.d.ts +15 -0
  130. package/dist/lightbox/item/lightbox-item.js +10 -1
  131. package/dist/lightbox/root/lightbox-root.d.ts +61 -1
  132. package/dist/lightbox/root/lightbox-root.js +94 -4
  133. package/dist/line-chart/root/line-chart-root.d.ts +11 -3
  134. package/dist/line-chart/root/line-chart-root.js +19 -5
  135. package/dist/list/item/list-item.d.ts +68 -1
  136. package/dist/list/item/list-item.js +66 -4
  137. package/dist/list/numbering.d.ts +14 -0
  138. package/dist/list/numbering.js +8 -0
  139. package/dist/list/root/list-root.d.ts +106 -9
  140. package/dist/list/root/list-root.js +189 -4
  141. package/dist/list/selection.d.ts +19 -0
  142. package/dist/list/selection.js +21 -0
  143. package/dist/listbox/root/listbox-root.d.ts +74 -3
  144. package/dist/listbox/root/listbox-root.js +86 -9
  145. package/dist/loader/busy.d.ts +17 -0
  146. package/dist/loader/busy.js +24 -0
  147. package/dist/loader/root/loader-root.d.ts +37 -0
  148. package/dist/loader/root/loader-root.js +52 -3
  149. package/dist/map/root/map-root.d.ts +6 -2
  150. package/dist/map/root/map-root.js +5 -2
  151. package/dist/megamenu/root/megamenu-root.d.ts +21 -0
  152. package/dist/megamenu/root/megamenu-root.js +16 -2
  153. package/dist/menu/index.d.ts +1 -0
  154. package/dist/menu/index.js +1 -0
  155. package/dist/menu/item/menu-item.d.ts +38 -11
  156. package/dist/menu/item/menu-item.js +33 -1
  157. package/dist/menu/root/menu-root.d.ts +25 -1
  158. package/dist/menu/root/menu-root.js +63 -6
  159. package/dist/menu/section/menu-section.d.ts +55 -0
  160. package/dist/menu/section/menu-section.js +60 -0
  161. package/dist/meter/root/meter-root.d.ts +7 -0
  162. package/dist/meter/root/meter-root.js +6 -3
  163. package/dist/navigation/root/navigation-root.d.ts +16 -1
  164. package/dist/navigation/root/navigation-root.js +27 -1
  165. package/dist/notifications/feed-keys.d.ts +10 -0
  166. package/dist/notifications/feed-keys.js +14 -0
  167. package/dist/notifications/notification/notification.d.ts +17 -0
  168. package/dist/notifications/notification/notification.js +21 -2
  169. package/dist/notifications/root/notifications-root.d.ts +60 -0
  170. package/dist/notifications/root/notifications-root.js +76 -1
  171. package/dist/number-input/root/number-input-root.d.ts +47 -0
  172. package/dist/number-input/root/number-input-root.js +58 -22
  173. package/dist/object-inspector/root/object-inspector-root.d.ts +98 -16
  174. package/dist/object-inspector/root/object-inspector-root.js +180 -80
  175. package/dist/object-inspector/rows.d.ts +57 -0
  176. package/dist/object-inspector/rows.js +86 -0
  177. package/dist/option/root/option-root.d.ts +54 -5
  178. package/dist/option/root/option-root.js +34 -5
  179. package/dist/outline/levels.d.ts +31 -0
  180. package/dist/outline/levels.js +23 -0
  181. package/dist/outline/root/outline-root.d.ts +68 -3
  182. package/dist/outline/root/outline-root.js +73 -8
  183. package/dist/pagination/size/pagination-size.d.ts +11 -2
  184. package/dist/pagination/size/pagination-size.js +19 -4
  185. package/dist/pin-input/format.d.ts +7 -0
  186. package/dist/pin-input/format.js +16 -0
  187. package/dist/pin-input/root/pin-input-root.d.ts +21 -0
  188. package/dist/pin-input/root/pin-input-root.js +29 -2
  189. package/dist/popover/root/popover-root.d.ts +62 -4
  190. package/dist/popover/root/popover-root.js +53 -5
  191. package/dist/progress/root/progress-root.d.ts +7 -0
  192. package/dist/progress/root/progress-root.js +9 -3
  193. package/dist/qr-code/export.d.ts +31 -0
  194. package/dist/qr-code/export.js +10 -0
  195. package/dist/qr-code/root/qr-code-root.d.ts +26 -0
  196. package/dist/qr-code/root/qr-code-root.js +49 -2
  197. package/dist/radio/group/radio-group.d.ts +17 -0
  198. package/dist/radio/group/radio-group.js +14 -1
  199. package/dist/rating/root/rating-root.d.ts +25 -0
  200. package/dist/rating/root/rating-root.js +46 -4
  201. package/dist/scatter-chart/root/scatter-chart-root.d.ts +17 -3
  202. package/dist/scatter-chart/root/scatter-chart-root.js +25 -7
  203. package/dist/scroll-area/root/scroll-area-root.d.ts +113 -0
  204. package/dist/scroll-area/root/scroll-area-root.js +218 -3
  205. package/dist/scroll-area/scrollbar.d.ts +65 -0
  206. package/dist/scroll-area/scrollbar.js +24 -0
  207. package/dist/select/root/select-root.d.ts +24 -0
  208. package/dist/select/root/select-root.js +21 -7
  209. package/dist/skeleton/root/skeleton-root.d.ts +25 -0
  210. package/dist/skeleton/root/skeleton-root.js +17 -2
  211. package/dist/slider/root/slider-root.d.ts +39 -0
  212. package/dist/slider/root/slider-root.js +45 -9
  213. package/dist/splitter/root/splitter-root.d.ts +13 -0
  214. package/dist/splitter/root/splitter-root.js +20 -2
  215. package/dist/splitter/snap.d.ts +9 -0
  216. package/dist/splitter/snap.js +12 -0
  217. package/dist/stat/root/stat-root.d.ts +2 -0
  218. package/dist/stat/root/stat-root.js +1 -1
  219. package/dist/steps/reach.d.ts +15 -0
  220. package/dist/steps/reach.js +12 -0
  221. package/dist/steps/root/steps-root.d.ts +30 -0
  222. package/dist/steps/root/steps-root.js +53 -0
  223. package/dist/steps/step/step.d.ts +39 -2
  224. package/dist/steps/step/step.js +29 -7
  225. package/dist/switch/root/switch-root.d.ts +12 -2
  226. package/dist/switch/root/switch-root.js +6 -1
  227. package/dist/table/column/table-column.d.ts +11 -0
  228. package/dist/table/column/table-column.js +6 -1
  229. package/dist/table/root/table-root.d.ts +101 -0
  230. package/dist/table/root/table-root.js +166 -5
  231. package/dist/table/row/table-row.d.ts +47 -1
  232. package/dist/table/row/table-row.js +39 -2
  233. package/dist/tabs/panel/tab-panel.d.ts +9 -5
  234. package/dist/tabs/panel/tab-panel.js +3 -4
  235. package/dist/tabs/root/tabs-root.d.ts +25 -1
  236. package/dist/tabs/root/tabs-root.js +21 -3
  237. package/dist/tabs/tab/tab.d.ts +36 -4
  238. package/dist/tabs/tab/tab.js +46 -3
  239. package/dist/tag/group/tag-group.d.ts +107 -0
  240. package/dist/tag/group/tag-group.js +157 -0
  241. package/dist/tag/index.d.ts +1 -0
  242. package/dist/tag/index.js +1 -0
  243. package/dist/tag/root/tag-root.d.ts +60 -0
  244. package/dist/tag/root/tag-root.js +74 -18
  245. package/dist/tag/selection.d.ts +10 -0
  246. package/dist/tag/selection.js +12 -0
  247. package/dist/textarea/grow.d.ts +22 -0
  248. package/dist/textarea/grow.js +20 -0
  249. package/dist/textarea/root/textarea-root.d.ts +9 -0
  250. package/dist/textarea/root/textarea-root.js +9 -1
  251. package/dist/time-input/root/time-input-root.d.ts +44 -5
  252. package/dist/time-input/root/time-input-root.js +69 -39
  253. package/dist/time-picker/root/time-picker-root.d.ts +54 -8
  254. package/dist/time-picker/root/time-picker-root.js +121 -91
  255. package/dist/timeline/group/timeline-group.d.ts +46 -0
  256. package/dist/timeline/group/timeline-group.js +37 -0
  257. package/dist/timeline/index.d.ts +1 -0
  258. package/dist/timeline/index.js +1 -0
  259. package/dist/timeline/root/timeline-root.d.ts +10 -3
  260. package/dist/toast/hotkey.d.ts +22 -0
  261. package/dist/toast/hotkey.js +23 -0
  262. package/dist/toast/item/toast-item.d.ts +26 -18
  263. package/dist/toast/item/toast-item.js +55 -48
  264. package/dist/toast/root/toast-root.d.ts +42 -8
  265. package/dist/toast/root/toast-root.js +64 -4
  266. package/dist/toggle/group/toggle-group.d.ts +57 -15
  267. package/dist/toggle/group/toggle-group.js +69 -9
  268. package/dist/toggle/root/toggle-root.d.ts +12 -1
  269. package/dist/toggle/root/toggle-root.js +11 -3
  270. package/dist/toolbar/root/toolbar-root.d.ts +13 -0
  271. package/dist/toolbar/root/toolbar-root.js +15 -5
  272. package/dist/tooltip/focus-target.d.ts +6 -0
  273. package/dist/tooltip/focus-target.js +9 -0
  274. package/dist/tooltip/root/tooltip-root.d.ts +42 -17
  275. package/dist/tooltip/root/tooltip-root.js +50 -9
  276. package/dist/tour/naming.d.ts +30 -0
  277. package/dist/tour/naming.js +10 -0
  278. package/dist/tour/root/tour-root.d.ts +35 -0
  279. package/dist/tour/root/tour-root.js +56 -5
  280. package/dist/tour/stop/tour-stop.d.ts +53 -8
  281. package/dist/tour/stop/tour-stop.js +45 -15
  282. package/dist/tour/wait.d.ts +11 -0
  283. package/dist/tour/wait.js +19 -0
  284. package/dist/tree/item/tree-item.d.ts +54 -1
  285. package/dist/tree/item/tree-item.js +89 -20
  286. package/dist/tree/root/tree-root.d.ts +37 -0
  287. package/dist/tree/root/tree-root.js +51 -6
  288. package/dist/tree/selection.d.ts +24 -0
  289. package/dist/tree/selection.js +26 -0
  290. package/dist/trend/root/trend-root.d.ts +13 -0
  291. package/dist/trend/root/trend-root.js +14 -9
  292. package/dist/video/media-events.d.ts +49 -0
  293. package/dist/video/media-events.js +39 -0
  294. package/dist/video/root/video-root.d.ts +99 -13
  295. package/dist/video/root/video-root.js +84 -47
  296. package/dist/video-playlist/menu/video-playlist-menu.d.ts +3 -0
  297. package/dist/video-playlist/menu/video-playlist-menu.js +2 -1
  298. package/dist/video-playlist/order.d.ts +41 -0
  299. package/dist/video-playlist/order.js +34 -0
  300. package/dist/video-playlist/root/video-playlist-root.d.ts +70 -2
  301. package/dist/video-playlist/root/video-playlist-root.js +60 -16
  302. package/dist/virtual-list/controls.d.ts +4 -0
  303. package/dist/virtual-list/controls.js +30 -0
  304. package/dist/virtual-list/fill.d.ts +30 -0
  305. package/dist/virtual-list/fill.js +39 -0
  306. package/dist/virtual-list/keys.d.ts +15 -0
  307. package/dist/virtual-list/keys.js +24 -0
  308. package/dist/virtual-list/root/virtual-list-root.d.ts +155 -23
  309. package/dist/virtual-list/root/virtual-list-root.js +175 -34
  310. package/lint.json +1 -1
  311. package/package.json +5 -5
  312. package/types/jsx.d.ts +8871 -1286
  313. package/types/svelte.d.ts +3 -0
  314. package/types/vue.d.ts +1918 -269
@@ -1,4 +1,4 @@
1
- import { HelixElement } from '@fusion.dev/helix-core';
1
+ import { HelixFormElement } from '@fusion.dev/helix-core';
2
2
  import { nothing, type PropertyValues, type TemplateResult } from 'lit';
3
3
  import '../../option/index.js';
4
4
  import '../../select/index.js';
@@ -28,6 +28,11 @@ import '../../select/index.js';
28
28
  * Re-querying and returning to page one is up to you, because only you know
29
29
  * whether the current position should be kept.
30
30
  *
31
+ * It takes part in a form. Give it a `name` and the size in force is submitted
32
+ * under that name, so a `GET` form carries it in the address beside the page.
33
+ * A form reset returns it to `default-value`, and `disabled`, or a disabled
34
+ * `<fieldset>` around it, turns the select off.
35
+ *
31
36
  * @since 0.1.0
32
37
  * @status stable
33
38
  * @aliases Page size, Rows per page
@@ -67,7 +72,7 @@ import '../../select/index.js';
67
72
  *
68
73
  * @cssstate empty - While there are no sizes to offer.
69
74
  */
70
- export declare class HelixHeadlessPaginationSize extends HelixElement {
75
+ export declare class HelixHeadlessPaginationSize extends HelixFormElement {
71
76
  /**
72
77
  * The size to start on when `value` is not set.
73
78
  */
@@ -115,6 +120,10 @@ export declare class HelixHeadlessPaginationSize extends HelixElement {
115
120
  * after it, and a refused size still sent it.
116
121
  */
117
122
  private readonly stopNative;
123
+ /** Returns to the size the markup declared, as a native `<select>` does on a reset. */
124
+ formResetCallback(): void;
125
+ /** Takes back the size a browser restores with the form, or the declared one. */
126
+ formStateRestoreCallback(state: string | File | FormData | null): void;
118
127
  protected willUpdate(changed: PropertyValues): void;
119
128
  /**
120
129
  * The control itself, which is the whole of this part, behind a seam the styled tier can move.
@@ -4,13 +4,13 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, formatNumbers, HelixBeforeChangeEvent, HelixElement, requestChange, } from '@fusion.dev/helix-core';
7
+ import { customElement, formatNumbers, HelixBeforeChangeEvent, HelixFormElement, requestChange, } from '@fusion.dev/helix-core';
8
8
  import { nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import { html } from 'lit/static-html.js';
11
11
  import '../../option/index.js';
12
12
  import '../../select/index.js';
13
- let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends HelixElement {
13
+ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends HelixFormElement {
14
14
  constructor() {
15
15
  super(...arguments);
16
16
  this.defaultValue = 0;
@@ -29,8 +29,8 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
29
29
  const previous = this.value;
30
30
  this.valueState = size;
31
31
  this.requestUpdate('value', previous);
32
- this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
33
- this.dispatchEvent(new Event('change', { bubbles: true, composed: false }));
32
+ this.announceInput();
33
+ this.announceChange();
34
34
  },
35
35
  event: (size) => new HelixBeforeChangeEvent({ value: String(size) }),
36
36
  host: this,
@@ -68,9 +68,23 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
68
68
  const options = this.options;
69
69
  return options.includes(this.value) ? this.value : (options[0] ?? 0);
70
70
  }
71
+ formResetCallback() {
72
+ super.formResetCallback();
73
+ const previous = this.value;
74
+ this.valueState = undefined;
75
+ this.requestUpdate('value', previous);
76
+ }
77
+ formStateRestoreCallback(state) {
78
+ const size = typeof state === 'string' ? Number.parseInt(state, 10) : Number.NaN;
79
+ const previous = this.value;
80
+ this.valueState = Number.isFinite(size) && size > 0 ? size : undefined;
81
+ this.requestUpdate('value', previous);
82
+ }
71
83
  willUpdate(changed) {
72
84
  super.willUpdate(changed);
73
85
  this.toggleState('empty', this.options.length === 0);
86
+ const current = this.current;
87
+ this.internals.setFormValue(current > 0 ? String(current) : null);
74
88
  }
75
89
  renderSelect() {
76
90
  const select = this.tag('select');
@@ -86,6 +100,7 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
86
100
  listbox-search-field: control-listbox-search-field, surface: control-surface,
87
101
  trigger: control-trigger, value: control-value"
88
102
  label=${this.label}
103
+ ?disabled=${this.isDisabled}
89
104
  .value=${String(this.current)}
90
105
  @helix-before-change=${this.handleChange}
91
106
  @input=${this.stopNative}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Where a `format` puts separators in a row of boxes: for each box, the text
3
+ * drawn after it, or nothing. `#` and `*` stand for a box and anything else is
4
+ * drawn, so `###-###` puts a dash after the third box. Web Awesome's OTP input
5
+ * takes the same shape.
6
+ */
7
+ export declare const separatorsAfter: (format: string, count: number) => string[];
@@ -0,0 +1,16 @@
1
+ export const separatorsAfter = (format, count) => {
2
+ const after = Array.from({ length: count }, () => '');
3
+ let box = -1;
4
+ for (const character of format) {
5
+ if (character === '#' || character === '*') {
6
+ box += 1;
7
+ if (box >= count) {
8
+ break;
9
+ }
10
+ }
11
+ else if (box >= 0 && box < count - 1) {
12
+ after[box] += character;
13
+ }
14
+ }
15
+ return after;
16
+ };
@@ -22,6 +22,12 @@ declare const HelixHeadlessPinInput_base: (new (...args: any[]) => import("@fusi
22
22
  * Only the first cell has `autocomplete="one-time-code"`, because the hint
23
23
  * applies to the whole field.
24
24
  *
25
+ * `autosubmit` submits the form once the last box is filled, through the form's
26
+ * default button where there is one. `format` draws separators between the
27
+ * boxes, such as the dash in `###-###`, as text a screen reader skips. Delete
28
+ * removes the character in the focused box and pulls the rest of the code
29
+ * back, as Backspace removes the one before it.
30
+ *
25
31
  * The row of cells always runs left to right, with `dir="ltr"`, including in
26
32
  * Arabic and Hebrew. The first box is the leftmost, a paste fills to the right,
27
33
  * and the right arrow moves to the next box. The label, hint, and feedback
@@ -47,11 +53,14 @@ declare const HelixHeadlessPinInput_base: (new (...args: any[]) => import("@fusi
47
53
  * @csspart field - The row of boxes, ordered left to right in every language.
48
54
  * @csspart hint - The help under the boxes, shown while there is no feedback.
49
55
  * @csspart label - The label above the boxes.
56
+ * @csspart separator - The text `format` draws between two boxes.
50
57
  *
51
58
  * @cssstate invalid - The control has an error to show, from the browser's validation or from your `feedback`.
52
59
  */
53
60
  export declare class HelixHeadlessPinInput extends HelixHeadlessPinInput_base {
54
61
  protected readonly aria: AriaForwardController;
62
+ /** @internal The element a missing name is checked on: the row of cells, so the name of one cell does not count as the name of the field. */
63
+ protected get namedControl(): HTMLElement | null;
55
64
  /** Typed or dragged, so every edit is announced. See `announcesInput`. */
56
65
  protected readonly announcesInput = true;
57
66
  /**
@@ -63,10 +72,22 @@ export declare class HelixHeadlessPinInput extends HelixHeadlessPinInput_base {
63
72
  * the same code is one offer made six times.
64
73
  */
65
74
  autocomplete: string;
75
+ /**
76
+ * Whether the form is submitted once the last box is filled, as Web
77
+ * Awesome's `autosubmit` and Radix's `autoSubmit`. Only for a code the field
78
+ * took: a refused last character submits nothing.
79
+ */
80
+ autosubmit: boolean;
66
81
  /**
67
82
  * Accessible name for one box, with `{index}` and `{length}` filled in.
68
83
  */
69
84
  cellLabel: string;
85
+ /**
86
+ * Separators drawn between the boxes: `#` or `*` for a box and anything
87
+ * else as it is written, so `###-###` draws a dash after the third. The
88
+ * separators are hidden from screen readers and are not part of the value.
89
+ */
90
+ format: string;
70
91
  /**
71
92
  * How many characters the code has.
72
93
  */
@@ -7,6 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { AriaForwardController, customElement, fillTemplate, HelixCompleteEvent, HelixFormElement, MixinControllerValue, MixinField, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
+ import { separatorsAfter } from '../format.js';
10
11
  let HelixHeadlessPinInput = class HelixHeadlessPinInput extends MixinControllerValue(MixinField(HelixFormElement)) {
11
12
  constructor() {
12
13
  super(...arguments);
@@ -15,7 +16,9 @@ let HelixHeadlessPinInput = class HelixHeadlessPinInput extends MixinControllerV
15
16
  });
16
17
  this.announcesInput = true;
17
18
  this.autocomplete = 'one-time-code';
19
+ this.autosubmit = false;
18
20
  this.cellLabel = 'Character {index} of {length}';
21
+ this.format = '';
19
22
  this.length = 6;
20
23
  this.mask = false;
21
24
  this.placeholder = '';
@@ -62,7 +65,16 @@ let HelixHeadlessPinInput = class HelixHeadlessPinInput extends MixinControllerV
62
65
  : event.key === 'End'
63
66
  ? Math.min(this.value.length, this.count - 1)
64
67
  : at + step;
65
- if (event.key === 'Backspace' && cell.value === '' && at > 0) {
68
+ if (event.key === 'Delete' && at < this.value.length) {
69
+ const characters = this.characters;
70
+ characters.splice(at, 1);
71
+ this.requestValue(characters.join('').replace(/\s+$/, ''));
72
+ this.updateComplete.then(() => {
73
+ this.paint();
74
+ this.cells[at]?.focus();
75
+ });
76
+ }
77
+ else if (event.key === 'Backspace' && cell.value === '' && at > 0) {
66
78
  const characters = this.characters;
67
79
  characters[at - 1] = '';
68
80
  this.requestValue(characters.join('').replace(/\s+$/, ''));
@@ -106,6 +118,9 @@ let HelixHeadlessPinInput = class HelixHeadlessPinInput extends MixinControllerV
106
118
  }
107
119
  };
108
120
  }
121
+ get namedControl() {
122
+ return this.partNamed('field');
123
+ }
109
124
  static { this.shadowRootOptions = {
110
125
  ...HelixFormElement.shadowRootOptions,
111
126
  delegatesFocus: true,
@@ -149,6 +164,9 @@ let HelixHeadlessPinInput = class HelixHeadlessPinInput extends MixinControllerV
149
164
  if (applied && this.value === next && next.length === this.count) {
150
165
  this.dispatchEvent(new HelixCompleteEvent({ value: next }));
151
166
  this.commit();
167
+ if (this.autosubmit) {
168
+ this.submitImplicitly();
169
+ }
152
170
  }
153
171
  });
154
172
  }
@@ -213,6 +231,7 @@ let HelixHeadlessPinInput = class HelixHeadlessPinInput extends MixinControllerV
213
231
  }
214
232
  render() {
215
233
  const characters = this.characters;
234
+ const separators = separatorsAfter(this.format, this.count);
216
235
  return html `${this.renderGroupLabel()}
217
236
  <div
218
237
  dir="ltr"
@@ -239,7 +258,9 @@ let HelixHeadlessPinInput = class HelixHeadlessPinInput extends MixinControllerV
239
258
  @keydown=${this.handleKeydown}
240
259
  @keypress=${this.handleKeypress}
241
260
  @paste=${this.handlePaste}
242
- />`)}
261
+ />${separators[at]
262
+ ? html `<span part="separator" aria-hidden="true">${separators[at]}</span>`
263
+ : nothing}`)}
243
264
  </div>
244
265
  ${this.renderHint()}${this.renderFeedback()}`;
245
266
  }
@@ -247,9 +268,15 @@ let HelixHeadlessPinInput = class HelixHeadlessPinInput extends MixinControllerV
247
268
  __decorate([
248
269
  property()
249
270
  ], HelixHeadlessPinInput.prototype, "autocomplete", void 0);
271
+ __decorate([
272
+ property({ type: Boolean })
273
+ ], HelixHeadlessPinInput.prototype, "autosubmit", void 0);
250
274
  __decorate([
251
275
  property({ attribute: 'cell-label' })
252
276
  ], HelixHeadlessPinInput.prototype, "cellLabel", void 0);
277
+ __decorate([
278
+ property()
279
+ ], HelixHeadlessPinInput.prototype, "format", void 0);
253
280
  __decorate([
254
281
  property({ type: Number })
255
282
  ], HelixHeadlessPinInput.prototype, "length", void 0);
@@ -21,9 +21,28 @@ declare const HelixHeadlessPopover_base: (new (...args: any[]) => import("@fusio
21
21
  * commands work as they do on `Dialog` and `Drawer`, so a button anywhere on
22
22
  * the page can open the popover with no script.
23
23
  *
24
- * It closes on Escape, on a press outside it, and when focus moves out of the
25
- * trigger and the panel to somewhere else on the page. It does not trap focus.
26
- * An `aria-labelledby` on the host names the panel in place of `label`.
24
+ * **Opening moves focus into the panel**, to the first control in it, or to the
25
+ * panel itself where it holds none, and closing from inside gives it back to
26
+ * the trigger. It closes on Escape, on a press outside it, and when focus moves
27
+ * out of the trigger and the panel to somewhere else on the page.
28
+ *
29
+ * `modal` keeps `Tab` inside the panel while it is open and says so with
30
+ * `aria-modal`, for a panel that has to be answered before the page goes on.
31
+ * Without it the popover does not trap focus.
32
+ *
33
+ * The panel's name is `label` when you set it. Otherwise it is the first
34
+ * heading in the panel, or the elements an `aria-labelledby` on the host names.
35
+ *
36
+ * `arrow` draws a point on the panel's edge facing the trigger. The side the
37
+ * panel landed on is on the host as `:state(placed-top)` and its kin, and the
38
+ * trigger's width is on the panel as `--floating-anchor-inline-size`, for a
39
+ * panel as wide as its trigger:
40
+ *
41
+ * ```css
42
+ * helix-popover::part(popover) {
43
+ * min-inline-size: var(--floating-anchor-inline-size);
44
+ * }
45
+ * ```
27
46
  *
28
47
  * @since 0.1.0
29
48
  * @status stable
@@ -38,16 +57,38 @@ declare const HelixHeadlessPopover_base: (new (...args: any[]) => import("@fusio
38
57
  * @event {HelixBeforeOpenEvent} helix-before-open - Fired before it opens, and cancelable.
39
58
  * @event {ToggleEvent} toggle - Fired after the panel opens or closes, with `newState` and `oldState`.
40
59
  *
60
+ * @csspart arrow - The point on the panel's edge facing the trigger, drawn with `arrow`.
61
+ * @csspart arrow-bottom - Added to `arrow` while the panel is below its trigger, with the point on the panel's top edge.
62
+ * @csspart arrow-left - Added to `arrow` while the panel is left of its trigger, with the point on the panel's right edge.
63
+ * @csspart arrow-right - Added to `arrow` while the panel is right of its trigger, with the point on the panel's left edge.
64
+ * @csspart arrow-top - Added to `arrow` while the panel is above its trigger, with the point on the panel's bottom edge.
41
65
  * @csspart content - The scrolling region inside the panel.
42
66
  * @csspart popover - The panel.
43
67
  *
44
68
  * @cssstate open - While the popover is open.
69
+ * @cssstate placed-bottom - While the panel sits below its trigger.
70
+ * @cssstate placed-left - While the panel sits to the left of its trigger.
71
+ * @cssstate placed-right - While the panel sits to the right of its trigger.
72
+ * @cssstate placed-top - While the panel sits above its trigger.
45
73
  */
46
74
  export declare class HelixHeadlessPopover extends HelixHeadlessPopover_base {
47
75
  /**
48
- * The panel's name, read by screen readers.
76
+ * Draws a point on the panel's edge facing the trigger.
77
+ *
78
+ * Off by default, which is the house style: a panel that opens from its
79
+ * trigger already reads as belonging to it.
80
+ */
81
+ arrow: boolean;
82
+ /**
83
+ * The panel's name, read by screen readers. Left at `Popover`, the first
84
+ * heading in the panel names it instead.
49
85
  */
50
86
  label: string;
87
+ /**
88
+ * Keeps `Tab` inside the panel while it is open, and marks the panel
89
+ * `aria-modal`. A press outside and Escape still close it.
90
+ */
91
+ modal: boolean;
51
92
  protected readonly aria: AriaForwardController;
52
93
  /**
53
94
  * Space between the trigger and the panel, in pixels.
@@ -60,6 +101,23 @@ export declare class HelixHeadlessPopover extends HelixHeadlessPopover_base {
60
101
  */
61
102
  placement: Placement;
62
103
  private readonly panel;
104
+ /**
105
+ * The side of its trigger the panel last landed on, which names the arrow's
106
+ * second part. Undefined until the first placement, which the server never
107
+ * makes.
108
+ */
109
+ private side?;
110
+ private readonly scope;
111
+ /** What is assigned to the panel's slot. */
112
+ private get slotted();
113
+ /** Whether the first heading in the panel is what names it. */
114
+ private namedByHeading;
115
+ /**
116
+ * Names the panel by its first heading, where `label` was left alone and no
117
+ * `aria-labelledby` on the host names it. An element reference, for the
118
+ * reason `Dialog` gives.
119
+ */
120
+ private nameByHeading;
63
121
  /**
64
122
  * The invoker that last opened the panel, when a command did.
65
123
  *
@@ -4,13 +4,15 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { AriaForwardController, anchorElement, CommandController, customElement, deepActiveElement, HelixElement, MixinControllerOpen, PopoverController, tellDisclosure, } from '@fusion.dev/helix-core';
8
- import { html } from 'lit';
9
- import { property } from 'lit/decorators.js';
7
+ import { AriaForwardController, anchorElement, arrowReach, CommandController, customElement, deepActiveElement, FocusScopeController, HelixElement, headingIn, MixinControllerOpen, PopoverController, reflectElements, sideOf, tellDisclosure, } from '@fusion.dev/helix-core';
8
+ import { html, nothing } from 'lit';
9
+ import { property, state } from 'lit/decorators.js';
10
10
  let HelixHeadlessPopover = class HelixHeadlessPopover extends MixinControllerOpen(HelixElement) {
11
11
  constructor() {
12
12
  super(...arguments);
13
+ this.arrow = false;
13
14
  this.label = 'Popover';
15
+ this.modal = false;
14
16
  this.aria = new AriaForwardController(this, {
15
17
  target: () => this.partNamed('popover'),
16
18
  });
@@ -18,13 +20,28 @@ let HelixHeadlessPopover = class HelixHeadlessPopover extends MixinControllerOpe
18
20
  this.placement = 'bottom-start';
19
21
  this.panel = new PopoverController(this, {
20
22
  anchor: () => this.trigger,
23
+ arrow: () => this.partNamed('arrow'),
21
24
  boundary: () => [this, this.invoker],
22
- offset: () => this.offset,
25
+ offset: () => this.offset + arrowReach(this.partNamed('arrow')),
23
26
  onDismiss: () => this.hide(),
27
+ onPlace: (placement) => {
28
+ const side = sideOf(placement);
29
+ this.toggleState('placed-bottom', side === 'bottom');
30
+ this.toggleState('placed-left', side === 'left');
31
+ this.toggleState('placed-right', side === 'right');
32
+ this.toggleState('placed-top', side === 'top');
33
+ this.side = side;
34
+ },
24
35
  open: () => this.open,
25
36
  placement: () => this.placement,
26
37
  surface: () => this.partNamed('popover'),
27
38
  });
39
+ this.scope = new FocusScopeController(this, {
40
+ contain: () => this.modal && this.open,
41
+ contents: () => this.slotted,
42
+ surface: () => this.partNamed('popover'),
43
+ });
44
+ this.namedByHeading = false;
28
45
  this.commands = new CommandController(this, {
29
46
  commands: {
30
47
  '--close': () => this.hide(),
@@ -62,6 +79,16 @@ let HelixHeadlessPopover = class HelixHeadlessPopover extends MixinControllerOpe
62
79
  }
63
80
  };
64
81
  }
82
+ get slotted() {
83
+ return (this.renderRoot
84
+ ?.querySelector('slot:not([name])')
85
+ ?.assignedElements({ flatten: true }) ?? []);
86
+ }
87
+ nameByHeading() {
88
+ const asked = this.label !== 'Popover' || this.hasAttribute('aria-labelledby');
89
+ const heading = asked ? null : headingIn(this.slotted);
90
+ this.namedByHeading = reflectElements(this.partNamed('popover'), 'ariaLabelledByElements', heading ? [heading] : [], this.namedByHeading);
91
+ }
65
92
  get trigger() {
66
93
  return (this.invoker ??
67
94
  anchorElement(this.renderRoot?.querySelector('slot[name="trigger"]'), this));
@@ -95,6 +122,10 @@ let HelixHeadlessPopover = class HelixHeadlessPopover extends MixinControllerOpe
95
122
  updated(changed) {
96
123
  super.updated(changed);
97
124
  this.tellTrigger();
125
+ this.nameByHeading();
126
+ if (changed.has('open') && this.open && changed.get('open') === false) {
127
+ this.scope.enter();
128
+ }
98
129
  }
99
130
  render() {
100
131
  return html `<slot name="trigger" @click=${this.handleTriggerClick}></slot>
@@ -103,21 +134,38 @@ let HelixHeadlessPopover = class HelixHeadlessPopover extends MixinControllerOpe
103
134
  popover="manual"
104
135
  role="dialog"
105
136
  aria-label=${this.label}
137
+ aria-modal=${this.modal ? 'true' : nothing}
138
+ tabindex="-1"
106
139
  ?hidden=${!this.open}
107
140
  >
108
- <div part="content"><slot></slot></div>
141
+ ${this.arrow
142
+ ? html `<div
143
+ part="arrow${this.side ? { bottom: ' arrow-bottom', left: ' arrow-left', right: ' arrow-right', top: ' arrow-top' }[this.side] : ''}"
144
+ aria-hidden="true"
145
+ ></div>`
146
+ : nothing}
147
+ <div part="content"><slot @slotchange=${this.nameByHeading}></slot></div>
109
148
  </div>`;
110
149
  }
111
150
  };
151
+ __decorate([
152
+ property({ type: Boolean })
153
+ ], HelixHeadlessPopover.prototype, "arrow", void 0);
112
154
  __decorate([
113
155
  property()
114
156
  ], HelixHeadlessPopover.prototype, "label", void 0);
157
+ __decorate([
158
+ property({ type: Boolean })
159
+ ], HelixHeadlessPopover.prototype, "modal", void 0);
115
160
  __decorate([
116
161
  property({ type: Number })
117
162
  ], HelixHeadlessPopover.prototype, "offset", void 0);
118
163
  __decorate([
119
164
  property()
120
165
  ], HelixHeadlessPopover.prototype, "placement", void 0);
166
+ __decorate([
167
+ state()
168
+ ], HelixHeadlessPopover.prototype, "side", void 0);
121
169
  HelixHeadlessPopover = __decorate([
122
170
  customElement('helix-headless-popover')
123
171
  ], HelixHeadlessPopover);
@@ -21,6 +21,8 @@ import { type PropertyValues, type TemplateResult } from 'lit';
21
21
  * @aliases Progress bar, Loading bar
22
22
  * @documentation https://fusion.dev/helix/components/progress
23
23
  *
24
+ * @slot label - A visible label. Its words name the progress bar in place of `label`.
25
+ *
24
26
  * @csspart groove - The unfilled circle under the ring's filled arc.
25
27
  * @csspart indicator - The filled part that shows the work done.
26
28
  * @csspart track - The full length the work is measured against.
@@ -46,6 +48,9 @@ export declare class HelixHeadlessProgress extends HelixElement {
46
48
  indeterminate: boolean;
47
49
  /**
48
50
  * Accessible name for what is in progress.
51
+ *
52
+ * A visible label in the `label` slot names it instead, with the words it
53
+ * shows, so the name and the label cannot disagree.
49
54
  */
50
55
  label: string;
51
56
  /**
@@ -114,6 +119,8 @@ export declare class HelixHeadlessProgress extends HelixElement {
114
119
  /** What is done, as a fraction of the whole, between 0 and 1. */
115
120
  get fraction(): number;
116
121
  protected willUpdate(changed: PropertyValues): void;
122
+ /** A label's words changed, so the name is written again. */
123
+ private readonly renamed;
117
124
  protected render(): TemplateResult;
118
125
  }
119
126
  declare global {
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, HelixElement, hostAria } from '@fusion.dev/helix-core';
7
+ import { customElement, HelixElement, hostAria, slottedWords } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  const percents = new Map();
@@ -30,6 +30,9 @@ let HelixHeadlessProgress = class HelixHeadlessProgress extends HelixElement {
30
30
  this.showValue = false;
31
31
  this.value = 0;
32
32
  this.valueText = '';
33
+ this.renamed = () => {
34
+ this.requestUpdate();
35
+ };
33
36
  }
34
37
  get range() {
35
38
  const min = Number.isFinite(this.min) ? this.min : 0;
@@ -41,7 +44,10 @@ let HelixHeadlessProgress = class HelixHeadlessProgress extends HelixElement {
41
44
  }
42
45
  willUpdate(changed) {
43
46
  super.willUpdate(changed);
44
- hostAria(this.internals, { label: this.label, role: 'progressbar' });
47
+ hostAria(this.internals, {
48
+ label: slottedWords(this, ['label']) || this.label,
49
+ role: 'progressbar',
50
+ });
45
51
  const { max, min } = this.range;
46
52
  this.internals.ariaValueMin = String(min);
47
53
  this.internals.ariaValueMax = String(max);
@@ -56,7 +62,7 @@ let HelixHeadlessProgress = class HelixHeadlessProgress extends HelixElement {
56
62
  <circle part="groove" />
57
63
  <circle part="indicator" pathLength="100" style="--progress-fraction: ${fraction}" />
58
64
  </svg>`;
59
- return html `${this.shape === 'ring'
65
+ return html `<slot name="label" @slotchange=${this.renamed}></slot>${this.shape === 'ring'
60
66
  ? ring
61
67
  : html `<div part="track">
62
68
  <div part="indicator" style="--progress-fraction: ${fraction}"></div>
@@ -0,0 +1,31 @@
1
+ /**
2
+ * A drawn code as a file of its own: an SVG with its colors written in, which
3
+ * an image can load and a canvas can turn into a PNG.
4
+ *
5
+ * Beside the family's `index.ts`, because writing a file is not the element's
6
+ * template, and the markup is a pure function of what the element drew.
7
+ */
8
+ /** What a code is drawn with, read from the element once it has rendered. */
9
+ export interface QrDrawing {
10
+ /** The fill behind the code, quiet zone included. */
11
+ background: string;
12
+ /** The side of the `viewBox`, quiet zone included. */
13
+ box: number;
14
+ /** The color of the corner squares. */
15
+ finderColor: string;
16
+ /** The path of the corner squares. */
17
+ finders: string;
18
+ /** The color of every other module. */
19
+ moduleColor: string;
20
+ /** The path of every other module. */
21
+ modules: string;
22
+ /** The quiet zone, in modules, that both paths are moved in by. */
23
+ quiet: number;
24
+ }
25
+ /**
26
+ * The code as standalone SVG markup, sized `size` pixels square.
27
+ *
28
+ * The background is a rectangle under the code, since a scanner needs the
29
+ * light quiet zone and a transparent file put on a dark page has none.
30
+ */
31
+ export declare const qrSvg: (drawing: QrDrawing, size: number) => string;
@@ -0,0 +1,10 @@
1
+ const attribute = (value) => value.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;');
2
+ export const qrSvg = (drawing, size) => {
3
+ const shift = `translate(${drawing.quiet} ${drawing.quiet})`;
4
+ return (`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${drawing.box} ${drawing.box}"` +
5
+ ` width="${size}" height="${size}" shape-rendering="crispEdges">` +
6
+ `<rect width="${drawing.box}" height="${drawing.box}" fill="${attribute(drawing.background)}"/>` +
7
+ `<path d="${attribute(drawing.modules)}" transform="${shift}" fill="${attribute(drawing.moduleColor)}"/>` +
8
+ `<path d="${attribute(drawing.finders)}" transform="${shift}" fill="${attribute(drawing.finderColor)}"/>` +
9
+ '</svg>');
10
+ };
@@ -30,6 +30,10 @@ export type QrStyle = 'dots' | 'rounded' | 'square';
30
30
  * long once a logo raises the level to `H`. A value too long for the level
31
31
  * draws no code, and the element fires `error`.
32
32
  *
33
+ * `toSvg()`, `toPng()` and `download()` give the drawn code as a file of its
34
+ * own, in the colors it is drawn in, for a page that offers it to save or
35
+ * print, as Zag's download trigger does.
36
+ *
33
37
  * @since 0.1.0
34
38
  * @status stable
35
39
  * @category media
@@ -103,6 +107,28 @@ export declare class HelixHeadlessQrCode extends HelixElement {
103
107
  */
104
108
  private encoded;
105
109
  protected updated(changed: PropertyValues): void;
110
+ /**
111
+ * The code as an SVG file of its own, `size` pixels square, in the colors it
112
+ * is drawn in, with its background under the quiet zone.
113
+ *
114
+ * `''` where no code is drawn, before the first render or for a value too
115
+ * long for the level. A slotted logo is not in the file, being the page's
116
+ * own markup; save the file at `H` and the code still scans without it.
117
+ */
118
+ toSvg(size?: number): string;
119
+ /**
120
+ * The code as a PNG, `size` pixels square, drawn from `toSvg()`.
121
+ *
122
+ * `null` where no code is drawn.
123
+ */
124
+ toPng(size?: number): Promise<Blob | null>;
125
+ /**
126
+ * Saves the code as a PNG named `filename`, `size` pixels square.
127
+ *
128
+ * Call it from a press, since a browser lets a page start a download only
129
+ * in answer to one. Does nothing where no code is drawn.
130
+ */
131
+ download(filename?: string, size?: number): Promise<void>;
106
132
  private renderCode;
107
133
  protected render(): TemplateResult;
108
134
  }