@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,285 @@
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 { registerIcons } from "../lib/icons.js";
5
+ import { setOrRemove } from "../lib/dom.js";
6
+ import { JlIcon } from "../atoms/jl-icon.js";
7
+ import { highlightSegments } from "../lib/fuzzy.js";
8
+ import { hotkeyLabels, isApplePlatform, matchesHotkey, parseHotkey } from "../lib/hotkey.js";
9
+ import { groupMatches, matchCommands } from "../lib/palette.js";
10
+ import jl_command_palette_default from "./jl-command-palette.css_raw.js";
11
+ import { css } from "@jadis/core";
12
+ import { Search } from "lucide";
13
+ import { jsx, jsxs } from "@jadis/core/jsx-runtime";
14
+ // src/organisms/jl-command-palette.tsx
15
+ registerIcons({ search: Search });
16
+ var DEFAULT_HOTKEY = "mod+k";
17
+ var NO_HOTKEY = "none";
18
+ var DEFAULT_PLACEHOLDER = "Type a command or search…";
19
+ var DEFAULT_EMPTY_TEXT = "No matching commands";
20
+ var DEFAULT_LABEL = "Command palette";
21
+ var SEARCH_ICON_SIZE = 18;
22
+ var OPTION_ICON_SIZE = 16;
23
+ /** How far each key moves the active command. */
24
+ var MOVES = /* @__PURE__ */ new Map([["ArrowDown", 1], ["ArrowUp", -1]]);
25
+ var optionId = (index) => `option-${index}`;
26
+ var onApple = () => isApplePlatform(navigator.platform);
27
+ function keycaps(shortcut) {
28
+ return hotkeyLabels(shortcut, onApple()).map((label) => /* @__PURE__ */ jsx("kbd", { children: label }));
29
+ }
30
+ function highlighted(label, positions) {
31
+ return highlightSegments(label, positions).map((segment) => segment.marked ? /* @__PURE__ */ jsx("mark", { children: segment.text }) : segment.text);
32
+ }
33
+ /**
34
+ * A search box over every command of an app, opened by ⌘K (Ctrl+K off Apple) or `show()`. Typing filters the
35
+ * commands by their letters in order, best matches first, under their groups; arrows move, Enter runs the command
36
+ * (`select` with its id) and Escape closes. It sits near the top of the window, on the browser's modal `<dialog>`.
37
+ */
38
+ var JlCommandPalette = class extends JlElement {
39
+ static selector = "jl-command-palette";
40
+ events = this.useEvents();
41
+ commands = this.useChange([], () => this.renderResults(), {
42
+ attribute: "commands",
43
+ parse: jsonOf([])
44
+ });
45
+ open = this.useChange(false, (value) => this.renderOpen(value), { attribute: "open" });
46
+ placeholder = this.useChange(DEFAULT_PLACEHOLDER, (value) => {
47
+ this._refs.input.placeholder = value;
48
+ }, { attribute: "placeholder" });
49
+ /** The keys that open and close it from anywhere on the page; `none` for no keys. `mod` is ⌘ or Ctrl. */
50
+ hotkey = this.useChange(DEFAULT_HOTKEY, () => this.renderHotkey(), { attribute: "hotkey" });
51
+ /** What it says when nothing matches. */
52
+ emptyText = this.useChange(DEFAULT_EMPTY_TEXT, (value) => {
53
+ this._refs.empty.textContent = value;
54
+ }, { attribute: "empty-text" });
55
+ /** The dialog's name for screen readers. */
56
+ label = this.useChange(DEFAULT_LABEL, (value) => this._refs.dialog.setAttribute("aria-label", value), { attribute: "label" });
57
+ _state = {
58
+ active: 0,
59
+ matches: []
60
+ };
61
+ _refs = this.useRefs((ref) => ({
62
+ dialog: ref("dialog"),
63
+ empty: ref(".empty"),
64
+ hotkeyHint: ref(".hotkey-hint"),
65
+ hotkeyKeys: ref(".hotkey-keys"),
66
+ input: ref("input"),
67
+ results: ref(".results")
68
+ }));
69
+ show() {
70
+ this.open.set(true);
71
+ }
72
+ close() {
73
+ this.open.set(false);
74
+ }
75
+ templateHtml() {
76
+ return /* @__PURE__ */ jsxs("dialog", {
77
+ attrs: { part: "base" },
78
+ children: [
79
+ /* @__PURE__ */ jsxs("div", {
80
+ class: "search",
81
+ children: [
82
+ /* @__PURE__ */ jsx(JlIcon, {
83
+ class: "search-icon",
84
+ name: "search",
85
+ size: SEARCH_ICON_SIZE
86
+ }),
87
+ /* @__PURE__ */ jsx("input", {
88
+ type: "text",
89
+ role: "combobox",
90
+ "aria-expanded": "true",
91
+ "aria-controls": "results",
92
+ "aria-autocomplete": "list",
93
+ autocomplete: "off",
94
+ spellcheck: false
95
+ }),
96
+ /* @__PURE__ */ jsx("kbd", {
97
+ class: "escape",
98
+ children: "Esc"
99
+ })
100
+ ]
101
+ }),
102
+ /* @__PURE__ */ jsx("div", {
103
+ class: "results",
104
+ id: "results",
105
+ role: "listbox",
106
+ "aria-label": "Commands"
107
+ }),
108
+ /* @__PURE__ */ jsx("p", {
109
+ class: "empty",
110
+ role: "status",
111
+ hidden: true
112
+ }),
113
+ /* @__PURE__ */ jsxs("footer", {
114
+ "aria-hidden": "true",
115
+ children: [
116
+ /* @__PURE__ */ jsxs("span", {
117
+ class: "hint",
118
+ children: [
119
+ /* @__PURE__ */ jsx("kbd", { children: "↑" }),
120
+ /* @__PURE__ */ jsx("kbd", { children: "↓" }),
121
+ "to move"
122
+ ]
123
+ }),
124
+ /* @__PURE__ */ jsxs("span", {
125
+ class: "hint",
126
+ children: [/* @__PURE__ */ jsx("kbd", { children: "↵" }), "to run"]
127
+ }),
128
+ /* @__PURE__ */ jsxs("span", {
129
+ class: "hint hotkey-hint",
130
+ children: [/* @__PURE__ */ jsx("span", { class: "hotkey-keys" }), "to close"]
131
+ })
132
+ ]
133
+ })
134
+ ]
135
+ });
136
+ }
137
+ templateCss() {
138
+ return css`${BASE_STYLES}${jl_command_palette_default}`;
139
+ }
140
+ onConnect() {
141
+ const dialog = this._refs.dialog;
142
+ const input = this._refs.input;
143
+ this.on(document, "keydown", (event) => this.toggleOnHotkey(event));
144
+ this.on(input, "input", (event) => {
145
+ event.stopPropagation();
146
+ this.renderResults();
147
+ });
148
+ this.on(input, "keydown", (event) => this.navigate(event));
149
+ this.on(this._refs.results, "pointermove", (event) => {
150
+ const index = this.indexOf(event.target);
151
+ if (index !== null && index !== this._state.active) this.activate(index);
152
+ });
153
+ this.on(this._refs.results, "click", (event) => {
154
+ const index = this.indexOf(event.target);
155
+ if (index !== null) this.choose(index);
156
+ });
157
+ this.on(dialog, "close", () => {
158
+ this.reflect("open", false);
159
+ this.open.set(false);
160
+ this.events.emit("close");
161
+ });
162
+ this.on(dialog, "click", (event) => {
163
+ if (event.target === dialog) this.close();
164
+ });
165
+ this.renderOpen(this.open.get());
166
+ }
167
+ toggleOnHotkey(event) {
168
+ const hotkey = this.hotkey.get();
169
+ if (hotkey === "" || hotkey === NO_HOTKEY || event.defaultPrevented) return;
170
+ if (!matchesHotkey(event, parseHotkey(hotkey), onApple())) return;
171
+ event.preventDefault();
172
+ this.open.set(!this.open.get());
173
+ }
174
+ navigate(event) {
175
+ const move = MOVES.get(event.key);
176
+ if (move !== void 0) {
177
+ event.preventDefault();
178
+ this.move(move);
179
+ return;
180
+ }
181
+ if (event.key === "Enter" && !event.isComposing) {
182
+ event.preventDefault();
183
+ this.choose(this._state.active);
184
+ }
185
+ }
186
+ indexOf(target) {
187
+ const option = target instanceof Element ? target.closest("[role=\"option\"]") : null;
188
+ return option === null ? null : Number(option.dataset.index);
189
+ }
190
+ move(step) {
191
+ const count = this._state.matches.length;
192
+ if (count === 0) return;
193
+ this.activate((this._state.active + step + count) % count);
194
+ }
195
+ choose(index) {
196
+ const match = this._state.matches[index];
197
+ if (match === void 0) return;
198
+ this.close();
199
+ this.events.emit("select", match.command.id);
200
+ }
201
+ renderOpen(open) {
202
+ const dialog = this._refs.dialog;
203
+ if (open === dialog.open || !this.isConnected) return;
204
+ if (!open) {
205
+ this.reflect("open", false);
206
+ dialog.close();
207
+ return;
208
+ }
209
+ this._refs.input.value = "";
210
+ this.renderResults();
211
+ dialog.showModal();
212
+ this._refs.input.focus();
213
+ this.reflect("open", true);
214
+ this.events.emit("open");
215
+ }
216
+ renderHotkey() {
217
+ const hotkey = this.hotkey.get();
218
+ const none = hotkey === "" || hotkey === NO_HOTKEY;
219
+ this._refs.hotkeyHint.hidden = none;
220
+ this._refs.hotkeyKeys.replaceChildren(...none ? [] : keycaps(hotkey));
221
+ }
222
+ renderResults() {
223
+ const groups = groupMatches(matchCommands(this.commands.get(), this._refs.input.value));
224
+ this._state.matches = groups.flatMap((group) => group.matches);
225
+ this._refs.results.replaceChildren(...groups.map((group, index) => this.groupNode(group, index)));
226
+ this._refs.results.hidden = this._state.matches.length === 0;
227
+ this._refs.empty.hidden = this._state.matches.length > 0;
228
+ this.activate(0);
229
+ }
230
+ groupNode(group, groupIndex) {
231
+ const first = this._state.matches.indexOf(group.matches[0]);
232
+ const options = group.matches.map((match, index) => this.optionNode(match, first + index));
233
+ if (group.label === "") return /* @__PURE__ */ jsx("div", {
234
+ role: "group",
235
+ children: options
236
+ });
237
+ const labelId = `group-${groupIndex}`;
238
+ return /* @__PURE__ */ jsxs("div", {
239
+ role: "group",
240
+ "aria-labelledby": labelId,
241
+ children: [/* @__PURE__ */ jsx("div", {
242
+ class: "group-label",
243
+ id: labelId,
244
+ "aria-hidden": "true",
245
+ children: group.label
246
+ }), options]
247
+ });
248
+ }
249
+ optionNode(match, index) {
250
+ const { command } = match;
251
+ const icon = command.icon === void 0 ? /* @__PURE__ */ jsx("span", { class: "option-icon" }) : /* @__PURE__ */ jsx(JlIcon, {
252
+ class: "option-icon",
253
+ name: command.icon,
254
+ size: OPTION_ICON_SIZE
255
+ });
256
+ return /* @__PURE__ */ jsxs("div", {
257
+ class: "option",
258
+ role: "option",
259
+ id: optionId(index),
260
+ "data-index": index,
261
+ "aria-selected": "false",
262
+ children: [
263
+ icon,
264
+ /* @__PURE__ */ jsx("span", {
265
+ class: "option-label",
266
+ children: highlighted(command.label, match.positions)
267
+ }),
268
+ command.shortcut === void 0 ? null : /* @__PURE__ */ jsx("span", {
269
+ class: "keys",
270
+ children: keycaps(command.shortcut)
271
+ })
272
+ ]
273
+ });
274
+ }
275
+ activate(index) {
276
+ this._state.active = index;
277
+ const options = this._refs.results.querySelectorAll("[role=\"option\"]");
278
+ for (const option of options) option.setAttribute("aria-selected", String(Number(option.dataset.index) === index));
279
+ const active = options[index];
280
+ setOrRemove(this._refs.input, "aria-activedescendant", active === void 0 ? "" : optionId(index));
281
+ active?.scrollIntoView({ block: "nearest" });
282
+ }
283
+ };
284
+ JlCommandPalette.register();
285
+ export { JlCommandPalette };
@@ -0,0 +1,3 @@
1
+ // src/organisms/jl-confirm.css?raw
2
+ var jl_confirm_default = ":host {\n display: contents;\n}\n\n.text {\n color: var(--jl-text-2);\n}\n";
3
+ export { jl_confirm_default as default };
@@ -0,0 +1,56 @@
1
+ import { JlElement } from '../base/jl-element';
2
+ import type { ConfirmOptions, ConfirmTone } from '../types/jl-confirm.types';
3
+ export declare const CONFIRM_TONES: readonly ConfirmTone[];
4
+ /**
5
+ * A yes-or-no question in a small modal dialog. `ask()` opens it and resolves `true` on confirm, `false` on cancel,
6
+ * Escape or a click outside. Most pages call `confirmDialog({ heading, text })`, which makes one, asks, and removes
7
+ * it. With the danger tone the confirm button is red and the focus starts on Cancel.
8
+ */
9
+ export declare class JlConfirm extends JlElement {
10
+ static readonly selector = "jl-confirm";
11
+ readonly events: Readonly<import("@jadis/core").UseEventsHandler<{
12
+ confirm: undefined;
13
+ cancel: undefined;
14
+ }>>;
15
+ readonly heading: Readonly<Readonly<{
16
+ get(): string;
17
+ set(setter: string | ((prevState: string) => string)): void;
18
+ }>>;
19
+ readonly text: Readonly<Readonly<{
20
+ get(): string;
21
+ set(setter: string | ((prevState: string) => string)): void;
22
+ }>>;
23
+ readonly confirmLabel: Readonly<Readonly<{
24
+ get(): string;
25
+ set(setter: string | ((prevState: string) => string)): void;
26
+ }>>;
27
+ readonly cancelLabel: Readonly<Readonly<{
28
+ get(): string;
29
+ set(setter: string | ((prevState: string) => string)): void;
30
+ }>>;
31
+ readonly tone: Readonly<Readonly<{
32
+ get(): ConfirmTone;
33
+ set(setter: ((prevState: ConfirmTone) => ConfirmTone) | ConfirmTone): void;
34
+ }>>;
35
+ private readonly _question;
36
+ private readonly _refs;
37
+ /** Opens the question; resolves `true` when confirmed, `false` otherwise. Asking again while open waits for the same answer. */
38
+ ask(): Promise<boolean>;
39
+ templateHtml(): Node;
40
+ templateCss(): string;
41
+ onConnect(): void;
42
+ /** Every way the dialog closes ends in its close event: that is where the answer is given. */
43
+ private openFor;
44
+ /** Cancel for a dangerous question, so that a quick Enter never destroys anything; confirm otherwise. */
45
+ private focusFirst;
46
+ private answer;
47
+ }
48
+ /**
49
+ * Asks a yes-or-no question in a modal dialog and resolves the answer: `true` on confirm, `false` on cancel,
50
+ * Escape or a click outside. The dialog is removed once answered.
51
+ *
52
+ * ```ts
53
+ * if (await confirmDialog({ heading: 'Delete the file?', tone: 'danger', confirmLabel: 'Delete' })) { … }
54
+ * ```
55
+ */
56
+ export declare function confirmDialog(options: ConfirmOptions): Promise<boolean>;
@@ -0,0 +1,132 @@
1
+ import { BASE_STYLES } from "../styles/shared.js";
2
+ import { JlElement } from "../base/jl-element.js";
3
+ import { oneOf } from "../lib/attributes.js";
4
+ import { define } from "../lib/define.js";
5
+ import { JlButton } from "../atoms/jl-button.js";
6
+ import jl_confirm_default from "./jl-confirm.css_raw.js";
7
+ import { JlDialog } from "./jl-dialog.js";
8
+ import { css } from "@jadis/core";
9
+ import { jsx, jsxs } from "@jadis/core/jsx-runtime";
10
+ // src/organisms/jl-confirm.tsx
11
+ define(JlDialog);
12
+ var CONFIRM_TONES = ["accent", "danger"];
13
+ var CONFIRM_VARIANTS = {
14
+ accent: "primary",
15
+ danger: "danger"
16
+ };
17
+ var DEFAULT_CONFIRM = "Confirm";
18
+ var DEFAULT_CANCEL = "Cancel";
19
+ var CLOSE = "close";
20
+ /**
21
+ * A yes-or-no question in a small modal dialog. `ask()` opens it and resolves `true` on confirm, `false` on cancel,
22
+ * Escape or a click outside. Most pages call `confirmDialog({ heading, text })`, which makes one, asks, and removes
23
+ * it. With the danger tone the confirm button is red and the focus starts on Cancel.
24
+ */
25
+ var JlConfirm = class extends JlElement {
26
+ static selector = "jl-confirm";
27
+ events = this.useEvents();
28
+ heading = this.useChange("", (value) => this._refs.dialog.heading.set(value), { attribute: "heading" });
29
+ text = this.useChange("", (value) => {
30
+ this._refs.text.textContent = value;
31
+ this._refs.text.hidden = value === "";
32
+ }, { attribute: "text" });
33
+ confirmLabel = this.useChange(DEFAULT_CONFIRM, (value) => this._refs.confirm.label.set(value), { attribute: "confirm-label" });
34
+ cancelLabel = this.useChange(DEFAULT_CANCEL, (value) => this._refs.cancel.label.set(value), { attribute: "cancel-label" });
35
+ tone = this.useChange("accent", (value) => {
36
+ this.reflect("tone", value);
37
+ this._refs.confirm.variant.set(CONFIRM_VARIANTS[value]);
38
+ }, {
39
+ attribute: "tone",
40
+ parse: oneOf(CONFIRM_TONES, "accent")
41
+ });
42
+ _question = {
43
+ confirmed: false,
44
+ pending: null
45
+ };
46
+ _refs = this.useRefs((ref) => ({
47
+ cancel: ref(".cancel"),
48
+ confirm: ref(".confirm"),
49
+ dialog: ref("jl-dialog"),
50
+ text: ref(".text")
51
+ }));
52
+ /** Opens the question; resolves `true` when confirmed, `false` otherwise. Asking again while open waits for the same answer. */
53
+ ask() {
54
+ const pending = this._question.pending ?? new Promise((resolve) => this.whenRendered(() => this.openFor(resolve)));
55
+ this._question.pending = pending;
56
+ return pending;
57
+ }
58
+ templateHtml() {
59
+ return /* @__PURE__ */ jsxs("jl-dialog", {
60
+ size: "sm",
61
+ children: [
62
+ /* @__PURE__ */ jsx("p", {
63
+ class: "text",
64
+ hidden: true
65
+ }),
66
+ /* @__PURE__ */ jsx("slot", {}),
67
+ /* @__PURE__ */ jsx(JlButton, {
68
+ slot: "actions",
69
+ class: "cancel",
70
+ label: DEFAULT_CANCEL
71
+ }),
72
+ /* @__PURE__ */ jsx(JlButton, {
73
+ slot: "actions",
74
+ class: "confirm",
75
+ variant: "primary",
76
+ label: DEFAULT_CONFIRM
77
+ })
78
+ ]
79
+ });
80
+ }
81
+ templateCss() {
82
+ return css`${BASE_STYLES}${jl_confirm_default}`;
83
+ }
84
+ onConnect() {
85
+ this._refs.cancel.events.register("press", () => this._refs.dialog.close());
86
+ this._refs.confirm.events.register("press", () => {
87
+ this._question.confirmed = true;
88
+ this._refs.dialog.close();
89
+ });
90
+ }
91
+ /** Every way the dialog closes ends in its close event: that is where the answer is given. */
92
+ openFor(resolve) {
93
+ const dialog = this._refs.dialog;
94
+ this._question.confirmed = false;
95
+ dialog.addEventListener(CLOSE, () => this.answer(resolve), { once: true });
96
+ dialog.show();
97
+ window.setTimeout(() => this.focusFirst());
98
+ }
99
+ /** Cancel for a dangerous question, so that a quick Enter never destroys anything; confirm otherwise. */
100
+ focusFirst() {
101
+ if (this._question.pending === null) return;
102
+ (this.tone.get() === "danger" ? this._refs.cancel : this._refs.confirm).focus();
103
+ }
104
+ answer(resolve) {
105
+ const confirmed = this._question.confirmed;
106
+ this._question.pending = null;
107
+ this._question.confirmed = false;
108
+ this.events.emit(confirmed ? "confirm" : "cancel");
109
+ resolve(confirmed);
110
+ }
111
+ };
112
+ JlConfirm.register();
113
+ /**
114
+ * Asks a yes-or-no question in a modal dialog and resolves the answer: `true` on confirm, `false` on cancel,
115
+ * Escape or a click outside. The dialog is removed once answered.
116
+ *
117
+ * ```ts
118
+ * if (await confirmDialog({ heading: 'Delete the file?', tone: 'danger', confirmLabel: 'Delete' })) { … }
119
+ * ```
120
+ */
121
+ function confirmDialog(options) {
122
+ const element = /* @__PURE__ */ jsx(JlConfirm, {
123
+ heading: options.heading,
124
+ text: options.text,
125
+ confirmLabel: options.confirmLabel,
126
+ cancelLabel: options.cancelLabel,
127
+ tone: options.tone
128
+ });
129
+ document.body.append(element);
130
+ return element.ask().finally(() => element.remove());
131
+ }
132
+ export { CONFIRM_TONES, JlConfirm, confirmDialog };
@@ -0,0 +1,3 @@
1
+ // src/organisms/jl-dialog.css?raw
2
+ var jl_dialog_default = ":host {\n display: contents;\n --width: 520px;\n}\n\n:host([size=\"sm\"]) {\n --width: 400px;\n}\n\n:host([size=\"lg\"]) {\n --width: 820px;\n}\n\n:host([size=\"full\"]) {\n --width: 100vw;\n}\n\ndialog {\n display: flex;\n flex-direction: column;\n width: min(var(--width), calc(100vw - 32px));\n max-height: min(760px, calc(100dvh - 48px));\n padding: 0;\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 box-shadow: var(--jl-shadow-lg);\n}\n\ndialog:not([open]) {\n display: none;\n}\n\n:host([size=\"full\"]) dialog {\n max-height: calc(100dvh - 32px);\n height: calc(100dvh - 32px);\n}\n\ndialog[open] {\n animation: rise var(--jl-slow) var(--jl-ease);\n}\n\ndialog::backdrop {\n background: var(--jl-scrim);\n backdrop-filter: blur(2px);\n}\n\nheader {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 20px 16px 4px 24px;\n}\n\n.titles {\n display: grid;\n flex: 1;\n gap: 4px;\n padding-top: 4px;\n}\n\nh2 {\n font-size: 17px;\n font-weight: 650;\n letter-spacing: -0.01em;\n line-height: 1.3;\n}\n\n.description {\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n line-height: 1.5;\n}\n\n.body {\n flex: 1;\n padding: 16px 24px;\n overflow: auto;\n line-height: 1.55;\n}\n\nfooter {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-end;\n gap: 8px;\n padding: 0 24px 20px;\n}\n\n@keyframes rise {\n from {\n opacity: 0;\n transform: translateY(8px) scale(0.98);\n }\n}\n";
3
+ export { jl_dialog_default as default };
@@ -0,0 +1,43 @@
1
+ import { JlElement } from '../base/jl-element';
2
+ import type { DialogSize } from '../types/jl-dialog.types';
3
+ export declare const DIALOG_SIZES: readonly DialogSize[];
4
+ /**
5
+ * A modal window over the page, on the browser's own `<dialog>`: focus stays inside, Escape closes it. The
6
+ * content goes in the default slot, the buttons in `slot="actions"`. Open it with `open` or `show()`.
7
+ */
8
+ export declare class JlDialog extends JlElement {
9
+ static readonly selector = "jl-dialog";
10
+ readonly events: Readonly<import("@jadis/core").UseEventsHandler<{
11
+ open: undefined;
12
+ close: undefined;
13
+ }>>;
14
+ readonly heading: Readonly<Readonly<{
15
+ get(): string;
16
+ set(setter: string | ((prevState: string) => string)): void;
17
+ }>>;
18
+ readonly description: Readonly<Readonly<{
19
+ get(): string;
20
+ set(setter: string | ((prevState: string) => string)): void;
21
+ }>>;
22
+ readonly size: Readonly<Readonly<{
23
+ get(): DialogSize;
24
+ set(setter: ((prevState: DialogSize) => DialogSize) | DialogSize): void;
25
+ }>>;
26
+ readonly open: Readonly<Readonly<{
27
+ get(): boolean;
28
+ set(setter: boolean | ((prevState: boolean) => boolean)): void;
29
+ }>>;
30
+ /** Keeps the dialog open on Escape and on a click outside: only its own buttons close it. */
31
+ readonly persistent: Readonly<Readonly<{
32
+ get(): boolean;
33
+ set(setter: boolean | ((prevState: boolean) => boolean)): void;
34
+ }>>;
35
+ private readonly _refs;
36
+ show(): void;
37
+ close(): void;
38
+ templateHtml(): Node;
39
+ templateCss(): string;
40
+ onConnect(): void;
41
+ private renderFooter;
42
+ private renderOpen;
43
+ }
@@ -0,0 +1,120 @@
1
+ import { BASE_STYLES } from "../styles/shared.js";
2
+ import { JlElement } from "../base/jl-element.js";
3
+ import { oneOf } from "../lib/attributes.js";
4
+ import { registerIcons } from "../lib/icons.js";
5
+ import { JlButton } from "../atoms/jl-button.js";
6
+ import jl_dialog_default from "./jl-dialog.css_raw.js";
7
+ import { css } from "@jadis/core";
8
+ import { X } from "lucide";
9
+ import { jsx, jsxs } from "@jadis/core/jsx-runtime";
10
+ // src/organisms/jl-dialog.tsx
11
+ registerIcons({ x: X });
12
+ var DIALOG_SIZES = [
13
+ "md",
14
+ "sm",
15
+ "lg",
16
+ "full"
17
+ ];
18
+ /**
19
+ * A modal window over the page, on the browser's own `<dialog>`: focus stays inside, Escape closes it. The
20
+ * content goes in the default slot, the buttons in `slot="actions"`. Open it with `open` or `show()`.
21
+ */
22
+ var JlDialog = class extends JlElement {
23
+ static selector = "jl-dialog";
24
+ events = this.useEvents();
25
+ heading = this.useChange("", (value) => {
26
+ this._refs.heading.textContent = value;
27
+ }, { attribute: "heading" });
28
+ description = this.useChange("", (value) => {
29
+ this._refs.description.textContent = value;
30
+ this._refs.description.hidden = value === "";
31
+ }, { attribute: "description" });
32
+ size = this.useChange("md", (value) => this.reflect("size", value), {
33
+ attribute: "size",
34
+ parse: oneOf(DIALOG_SIZES, "md")
35
+ });
36
+ open = this.useChange(false, (value) => this.renderOpen(value), { attribute: "open" });
37
+ /** Keeps the dialog open on Escape and on a click outside: only its own buttons close it. */
38
+ persistent = this.useChange(false, (value) => {
39
+ this._refs.close.hidden = value;
40
+ }, { attribute: "persistent" });
41
+ _refs = this.useRefs((ref) => ({
42
+ actions: ref("slot[name=\"actions\"]"),
43
+ close: ref(".close"),
44
+ description: ref(".description"),
45
+ dialog: ref("dialog"),
46
+ footer: ref("footer"),
47
+ heading: ref("h2")
48
+ }));
49
+ show() {
50
+ this.open.set(true);
51
+ }
52
+ close() {
53
+ this.open.set(false);
54
+ }
55
+ templateHtml() {
56
+ return /* @__PURE__ */ jsxs("dialog", {
57
+ attrs: { part: "base" },
58
+ "aria-labelledby": "heading",
59
+ children: [
60
+ /* @__PURE__ */ jsxs("header", { children: [/* @__PURE__ */ jsxs("div", {
61
+ class: "titles",
62
+ children: [/* @__PURE__ */ jsx("h2", { id: "heading" }), /* @__PURE__ */ jsx("p", {
63
+ class: "description",
64
+ hidden: true
65
+ })]
66
+ }), /* @__PURE__ */ jsx(JlButton, {
67
+ class: "close",
68
+ variant: "ghost",
69
+ icon: "x",
70
+ hint: "Close",
71
+ size: "sm"
72
+ })] }),
73
+ /* @__PURE__ */ jsx("div", {
74
+ class: "body",
75
+ children: /* @__PURE__ */ jsx("slot", {})
76
+ }),
77
+ /* @__PURE__ */ jsx("footer", {
78
+ hidden: true,
79
+ children: /* @__PURE__ */ jsx("slot", { name: "actions" })
80
+ })
81
+ ]
82
+ });
83
+ }
84
+ templateCss() {
85
+ return css`${BASE_STYLES}${jl_dialog_default}`;
86
+ }
87
+ onConnect() {
88
+ const dialog = this._refs.dialog;
89
+ this._refs.close.events.register("press", () => this.close());
90
+ this.on(dialog, "close", () => {
91
+ this.open.set(false);
92
+ this.events.emit("close");
93
+ });
94
+ this.on(dialog, "cancel", (event) => {
95
+ if (this.persistent.get()) event.preventDefault();
96
+ });
97
+ this.on(dialog, "click", (event) => {
98
+ if (event.target === dialog && !this.persistent.get()) this.close();
99
+ });
100
+ this.renderFooter();
101
+ this.on(this._refs.actions, "slotchange", () => this.renderFooter());
102
+ }
103
+ renderFooter() {
104
+ this._refs.footer.hidden = this._refs.actions.assignedElements().length === 0;
105
+ }
106
+ renderOpen(open) {
107
+ const dialog = this._refs.dialog;
108
+ this.reflect("open", open);
109
+ if (open === dialog.open || !this.isConnected) return;
110
+ if (open) {
111
+ this.renderFooter();
112
+ dialog.showModal();
113
+ this.events.emit("open");
114
+ return;
115
+ }
116
+ dialog.close();
117
+ }
118
+ };
119
+ JlDialog.register();
120
+ export { DIALOG_SIZES, JlDialog };
@@ -0,0 +1,3 @@
1
+ // src/organisms/jl-drawer.css?raw
2
+ var jl_drawer_default = ":host {\n display: contents;\n --size: 420px;\n --from: translateX(100%);\n}\n\n:host([size=\"sm\"]) {\n --size: 320px;\n}\n\n:host([size=\"lg\"]) {\n --size: 640px;\n}\n\n:host([placement=\"left\"]) {\n --from: translateX(-100%);\n}\n\n:host([placement=\"bottom\"]) {\n --size: 60dvh;\n --from: translateY(100%);\n}\n\n:host([placement=\"bottom\"][size=\"sm\"]) {\n --size: 40dvh;\n}\n\n:host([placement=\"bottom\"][size=\"lg\"]) {\n --size: 88dvh;\n}\n\ndialog {\n position: fixed;\n inset: 0 0 0 auto;\n display: none;\n flex-direction: column;\n width: min(var(--size), calc(100vw - 24px));\n max-width: none;\n height: 100dvh;\n max-height: none;\n margin: 0;\n padding: 0;\n border: none;\n border-left: 1px solid var(--jl-line);\n background: var(--jl-surface);\n color: var(--jl-text);\n font-size: var(--jl-font-md);\n box-shadow: var(--jl-shadow-lg);\n transform: var(--from);\n /* display and overlay stay until the slide out ends, so closing animates too. */\n transition:\n transform var(--jl-slow) var(--jl-ease),\n display var(--jl-slow) allow-discrete,\n overlay var(--jl-slow) allow-discrete;\n}\n\ndialog[open] {\n display: flex;\n transform: none;\n}\n\n@starting-style {\n dialog[open] {\n transform: var(--from);\n }\n}\n\n:host([placement=\"left\"]) dialog {\n inset: 0 auto 0 0;\n border-right: 1px solid var(--jl-line);\n border-left: none;\n}\n\n:host([placement=\"bottom\"]) dialog {\n inset: auto 0 0;\n width: 100%;\n height: auto;\n max-height: var(--size);\n border: 1px solid var(--jl-line);\n border-bottom: none;\n border-radius: var(--jl-radius-xl) var(--jl-radius-xl) 0 0;\n}\n\ndialog::backdrop {\n background: transparent;\n transition:\n background var(--jl-slow) var(--jl-ease),\n display var(--jl-slow) allow-discrete,\n overlay var(--jl-slow) allow-discrete;\n}\n\ndialog[open]::backdrop {\n background: var(--jl-scrim);\n}\n\n@starting-style {\n dialog[open]::backdrop {\n background: transparent;\n }\n}\n\n.handle {\n display: none;\n}\n\n:host([placement=\"bottom\"]) .handle {\n display: block;\n flex: none;\n width: 40px;\n height: 4px;\n margin: 10px auto 0;\n border-radius: var(--jl-radius-pill);\n background: var(--jl-line-strong);\n}\n\nheader {\n display: flex;\n flex: none;\n align-items: flex-start;\n gap: 12px;\n padding: 18px 16px 14px 24px;\n border-bottom: 1px solid var(--jl-line);\n}\n\n:host([placement=\"bottom\"]) header {\n padding-top: 10px;\n}\n\n.titles {\n display: grid;\n flex: 1;\n gap: 4px;\n min-width: 0;\n padding-top: 4px;\n}\n\nh2 {\n font-size: 17px;\n font-weight: 650;\n letter-spacing: -0.01em;\n line-height: 1.3;\n}\n\n.description {\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n line-height: 1.5;\n}\n\n.actions {\n display: flex;\n flex: none;\n align-items: center;\n gap: 4px;\n}\n\n.body {\n flex: 1;\n min-height: 0;\n padding: 20px 24px;\n overflow: auto;\n line-height: 1.55;\n overscroll-behavior: contain;\n}\n\nfooter {\n display: flex;\n flex: none;\n flex-wrap: wrap;\n justify-content: flex-end;\n gap: 8px;\n padding: 14px 24px;\n border-top: 1px solid var(--jl-line);\n background: var(--jl-surface);\n}\n\n:host([placement=\"bottom\"]) footer {\n padding-bottom: max(14px, env(safe-area-inset-bottom));\n}\n";
3
+ export { jl_drawer_default as default };