@gjermundgaraba-designs/pixel-paper 0.23.0 → 0.25.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 +11 -8
- package/dist/src/iconButton/iconButton.d.ts +6 -1
- package/dist/src/iconButton/iconButton.d.ts.map +1 -1
- package/dist/src/iconButton/iconButton.js +7 -2
- package/dist/src/panel/panel.d.ts +3 -0
- package/dist/src/panel/panel.d.ts.map +1 -1
- package/dist/src/panel/panel.js +2 -1
- package/dist/src/rail/index.d.ts +1 -1
- package/dist/src/rail/index.d.ts.map +1 -1
- package/dist/src/rail/index.js +1 -1
- package/dist/src/rail/rail.d.ts +78 -17
- package/dist/src/rail/rail.d.ts.map +1 -1
- package/dist/src/rail/rail.js +98 -41
- package/dist/src/reel/index.d.ts +1 -1
- package/dist/src/reel/index.d.ts.map +1 -1
- package/dist/src/reel/index.js +1 -1
- package/dist/src/reel/reel.d.ts +85 -7
- package/dist/src/reel/reel.d.ts.map +1 -1
- package/dist/src/reel/reel.js +232 -115
- package/dist/src/tips/tips.d.ts +30 -1
- package/dist/src/tips/tips.d.ts.map +1 -1
- package/dist/src/tips/tips.js +53 -31
- package/package.json +1 -1
- package/src/iconButton/iconButton.ts +19 -2
- package/src/panel/panel.ts +5 -0
- package/src/pixel-paper.css +167 -4
- package/src/rail/index.ts +2 -0
- package/src/rail/rail.ts +119 -41
- package/src/reel/index.ts +2 -0
- package/src/reel/reel.ts +221 -31
- package/src/tips/tips.ts +71 -35
- package/src/tokens.css +1 -0
package/dist/src/tips/tips.d.ts
CHANGED
|
@@ -12,15 +12,18 @@ export declare const TipState: import("foldkit/schema").TaggedUnion<{
|
|
|
12
12
|
readonly Cold: {};
|
|
13
13
|
readonly Waiting: {
|
|
14
14
|
text: Schema.String;
|
|
15
|
+
maybeKey: Schema.Option<Schema.String>;
|
|
15
16
|
side: Schema.Literals<readonly ["Top", "Right"]>;
|
|
16
17
|
};
|
|
17
18
|
readonly Shown: {
|
|
18
19
|
text: Schema.String;
|
|
20
|
+
maybeKey: Schema.Option<Schema.String>;
|
|
19
21
|
side: Schema.Literals<readonly ["Top", "Right"]>;
|
|
20
22
|
trigger: Schema.Literals<readonly ["Pointer", "Focus"]>;
|
|
21
23
|
};
|
|
22
24
|
readonly Leaving: {
|
|
23
25
|
text: Schema.String;
|
|
26
|
+
maybeKey: Schema.Option<Schema.String>;
|
|
24
27
|
side: Schema.Literals<readonly ["Top", "Right"]>;
|
|
25
28
|
trigger: Schema.Literals<readonly ["Pointer", "Focus"]>;
|
|
26
29
|
};
|
|
@@ -36,15 +39,18 @@ export declare const Model: Schema.Struct<{
|
|
|
36
39
|
readonly Cold: {};
|
|
37
40
|
readonly Waiting: {
|
|
38
41
|
text: Schema.String;
|
|
42
|
+
maybeKey: Schema.Option<Schema.String>;
|
|
39
43
|
side: Schema.Literals<readonly ["Top", "Right"]>;
|
|
40
44
|
};
|
|
41
45
|
readonly Shown: {
|
|
42
46
|
text: Schema.String;
|
|
47
|
+
maybeKey: Schema.Option<Schema.String>;
|
|
43
48
|
side: Schema.Literals<readonly ["Top", "Right"]>;
|
|
44
49
|
trigger: Schema.Literals<readonly ["Pointer", "Focus"]>;
|
|
45
50
|
};
|
|
46
51
|
readonly Leaving: {
|
|
47
52
|
text: Schema.String;
|
|
53
|
+
maybeKey: Schema.Option<Schema.String>;
|
|
48
54
|
side: Schema.Literals<readonly ["Top", "Right"]>;
|
|
49
55
|
trigger: Schema.Literals<readonly ["Pointer", "Focus"]>;
|
|
50
56
|
};
|
|
@@ -56,12 +62,14 @@ export type Model = typeof Model.Type;
|
|
|
56
62
|
export declare const Message: import("foldkit/message").MessageUnion<{
|
|
57
63
|
readonly EnteredTipTarget: {
|
|
58
64
|
text: Schema.String;
|
|
65
|
+
maybeKey: Schema.Option<Schema.String>;
|
|
59
66
|
side: Schema.Literals<readonly ["Top", "Right"]>;
|
|
60
67
|
};
|
|
61
68
|
readonly LeftTipTarget: {};
|
|
62
69
|
readonly EnteredTip: {};
|
|
63
70
|
readonly FocusedTipTarget: {
|
|
64
71
|
text: Schema.String;
|
|
72
|
+
maybeKey: Schema.Option<Schema.String>;
|
|
65
73
|
side: Schema.Literals<readonly ["Top", "Right"]>;
|
|
66
74
|
};
|
|
67
75
|
readonly BlurredTipTarget: {};
|
|
@@ -136,16 +144,19 @@ export declare const update: (model: Model, message: Message) => Readonly<{
|
|
|
136
144
|
} | {
|
|
137
145
|
readonly _tag: "Leaving";
|
|
138
146
|
readonly text: string;
|
|
147
|
+
readonly maybeKey: Option.Option<string>;
|
|
139
148
|
readonly side: "Right" | "Top";
|
|
140
149
|
readonly trigger: "Focus" | "Pointer";
|
|
141
150
|
} | {
|
|
142
151
|
readonly _tag: "Shown";
|
|
143
152
|
readonly text: string;
|
|
153
|
+
readonly maybeKey: Option.Option<string>;
|
|
144
154
|
readonly side: "Right" | "Top";
|
|
145
155
|
readonly trigger: "Focus" | "Pointer";
|
|
146
156
|
} | {
|
|
147
157
|
readonly _tag: "Waiting";
|
|
148
158
|
readonly text: string;
|
|
159
|
+
readonly maybeKey: Option.Option<string>;
|
|
149
160
|
readonly side: "Right" | "Top";
|
|
150
161
|
} | {
|
|
151
162
|
readonly _tag: "Warm";
|
|
@@ -171,10 +182,12 @@ export declare const update: (model: Model, message: Message) => Readonly<{
|
|
|
171
182
|
} | {
|
|
172
183
|
readonly _tag: "EnteredTipTarget";
|
|
173
184
|
readonly text: string;
|
|
185
|
+
readonly maybeKey: Option.Option<string>;
|
|
174
186
|
readonly side: "Right" | "Top";
|
|
175
187
|
} | {
|
|
176
188
|
readonly _tag: "FocusedTipTarget";
|
|
177
189
|
readonly text: string;
|
|
190
|
+
readonly maybeKey: Option.Option<string>;
|
|
178
191
|
readonly side: "Right" | "Top";
|
|
179
192
|
} | {
|
|
180
193
|
readonly _tag: "LeftTipTarget";
|
|
@@ -210,16 +223,19 @@ export declare const subscriptions: <Prefix extends string>(keyPrefix: Prefix) =
|
|
|
210
223
|
} | {
|
|
211
224
|
readonly _tag: "Leaving";
|
|
212
225
|
readonly text: string;
|
|
226
|
+
readonly maybeKey: Option.Option<string>;
|
|
213
227
|
readonly side: "Right" | "Top";
|
|
214
228
|
readonly trigger: "Focus" | "Pointer";
|
|
215
229
|
} | {
|
|
216
230
|
readonly _tag: "Shown";
|
|
217
231
|
readonly text: string;
|
|
232
|
+
readonly maybeKey: Option.Option<string>;
|
|
218
233
|
readonly side: "Right" | "Top";
|
|
219
234
|
readonly trigger: "Focus" | "Pointer";
|
|
220
235
|
} | {
|
|
221
236
|
readonly _tag: "Waiting";
|
|
222
237
|
readonly text: string;
|
|
238
|
+
readonly maybeKey: Option.Option<string>;
|
|
223
239
|
readonly side: "Right" | "Top";
|
|
224
240
|
} | {
|
|
225
241
|
readonly _tag: "Warm";
|
|
@@ -244,10 +260,12 @@ export declare const subscriptions: <Prefix extends string>(keyPrefix: Prefix) =
|
|
|
244
260
|
} | {
|
|
245
261
|
readonly _tag: "EnteredTipTarget";
|
|
246
262
|
readonly text: string;
|
|
263
|
+
readonly maybeKey: Option.Option<string>;
|
|
247
264
|
readonly side: "Right" | "Top";
|
|
248
265
|
} | {
|
|
249
266
|
readonly _tag: "FocusedTipTarget";
|
|
250
267
|
readonly text: string;
|
|
268
|
+
readonly maybeKey: Option.Option<string>;
|
|
251
269
|
readonly side: "Right" | "Top";
|
|
252
270
|
} | {
|
|
253
271
|
readonly _tag: "LeftTipTarget";
|
|
@@ -268,16 +286,19 @@ export declare const subscriptions: <Prefix extends string>(keyPrefix: Prefix) =
|
|
|
268
286
|
} | {
|
|
269
287
|
readonly _tag: "Leaving";
|
|
270
288
|
readonly text: string;
|
|
289
|
+
readonly maybeKey: Option.Option<string>;
|
|
271
290
|
readonly side: "Right" | "Top";
|
|
272
291
|
readonly trigger: "Focus" | "Pointer";
|
|
273
292
|
} | {
|
|
274
293
|
readonly _tag: "Shown";
|
|
275
294
|
readonly text: string;
|
|
295
|
+
readonly maybeKey: Option.Option<string>;
|
|
276
296
|
readonly side: "Right" | "Top";
|
|
277
297
|
readonly trigger: "Focus" | "Pointer";
|
|
278
298
|
} | {
|
|
279
299
|
readonly _tag: "Waiting";
|
|
280
300
|
readonly text: string;
|
|
301
|
+
readonly maybeKey: Option.Option<string>;
|
|
281
302
|
readonly side: "Right" | "Top";
|
|
282
303
|
} | {
|
|
283
304
|
readonly _tag: "Warm";
|
|
@@ -302,10 +323,12 @@ export declare const subscriptions: <Prefix extends string>(keyPrefix: Prefix) =
|
|
|
302
323
|
} | {
|
|
303
324
|
readonly _tag: "EnteredTipTarget";
|
|
304
325
|
readonly text: string;
|
|
326
|
+
readonly maybeKey: Option.Option<string>;
|
|
305
327
|
readonly side: "Right" | "Top";
|
|
306
328
|
} | {
|
|
307
329
|
readonly _tag: "FocusedTipTarget";
|
|
308
330
|
readonly text: string;
|
|
331
|
+
readonly maybeKey: Option.Option<string>;
|
|
309
332
|
readonly side: "Right" | "Top";
|
|
310
333
|
} | {
|
|
311
334
|
readonly _tag: "LeftTipTarget";
|
|
@@ -321,7 +344,8 @@ export declare const subscriptions: <Prefix extends string>(keyPrefix: Prefix) =
|
|
|
321
344
|
} extends infer T ? { readonly [Key in keyof T as `${Prefix}${Capitalize<Key>}`]: T[Key]; } : never;
|
|
322
345
|
/**
|
|
323
346
|
* The page's one tip: `div.tip[popover="manual"][aria-hidden="true"]`, which shows the words
|
|
324
|
-
* of any control carrying `data-tip` (IconButton, the glyph switch, a board's grip)
|
|
347
|
+
* of any control carrying `data-tip` (IconButton, the glyph switch, a board's grip), then the
|
|
348
|
+
* key in its `data-tip-key` where it has one (an IconButton's `keyHint`). Render it
|
|
325
349
|
* once, beside the Announcer, and lift `subscriptions(keyPrefix)`. It opens on a resting
|
|
326
350
|
* pointer after a moment (at once while another has just closed), never on touch, and on
|
|
327
351
|
* keyboard focus; it can be hovered; leaving, blur, a press or any key closes it, and Escape
|
|
@@ -340,16 +364,19 @@ export declare const view: import("foldkit/submodel").View<{
|
|
|
340
364
|
} | {
|
|
341
365
|
readonly _tag: "Leaving";
|
|
342
366
|
readonly text: string;
|
|
367
|
+
readonly maybeKey: Option.Option<string>;
|
|
343
368
|
readonly side: "Right" | "Top";
|
|
344
369
|
readonly trigger: "Focus" | "Pointer";
|
|
345
370
|
} | {
|
|
346
371
|
readonly _tag: "Shown";
|
|
347
372
|
readonly text: string;
|
|
373
|
+
readonly maybeKey: Option.Option<string>;
|
|
348
374
|
readonly side: "Right" | "Top";
|
|
349
375
|
readonly trigger: "Focus" | "Pointer";
|
|
350
376
|
} | {
|
|
351
377
|
readonly _tag: "Waiting";
|
|
352
378
|
readonly text: string;
|
|
379
|
+
readonly maybeKey: Option.Option<string>;
|
|
353
380
|
readonly side: "Right" | "Top";
|
|
354
381
|
} | {
|
|
355
382
|
readonly _tag: "Warm";
|
|
@@ -374,10 +401,12 @@ export declare const view: import("foldkit/submodel").View<{
|
|
|
374
401
|
} | {
|
|
375
402
|
readonly _tag: "EnteredTipTarget";
|
|
376
403
|
readonly text: string;
|
|
404
|
+
readonly maybeKey: Option.Option<string>;
|
|
377
405
|
readonly side: "Right" | "Top";
|
|
378
406
|
} | {
|
|
379
407
|
readonly _tag: "FocusedTipTarget";
|
|
380
408
|
readonly text: string;
|
|
409
|
+
readonly maybeKey: Option.Option<string>;
|
|
381
410
|
readonly side: "Right" | "Top";
|
|
382
411
|
} | {
|
|
383
412
|
readonly _tag: "LeftTipTarget";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tips.d.ts","sourceRoot":"","sources":["../../../src/tips/tips.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"tips.d.ts","sourceRoot":"","sources":["../../../src/tips/tips.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,MAAM,EAIN,MAAM,EACN,MAAM,EAGP,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAC;AAQ3C,OAAO,KAAK,YAAY,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,KAAK,MAAM,MAAM,gBAAgB,CAAC;AAW9C,iEAAiE;AACjE,eAAO,MAAM,OAAO,gDAAwC,CAAC;AAC7D,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAC;AAQ1C;;+FAE+F;AAC/F,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;EAMnB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAC;AAE5C;sDACsD;AACtD,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;EAIhB,CAAC;AACH,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAC;AAItC,uDAAuD;AACvD,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;QAQY,OAAO;;;QACR,OAAO;;;QACN,OAAO;;;;EAGrC,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAC;AAI1C,2FAA2F;AAC3F,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAElD,yCAAyC;AACzC,eAAO,MAAM,IAAI,WAAY,UAAU,KAAG,KAIxC,CAAC;AAIH,oDAAoD;AACpD,eAAO,MAAM,EAAE,UAAW,KAAK,KAAG,MAAkB,CAAC;AA8DrD;;;0CAG0C;AAC1C,eAAO,MAAM,OAAO;;;;;;iBAmBlB,CAAC;AAEH,sBAAsB;AACtB,eAAO,MAAM,OAAO;;;;iBAQlB,CAAC;AAEH,mCAAmC;AACnC,eAAO,MAAM,iBAAiB;;;;;iBAK5B,CAAC;AAEH,iDAAiD;AACjD,eAAO,MAAM,gBAAgB;;;;;iBAK3B,CAAC;AAEH,+EAA+E;AAC/E,eAAO,MAAM,iBAAiB;;;;;iBAK5B,CAAC;AAyEH,6EAA6E;AAC7E,eAAO,MAAM,MAAM,UAAW,KAAK,WAAW,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmDjD,CAAC;AAIL,KAAK,aAAa,GACd,OAAO,OAAO,CAAC,gBAAgB,CAAC,IAAI,GACpC,OAAO,OAAO,CAAC,aAAa,CAAC,IAAI,GACjC,OAAO,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;AA0BnC;gEACgE;AAChE,eAAO,MAAM,kBAAkB,UACtB,MAAM,SACN,YAAY,KAClB,MAAM,CAAC,MAAM,CAAC,aAAa,CAkB7B,CAAC;AAUF;kCACkC;AAClC,eAAO,MAAM,eAAe,UAAW,UAAU,KAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAQtE,CAAC;AAEJ;;;0CAG0C;AAC1C,eAAO,MAAM,UAAU,UAAW,aAAa,WAAW,OAAO,KAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAUxF,CAAC;AAoEF;;;8BAG8B;AAC9B,eAAO,MAAM,aAAa,GAAI,MAAM,SAAS,MAAM,aAAa,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mGAC7B,CAAC;AAW1C;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAqBf,CAAC"}
|
package/dist/src/tips/tips.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { brandViewResult as __foldkitBrandViewResult } from 'foldkit/brand'
|
|
2
|
-
import { Array, Duration, Effect, Match, Number, Option, Schema, Stream, pipe } from "effect";
|
|
2
|
+
import { Array, Duration, Effect, Equal, Match, Number, Option, Schema, Stream, pipe, } 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";
|
|
@@ -15,7 +15,9 @@ import { prefixKeys } from "../subscription/prefixKeys.js";
|
|
|
15
15
|
const Side = Schema.Literals(["Top", "Right"]);
|
|
16
16
|
/** What brought the tip: a resting pointer or keyboard focus. */
|
|
17
17
|
export const Trigger = Schema.Literals(["Pointer", "Focus"]);
|
|
18
|
-
|
|
18
|
+
/** What a tip says: its control's name, and the key that does the same where the control
|
|
19
|
+
* names one (`data-tip-key`). */
|
|
20
|
+
const Words = { text: Schema.String, maybeKey: Schema.Option(Schema.String), side: Side };
|
|
19
21
|
const ShownWords = { ...Words, trigger: Trigger };
|
|
20
22
|
/** Where the page's tip is. `Cold`: none lately. `Waiting`: a pointer rests on a control, for
|
|
21
23
|
* a moment first. `Shown`. `Leaving`: the pointer left, with a moment to cross onto the tip.
|
|
@@ -37,10 +39,10 @@ export const Model = Schema.Struct({
|
|
|
37
39
|
// MESSAGE
|
|
38
40
|
/** Union of all Messages the tip layer can produce. */
|
|
39
41
|
export const Message = defineMessageUnion({
|
|
40
|
-
EnteredTipTarget:
|
|
42
|
+
EnteredTipTarget: Words,
|
|
41
43
|
LeftTipTarget: {},
|
|
42
44
|
EnteredTip: {},
|
|
43
|
-
FocusedTipTarget:
|
|
45
|
+
FocusedTipTarget: Words,
|
|
44
46
|
BlurredTipTarget: {},
|
|
45
47
|
PressedPointer: {},
|
|
46
48
|
PressedKey: {},
|
|
@@ -70,6 +72,8 @@ const GRACE = Duration.millis(120);
|
|
|
70
72
|
const WARMTH = Duration.millis(400);
|
|
71
73
|
/** The attribute that holds a control's tip: its accessible name. */
|
|
72
74
|
const TIP_ATTRIBUTE = "data-tip";
|
|
75
|
+
/** The attribute that holds the key a control's tip prints after its name. */
|
|
76
|
+
const TIP_KEY_ATTRIBUTE = "data-tip-key";
|
|
73
77
|
const TIP_SELECTOR = `[${TIP_ATTRIBUTE}]`;
|
|
74
78
|
const hasText = (element, text) => __foldkitBrandViewResult((element.isConnected && element.getAttribute(TIP_ATTRIBUTE) === text), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#hasText");
|
|
75
79
|
/** The control a tip belongs to, found when it opens: the innermost hovered element with
|
|
@@ -117,9 +121,10 @@ export const WaitBeforeCooling = Command.define("WaitBeforeCooling", {
|
|
|
117
121
|
messages: [Message.CompletedWaitBeforeCooling],
|
|
118
122
|
execute: ({ version }) => __foldkitBrandViewResult((Effect.sleep(WARMTH).pipe(Effect.as(Message.CompletedWaitBeforeCooling({ version })))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#execute~5"),
|
|
119
123
|
});
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
124
|
+
const wordsOf = ({ text, maybeKey, side }) => (__foldkitBrandViewResult(({ text, maybeKey, side }), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#wordsOf"));
|
|
125
|
+
const show = (model, words, trigger) => (__foldkitBrandViewResult(({
|
|
126
|
+
model: modifyFields(model, { state: () => __foldkitBrandViewResult((TipState.Shown({ ...wordsOf(words), trigger })), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#state") }),
|
|
127
|
+
commands: [ShowTip({ tipId: model.id, text: words.text, trigger })],
|
|
123
128
|
}), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#show"));
|
|
124
129
|
const hide = (model) => {
|
|
125
130
|
const nextVersion = Number.increment(model.version);
|
|
@@ -128,12 +133,12 @@ const hide = (model) => {
|
|
|
128
133
|
commands: [HideTip({ tipId: model.id }), WaitBeforeCooling({ version: nextVersion })],
|
|
129
134
|
}), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#hide");
|
|
130
135
|
};
|
|
131
|
-
const wait = (model,
|
|
136
|
+
const wait = (model, words) => {
|
|
132
137
|
const nextVersion = Number.increment(model.version);
|
|
133
138
|
return __foldkitBrandViewResult(({
|
|
134
139
|
model: modifyFields(model, {
|
|
135
140
|
version: () => __foldkitBrandViewResult((nextVersion), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#version~2"),
|
|
136
|
-
state: () => __foldkitBrandViewResult((TipState.Waiting(
|
|
141
|
+
state: () => __foldkitBrandViewResult((TipState.Waiting(wordsOf(words))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#state~3"),
|
|
137
142
|
}),
|
|
138
143
|
commands: [WaitBeforeShowing({ version: nextVersion })],
|
|
139
144
|
}), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#wait");
|
|
@@ -143,7 +148,7 @@ const leave = (model, shown) => {
|
|
|
143
148
|
return __foldkitBrandViewResult(({
|
|
144
149
|
model: modifyFields(model, {
|
|
145
150
|
version: () => __foldkitBrandViewResult((nextVersion), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#version~3"),
|
|
146
|
-
state: () => __foldkitBrandViewResult((TipState.Leaving({
|
|
151
|
+
state: () => __foldkitBrandViewResult((TipState.Leaving({ ...wordsOf(shown), trigger: shown.trigger })), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#state~4"),
|
|
147
152
|
}),
|
|
148
153
|
commands: [WaitBeforeHiding({ version: nextVersion })],
|
|
149
154
|
}), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#leave");
|
|
@@ -159,47 +164,55 @@ const dismiss = (model) => __foldkitBrandViewResult((TipState.match(model.state,
|
|
|
159
164
|
Leaving: () => __foldkitBrandViewResult((hide(model)), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#Leaving"),
|
|
160
165
|
Warm: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#Warm")),
|
|
161
166
|
})), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#dismiss");
|
|
162
|
-
const entered = (model,
|
|
163
|
-
Cold: () => __foldkitBrandViewResult((wait(model,
|
|
164
|
-
Waiting: (waiting) => (__foldkitBrandViewResult((waiting.text === text ? { model } : wait(model,
|
|
165
|
-
Shown: (shown) => (__foldkitBrandViewResult((shown.text === text ? { model } : show(model,
|
|
166
|
-
Leaving: (leaving) => __foldkitBrandViewResult((leaving.text === text
|
|
167
|
+
const entered = (model, words) => __foldkitBrandViewResult((TipState.match(model.state, {
|
|
168
|
+
Cold: () => __foldkitBrandViewResult((wait(model, words)), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#Cold~2"),
|
|
169
|
+
Waiting: (waiting) => (__foldkitBrandViewResult((waiting.text === words.text ? { model } : wait(model, words)), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#Waiting~2")),
|
|
170
|
+
Shown: (shown) => (__foldkitBrandViewResult((shown.text === words.text ? { model } : show(model, words, "Pointer")), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#Shown~2")),
|
|
171
|
+
Leaving: (leaving) => __foldkitBrandViewResult((leaving.text === words.text
|
|
167
172
|
? {
|
|
168
173
|
model: modifyFields(model, {
|
|
169
|
-
state: () => __foldkitBrandViewResult((TipState.Shown({
|
|
174
|
+
state: () => __foldkitBrandViewResult((TipState.Shown({ ...wordsOf(words), trigger: leaving.trigger })), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#state~6"),
|
|
170
175
|
}),
|
|
171
176
|
}
|
|
172
|
-
: show(model,
|
|
173
|
-
Warm: () => __foldkitBrandViewResult((show(model,
|
|
177
|
+
: show(model, words, "Pointer")), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#Leaving~2"),
|
|
178
|
+
Warm: () => __foldkitBrandViewResult((show(model, words, "Pointer")), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#Warm~2"),
|
|
174
179
|
})), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#entered");
|
|
175
180
|
/** Processes a tip layer Message and returns the next Model and Commands. */
|
|
176
181
|
export const update = (model, message) => __foldkitBrandViewResult((Message.match(message, {
|
|
177
|
-
EnteredTipTarget: (
|
|
182
|
+
EnteredTipTarget: (words) => __foldkitBrandViewResult((entered(model, wordsOf(words))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#EnteredTipTarget"),
|
|
178
183
|
LeftTipTarget: () => __foldkitBrandViewResult((TipState.matchOrElse(model.state, {
|
|
179
184
|
Waiting: () => __foldkitBrandViewResult((cool(model)), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#Waiting~3"),
|
|
180
185
|
Shown: (shown) => (__foldkitBrandViewResult((shown.trigger === "Pointer" ? leave(model, shown) : { model }), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#Shown~3")),
|
|
181
186
|
}, () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~11")))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#LeftTipTarget"),
|
|
182
187
|
EnteredTip: () => __foldkitBrandViewResult((TipState.matchOrElse(model.state, {
|
|
183
|
-
Leaving: (
|
|
184
|
-
model: modifyFields(model, {
|
|
188
|
+
Leaving: (leaving) => (__foldkitBrandViewResult(({
|
|
189
|
+
model: modifyFields(model, {
|
|
190
|
+
state: () => __foldkitBrandViewResult((TipState.Shown({ ...wordsOf(leaving), trigger: leaving.trigger })), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#state~7"),
|
|
191
|
+
}),
|
|
185
192
|
}), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#Leaving~3")),
|
|
186
193
|
}, () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~12")))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#EnteredTip"),
|
|
187
|
-
FocusedTipTarget: (
|
|
194
|
+
FocusedTipTarget: (words) => __foldkitBrandViewResult((show(model, wordsOf(words), "Focus")), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#FocusedTipTarget"),
|
|
188
195
|
BlurredTipTarget: () => __foldkitBrandViewResult((dismiss(model)), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#BlurredTipTarget"),
|
|
189
196
|
PressedPointer: () => __foldkitBrandViewResult((dismiss(model)), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#PressedPointer"),
|
|
190
197
|
PressedKey: () => __foldkitBrandViewResult((dismiss(model)), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#PressedKey"),
|
|
191
198
|
CompletedWaitBeforeShowing: ({ version }) => __foldkitBrandViewResult((TipState.matchOrElse(model.state, {
|
|
192
|
-
Waiting: (
|
|
199
|
+
Waiting: (waiting) => __foldkitBrandViewResult((model.version === version ? show(model, wordsOf(waiting), "Pointer") : { model }), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#Waiting~4"),
|
|
193
200
|
}, () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~13")))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#CompletedWaitBeforeShowing"),
|
|
194
201
|
CompletedWaitBeforeHiding: ({ version }) => __foldkitBrandViewResult((TipState.matchOrElse(model.state, { Leaving: () => (__foldkitBrandViewResult((model.version === version ? hide(model) : { model }), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#Leaving~4")) }, () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~14")))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#CompletedWaitBeforeHiding"),
|
|
195
202
|
CompletedWaitBeforeCooling: ({ version }) => __foldkitBrandViewResult((TipState.matchOrElse(model.state, { Warm: () => (__foldkitBrandViewResult((model.version === version ? cool(model) : { model }), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#Warm~3")) }, () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~15")))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#CompletedWaitBeforeCooling"),
|
|
196
203
|
CompletedShowTip: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#CompletedShowTip")),
|
|
197
204
|
CompletedHideTip: () => (__foldkitBrandViewResult(({ model }), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#CompletedHideTip")),
|
|
198
205
|
})), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#update");
|
|
199
|
-
|
|
206
|
+
/** A control in a vertical strip of tools, or set in vertical writing (a folded rail's title
|
|
207
|
+
* bar), takes its tip at its side, where the tip would cover the next tool or the top bar. */
|
|
208
|
+
const sideOf = (element) => __foldkitBrandViewResult((element.closest('[aria-orientation="vertical"]') === null &&
|
|
209
|
+
!getComputedStyle(element).writingMode.startsWith("vertical")
|
|
210
|
+
? "Top"
|
|
211
|
+
: "Right"), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#sideOf");
|
|
200
212
|
const tipTargetOf = (target) => __foldkitBrandViewResult((pipe(Option.liftPredicate(target, (node) => __foldkitBrandViewResult((node instanceof Element), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~16")), Option.flatMap((element) => __foldkitBrandViewResult((Option.fromNullishOr(element.closest(TIP_SELECTOR))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~17")), Option.flatMap((element) => __foldkitBrandViewResult((Option.map(Option.fromNullishOr(element.getAttribute(TIP_ATTRIBUTE)), (text) => (__foldkitBrandViewResult(({
|
|
201
213
|
element,
|
|
202
214
|
text,
|
|
215
|
+
maybeKey: Option.fromNullishOr(element.getAttribute(TIP_KEY_ATTRIBUTE)),
|
|
203
216
|
side: sideOf(element),
|
|
204
217
|
}), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~19")))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~18")))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#tipTargetOf");
|
|
205
218
|
/** What a pointer arriving over `target` means for the tip: over a control with a tip, over
|
|
@@ -214,12 +227,12 @@ export const pointerOverMessage = (tipId, event) => {
|
|
|
214
227
|
}
|
|
215
228
|
return __foldkitBrandViewResult((Option.some(Option.match(tipTargetOf(event.target), {
|
|
216
229
|
onNone: () => __foldkitBrandViewResult((Message.LeftTipTarget()), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#onNone"),
|
|
217
|
-
onSome: (
|
|
230
|
+
onSome: (target) => __foldkitBrandViewResult((Message.EnteredTipTarget(wordsOf(target))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#onSome"),
|
|
218
231
|
}))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#pointerOverMessage");
|
|
219
232
|
};
|
|
220
233
|
/** What focus arriving on `target` means for the tip: keyboard focus (`:focus-visible`) on a
|
|
221
234
|
* control with a tip shows it; any other focus says nothing. */
|
|
222
|
-
const focusInMessage = (event) => __foldkitBrandViewResult((Option.map(Option.filter(tipTargetOf(event.target), ({ element }) => __foldkitBrandViewResult((element.matches(":focus-visible")), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~20")), (
|
|
235
|
+
const focusInMessage = (event) => __foldkitBrandViewResult((Option.map(Option.filter(tipTargetOf(event.target), ({ element }) => __foldkitBrandViewResult((element.matches(":focus-visible")), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~20")), (target) => __foldkitBrandViewResult((Message.FocusedTipTarget(wordsOf(target))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~21"))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#focusInMessage");
|
|
223
236
|
/** Focus leaving a control with a tip, not into a part of itself, closes the tip (and
|
|
224
237
|
* cancels one still waiting). */
|
|
225
238
|
export const focusOutMessage = (event) => __foldkitBrandViewResult((Option.map(Option.filter(tipTargetOf(event.target), ({ element }) => __foldkitBrandViewResult((!(event.relatedTarget instanceof Node && element.contains(event.relatedTarget))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~22")), () => __foldkitBrandViewResult((Message.BlurredTipTarget()), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~23"))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#focusOutMessage");
|
|
@@ -244,7 +257,9 @@ const pointerOverChanges = (tipId) => __foldkitBrandViewResult((Dom.streamFromEv
|
|
|
244
257
|
}).pipe(Stream.changesWith((previous, next) => __foldkitBrandViewResult((previous._tag === next._tag && sameWords(previous, next)), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~24")))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#pointerOverChanges");
|
|
245
258
|
const sameWords = (previous, next) => __foldkitBrandViewResult((previous._tag !== "EnteredTipTarget" ||
|
|
246
259
|
next._tag !== "EnteredTipTarget" ||
|
|
247
|
-
(previous.text === next.text &&
|
|
260
|
+
(previous.text === next.text &&
|
|
261
|
+
previous.side === next.side &&
|
|
262
|
+
Equal.equals(previous.maybeKey, next.maybeKey))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#sameWords");
|
|
248
263
|
const tipSubscriptions = Subscription.make()((entry) => (__foldkitBrandViewResult(({
|
|
249
264
|
pointerAndFocus: entry({ tipId: Schema.String }, {
|
|
250
265
|
modelToDependencies: (model) => (__foldkitBrandViewResult(({ tipId: model.id }), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#modelToDependencies")),
|
|
@@ -286,10 +301,11 @@ const tipSubscriptions = Subscription.make()((entry) => (__foldkitBrandViewResul
|
|
|
286
301
|
* only while a tip shows. */
|
|
287
302
|
export const subscriptions = (keyPrefix) => __foldkitBrandViewResult((prefixKeys(keyPrefix, tipSubscriptions)), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#subscriptions");
|
|
288
303
|
// VIEW
|
|
289
|
-
const
|
|
304
|
+
const maybeWordsOf = (model) => __foldkitBrandViewResult((Match.value(model.state).pipe(Match.withReturnType(), Match.tag("Waiting", "Shown", "Leaving", (words) => __foldkitBrandViewResult((Option.some(wordsOf(words))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~26")), Match.orElse(() => __foldkitBrandViewResult((Option.none()), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~27")))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#maybeWordsOf");
|
|
290
305
|
/**
|
|
291
306
|
* The page's one tip: `div.tip[popover="manual"][aria-hidden="true"]`, which shows the words
|
|
292
|
-
* of any control carrying `data-tip` (IconButton, the glyph switch, a board's grip)
|
|
307
|
+
* of any control carrying `data-tip` (IconButton, the glyph switch, a board's grip), then the
|
|
308
|
+
* key in its `data-tip-key` where it has one (an IconButton's `keyHint`). Render it
|
|
293
309
|
* once, beside the Announcer, and lift `subscriptions(keyPrefix)`. It opens on a resting
|
|
294
310
|
* pointer after a moment (at once while another has just closed), never on touch, and on
|
|
295
311
|
* keyboard focus; it can be hovered; leaving, blur, a press or any key closes it, and Escape
|
|
@@ -301,7 +317,7 @@ const wordsOf = (model) => __foldkitBrandViewResult((Match.value(model.state).pi
|
|
|
301
317
|
* accessibility tree, and any control takes one by carrying `data-tip`.
|
|
302
318
|
*/
|
|
303
319
|
export const view = defineView((model, h) => {
|
|
304
|
-
const maybeWords =
|
|
320
|
+
const maybeWords = maybeWordsOf(model);
|
|
305
321
|
return __foldkitBrandViewResult((h.div([
|
|
306
322
|
h.Id(model.id),
|
|
307
323
|
h.Popover("manual"),
|
|
@@ -310,5 +326,11 @@ export const view = defineView((model, h) => {
|
|
|
310
326
|
...(Option.exists(maybeWords, ({ side }) => __foldkitBrandViewResult((side === "Right"), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~29"))
|
|
311
327
|
? [h.DataAttribute("side", "right")]
|
|
312
328
|
: []),
|
|
313
|
-
], Option.
|
|
329
|
+
], Option.match(maybeWords, {
|
|
330
|
+
onNone: () => __foldkitBrandViewResult(([]), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#onNone~3"),
|
|
331
|
+
onSome: ({ text, maybeKey }) => __foldkitBrandViewResult(([
|
|
332
|
+
text,
|
|
333
|
+
...Array.fromOption(Option.map(maybeKey, (key) => __foldkitBrandViewResult((h.kbd([h.Class("key-hint")], [key])), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~30"))),
|
|
334
|
+
]), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#onSome~3"),
|
|
335
|
+
}))), "@gjermundgaraba-designs/pixel-paper/src/tips/tips.js#anonymous~28");
|
|
314
336
|
});
|
package/package.json
CHANGED
|
@@ -2,8 +2,10 @@ import { Button as UiButton } from "@foldkit/ui";
|
|
|
2
2
|
import type { Html, HtmlBuilder } from "foldkit/html";
|
|
3
3
|
|
|
4
4
|
import type { Attributes } from "../attributes/attributes.ts";
|
|
5
|
+
import type { KeyHintConfig } from "../button/button.ts";
|
|
5
6
|
import * as Glyph from "../glyph/glyph.ts";
|
|
6
7
|
import type { GlyphName } from "../glyph/glyphs.ts";
|
|
8
|
+
import { keyLabel } from "../keyHint/keyLabel.ts";
|
|
7
9
|
|
|
8
10
|
// VIEW
|
|
9
11
|
|
|
@@ -17,13 +19,25 @@ export type ViewConfig<Message> = Readonly<{
|
|
|
17
19
|
isQuiet?: boolean;
|
|
18
20
|
/** Unavailable but focusable (`aria-disabled`), as in `@foldkit/ui`. */
|
|
19
21
|
isDisabled?: boolean;
|
|
22
|
+
/** The key that does the same, printed in the tip after the label (`data-tip-key`): the
|
|
23
|
+
* button has no words to print it beside. */
|
|
24
|
+
keyHint?: KeyHintConfig;
|
|
20
25
|
/** Further attributes for the `<button>`, never a class. */
|
|
21
26
|
attributes?: Attributes<Message>;
|
|
22
27
|
}>;
|
|
23
28
|
|
|
24
|
-
/** A bare glyph button, 24px square. Its label is its accessible name and its tip
|
|
29
|
+
/** A bare glyph button, 24px square. Its label is its accessible name and its tip, and its
|
|
30
|
+
* key, where it has one, prints in the tip after the label. */
|
|
25
31
|
export const view = <Message>(config: ViewConfig<Message>, h: HtmlBuilder<Message>): Html => {
|
|
26
|
-
const {
|
|
32
|
+
const {
|
|
33
|
+
glyph,
|
|
34
|
+
label,
|
|
35
|
+
onClick,
|
|
36
|
+
isQuiet = false,
|
|
37
|
+
isDisabled = false,
|
|
38
|
+
keyHint,
|
|
39
|
+
attributes = [],
|
|
40
|
+
} = config;
|
|
27
41
|
|
|
28
42
|
return UiButton.view(
|
|
29
43
|
{
|
|
@@ -36,6 +50,9 @@ export const view = <Message>(config: ViewConfig<Message>, h: HtmlBuilder<Messag
|
|
|
36
50
|
...groups.button,
|
|
37
51
|
h.AriaLabel(label),
|
|
38
52
|
h.DataAttribute("tip", label),
|
|
53
|
+
...(keyHint === undefined
|
|
54
|
+
? []
|
|
55
|
+
: [h.DataAttribute("tip-key", keyLabel(keyHint.keys, keyHint.platform))]),
|
|
39
56
|
h.Class(isQuiet ? "iconbtn quiet" : "iconbtn"),
|
|
40
57
|
],
|
|
41
58
|
[Glyph.view({ name: glyph }, h)],
|
package/src/panel/panel.ts
CHANGED
|
@@ -26,6 +26,9 @@ export type ViewConfig = Readonly<{
|
|
|
26
26
|
/** Small Buttons and IconButtons at the title bar's right end, after the meta. On the ink
|
|
27
27
|
* bar they print in paper, flat, and ring in their own colour inside their edge. */
|
|
28
28
|
actions?: ReadonlyArray<Html | string>;
|
|
29
|
+
/** A strip on the head tint between the title bar and the body, for a field that picks what
|
|
30
|
+
* the body shows (an area over its tasks). Its labels print in on-head. */
|
|
31
|
+
shelf?: ReadonlyArray<Html | string>;
|
|
29
32
|
body: ReadonlyArray<Html | string>;
|
|
30
33
|
/** A ruled foot under the body: a note line, then actions pushed right. */
|
|
31
34
|
foot?: ReadonlyArray<Html | string>;
|
|
@@ -46,6 +49,7 @@ export const view = <Message>(config: ViewConfig, h: HtmlBuilder<Message>): Html
|
|
|
46
49
|
lead = [],
|
|
47
50
|
meta,
|
|
48
51
|
actions = [],
|
|
52
|
+
shelf = [],
|
|
49
53
|
body,
|
|
50
54
|
foot = [],
|
|
51
55
|
isFlush = false,
|
|
@@ -68,6 +72,7 @@ export const view = <Message>(config: ViewConfig, h: HtmlBuilder<Message>): Html
|
|
|
68
72
|
...slotView("span", "panel-acts", actions, h),
|
|
69
73
|
],
|
|
70
74
|
),
|
|
75
|
+
...slotView("div", "panel-shelf", shelf, h),
|
|
71
76
|
...(isFlush ? body : [h.div([h.Class("panel-body")], body)]),
|
|
72
77
|
...slotView("div", "panel-foot", foot, h),
|
|
73
78
|
],
|