@gjermundgaraba-designs/pixel-paper 0.17.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 +41 -12
- 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/glyph/glyph.d.ts +3 -1
- package/dist/src/glyph/glyph.d.ts.map +1 -1
- package/dist/src/glyph/glyph.js +2 -1
- package/dist/src/glyph/glyphs.d.ts +3 -0
- package/dist/src/glyph/glyphs.d.ts.map +1 -1
- package/dist/src/glyph/glyphs.js +4 -3
- package/dist/src/identity/identity.d.ts +2 -0
- package/dist/src/identity/identity.d.ts.map +1 -1
- package/dist/src/identity/identity.js +8 -2
- 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/meter/meter.d.ts +5 -1
- package/dist/src/meter/meter.d.ts.map +1 -1
- package/dist/src/meter/meter.js +15 -3
- package/dist/src/monogram/monogram.d.ts +7 -2
- package/dist/src/monogram/monogram.d.ts.map +1 -1
- package/dist/src/monogram/monogram.js +24 -6
- package/dist/src/panel/panel.d.ts +5 -1
- package/dist/src/panel/panel.d.ts.map +1 -1
- package/dist/src/panel/panel.js +7 -3
- 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/glyph/glyph.ts +2 -1
- package/src/glyph/glyphs.ts +6 -4
- package/src/identity/identity.ts +10 -2
- package/src/index.ts +1 -0
- package/src/meter/meter.ts +18 -2
- package/src/monogram/monogram.ts +46 -6
- package/src/panel/panel.ts +21 -3
- package/src/pixel-paper.css +249 -2
- 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
package/src/panel/panel.ts
CHANGED
|
@@ -14,6 +14,10 @@ export type ViewConfig = Readonly<{
|
|
|
14
14
|
id: string;
|
|
15
15
|
/** Pixel caps in the inverted title bar. */
|
|
16
16
|
title: string;
|
|
17
|
+
/** What screen readers call the panel where its title repeats among its siblings (panels
|
|
18
|
+
* titled by a kind, one per account): the title and what tells this one apart. The
|
|
19
|
+
* title names it otherwise. */
|
|
20
|
+
name?: string;
|
|
17
21
|
/** A quiet IconButton before the title, such as the grip a Sortable of panels hands each
|
|
18
22
|
* panel. On the ink bar it prints as `actions` do. */
|
|
19
23
|
lead?: ReadonlyArray<Html | string>;
|
|
@@ -33,13 +37,27 @@ export type ViewConfig = Readonly<{
|
|
|
33
37
|
export const titleId = (id: string): string => `${id}-title`;
|
|
34
38
|
|
|
35
39
|
/** The unit of the system: paper in a 2px ink box on a 5px print shadow, under a title bar. A
|
|
36
|
-
* region landmark (`<section>`) named by its `h2` title, keyed by its `id`. */
|
|
40
|
+
* region landmark (`<section>`) named by its `h2` title, or by `name`, keyed by its `id`. */
|
|
37
41
|
export const view = <Message>(config: ViewConfig, h: HtmlBuilder<Message>): Html => {
|
|
38
|
-
const {
|
|
42
|
+
const {
|
|
43
|
+
id,
|
|
44
|
+
title,
|
|
45
|
+
name,
|
|
46
|
+
lead = [],
|
|
47
|
+
meta,
|
|
48
|
+
actions = [],
|
|
49
|
+
body,
|
|
50
|
+
foot = [],
|
|
51
|
+
isFlush = false,
|
|
52
|
+
} = config;
|
|
39
53
|
|
|
40
54
|
return h.keyed("section")(
|
|
41
55
|
id,
|
|
42
|
-
[
|
|
56
|
+
[
|
|
57
|
+
h.Id(id),
|
|
58
|
+
name === undefined ? h.AriaLabelledBy(titleId(id)) : h.AriaLabel(name),
|
|
59
|
+
h.Class("panel"),
|
|
60
|
+
],
|
|
43
61
|
[
|
|
44
62
|
h.header(
|
|
45
63
|
[h.Class("panel-tb")],
|
package/src/pixel-paper.css
CHANGED
|
@@ -3433,7 +3433,8 @@ dialog.veil:focus {
|
|
|
3433
3433
|
padding: 6px;
|
|
3434
3434
|
}
|
|
3435
3435
|
|
|
3436
|
-
.sortable-lift
|
|
3436
|
+
.sortable-lift,
|
|
3437
|
+
.reel-lift {
|
|
3437
3438
|
width: var(--lift-width, 320px);
|
|
3438
3439
|
translate: var(--lift-x, 0) var(--lift-y, 0);
|
|
3439
3440
|
}
|
|
@@ -3655,6 +3656,16 @@ dialog.veil:focus {
|
|
|
3655
3656
|
flex-wrap: wrap;
|
|
3656
3657
|
}
|
|
3657
3658
|
|
|
3659
|
+
/* a toned meter's lit cells take its reading's tone, amber from 80% and red at the maximum,
|
|
3660
|
+
unless the reading is stale */
|
|
3661
|
+
.meter-row.toned.high:not(.stale) .cells .cell.on {
|
|
3662
|
+
background: var(--amber);
|
|
3663
|
+
}
|
|
3664
|
+
|
|
3665
|
+
.meter-row.toned.full:not(.stale) .cells .cell.on {
|
|
3666
|
+
background: var(--red);
|
|
3667
|
+
}
|
|
3668
|
+
|
|
3658
3669
|
/* a stale reading prints its cells muted: the number is last known, not current */
|
|
3659
3670
|
.meter-row.stale .cells .cell.on {
|
|
3660
3671
|
background: var(--muted);
|
|
@@ -4522,7 +4533,7 @@ dialog.veil:focus {
|
|
|
4522
4533
|
position: absolute;
|
|
4523
4534
|
}
|
|
4524
4535
|
|
|
4525
|
-
/* ---------- monograms: letters in an ink square,
|
|
4536
|
+
/* ---------- monograms: letters in an ink square, or a mark the product draws in cells ---------- */
|
|
4526
4537
|
|
|
4527
4538
|
.monogram {
|
|
4528
4539
|
display: inline-grid;
|
|
@@ -4551,6 +4562,16 @@ dialog.veil:focus {
|
|
|
4551
4562
|
color: var(--paper);
|
|
4552
4563
|
}
|
|
4553
4564
|
|
|
4565
|
+
/* a mark drawn in cells prints bare, in ink, in the square the letters would take */
|
|
4566
|
+
.monogram.drawn {
|
|
4567
|
+
border: 0;
|
|
4568
|
+
background: none;
|
|
4569
|
+
}
|
|
4570
|
+
|
|
4571
|
+
.monogram.drawn.current {
|
|
4572
|
+
background: var(--ink);
|
|
4573
|
+
}
|
|
4574
|
+
|
|
4554
4575
|
/* ---------- identity: who or what, as its monogram beside its name ---------- */
|
|
4555
4576
|
|
|
4556
4577
|
.identity {
|
|
@@ -5101,6 +5122,11 @@ dialog.veil:focus {
|
|
|
5101
5122
|
user-select: none;
|
|
5102
5123
|
}
|
|
5103
5124
|
|
|
5125
|
+
/* a lead (a reel's grip) trims the bar's left, as a panel's does */
|
|
5126
|
+
.window > .panel-tb:has(> .panel-lead) {
|
|
5127
|
+
padding-left: 3px;
|
|
5128
|
+
}
|
|
5129
|
+
|
|
5104
5130
|
.window > .panel-tb h2 {
|
|
5105
5131
|
flex: 1;
|
|
5106
5132
|
min-width: 0;
|
|
@@ -5143,6 +5169,227 @@ dialog.veil:focus {
|
|
|
5143
5169
|
min-width: 0;
|
|
5144
5170
|
}
|
|
5145
5171
|
|
|
5172
|
+
/* ---------- the reel: a scrolling row of columns of panes ---------- */
|
|
5173
|
+
|
|
5174
|
+
/* the reel takes its height from whatever holds it; the held copy hangs from it, outside the
|
|
5175
|
+
scroller, whose containment would hold a fixed copy inside it */
|
|
5176
|
+
.reel {
|
|
5177
|
+
height: 100%;
|
|
5178
|
+
min-height: 0;
|
|
5179
|
+
}
|
|
5180
|
+
|
|
5181
|
+
/* the scroller, sideways and, where a column is taller than the view, down. Its size is what
|
|
5182
|
+
a column's width (100cqw) and least height (100cqh) are shares of, so it takes no padding */
|
|
5183
|
+
.reel-view {
|
|
5184
|
+
height: 100%;
|
|
5185
|
+
overflow: auto;
|
|
5186
|
+
overscroll-behavior: contain;
|
|
5187
|
+
container-type: size;
|
|
5188
|
+
}
|
|
5189
|
+
|
|
5190
|
+
/* the columns in a row, and the panes' containing block. Each pane is pinned to its slot by
|
|
5191
|
+
anchor positioning, so a move changes where a pane is drawn and never its place in the page */
|
|
5192
|
+
.reel-track {
|
|
5193
|
+
position: relative;
|
|
5194
|
+
display: flex;
|
|
5195
|
+
align-items: flex-start;
|
|
5196
|
+
width: max-content;
|
|
5197
|
+
min-width: 100%;
|
|
5198
|
+
min-height: 100%;
|
|
5199
|
+
padding-bottom: var(--reel-gutter);
|
|
5200
|
+
}
|
|
5201
|
+
|
|
5202
|
+
.reel-gap {
|
|
5203
|
+
position: relative;
|
|
5204
|
+
flex: none;
|
|
5205
|
+
align-self: stretch;
|
|
5206
|
+
width: var(--reel-gutter);
|
|
5207
|
+
}
|
|
5208
|
+
|
|
5209
|
+
/* a column is width × (view − gutter) − gutter wide, so columns whose widths add up to one
|
|
5210
|
+
fill the view with a gutter between each and at either side; never under the minimum. It is
|
|
5211
|
+
the view's height, and taller where its panes need more, which the view scrolls to */
|
|
5212
|
+
.reel-column {
|
|
5213
|
+
display: flex;
|
|
5214
|
+
flex: none;
|
|
5215
|
+
flex-direction: column;
|
|
5216
|
+
width: max(
|
|
5217
|
+
var(--reel-column-min),
|
|
5218
|
+
var(--reel-width) * (100cqw - var(--reel-gutter)) - var(--reel-gutter)
|
|
5219
|
+
);
|
|
5220
|
+
min-height: calc(100cqh - var(--reel-gutter));
|
|
5221
|
+
}
|
|
5222
|
+
|
|
5223
|
+
/* the column's head, in the gutter above its panes: its grip and its width */
|
|
5224
|
+
.reel-column-head {
|
|
5225
|
+
display: flex;
|
|
5226
|
+
flex: none;
|
|
5227
|
+
align-items: center;
|
|
5228
|
+
gap: var(--space-s);
|
|
5229
|
+
padding-block: 4px;
|
|
5230
|
+
}
|
|
5231
|
+
|
|
5232
|
+
.reel-width {
|
|
5233
|
+
font-family: var(--font-px);
|
|
5234
|
+
font-size: var(--type-state);
|
|
5235
|
+
letter-spacing: var(--tracking-state);
|
|
5236
|
+
text-transform: uppercase;
|
|
5237
|
+
color: var(--muted);
|
|
5238
|
+
}
|
|
5239
|
+
|
|
5240
|
+
/* a slot holds a pane's place, its share of the column by weight; the pane is drawn over it */
|
|
5241
|
+
.reel-slot {
|
|
5242
|
+
position: relative;
|
|
5243
|
+
flex: var(--reel-weight, 1) 1 0;
|
|
5244
|
+
min-height: var(--reel-pane-min);
|
|
5245
|
+
anchor-name: var(--reel-anchor);
|
|
5246
|
+
}
|
|
5247
|
+
|
|
5248
|
+
/* the splitters: the gutter between two panes, and the one after each column */
|
|
5249
|
+
.reel-split {
|
|
5250
|
+
position: relative;
|
|
5251
|
+
flex: none;
|
|
5252
|
+
height: var(--reel-gutter);
|
|
5253
|
+
cursor: row-resize;
|
|
5254
|
+
touch-action: none;
|
|
5255
|
+
}
|
|
5256
|
+
|
|
5257
|
+
.reel-resize {
|
|
5258
|
+
cursor: col-resize;
|
|
5259
|
+
touch-action: none;
|
|
5260
|
+
}
|
|
5261
|
+
|
|
5262
|
+
/* a splitter shows itself as a 2px ink line along the middle of its gutter while it is
|
|
5263
|
+
hovered or focused; focused, the ring is the system's */
|
|
5264
|
+
.reel-resize::after,
|
|
5265
|
+
.reel-split::after {
|
|
5266
|
+
content: "";
|
|
5267
|
+
position: absolute;
|
|
5268
|
+
background: var(--ink);
|
|
5269
|
+
opacity: 0;
|
|
5270
|
+
pointer-events: none;
|
|
5271
|
+
}
|
|
5272
|
+
|
|
5273
|
+
.reel-resize::after {
|
|
5274
|
+
top: 0;
|
|
5275
|
+
bottom: var(--reel-gutter);
|
|
5276
|
+
left: calc(50% - 1px);
|
|
5277
|
+
width: var(--line);
|
|
5278
|
+
}
|
|
5279
|
+
|
|
5280
|
+
.reel-split::after {
|
|
5281
|
+
left: 0;
|
|
5282
|
+
right: 0;
|
|
5283
|
+
top: calc(50% - 1px);
|
|
5284
|
+
height: var(--line);
|
|
5285
|
+
}
|
|
5286
|
+
|
|
5287
|
+
.reel-resize:is(:hover, :focus-visible)::after,
|
|
5288
|
+
.reel-split:is(:hover, :focus-visible)::after {
|
|
5289
|
+
opacity: 1;
|
|
5290
|
+
}
|
|
5291
|
+
|
|
5292
|
+
.reel-resize:focus-visible,
|
|
5293
|
+
.reel-split:focus-visible {
|
|
5294
|
+
outline-offset: -2px;
|
|
5295
|
+
}
|
|
5296
|
+
|
|
5297
|
+
/* where a drop would land: a 2px dashed ink line down the gap it would open, or across the
|
|
5298
|
+
gutter between the panes it would join, drawn over the layout so nothing moves under it */
|
|
5299
|
+
.reel-gap.drop-here::before {
|
|
5300
|
+
content: "";
|
|
5301
|
+
position: absolute;
|
|
5302
|
+
top: 0;
|
|
5303
|
+
bottom: var(--reel-gutter);
|
|
5304
|
+
left: calc(50% - 1px);
|
|
5305
|
+
border-left: var(--line) dashed var(--ink);
|
|
5306
|
+
pointer-events: none;
|
|
5307
|
+
}
|
|
5308
|
+
|
|
5309
|
+
.reel-slot:is(.drop-before, .drop-after)::before {
|
|
5310
|
+
content: "";
|
|
5311
|
+
position: absolute;
|
|
5312
|
+
left: 0;
|
|
5313
|
+
right: 0;
|
|
5314
|
+
border-top: var(--line) dashed var(--ink);
|
|
5315
|
+
pointer-events: none;
|
|
5316
|
+
}
|
|
5317
|
+
|
|
5318
|
+
.reel-slot.drop-before::before {
|
|
5319
|
+
top: calc(var(--reel-gutter) / -2 - 1px);
|
|
5320
|
+
}
|
|
5321
|
+
|
|
5322
|
+
.reel-slot.drop-after::before {
|
|
5323
|
+
bottom: calc(var(--reel-gutter) / -2 - 1px);
|
|
5324
|
+
}
|
|
5325
|
+
|
|
5326
|
+
/* the panes' layer is no box of its own: each pane's containing block is the track */
|
|
5327
|
+
.reel-panes {
|
|
5328
|
+
display: contents;
|
|
5329
|
+
}
|
|
5330
|
+
|
|
5331
|
+
/* a pane or a column scrolled into view keeps its gutter showing */
|
|
5332
|
+
.reel-pane,
|
|
5333
|
+
.reel-column {
|
|
5334
|
+
scroll-margin: var(--reel-gutter);
|
|
5335
|
+
}
|
|
5336
|
+
|
|
5337
|
+
.reel-pane {
|
|
5338
|
+
position: absolute;
|
|
5339
|
+
position-anchor: var(--reel-anchor);
|
|
5340
|
+
top: anchor(top);
|
|
5341
|
+
right: anchor(right);
|
|
5342
|
+
bottom: anchor(bottom);
|
|
5343
|
+
left: anchor(left);
|
|
5344
|
+
min-width: 0;
|
|
5345
|
+
}
|
|
5346
|
+
|
|
5347
|
+
/* the focused pane lifts onto the card shadow; taking focus itself (it holds no control), it
|
|
5348
|
+
keeps the system's ring outside its window */
|
|
5349
|
+
.reel-pane.focused > .window {
|
|
5350
|
+
box-shadow: var(--shadow-card);
|
|
5351
|
+
}
|
|
5352
|
+
|
|
5353
|
+
.reel-pane:focus-visible {
|
|
5354
|
+
outline: 0;
|
|
5355
|
+
}
|
|
5356
|
+
|
|
5357
|
+
.reel-pane:focus-visible > .window {
|
|
5358
|
+
outline: var(--line) solid var(--ink);
|
|
5359
|
+
outline-offset: 2px;
|
|
5360
|
+
}
|
|
5361
|
+
|
|
5362
|
+
.reel-pane.drag-dim {
|
|
5363
|
+
opacity: 0.4;
|
|
5364
|
+
}
|
|
5365
|
+
|
|
5366
|
+
/* only the grips lift: a pane's text selects and its terminal takes the pointer */
|
|
5367
|
+
[data-reel-grip] {
|
|
5368
|
+
cursor: grab;
|
|
5369
|
+
touch-action: none;
|
|
5370
|
+
}
|
|
5371
|
+
|
|
5372
|
+
/* the held copy, following the pointer from the window's corner (its transform puts it at the
|
|
5373
|
+
pointer): the title bars alone, tinted head on the card shadow */
|
|
5374
|
+
.reel-lift {
|
|
5375
|
+
position: fixed;
|
|
5376
|
+
top: 0;
|
|
5377
|
+
left: 0;
|
|
5378
|
+
z-index: 9999;
|
|
5379
|
+
pointer-events: none;
|
|
5380
|
+
}
|
|
5381
|
+
|
|
5382
|
+
.reel-lifted {
|
|
5383
|
+
display: grid;
|
|
5384
|
+
gap: var(--space-s);
|
|
5385
|
+
}
|
|
5386
|
+
|
|
5387
|
+
.reel-lifted .window {
|
|
5388
|
+
height: auto;
|
|
5389
|
+
background: var(--head);
|
|
5390
|
+
box-shadow: var(--shadow-card);
|
|
5391
|
+
}
|
|
5392
|
+
|
|
5146
5393
|
/* ---------- images and media: a picture or a player in a 2px ink frame, at rest ---------- */
|
|
5147
5394
|
|
|
5148
5395
|
/* a figure sits at rest wherever it is placed (a panel, prose): no print shadow. The frame
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export { Layout, OutMessage, Pane, apply } from "./layout.ts";
|
|
2
|
+
export {
|
|
3
|
+
Action,
|
|
4
|
+
AnnounceReel,
|
|
5
|
+
FocusGrip,
|
|
6
|
+
FocusPane,
|
|
7
|
+
Message,
|
|
8
|
+
Model,
|
|
9
|
+
RestoreFocus,
|
|
10
|
+
ScrollIntoView,
|
|
11
|
+
SizeLiftedPane,
|
|
12
|
+
focusedPaneId,
|
|
13
|
+
init,
|
|
14
|
+
perform,
|
|
15
|
+
reconcile,
|
|
16
|
+
subscriptions,
|
|
17
|
+
update,
|
|
18
|
+
view,
|
|
19
|
+
} from "./reel.ts";
|
|
20
|
+
export type { InitConfig, PaneRender, UpdateContext, ViewInputs } from "./reel.ts";
|