@gjermundgaraba/pixel-paper 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (387) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +50 -2
  3. package/dist/_virtual/_rolldown/runtime.js +13 -0
  4. package/dist/announcer/announcer.d.ts +35 -0
  5. package/dist/announcer/announcer.js +121 -0
  6. package/dist/announcer/index.d.ts +5 -0
  7. package/dist/announcer/index.js +11 -0
  8. package/dist/attributes/attributes.d.ts +4 -0
  9. package/dist/banner/banner.d.ts +20 -0
  10. package/dist/banner/banner.js +18 -0
  11. package/dist/banner/index.d.ts +5 -0
  12. package/dist/banner/index.js +6 -0
  13. package/dist/bench/bench.d.ts +16 -0
  14. package/dist/bench/bench.js +12 -0
  15. package/dist/bench/index.d.ts +5 -0
  16. package/dist/bench/index.js +6 -0
  17. package/dist/board/board.d.ts +1151 -0
  18. package/dist/board/board.js +449 -0
  19. package/dist/board/index.d.ts +6 -0
  20. package/dist/board/index.js +21 -0
  21. package/dist/button/button.d.ts +54 -0
  22. package/dist/button/button.js +50 -0
  23. package/dist/button/index.d.ts +5 -0
  24. package/dist/button/index.js +9 -0
  25. package/dist/card/card.d.ts +66 -0
  26. package/dist/card/card.js +70 -0
  27. package/dist/card/index.d.ts +5 -0
  28. package/dist/card/index.js +10 -0
  29. package/dist/chip/chip.d.ts +27 -0
  30. package/dist/chip/chip.js +34 -0
  31. package/dist/chip/index.d.ts +5 -0
  32. package/dist/chip/index.js +9 -0
  33. package/dist/choice/choice.d.ts +16 -0
  34. package/dist/choice/choice.js +17 -0
  35. package/dist/choice/index.d.ts +5 -0
  36. package/dist/choice/index.js +6 -0
  37. package/dist/code-editor/code-editor.d.ts +15 -0
  38. package/dist/code-editor/code-editor.js +22 -0
  39. package/dist/code-editor/index.d.ts +5 -0
  40. package/dist/code-editor/index.js +6 -0
  41. package/dist/code-surface/code-surface.d.ts +12 -0
  42. package/dist/code-surface/code-surface.js +12 -0
  43. package/dist/code-surface/index.d.ts +5 -0
  44. package/dist/code-surface/index.js +6 -0
  45. package/dist/command-palette/command-palette.d.ts +579 -0
  46. package/dist/command-palette/command-palette.js +600 -0
  47. package/dist/command-palette/index.d.ts +9 -0
  48. package/dist/command-palette/index.js +32 -0
  49. package/dist/command-palette/keys.d.ts +13 -0
  50. package/dist/command-palette/keys.js +71 -0
  51. package/dist/command-palette/match.d.ts +43 -0
  52. package/dist/command-palette/match.js +45 -0
  53. package/dist/command-palette/message.d.ts +94 -0
  54. package/dist/command-palette/message.js +46 -0
  55. package/dist/confirm-dialog/confirm-dialog.d.ts +287 -0
  56. package/dist/confirm-dialog/confirm-dialog.js +115 -0
  57. package/dist/confirm-dialog/index.d.ts +5 -0
  58. package/dist/confirm-dialog/index.js +17 -0
  59. package/dist/copy-button/copy-button.d.ts +99 -0
  60. package/dist/copy-button/copy-button.js +96 -0
  61. package/dist/copy-button/index.d.ts +5 -0
  62. package/dist/copy-button/index.js +13 -0
  63. package/dist/crumbs/crumbs.d.ts +15 -0
  64. package/dist/crumbs/crumbs.js +11 -0
  65. package/dist/crumbs/index.d.ts +5 -0
  66. package/dist/crumbs/index.js +6 -0
  67. package/dist/deck/deck.d.ts +9 -0
  68. package/dist/deck/deck.js +9 -0
  69. package/dist/deck/index.d.ts +5 -0
  70. package/dist/deck/index.js +6 -0
  71. package/dist/dialog/dialog.d.ts +278 -0
  72. package/dist/dialog/dialog.js +145 -0
  73. package/dist/dialog/fold.d.ts +58 -0
  74. package/dist/dialog/fold.js +63 -0
  75. package/dist/dialog/index.d.ts +6 -0
  76. package/dist/dialog/index.js +21 -0
  77. package/dist/disclosure/disclosure.d.ts +24 -0
  78. package/dist/disclosure/disclosure.js +25 -0
  79. package/dist/disclosure/index.d.ts +5 -0
  80. package/dist/disclosure/index.js +6 -0
  81. package/dist/dom/html-element.js +8 -0
  82. package/dist/drag/drag.d.ts +15 -0
  83. package/dist/drag/drag.js +123 -0
  84. package/dist/drop-zone/drop-zone.d.ts +119 -0
  85. package/dist/drop-zone/drop-zone.js +64 -0
  86. package/dist/drop-zone/index.d.ts +5 -0
  87. package/dist/drop-zone/index.js +14 -0
  88. package/dist/empty-state/empty-state.d.ts +18 -0
  89. package/dist/empty-state/empty-state.js +16 -0
  90. package/dist/empty-state/index.d.ts +5 -0
  91. package/dist/empty-state/index.js +6 -0
  92. package/dist/error-summary/error-summary.d.ts +34 -0
  93. package/dist/error-summary/error-summary.js +33 -0
  94. package/dist/error-summary/index.d.ts +5 -0
  95. package/dist/error-summary/index.js +6 -0
  96. package/dist/field/field.d.ts +35 -0
  97. package/dist/field/field.js +34 -0
  98. package/dist/field/index.d.ts +5 -0
  99. package/dist/field/index.js +6 -0
  100. package/dist/field-grid/field-grid.d.ts +8 -0
  101. package/dist/field-grid/field-grid.js +8 -0
  102. package/dist/field-grid/index.d.ts +5 -0
  103. package/dist/field-grid/index.js +6 -0
  104. package/dist/fields/fields.js +9 -0
  105. package/dist/fieldset/fieldset.d.ts +13 -0
  106. package/dist/fieldset/fieldset.js +13 -0
  107. package/dist/fieldset/index.d.ts +5 -0
  108. package/dist/fieldset/index.js +6 -0
  109. package/dist/filter-chip/filter-chip.d.ts +21 -0
  110. package/dist/filter-chip/filter-chip.js +28 -0
  111. package/dist/filter-chip/index.d.ts +5 -0
  112. package/dist/filter-chip/index.js +6 -0
  113. package/dist/filter-strip/filter-strip.d.ts +12 -0
  114. package/dist/filter-strip/filter-strip.js +13 -0
  115. package/dist/filter-strip/index.d.ts +5 -0
  116. package/dist/filter-strip/index.js +6 -0
  117. package/dist/flash-word/flash-word.d.ts +31 -0
  118. package/dist/flash-word/flash-word.js +31 -0
  119. package/dist/flash-word/index.d.ts +5 -0
  120. package/dist/flash-word/index.js +9 -0
  121. package/dist/focus/focus.d.ts +15 -0
  122. package/dist/focus/focus.js +17 -0
  123. package/dist/focus/index.d.ts +5 -0
  124. package/dist/focus/index.js +9 -0
  125. package/dist/format/format.js +52 -0
  126. package/dist/format/index.d.ts +5 -0
  127. package/dist/format/index.js +6 -0
  128. package/dist/glyph/glyph.d.ts +9 -0
  129. package/dist/glyph/glyph.js +25 -0
  130. package/dist/glyph/glyphs.d.ts +381 -0
  131. package/dist/glyph/glyphs.js +2603 -0
  132. package/dist/glyph/index.d.ts +5 -0
  133. package/dist/glyph/index.js +6 -0
  134. package/dist/group/group.d.ts +8 -0
  135. package/dist/group/group.js +9 -0
  136. package/dist/group/index.d.ts +5 -0
  137. package/dist/group/index.js +6 -0
  138. package/dist/history/history.d.ts +34 -0
  139. package/dist/history/history.js +15 -0
  140. package/dist/history/index.d.ts +5 -0
  141. package/dist/history/index.js +6 -0
  142. package/dist/icon-button/icon-button.d.ts +23 -0
  143. package/dist/icon-button/icon-button.js +23 -0
  144. package/dist/icon-button/index.d.ts +5 -0
  145. package/dist/icon-button/index.js +6 -0
  146. package/dist/identity/identity.d.ts +15 -0
  147. package/dist/identity/identity.js +15 -0
  148. package/dist/identity/index.d.ts +5 -0
  149. package/dist/identity/index.js +6 -0
  150. package/dist/index.d.ts +85 -0
  151. package/dist/index.js +85 -0
  152. package/dist/inline-input/index.d.ts +5 -0
  153. package/dist/inline-input/index.js +20 -0
  154. package/dist/inline-input/inline-input.d.ts +196 -0
  155. package/dist/inline-input/inline-input.js +212 -0
  156. package/dist/key-help/index.d.ts +5 -0
  157. package/dist/key-help/index.js +18 -0
  158. package/dist/key-help/key-help.d.ts +255 -0
  159. package/dist/key-help/key-help.js +137 -0
  160. package/dist/key-hint/index.d.ts +6 -0
  161. package/dist/key-hint/index.js +12 -0
  162. package/dist/key-hint/key-hint.d.ts +13 -0
  163. package/dist/key-hint/key-hint.js +7 -0
  164. package/dist/key-hint/key-label.d.ts +18 -0
  165. package/dist/key-hint/key-label.js +77 -0
  166. package/dist/keymap/keymap.d.ts +11 -0
  167. package/dist/keymap/keymap.js +9 -0
  168. package/dist/keys/keys.js +4 -0
  169. package/dist/line-diff/diff.d.ts +2 -0
  170. package/dist/line-diff/diff.js +73 -0
  171. package/dist/line-diff/index.d.ts +6 -0
  172. package/dist/line-diff/index.js +10 -0
  173. package/dist/line-diff/line-diff.d.ts +21 -0
  174. package/dist/line-diff/line-diff.js +75 -0
  175. package/dist/line-diff/patch.d.ts +15 -0
  176. package/dist/line-diff/patch.js +120 -0
  177. package/dist/link-button/index.d.ts +5 -0
  178. package/dist/link-button/index.js +6 -0
  179. package/dist/link-button/link-button.d.ts +11 -0
  180. package/dist/link-button/link-button.js +10 -0
  181. package/dist/link-state/index.d.ts +5 -0
  182. package/dist/link-state/index.js +6 -0
  183. package/dist/link-state/link-state.d.ts +15 -0
  184. package/dist/link-state/link-state.js +17 -0
  185. package/dist/live-region/index.d.ts +5 -0
  186. package/dist/live-region/index.js +9 -0
  187. package/dist/live-region/live-region.d.ts +39 -0
  188. package/dist/live-region/live-region.js +33 -0
  189. package/dist/loading/index.d.ts +5 -0
  190. package/dist/loading/index.js +6 -0
  191. package/dist/loading/loading.d.ts +19 -0
  192. package/dist/loading/loading.js +16 -0
  193. package/dist/locale/locale.d.ts +3 -0
  194. package/dist/locale/locale.js +5 -0
  195. package/dist/mark/index.d.ts +5 -0
  196. package/dist/mark/index.js +6 -0
  197. package/dist/mark/mark.d.ts +15 -0
  198. package/dist/mark/mark.js +30 -0
  199. package/dist/menu/index.d.ts +7 -0
  200. package/dist/menu/index.js +25 -0
  201. package/dist/menu/item.d.ts +236 -0
  202. package/dist/menu/item.js +19 -0
  203. package/dist/menu/menu.d.ts +206 -0
  204. package/dist/menu/menu.js +208 -0
  205. package/dist/menu/slip.js +163 -0
  206. package/dist/meter/index.d.ts +5 -0
  207. package/dist/meter/index.js +6 -0
  208. package/dist/meter/meter.d.ts +38 -0
  209. package/dist/meter/meter.js +69 -0
  210. package/dist/monogram/monogram.js +33 -0
  211. package/dist/nav-strip/index.d.ts +5 -0
  212. package/dist/nav-strip/index.js +6 -0
  213. package/dist/nav-strip/nav-strip.d.ts +19 -0
  214. package/dist/nav-strip/nav-strip.js +21 -0
  215. package/dist/notice/index.d.ts +5 -0
  216. package/dist/notice/index.js +6 -0
  217. package/dist/notice/notice.d.ts +23 -0
  218. package/dist/notice/notice.js +35 -0
  219. package/dist/outcome/index.d.ts +5 -0
  220. package/dist/outcome/index.js +6 -0
  221. package/dist/outcome/outcome.d.ts +19 -0
  222. package/dist/outcome/outcome.js +14 -0
  223. package/dist/page-head/index.d.ts +5 -0
  224. package/dist/page-head/index.js +6 -0
  225. package/dist/page-head/page-head.d.ts +13 -0
  226. package/dist/page-head/page-head.js +10 -0
  227. package/dist/panel/index.d.ts +5 -0
  228. package/dist/panel/index.js +6 -0
  229. package/dist/panel/panel.d.ts +35 -0
  230. package/dist/panel/panel.js +25 -0
  231. package/dist/password-field/index.d.ts +5 -0
  232. package/dist/password-field/index.js +6 -0
  233. package/dist/password-field/password-field.d.ts +33 -0
  234. package/dist/password-field/password-field.js +39 -0
  235. package/dist/places/index.d.ts +5 -0
  236. package/dist/places/index.js +6 -0
  237. package/dist/places/places.d.ts +32 -0
  238. package/dist/places/places.js +22 -0
  239. package/dist/props-list/index.d.ts +5 -0
  240. package/dist/props-list/index.js +6 -0
  241. package/dist/props-list/props-list.d.ts +18 -0
  242. package/dist/props-list/props-list.js +12 -0
  243. package/dist/prose/index.d.ts +5 -0
  244. package/dist/prose/index.js +6 -0
  245. package/dist/prose/prose.d.ts +14 -0
  246. package/dist/prose/prose.js +6 -0
  247. package/dist/query-chip/index.d.ts +5 -0
  248. package/dist/query-chip/index.js +6 -0
  249. package/dist/query-chip/query-chip.d.ts +18 -0
  250. package/dist/query-chip/query-chip.js +17 -0
  251. package/dist/radio-choices/index.d.ts +5 -0
  252. package/dist/radio-choices/index.js +12 -0
  253. package/dist/radio-choices/radio-choices.d.ts +105 -0
  254. package/dist/radio-choices/radio-choices.js +56 -0
  255. package/dist/rail/index.d.ts +5 -0
  256. package/dist/rail/index.js +22 -0
  257. package/dist/rail/rail.d.ts +403 -0
  258. package/dist/rail/rail.js +355 -0
  259. package/dist/reel/index.d.ts +6 -0
  260. package/dist/reel/index.js +26 -0
  261. package/dist/reel/layout.d.ts +58 -0
  262. package/dist/reel/layout.js +378 -0
  263. package/dist/reel/reel.d.ts +1070 -0
  264. package/dist/reel/reel.js +1019 -0
  265. package/dist/remote/index.d.ts +5 -0
  266. package/dist/remote/index.js +6 -0
  267. package/dist/remote/remote.d.ts +28 -0
  268. package/dist/remote/remote.js +41 -0
  269. package/dist/rows/index.d.ts +5 -0
  270. package/dist/rows/index.js +12 -0
  271. package/dist/rows/rows.d.ts +116 -0
  272. package/dist/rows/rows.js +67 -0
  273. package/dist/scheme/index.d.ts +6 -0
  274. package/dist/scheme/index.js +10 -0
  275. package/dist/scheme/scheme-switch.d.ts +98 -0
  276. package/dist/scheme/scheme-switch.js +118 -0
  277. package/dist/scheme/scheme.d.ts +5 -0
  278. package/dist/scheme/scheme.js +16 -0
  279. package/dist/scheme/script.d.ts +8 -0
  280. package/dist/scheme/script.js +10 -0
  281. package/dist/secret/index.d.ts +5 -0
  282. package/dist/secret/index.js +6 -0
  283. package/dist/secret/secret.d.ts +13 -0
  284. package/dist/secret/secret.js +9 -0
  285. package/dist/segmented/index.d.ts +5 -0
  286. package/dist/segmented/index.js +6 -0
  287. package/dist/segmented/segmented.d.ts +17 -0
  288. package/dist/segmented/segmented.js +17 -0
  289. package/dist/select-field/index.d.ts +5 -0
  290. package/dist/select-field/index.js +6 -0
  291. package/dist/select-field/select-field.d.ts +38 -0
  292. package/dist/select-field/select-field.js +29 -0
  293. package/dist/sheet/index.d.ts +5 -0
  294. package/dist/sheet/index.js +6 -0
  295. package/dist/sheet/sheet.d.ts +16 -0
  296. package/dist/sheet/sheet.js +15 -0
  297. package/dist/skip-link/index.d.ts +5 -0
  298. package/dist/skip-link/index.js +9 -0
  299. package/dist/skip-link/skip-link.d.ts +23 -0
  300. package/dist/skip-link/skip-link.js +36 -0
  301. package/dist/slot/slot.js +8 -0
  302. package/dist/sortable/index.d.ts +5 -0
  303. package/dist/sortable/index.js +16 -0
  304. package/dist/sortable/sortable.d.ts +1125 -0
  305. package/dist/sortable/sortable.js +431 -0
  306. package/dist/stack/index.d.ts +5 -0
  307. package/dist/stack/index.js +6 -0
  308. package/dist/stack/stack.d.ts +15 -0
  309. package/dist/stack/stack.js +12 -0
  310. package/dist/stage/index.d.ts +5 -0
  311. package/dist/stage/index.js +6 -0
  312. package/dist/stage/stage.d.ts +14 -0
  313. package/dist/stage/stage.js +11 -0
  314. package/dist/stat/index.d.ts +5 -0
  315. package/dist/stat/index.js +6 -0
  316. package/dist/stat/stat.d.ts +18 -0
  317. package/dist/stat/stat.js +13 -0
  318. package/dist/status-bar/index.d.ts +6 -0
  319. package/dist/status-bar/index.js +11 -0
  320. package/dist/status-bar/status-bar.d.ts +28 -0
  321. package/dist/status-bar/status-bar.js +19 -0
  322. package/dist/subscription/prefix-keys.js +12 -0
  323. package/dist/table/index.d.ts +5 -0
  324. package/dist/table/index.js +6 -0
  325. package/dist/table/table.d.ts +26 -0
  326. package/dist/table/table.js +18 -0
  327. package/dist/tabs/index.d.ts +5 -0
  328. package/dist/tabs/index.js +14 -0
  329. package/dist/tabs/tabs.d.ts +125 -0
  330. package/dist/tabs/tabs.js +57 -0
  331. package/dist/tag/index.d.ts +5 -0
  332. package/dist/tag/index.js +6 -0
  333. package/dist/tag/tag.d.ts +16 -0
  334. package/dist/tag/tag.js +25 -0
  335. package/dist/text-button/index.d.ts +5 -0
  336. package/dist/text-button/index.js +6 -0
  337. package/dist/text-button/text-button.d.ts +8 -0
  338. package/dist/text-button/text-button.js +12 -0
  339. package/dist/textarea-field/index.d.ts +5 -0
  340. package/dist/textarea-field/index.js +6 -0
  341. package/dist/textarea-field/textarea-field.d.ts +28 -0
  342. package/dist/textarea-field/textarea-field.js +30 -0
  343. package/dist/time/index.d.ts +5 -0
  344. package/dist/time/index.js +9 -0
  345. package/dist/time/time.d.ts +38 -0
  346. package/dist/time/time.js +63 -0
  347. package/dist/tips/index.d.ts +5 -0
  348. package/dist/tips/index.js +14 -0
  349. package/dist/tips/tips.d.ts +339 -0
  350. package/dist/tips/tips.js +308 -0
  351. package/dist/toast/index.d.ts +5 -0
  352. package/dist/toast/index.js +17 -0
  353. package/dist/toast/stack.d.ts +7 -0
  354. package/dist/toast/stack.js +23 -0
  355. package/dist/toast/toast.d.ts +559 -0
  356. package/dist/toast/toast.js +269 -0
  357. package/dist/toc/index.d.ts +5 -0
  358. package/dist/toc/index.js +9 -0
  359. package/dist/toc/toc.d.ts +42 -0
  360. package/dist/toc/toc.js +35 -0
  361. package/dist/top-bar/bar-height.d.ts +26 -0
  362. package/dist/top-bar/bar-height.js +43 -0
  363. package/dist/top-bar/index.d.ts +6 -0
  364. package/dist/top-bar/index.js +12 -0
  365. package/dist/top-bar/top-bar.d.ts +19 -0
  366. package/dist/top-bar/top-bar.js +18 -0
  367. package/dist/wall/index.d.ts +5 -0
  368. package/dist/wall/index.js +9 -0
  369. package/dist/wall/wall.d.ts +16 -0
  370. package/dist/wall/wall.js +15 -0
  371. package/dist/window/index.d.ts +5 -0
  372. package/dist/window/index.js +6 -0
  373. package/dist/window/window.d.ts +28 -0
  374. package/dist/window/window.js +29 -0
  375. package/dist/wordmark/index.d.ts +5 -0
  376. package/dist/wordmark/index.js +6 -0
  377. package/dist/wordmark/wordmark.d.ts +10 -0
  378. package/dist/wordmark/wordmark.js +10 -0
  379. package/dist/wrap/index.d.ts +5 -0
  380. package/dist/wrap/index.js +6 -0
  381. package/dist/wrap/wrap.d.ts +12 -0
  382. package/dist/wrap/wrap.js +9 -0
  383. package/fonts/DepartureMono-Regular.woff2 +0 -0
  384. package/fonts/LICENSE.txt +2 -0
  385. package/package.json +57 -3
  386. package/src/pixel-paper.css +4611 -0
  387. package/src/tokens.css +151 -0
@@ -0,0 +1,236 @@
1
+ import { KeyHintConfig } from "../button/button.js";
2
+ import { Data } from "effect";
3
+ /** One entry in a menu. Build them with `action`, `radio`, `check`, `link` and `group`. */
4
+ export type Item = Data.TaggedEnum<{
5
+ /** An action (`role="menuitem"`): choosing it reports `Selected` with its id and closes the
6
+ * slip. */
7
+ Action: {
8
+ readonly id: string;
9
+ readonly label: string;
10
+ /** The key that does the same, printed at the right. */
11
+ readonly keyHint?: KeyHintConfig;
12
+ /** Visible but not possible now (`aria-disabled`): it prints muted, the arrows still stop
13
+ * on it (the ARIA menu pattern), and choosing it does nothing. */
14
+ readonly isDisabled?: boolean;
15
+ };
16
+ /** One choice among its siblings (`role="menuitemradio"`, `aria-checked`): a palette, an
17
+ * area, a layout. The checked one prints inverted. Choosing it reports `Selected` and
18
+ * closes the slip; the parent moves the check. Put a set of them in a `group`. */
19
+ Radio: {
20
+ readonly id: string;
21
+ readonly label: string;
22
+ readonly isChecked: boolean;
23
+ };
24
+ /** A setting that toggles (`role="menuitemcheckbox"`, `aria-checked`): choosing it reports
25
+ * `Toggled` and keeps the slip open; the parent flips the value it keeps. */
26
+ Check: {
27
+ readonly id: string;
28
+ readonly label: string;
29
+ readonly isChecked: boolean;
30
+ };
31
+ /** A place to go: a real link (`<a role="menuitem">`), so a new tab can open it. Choosing it
32
+ * follows the link, closes the slip and reports `Selected`. */
33
+ Link: {
34
+ readonly id: string;
35
+ readonly label: string;
36
+ readonly href: string;
37
+ };
38
+ /** Items under a heading (`role="group"`, named by the heading): `"Appearance"` over the
39
+ * palettes, `"Account"` over sign out. A set of radio items belongs in one. The label is
40
+ * the group's identity in its slip: two groups there do not share one. */
41
+ Group: {
42
+ readonly label: string;
43
+ readonly items: readonly Entry[];
44
+ };
45
+ }>;
46
+ /** One row of a menu or of a group: any item but a group. */
47
+ export type Entry = Exclude<Item, {
48
+ readonly _tag: "Group";
49
+ }>;
50
+ /** The constructors, guards (`$is`) and matcher (`$match`) of `Item`. */
51
+ export declare const Item: {
52
+ readonly $is: <Tag extends "Action" | "Check" | "Group" | "Link" | "Radio">(tag: Tag) => (u: unknown) => u is Extract<{
53
+ readonly _tag: "Action";
54
+ readonly id: string;
55
+ readonly label: string;
56
+ readonly keyHint?: KeyHintConfig;
57
+ readonly isDisabled?: boolean;
58
+ }, {
59
+ readonly _tag: Tag;
60
+ }> | Extract<{
61
+ readonly _tag: "Check";
62
+ readonly id: string;
63
+ readonly label: string;
64
+ readonly isChecked: boolean;
65
+ }, {
66
+ readonly _tag: Tag;
67
+ }> | Extract<{
68
+ readonly _tag: "Group";
69
+ readonly label: string;
70
+ readonly items: readonly Entry[];
71
+ }, {
72
+ readonly _tag: Tag;
73
+ }> | Extract<{
74
+ readonly _tag: "Link";
75
+ readonly id: string;
76
+ readonly label: string;
77
+ readonly href: string;
78
+ }, {
79
+ readonly _tag: Tag;
80
+ }> | Extract<{
81
+ readonly _tag: "Radio";
82
+ readonly id: string;
83
+ readonly label: string;
84
+ readonly isChecked: boolean;
85
+ }, {
86
+ readonly _tag: Tag;
87
+ }>;
88
+ readonly $match: {
89
+ <Cases extends { readonly [Tag in "Action" | "Check" | "Group" | "Link" | "Radio"]: (args: Extract<{
90
+ readonly _tag: "Action";
91
+ readonly id: string;
92
+ readonly label: string;
93
+ readonly keyHint?: KeyHintConfig;
94
+ readonly isDisabled?: boolean;
95
+ } | {
96
+ readonly _tag: "Check";
97
+ readonly id: string;
98
+ readonly label: string;
99
+ readonly isChecked: boolean;
100
+ } | {
101
+ readonly _tag: "Group";
102
+ readonly label: string;
103
+ readonly items: readonly Entry[];
104
+ } | {
105
+ readonly _tag: "Link";
106
+ readonly id: string;
107
+ readonly label: string;
108
+ readonly href: string;
109
+ } | {
110
+ readonly _tag: "Radio";
111
+ readonly id: string;
112
+ readonly label: string;
113
+ readonly isChecked: boolean;
114
+ }, {
115
+ readonly _tag: Tag;
116
+ }>) => any; }>(cases: Cases): (value: {
117
+ readonly _tag: "Action";
118
+ readonly id: string;
119
+ readonly label: string;
120
+ readonly keyHint?: KeyHintConfig;
121
+ readonly isDisabled?: boolean;
122
+ } | {
123
+ readonly _tag: "Check";
124
+ readonly id: string;
125
+ readonly label: string;
126
+ readonly isChecked: boolean;
127
+ } | {
128
+ readonly _tag: "Group";
129
+ readonly label: string;
130
+ readonly items: readonly Entry[];
131
+ } | {
132
+ readonly _tag: "Link";
133
+ readonly id: string;
134
+ readonly label: string;
135
+ readonly href: string;
136
+ } | {
137
+ readonly _tag: "Radio";
138
+ readonly id: string;
139
+ readonly label: string;
140
+ readonly isChecked: boolean;
141
+ }) => import("effect/Unify").Unify<ReturnType<Cases["Action" | "Check" | "Group" | "Link" | "Radio"]>>;
142
+ <Cases extends { readonly [Tag in "Action" | "Check" | "Group" | "Link" | "Radio"]: (args: Extract<{
143
+ readonly _tag: "Action";
144
+ readonly id: string;
145
+ readonly label: string;
146
+ readonly keyHint?: KeyHintConfig;
147
+ readonly isDisabled?: boolean;
148
+ } | {
149
+ readonly _tag: "Check";
150
+ readonly id: string;
151
+ readonly label: string;
152
+ readonly isChecked: boolean;
153
+ } | {
154
+ readonly _tag: "Group";
155
+ readonly label: string;
156
+ readonly items: readonly Entry[];
157
+ } | {
158
+ readonly _tag: "Link";
159
+ readonly id: string;
160
+ readonly label: string;
161
+ readonly href: string;
162
+ } | {
163
+ readonly _tag: "Radio";
164
+ readonly id: string;
165
+ readonly label: string;
166
+ readonly isChecked: boolean;
167
+ }, {
168
+ readonly _tag: Tag;
169
+ }>) => any; }>(value: {
170
+ readonly _tag: "Action";
171
+ readonly id: string;
172
+ readonly label: string;
173
+ readonly keyHint?: KeyHintConfig;
174
+ readonly isDisabled?: boolean;
175
+ } | {
176
+ readonly _tag: "Check";
177
+ readonly id: string;
178
+ readonly label: string;
179
+ readonly isChecked: boolean;
180
+ } | {
181
+ readonly _tag: "Group";
182
+ readonly label: string;
183
+ readonly items: readonly Entry[];
184
+ } | {
185
+ readonly _tag: "Link";
186
+ readonly id: string;
187
+ readonly label: string;
188
+ readonly href: string;
189
+ } | {
190
+ readonly _tag: "Radio";
191
+ readonly id: string;
192
+ readonly label: string;
193
+ readonly isChecked: boolean;
194
+ }, cases: Cases): import("effect/Unify").Unify<ReturnType<Cases["Action" | "Check" | "Group" | "Link" | "Radio"]>>;
195
+ };
196
+ readonly Action: Data.TaggedEnum.ConstructorFrom<{
197
+ readonly _tag: "Action";
198
+ readonly id: string;
199
+ readonly label: string;
200
+ readonly keyHint?: KeyHintConfig;
201
+ readonly isDisabled?: boolean;
202
+ }, "_tag">;
203
+ readonly Check: Data.TaggedEnum.ConstructorFrom<{
204
+ readonly _tag: "Check";
205
+ readonly id: string;
206
+ readonly label: string;
207
+ readonly isChecked: boolean;
208
+ }, "_tag">;
209
+ readonly Group: Data.TaggedEnum.ConstructorFrom<{
210
+ readonly _tag: "Group";
211
+ readonly label: string;
212
+ readonly items: readonly Entry[];
213
+ }, "_tag">;
214
+ readonly Link: Data.TaggedEnum.ConstructorFrom<{
215
+ readonly _tag: "Link";
216
+ readonly id: string;
217
+ readonly label: string;
218
+ readonly href: string;
219
+ }, "_tag">;
220
+ readonly Radio: Data.TaggedEnum.ConstructorFrom<{
221
+ readonly _tag: "Radio";
222
+ readonly id: string;
223
+ readonly label: string;
224
+ readonly isChecked: boolean;
225
+ }, "_tag">;
226
+ };
227
+ /** An action item; see `Item`'s `Action`. */
228
+ export declare const action: (config: Data.TaggedEnum.Args<Item, "Action">) => Entry;
229
+ /** A radio item; see `Item`'s `Radio`. */
230
+ export declare const radio: (config: Data.TaggedEnum.Args<Item, "Radio">) => Entry;
231
+ /** A check item; see `Item`'s `Check`. */
232
+ export declare const check: (config: Data.TaggedEnum.Args<Item, "Check">) => Entry;
233
+ /** A link item; see `Item`'s `Link`. */
234
+ export declare const link: (config: Data.TaggedEnum.Args<Item, "Link">) => Entry;
235
+ /** A group of items under a heading; see `Item`'s `Group`. */
236
+ export declare const group: (label: string, items: readonly Entry[]) => Item;
@@ -0,0 +1,19 @@
1
+ import { brandViewResult as __foldkitBrandViewResult } from 'foldkit/brand'
2
+ import { Data } from "effect";
3
+ // src/menu/item.ts
4
+ /** The constructors, guards (`$is`) and matcher (`$match`) of `Item`. */
5
+ const Item = Data.taggedEnum();
6
+ /** An action item; see `Item`'s `Action`. */
7
+ const action = (config) => __foldkitBrandViewResult((Item.Action(config)), "@gjermundgaraba/pixel-paper/menu/item.js#action");
8
+ /** A radio item; see `Item`'s `Radio`. */
9
+ const radio = (config) => __foldkitBrandViewResult((Item.Radio(config)), "@gjermundgaraba/pixel-paper/menu/item.js#radio");
10
+ /** A check item; see `Item`'s `Check`. */
11
+ const check = (config) => __foldkitBrandViewResult((Item.Check(config)), "@gjermundgaraba/pixel-paper/menu/item.js#check");
12
+ /** A link item; see `Item`'s `Link`. */
13
+ const link = (config) => __foldkitBrandViewResult((Item.Link(config)), "@gjermundgaraba/pixel-paper/menu/item.js#link");
14
+ /** A group of items under a heading; see `Item`'s `Group`. */
15
+ const group = (label, items) => __foldkitBrandViewResult((Item.Group({
16
+ label,
17
+ items
18
+ })), "@gjermundgaraba/pixel-paper/menu/item.js#group");
19
+ export { Item, action, check, group, link, radio };
@@ -0,0 +1,206 @@
1
+ import { GlyphName } from "../glyph/glyphs.js";
2
+ import { Variant } from "../button/button.js";
3
+ import { Item } from "./item.js";
4
+ import { Effect, Option, Schema } from "effect";
5
+ import "foldkit/command";
6
+ import { Html } from "foldkit/html";
7
+ import * as Mount from "foldkit/mount";
8
+ import * as Update from "foldkit/update";
9
+ /** Schema for a menu: its id, whether its slip is open, and which end of the slip takes
10
+ * focus as it opens. One Model serves one toggle: a menu on every row of a list is a Model
11
+ * per row, each with its own id, never one Model handed from row to row. */
12
+ export declare const Model: Schema.Struct<{
13
+ readonly id: Schema.String;
14
+ readonly isOpen: Schema.Boolean;
15
+ readonly edge: Schema.Literals<readonly ["First", "Last"]>;
16
+ }>;
17
+ export type Model = typeof Model.Type;
18
+ /** Union of all Messages a menu can produce. `LeftSlip` (focus went outside the slip),
19
+ * `UnmountedSlip` (the slip left the page) and `CompletedFocus` (focus is back on the
20
+ * toggle) can arrive after the menu has closed. Each must reach the Model of the menu that
21
+ * sent it, where a late one changes nothing: given to another menu's Model, a late `LeftSlip`
22
+ * or `UnmountedSlip` closes that one. */
23
+ export declare const Message: import("foldkit/message").MessageUnion<{
24
+ readonly ClickedToggle: {};
25
+ readonly PressedToggleArrow: {
26
+ edge: Schema.Literals<readonly ["First", "Last"]>;
27
+ };
28
+ readonly SelectedItem: {
29
+ id: Schema.String;
30
+ kind: Schema.Literals<readonly ["Action", "Radio", "Check", "Link"]>;
31
+ };
32
+ readonly PressedEscape: {};
33
+ readonly PressedTab: {};
34
+ readonly LeftSlip: {};
35
+ readonly UnmountedSlip: {};
36
+ readonly CompletedPlaceSlip: {};
37
+ readonly CompletedFocus: {};
38
+ readonly CompletedFocusEdge: {};
39
+ }>;
40
+ export type Message = typeof Message.Type;
41
+ /** Union of OutMessages a menu reports. `Selected`: an action, a radio item or a link was
42
+ * chosen and the slip has closed (the browser follows a link itself). `Toggled`: a check item
43
+ * was chosen; the slip stays open and the parent flips the value it keeps. */
44
+ export declare const OutMessage: import("foldkit/message").MessageUnion<{
45
+ readonly Selected: {
46
+ id: Schema.String;
47
+ };
48
+ readonly Toggled: {
49
+ id: Schema.String;
50
+ };
51
+ }>;
52
+ export type OutMessage = typeof OutMessage.Type;
53
+ /** Configuration for creating a menu with `init`. The `id` must be unique in the document. */
54
+ export type InitConfig = Readonly<{
55
+ id: string;
56
+ }>;
57
+ /** Creates a closed menu. */
58
+ export declare const init: (config: InitConfig) => Model;
59
+ /** The menu's id, unique in the document. */
60
+ export declare const id: (model: Model) => string;
61
+ /** Whether the slip is open: a parent pauses its own page keys while it is. */
62
+ export declare const isOpen: (model: Model) => boolean;
63
+ /** Processes a menu Message and returns the next Model, Commands and OutMessage. */
64
+ export declare const update: (model: Model, message: Message) => Readonly<{
65
+ model: {
66
+ readonly id: string;
67
+ readonly isOpen: boolean;
68
+ readonly edge: "First" | "Last";
69
+ };
70
+ commands?: Update.Commands<{
71
+ readonly _tag: "CompletedFocusEdge";
72
+ } | {
73
+ readonly _tag: "ClickedToggle";
74
+ } | {
75
+ readonly _tag: "PressedEscape";
76
+ } | {
77
+ readonly _tag: "CompletedFocus";
78
+ } | {
79
+ readonly _tag: "CompletedPlaceSlip";
80
+ } | {
81
+ readonly _tag: "LeftSlip";
82
+ } | {
83
+ readonly _tag: "PressedTab";
84
+ } | {
85
+ readonly _tag: "PressedToggleArrow";
86
+ readonly edge: "First" | "Last";
87
+ } | {
88
+ readonly _tag: "SelectedItem";
89
+ readonly id: string;
90
+ readonly kind: "Action" | "Check" | "Link" | "Radio";
91
+ } | {
92
+ readonly _tag: "UnmountedSlip";
93
+ }, never>;
94
+ outMessage?: {
95
+ readonly _tag: "Selected";
96
+ readonly id: string;
97
+ } | {
98
+ readonly _tag: "Toggled";
99
+ readonly id: string;
100
+ };
101
+ }>;
102
+ /** ↓ and ↑ on the toggle open the slip on its first or last row (Enter and Space click it),
103
+ * their default prevented (see `toggleKey`). In a Scene, resolve it with
104
+ * `Message.PressedToggleArrow`. */
105
+ export declare const BindToggleKeys: Mount.MountDefinitionNoArgs<"BindToggleKeys", {
106
+ readonly _tag: "PressedToggleArrow";
107
+ readonly edge: "First" | "Last";
108
+ }>;
109
+ /** The open slip: hung under the toggle by `@foldkit/ui`'s Anchor (portaled, into the dialog
110
+ * when inside one), focus on its first or last row, and its keys (see `handleSlipKey`). It
111
+ * reports `CompletedPlaceSlip` once set up; in a Scene, resolve it with that. */
112
+ export declare const BindSlip: Mount.MountDefinitionWithArgs<"BindSlip", {
113
+ toggleId: Schema.String;
114
+ isEnd: Schema.Boolean;
115
+ edge: Schema.Literals<readonly ["First", "Last"]>;
116
+ }, {
117
+ readonly _tag: "PressedEscape";
118
+ } | {
119
+ readonly _tag: "CompletedPlaceSlip";
120
+ } | {
121
+ readonly _tag: "LeftSlip";
122
+ } | {
123
+ readonly _tag: "PressedTab";
124
+ }>;
125
+ /** Which edge of the toggle the slip hangs from. */
126
+ export declare const Align: Schema.Literals<readonly ["Start", "End"]>;
127
+ export type Align = typeof Align.Type;
128
+ /** Per-render inputs passed to `view` through `h.submodel`'s `viewInputs`. */
129
+ export type ViewInputs = Readonly<{
130
+ /** The toggle's accessible name, which also names the slip. Printed as its words unless
131
+ * `glyph` or `toggleContent` replaces them; then it is the toggle's `aria-label` and tip,
132
+ * so start it with any words the content shows. */
133
+ label: string;
134
+ items: readonly Item[];
135
+ /** A glyph toggle (`iconbtn`): the glyph alone, `label` its name and tip. */
136
+ glyph?: GlyphName;
137
+ /** A glyph toggle muted until hovered: a row's `more` menu. */
138
+ isQuiet?: boolean;
139
+ /** The toggle's own content in place of `label`'s words: a glyph, the current choice's
140
+ * title, a count, a caret. A small button with the menu's classes still. Markup that
141
+ * carries no handlers: it is built in the application's boundary and rendered inside the
142
+ * toggle, in this Submodel's. */
143
+ toggleContent?: ReadonlyArray<Html | string>;
144
+ /** The toggle's look when it is a button (`Primary` for a page's main action). */
145
+ variant?: Exclude<Variant, "Danger">;
146
+ align?: Align;
147
+ }>;
148
+ /**
149
+ * A printed slip under its toggle. The toggle is a button, built on `@foldkit/ui`'s Button,
150
+ * with `aria-haspopup="menu"` and `aria-expanded`; the slip is `role="menu"` named by the
151
+ * toggle, hung under it above the page (inside the open dialog when there is one), flipping
152
+ * near the window edge. Its rows
153
+ * take real focus: the first as it opens (the last on ↑), ↑ and ↓ move and wrap, Home and End
154
+ * go to the ends, a letter goes to the row it starts, and unavailable rows are stopped on.
155
+ * Enter, Space or a click chooses; Escape or Tab closes and puts focus back on the toggle; a
156
+ * click elsewhere closes it, and so does the slip leaving the page while open (the row the menu
157
+ * sits on is gone). Radio and check rows say `aria-checked`, a link to the current page
158
+ * `aria-current`. A check row keeps the slip open. The menu does not trap focus, so it
159
+ * hosts no live region.
160
+ */
161
+ export declare const view: import("foldkit/submodel").View<{
162
+ readonly id: string;
163
+ readonly isOpen: boolean;
164
+ readonly edge: "First" | "Last";
165
+ }, {
166
+ readonly _tag: "CompletedFocusEdge";
167
+ } | {
168
+ readonly _tag: "ClickedToggle";
169
+ } | {
170
+ readonly _tag: "PressedEscape";
171
+ } | {
172
+ readonly _tag: "CompletedFocus";
173
+ } | {
174
+ readonly _tag: "CompletedPlaceSlip";
175
+ } | {
176
+ readonly _tag: "LeftSlip";
177
+ } | {
178
+ readonly _tag: "PressedTab";
179
+ } | {
180
+ readonly _tag: "PressedToggleArrow";
181
+ readonly edge: "First" | "Last";
182
+ } | {
183
+ readonly _tag: "SelectedItem";
184
+ readonly id: string;
185
+ readonly kind: "Action" | "Check" | "Link" | "Radio";
186
+ } | {
187
+ readonly _tag: "UnmountedSlip";
188
+ }, Readonly<{
189
+ /** The toggle's accessible name, which also names the slip. Printed as its words unless
190
+ * `glyph` or `toggleContent` replaces them; then it is the toggle's `aria-label` and tip,
191
+ * so start it with any words the content shows. */
192
+ label: string;
193
+ items: readonly Item[];
194
+ /** A glyph toggle (`iconbtn`): the glyph alone, `label` its name and tip. */
195
+ glyph?: GlyphName;
196
+ /** A glyph toggle muted until hovered: a row's `more` menu. */
197
+ isQuiet?: boolean;
198
+ /** The toggle's own content in place of `label`'s words: a glyph, the current choice's
199
+ * title, a count, a caret. A small button with the menu's classes still. Markup that
200
+ * carries no handlers: it is built in the application's boundary and rendered inside the
201
+ * toggle, in this Submodel's. */
202
+ toggleContent?: ReadonlyArray<Html | string>;
203
+ /** The toggle's look when it is a button (`Primary` for a page's main action). */
204
+ variant?: Exclude<Variant, "Danger">;
205
+ align?: Align;
206
+ }>>;
@@ -0,0 +1,208 @@
1
+ import { brandViewResult as __foldkitBrandViewResult } from 'foldkit/brand'
2
+ import { view as view$1 } from "../glyph/glyph.js";
3
+ import { lookClassName } from "../button/button.js";
4
+ import { isPlain } from "../keys/keys.js";
5
+ import { Focus } from "../focus/focus.js";
6
+ import { ChoiceKind, Edge, anchorUnder, edgeSelector, rowsView, slipStream } from "./slip.js";
7
+ import { Effect, Match, Option, Schema, pipe } from "effect";
8
+ import * as Command from "foldkit/command";
9
+ import { defineMessageUnion } from "foldkit/message";
10
+ import { Button } from "@foldkit/ui";
11
+ import * as Mount from "foldkit/mount";
12
+ import { modifyFields } from "foldkit/struct";
13
+ import { defineView } from "foldkit/submodel";
14
+ import * as Update from "foldkit/update";
15
+ import * as Dom from "foldkit/dom";
16
+ // src/menu/menu.ts
17
+ /** Schema for a menu: its id, whether its slip is open, and which end of the slip takes
18
+ * focus as it opens. One Model serves one toggle: a menu on every row of a list is a Model
19
+ * per row, each with its own id, never one Model handed from row to row. */
20
+ const Model = Schema.Struct({
21
+ id: Schema.String,
22
+ isOpen: Schema.Boolean,
23
+ edge: Edge
24
+ });
25
+ /** Union of all Messages a menu can produce. `LeftSlip` (focus went outside the slip),
26
+ * `UnmountedSlip` (the slip left the page) and `CompletedFocus` (focus is back on the
27
+ * toggle) can arrive after the menu has closed. Each must reach the Model of the menu that
28
+ * sent it, where a late one changes nothing: given to another menu's Model, a late `LeftSlip`
29
+ * or `UnmountedSlip` closes that one. */
30
+ const Message = defineMessageUnion({
31
+ ClickedToggle: {},
32
+ PressedToggleArrow: { edge: Edge },
33
+ SelectedItem: {
34
+ id: Schema.String,
35
+ kind: ChoiceKind
36
+ },
37
+ PressedEscape: {},
38
+ PressedTab: {},
39
+ LeftSlip: {},
40
+ UnmountedSlip: {},
41
+ CompletedPlaceSlip: {},
42
+ CompletedFocus: {},
43
+ CompletedFocusEdge: {}
44
+ });
45
+ /** Union of OutMessages a menu reports. `Selected`: an action, a radio item or a link was
46
+ * chosen and the slip has closed (the browser follows a link itself). `Toggled`: a check item
47
+ * was chosen; the slip stays open and the parent flips the value it keeps. */
48
+ const OutMessage = defineMessageUnion({
49
+ Selected: { id: Schema.String },
50
+ Toggled: { id: Schema.String }
51
+ });
52
+ /** Creates a closed menu. */
53
+ const init = (config) => (__foldkitBrandViewResult(({
54
+ id: config.id,
55
+ isOpen: false,
56
+ edge: "First"
57
+ }), "@gjermundgaraba/pixel-paper/menu/menu.js#init"));
58
+ /** The menu's id, unique in the document. */
59
+ const id = (model) => __foldkitBrandViewResult((model.id), "@gjermundgaraba/pixel-paper/menu/menu.js#id");
60
+ /** Whether the slip is open: a parent pauses its own page keys while it is. */
61
+ const isOpen = (model) => __foldkitBrandViewResult((model.isOpen), "@gjermundgaraba/pixel-paper/menu/menu.js#isOpen");
62
+ const toggleId = (model) => __foldkitBrandViewResult((`${model.id}-toggle`), "@gjermundgaraba/pixel-paper/menu/menu.js#toggleId");
63
+ const slipId = (model) => __foldkitBrandViewResult((`${model.id}-slip`), "@gjermundgaraba/pixel-paper/menu/menu.js#slipId");
64
+ /** Moves focus to an end of the open slip (↓ or ↑ on the toggle while it is open). */
65
+ const FocusEdge = Command.define("FocusEdge", {
66
+ args: {
67
+ slipId: Schema.String,
68
+ edge: Edge
69
+ },
70
+ messages: [Message.CompletedFocusEdge],
71
+ execute: ({ slipId: openSlipId, edge }) => __foldkitBrandViewResult((Dom.focus(`#${CSS.escape(openSlipId)} ${edgeSelector(edge)}`).pipe(Effect.ignore, Effect.as(Message.CompletedFocusEdge()))), "@gjermundgaraba/pixel-paper/menu/menu.js#execute")
72
+ });
73
+ const opened = (model, edge) => __foldkitBrandViewResult((modifyFields(model, {
74
+ isOpen: () => __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/menu/menu.js#isOpen~2"),
75
+ edge: () => __foldkitBrandViewResult((edge), "@gjermundgaraba/pixel-paper/menu/menu.js#edge")
76
+ })), "@gjermundgaraba/pixel-paper/menu/menu.js#opened");
77
+ const closed = (model) => __foldkitBrandViewResult((modifyFields(model, { isOpen: () => __foldkitBrandViewResult((false), "@gjermundgaraba/pixel-paper/menu/menu.js#isOpen~3") })), "@gjermundgaraba/pixel-paper/menu/menu.js#closed");
78
+ const closedWithFocus = (model) => (__foldkitBrandViewResult(({
79
+ model: closed(model),
80
+ commands: [Focus({ id: toggleId(model) })]
81
+ }), "@gjermundgaraba/pixel-paper/menu/menu.js#closedWithFocus"));
82
+ /** Processes a menu Message and returns the next Model, Commands and OutMessage. */
83
+ const update = (model, message) => __foldkitBrandViewResult((Message.match(message, {
84
+ ClickedToggle: () => (__foldkitBrandViewResult(({ model: model.isOpen ? closed(model) : opened(model, "First") }), "@gjermundgaraba/pixel-paper/menu/menu.js#ClickedToggle")),
85
+ PressedToggleArrow: ({ edge }) => __foldkitBrandViewResult((model.isOpen ? {
86
+ model,
87
+ commands: [FocusEdge({
88
+ slipId: slipId(model),
89
+ edge
90
+ })]
91
+ } : { model: opened(model, edge) }), "@gjermundgaraba/pixel-paper/menu/menu.js#PressedToggleArrow"),
92
+ SelectedItem: ({ id: itemId, kind }) => __foldkitBrandViewResult((kind === "Check" ? {
93
+ model,
94
+ outMessage: OutMessage.Toggled({ id: itemId })
95
+ } : pipe(closedWithFocus(model), Update.withOutMessage(OutMessage.Selected({ id: itemId })))), "@gjermundgaraba/pixel-paper/menu/menu.js#SelectedItem"),
96
+ PressedEscape: () => __foldkitBrandViewResult((closedWithFocus(model)), "@gjermundgaraba/pixel-paper/menu/menu.js#PressedEscape"),
97
+ PressedTab: () => __foldkitBrandViewResult((closedWithFocus(model)), "@gjermundgaraba/pixel-paper/menu/menu.js#PressedTab"),
98
+ LeftSlip: () => (__foldkitBrandViewResult(({ model: closed(model) }), "@gjermundgaraba/pixel-paper/menu/menu.js#LeftSlip")),
99
+ UnmountedSlip: () => (__foldkitBrandViewResult(({ model: closed(model) }), "@gjermundgaraba/pixel-paper/menu/menu.js#UnmountedSlip")),
100
+ CompletedPlaceSlip: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba/pixel-paper/menu/menu.js#CompletedPlaceSlip")),
101
+ CompletedFocus: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba/pixel-paper/menu/menu.js#CompletedFocus")),
102
+ CompletedFocusEdge: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba/pixel-paper/menu/menu.js#CompletedFocusEdge"))
103
+ })), "@gjermundgaraba/pixel-paper/menu/menu.js#update");
104
+ const toggleEdge = (key) => __foldkitBrandViewResult((Match.value(key).pipe(Match.withReturnType(), Match.when("ArrowDown", () => __foldkitBrandViewResult((Option.some("First")), "@gjermundgaraba/pixel-paper/menu/menu.js#anonymous")), Match.when("ArrowUp", () => __foldkitBrandViewResult((Option.some("Last")), "@gjermundgaraba/pixel-paper/menu/menu.js#anonymous~2")), Match.orElse(() => __foldkitBrandViewResult((Option.none()), "@gjermundgaraba/pixel-paper/menu/menu.js#anonymous~3")))), "@gjermundgaraba/pixel-paper/menu/menu.js#toggleEdge");
105
+ const toggleKey = (event) => __foldkitBrandViewResult((event.isComposing || event.defaultPrevented || !isPlain(event) ? Option.none() : Option.map(toggleEdge(event.key), (edge) => __foldkitBrandViewResult((Message.PressedToggleArrow({ edge })), "@gjermundgaraba/pixel-paper/menu/menu.js#anonymous~4"))), "@gjermundgaraba/pixel-paper/menu/menu.js#toggleKey");
106
+ /** ↓ and ↑ on the toggle open the slip on its first or last row (Enter and Space click it),
107
+ * their default prevented (see `toggleKey`). In a Scene, resolve it with
108
+ * `Message.PressedToggleArrow`. */
109
+ const BindToggleKeys = Mount.defineStream("BindToggleKeys", {
110
+ messages: [Message.PressedToggleArrow],
111
+ execute: ({ element }) => __foldkitBrandViewResult((Dom.streamFromEventFilterMapPreventDefault({
112
+ target: element,
113
+ type: "keydown",
114
+ filterMapEvent: toggleKey
115
+ })), "@gjermundgaraba/pixel-paper/menu/menu.js#execute~2")
116
+ });
117
+ /** The open slip: hung under the toggle by `@foldkit/ui`'s Anchor (portaled, into the dialog
118
+ * when inside one), focus on its first or last row, and its keys (see `handleSlipKey`). It
119
+ * reports `CompletedPlaceSlip` once set up; in a Scene, resolve it with that. */
120
+ const BindSlip = Mount.defineStream("BindSlip", {
121
+ args: {
122
+ toggleId: Schema.String,
123
+ isEnd: Schema.Boolean,
124
+ edge: Edge
125
+ },
126
+ messages: [
127
+ Message.CompletedPlaceSlip,
128
+ Message.PressedEscape,
129
+ Message.PressedTab,
130
+ Message.LeftSlip
131
+ ],
132
+ execute: ({ element, toggleId: slipToggleId, isEnd, edge }) => __foldkitBrandViewResult((slipStream(element, {
133
+ placed: Message.CompletedPlaceSlip(),
134
+ events: {
135
+ escape: Message.PressedEscape(),
136
+ tab: Message.PressedTab(),
137
+ left: Message.LeftSlip()
138
+ },
139
+ keepId: Option.some(slipToggleId),
140
+ setup: anchorUnder({
141
+ toggleId: slipToggleId,
142
+ isEnd,
143
+ edge
144
+ })
145
+ })), "@gjermundgaraba/pixel-paper/menu/menu.js#execute~3")
146
+ });
147
+ Schema.Literals(["Start", "End"]);
148
+ const isNamedByLabel = (viewInputs) => __foldkitBrandViewResult((viewInputs.glyph !== void 0 || viewInputs.toggleContent !== void 0), "@gjermundgaraba/pixel-paper/menu/menu.js#isNamedByLabel");
149
+ const toggleClass = (viewInputs) => {
150
+ const { glyph, isQuiet = false, toggleContent, variant = "Default" } = viewInputs;
151
+ if (glyph === void 0 || toggleContent !== void 0) return __foldkitBrandViewResult((lookClassName({
152
+ variant,
153
+ isSmall: true
154
+ })), "@gjermundgaraba/pixel-paper/menu/menu.js#toggleClass");
155
+ return __foldkitBrandViewResult((isQuiet ? "iconbtn quiet" : "iconbtn"), "@gjermundgaraba/pixel-paper/menu/menu.js#toggleClass");
156
+ };
157
+ const toggleView = (model, viewInputs, h) => {
158
+ const { label, glyph, toggleContent } = viewInputs;
159
+ return __foldkitBrandViewResult((Button.view({
160
+ onClick: Message.ClickedToggle(),
161
+ toView: (groups) => __foldkitBrandViewResult((h.button([
162
+ ...groups.button,
163
+ h.Id(toggleId(model)),
164
+ h.AriaHasPopup("menu"),
165
+ h.AriaExpanded(model.isOpen),
166
+ ...model.isOpen ? [h.AriaControls(slipId(model))] : [],
167
+ ...isNamedByLabel(viewInputs) ? [h.AriaLabel(label), h.DataAttribute("tip", label)] : [],
168
+ h.OnMount(BindToggleKeys()),
169
+ h.Class(toggleClass(viewInputs))
170
+ ], toggleContent ?? (glyph === void 0 ? [label] : [view$1({ name: glyph }, h)]))), "@gjermundgaraba/pixel-paper/menu/menu.js#toView")
171
+ }, h)), "@gjermundgaraba/pixel-paper/menu/menu.js#toggleView");
172
+ };
173
+ /**
174
+ * A printed slip under its toggle. The toggle is a button, built on `@foldkit/ui`'s Button,
175
+ * with `aria-haspopup="menu"` and `aria-expanded`; the slip is `role="menu"` named by the
176
+ * toggle, hung under it above the page (inside the open dialog when there is one), flipping
177
+ * near the window edge. Its rows
178
+ * take real focus: the first as it opens (the last on ↑), ↑ and ↓ move and wrap, Home and End
179
+ * go to the ends, a letter goes to the row it starts, and unavailable rows are stopped on.
180
+ * Enter, Space or a click chooses; Escape or Tab closes and puts focus back on the toggle; a
181
+ * click elsewhere closes it, and so does the slip leaving the page while open (the row the menu
182
+ * sits on is gone). Radio and check rows say `aria-checked`, a link to the current page
183
+ * `aria-current`. A check row keeps the slip open. The menu does not trap focus, so it
184
+ * hosts no live region.
185
+ */
186
+ const view = defineView((model, viewInputs, h) => {
187
+ const { label, items, align = "Start" } = viewInputs;
188
+ return __foldkitBrandViewResult((h.div([h.Class("menu-wrap")], [toggleView(model, viewInputs, h), ...model.isOpen ? [h.div([
189
+ h.Id(slipId(model)),
190
+ h.Role("menu"),
191
+ isNamedByLabel(viewInputs) ? h.AriaLabel(label) : h.AriaLabelledBy(toggleId(model)),
192
+ h.OnMount(BindSlip({
193
+ toggleId: toggleId(model),
194
+ isEnd: align === "End",
195
+ edge: model.edge
196
+ })),
197
+ h.OnUnmount(Message.UnmountedSlip()),
198
+ h.Class("menu")
199
+ ], rowsView({
200
+ slipId: slipId(model),
201
+ items,
202
+ toChoose: (itemId, kind) => __foldkitBrandViewResult((Message.SelectedItem({
203
+ id: itemId,
204
+ kind
205
+ })), "@gjermundgaraba/pixel-paper/menu/menu.js#toChoose")
206
+ }, h))] : []])), "@gjermundgaraba/pixel-paper/menu/menu.js#anonymous~5");
207
+ });
208
+ export { BindSlip, BindToggleKeys, FocusEdge, Message, Model, OutMessage, id, init, isOpen, toggleKey, update, view };