@gjermundgaraba-designs/pixel-paper 0.20.1 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/DESIGN.md +21 -15
  2. package/dist/src/bench/bench.d.ts +14 -0
  3. package/dist/src/bench/bench.d.ts.map +1 -0
  4. package/dist/src/bench/bench.js +9 -0
  5. package/dist/src/bench/index.d.ts +3 -0
  6. package/dist/src/bench/index.d.ts.map +1 -0
  7. package/dist/src/bench/index.js +1 -0
  8. package/dist/src/chip/chip.d.ts +10 -0
  9. package/dist/src/chip/chip.d.ts.map +1 -1
  10. package/dist/src/chip/chip.js +19 -0
  11. package/dist/src/chip/index.d.ts +2 -2
  12. package/dist/src/chip/index.d.ts.map +1 -1
  13. package/dist/src/chip/index.js +1 -1
  14. package/dist/src/drag/drag.d.ts +18 -0
  15. package/dist/src/drag/drag.d.ts.map +1 -1
  16. package/dist/src/drag/drag.js +35 -7
  17. package/dist/src/field/field.d.ts +3 -0
  18. package/dist/src/field/field.d.ts.map +1 -1
  19. package/dist/src/field/field.js +2 -2
  20. package/dist/src/index.d.ts +1 -0
  21. package/dist/src/index.d.ts.map +1 -1
  22. package/dist/src/index.js +1 -0
  23. package/dist/src/lineDiff/index.d.ts +2 -0
  24. package/dist/src/lineDiff/index.d.ts.map +1 -1
  25. package/dist/src/lineDiff/index.js +1 -0
  26. package/dist/src/lineDiff/lineDiff.d.ts +8 -4
  27. package/dist/src/lineDiff/lineDiff.d.ts.map +1 -1
  28. package/dist/src/lineDiff/lineDiff.js +19 -15
  29. package/dist/src/lineDiff/patch.d.ts +35 -0
  30. package/dist/src/lineDiff/patch.d.ts.map +1 -0
  31. package/dist/src/lineDiff/patch.js +146 -0
  32. package/dist/src/menu/menu.d.ts +6 -6
  33. package/dist/src/rail/index.d.ts +1 -1
  34. package/dist/src/rail/index.d.ts.map +1 -1
  35. package/dist/src/rail/index.js +1 -1
  36. package/dist/src/rail/rail.d.ts +217 -17
  37. package/dist/src/rail/rail.d.ts.map +1 -1
  38. package/dist/src/rail/rail.js +133 -15
  39. package/dist/src/reel/index.d.ts +1 -1
  40. package/dist/src/reel/index.d.ts.map +1 -1
  41. package/dist/src/reel/index.js +1 -1
  42. package/dist/src/reel/layout.d.ts +21 -26
  43. package/dist/src/reel/layout.d.ts.map +1 -1
  44. package/dist/src/reel/layout.js +84 -106
  45. package/dist/src/reel/reel.d.ts +30 -172
  46. package/dist/src/reel/reel.d.ts.map +1 -1
  47. package/dist/src/reel/reel.js +144 -195
  48. package/dist/src/rows/rows.d.ts +9 -1
  49. package/dist/src/rows/rows.d.ts.map +1 -1
  50. package/dist/src/rows/rows.js +1 -1
  51. package/dist/src/sortable/sortable.d.ts +30 -30
  52. package/dist/src/toast/toast.d.ts +12 -12
  53. package/dist/src/window/window.d.ts +3 -1
  54. package/dist/src/window/window.d.ts.map +1 -1
  55. package/package.json +1 -1
  56. package/src/bench/bench.ts +24 -0
  57. package/src/bench/index.ts +2 -0
  58. package/src/chip/chip.ts +31 -0
  59. package/src/chip/index.ts +2 -2
  60. package/src/drag/drag.ts +60 -1
  61. package/src/field/field.ts +5 -1
  62. package/src/index.ts +1 -0
  63. package/src/lineDiff/index.ts +2 -0
  64. package/src/lineDiff/lineDiff.ts +29 -24
  65. package/src/lineDiff/patch.ts +218 -0
  66. package/src/pixel-paper.css +202 -32
  67. package/src/rail/index.ts +2 -0
  68. package/src/rail/rail.ts +181 -16
  69. package/src/reel/index.ts +0 -1
  70. package/src/reel/layout.ts +78 -118
  71. package/src/reel/reel.ts +108 -216
  72. package/src/rows/rows.ts +14 -2
  73. package/src/tokens.css +2 -1
  74. package/src/window/window.ts +3 -1
@@ -2,12 +2,20 @@ import { Effect, Option, Schema } from "effect";
2
2
  import * as Command from "foldkit/command";
3
3
  import type { Html } from "foldkit/html";
4
4
  import * as Mount from "foldkit/mount";
5
+ import * as Subscription from "foldkit/subscription";
5
6
  import type * as Update from "foldkit/update";
6
- /** Schema for a rail: whether it is open as a drawer (at 900px and under). Wider, it is
7
- * always in the page and this stays false. */
7
+ /** Schema for a rail: whether it is open as a drawer (at 900px and under; wider, it is always
8
+ * in the page and this stays false), and its splitter while a pointer drags it. Its width is
9
+ * the parent's. */
8
10
  export declare const Model: Schema.Struct<{
9
11
  readonly id: Schema.String;
10
12
  readonly isOpen: Schema.Boolean;
13
+ readonly maybeResizing: Schema.Option<Schema.Struct<{
14
+ readonly pointerId: Schema.Number;
15
+ readonly pressX: Schema.Number;
16
+ readonly fromWidth: Schema.Number;
17
+ readonly width: Schema.Number;
18
+ }>>;
11
19
  }>;
12
20
  export type Model = typeof Model.Type;
13
21
  /** Union of all Messages a rail can produce. `ClosedDrawer` is the browser closing it on
@@ -15,6 +23,22 @@ export type Model = typeof Model.Type;
15
23
  * the window growing past 900px while it is open, where the rail is back in the page. */
16
24
  export declare const Message: import("foldkit/message").MessageUnion<{
17
25
  readonly ClickedOpen: {};
26
+ readonly PressedSplitter: {
27
+ pointerId: Schema.Number;
28
+ clientX: Schema.Number;
29
+ width: Schema.Number;
30
+ };
31
+ readonly MovedSplitter: {
32
+ clientX: Schema.Number;
33
+ };
34
+ readonly ReleasedSplitter: {
35
+ clientX: Schema.Number;
36
+ };
37
+ readonly CancelledSplitter: {};
38
+ readonly PressedEscape: {};
39
+ readonly PressedSplitterKey: {
40
+ width: Schema.Number;
41
+ };
18
42
  readonly ClickedClose: {};
19
43
  readonly ClosedDrawer: {};
20
44
  readonly BlurredDrawer: {};
@@ -23,12 +47,21 @@ export declare const Message: import("foldkit/message").MessageUnion<{
23
47
  readonly CompletedHideRailDrawer: {};
24
48
  }>;
25
49
  export type Message = typeof Message.Type;
50
+ /** What a rail asks of its parent. `ResizedRail`: its splitter was let go, or stepped by a
51
+ * key, at `width` pixels, within the rail's bounds; the parent keeps it (per client) and
52
+ * passes it back as the view's `maybeWidth`. */
53
+ export declare const OutMessage: import("foldkit/message").MessageUnion<{
54
+ readonly ResizedRail: {
55
+ width: Schema.Number;
56
+ };
57
+ }>;
58
+ export type OutMessage = typeof OutMessage.Type;
26
59
  /** Configuration for creating a rail with `init`. The `id` is the rail's, unique in the
27
60
  * document. */
28
61
  export type InitConfig = Readonly<{
29
62
  id: string;
30
63
  }>;
31
- /** Creates a rail, closed. */
64
+ /** Creates a rail, closed, its splitter at rest. */
32
65
  export declare const init: (config: InitConfig) => Model;
33
66
  /** The rail's id, unique in the document. */
34
67
  export declare const id: (model: Model) => string;
@@ -55,14 +88,25 @@ export declare const HideRailDrawer: Command.CommandDefinitionWithArgs<"HideRail
55
88
  type UpdateReturn = Update.Return<Model, Message>;
56
89
  /** Closes the rail's drawer, focus back on its button. */
57
90
  export declare const close: (model: Model) => UpdateReturn;
58
- /** Processes a rail Message and returns the next Model and Commands. */
91
+ /** Processes a rail Message and returns the next Model, Commands and OutMessage: a splitter let
92
+ * go where it changes the width, or stepped by a key, asks for the width. */
59
93
  export declare const update: (model: Model, message: Message) => Readonly<{
60
94
  model: {
61
95
  readonly id: string;
62
96
  readonly isOpen: boolean;
97
+ readonly maybeResizing: Option.Option<{
98
+ readonly pointerId: number;
99
+ readonly pressX: number;
100
+ readonly fromWidth: number;
101
+ readonly width: number;
102
+ }>;
63
103
  };
64
104
  commands?: Update.Commands<{
105
+ readonly _tag: "PressedEscape";
106
+ } | {
65
107
  readonly _tag: "BlurredDrawer";
108
+ } | {
109
+ readonly _tag: "CancelledSplitter";
66
110
  } | {
67
111
  readonly _tag: "ClickedClose";
68
112
  } | {
@@ -73,10 +117,27 @@ export declare const update: (model: Model, message: Message) => Readonly<{
73
117
  readonly _tag: "CompletedHideRailDrawer";
74
118
  } | {
75
119
  readonly _tag: "CompletedShowRailDrawer";
120
+ } | {
121
+ readonly _tag: "MovedSplitter";
122
+ readonly clientX: number;
123
+ } | {
124
+ readonly _tag: "PressedSplitter";
125
+ readonly pointerId: number;
126
+ readonly clientX: number;
127
+ readonly width: number;
128
+ } | {
129
+ readonly _tag: "PressedSplitterKey";
130
+ readonly width: number;
131
+ } | {
132
+ readonly _tag: "ReleasedSplitter";
133
+ readonly clientX: number;
76
134
  } | {
77
135
  readonly _tag: "WidenedPastDrawer";
78
136
  }, never>;
79
- outMessage?: never;
137
+ outMessage?: {
138
+ readonly _tag: "ResizedRail";
139
+ readonly width: number;
140
+ };
80
141
  }>;
81
142
  type DrawerMessage = typeof Message.ClosedDrawer.Type | typeof Message.BlurredDrawer.Type | typeof Message.WidenedPastDrawer.Type;
82
143
  /** The window crossing the drawer's width: growing past it while the drawer is open closes
@@ -98,28 +159,138 @@ export declare const FollowRailDrawer: Mount.MountDefinitionNoArgs<"FollowRailDr
98
159
  } | {
99
160
  readonly _tag: "WidenedPastDrawer";
100
161
  }>;
162
+ /** A dragged splitter follows the pointer, and Escape puts it back before a dialog or the
163
+ * page sees it, from listeners that run only while it is dragged. Lift them into the
164
+ * application's Subscriptions behind a key prefix of the parent's: `subscriptions("rail")` is
165
+ * keyed `railResize` and `railEscape`. */
166
+ export declare const subscriptions: <Prefix extends string>(keyPrefix: Prefix) => {
167
+ readonly resize: Subscription.EntryWithoutKeepAlive<{
168
+ readonly id: string;
169
+ readonly isOpen: boolean;
170
+ readonly maybeResizing: Option.Option<{
171
+ readonly pointerId: number;
172
+ readonly pressX: number;
173
+ readonly fromWidth: number;
174
+ readonly width: number;
175
+ }>;
176
+ }, {
177
+ readonly _tag: "PressedEscape";
178
+ } | {
179
+ readonly _tag: "BlurredDrawer";
180
+ } | {
181
+ readonly _tag: "CancelledSplitter";
182
+ } | {
183
+ readonly _tag: "ClickedClose";
184
+ } | {
185
+ readonly _tag: "ClickedOpen";
186
+ } | {
187
+ readonly _tag: "ClosedDrawer";
188
+ } | {
189
+ readonly _tag: "CompletedHideRailDrawer";
190
+ } | {
191
+ readonly _tag: "CompletedShowRailDrawer";
192
+ } | {
193
+ readonly _tag: "MovedSplitter";
194
+ readonly clientX: number;
195
+ } | {
196
+ readonly _tag: "PressedSplitter";
197
+ readonly pointerId: number;
198
+ readonly clientX: number;
199
+ readonly width: number;
200
+ } | {
201
+ readonly _tag: "PressedSplitterKey";
202
+ readonly width: number;
203
+ } | {
204
+ readonly _tag: "ReleasedSplitter";
205
+ readonly clientX: number;
206
+ } | {
207
+ readonly _tag: "WidenedPastDrawer";
208
+ }, {
209
+ readonly maybePointerId: Option.Option<number>;
210
+ }, never> & {
211
+ readonly __subscription: never;
212
+ };
213
+ readonly escape: Subscription.EntryWithoutKeepAlive<{
214
+ readonly id: string;
215
+ readonly isOpen: boolean;
216
+ readonly maybeResizing: Option.Option<{
217
+ readonly pointerId: number;
218
+ readonly pressX: number;
219
+ readonly fromWidth: number;
220
+ readonly width: number;
221
+ }>;
222
+ }, {
223
+ readonly _tag: "PressedEscape";
224
+ } | {
225
+ readonly _tag: "BlurredDrawer";
226
+ } | {
227
+ readonly _tag: "CancelledSplitter";
228
+ } | {
229
+ readonly _tag: "ClickedClose";
230
+ } | {
231
+ readonly _tag: "ClickedOpen";
232
+ } | {
233
+ readonly _tag: "ClosedDrawer";
234
+ } | {
235
+ readonly _tag: "CompletedHideRailDrawer";
236
+ } | {
237
+ readonly _tag: "CompletedShowRailDrawer";
238
+ } | {
239
+ readonly _tag: "MovedSplitter";
240
+ readonly clientX: number;
241
+ } | {
242
+ readonly _tag: "PressedSplitter";
243
+ readonly pointerId: number;
244
+ readonly clientX: number;
245
+ readonly width: number;
246
+ } | {
247
+ readonly _tag: "PressedSplitterKey";
248
+ readonly width: number;
249
+ } | {
250
+ readonly _tag: "ReleasedSplitter";
251
+ readonly clientX: number;
252
+ } | {
253
+ readonly _tag: "WidenedPastDrawer";
254
+ }, {
255
+ readonly isResizing: boolean;
256
+ }, never> & {
257
+ readonly __subscription: never;
258
+ };
259
+ } extends infer T ? { readonly [Key in keyof T as `${Prefix}${Capitalize<Key>}`]: T[Key]; } : never;
101
260
  /** Per-render inputs passed to `view` through `h.submodel`'s `viewInputs`. */
102
261
  export type ViewInputs = Readonly<{
103
- /** Names the rail for screen readers, and its button and drawer head (`"collections"`). */
262
+ /** Names the rail for screen readers, and its button, drawer head and splitter
263
+ * (`"collections"`). */
104
264
  label: string;
265
+ /** The width the reader gave the rail, in pixels, as the parent keeps it from `ResizedRail`
266
+ * (for this client: another reader's window is not this one's); none for the stylesheet's.
267
+ * A width out of the rail's bounds prints at the nearer bound. */
268
+ maybeWidth: Option.Option<number>;
105
269
  /** The rail's panels: a tree, places, filters. A function because a Submodel's viewInputs
106
270
  * may hold functions only at the top level, and Foldkit runs this one in the parent's
107
271
  * boundary, so the handlers in what it returns dispatch the parent's Messages. */
108
272
  toAsideView: () => ReadonlyArray<Html>;
109
- /** The deck beside the rail, usually `main.deck#main`, given the button that opens the
110
- * drawer to print first in it. A function because it receives that button, and runs in the
111
- * parent's boundary like `toAsideView`. */
273
+ /** The page beside the rail, `main.deck#main` or `main.bench#main`, given the button that
274
+ * opens the drawer to print first in it. A function because it receives that button, and
275
+ * runs in the parent's boundary like `toAsideView`. */
112
276
  toDeckView: (openButton: Html) => Html;
113
277
  }>;
114
278
  /**
115
279
  * A column of panels beside the deck, fixed under the top bar and scrolling itself:
116
- * `div.railed >` the deck, then `aside.rail[popover="auto"][aria-label]`. One element serves
117
- * both layouts, so nothing in it renders twice or loses its state. At 900px and under it leaves the
118
- * page, and `span.rail-open > button.btn.small` at the top of the deck opens the same element as a
119
- * drawer over a veil, its head (the name and a close glyph) showing. Opening focuses its first
280
+ * `div.railed >` the deck, then `aside.rail[popover="auto"][aria-label]`, then its splitter,
281
+ * `div.rail-resize[role="separator"]`, on its right edge. One element serves both layouts, so
282
+ * nothing in it renders twice or loses its state. At 900px and under it leaves the page, and
283
+ * `span.rail-open > button.btn.small` at the top of the deck opens the same element as a drawer
284
+ * over a veil, its head (the name and a close glyph) showing. Opening focuses its first
120
285
  * control; Escape, a press on the veil, the close glyph, focus leaving or the window growing
121
286
  * past 900px closes it, and the first three put focus back on the button.
122
287
  *
288
+ * Its splitter sizes it, by a pointer (previewed as it moves) or the side arrows, within its
289
+ * bounds, and reports the width as `ResizedRail` for the parent to keep and pass back as
290
+ * `maybeWidth`, which the view sets as `--rail` on `div.railed`, so the page's padding and the
291
+ * rail's width follow it. The drawer keeps its own width. Lift `subscriptions(keyPrefix)` into
292
+ * the application's, or a dragged splitter follows nothing.
293
+ *
123
294
  * Its state is its own, not `@foldkit/ui`'s Popover: that panel is placed by Floating UI and
124
295
  * rendered only while open, and this one is always in the page, placed by the stylesheet, and
125
296
  * opened as a native popover so the browser keeps it in the top layer.
@@ -127,8 +298,18 @@ export type ViewInputs = Readonly<{
127
298
  export declare const view: import("foldkit/submodel").View<{
128
299
  readonly id: string;
129
300
  readonly isOpen: boolean;
301
+ readonly maybeResizing: Option.Option<{
302
+ readonly pointerId: number;
303
+ readonly pressX: number;
304
+ readonly fromWidth: number;
305
+ readonly width: number;
306
+ }>;
130
307
  }, {
308
+ readonly _tag: "PressedEscape";
309
+ } | {
131
310
  readonly _tag: "BlurredDrawer";
311
+ } | {
312
+ readonly _tag: "CancelledSplitter";
132
313
  } | {
133
314
  readonly _tag: "ClickedClose";
134
315
  } | {
@@ -139,18 +320,37 @@ export declare const view: import("foldkit/submodel").View<{
139
320
  readonly _tag: "CompletedHideRailDrawer";
140
321
  } | {
141
322
  readonly _tag: "CompletedShowRailDrawer";
323
+ } | {
324
+ readonly _tag: "MovedSplitter";
325
+ readonly clientX: number;
326
+ } | {
327
+ readonly _tag: "PressedSplitter";
328
+ readonly pointerId: number;
329
+ readonly clientX: number;
330
+ readonly width: number;
331
+ } | {
332
+ readonly _tag: "PressedSplitterKey";
333
+ readonly width: number;
334
+ } | {
335
+ readonly _tag: "ReleasedSplitter";
336
+ readonly clientX: number;
142
337
  } | {
143
338
  readonly _tag: "WidenedPastDrawer";
144
339
  }, Readonly<{
145
- /** Names the rail for screen readers, and its button and drawer head (`"collections"`). */
340
+ /** Names the rail for screen readers, and its button, drawer head and splitter
341
+ * (`"collections"`). */
146
342
  label: string;
343
+ /** The width the reader gave the rail, in pixels, as the parent keeps it from `ResizedRail`
344
+ * (for this client: another reader's window is not this one's); none for the stylesheet's.
345
+ * A width out of the rail's bounds prints at the nearer bound. */
346
+ maybeWidth: Option.Option<number>;
147
347
  /** The rail's panels: a tree, places, filters. A function because a Submodel's viewInputs
148
348
  * may hold functions only at the top level, and Foldkit runs this one in the parent's
149
349
  * boundary, so the handlers in what it returns dispatch the parent's Messages. */
150
350
  toAsideView: () => ReadonlyArray<Html>;
151
- /** The deck beside the rail, usually `main.deck#main`, given the button that opens the
152
- * drawer to print first in it. A function because it receives that button, and runs in the
153
- * parent's boundary like `toAsideView`. */
351
+ /** The page beside the rail, `main.deck#main` or `main.bench#main`, given the button that
352
+ * opens the drawer to print first in it. A function because it receives that button, and
353
+ * runs in the parent's boundary like `toAsideView`. */
154
354
  toDeckView: (openButton: Html) => Html;
155
355
  }>>;
156
356
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"rail.d.ts","sourceRoot":"","sources":["../../../src/rail/rail.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rail.d.ts","sourceRoot":"","sources":["../../../src/rail/rail.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { brandViewResult as __foldkitBrandViewResult } from 'foldkit/brand'
2
- import { Array, Cause, Effect, Option, Schema, Stream } from "effect";
2
+ import { Array, Cause, Effect, Number, Option, Schema, Stream } from "effect";
3
3
  import * as Command from "foldkit/command";
4
4
  import * as Dom from "foldkit/dom";
5
5
  import { defineMessageUnion } from "foldkit/message";
@@ -7,14 +7,27 @@ import * as Mount from "foldkit/mount";
7
7
  import * as Render from "foldkit/render";
8
8
  import { modifyFields } from "foldkit/struct";
9
9
  import { defineView } from "foldkit/submodel";
10
+ import * as Subscription from "foldkit/subscription";
10
11
  import * as Button from "../button/button.js";
12
+ import { escapeKeys, markDragging, pointerMessages, splitterAttributes } from "../drag/drag.js";
11
13
  import * as IconButton from "../iconButton/iconButton.js";
14
+ import { prefixKeys } from "../subscription/prefixKeys.js";
12
15
  // MODEL
13
- /** Schema for a rail: whether it is open as a drawer (at 900px and under). Wider, it is
14
- * always in the page and this stays false. */
16
+ /** A splitter a pointer drags: pressed at `pressX` on a rail `fromWidth` wide, and the width
17
+ * it previews. */
18
+ const Resizing = Schema.Struct({
19
+ pointerId: Schema.Number,
20
+ pressX: Schema.Number,
21
+ fromWidth: Schema.Number,
22
+ width: Schema.Number,
23
+ });
24
+ /** Schema for a rail: whether it is open as a drawer (at 900px and under; wider, it is always
25
+ * in the page and this stays false), and its splitter while a pointer drags it. Its width is
26
+ * the parent's. */
15
27
  export const Model = Schema.Struct({
16
28
  id: Schema.String,
17
29
  isOpen: Schema.Boolean,
30
+ maybeResizing: Schema.Option(Resizing),
18
31
  });
19
32
  // MESSAGE
20
33
  /** Union of all Messages a rail can produce. `ClosedDrawer` is the browser closing it on
@@ -22,6 +35,12 @@ export const Model = Schema.Struct({
22
35
  * the window growing past 900px while it is open, where the rail is back in the page. */
23
36
  export const Message = defineMessageUnion({
24
37
  ClickedOpen: {},
38
+ PressedSplitter: { pointerId: Schema.Number, clientX: Schema.Number, width: Schema.Number },
39
+ MovedSplitter: { clientX: Schema.Number },
40
+ ReleasedSplitter: { clientX: Schema.Number },
41
+ CancelledSplitter: {},
42
+ PressedEscape: {},
43
+ PressedSplitterKey: { width: Schema.Number },
25
44
  ClickedClose: {},
26
45
  ClosedDrawer: {},
27
46
  BlurredDrawer: {},
@@ -29,8 +48,27 @@ export const Message = defineMessageUnion({
29
48
  CompletedShowRailDrawer: {},
30
49
  CompletedHideRailDrawer: {},
31
50
  });
32
- /** Creates a rail, closed. */
33
- export const init = (config) => (__foldkitBrandViewResult(({ id: config.id, isOpen: false }), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#init"));
51
+ /** What a rail asks of its parent. `ResizedRail`: its splitter was let go, or stepped by a
52
+ * key, at `width` pixels, within the rail's bounds; the parent keeps it (per client) and
53
+ * passes it back as the view's `maybeWidth`. */
54
+ export const OutMessage = defineMessageUnion({
55
+ ResizedRail: { width: Schema.Number },
56
+ });
57
+ /** Creates a rail, closed, its splitter at rest. */
58
+ export const init = (config) => (__foldkitBrandViewResult(({
59
+ id: config.id,
60
+ isOpen: false,
61
+ maybeResizing: Option.none(),
62
+ }), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#init"));
63
+ // WIDTH
64
+ /** The rail's widths, in pixels: before the reader sizes it (as the stylesheet's `--rail` has
65
+ * it, which the splitter says as its value until a width is given), the least its panels
66
+ * still fit in (a tree's row keeps a glyph, a dot and a few words of its title), the most
67
+ * (which leaves the deck at least 421px of a 901px window, the narrowest one the rail stands
68
+ * in, more than a phone has), and what an arrow on its splitter moves it. The bounds and the
69
+ * step are the component's, not tokens: the splitter says them as its values. */
70
+ const WIDTH = { start: 272, least: 220, most: 480, step: 16 };
71
+ const bounded = (width) => __foldkitBrandViewResult((Math.round(Number.clamp(width, { minimum: WIDTH.least, maximum: WIDTH.most }))), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#bounded");
34
72
  // ACCESSORS
35
73
  /** The rail's id, unique in the document. */
36
74
  export const id = (model) => __foldkitBrandViewResult((model.id), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#id");
@@ -85,9 +123,35 @@ const open = (model) => (__foldkitBrandViewResult(({
85
123
  }), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#open"));
86
124
  /** Closes the rail's drawer, focus back on its button. */
87
125
  export const close = (model) => __foldkitBrandViewResult((closeDrawer(model, true)), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#close");
88
- /** Processes a rail Message and returns the next Model and Commands. */
126
+ const withResizing = (model, maybeResizing) => __foldkitBrandViewResult((modifyFields(model, { maybeResizing: () => __foldkitBrandViewResult((maybeResizing), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#maybeResizing") })), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#withResizing");
127
+ /** The width a dragged splitter previews with the pointer at `clientX`. */
128
+ const dragTo = (model, clientX) => __foldkitBrandViewResult((withResizing(model, Option.map(model.maybeResizing, (resizing) => (__foldkitBrandViewResult(({
129
+ ...resizing,
130
+ width: bounded(resizing.fromWidth + clientX - resizing.pressX),
131
+ }), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#anonymous~7"))))), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#dragTo");
132
+ /** Processes a rail Message and returns the next Model, Commands and OutMessage: a splitter let
133
+ * go where it changes the width, or stepped by a key, asks for the width. */
89
134
  export const update = (model, message) => __foldkitBrandViewResult((Message.match(message, {
90
135
  ClickedOpen: () => __foldkitBrandViewResult((open(model)), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#ClickedOpen"),
136
+ PressedSplitter: ({ pointerId, clientX, width }) => __foldkitBrandViewResult((Option.isSome(model.maybeResizing)
137
+ ? { model }
138
+ : {
139
+ model: withResizing(model, Option.some({ pointerId, pressX: clientX, fromWidth: width, width })),
140
+ }), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#PressedSplitter"),
141
+ MovedSplitter: ({ clientX }) => (__foldkitBrandViewResult(({ model: dragTo(model, clientX) }), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#MovedSplitter")),
142
+ ReleasedSplitter: ({ clientX }) => __foldkitBrandViewResult((Option.match(dragTo(model, clientX).maybeResizing, {
143
+ onNone: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#onNone")),
144
+ onSome: ({ fromWidth, width }) => (__foldkitBrandViewResult(({
145
+ model: withResizing(model, Option.none()),
146
+ ...(width === fromWidth ? {} : { outMessage: OutMessage.ResizedRail({ width }) }),
147
+ }), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#onSome")),
148
+ })), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#ReleasedSplitter"),
149
+ CancelledSplitter: () => (__foldkitBrandViewResult(({ model: withResizing(model, Option.none()) }), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#CancelledSplitter")),
150
+ PressedEscape: () => (__foldkitBrandViewResult(({ model: withResizing(model, Option.none()) }), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#PressedEscape")),
151
+ PressedSplitterKey: ({ width }) => (__foldkitBrandViewResult(({
152
+ model,
153
+ outMessage: OutMessage.ResizedRail({ width: bounded(width) }),
154
+ }), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#PressedSplitterKey")),
91
155
  ClickedClose: () => __foldkitBrandViewResult((close(model)), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#ClickedClose"),
92
156
  ClosedDrawer: () => __foldkitBrandViewResult((close(model)), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#ClosedDrawer"),
93
157
  BlurredDrawer: () => __foldkitBrandViewResult((closeDrawer(model, false)), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#BlurredDrawer"),
@@ -102,10 +166,10 @@ const DRAWER_QUERY = "(max-width: 900px)";
102
166
  export const widthChangeMessage = (isDrawerWidth, isDrawerOpen) => __foldkitBrandViewResult((!isDrawerWidth && isDrawerOpen ? Option.some(Message.WidenedPastDrawer()) : Option.none()), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#widthChangeMessage");
103
167
  /** The browser closing the drawer (Escape, a press on the veil); a toggle that opened it says
104
168
  * nothing. */
105
- export const drawerToggleMessage = (event) => __foldkitBrandViewResult((Option.liftPredicate(Message.ClosedDrawer(), () => __foldkitBrandViewResult((event.newState === "closed"), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#anonymous~7"))), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#drawerToggleMessage");
169
+ export const drawerToggleMessage = (event) => __foldkitBrandViewResult((Option.liftPredicate(Message.ClosedDrawer(), () => __foldkitBrandViewResult((event.newState === "closed"), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#anonymous~8"))), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#drawerToggleMessage");
106
170
  /** Focus leaving the drawer while it is open (`isDrawerOpen`, the rail matching
107
171
  * `:popover-open`); focus moving inside it says nothing. */
108
- export const drawerFocusOutMessage = (rail, event, isDrawerOpen) => __foldkitBrandViewResult((Option.liftPredicate(Message.BlurredDrawer(), () => __foldkitBrandViewResult((isDrawerOpen && event.relatedTarget instanceof Node && !rail.contains(event.relatedTarget)), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#anonymous~8"))), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#drawerFocusOutMessage");
172
+ export const drawerFocusOutMessage = (rail, event, isDrawerOpen) => __foldkitBrandViewResult((Option.liftPredicate(Message.BlurredDrawer(), () => __foldkitBrandViewResult((isDrawerOpen && event.relatedTarget instanceof Node && !rail.contains(event.relatedTarget)), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#anonymous~9"))), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#drawerFocusOutMessage");
109
173
  /** Follows the drawer the browser shows: the browser closing it (Escape, a press on the
110
174
  * veil), focus leaving it while it is open, and the window growing past its width while it
111
175
  * is open, each of which closes the rail. */
@@ -126,27 +190,61 @@ export const FollowRailDrawer = Mount.defineStream("FollowRailDrawer", {
126
190
  const fromWidth = Dom.streamFromMediaQuery({
127
191
  query: DRAWER_QUERY,
128
192
  mapMatches: (isDrawerWidth) => __foldkitBrandViewResult((widthChangeMessage(isDrawerWidth, isDrawerOpen())), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#mapMatches"),
129
- }).pipe(Stream.filter(Option.isSome), Stream.map(({ value }) => __foldkitBrandViewResult((value), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#anonymous~9")));
193
+ }).pipe(Stream.filter(Option.isSome), Stream.map(({ value }) => __foldkitBrandViewResult((value), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#anonymous~10")));
130
194
  return __foldkitBrandViewResult((Stream.mergeAll([fromToggle, fromFocusOut, fromWidth], {
131
195
  concurrency: "unbounded",
132
196
  })), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#execute~3");
133
197
  },
134
198
  });
199
+ // SUBSCRIPTION
200
+ const railSubscriptions = Subscription.make()((entry) => (__foldkitBrandViewResult(({
201
+ resize: entry({ maybePointerId: Schema.Option(Schema.Number) }, {
202
+ modelToDependencies: (model) => (__foldkitBrandViewResult(({
203
+ maybePointerId: Option.map(model.maybeResizing, ({ pointerId }) => __foldkitBrandViewResult((pointerId), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#anonymous~12")),
204
+ }), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#modelToDependencies")),
205
+ dependenciesToStream: ({ maybePointerId }) => __foldkitBrandViewResult((Option.match(maybePointerId, {
206
+ onNone: () => __foldkitBrandViewResult((Stream.empty), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#onNone~2"),
207
+ onSome: (pointerId) => __foldkitBrandViewResult((Stream.merge(pointerMessages(pointerId, {
208
+ moved: ({ clientX }) => __foldkitBrandViewResult((Message.MovedSplitter({ clientX })), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#moved"),
209
+ released: ({ clientX }) => __foldkitBrandViewResult((Message.ReleasedSplitter({ clientX })), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#released"),
210
+ cancelled: () => __foldkitBrandViewResult((Message.CancelledSplitter()), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#cancelled"),
211
+ }), markDragging)), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#onSome~2"),
212
+ })), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#dependenciesToStream"),
213
+ }),
214
+ escape: entry({ isResizing: Schema.Boolean }, {
215
+ modelToDependencies: (model) => (__foldkitBrandViewResult(({ isResizing: Option.isSome(model.maybeResizing) }), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#modelToDependencies~2")),
216
+ dependenciesToStream: ({ isResizing }) => __foldkitBrandViewResult((isResizing ? escapeKeys(Message.PressedEscape()) : Stream.empty), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#dependenciesToStream~2"),
217
+ }),
218
+ }), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#anonymous~11")));
219
+ /** A dragged splitter follows the pointer, and Escape puts it back before a dialog or the
220
+ * page sees it, from listeners that run only while it is dragged. Lift them into the
221
+ * application's Subscriptions behind a key prefix of the parent's: `subscriptions("rail")` is
222
+ * keyed `railResize` and `railEscape`. */
223
+ export const subscriptions = (keyPrefix) => __foldkitBrandViewResult((prefixKeys(keyPrefix, railSubscriptions)), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#subscriptions");
135
224
  /**
136
225
  * A column of panels beside the deck, fixed under the top bar and scrolling itself:
137
- * `div.railed >` the deck, then `aside.rail[popover="auto"][aria-label]`. One element serves
138
- * both layouts, so nothing in it renders twice or loses its state. At 900px and under it leaves the
139
- * page, and `span.rail-open > button.btn.small` at the top of the deck opens the same element as a
140
- * drawer over a veil, its head (the name and a close glyph) showing. Opening focuses its first
226
+ * `div.railed >` the deck, then `aside.rail[popover="auto"][aria-label]`, then its splitter,
227
+ * `div.rail-resize[role="separator"]`, on its right edge. One element serves both layouts, so
228
+ * nothing in it renders twice or loses its state. At 900px and under it leaves the page, and
229
+ * `span.rail-open > button.btn.small` at the top of the deck opens the same element as a drawer
230
+ * over a veil, its head (the name and a close glyph) showing. Opening focuses its first
141
231
  * control; Escape, a press on the veil, the close glyph, focus leaving or the window growing
142
232
  * past 900px closes it, and the first three put focus back on the button.
143
233
  *
234
+ * Its splitter sizes it, by a pointer (previewed as it moves) or the side arrows, within its
235
+ * bounds, and reports the width as `ResizedRail` for the parent to keep and pass back as
236
+ * `maybeWidth`, which the view sets as `--rail` on `div.railed`, so the page's padding and the
237
+ * rail's width follow it. The drawer keeps its own width. Lift `subscriptions(keyPrefix)` into
238
+ * the application's, or a dragged splitter follows nothing.
239
+ *
144
240
  * Its state is its own, not `@foldkit/ui`'s Popover: that panel is placed by Floating UI and
145
241
  * rendered only while open, and this one is always in the page, placed by the stylesheet, and
146
242
  * opened as a native popover so the browser keeps it in the top layer.
147
243
  */
148
244
  export const view = defineView((model, viewInputs, h) => {
149
245
  const { label, toAsideView, toDeckView } = viewInputs;
246
+ const maybeWidth = Option.orElse(Option.map(model.maybeResizing, ({ width }) => __foldkitBrandViewResult((width), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#anonymous~14")), () => __foldkitBrandViewResult((Option.map(viewInputs.maybeWidth, bounded)), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#anonymous~15"));
247
+ const width = Option.getOrElse(maybeWidth, () => __foldkitBrandViewResult((WIDTH.start), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#anonymous~16"));
150
248
  const openButton = h.span([h.Class("rail-open")], [
151
249
  Button.view({
152
250
  label,
@@ -162,7 +260,10 @@ export const view = defineView((model, viewInputs, h) => {
162
260
  ]);
163
261
  // NOTE: the deck comes first so the page's main content, and its h1, precede the rail's
164
262
  // panels in reading order; the stylesheet places the rail, fixed, at the left.
165
- return __foldkitBrandViewResult((h.div([h.Class("railed")], [
263
+ return __foldkitBrandViewResult((h.div([
264
+ h.Class("railed"),
265
+ ...Array.fromOption(Option.map(maybeWidth, (shown) => __foldkitBrandViewResult((h.Style({ "--rail": `${shown}px` })), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#anonymous~17"))),
266
+ ], [
166
267
  toDeckView(openButton),
167
268
  h.aside([
168
269
  h.Id(model.id),
@@ -177,5 +278,22 @@ export const view = defineView((model, viewInputs, h) => {
177
278
  ]),
178
279
  ...toAsideView(),
179
280
  ]),
180
- ])), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#anonymous~10");
281
+ h.div([
282
+ h.Class("rail-resize"),
283
+ h.Role("separator"),
284
+ h.AriaLabel(`Width of ${label}`),
285
+ h.AriaControls(model.id),
286
+ h.AriaValuemin(WIDTH.least),
287
+ h.AriaValuemax(WIDTH.most),
288
+ h.AriaValuenow(width),
289
+ h.AriaValuetext(`${width} pixels`),
290
+ h.Tabindex(0),
291
+ ...splitterAttributes({
292
+ orientation: "vertical",
293
+ isIdle: Option.isNone(model.maybeResizing),
294
+ onPress: (pointerId, clientX) => __foldkitBrandViewResult((Message.PressedSplitter({ pointerId, clientX, width })), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#onPress"),
295
+ onStep: (direction) => __foldkitBrandViewResult((Message.PressedSplitterKey({ width: bounded(width + direction * WIDTH.step) })), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#onStep"),
296
+ }, h),
297
+ ]),
298
+ ])), "@gjermundgaraba-designs/pixel-paper/src/rail/rail.js#anonymous~13");
181
299
  });
@@ -1,4 +1,4 @@
1
1
  export { Layout, OutMessage, Pane, apply } from "./layout.ts";
2
- export { Action, AnnounceReel, FocusGrip, FocusPane, Message, Model, RestoreFocus, ScrollIntoView, SizeLiftedPane, focusedPaneId, init, perform, reconcile, subscriptions, update, view, } from "./reel.ts";
2
+ export { Action, AnnounceReel, FocusPane, Message, Model, RestoreFocus, ScrollIntoView, SizeLiftedPane, focusedPaneId, init, perform, reconcile, subscriptions, update, view, } from "./reel.ts";
3
3
  export type { InitConfig, PaneRender, UpdateContext, ViewInputs } from "./reel.ts";
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/reel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EACL,MAAM,EACN,YAAY,EACZ,SAAS,EACT,SAAS,EACT,OAAO,EACP,KAAK,EACL,YAAY,EACZ,cAAc,EACd,cAAc,EACd,aAAa,EACb,IAAI,EACJ,OAAO,EACP,SAAS,EACT,aAAa,EACb,MAAM,EACN,IAAI,GACL,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/reel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EACL,MAAM,EACN,YAAY,EACZ,SAAS,EACT,OAAO,EACP,KAAK,EACL,YAAY,EACZ,cAAc,EACd,cAAc,EACd,aAAa,EACb,IAAI,EACJ,OAAO,EACP,SAAS,EACT,aAAa,EACb,MAAM,EACN,IAAI,GACL,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
@@ -1,2 +1,2 @@
1
1
  export { Layout, OutMessage, Pane, apply } from "./layout.js";
2
- export { Action, AnnounceReel, FocusGrip, FocusPane, Message, Model, RestoreFocus, ScrollIntoView, SizeLiftedPane, focusedPaneId, init, perform, reconcile, subscriptions, update, view, } from "./reel.js";
2
+ export { Action, AnnounceReel, FocusPane, Message, Model, RestoreFocus, ScrollIntoView, SizeLiftedPane, focusedPaneId, init, perform, reconcile, subscriptions, update, view, } from "./reel.js";