@gjermundgaraba-designs/pixel-paper 0.18.0 → 0.19.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 +25 -4
- package/dist/src/drag/drag.d.ts +3 -0
- package/dist/src/drag/drag.d.ts.map +1 -1
- package/dist/src/drag/drag.js +14 -10
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/reel/index.d.ts +4 -0
- package/dist/src/reel/index.d.ts.map +1 -0
- package/dist/src/reel/index.js +2 -0
- package/dist/src/reel/layout.d.ts +180 -0
- package/dist/src/reel/layout.d.ts.map +1 -0
- package/dist/src/reel/layout.js +370 -0
- package/dist/src/reel/reel.d.ts +1158 -0
- package/dist/src/reel/reel.d.ts.map +1 -0
- package/dist/src/reel/reel.js +922 -0
- package/dist/src/sortable/sortable.d.ts +30 -30
- package/dist/src/sortable/sortable.d.ts.map +1 -1
- package/dist/src/sortable/sortable.js +2 -10
- package/dist/src/toast/toast.d.ts +12 -12
- package/dist/src/window/window.d.ts +2 -0
- package/dist/src/window/window.d.ts.map +1 -1
- package/dist/src/window/window.js +2 -1
- package/package.json +1 -1
- package/src/drag/drag.ts +19 -4
- package/src/index.ts +1 -0
- package/src/pixel-paper.css +228 -1
- package/src/reel/index.ts +20 -0
- package/src/reel/layout.ts +602 -0
- package/src/reel/reel.ts +1597 -0
- package/src/sortable/sortable.ts +8 -16
- package/src/tokens.css +5 -0
- package/src/window/window.ts +4 -0
|
@@ -0,0 +1,922 @@
|
|
|
1
|
+
import { brandViewResult as __foldkitBrandViewResult } from 'foldkit/brand'
|
|
2
|
+
import { Array, Effect, Equal, Match, Number, Option, Order, Schema, Stream, String } from "effect";
|
|
3
|
+
import * as Command from "foldkit/command";
|
|
4
|
+
import { defineMessageUnion } from "foldkit/message";
|
|
5
|
+
import * as Mount from "foldkit/mount";
|
|
6
|
+
import * as Render from "foldkit/render";
|
|
7
|
+
import { defineTaggedUnion } from "foldkit/schema";
|
|
8
|
+
import { modifyFields } from "foldkit/struct";
|
|
9
|
+
import { defineView } from "foldkit/submodel";
|
|
10
|
+
import * as Subscription from "foldkit/subscription";
|
|
11
|
+
import * as Announcer from "../announcer/announcer.js";
|
|
12
|
+
import * as Button from "../button/button.js";
|
|
13
|
+
import { LEFT_BUTTON, escapeKeys, markDragging, measureLift, pressingPointer, } from "../drag/drag.js";
|
|
14
|
+
import * as Glyph from "../glyph/glyph.js";
|
|
15
|
+
import * as IconButton from "../iconButton/iconButton.js";
|
|
16
|
+
import { prefixKeys } from "../subscription/prefixKeys.js";
|
|
17
|
+
import { OutMessage, Resize, Splitter, Step, Subject, Target, WHERE_IT_WAS, apply, columnOf, columnOfTarget, fill, firstPlace, isPresent, isSplitterPresent, isTargetPresent, landingWords, nextPreset, originOf, placeAt, placeOf, placeWords, requestOf, resizeOf, steppedTarget, subjectWords, targetAtPoint, whereWords, widthMark, widthWords, } from "./layout.js";
|
|
18
|
+
// MODEL
|
|
19
|
+
/** The words a reel says. `{pane}` is a pane's label, `{subject}` what is held (a pane, or a
|
|
20
|
+
* column by its first pane), `{where}` a place and `{column}` a column's number. */
|
|
21
|
+
const COPY = {
|
|
22
|
+
paneGrip: "Move {pane}",
|
|
23
|
+
columnGrip: "Move column {column}",
|
|
24
|
+
gripHelp: "Press space to pick it up. Arrow keys move it, space drops it, escape or tab puts it back.",
|
|
25
|
+
widthLabel: "Width of column {column}",
|
|
26
|
+
heightLabel: "Height of {pane}",
|
|
27
|
+
focused: "{pane}, {where}.",
|
|
28
|
+
moved: "{subject} moved to {where}.",
|
|
29
|
+
widened: "Column {column} takes {width}.",
|
|
30
|
+
pickedUp: "Picked up {subject}.",
|
|
31
|
+
pickedUpByKeyboard: "Picked up {subject}. Arrow keys move it, space drops it, escape or tab puts it back.",
|
|
32
|
+
over: "{subject}, {where}.",
|
|
33
|
+
dropped: "{subject} dropped at {where}.",
|
|
34
|
+
putBack: "{subject} put back where it was.",
|
|
35
|
+
cancelled: "Move cancelled. {subject} put back where it was.",
|
|
36
|
+
gone: "Move cancelled.",
|
|
37
|
+
};
|
|
38
|
+
/** The focused pane, with where it last sat, so focus finds a neighbour when it goes. */
|
|
39
|
+
const Focus = Schema.Struct({ paneId: Schema.String, column: Schema.Number, row: Schema.Number });
|
|
40
|
+
/** How something is held: by a pointer, pressed at (`pressX`, `pressY`) and now at (`x`,
|
|
41
|
+
* `y`), carrying it once it has moved past the threshold; or by the keyboard, on its grip. */
|
|
42
|
+
const By = defineTaggedUnion({
|
|
43
|
+
Pointer: {
|
|
44
|
+
pointerId: Schema.Number,
|
|
45
|
+
pressX: Schema.Number,
|
|
46
|
+
pressY: Schema.Number,
|
|
47
|
+
x: Schema.Number,
|
|
48
|
+
y: Schema.Number,
|
|
49
|
+
isCarrying: Schema.Boolean,
|
|
50
|
+
},
|
|
51
|
+
Keyboard: {},
|
|
52
|
+
});
|
|
53
|
+
/** What is held, how, and where it would land: none while a pointer is outside the reel. */
|
|
54
|
+
const Held = Schema.Struct({
|
|
55
|
+
subject: Subject,
|
|
56
|
+
by: By,
|
|
57
|
+
maybeTarget: Schema.Option(Target),
|
|
58
|
+
});
|
|
59
|
+
/** A splitter a pointer drags, pressed at (`pressX`, `pressY`), with the resize it previews. */
|
|
60
|
+
const Resizing = Schema.Struct({
|
|
61
|
+
splitter: Splitter,
|
|
62
|
+
pointerId: Schema.Number,
|
|
63
|
+
pressX: Schema.Number,
|
|
64
|
+
pressY: Schema.Number,
|
|
65
|
+
maybeResize: Schema.Option(Resize),
|
|
66
|
+
});
|
|
67
|
+
/** Schema for a reel: its id, the focused pane, what is held and a splitter being dragged. All
|
|
68
|
+
* of it is this client's; the layout is the application's. */
|
|
69
|
+
export const Model = Schema.Struct({
|
|
70
|
+
id: Schema.String,
|
|
71
|
+
maybeFocus: Schema.Option(Focus),
|
|
72
|
+
maybeHeld: Schema.Option(Held),
|
|
73
|
+
maybeResizing: Schema.Option(Resizing),
|
|
74
|
+
});
|
|
75
|
+
// MESSAGE
|
|
76
|
+
const PointerAt = Schema.Struct({
|
|
77
|
+
clientX: Schema.Number,
|
|
78
|
+
clientY: Schema.Number,
|
|
79
|
+
maybeTarget: Schema.Option(Target),
|
|
80
|
+
});
|
|
81
|
+
/** Union of all Messages a reel can produce. */
|
|
82
|
+
export const Message = defineMessageUnion({
|
|
83
|
+
PressedGrip: {
|
|
84
|
+
subject: Subject,
|
|
85
|
+
pointerId: Schema.Number,
|
|
86
|
+
clientX: Schema.Number,
|
|
87
|
+
clientY: Schema.Number,
|
|
88
|
+
},
|
|
89
|
+
PressedGripKey: { subject: Subject },
|
|
90
|
+
MovedPointer: PointerAt.fields,
|
|
91
|
+
ReleasedPointer: PointerAt.fields,
|
|
92
|
+
CancelledPointer: {},
|
|
93
|
+
SteppedHeld: { step: Step },
|
|
94
|
+
DroppedHeld: {},
|
|
95
|
+
LeftGrip: {},
|
|
96
|
+
PressedEscape: {},
|
|
97
|
+
FocusedPane: { paneId: Schema.String },
|
|
98
|
+
PressedSplitter: {
|
|
99
|
+
splitter: Splitter,
|
|
100
|
+
pointerId: Schema.Number,
|
|
101
|
+
clientX: Schema.Number,
|
|
102
|
+
clientY: Schema.Number,
|
|
103
|
+
},
|
|
104
|
+
MovedSplitter: { share: Schema.Number },
|
|
105
|
+
ReleasedSplitter: { share: Schema.Number },
|
|
106
|
+
CancelledSplitter: {},
|
|
107
|
+
PressedSplitterKey: { splitter: Splitter, share: Schema.Number },
|
|
108
|
+
CompletedAnnounceReel: {},
|
|
109
|
+
CompletedFocusPane: {},
|
|
110
|
+
CompletedRestoreFocus: {},
|
|
111
|
+
CompletedFocusGrip: {},
|
|
112
|
+
CompletedScrollIntoView: {},
|
|
113
|
+
CompletedSizeLiftedPane: {},
|
|
114
|
+
});
|
|
115
|
+
/** Creates a reel focused on its first pane, holding nothing, at rest. */
|
|
116
|
+
export const init = (config) => (__foldkitBrandViewResult(({
|
|
117
|
+
id: config.id,
|
|
118
|
+
maybeFocus: Option.none(),
|
|
119
|
+
maybeHeld: Option.none(),
|
|
120
|
+
maybeResizing: Option.none(),
|
|
121
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#init"));
|
|
122
|
+
// ACCESSORS
|
|
123
|
+
const focusedPlace = (model, layout) => __foldkitBrandViewResult((Option.orElse(Option.flatMap(model.maybeFocus, (focus) => __foldkitBrandViewResult((Option.orElse(placeOf(layout, focus.paneId), () => {
|
|
124
|
+
const column = Number.clamp(focus.column, { minimum: 0, maximum: layout.length - 1 });
|
|
125
|
+
const rows = Option.match(Array.get(layout, column), {
|
|
126
|
+
onNone: () => __foldkitBrandViewResult((0), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone"),
|
|
127
|
+
onSome: (found) => __foldkitBrandViewResult((found.panes.length), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome"),
|
|
128
|
+
});
|
|
129
|
+
return __foldkitBrandViewResult((placeAt(layout, column, Number.clamp(focus.row, { minimum: 0, maximum: rows - 1 }))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~2");
|
|
130
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous")), () => __foldkitBrandViewResult((firstPlace(layout)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~3"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#focusedPlace");
|
|
131
|
+
/** The pane focus is on: the one last focused, or, when it has gone from `layout`, the pane
|
|
132
|
+
* now nearest its place; the first pane before any is focused. None for an empty layout. */
|
|
133
|
+
export const focusedPaneId = (model, layout) => __foldkitBrandViewResult((Option.map(focusedPlace(model, layout), ({ pane }) => __foldkitBrandViewResult((pane.id), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~4"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#focusedPaneId");
|
|
134
|
+
const isHolding = (model) => __foldkitBrandViewResult((Option.isSome(model.maybeHeld)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#isHolding");
|
|
135
|
+
/** Whether `held` is carried: by the keyboard, or by a pointer past the threshold. */
|
|
136
|
+
const isCarried = (held) => __foldkitBrandViewResult((By.match(held.by, { Pointer: ({ isCarrying }) => __foldkitBrandViewResult((isCarrying), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Pointer"), Keyboard: () => __foldkitBrandViewResult((true), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Keyboard") })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#isCarried");
|
|
137
|
+
// DOM HOOKS
|
|
138
|
+
const paneHook = (model, paneId) => __foldkitBrandViewResult((`${model.id}/pane/${paneId}`), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#paneHook");
|
|
139
|
+
const columnHook = (model, columnId) => __foldkitBrandViewResult((`${model.id}/column/${columnId}`), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#columnHook");
|
|
140
|
+
const subjectHook = (model, subject) => __foldkitBrandViewResult((Subject.match(subject, {
|
|
141
|
+
Pane: ({ paneId }) => __foldkitBrandViewResult((paneHook(model, paneId)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Pane"),
|
|
142
|
+
Column: ({ columnId }) => __foldkitBrandViewResult((columnHook(model, columnId)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Column"),
|
|
143
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#subjectHook");
|
|
144
|
+
const scrollerOf = (reelHook) => __foldkitBrandViewResult((Option.fromNullishOr(document.querySelector(`[data-reel="${CSS.escape(reelHook)}"] > .reel-view`))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#scrollerOf");
|
|
145
|
+
const paneElement = (hook) => __foldkitBrandViewResult((Option.fromNullishOr(document.querySelector(`[data-reel-pane="${CSS.escape(hook)}"]`))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#paneElement");
|
|
146
|
+
/** Puts the keyboard in `pane`: on its control marked `data-reel-focus` (a terminal's input),
|
|
147
|
+
* or on the pane itself, without scrolling the page. */
|
|
148
|
+
const focusInto = (pane) => {
|
|
149
|
+
Option.getOrElse(Option.fromNullishOr(pane.querySelector("[data-reel-focus]")), () => __foldkitBrandViewResult((pane), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~5")).focus({ preventScroll: true });
|
|
150
|
+
};
|
|
151
|
+
// COMMAND
|
|
152
|
+
/** Says a focus move, a move or a step of a drag through the page's live region (as
|
|
153
|
+
* `Announcer.Announce` does). */
|
|
154
|
+
export const AnnounceReel = Command.define("AnnounceReel", {
|
|
155
|
+
args: { text: Schema.String },
|
|
156
|
+
messages: [Message.CompletedAnnounceReel],
|
|
157
|
+
execute: ({ text }) => __foldkitBrandViewResult((Announcer.announce(text).pipe(Effect.as(Message.CompletedAnnounceReel()))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#execute"),
|
|
158
|
+
});
|
|
159
|
+
/** Focuses the pane `paneHook` names, unless focus is already inside it: the control in it
|
|
160
|
+
* marked `data-reel-focus` (a terminal's input), or the pane itself. It does not scroll;
|
|
161
|
+
* ScrollIntoView does. */
|
|
162
|
+
export const FocusPane = Command.define("FocusPane", {
|
|
163
|
+
args: { paneHook: Schema.String },
|
|
164
|
+
messages: [Message.CompletedFocusPane],
|
|
165
|
+
execute: ({ paneHook: hook }) => __foldkitBrandViewResult((Effect.gen(function* () {
|
|
166
|
+
yield* Render.afterCommit;
|
|
167
|
+
yield* Effect.sync(() => {
|
|
168
|
+
Option.map(Option.filter(paneElement(hook), (pane) => __foldkitBrandViewResult((!pane.contains(document.activeElement)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~8")), focusInto);
|
|
169
|
+
});
|
|
170
|
+
return __foldkitBrandViewResult((Message.CompletedFocusPane()), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~6");
|
|
171
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#execute~2"),
|
|
172
|
+
});
|
|
173
|
+
/** Focuses the pane `paneHook` names only where focus was lost (it left with the pane that
|
|
174
|
+
* held it), so focus the reader put somewhere else stays there. */
|
|
175
|
+
export const RestoreFocus = Command.define("RestoreFocus", {
|
|
176
|
+
args: { paneHook: Schema.String },
|
|
177
|
+
messages: [Message.CompletedRestoreFocus],
|
|
178
|
+
execute: ({ paneHook: hook }) => __foldkitBrandViewResult((Effect.gen(function* () {
|
|
179
|
+
yield* Render.afterCommit;
|
|
180
|
+
yield* Effect.sync(() => {
|
|
181
|
+
const active = document.activeElement;
|
|
182
|
+
if (active === null || active === document.body) {
|
|
183
|
+
Option.map(paneElement(hook), focusInto);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
return __foldkitBrandViewResult((Message.CompletedRestoreFocus()), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~9");
|
|
187
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#execute~3"),
|
|
188
|
+
});
|
|
189
|
+
/** Puts focus back on a column's grip once the render that moved its column is in the page:
|
|
190
|
+
* a column's element moves with it, which takes focus off its grip. */
|
|
191
|
+
export const FocusGrip = Command.define("FocusGrip", {
|
|
192
|
+
args: { gripHook: Schema.String },
|
|
193
|
+
messages: [Message.CompletedFocusGrip],
|
|
194
|
+
execute: ({ gripHook }) => __foldkitBrandViewResult((Effect.gen(function* () {
|
|
195
|
+
yield* Render.afterCommit;
|
|
196
|
+
yield* Effect.sync(() => {
|
|
197
|
+
document
|
|
198
|
+
.querySelector(`[data-reel-grip="${CSS.escape(gripHook)}"]`)
|
|
199
|
+
?.focus({ preventScroll: true });
|
|
200
|
+
});
|
|
201
|
+
return __foldkitBrandViewResult((Message.CompletedFocusGrip()), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~11");
|
|
202
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#execute~4"),
|
|
203
|
+
});
|
|
204
|
+
/** Scrolls the pane or column `hook` names into view, by the least distance either way, its
|
|
205
|
+
* gutter kept by the stylesheet's `scroll-margin`, once the render that placed it is in the
|
|
206
|
+
* page. It jumps: motion is stepped or instant, and a follow is instant. */
|
|
207
|
+
export const ScrollIntoView = Command.define("ScrollIntoView", {
|
|
208
|
+
args: { hook: Schema.String },
|
|
209
|
+
messages: [Message.CompletedScrollIntoView],
|
|
210
|
+
execute: ({ hook }) => __foldkitBrandViewResult((Effect.gen(function* () {
|
|
211
|
+
yield* Render.afterCommit;
|
|
212
|
+
yield* Effect.sync(() => {
|
|
213
|
+
document
|
|
214
|
+
.querySelector(`[data-reel-pane="${CSS.escape(hook)}"], [data-reel-hook="${CSS.escape(hook)}"]`)
|
|
215
|
+
?.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
216
|
+
});
|
|
217
|
+
return __foldkitBrandViewResult((Message.CompletedScrollIntoView()), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~13");
|
|
218
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#execute~5"),
|
|
219
|
+
});
|
|
220
|
+
/** How far a pointer moves from its press before it carries what it pressed. */
|
|
221
|
+
const CARRY_THRESHOLD = 5;
|
|
222
|
+
const withHeld = (model, maybeHeld) => __foldkitBrandViewResult((modifyFields(model, { maybeHeld: () => __foldkitBrandViewResult((maybeHeld), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#maybeHeld") })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#withHeld");
|
|
223
|
+
const withResizing = (model, maybeResizing) => __foldkitBrandViewResult((modifyFields(model, { maybeResizing: () => __foldkitBrandViewResult((maybeResizing), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#maybeResizing") })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#withResizing");
|
|
224
|
+
const focusOn = (model, place) => __foldkitBrandViewResult((modifyFields(model, {
|
|
225
|
+
maybeFocus: () => __foldkitBrandViewResult((Option.some({ paneId: place.pane.id, column: place.columnIndex, row: place.row })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#maybeFocus"),
|
|
226
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#focusOn");
|
|
227
|
+
const announce = (text) => __foldkitBrandViewResult((AnnounceReel({ text })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#announce");
|
|
228
|
+
const heldWords = (layout, held) => __foldkitBrandViewResult((String.capitalize(Option.getOrElse(subjectWords(layout, held.subject), () => __foldkitBrandViewResult((""), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~15")))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#heldWords");
|
|
229
|
+
const scrollToTarget = (model, layout, target) => __foldkitBrandViewResult((Array.fromOption(Option.map(columnOfTarget(layout, target), (columnId) => __foldkitBrandViewResult((ScrollIntoView({ hook: columnHook(model, columnId) })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~16")))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#scrollToTarget");
|
|
230
|
+
/** Lets go of what is held: dropped at its target when it is carried and the drop changes
|
|
231
|
+
* something (reported as the request), put back otherwise, said in `putBack`'s words. A
|
|
232
|
+
* column dropped by the keyboard gets its grip's focus back. */
|
|
233
|
+
const letGo = (model, layout, held, putBack) => {
|
|
234
|
+
const released = withHeld(model, Option.none());
|
|
235
|
+
if (!isCarried(held)) {
|
|
236
|
+
return __foldkitBrandViewResult(({ model: released }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#letGo");
|
|
237
|
+
}
|
|
238
|
+
const subject = heldWords(layout, held);
|
|
239
|
+
const maybeRequest = Option.flatMap(held.maybeTarget, (target) => __foldkitBrandViewResult((requestOf(layout, held.subject, target)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~17"));
|
|
240
|
+
// a column that moves takes focus off its grip; one put back never left its place
|
|
241
|
+
const refocus = held.subject._tag === "Column" && held.by._tag === "Keyboard"
|
|
242
|
+
? [FocusGrip({ gripHook: subjectHook(model, held.subject) })]
|
|
243
|
+
: [];
|
|
244
|
+
return __foldkitBrandViewResult((Option.match(maybeRequest, {
|
|
245
|
+
onNone: () => (__foldkitBrandViewResult(({
|
|
246
|
+
model: released,
|
|
247
|
+
commands: [announce(fill(putBack, { subject }))],
|
|
248
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~2")),
|
|
249
|
+
onSome: (request) => (__foldkitBrandViewResult(({
|
|
250
|
+
model: released,
|
|
251
|
+
commands: [
|
|
252
|
+
...refocus,
|
|
253
|
+
announce(fill(COPY.dropped, {
|
|
254
|
+
subject,
|
|
255
|
+
where: Option.getOrElse(whereWords(apply(layout, request), held.subject), () => __foldkitBrandViewResult((WHERE_IT_WAS), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~18")),
|
|
256
|
+
})),
|
|
257
|
+
],
|
|
258
|
+
outMessage: request,
|
|
259
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~2")),
|
|
260
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#letGo");
|
|
261
|
+
};
|
|
262
|
+
const cancel = (model, layout, held) => __foldkitBrandViewResult((letGo(model, layout, { ...held, maybeTarget: Option.none() }, COPY.cancelled)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#cancel");
|
|
263
|
+
const lift = (model, layout, subject, by) => __foldkitBrandViewResult((Option.match(Option.filter(originOf(layout, subject), () => __foldkitBrandViewResult((!isHolding(model) && Option.isNone(model.maybeResizing)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~19")), {
|
|
264
|
+
onNone: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~3")),
|
|
265
|
+
onSome: (origin) => {
|
|
266
|
+
const held = { subject, by, maybeTarget: Option.some(origin) };
|
|
267
|
+
return __foldkitBrandViewResult(({
|
|
268
|
+
model: withHeld(model, Option.some(held)),
|
|
269
|
+
commands: by._tag === "Keyboard"
|
|
270
|
+
? [announce(fill(COPY.pickedUpByKeyboard, { subject: heldWords(layout, held) }))]
|
|
271
|
+
: [],
|
|
272
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~3");
|
|
273
|
+
},
|
|
274
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#lift");
|
|
275
|
+
const movePointer = (model, layout, held, pointer) => __foldkitBrandViewResult((By.match(held.by, {
|
|
276
|
+
Keyboard: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Keyboard~2")),
|
|
277
|
+
Pointer: (by) => {
|
|
278
|
+
const isCarrying = by.isCarrying ||
|
|
279
|
+
Math.hypot(pointer.clientX - by.pressX, pointer.clientY - by.pressY) > CARRY_THRESHOLD;
|
|
280
|
+
const next = {
|
|
281
|
+
...held,
|
|
282
|
+
by: By.Pointer({ ...by, x: pointer.clientX, y: pointer.clientY, isCarrying }),
|
|
283
|
+
maybeTarget: isCarrying ? pointer.maybeTarget : held.maybeTarget,
|
|
284
|
+
};
|
|
285
|
+
return __foldkitBrandViewResult(({
|
|
286
|
+
model: withHeld(model, Option.some(next)),
|
|
287
|
+
commands: isCarrying && !by.isCarrying
|
|
288
|
+
? [announce(fill(COPY.pickedUp, { subject: heldWords(layout, held) }))]
|
|
289
|
+
: [],
|
|
290
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Pointer~2");
|
|
291
|
+
},
|
|
292
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#movePointer");
|
|
293
|
+
/** A keyboard step of what is held, resolved from the layout, with the reel scrolled to the
|
|
294
|
+
* column it lands by. */
|
|
295
|
+
const stepHeld = (model, layout, held, step) => __foldkitBrandViewResult((Option.match(Option.filter(held.maybeTarget, () => __foldkitBrandViewResult((held.by._tag === "Keyboard"), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~20")), {
|
|
296
|
+
onNone: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~4")),
|
|
297
|
+
onSome: (target) => {
|
|
298
|
+
const next = steppedTarget(layout, held.subject, target, step);
|
|
299
|
+
if (Equal.equals(next, target)) {
|
|
300
|
+
return __foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~4");
|
|
301
|
+
}
|
|
302
|
+
return __foldkitBrandViewResult(({
|
|
303
|
+
model: withHeld(model, Option.some({ ...held, maybeTarget: Option.some(next) })),
|
|
304
|
+
commands: [
|
|
305
|
+
announce(fill(COPY.over, {
|
|
306
|
+
subject: heldWords(layout, held),
|
|
307
|
+
where: landingWords(layout, held.subject, next),
|
|
308
|
+
})),
|
|
309
|
+
...scrollToTarget(model, layout, next),
|
|
310
|
+
],
|
|
311
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~4");
|
|
312
|
+
},
|
|
313
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#stepHeld");
|
|
314
|
+
const whileHeld = (model, f) => __foldkitBrandViewResult((Option.match(model.maybeHeld, { onNone: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~5")), onSome: f })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#whileHeld");
|
|
315
|
+
const whileHeldBy = (model, by, f) => __foldkitBrandViewResult((whileHeld(model, (held) => (__foldkitBrandViewResult((held.by._tag === by ? f(held) : { model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~21")))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#whileHeldBy");
|
|
316
|
+
/** The resize a splitter dragged `share` of its scale asks for: previewed while it moves, and
|
|
317
|
+
* asked for when it is let go. */
|
|
318
|
+
const resizeSplitter = (model, layout, share, isLetGo) => __foldkitBrandViewResult((Option.match(model.maybeResizing, {
|
|
319
|
+
onNone: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~6")),
|
|
320
|
+
onSome: (resizing) => {
|
|
321
|
+
const maybeResize = resizeOf(layout, resizing.splitter, share);
|
|
322
|
+
if (!isLetGo) {
|
|
323
|
+
return __foldkitBrandViewResult(({ model: withResizing(model, Option.some({ ...resizing, maybeResize })) }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~5");
|
|
324
|
+
}
|
|
325
|
+
return __foldkitBrandViewResult((Option.match(maybeResize, {
|
|
326
|
+
onNone: () => (__foldkitBrandViewResult(({ model: withResizing(model, Option.none()) }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~7")),
|
|
327
|
+
onSome: (resize) => (__foldkitBrandViewResult(({ model: withResizing(model, Option.none()), outMessage: resize }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~6")),
|
|
328
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~5");
|
|
329
|
+
},
|
|
330
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#resizeSplitter");
|
|
331
|
+
/** Processes a reel Message against the layout as the application holds it now, and returns
|
|
332
|
+
* the next Model, Commands and OutMessage. */
|
|
333
|
+
export const update = (model, message, context) => {
|
|
334
|
+
const { layout } = context;
|
|
335
|
+
return __foldkitBrandViewResult((Message.match(message, {
|
|
336
|
+
PressedGrip: ({ subject, pointerId, clientX, clientY }) => __foldkitBrandViewResult((lift(model, layout, subject, By.Pointer({
|
|
337
|
+
pointerId,
|
|
338
|
+
pressX: clientX,
|
|
339
|
+
pressY: clientY,
|
|
340
|
+
x: clientX,
|
|
341
|
+
y: clientY,
|
|
342
|
+
isCarrying: false,
|
|
343
|
+
}))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#PressedGrip"),
|
|
344
|
+
PressedGripKey: ({ subject }) => __foldkitBrandViewResult((lift(model, layout, subject, By.Keyboard())), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#PressedGripKey"),
|
|
345
|
+
MovedPointer: (pointer) => __foldkitBrandViewResult((whileHeldBy(model, "Pointer", (held) => __foldkitBrandViewResult((movePointer(model, layout, held, pointer)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~22"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#MovedPointer"),
|
|
346
|
+
ReleasedPointer: (pointer) => __foldkitBrandViewResult((whileHeldBy(model, "Pointer", (held) => __foldkitBrandViewResult((letGo(model, layout, isCarried(held) ? { ...held, maybeTarget: pointer.maybeTarget } : held, COPY.putBack)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~23"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#ReleasedPointer"),
|
|
347
|
+
CancelledPointer: () => __foldkitBrandViewResult((whileHeldBy(model, "Pointer", (held) => __foldkitBrandViewResult((letGo(model, layout, { ...held, maybeTarget: Option.none() }, COPY.putBack)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~24"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#CancelledPointer"),
|
|
348
|
+
SteppedHeld: ({ step }) => __foldkitBrandViewResult((whileHeldBy(model, "Keyboard", (held) => __foldkitBrandViewResult((stepHeld(model, layout, held, step)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~25"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#SteppedHeld"),
|
|
349
|
+
DroppedHeld: () => __foldkitBrandViewResult((whileHeldBy(model, "Keyboard", (held) => __foldkitBrandViewResult((letGo(model, layout, held, COPY.putBack)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~26"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#DroppedHeld"),
|
|
350
|
+
LeftGrip: () => __foldkitBrandViewResult((whileHeldBy(model, "Keyboard", (held) => __foldkitBrandViewResult((cancel(model, layout, held)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~27"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#LeftGrip"),
|
|
351
|
+
PressedEscape: () => __foldkitBrandViewResult((Option.isSome(model.maybeResizing)
|
|
352
|
+
? { model: withResizing(model, Option.none()) }
|
|
353
|
+
: whileHeld(model, (held) => __foldkitBrandViewResult((cancel(model, layout, held)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~28"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#PressedEscape"),
|
|
354
|
+
FocusedPane: ({ paneId }) => __foldkitBrandViewResult((Option.match(Option.filter(placeOf(layout, paneId), () => __foldkitBrandViewResult((!Option.exists(model.maybeFocus, (focus) => __foldkitBrandViewResult((focus.paneId === paneId), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~30"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~29")), {
|
|
355
|
+
onNone: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~8")),
|
|
356
|
+
onSome: (place) => (__foldkitBrandViewResult(({ model: focusOn(model, place) }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~7")),
|
|
357
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#FocusedPane"),
|
|
358
|
+
PressedSplitter: ({ splitter, pointerId, clientX, clientY }) => __foldkitBrandViewResult((isHolding(model) || Option.isSome(model.maybeResizing) || !isSplitterPresent(layout, splitter)
|
|
359
|
+
? { model }
|
|
360
|
+
: {
|
|
361
|
+
model: withResizing(model, Option.some({
|
|
362
|
+
splitter,
|
|
363
|
+
pointerId,
|
|
364
|
+
pressX: clientX,
|
|
365
|
+
pressY: clientY,
|
|
366
|
+
maybeResize: Option.none(),
|
|
367
|
+
})),
|
|
368
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#PressedSplitter"),
|
|
369
|
+
MovedSplitter: ({ share }) => __foldkitBrandViewResult((resizeSplitter(model, layout, share, false)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#MovedSplitter"),
|
|
370
|
+
ReleasedSplitter: ({ share }) => __foldkitBrandViewResult((resizeSplitter(model, layout, share, true)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#ReleasedSplitter"),
|
|
371
|
+
CancelledSplitter: () => (__foldkitBrandViewResult(({ model: withResizing(model, Option.none()) }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#CancelledSplitter")),
|
|
372
|
+
PressedSplitterKey: ({ splitter, share }) => __foldkitBrandViewResult((Option.match(resizeOf(layout, splitter, share), {
|
|
373
|
+
onNone: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~9")),
|
|
374
|
+
onSome: (resize) => (__foldkitBrandViewResult(({ model, outMessage: resize }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~8")),
|
|
375
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#PressedSplitterKey"),
|
|
376
|
+
CompletedAnnounceReel: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#CompletedAnnounceReel")),
|
|
377
|
+
CompletedFocusPane: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#CompletedFocusPane")),
|
|
378
|
+
CompletedRestoreFocus: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#CompletedRestoreFocus")),
|
|
379
|
+
CompletedFocusGrip: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#CompletedFocusGrip")),
|
|
380
|
+
CompletedScrollIntoView: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#CompletedScrollIntoView")),
|
|
381
|
+
CompletedSizeLiftedPane: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#CompletedSizeLiftedPane")),
|
|
382
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#update");
|
|
383
|
+
};
|
|
384
|
+
// CAPABILITIES
|
|
385
|
+
/**
|
|
386
|
+
* Brings the reel in line with a layout that changed: call it whenever the application changes
|
|
387
|
+
* the layout, by a request it applied, another client's or one of its own (a pane closed). The
|
|
388
|
+
* focused pane's place is read again; when it has gone, focus moves to the pane now nearest
|
|
389
|
+
* where it was, and the keyboard follows where it went with the pane. A drag whose pane or
|
|
390
|
+
* column has gone is cancelled, and one whose target's column has gone aims where it started;
|
|
391
|
+
* a splitter whose column or pane has gone lets go.
|
|
392
|
+
*/
|
|
393
|
+
export const reconcile = (model, context) => {
|
|
394
|
+
const { layout } = context;
|
|
395
|
+
const isFocusGone = Option.exists(model.maybeFocus, (focus) => __foldkitBrandViewResult((Option.isNone(placeOf(layout, focus.paneId))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~31"));
|
|
396
|
+
const maybePlace = Option.filter(focusedPlace(model, layout), () => __foldkitBrandViewResult((Option.isSome(model.maybeFocus)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~32"));
|
|
397
|
+
const focused = Option.match(maybePlace, {
|
|
398
|
+
onNone: () => __foldkitBrandViewResult((model), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~10"),
|
|
399
|
+
onSome: (place) => __foldkitBrandViewResult((focusOn(model, place)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~9"),
|
|
400
|
+
});
|
|
401
|
+
const restore = Array.fromOption(Option.map(Option.filter(maybePlace, () => __foldkitBrandViewResult((isFocusGone), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~33")), (place) => __foldkitBrandViewResult((RestoreFocus({ paneHook: paneHook(model, place.pane.id) })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~34")));
|
|
402
|
+
const settled = Option.exists(model.maybeResizing, ({ splitter }) => __foldkitBrandViewResult((isSplitterPresent(layout, splitter)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~35"))
|
|
403
|
+
? focused
|
|
404
|
+
: withResizing(focused, Option.none());
|
|
405
|
+
return __foldkitBrandViewResult((Option.match(settled.maybeHeld, {
|
|
406
|
+
onNone: () => (__foldkitBrandViewResult(({ model: settled, commands: restore }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~11")),
|
|
407
|
+
onSome: (held) => {
|
|
408
|
+
if (!isPresent(layout, held.subject)) {
|
|
409
|
+
return __foldkitBrandViewResult(({
|
|
410
|
+
model: withHeld(settled, Option.none()),
|
|
411
|
+
commands: [...restore, announce(COPY.gone)],
|
|
412
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~10");
|
|
413
|
+
}
|
|
414
|
+
const maybeTarget = Option.orElse(Option.filter(held.maybeTarget, (target) => __foldkitBrandViewResult((isTargetPresent(layout, target)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~36")), () => (__foldkitBrandViewResult((held.by._tag === "Keyboard" ? originOf(layout, held.subject) : Option.none()), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~37")));
|
|
415
|
+
return __foldkitBrandViewResult(({
|
|
416
|
+
model: withHeld(settled, Option.some({ ...held, maybeTarget })),
|
|
417
|
+
commands: restore,
|
|
418
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~10");
|
|
419
|
+
},
|
|
420
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#reconcile");
|
|
421
|
+
};
|
|
422
|
+
/** What the application's keys ask of the reel. `Focus*`: focus the pane beside the focused
|
|
423
|
+
* one. `MovePane*`: move the focused pane up or down its column, or into the column beside it
|
|
424
|
+
* (past the first or last column, into a column of its own). `MoveColumn*`: move its column.
|
|
425
|
+
* `CycleWidth`: its column's width to the next preset. `PullOut`: the pane into a column of
|
|
426
|
+
* its own, right of its column. */
|
|
427
|
+
export const Action = Schema.Literals([
|
|
428
|
+
"FocusLeft",
|
|
429
|
+
"FocusRight",
|
|
430
|
+
"FocusUp",
|
|
431
|
+
"FocusDown",
|
|
432
|
+
"MovePaneLeft",
|
|
433
|
+
"MovePaneRight",
|
|
434
|
+
"MovePaneUp",
|
|
435
|
+
"MovePaneDown",
|
|
436
|
+
"MoveColumnLeft",
|
|
437
|
+
"MoveColumnRight",
|
|
438
|
+
"CycleWidth",
|
|
439
|
+
"PullOut",
|
|
440
|
+
]);
|
|
441
|
+
const focusStep = (model, layout, place) => (__foldkitBrandViewResult(({
|
|
442
|
+
model: focusOn(model, place),
|
|
443
|
+
commands: [
|
|
444
|
+
FocusPane({ paneHook: paneHook(model, place.pane.id) }),
|
|
445
|
+
ScrollIntoView({ hook: paneHook(model, place.pane.id) }),
|
|
446
|
+
announce(fill(COPY.focused, { pane: place.pane.label, where: placeWords(layout, place) })),
|
|
447
|
+
],
|
|
448
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#focusStep"));
|
|
449
|
+
/** Asks for `request` with focus kept on the pane it moves, at its new place, the reel
|
|
450
|
+
* scrolled to it and the move said; nothing where it would change nothing. */
|
|
451
|
+
const requestStep = (model, layout, place, subject, maybeRequest) => __foldkitBrandViewResult((Option.match(Option.filter(maybeRequest, (request) => __foldkitBrandViewResult((!Equal.equals(apply(layout, request), layout)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~38")), {
|
|
452
|
+
onNone: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~12")),
|
|
453
|
+
onSome: (request) => {
|
|
454
|
+
const next = apply(layout, request);
|
|
455
|
+
const landing = Option.getOrElse(placeOf(next, place.pane.id), () => __foldkitBrandViewResult((place), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~39"));
|
|
456
|
+
const words = Option.getOrElse(subjectWords(layout, subject), () => __foldkitBrandViewResult((place.pane.label), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~40"));
|
|
457
|
+
const where = Option.getOrElse(whereWords(next, subject), () => __foldkitBrandViewResult((WHERE_IT_WAS), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~41"));
|
|
458
|
+
return __foldkitBrandViewResult(({
|
|
459
|
+
model: focusOn(model, landing),
|
|
460
|
+
commands: [
|
|
461
|
+
ScrollIntoView({ hook: paneHook(model, place.pane.id) }),
|
|
462
|
+
announce(fill(COPY.moved, { subject: String.capitalize(words), where })),
|
|
463
|
+
],
|
|
464
|
+
outMessage: request,
|
|
465
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~11");
|
|
466
|
+
},
|
|
467
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#requestStep");
|
|
468
|
+
const columnIdAt = (layout, index) => __foldkitBrandViewResult((Option.map(Array.get(layout, index), ({ id }) => __foldkitBrandViewResult((id), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~42"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#columnIdAt");
|
|
469
|
+
/**
|
|
470
|
+
* Does what the application's key for `action` asks, from the focused pane, against the
|
|
471
|
+
* layout as the application holds it: focus moves focus the pane and scroll the reel to it;
|
|
472
|
+
* moves report their request as the OutMessage, which the application applies, with focus
|
|
473
|
+
* kept on the pane. Each is said through the live region. Nothing happens while something is
|
|
474
|
+
* held, or where there is nowhere to go.
|
|
475
|
+
*/
|
|
476
|
+
export const perform = (model, action, context) => {
|
|
477
|
+
const { layout } = context;
|
|
478
|
+
return __foldkitBrandViewResult((Option.match(Option.filter(focusedPlace(model, layout), () => __foldkitBrandViewResult((!isHolding(model)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~43")), {
|
|
479
|
+
onNone: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~13")),
|
|
480
|
+
onSome: (place) => {
|
|
481
|
+
const { column, columnIndex, row, pane } = place;
|
|
482
|
+
const rows = column.panes.length;
|
|
483
|
+
const paneId = pane.id;
|
|
484
|
+
const ask = (maybeRequest, subject = Subject.Pane({ paneId })) => __foldkitBrandViewResult((requestStep(model, layout, place, subject, maybeRequest)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#ask");
|
|
485
|
+
const focusAt = (toColumn, toRow) => __foldkitBrandViewResult((Option.match(Option.flatMap(Array.get(layout, toColumn), (found) => __foldkitBrandViewResult((placeAt(layout, toColumn, Number.clamp(toRow, { minimum: 0, maximum: found.panes.length - 1 }))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~44")), {
|
|
486
|
+
onNone: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~14")),
|
|
487
|
+
onSome: (next) => __foldkitBrandViewResult((next.pane.id === paneId ? { model } : focusStep(model, layout, next)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~13"),
|
|
488
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#focusAt");
|
|
489
|
+
const sideways = (toColumn, edge) => __foldkitBrandViewResult((ask(Option.match(Array.get(layout, toColumn), {
|
|
490
|
+
onSome: (found) => __foldkitBrandViewResult((Option.some(OutMessage.MovedPane({
|
|
491
|
+
paneId,
|
|
492
|
+
toColumnId: found.id,
|
|
493
|
+
toIndex: Math.min(row, found.panes.length),
|
|
494
|
+
}))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~14"),
|
|
495
|
+
onNone: () => __foldkitBrandViewResult((Option.liftPredicate(OutMessage.PulledOutPane({ paneId, maybeBeforeColumnId: edge }), () => __foldkitBrandViewResult((rows > 1), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~45"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~15"),
|
|
496
|
+
}))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#sideways");
|
|
497
|
+
const moveColumn = (maybeBefore) => __foldkitBrandViewResult((ask(Option.map(maybeBefore, (maybeBeforeColumnId) => __foldkitBrandViewResult((OutMessage.MovedColumn({ columnId: column.id, maybeBeforeColumnId })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~46")), Subject.Column({ columnId: column.id }))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#moveColumn");
|
|
498
|
+
return __foldkitBrandViewResult((Match.value(action).pipe(Match.withReturnType(), Match.when("FocusLeft", () => __foldkitBrandViewResult((focusAt(columnIndex - 1, row)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~47")), Match.when("FocusRight", () => __foldkitBrandViewResult((focusAt(columnIndex + 1, row)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~48")), Match.when("FocusUp", () => (__foldkitBrandViewResult((row > 0 ? focusAt(columnIndex, row - 1) : { model }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~49"))), Match.when("FocusDown", () => __foldkitBrandViewResult((focusAt(columnIndex, row + 1)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~50")), Match.when("MovePaneUp", () => __foldkitBrandViewResult((ask(Option.some(OutMessage.MovedPane({ paneId, toColumnId: column.id, toIndex: row - 1 })))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~51")), Match.when("MovePaneDown", () => __foldkitBrandViewResult((ask(Option.some(OutMessage.MovedPane({ paneId, toColumnId: column.id, toIndex: row + 1 })))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~52")), Match.when("MovePaneLeft", () => __foldkitBrandViewResult((sideways(columnIndex - 1, columnIdAt(layout, 0))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~53")), Match.when("MovePaneRight", () => __foldkitBrandViewResult((sideways(columnIndex + 1, Option.none())), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~54")), Match.when("MoveColumnLeft", () => __foldkitBrandViewResult((moveColumn(Option.map(columnIdAt(layout, columnIndex - 1), (before) => __foldkitBrandViewResult((Option.some(before)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~56")))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~55")), Match.when("MoveColumnRight", () => __foldkitBrandViewResult((moveColumn(Option.map(columnIdAt(layout, columnIndex + 1), () => __foldkitBrandViewResult((columnIdAt(layout, columnIndex + 2)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~58")))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~57")), Match.when("CycleWidth", () => {
|
|
499
|
+
const width = nextPreset(column.width);
|
|
500
|
+
return __foldkitBrandViewResult(({
|
|
501
|
+
model,
|
|
502
|
+
commands: [
|
|
503
|
+
ScrollIntoView({ hook: paneHook(model, paneId) }),
|
|
504
|
+
announce(fill(COPY.widened, { column: columnIndex + 1, width: widthWords(width) })),
|
|
505
|
+
],
|
|
506
|
+
outMessage: OutMessage.ResizedColumn({ columnId: column.id, width }),
|
|
507
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~59");
|
|
508
|
+
}), Match.when("PullOut", () => __foldkitBrandViewResult((ask(Option.liftPredicate(OutMessage.PulledOutPane({
|
|
509
|
+
paneId,
|
|
510
|
+
maybeBeforeColumnId: columnIdAt(layout, columnIndex + 1),
|
|
511
|
+
}), () => __foldkitBrandViewResult((rows > 1), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~61")))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~60")), Match.exhaustive)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~12");
|
|
512
|
+
},
|
|
513
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#perform");
|
|
514
|
+
};
|
|
515
|
+
// SUBSCRIPTION
|
|
516
|
+
/** How near the reel's edges a carried pane scrolls it, how fast, and the longest frame it
|
|
517
|
+
* counts, so a tab coming back from the background does not jump. */
|
|
518
|
+
const EDGE_SCROLL = 40;
|
|
519
|
+
const EDGE_SCROLL_PIXELS_PER_MILLI = 0.8;
|
|
520
|
+
const LONGEST_FRAME_MILLIS = 50;
|
|
521
|
+
/** A column as the pointer reads it from the page: its edges, and the middles of its slots
|
|
522
|
+
* but the held pane's. */
|
|
523
|
+
const columnBoxOf = (element, subject) => {
|
|
524
|
+
const rect = element.getBoundingClientRect();
|
|
525
|
+
const heldId = Subject.match(subject, {
|
|
526
|
+
Pane: ({ paneId }) => __foldkitBrandViewResult((Option.some(paneId)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Pane~2"),
|
|
527
|
+
Column: () => __foldkitBrandViewResult((Option.none()), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Column~2"),
|
|
528
|
+
});
|
|
529
|
+
return __foldkitBrandViewResult(({
|
|
530
|
+
id: element.getAttribute("data-reel-column") ?? "",
|
|
531
|
+
left: rect.left,
|
|
532
|
+
right: rect.right,
|
|
533
|
+
slotMiddles: Array.map(Array.filter(Array.fromIterable(element.querySelectorAll("[data-reel-slot]")), (slot) => __foldkitBrandViewResult((!Option.contains(heldId, slot.getAttribute("data-reel-slot") ?? "")), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~62")), (slot) => {
|
|
534
|
+
const slotRect = slot.getBoundingClientRect();
|
|
535
|
+
return __foldkitBrandViewResult((slotRect.top + slotRect.height / 2), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~63");
|
|
536
|
+
}),
|
|
537
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#columnBoxOf");
|
|
538
|
+
};
|
|
539
|
+
/** Where a pointer at (`clientX`, `clientY`) would drop `subject` in the reel `reelHook`
|
|
540
|
+
* names, read from where its columns and their slots sit: none outside the reel. */
|
|
541
|
+
const pointerTarget = (reelHook, subject, clientX, clientY) => __foldkitBrandViewResult((Option.map(Option.filter(scrollerOf(reelHook), (view) => {
|
|
542
|
+
const rect = view.getBoundingClientRect();
|
|
543
|
+
return (__foldkitBrandViewResult((clientX >= rect.left &&
|
|
544
|
+
clientX <= rect.right &&
|
|
545
|
+
clientY >= rect.top &&
|
|
546
|
+
clientY <= rect.bottom), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~64"));
|
|
547
|
+
}), (view) => __foldkitBrandViewResult((targetAtPoint(subject, Array.map(Array.fromIterable(view.querySelectorAll("[data-reel-column]")), (element) => __foldkitBrandViewResult((columnBoxOf(element, subject)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~66")), clientX, clientY)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~65"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#pointerTarget");
|
|
548
|
+
const PointerHold = Schema.Struct({
|
|
549
|
+
reelHook: Schema.String,
|
|
550
|
+
subject: Subject,
|
|
551
|
+
pointerId: Schema.Number,
|
|
552
|
+
});
|
|
553
|
+
const pointerAt = (hold, event) => (__foldkitBrandViewResult(({
|
|
554
|
+
clientX: event.clientX,
|
|
555
|
+
clientY: event.clientY,
|
|
556
|
+
maybeTarget: pointerTarget(hold.reelHook, hold.subject, event.clientX, event.clientY),
|
|
557
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#pointerAt"));
|
|
558
|
+
/** The pressing pointer's moves, release and cancel; another pointer's are not the reel's. */
|
|
559
|
+
const pointerMessages = (hold) => __foldkitBrandViewResult((Stream.map(pressingPointer(hold.pointerId), (event) => __foldkitBrandViewResult((Match.value(event.type).pipe(Match.when("pointermove", () => __foldkitBrandViewResult((Message.MovedPointer(pointerAt(hold, event))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~68")), Match.when("pointerup", () => __foldkitBrandViewResult((Message.ReleasedPointer(pointerAt(hold, event))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~69")), Match.orElse(() => __foldkitBrandViewResult((Message.CancelledPointer()), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~70")))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~67"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#pointerMessages");
|
|
560
|
+
/** Which way a pointer at `at` scrolls a box from `low` to `high`: towards the edge it is near. */
|
|
561
|
+
const towards = (at, low, high) => {
|
|
562
|
+
if (at < low + EDGE_SCROLL) {
|
|
563
|
+
return __foldkitBrandViewResult((-1), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#towards");
|
|
564
|
+
}
|
|
565
|
+
else if (at > high - EDGE_SCROLL) {
|
|
566
|
+
return __foldkitBrandViewResult((1), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#towards");
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
return __foldkitBrandViewResult((0), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#towards");
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
/** While a pointer carries a pane or a column near the reel's edges, the reel scrolls that way,
|
|
573
|
+
* by the time each frame took, so a drop can reach a column or a place out of view. */
|
|
574
|
+
const edgeScroll = (hold) => __foldkitBrandViewResult((Stream.callback(() => __foldkitBrandViewResult((Effect.acquireRelease(Effect.sync(() => {
|
|
575
|
+
const state = {
|
|
576
|
+
maybeAt: Option.none(),
|
|
577
|
+
frame: 0,
|
|
578
|
+
last: performance.now(),
|
|
579
|
+
};
|
|
580
|
+
const onMove = (event) => {
|
|
581
|
+
if (event.pointerId === hold.pointerId) {
|
|
582
|
+
state.maybeAt = Option.some({ x: event.clientX, y: event.clientY });
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
const step = (now) => {
|
|
586
|
+
const distance = Math.min(now - state.last, LONGEST_FRAME_MILLIS) * EDGE_SCROLL_PIXELS_PER_MILLI;
|
|
587
|
+
state.last = now;
|
|
588
|
+
Option.map(Option.all({ view: scrollerOf(hold.reelHook), at: state.maybeAt }), ({ view, at }) => {
|
|
589
|
+
const rect = view.getBoundingClientRect();
|
|
590
|
+
view.scrollLeft += towards(at.x, rect.left, rect.right) * distance;
|
|
591
|
+
view.scrollTop += towards(at.y, rect.top, rect.bottom) * distance;
|
|
592
|
+
});
|
|
593
|
+
state.frame = requestAnimationFrame(step);
|
|
594
|
+
};
|
|
595
|
+
document.addEventListener("pointermove", onMove);
|
|
596
|
+
state.frame = requestAnimationFrame(step);
|
|
597
|
+
return __foldkitBrandViewResult(({ state, onMove }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~72");
|
|
598
|
+
}), ({ state, onMove }) => __foldkitBrandViewResult((Effect.sync(() => {
|
|
599
|
+
cancelAnimationFrame(state.frame);
|
|
600
|
+
document.removeEventListener("pointermove", onMove);
|
|
601
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~74")).pipe(Effect.flatMap(() => __foldkitBrandViewResult((Effect.never), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~76")))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~71"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#edgeScroll");
|
|
602
|
+
const SplitterHold = Schema.Struct({
|
|
603
|
+
reelHook: Schema.String,
|
|
604
|
+
splitter: Splitter,
|
|
605
|
+
pointerId: Schema.Number,
|
|
606
|
+
pressX: Schema.Number,
|
|
607
|
+
pressY: Schema.Number,
|
|
608
|
+
});
|
|
609
|
+
const heightOf = (element) => __foldkitBrandViewResult((element.getBoundingClientRect().height), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#heightOf");
|
|
610
|
+
/** The pixels a splitter's share is counted in, read when its drag begins: the reel's width
|
|
611
|
+
* less a gutter for a width (a column is `width × (view − gutter) − gutter` wide), its
|
|
612
|
+
* column's panes' height for a pane splitter. */
|
|
613
|
+
const scaleOf = (hold) => __foldkitBrandViewResult((Option.getOrElse(Option.map(scrollerOf(hold.reelHook), (view) => __foldkitBrandViewResult((Splitter.match(hold.splitter, {
|
|
614
|
+
Width: () => __foldkitBrandViewResult((view.clientWidth -
|
|
615
|
+
Option.getOrElse(Option.map(Option.fromNullishOr(view.querySelector(".reel-gap")), (gap) => __foldkitBrandViewResult((gap.getBoundingClientRect().width), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~78")), () => __foldkitBrandViewResult((0), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~79"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Width"),
|
|
616
|
+
Split: ({ abovePaneId }) => __foldkitBrandViewResult((Number.sumAll(Array.map(Array.fromIterable(view
|
|
617
|
+
.querySelector(`[data-reel-slot="${CSS.escape(abovePaneId)}"]`)
|
|
618
|
+
?.closest(".reel-column")
|
|
619
|
+
?.querySelectorAll("[data-reel-slot]") ?? []), heightOf))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Split"),
|
|
620
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~77")), () => __foldkitBrandViewResult((0), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~80"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#scaleOf");
|
|
621
|
+
/** The dragging pointer's moves, release and cancel, as shares of the splitter's scale. */
|
|
622
|
+
const splitterMessages = (hold) => __foldkitBrandViewResult((Stream.suspend(() => {
|
|
623
|
+
const scale = scaleOf(hold);
|
|
624
|
+
const shareOf = (event) => {
|
|
625
|
+
const moved = hold.splitter._tag === "Width" ? event.clientX - hold.pressX : event.clientY - hold.pressY;
|
|
626
|
+
return __foldkitBrandViewResult((scale > 0 ? moved / scale : 0), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#shareOf");
|
|
627
|
+
};
|
|
628
|
+
return __foldkitBrandViewResult((Stream.map(pressingPointer(hold.pointerId), (event) => __foldkitBrandViewResult((Match.value(event.type).pipe(Match.when("pointermove", () => __foldkitBrandViewResult((Message.MovedSplitter({ share: shareOf(event) })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~83")), Match.when("pointerup", () => __foldkitBrandViewResult((Message.ReleasedSplitter({ share: shareOf(event) })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~84")), Match.orElse(() => __foldkitBrandViewResult((Message.CancelledSplitter()), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~85")))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~82"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~81");
|
|
629
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#splitterMessages");
|
|
630
|
+
const pointerHoldOf = (model, isCarryingOnly) => __foldkitBrandViewResult((Option.flatMap(model.maybeHeld, ({ subject, by }) => __foldkitBrandViewResult((By.match(by, {
|
|
631
|
+
Keyboard: () => __foldkitBrandViewResult((Option.none()), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Keyboard~3"),
|
|
632
|
+
Pointer: ({ pointerId, isCarrying }) => __foldkitBrandViewResult((isCarryingOnly && !isCarrying
|
|
633
|
+
? Option.none()
|
|
634
|
+
: Option.some({ reelHook: model.id, subject, pointerId })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Pointer~3"),
|
|
635
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~86"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#pointerHoldOf");
|
|
636
|
+
const reelSubscriptions = Subscription.make()((entry) => (__foldkitBrandViewResult(({
|
|
637
|
+
pointer: entry({ maybeHold: Schema.Option(PointerHold) }, {
|
|
638
|
+
modelToDependencies: (model) => (__foldkitBrandViewResult(({ maybeHold: pointerHoldOf(model, false) }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#modelToDependencies")),
|
|
639
|
+
dependenciesToStream: ({ maybeHold }) => __foldkitBrandViewResult((Option.match(maybeHold, {
|
|
640
|
+
onNone: () => __foldkitBrandViewResult((Stream.empty), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~16"),
|
|
641
|
+
onSome: (hold) => __foldkitBrandViewResult((Stream.merge(pointerMessages(hold), markDragging)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~15"),
|
|
642
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#dependenciesToStream"),
|
|
643
|
+
}),
|
|
644
|
+
edge: entry({ maybeHold: Schema.Option(PointerHold) }, {
|
|
645
|
+
modelToDependencies: (model) => (__foldkitBrandViewResult(({ maybeHold: pointerHoldOf(model, true) }), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#modelToDependencies~2")),
|
|
646
|
+
dependenciesToStream: ({ maybeHold }) => __foldkitBrandViewResult((Option.match(maybeHold, { onNone: () => __foldkitBrandViewResult((Stream.empty), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~17"), onSome: edgeScroll })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#dependenciesToStream~2"),
|
|
647
|
+
}),
|
|
648
|
+
resize: entry({ maybeHold: Schema.Option(SplitterHold) }, {
|
|
649
|
+
modelToDependencies: (model) => (__foldkitBrandViewResult(({
|
|
650
|
+
maybeHold: Option.map(model.maybeResizing, ({ splitter, pointerId, pressX, pressY }) => (__foldkitBrandViewResult(({
|
|
651
|
+
reelHook: model.id,
|
|
652
|
+
splitter,
|
|
653
|
+
pointerId,
|
|
654
|
+
pressX,
|
|
655
|
+
pressY,
|
|
656
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~88"))),
|
|
657
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#modelToDependencies~3")),
|
|
658
|
+
dependenciesToStream: ({ maybeHold }) => __foldkitBrandViewResult((Option.match(maybeHold, {
|
|
659
|
+
onNone: () => __foldkitBrandViewResult((Stream.empty), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~18"),
|
|
660
|
+
onSome: (hold) => __foldkitBrandViewResult((Stream.merge(splitterMessages(hold), markDragging)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~16"),
|
|
661
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#dependenciesToStream~3"),
|
|
662
|
+
}),
|
|
663
|
+
escape: entry({ isHolding: Schema.Boolean }, {
|
|
664
|
+
modelToDependencies: (model) => (__foldkitBrandViewResult(({
|
|
665
|
+
isHolding: isHolding(model) || Option.isSome(model.maybeResizing),
|
|
666
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#modelToDependencies~4")),
|
|
667
|
+
dependenciesToStream: ({ isHolding: isHoldingNow }) => __foldkitBrandViewResult((isHoldingNow ? escapeKeys(Message.PressedEscape()) : Stream.empty), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#dependenciesToStream~4"),
|
|
668
|
+
}),
|
|
669
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~87")));
|
|
670
|
+
/** A held pane or column follows the pointer (the reel scrolling near its edges), a dragged
|
|
671
|
+
* splitter resizes, and Escape puts either back, before a dialog or the page sees it, from
|
|
672
|
+
* listeners that run only while something is held. Lift them into the application's
|
|
673
|
+
* Subscriptions, once per reel, behind a key prefix of the parent's: `subscriptions("tiles")`
|
|
674
|
+
* is keyed `tilesPointer`, `tilesEdge`, `tilesResize` and `tilesEscape`. */
|
|
675
|
+
export const subscriptions = (keyPrefix) => __foldkitBrandViewResult((prefixKeys(keyPrefix, reelSubscriptions)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#subscriptions");
|
|
676
|
+
// MOUNT
|
|
677
|
+
/** Sizes the copy that follows the pointer to what it lifts, and keeps the pointer where it
|
|
678
|
+
* pressed. Measures the source once, when the copy appears. */
|
|
679
|
+
export const SizeLiftedPane = Mount.define("SizeLiftedPane", {
|
|
680
|
+
args: { sourceSelector: Schema.String, pressX: Schema.Number, pressY: Schema.Number },
|
|
681
|
+
messages: [Message.CompletedSizeLiftedPane],
|
|
682
|
+
execute: ({ element, sourceSelector, pressX, pressY }) => __foldkitBrandViewResult((Effect.sync(() => {
|
|
683
|
+
measureLift(element, sourceSelector, pressX, pressY);
|
|
684
|
+
return __foldkitBrandViewResult((Message.CompletedSizeLiftedPane()), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~89");
|
|
685
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#execute~6"),
|
|
686
|
+
});
|
|
687
|
+
const helpId = (model) => __foldkitBrandViewResult((`${model.id}-grip-help`), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#helpId");
|
|
688
|
+
/** The share of the reel or the column a splitter's arrow key moves. */
|
|
689
|
+
const SPLITTER_STEP = 0.05;
|
|
690
|
+
const HELD_STEPS = {
|
|
691
|
+
ArrowUp: "Up",
|
|
692
|
+
ArrowDown: "Down",
|
|
693
|
+
ArrowLeft: "Left",
|
|
694
|
+
ArrowRight: "Right",
|
|
695
|
+
};
|
|
696
|
+
const isPlain = (modifiers) => __foldkitBrandViewResult((!modifiers.shiftKey && !modifiers.ctrlKey && !modifiers.altKey && !modifiers.metaKey), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#isPlain");
|
|
697
|
+
const isDropKey = (key) => __foldkitBrandViewResult((key === " " || key === "Enter"), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#isDropKey");
|
|
698
|
+
/** The anchor that pins a pane to its slot. Pane ids are the application's, so the name is
|
|
699
|
+
* the pane's place in the id order, which the slot and the pane read from one list. */
|
|
700
|
+
const anchorName = (index) => __foldkitBrandViewResult((`--reel-${index}`), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anchorName");
|
|
701
|
+
/** The panes in their layer's order: by id, which no move changes. */
|
|
702
|
+
const byId = Order.mapInput(Order.String, (pane) => __foldkitBrandViewResult((pane.id), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~90"));
|
|
703
|
+
/** Where a carried drop would land, marked: none where it would change nothing. */
|
|
704
|
+
const markOf = (model, layout) => __foldkitBrandViewResult((Option.flatMap(Option.filter(model.maybeHeld, isCarried), (held) => __foldkitBrandViewResult((Option.filter(held.maybeTarget, (target) => __foldkitBrandViewResult((Option.isSome(requestOf(layout, held.subject, target))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~92"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~91"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#markOf");
|
|
705
|
+
const heldPanesOf = (model, layout) => __foldkitBrandViewResult((new Set(Option.match(Option.filter(model.maybeHeld, isCarried), {
|
|
706
|
+
onNone: () => __foldkitBrandViewResult(([]), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~19"),
|
|
707
|
+
onSome: ({ subject }) => __foldkitBrandViewResult((Subject.match(subject, {
|
|
708
|
+
Pane: ({ paneId }) => __foldkitBrandViewResult(([paneId]), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Pane~3"),
|
|
709
|
+
Column: ({ columnId }) => __foldkitBrandViewResult((Option.match(columnOf(layout, columnId), {
|
|
710
|
+
onNone: () => __foldkitBrandViewResult(([]), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~20"),
|
|
711
|
+
onSome: (column) => __foldkitBrandViewResult((Array.map(column.panes, (pane) => __foldkitBrandViewResult((pane.id), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~93"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~18"),
|
|
712
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Column~3"),
|
|
713
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~17"),
|
|
714
|
+
}))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#heldPanesOf");
|
|
715
|
+
const gripView = (model, subject, label, h) => {
|
|
716
|
+
const isIdleNow = !isHolding(model) && Option.isNone(model.maybeResizing);
|
|
717
|
+
const maybeHeldHere = Option.filter(model.maybeHeld, (held) => __foldkitBrandViewResult((Equal.equals(held.subject, subject)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~94"));
|
|
718
|
+
const isHeld = Option.exists(maybeHeldHere, isCarried);
|
|
719
|
+
const isKeyboardHeld = Option.exists(maybeHeldHere, (held) => __foldkitBrandViewResult((held.by._tag === "Keyboard"), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~95"));
|
|
720
|
+
// the keyboard holds an item on its grip: the keys are the grip's own, and focus leaving the
|
|
721
|
+
// grip puts the item back, so a field reached by Tab types as it should
|
|
722
|
+
const onGripKey = h.OnKeyDownPreventDefault((key, modifiers) => {
|
|
723
|
+
if (!isPlain(modifiers)) {
|
|
724
|
+
return __foldkitBrandViewResult((Option.none()), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~96");
|
|
725
|
+
}
|
|
726
|
+
else if (isKeyboardHeld) {
|
|
727
|
+
return __foldkitBrandViewResult((isDropKey(key)
|
|
728
|
+
? Option.some(Message.DroppedHeld())
|
|
729
|
+
: Option.map(Option.fromNullishOr(HELD_STEPS[key]), (step) => __foldkitBrandViewResult((Message.SteppedHeld({ step })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~97"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~96");
|
|
730
|
+
}
|
|
731
|
+
else {
|
|
732
|
+
return __foldkitBrandViewResult((Option.liftPredicate(Message.PressedGripKey({ subject }), () => __foldkitBrandViewResult((isIdleNow && isDropKey(key)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~98"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~96");
|
|
733
|
+
}
|
|
734
|
+
});
|
|
735
|
+
const onGripPress = h.OnPointerDown((_pointerType, button, _screenX, _screenY, _time, clientX, clientY, pointerId) => __foldkitBrandViewResult((Option.liftPredicate(Message.PressedGrip({ subject, pointerId, clientX, clientY }), () => __foldkitBrandViewResult((isIdleNow && button === LEFT_BUTTON), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~100"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~99"));
|
|
736
|
+
return __foldkitBrandViewResult((IconButton.view({
|
|
737
|
+
glyph: "grip",
|
|
738
|
+
label,
|
|
739
|
+
isQuiet: true,
|
|
740
|
+
attributes: [
|
|
741
|
+
h.DataAttribute("reel-grip", subjectHook(model, subject)),
|
|
742
|
+
h.AriaRoleDescription("draggable"),
|
|
743
|
+
h.AriaDescribedBy(helpId(model)),
|
|
744
|
+
Button.pressedAttribute(isHeld, h),
|
|
745
|
+
onGripKey,
|
|
746
|
+
onGripPress,
|
|
747
|
+
...(isKeyboardHeld ? [h.OnBlur(Message.LeftGrip())] : []),
|
|
748
|
+
],
|
|
749
|
+
}, h)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#gripView");
|
|
750
|
+
};
|
|
751
|
+
/** A splitter's handlers: a pointer drags it, and its arrows (the side ones for a width, up
|
|
752
|
+
* and down for a height), unmodified, step it; a modified arrow is the application's. */
|
|
753
|
+
const splitterAttributes = (model, splitter, h) => {
|
|
754
|
+
const [less, more] = splitter._tag === "Width" ? ["ArrowLeft", "ArrowRight"] : ["ArrowUp", "ArrowDown"];
|
|
755
|
+
return __foldkitBrandViewResult(([
|
|
756
|
+
h.OnPointerDown((_pointerType, button, _screenX, _screenY, _time, clientX, clientY, pointerId) => __foldkitBrandViewResult((Option.liftPredicate(Message.PressedSplitter({ splitter, pointerId, clientX, clientY }), () => __foldkitBrandViewResult((button === LEFT_BUTTON && !isHolding(model) && Option.isNone(model.maybeResizing)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~102"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~101")),
|
|
757
|
+
h.OnKeyDownPreventDefault((key, modifiers) => __foldkitBrandViewResult((Option.liftPredicate(Message.PressedSplitterKey({
|
|
758
|
+
splitter,
|
|
759
|
+
share: key === more ? SPLITTER_STEP : -SPLITTER_STEP,
|
|
760
|
+
}), () => __foldkitBrandViewResult((isPlain(modifiers) && (key === less || key === more)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~104"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~103")),
|
|
761
|
+
]), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#splitterAttributes");
|
|
762
|
+
};
|
|
763
|
+
const dropClass = (info, column, paneId) => __foldkitBrandViewResult((Option.match(Option.flatMap(info.maybeMark, (mark) => {
|
|
764
|
+
if (mark._tag !== "Into" || mark.columnId !== column.id) {
|
|
765
|
+
return __foldkitBrandViewResult((Option.none()), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~105");
|
|
766
|
+
}
|
|
767
|
+
const others = Array.filter(column.panes, (pane) => __foldkitBrandViewResult((!info.heldPaneIds.has(pane.id)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~106"));
|
|
768
|
+
return __foldkitBrandViewResult((Option.orElse(Option.map(Option.filter(Array.get(others, mark.index), (pane) => __foldkitBrandViewResult((pane.id === paneId), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~107")), () => __foldkitBrandViewResult((" drop-before"), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~108")), () => __foldkitBrandViewResult((Option.map(Option.filter(Array.last(others), (pane) => __foldkitBrandViewResult((mark.index >= others.length && pane.id === paneId), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~110")), () => __foldkitBrandViewResult((" drop-after"), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~111"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~109"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~105");
|
|
769
|
+
}), { onNone: () => __foldkitBrandViewResult((""), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~21"), onSome: (mark) => __foldkitBrandViewResult((mark), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~19") })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#dropClass");
|
|
770
|
+
const isGapMarked = (info, maybeBeforeColumnId) => __foldkitBrandViewResult((Option.exists(info.maybeMark, (mark) => __foldkitBrandViewResult((mark._tag === "Gap" && Equal.equals(mark.maybeBeforeColumnId, maybeBeforeColumnId)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~112"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#isGapMarked");
|
|
771
|
+
const slotView = (info, anchors, column, pane, h) => __foldkitBrandViewResult((h.keyed("div")(pane.id, [
|
|
772
|
+
h.Class(`reel-slot${dropClass(info, column, pane.id)}`),
|
|
773
|
+
h.DataAttribute("reel-slot", pane.id),
|
|
774
|
+
h.Style({ "--reel-weight": `${pane.weight}`, "--reel-anchor": anchors.get(pane.id) ?? "none" }),
|
|
775
|
+
])), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#slotView");
|
|
776
|
+
const splitView = (model, above, share, h) => __foldkitBrandViewResult((h.keyed("div")(`split:${above.id}`, [
|
|
777
|
+
h.Class("reel-split"),
|
|
778
|
+
h.Role("separator"),
|
|
779
|
+
h.AriaOrientation("horizontal"),
|
|
780
|
+
h.AriaLabel(fill(COPY.heightLabel, { pane: above.label })),
|
|
781
|
+
h.AriaValuemin(0),
|
|
782
|
+
h.AriaValuemax(100),
|
|
783
|
+
h.AriaValuenow(Math.round(share * 100)),
|
|
784
|
+
h.Tabindex(0),
|
|
785
|
+
h.DataAttribute("reel-split", above.id),
|
|
786
|
+
...splitterAttributes(model, Splitter.Split({ abovePaneId: above.id }), h),
|
|
787
|
+
])), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#splitView");
|
|
788
|
+
const columnView = (info, anchors, column, index, h) => {
|
|
789
|
+
const { model, layout } = info;
|
|
790
|
+
const total = Number.sumAll(Array.map(column.panes, (pane) => __foldkitBrandViewResult((pane.weight), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~113")));
|
|
791
|
+
const stack = Array.flatMap(column.panes, (pane, row) => __foldkitBrandViewResult(([
|
|
792
|
+
...Array.fromOption(Option.map(Array.get(column.panes, row - 1), (above) => __foldkitBrandViewResult((splitView(model, above, total > 0 ? above.weight / total : 0, h)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~115"))),
|
|
793
|
+
slotView(info, anchors, column, pane, h),
|
|
794
|
+
]), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~114"));
|
|
795
|
+
const maybeNextId = Option.map(Array.get(layout, index + 1), ({ id }) => __foldkitBrandViewResult((id), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~116"));
|
|
796
|
+
return __foldkitBrandViewResult(([
|
|
797
|
+
h.keyed("div")(`column:${column.id}`, [
|
|
798
|
+
h.Class("reel-column"),
|
|
799
|
+
h.DataAttribute("reel-column", column.id),
|
|
800
|
+
h.DataAttribute("reel-hook", columnHook(model, column.id)),
|
|
801
|
+
h.Style({ "--reel-width": `${column.width}` }),
|
|
802
|
+
], [
|
|
803
|
+
h.div([h.Class("reel-column-head")], [
|
|
804
|
+
gripView(model, Subject.Column({ columnId: column.id }), fill(COPY.columnGrip, { column: index + 1 }), h),
|
|
805
|
+
h.span([h.Class("reel-width"), h.AriaHidden(true)], [widthMark(column.width)]),
|
|
806
|
+
]),
|
|
807
|
+
...stack,
|
|
808
|
+
]),
|
|
809
|
+
h.keyed("div")(`resize:${column.id}`, [
|
|
810
|
+
h.Class(`reel-gap reel-resize${isGapMarked(info, maybeNextId) ? " drop-here" : ""}`),
|
|
811
|
+
h.Role("separator"),
|
|
812
|
+
h.AriaOrientation("vertical"),
|
|
813
|
+
h.AriaLabel(fill(COPY.widthLabel, { column: index + 1 })),
|
|
814
|
+
h.AriaValuemin(0),
|
|
815
|
+
h.AriaValuemax(100),
|
|
816
|
+
h.AriaValuenow(Math.round(column.width * 100)),
|
|
817
|
+
h.AriaValuetext(widthWords(column.width)),
|
|
818
|
+
h.Tabindex(0),
|
|
819
|
+
h.DataAttribute("reel-resize", column.id),
|
|
820
|
+
...splitterAttributes(model, Splitter.Width({ columnId: column.id }), h),
|
|
821
|
+
]),
|
|
822
|
+
]), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#columnView");
|
|
823
|
+
};
|
|
824
|
+
const paneLayerView = (info, panes, anchors, h) => {
|
|
825
|
+
const { model } = info;
|
|
826
|
+
// NOTE: the panes keep one order in the page, by id, whatever the layout: a move changes
|
|
827
|
+
// only where each is anchored, so no pane's element is taken out and put back, which would
|
|
828
|
+
// drop focus, a terminal's scroll and whatever a Mount holds inside it.
|
|
829
|
+
return __foldkitBrandViewResult((h.div([h.Class("reel-panes")], Array.map(panes, (pane) => {
|
|
830
|
+
const isFocused = Option.contains(info.maybeFocusedId, pane.id);
|
|
831
|
+
const isHeld = info.heldPaneIds.has(pane.id);
|
|
832
|
+
return __foldkitBrandViewResult((h.keyed("div")(pane.id, [
|
|
833
|
+
h.Class(`reel-pane${isFocused ? " focused" : ""}${isHeld ? " drag-dim" : ""}`),
|
|
834
|
+
h.DataAttribute("reel-pane", paneHook(model, pane.id)),
|
|
835
|
+
h.Style({ "--reel-anchor": anchors.get(pane.id) ?? "none" }),
|
|
836
|
+
h.Tabindex(-1),
|
|
837
|
+
h.OnFocusEnter(Message.FocusedPane({ paneId: pane.id })),
|
|
838
|
+
], [
|
|
839
|
+
info.toPaneView(pane, {
|
|
840
|
+
grip: gripView(model, Subject.Pane({ paneId: pane.id }), fill(COPY.paneGrip, { pane: pane.label }), h),
|
|
841
|
+
id: `${model.id}-${pane.id}`,
|
|
842
|
+
}),
|
|
843
|
+
])), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~117");
|
|
844
|
+
}))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#paneLayerView");
|
|
845
|
+
};
|
|
846
|
+
/** The copy a pointer carries: the held panes' title bars, drawn by the reel from their
|
|
847
|
+
* labels, so whatever a pane holds (a terminal, a canvas) is never built twice. */
|
|
848
|
+
const liftedCopyView = (info, h) => {
|
|
849
|
+
const { model, layout } = info;
|
|
850
|
+
return __foldkitBrandViewResult((Array.fromOption(Option.flatMap(model.maybeHeld, (held) => __foldkitBrandViewResult((By.match(held.by, {
|
|
851
|
+
Keyboard: () => __foldkitBrandViewResult((Option.none()), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Keyboard~4"),
|
|
852
|
+
Pointer: ({ isCarrying, pressX, pressY, x, y }) => __foldkitBrandViewResult((Option.liftPredicate(h.div([
|
|
853
|
+
h.Class("reel-lift"),
|
|
854
|
+
h.Style({ transform: `translate3d(${x}px, ${y}px, 0)` }),
|
|
855
|
+
h.AriaHidden(true),
|
|
856
|
+
h.Inert(true),
|
|
857
|
+
h.OnMount(SizeLiftedPane({
|
|
858
|
+
sourceSelector: Subject.match(held.subject, {
|
|
859
|
+
Pane: () => __foldkitBrandViewResult((`[data-reel-pane="${CSS.escape(subjectHook(model, held.subject))}"]`), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Pane~4"),
|
|
860
|
+
Column: () => __foldkitBrandViewResult((`[data-reel-hook="${CSS.escape(subjectHook(model, held.subject))}"]`), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Column~4"),
|
|
861
|
+
}),
|
|
862
|
+
pressX,
|
|
863
|
+
pressY,
|
|
864
|
+
})),
|
|
865
|
+
], [
|
|
866
|
+
h.div([h.Class("reel-lifted")], Array.map(Array.filter(Array.flatMap(layout, (column) => __foldkitBrandViewResult((column.panes), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~119")), (pane) => __foldkitBrandViewResult((info.heldPaneIds.has(pane.id)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~120")), (pane) => __foldkitBrandViewResult((h.div([h.Class("panel window")], [
|
|
867
|
+
h.div([h.Class("panel-tb")], [
|
|
868
|
+
h.span([h.Class("panel-lead")], [
|
|
869
|
+
h.span([h.Class("iconbtn quiet")], [Glyph.view({ name: "grip" }, h)]),
|
|
870
|
+
]),
|
|
871
|
+
h.h2([], [pane.label]),
|
|
872
|
+
]),
|
|
873
|
+
])), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~121"))),
|
|
874
|
+
]), () => __foldkitBrandViewResult((isCarrying), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~122"))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#Pointer~4"),
|
|
875
|
+
})), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~118")))), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#liftedCopyView");
|
|
876
|
+
};
|
|
877
|
+
/** The layout as it prints, with a dragged splitter's resize shown before it is asked for. */
|
|
878
|
+
const previewed = (model, layout) => __foldkitBrandViewResult((Option.match(Option.flatMap(model.maybeResizing, ({ maybeResize }) => __foldkitBrandViewResult((maybeResize), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~123")), { onNone: () => __foldkitBrandViewResult((layout), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onNone~22"), onSome: (resize) => __foldkitBrandViewResult((apply(layout, resize)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#onSome~20") })), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#previewed");
|
|
879
|
+
/**
|
|
880
|
+
* A row of columns wider than the view when it must be, each a stack of panes, scrolled
|
|
881
|
+
* sideways, and down where a column is taller than the view: `div.reel` holding the scroller
|
|
882
|
+
* `div.reel-view`, whose `div.reel-track` lays out the columns (`div.reel-column`, each a head
|
|
883
|
+
* with its grip and width, then a slot per pane with a splitter between) with a splitter after
|
|
884
|
+
* each, and the panes themselves in `div.reel-panes`, each pinned to its slot by anchor
|
|
885
|
+
* positioning. The reel takes its height from whatever holds it. The layout is the parent's;
|
|
886
|
+
* each pane renders through `toPaneView`.
|
|
887
|
+
*
|
|
888
|
+
* A pane's grip, or a column's, lifts it under a pointer or the keyboard: Space or Enter picks
|
|
889
|
+
* it up, the arrows move it (left and right through the gaps and columns, up and down among a
|
|
890
|
+
* column's panes), Space drops it, and Escape or Tab puts it back. A drop reports what it asks
|
|
891
|
+
* of the layout as the OutMessage. Lift `subscriptions(keyPrefix)` into the application's, or
|
|
892
|
+
* nothing follows the pointer, and call `reconcile` whenever the layout changes.
|
|
893
|
+
*/
|
|
894
|
+
export const view = defineView((model, viewInputs, h) => {
|
|
895
|
+
const { label, toPaneView } = viewInputs;
|
|
896
|
+
const layout = previewed(model, viewInputs.layout);
|
|
897
|
+
const panes = Array.sort(Array.flatMap(layout, (column) => __foldkitBrandViewResult((column.panes), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~125")), byId);
|
|
898
|
+
const anchors = new Map(Array.map(panes, (pane, index) => __foldkitBrandViewResult(([pane.id, anchorName(index)]), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~126")));
|
|
899
|
+
const info = {
|
|
900
|
+
model,
|
|
901
|
+
layout,
|
|
902
|
+
toPaneView,
|
|
903
|
+
maybeFocusedId: focusedPaneId(model, layout),
|
|
904
|
+
maybeMark: markOf(model, layout),
|
|
905
|
+
heldPaneIds: heldPanesOf(model, layout),
|
|
906
|
+
};
|
|
907
|
+
return __foldkitBrandViewResult((h.div([h.Class("reel"), h.Role("group"), h.AriaLabel(label), h.DataAttribute("reel", model.id)], [
|
|
908
|
+
h.div([h.Class("reel-view")], [
|
|
909
|
+
h.div([h.Class("reel-track")], [
|
|
910
|
+
h.keyed("div")("gap:start", [
|
|
911
|
+
h.Class(`reel-gap${isGapMarked(info, Option.map(Array.head(layout), ({ id }) => __foldkitBrandViewResult((id), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~127")))
|
|
912
|
+
? " drop-here"
|
|
913
|
+
: ""}`),
|
|
914
|
+
]),
|
|
915
|
+
...Array.flatMap(layout, (column, index) => __foldkitBrandViewResult((columnView(info, anchors, column, index, h)), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~128")),
|
|
916
|
+
paneLayerView(info, panes, anchors, h),
|
|
917
|
+
]),
|
|
918
|
+
]),
|
|
919
|
+
h.p([h.Id(helpId(model)), h.Class("sr-only")], [COPY.gripHelp]),
|
|
920
|
+
...liftedCopyView(info, h),
|
|
921
|
+
])), "@gjermundgaraba-designs/pixel-paper/src/reel/reel.js#anonymous~124");
|
|
922
|
+
});
|