@syware/jlib 0.1.3 → 0.2.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.
@@ -2,7 +2,7 @@ import { BASE_STYLES } from "../styles/shared.js";
2
2
  import { JlElement } from "../base/jl-element.js";
3
3
  import { oneOf } from "../lib/attributes.js";
4
4
  import { registerIcons } from "../lib/icons.js";
5
- import { TONE_ICONS } from "../lib/options.js";
5
+ import { TONE_ICONS, TONE_ICON_FILLED } from "../lib/options.js";
6
6
  import { JlIcon } from "../atoms/jl-icon.js";
7
7
  import { JlButton } from "../atoms/jl-button.js";
8
8
  import jl_toast_default from "./jl-toast.css_raw.js";
@@ -257,9 +257,11 @@ var JlToast = class extends JlElement {
257
257
  holdsFocus(next) {
258
258
  return next instanceof Node && (next === this || this.contains(next) || this._refs.toast.contains(next));
259
259
  }
260
+ /** The tone's own icon is filled, so its colour shows at a glance; an icon of the page's stays as it is drawn. */
260
261
  renderIcon() {
261
262
  const icon = this.icon.get();
262
263
  this._refs.icon.name.set(icon === "" ? TONE_ICONS[this.tone.get()] : icon);
264
+ this._refs.icon.filled.set(icon === "" && TONE_ICON_FILLED[this.tone.get()]);
263
265
  }
264
266
  /** Inside a toaster, its live region announces the toast; alone, the toast is its own. */
265
267
  renderRole() {
@@ -0,0 +1,3 @@
1
+ // src/organisms/jl-flow.css?raw
2
+ var jl_flow_default = ":host {\n display: block;\n height: 420px;\n min-height: 0;\n}\n\n.viewport {\n position: relative;\n height: 100%;\n overflow: clip;\n border: 1px solid var(--jl-line);\n border-radius: var(--jl-radius-lg);\n background-color: var(--jl-surface-2);\n background-image: radial-gradient(circle, var(--jl-line-strong) 1px, transparent 1.2px);\n outline: none;\n touch-action: none;\n user-select: none;\n}\n\n.viewport:focus-visible {\n box-shadow: var(--jl-focus-ring);\n}\n\n.world,\n.nodes,\n.edges {\n position: absolute;\n top: 0;\n left: 0;\n}\n\n.world {\n transform-origin: 0 0;\n}\n\n.edges {\n overflow: visible;\n pointer-events: none;\n}\n\n.edge {\n fill: none;\n stroke: color-mix(in srgb, var(--tone, var(--jl-muted)) 60%, var(--jl-line-strong));\n stroke-width: 2;\n stroke-linecap: round;\n}\n\n.edge[data-tone=\"danger\"] {\n stroke-dasharray: 6 5;\n}\n\n.edge-hit {\n fill: none;\n stroke: transparent;\n stroke-width: 14;\n pointer-events: stroke;\n cursor: pointer;\n}\n\n.edge-group:hover .edge {\n stroke: var(--tone, var(--jl-muted));\n}\n\n.edge-group.selected .edge {\n stroke: var(--jl-accent);\n stroke-width: 3;\n}\n\n.draft {\n stroke: var(--jl-accent);\n stroke-dasharray: 5 5;\n}\n\n.node {\n --tone: var(--jl-accent);\n position: absolute;\n top: 0;\n left: 0;\n display: flex;\n align-items: center;\n gap: var(--jl-space-3);\n width: 240px;\n height: 64px;\n padding: 0 var(--jl-space-3) var(--jl-space-1);\n border: 1px solid var(--jl-line);\n border-radius: var(--jl-radius-lg);\n background: var(--jl-surface);\n box-shadow: var(--jl-shadow-sm);\n cursor: grab;\n transition:\n border-color var(--jl-fast) var(--jl-ease),\n box-shadow var(--jl-fast) var(--jl-ease);\n}\n\n.node:hover {\n border-color: var(--jl-line-strong);\n}\n\n.node:focus-visible {\n outline: none;\n box-shadow: var(--jl-focus-ring);\n}\n\n.node.selected {\n border-color: var(--jl-accent);\n box-shadow: 0 0 0 3px var(--jl-accent-soft);\n}\n\n.input {\n position: absolute;\n top: -5px;\n left: 50%;\n width: 10px;\n height: 10px;\n border: 2px solid var(--jl-surface);\n border-radius: 50%;\n background: var(--jl-line-strong);\n transform: translateX(-50%);\n}\n\n.icon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: var(--jl-radius);\n background: color-mix(in srgb, var(--tone) 14%, var(--jl-surface));\n color: var(--tone);\n}\n\n.text {\n display: grid;\n min-width: 0;\n}\n\n.label,\n.description {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.label {\n color: var(--jl-text);\n font-size: var(--jl-font-sm);\n font-weight: 600;\n}\n\n.description {\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n}\n\n.ports {\n position: absolute;\n right: 0;\n bottom: -11px;\n left: 0;\n height: 22px;\n}\n\n.port {\n --tone: var(--jl-muted);\n position: absolute;\n top: 0;\n display: inline-flex;\n align-items: center;\n gap: var(--jl-space-1);\n height: 22px;\n padding: 0 7px;\n border: 1px solid color-mix(in srgb, var(--tone) 35%, var(--jl-line));\n border-radius: var(--jl-radius-pill);\n background: var(--jl-surface);\n color: color-mix(in srgb, var(--tone) 80%, var(--jl-text));\n font-size: var(--jl-font-xs);\n font-weight: 600;\n white-space: nowrap;\n transform: translateX(-50%);\n cursor: crosshair;\n}\n\n.port:has(.add) {\n padding-right: 3px;\n}\n\n.dot {\n flex: none;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--tone);\n}\n\n.port-label {\n overflow: hidden;\n min-width: 0;\n text-overflow: ellipsis;\n}\n\n.add,\n.remove-edge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n border-radius: 50%;\n cursor: pointer;\n}\n\n.add {\n width: 16px;\n height: 16px;\n border: none;\n background: color-mix(in srgb, var(--tone) 16%, var(--jl-surface));\n color: var(--tone);\n}\n\n.add:hover {\n background: var(--tone);\n color: var(--jl-surface);\n}\n\n.remove-edge {\n position: absolute;\n top: 0;\n left: 0;\n width: 24px;\n height: 24px;\n border: 1px solid var(--jl-line);\n background: var(--jl-surface);\n color: var(--jl-danger);\n}\n\n.remove-edge:hover {\n border-color: var(--jl-danger);\n background: var(--jl-danger);\n color: var(--jl-on-danger);\n}\n\n.empty {\n position: absolute;\n inset: 0;\n display: grid;\n place-items: center;\n padding: var(--jl-space-6);\n color: var(--jl-muted);\n text-align: center;\n pointer-events: none;\n}\n\n.empty[hidden] {\n display: none;\n}\n\n.empty ::slotted(*) {\n pointer-events: auto;\n}\n\n.controls {\n position: absolute;\n bottom: var(--jl-space-3);\n left: var(--jl-space-3);\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 2px;\n border: 1px solid var(--jl-line);\n border-radius: var(--jl-radius);\n background: var(--jl-surface);\n}\n\n/* The zoom buttons: small and quiet, as ghost buttons. */\n.control {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--jl-control-sm);\n height: var(--jl-control-sm);\n padding: 0;\n border: none;\n border-radius: var(--jl-radius-sm);\n background: transparent;\n color: var(--jl-accent);\n cursor: pointer;\n transition: background var(--jl-fast) var(--jl-ease);\n}\n\n.control:hover {\n background: var(--jl-accent-soft);\n}\n\n.zoom-label {\n min-width: 40px;\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n font-variant-numeric: tabular-nums;\n text-align: center;\n}\n\n/* The tones of icons, exits and edges: after .node and .port, whose default tones they replace. */\n[data-tone=\"neutral\"] {\n --tone: var(--jl-muted);\n}\n\n[data-tone=\"accent\"] {\n --tone: var(--jl-accent);\n}\n\n[data-tone=\"ok\"] {\n --tone: var(--jl-ok);\n}\n\n[data-tone=\"warn\"] {\n --tone: var(--jl-warn);\n}\n\n[data-tone=\"danger\"] {\n --tone: var(--jl-danger);\n}\n\n[data-tone=\"info\"] {\n --tone: var(--jl-info);\n}\n\n/* View only: nodes are pressed to be selected, not dragged, and their exits do not connect. */\n:host([readonly]) .node,\n:host([readonly]) .port {\n cursor: pointer;\n}\n\n/* View only: the layout stays as it was given. */\n:host([readonly]) .tidy {\n display: none;\n}\n";
3
+ export { jl_flow_default as default };
@@ -0,0 +1,86 @@
1
+ import { JlElement } from '../base/jl-element';
2
+ import type { FlowAddRequest, FlowGraph } from '../types/jl-flow.types';
3
+ /**
4
+ * A flow of nodes joined by edges, to edit: people move the nodes, draw an edge from a node's exit to another node,
5
+ * press + on a free exit to ask for the next node, and move and zoom the view. Every edit goes out as a new graph
6
+ * (`change`); the page adds nodes itself, when `add` asks.
7
+ */
8
+ export declare class JlFlow extends JlElement {
9
+ static readonly selector = "jl-flow";
10
+ readonly events: Readonly<import("@jadis/core").UseEventsHandler<{
11
+ change: FlowGraph;
12
+ select: string;
13
+ add: FlowAddRequest;
14
+ }>>;
15
+ readonly graph: Readonly<Readonly<{
16
+ get(): FlowGraph;
17
+ set(setter: FlowGraph | ((prevState: FlowGraph) => FlowGraph)): void;
18
+ }>>;
19
+ /** The id of the selected node; the view moves to show it. */
20
+ readonly selected: Readonly<Readonly<{
21
+ get(): string;
22
+ set(setter: string | ((prevState: string) => string)): void;
23
+ }>>;
24
+ /** View only: nodes can be selected, not moved, joined or removed. */
25
+ readonly readonly: Readonly<Readonly<{
26
+ get(): boolean;
27
+ set(setter: boolean | ((prevState: boolean) => boolean)): void;
28
+ }>>;
29
+ /** The canvas's name for screen readers. */
30
+ readonly label: Readonly<Readonly<{
31
+ get(): string;
32
+ set(setter: string | ((prevState: string) => string)): void;
33
+ }>>;
34
+ private readonly _state;
35
+ private readonly _nodes;
36
+ private readonly _svg;
37
+ private readonly _refs;
38
+ /** Moves and zooms the view to show every node, never larger than life. */
39
+ fit(): void;
40
+ /** Lays the nodes out again, in rows from the starts down (`change` gives the new positions), and shows them all. */
41
+ layout(): void;
42
+ templateHtml(): Node;
43
+ templateCss(): string;
44
+ onConnect(): void;
45
+ private show;
46
+ /** An edit: drawn, kept, and sent to the page. */
47
+ private commit;
48
+ private select;
49
+ private selectEdge;
50
+ private removeSelection;
51
+ private nodeOf;
52
+ private pointerDown;
53
+ private gestureFor;
54
+ private pointerMove;
55
+ private drag;
56
+ private drawDraft;
57
+ private pointerUp;
58
+ /** An edge dropped on a node joins it; dropped on empty space, it asks for a node there. */
59
+ private connectAt;
60
+ private pressAdd;
61
+ private key;
62
+ /** The arrows move the selected node; with Shift, further. */
63
+ private nudge;
64
+ /** Moves the view, when needed, so that a node is in sight: one just added, or moved with the keys. */
65
+ private reveal;
66
+ /** Two fingers or the wheel move the view; with Ctrl or ⌘ (a pinch on a trackpad), they zoom. */
67
+ private wheel;
68
+ private zoomBy;
69
+ private setViewport;
70
+ private applyViewport;
71
+ private screenPoint;
72
+ private worldPoint;
73
+ private render;
74
+ /** The nodes' elements stay from one drawing to the next: the focused one keeps the focus. */
75
+ private renderNodes;
76
+ private createNode;
77
+ private drawNode;
78
+ private portElement;
79
+ private place;
80
+ private renderSelection;
81
+ private renderEdges;
82
+ /** An edge, with a wide invisible twin that catches the pointer: a thin line is still easy to press. */
83
+ private edgeGroup;
84
+ /** The button that removes the selected edge, in its middle. */
85
+ private renderEdgeTool;
86
+ }