@gjermundgaraba-designs/pixel-paper 0.13.0 → 0.14.1

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 (130) hide show
  1. package/DESIGN.md +29 -22
  2. package/dist/src/announcer/announcer.d.ts +34 -26
  3. package/dist/src/announcer/announcer.d.ts.map +1 -1
  4. package/dist/src/announcer/announcer.js +42 -32
  5. package/dist/src/announcer/index.d.ts +1 -1
  6. package/dist/src/announcer/index.d.ts.map +1 -1
  7. package/dist/src/announcer/index.js +1 -1
  8. package/dist/src/banner/banner.d.ts +1 -1
  9. package/dist/src/banner/banner.js +1 -1
  10. package/dist/src/barChart/barChart.js +1 -1
  11. package/dist/src/board/board.d.ts +1 -4
  12. package/dist/src/board/board.d.ts.map +1 -1
  13. package/dist/src/board/board.js +8 -71
  14. package/dist/src/button/button.d.ts +1 -1
  15. package/dist/src/button/button.js +1 -1
  16. package/dist/src/card/card.d.ts +36 -9
  17. package/dist/src/card/card.d.ts.map +1 -1
  18. package/dist/src/card/card.js +46 -8
  19. package/dist/src/card/index.d.ts +2 -2
  20. package/dist/src/card/index.d.ts.map +1 -1
  21. package/dist/src/card/index.js +1 -1
  22. package/dist/src/commandPalette/commandPalette.d.ts +4 -0
  23. package/dist/src/commandPalette/commandPalette.d.ts.map +1 -1
  24. package/dist/src/confirmDialog/confirmDialog.d.ts +20 -27
  25. package/dist/src/confirmDialog/confirmDialog.d.ts.map +1 -1
  26. package/dist/src/confirmDialog/confirmDialog.js +23 -20
  27. package/dist/src/confirmDialog/index.d.ts +1 -1
  28. package/dist/src/confirmDialog/index.d.ts.map +1 -1
  29. package/dist/src/confirmDialog/index.js +1 -1
  30. package/dist/src/contextMenu/contextMenu.d.ts +6 -6
  31. package/dist/src/dialog/dialog.d.ts +40 -9
  32. package/dist/src/dialog/dialog.d.ts.map +1 -1
  33. package/dist/src/dialog/dialog.js +37 -15
  34. package/dist/src/dialog/index.d.ts +1 -1
  35. package/dist/src/dialog/index.d.ts.map +1 -1
  36. package/dist/src/dialog/index.js +1 -1
  37. package/dist/src/drag/drag.d.ts +40 -0
  38. package/dist/src/drag/drag.d.ts.map +1 -0
  39. package/dist/src/drag/drag.js +134 -0
  40. package/dist/src/emptyState/emptyState.d.ts +6 -4
  41. package/dist/src/emptyState/emptyState.d.ts.map +1 -1
  42. package/dist/src/emptyState/emptyState.js +1 -1
  43. package/dist/src/errorSummary/errorSummary.d.ts +1 -1
  44. package/dist/src/errorSummary/errorSummary.js +1 -1
  45. package/dist/src/index.d.ts +3 -0
  46. package/dist/src/index.d.ts.map +1 -1
  47. package/dist/src/index.js +3 -0
  48. package/dist/src/keyHelp/keyHelp.d.ts +4 -0
  49. package/dist/src/keyHelp/keyHelp.d.ts.map +1 -1
  50. package/dist/src/lineChart/lineChart.js +1 -1
  51. package/dist/src/liveRegion/index.d.ts +3 -0
  52. package/dist/src/liveRegion/index.d.ts.map +1 -0
  53. package/dist/src/liveRegion/index.js +1 -0
  54. package/dist/src/liveRegion/liveRegion.d.ts +42 -0
  55. package/dist/src/liveRegion/liveRegion.d.ts.map +1 -0
  56. package/dist/src/liveRegion/liveRegion.js +35 -0
  57. package/dist/src/loading/loading.d.ts +8 -3
  58. package/dist/src/loading/loading.d.ts.map +1 -1
  59. package/dist/src/loading/loading.js +4 -3
  60. package/dist/src/menu/menu.d.ts +6 -6
  61. package/dist/src/meter/meter.d.ts +3 -0
  62. package/dist/src/meter/meter.d.ts.map +1 -1
  63. package/dist/src/meter/meter.js +6 -3
  64. package/dist/src/remote/index.d.ts +3 -0
  65. package/dist/src/remote/index.d.ts.map +1 -0
  66. package/dist/src/remote/index.js +1 -0
  67. package/dist/src/remote/remote.d.ts +29 -0
  68. package/dist/src/remote/remote.d.ts.map +1 -0
  69. package/dist/src/remote/remote.js +41 -0
  70. package/dist/src/skipLink/index.d.ts +1 -1
  71. package/dist/src/skipLink/index.d.ts.map +1 -1
  72. package/dist/src/skipLink/index.js +1 -1
  73. package/dist/src/skipLink/skipLink.d.ts +24 -8
  74. package/dist/src/skipLink/skipLink.d.ts.map +1 -1
  75. package/dist/src/skipLink/skipLink.js +27 -8
  76. package/dist/src/sortable/index.d.ts +3 -0
  77. package/dist/src/sortable/index.d.ts.map +1 -0
  78. package/dist/src/sortable/index.js +1 -0
  79. package/dist/src/sortable/sortable.d.ts +1144 -0
  80. package/dist/src/sortable/sortable.d.ts.map +1 -0
  81. package/dist/src/sortable/sortable.js +504 -0
  82. package/dist/src/toast/index.d.ts +1 -1
  83. package/dist/src/toast/index.d.ts.map +1 -1
  84. package/dist/src/toast/index.js +1 -1
  85. package/dist/src/toast/toast.d.ts +32 -20
  86. package/dist/src/toast/toast.d.ts.map +1 -1
  87. package/dist/src/toast/toast.js +8 -3
  88. package/dist/src/topBar/barHeight.d.ts +6 -0
  89. package/dist/src/topBar/barHeight.d.ts.map +1 -1
  90. package/dist/src/topBar/barHeight.js +4 -0
  91. package/dist/src/topBar/index.d.ts +1 -1
  92. package/dist/src/topBar/index.d.ts.map +1 -1
  93. package/dist/src/topBar/index.js +1 -1
  94. package/dist/src/topBar/topBar.d.ts +1 -2
  95. package/dist/src/topBar/topBar.d.ts.map +1 -1
  96. package/package.json +1 -1
  97. package/src/announcer/announcer.ts +48 -32
  98. package/src/announcer/index.ts +1 -1
  99. package/src/banner/banner.ts +1 -1
  100. package/src/barChart/barChart.ts +1 -1
  101. package/src/board/board.ts +18 -87
  102. package/src/button/button.ts +1 -1
  103. package/src/card/card.ts +121 -21
  104. package/src/card/index.ts +2 -2
  105. package/src/confirmDialog/confirmDialog.ts +27 -33
  106. package/src/confirmDialog/index.ts +2 -0
  107. package/src/dialog/dialog.ts +47 -18
  108. package/src/dialog/index.ts +3 -1
  109. package/src/drag/drag.ts +207 -0
  110. package/src/emptyState/emptyState.ts +7 -5
  111. package/src/errorSummary/errorSummary.ts +1 -1
  112. package/src/index.ts +3 -0
  113. package/src/lineChart/lineChart.ts +1 -1
  114. package/src/liveRegion/index.ts +2 -0
  115. package/src/liveRegion/liveRegion.ts +75 -0
  116. package/src/loading/loading.ts +11 -5
  117. package/src/meter/meter.ts +17 -3
  118. package/src/pixel-paper.css +182 -27
  119. package/src/remote/index.ts +2 -0
  120. package/src/remote/remote.ts +76 -0
  121. package/src/skipLink/index.ts +1 -1
  122. package/src/skipLink/skipLink.ts +38 -9
  123. package/src/sortable/index.ts +14 -0
  124. package/src/sortable/sortable.ts +857 -0
  125. package/src/toast/index.ts +1 -0
  126. package/src/toast/toast.ts +9 -3
  127. package/src/tokens.css +13 -11
  128. package/src/topBar/barHeight.ts +6 -0
  129. package/src/topBar/index.ts +1 -1
  130. package/src/topBar/topBar.ts +1 -2
@@ -221,7 +221,7 @@ export declare const FocusSlip: Command.CommandDefinitionWithArgs<"FocusSlip", {
221
221
  * slip added to a stack already on the page is read from there, and this says nothing more. A
222
222
  * stack mounted in the same render (it moved to another host, a Dialog opening or closing in
223
223
  * the same update) is a live region that arrives already holding the slip, which goes
224
- * unheard: then the slip is said through the page's live region (see `Announcer.announce`),
224
+ * unheard: then the slip is said through the page's live region (as `Announcer.Announce` does),
225
225
  * which follows the same host. It compares the stack element before and after the render.
226
226
  */
227
227
  export declare const AnnounceSlip: Command.CommandDefinitionWithArgs<"AnnounceSlip", {
@@ -286,6 +286,8 @@ export declare const update: (model: Model, message: Message) => Readonly<{
286
286
  };
287
287
  commands?: Update.Commands<{
288
288
  readonly _tag: "CompletedFocus";
289
+ } | {
290
+ readonly _tag: "PressedEscape";
289
291
  } | {
290
292
  readonly _tag: "BlurredStack";
291
293
  } | {
@@ -324,6 +326,8 @@ export declare const update: (model: Model, message: Message) => Readonly<{
324
326
  readonly pendingDismissVersion: number;
325
327
  readonly isHovered: boolean;
326
328
  readonly swipeState: {
329
+ readonly _tag: "Idle";
330
+ } | {
327
331
  readonly _tag: "Dismissing";
328
332
  readonly offsetX: number;
329
333
  readonly direction: "Left" | "Right";
@@ -332,8 +336,6 @@ export declare const update: (model: Model, message: Message) => Readonly<{
332
336
  readonly pointerId: number;
333
337
  readonly startX: number;
334
338
  readonly currentX: number;
335
- } | {
336
- readonly _tag: "Idle";
337
339
  } | {
338
340
  readonly _tag: "Settling";
339
341
  readonly offsetX: number;
@@ -369,15 +371,15 @@ export declare const update: (model: Model, message: Message) => Readonly<{
369
371
  readonly _tag: "GotAnimationMessage";
370
372
  readonly entryId: string;
371
373
  readonly message: {
374
+ readonly _tag: "Hid";
375
+ } | {
376
+ readonly _tag: "Showed";
377
+ } | {
372
378
  readonly _tag: "CompletedWaitForPaint";
373
379
  readonly generation: number;
374
380
  } | {
375
381
  readonly _tag: "EndedAnimation";
376
382
  readonly generation: number;
377
- } | {
378
- readonly _tag: "Hid";
379
- } | {
380
- readonly _tag: "Showed";
381
383
  };
382
384
  } | {
383
385
  readonly _tag: "HoveredEntry";
@@ -401,8 +403,6 @@ export declare const update: (model: Model, message: Message) => Readonly<{
401
403
  };
402
404
  } | {
403
405
  readonly _tag: "MovedHost";
404
- } | {
405
- readonly _tag: "PressedEscape";
406
406
  }, never>;
407
407
  outMessage?: {
408
408
  readonly _tag: "SelectedAction";
@@ -442,14 +442,14 @@ export declare const stackFocusOut: (stack: Element, event: FocusEvent) => Optio
442
442
  export declare const stackKey: (event: KeyboardEvent) => Option.Option<typeof Message.PressedEscape.Type>;
443
443
  /** The stack's focus and keys: focus coming in (and from where) and going out, and Escape
444
444
  * on a slip, which takes the newest and keeps a Dialog the stack sits in open (its default is
445
- * prevented). In a Scene, resolve it with `Message.BlurredStack`. */
445
+ * prevented). In a Scene, resolve it with `sceneMounts`. */
446
446
  export declare const BindStack: Mount.MountDefinitionNoArgs<"BindStack", {
447
+ readonly _tag: "PressedEscape";
448
+ } | {
447
449
  readonly _tag: "BlurredStack";
448
450
  } | {
449
451
  readonly _tag: "FocusedStack";
450
452
  readonly maybeFromId: Option.Option<string>;
451
- } | {
452
- readonly _tag: "PressedEscape";
453
453
  }>;
454
454
  /**
455
455
  * The page's toasts: printed slips at the bottom right (across the bottom on a phone), the
@@ -517,6 +517,8 @@ export declare const view: import("foldkit/submodel").View<{
517
517
  readonly maybeReturnFocusId: Option.Option<string>;
518
518
  }, {
519
519
  readonly _tag: "CompletedFocus";
520
+ } | {
521
+ readonly _tag: "PressedEscape";
520
522
  } | {
521
523
  readonly _tag: "BlurredStack";
522
524
  } | {
@@ -555,6 +557,8 @@ export declare const view: import("foldkit/submodel").View<{
555
557
  readonly pendingDismissVersion: number;
556
558
  readonly isHovered: boolean;
557
559
  readonly swipeState: {
560
+ readonly _tag: "Idle";
561
+ } | {
558
562
  readonly _tag: "Dismissing";
559
563
  readonly offsetX: number;
560
564
  readonly direction: "Left" | "Right";
@@ -563,8 +567,6 @@ export declare const view: import("foldkit/submodel").View<{
563
567
  readonly pointerId: number;
564
568
  readonly startX: number;
565
569
  readonly currentX: number;
566
- } | {
567
- readonly _tag: "Idle";
568
570
  } | {
569
571
  readonly _tag: "Settling";
570
572
  readonly offsetX: number;
@@ -600,15 +602,15 @@ export declare const view: import("foldkit/submodel").View<{
600
602
  readonly _tag: "GotAnimationMessage";
601
603
  readonly entryId: string;
602
604
  readonly message: {
605
+ readonly _tag: "Hid";
606
+ } | {
607
+ readonly _tag: "Showed";
608
+ } | {
603
609
  readonly _tag: "CompletedWaitForPaint";
604
610
  readonly generation: number;
605
611
  } | {
606
612
  readonly _tag: "EndedAnimation";
607
613
  readonly generation: number;
608
- } | {
609
- readonly _tag: "Hid";
610
- } | {
611
- readonly _tag: "Showed";
612
614
  };
613
615
  } | {
614
616
  readonly _tag: "HoveredEntry";
@@ -632,8 +634,18 @@ export declare const view: import("foldkit/submodel").View<{
632
634
  };
633
635
  } | {
634
636
  readonly _tag: "MovedHost";
635
- } | {
636
- readonly _tag: "PressedEscape";
637
637
  }, void>;
638
+ /** What a parent's Scene resolves the stack's Mounts with, each with a Message that changes
639
+ * nothing: `Scene.Mount.resolveAll(...Toast.sceneMounts)`. */
640
+ export declare const sceneMounts: readonly [readonly [Mount.MountDefinitionNoArgs<"BindStack", {
641
+ readonly _tag: "PressedEscape";
642
+ } | {
643
+ readonly _tag: "BlurredStack";
644
+ } | {
645
+ readonly _tag: "FocusedStack";
646
+ readonly maybeFromId: Option.Option<string>;
647
+ }>, {
648
+ readonly _tag: "BlurredStack";
649
+ }]];
638
650
  export {};
639
651
  //# sourceMappingURL=toast.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../../../src/toast/toast.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../../../src/toast/toast.ts"],"names":[],"mappings":"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"}
@@ -109,7 +109,7 @@ const stackElement = (stackId) => __foldkitBrandViewResult((Option.fromNullishOr
109
109
  * slip added to a stack already on the page is read from there, and this says nothing more. A
110
110
  * stack mounted in the same render (it moved to another host, a Dialog opening or closing in
111
111
  * the same update) is a live region that arrives already holding the slip, which goes
112
- * unheard: then the slip is said through the page's live region (see `Announcer.announce`),
112
+ * unheard: then the slip is said through the page's live region (as `Announcer.Announce` does),
113
113
  * which follows the same host. It compares the stack element before and after the render.
114
114
  */
115
115
  export const AnnounceSlip = Command.define("AnnounceSlip", {
@@ -156,7 +156,9 @@ export const update = (model, message) => __foldkitBrandViewResult((Message.matc
156
156
  isFocusIn: () => __foldkitBrandViewResult((true), "@gjermundgaraba-designs/pixel-paper/src/toast/toast.js#isFocusIn~2"),
157
157
  maybeReturnFocusId: (returnId) => (__foldkitBrandViewResult((model.isFocusIn ? returnId : maybeFromId), "@gjermundgaraba-designs/pixel-paper/src/toast/toast.js#maybeReturnFocusId")),
158
158
  }))), "@gjermundgaraba-designs/pixel-paper/src/toast/toast.js#FocusedStack"),
159
- BlurredStack: () => __foldkitBrandViewResult((releaseUnlessHeld(modifyFields(model, { isFocusIn: () => __foldkitBrandViewResult((false), "@gjermundgaraba-designs/pixel-paper/src/toast/toast.js#isFocusIn~3") }), Option.none())), "@gjermundgaraba-designs/pixel-paper/src/toast/toast.js#BlurredStack"),
159
+ BlurredStack: () => __foldkitBrandViewResult((model.isFocusIn
160
+ ? releaseUnlessHeld(modifyFields(model, { isFocusIn: () => __foldkitBrandViewResult((false), "@gjermundgaraba-designs/pixel-paper/src/toast/toast.js#isFocusIn~3") }), Option.none())
161
+ : { model }), "@gjermundgaraba-designs/pixel-paper/src/toast/toast.js#BlurredStack"),
160
162
  PressedEscape: () => __foldkitBrandViewResult((Option.match(Array.last(slips(model)), {
161
163
  onNone: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/toast/toast.js#onNone~3")),
162
164
  onSome: (newest) => __foldkitBrandViewResult((dismissKeepingFocus(model, newest.id)), "@gjermundgaraba-designs/pixel-paper/src/toast/toast.js#onSome~3"),
@@ -246,7 +248,7 @@ export const stackFocusOut = (stack, event) => __foldkitBrandViewResult((Option.
246
248
  export const stackKey = (event) => __foldkitBrandViewResult((Option.liftPredicate(Message.PressedEscape(), () => __foldkitBrandViewResult((isEscape(event)), "@gjermundgaraba-designs/pixel-paper/src/toast/toast.js#anonymous~26"))), "@gjermundgaraba-designs/pixel-paper/src/toast/toast.js#stackKey");
247
249
  /** The stack's focus and keys: focus coming in (and from where) and going out, and Escape
248
250
  * on a slip, which takes the newest and keeps a Dialog the stack sits in open (its default is
249
- * prevented). In a Scene, resolve it with `Message.BlurredStack`. */
251
+ * prevented). In a Scene, resolve it with `sceneMounts`. */
250
252
  export const BindStack = Mount.defineStream("BindStack", {
251
253
  messages: [Message.FocusedStack, Message.BlurredStack, Message.PressedEscape],
252
254
  execute: ({ element }) => __foldkitBrandViewResult((Stream.mergeAll([
@@ -294,3 +296,6 @@ export const view = defineView((model, h) => __foldkitBrandViewResult((h.div([h.
294
296
  toParentMessage: (message) => __foldkitBrandViewResult((Message.GotStackMessage({ message })), "@gjermundgaraba-designs/pixel-paper/src/toast/toast.js#toParentMessage~2"),
295
297
  }),
296
298
  ])), "@gjermundgaraba-designs/pixel-paper/src/toast/toast.js#anonymous~27"));
299
+ /** What a parent's Scene resolves the stack's Mounts with, each with a Message that changes
300
+ * nothing: `Scene.Mount.resolveAll(...Toast.sceneMounts)`. */
301
+ export const sceneMounts = [[BindStack, Message.BlurredStack()]];
@@ -18,6 +18,12 @@ export declare const MeasureHeight: Mount.MountDefinitionWithArgs<"MeasureHeight
18
18
  }, {
19
19
  readonly _tag: "CompletedMeasureHeight";
20
20
  }>;
21
+ /** What a parent's Scene resolves the bar's Mount with, the Message lifted as the bar's
22
+ * `toParentMessage` lifts it: `Scene.Mount.resolveAll(...TopBar.sceneMounts(toParentMessage))`.
23
+ * It matches by name, since the Mount the parent holds reports the parent's Message. */
24
+ export declare const sceneMounts: <ParentMessage>(toParentMessage: (message: Message) => ParentMessage) => readonly [readonly [{
25
+ readonly name: "MeasureHeight";
26
+ }, ParentMessage]];
21
27
  /** The bar's measuring attributes, its Mount lifted into the parent's Message. */
22
28
  export declare const measureAttributes: <ParentMessage>(toParentMessage: (message: Message) => ParentMessage, args: Readonly<{
23
29
  selector: string;
@@ -1 +1 @@
1
- {"version":3,"file":"barHeight.d.ts","sourceRoot":"","sources":["../../../src/topBar/barHeight.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,KAAK,KAAK,MAAM,eAAe,CAAC;AAEvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAI9D;mDACmD;AACnD,eAAO,MAAM,OAAO;;EAAqD,CAAC;AAC1E,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAC;AAO1C;;;uBAGuB;AACvB,eAAO,MAAM,aAAa;;;;;EAyBxB,CAAC;AAEH,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,GAAI,aAAa,mBAC5B,CAAC,OAAO,EAAE,OAAO,KAAK,aAAa,QAC9C,QAAQ,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,KACnD,WAAW,CAAC,aAAa,CAAC,KAC5B,UAAU,CAAC,aAAa,CAAwE,CAAC"}
1
+ {"version":3,"file":"barHeight.d.ts","sourceRoot":"","sources":["../../../src/topBar/barHeight.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,KAAK,KAAK,MAAM,eAAe,CAAC;AAEvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAI9D;mDACmD;AACnD,eAAO,MAAM,OAAO;;EAAqD,CAAC;AAC1E,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAC;AAO1C;;;uBAGuB;AACvB,eAAO,MAAM,aAAa;;;;;EAyBxB,CAAC;AAEH;;yFAEyF;AACzF,eAAO,MAAM,WAAW,GAAI,aAAa,mBAAmB,CAAC,OAAO,EAAE,OAAO,KAAK,aAAa;aACzF,IAAI;kBAAoF,CAAC;AAE/F,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,GAAI,aAAa,mBAC5B,CAAC,OAAO,EAAE,OAAO,KAAK,aAAa,QAC9C,QAAQ,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,KACnD,WAAW,CAAC,aAAa,CAAC,KAC5B,UAAU,CAAC,aAAa,CAAwE,CAAC"}
@@ -33,5 +33,9 @@ export const MeasureHeight = Mount.define("MeasureHeight", {
33
33
  return __foldkitBrandViewResult((Message.CompletedMeasureHeight()), "@gjermundgaraba-designs/pixel-paper/src/topBar/barHeight.js#anonymous");
34
34
  })), "@gjermundgaraba-designs/pixel-paper/src/topBar/barHeight.js#execute"),
35
35
  });
36
+ /** What a parent's Scene resolves the bar's Mount with, the Message lifted as the bar's
37
+ * `toParentMessage` lifts it: `Scene.Mount.resolveAll(...TopBar.sceneMounts(toParentMessage))`.
38
+ * It matches by name, since the Mount the parent holds reports the parent's Message. */
39
+ export const sceneMounts = (toParentMessage) => __foldkitBrandViewResult(([[{ name: MeasureHeight.name }, toParentMessage(Message.CompletedMeasureHeight())]]), "@gjermundgaraba-designs/pixel-paper/src/topBar/barHeight.js#sceneMounts");
36
40
  /** The bar's measuring attributes, its Mount lifted into the parent's Message. */
37
41
  export const measureAttributes = (toParentMessage, args, h) => __foldkitBrandViewResult(([h.OnMount(Mount.mapMessage(MeasureHeight(args), toParentMessage))]), "@gjermundgaraba-designs/pixel-paper/src/topBar/barHeight.js#measureAttributes");
@@ -1,4 +1,4 @@
1
- export { MeasureHeight, Message } from "./barHeight.ts";
1
+ export { MeasureHeight, Message, sceneMounts } from "./barHeight.ts";
2
2
  export { view } from "./topBar.ts";
3
3
  export type { ViewConfig } from "./topBar.ts";
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/topBar/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/topBar/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
@@ -1,2 +1,2 @@
1
- export { MeasureHeight, Message } from "./barHeight.js";
1
+ export { MeasureHeight, Message, sceneMounts } from "./barHeight.js";
2
2
  export { view } from "./topBar.js";
@@ -11,8 +11,7 @@ export type ViewConfig<Message> = Readonly<{
11
11
  /** Lifts the bar's lifecycle Message (`MeasureHeight` started: the page's first top bar
12
12
  * keeps `--topbar-h` at its height however it wraps, so anchors land clear of it) into the
13
13
  * parent's Message, which the parent's update takes and changes nothing for. In a Scene,
14
- * resolve the Mount by name with the lifted Message:
15
- * `Scene.Mount.resolve({ name: TopBar.MeasureHeight.name }, toParentMessage(TopBar.Message.CompletedMeasureHeight()))`. */
14
+ * resolve it with `TopBar.sceneMounts(toParentMessage)`. */
16
15
  toParentMessage: (message: BarHeightMessage) => Message;
17
16
  }>;
18
17
  /** The sticky paper bar across the top of an interface, closed by a 2px ink rule: the page's
@@ -1 +1 @@
1
- {"version":3,"file":"topBar.d.ts","sourceRoot":"","sources":["../../../src/topBar/topBar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGtD,OAAO,EAAE,KAAK,OAAO,IAAI,gBAAgB,EAAqB,MAAM,gBAAgB,CAAC;AAIrF,yDAAyD;AACzD,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,iCAAiC;IACjC,KAAK,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC,6EAA6E;IAC7E,GAAG,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;IAC1B,oDAAoD;IACpD,KAAK,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACrC;;;;gIAI4H;IAC5H,eAAe,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC;CACzD,CAAC,CAAC;AAEH;kFACkF;AAClF,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,CAAC,OAAO,CAAC,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAUpF,CAAC"}
1
+ {"version":3,"file":"topBar.d.ts","sourceRoot":"","sources":["../../../src/topBar/topBar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGtD,OAAO,EAAE,KAAK,OAAO,IAAI,gBAAgB,EAAqB,MAAM,gBAAgB,CAAC;AAIrF,yDAAyD;AACzD,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,iCAAiC;IACjC,KAAK,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC,6EAA6E;IAC7E,GAAG,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;IAC1B,oDAAoD;IACpD,KAAK,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACrC;;;iEAG6D;IAC7D,eAAe,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC;CACzD,CAAC,CAAC;AAEH;kFACkF;AAClF,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,CAAC,OAAO,CAAC,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAUpF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjermundgaraba-designs/pixel-paper",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,10 +1,24 @@
1
- import { Array, Duration, Effect, Option, pipe } from "effect";
1
+ import { Array, Duration, Effect, Option, Schema, pipe } from "effect";
2
+ import * as Command from "foldkit/command";
2
3
  import type { Html, HtmlBuilder } from "foldkit/html";
4
+ import { defineMessageUnion } from "foldkit/message";
3
5
  import * as Render from "foldkit/render";
4
6
 
7
+ // MESSAGE
8
+
9
+ /** What `Announce` and `Flash` report. An application that runs them puts
10
+ * `CompletedAnnounce: {}` and `CompletedFlash: {}` in its own Message union, which these tags
11
+ * match, and its update changes nothing for them. */
12
+ export const Message = defineMessageUnion({
13
+ CompletedAnnounce: {},
14
+ CompletedFlash: {},
15
+ });
16
+ export type Message = typeof Message.Type;
17
+
5
18
  // HOSTING
6
19
 
7
- /** The attribute that marks the page's live region. */
20
+ /** The attribute that marks the page's live region, which a test finds it by: Loading's line
21
+ * is a `role="status"` too, so counting that role counts more than the one region. */
8
22
  export const ANNOUNCER_ATTRIBUTE = "data-pixel-paper-announcer";
9
23
 
10
24
  const ANNOUNCER_SELECTOR = `[${ANNOUNCER_ATTRIBUTE}]`;
@@ -12,14 +26,9 @@ const ANNOUNCER_SELECTOR = `[${ANNOUNCER_ATTRIBUTE}]`;
12
26
  /**
13
27
  * The page's one polite live region, empty until something is said. Render exactly one,
14
28
  * placed by the rule every pixel-paper application follows, because an open Dialog makes
15
- * everything outside it inert and hidden from screen readers:
16
- *
17
- * - while a Dialog is open, inside the topmost open one: pass it as that Dialog's
18
- * `toLiveRegionView` (ConfirmDialog, KeyHelp and CommandPalette pass theirs through);
19
- * - otherwise at the end of the body.
20
- *
21
- * Decide which from the application's Model (which dialog is open), so the region moves
22
- * with the dialogs. A Toast stack follows the same rule.
29
+ * everything outside it inert and hidden from screen readers: inside the topmost open Dialog,
30
+ * otherwise at the end of the body. `LiveRegion.view` renders it with the toast stack, and
31
+ * `LiveRegion.place` puts them where the rule says.
23
32
  */
24
33
  export const view = <Message>(h: HtmlBuilder<Message>): Html =>
25
34
  h.div([
@@ -72,22 +81,9 @@ const sayIn = (region: HTMLElement, text: string): Effect.Effect<void> =>
72
81
  yield* Effect.sync(() => speak(region));
73
82
  });
74
83
 
75
- /**
76
- * Says `text` to screen readers through the page's live region (see `view`). Words said in
77
- * the same moment are read together, and the region clears first, so the same words twice
78
- * are read twice. Without a region on the page it does nothing.
79
- *
80
- * Run it from the application's own Command, as Foldkit's `Dom` Effects are run, so its
81
- * result is the application's Message:
82
- *
83
- * ```ts
84
- * const Announce = Command.define("Announce", {
85
- * args: { text: Schema.String },
86
- * messages: [Message.CompletedAnnounce],
87
- * execute: ({ text }) => Announcer.announce(text).pipe(Effect.as(Message.CompletedAnnounce())),
88
- * });
89
- * ```
90
- */
84
+ /** Says `text` to screen readers through the page's live region, once it has rendered. A
85
+ * component that says its own steps (a board's move, a copy) runs it from a Command of its
86
+ * own, named for what it says. */
91
87
  export const announce = (text: string): Effect.Effect<void> =>
92
88
  Effect.gen(function* () {
93
89
  yield* Render.afterCommit;
@@ -141,12 +137,7 @@ const runFlash = (element: Element): void => {
141
137
  }
142
138
  };
143
139
 
144
- /**
145
- * Inverts the element `selector` finds for one beat (`--motion-flash`): the signal that a
146
- * change was committed. A second flash mid-beat restarts it. With `prefers-reduced-motion`
147
- * it holds a still 2px ink ring for the beat instead. Pair it with `announce`, which says
148
- * what the flash shows, and run it from the application's own Command as `announce` is.
149
- */
140
+ /** Inverts the element `selector` finds for one beat; `Flash` runs it. */
150
141
  export const flash = (selector: string): Effect.Effect<void> =>
151
142
  Effect.sync(() => {
152
143
  const maybeElement = Option.fromNullishOr(document.querySelector(selector));
@@ -154,3 +145,28 @@ export const flash = (selector: string): Effect.Effect<void> =>
154
145
  runFlash(maybeElement.value);
155
146
  }
156
147
  });
148
+
149
+ // COMMAND
150
+
151
+ /**
152
+ * Says `text` to screen readers through the page's live region (see `view`). Words said in
153
+ * the same moment are read together, and the region clears first, so the same words twice
154
+ * are read twice. Without a region on the page it does nothing. Reports `CompletedAnnounce`.
155
+ */
156
+ export const Announce = Command.define("Announce", {
157
+ args: { text: Schema.String },
158
+ messages: [Message.CompletedAnnounce],
159
+ execute: ({ text }) => announce(text).pipe(Effect.as(Message.CompletedAnnounce())),
160
+ });
161
+
162
+ /**
163
+ * Inverts the element `selector` finds for one beat (`--motion-flash`): the signal that a
164
+ * change was committed. A second flash mid-beat restarts it. With `prefers-reduced-motion`
165
+ * it holds a still 2px ink ring for the beat instead. Return it beside `Announce`, which says
166
+ * what the flash shows. Reports `CompletedFlash`.
167
+ */
168
+ export const Flash = Command.define("Flash", {
169
+ args: { selector: Schema.String },
170
+ messages: [Message.CompletedFlash],
171
+ execute: ({ selector }) => flash(selector).pipe(Effect.as(Message.CompletedFlash())),
172
+ });
@@ -1 +1 @@
1
- export { announce, flash, view } from "./announcer.ts";
1
+ export { ANNOUNCER_ATTRIBUTE, Announce, Flash, view } from "./announcer.ts";
@@ -20,7 +20,7 @@ export type ViewConfig = Readonly<{
20
20
  * interface is in (offline, reconnecting, read-only), for as long as it lasts. One at a
21
21
  * time. It is not a live region, since it arrives already holding its sentence, which would
22
22
  * go unheard: the application says the state once, when it begins, through the page's live
23
- * region (`Announcer.announce`, from its own Command). An outcome that comes and goes is a
23
+ * region (the `Announcer.Announce` Command). An outcome that comes and goes is a
24
24
  * toast; a word beside the control that did it is a FlashWord. */
25
25
  export const view = <Message>(config: ViewConfig, h: HtmlBuilder<Message>): Html => {
26
26
  const { body, tone = "Error", actions = [] } = config;
@@ -185,7 +185,7 @@ export const view = <Message>(config: ViewConfig, h: HtmlBuilder<Message>): Html
185
185
  const rootAttributes = [h.Class("chart")];
186
186
 
187
187
  return Array.match(points, {
188
- onEmpty: () => EmptyState.view({ title: empty }, h),
188
+ onEmpty: () => EmptyState.view({ title: empty, headingLevel: "Strong" }, h),
189
189
  onNonEmpty: (present) =>
190
190
  isRows
191
191
  ? h.div(rootAttributes, [
@@ -1,7 +1,6 @@
1
1
  import { Button as UiButton, DragAndDrop as UiDragAndDrop } from "@foldkit/ui";
2
2
  import { Array, Effect, Equal, Match, Option, Schema, Stream, pipe } from "effect";
3
3
  import * as Command from "foldkit/command";
4
- import * as Dom from "foldkit/dom";
5
4
  import {
6
5
  type Attribute,
7
6
  type ChildAttribute,
@@ -24,6 +23,17 @@ import * as IconButton from "../iconButton/iconButton.ts";
24
23
  import { LOCALE } from "../locale/locale.ts";
25
24
  import { slotView } from "../slot/slot.ts";
26
25
  import { prefixKeys } from "../subscription/prefixKeys.ts";
26
+ import {
27
+ LEFT_BUTTON,
28
+ activatedKeyboardDrag,
29
+ cancelledDrag,
30
+ escapeKeys,
31
+ innerControls,
32
+ isCarrying,
33
+ measureLift,
34
+ phaseOf,
35
+ pressedDraggable,
36
+ } from "../drag/drag.ts";
27
37
 
28
38
  // MODEL
29
39
 
@@ -185,32 +195,9 @@ const CARD_ATTRIBUTE = "board-card";
185
195
  const TITLE_ATTRIBUTE = "board-title";
186
196
  const GRIP_ATTRIBUTE = "board-grip";
187
197
 
188
- // PHASE
189
-
190
- const Phase = Schema.Literals(["Idle", "Pressed", "PointerDragging", "KeyboardDragging"]);
191
- type Phase = typeof Phase.Type;
192
-
193
- // NOTE: @foldkit/ui gap: DragAndDrop has no accessor for which input holds a card.
194
- // `ghostStyle` is Some only while a pointer drags, so it tells a pointer drag from a keyboard
195
- // one.
196
- const phaseOf = (dragAndDrop: UiDragAndDrop.Model): Phase => {
197
- if (Option.isNone(UiDragAndDrop.maybeDraggedItemId(dragAndDrop))) {
198
- return "Idle";
199
- } else if (!UiDragAndDrop.isDragging(dragAndDrop)) {
200
- return "Pressed";
201
- } else if (Option.isSome(UiDragAndDrop.ghostStyle(dragAndDrop))) {
202
- return "PointerDragging";
203
- } else {
204
- return "KeyboardDragging";
205
- }
206
- };
207
-
208
- const isCarrying = (phase: Phase): boolean =>
209
- phase === "PointerDragging" || phase === "KeyboardDragging";
210
-
211
198
  // COMMAND
212
199
 
213
- /** Says a step of a move through the page's live region (`Announcer.announce`), which is
200
+ /** Says a step of a move through the page's live region (as `Announcer.Announce` does), which is
214
201
  * inside the topmost open dialog when there is one. */
215
202
  export const AnnounceMove = Command.define("AnnounceMove", {
216
203
  args: { text: Schema.String },
@@ -386,25 +373,6 @@ const settle =
386
373
  );
387
374
  };
388
375
 
389
- // NOTE: @foldkit/ui gap: DragAndDrop exposes no update capability for a press, a keyboard
390
- // pick-up or a cancel, and its `draggable` bundle (`role="option"`, `tabindex`) cannot sit on
391
- // the grip's button, so the board builds these three child Messages itself.
392
- const pressedDraggable = (
393
- fields: Parameters<typeof UiDragAndDrop.Message.PressedDraggable>[0],
394
- ): UiDragAndDrop.Message =>
395
- // oxlint-disable-next-line foldkit/no-child-message-construction-in-root
396
- UiDragAndDrop.Message.PressedDraggable(fields);
397
-
398
- const activatedKeyboardDrag = (
399
- fields: Parameters<typeof UiDragAndDrop.Message.ActivatedKeyboardDrag>[0],
400
- ): UiDragAndDrop.Message =>
401
- // oxlint-disable-next-line foldkit/no-child-message-construction-in-root
402
- UiDragAndDrop.Message.ActivatedKeyboardDrag(fields);
403
-
404
- const cancelledDrag = (): UiDragAndDrop.Message =>
405
- // oxlint-disable-next-line foldkit/no-child-message-construction-in-root
406
- UiDragAndDrop.Message.CancelledDrag();
407
-
408
376
  const holding = (model: Model, held: Held): Model =>
409
377
  modifyFields(model, { maybeHeld: () => Option.some(held) });
410
378
 
@@ -577,34 +545,13 @@ export const setMovable = (model: Model, isMovable: boolean): UpdateReturn => {
577
545
 
578
546
  // SUBSCRIPTION
579
547
 
580
- // NOTE: @foldkit/ui gap: DragAndDrop's own Escape cancels the move and lets the key travel
581
- // on, to a dialog around the board. The board takes the key first and stops it.
582
- /** Escape while a card is pressed or held cancels it and goes no further: it is taken on the
583
- * window, before the page's own key bindings or a dialog see it. */
584
- export const escapeMessage = (event: KeyboardEvent): Option.Option<Message> => {
585
- if (event.key !== "Escape" || event.isComposing) {
586
- return Option.none();
587
- }
588
-
589
- event.preventDefault();
590
- event.stopPropagation();
591
- return Option.some(Message.PressedEscape());
592
- };
593
-
594
- const escapeKeys: Stream.Stream<Message> = Dom.streamFromEventFilterMap({
595
- target: () => window,
596
- type: "keydown",
597
- filterMapEvent: escapeMessage,
598
- options: { capture: true },
599
- });
600
-
601
548
  const holdingSubscriptions = Subscription.make<Model, Message>()((entry) => ({
602
549
  escape: entry(
603
550
  { isHolding: Schema.Boolean },
604
551
  {
605
552
  modelToDependencies: (model) => ({ isHolding: isHolding(model) }),
606
553
  dependenciesToStream: ({ isHolding: isHoldingNow }) =>
607
- isHoldingNow ? escapeKeys : Stream.empty,
554
+ isHoldingNow ? escapeKeys(Message.PressedEscape()) : Stream.empty,
608
555
  },
609
556
  ),
610
557
  }));
@@ -644,15 +591,7 @@ export const SizeLiftedCard = Mount.define("SizeLiftedCard", {
644
591
  messages: [Message.CompletedSizeLiftedCard],
645
592
  execute: ({ element, cardHook: hook, pressX, pressY }) =>
646
593
  Effect.sync(() => {
647
- const maybeCard = Option.fromNullishOr(
648
- document.querySelector(`[data-sortable-id="${CSS.escape(hook)}"]`),
649
- );
650
- if (Option.isSome(maybeCard) && element instanceof HTMLElement) {
651
- const rect = maybeCard.value.getBoundingClientRect();
652
- element.style.setProperty("--lift-width", `${rect.width}px`);
653
- element.style.setProperty("--lift-x", `${rect.left - pressX}px`);
654
- element.style.setProperty("--lift-y", `${rect.top - pressY}px`);
655
- }
594
+ measureLift(element, `[data-sortable-id="${CSS.escape(hook)}"]`, pressX, pressY);
656
595
  return Message.CompletedSizeLiftedCard();
657
596
  }),
658
597
  });
@@ -693,17 +632,7 @@ export type ViewInputs = Readonly<{
693
632
  toColumnAttributes?: (column: Column) => ReadonlyArray<ChildAttribute>;
694
633
  }>;
695
634
 
696
- const LEFT_BUTTON = 0;
697
-
698
- const INNER_CONTROL = [
699
- "input",
700
- "textarea",
701
- "select",
702
- "a[href]",
703
- '[contenteditable]:not([contenteditable="false"])',
704
- `button:not([data-${TITLE_ATTRIBUTE}]):not([data-${GRIP_ATTRIBUTE}])`,
705
- "[data-no-lift]",
706
- ].join(", ");
635
+ const INNER_CONTROL = innerControls(`[data-${TITLE_ATTRIBUTE}], [data-${GRIP_ATTRIBUTE}]`);
707
636
 
708
637
  const isInside = (outer: Element, inner: Element | null): boolean =>
709
638
  inner !== null && outer.contains(inner);
@@ -961,7 +890,9 @@ const columnView = (info: PlaceInfo, column: Column, h: HtmlBuilder<Message>): H
961
890
  ),
962
891
  ...Array.match(items, {
963
892
  onEmpty: () => info.toEmptyView(column),
964
- onNonEmpty: (cards) => [h.ul([h.Class("board-cards")], cards)],
893
+ // NOTE: Safari takes list semantics from a list printed without markers, so the
894
+ // list says it is one
895
+ onNonEmpty: (cards) => [h.ul([h.Role("list"), h.Class("board-cards")], cards)],
965
896
  }),
966
897
  ],
967
898
  ),
@@ -107,7 +107,7 @@ const wordsView = <Message>(
107
107
  * While busy it is `aria-busy` too.
108
108
  *
109
109
  * Enter in a field can still submit a form that has no live submit button, so the form's
110
- * own update must ignore a submit while its work is saving (see `Card`'s `onSubmit`).
110
+ * own update must ignore a submit while its work is saving (see `Card.formView`).
111
111
  */
112
112
  export const view = <Message>(config: ViewConfig<Message>, h: HtmlBuilder<Message>): Html => {
113
113
  const {