@syware/jlib 0.0.0-stage → 0.1.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 (331) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +133 -2
  3. package/dist/all.d.ts +1 -0
  4. package/dist/all.js +75 -0
  5. package/dist/atoms/jl-avatar.css_raw.js +3 -0
  6. package/dist/atoms/jl-avatar.d.ts +52 -0
  7. package/dist/atoms/jl-avatar.js +167 -0
  8. package/dist/atoms/jl-badge.css_raw.js +3 -0
  9. package/dist/atoms/jl-badge.d.ts +32 -0
  10. package/dist/atoms/jl-badge.js +60 -0
  11. package/dist/atoms/jl-button.css_raw.js +3 -0
  12. package/dist/atoms/jl-button.d.ts +70 -0
  13. package/dist/atoms/jl-button.js +146 -0
  14. package/dist/atoms/jl-checkbox.css_raw.js +3 -0
  15. package/dist/atoms/jl-checkbox.d.ts +61 -0
  16. package/dist/atoms/jl-checkbox.js +149 -0
  17. package/dist/atoms/jl-chip.css_raw.js +3 -0
  18. package/dist/atoms/jl-chip.d.ts +59 -0
  19. package/dist/atoms/jl-chip.js +164 -0
  20. package/dist/atoms/jl-divider.css_raw.js +3 -0
  21. package/dist/atoms/jl-divider.d.ts +26 -0
  22. package/dist/atoms/jl-divider.js +59 -0
  23. package/dist/atoms/jl-icon.css_raw.js +3 -0
  24. package/dist/atoms/jl-icon.d.ts +25 -0
  25. package/dist/atoms/jl-icon.js +41 -0
  26. package/dist/atoms/jl-input.css_raw.js +3 -0
  27. package/dist/atoms/jl-input.d.ts +112 -0
  28. package/dist/atoms/jl-input.js +202 -0
  29. package/dist/atoms/jl-kbd.css_raw.js +3 -0
  30. package/dist/atoms/jl-kbd.d.ts +17 -0
  31. package/dist/atoms/jl-kbd.js +62 -0
  32. package/dist/atoms/jl-link.css_raw.js +3 -0
  33. package/dist/atoms/jl-link.d.ts +37 -0
  34. package/dist/atoms/jl-link.js +86 -0
  35. package/dist/atoms/jl-progress-ring.css_raw.js +3 -0
  36. package/dist/atoms/jl-progress-ring.d.ts +49 -0
  37. package/dist/atoms/jl-progress-ring.js +132 -0
  38. package/dist/atoms/jl-progress.css_raw.js +3 -0
  39. package/dist/atoms/jl-progress.d.ts +43 -0
  40. package/dist/atoms/jl-progress.js +109 -0
  41. package/dist/atoms/jl-rating.css_raw.js +3 -0
  42. package/dist/atoms/jl-rating.d.ts +73 -0
  43. package/dist/atoms/jl-rating.js +184 -0
  44. package/dist/atoms/jl-select.css_raw.js +3 -0
  45. package/dist/atoms/jl-select.d.ts +70 -0
  46. package/dist/atoms/jl-select.js +146 -0
  47. package/dist/atoms/jl-skeleton.css_raw.js +3 -0
  48. package/dist/atoms/jl-skeleton.d.ts +34 -0
  49. package/dist/atoms/jl-skeleton.js +63 -0
  50. package/dist/atoms/jl-slider.css_raw.js +3 -0
  51. package/dist/atoms/jl-slider.d.ts +65 -0
  52. package/dist/atoms/jl-slider.js +143 -0
  53. package/dist/atoms/jl-spinner.css_raw.js +3 -0
  54. package/dist/atoms/jl-spinner.d.ts +16 -0
  55. package/dist/atoms/jl-spinner.js +26 -0
  56. package/dist/atoms/jl-switch.css_raw.js +3 -0
  57. package/dist/atoms/jl-switch.d.ts +57 -0
  58. package/dist/atoms/jl-switch.js +125 -0
  59. package/dist/atoms/jl-textarea.css_raw.js +3 -0
  60. package/dist/atoms/jl-textarea.d.ts +81 -0
  61. package/dist/atoms/jl-textarea.js +148 -0
  62. package/dist/base/jl-element.d.ts +16 -0
  63. package/dist/base/jl-element.js +35 -0
  64. package/dist/base/jl-form-control.d.ts +29 -0
  65. package/dist/base/jl-form-control.js +44 -0
  66. package/dist/index.d.ts +119 -0
  67. package/dist/index.js +72 -0
  68. package/dist/lib/arrow.d.ts +6 -0
  69. package/dist/lib/arrow.js +15 -0
  70. package/dist/lib/attributes.d.ts +9 -0
  71. package/dist/lib/attributes.js +22 -0
  72. package/dist/lib/avatar.d.ts +11 -0
  73. package/dist/lib/avatar.js +37 -0
  74. package/dist/lib/calendar.d.ts +48 -0
  75. package/dist/lib/calendar.js +166 -0
  76. package/dist/lib/css-length.d.ts +2 -0
  77. package/dist/lib/css-length.js +8 -0
  78. package/dist/lib/define.d.ts +9 -0
  79. package/dist/lib/define.js +9 -0
  80. package/dist/lib/dom.d.ts +4 -0
  81. package/dist/lib/dom.js +16 -0
  82. package/dist/lib/files.d.ts +18 -0
  83. package/dist/lib/files.js +89 -0
  84. package/dist/lib/floating.d.ts +13 -0
  85. package/dist/lib/floating.js +127 -0
  86. package/dist/lib/fuzzy.d.ts +26 -0
  87. package/dist/lib/fuzzy.js +149 -0
  88. package/dist/lib/highlight.d.ts +5 -0
  89. package/dist/lib/highlight.js +267 -0
  90. package/dist/lib/hotkey.d.ts +9 -0
  91. package/dist/lib/hotkey.js +101 -0
  92. package/dist/lib/icon-set.d.ts +95 -0
  93. package/dist/lib/icon-set.js +97 -0
  94. package/dist/lib/icons.d.ts +12 -0
  95. package/dist/lib/icons.js +39 -0
  96. package/dist/lib/indicator.d.ts +6 -0
  97. package/dist/lib/indicator.js +18 -0
  98. package/dist/lib/keep-in-view.d.ts +5 -0
  99. package/dist/lib/keep-in-view.js +15 -0
  100. package/dist/lib/key-shortcut.d.ts +20 -0
  101. package/dist/lib/key-shortcut.js +100 -0
  102. package/dist/lib/keycaps.d.ts +8 -0
  103. package/dist/lib/keycaps.js +162 -0
  104. package/dist/lib/locale.d.ts +4 -0
  105. package/dist/lib/locale.js +13 -0
  106. package/dist/lib/nav-tree.d.ts +9 -0
  107. package/dist/lib/nav-tree.js +30 -0
  108. package/dist/lib/numeric.d.ts +20 -0
  109. package/dist/lib/numeric.js +50 -0
  110. package/dist/lib/option-filter.d.ts +29 -0
  111. package/dist/lib/option-filter.js +108 -0
  112. package/dist/lib/option-groups.d.ts +6 -0
  113. package/dist/lib/option-groups.js +26 -0
  114. package/dist/lib/options.d.ts +5 -0
  115. package/dist/lib/options.js +24 -0
  116. package/dist/lib/pagination.d.ts +9 -0
  117. package/dist/lib/pagination.js +52 -0
  118. package/dist/lib/palette.d.ts +8 -0
  119. package/dist/lib/palette.js +46 -0
  120. package/dist/lib/progress.d.ts +20 -0
  121. package/dist/lib/progress.js +33 -0
  122. package/dist/lib/rating.d.ts +7 -0
  123. package/dist/lib/rating.js +26 -0
  124. package/dist/lib/roving-index.d.ts +10 -0
  125. package/dist/lib/roving-index.js +32 -0
  126. package/dist/lib/roving.d.ts +11 -0
  127. package/dist/lib/roving.js +21 -0
  128. package/dist/lib/slots.d.ts +2 -0
  129. package/dist/lib/slots.js +6 -0
  130. package/dist/lib/sparkline.d.ts +11 -0
  131. package/dist/lib/sparkline.js +42 -0
  132. package/dist/lib/split.d.ts +12 -0
  133. package/dist/lib/split.js +37 -0
  134. package/dist/lib/surface.d.ts +7 -0
  135. package/dist/lib/surface.js +28 -0
  136. package/dist/lib/table.d.ts +30 -0
  137. package/dist/lib/table.js +110 -0
  138. package/dist/lib/tags.d.ts +14 -0
  139. package/dist/lib/tags.js +29 -0
  140. package/dist/lib/text.d.ts +5 -0
  141. package/dist/lib/text.js +13 -0
  142. package/dist/lib/tokens.d.ts +5 -0
  143. package/dist/lib/tokens.js +15 -0
  144. package/dist/lib/tree.d.ts +16 -0
  145. package/dist/lib/tree.js +89 -0
  146. package/dist/lib/trend.d.ts +3 -0
  147. package/dist/lib/trend.js +15 -0
  148. package/dist/lib/trigger.d.ts +11 -0
  149. package/dist/lib/trigger.js +34 -0
  150. package/dist/molecules/jl-accordion-item.css_raw.js +3 -0
  151. package/dist/molecules/jl-accordion-item.d.ts +34 -0
  152. package/dist/molecules/jl-accordion-item.js +82 -0
  153. package/dist/molecules/jl-accordion.css_raw.js +3 -0
  154. package/dist/molecules/jl-accordion.d.ts +27 -0
  155. package/dist/molecules/jl-accordion.js +61 -0
  156. package/dist/molecules/jl-alert.css_raw.js +3 -0
  157. package/dist/molecules/jl-alert.d.ts +38 -0
  158. package/dist/molecules/jl-alert.js +131 -0
  159. package/dist/molecules/jl-avatar-group.css_raw.js +3 -0
  160. package/dist/molecules/jl-avatar-group.d.ts +28 -0
  161. package/dist/molecules/jl-avatar-group.js +69 -0
  162. package/dist/molecules/jl-breadcrumb.css_raw.js +3 -0
  163. package/dist/molecules/jl-breadcrumb.d.ts +35 -0
  164. package/dist/molecules/jl-breadcrumb.js +126 -0
  165. package/dist/molecules/jl-calendar.css_raw.js +3 -0
  166. package/dist/molecules/jl-calendar.d.ts +101 -0
  167. package/dist/molecules/jl-calendar.js +314 -0
  168. package/dist/molecules/jl-card.css_raw.js +3 -0
  169. package/dist/molecules/jl-card.d.ts +46 -0
  170. package/dist/molecules/jl-card.js +172 -0
  171. package/dist/molecules/jl-code-block.css_raw.js +3 -0
  172. package/dist/molecules/jl-code-block.d.ts +44 -0
  173. package/dist/molecules/jl-code-block.js +106 -0
  174. package/dist/molecules/jl-combobox.css_raw.js +3 -0
  175. package/dist/molecules/jl-combobox.d.ts +120 -0
  176. package/dist/molecules/jl-combobox.js +450 -0
  177. package/dist/molecules/jl-copy-button.css_raw.js +3 -0
  178. package/dist/molecules/jl-copy-button.d.ts +31 -0
  179. package/dist/molecules/jl-copy-button.js +69 -0
  180. package/dist/molecules/jl-date-picker.css_raw.js +3 -0
  181. package/dist/molecules/jl-date-picker.d.ts +109 -0
  182. package/dist/molecules/jl-date-picker.js +322 -0
  183. package/dist/molecules/jl-empty.css_raw.js +3 -0
  184. package/dist/molecules/jl-empty.d.ts +32 -0
  185. package/dist/molecules/jl-empty.js +94 -0
  186. package/dist/molecules/jl-field.css_raw.js +3 -0
  187. package/dist/molecules/jl-field.d.ts +49 -0
  188. package/dist/molecules/jl-field.js +147 -0
  189. package/dist/molecules/jl-file-drop.css_raw.js +3 -0
  190. package/dist/molecules/jl-file-drop.d.ts +93 -0
  191. package/dist/molecules/jl-file-drop.js +366 -0
  192. package/dist/molecules/jl-list-item.css_raw.js +3 -0
  193. package/dist/molecules/jl-list-item.d.ts +56 -0
  194. package/dist/molecules/jl-list-item.js +176 -0
  195. package/dist/molecules/jl-menu.css_raw.js +3 -0
  196. package/dist/molecules/jl-menu.d.ts +62 -0
  197. package/dist/molecules/jl-menu.js +288 -0
  198. package/dist/molecules/jl-number-input.css_raw.js +3 -0
  199. package/dist/molecules/jl-number-input.d.ts +81 -0
  200. package/dist/molecules/jl-number-input.js +220 -0
  201. package/dist/molecules/jl-pagination.css_raw.js +3 -0
  202. package/dist/molecules/jl-pagination.d.ts +59 -0
  203. package/dist/molecules/jl-pagination.js +172 -0
  204. package/dist/molecules/jl-popover.css_raw.js +3 -0
  205. package/dist/molecules/jl-popover.d.ts +49 -0
  206. package/dist/molecules/jl-popover.js +152 -0
  207. package/dist/molecules/jl-radio-group.css_raw.js +3 -0
  208. package/dist/molecules/jl-radio-group.d.ts +71 -0
  209. package/dist/molecules/jl-radio-group.js +202 -0
  210. package/dist/molecules/jl-search.css_raw.js +3 -0
  211. package/dist/molecules/jl-search.d.ts +71 -0
  212. package/dist/molecules/jl-search.js +210 -0
  213. package/dist/molecules/jl-segmented.css_raw.js +3 -0
  214. package/dist/molecules/jl-segmented.d.ts +65 -0
  215. package/dist/molecules/jl-segmented.js +187 -0
  216. package/dist/molecules/jl-stat.css_raw.js +3 -0
  217. package/dist/molecules/jl-stat.d.ts +55 -0
  218. package/dist/molecules/jl-stat.js +169 -0
  219. package/dist/molecules/jl-steps.css_raw.js +3 -0
  220. package/dist/molecules/jl-steps.d.ts +44 -0
  221. package/dist/molecules/jl-steps.js +118 -0
  222. package/dist/molecules/jl-tab-panel.css_raw.js +3 -0
  223. package/dist/molecules/jl-tab-panel.d.ts +35 -0
  224. package/dist/molecules/jl-tab-panel.js +35 -0
  225. package/dist/molecules/jl-tabs.css_raw.js +3 -0
  226. package/dist/molecules/jl-tabs.d.ts +51 -0
  227. package/dist/molecules/jl-tabs.js +198 -0
  228. package/dist/molecules/jl-tag-input.css_raw.js +3 -0
  229. package/dist/molecules/jl-tag-input.d.ts +103 -0
  230. package/dist/molecules/jl-tag-input.js +429 -0
  231. package/dist/molecules/jl-timeline.css_raw.js +3 -0
  232. package/dist/molecules/jl-timeline.d.ts +28 -0
  233. package/dist/molecules/jl-timeline.js +81 -0
  234. package/dist/molecules/jl-toast.css_raw.js +3 -0
  235. package/dist/molecules/jl-toast.d.ts +75 -0
  236. package/dist/molecules/jl-toast.js +274 -0
  237. package/dist/molecules/jl-tooltip.css_raw.js +3 -0
  238. package/dist/molecules/jl-tooltip.d.ts +44 -0
  239. package/dist/molecules/jl-tooltip.js +160 -0
  240. package/dist/organisms/jl-command-palette.css_raw.js +3 -0
  241. package/dist/organisms/jl-command-palette.d.ts +60 -0
  242. package/dist/organisms/jl-command-palette.js +285 -0
  243. package/dist/organisms/jl-confirm.css_raw.js +3 -0
  244. package/dist/organisms/jl-confirm.d.ts +56 -0
  245. package/dist/organisms/jl-confirm.js +132 -0
  246. package/dist/organisms/jl-dialog.css_raw.js +3 -0
  247. package/dist/organisms/jl-dialog.d.ts +43 -0
  248. package/dist/organisms/jl-dialog.js +120 -0
  249. package/dist/organisms/jl-drawer.css_raw.js +3 -0
  250. package/dist/organisms/jl-drawer.d.ts +50 -0
  251. package/dist/organisms/jl-drawer.js +141 -0
  252. package/dist/organisms/jl-navbar.css_raw.js +3 -0
  253. package/dist/organisms/jl-navbar.d.ts +32 -0
  254. package/dist/organisms/jl-navbar.js +121 -0
  255. package/dist/organisms/jl-page-header.css_raw.js +3 -0
  256. package/dist/organisms/jl-page-header.d.ts +26 -0
  257. package/dist/organisms/jl-page-header.js +85 -0
  258. package/dist/organisms/jl-side-nav.css_raw.js +3 -0
  259. package/dist/organisms/jl-side-nav.d.ts +60 -0
  260. package/dist/organisms/jl-side-nav.js +269 -0
  261. package/dist/organisms/jl-table.css_raw.js +3 -0
  262. package/dist/organisms/jl-table.d.ts +109 -0
  263. package/dist/organisms/jl-table.js +318 -0
  264. package/dist/organisms/jl-toaster.css_raw.js +3 -0
  265. package/dist/organisms/jl-toaster.d.ts +48 -0
  266. package/dist/organisms/jl-toaster.js +142 -0
  267. package/dist/organisms/jl-tree.css_raw.js +3 -0
  268. package/dist/organisms/jl-tree.d.ts +59 -0
  269. package/dist/organisms/jl-tree.js +198 -0
  270. package/dist/styles/base.css_raw.js +3 -0
  271. package/dist/styles/control.css_raw.js +3 -0
  272. package/dist/styles/floating.css_raw.js +3 -0
  273. package/dist/styles/shared.d.ts +8 -0
  274. package/dist/styles/shared.js +14 -0
  275. package/dist/styles/tokens.css_raw.js +3 -0
  276. package/dist/templates/jl-app-shell.css_raw.js +3 -0
  277. package/dist/templates/jl-app-shell.d.ts +37 -0
  278. package/dist/templates/jl-app-shell.js +150 -0
  279. package/dist/templates/jl-split-view.css_raw.js +3 -0
  280. package/dist/templates/jl-split-view.d.ts +49 -0
  281. package/dist/templates/jl-split-view.js +149 -0
  282. package/dist/tokens.css +188 -0
  283. package/dist/types/calendar.types.d.ts +11 -0
  284. package/dist/types/files.types.d.ts +23 -0
  285. package/dist/types/floating.types.d.ts +13 -0
  286. package/dist/types/fuzzy.types.d.ts +10 -0
  287. package/dist/types/highlight.types.d.ts +6 -0
  288. package/dist/types/hotkey.types.d.ts +19 -0
  289. package/dist/types/jl-accordion.types.d.ts +2 -0
  290. package/dist/types/jl-avatar.types.d.ts +10 -0
  291. package/dist/types/jl-breadcrumb.types.d.ts +6 -0
  292. package/dist/types/jl-button.types.d.ts +3 -0
  293. package/dist/types/jl-card.types.d.ts +2 -0
  294. package/dist/types/jl-chip.types.d.ts +1 -0
  295. package/dist/types/jl-combobox.types.d.ts +8 -0
  296. package/dist/types/jl-command-palette.types.d.ts +22 -0
  297. package/dist/types/jl-confirm.types.d.ts +10 -0
  298. package/dist/types/jl-dialog.types.d.ts +1 -0
  299. package/dist/types/jl-divider.types.d.ts +2 -0
  300. package/dist/types/jl-drawer.types.d.ts +4 -0
  301. package/dist/types/jl-empty.types.d.ts +2 -0
  302. package/dist/types/jl-field.types.d.ts +2 -0
  303. package/dist/types/jl-input.types.d.ts +1 -0
  304. package/dist/types/jl-link.types.d.ts +2 -0
  305. package/dist/types/jl-menu.types.d.ts +22 -0
  306. package/dist/types/jl-navbar.types.d.ts +6 -0
  307. package/dist/types/jl-progress.types.d.ts +3 -0
  308. package/dist/types/jl-radio-group.types.d.ts +10 -0
  309. package/dist/types/jl-segmented.types.d.ts +7 -0
  310. package/dist/types/jl-select.types.d.ts +12 -0
  311. package/dist/types/jl-side-nav.types.d.ts +17 -0
  312. package/dist/types/jl-skeleton.types.d.ts +2 -0
  313. package/dist/types/jl-slider.types.d.ts +5 -0
  314. package/dist/types/jl-split-view.types.d.ts +2 -0
  315. package/dist/types/jl-stat.types.d.ts +2 -0
  316. package/dist/types/jl-steps.types.d.ts +8 -0
  317. package/dist/types/jl-switch.types.d.ts +1 -0
  318. package/dist/types/jl-table.types.d.ts +30 -0
  319. package/dist/types/jl-tabs.types.d.ts +2 -0
  320. package/dist/types/jl-timeline.types.d.ts +10 -0
  321. package/dist/types/jl-toast.types.d.ts +2 -0
  322. package/dist/types/jl-toaster.types.d.ts +23 -0
  323. package/dist/types/jl-tree.types.d.ts +26 -0
  324. package/dist/types/key-shortcut.types.d.ts +9 -0
  325. package/dist/types/keycaps.types.d.ts +7 -0
  326. package/dist/types/option-filter.types.d.ts +10 -0
  327. package/dist/types/options.types.d.ts +4 -0
  328. package/dist/types/pagination.types.d.ts +8 -0
  329. package/dist/types/roving-index.types.d.ts +2 -0
  330. package/dist/types/sparkline.types.d.ts +11 -0
  331. package/package.json +102 -4
@@ -0,0 +1,429 @@
1
+ import { BASE_STYLES, CONTROL_STYLES, FLOATING_STYLES } from "../styles/shared.js";
2
+ import { JlFormControl } from "../base/jl-form-control.js";
3
+ import { clampedNumber, jsonOf, oneOf } from "../lib/attributes.js";
4
+ import { followAnchor } from "../lib/floating.js";
5
+ import { registerIcons } from "../lib/icons.js";
6
+ import { CONTROL_SIZES } from "../lib/options.js";
7
+ import { setOrRemove, uniqueId } from "../lib/dom.js";
8
+ import { JlIcon } from "../atoms/jl-icon.js";
9
+ import { keepInView } from "../lib/keep-in-view.js";
10
+ import { filterOptions, matchParts, nextEnabledIndex } from "../lib/option-filter.js";
11
+ import { addTags, hasTag, hasTagSeparator, splitTags } from "../lib/tags.js";
12
+ import jl_tag_input_default from "./jl-tag-input.css_raw.js";
13
+ import { css } from "@jadis/core";
14
+ import { X } from "lucide";
15
+ import { Fragment, jsx, jsxs } from "@jadis/core/jsx-runtime";
16
+ // src/molecules/jl-tag-input.tsx
17
+ registerIcons({ x: X });
18
+ var REMOVE_ICON_SIZE = 12;
19
+ var NONE = -1;
20
+ var PLACEMENT = "bottom-start";
21
+ var VALUE_MISSING = "Add at least one tag.";
22
+ var NO_LIMIT = 0;
23
+ var COMMA = ",";
24
+ var MAX_SUGGESTIONS = 8;
25
+ var FLASH_MS = 600;
26
+ /** A JSON attribute that should hold a list of texts; anything else gives an empty list. */
27
+ var parseTextList = (value) => {
28
+ const parsed = jsonOf([])(value);
29
+ return Array.isArray(parsed) ? parsed.map(String) : [];
30
+ };
31
+ var highlighted = (label, query) => matchParts(label, query).map((part) => part.matched ? /* @__PURE__ */ jsx("mark", { children: part.text }) : part.text);
32
+ /**
33
+ * A field that collects short texts as chips: Enter or a comma adds what was typed, Backspace in the empty field
34
+ * removes the last chip, a pasted list adds each of its items. The form gets each tag under the field's name.
35
+ */
36
+ var JlTagInput = class extends JlFormControl {
37
+ static selector = "jl-tag-input";
38
+ events = this.useEvents();
39
+ value = this.useChange([], () => this.renderTags(), {
40
+ attribute: "value",
41
+ parse: parseTextList
42
+ });
43
+ placeholder = this.useChange("", () => this.renderPlaceholder(), { attribute: "placeholder" });
44
+ /** The field's name for screen readers, when no visible label names it. */
45
+ label = this.useChange("", (value) => setOrRemove(this._refs.native, "aria-label", value), { attribute: "label" });
46
+ /** The most tags the field takes; 0 for no limit. */
47
+ max = this.useChange(NO_LIMIT, () => this.renderTags(), {
48
+ attribute: "max",
49
+ parse: clampedNumber(NO_LIMIT, 0, Number.MAX_SAFE_INTEGER)
50
+ });
51
+ /** Tags offered in a list while people type. */
52
+ suggestions = this.useChange([], (value) => this.renderSuggestionRole(value), {
53
+ attribute: "suggestions",
54
+ parse: parseTextList
55
+ });
56
+ required = this.useChange(false, (value) => {
57
+ this._refs.native.toggleAttribute("aria-required", value);
58
+ this.reflect("required", value);
59
+ this.renderValidity();
60
+ }, { attribute: "required" });
61
+ disabled = this.useChange(false, (value) => this.renderDisabled(value), { attribute: "disabled" });
62
+ /** Draws the field in the danger colour, for an error the page found itself. */
63
+ invalid = this.useChange(false, (value) => {
64
+ this.reflect("invalid", value);
65
+ this._refs.native.toggleAttribute("aria-invalid", value);
66
+ }, { attribute: "invalid" });
67
+ size = this.useChange("md", (value) => this.reflect("size", value), {
68
+ attribute: "size",
69
+ parse: oneOf(CONTROL_SIZES, "md")
70
+ });
71
+ _listId = uniqueId("jl-tag-input-list");
72
+ _state = {
73
+ active: NONE,
74
+ matches: [],
75
+ opening: new AbortController()
76
+ };
77
+ _nameWatch = new MutationObserver(() => this.renderFormValue());
78
+ _refs = this.useRefs((ref) => ({
79
+ control: ref(".control"),
80
+ listbox: ref(".listbox"),
81
+ native: ref("input"),
82
+ popup: ref(".popup"),
83
+ status: ref(".status"),
84
+ tags: ref(".tags")
85
+ }));
86
+ focus(options) {
87
+ this._refs.native.focus(options);
88
+ }
89
+ templateHtml() {
90
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
91
+ /* @__PURE__ */ jsxs("div", {
92
+ class: "control",
93
+ attrs: { part: "base" },
94
+ children: [/* @__PURE__ */ jsx("ul", {
95
+ class: "tags",
96
+ role: "list"
97
+ }), /* @__PURE__ */ jsx("input", {
98
+ class: "native",
99
+ autocomplete: "off"
100
+ })]
101
+ }),
102
+ /* @__PURE__ */ jsx("div", {
103
+ class: "floating panel popup",
104
+ popover: "manual",
105
+ attrs: { part: "list" },
106
+ children: /* @__PURE__ */ jsx("div", {
107
+ class: "listbox",
108
+ role: "listbox",
109
+ id: this._listId
110
+ })
111
+ }),
112
+ /* @__PURE__ */ jsx("span", {
113
+ class: "status sr-only",
114
+ role: "status"
115
+ })
116
+ ] });
117
+ }
118
+ templateCss() {
119
+ return css`${BASE_STYLES}${CONTROL_STYLES}${FLOATING_STYLES}${jl_tag_input_default}`;
120
+ }
121
+ onConnect() {
122
+ const native = this._refs.native;
123
+ this._nameWatch.observe(this, {
124
+ attributeFilter: ["name"],
125
+ attributes: true
126
+ });
127
+ this.renderFormValue();
128
+ this.on(native, "input", (event) => {
129
+ event.stopPropagation();
130
+ this.onType();
131
+ });
132
+ this.on(native, "keydown", (event) => this.onFieldKey(event));
133
+ this.on(native, "paste", (event) => this.onPaste(event));
134
+ this.on(native, "blur", () => this.commitText());
135
+ this.on(this._refs.control, "click", (event) => this.onControlClick(event));
136
+ this.on(this._refs.tags, "keydown", (event) => this.onTagKey(event));
137
+ this.on(this._refs.popup, "mousedown", (event) => event.preventDefault());
138
+ this.on(this._refs.listbox, "click", (event) => this.pick(this.suggestionAt(event)));
139
+ }
140
+ onDisconnect() {
141
+ this._nameWatch.disconnect();
142
+ this._state.opening.abort();
143
+ }
144
+ resetValue() {
145
+ this._refs.native.value = "";
146
+ this.value.set(parseTextList(this.getAttribute("value")));
147
+ }
148
+ setDisabledByForm(disabled) {
149
+ this.whenRendered(() => {
150
+ this._refs.native.disabled = disabled || this.disabled.get();
151
+ });
152
+ }
153
+ onType() {
154
+ const native = this._refs.native;
155
+ if (hasTagSeparator(native.value)) {
156
+ this.add(splitTags(native.value));
157
+ return;
158
+ }
159
+ this.renderMatches();
160
+ }
161
+ onFieldKey(event) {
162
+ if ((/* @__PURE__ */ new Map([
163
+ [COMMA, () => {
164
+ this.commitText();
165
+ return true;
166
+ }],
167
+ ["ArrowDown", () => this.moveActive(1)],
168
+ ["ArrowLeft", () => this.focusLastTag()],
169
+ ["ArrowUp", () => this.moveActive(-1)],
170
+ ["Backspace", () => this.removeLastIfEmpty()],
171
+ ["Enter", () => this.onEnter()],
172
+ ["Escape", () => this.closeList()]
173
+ ])).get(event.key)?.() === true) event.preventDefault();
174
+ }
175
+ /** Enter adds the suggestion the arrows reached, or the typed text; in an empty field it submits the form. */
176
+ onEnter() {
177
+ const active = this._state.matches[this._state.active];
178
+ if (this.isOpen() && active !== void 0) {
179
+ this.pick(active);
180
+ return true;
181
+ }
182
+ return this.commitText();
183
+ }
184
+ /** A pasted list adds each of its items; a single word is pasted as text. */
185
+ onPaste(event) {
186
+ const pasted = event.clipboardData?.getData("text") ?? "";
187
+ if (!hasTagSeparator(pasted)) return;
188
+ event.preventDefault();
189
+ const native = this._refs.native;
190
+ const before = native.value.slice(0, native.selectionStart ?? native.value.length);
191
+ const after = native.value.slice(native.selectionEnd ?? native.value.length);
192
+ this.add(splitTags(`${before}${pasted}${after}`));
193
+ }
194
+ onControlClick(event) {
195
+ const remove = event.target.closest(".tag-remove");
196
+ if (remove !== null) {
197
+ this.removeAt(Number(remove.dataset.index));
198
+ this.focus();
199
+ return;
200
+ }
201
+ if (event.target === this._refs.control) this.focus();
202
+ }
203
+ /** On a chip's remove button: arrows move between chips and back to the field, Backspace or Delete removes it. */
204
+ onTagKey(event) {
205
+ const button = event.target.closest(".tag-remove");
206
+ if (button === null) return;
207
+ const index = Number(button.dataset.index);
208
+ const handler = (/* @__PURE__ */ new Map([
209
+ ["ArrowLeft", () => this.focusTag(Math.max(0, index - 1))],
210
+ ["ArrowRight", () => this.focusTag(index + 1)],
211
+ ["Backspace", () => this.removeAndFocus(index)],
212
+ ["Delete", () => this.removeAndFocus(index)]
213
+ ])).get(event.key);
214
+ if (handler !== void 0) {
215
+ event.preventDefault();
216
+ handler();
217
+ }
218
+ }
219
+ /** Adds the typed text as tags; true when there was text to add. */
220
+ commitText() {
221
+ const text = this._refs.native.value;
222
+ this.closeList();
223
+ if (text.trim() === "") return false;
224
+ this.add(splitTags(text));
225
+ return true;
226
+ }
227
+ add(candidates) {
228
+ const before = this.value.get();
229
+ const result = addTags(before, candidates, this.max.get());
230
+ const added = result.tags.slice(before.length);
231
+ if (!(added.length === 0 && result.duplicates.length === 0)) this._refs.native.value = "";
232
+ this.closeList();
233
+ if (added.length > 0) {
234
+ this.value.set(result.tags);
235
+ this.announce(`Added ${added.join(", ")}`);
236
+ this.events.emit("change", result.tags);
237
+ }
238
+ this.flash(result.duplicates);
239
+ }
240
+ removeAt(index) {
241
+ const tags = this.value.get();
242
+ const removed = tags[index];
243
+ if (removed === void 0 || this.disabled.get()) return;
244
+ const next = tags.filter((_, position) => position !== index);
245
+ this.value.set(next);
246
+ this.announce(`Removed ${removed}`);
247
+ this.events.emit("change", next);
248
+ }
249
+ removeAndFocus(index) {
250
+ this.removeAt(index);
251
+ if (this.value.get().length === 0) {
252
+ this.focus();
253
+ return;
254
+ }
255
+ this.focusTag(Math.max(0, index - 1));
256
+ }
257
+ removeLastIfEmpty() {
258
+ if (this._refs.native.value !== "" || this.value.get().length === 0) return false;
259
+ this.removeAt(this.value.get().length - 1);
260
+ return true;
261
+ }
262
+ focusLastTag() {
263
+ const native = this._refs.native;
264
+ const count = this.value.get().length;
265
+ if (native.selectionStart !== 0 || native.selectionEnd !== 0 || count === 0 || this.disabled.get()) return false;
266
+ this.focusTag(count - 1);
267
+ return true;
268
+ }
269
+ /** Focuses a chip's remove button; past the last chip, the field. */
270
+ focusTag(index) {
271
+ const button = this._refs.tags.querySelector(`.tag-remove[data-index="${index}"]`);
272
+ if (button === null) {
273
+ this.focus();
274
+ return;
275
+ }
276
+ button.focus();
277
+ }
278
+ /** Points at the chips people tried to add again. */
279
+ flash(duplicates) {
280
+ const tags = this.value.get();
281
+ for (const chip of this._refs.tags.querySelectorAll(".tag")) {
282
+ const tag = tags[Number(chip.dataset.index)];
283
+ if (tag === void 0 || !hasTag(duplicates, tag)) continue;
284
+ chip.classList.add("flash");
285
+ window.setTimeout(() => chip.classList.remove("flash"), FLASH_MS);
286
+ }
287
+ }
288
+ announce(message) {
289
+ this._refs.status.textContent = message;
290
+ }
291
+ isOpen() {
292
+ return this._refs.popup.matches(":popover-open");
293
+ }
294
+ /** The suggestions that match the typed text and are not tags yet; the list opens while there are some. */
295
+ renderMatches() {
296
+ const query = this._refs.native.value.trim();
297
+ const tags = this.value.get();
298
+ const candidates = this.suggestions.get().filter((suggestion) => !hasTag(tags, suggestion)).map((label) => ({ label }));
299
+ const matches = query === "" ? [] : filterOptions(candidates, query).slice(0, MAX_SUGGESTIONS);
300
+ this._state.matches = matches;
301
+ this._state.active = NONE;
302
+ this._refs.listbox.replaceChildren(...matches.map((match, index) => /* @__PURE__ */ jsx("div", {
303
+ class: "option",
304
+ role: "option",
305
+ id: `${this._listId}-${index}`,
306
+ "data-index": String(index),
307
+ "aria-selected": "false",
308
+ children: highlighted(match.label, query)
309
+ })));
310
+ this.renderActive();
311
+ if (matches.length === 0) {
312
+ this.closeList();
313
+ return;
314
+ }
315
+ this.openList();
316
+ }
317
+ openList() {
318
+ if (this.isOpen()) return;
319
+ const popup = this._refs.popup;
320
+ popup.showPopover();
321
+ this._state.opening.abort();
322
+ this._state.opening = new AbortController();
323
+ followAnchor(this._refs.native, popup, PLACEMENT, this._state.opening.signal);
324
+ this._refs.native.setAttribute("aria-expanded", "true");
325
+ }
326
+ /** Closes the suggestions; true when they were open, so Escape goes no further. */
327
+ closeList() {
328
+ if (!this.isOpen()) return false;
329
+ this._refs.popup.hidePopover();
330
+ this._state.opening.abort();
331
+ this._state.active = NONE;
332
+ this.renderActive();
333
+ this._refs.native.setAttribute("aria-expanded", "false");
334
+ return true;
335
+ }
336
+ moveActive(direction) {
337
+ if (!this.isOpen()) return false;
338
+ this._state.active = nextEnabledIndex(this._state.matches, this._state.active, direction);
339
+ this.renderActive();
340
+ const item = this._refs.listbox.children[this._state.active];
341
+ if (item instanceof HTMLElement) keepInView(this._refs.listbox, item);
342
+ return true;
343
+ }
344
+ renderActive() {
345
+ const active = this._state.active;
346
+ for (const item of this._refs.listbox.querySelectorAll("[data-index]")) {
347
+ const isActive = Number(item.dataset.index) === active;
348
+ item.classList.toggle("active", isActive);
349
+ item.setAttribute("aria-selected", String(isActive));
350
+ }
351
+ setOrRemove(this._refs.native, "aria-activedescendant", active === NONE ? "" : `${this._listId}-${active}`);
352
+ }
353
+ suggestionAt(event) {
354
+ const item = event.target.closest("[data-index]");
355
+ return item === null ? void 0 : this._state.matches[Number(item.dataset.index)];
356
+ }
357
+ pick(suggestion) {
358
+ if (suggestion === void 0) return;
359
+ this.add([suggestion.label]);
360
+ this.focus();
361
+ }
362
+ /** The field is a combobox only when it offers suggestions. */
363
+ renderSuggestionRole(suggestions) {
364
+ const native = this._refs.native;
365
+ const offers = suggestions.length > 0;
366
+ setOrRemove(native, "role", offers ? "combobox" : "");
367
+ setOrRemove(native, "aria-autocomplete", offers ? "list" : "");
368
+ setOrRemove(native, "aria-controls", offers ? this._listId : "");
369
+ setOrRemove(native, "aria-expanded", offers ? String(this.isOpen()) : "");
370
+ }
371
+ renderTags() {
372
+ const tags = this.value.get();
373
+ const editable = !this.disabled.get();
374
+ this._refs.tags.replaceChildren(...tags.map((tag, index) => /* @__PURE__ */ jsxs("li", {
375
+ class: "tag",
376
+ "data-index": String(index),
377
+ children: [/* @__PURE__ */ jsx("span", {
378
+ class: "tag-text",
379
+ children: tag
380
+ }), editable ? /* @__PURE__ */ jsx("button", {
381
+ class: "tag-remove",
382
+ type: "button",
383
+ tabIndex: -1,
384
+ "aria-label": `Remove ${tag}`,
385
+ "data-index": String(index),
386
+ children: /* @__PURE__ */ jsx(JlIcon, {
387
+ name: "x",
388
+ size: REMOVE_ICON_SIZE
389
+ })
390
+ }) : null]
391
+ })));
392
+ const max = this.max.get();
393
+ this.reflect("full", max !== NO_LIMIT && tags.length >= max);
394
+ this.renderPlaceholder();
395
+ this.renderFormValue();
396
+ this.renderValidity();
397
+ }
398
+ /** The placeholder shows while there is no tag; chips take its place. */
399
+ renderPlaceholder() {
400
+ const empty = this.value.get().length === 0;
401
+ setOrRemove(this._refs.native, "placeholder", empty ? this.placeholder.get() : "");
402
+ }
403
+ /** Each tag is its own entry under the field's name, as several checked boxes of one name would be. */
404
+ renderFormValue() {
405
+ const name = this.getAttribute("name") ?? "";
406
+ if (name === "") {
407
+ this.internals.setFormValue(null);
408
+ return;
409
+ }
410
+ const data = new FormData();
411
+ for (const tag of this.value.get()) data.append(name, tag);
412
+ this.internals.setFormValue(data);
413
+ }
414
+ renderValidity() {
415
+ if (this.required.get() && this.value.get().length === 0) {
416
+ this.internals.setValidity({ valueMissing: true }, VALUE_MISSING, this._refs.native);
417
+ return;
418
+ }
419
+ this.internals.setValidity({});
420
+ }
421
+ renderDisabled(disabled) {
422
+ this._refs.native.disabled = disabled;
423
+ this.reflect("disabled", disabled);
424
+ this.closeList();
425
+ this.renderTags();
426
+ }
427
+ };
428
+ JlTagInput.register();
429
+ export { JlTagInput };
@@ -0,0 +1,3 @@
1
+ // src/molecules/jl-timeline.css?raw
2
+ var jl_timeline_default = ":host {\n display: block;\n --marker: 22px;\n --gap: 20px;\n --title-size: var(--jl-font-md);\n}\n\n:host([compact]) {\n --marker: 18px;\n --gap: 12px;\n --title-size: var(--jl-font-sm);\n}\n\n.timeline {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.event {\n position: relative;\n display: grid;\n grid-template-columns: var(--marker) minmax(0, 1fr);\n gap: 12px;\n padding-bottom: var(--gap);\n --tone: var(--jl-muted);\n --soft: var(--jl-surface-3);\n}\n\n.event:last-child {\n padding-bottom: 0;\n}\n\n.event[data-tone=\"accent\"] {\n --tone: var(--jl-accent);\n --soft: var(--jl-accent-soft);\n}\n\n.event[data-tone=\"ok\"] {\n --tone: var(--jl-ok);\n --soft: var(--jl-ok-soft);\n}\n\n.event[data-tone=\"warn\"] {\n --tone: var(--jl-warn);\n --soft: var(--jl-warn-soft);\n}\n\n.event[data-tone=\"danger\"] {\n --tone: var(--jl-danger);\n --soft: var(--jl-danger-soft);\n}\n\n.event[data-tone=\"info\"] {\n --tone: var(--jl-info);\n --soft: var(--jl-info-soft);\n}\n\n/* The line runs from this marker's centre to the next one's, behind the markers. */\n.event:not(:last-child)::before {\n position: absolute;\n top: 10px;\n bottom: -10px;\n left: calc(var(--marker) / 2 - 0.5px);\n width: 1px;\n background: var(--jl-line-strong);\n content: \"\";\n}\n\n.rail {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n height: 20px;\n}\n\n.marker {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n}\n\n.dot {\n width: 10px;\n height: 10px;\n background: var(--tone);\n box-shadow: 0 0 0 3px var(--jl-surface);\n}\n\n:host([compact]) .dot {\n width: 8px;\n height: 8px;\n}\n\n.circle {\n width: var(--marker);\n height: var(--marker);\n border: 1px solid color-mix(in srgb, var(--tone) 30%, var(--soft));\n background: var(--soft);\n color: var(--tone);\n box-shadow: 0 0 0 3px var(--jl-surface);\n}\n\n.content {\n display: grid;\n gap: 2px;\n}\n\n.line {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n justify-content: space-between;\n gap: 2px 12px;\n}\n\n.title {\n color: var(--jl-text);\n font-size: var(--title-size);\n font-weight: 600;\n line-height: 20px;\n}\n\n.time {\n flex: none;\n margin-left: auto;\n color: var(--jl-muted);\n font-family: var(--jl-font-mono);\n font-size: var(--jl-font-xs);\n}\n\n.description {\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n line-height: 1.5;\n}\n\n:host([compact]) .description {\n font-size: var(--jl-font-xs);\n}\n";
3
+ export { jl_timeline_default as default };
@@ -0,0 +1,28 @@
1
+ import { JlElement } from '../base/jl-element';
2
+ import type { TimelineItem } from '../types/jl-timeline.types';
3
+ /**
4
+ * What happened, in order, along a vertical line: each event a dot (or an icon in a circle) in its tone's colour,
5
+ * a title, an optional description, and its time on the right. `compact` tightens it for side panels.
6
+ */
7
+ export declare class JlTimeline extends JlElement {
8
+ static readonly selector = "jl-timeline";
9
+ readonly items: Readonly<Readonly<{
10
+ get(): TimelineItem[];
11
+ set(setter: TimelineItem[] | ((prevState: TimelineItem[]) => TimelineItem[])): void;
12
+ }>>;
13
+ /** Smaller markers and less space between events. */
14
+ readonly compact: Readonly<Readonly<{
15
+ get(): boolean;
16
+ set(setter: boolean | ((prevState: boolean) => boolean)): void;
17
+ }>>;
18
+ /** The list's name for screen readers. */
19
+ readonly label: Readonly<Readonly<{
20
+ get(): string;
21
+ set(setter: string | ((prevState: string) => string)): void;
22
+ }>>;
23
+ private readonly _refs;
24
+ templateHtml(): Node;
25
+ templateCss(): string;
26
+ private render;
27
+ private itemNode;
28
+ }
@@ -0,0 +1,81 @@
1
+ import { BASE_STYLES } from "../styles/shared.js";
2
+ import { JlElement } from "../base/jl-element.js";
3
+ import { jsonOf } from "../lib/attributes.js";
4
+ import { setOrRemove } from "../lib/dom.js";
5
+ import { JlIcon } from "../atoms/jl-icon.js";
6
+ import jl_timeline_default from "./jl-timeline.css_raw.js";
7
+ import { css } from "@jadis/core";
8
+ import { jsx, jsxs } from "@jadis/core/jsx-runtime";
9
+ // src/molecules/jl-timeline.tsx
10
+ var ICON_SIZE = 14;
11
+ var COMPACT_ICON_SIZE = 12;
12
+ /**
13
+ * What happened, in order, along a vertical line: each event a dot (or an icon in a circle) in its tone's colour,
14
+ * a title, an optional description, and its time on the right. `compact` tightens it for side panels.
15
+ */
16
+ var JlTimeline = class extends JlElement {
17
+ static selector = "jl-timeline";
18
+ items = this.useChange([], () => this.render(), {
19
+ attribute: "items",
20
+ parse: jsonOf([])
21
+ });
22
+ /** Smaller markers and less space between events. */
23
+ compact = this.useChange(false, (value) => {
24
+ this.reflect("compact", value);
25
+ this.render();
26
+ }, { attribute: "compact" });
27
+ /** The list's name for screen readers. */
28
+ label = this.useChange("", (value) => setOrRemove(this._refs.list, "aria-label", value), { attribute: "label" });
29
+ _refs = this.useRefs((ref) => ({ list: ref("ol") }));
30
+ templateHtml() {
31
+ return /* @__PURE__ */ jsx("ol", {
32
+ class: "timeline",
33
+ attrs: { part: "base" }
34
+ });
35
+ }
36
+ templateCss() {
37
+ return css`${BASE_STYLES}${jl_timeline_default}`;
38
+ }
39
+ render() {
40
+ this._refs.list.replaceChildren(...this.items.get().map((item) => this.itemNode(item)));
41
+ }
42
+ itemNode(item) {
43
+ const size = this.compact.get() ? COMPACT_ICON_SIZE : ICON_SIZE;
44
+ const marker = item.icon === void 0 ? /* @__PURE__ */ jsx("span", {
45
+ class: "marker dot",
46
+ "aria-hidden": "true"
47
+ }) : /* @__PURE__ */ jsx("span", {
48
+ class: "marker circle",
49
+ "aria-hidden": "true",
50
+ children: /* @__PURE__ */ jsx(JlIcon, {
51
+ name: item.icon,
52
+ size
53
+ })
54
+ });
55
+ return /* @__PURE__ */ jsxs("li", {
56
+ class: "event",
57
+ "data-tone": item.tone ?? "neutral",
58
+ children: [/* @__PURE__ */ jsx("span", {
59
+ class: "rail",
60
+ children: marker
61
+ }), /* @__PURE__ */ jsxs("div", {
62
+ class: "content",
63
+ children: [/* @__PURE__ */ jsxs("div", {
64
+ class: "line",
65
+ children: [/* @__PURE__ */ jsx("p", {
66
+ class: "title",
67
+ children: item.title
68
+ }), item.time === void 0 ? null : /* @__PURE__ */ jsx("time", {
69
+ class: "time",
70
+ children: item.time
71
+ })]
72
+ }), item.description === void 0 ? null : /* @__PURE__ */ jsx("p", {
73
+ class: "description",
74
+ children: item.description
75
+ })]
76
+ })]
77
+ });
78
+ }
79
+ };
80
+ JlTimeline.register();
81
+ export { JlTimeline };
@@ -0,0 +1,3 @@
1
+ // src/molecules/jl-toast.css?raw
2
+ var jl_toast_default = ":host {\n display: block;\n --tone: var(--jl-text-2);\n --bar: var(--jl-brand);\n}\n\n:host([tone=\"ok\"]) {\n --tone: var(--jl-ok);\n --bar: var(--jl-ok);\n}\n\n:host([tone=\"warn\"]) {\n --tone: var(--jl-warn);\n --bar: var(--jl-warn);\n}\n\n:host([tone=\"danger\"]) {\n --tone: var(--jl-danger);\n --bar: var(--jl-danger);\n}\n\n:host([tone=\"info\"]) {\n --tone: var(--jl-info);\n --bar: var(--jl-info);\n}\n\n.toast {\n position: relative;\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 14px 12px 14px 16px;\n overflow: hidden;\n border: 1px solid var(--jl-line);\n border-radius: var(--jl-radius-lg);\n background: var(--jl-surface);\n color: var(--jl-text);\n font-size: var(--jl-font-md);\n line-height: 20px;\n box-shadow: var(--jl-shadow-lg);\n}\n\n.icon {\n margin-top: 1px;\n color: var(--tone);\n}\n\n.content {\n display: grid;\n flex: 1;\n gap: 2px;\n min-width: 0;\n overflow-wrap: anywhere;\n}\n\n.heading {\n font-weight: 650;\n}\n\n.text {\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n}\n\n.heading[hidden] + .text {\n color: var(--jl-text-2);\n font-size: var(--jl-font-md);\n}\n\n.buttons {\n display: flex;\n flex: none;\n align-items: center;\n gap: 2px;\n margin: -5px -4px -5px 0;\n}\n\n.buttons:not(:has(jl-button:not([hidden]))) {\n display: none;\n}\n\n.close {\n --jl-accent: var(--jl-muted);\n --jl-accent-soft: var(--jl-surface-3);\n}\n\n.progress {\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n height: 2px;\n}\n\n.bar {\n height: 100%;\n background: var(--bar);\n transform-origin: left center;\n}\n\n:host([paused]) .bar {\n opacity: 0.55;\n}\n\n/* The line still counts the time, but does not move for people who asked for less motion. */\n@media (prefers-reduced-motion: reduce) {\n .progress {\n visibility: hidden;\n }\n}\n";
3
+ export { jl_toast_default as default };
@@ -0,0 +1,75 @@
1
+ import { JlElement } from '../base/jl-element';
2
+ import type { ToastTone } from '../types/jl-toast.types';
3
+ export declare const TOAST_TONES: readonly ToastTone[];
4
+ /**
5
+ * One notification: a heading, a line of text, an icon in its tone's colour, and maybe an action such as "Undo".
6
+ * With a `duration` it closes by itself, a thin line showing the time left; hovering or focusing it pauses the
7
+ * line. It emits `dismiss` once it has closed. Most pages call `toast()` rather than writing it.
8
+ */
9
+ export declare class JlToast extends JlElement {
10
+ static readonly selector = "jl-toast";
11
+ readonly events: Readonly<import("@jadis/core").UseEventsHandler<{
12
+ action: undefined;
13
+ dismiss: undefined;
14
+ }>>;
15
+ readonly tone: Readonly<Readonly<{
16
+ get(): ToastTone;
17
+ set(setter: ((prevState: ToastTone) => ToastTone) | ToastTone): void;
18
+ }>>;
19
+ readonly heading: Readonly<Readonly<{
20
+ get(): string;
21
+ set(setter: string | ((prevState: string) => string)): void;
22
+ }>>;
23
+ readonly text: Readonly<Readonly<{
24
+ get(): string;
25
+ set(setter: string | ((prevState: string) => string)): void;
26
+ }>>;
27
+ /** An icon name; the tone's icon when empty. */
28
+ readonly icon: Readonly<Readonly<{
29
+ get(): string;
30
+ set(setter: string | ((prevState: string) => string)): void;
31
+ }>>;
32
+ /** Shows a close button. */
33
+ readonly closable: Readonly<Readonly<{
34
+ get(): boolean;
35
+ set(setter: boolean | ((prevState: boolean) => boolean)): void;
36
+ }>>;
37
+ /** The text of a quiet button that emits `action`, then closes the toast. */
38
+ readonly actionLabel: Readonly<Readonly<{
39
+ get(): string;
40
+ set(setter: string | ((prevState: string) => string)): void;
41
+ }>>;
42
+ /** How long it stays, in milliseconds; 0 keeps it until it is closed. */
43
+ readonly duration: Readonly<Readonly<{
44
+ get(): number;
45
+ set(setter: number | ((prevState: number) => number)): void;
46
+ }>>;
47
+ private readonly _timer;
48
+ private readonly _hold;
49
+ private readonly _refs;
50
+ /** Closes the toast: it leaves, hides, then emits `dismiss`. */
51
+ dismiss(): void;
52
+ /** Shows a dismissed toast again, with its time from the start. */
53
+ show(): void;
54
+ templateHtml(): Node;
55
+ templateCss(): string;
56
+ onConnect(): void;
57
+ onDisconnect(): void;
58
+ /** The way in, once per showing; WAAPI so that the toaster moving in the top layer does not replay it. */
59
+ private enter;
60
+ private enterOffset;
61
+ private finishLeaving;
62
+ /**
63
+ * The time left is the progress line's own animation: pausing it pauses the countdown, and it is not cut short by
64
+ * reduced motion the way CSS animations are.
65
+ */
66
+ private startTimer;
67
+ private stopTimer;
68
+ private resumeTimer;
69
+ private hold;
70
+ /** Whether the focus, moving to `next`, stays in the toast (its buttons, or what the page slotted in it). */
71
+ private holdsFocus;
72
+ private renderIcon;
73
+ /** Inside a toaster, its live region announces the toast; alone, the toast is its own. */
74
+ private renderRole;
75
+ }