@gjermundgaraba-designs/pixel-paper 0.16.0 → 0.18.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 +17 -9
- 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/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/sortable/index.d.ts +1 -1
- package/dist/src/sortable/index.d.ts.map +1 -1
- package/dist/src/sortable/index.js +1 -1
- package/dist/src/sortable/sortable.d.ts +3 -3
- package/dist/src/sortable/sortable.d.ts.map +1 -1
- package/dist/src/sortable/sortable.js +32 -57
- package/package.json +1 -1
- package/src/glyph/glyph.ts +2 -1
- package/src/glyph/glyphs.ts +6 -4
- package/src/identity/identity.ts +10 -2
- 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 +22 -14
- package/src/sortable/index.ts +1 -0
- package/src/sortable/sortable.ts +21 -58
package/DESIGN.md
CHANGED
|
@@ -602,6 +602,14 @@ components:
|
|
|
602
602
|
backgroundColor: "{colors.muted}"
|
|
603
603
|
width: "10px"
|
|
604
604
|
height: "14px"
|
|
605
|
+
meter-cell-toned-high:
|
|
606
|
+
backgroundColor: "{colors.amber}"
|
|
607
|
+
width: "10px"
|
|
608
|
+
height: "14px"
|
|
609
|
+
meter-cell-toned-full:
|
|
610
|
+
backgroundColor: "{colors.red}"
|
|
611
|
+
width: "10px"
|
|
612
|
+
height: "14px"
|
|
605
613
|
strength-cell:
|
|
606
614
|
backgroundColor: "{colors.head}"
|
|
607
615
|
width: "24px"
|
|
@@ -802,9 +810,9 @@ Two neutral palettes over one set of tokens, with three meaning hues shared betw
|
|
|
802
810
|
|
|
803
811
|
### Primary
|
|
804
812
|
|
|
805
|
-
- **Marker Amber** (`{colors.amber}`, both palettes): the Mark (a viewfinder glyph on an amber square beside a marked item), the warn chip (an update waiting, a source behind), a meter reading at or above 80% of its limit, the glyph box of a warning notice, of a confirm dialog and of a reconnecting banner; a stat's change or a bar's reading that the product calls a warning. Always carries Printer Ink text (`{colors.on-status}`); an amber glyph on paper is never allowed because it fails contrast. Where every row is marked the Mark prints plain (muted, no fill): amber is for the one among many.
|
|
813
|
+
- **Marker Amber** (`{colors.amber}`, both palettes): the Mark (a viewfinder glyph on an amber square beside a marked item), the warn chip (an update waiting, a source behind), a meter reading at or above 80% of its limit and a toned meter's lit cells there, the glyph box of a warning notice, of a confirm dialog and of a reconnecting banner; a stat's change or a bar's reading that the product calls a warning. Always carries Printer Ink text (`{colors.on-status}`); an amber glyph on paper is never allowed because it fails contrast. Where every row is marked the Mark prints plain (muted, no fill): amber is for the one among many.
|
|
806
814
|
- **Active Green** (`{colors.green}`, both palettes): the go chip of something that is live or in sync. Also carries Printer Ink text. Nothing else is green.
|
|
807
|
-
- **Urgent Red** (`{colors.red}` paper / `{colors.red-plum}` plum): the danger button's text, border and shadow tint; the blocked and limit-reached chips; a field's error line; the error notice's and error toast's border and glyph box; the offline word and an offline banner's glyph box; a stat's change or a bar's reading at fault; a broken image, video or audio frame; a stale age, a late due day (on a cursor row or card, a red slip with `on-red` text), a failed check, a stale meter's foot; a failed field's rule and label, a failed radio or select box, a fieldset's legend over a failed control; a link to a page that does not exist; the minus sign of a deleted diff line. Red fills carry Paper White text on paper (`{colors.on-red}`) and Printer Ink on plum (`{colors.on-red-plum}`), because plum lightens red for text contrast.
|
|
815
|
+
- **Urgent Red** (`{colors.red}` paper / `{colors.red-plum}` plum): the danger button's text, border and shadow tint; the blocked and limit-reached chips; a toned meter's lit cells at its limit; a field's error line; the error notice's and error toast's border and glyph box; the offline word and an offline banner's glyph box; a stat's change or a bar's reading at fault; a broken image, video or audio frame; a stale age, a late due day (on a cursor row or card, a red slip with `on-red` text), a failed check, a stale meter's foot; a failed field's rule and label, a failed radio or select box, a fieldset's legend over a failed control; a link to a page that does not exist; the minus sign of a deleted diff line. Red fills carry Paper White text on paper (`{colors.on-red}`) and Printer Ink on plum (`{colors.on-red-plum}`), because plum lightens red for text contrast.
|
|
808
816
|
|
|
809
817
|
### Neutral
|
|
810
818
|
|
|
@@ -824,7 +832,7 @@ What a program prints (terminal output, highlighted code, a log) is content, not
|
|
|
824
832
|
|
|
825
833
|
**The Content Ink Rule.** The `--term-*` and `--code-*` tokens colour only what a program printed, inside a code surface, a terminal, a log or a library adapter. They never colour chrome, state, a border, a fill or a person: a busy build is a chip, not a cyan word, and presence is a Monogram, not a hue.
|
|
826
834
|
|
|
827
|
-
**The Meaning Colour Rule.** Amber means marked or warning, green means active or in sync, red means urgent, offline, error, missing or destructive. Every other colour on a surface is a neutral token. A new element that wants colour must be one of those three meanings, or it is ink (content inks aside; see the Content Ink Rule). A meter's cells stay ink at every level
|
|
835
|
+
**The Meaning Colour Rule.** Amber means marked or warning, green means active or in sync, red means urgent, offline, error, missing or destructive. Every other colour on a surface is a neutral token. A new element that wants colour must be one of those three meanings, or it is ink (content inks aside; see the Content Ink Rule). A meter's cells stay ink at every level and the reading beside them carries the colour, except in a toned meter (`isToned`): on a page whose readings are scanned for their level, a wall of limits, the lit cells take the reading's amber from 80% and its red at the limit, and the reading beside them still says so in a mark or a chip, so the level never rests on colour. A search hit is inverted ink and a list's cursor row a muted outline, never amber, because a hit is a selection, not a warning. Charts and stats keep the rule: bar cells and the line stay ink (a second series is muted ink with smaller cells, never a hue), and a stat's change prints in ink with a direction glyph, because up is not good and down is not bad until the product says so; only a reading the product calls a warning or a fault takes amber or red.
|
|
828
836
|
|
|
829
837
|
**The Red On Commit Rule.** Red never rests on a button. Row and form actions that destroy something (disable, delete, restore over, reset) are neutral buttons; the ConfirmDialog they open carries the one red button, the commit. Red at rest belongs to states only: a blocked chip, a failed check, a missing page, the offline word. A `ConfirmDialog` with `isDanger` is the only destructive confirm: there is no inline arm-then-confirm button ("delete" that turns into "sure?"), because the dialog gives the commit protected focus (cancel is the default) and an alert dialog's semantics, while an armed button is easy to double-click through and shifts the layout as its word changes.
|
|
830
838
|
|
|
@@ -1027,9 +1035,9 @@ The printed button: a paper rectangle in a 2px ink frame that casts a 3px shadow
|
|
|
1027
1035
|
|
|
1028
1036
|
### Monograms
|
|
1029
1037
|
|
|
1030
|
-
**Monogram** → `span.monogram[role="img"][aria-label]` (`.large`, `.current`): one or two letters (the label's initials, or `letters`) in the 11px pixel face, uppercase, centred in a 22px square closed by a 2px ink border on paper; large is 34px with 14px letters, for a card of readings or a wall. `isCurrent` inverts it: you, among others. `isDecorative` → `span.monogram[aria-hidden="true"]`, for a monogram beside the same name in words, which screen readers then hear once. The system draws no logos: a provider, a source, a harness or a person is a monogram beside its name, never a brand mark and
|
|
1038
|
+
**Monogram** → `span.monogram[role="img"][aria-label]` (`.large`, `.current`): one or two letters (the label's initials, or `letters`) in the 11px pixel face, uppercase, centred in a 22px square closed by a 2px ink border on paper; large is 34px with 14px letters, for a card of readings or a wall. `isCurrent` inverts it: you, among others. `isDecorative` → `span.monogram[aria-hidden="true"]`, for a monogram beside the same name in words, which screen readers then hear once. The system draws no logos of its own: a provider, a source, a harness or a person is a monogram beside its name, never a picture and never a brand colour. Where the product knows a provider's own mark, it may redraw it in cells (`drawing`: rows of `#` and `.`, as a glyph is drawn) → `span.monogram.drawn > svg.px-icon`: the mark prints bare in ink, without the border or the paper, in the square the letters would take, a pixel per cell (two in a large monogram, so a 16-cell drawing is 32px in the 34px square); `isCurrent` sets it in paper on an ink square.
|
|
1031
1039
|
|
|
1032
|
-
**Identity** → `div.identity (.large) > span.monogram[aria-hidden="true"] + span.identity-text > strong + span.meta`: that pairing as one piece, its name read once (the monogram is decorative beside it). The name in the sans at 600 (16px when large, beside the large monogram, as a card's subject), wrapping rather than clipping; under it a meta line of whatever says which one (an id in code, a kind in a Tag), 8px apart and wrapping. A consent card names the client asking with it; a list of sources, harnesses or people names each.
|
|
1040
|
+
**Identity** → `div.identity (.large) > span.monogram[aria-hidden="true"] + span.identity-text > strong + span.meta`: that pairing as one piece (its monogram letters or drawn), its name read once (the monogram is decorative beside it). The name in the sans at 600 (16px when large, beside the large monogram, as a card's subject), wrapping rather than clipping; under it a meta line of whatever says which one (an id in code, a kind in a Tag), 8px apart and wrapping. A consent card names the client asking with it; a list of sources, harnesses or people names each.
|
|
1033
1041
|
|
|
1034
1042
|
### Time
|
|
1035
1043
|
|
|
@@ -1037,7 +1045,7 @@ The printed button: a paper rectangle in a 2px ink frame that casts a 3px shadow
|
|
|
1037
1045
|
|
|
1038
1046
|
### Panels
|
|
1039
1047
|
|
|
1040
|
-
- **Panel** → `section.panel[aria-labelledby]
|
|
1048
|
+
- **Panel** → `section.panel[aria-labelledby]` (`[aria-label]` with `name`) `> header.panel-tb > span.panel-lead + h2 + span.meta`, then `div.panel-body` (or the body directly when `isFlush`), then `div.panel-foot`. The section is named by its title, or by `name` where the title repeats among its siblings (panels titled by a kind, one per account), so each landmark keeps a name of its own. It is keyed by its `id`, so a panel among siblings that come and go keeps its own element, and a panel under another id is another element: one that replaces another in the same place is built anew (a live region inside it is inserted, not kept), so keep one panel under one id across states that should share it. Square, 2px ink border, Paper White, panel shadow. The title bar is inverted Departure Mono 13px uppercase 0.08em (`--tracking-title`), `padding: 6px 12px`; its meta is 11px at 75% opacity. A control in a title bar (a panel's, a window's or a card's) rings in paper, 2px inside its own edge, because the ink ring would vanish on the ink bar. The body pads 16px with a 14px grid gap; the foot pads `10px 12px` over a 1px rule, with a `.push` slot that goes right. `actions` puts small Buttons and IconButtons in `span.panel-acts` (6px apart) at the title bar's right end, after the meta; the bar trims to `3px 3px 3px 12px` at 31px or more. `lead` puts a quiet IconButton in `span.panel-lead` before the title (a Sortable's grip), and the bar trims its left to 3px the same way; a quiet icon button there prints in paper, hovered too, and held at 60%. On the ink bar a button is a paper outline (a primary one fills paper), flat, nudged 1px when pressed, its ring 4px inside in its own colour; disabled, it prints at 60%.
|
|
1041
1049
|
- **Deck** → `main.deck#main`: the column of panels.
|
|
1042
1050
|
- **EmptyState** → `div.empty > h3.empty-title + p`: `headingLevel` is required and picks the title's element, which looks the same at every level. Where the empty state is a page's or a section's main content it is a heading, `3` inside a Panel (whose title is an `h2`), `1` for a gate or a missing page; `"Strong"` prints `strong.empty-title` where it is not (a chart with nothing to chart, a picture of the state). Centred, `26px 16px`, a 12px uppercase 0.08em (`--tracking-title`) headline, a muted 46ch sentence, an optional action 6px below.
|
|
1043
1051
|
- **Wall** → `main.wall`, `Wall.markView` → `div.wall-mark` (a 30px ink-bordered glyph box beside the 22px wordmark). `Wall.cornerView` → `aside.wall-corner[aria-label]`, rendered just before the Wall: a paper slip in a 2px ink box on the 3px shadow, `6px 8px`, holding what a top bar would (see Layout).
|
|
@@ -1097,7 +1105,7 @@ One keyboard for the page, Vim first, with the arrows beside the letters. The ke
|
|
|
1097
1105
|
|
|
1098
1106
|
### Sortable
|
|
1099
1107
|
|
|
1100
|
-
**Sortable** (Submodel over `@foldkit/ui`'s DragAndDrop, for items the reader puts in order: a list of rows, a grid of tiles, or a grid of the page's panels) → `div.sortable (.grid, .panels)` holding `ul.sortable-items[aria-label]` (a plain list: no listbox, so an item's content may hold anything) of `li.sortable-item (.movable, .drag-dim, .drop-before, .drop-after)`, each a grip, then `div.sortable-body` with the parent's content, and the list's keyboard help in a `p.sr-only`. `"List"` (the default) prints rows edge to edge between 1px rules, for a flush panel, `8px 16px 8px 10px
|
|
1108
|
+
**Sortable** (Submodel over `@foldkit/ui`'s DragAndDrop, for items the reader puts in order: a list of rows, a grid of tiles, or a grid of the page's panels) → `div.sortable (.grid, .panels)` holding `ul.sortable-items[aria-label]` (a plain list: no listbox, so an item's content may hold anything) of `li.sortable-item (.movable, .drag-dim, .drop-before, .drop-after)`, each a grip, then `div.sortable-body` with the parent's content, and the list's keyboard help in a `p.sr-only`. `"List"` (the default) prints rows edge to edge between 1px rules, for a flush panel, `8px 16px 8px 10px`; `"Grid"` prints tiles that wrap, 180px and up, 12px apart: paper slips in a 2px ink border on the 3px print shadow. `"Panels"` prints each item as the parent's own Panel, up to three across in the deck's 24px gutter and 300px and up, so two across and then one as the column narrows; a row takes its tallest panel's height, each panel's foot sits at its bottom, and the list hands each item its grip (`render.grip`) for the panel's `lead` instead of printing it beside the item. The held copy is the whole panel, tinted head on the 8px card shadow, under ids of its own, and the drop line runs down the middle of the gutter. `isReadOnly`, for a reader who may look but not reorder, prints every grip held and lifts nothing, as holding moves does. Each item starts with a quiet `button.iconbtn` grip (in a panel's title bar, for `"Panels"`) (the grip glyph, named "Move <label>", `aria-roledescription="draggable"`, `aria-pressed`, described by the keyboard help); while moves are held it stays, held (`aria-disabled`, in the keyboard), so focus on it stays put when holding moves cancels one. Only the grip lifts an item, under a mouse, a finger or a pen (`cursor: grab` and `touch-action: none` on a movable grip only), so the rest of an item selects its text and a finger on it scrolls the page; the keyboard takes the grip too: Space or Enter picks the item up, every arrow moves it one place in reading order, Space or Enter drops it, Escape puts it back (taken before a dialog or the page's keys see it), and Tab leaves it where it is. Only the pointer that pressed moves the item; the browser cancelling it puts the item back. The held item dims to 40% in place (`.drag-dim`) and keeps its own print; a copy of it, `.lifted`, tinted head on the 8px card shadow in a 2px ink border (`aria-hidden`, `inert`, rendered with `isLifted`, so it carries no ids), follows the pointer in `div.sortable-lift`, or, held by the keyboard, prints in the list where it would land, in `li.sortable-slot`, counted as no item. Where a pointer would drop it, a 2px dashed ink line prints beside the item it lands next to (`.drop-before`, or `.drop-after` past the last), over the layout, so nothing moves under the pointer. The pointer's place is read from the item whose centre is closest, across where items sit side by side and down a column, and read again where the pointer is let go, so a page that scrolled under a still pointer drops where the pointer is. Each step is said through the page's live region in words from the item's `label` and its place, counted from one ("Beta, 3 of 4."). The items are the parent's: a drop reports `Moved`, and the parent moves the item, or decides not to, and flashes it; a drop where the item was, outside the list, or while moves are held reports nothing. While a pointer presses or carries an item the page's root carries `data-pixel-paper-dragging`, which prints the grabbing cursor everywhere and holds text selection.
|
|
1101
1109
|
|
|
1102
1110
|
### Inputs / Fields
|
|
1103
1111
|
|
|
@@ -1139,7 +1147,7 @@ One keyboard for the page, Vim first, with the arrows beside the letters. The ke
|
|
|
1139
1147
|
|
|
1140
1148
|
### Meters and cells
|
|
1141
1149
|
|
|
1142
|
-
**Cells** (`Meter.cellsView`) → `span.cells[role="meter"] > span.cell (.on)` (`.short` for 24×8px cells). **Meter** (over `@foldkit/ui`'s Meter) → `li.meter-row (.stale)` in `Meter.listView` → `ul.meters`: a reading against a maximum in the vocabulary of `<meter>` (`value`, `max`): the label (name register) and an optional detail (meta) beside twenty cells lit in ink up to the reading; then the reading's state (the percentage in the 12px pixel face below 80% of max, the amber reading mark from 80%, a red chip at max holding `full` or the percentage; below max it never prints 100% or lights every cell, so 49,999 of 50,000 reads 99% with 19 cells); then the numbers (or `valueText`) in 11px muted tabular figures, formatted in English (`41,200`) so server and browser agree, left out with `hasNumbers: false` where they would repeat the percentage (`valueText: "62% used"` beside 62%; screen readers still hear it); then `div.meter-foot` (resets, last read; `.late` red). `ul.meters` is a size container (`container: meters`), so a row lays out by the column it is placed in, not the window: from 560px the name and detail sit in a left column (180px to 240px) beside the cells; narrower, the row stacks and the numbers take a line of their own; under 280px, 240px and 200px the cells step down to 8, 6 and 4px wide, whole pixels. A meter list fits any column from 160px; give it the column's width (a flush panel's body), since a size container takes no width from its content. A stale meter (`isStale`: the last reading failed, the numbers are the last known) prints its lit cells muted and its name ends in "(stale)" for screen readers (`span.sr-only`), so the state never rests on colour; the caller says why and when it was last read in the foot line.
|
|
1150
|
+
**Cells** (`Meter.cellsView`) → `span.cells[role="meter"] > span.cell (.on)` (`.short` for 24×8px cells). **Meter** (over `@foldkit/ui`'s Meter) → `li.meter-row (.stale, .toned (.high, .full))` in `Meter.listView` → `ul.meters`: a reading against a maximum in the vocabulary of `<meter>` (`value`, `max`): the label (name register) and an optional detail (meta) beside twenty cells lit in ink up to the reading; then the reading's state (the percentage in the 12px pixel face below 80% of max, the amber reading mark from 80%, a red chip at max holding `full` or the percentage; below max it never prints 100% or lights every cell, so 49,999 of 50,000 reads 99% with 19 cells); then the numbers (or `valueText`) in 11px muted tabular figures, formatted in English (`41,200`) so server and browser agree, left out with `hasNumbers: false` where they would repeat the percentage (`valueText: "62% used"` beside 62%; screen readers still hear it); then `div.meter-foot` (resets, last read; `.late` red). `ul.meters` is a size container (`container: meters`), so a row lays out by the column it is placed in, not the window: from 560px the name and detail sit in a left column (180px to 240px) beside the cells; narrower, the row stacks and the numbers take a line of their own; under 280px, 240px and 200px the cells step down to 8, 6 and 4px wide, whole pixels. A meter list fits any column from 160px; give it the column's width (a flush panel's body), since a size container takes no width from its content. A stale meter (`isStale`: the last reading failed, the numbers are the last known) prints its lit cells muted and its name ends in "(stale)" for screen readers (`span.sr-only`), so the state never rests on colour; the caller says why and when it was last read in the foot line. A toned meter (`isToned`) lights its cells amber from 80% (`.toned.high`) and red at max (`.toned.full`), beside the same mark or chip; for a page of readings scanned for their level, such as a wall of limits, where the cells are what the eye finds first. A stale reading's muted cells win over the tone.
|
|
1143
1151
|
|
|
1144
1152
|
### Stats
|
|
1145
1153
|
|
|
@@ -1251,7 +1259,7 @@ Each component is `src/<name>/<name>.ts` with an explicit `index.ts`, a colocate
|
|
|
1251
1259
|
- **Don't** round a corner, blur a shadow, or tint a shadow with anything other than Shadow (or Danger Shadow on a danger button).
|
|
1252
1260
|
- **Don't** use amber, green or red for decoration, and don't put an amber or green glyph on paper without its fill.
|
|
1253
1261
|
- **Don't** let a content ink (`--term-*`, `--code-*`) out of code, terminals and logs: not on a chip, a border, a state word or a person.
|
|
1254
|
-
- **Don't** colour a meter's cells by level, or highlight a search hit in amber; the warning lives in the reading and a hit is a selection.
|
|
1262
|
+
- **Don't** colour a meter's cells by level outside a toned meter, or highlight a search hit in amber; the warning lives in the reading and a hit is a selection.
|
|
1255
1263
|
- **Don't** chart in hues, curves, diagonals or filled areas, or colour a stat's change by its direction; cells and stepped lines stay ink and only a toned reading carries colour.
|
|
1256
1264
|
- **Don't** print figures as a row of raised cards each holding one big number; Stats are ruled cells in a flush panel that names what they measure.
|
|
1257
1265
|
- **Don't** build an inline arm-then-confirm button ("delete" that turns into "sure?"); the one destructive confirm is a ConfirmDialog with `isDanger`.
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { Html, HtmlBuilder } from "foldkit/html";
|
|
2
|
-
import { type GlyphName } from "./glyphs.ts";
|
|
2
|
+
import { type Cell, type GlyphName } from "./glyphs.ts";
|
|
3
3
|
/** Configuration for rendering a glyph with `view`. */
|
|
4
4
|
export type ViewConfig = Readonly<{
|
|
5
5
|
name: GlyphName;
|
|
6
6
|
/** Rendered size in px. The grid is always 12x12; 12 is the size it was drawn for. */
|
|
7
7
|
size?: number;
|
|
8
8
|
}>;
|
|
9
|
+
/** One inked rectangle of a drawing, in `currentColor`. */
|
|
10
|
+
export declare const cellView: <Message>(h: HtmlBuilder<Message>) => ([x, y, width, height]: Cell) => Html;
|
|
9
11
|
/** One glyph from the inventory, in `currentColor`. Decorative: label the control that holds
|
|
10
12
|
* it. */
|
|
11
13
|
export declare const view: <Message>(config: ViewConfig, h: HtmlBuilder<Message>) => Html;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glyph.d.ts","sourceRoot":"","sources":["../../../src/glyph/glyph.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,
|
|
1
|
+
{"version":3,"file":"glyph.d.ts","sourceRoot":"","sources":["../../../src/glyph/glyph.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,SAAS,EAAU,MAAM,aAAa,CAAC;AAMhE,uDAAuD;AACvD,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,IAAI,EAAE,SAAS,CAAC;IAChB,sFAAsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAEH,2DAA2D;AAC3D,eAAO,MAAM,QAAQ,GAClB,OAAO,KAAK,WAAW,CAAC,OAAO,CAAC,6BACT,IAAI,KAAG,IAO3B,CAAC;AAEP;UACU;AACV,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAa3E,CAAC"}
|
package/dist/src/glyph/glyph.js
CHANGED
|
@@ -3,7 +3,8 @@ import { Array } from "effect";
|
|
|
3
3
|
import { glyphs } from "./glyphs.js";
|
|
4
4
|
// VIEW
|
|
5
5
|
const DRAWN_SIZE = 12;
|
|
6
|
-
|
|
6
|
+
/** One inked rectangle of a drawing, in `currentColor`. */
|
|
7
|
+
export const cellView = (h) => __foldkitBrandViewResult((([x, y, width, height]) => __foldkitBrandViewResult((h.rect([
|
|
7
8
|
h.X(`${x}`),
|
|
8
9
|
h.Y(`${y}`),
|
|
9
10
|
h.Width(`${width}`),
|
|
@@ -374,6 +374,9 @@ export type GlyphName = {
|
|
|
374
374
|
}[keyof Families];
|
|
375
375
|
/** The rows of a drawing, trimmed: twelve strings of twelve `#` or `.` for a well-drawn glyph. */
|
|
376
376
|
export declare const artRows: (art: string) => ReadonlyArray<string>;
|
|
377
|
+
/** A drawing as rectangles one cell tall: one for each horizontal run of ink in each row,
|
|
378
|
+
* up to `width` cells into the row. */
|
|
379
|
+
export declare const toCells: (art: string, width: number) => ReadonlyArray<Cell>;
|
|
377
380
|
/** Every glyph as the rectangles `Glyph.view` draws. */
|
|
378
381
|
export declare const glyphs: Record.ReadonlyRecord<GlyphName, ReadonlyArray<Cell>>;
|
|
379
382
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glyphs.d.ts","sourceRoot":"","sources":["../../../src/glyph/glyphs.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"glyphs.d.ts","sourceRoot":"","sources":["../../../src/glyph/glyphs.ts"],"names":[],"mappings":"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"}
|
package/dist/src/glyph/glyphs.js
CHANGED
|
@@ -2589,14 +2589,15 @@ const GRID_SIZE = 12;
|
|
|
2589
2589
|
/** The rows of a drawing, trimmed: twelve strings of twelve `#` or `.` for a well-drawn glyph. */
|
|
2590
2590
|
export const artRows = (art) => __foldkitBrandViewResult((pipe(art, String.trim, String.split("\n"), Array.map(String.trim))), "@gjermundgaraba-designs/pixel-paper/src/glyph/glyphs.js#artRows");
|
|
2591
2591
|
const INK_RUN = /#+/g;
|
|
2592
|
-
/** A drawing as rectangles one cell tall: one for each horizontal run of ink in each row
|
|
2593
|
-
|
|
2592
|
+
/** A drawing as rectangles one cell tall: one for each horizontal run of ink in each row,
|
|
2593
|
+
* up to `width` cells into the row. */
|
|
2594
|
+
export const toCells = (art, width) => __foldkitBrandViewResult((Array.flatMap(artRows(art), (row, y) => __foldkitBrandViewResult((Array.map(Array.fromIterable(row.slice(0, width).matchAll(INK_RUN)), (run) => __foldkitBrandViewResult(([
|
|
2594
2595
|
run.index,
|
|
2595
2596
|
y,
|
|
2596
2597
|
run[0].length,
|
|
2597
2598
|
1,
|
|
2598
2599
|
]), "@gjermundgaraba-designs/pixel-paper/src/glyph/glyphs.js#anonymous~2"))), "@gjermundgaraba-designs/pixel-paper/src/glyph/glyphs.js#anonymous"))), "@gjermundgaraba-designs/pixel-paper/src/glyph/glyphs.js#toCells");
|
|
2599
|
-
const drawFamily = (family) => __foldkitBrandViewResult((Record.map(family, toCells)), "@gjermundgaraba-designs/pixel-paper/src/glyph/glyphs.js#drawFamily");
|
|
2600
|
+
const drawFamily = (family) => __foldkitBrandViewResult((Record.map(family, (art) => __foldkitBrandViewResult((toCells(art, GRID_SIZE)), "@gjermundgaraba-designs/pixel-paper/src/glyph/glyphs.js#anonymous~3"))), "@gjermundgaraba-designs/pixel-paper/src/glyph/glyphs.js#drawFamily");
|
|
2600
2601
|
/** Every glyph as the rectangles `Glyph.view` draws. */
|
|
2601
2602
|
export const glyphs = {
|
|
2602
2603
|
...drawFamily(direction),
|
|
@@ -5,6 +5,8 @@ export type ViewConfig = Readonly<{
|
|
|
5
5
|
label: string;
|
|
6
6
|
/** The monogram's letters, when the name's initials are not the ones people know. */
|
|
7
7
|
letters?: string;
|
|
8
|
+
/** The monogram's mark drawn in cells, in place of its letters (see Monogram). */
|
|
9
|
+
drawing?: string;
|
|
8
10
|
/** A line under the name: an id, a kind, a scope. */
|
|
9
11
|
meta?: ReadonlyArray<Html | string>;
|
|
10
12
|
/** Beside a name set large, as a card's subject. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../../src/identity/identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAOtD,2DAA2D;AAC3D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AAEH;qFACqF;AACrF,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../../src/identity/identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAOtD,2DAA2D;AAC3D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AAEH;qFACqF;AACrF,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAsB3E,CAAC"}
|
|
@@ -4,9 +4,15 @@ import { slotView } from "../slot/slot.js";
|
|
|
4
4
|
/** Who or what something is: its monogram beside its name in the sans, and a meta line.
|
|
5
5
|
* Screen readers hear the name once: the monogram beside it is hidden from them. */
|
|
6
6
|
export const view = (config, h) => {
|
|
7
|
-
const { label, letters, meta = [], isLarge = false } = config;
|
|
7
|
+
const { label, letters, drawing, meta = [], isLarge = false } = config;
|
|
8
8
|
return __foldkitBrandViewResult((h.div([h.Class(isLarge ? "identity large" : "identity")], [
|
|
9
|
-
Monogram.view({
|
|
9
|
+
Monogram.view({
|
|
10
|
+
label,
|
|
11
|
+
...(letters !== undefined && { letters }),
|
|
12
|
+
...(drawing !== undefined && { drawing }),
|
|
13
|
+
isLarge,
|
|
14
|
+
isDecorative: true,
|
|
15
|
+
}, h),
|
|
10
16
|
h.span([h.Class("identity-text")], [h.strong([], [label]), ...slotView("span", "meta", meta, h)]),
|
|
11
17
|
])), "@gjermundgaraba-designs/pixel-paper/src/identity/identity.js#view");
|
|
12
18
|
};
|
|
@@ -37,6 +37,10 @@ export type MeterConfig = Readonly<{
|
|
|
37
37
|
hasNumbers?: boolean;
|
|
38
38
|
/** In a red chip once the value reaches `max`. The percentage by default. */
|
|
39
39
|
full?: string;
|
|
40
|
+
/** The lit cells take the reading's tone as well: amber from 80%, red at `max`. For a page
|
|
41
|
+
* of readings scanned for their level, such as a wall of limits; the reading beside the
|
|
42
|
+
* cells still says it in a mark or a chip. */
|
|
43
|
+
isToned?: boolean;
|
|
40
44
|
/** The last reading failed: the cells print muted, the numbers are the last known, and
|
|
41
45
|
* screen readers hear "(stale)" after the name. Say why, and when it was last read, in
|
|
42
46
|
* `foot`. */
|
|
@@ -52,7 +56,7 @@ export type ListViewConfig = Readonly<{
|
|
|
52
56
|
* A ruled list of meters, edge to edge in a flush panel. Each is a named reading against a
|
|
53
57
|
* maximum, in the vocabulary of `<meter>`, built on `@foldkit/ui`'s Meter: 20 cells, the
|
|
54
58
|
* percentage (amber from 80%, a red chip at `max`, and neither 100% nor every cell before it),
|
|
55
|
-
* the numbers in English, a foot line. The cells are the `meter`, named by the printed label,
|
|
59
|
+
* the numbers in English, a foot line. The cells print ink unless the meter `isToned`. The cells are the `meter`, named by the printed label,
|
|
56
60
|
* with the value, the maximum and the numbers in words for screen readers.
|
|
57
61
|
*/
|
|
58
62
|
export declare const listView: <Message>(config: ListViewConfig, h: HtmlBuilder<Message>) => Html;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meter.d.ts","sourceRoot":"","sources":["../../../src/meter/meter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAatD,0DAA0D;AAC1D,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;IACjC,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,0BAA0B;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AASH;0EAC0E;AAC1E,eAAO,MAAM,SAAS,GAAI,OAAO,UAAU,WAAW,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAmBjF,CAAC;AAIF,iCAAiC;AACjC,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;IACjC,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,MAAM,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;yCACqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;uFACmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;kBAEc;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uDAAuD;IACvD,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;CACrC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"meter.d.ts","sourceRoot":"","sources":["../../../src/meter/meter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAatD,0DAA0D;AAC1D,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;IACjC,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,0BAA0B;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AASH;0EAC0E;AAC1E,eAAO,MAAM,SAAS,GAAI,OAAO,UAAU,WAAW,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAmBjF,CAAC;AAIF,iCAAiC;AACjC,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;IACjC,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,MAAM,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;yCACqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;uFACmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;mDAE+C;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;kBAEc;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uDAAuD;IACvD,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;CACrC,CAAC,CAAC;AAoGH,oEAAoE;AACpE,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;CACpC,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,GAAI,OAAO,UAAU,cAAc,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAMjF,CAAC"}
|
package/dist/src/meter/meter.js
CHANGED
|
@@ -47,18 +47,30 @@ const percentView = (config, percent, isFull, h) => {
|
|
|
47
47
|
return __foldkitBrandViewResult((h.span([h.Class("pct")], [percentText])), "@gjermundgaraba-designs/pixel-paper/src/meter/meter.js#percentView");
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
|
+
const toneClass = (value, max, isFull) => {
|
|
51
|
+
if (isFull) {
|
|
52
|
+
return __foldkitBrandViewResult((" toned full"), "@gjermundgaraba-designs/pixel-paper/src/meter/meter.js#toneClass");
|
|
53
|
+
}
|
|
54
|
+
else if (value >= max * HIGH_SHARE) {
|
|
55
|
+
return __foldkitBrandViewResult((" toned high"), "@gjermundgaraba-designs/pixel-paper/src/meter/meter.js#toneClass");
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
return __foldkitBrandViewResult((" toned"), "@gjermundgaraba-designs/pixel-paper/src/meter/meter.js#toneClass");
|
|
59
|
+
}
|
|
60
|
+
};
|
|
50
61
|
const meterView = (config, h) => {
|
|
51
|
-
const { id, label, value, max, detail = [], foot = [], isStale = false, hasNumbers = true, } = config;
|
|
62
|
+
const { id, label, value, max, detail = [], foot = [], isStale = false, hasNumbers = true, isToned = false, } = config;
|
|
52
63
|
const share = max > 0 ? Math.min(1, Math.max(0, value / max)) : 0;
|
|
53
64
|
const isFull = value >= max;
|
|
54
65
|
const numbers = config.valueText ?? numbersText(value, max, config.unit);
|
|
66
|
+
const rowClass = `meter-row${isStale ? " stale" : ""}${isToned ? toneClass(value, max, isFull) : ""}`;
|
|
55
67
|
return __foldkitBrandViewResult((UiMeter.view({
|
|
56
68
|
id,
|
|
57
69
|
value,
|
|
58
70
|
min: 0,
|
|
59
71
|
max,
|
|
60
72
|
valueText: numbers,
|
|
61
|
-
toView: (groups) => __foldkitBrandViewResult((h.keyed("li")(id, [h.Class(
|
|
73
|
+
toView: (groups) => __foldkitBrandViewResult((h.keyed("li")(id, [h.Class(rowClass)], [
|
|
62
74
|
h.div([h.Class("meter-head")], [
|
|
63
75
|
h.span([...groups.label, h.Class("meter-name")], [label, ...(isStale ? [h.span([h.Class("sr-only")], [" (stale)"])] : [])]),
|
|
64
76
|
...slotView("span", "meter-detail", detail, h),
|
|
@@ -76,7 +88,7 @@ const meterView = (config, h) => {
|
|
|
76
88
|
* A ruled list of meters, edge to edge in a flush panel. Each is a named reading against a
|
|
77
89
|
* maximum, in the vocabulary of `<meter>`, built on `@foldkit/ui`'s Meter: 20 cells, the
|
|
78
90
|
* percentage (amber from 80%, a red chip at `max`, and neither 100% nor every cell before it),
|
|
79
|
-
* the numbers in English, a foot line. The cells are the `meter`, named by the printed label,
|
|
91
|
+
* the numbers in English, a foot line. The cells print ink unless the meter `isToned`. The cells are the `meter`, named by the printed label,
|
|
80
92
|
* with the value, the maximum and the numbers in words for screen readers.
|
|
81
93
|
*/
|
|
82
94
|
export const listView = (config, h) => __foldkitBrandViewResult((h.ul(
|
|
@@ -5,6 +5,11 @@ export type ViewConfig = Readonly<{
|
|
|
5
5
|
label: string;
|
|
6
6
|
/** One or two letters, when the name's initials are not the ones people know. */
|
|
7
7
|
letters?: string;
|
|
8
|
+
/** A mark the product draws in cells, in place of the letters: rows of `#` (ink) and `.`,
|
|
9
|
+
* as a glyph is drawn, on a grid of up to 16 for a large monogram. It prints bare, in ink,
|
|
10
|
+
* a pixel per cell (two when large): a provider's own mark redrawn in the system's
|
|
11
|
+
* cells, never a picture or a brand colour. */
|
|
12
|
+
drawing?: string;
|
|
8
13
|
/** 34px, beside a name set large (a card of readings, a wall). */
|
|
9
14
|
isLarge?: boolean;
|
|
10
15
|
/** You, among others: the monogram inverts. */
|
|
@@ -13,7 +18,7 @@ export type ViewConfig = Readonly<{
|
|
|
13
18
|
* the name once, from the words. */
|
|
14
19
|
isDecorative?: boolean;
|
|
15
20
|
}>;
|
|
16
|
-
/** Letters in an ink square
|
|
17
|
-
*
|
|
21
|
+
/** Letters in an ink square, or a mark the product draws in cells: the identity of a person,
|
|
22
|
+
* a provider or a source. An image named by `label`, or hidden when `isDecorative`. */
|
|
18
23
|
export declare const view: <Message>(config: ViewConfig, h: HtmlBuilder<Message>) => Html;
|
|
19
24
|
//# sourceMappingURL=monogram.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"monogram.d.ts","sourceRoot":"","sources":["../../../src/monogram/monogram.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"monogram.d.ts","sourceRoot":"","sources":["../../../src/monogram/monogram.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAsDtD,0DAA0D;AAC1D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;oDAGgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;yCACqC;IACrC,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC,CAAC;AAEH;wFACwF;AACxF,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAmB3E,CAAC"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { brandViewResult as __foldkitBrandViewResult } from 'foldkit/brand'
|
|
2
|
-
import { Array, String, pipe } from "effect";
|
|
2
|
+
import { Array, Number, String, pipe } from "effect";
|
|
3
|
+
import { cellView } from "../glyph/glyph.js";
|
|
4
|
+
import { artRows, toCells } from "../glyph/glyphs.js";
|
|
3
5
|
// LETTERS
|
|
4
6
|
const WORD_BREAK = /[\s._-]+/;
|
|
5
7
|
const LETTER_COUNT = 2;
|
|
@@ -11,12 +13,28 @@ const initials = (name) => __foldkitBrandViewResult((pipe(name.split(WORD_BREAK)
|
|
|
11
13
|
? pipe(Array.take(words, LETTER_COUNT), Array.map((word) => __foldkitBrandViewResult((word.slice(0, 1)), "@gjermundgaraba-designs/pixel-paper/src/monogram/monogram.js#anonymous")), Array.join(""))
|
|
12
14
|
: Array.headNonEmpty(words).slice(0, LETTER_COUNT)), "@gjermundgaraba-designs/pixel-paper/src/monogram/monogram.js#onNonEmpty"),
|
|
13
15
|
}))), "@gjermundgaraba-designs/pixel-paper/src/monogram/monogram.js#initials");
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
// DRAWING
|
|
17
|
+
/** A drawing prints a pixel per cell, two in a large monogram, so its cells stay whole. */
|
|
18
|
+
const DRAWN_CELL = 1;
|
|
19
|
+
const LARGE_DRAWN_CELL = 2;
|
|
20
|
+
const drawingView = (art, isLarge, h) => {
|
|
21
|
+
const rows = artRows(art);
|
|
22
|
+
const columns = Array.reduce(rows, 0, (widest, row) => __foldkitBrandViewResult((Number.max(widest, row.length)), "@gjermundgaraba-designs/pixel-paper/src/monogram/monogram.js#anonymous~2"));
|
|
23
|
+
const cell = isLarge ? LARGE_DRAWN_CELL : DRAWN_CELL;
|
|
24
|
+
return __foldkitBrandViewResult((h.svg([
|
|
25
|
+
h.ViewBox(`0 0 ${columns} ${rows.length}`),
|
|
26
|
+
h.Width(`${columns * cell}`),
|
|
27
|
+
h.Height(`${rows.length * cell}`),
|
|
28
|
+
h.AriaHidden(true),
|
|
29
|
+
h.Class("px-icon"),
|
|
30
|
+
], Array.map(toCells(art, columns), cellView(h)))), "@gjermundgaraba-designs/pixel-paper/src/monogram/monogram.js#drawingView");
|
|
31
|
+
};
|
|
32
|
+
/** Letters in an ink square, or a mark the product draws in cells: the identity of a person,
|
|
33
|
+
* a provider or a source. An image named by `label`, or hidden when `isDecorative`. */
|
|
16
34
|
export const view = (config, h) => {
|
|
17
|
-
const { label, letters, isLarge = false, isCurrent = false, isDecorative = false } = config;
|
|
35
|
+
const { label, letters, drawing, isLarge = false, isCurrent = false, isDecorative = false, } = config;
|
|
18
36
|
return __foldkitBrandViewResult((h.span([
|
|
19
37
|
...(isDecorative ? [h.AriaHidden(true)] : [h.Role("img"), h.AriaLabel(label)]),
|
|
20
|
-
h.Class(`monogram${isLarge ? " large" : ""}${isCurrent ? " current" : ""}`),
|
|
21
|
-
], [letters ?? initials(label)])), "@gjermundgaraba-designs/pixel-paper/src/monogram/monogram.js#view");
|
|
38
|
+
h.Class(`monogram${drawing === undefined ? "" : " drawn"}${isLarge ? " large" : ""}${isCurrent ? " current" : ""}`),
|
|
39
|
+
], [drawing === undefined ? (letters ?? initials(label)) : drawingView(drawing, isLarge, h)])), "@gjermundgaraba-designs/pixel-paper/src/monogram/monogram.js#view");
|
|
22
40
|
};
|
|
@@ -9,6 +9,10 @@ export type ViewConfig = Readonly<{
|
|
|
9
9
|
id: string;
|
|
10
10
|
/** Pixel caps in the inverted title bar. */
|
|
11
11
|
title: string;
|
|
12
|
+
/** What screen readers call the panel where its title repeats among its siblings (panels
|
|
13
|
+
* titled by a kind, one per account): the title and what tells this one apart. The
|
|
14
|
+
* title names it otherwise. */
|
|
15
|
+
name?: string;
|
|
12
16
|
/** A quiet IconButton before the title, such as the grip a Sortable of panels hands each
|
|
13
17
|
* panel. On the ink bar it prints as `actions` do. */
|
|
14
18
|
lead?: ReadonlyArray<Html | string>;
|
|
@@ -26,6 +30,6 @@ export type ViewConfig = Readonly<{
|
|
|
26
30
|
/** The id of a panel's title, which names it. */
|
|
27
31
|
export declare const titleId: (id: string) => string;
|
|
28
32
|
/** The unit of the system: paper in a 2px ink box on a 5px print shadow, under a title bar. A
|
|
29
|
-
* region landmark (`<section>`) named by its `h2` title, keyed by its `id`. */
|
|
33
|
+
* region landmark (`<section>`) named by its `h2` title, or by `name`, keyed by its `id`. */
|
|
30
34
|
export declare const view: <Message>(config: ViewConfig, h: HtmlBuilder<Message>) => Html;
|
|
31
35
|
//# sourceMappingURL=panel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../../src/panel/panel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAMtD,uDAAuD;AACvD,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC;;;;kCAI8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd;2DACuD;IACvD,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;yFACqF;IACrF,OAAO,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACvC,IAAI,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACnC,2EAA2E;IAC3E,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC,uFAAuF;IACvF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AAEH,iDAAiD;AACjD,eAAO,MAAM,OAAO,OAAQ,MAAM,KAAG,MAAuB,CAAC;AAE7D;
|
|
1
|
+
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../../src/panel/panel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAMtD,uDAAuD;AACvD,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC;;;;kCAI8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd;;oCAEgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;2DACuD;IACvD,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;yFACqF;IACrF,OAAO,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACvC,IAAI,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACnC,2EAA2E;IAC3E,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC,uFAAuF;IACvF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AAEH,iDAAiD;AACjD,eAAO,MAAM,OAAO,OAAQ,MAAM,KAAG,MAAuB,CAAC;AAE7D;8FAC8F;AAC9F,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAkC3E,CAAC"}
|
package/dist/src/panel/panel.js
CHANGED
|
@@ -3,10 +3,14 @@ import { slotView } from "../slot/slot.js";
|
|
|
3
3
|
/** The id of a panel's title, which names it. */
|
|
4
4
|
export const titleId = (id) => __foldkitBrandViewResult((`${id}-title`), "@gjermundgaraba-designs/pixel-paper/src/panel/panel.js#titleId");
|
|
5
5
|
/** The unit of the system: paper in a 2px ink box on a 5px print shadow, under a title bar. A
|
|
6
|
-
* region landmark (`<section>`) named by its `h2` title, keyed by its `id`. */
|
|
6
|
+
* region landmark (`<section>`) named by its `h2` title, or by `name`, keyed by its `id`. */
|
|
7
7
|
export const view = (config, h) => {
|
|
8
|
-
const { id, title, lead = [], meta, actions = [], body, foot = [], isFlush = false } = config;
|
|
9
|
-
return __foldkitBrandViewResult((h.keyed("section")(id, [
|
|
8
|
+
const { id, title, name, lead = [], meta, actions = [], body, foot = [], isFlush = false, } = config;
|
|
9
|
+
return __foldkitBrandViewResult((h.keyed("section")(id, [
|
|
10
|
+
h.Id(id),
|
|
11
|
+
name === undefined ? h.AriaLabelledBy(titleId(id)) : h.AriaLabel(name),
|
|
12
|
+
h.Class("panel"),
|
|
13
|
+
], [
|
|
10
14
|
h.header([h.Class("panel-tb")], [
|
|
11
15
|
...slotView("span", "panel-lead", lead, h),
|
|
12
16
|
h.h2([h.Id(titleId(id))], [title]),
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { AnnounceReorder, Item, Message, Model, OutMessage, SizeLiftedItem, init, setMovable, subscriptions, update, view, } from "./sortable.ts";
|
|
1
|
+
export { AnnounceReorder, Item, Message, Model, OutMessage, SizeLiftedItem, init, isHolding, setMovable, subscriptions, update, view, } from "./sortable.ts";
|
|
2
2
|
export type { InitConfig, ItemRender, Layout, ViewInputs } from "./sortable.ts";
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/sortable/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,IAAI,EACJ,OAAO,EACP,KAAK,EACL,UAAU,EACV,cAAc,EACd,IAAI,EACJ,UAAU,EACV,aAAa,EACb,MAAM,EACN,IAAI,GACL,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/sortable/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,IAAI,EACJ,OAAO,EACP,KAAK,EACL,UAAU,EACV,cAAc,EACd,IAAI,EACJ,SAAS,EACT,UAAU,EACV,aAAa,EACb,MAAM,EACN,IAAI,GACL,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { AnnounceReorder, Item, Message, Model, OutMessage, SizeLiftedItem, init, setMovable, subscriptions, update, view, } from "./sortable.js";
|
|
1
|
+
export { AnnounceReorder, Item, Message, Model, OutMessage, SizeLiftedItem, init, isHolding, setMovable, subscriptions, update, view, } from "./sortable.js";
|
|
@@ -988,9 +988,9 @@ export type ViewInputs = Readonly<{
|
|
|
988
988
|
* `li.sortable-item`, each its grip and the parent's content (a panel holds its grip in its
|
|
989
989
|
* title bar). The items are the parent's; a drop reports `Moved`.
|
|
990
990
|
*
|
|
991
|
-
*
|
|
992
|
-
*
|
|
993
|
-
* up, every arrow moves it one place in reading order, Space drops it and Escape puts it back.
|
|
991
|
+
* Only the grip lifts an item, under every pointer, so the item's own text selects and a
|
|
992
|
+
* finger on it scrolls the page; the keyboard takes the grip too: Space or Enter picks the
|
|
993
|
+
* item up, every arrow moves it one place in reading order, Space drops it and Escape puts it back.
|
|
994
994
|
* The held item dims in place; a copy, lifted onto the card shadow, follows the pointer or
|
|
995
995
|
* prints where the keyboard would drop it; each step is said through the page's live region.
|
|
996
996
|
* Lift `subscriptions(keyPrefix)` into the application's, or nothing follows the pointer or
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sortable.d.ts","sourceRoot":"","sources":["../../../src/sortable/sortable.ts"],"names":[],"mappings":"AACA,OAAO,EAAS,MAAM,EAAS,MAAM,EAAE,MAAM,EAAE,MAAM,EAAQ,MAAM,QAAQ,CAAC;AAC5E,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAC;AAC3C,OAAO,KAAK,EAAa,IAAI,EAAe,MAAM,cAAc,CAAC;AAEjE,OAAO,KAAK,KAAK,MAAM,eAAe,CAAC;AAGvC,OAAO,KAAK,YAAY,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,MAAM,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"sortable.d.ts","sourceRoot":"","sources":["../../../src/sortable/sortable.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ import * as Subscription from "foldkit/subscription";
|
|
|
10
10
|
import * as Update from "foldkit/update";
|
|
11
11
|
import * as Announcer from "../announcer/announcer.js";
|
|
12
12
|
import * as Button from "../button/button.js";
|
|
13
|
-
import { LEFT_BUTTON, activatedKeyboardDrag, cancelledDrag, escapeKeys,
|
|
13
|
+
import { LEFT_BUTTON, activatedKeyboardDrag, cancelledDrag, escapeKeys, insertionIndex, isCarrying, markDragging, measureLift, movedPointer, phaseOf, pressedDraggable, releasedPointer, } from "../drag/drag.js";
|
|
14
14
|
import * as Glyph from "../glyph/glyph.js";
|
|
15
15
|
import * as IconButton from "../iconButton/iconButton.js";
|
|
16
16
|
import { LOCALE } from "../locale/locale.js";
|
|
@@ -112,7 +112,6 @@ const id = (model) => __foldkitBrandViewResult((model.dragAndDrop.id), "@gjermun
|
|
|
112
112
|
export const isHolding = (model) => __foldkitBrandViewResult((Option.isSome(UiDragAndDrop.maybeDraggedItemId(model.dragAndDrop))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#isHolding");
|
|
113
113
|
// DOM HOOKS
|
|
114
114
|
const itemHook = (model, itemId) => __foldkitBrandViewResult((`${id(model)}/${itemId}`), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#itemHook");
|
|
115
|
-
const ITEM_ATTRIBUTE = "sortable-item";
|
|
116
115
|
const GRIP_ATTRIBUTE = "sortable-grip";
|
|
117
116
|
// COMMAND
|
|
118
117
|
/** Says a step of a move through the page's live region (as `Announcer.Announce` does). */
|
|
@@ -349,21 +348,6 @@ export const SizeLiftedItem = Mount.define("SizeLiftedItem", {
|
|
|
349
348
|
return __foldkitBrandViewResult((Message.CompletedSizeLiftedItem()), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~33");
|
|
350
349
|
})), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#execute~2"),
|
|
351
350
|
});
|
|
352
|
-
const INNER_CONTROL = innerControls(`[data-${GRIP_ATTRIBUTE}]`);
|
|
353
|
-
/** Whether a press lifts the item: on its grip under any pointer, on its body under a mouse,
|
|
354
|
-
* and never on a control inside it. */
|
|
355
|
-
const isLiftingPress = (target, pointerType) => {
|
|
356
|
-
if (!(target instanceof Element)) {
|
|
357
|
-
return __foldkitBrandViewResult((pointerType === "mouse"), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#isLiftingPress");
|
|
358
|
-
}
|
|
359
|
-
const isOnGrip = target.closest(`[data-${GRIP_ATTRIBUTE}]`) !== null;
|
|
360
|
-
const maybeItem = Option.fromNullishOr(target.closest(`[data-${ITEM_ATTRIBUTE}]`));
|
|
361
|
-
const isOnControl = Option.exists(maybeItem, (item) => {
|
|
362
|
-
const control = target.closest(INNER_CONTROL);
|
|
363
|
-
return __foldkitBrandViewResult((control !== null && item.contains(control)), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~34");
|
|
364
|
-
});
|
|
365
|
-
return __foldkitBrandViewResult((isOnGrip || (pointerType === "mouse" && !isOnControl)), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#isLiftingPress");
|
|
366
|
-
};
|
|
367
351
|
const helpId = (model) => __foldkitBrandViewResult((`${id(model)}-grip-help`), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#helpId");
|
|
368
352
|
const isHeldItem = (model, itemId) => __foldkitBrandViewResult((UiDragAndDrop.isDragging(model.dragAndDrop) &&
|
|
369
353
|
Option.contains(UiDragAndDrop.maybeDraggedItemId(model.dragAndDrop), itemHook(model, itemId))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#isHeldItem");
|
|
@@ -378,7 +362,16 @@ const liftedView = (info, item, h) => __foldkitBrandViewResult((h.div([h.Class("
|
|
|
378
362
|
const gripView = (info, item, h) => {
|
|
379
363
|
const { model, isMovable, items } = info;
|
|
380
364
|
const isIdleNow = phaseOf(model.dragAndDrop) === "Idle";
|
|
381
|
-
const onGripKey = h.OnKeyDownPreventDefault((key) => __foldkitBrandViewResult((Option.liftPredicate(Message.PressedGripKey({ itemId: item.id, items }), () => __foldkitBrandViewResult((isIdleNow && (key === " " || key === "Enter")), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
365
|
+
const onGripKey = h.OnKeyDownPreventDefault((key) => __foldkitBrandViewResult((Option.liftPredicate(Message.PressedGripKey({ itemId: item.id, items }), () => __foldkitBrandViewResult((isIdleNow && (key === " " || key === "Enter")), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~35"))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~34"));
|
|
366
|
+
const onGripPress = h.OnPointerDown((_pointerType, button, screenX, screenY, _time, clientX, clientY, pointerId) => __foldkitBrandViewResult((Option.liftPredicate(Message.PressedItem({
|
|
367
|
+
itemId: item.id,
|
|
368
|
+
pointerId,
|
|
369
|
+
screenX,
|
|
370
|
+
screenY,
|
|
371
|
+
clientX,
|
|
372
|
+
clientY,
|
|
373
|
+
items,
|
|
374
|
+
}), () => __foldkitBrandViewResult((isIdleNow && button === LEFT_BUTTON), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~37"))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~36"));
|
|
382
375
|
// NOTE: @foldkit/ui gap: DragAndDrop's `draggable` bundle forces `role="option"`, which a
|
|
383
376
|
// plain list's items are not. So the grip carries the ui's `data-draggable-id` by hand, and
|
|
384
377
|
// FocusItem finds the grip by it. While moves are held the grip stays, held, so the focus
|
|
@@ -394,62 +387,44 @@ const gripView = (info, item, h) => {
|
|
|
394
387
|
h.AriaRoleDescription("draggable"),
|
|
395
388
|
h.AriaDescribedBy(helpId(model)),
|
|
396
389
|
Button.pressedAttribute(isHeldItem(model, item.id), h),
|
|
397
|
-
...(isMovable ? [onGripKey] : []),
|
|
390
|
+
...(isMovable ? [onGripKey, onGripPress] : []),
|
|
398
391
|
],
|
|
399
392
|
}, h)), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#gripView");
|
|
400
393
|
};
|
|
401
|
-
const itemAttributes = (info, item, h) => {
|
|
402
|
-
const { model, isMovable, items } = info;
|
|
403
|
-
const isIdleNow = phaseOf(model.dragAndDrop) === "Idle";
|
|
404
|
-
const onPress = h.OnPointerDown((pointerType, button, screenX, screenY, _time, clientX, clientY, pointerId, target) => __foldkitBrandViewResult((Option.liftPredicate(Message.PressedItem({
|
|
405
|
-
itemId: item.id,
|
|
406
|
-
pointerId,
|
|
407
|
-
screenX,
|
|
408
|
-
screenY,
|
|
409
|
-
clientX,
|
|
410
|
-
clientY,
|
|
411
|
-
items,
|
|
412
|
-
}), () => __foldkitBrandViewResult((isIdleNow && isMovable && button === LEFT_BUTTON && isLiftingPress(target, pointerType)), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~38"))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~37"));
|
|
413
|
-
return __foldkitBrandViewResult(([h.DataAttribute(ITEM_ATTRIBUTE, ""), onPress]), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#itemAttributes");
|
|
414
|
-
};
|
|
415
394
|
/** Where a pointer would drop the held item, marked on the item it would land beside: before
|
|
416
395
|
* the other item at its target, or after the last. None where it already was. */
|
|
417
|
-
const dropMarkOf = (model) => __foldkitBrandViewResult((pipe(model.maybeHeld, Option.filter(() => __foldkitBrandViewResult((phaseOf(model.dragAndDrop) === "PointerDragging"), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
418
|
-
const others = Array.filter(held.items, (item) => __foldkitBrandViewResult((item.id !== held.item.id), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
396
|
+
const dropMarkOf = (model) => __foldkitBrandViewResult((pipe(model.maybeHeld, Option.filter(() => __foldkitBrandViewResult((phaseOf(model.dragAndDrop) === "PointerDragging"), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~38")), Option.flatMap((held) => __foldkitBrandViewResult((pipe(targetIndex(model, held), Option.filter((index) => __foldkitBrandViewResult((!Option.contains(indexOf(held.items, held.item.id), index)), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~40")), Option.flatMap((index) => {
|
|
397
|
+
const others = Array.filter(held.items, (item) => __foldkitBrandViewResult((item.id !== held.item.id), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~42"));
|
|
419
398
|
return __foldkitBrandViewResult((Option.orElse(Option.map(Array.get(others, index), (item) => (__foldkitBrandViewResult(({
|
|
420
399
|
itemId: item.id,
|
|
421
400
|
side: "Before",
|
|
422
|
-
}), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
401
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~43"))), () => __foldkitBrandViewResult((Option.map(Array.last(others), (item) => (__foldkitBrandViewResult(({
|
|
423
402
|
itemId: item.id,
|
|
424
403
|
side: "After",
|
|
425
|
-
}), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
426
|
-
}))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
427
|
-
const dropClass = (info, item) => __foldkitBrandViewResult((Option.match(Option.filter(info.maybeDropMark, ({ itemId }) => __foldkitBrandViewResult((itemId === item.id), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
404
|
+
}), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~45")))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~44"))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~41");
|
|
405
|
+
}))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~39")))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#dropMarkOf");
|
|
406
|
+
const dropClass = (info, item) => __foldkitBrandViewResult((Option.match(Option.filter(info.maybeDropMark, ({ itemId }) => __foldkitBrandViewResult((itemId === item.id), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~46")), {
|
|
428
407
|
onNone: () => __foldkitBrandViewResult((""), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#onNone~5"),
|
|
429
408
|
onSome: ({ side }) => (__foldkitBrandViewResult((side === "Before" ? " drop-before" : " drop-after"), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#onSome~5")),
|
|
430
409
|
})), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#dropClass");
|
|
431
410
|
const itemClass = (info, item) => __foldkitBrandViewResult((`sortable-item${info.isMovable ? " movable" : ""}${isHeldItem(info.model, item.id) ? " drag-dim" : ""}${dropClass(info, item)}`), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#itemClass");
|
|
432
|
-
const itemView = (info, item, h) => __foldkitBrandViewResult((h.keyed("li")(item.id, [
|
|
433
|
-
...UiDragAndDrop.sortable(itemHook(info.model, item.id)),
|
|
434
|
-
...itemAttributes(info, item, h),
|
|
435
|
-
h.Class(itemClass(info, item)),
|
|
436
|
-
], itemContents(info, item, { isLifted: false, grip: gripView(info, item, h) }, h))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#itemView");
|
|
411
|
+
const itemView = (info, item, h) => __foldkitBrandViewResult((h.keyed("li")(item.id, [...UiDragAndDrop.sortable(itemHook(info.model, item.id)), h.Class(itemClass(info, item))], itemContents(info, item, { isLifted: false, grip: gripView(info, item, h) }, h))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#itemView");
|
|
437
412
|
/** The items in order, with the held item's copy where the keyboard would drop it: before the
|
|
438
413
|
* other item at its target, or last. The copy carries no `data-sortable-id`, so it is not
|
|
439
414
|
* counted as an item. */
|
|
440
415
|
const itemsView = (info, h) => {
|
|
441
416
|
const { model, items } = info;
|
|
442
|
-
const rows = Array.map(items, (item) => (__foldkitBrandViewResult(({ item, html: itemView(info, item, h) }), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
443
|
-
const maybeSlot = pipe(model.maybeHeld, Option.filter(() => __foldkitBrandViewResult((phaseOf(model.dragAndDrop) === "KeyboardDragging"), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
417
|
+
const rows = Array.map(items, (item) => (__foldkitBrandViewResult(({ item, html: itemView(info, item, h) }), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~47")));
|
|
418
|
+
const maybeSlot = pipe(model.maybeHeld, Option.filter(() => __foldkitBrandViewResult((phaseOf(model.dragAndDrop) === "KeyboardDragging"), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~48")), Option.flatMap((held) => __foldkitBrandViewResult((Option.map(targetIndex(model, held), (index) => (__foldkitBrandViewResult(({ held, index }), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~50")))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~49")));
|
|
444
419
|
return __foldkitBrandViewResult((Option.match(maybeSlot, {
|
|
445
|
-
onNone: () => __foldkitBrandViewResult((Array.map(rows, ({ html }) => __foldkitBrandViewResult((html), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
420
|
+
onNone: () => __foldkitBrandViewResult((Array.map(rows, ({ html }) => __foldkitBrandViewResult((html), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~51"))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#onNone~6"),
|
|
446
421
|
onSome: ({ held, index }) => {
|
|
447
422
|
const slot = h.keyed("li")("sortable-slot", [h.Class("sortable-slot"), h.AriaHidden(true), h.Inert(true)], [liftedView(info, held.item, h)]);
|
|
448
|
-
const others = Array.filter(rows, ({ item }) => __foldkitBrandViewResult((item.id !== held.item.id), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
423
|
+
const others = Array.filter(rows, ({ item }) => __foldkitBrandViewResult((item.id !== held.item.id), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~52"));
|
|
449
424
|
const maybeBefore = Array.get(others, index);
|
|
450
425
|
return __foldkitBrandViewResult((Option.match(maybeBefore, {
|
|
451
|
-
onNone: () => __foldkitBrandViewResult(([...Array.map(rows, ({ html }) => __foldkitBrandViewResult((html), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
452
|
-
onSome: (before) => __foldkitBrandViewResult((Array.flatMap(rows, ({ item, html }) => __foldkitBrandViewResult((item.id === before.item.id ? [slot, html] : [html]), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
426
|
+
onNone: () => __foldkitBrandViewResult(([...Array.map(rows, ({ html }) => __foldkitBrandViewResult((html), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~53")), slot]), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#onNone~7"),
|
|
427
|
+
onSome: (before) => __foldkitBrandViewResult((Array.flatMap(rows, ({ item, html }) => __foldkitBrandViewResult((item.id === before.item.id ? [slot, html] : [html]), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~54"))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#onSome~7"),
|
|
453
428
|
})), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#onSome~6");
|
|
454
429
|
},
|
|
455
430
|
})), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#itemsView");
|
|
@@ -459,7 +434,7 @@ const liftedCopyView = (info, h) => {
|
|
|
459
434
|
const maybeLifted = Option.all({
|
|
460
435
|
style: UiDragAndDrop.ghostStyle(model.dragAndDrop),
|
|
461
436
|
held: model.maybeHeld,
|
|
462
|
-
press: Option.flatMap(model.maybeHeld, ({ maybePress }) => __foldkitBrandViewResult((maybePress), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
437
|
+
press: Option.flatMap(model.maybeHeld, ({ maybePress }) => __foldkitBrandViewResult((maybePress), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~55")),
|
|
463
438
|
});
|
|
464
439
|
return __foldkitBrandViewResult((Array.fromOption(Option.map(maybeLifted, ({ style, held, press }) => __foldkitBrandViewResult((h.div([
|
|
465
440
|
h.Class("sortable-lift"),
|
|
@@ -471,18 +446,18 @@ const liftedCopyView = (info, h) => {
|
|
|
471
446
|
pressX: press.clientX,
|
|
472
447
|
pressY: press.clientY,
|
|
473
448
|
})),
|
|
474
|
-
], [liftedView(info, held.item, h)])), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
449
|
+
], [liftedView(info, held.item, h)])), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~56")))), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#liftedCopyView");
|
|
475
450
|
};
|
|
476
|
-
const layoutClass = (layout) => __foldkitBrandViewResult((Match.value(layout).pipe(Match.withReturnType(), Match.when("List", () => __foldkitBrandViewResult(("sortable"), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
451
|
+
const layoutClass = (layout) => __foldkitBrandViewResult((Match.value(layout).pipe(Match.withReturnType(), Match.when("List", () => __foldkitBrandViewResult(("sortable"), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~57")), Match.when("Grid", () => __foldkitBrandViewResult(("sortable grid"), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~58")), Match.when("Panels", () => __foldkitBrandViewResult(("sortable panels"), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~59")), Match.exhaustive)), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#layoutClass");
|
|
477
452
|
/**
|
|
478
453
|
* Items the reader puts in order, as rows, as tiles or as panels, built on `@foldkit/ui`'s
|
|
479
454
|
* DragAndDrop: `div.sortable` holding `ul.sortable-items` (named by `label`) of
|
|
480
455
|
* `li.sortable-item`, each its grip and the parent's content (a panel holds its grip in its
|
|
481
456
|
* title bar). The items are the parent's; a drop reports `Moved`.
|
|
482
457
|
*
|
|
483
|
-
*
|
|
484
|
-
*
|
|
485
|
-
* up, every arrow moves it one place in reading order, Space drops it and Escape puts it back.
|
|
458
|
+
* Only the grip lifts an item, under every pointer, so the item's own text selects and a
|
|
459
|
+
* finger on it scrolls the page; the keyboard takes the grip too: Space or Enter picks the
|
|
460
|
+
* item up, every arrow moves it one place in reading order, Space drops it and Escape puts it back.
|
|
486
461
|
* The held item dims in place; a copy, lifted onto the card shadow, follows the pointer or
|
|
487
462
|
* prints where the keyboard would drop it; each step is said through the page's live region.
|
|
488
463
|
* Lift `subscriptions(keyPrefix)` into the application's, or nothing follows the pointer or
|
|
@@ -509,5 +484,5 @@ export const view = defineView((model, viewInputs, h) => {
|
|
|
509
484
|
], itemsView(info, h)),
|
|
510
485
|
h.p([h.Id(helpId(model)), h.Class("sr-only")], [COPY.gripHelp]),
|
|
511
486
|
...liftedCopyView(info, h),
|
|
512
|
-
])), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~
|
|
487
|
+
])), "@gjermundgaraba-designs/pixel-paper/src/sortable/sortable.js#anonymous~60");
|
|
513
488
|
});
|
package/package.json
CHANGED
package/src/glyph/glyph.ts
CHANGED
|
@@ -14,7 +14,8 @@ export type ViewConfig = Readonly<{
|
|
|
14
14
|
size?: number;
|
|
15
15
|
}>;
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
/** One inked rectangle of a drawing, in `currentColor`. */
|
|
18
|
+
export const cellView =
|
|
18
19
|
<Message>(h: HtmlBuilder<Message>) =>
|
|
19
20
|
([x, y, width, height]: Cell): Html =>
|
|
20
21
|
h.rect([
|
package/src/glyph/glyphs.ts
CHANGED
|
@@ -2614,10 +2614,11 @@ export const artRows = (art: string): ReadonlyArray<string> =>
|
|
|
2614
2614
|
|
|
2615
2615
|
const INK_RUN = /#+/g;
|
|
2616
2616
|
|
|
2617
|
-
/** A drawing as rectangles one cell tall: one for each horizontal run of ink in each row
|
|
2618
|
-
|
|
2617
|
+
/** A drawing as rectangles one cell tall: one for each horizontal run of ink in each row,
|
|
2618
|
+
* up to `width` cells into the row. */
|
|
2619
|
+
export const toCells = (art: string, width: number): ReadonlyArray<Cell> =>
|
|
2619
2620
|
Array.flatMap(artRows(art), (row, y) =>
|
|
2620
|
-
Array.map(Array.fromIterable(row.slice(0,
|
|
2621
|
+
Array.map(Array.fromIterable(row.slice(0, width).matchAll(INK_RUN)), (run): Cell => [
|
|
2621
2622
|
run.index,
|
|
2622
2623
|
y,
|
|
2623
2624
|
run[0].length,
|
|
@@ -2627,7 +2628,8 @@ const toCells = (art: string): ReadonlyArray<Cell> =>
|
|
|
2627
2628
|
|
|
2628
2629
|
const drawFamily = <Name extends string>(
|
|
2629
2630
|
family: Record.ReadonlyRecord<Name, string>,
|
|
2630
|
-
): Record.ReadonlyRecord<Name, ReadonlyArray<Cell>> =>
|
|
2631
|
+
): Record.ReadonlyRecord<Name, ReadonlyArray<Cell>> =>
|
|
2632
|
+
Record.map(family, (art) => toCells(art, GRID_SIZE));
|
|
2631
2633
|
|
|
2632
2634
|
/** Every glyph as the rectangles `Glyph.view` draws. */
|
|
2633
2635
|
export const glyphs: Record.ReadonlyRecord<GlyphName, ReadonlyArray<Cell>> = {
|
package/src/identity/identity.ts
CHANGED
|
@@ -11,6 +11,8 @@ export type ViewConfig = Readonly<{
|
|
|
11
11
|
label: string;
|
|
12
12
|
/** The monogram's letters, when the name's initials are not the ones people know. */
|
|
13
13
|
letters?: string;
|
|
14
|
+
/** The monogram's mark drawn in cells, in place of its letters (see Monogram). */
|
|
15
|
+
drawing?: string;
|
|
14
16
|
/** A line under the name: an id, a kind, a scope. */
|
|
15
17
|
meta?: ReadonlyArray<Html | string>;
|
|
16
18
|
/** Beside a name set large, as a card's subject. */
|
|
@@ -20,13 +22,19 @@ export type ViewConfig = Readonly<{
|
|
|
20
22
|
/** Who or what something is: its monogram beside its name in the sans, and a meta line.
|
|
21
23
|
* Screen readers hear the name once: the monogram beside it is hidden from them. */
|
|
22
24
|
export const view = <Message>(config: ViewConfig, h: HtmlBuilder<Message>): Html => {
|
|
23
|
-
const { label, letters, meta = [], isLarge = false } = config;
|
|
25
|
+
const { label, letters, drawing, meta = [], isLarge = false } = config;
|
|
24
26
|
|
|
25
27
|
return h.div(
|
|
26
28
|
[h.Class(isLarge ? "identity large" : "identity")],
|
|
27
29
|
[
|
|
28
30
|
Monogram.view(
|
|
29
|
-
{
|
|
31
|
+
{
|
|
32
|
+
label,
|
|
33
|
+
...(letters !== undefined && { letters }),
|
|
34
|
+
...(drawing !== undefined && { drawing }),
|
|
35
|
+
isLarge,
|
|
36
|
+
isDecorative: true,
|
|
37
|
+
},
|
|
30
38
|
h,
|
|
31
39
|
),
|
|
32
40
|
h.span(
|
package/src/meter/meter.ts
CHANGED
|
@@ -81,6 +81,10 @@ export type MeterConfig = Readonly<{
|
|
|
81
81
|
hasNumbers?: boolean;
|
|
82
82
|
/** In a red chip once the value reaches `max`. The percentage by default. */
|
|
83
83
|
full?: string;
|
|
84
|
+
/** The lit cells take the reading's tone as well: amber from 80%, red at `max`. For a page
|
|
85
|
+
* of readings scanned for their level, such as a wall of limits; the reading beside the
|
|
86
|
+
* cells still says it in a mark or a chip. */
|
|
87
|
+
isToned?: boolean;
|
|
84
88
|
/** The last reading failed: the cells print muted, the numbers are the last known, and
|
|
85
89
|
* screen readers hear "(stale)" after the name. Say why, and when it was last read, in
|
|
86
90
|
* `foot`. */
|
|
@@ -119,6 +123,16 @@ const percentView = <Message>(
|
|
|
119
123
|
}
|
|
120
124
|
};
|
|
121
125
|
|
|
126
|
+
const toneClass = (value: number, max: number, isFull: boolean): string => {
|
|
127
|
+
if (isFull) {
|
|
128
|
+
return " toned full";
|
|
129
|
+
} else if (value >= max * HIGH_SHARE) {
|
|
130
|
+
return " toned high";
|
|
131
|
+
} else {
|
|
132
|
+
return " toned";
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
122
136
|
const meterView = <Message>(config: MeterConfig, h: HtmlBuilder<Message>): Html => {
|
|
123
137
|
const {
|
|
124
138
|
id,
|
|
@@ -129,10 +143,12 @@ const meterView = <Message>(config: MeterConfig, h: HtmlBuilder<Message>): Html
|
|
|
129
143
|
foot = [],
|
|
130
144
|
isStale = false,
|
|
131
145
|
hasNumbers = true,
|
|
146
|
+
isToned = false,
|
|
132
147
|
} = config;
|
|
133
148
|
const share = max > 0 ? Math.min(1, Math.max(0, value / max)) : 0;
|
|
134
149
|
const isFull = value >= max;
|
|
135
150
|
const numbers = config.valueText ?? numbersText(value, max, config.unit);
|
|
151
|
+
const rowClass = `meter-row${isStale ? " stale" : ""}${isToned ? toneClass(value, max, isFull) : ""}`;
|
|
136
152
|
|
|
137
153
|
return UiMeter.view(
|
|
138
154
|
{
|
|
@@ -144,7 +160,7 @@ const meterView = <Message>(config: MeterConfig, h: HtmlBuilder<Message>): Html
|
|
|
144
160
|
toView: (groups) =>
|
|
145
161
|
h.keyed("li")(
|
|
146
162
|
id,
|
|
147
|
-
[h.Class(
|
|
163
|
+
[h.Class(rowClass)],
|
|
148
164
|
[
|
|
149
165
|
h.div(
|
|
150
166
|
[h.Class("meter-head")],
|
|
@@ -184,7 +200,7 @@ export type ListViewConfig = Readonly<{
|
|
|
184
200
|
* A ruled list of meters, edge to edge in a flush panel. Each is a named reading against a
|
|
185
201
|
* maximum, in the vocabulary of `<meter>`, built on `@foldkit/ui`'s Meter: 20 cells, the
|
|
186
202
|
* percentage (amber from 80%, a red chip at `max`, and neither 100% nor every cell before it),
|
|
187
|
-
* the numbers in English, a foot line. The cells are the `meter`, named by the printed label,
|
|
203
|
+
* the numbers in English, a foot line. The cells print ink unless the meter `isToned`. The cells are the `meter`, named by the printed label,
|
|
188
204
|
* with the value, the maximum and the numbers in words for screen readers.
|
|
189
205
|
*/
|
|
190
206
|
export const listView = <Message>(config: ListViewConfig, h: HtmlBuilder<Message>): Html =>
|
package/src/monogram/monogram.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { Array, String, pipe } from "effect";
|
|
1
|
+
import { Array, Number, String, pipe } from "effect";
|
|
2
2
|
import type { Html, HtmlBuilder } from "foldkit/html";
|
|
3
3
|
|
|
4
|
+
import { cellView } from "../glyph/glyph.ts";
|
|
5
|
+
import { artRows, toCells } from "../glyph/glyphs.ts";
|
|
6
|
+
|
|
4
7
|
// LETTERS
|
|
5
8
|
|
|
6
9
|
const WORD_BREAK = /[\s._-]+/;
|
|
@@ -25,6 +28,29 @@ const initials = (name: string): string =>
|
|
|
25
28
|
}),
|
|
26
29
|
);
|
|
27
30
|
|
|
31
|
+
// DRAWING
|
|
32
|
+
|
|
33
|
+
/** A drawing prints a pixel per cell, two in a large monogram, so its cells stay whole. */
|
|
34
|
+
const DRAWN_CELL = 1;
|
|
35
|
+
const LARGE_DRAWN_CELL = 2;
|
|
36
|
+
|
|
37
|
+
const drawingView = <Message>(art: string, isLarge: boolean, h: HtmlBuilder<Message>): Html => {
|
|
38
|
+
const rows = artRows(art);
|
|
39
|
+
const columns = Array.reduce(rows, 0, (widest, row) => Number.max(widest, row.length));
|
|
40
|
+
const cell = isLarge ? LARGE_DRAWN_CELL : DRAWN_CELL;
|
|
41
|
+
|
|
42
|
+
return h.svg(
|
|
43
|
+
[
|
|
44
|
+
h.ViewBox(`0 0 ${columns} ${rows.length}`),
|
|
45
|
+
h.Width(`${columns * cell}`),
|
|
46
|
+
h.Height(`${rows.length * cell}`),
|
|
47
|
+
h.AriaHidden(true),
|
|
48
|
+
h.Class("px-icon"),
|
|
49
|
+
],
|
|
50
|
+
Array.map(toCells(art, columns), cellView(h)),
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
28
54
|
// VIEW
|
|
29
55
|
|
|
30
56
|
/** Configuration for rendering a monogram with `view`. */
|
|
@@ -33,6 +59,11 @@ export type ViewConfig = Readonly<{
|
|
|
33
59
|
label: string;
|
|
34
60
|
/** One or two letters, when the name's initials are not the ones people know. */
|
|
35
61
|
letters?: string;
|
|
62
|
+
/** A mark the product draws in cells, in place of the letters: rows of `#` (ink) and `.`,
|
|
63
|
+
* as a glyph is drawn, on a grid of up to 16 for a large monogram. It prints bare, in ink,
|
|
64
|
+
* a pixel per cell (two when large): a provider's own mark redrawn in the system's
|
|
65
|
+
* cells, never a picture or a brand colour. */
|
|
66
|
+
drawing?: string;
|
|
36
67
|
/** 34px, beside a name set large (a card of readings, a wall). */
|
|
37
68
|
isLarge?: boolean;
|
|
38
69
|
/** You, among others: the monogram inverts. */
|
|
@@ -42,16 +73,25 @@ export type ViewConfig = Readonly<{
|
|
|
42
73
|
isDecorative?: boolean;
|
|
43
74
|
}>;
|
|
44
75
|
|
|
45
|
-
/** Letters in an ink square
|
|
46
|
-
*
|
|
76
|
+
/** Letters in an ink square, or a mark the product draws in cells: the identity of a person,
|
|
77
|
+
* a provider or a source. An image named by `label`, or hidden when `isDecorative`. */
|
|
47
78
|
export const view = <Message>(config: ViewConfig, h: HtmlBuilder<Message>): Html => {
|
|
48
|
-
const {
|
|
79
|
+
const {
|
|
80
|
+
label,
|
|
81
|
+
letters,
|
|
82
|
+
drawing,
|
|
83
|
+
isLarge = false,
|
|
84
|
+
isCurrent = false,
|
|
85
|
+
isDecorative = false,
|
|
86
|
+
} = config;
|
|
49
87
|
|
|
50
88
|
return h.span(
|
|
51
89
|
[
|
|
52
90
|
...(isDecorative ? [h.AriaHidden(true)] : [h.Role("img"), h.AriaLabel(label)]),
|
|
53
|
-
h.Class(
|
|
91
|
+
h.Class(
|
|
92
|
+
`monogram${drawing === undefined ? "" : " drawn"}${isLarge ? " large" : ""}${isCurrent ? " current" : ""}`,
|
|
93
|
+
),
|
|
54
94
|
],
|
|
55
|
-
[letters ?? initials(label)],
|
|
95
|
+
[drawing === undefined ? (letters ?? initials(label)) : drawingView(drawing, isLarge, h)],
|
|
56
96
|
);
|
|
57
97
|
};
|
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
|
@@ -3369,24 +3369,16 @@ dialog.veil:focus {
|
|
|
3369
3369
|
min-width: 0;
|
|
3370
3370
|
}
|
|
3371
3371
|
|
|
3372
|
-
.sortable-item.movable {
|
|
3373
|
-
cursor: grab;
|
|
3374
|
-
}
|
|
3375
|
-
|
|
3376
3372
|
.sortable-item [data-sortable-grip] {
|
|
3377
3373
|
flex: none;
|
|
3378
3374
|
}
|
|
3379
3375
|
|
|
3376
|
+
/* the grip is the only handle: the rest of the item selects its text and scrolls the page */
|
|
3380
3377
|
.sortable-item.movable [data-sortable-grip] {
|
|
3381
3378
|
cursor: grab;
|
|
3382
|
-
/* the grip is where a finger drags; the rest of the item scrolls the page */
|
|
3383
3379
|
touch-action: none;
|
|
3384
3380
|
}
|
|
3385
3381
|
|
|
3386
|
-
.sortable-item.movable:hover {
|
|
3387
|
-
background: var(--head);
|
|
3388
|
-
}
|
|
3389
|
-
|
|
3390
3382
|
.sortable-item.drag-dim {
|
|
3391
3383
|
opacity: 0.4;
|
|
3392
3384
|
}
|
|
@@ -3489,10 +3481,6 @@ dialog.veil:focus {
|
|
|
3489
3481
|
background: none;
|
|
3490
3482
|
}
|
|
3491
3483
|
|
|
3492
|
-
.sortable.panels .sortable-item.movable:hover {
|
|
3493
|
-
background: none;
|
|
3494
|
-
}
|
|
3495
|
-
|
|
3496
3484
|
.sortable.panels .sortable-body {
|
|
3497
3485
|
height: 100%;
|
|
3498
3486
|
}
|
|
@@ -3667,6 +3655,16 @@ dialog.veil:focus {
|
|
|
3667
3655
|
flex-wrap: wrap;
|
|
3668
3656
|
}
|
|
3669
3657
|
|
|
3658
|
+
/* a toned meter's lit cells take its reading's tone, amber from 80% and red at the maximum,
|
|
3659
|
+
unless the reading is stale */
|
|
3660
|
+
.meter-row.toned.high:not(.stale) .cells .cell.on {
|
|
3661
|
+
background: var(--amber);
|
|
3662
|
+
}
|
|
3663
|
+
|
|
3664
|
+
.meter-row.toned.full:not(.stale) .cells .cell.on {
|
|
3665
|
+
background: var(--red);
|
|
3666
|
+
}
|
|
3667
|
+
|
|
3670
3668
|
/* a stale reading prints its cells muted: the number is last known, not current */
|
|
3671
3669
|
.meter-row.stale .cells .cell.on {
|
|
3672
3670
|
background: var(--muted);
|
|
@@ -4534,7 +4532,7 @@ dialog.veil:focus {
|
|
|
4534
4532
|
position: absolute;
|
|
4535
4533
|
}
|
|
4536
4534
|
|
|
4537
|
-
/* ---------- monograms: letters in an ink square,
|
|
4535
|
+
/* ---------- monograms: letters in an ink square, or a mark the product draws in cells ---------- */
|
|
4538
4536
|
|
|
4539
4537
|
.monogram {
|
|
4540
4538
|
display: inline-grid;
|
|
@@ -4563,6 +4561,16 @@ dialog.veil:focus {
|
|
|
4563
4561
|
color: var(--paper);
|
|
4564
4562
|
}
|
|
4565
4563
|
|
|
4564
|
+
/* a mark drawn in cells prints bare, in ink, in the square the letters would take */
|
|
4565
|
+
.monogram.drawn {
|
|
4566
|
+
border: 0;
|
|
4567
|
+
background: none;
|
|
4568
|
+
}
|
|
4569
|
+
|
|
4570
|
+
.monogram.drawn.current {
|
|
4571
|
+
background: var(--ink);
|
|
4572
|
+
}
|
|
4573
|
+
|
|
4566
4574
|
/* ---------- identity: who or what, as its monogram beside its name ---------- */
|
|
4567
4575
|
|
|
4568
4576
|
.identity {
|
package/src/sortable/index.ts
CHANGED
package/src/sortable/sortable.ts
CHANGED
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
activatedKeyboardDrag,
|
|
17
17
|
cancelledDrag,
|
|
18
18
|
escapeKeys,
|
|
19
|
-
innerControls,
|
|
20
19
|
insertionIndex,
|
|
21
20
|
isCarrying,
|
|
22
21
|
markDragging,
|
|
@@ -158,7 +157,6 @@ export const isHolding = (model: Model): boolean =>
|
|
|
158
157
|
|
|
159
158
|
const itemHook = (model: Model, itemId: string): string => `${id(model)}/${itemId}`;
|
|
160
159
|
|
|
161
|
-
const ITEM_ATTRIBUTE = "sortable-item";
|
|
162
160
|
const GRIP_ATTRIBUTE = "sortable-grip";
|
|
163
161
|
|
|
164
162
|
// COMMAND
|
|
@@ -596,25 +594,6 @@ export type ViewInputs = Readonly<{
|
|
|
596
594
|
toItemView: (item: Item, render: ItemRender) => ReadonlyArray<Html>;
|
|
597
595
|
}>;
|
|
598
596
|
|
|
599
|
-
const INNER_CONTROL = innerControls(`[data-${GRIP_ATTRIBUTE}]`);
|
|
600
|
-
|
|
601
|
-
/** Whether a press lifts the item: on its grip under any pointer, on its body under a mouse,
|
|
602
|
-
* and never on a control inside it. */
|
|
603
|
-
const isLiftingPress = (target: EventTarget | null, pointerType: string): boolean => {
|
|
604
|
-
if (!(target instanceof Element)) {
|
|
605
|
-
return pointerType === "mouse";
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
const isOnGrip = target.closest(`[data-${GRIP_ATTRIBUTE}]`) !== null;
|
|
609
|
-
const maybeItem = Option.fromNullishOr(target.closest(`[data-${ITEM_ATTRIBUTE}]`));
|
|
610
|
-
const isOnControl = Option.exists(maybeItem, (item) => {
|
|
611
|
-
const control = target.closest(INNER_CONTROL);
|
|
612
|
-
return control !== null && item.contains(control);
|
|
613
|
-
});
|
|
614
|
-
|
|
615
|
-
return isOnGrip || (pointerType === "mouse" && !isOnControl);
|
|
616
|
-
};
|
|
617
|
-
|
|
618
597
|
type ListInfo = Readonly<{
|
|
619
598
|
model: Model;
|
|
620
599
|
layout: Layout;
|
|
@@ -666,6 +645,22 @@ const gripView = (info: ListInfo, item: Item, h: HtmlBuilder<Message>): Html =>
|
|
|
666
645
|
),
|
|
667
646
|
);
|
|
668
647
|
|
|
648
|
+
const onGripPress: Attribute<Message> = h.OnPointerDown(
|
|
649
|
+
(_pointerType, button, screenX, screenY, _time, clientX, clientY, pointerId) =>
|
|
650
|
+
Option.liftPredicate(
|
|
651
|
+
Message.PressedItem({
|
|
652
|
+
itemId: item.id,
|
|
653
|
+
pointerId,
|
|
654
|
+
screenX,
|
|
655
|
+
screenY,
|
|
656
|
+
clientX,
|
|
657
|
+
clientY,
|
|
658
|
+
items,
|
|
659
|
+
}),
|
|
660
|
+
() => isIdleNow && button === LEFT_BUTTON,
|
|
661
|
+
),
|
|
662
|
+
);
|
|
663
|
+
|
|
669
664
|
// NOTE: @foldkit/ui gap: DragAndDrop's `draggable` bundle forces `role="option"`, which a
|
|
670
665
|
// plain list's items are not. So the grip carries the ui's `data-draggable-id` by hand, and
|
|
671
666
|
// FocusItem finds the grip by it. While moves are held the grip stays, held, so the focus
|
|
@@ -682,41 +677,13 @@ const gripView = (info: ListInfo, item: Item, h: HtmlBuilder<Message>): Html =>
|
|
|
682
677
|
h.AriaRoleDescription("draggable"),
|
|
683
678
|
h.AriaDescribedBy(helpId(model)),
|
|
684
679
|
Button.pressedAttribute(isHeldItem(model, item.id), h),
|
|
685
|
-
...(isMovable ? [onGripKey] : []),
|
|
680
|
+
...(isMovable ? [onGripKey, onGripPress] : []),
|
|
686
681
|
],
|
|
687
682
|
},
|
|
688
683
|
h,
|
|
689
684
|
);
|
|
690
685
|
};
|
|
691
686
|
|
|
692
|
-
const itemAttributes = (
|
|
693
|
-
info: ListInfo,
|
|
694
|
-
item: Item,
|
|
695
|
-
h: HtmlBuilder<Message>,
|
|
696
|
-
): ReadonlyArray<Attribute<Message>> => {
|
|
697
|
-
const { model, isMovable, items } = info;
|
|
698
|
-
const isIdleNow = phaseOf(model.dragAndDrop) === "Idle";
|
|
699
|
-
|
|
700
|
-
const onPress = h.OnPointerDown(
|
|
701
|
-
(pointerType, button, screenX, screenY, _time, clientX, clientY, pointerId, target) =>
|
|
702
|
-
Option.liftPredicate(
|
|
703
|
-
Message.PressedItem({
|
|
704
|
-
itemId: item.id,
|
|
705
|
-
pointerId,
|
|
706
|
-
screenX,
|
|
707
|
-
screenY,
|
|
708
|
-
clientX,
|
|
709
|
-
clientY,
|
|
710
|
-
items,
|
|
711
|
-
}),
|
|
712
|
-
() =>
|
|
713
|
-
isIdleNow && isMovable && button === LEFT_BUTTON && isLiftingPress(target, pointerType),
|
|
714
|
-
),
|
|
715
|
-
);
|
|
716
|
-
|
|
717
|
-
return [h.DataAttribute(ITEM_ATTRIBUTE, ""), onPress];
|
|
718
|
-
};
|
|
719
|
-
|
|
720
687
|
type DropMark = Readonly<{ itemId: string; side: "Before" | "After" }>;
|
|
721
688
|
|
|
722
689
|
/** Where a pointer would drop the held item, marked on the item it would land beside: before
|
|
@@ -762,11 +729,7 @@ const itemClass = (info: ListInfo, item: Item): string =>
|
|
|
762
729
|
const itemView = (info: ListInfo, item: Item, h: HtmlBuilder<Message>): Html =>
|
|
763
730
|
h.keyed("li")(
|
|
764
731
|
item.id,
|
|
765
|
-
[
|
|
766
|
-
...UiDragAndDrop.sortable(itemHook(info.model, item.id)),
|
|
767
|
-
...itemAttributes(info, item, h),
|
|
768
|
-
h.Class(itemClass(info, item)),
|
|
769
|
-
],
|
|
732
|
+
[...UiDragAndDrop.sortable(itemHook(info.model, item.id)), h.Class(itemClass(info, item))],
|
|
770
733
|
itemContents(info, item, { isLifted: false, grip: gripView(info, item, h) }, h),
|
|
771
734
|
);
|
|
772
735
|
|
|
@@ -849,9 +812,9 @@ const layoutClass = (layout: Layout): string =>
|
|
|
849
812
|
* `li.sortable-item`, each its grip and the parent's content (a panel holds its grip in its
|
|
850
813
|
* title bar). The items are the parent's; a drop reports `Moved`.
|
|
851
814
|
*
|
|
852
|
-
*
|
|
853
|
-
*
|
|
854
|
-
* up, every arrow moves it one place in reading order, Space drops it and Escape puts it back.
|
|
815
|
+
* Only the grip lifts an item, under every pointer, so the item's own text selects and a
|
|
816
|
+
* finger on it scrolls the page; the keyboard takes the grip too: Space or Enter picks the
|
|
817
|
+
* item up, every arrow moves it one place in reading order, Space drops it and Escape puts it back.
|
|
855
818
|
* The held item dims in place; a copy, lifted onto the card shadow, follows the pointer or
|
|
856
819
|
* prints where the keyboard would drop it; each step is said through the page's live region.
|
|
857
820
|
* Lift `subscriptions(keyPrefix)` into the application's, or nothing follows the pointer or
|