@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,187 @@
1
+ import { BASE_STYLES } from "../styles/shared.js";
2
+ import { JlFormControl } from "../base/jl-form-control.js";
3
+ import { jsonOf, oneOf } from "../lib/attributes.js";
4
+ import { CONTROL_SIZES } from "../lib/options.js";
5
+ import { setOrRemove } from "../lib/dom.js";
6
+ import { JlIcon } from "../atoms/jl-icon.js";
7
+ import { firstIndex, lastIndex, stepIndex } from "../lib/roving.js";
8
+ import { moveIndicator } from "../lib/indicator.js";
9
+ import jl_segmented_default from "./jl-segmented.css_raw.js";
10
+ import { css } from "@jadis/core";
11
+ import { jsx, jsxs } from "@jadis/core/jsx-runtime";
12
+ // src/molecules/jl-segmented.tsx
13
+ var ICON_SIZES = {
14
+ lg: 18,
15
+ md: 16,
16
+ sm: 14
17
+ };
18
+ var KEY_MOVES = /* @__PURE__ */ new Map([
19
+ ["ArrowDown", (enabled, from) => stepIndex(enabled, from, 1)],
20
+ ["ArrowLeft", (enabled, from) => stepIndex(enabled, from, -1)],
21
+ ["ArrowRight", (enabled, from) => stepIndex(enabled, from, 1)],
22
+ ["ArrowUp", (enabled, from) => stepIndex(enabled, from, -1)],
23
+ ["End", lastIndex],
24
+ ["Home", firstIndex]
25
+ ]);
26
+ /**
27
+ * A row of a few exclusive choices with a thumb that slides to the chosen one: a view switch, a period, a
28
+ * density. It takes part in forms like a radio group; `change` fires with the value people pick.
29
+ */
30
+ var JlSegmented = class extends JlFormControl {
31
+ static selector = "jl-segmented";
32
+ events = this.useEvents();
33
+ options = this.useChange([], () => this.renderOptions(), {
34
+ attribute: "options",
35
+ parse: jsonOf([])
36
+ });
37
+ /** The chosen option's value; the first option that can be chosen when it names none. */
38
+ value = this.useChange("", () => this.renderValue(), { attribute: "value" });
39
+ size = this.useChange("md", (value) => {
40
+ this.reflect("size", value);
41
+ this.renderOptions();
42
+ }, {
43
+ attribute: "size",
44
+ parse: oneOf(CONTROL_SIZES, "md")
45
+ });
46
+ /** Takes the whole width, the options sharing it. */
47
+ block = this.useChange(false, (value) => {
48
+ this.reflect("block", value);
49
+ this.placeThumb();
50
+ }, { attribute: "block" });
51
+ disabled = this.useChange(false, (value) => {
52
+ this.reflect("disabled", value);
53
+ this.renderDisabled();
54
+ }, { attribute: "disabled" });
55
+ /** The group's name for screen readers, when no visible label names it. */
56
+ label = this.useChange("", (value) => setOrRemove(this._refs.group, "aria-label", value), { attribute: "label" });
57
+ _state = { disabledByForm: false };
58
+ _resize = new ResizeObserver(() => this.placeThumb());
59
+ _refs = this.useRefs((ref) => ({
60
+ group: ref(".group"),
61
+ thumb: ref(".thumb")
62
+ }));
63
+ focus(options) {
64
+ this.selectedSegment()?.focus(options);
65
+ }
66
+ templateHtml() {
67
+ return /* @__PURE__ */ jsx("div", {
68
+ class: "group",
69
+ role: "radiogroup",
70
+ attrs: { part: "base" },
71
+ children: /* @__PURE__ */ jsx("span", {
72
+ class: "thumb",
73
+ "aria-hidden": "true",
74
+ hidden: true
75
+ })
76
+ });
77
+ }
78
+ templateCss() {
79
+ return css`${BASE_STYLES}${jl_segmented_default}`;
80
+ }
81
+ onConnect() {
82
+ this._resize.observe(this._refs.group);
83
+ this.on(this._refs.group, "click", (event) => {
84
+ const segment = event.target.closest(".segment");
85
+ if (segment !== null) this.choose(this.segments().indexOf(segment), false);
86
+ });
87
+ this.on(this._refs.group, "keydown", (event) => this.onKeydown(event));
88
+ }
89
+ onDisconnect() {
90
+ this._resize.disconnect();
91
+ }
92
+ resetValue() {
93
+ this.value.set(this.getAttribute("value") ?? "");
94
+ }
95
+ /** The browser calls it for a disabled fieldset and for the element's own `disabled`, even before it renders. */
96
+ setDisabledByForm(disabled) {
97
+ this._state.disabledByForm = disabled;
98
+ this.whenRendered(() => this.renderDisabled());
99
+ }
100
+ segments() {
101
+ return [...this._refs.group.querySelectorAll(".segment")];
102
+ }
103
+ selectedSegment() {
104
+ return this.segments().find((segment) => segment.getAttribute("aria-checked") === "true") ?? null;
105
+ }
106
+ isDisabled() {
107
+ return this.disabled.get() || this._state.disabledByForm;
108
+ }
109
+ renderOptions() {
110
+ const iconSize = ICON_SIZES[this.size.get()];
111
+ const segments = this.options.get().map((option) => this.segment(option, iconSize));
112
+ this._refs.group.replaceChildren(this._refs.thumb, ...segments);
113
+ this.renderValue();
114
+ this.renderDisabled();
115
+ }
116
+ /** A segment; with only an icon, its value names it. */
117
+ segment(option, iconSize) {
118
+ const label = option.label ?? "";
119
+ const name = label === "" ? option.value : void 0;
120
+ return /* @__PURE__ */ jsxs("button", {
121
+ type: "button",
122
+ role: "radio",
123
+ "aria-checked": "false",
124
+ "aria-label": name,
125
+ title: name,
126
+ class: "segment",
127
+ "data-value": option.value,
128
+ "data-disabled": option.disabled === true ? "" : void 0,
129
+ children: [option.icon === void 0 ? "" : /* @__PURE__ */ jsx(JlIcon, {
130
+ name: option.icon,
131
+ size: iconSize
132
+ }), label === "" ? "" : /* @__PURE__ */ jsx("span", {
133
+ class: "label",
134
+ children: label
135
+ })]
136
+ });
137
+ }
138
+ /** The chosen option's index: the one `value` names, or else the first that can be chosen. */
139
+ selectedIndex() {
140
+ const options = this.options.get();
141
+ const named = options.findIndex((option) => option.value === this.value.get() && option.disabled !== true);
142
+ return named === -1 ? options.findIndex((option) => option.disabled !== true) : named;
143
+ }
144
+ renderValue() {
145
+ const option = this.options.get()[this.selectedIndex()];
146
+ if (option !== void 0 && option.value !== this.value.get()) {
147
+ this.value.set(option.value);
148
+ return;
149
+ }
150
+ const value = option?.value ?? "";
151
+ this.segments().forEach((segment) => {
152
+ const checked = segment.dataset.value === value;
153
+ segment.setAttribute("aria-checked", String(checked));
154
+ segment.tabIndex = checked ? 0 : -1;
155
+ });
156
+ this.internals.setFormValue(value);
157
+ this.placeThumb();
158
+ }
159
+ renderDisabled() {
160
+ const disabled = this.isDisabled();
161
+ this._refs.group.toggleAttribute("aria-disabled", disabled);
162
+ for (const segment of this.segments()) segment.disabled = disabled || segment.hasAttribute("data-disabled");
163
+ }
164
+ placeThumb() {
165
+ moveIndicator(this._refs.thumb, this.selectedSegment());
166
+ }
167
+ onKeydown(event) {
168
+ const move = KEY_MOVES.get(event.key);
169
+ const segments = this.segments();
170
+ const from = segments.indexOf(event.target);
171
+ if (move === void 0 || from === -1) return;
172
+ event.preventDefault();
173
+ this.choose(move(segments.map((segment) => !segment.disabled), from), true);
174
+ }
175
+ /** Chooses an option people picked, and says so. */
176
+ choose(index, focus) {
177
+ const option = this.options.get()[index];
178
+ const segment = this.segments()[index];
179
+ if (option === void 0 || segment === void 0 || segment.disabled) return;
180
+ if (focus) segment.focus();
181
+ if (option.value === this.value.get()) return;
182
+ this.value.set(option.value);
183
+ this.events.emit("change", option.value);
184
+ }
185
+ };
186
+ JlSegmented.register();
187
+ export { JlSegmented };
@@ -0,0 +1,3 @@
1
+ // src/molecules/jl-stat.css?raw
2
+ var jl_stat_default = ":host {\n display: block;\n --mood: var(--jl-muted);\n}\n\n:host([mood=\"good\"]) {\n --mood: var(--jl-ok);\n}\n\n:host([mood=\"bad\"]) {\n --mood: var(--jl-danger);\n}\n\n.stat {\n display: grid;\n gap: 4px;\n min-width: 0;\n}\n\n.top {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.label {\n flex: 1;\n min-width: 0;\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n font-weight: 600;\n line-height: 1.4;\n}\n\n.icon {\n color: var(--jl-faint);\n}\n\n.figure {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n column-gap: 10px;\n}\n\n.value {\n color: var(--jl-text);\n font-size: var(--jl-font-2xl);\n font-variant-numeric: tabular-nums;\n font-weight: 700;\n letter-spacing: -0.02em;\n line-height: 1.2;\n}\n\n.delta {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n color: var(--mood);\n font-size: var(--jl-font-sm);\n font-variant-numeric: tabular-nums;\n font-weight: 650;\n white-space: nowrap;\n}\n\n.caption {\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n line-height: 1.4;\n}\n\n.spark {\n height: 36px;\n margin-top: 8px;\n}\n\n.spark svg {\n display: block;\n width: 100%;\n height: 100%;\n overflow: visible;\n}\n\n.line {\n fill: none;\n stroke: var(--jl-accent);\n stroke-linecap: round;\n stroke-linejoin: round;\n stroke-width: 2;\n vector-effect: non-scaling-stroke;\n}\n\n.area {\n fill: color-mix(in srgb, var(--jl-accent) 10%, transparent);\n stroke: none;\n}\n";
3
+ export { jl_stat_default as default };
@@ -0,0 +1,55 @@
1
+ import { JlElement } from '../base/jl-element';
2
+ import type { StatTrend } from '../types/jl-stat.types';
3
+ export declare const STAT_TRENDS: readonly StatTrend[];
4
+ /**
5
+ * A key figure: what it measures, its value, how it moved (`delta`, coloured by its trend) and an optional
6
+ * sparkline of its recent `points`. Put it in a card for a tile; several make a dashboard's row.
7
+ */
8
+ export declare class JlStat extends JlElement {
9
+ static readonly selector = "jl-stat";
10
+ /** What the figure measures: "Revenue", "Active users". */
11
+ readonly label: Readonly<Readonly<{
12
+ get(): string;
13
+ set(setter: string | ((prevState: string) => string)): void;
14
+ }>>;
15
+ /** The figure, as people read it: "$48,210", "1,204", "98.2%". */
16
+ readonly value: Readonly<Readonly<{
17
+ get(): string;
18
+ set(setter: string | ((prevState: string) => string)): void;
19
+ }>>;
20
+ /** How it changed: "+12.5%", "-3". Its sign gives the trend when `trend` is not set. */
21
+ readonly delta: Readonly<Readonly<{
22
+ get(): string;
23
+ set(setter: string | ((prevState: string) => string)): void;
24
+ }>>;
25
+ /** Which way it went; read from the delta's sign when absent. */
26
+ readonly trend: Readonly<Readonly<{
27
+ get(): "" | StatTrend;
28
+ set(setter: "" | ((prevState: "" | StatTrend) => "" | StatTrend) | StatTrend): void;
29
+ }>>;
30
+ /** For figures where down is good (costs, errors, load time): down is green, up is red. */
31
+ readonly invert: Readonly<Readonly<{
32
+ get(): boolean;
33
+ set(setter: boolean | ((prevState: boolean) => boolean)): void;
34
+ }>>;
35
+ readonly icon: Readonly<Readonly<{
36
+ get(): string;
37
+ set(setter: string | ((prevState: string) => string)): void;
38
+ }>>;
39
+ /** A note under the figure: "vs. last month". */
40
+ readonly caption: Readonly<Readonly<{
41
+ get(): string;
42
+ set(setter: string | ((prevState: string) => string)): void;
43
+ }>>;
44
+ /** Recent values, oldest first, drawn as a sparkline: `[4, 6, 5, 9, 12]`. */
45
+ readonly points: Readonly<Readonly<{
46
+ get(): number[];
47
+ set(setter: number[] | ((prevState: number[]) => number[])): void;
48
+ }>>;
49
+ private readonly _refs;
50
+ templateHtml(): Node;
51
+ templateCss(): string;
52
+ private effectiveTrend;
53
+ private renderDelta;
54
+ private renderSparkline;
55
+ }
@@ -0,0 +1,169 @@
1
+ import { BASE_STYLES } from "../styles/shared.js";
2
+ import { JlElement } from "../base/jl-element.js";
3
+ import { jsonOf, oneOf } from "../lib/attributes.js";
4
+ import { registerIcons } from "../lib/icons.js";
5
+ import { JlIcon } from "../atoms/jl-icon.js";
6
+ import { areaAttribute, pointsAttribute, sparklinePoints } from "../lib/sparkline.js";
7
+ import { trendOfDelta } from "../lib/trend.js";
8
+ import jl_stat_default from "./jl-stat.css_raw.js";
9
+ import { css } from "@jadis/core";
10
+ import { Minus, TrendingDown, TrendingUp } from "lucide";
11
+ import { jsx, jsxs } from "@jadis/core/jsx-runtime";
12
+ // src/molecules/jl-stat.tsx
13
+ registerIcons({
14
+ minus: Minus,
15
+ "trending-down": TrendingDown,
16
+ "trending-up": TrendingUp
17
+ });
18
+ var STAT_TRENDS = [
19
+ "up",
20
+ "down",
21
+ "flat"
22
+ ];
23
+ var SVG_NS = "http://www.w3.org/2000/svg";
24
+ var SPARK_BOX = {
25
+ height: 32,
26
+ inset: 2,
27
+ width: 100
28
+ };
29
+ var ICON_SIZE = 16;
30
+ var TREND_ICON_SIZE = 14;
31
+ var TREND_ICONS = {
32
+ down: "trending-down",
33
+ flat: "minus",
34
+ up: "trending-up"
35
+ };
36
+ var TREND_MOODS = {
37
+ down: "bad",
38
+ flat: "neutral",
39
+ up: "good"
40
+ };
41
+ var INVERTED_MOODS = {
42
+ down: "good",
43
+ flat: "neutral",
44
+ up: "bad"
45
+ };
46
+ var isNumberList = (value) => Array.isArray(value) && value.every((item) => typeof item === "number");
47
+ /**
48
+ * A key figure: what it measures, its value, how it moved (`delta`, coloured by its trend) and an optional
49
+ * sparkline of its recent `points`. Put it in a card for a tile; several make a dashboard's row.
50
+ */
51
+ var JlStat = class extends JlElement {
52
+ static selector = "jl-stat";
53
+ /** What the figure measures: "Revenue", "Active users". */
54
+ label = this.useChange("", (value) => {
55
+ this._refs.label.textContent = value;
56
+ }, { attribute: "label" });
57
+ /** The figure, as people read it: "$48,210", "1,204", "98.2%". */
58
+ value = this.useChange("", (value) => {
59
+ this._refs.value.textContent = value;
60
+ }, { attribute: "value" });
61
+ /** How it changed: "+12.5%", "-3". Its sign gives the trend when `trend` is not set. */
62
+ delta = this.useChange("", () => this.renderDelta(), { attribute: "delta" });
63
+ /** Which way it went; read from the delta's sign when absent. */
64
+ trend = this.useChange("", () => this.renderDelta(), {
65
+ attribute: "trend",
66
+ parse: oneOf(["", ...STAT_TRENDS], "")
67
+ });
68
+ /** For figures where down is good (costs, errors, load time): down is green, up is red. */
69
+ invert = this.useChange(false, () => this.renderDelta(), { attribute: "invert" });
70
+ icon = this.useChange("", (value) => {
71
+ this._refs.icon.name.set(value);
72
+ this._refs.icon.hidden = value === "";
73
+ }, { attribute: "icon" });
74
+ /** A note under the figure: "vs. last month". */
75
+ caption = this.useChange("", (value) => {
76
+ this._refs.caption.textContent = value;
77
+ this._refs.caption.hidden = value === "";
78
+ }, { attribute: "caption" });
79
+ /** Recent values, oldest first, drawn as a sparkline: `[4, 6, 5, 9, 12]`. */
80
+ points = this.useChange([], () => this.renderSparkline(), {
81
+ attribute: "points",
82
+ parse: jsonOf([])
83
+ });
84
+ _refs = this.useRefs((ref) => ({
85
+ caption: ref(".caption"),
86
+ delta: ref(".delta"),
87
+ deltaText: ref(".delta-text"),
88
+ icon: ref(".icon"),
89
+ label: ref(".label"),
90
+ spark: ref(".spark"),
91
+ trendIcon: ref(".trend-icon"),
92
+ value: ref(".value")
93
+ }));
94
+ templateHtml() {
95
+ return /* @__PURE__ */ jsxs("div", {
96
+ class: "stat",
97
+ attrs: { part: "base" },
98
+ children: [
99
+ /* @__PURE__ */ jsxs("div", {
100
+ class: "top",
101
+ children: [/* @__PURE__ */ jsx("span", { class: "label" }), /* @__PURE__ */ jsx(JlIcon, {
102
+ class: "icon",
103
+ size: ICON_SIZE,
104
+ hidden: true
105
+ })]
106
+ }),
107
+ /* @__PURE__ */ jsxs("div", {
108
+ class: "figure",
109
+ children: [/* @__PURE__ */ jsx("span", { class: "value" }), /* @__PURE__ */ jsxs("span", {
110
+ class: "delta",
111
+ hidden: true,
112
+ children: [/* @__PURE__ */ jsx(JlIcon, {
113
+ class: "trend-icon",
114
+ size: TREND_ICON_SIZE
115
+ }), /* @__PURE__ */ jsx("span", { class: "delta-text" })]
116
+ })]
117
+ }),
118
+ /* @__PURE__ */ jsx("p", {
119
+ class: "caption",
120
+ hidden: true
121
+ }),
122
+ /* @__PURE__ */ jsx("div", {
123
+ class: "spark",
124
+ "aria-hidden": "true",
125
+ hidden: true
126
+ })
127
+ ]
128
+ });
129
+ }
130
+ templateCss() {
131
+ return css`${BASE_STYLES}${jl_stat_default}`;
132
+ }
133
+ effectiveTrend() {
134
+ return this.trend.get() || trendOfDelta(this.delta.get());
135
+ }
136
+ renderDelta() {
137
+ const delta = this.delta.get();
138
+ const trend = this.effectiveTrend();
139
+ const moods = this.invert.get() ? INVERTED_MOODS : TREND_MOODS;
140
+ this._refs.deltaText.textContent = delta;
141
+ this._refs.delta.hidden = delta === "";
142
+ this._refs.trendIcon.name.set(TREND_ICONS[trend]);
143
+ this.reflect("direction", trend);
144
+ this.reflect("mood", moods[trend]);
145
+ }
146
+ renderSparkline() {
147
+ const values = this.points.get();
148
+ const points = sparklinePoints(isNumberList(values) ? values : [], SPARK_BOX);
149
+ const spark = this._refs.spark;
150
+ spark.hidden = points.length === 0;
151
+ if (points.length === 0) {
152
+ spark.replaceChildren();
153
+ return;
154
+ }
155
+ const svg = document.createElementNS(SVG_NS, "svg");
156
+ svg.setAttribute("viewBox", `0 0 ${SPARK_BOX.width} ${SPARK_BOX.height}`);
157
+ svg.setAttribute("preserveAspectRatio", "none");
158
+ const area = document.createElementNS(SVG_NS, "polygon");
159
+ area.setAttribute("class", "area");
160
+ area.setAttribute("points", areaAttribute(points, SPARK_BOX));
161
+ const line = document.createElementNS(SVG_NS, "polyline");
162
+ line.setAttribute("class", "line");
163
+ line.setAttribute("points", pointsAttribute(points));
164
+ svg.append(area, line);
165
+ spark.replaceChildren(svg);
166
+ }
167
+ };
168
+ JlStat.register();
169
+ export { JlStat, STAT_TRENDS };
@@ -0,0 +1,3 @@
1
+ // src/molecules/jl-steps.css?raw
2
+ var jl_steps_default = ":host {\n display: block;\n container-type: inline-size;\n --marker: 28px;\n}\n\nol {\n display: flex;\n padding: 0;\n list-style: none;\n}\n\n.step {\n display: flex;\n flex: 1;\n min-width: 0;\n}\n\n.step:last-child {\n flex: none;\n}\n\n.head {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n padding: 0;\n border: none;\n border-radius: var(--jl-radius-xs);\n background: none;\n text-align: start;\n}\n\nbutton.head {\n cursor: pointer;\n}\n\n.marker {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: var(--marker);\n height: var(--marker);\n border: 1px solid var(--jl-line-strong);\n border-radius: 50%;\n background: var(--jl-surface);\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n font-weight: 650;\n font-variant-numeric: tabular-nums;\n}\n\n.text {\n display: grid;\n gap: 2px;\n min-width: 0;\n padding-top: 4px;\n}\n\n.label {\n color: var(--jl-muted);\n font-size: var(--jl-font-md);\n font-weight: 600;\n line-height: 20px;\n}\n\n.description {\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n line-height: 1.45;\n}\n\n.step[data-status=\"done\"] .marker {\n border-color: var(--jl-accent-line);\n background: var(--jl-accent-soft);\n color: var(--jl-accent);\n}\n\n.step[data-status=\"done\"] .label {\n color: var(--jl-text);\n}\n\n.step[data-status=\"current\"] .marker {\n border-color: var(--jl-accent);\n background: var(--jl-accent);\n color: var(--jl-on-accent);\n box-shadow: 0 0 0 4px var(--jl-accent-soft);\n}\n\n.step[data-status=\"current\"] .label {\n color: var(--jl-text);\n font-weight: 700;\n}\n\nbutton.head:hover .label {\n text-decoration: underline;\n text-underline-offset: 3px;\n}\n\n.line {\n flex: 1;\n min-width: 16px;\n height: 1px;\n margin: calc(var(--marker) / 2) 12px 0;\n background: var(--jl-line-strong);\n}\n\n.step[data-status=\"done\"] .line {\n background: var(--jl-accent);\n}\n\n.step:last-child .line {\n display: none;\n}\n\n/* Vertical: the markers in a column joined by a rule, the text beside them. */\n:host([orientation=\"vertical\"]) ol {\n flex-direction: column;\n}\n\n:host([orientation=\"vertical\"]) .step {\n position: relative;\n flex: none;\n padding-bottom: 24px;\n}\n\n:host([orientation=\"vertical\"]) .step:last-child {\n padding-bottom: 0;\n}\n\n:host([orientation=\"vertical\"]) .line {\n position: absolute;\n top: calc(var(--marker) + 4px);\n bottom: 4px;\n left: calc(var(--marker) / 2);\n width: 1px;\n height: auto;\n min-width: 0;\n margin: 0;\n}\n\n/* Narrow, the horizontal steps keep their markers and only the current step's text. */\n@container (width < 560px) {\n /* Out of sight, still read: the same rules as .sr-only. */\n :host(:not([orientation=\"vertical\"])) .step:not([data-status=\"current\"]) .text {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n }\n\n :host(:not([orientation=\"vertical\"])) .description {\n display: none;\n }\n\n :host(:not([orientation=\"vertical\"])) .line {\n margin: calc(var(--marker) / 2) 8px 0;\n }\n}\n";
3
+ export { jl_steps_default as default };
@@ -0,0 +1,44 @@
1
+ import { JlElement } from '../base/jl-element';
2
+ import type { StepItem, StepsOrientation } from '../types/jl-steps.types';
3
+ export declare const STEPS_ORIENTATIONS: readonly StepsOrientation[];
4
+ /**
5
+ * The steps of a process and where people are in it: done steps show a check, the current one is in the accent
6
+ * colour. With `clickable`, people can go back to a done step; `change` fires with its index.
7
+ */
8
+ export declare class JlSteps extends JlElement {
9
+ static readonly selector = "jl-steps";
10
+ readonly events: Readonly<import("@jadis/core").UseEventsHandler<{
11
+ change: number;
12
+ }>>;
13
+ readonly items: Readonly<Readonly<{
14
+ get(): StepItem[];
15
+ set(setter: StepItem[] | ((prevState: StepItem[]) => StepItem[])): void;
16
+ }>>;
17
+ /** The index of the current step, from 0; the number of steps when all are done. */
18
+ readonly current: Readonly<Readonly<{
19
+ get(): number;
20
+ set(setter: number | ((prevState: number) => number)): void;
21
+ }>>;
22
+ readonly orientation: Readonly<Readonly<{
23
+ get(): StepsOrientation;
24
+ set(setter: ((prevState: StepsOrientation) => StepsOrientation) | StepsOrientation): void;
25
+ }>>;
26
+ /** Done steps become buttons that go back to them. */
27
+ readonly clickable: Readonly<Readonly<{
28
+ get(): boolean;
29
+ set(setter: boolean | ((prevState: boolean) => boolean)): void;
30
+ }>>;
31
+ /** The list's name for screen readers. */
32
+ readonly label: Readonly<Readonly<{
33
+ get(): string;
34
+ set(setter: string | ((prevState: string) => string)): void;
35
+ }>>;
36
+ private readonly _refs;
37
+ templateHtml(): Node;
38
+ templateCss(): string;
39
+ onConnect(): void;
40
+ private render;
41
+ private step;
42
+ /** Goes back to a done step people picked, and says so. */
43
+ private goBackTo;
44
+ }
@@ -0,0 +1,118 @@
1
+ import { BASE_STYLES } from "../styles/shared.js";
2
+ import { JlElement } from "../base/jl-element.js";
3
+ import { clampedNumber, jsonOf, oneOf } from "../lib/attributes.js";
4
+ import { registerIcons } from "../lib/icons.js";
5
+ import { JlIcon } from "../atoms/jl-icon.js";
6
+ import jl_steps_default from "./jl-steps.css_raw.js";
7
+ import { css } from "@jadis/core";
8
+ import { Check } from "lucide";
9
+ import { jsx, jsxs } from "@jadis/core/jsx-runtime";
10
+ // src/molecules/jl-steps.tsx
11
+ registerIcons({ check: Check });
12
+ var STEPS_ORIENTATIONS = ["horizontal", "vertical"];
13
+ var CHECK_SIZE = 14;
14
+ var MAX_STEPS = 100;
15
+ var DEFAULT_LABEL = "Progress";
16
+ var STATUS_TEXT = {
17
+ current: ", current step",
18
+ done: ", completed",
19
+ upcoming: ""
20
+ };
21
+ var statusOf = (index, current) => {
22
+ if (index < current) return "done";
23
+ return index === current ? "current" : "upcoming";
24
+ };
25
+ /**
26
+ * The steps of a process and where people are in it: done steps show a check, the current one is in the accent
27
+ * colour. With `clickable`, people can go back to a done step; `change` fires with its index.
28
+ */
29
+ var JlSteps = class extends JlElement {
30
+ static selector = "jl-steps";
31
+ events = this.useEvents();
32
+ items = this.useChange([], () => this.render(), {
33
+ attribute: "items",
34
+ parse: jsonOf([])
35
+ });
36
+ /** The index of the current step, from 0; the number of steps when all are done. */
37
+ current = this.useChange(0, () => this.render(), {
38
+ attribute: "current",
39
+ parse: clampedNumber(0, 0, MAX_STEPS)
40
+ });
41
+ orientation = this.useChange("horizontal", (value) => this.reflect("orientation", value), {
42
+ attribute: "orientation",
43
+ parse: oneOf(STEPS_ORIENTATIONS, "horizontal")
44
+ });
45
+ /** Done steps become buttons that go back to them. */
46
+ clickable = this.useChange(false, () => this.render(), { attribute: "clickable" });
47
+ /** The list's name for screen readers. */
48
+ label = this.useChange(DEFAULT_LABEL, (value) => {
49
+ this._refs.list.setAttribute("aria-label", value || DEFAULT_LABEL);
50
+ }, { attribute: "label" });
51
+ _refs = this.useRefs((ref) => ({ list: ref("ol") }));
52
+ templateHtml() {
53
+ return /* @__PURE__ */ jsx("ol", { attrs: { part: "base" } });
54
+ }
55
+ templateCss() {
56
+ return css`${BASE_STYLES}${jl_steps_default}`;
57
+ }
58
+ onConnect() {
59
+ this.on(this._refs.list, "click", (event) => {
60
+ const target = event.target.closest("button[data-index]");
61
+ if (target !== null) this.goBackTo(Number(target.dataset.index));
62
+ });
63
+ }
64
+ render() {
65
+ const current = this.current.get();
66
+ this._refs.list.replaceChildren(...this.items.get().map((item, index) => this.step(item, index, statusOf(index, current))));
67
+ }
68
+ step(item, index, status) {
69
+ const content = [/* @__PURE__ */ jsx("span", {
70
+ class: "marker",
71
+ "aria-hidden": "true",
72
+ children: status === "done" ? /* @__PURE__ */ jsx(JlIcon, {
73
+ name: "check",
74
+ size: CHECK_SIZE
75
+ }) : String(index + 1)
76
+ }), /* @__PURE__ */ jsxs("span", {
77
+ class: "text",
78
+ children: [/* @__PURE__ */ jsxs("span", {
79
+ class: "label",
80
+ children: [item.label, /* @__PURE__ */ jsx("span", {
81
+ class: "sr-only",
82
+ children: STATUS_TEXT[status]
83
+ })]
84
+ }), item.description === void 0 ? "" : /* @__PURE__ */ jsx("span", {
85
+ class: "description",
86
+ children: item.description
87
+ })]
88
+ })];
89
+ const canGoBack = status === "done" && this.clickable.get();
90
+ return /* @__PURE__ */ jsxs("li", {
91
+ class: "step",
92
+ "data-status": status,
93
+ "aria-current": status === "current" ? "step" : void 0,
94
+ children: [canGoBack ? /* @__PURE__ */ jsx("button", {
95
+ type: "button",
96
+ class: "head",
97
+ "data-index": index,
98
+ children: content
99
+ }) : /* @__PURE__ */ jsx("div", {
100
+ class: "head",
101
+ tabIndex: status === "current" ? -1 : void 0,
102
+ children: content
103
+ }), /* @__PURE__ */ jsx("span", {
104
+ class: "line",
105
+ "aria-hidden": "true"
106
+ })]
107
+ });
108
+ }
109
+ /** Goes back to a done step people picked, and says so. */
110
+ goBackTo(index) {
111
+ if (index >= this.current.get()) return;
112
+ this.current.set(index);
113
+ this.events.emit("change", index);
114
+ this._refs.list.querySelector("[aria-current] .head")?.focus();
115
+ }
116
+ };
117
+ JlSteps.register();
118
+ export { JlSteps, STEPS_ORIENTATIONS };
@@ -0,0 +1,3 @@
1
+ // src/molecules/jl-tab-panel.css?raw
2
+ var jl_tab_panel_default = ":host {\n display: block;\n border-radius: var(--jl-radius-xs);\n}\n\n/* jl-tabs marks the open panel; the others stay out of the page. */\n:host(:not([selected])) {\n display: none;\n}\n\n:host(:focus-visible) {\n outline: none;\n box-shadow: var(--jl-focus-ring);\n}\n";
3
+ export { jl_tab_panel_default as default };
@@ -0,0 +1,35 @@
1
+ import { JlElement } from '../base/jl-element';
2
+ /**
3
+ * One panel of a `jl-tabs`: its content, and what its tab shows (`label`, `icon`, `badge`). The tabs open one
4
+ * panel at a time and mark it `selected`; outside of `jl-tabs` a panel shows nothing.
5
+ */
6
+ export declare class JlTabPanel extends JlElement {
7
+ static readonly selector = "jl-tab-panel";
8
+ /** What `jl-tabs`'s `value` names to open this panel; its position in the tabs when empty. */
9
+ readonly name: Readonly<Readonly<{
10
+ get(): string;
11
+ set(setter: string | ((prevState: string) => string)): void;
12
+ }>>;
13
+ /** The tab's text, and the panel's name for screen readers. */
14
+ readonly label: Readonly<Readonly<{
15
+ get(): string;
16
+ set(setter: string | ((prevState: string) => string)): void;
17
+ }>>;
18
+ /** An icon before the tab's text. */
19
+ readonly icon: Readonly<Readonly<{
20
+ get(): string;
21
+ set(setter: string | ((prevState: string) => string)): void;
22
+ }>>;
23
+ /** A short count or word after the tab's text: "3", "New". */
24
+ readonly badge: Readonly<Readonly<{
25
+ get(): string;
26
+ set(setter: string | ((prevState: string) => string)): void;
27
+ }>>;
28
+ readonly disabled: Readonly<Readonly<{
29
+ get(): boolean;
30
+ set(setter: boolean | ((prevState: boolean) => boolean)): void;
31
+ }>>;
32
+ private readonly _internals;
33
+ templateHtml(): Node;
34
+ templateCss(): string;
35
+ }
@@ -0,0 +1,35 @@
1
+ import { BASE_STYLES } from "../styles/shared.js";
2
+ import { JlElement } from "../base/jl-element.js";
3
+ import jl_tab_panel_default from "./jl-tab-panel.css_raw.js";
4
+ import { css } from "@jadis/core";
5
+ import { jsx } from "@jadis/core/jsx-runtime";
6
+ // src/molecules/jl-tab-panel.tsx
7
+ var ROLE = "tabpanel";
8
+ /**
9
+ * One panel of a `jl-tabs`: its content, and what its tab shows (`label`, `icon`, `badge`). The tabs open one
10
+ * panel at a time and mark it `selected`; outside of `jl-tabs` a panel shows nothing.
11
+ */
12
+ var JlTabPanel = class extends JlElement {
13
+ static selector = "jl-tab-panel";
14
+ /** What `jl-tabs`'s `value` names to open this panel; its position in the tabs when empty. */
15
+ name = this.useChange("", (value) => this.reflect("name", value), { attribute: "name" });
16
+ /** The tab's text, and the panel's name for screen readers. */
17
+ label = this.useChange("", (value) => {
18
+ this.reflect("label", value);
19
+ this._internals.ariaLabel = value === "" ? null : value;
20
+ }, { attribute: "label" });
21
+ /** An icon before the tab's text. */
22
+ icon = this.useChange("", (value) => this.reflect("icon", value), { attribute: "icon" });
23
+ /** A short count or word after the tab's text: "3", "New". */
24
+ badge = this.useChange("", (value) => this.reflect("badge", value), { attribute: "badge" });
25
+ disabled = this.useChange(false, (value) => this.reflect("disabled", value), { attribute: "disabled" });
26
+ _internals = Object.assign(this.attachInternals(), { role: ROLE });
27
+ templateHtml() {
28
+ return /* @__PURE__ */ jsx("slot", {});
29
+ }
30
+ templateCss() {
31
+ return css`${BASE_STYLES}${jl_tab_panel_default}`;
32
+ }
33
+ };
34
+ JlTabPanel.register();
35
+ export { JlTabPanel };