@syware/jlib 0.1.3 → 0.3.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/README.md +3 -17
- package/dist/all.js +5 -4
- package/dist/atoms/jl-icon.css_raw.js +1 -1
- package/dist/atoms/jl-icon.d.ts +7 -1
- package/dist/atoms/jl-icon.js +4 -1
- package/dist/atoms/jl-input.d.ts +1 -0
- package/dist/atoms/jl-input.js +2 -0
- package/dist/atoms/jl-progress-ring.js +1 -6
- package/dist/atoms/jl-select.d.ts +6 -0
- package/dist/atoms/jl-select.js +18 -1
- package/dist/atoms/jl-switch.d.ts +12 -1
- package/dist/atoms/jl-switch.js +11 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -3
- package/dist/lib/calendar.d.ts +15 -1
- package/dist/lib/calendar.js +72 -1
- package/dist/lib/dom.d.ts +2 -0
- package/dist/lib/dom.js +8 -1
- package/dist/lib/flow.d.ts +70 -0
- package/dist/lib/flow.js +353 -0
- package/dist/lib/options.d.ts +5 -0
- package/dist/lib/options.js +13 -1
- package/dist/molecules/jl-accordion-item.css_raw.js +1 -1
- package/dist/molecules/jl-accordion-item.d.ts +6 -1
- package/dist/molecules/jl-accordion-item.js +21 -6
- package/dist/molecules/jl-alert.d.ts +1 -0
- package/dist/molecules/jl-alert.js +3 -1
- package/dist/molecules/jl-date-picker.d.ts +10 -4
- package/dist/molecules/jl-date-picker.js +21 -8
- package/dist/molecules/jl-search.d.ts +3 -1
- package/dist/molecules/jl-search.js +8 -6
- package/dist/molecules/jl-segmented.css_raw.js +1 -1
- package/dist/molecules/jl-segmented.js +14 -7
- package/dist/molecules/jl-stat.css_raw.js +1 -1
- package/dist/molecules/jl-stat.d.ts +6 -0
- package/dist/molecules/jl-stat.js +6 -0
- package/dist/molecules/jl-steps.css_raw.js +1 -1
- package/dist/molecules/jl-timeline.css_raw.js +1 -1
- package/dist/molecules/jl-timeline.d.ts +2 -1
- package/dist/molecules/jl-timeline.js +18 -16
- package/dist/molecules/jl-toast.css_raw.js +1 -1
- package/dist/molecules/jl-toast.d.ts +1 -0
- package/dist/molecules/jl-toast.js +3 -1
- package/dist/organisms/jl-flow.css_raw.js +3 -0
- package/dist/organisms/jl-flow.d.ts +109 -0
- package/dist/organisms/jl-flow.js +755 -0
- package/dist/types/calendar.types.d.ts +2 -0
- package/dist/types/jl-flow.types.d.ts +94 -0
- package/dist/types/jl-segmented.types.d.ts +2 -0
- package/package.json +1 -1
|
@@ -77,6 +77,13 @@ var JlSearch = class extends JlFormControl {
|
|
|
77
77
|
select() {
|
|
78
78
|
this._refs.native.select();
|
|
79
79
|
}
|
|
80
|
+
/** Empties the field, as its clear button does: `input` and `search` fire with `''`, and it takes the focus. */
|
|
81
|
+
clear() {
|
|
82
|
+
this.value.set("");
|
|
83
|
+
this.events.emit("input", "");
|
|
84
|
+
this.search("");
|
|
85
|
+
this.focus();
|
|
86
|
+
}
|
|
80
87
|
templateHtml() {
|
|
81
88
|
return /* @__PURE__ */ jsxs("div", {
|
|
82
89
|
class: "control",
|
|
@@ -151,6 +158,7 @@ var JlSearch = class extends JlFormControl {
|
|
|
151
158
|
if (event.key === "Enter") {
|
|
152
159
|
event.preventDefault();
|
|
153
160
|
this.search(this.value.get());
|
|
161
|
+
this.events.emit("enter", this.value.get());
|
|
154
162
|
return;
|
|
155
163
|
}
|
|
156
164
|
if (event.key === "Escape" && this.value.get() !== "") {
|
|
@@ -178,12 +186,6 @@ var JlSearch = class extends JlFormControl {
|
|
|
178
186
|
this._state.lastSearch = query;
|
|
179
187
|
this.events.emit("search", query);
|
|
180
188
|
}
|
|
181
|
-
clear() {
|
|
182
|
-
this.value.set("");
|
|
183
|
-
this.events.emit("input", "");
|
|
184
|
-
this.search("");
|
|
185
|
-
this.focus();
|
|
186
|
-
}
|
|
187
189
|
renderValue(value) {
|
|
188
190
|
const native = this._refs.native;
|
|
189
191
|
if (native.value !== value) native.value = value;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/molecules/jl-segmented.css?raw
|
|
2
|
-
var jl_segmented_default = ":host {\n display: inline-flex;\n vertical-align: middle;\n /* Its own width, even as a grid or flex item that would stretch it: block asks for the whole width. */\n justify-self: start;\n max-width: 100%;\n --height: var(--jl-control-md);\n --pad: 12px;\n --font-size: var(--jl-font-sm);\n}\n\n:host([size=\"sm\"]) {\n --height: var(--jl-control-sm);\n --pad: 10px;\n --font-size: var(--jl-font-xs);\n}\n\n:host([size=\"lg\"]) {\n --height: var(--jl-control-lg);\n --pad: 16px;\n --font-size: var(--jl-font-md);\n}\n\n:host([block]) {\n display: flex;\n justify-self: stretch;\n}\n\n.group {\n position: relative;\n display: flex;\n flex: 1;\n overflow-x: auto;\n scrollbar-width: none;\n min-width: 0;\n height: var(--height);\n padding: 2px;\n border: 1px solid var(--jl-line);\n border-radius: var(--jl-radius-sm);\n background: var(--jl-surface-2);\n}\n\n.segment {\n position: relative;\n z-index: 1;\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n gap: 6px;\n min-width: calc(var(--height) - 6px);\n padding: 0 var(--pad);\n border: none;\n border-radius: calc(var(--jl-radius-sm) - 3px);\n background: none;\n color: var(--jl-muted);\n font-size: var(--font-size);\n font-weight: 600;\n white-space: nowrap;\n cursor: pointer;\n transition: color var(--jl-fast) var(--jl-ease);\n}\n\n.segment:hover:not(:disabled) {\n color: var(--jl-text);\n}\n\n.segment[aria-checked=\"true\"] {\n color: var(--jl-text);\n}\n\n.segment:disabled {\n cursor: not-allowed;\n opacity: 0.45;\n}\n\n:host([block]) .segment {\n flex: 1 1 0;\n}\n\n/* The chosen option's raised surface, slid under it. */\n.thumb {\n position: absolute;\n top: 0;\n left: 0;\n width: var(--w);\n height: var(--h);\n border: 1px solid var(--jl-line-strong);\n border-radius: calc(var(--jl-radius-sm) - 3px);\n /* Raised over the track: white on light grey, a lighter grey on a dark ground. */\n background: light-dark(var(--jl-surface), var(--jl-surface-3));\n box-shadow: var(--jl-shadow-sm);\n transform: translate(var(--x), var(--y));\n pointer-events: none;\n}\n\n.thumb[data-placed] {\n transition:\n transform var(--jl-slow) var(--jl-ease),\n width var(--jl-slow) var(--jl-ease);\n}\n\n.group[aria-disabled] {\n opacity: 0.55;\n}\n\n.group[aria-disabled] .segment {\n opacity: 1;\n}\n\n/* The track scrolls when the options do not fit: a ring drawn outside the segment would be cut. */\n.segment:focus-visible {\n box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--jl-brand) 60%, transparent);\n}\n";
|
|
2
|
+
var jl_segmented_default = ":host {\n display: inline-flex;\n vertical-align: middle;\n /* Its own width, even as a grid or flex item that would stretch it: block asks for the whole width. */\n justify-self: start;\n max-width: 100%;\n --height: var(--jl-control-md);\n --pad: 12px;\n --font-size: var(--jl-font-sm);\n}\n\n:host([size=\"sm\"]) {\n --height: var(--jl-control-sm);\n --pad: 10px;\n --font-size: var(--jl-font-xs);\n}\n\n:host([size=\"lg\"]) {\n --height: var(--jl-control-lg);\n --pad: 16px;\n --font-size: var(--jl-font-md);\n}\n\n:host([block]) {\n display: flex;\n justify-self: stretch;\n}\n\n.group {\n position: relative;\n display: flex;\n flex: 1;\n overflow-x: auto;\n scrollbar-width: none;\n min-width: 0;\n height: var(--height);\n padding: 2px;\n border: 1px solid var(--jl-line);\n border-radius: var(--jl-radius-sm);\n background: var(--jl-surface-2);\n}\n\n.segment {\n position: relative;\n z-index: 1;\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n gap: 6px;\n min-width: calc(var(--height) - 6px);\n padding: 0 var(--pad);\n border: none;\n border-radius: calc(var(--jl-radius-sm) - 3px);\n background: none;\n color: var(--jl-muted);\n font-size: var(--font-size);\n font-weight: 600;\n white-space: nowrap;\n cursor: pointer;\n transition: color var(--jl-fast) var(--jl-ease);\n}\n\n.segment:hover:not(:disabled) {\n color: var(--jl-text);\n}\n\n.segment[aria-checked=\"true\"] {\n color: var(--jl-text);\n}\n\n.badge {\n min-width: 18px;\n padding: 0 6px;\n border-radius: var(--jl-radius-pill);\n background: var(--jl-surface-3);\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n font-weight: 650;\n line-height: 18px;\n text-align: center;\n}\n\n.segment[aria-checked=\"true\"] .badge {\n background: var(--jl-accent-soft);\n color: var(--jl-accent);\n}\n\n.segment:disabled {\n cursor: not-allowed;\n opacity: 0.45;\n}\n\n:host([block]) .segment {\n flex: 1 1 0;\n}\n\n/* The chosen option's raised surface, slid under it. */\n.thumb {\n position: absolute;\n top: 0;\n left: 0;\n width: var(--w);\n height: var(--h);\n border: 1px solid var(--jl-line-strong);\n border-radius: calc(var(--jl-radius-sm) - 3px);\n /* Raised over the track: white on light grey, a lighter grey on a dark ground. */\n background: light-dark(var(--jl-surface), var(--jl-surface-3));\n box-shadow: var(--jl-shadow-sm);\n transform: translate(var(--x), var(--y));\n pointer-events: none;\n}\n\n.thumb[data-placed] {\n transition:\n transform var(--jl-slow) var(--jl-ease),\n width var(--jl-slow) var(--jl-ease);\n}\n\n.group[aria-disabled] {\n opacity: 0.55;\n}\n\n.group[aria-disabled] .segment {\n opacity: 1;\n}\n\n/* The track scrolls when the options do not fit: a ring drawn outside the segment would be cut. */\n.segment:focus-visible {\n box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--jl-brand) 60%, transparent);\n}\n";
|
|
3
3
|
export { jl_segmented_default as default };
|
|
@@ -126,13 +126,20 @@ var JlSegmented = class extends JlFormControl {
|
|
|
126
126
|
class: "segment",
|
|
127
127
|
"data-value": option.value,
|
|
128
128
|
"data-disabled": option.disabled === true ? "" : void 0,
|
|
129
|
-
children: [
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
129
|
+
children: [
|
|
130
|
+
option.icon === void 0 ? "" : /* @__PURE__ */ jsx(JlIcon, {
|
|
131
|
+
name: option.icon,
|
|
132
|
+
size: iconSize
|
|
133
|
+
}),
|
|
134
|
+
label === "" ? "" : /* @__PURE__ */ jsx("span", {
|
|
135
|
+
class: "label",
|
|
136
|
+
children: label
|
|
137
|
+
}),
|
|
138
|
+
option.badge === void 0 ? "" : /* @__PURE__ */ jsx("span", {
|
|
139
|
+
class: "badge",
|
|
140
|
+
children: String(option.badge)
|
|
141
|
+
})
|
|
142
|
+
]
|
|
136
143
|
});
|
|
137
144
|
}
|
|
138
145
|
/** The chosen option's index: the one `value` names, or else the first that can be chosen. */
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/molecules/jl-stat.css?raw
|
|
2
|
-
var jl_stat_default = ":host {\n display: block;\n --mood: var(--jl-muted);\n}\n\n:host([mood=\"good\"]) {\n --mood: var(--jl-ok);\n}\n\n:host([mood=\"bad\"]) {\n --mood: var(--jl-danger);\n}\n\n.stat {\n display: grid;\n gap: 4px;\n min-width: 0;\n}\n\n.top {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.label {\n flex: 1;\n min-width: 0;\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n font-weight: 600;\n line-height: 1.4;\n}\n\n.icon {\n color: var(--jl-faint);\n}\n\n.figure {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n column-gap: 10px;\n}\n\n.value {\n color: var(--jl-text);\n font-size: var(--jl-font-2xl);\n font-variant-numeric: tabular-nums;\n font-weight: 700;\n letter-spacing: -0.02em;\n line-height: 1.2;\n}\n\n.delta {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n color: var(--mood);\n font-size: var(--jl-font-sm);\n font-variant-numeric: tabular-nums;\n font-weight: 650;\n white-space: nowrap;\n}\n\n.caption {\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n line-height: 1.4;\n}\n\n.spark {\n height: 36px;\n margin-top: 8px;\n}\n\n.spark svg {\n display: block;\n width: 100%;\n height: 100%;\n overflow: visible;\n}\n\n.line {\n fill: none;\n stroke: var(--jl-accent);\n stroke-linecap: round;\n stroke-linejoin: round;\n stroke-width: 2;\n vector-effect: non-scaling-stroke;\n}\n\n.area {\n fill: color-mix(in srgb, var(--jl-accent) 10%, transparent);\n stroke: none;\n}\n";
|
|
2
|
+
var jl_stat_default = ":host {\n display: block;\n --mood: var(--jl-muted);\n}\n\n:host([mood=\"good\"]) {\n --mood: var(--jl-ok);\n}\n\n:host([mood=\"bad\"]) {\n --mood: var(--jl-danger);\n}\n\n.stat {\n display: grid;\n gap: 4px;\n min-width: 0;\n}\n\n.top {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.label {\n flex: 1;\n min-width: 0;\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n font-weight: 600;\n line-height: 1.4;\n}\n\n.icon {\n color: var(--jl-faint);\n}\n\n:host([tone=\"accent\"]) .icon {\n color: var(--jl-accent);\n}\n\n:host([tone=\"ok\"]) .icon {\n color: var(--jl-ok);\n}\n\n:host([tone=\"warn\"]) .icon {\n color: var(--jl-warn);\n}\n\n:host([tone=\"danger\"]) .icon {\n color: var(--jl-danger);\n}\n\n:host([tone=\"info\"]) .icon {\n color: var(--jl-info);\n}\n\n.figure {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n column-gap: 10px;\n}\n\n.value {\n color: var(--jl-text);\n font-size: var(--jl-font-2xl);\n font-variant-numeric: tabular-nums;\n font-weight: 700;\n letter-spacing: -0.02em;\n line-height: 1.2;\n}\n\n.delta {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n color: var(--mood);\n font-size: var(--jl-font-sm);\n font-variant-numeric: tabular-nums;\n font-weight: 650;\n white-space: nowrap;\n}\n\n.caption {\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n line-height: 1.4;\n}\n\n.spark {\n height: 36px;\n margin-top: 8px;\n}\n\n.spark svg {\n display: block;\n width: 100%;\n height: 100%;\n overflow: visible;\n}\n\n.line {\n fill: none;\n stroke: var(--jl-accent);\n stroke-linecap: round;\n stroke-linejoin: round;\n stroke-width: 2;\n vector-effect: non-scaling-stroke;\n}\n\n.area {\n fill: color-mix(in srgb, var(--jl-accent) 10%, transparent);\n stroke: none;\n}\n";
|
|
3
3
|
export { jl_stat_default as default };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { JlElement } from '../base/jl-element';
|
|
2
2
|
import type { StatTrend } from '../types/jl-stat.types';
|
|
3
|
+
import type { Tone } from '../types/options.types';
|
|
3
4
|
export declare const STAT_TRENDS: readonly StatTrend[];
|
|
4
5
|
/**
|
|
5
6
|
* A key figure: what it measures, its value, how it moved (`delta`, coloured by its trend) and an optional
|
|
@@ -36,6 +37,11 @@ export declare class JlStat extends JlElement {
|
|
|
36
37
|
get(): string;
|
|
37
38
|
set(setter: string | ((prevState: string) => string)): void;
|
|
38
39
|
}>>;
|
|
40
|
+
/** The colour of the icon: neutral (quiet) by default, or what the figure is about (`ok`, `info`…). */
|
|
41
|
+
readonly tone: Readonly<Readonly<{
|
|
42
|
+
get(): Tone;
|
|
43
|
+
set(setter: ((prevState: Tone) => Tone) | Tone): void;
|
|
44
|
+
}>>;
|
|
39
45
|
/** A note under the figure: "vs. last month". */
|
|
40
46
|
readonly caption: Readonly<Readonly<{
|
|
41
47
|
get(): string;
|
|
@@ -2,6 +2,7 @@ import { BASE_STYLES } from "../styles/shared.js";
|
|
|
2
2
|
import { JlElement } from "../base/jl-element.js";
|
|
3
3
|
import { jsonOf, oneOf } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
|
+
import { TONES } from "../lib/options.js";
|
|
5
6
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
6
7
|
import { areaAttribute, pointsAttribute, sparklinePoints } from "../lib/sparkline.js";
|
|
7
8
|
import { trendOfDelta } from "../lib/trend.js";
|
|
@@ -71,6 +72,11 @@ var JlStat = class extends JlElement {
|
|
|
71
72
|
this._refs.icon.name.set(value);
|
|
72
73
|
this._refs.icon.hidden = value === "";
|
|
73
74
|
}, { attribute: "icon" });
|
|
75
|
+
/** The colour of the icon: neutral (quiet) by default, or what the figure is about (`ok`, `info`…). */
|
|
76
|
+
tone = this.useChange("neutral", (value) => this.reflect("tone", value), {
|
|
77
|
+
attribute: "tone",
|
|
78
|
+
parse: oneOf(TONES, "neutral")
|
|
79
|
+
});
|
|
74
80
|
/** A note under the figure: "vs. last month". */
|
|
75
81
|
caption = this.useChange("", (value) => {
|
|
76
82
|
this._refs.caption.textContent = value;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/molecules/jl-steps.css?raw
|
|
2
|
-
var jl_steps_default = ":host {\n display: block;\n container-type: inline-size;\n --marker: 28px;\n}\n\nol {\n display: flex;\n padding: 0;\n list-style: none;\n}\n\n.step {\n display: flex;\n flex: 1;\n min-width: 0;\n}\n\n.step:last-child {\n flex: none;\n}\n\n.head {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n padding: 0;\n border: none;\n border-radius: var(--jl-radius-xs);\n background: none;\n text-align: start;\n}\n\nbutton.head {\n cursor: pointer;\n}\n\n.marker {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: var(--marker);\n height: var(--marker);\n border: 1px solid var(--jl-line-strong);\n border-radius: 50%;\n background: var(--jl-surface);\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n font-weight: 650;\n font-variant-numeric: tabular-nums;\n}\n\n.text {\n display: grid;\n gap: 2px;\n min-width: 0;\n padding-top: 4px;\n}\n\n.label {\n color: var(--jl-muted);\n font-size: var(--jl-font-md);\n font-weight: 600;\n line-height: 20px;\n}\n\n.description {\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n line-height: 1.45;\n}\n\n.step[data-status=\"done\"] .marker {\n border-color: var(--jl-accent-line);\n background: var(--jl-accent-soft);\n color: var(--jl-accent);\n}\n\n.step[data-status=\"done\"] .label {\n color: var(--jl-text);\n}\n\n.step[data-status=\"current\"] .marker {\n border-color: var(--jl-accent);\n background: var(--jl-accent);\n color: var(--jl-on-accent);\n box-shadow: 0 0 0 4px var(--jl-accent-soft);\n}\n\n.step[data-status=\"current\"] .label {\n color: var(--jl-
|
|
2
|
+
var jl_steps_default = ":host {\n display: block;\n container-type: inline-size;\n --marker: 28px;\n}\n\nol {\n display: flex;\n padding: 0;\n list-style: none;\n}\n\n.step {\n display: flex;\n flex: 1;\n min-width: 0;\n}\n\n.step:last-child {\n flex: none;\n}\n\n.head {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n padding: 0;\n border: none;\n border-radius: var(--jl-radius-xs);\n background: none;\n text-align: start;\n}\n\nbutton.head {\n cursor: pointer;\n}\n\n.marker {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: var(--marker);\n height: var(--marker);\n border: 1px solid var(--jl-line-strong);\n border-radius: 50%;\n background: var(--jl-surface);\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n font-weight: 650;\n font-variant-numeric: tabular-nums;\n}\n\n.text {\n display: grid;\n gap: 2px;\n min-width: 0;\n padding-top: 4px;\n}\n\n.label {\n color: var(--jl-muted);\n font-size: var(--jl-font-md);\n font-weight: 600;\n line-height: 20px;\n}\n\n.description {\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n line-height: 1.45;\n}\n\n.step[data-status=\"done\"] .marker {\n border-color: var(--jl-accent-line);\n background: var(--jl-accent-soft);\n color: var(--jl-accent);\n}\n\n.step[data-status=\"done\"] .label {\n color: var(--jl-text);\n}\n\n.step[data-status=\"current\"] .marker {\n border-color: var(--jl-accent);\n background: var(--jl-accent);\n color: var(--jl-on-accent);\n box-shadow: 0 0 0 4px var(--jl-accent-soft);\n}\n\n.step[data-status=\"current\"] .label {\n color: var(--jl-accent);\n font-weight: 700;\n}\n\nbutton.head:hover .label {\n text-decoration: underline;\n text-underline-offset: 3px;\n}\n\n.line {\n flex: 1;\n min-width: 24px;\n height: 1px;\n /* Further from the label before it than from the next marker: a label reads as its own step's. */\n margin: calc(var(--marker) / 2) 12px 0 20px;\n background: var(--jl-line-strong);\n}\n\n.step[data-status=\"done\"] .line {\n background: var(--jl-accent);\n}\n\n.step:last-child .line {\n display: none;\n}\n\n/* Vertical: the markers in a column joined by a rule, the text beside them. */\n:host([orientation=\"vertical\"]) ol {\n flex-direction: column;\n}\n\n:host([orientation=\"vertical\"]) .step {\n position: relative;\n flex: none;\n padding-bottom: 24px;\n}\n\n:host([orientation=\"vertical\"]) .step:last-child {\n padding-bottom: 0;\n}\n\n:host([orientation=\"vertical\"]) .line {\n position: absolute;\n top: calc(var(--marker) + 4px);\n bottom: 4px;\n left: calc(var(--marker) / 2 - 0.5px);\n width: 1px;\n height: auto;\n min-width: 0;\n margin: 0;\n}\n\n/* Narrow, the horizontal steps keep their markers and only the current step's text. */\n@container (width < 560px) {\n /* Out of sight, still read: the same rules as .sr-only. */\n :host(:not([orientation=\"vertical\"])) .step:not([data-status=\"current\"]) .text {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n }\n\n :host(:not([orientation=\"vertical\"])) .description {\n display: none;\n }\n\n :host(:not([orientation=\"vertical\"])) .line {\n min-width: 8px;\n margin: calc(var(--marker) / 2) 8px 0;\n }\n\n /* The current step takes three shares of the room, the others one, never less than their marker and line: the\n label never runs into the next step, and takes an ellipsis only when there is no room at all. */\n :host(:not([orientation=\"vertical\"])) .step:not([data-status=\"current\"]) {\n min-width: min-content;\n }\n\n :host(:not([orientation=\"vertical\"])) .step[data-status=\"current\"] {\n flex: 3 1 0;\n }\n\n :host(:not([orientation=\"vertical\"])) .step[data-status=\"current\"] .label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n :host(:not([orientation=\"vertical\"])) .step[data-status=\"current\"] .line {\n min-width: 24px;\n margin-left: 16px;\n }\n}\n";
|
|
3
3
|
export { jl_steps_default as default };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/molecules/jl-timeline.css?raw
|
|
2
|
-
var jl_timeline_default = ":host {\n display: block;\n --marker: 22px;\n --gap: 20px;\n --title-size: var(--jl-font-md);\n}\n\n:host([compact]) {\n --marker: 18px;\n --gap: 12px;\n --title-size: var(--jl-font-sm);\n}\n\n.timeline {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.event {\n position: relative;\n display: grid;\n grid-template-columns: var(--marker) minmax(0, 1fr);\n
|
|
2
|
+
var jl_timeline_default = ":host {\n display: block;\n --marker: 22px;\n --gap: 20px;\n --title-size: var(--jl-font-md);\n}\n\n:host([compact]) {\n --marker: 18px;\n --gap: 12px;\n --title-size: var(--jl-font-sm);\n}\n\n.timeline {\n /* The markers (and the room after them), the times and the texts in three columns shared by every event: the times\n line up beside their markers, each next to its title, however wide the timeline. Without any time, the middle\n column takes no room. */\n display: grid;\n grid-template-columns: calc(var(--marker) + 12px) auto minmax(0, 1fr);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.event {\n position: relative;\n display: grid;\n grid-column: 1 / -1;\n /* Browsers without subgrid keep the columns per event. */\n grid-template-columns: calc(var(--marker) + 12px) auto minmax(0, 1fr);\n padding-bottom: var(--gap);\n --tone: var(--jl-muted);\n --soft: var(--jl-surface-3);\n}\n\n@supports (grid-template-columns: subgrid) {\n .event {\n grid-template-columns: subgrid;\n }\n}\n\n.event:last-child {\n padding-bottom: 0;\n}\n\n.event[data-tone=\"accent\"] {\n --tone: var(--jl-accent);\n --soft: var(--jl-accent-soft);\n}\n\n.event[data-tone=\"ok\"] {\n --tone: var(--jl-ok);\n --soft: var(--jl-ok-soft);\n}\n\n.event[data-tone=\"warn\"] {\n --tone: var(--jl-warn);\n --soft: var(--jl-warn-soft);\n}\n\n.event[data-tone=\"danger\"] {\n --tone: var(--jl-danger);\n --soft: var(--jl-danger-soft);\n}\n\n.event[data-tone=\"info\"] {\n --tone: var(--jl-info);\n --soft: var(--jl-info-soft);\n}\n\n/* The line runs from this marker's centre to the next one's, behind the markers. */\n.event:not(:last-child)::before {\n position: absolute;\n top: 10px;\n bottom: -10px;\n left: calc(var(--marker) / 2 - 0.5px);\n width: 1px;\n background: var(--jl-line-strong);\n content: \"\";\n}\n\n.rail {\n position: relative;\n grid-column: 1;\n width: var(--marker);\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n height: 20px;\n}\n\n.marker {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n}\n\n.dot {\n width: 10px;\n height: 10px;\n background: var(--tone);\n box-shadow: 0 0 0 3px var(--jl-surface);\n}\n\n:host([compact]) .dot {\n width: 8px;\n height: 8px;\n}\n\n.circle {\n width: var(--marker);\n height: var(--marker);\n border: 1px solid color-mix(in srgb, var(--tone) 30%, var(--soft));\n background: var(--soft);\n color: var(--tone);\n box-shadow: 0 0 0 3px var(--jl-surface);\n}\n\n.content {\n display: grid;\n grid-column: 3;\n gap: 2px;\n}\n\n.title {\n color: var(--jl-text);\n font-size: var(--title-size);\n font-weight: 600;\n line-height: 20px;\n}\n\n.time {\n grid-column: 2;\n padding-right: 12px;\n color: var(--jl-muted);\n font-family: var(--jl-font-mono);\n font-size: var(--jl-font-xs);\n /* On the title's line. */\n line-height: 20px;\n white-space: nowrap;\n}\n\n.description {\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n line-height: 1.5;\n}\n\n:host([compact]) .description {\n font-size: var(--jl-font-xs);\n}\n";
|
|
3
3
|
export { jl_timeline_default as default };
|
|
@@ -2,7 +2,8 @@ import { JlElement } from '../base/jl-element';
|
|
|
2
2
|
import type { TimelineItem } from '../types/jl-timeline.types';
|
|
3
3
|
/**
|
|
4
4
|
* What happened, in order, along a vertical line: each event a dot (or an icon in a circle) in its tone's colour,
|
|
5
|
-
*
|
|
5
|
+
* its time beside the marker (the times in one column), a title and an optional description. `compact` tightens it
|
|
6
|
+
* for side panels.
|
|
6
7
|
*/
|
|
7
8
|
export declare class JlTimeline extends JlElement {
|
|
8
9
|
static readonly selector = "jl-timeline";
|
|
@@ -11,7 +11,8 @@ var ICON_SIZE = 14;
|
|
|
11
11
|
var COMPACT_ICON_SIZE = 12;
|
|
12
12
|
/**
|
|
13
13
|
* What happened, in order, along a vertical line: each event a dot (or an icon in a circle) in its tone's colour,
|
|
14
|
-
*
|
|
14
|
+
* its time beside the marker (the times in one column), a title and an optional description. `compact` tightens it
|
|
15
|
+
* for side panels.
|
|
15
16
|
*/
|
|
16
17
|
var JlTimeline = class extends JlElement {
|
|
17
18
|
static selector = "jl-timeline";
|
|
@@ -55,25 +56,26 @@ var JlTimeline = class extends JlElement {
|
|
|
55
56
|
return /* @__PURE__ */ jsxs("li", {
|
|
56
57
|
class: "event",
|
|
57
58
|
"data-tone": item.tone ?? "neutral",
|
|
58
|
-
children: [
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class: "
|
|
59
|
+
children: [
|
|
60
|
+
/* @__PURE__ */ jsx("span", {
|
|
61
|
+
class: "rail",
|
|
62
|
+
children: marker
|
|
63
|
+
}),
|
|
64
|
+
item.time === void 0 ? null : /* @__PURE__ */ jsx("time", {
|
|
65
|
+
class: "time",
|
|
66
|
+
children: item.time
|
|
67
|
+
}),
|
|
68
|
+
/* @__PURE__ */ jsxs("div", {
|
|
69
|
+
class: "content",
|
|
65
70
|
children: [/* @__PURE__ */ jsx("p", {
|
|
66
71
|
class: "title",
|
|
67
72
|
children: item.title
|
|
68
|
-
}), item.
|
|
69
|
-
class: "
|
|
70
|
-
children: item.
|
|
73
|
+
}), item.description === void 0 ? null : /* @__PURE__ */ jsx("p", {
|
|
74
|
+
class: "description",
|
|
75
|
+
children: item.description
|
|
71
76
|
})]
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
children: item.description
|
|
75
|
-
})]
|
|
76
|
-
})]
|
|
77
|
+
})
|
|
78
|
+
]
|
|
77
79
|
});
|
|
78
80
|
}
|
|
79
81
|
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/molecules/jl-toast.css?raw
|
|
2
|
-
var jl_toast_default = ":host {\n display: block;\n --
|
|
2
|
+
var jl_toast_default = ":host {\n display: block;\n /* Coloured as jl-alert is, from the same tokens: a toned toast is tinted, its border and icon in its tone. */\n --fg: var(--jl-text-2);\n --bg: var(--jl-surface);\n --border: var(--jl-line);\n --bar: var(--jl-brand);\n}\n\n:host([tone=\"ok\"]),\n:host([tone=\"warn\"]),\n:host([tone=\"danger\"]),\n:host([tone=\"info\"]) {\n --border: color-mix(in srgb, var(--fg) 24%, var(--bg));\n --bar: var(--fg);\n}\n\n:host([tone=\"ok\"]) {\n --fg: var(--jl-ok);\n --bg: var(--jl-ok-soft);\n}\n\n:host([tone=\"warn\"]) {\n --fg: var(--jl-warn);\n --bg: var(--jl-warn-soft);\n}\n\n:host([tone=\"danger\"]) {\n --fg: var(--jl-danger);\n --bg: var(--jl-danger-soft);\n}\n\n:host([tone=\"info\"]) {\n --fg: var(--jl-info);\n --bg: var(--jl-info-soft);\n}\n\n.toast {\n position: relative;\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 14px 12px 14px 16px;\n overflow: hidden;\n border: 1px solid var(--border);\n border-radius: var(--jl-radius-lg);\n background: var(--bg);\n color: var(--jl-text);\n font-size: var(--jl-font-md);\n line-height: 20px;\n box-shadow: var(--jl-shadow-lg);\n}\n\n.icon {\n margin-top: 1px;\n color: var(--fg);\n}\n\n.content {\n display: grid;\n flex: 1;\n gap: 2px;\n min-width: 0;\n overflow-wrap: anywhere;\n}\n\n.heading {\n font-weight: 650;\n}\n\n.text {\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n}\n\n.heading[hidden] + .text {\n color: var(--jl-text-2);\n font-size: var(--jl-font-md);\n}\n\n.buttons {\n display: flex;\n flex: none;\n align-items: center;\n gap: 2px;\n margin: -5px -4px -5px 0;\n}\n\n.buttons:not(:has(jl-button:not([hidden]))) {\n display: none;\n}\n\n.close {\n --jl-accent: var(--fg);\n --jl-accent-soft: color-mix(in srgb, var(--fg) 12%, transparent);\n}\n\n.progress {\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n height: 2px;\n}\n\n.bar {\n height: 100%;\n background: var(--bar);\n transform-origin: left center;\n}\n\n:host([paused]) .bar {\n opacity: 0.55;\n}\n\n/* The line still counts the time, but does not move for people who asked for less motion. */\n@media (prefers-reduced-motion: reduce) {\n .progress {\n visibility: hidden;\n }\n}\n";
|
|
3
3
|
export { jl_toast_default as default };
|
|
@@ -69,6 +69,7 @@ export declare class JlToast extends JlElement {
|
|
|
69
69
|
private hold;
|
|
70
70
|
/** Whether the focus, moving to `next`, stays in the toast (its buttons, or what the page slotted in it). */
|
|
71
71
|
private holdsFocus;
|
|
72
|
+
/** 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. */
|
|
72
73
|
private renderIcon;
|
|
73
74
|
/** Inside a toaster, its live region announces the toast; alone, the toast is its own. */
|
|
74
75
|
private renderRole;
|
|
@@ -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.taken .edge {\n stroke: var(--tone, var(--jl-muted));\n stroke-width: 3;\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/* The box's size is the one lib/flow.ts computes the edges with: 240 wide, and the height the script sets (64, or 96\n with a detail line). */\n.node {\n --tone: var(--jl-accent);\n position: absolute;\n top: 0;\n left: 0;\n display: flex;\n flex-direction: column;\n justify-content: center;\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/* How a node did in a run: a ring while it works or waits for someone, a border once it is done or failed. */\n.node[data-status=\"running\"] {\n --state: var(--jl-info);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--jl-info) 30%, transparent);\n}\n\n.node[data-status=\"done\"] {\n --state: var(--jl-ok);\n border-color: color-mix(in srgb, var(--jl-ok) 55%, var(--jl-line));\n}\n\n.node[data-status=\"waiting\"] {\n --state: var(--jl-brand);\n border-color: var(--jl-brand);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--jl-brand) 30%, transparent);\n}\n\n.node[data-status=\"failed\"] {\n --state: var(--jl-danger);\n border-color: var(--jl-danger);\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.head {\n display: flex;\n align-items: center;\n gap: var(--jl-space-3);\n min-width: 0;\n}\n\n/* With a detail line, the head sits at the top and the detail under it, clear of the exits below. */\n.node:has(.detail) {\n justify-content: flex-start;\n padding-top: 10px;\n}\n\n.detail {\n overflow: hidden;\n margin-top: 6px;\n padding-top: 5px;\n line-height: 16px;\n border-top: 1px dashed var(--jl-line);\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.problem {\n display: inline-flex;\n flex: none;\n color: var(--jl-danger);\n}\n\n.status {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: var(--state);\n color: var(--jl-on-accent);\n}\n\n.node[data-status=\"running\"] .status jl-icon {\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n to {\n rotate: 360deg;\n }\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 flex: 1;\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/* The exit a run left by. */\n.port[data-taken] {\n border-color: var(--tone);\n background: color-mix(in srgb, var(--tone) 14%, var(--jl-surface));\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,109 @@
|
|
|
1
|
+
import { JlElement } from '../base/jl-element';
|
|
2
|
+
import type { FlowAddRequest, FlowDropRequest, FlowGraph, FlowPoint } 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` or `drop` asks. Nodes can show how a run went (`status`,
|
|
7
|
+
* `taken`) and what to fix (`problem`).
|
|
8
|
+
*/
|
|
9
|
+
export declare class JlFlow extends JlElement {
|
|
10
|
+
static readonly selector = "jl-flow";
|
|
11
|
+
readonly events: Readonly<import("@jadis/core").UseEventsHandler<{
|
|
12
|
+
change: FlowGraph;
|
|
13
|
+
select: string;
|
|
14
|
+
add: FlowAddRequest;
|
|
15
|
+
drop: FlowDropRequest;
|
|
16
|
+
}>>;
|
|
17
|
+
readonly graph: Readonly<Readonly<{
|
|
18
|
+
get(): FlowGraph;
|
|
19
|
+
set(setter: FlowGraph | ((prevState: FlowGraph) => FlowGraph)): void;
|
|
20
|
+
}>>;
|
|
21
|
+
/** The id of the selected node; the view moves to show it. */
|
|
22
|
+
readonly selected: Readonly<Readonly<{
|
|
23
|
+
get(): string;
|
|
24
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
25
|
+
}>>;
|
|
26
|
+
/** View only: nodes can be selected, not moved, joined or removed. */
|
|
27
|
+
readonly readonly: Readonly<Readonly<{
|
|
28
|
+
get(): boolean;
|
|
29
|
+
set(setter: boolean | ((prevState: boolean) => boolean)): void;
|
|
30
|
+
}>>;
|
|
31
|
+
/**
|
|
32
|
+
* The drag-and-drop type the canvas takes (`application/x-step`): something dragged in carrying it asks for a node
|
|
33
|
+
* where it is dropped, with `drop`.
|
|
34
|
+
*/
|
|
35
|
+
readonly dropType: Readonly<Readonly<{
|
|
36
|
+
get(): string;
|
|
37
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
38
|
+
}>>;
|
|
39
|
+
/** The canvas's name for screen readers. */
|
|
40
|
+
readonly label: Readonly<Readonly<{
|
|
41
|
+
get(): string;
|
|
42
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
43
|
+
}>>;
|
|
44
|
+
private readonly _state;
|
|
45
|
+
private readonly _nodes;
|
|
46
|
+
private readonly _svg;
|
|
47
|
+
private readonly _refs;
|
|
48
|
+
/** Moves and zooms the view to show every node, never larger than life. */
|
|
49
|
+
fit(): void;
|
|
50
|
+
/** Moves the view, when needed, so that a node is in sight: one just added, or moved with the keys. */
|
|
51
|
+
reveal(id: string): void;
|
|
52
|
+
/** Where a node added after an exit goes, as + puts it: a row below, under that exit. */
|
|
53
|
+
positionAfter(from: string, port: string): FlowPoint;
|
|
54
|
+
/** Where a node added without a place goes: in the middle of the view (its top left corner). */
|
|
55
|
+
centerPosition(): FlowPoint;
|
|
56
|
+
/** Lays the nodes out again, in rows from the starts down (`change` gives the new positions), and shows them all. */
|
|
57
|
+
layout(): void;
|
|
58
|
+
templateHtml(): Node;
|
|
59
|
+
templateCss(): string;
|
|
60
|
+
onConnect(): void;
|
|
61
|
+
private show;
|
|
62
|
+
/** An edit: drawn, kept, and sent to the page. */
|
|
63
|
+
private commit;
|
|
64
|
+
private select;
|
|
65
|
+
private selectEdge;
|
|
66
|
+
private removeSelection;
|
|
67
|
+
private nodeOf;
|
|
68
|
+
private pointerDown;
|
|
69
|
+
private gestureFor;
|
|
70
|
+
private pointerMove;
|
|
71
|
+
private drag;
|
|
72
|
+
private drawDraft;
|
|
73
|
+
private pointerUp;
|
|
74
|
+
/** An edge dropped on a node joins it; dropped on empty space, it asks for a node there. */
|
|
75
|
+
private connectAt;
|
|
76
|
+
private pressAdd;
|
|
77
|
+
/** Whether a drag carries what the canvas takes: then it may be dropped here. */
|
|
78
|
+
private carriesDrop;
|
|
79
|
+
private dragOver;
|
|
80
|
+
private dropOn;
|
|
81
|
+
private key;
|
|
82
|
+
/** The arrows move the selected node; with Shift, further. */
|
|
83
|
+
private nudge;
|
|
84
|
+
/** Two fingers or the wheel move the view; with Ctrl or ⌘ (a pinch on a trackpad), they zoom. */
|
|
85
|
+
private wheel;
|
|
86
|
+
private zoomBy;
|
|
87
|
+
private setViewport;
|
|
88
|
+
private applyViewport;
|
|
89
|
+
private screenPoint;
|
|
90
|
+
private worldPoint;
|
|
91
|
+
private render;
|
|
92
|
+
/** The nodes' elements stay from one drawing to the next: the focused one keeps the focus. */
|
|
93
|
+
private renderNodes;
|
|
94
|
+
private createNode;
|
|
95
|
+
private drawNode;
|
|
96
|
+
/** A colour of the page's own for the icon wins over the tone's. */
|
|
97
|
+
private paintIcon;
|
|
98
|
+
private portElement;
|
|
99
|
+
private place;
|
|
100
|
+
private renderSelection;
|
|
101
|
+
private renderEdges;
|
|
102
|
+
/**
|
|
103
|
+
* An edge, with a wide invisible twin that catches the pointer: a thin line is still easy to press. One a run took
|
|
104
|
+
* stands out.
|
|
105
|
+
*/
|
|
106
|
+
private edgeGroup;
|
|
107
|
+
/** The button that removes the selected edge, in its middle. */
|
|
108
|
+
private renderEdgeTool;
|
|
109
|
+
}
|