@gjermundgaraba-designs/pixel-paper 0.14.0 → 0.15.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.
package/DESIGN.md CHANGED
@@ -1055,11 +1055,11 @@ The printed button: a paper rectangle in a 2px ink frame that casts a 3px shadow
1055
1055
 
1056
1056
  ### Cards (dialogs)
1057
1057
 
1058
- **Dialog** is a Submodel over `@foldkit/ui`'s Dialog: a `<dialog class="veil">` that fills the viewport, opened with `show()` in place rather than `showModal()` in the top layer. That is a deliberate exception to the baseline's "prefer the platform" for overlays: Foldkit's Dialog (through `Dom.showDialog`) makes everything outside the dialog `inert` and `aria-hidden`, traps focus, handles Escape on the topmost dialog and returns focus on close, so the platform's modal behaviour is reproduced, not dropped; what is lost is the top layer and its `::backdrop`. The veil is therefore an element of its own, `div.veil-backdrop` (fixed, Veil with the ink checker grain, entering in 3 steps over 0.12s), under `div.veil-pad` (`.top` for the palette), which lets a press through everywhere but on the card it holds; a press on the veil, Escape, or a control given the `closeButton` group closes it and reports `Closed`. While its work must land in it (a save whose failure the reader has to see), the update that starts the work holds those three in the dialog's Model (`Dialog.setCloseHeld`), so its update leaves them out, however soon after the start they come: it stays open and reports no `Closed`. The update where the work fails lets go (`Dialog.setCloseHeld(model, false)`), or the reader is shut in with the failure; `Dialog.close` closes it and lets go of the hold. Opening and closing are the parent's, through `Dialog.open` and `Dialog.close` in its update, and a step the parent asked for reports nothing; `Dialog.foldDialog` lifts a dialog the parent always holds (its update, `open` and `close`) into the parent at once, `Closed` reported only where the parent maps it. The content is the parent's `toView`, which receives the attribute groups to spread (`title`, `description`, `initialFocus`, `closeButton`, `actionBar`). Focus starts on the element given the `initialFocus` group, else the first control. The Card inside names the dialog through its title (the `title` group, `aria-labelledby`); a dialog without a heading takes `label`, printed for screen readers only. `isAlert` makes it an `alertdialog`, and `hasDescription` points `aria-describedby` at the element given the `description` group. Because the page outside is inert and hidden, anything that must be heard or reached while it is open renders inside it: the topmost open dialog hosts the page's live region and the toast stack, both outside the card, through its `toLiveRegionView` (see Building components).
1058
+ **Dialog** is a Submodel over `@foldkit/ui`'s Dialog: a `<dialog class="veil">` that fills the viewport, opened with `show()` in place rather than `showModal()` in the top layer. That is a deliberate exception to the baseline's "prefer the platform" for overlays: Foldkit's Dialog (through `Dom.showDialog`) makes everything outside the dialog `inert` and `aria-hidden`, traps focus, handles Escape on the topmost dialog and returns focus on close, so the platform's modal behaviour is reproduced, not dropped; what is lost is the top layer and its `::backdrop`. The veil is therefore an element of its own, `div.veil-backdrop` (fixed, Veil with the ink checker grain, entering in 3 steps over 0.12s), under `div.veil-pad` (`.top` for the palette), which lets a press through everywhere but on the card it holds; a press on the veil, Escape, or a control given the `closeButton` group closes it and reports `Closed`. While its work must land in it (a save whose failure the reader has to see), the parent holds those three: its update passes `isCloseHeld` to the dialog's (`Dialog.update(model, message, { isCloseHeld })`, or `foldDialog`'s `isCloseHeld: (model) => model.isSaving`), read from its own state as each Message arrives, so the hold starts with the work, ends with it, and covers a key pressed before the next render: the dialog stays open and reports no `Closed`. Nothing is stored, so there is nothing to let go of. Opening and closing are the parent's, through `Dialog.open` and `Dialog.close` in its update, and a step the parent asked for reports nothing; `Dialog.foldDialog` lifts a dialog the parent always holds (its update, `open` and `close`) into the parent at once, `Closed` reported only where the parent maps it. The content is the parent's `toView`, which receives the attribute groups to spread (`title`, `description`, `initialFocus`, `closeButton`, `actionBar`). Focus starts on the element given the `initialFocus` group, else the first control. The Card inside names the dialog through its title (the `title` group, `aria-labelledby`); a dialog without a heading takes `label`, printed for screen readers only. `isAlert` makes it an `alertdialog`, and `hasDescription` points `aria-describedby` at the element given the `description` group. Because the page outside is inert and hidden, anything that must be heard or reached while it is open renders inside it: the topmost open dialog hosts the page's live region and the toast stack, both outside the card, through its `toLiveRegionView` (see Building components).
1059
1059
 
1060
- **Card** → `div.card` (`.narrow`; `form.card` from `Card.formView`, named by its title (`aria-label`), so a form landmark; no role of its own, the Dialog around it is the dialog): a paper panel with the card shadow, `min(680px, 100%)` (440px narrow), entering in 3 steps over 0.14s from `scale(0.97)`. An inverted title bar `header.card-tb` (`6px 8px 6px 12px`, 13px uppercase 0.06em (`--tracking-head`), a close IconButton when it has `closeAttributes`, held by `Card.formView`'s `isBusy` while work the reader may not walk away from runs: `aria-disabled`, in the keyboard, its `closeAttributes` and so its handler dropped, faded to 0.6 on the bar, as a held button in a panel's title bar), a scrolling `div.card-body` (16px, 14px gap; a word longer than the card, a path or an id, breaks rather than widening it), and `div.card-actions` (`12px 16px`) over a 2px ink rule: `lead` first, then `span.card-acts` holding the actions at the right, which drop below the lead together when the bar wraps. Inside a Dialog, where the page's keys wait, the bar moves focus between its actions: `h` or ← to the one before, `l` or → to the one after, in the order they print, stopping at the ends, never pressing one (Enter, Space and Tab stay the browser's). The keys are bound by a Mount on the bar (`BindActionKeys`), which reads the real key event: only a key whose target is one of that bar's own buttons or links, unmodified, outside an IME and not already handled, and only when there is an action that way, moves focus and has its default prevented. A field, the title bar's close, a menu's items and a nested dialog's bar keep their keys. A disabled action is passed over; an `aria-disabled` one (held: busy, done or disabled) is still a stop and still ignores presses. **Card.formView** is the one way to make a form card: its `body` in one Fields group, then the action bar's cancel (`cancel`, closing through `closeAttributes`) and the primary default submit button (`submit`, its id `Card.submitId(id)`). One flag, `isBusy`, holds every way the form could change or leave while its work runs: the submit button prints busy and turns `type="button"`, the close glyph and cancel are held with their close attributes dropped, and the Fields group is natively disabled and `aria-busy`, so nothing changes under the send and nothing sends twice. In a Dialog, the update that sends also holds the Dialog's ways out (`Dialog.setCloseHeld`), Escape and the veil among them, and the update where the send fails lets go of both, the reason on the field (the specimen's rename refuses a name with a slash). `isSubmitDisabled` holds the submit button alone while there is nothing to send (a name unchanged), the fields and cancel live. The fields leave the keyboard as they are held, so the update moves focus to the submit button as it sends (`Focus.Focus({ id: Card.submitId(id) })`), and it still ignores `onSubmit` while busy, for an Enter that raced the render. A ConfirmDialog with `isDanger` still opens on cancel.
1060
+ **Card** → `div.card` (`.narrow`; `form.card` from `Card.formView`, named by its title (`aria-label`), so a form landmark; no role of its own, the Dialog around it is the dialog): a paper panel with the card shadow, `min(680px, 100%)` (440px narrow), entering in 3 steps over 0.14s from `scale(0.97)`. An inverted title bar `header.card-tb` (`6px 8px 6px 12px`, 13px uppercase 0.06em (`--tracking-head`), a close IconButton when it has `closeAttributes`, held by `Card.formView`'s `isBusy` while work the reader may not walk away from runs: `aria-disabled`, in the keyboard, its `closeAttributes` and so its handler dropped, faded to 0.6 on the bar, as a held button in a panel's title bar), a scrolling `div.card-body` (16px, 14px gap; a word longer than the card, a path or an id, breaks rather than widening it), and `div.card-actions` (`12px 16px`) over a 2px ink rule: `lead` first, then `span.card-acts` holding the actions at the right, which drop below the lead together when the bar wraps. Inside a Dialog, where the page's keys wait, the bar moves focus between its actions: `h` or ← to the one before, `l` or → to the one after, in the order they print, stopping at the ends, never pressing one (Enter, Space and Tab stay the browser's). The keys are bound by a Mount on the bar (`BindActionKeys`), which reads the real key event: only a key whose target is one of that bar's own buttons or links, unmodified, outside an IME and not already handled, and only when there is an action that way, moves focus and has its default prevented. A field, the title bar's close, a menu's items and a nested dialog's bar keep their keys. A disabled action is passed over; an `aria-disabled` one (held: busy, done or disabled) is still a stop and still ignores presses. **Card.formView** is the one way to make a form card: its `body` in one Fields group, then the action bar's `lead` (a form's own delete, before the push), cancel (`cancel`, closing through `closeAttributes`) and the primary default submit button (`submit`, its id `Card.submitId(id)`). One flag, `isBusy`, holds every way the form could change or leave while its work runs: the submit button prints busy and turns `type="button"`, the close glyph and cancel are held with their close attributes dropped, and the Fields group is natively disabled and `aria-busy`, so nothing changes under the send and nothing sends twice. In a Dialog, the state that sets `isBusy` is the `isCloseHeld` the parent passes the Dialog's update, so Escape and the veil are held with it, and a failed send frees both, the reason on the field (the specimen's rename refuses a name with a slash). `notices` print above the Fields group, outside the hold: what the page says while the form is open (a lost connection with its retry), whose controls stay live while it sends. `isSubmitDisabled` holds the submit button alone while there is nothing to send (a name unchanged), the fields and cancel live. The fields leave the keyboard as they are held, so the update moves focus to the submit button as it sends (`Focus.Focus({ id: Card.submitId(id) })`), and it still ignores `onSubmit` while busy, for an Enter that raced the render. A ConfirmDialog with `isDanger` still opens on cancel.
1061
1061
 
1062
- - **ConfirmDialog** → a Submodel over Dialog (an `alertdialog` when `isDanger`, a `dialog` otherwise) holding a narrow Card whose body is an Outcome (warn, or error when `isDanger`), the Outcome's body describing the dialog. Its view inputs follow the system's words: `title` (the title bar), `question` (the Outcome's title), `body`, and `label` (the confirming button's word). Without `isDanger` the confirm is primary and default; with it the confirm is the red button and cancel is the default, where focus starts. `Confirmed` does not close it: work that takes a while stays in the dialog. `isBusy` holds the confirming button (its word, the working cursor, focus kept, a second press ignored) while cancel stays live; the parent calls `ConfirmDialog.close` when the work lands, or keeps it open while it is not done. `isDisabled` holds it the same way without the working cursor, for an action that is blocked rather than running (writes not accepted yet). `toDetailView` prints the application's own content under the sentence, inside the Outcome's body and so in the dialog's description: what the work said back (a refused delete's reason as an error Notice) or a notice with its own retry. Cancel, Escape and the veil report `Cancelled`; the parent decides whether that also stops work already running, and ignores the work's result once cancelled. Where the reader may not walk away from the work (its failure must land in the dialog), the update that starts it holds the ways out (`ConfirmDialog.setCloseHeld`): cancel prints held (`aria-disabled`, in the keyboard, no ring and no shadow while the busy commit keeps focus), and cancel, Escape and a press on the veil change nothing, so the dialog stays open and reports no `Cancelled`; the update where the work fails lets go, and `close` closes it and lets go.
1062
+ - **ConfirmDialog** → a Submodel over Dialog (an `alertdialog` when `isDanger`, a `dialog` otherwise) holding a narrow Card whose body is an Outcome (warn, or error when `isDanger`), the Outcome's body describing the dialog. Its view inputs follow the system's words: `title` (the title bar), `question` (the Outcome's title), `body`, and `label` (the confirming button's word). Without `isDanger` the confirm is primary and default; with it the confirm is the red button and cancel is the default, where focus starts. `Confirmed` does not close it: work that takes a while stays in the dialog. `isBusy` holds the confirming button (its word, the working cursor, focus kept, a second press ignored) and cancel (`aria-disabled`, in the keyboard, no ring and no shadow while the busy commit keeps focus); the parent calls `ConfirmDialog.close` when the work lands, or keeps it open while it is not done. `isDisabled` holds it the same way without the working cursor, for an action that is blocked rather than running (writes not accepted yet). `toDetailView` prints the application's own content under the sentence, inside the Outcome's body and so in the dialog's description: what the work said back (a refused delete's reason as an error Notice) or a notice with its own retry. Cancel, Escape and the veil report `Cancelled`; the parent decides whether that also stops work already running, and ignores the work's result once cancelled. The parent passes the same state as `isCloseHeld` to `ConfirmDialog.update`, so cancel, Escape and a press on the veil change nothing while the work runs: the dialog stays open and reports no `Cancelled`, and the reader sees how it ends.
1063
1063
  - **CommandPalette** (Submodel over Dialog and `@foldkit/ui`'s Input with a listbox of its own, since a combobox would not let the cursor land on held rows or Escape reach the Dialog) → a card at 18vh holding `div.palette-q` (a `span.palette-scope` and a combobox input), `div.palette-detail` when the app gives `toDetailView`, `div.palette-list[role="listbox"]` of `div.palette-group` headings and `div.palette-row[role="option"][aria-selected]` rows (control register; `isAuthored` titles, `.authored`, set in sans with a glyph and wait for a query), a `div.sr-only[role="status"]`, and `div.palette-more`. Once a query is typed the status says how many rows it finds ("3 results.", "Nothing matches."); it is empty as the card opens and on a fresh page, so it is never mounted holding its words (rule 12). Labels and hints wrap within their row, including long names and destination paths. One cursor: the inverted row, moved by the keys only. ↑ ↓ move it and stop at the ends, each key one row from where the last left it however fast they come (the field's own handler, in the view, reports `PressedArrowKey` with the rows its render showed, and update steps from the Model's cursor); Home and End stay the field's, moving the caret; Enter does what a click on its row does, decided in update from what the render showed each row to be (held, opening a page, a choice on a page): a command closes the palette first so what it opens takes focus, and reports `SelectedCommand`. An arrow or an Enter pressed before the list has caught up with the keys before it (straight after a letter, or before the arrows already waiting have moved the cursor) cannot name a row yet, so it waits for the next render: the row that render shows the cursor on becomes the cursor, and a waiting Enter acts on it as on any row. So arrows typed straight after a letter step through the new query's rows, and an Enter acts on the keys before it, never on letters typed after it. While the palette is open, ↑ ↓ and Enter pressed before its field has focus (straight after the key that opened it) are its own too: `CommandPalette.subscriptions(keyPrefix)` takes them on the window before the page's bindings see them, and they wait as above. A key an IME is composing stays the IME's. The pointer shades the row under it (Header Grey, as a list's row) and a click runs that row; it never moves the cursor and never scrolls. The cursor comes into view on every key that moves it, when the view or the query changes, and when its row leaves the list (it falls back to the first): the app, which changes the list, returns `CommandPalette.ScrollToCursor` with the palette's id; a row that only reflows is not followed. The cursor holds to its row by id while the app updates the list; `CommandPalette.maybeCursorId` reads the row it shows for a list of commands, so the app can compare it before and after its change. A row with `isDisabled` prints muted (`[aria-disabled="true"]`), its `reason` in the hint, and the cursor still lands on it but Enter and a click do nothing. **Pages:** a command with a `page` (a status, a date, a destination) ends in a caret and opens that page in place instead of closing: `div.palette-q` holds a Back IconButton, the scope chip (what the commands act on, kept on every page), the page's title (`span.palette-title`, pixel caps), then the page's own field (placeholder `find`, else "type to narrow"), focused. A long scope wraps inside its chip and the field takes its own line when too little is left beside it, so nothing leaves the card at 390px. The choices are found in like the commands. The choice in force now (`current`) carries a `current` tag and cannot be picked again. The cursor starts on the page's `start` (the next status; the first choice a typed query finds), else on `current`, else on the first choice, read while the reader has not moved it, so an application that keeps `start` steady across a change made elsewhere moves the tag, not the cursor. Back, or Backspace in an empty field, returns to the commands with their query and cursor as they were, also when the palette opened straight on a page (`CommandPalette.openAt`). A pick (`SelectedChoice`) holds the page until the parent answers: the row prints the working cursor, the list is `aria-busy`, and moving, picking, typing and Back wait. With `CommandPalette.pickSucceeded` the palette closes; with `pickFailed` the page stays with its query, focus and the cursor on that choice, and the app says why in `toDetailView`, which shows on the commands and on every page alike. Escape closes the whole palette, even while a pick is out, and reports `Closed`; an answer arriving after that, or after the page was left, changes nothing. A page whose command leaves the list gives way to the commands. One level: choices do not open pages.
1064
1064
  - **Keymap** → `div.keymap > div > h3 + div.keymap-row > kbd + span`: keys in the 11px pixel face under 10px muted group heads, for a narrow Card.
1065
1065
 
@@ -1221,7 +1221,8 @@ Each component is `src/<name>/<name>.ts` with an explicit `index.ts`, a colocate
1221
1221
  15. **A Mount reports through the parent.** A View that owns a Mount takes a required `toParentMessage: (message: X.Message) => ParentMessage` (TopBar, StatusBar, Toolbar, the mermaid adapter), and a fire-and-forget Mount maps to a caller `Completed*` Message the parent may ignore. A bare `onX: Message` is used only where the parent's Model acts on the fact (ImageFrame's `onBroken`). In a Scene, resolve the Mount by name with the lifted Message: `Scene.Mount.resolve({ name: X.Mount.name }, toParentMessage(...))`. Where every application's Scene must resolve a component's Mounts to render a page at all, the namespace exports `sceneMounts`, the matchers paired with Messages that change nothing, for `Scene.Mount.resolveAll(...X.sceneMounts)`: `TopBar.sceneMounts(toParentMessage)`, `Toast.sceneMounts` and `Dialog.sceneMounts` (which serves ConfirmDialog, KeyHelp and CommandPalette too).
1222
1222
  16. **Fragment links focus through the application.** A link to `#id` (SkipLink, an ErrorSummary's links) needs the application's URL handler to return `SkipLink.ScrollToFragment` for the changed URL, since Foldkit routes the click.
1223
1223
  17. **Platform services are the application's.** A component that needs a platform service says so in its TSDoc and here (CopyButton writes through Effect's `Clipboard`), and the application provides the Layer in its `resources`.
1224
- 18. **Upstream gaps.** Where `@foldkit/ui` lacks a capability, the workaround carries `// NOTE: @foldkit/ui gap: <what>` at its site, and that note is the record: there is no list beside it. A wrapper that must build a child Message itself says so in the same note, with a lint disable on that line alone.
1224
+ 18. **Held work gives up.** Work that holds a dialog's ways out (a save, a delete) waits on something outside the page, which can hang, and a hang would shut the reader in. Its Command ends in a timeout mapped to its failure Message (`Effect.timeoutOrElse({ duration, orElse: () => Effect.succeed(FailedSave({ … })) })`), so the hold always ends with the reason in the dialog.
1225
+ 19. **Upstream gaps.** Where `@foldkit/ui` lacks a capability, the workaround carries `// NOTE: @foldkit/ui gap: <what>` at its site, and that note is the record: there is no list beside it. A wrapper that must build a child Message itself says so in the same note, with a lint disable on that line alone.
1225
1226
 
1226
1227
  ## Do's and Don'ts
1227
1228
 
@@ -24,13 +24,18 @@ export type ViewConfig<Message> = Readonly<{
24
24
  /** The raised surface: paper in a 2px ink box on the 8px print shadow, under a title bar. */
25
25
  export declare const view: <Message>(config: ViewConfig<Message>, h: HtmlBuilder<Message>) => Html;
26
26
  /** Configuration for rendering a form card with `formView`: a card's, but for its body, its
27
- * close attributes and its action bar, which the form fills. */
28
- export type FormViewConfig<Message> = Omit<ViewConfig<Message>, "body" | "closeAttributes" | "actions" | "lead"> & Readonly<{
27
+ * close attributes and its actions, which the form fills. `lead` stays the card's: what
28
+ * goes before the push, such as a form's own delete. */
29
+ export type FormViewConfig<Message> = Omit<ViewConfig<Message>, "body" | "closeAttributes" | "actions"> & Readonly<{
29
30
  /** Unique in the document: the submit button's id is `submitId(id)`. */
30
31
  id: string;
31
32
  /** The form's content, fields and all, in one Fields group that `isBusy` holds. A link in
32
33
  * it (an ErrorSummary's) stays live. */
33
34
  body: ReadonlyArray<Html | string>;
35
+ /** Above the fields, outside the group `isBusy` holds: what the page says about the form
36
+ * while it is open (a lost connection with its retry), whose controls stay live while it
37
+ * sends. */
38
+ notices?: ReadonlyArray<Html | string>;
34
39
  /** The submit button's words. It prints primary, the card's default. */
35
40
  submit: string;
36
41
  /** The cancel button's words, before the submit. It closes through `closeAttributes`. */
@@ -40,9 +45,10 @@ export type FormViewConfig<Message> = Omit<ViewConfig<Message>, "body" | "closeA
40
45
  closeAttributes?: Attributes<Message>;
41
46
  /** The form's work is running (it sends): the submit button is busy, the close glyph and
42
47
  * cancel are held without `closeAttributes`, and the body is natively disabled, so
43
- * nothing changes under the send and nothing sends twice. In a Dialog, hold its ways out
44
- * too (`Dialog.setCloseHeld`), and let go of both where the send fails. Enter in a field can submit before the fields are held,
45
- * so the update still ignores `onSubmit` while busy. */
48
+ * nothing changes under the send and nothing sends twice. In a Dialog, pass the same state
49
+ * as `isCloseHeld` to its update, so Escape and the veil are held too. Enter in a field
50
+ * can submit before the fields are held, so the update still ignores `onSubmit` while
51
+ * busy. */
46
52
  isBusy?: boolean;
47
53
  /** The form cannot be sent yet (nothing to send): the submit button is held as a Button
48
54
  * is, and the fields and cancel stay live. Enter in a field can still submit, so the
@@ -55,7 +61,7 @@ export type FormViewConfig<Message> = Omit<ViewConfig<Message>, "body" | "closeA
55
61
  * to the page: the form's update moves it here as it sends, with
56
62
  * `Focus.Focus({ id: Card.submitId(id) })`. */
57
63
  export declare const submitId: (id: string) => string;
58
- /** A card that is a form, named by its title, so a form landmark: its body in one Fields
59
- * group, then cancel and the primary submit button in the action bar. */
64
+ /** A card that is a form, named by its title, so a form landmark: its notices, its body in
65
+ * one Fields group, then cancel and the primary submit button in the action bar. */
60
66
  export declare const formView: <Message>(config: FormViewConfig<Message>, h: HtmlBuilder<Message>) => Html;
61
67
  //# sourceMappingURL=card.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../../src/card/card.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAQ9D,sDAAsD;AACtD,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,0FAA0F;IAC1F,eAAe,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACnC;gDAC4C;IAC5C,eAAe,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IACtC,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6FAA6F;IAC7F,OAAO,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACvC,uEAAuE;IACvE,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC;6DACyD;IACzD,mBAAmB,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;CAC3C,CAAC,CAAC;AAsDH,6FAA6F;AAC7F,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,CAAC,OAAO,CAAC,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IACd,CAAC;AAIxE;iEACiE;AACjE,MAAM,MAAM,cAAc,CAAC,OAAO,IAAI,IAAI,CACxC,UAAU,CAAC,OAAO,CAAC,EACnB,MAAM,GAAG,iBAAiB,GAAG,SAAS,GAAG,MAAM,CAChD,GACC,QAAQ,CAAC;IACP,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAC;IACX;6CACyC;IACzC,IAAI,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACnC,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;wEACoE;IACpE,eAAe,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IACtC;;;;6DAIyD;IACzD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;6DAEyD;IACzD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,wEAAwE;IACxE,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AAEL;;gDAEgD;AAChD,eAAO,MAAM,QAAQ,OAAQ,MAAM,KAAG,MAAwB,CAAC;AAE/D;0EAC0E;AAC1E,eAAO,MAAM,QAAQ,GAAI,OAAO,UACtB,cAAc,CAAC,OAAO,CAAC,KAC5B,WAAW,CAAC,OAAO,CAAC,KACtB,IAwDF,CAAC"}
1
+ {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../../src/card/card.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAQ9D,sDAAsD;AACtD,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,0FAA0F;IAC1F,eAAe,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACnC;gDAC4C;IAC5C,eAAe,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IACtC,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6FAA6F;IAC7F,OAAO,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACvC,uEAAuE;IACvE,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC;6DACyD;IACzD,mBAAmB,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;CAC3C,CAAC,CAAC;AAsDH,6FAA6F;AAC7F,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,CAAC,OAAO,CAAC,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IACd,CAAC;AAIxE;;yDAEyD;AACzD,MAAM,MAAM,cAAc,CAAC,OAAO,IAAI,IAAI,CACxC,UAAU,CAAC,OAAO,CAAC,EACnB,MAAM,GAAG,iBAAiB,GAAG,SAAS,CACvC,GACC,QAAQ,CAAC;IACP,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAC;IACX;6CACyC;IACzC,IAAI,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACnC;;iBAEa;IACb,OAAO,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACvC,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;wEACoE;IACpE,eAAe,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IACtC;;;;;gBAKY;IACZ,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;6DAEyD;IACzD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,wEAAwE;IACxE,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AAEL;;gDAEgD;AAChD,eAAO,MAAM,QAAQ,OAAQ,MAAM,KAAG,MAAwB,CAAC;AAE/D;qFACqF;AACrF,eAAO,MAAM,QAAQ,GAAI,OAAO,UACtB,cAAc,CAAC,OAAO,CAAC,KAC5B,WAAW,CAAC,OAAO,CAAC,KACtB,IAyDF,CAAC"}
@@ -33,10 +33,10 @@ export const view = (config, h) => __foldkitBrandViewResult((h.div([h.Class(clas
33
33
  * to the page: the form's update moves it here as it sends, with
34
34
  * `Focus.Focus({ id: Card.submitId(id) })`. */
35
35
  export const submitId = (id) => __foldkitBrandViewResult((`${id}-submit`), "@gjermundgaraba-designs/pixel-paper/src/card/card.js#submitId");
36
- /** A card that is a form, named by its title, so a form landmark: its body in one Fields
37
- * group, then cancel and the primary submit button in the action bar. */
36
+ /** A card that is a form, named by its title, so a form landmark: its notices, its body in
37
+ * one Fields group, then cancel and the primary submit button in the action bar. */
38
38
  export const formView = (config, h) => {
39
- const { id, title, submit, cancel, closeAttributes, isBusy = false, isSubmitDisabled = false, onSubmit, } = config;
39
+ const { id, title, submit, cancel, closeAttributes, notices = [], isBusy = false, isSubmitDisabled = false, onSubmit, } = config;
40
40
  const cancelButton = cancel === undefined
41
41
  ? []
42
42
  : [
@@ -62,7 +62,7 @@ export const formView = (config, h) => {
62
62
  h.OnSubmit(onSubmit),
63
63
  ], childrenView({
64
64
  ...config,
65
- body: [Fields.view({ body: config.body, isBusy }, h)],
65
+ body: [...notices, Fields.view({ body: config.body, isBusy }, h)],
66
66
  isCloseHeld: isBusy,
67
67
  actions: [...cancelButton, submitButton],
68
68
  }, h))), "@gjermundgaraba-designs/pixel-paper/src/card/card.js#formView");
@@ -31,7 +31,6 @@ export declare const Model: Schema.Struct<{
31
31
  }>;
32
32
  readonly maybeFocusSelector: Schema.Option<Schema.String>;
33
33
  }>;
34
- readonly isCloseHeld: Schema.Boolean;
35
34
  }>;
36
35
  readonly query: Schema.String;
37
36
  readonly maybeCursor: Schema.Option<Schema.String>;
@@ -127,7 +126,6 @@ export declare const update: (model: Model, message: Message) => Readonly<{
127
126
  };
128
127
  readonly maybeFocusSelector: Option.Option<string>;
129
128
  };
130
- readonly isCloseHeld: boolean;
131
129
  };
132
130
  readonly query: string;
133
131
  readonly maybeCursor: Option.Option<string>;
@@ -291,7 +289,6 @@ export declare const subscriptions: <Prefix extends string>(keyPrefix: Prefix) =
291
289
  };
292
290
  readonly maybeFocusSelector: Option.Option<string>;
293
291
  };
294
- readonly isCloseHeld: boolean;
295
292
  };
296
293
  readonly query: string;
297
294
  readonly maybeCursor: Option.Option<string>;
@@ -460,7 +457,6 @@ export declare const view: import("foldkit/submodel").View<{
460
457
  };
461
458
  readonly maybeFocusSelector: Option.Option<string>;
462
459
  };
463
- readonly isCloseHeld: boolean;
464
460
  };
465
461
  readonly query: string;
466
462
  readonly maybeCursor: Option.Option<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"commandPalette.d.ts","sourceRoot":"","sources":["../../../src/commandPalette/commandPalette.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"commandPalette.d.ts","sourceRoot":"","sources":["../../../src/commandPalette/commandPalette.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { Schema } from "effect";
2
2
  import type { Html } from "foldkit/html";
3
3
  import * as Update from "foldkit/update";
4
+ import * as Dialog from "../dialog/dialog.ts";
4
5
  /** Schema for a confirm dialog: the pixel-paper Dialog it opens in. */
5
6
  export declare const Model: Schema.Struct<{
6
7
  readonly dialog: Schema.Struct<{
@@ -16,7 +17,6 @@ export declare const Model: Schema.Struct<{
16
17
  }>;
17
18
  readonly maybeFocusSelector: Schema.Option<Schema.String>;
18
19
  }>;
19
- readonly isCloseHeld: Schema.Boolean;
20
20
  }>;
21
21
  }>;
22
22
  export type Model = typeof Model.Type;
@@ -61,7 +61,7 @@ export type Message = typeof Message.Type;
61
61
  /** Union of OutMessages a confirm dialog reports. `Confirmed`: the reader pressed the action;
62
62
  * the dialog stays open until the parent calls `close`. `Cancelled`: cancel, Escape or a click
63
63
  * on the veil; the dialog has closed, and whether that also stops work already running is
64
- * the parent's to decide. Never reported while its ways out are held (`setCloseHeld`). */
64
+ * the parent's to decide. Never reported while its ways out are held (`Dialog.UpdateContext`). */
65
65
  export declare const OutMessage: import("foldkit/message").MessageUnion<{
66
66
  readonly Confirmed: {};
67
67
  readonly Cancelled: {};
@@ -73,8 +73,9 @@ export type InitConfig = Readonly<{
73
73
  }>;
74
74
  /** Creates a closed confirm dialog. */
75
75
  export declare const init: (config: InitConfig) => Model;
76
- /** Processes a confirm dialog Message and returns the next Model, Commands and OutMessage. */
77
- export declare const update: (model: Model, message: Message) => Readonly<{
76
+ /** Processes a confirm dialog Message and returns the next Model, Commands and OutMessage.
77
+ * While `context.isCloseHeld`, cancel, Escape and the veil change nothing. */
78
+ export declare const update: (model: Model, message: Message, context?: Dialog.UpdateContext) => Readonly<{
78
79
  model: {
79
80
  readonly dialog: {
80
81
  readonly dialog: {
@@ -89,7 +90,6 @@ export declare const update: (model: Model, message: Message) => Readonly<{
89
90
  };
90
91
  readonly maybeFocusSelector: import("effect/Option").Option<string>;
91
92
  };
92
- readonly isCloseHeld: boolean;
93
93
  };
94
94
  };
95
95
  commands?: Update.Commands<{
@@ -145,20 +145,13 @@ export declare const update: (model: Model, message: Message) => Readonly<{
145
145
  }>;
146
146
  /** Opens the confirm dialog: focus starts on the action, or on cancel when it is `isDanger`. */
147
147
  export declare const open: (model: Model) => Update.Return<Model, Message>;
148
- /** Closes the confirm dialog without reporting `Cancelled`, and lets go of a hold: call it
149
- * once confirmed work has landed. */
148
+ /** Closes the confirm dialog without reporting `Cancelled`: call it once confirmed work has
149
+ * landed. */
150
150
  export declare const close: (model: Model) => Update.Return<Model, Message>;
151
- /** Holds cancel, Escape and the veil, or lets them go: while held the dialog stays open and
152
- * reports no `Cancelled`, and cancel prints held (`aria-disabled`, in the keyboard). Hold it
153
- * in the update that starts confirmed work whose failure must land here, and let go in the
154
- * update where the work fails; `close` lets go once it lands. */
155
- export declare const setCloseHeld: (model: Model, isHeld: boolean) => Model;
156
151
  /** The confirm dialog's id, unique in the document. */
157
152
  export declare const id: (model: Model) => string;
158
153
  /** Whether the confirm dialog is open. */
159
154
  export declare const isOpen: (model: Model) => boolean;
160
- /** Whether its ways out are held (`setCloseHeld`). */
161
- export declare const isCloseHeld: (model: Model) => boolean;
162
155
  /** Per-render inputs passed to `view` through `h.submodel`'s `viewInputs`. */
163
156
  export type ViewInputs = Readonly<{
164
157
  /** The title bar: the action's name (`"Delete"`). */
@@ -178,8 +171,9 @@ export type ViewInputs = Readonly<{
178
171
  /** Destructive: the confirming button turns red and cancel becomes the default. */
179
172
  isDanger?: boolean;
180
173
  /** The confirmed work is running: the confirming button is held (its word stays, the
181
- * working cursor prints, a second press does nothing) and keeps focus. Cancel stays live
182
- * unless the dialog's ways out are held (`setCloseHeld`). */
174
+ * working cursor prints, a second press does nothing) and keeps focus, and cancel is held
175
+ * with it. Pair it with `isCloseHeld` in `update`'s context, from the same state, so
176
+ * Escape and the veil change nothing either. */
183
177
  isBusy?: boolean;
184
178
  /** The action cannot run now (nothing is running; it is blocked): the confirming button is
185
179
  * held, `aria-disabled` without the working cursor, and stays in the keyboard, so focus
@@ -198,9 +192,9 @@ export type ViewInputs = Readonly<{
198
192
  * arm-then-confirm button: red never rests on a button, and an armed button is easy to
199
193
  * double-click through.
200
194
  *
201
- * Work that takes a while stays in the dialog: set `isBusy` while it runs, `close` once it
202
- * has landed, and on failure keep it open with the error in `toDetailView`. Hold its ways
203
- * out with `setCloseHeld` too when the reader must stay to see how it ends.
195
+ * Work that takes a while stays in the dialog: set `isBusy` while it runs (and `isCloseHeld`
196
+ * in `update`'s context), `close` once it has landed, and on failure keep it open with the
197
+ * error in `toDetailView`.
204
198
  */
205
199
  export declare const view: import("foldkit/submodel").View<{
206
200
  readonly dialog: {
@@ -216,7 +210,6 @@ export declare const view: import("foldkit/submodel").View<{
216
210
  };
217
211
  readonly maybeFocusSelector: import("effect/Option").Option<string>;
218
212
  };
219
- readonly isCloseHeld: boolean;
220
213
  };
221
214
  }, {
222
215
  readonly _tag: "ClickedCancel";
@@ -280,8 +273,9 @@ export declare const view: import("foldkit/submodel").View<{
280
273
  /** Destructive: the confirming button turns red and cancel becomes the default. */
281
274
  isDanger?: boolean;
282
275
  /** The confirmed work is running: the confirming button is held (its word stays, the
283
- * working cursor prints, a second press does nothing) and keeps focus. Cancel stays live
284
- * unless the dialog's ways out are held (`setCloseHeld`). */
276
+ * working cursor prints, a second press does nothing) and keeps focus, and cancel is held
277
+ * with it. Pair it with `isCloseHeld` in `update`'s context, from the same state, so
278
+ * Escape and the veil change nothing either. */
285
279
  isBusy?: boolean;
286
280
  /** The action cannot run now (nothing is running; it is blocked): the confirming button is
287
281
  * held, `aria-disabled` without the working cursor, and stays in the keyboard, so focus
@@ -1 +1 @@
1
- {"version":3,"file":"confirmDialog.d.ts","sourceRoot":"","sources":["../../../src/confirmDialog/confirmDialog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"confirmDialog.d.ts","sourceRoot":"","sources":["../../../src/confirmDialog/confirmDialog.ts"],"names":[],"mappings":"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"}
@@ -25,7 +25,7 @@ export const Message = defineMessageUnion({
25
25
  /** Union of OutMessages a confirm dialog reports. `Confirmed`: the reader pressed the action;
26
26
  * the dialog stays open until the parent calls `close`. `Cancelled`: cancel, Escape or a click
27
27
  * on the veil; the dialog has closed, and whether that also stops work already running is
28
- * the parent's to decide. Never reported while its ways out are held (`setCloseHeld`). */
28
+ * the parent's to decide. Never reported while its ways out are held (`Dialog.UpdateContext`). */
29
29
  export const OutMessage = defineMessageUnion({
30
30
  Confirmed: {},
31
31
  Cancelled: {},
@@ -44,32 +44,27 @@ const dialogFold = foldDialog(Dialog, {
44
44
  toParentMessage: (message) => __foldkitBrandViewResult((Message.GotDialogMessage({ message })), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#toParentMessage"),
45
45
  toParentOutMessage: toCancelled,
46
46
  });
47
- /** Processes a confirm dialog Message and returns the next Model, Commands and OutMessage. */
48
- export const update = (model, message) => __foldkitBrandViewResult((Message.match(message, {
49
- GotDialogMessage: ({ message: dialogMessage }) => __foldkitBrandViewResult((dialogFold.update(model, dialogMessage)), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#GotDialogMessage"),
47
+ const FREE = { isCloseHeld: false };
48
+ /** Processes a confirm dialog Message and returns the next Model, Commands and OutMessage.
49
+ * While `context.isCloseHeld`, cancel, Escape and the veil change nothing. */
50
+ export const update = (model, message, context = FREE) => __foldkitBrandViewResult((Message.match(message, {
51
+ GotDialogMessage: ({ message: dialogMessage }) => __foldkitBrandViewResult((dialogFold.updateWith(context)(model, dialogMessage)), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#GotDialogMessage"),
50
52
  ClickedConfirm: () => (__foldkitBrandViewResult(({ model, outMessage: OutMessage.Confirmed() }), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#ClickedConfirm")),
51
- ClickedCancel: () => __foldkitBrandViewResult((Dialog.isCloseHeld(model.dialog)
53
+ ClickedCancel: () => __foldkitBrandViewResult((context.isCloseHeld
52
54
  ? { model }
53
55
  : pipe(dialogFold.close(model), Update.withOutMessage(OutMessage.Cancelled()))), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#ClickedCancel"),
54
56
  })), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#update");
55
57
  /** Opens the confirm dialog: focus starts on the action, or on cancel when it is `isDanger`. */
56
58
  export const open = (model) => __foldkitBrandViewResult((dialogFold.open(model)), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#open");
57
- /** Closes the confirm dialog without reporting `Cancelled`, and lets go of a hold: call it
58
- * once confirmed work has landed. */
59
+ /** Closes the confirm dialog without reporting `Cancelled`: call it once confirmed work has
60
+ * landed. */
59
61
  export const close = (model) => __foldkitBrandViewResult((dialogFold.close(model)), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#close");
60
- /** Holds cancel, Escape and the veil, or lets them go: while held the dialog stays open and
61
- * reports no `Cancelled`, and cancel prints held (`aria-disabled`, in the keyboard). Hold it
62
- * in the update that starts confirmed work whose failure must land here, and let go in the
63
- * update where the work fails; `close` lets go once it lands. */
64
- export const setCloseHeld = (model, isHeld) => __foldkitBrandViewResult((modifyFields(model, { dialog: (dialog) => __foldkitBrandViewResult((Dialog.setCloseHeld(dialog, isHeld)), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#dialog~2") })), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#setCloseHeld");
65
62
  // ACCESSORS
66
63
  /** The confirm dialog's id, unique in the document. */
67
64
  export const id = (model) => __foldkitBrandViewResult((Dialog.id(model.dialog)), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#id");
68
65
  /** Whether the confirm dialog is open. */
69
66
  export const isOpen = (model) => __foldkitBrandViewResult((Dialog.isOpen(model.dialog)), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#isOpen");
70
- /** Whether its ways out are held (`setCloseHeld`). */
71
- export const isCloseHeld = (model) => __foldkitBrandViewResult((Dialog.isCloseHeld(model.dialog)), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#isCloseHeld");
72
- const cardView = (model, viewInputs, render, h) => {
67
+ const cardView = (viewInputs, render, h) => {
73
68
  const { isDanger = false, isBusy = false, isDisabled = false, toDetailView } = viewInputs;
74
69
  const commit = Button.view({
75
70
  label: viewInputs.label,
@@ -83,7 +78,7 @@ const cardView = (model, viewInputs, render, h) => {
83
78
  const cancel = Button.view({
84
79
  label: "cancel",
85
80
  isDefault: isDanger,
86
- isDisabled: Dialog.isCloseHeld(model.dialog),
81
+ isDisabled: isBusy,
87
82
  onClick: Message.ClickedCancel(),
88
83
  attributes: isDanger ? render.initialFocus : [],
89
84
  }, h);
@@ -113,9 +108,9 @@ const cardView = (model, viewInputs, render, h) => {
113
108
  * arm-then-confirm button: red never rests on a button, and an armed button is easy to
114
109
  * double-click through.
115
110
  *
116
- * Work that takes a while stays in the dialog: set `isBusy` while it runs, `close` once it
117
- * has landed, and on failure keep it open with the error in `toDetailView`. Hold its ways
118
- * out with `setCloseHeld` too when the reader must stay to see how it ends.
111
+ * Work that takes a while stays in the dialog: set `isBusy` while it runs (and `isCloseHeld`
112
+ * in `update`'s context), `close` once it has landed, and on failure keep it open with the
113
+ * error in `toDetailView`.
119
114
  */
120
115
  export const view = defineView((model, viewInputs, h) => __foldkitBrandViewResult((h.submodel({
121
116
  slotId: id(model),
@@ -125,7 +120,7 @@ export const view = defineView((model, viewInputs, h) => __foldkitBrandViewResul
125
120
  isAlert: viewInputs.isDanger ?? false,
126
121
  hasDescription: true,
127
122
  toLiveRegionView: viewInputs.toLiveRegionView,
128
- toView: (render) => __foldkitBrandViewResult((cardView(model, viewInputs, render, h)), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#toView"),
123
+ toView: (render) => __foldkitBrandViewResult((cardView(viewInputs, render, h)), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#toView"),
129
124
  },
130
125
  toParentMessage: (message) => __foldkitBrandViewResult((Message.GotDialogMessage({ message })), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#toParentMessage~2"),
131
126
  })), "@gjermundgaraba-designs/pixel-paper/src/confirmDialog/confirmDialog.js#anonymous"));
@@ -1,3 +1,3 @@
1
- export { Message, Model, OutMessage, close, id, init, isCloseHeld, isOpen, open, setCloseHeld, update, view, } from "./confirmDialog.ts";
1
+ export { Message, Model, OutMessage, close, id, init, isOpen, open, update, view, } from "./confirmDialog.ts";
2
2
  export type { InitConfig, ViewInputs } from "./confirmDialog.ts";
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/confirmDialog/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,KAAK,EACL,UAAU,EACV,KAAK,EACL,EAAE,EACF,IAAI,EACJ,WAAW,EACX,MAAM,EACN,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,IAAI,GACL,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/confirmDialog/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,KAAK,EACL,UAAU,EACV,KAAK,EACL,EAAE,EACF,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,MAAM,EACN,IAAI,GACL,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC"}
@@ -1 +1 @@
1
- export { Message, Model, OutMessage, close, id, init, isCloseHeld, isOpen, open, setCloseHeld, update, view, } from "./confirmDialog.js";
1
+ export { Message, Model, OutMessage, close, id, init, isOpen, open, update, view, } from "./confirmDialog.js";
@@ -2,8 +2,7 @@ import { Option, Schema } from "effect";
2
2
  import { type ChildAttribute, type Html } from "foldkit/html";
3
3
  import * as Mount from "foldkit/mount";
4
4
  import type * as Update from "foldkit/update";
5
- /** Schema for a pixel-paper dialog: the `@foldkit/ui` Dialog it is built on, and whether its
6
- * ways out are held (`setCloseHeld`). */
5
+ /** Schema for a pixel-paper dialog: the `@foldkit/ui` Dialog it is built on. */
7
6
  export declare const Model: Schema.Struct<{
8
7
  readonly dialog: Schema.Struct<{
9
8
  readonly id: Schema.String;
@@ -17,7 +16,6 @@ export declare const Model: Schema.Struct<{
17
16
  }>;
18
17
  readonly maybeFocusSelector: Schema.Option<Schema.String>;
19
18
  }>;
20
- readonly isCloseHeld: Schema.Boolean;
21
19
  }>;
22
20
  export type Model = typeof Model.Type;
23
21
  /** Which way h, l and the side arrows move focus in a dialog's action bar. */
@@ -75,10 +73,17 @@ export declare const init: (config: InitConfig) => Model;
75
73
  export declare const id: (model: Model) => string;
76
74
  /** Whether the dialog is open. */
77
75
  export declare const isOpen: (model: Model) => boolean;
78
- /** Whether the dialog's ways out are held (`setCloseHeld`). */
79
- export declare const isCloseHeld: (model: Model) => boolean;
76
+ /** What a dialog's update reads from its parent as a Message arrives. */
77
+ export type UpdateContext = Readonly<{
78
+ /** The reader may not walk away from the work running now (a save whose failure must land
79
+ * in this dialog): Escape, a press on the veil and a control given the `closeButton` group
80
+ * change nothing and report no `Closed`. Read it from the parent's own state as the
81
+ * Message arrives (`isSaving(model)`), so it holds exactly while the work runs, however
82
+ * soon after the start a key comes. */
83
+ isCloseHeld: boolean;
84
+ }>;
80
85
  /** Processes a dialog Message and returns the next Model, Commands and OutMessage. */
81
- export declare const update: (model: Model, message: Message) => Readonly<{
86
+ export declare const update: (model: Model, message: Message, context?: UpdateContext) => Readonly<{
82
87
  model: {
83
88
  readonly dialog: {
84
89
  readonly id: string;
@@ -92,7 +97,6 @@ export declare const update: (model: Model, message: Message) => Readonly<{
92
97
  };
93
98
  readonly maybeFocusSelector: Option.Option<string>;
94
99
  };
95
- readonly isCloseHeld: boolean;
96
100
  };
97
101
  commands?: Update.Commands<{
98
102
  readonly _tag: "GotDialogMessage";
@@ -139,15 +143,8 @@ export declare const update: (model: Model, message: Message) => Readonly<{
139
143
  /** Opens the dialog: focus moves to the element given the `initialFocus` group, else to the
140
144
  * first control, and returns to where it was when the dialog closes. */
141
145
  export declare const open: (model: Model) => Update.Return<Model, Message>;
142
- /** Closes the dialog without reporting `Closed`, and lets go of a hold. */
146
+ /** Closes the dialog without reporting `Closed`. */
143
147
  export declare const close: (model: Model) => Update.Return<Model, Message>;
144
- /** Holds the dialog's ways out, or lets them go: while held, Escape, a press on the veil and
145
- * a control given the `closeButton` group leave it open and report no `Closed`, so the
146
- * result of work the reader may not walk away from (a save whose failure must land here)
147
- * lands in it. Hold it in the update that starts the work, and let go in the update where
148
- * the work fails, or the reader is shut in with the failure; `close` lets go once it lands.
149
- * Hold the card's own close controls too (`Card.formView`'s `isBusy`). */
150
- export declare const setCloseHeld: (model: Model, isHeld: boolean) => Model;
151
148
  /** Moves focus for one keydown in an action bar, and says which way it moved. It moves only
152
149
  * when the key's target is one of the bar's own actions and there is an action that way:
153
150
  * a key typed in a field, a menu's item or a nested dialog inside the bar, a key an IME is
@@ -235,7 +232,6 @@ export declare const view: import("foldkit/submodel").View<{
235
232
  };
236
233
  readonly maybeFocusSelector: Option.Option<string>;
237
234
  };
238
- readonly isCloseHeld: boolean;
239
235
  }, {
240
236
  readonly _tag: "GotDialogMessage";
241
237
  readonly message: {
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../src/dialog/dialog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../src/dialog/dialog.ts"],"names":[],"mappings":"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"}
@@ -10,11 +10,9 @@ import { defineView } from "foldkit/submodel";
10
10
  import { isPlain } from "../keys/keys.js";
11
11
  import { foldDialog } from "./fold.js";
12
12
  // MODEL
13
- /** Schema for a pixel-paper dialog: the `@foldkit/ui` Dialog it is built on, and whether its
14
- * ways out are held (`setCloseHeld`). */
13
+ /** Schema for a pixel-paper dialog: the `@foldkit/ui` Dialog it is built on. */
15
14
  export const Model = Schema.Struct({
16
15
  dialog: UiDialog.Model,
17
- isCloseHeld: Schema.Boolean,
18
16
  });
19
17
  /** Which way h, l and the side arrows move focus in a dialog's action bar. */
20
18
  const ActionDirection = Schema.Literals(["Previous", "Next"]);
@@ -36,15 +34,12 @@ export const OutMessage = defineMessageUnion({
36
34
  /** Creates a closed dialog. */
37
35
  export const init = (config) => (__foldkitBrandViewResult(({
38
36
  dialog: UiDialog.init({ id: config.id }),
39
- isCloseHeld: false,
40
37
  }), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#init"));
41
38
  // ACCESSORS
42
39
  /** The dialog's id, unique in the document. */
43
40
  export const id = (model) => __foldkitBrandViewResult((model.dialog.id), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#id");
44
41
  /** Whether the dialog is open. */
45
42
  export const isOpen = (model) => __foldkitBrandViewResult((model.dialog.isOpen), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#isOpen");
46
- /** Whether the dialog's ways out are held (`setCloseHeld`). */
47
- export const isCloseHeld = (model) => __foldkitBrandViewResult((model.isCloseHeld), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#isCloseHeld");
48
43
  // UPDATE
49
44
  const toOutMessage = UiDialog.OutMessage.match({
50
45
  Opened: () => __foldkitBrandViewResult((undefined), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#Opened"),
@@ -56,27 +51,21 @@ const dialogFold = foldDialog(UiDialog, {
56
51
  toParentMessage: (message) => __foldkitBrandViewResult((Message.GotDialogMessage({ message })), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#toParentMessage"),
57
52
  toParentOutMessage: toOutMessage,
58
53
  });
54
+ const FREE = { isCloseHeld: false };
59
55
  // NOTE: @foldkit/ui gap: Dialog has no way to hold a close. Escape, a press on the veil and a
60
56
  // control given the `closeButton` group all send `RequestedClose`, so a held dialog reads it
61
57
  // by its tag and leaves it out.
62
- const isHeldClose = (model, message) => __foldkitBrandViewResult((model.isCloseHeld && message._tag === "RequestedClose"), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#isHeldClose");
58
+ const isHeldClose = (context, message) => __foldkitBrandViewResult((context.isCloseHeld && message._tag === "RequestedClose"), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#isHeldClose");
63
59
  /** Processes a dialog Message and returns the next Model, Commands and OutMessage. */
64
- export const update = (model, message) => __foldkitBrandViewResult((Message.match(message, {
65
- GotDialogMessage: ({ message: dialogMessage }) => __foldkitBrandViewResult((isHeldClose(model, dialogMessage) ? { model } : dialogFold.update(model, dialogMessage)), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#GotDialogMessage"),
60
+ export const update = (model, message, context = FREE) => __foldkitBrandViewResult((Message.match(message, {
61
+ GotDialogMessage: ({ message: dialogMessage }) => __foldkitBrandViewResult((isHeldClose(context, dialogMessage) ? { model } : dialogFold.update(model, dialogMessage)), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#GotDialogMessage"),
66
62
  PressedActionKey: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#PressedActionKey")),
67
63
  })), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#update");
68
64
  /** Opens the dialog: focus moves to the element given the `initialFocus` group, else to the
69
65
  * first control, and returns to where it was when the dialog closes. */
70
66
  export const open = (model) => __foldkitBrandViewResult((dialogFold.open(model)), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#open");
71
- /** Closes the dialog without reporting `Closed`, and lets go of a hold. */
72
- export const close = (model) => __foldkitBrandViewResult((dialogFold.close(modifyFields(model, { isCloseHeld: () => __foldkitBrandViewResult((false), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#isCloseHeld~2") }))), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#close");
73
- /** Holds the dialog's ways out, or lets them go: while held, Escape, a press on the veil and
74
- * a control given the `closeButton` group leave it open and report no `Closed`, so the
75
- * result of work the reader may not walk away from (a save whose failure must land here)
76
- * lands in it. Hold it in the update that starts the work, and let go in the update where
77
- * the work fails, or the reader is shut in with the failure; `close` lets go once it lands.
78
- * Hold the card's own close controls too (`Card.formView`'s `isBusy`). */
79
- export const setCloseHeld = (model, isHeld) => __foldkitBrandViewResult((modifyFields(model, { isCloseHeld: () => __foldkitBrandViewResult((isHeld), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#isCloseHeld~3") })), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#setCloseHeld");
67
+ /** Closes the dialog without reporting `Closed`. */
68
+ export const close = (model) => __foldkitBrandViewResult((dialogFold.close(model)), "@gjermundgaraba-designs/pixel-paper/src/dialog/dialog.js#close");
80
69
  // ACTION BAR KEYS
81
70
  const ACTION_BAR_ATTRIBUTE = "data-pixel-paper-action-bar";
82
71
  const ACTION_SELECTOR = "button:not(:disabled), a[href]";
@@ -1,9 +1,10 @@
1
1
  import * as Update from "foldkit/update";
2
+ import type { UpdateContext } from "./dialog.ts";
2
3
  type ChildReturn<ChildModel, ChildMessage, ChildOutMessage> = Update.ReturnWithOutMessage<ChildModel, ChildMessage, ChildOutMessage>;
3
4
  /** A dialog a parent holds: its update, and the steps that open and close it (`@foldkit/ui`'s
4
5
  * Dialog, or pixel-paper's). */
5
6
  type DialogChild<ChildModel, ChildMessage, ChildOutMessage> = Readonly<{
6
- update: (model: ChildModel, message: ChildMessage) => ChildReturn<ChildModel, ChildMessage, ChildOutMessage>;
7
+ update: (model: ChildModel, message: ChildMessage, context: UpdateContext) => ChildReturn<ChildModel, ChildMessage, ChildOutMessage>;
7
8
  open: (model: ChildModel) => ChildReturn<ChildModel, ChildMessage, ChildOutMessage>;
8
9
  close: (model: ChildModel) => ChildReturn<ChildModel, ChildMessage, ChildOutMessage>;
9
10
  }>;
@@ -16,10 +17,17 @@ type DialogFoldConfig<ParentModel, ParentMessage, ParentOutMessage, ChildModel,
16
17
  * veil, a close button). Without it the dialog's OutMessages report nothing: a parent
17
18
  * that reads `isOpen` when it needs to. */
18
19
  toParentOutMessage?: (outMessage: ChildOutMessage) => ParentOutMessage | undefined;
20
+ /** Whether the dialog's ways out are held, read from the parent's own state as each
21
+ * Message arrives (`(model) => model.isSaving`). Free when not given. See
22
+ * `Dialog.UpdateContext`. */
23
+ isCloseHeld?: (model: ParentModel) => boolean;
19
24
  }>;
20
25
  /** The dialog folded into its parent: a dialog Message, and opening and closing it. */
21
26
  type DialogFold<ParentModel, ParentMessage, ParentOutMessage, ChildMessage> = Readonly<{
22
27
  update: (model: ParentModel, message: ChildMessage) => Update.ReturnWithOutMessage<ParentModel, ParentMessage, ParentOutMessage>;
28
+ /** The update a parent that is itself a dialog (ConfirmDialog) runs with the hold its own
29
+ * parent gave it. */
30
+ updateWith: (context: UpdateContext) => (model: ParentModel, message: ChildMessage) => Update.ReturnWithOutMessage<ParentModel, ParentMessage, ParentOutMessage>;
23
31
  open: (model: ParentModel) => Update.Return<ParentModel, ParentMessage>;
24
32
  close: (model: ParentModel) => Update.Return<ParentModel, ParentMessage>;
25
33
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"fold.d.ts","sourceRoot":"","sources":["../../../src/dialog/fold.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,gBAAgB,CAAC;AAIzC,KAAK,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,eAAe,IAAI,MAAM,CAAC,oBAAoB,CACvF,UAAU,EACV,YAAY,EACZ,eAAe,CAChB,CAAC;AAEF;iCACiC;AACjC,KAAK,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,eAAe,IAAI,QAAQ,CAAC;IACrE,MAAM,EAAE,CACN,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,YAAY,KAClB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC;IAC5D,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC;IACpF,KAAK,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC;CACtF,CAAC,CAAC;AAEH,gGAAgG;AAChG,KAAK,gBAAgB,CACnB,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,eAAe,IACb,QAAQ,CAAC;IACX,IAAI,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,UAAU,CAAC;IACzC,KAAK,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,KAAK,WAAW,CAAC;IACnE,eAAe,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,aAAa,CAAC;IAC1D;;gDAE4C;IAC5C,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,eAAe,KAAK,gBAAgB,GAAG,SAAS,CAAC;CACpF,CAAC,CAAC;AAEH,uFAAuF;AACvF,KAAK,UAAU,CAAC,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,YAAY,IAAI,QAAQ,CAAC;IACrF,MAAM,EAAE,CACN,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,YAAY,KAClB,MAAM,CAAC,oBAAoB,CAAC,WAAW,EAAE,aAAa,EAAE,gBAAgB,CAAC,CAAC;IAC/E,IAAI,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IACxE,KAAK,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;CAC1E,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;uFAsBuF;AACvF,eAAO,MAAM,UAAU,GACrB,WAAW,EACX,aAAa,EACb,UAAU,EACV,YAAY,EACZ,eAAe,EACf,gBAAgB,GAAG,KAAK,SAEjB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,eAAe,CAAC,UACrD,gBAAgB,CACtB,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,eAAe,CAChB,KACA,UAAU,CAAC,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,YAAY,CAqBvE,CAAC"}
1
+ {"version":3,"file":"fold.d.ts","sourceRoot":"","sources":["../../../src/dialog/fold.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,gBAAgB,CAAC;AAEzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,KAAK,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,eAAe,IAAI,MAAM,CAAC,oBAAoB,CACvF,UAAU,EACV,YAAY,EACZ,eAAe,CAChB,CAAC;AAEF;iCACiC;AACjC,KAAK,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,eAAe,IAAI,QAAQ,CAAC;IACrE,MAAM,EAAE,CACN,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,aAAa,KACnB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC;IAC5D,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC;IACpF,KAAK,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC;CACtF,CAAC,CAAC;AAEH,gGAAgG;AAChG,KAAK,gBAAgB,CACnB,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,eAAe,IACb,QAAQ,CAAC;IACX,IAAI,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,UAAU,CAAC;IACzC,KAAK,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,KAAK,WAAW,CAAC;IACnE,eAAe,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,aAAa,CAAC;IAC1D;;gDAE4C;IAC5C,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,eAAe,KAAK,gBAAgB,GAAG,SAAS,CAAC;IACnF;;kCAE8B;IAC9B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC;CAC/C,CAAC,CAAC;AAEH,uFAAuF;AACvF,KAAK,UAAU,CAAC,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,YAAY,IAAI,QAAQ,CAAC;IACrF,MAAM,EAAE,CACN,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,YAAY,KAClB,MAAM,CAAC,oBAAoB,CAAC,WAAW,EAAE,aAAa,EAAE,gBAAgB,CAAC,CAAC;IAC/E;0BACsB;IACtB,UAAU,EAAE,CACV,OAAO,EAAE,aAAa,KACnB,CACH,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,YAAY,KAClB,MAAM,CAAC,oBAAoB,CAAC,WAAW,EAAE,aAAa,EAAE,gBAAgB,CAAC,CAAC;IAC/E,IAAI,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IACxE,KAAK,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;CAC1E,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;uFAsBuF;AACvF,eAAO,MAAM,UAAU,GACrB,WAAW,EACX,aAAa,EACb,UAAU,EACV,YAAY,EACZ,eAAe,EACf,gBAAgB,GAAG,KAAK,SAEjB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,eAAe,CAAC,UACrD,gBAAgB,CACtB,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,eAAe,CAChB,KACA,UAAU,CAAC,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,YAAY,CAyBvE,CAAC"}
@@ -34,12 +34,16 @@ export const foldDialog = (child, config) => {
34
34
  // `RequestedOpen`, which reports `Opened`), and so can its update, so each fold needs a
35
35
  // step for an OutMessage. This one keeps the parent's Model: a step reports nothing.
36
36
  const foldOutMessage = () => __foldkitBrandViewResult(((model) => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/dialog/fold.js#anonymous"))), "@gjermundgaraba-designs/pixel-paper/src/dialog/fold.js#foldOutMessage");
37
- const { toParentOutMessage } = config;
38
- const update = toParentOutMessage === undefined
39
- ? Update.foldChild({ update: child.update, ...lift, foldOutMessage })
40
- : Update.foldChild({ update: child.update, ...lift, toParentOutMessage });
37
+ const { toParentOutMessage, isCloseHeld = () => __foldkitBrandViewResult((false), "@gjermundgaraba-designs/pixel-paper/src/dialog/fold.js#anonymous~2") } = config;
38
+ const updateWith = (context) => {
39
+ const childUpdate = (model, message) => __foldkitBrandViewResult((child.update(model, message, context)), "@gjermundgaraba-designs/pixel-paper/src/dialog/fold.js#childUpdate");
40
+ return __foldkitBrandViewResult((toParentOutMessage === undefined
41
+ ? Update.foldChild({ update: childUpdate, ...lift, foldOutMessage })
42
+ : Update.foldChild({ update: childUpdate, ...lift, toParentOutMessage })), "@gjermundgaraba-designs/pixel-paper/src/dialog/fold.js#updateWith");
43
+ };
41
44
  return __foldkitBrandViewResult(({
42
- update,
45
+ update: (model, message) => __foldkitBrandViewResult((updateWith({ isCloseHeld: isCloseHeld(model) })(model, message)), "@gjermundgaraba-designs/pixel-paper/src/dialog/fold.js#update"),
46
+ updateWith,
43
47
  open: Update.foldChildStep({ update: child.open, ...lift, foldOutMessage }),
44
48
  close: Update.foldChildStep({ update: child.close, ...lift, foldOutMessage }),
45
49
  }), "@gjermundgaraba-designs/pixel-paper/src/dialog/fold.js#foldDialog");
@@ -1,4 +1,4 @@
1
- export { BindActionKeys, Message, Model, OutMessage, close, id, init, isCloseHeld, isOpen, open, sceneMounts, setCloseHeld, update, view, } from "./dialog.ts";
2
- export type { InitConfig, Placement, RenderInfo, ViewInputs } from "./dialog.ts";
1
+ export { BindActionKeys, Message, Model, OutMessage, close, id, init, isOpen, open, sceneMounts, update, view, } from "./dialog.ts";
2
+ export type { InitConfig, Placement, RenderInfo, UpdateContext, ViewInputs } from "./dialog.ts";
3
3
  export { foldDialog } from "./fold.ts";
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dialog/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,OAAO,EACP,KAAK,EACL,UAAU,EACV,KAAK,EACL,EAAE,EACF,IAAI,EACJ,WAAW,EACX,MAAM,EACN,IAAI,EACJ,WAAW,EACX,YAAY,EACZ,MAAM,EACN,IAAI,GACL,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dialog/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,OAAO,EACP,KAAK,EACL,UAAU,EACV,KAAK,EACL,EAAE,EACF,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,WAAW,EACX,MAAM,EACN,IAAI,GACL,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAChG,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
@@ -1,2 +1,2 @@
1
- export { BindActionKeys, Message, Model, OutMessage, close, id, init, isCloseHeld, isOpen, open, sceneMounts, setCloseHeld, update, view, } from "./dialog.js";
1
+ export { BindActionKeys, Message, Model, OutMessage, close, id, init, isOpen, open, sceneMounts, update, view, } from "./dialog.js";
2
2
  export { foldDialog } from "./fold.js";
@@ -20,7 +20,6 @@ export declare const Model: Schema.Struct<{
20
20
  }>;
21
21
  readonly maybeFocusSelector: Schema.Option<Schema.String>;
22
22
  }>;
23
- readonly isCloseHeld: Schema.Boolean;
24
23
  }>;
25
24
  readonly query: Schema.String;
26
25
  }>;
@@ -106,7 +105,6 @@ export declare const update: (model: Model, message: Message) => Readonly<{
106
105
  };
107
106
  readonly maybeFocusSelector: import("effect/Option").Option<string>;
108
107
  };
109
- readonly isCloseHeld: boolean;
110
108
  };
111
109
  readonly query: string;
112
110
  };
@@ -184,7 +182,6 @@ export declare const subscriptions: {
184
182
  };
185
183
  readonly maybeFocusSelector: import("effect/Option").Option<string>;
186
184
  };
187
- readonly isCloseHeld: boolean;
188
185
  };
189
186
  readonly query: string;
190
187
  }, {
@@ -271,7 +268,6 @@ export declare const view: import("foldkit/submodel").View<{
271
268
  };
272
269
  readonly maybeFocusSelector: import("effect/Option").Option<string>;
273
270
  };
274
- readonly isCloseHeld: boolean;
275
271
  };
276
272
  readonly query: string;
277
273
  }, {
@@ -1 +1 @@
1
- {"version":3,"file":"keyHelp.d.ts","sourceRoot":"","sources":["../../../src/keyHelp/keyHelp.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"keyHelp.d.ts","sourceRoot":"","sources":["../../../src/keyHelp/keyHelp.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjermundgaraba-designs/pixel-paper",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
package/src/card/card.ts CHANGED
@@ -90,10 +90,11 @@ export const view = <Message>(config: ViewConfig<Message>, h: HtmlBuilder<Messag
90
90
  // FORM
91
91
 
92
92
  /** Configuration for rendering a form card with `formView`: a card's, but for its body, its
93
- * close attributes and its action bar, which the form fills. */
93
+ * close attributes and its actions, which the form fills. `lead` stays the card's: what
94
+ * goes before the push, such as a form's own delete. */
94
95
  export type FormViewConfig<Message> = Omit<
95
96
  ViewConfig<Message>,
96
- "body" | "closeAttributes" | "actions" | "lead"
97
+ "body" | "closeAttributes" | "actions"
97
98
  > &
98
99
  Readonly<{
99
100
  /** Unique in the document: the submit button's id is `submitId(id)`. */
@@ -101,6 +102,10 @@ export type FormViewConfig<Message> = Omit<
101
102
  /** The form's content, fields and all, in one Fields group that `isBusy` holds. A link in
102
103
  * it (an ErrorSummary's) stays live. */
103
104
  body: ReadonlyArray<Html | string>;
105
+ /** Above the fields, outside the group `isBusy` holds: what the page says about the form
106
+ * while it is open (a lost connection with its retry), whose controls stay live while it
107
+ * sends. */
108
+ notices?: ReadonlyArray<Html | string>;
104
109
  /** The submit button's words. It prints primary, the card's default. */
105
110
  submit: string;
106
111
  /** The cancel button's words, before the submit. It closes through `closeAttributes`. */
@@ -110,9 +115,10 @@ export type FormViewConfig<Message> = Omit<
110
115
  closeAttributes?: Attributes<Message>;
111
116
  /** The form's work is running (it sends): the submit button is busy, the close glyph and
112
117
  * cancel are held without `closeAttributes`, and the body is natively disabled, so
113
- * nothing changes under the send and nothing sends twice. In a Dialog, hold its ways out
114
- * too (`Dialog.setCloseHeld`), and let go of both where the send fails. Enter in a field can submit before the fields are held,
115
- * so the update still ignores `onSubmit` while busy. */
118
+ * nothing changes under the send and nothing sends twice. In a Dialog, pass the same state
119
+ * as `isCloseHeld` to its update, so Escape and the veil are held too. Enter in a field
120
+ * can submit before the fields are held, so the update still ignores `onSubmit` while
121
+ * busy. */
116
122
  isBusy?: boolean;
117
123
  /** The form cannot be sent yet (nothing to send): the submit button is held as a Button
118
124
  * is, and the fields and cancel stay live. Enter in a field can still submit, so the
@@ -127,8 +133,8 @@ export type FormViewConfig<Message> = Omit<
127
133
  * `Focus.Focus({ id: Card.submitId(id) })`. */
128
134
  export const submitId = (id: string): string => `${id}-submit`;
129
135
 
130
- /** A card that is a form, named by its title, so a form landmark: its body in one Fields
131
- * group, then cancel and the primary submit button in the action bar. */
136
+ /** A card that is a form, named by its title, so a form landmark: its notices, its body in
137
+ * one Fields group, then cancel and the primary submit button in the action bar. */
132
138
  export const formView = <Message>(
133
139
  config: FormViewConfig<Message>,
134
140
  h: HtmlBuilder<Message>,
@@ -139,6 +145,7 @@ export const formView = <Message>(
139
145
  submit,
140
146
  cancel,
141
147
  closeAttributes,
148
+ notices = [],
142
149
  isBusy = false,
143
150
  isSubmitDisabled = false,
144
151
  onSubmit,
@@ -181,7 +188,7 @@ export const formView = <Message>(
181
188
  childrenView(
182
189
  {
183
190
  ...config,
184
- body: [Fields.view({ body: config.body, isBusy }, h)],
191
+ body: [...notices, Fields.view({ body: config.body, isBusy }, h)],
185
192
  isCloseHeld: isBusy,
186
193
  actions: [...cancelButton, submitButton],
187
194
  },
@@ -34,7 +34,7 @@ export type Message = typeof Message.Type;
34
34
  /** Union of OutMessages a confirm dialog reports. `Confirmed`: the reader pressed the action;
35
35
  * the dialog stays open until the parent calls `close`. `Cancelled`: cancel, Escape or a click
36
36
  * on the veil; the dialog has closed, and whether that also stops work already running is
37
- * the parent's to decide. Never reported while its ways out are held (`setCloseHeld`). */
37
+ * the parent's to decide. Never reported while its ways out are held (`Dialog.UpdateContext`). */
38
38
  export const OutMessage = defineMessageUnion({
39
39
  Confirmed: {},
40
40
  Cancelled: {},
@@ -65,13 +65,17 @@ const dialogFold = foldDialog(Dialog, {
65
65
  toParentOutMessage: toCancelled,
66
66
  });
67
67
 
68
- /** Processes a confirm dialog Message and returns the next Model, Commands and OutMessage. */
69
- export const update = (model: Model, message: Message) =>
68
+ const FREE: Dialog.UpdateContext = { isCloseHeld: false };
69
+
70
+ /** Processes a confirm dialog Message and returns the next Model, Commands and OutMessage.
71
+ * While `context.isCloseHeld`, cancel, Escape and the veil change nothing. */
72
+ export const update = (model: Model, message: Message, context: Dialog.UpdateContext = FREE) =>
70
73
  Message.match<Update.ReturnWithOutMessage<Model, Message, OutMessage>>(message, {
71
- GotDialogMessage: ({ message: dialogMessage }) => dialogFold.update(model, dialogMessage),
74
+ GotDialogMessage: ({ message: dialogMessage }) =>
75
+ dialogFold.updateWith(context)(model, dialogMessage),
72
76
  ClickedConfirm: () => ({ model, outMessage: OutMessage.Confirmed() }),
73
77
  ClickedCancel: () =>
74
- Dialog.isCloseHeld(model.dialog)
78
+ context.isCloseHeld
75
79
  ? { model }
76
80
  : pipe(dialogFold.close(model), Update.withOutMessage(OutMessage.Cancelled())),
77
81
  });
@@ -79,17 +83,10 @@ export const update = (model: Model, message: Message) =>
79
83
  /** Opens the confirm dialog: focus starts on the action, or on cancel when it is `isDanger`. */
80
84
  export const open = (model: Model): Update.Return<Model, Message> => dialogFold.open(model);
81
85
 
82
- /** Closes the confirm dialog without reporting `Cancelled`, and lets go of a hold: call it
83
- * once confirmed work has landed. */
86
+ /** Closes the confirm dialog without reporting `Cancelled`: call it once confirmed work has
87
+ * landed. */
84
88
  export const close = (model: Model): Update.Return<Model, Message> => dialogFold.close(model);
85
89
 
86
- /** Holds cancel, Escape and the veil, or lets them go: while held the dialog stays open and
87
- * reports no `Cancelled`, and cancel prints held (`aria-disabled`, in the keyboard). Hold it
88
- * in the update that starts confirmed work whose failure must land here, and let go in the
89
- * update where the work fails; `close` lets go once it lands. */
90
- export const setCloseHeld = (model: Model, isHeld: boolean): Model =>
91
- modifyFields(model, { dialog: (dialog) => Dialog.setCloseHeld(dialog, isHeld) });
92
-
93
90
  // ACCESSORS
94
91
 
95
92
  /** The confirm dialog's id, unique in the document. */
@@ -98,9 +95,6 @@ export const id = (model: Model): string => Dialog.id(model.dialog);
98
95
  /** Whether the confirm dialog is open. */
99
96
  export const isOpen = (model: Model): boolean => Dialog.isOpen(model.dialog);
100
97
 
101
- /** Whether its ways out are held (`setCloseHeld`). */
102
- export const isCloseHeld = (model: Model): boolean => Dialog.isCloseHeld(model.dialog);
103
-
104
98
  // VIEW
105
99
 
106
100
  /** Per-render inputs passed to `view` through `h.submodel`'s `viewInputs`. */
@@ -122,8 +116,9 @@ export type ViewInputs = Readonly<{
122
116
  /** Destructive: the confirming button turns red and cancel becomes the default. */
123
117
  isDanger?: boolean;
124
118
  /** The confirmed work is running: the confirming button is held (its word stays, the
125
- * working cursor prints, a second press does nothing) and keeps focus. Cancel stays live
126
- * unless the dialog's ways out are held (`setCloseHeld`). */
119
+ * working cursor prints, a second press does nothing) and keeps focus, and cancel is held
120
+ * with it. Pair it with `isCloseHeld` in `update`'s context, from the same state, so
121
+ * Escape and the veil change nothing either. */
127
122
  isBusy?: boolean;
128
123
  /** The action cannot run now (nothing is running; it is blocked): the confirming button is
129
124
  * held, `aria-disabled` without the working cursor, and stays in the keyboard, so focus
@@ -135,7 +130,6 @@ export type ViewInputs = Readonly<{
135
130
  }>;
136
131
 
137
132
  const cardView = (
138
- model: Model,
139
133
  viewInputs: ViewInputs,
140
134
  render: Dialog.RenderInfo,
141
135
  h: HtmlBuilder<Message>,
@@ -158,7 +152,7 @@ const cardView = (
158
152
  {
159
153
  label: "cancel",
160
154
  isDefault: isDanger,
161
- isDisabled: Dialog.isCloseHeld(model.dialog),
155
+ isDisabled: isBusy,
162
156
  onClick: Message.ClickedCancel(),
163
157
  attributes: isDanger ? render.initialFocus : [],
164
158
  },
@@ -198,9 +192,9 @@ const cardView = (
198
192
  * arm-then-confirm button: red never rests on a button, and an armed button is easy to
199
193
  * double-click through.
200
194
  *
201
- * Work that takes a while stays in the dialog: set `isBusy` while it runs, `close` once it
202
- * has landed, and on failure keep it open with the error in `toDetailView`. Hold its ways
203
- * out with `setCloseHeld` too when the reader must stay to see how it ends.
195
+ * Work that takes a while stays in the dialog: set `isBusy` while it runs (and `isCloseHeld`
196
+ * in `update`'s context), `close` once it has landed, and on failure keep it open with the
197
+ * error in `toDetailView`.
204
198
  */
205
199
  export const view = defineView<Model, Message, ViewInputs>((model, viewInputs, h): Html =>
206
200
  h.submodel({
@@ -211,7 +205,7 @@ export const view = defineView<Model, Message, ViewInputs>((model, viewInputs, h
211
205
  isAlert: viewInputs.isDanger ?? false,
212
206
  hasDescription: true,
213
207
  toLiveRegionView: viewInputs.toLiveRegionView,
214
- toView: (render) => cardView(model, viewInputs, render, h),
208
+ toView: (render) => cardView(viewInputs, render, h),
215
209
  },
216
210
  toParentMessage: (message) => Message.GotDialogMessage({ message }),
217
211
  }),
@@ -5,10 +5,8 @@ export {
5
5
  close,
6
6
  id,
7
7
  init,
8
- isCloseHeld,
9
8
  isOpen,
10
9
  open,
11
- setCloseHeld,
12
10
  update,
13
11
  view,
14
12
  } from "./confirmDialog.ts";
@@ -13,11 +13,9 @@ import { foldDialog } from "./fold.ts";
13
13
 
14
14
  // MODEL
15
15
 
16
- /** Schema for a pixel-paper dialog: the `@foldkit/ui` Dialog it is built on, and whether its
17
- * ways out are held (`setCloseHeld`). */
16
+ /** Schema for a pixel-paper dialog: the `@foldkit/ui` Dialog it is built on. */
18
17
  export const Model = Schema.Struct({
19
18
  dialog: UiDialog.Model,
20
- isCloseHeld: Schema.Boolean,
21
19
  });
22
20
  export type Model = typeof Model.Type;
23
21
 
@@ -56,7 +54,6 @@ export type InitConfig = Readonly<{ id: string }>;
56
54
  /** Creates a closed dialog. */
57
55
  export const init = (config: InitConfig): Model => ({
58
56
  dialog: UiDialog.init({ id: config.id }),
59
- isCloseHeld: false,
60
57
  });
61
58
 
62
59
  // ACCESSORS
@@ -67,9 +64,6 @@ export const id = (model: Model): string => model.dialog.id;
67
64
  /** Whether the dialog is open. */
68
65
  export const isOpen = (model: Model): boolean => model.dialog.isOpen;
69
66
 
70
- /** Whether the dialog's ways out are held (`setCloseHeld`). */
71
- export const isCloseHeld = (model: Model): boolean => model.isCloseHeld;
72
-
73
67
  // UPDATE
74
68
 
75
69
  const toOutMessage = UiDialog.OutMessage.match<OutMessage | undefined>({
@@ -85,17 +79,29 @@ const dialogFold = foldDialog(UiDialog, {
85
79
  toParentOutMessage: toOutMessage,
86
80
  });
87
81
 
82
+ /** What a dialog's update reads from its parent as a Message arrives. */
83
+ export type UpdateContext = Readonly<{
84
+ /** The reader may not walk away from the work running now (a save whose failure must land
85
+ * in this dialog): Escape, a press on the veil and a control given the `closeButton` group
86
+ * change nothing and report no `Closed`. Read it from the parent's own state as the
87
+ * Message arrives (`isSaving(model)`), so it holds exactly while the work runs, however
88
+ * soon after the start a key comes. */
89
+ isCloseHeld: boolean;
90
+ }>;
91
+
92
+ const FREE: UpdateContext = { isCloseHeld: false };
93
+
88
94
  // NOTE: @foldkit/ui gap: Dialog has no way to hold a close. Escape, a press on the veil and a
89
95
  // control given the `closeButton` group all send `RequestedClose`, so a held dialog reads it
90
96
  // by its tag and leaves it out.
91
- const isHeldClose = (model: Model, message: UiDialog.Message): boolean =>
92
- model.isCloseHeld && message._tag === "RequestedClose";
97
+ const isHeldClose = (context: UpdateContext, message: UiDialog.Message): boolean =>
98
+ context.isCloseHeld && message._tag === "RequestedClose";
93
99
 
94
100
  /** Processes a dialog Message and returns the next Model, Commands and OutMessage. */
95
- export const update = (model: Model, message: Message) =>
101
+ export const update = (model: Model, message: Message, context: UpdateContext = FREE) =>
96
102
  Message.match<Update.ReturnWithOutMessage<Model, Message, OutMessage>>(message, {
97
103
  GotDialogMessage: ({ message: dialogMessage }) =>
98
- isHeldClose(model, dialogMessage) ? { model } : dialogFold.update(model, dialogMessage),
104
+ isHeldClose(context, dialogMessage) ? { model } : dialogFold.update(model, dialogMessage),
99
105
  PressedActionKey: () => ({ model }),
100
106
  });
101
107
 
@@ -103,18 +109,8 @@ export const update = (model: Model, message: Message) =>
103
109
  * first control, and returns to where it was when the dialog closes. */
104
110
  export const open = (model: Model): Update.Return<Model, Message> => dialogFold.open(model);
105
111
 
106
- /** Closes the dialog without reporting `Closed`, and lets go of a hold. */
107
- export const close = (model: Model): Update.Return<Model, Message> =>
108
- dialogFold.close(modifyFields(model, { isCloseHeld: () => false }));
109
-
110
- /** Holds the dialog's ways out, or lets them go: while held, Escape, a press on the veil and
111
- * a control given the `closeButton` group leave it open and report no `Closed`, so the
112
- * result of work the reader may not walk away from (a save whose failure must land here)
113
- * lands in it. Hold it in the update that starts the work, and let go in the update where
114
- * the work fails, or the reader is shut in with the failure; `close` lets go once it lands.
115
- * Hold the card's own close controls too (`Card.formView`'s `isBusy`). */
116
- export const setCloseHeld = (model: Model, isHeld: boolean): Model =>
117
- modifyFields(model, { isCloseHeld: () => isHeld });
112
+ /** Closes the dialog without reporting `Closed`. */
113
+ export const close = (model: Model): Update.Return<Model, Message> => dialogFold.close(model);
118
114
 
119
115
  // ACTION BAR KEYS
120
116
 
@@ -1,6 +1,8 @@
1
1
  import { Option } from "effect";
2
2
  import * as Update from "foldkit/update";
3
3
 
4
+ import type { UpdateContext } from "./dialog.ts";
5
+
4
6
  // FOLD
5
7
 
6
8
  type ChildReturn<ChildModel, ChildMessage, ChildOutMessage> = Update.ReturnWithOutMessage<
@@ -15,6 +17,7 @@ type DialogChild<ChildModel, ChildMessage, ChildOutMessage> = Readonly<{
15
17
  update: (
16
18
  model: ChildModel,
17
19
  message: ChildMessage,
20
+ context: UpdateContext,
18
21
  ) => ChildReturn<ChildModel, ChildMessage, ChildOutMessage>;
19
22
  open: (model: ChildModel) => ChildReturn<ChildModel, ChildMessage, ChildOutMessage>;
20
23
  close: (model: ChildModel) => ChildReturn<ChildModel, ChildMessage, ChildOutMessage>;
@@ -36,6 +39,10 @@ type DialogFoldConfig<
36
39
  * veil, a close button). Without it the dialog's OutMessages report nothing: a parent
37
40
  * that reads `isOpen` when it needs to. */
38
41
  toParentOutMessage?: (outMessage: ChildOutMessage) => ParentOutMessage | undefined;
42
+ /** Whether the dialog's ways out are held, read from the parent's own state as each
43
+ * Message arrives (`(model) => model.isSaving`). Free when not given. See
44
+ * `Dialog.UpdateContext`. */
45
+ isCloseHeld?: (model: ParentModel) => boolean;
39
46
  }>;
40
47
 
41
48
  /** The dialog folded into its parent: a dialog Message, and opening and closing it. */
@@ -44,6 +51,14 @@ type DialogFold<ParentModel, ParentMessage, ParentOutMessage, ChildMessage> = Re
44
51
  model: ParentModel,
45
52
  message: ChildMessage,
46
53
  ) => Update.ReturnWithOutMessage<ParentModel, ParentMessage, ParentOutMessage>;
54
+ /** The update a parent that is itself a dialog (ConfirmDialog) runs with the hold its own
55
+ * parent gave it. */
56
+ updateWith: (
57
+ context: UpdateContext,
58
+ ) => (
59
+ model: ParentModel,
60
+ message: ChildMessage,
61
+ ) => Update.ReturnWithOutMessage<ParentModel, ParentMessage, ParentOutMessage>;
47
62
  open: (model: ParentModel) => Update.Return<ParentModel, ParentMessage>;
48
63
  close: (model: ParentModel) => Update.Return<ParentModel, ParentMessage>;
49
64
  }>;
@@ -98,14 +113,18 @@ export const foldDialog = <
98
113
  // `RequestedOpen`, which reports `Opened`), and so can its update, so each fold needs a
99
114
  // step for an OutMessage. This one keeps the parent's Model: a step reports nothing.
100
115
  const foldOutMessage = () => (model: ParentModel) => ({ model });
101
- const { toParentOutMessage } = config;
102
- const update =
103
- toParentOutMessage === undefined
104
- ? Update.foldChild({ update: child.update, ...lift, foldOutMessage })
105
- : Update.foldChild({ update: child.update, ...lift, toParentOutMessage });
116
+ const { toParentOutMessage, isCloseHeld = () => false } = config;
117
+ const updateWith = (context: UpdateContext) => {
118
+ const childUpdate = (model: ChildModel, message: ChildMessage) =>
119
+ child.update(model, message, context);
120
+ return toParentOutMessage === undefined
121
+ ? Update.foldChild({ update: childUpdate, ...lift, foldOutMessage })
122
+ : Update.foldChild({ update: childUpdate, ...lift, toParentOutMessage });
123
+ };
106
124
 
107
125
  return {
108
- update,
126
+ update: (model, message) => updateWith({ isCloseHeld: isCloseHeld(model) })(model, message),
127
+ updateWith,
109
128
  open: Update.foldChildStep({ update: child.open, ...lift, foldOutMessage }),
110
129
  close: Update.foldChildStep({ update: child.close, ...lift, foldOutMessage }),
111
130
  };
@@ -6,13 +6,11 @@ export {
6
6
  close,
7
7
  id,
8
8
  init,
9
- isCloseHeld,
10
9
  isOpen,
11
10
  open,
12
11
  sceneMounts,
13
- setCloseHeld,
14
12
  update,
15
13
  view,
16
14
  } from "./dialog.ts";
17
- export type { InitConfig, Placement, RenderInfo, ViewInputs } from "./dialog.ts";
15
+ export type { InitConfig, Placement, RenderInfo, UpdateContext, ViewInputs } from "./dialog.ts";
18
16
  export { foldDialog } from "./fold.ts";