@wildwinter/app-shell 0.36.0 → 0.38.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 +25 -0
- package/dist/index.cjs +76 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -2
- package/dist/index.d.ts +39 -2
- package/dist/index.js +74 -23
- package/dist/index.js.map +1 -1
- package/dist/settings.css +11 -0
- package/dist/settings.css.map +1 -1
- package/dist/toast.css +33 -0
- package/dist/toast.css.map +1 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -106,6 +106,31 @@ needing and never had.
|
|
|
106
106
|
staleBar({ subject: "The project", onRestart: () => void rebuild() });
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
+
- **`toast`** - a transient remark: "Bundle published", "Save refused: ...".
|
|
110
|
+
Bottom-right, an outlined card on the surface colour with the kind in the
|
|
111
|
+
border, on the shared panel motion; one at a time, 4s (7s for an error).
|
|
112
|
+
Both apps had one, and they agreed on nothing but the sentences - place,
|
|
113
|
+
colour, timing, motion and ARIA all differed. It mounts its own node, so a
|
|
114
|
+
second window gets it by importing it. Bring `toast.css`.
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
toast(`Bundle published\n${where}`, "ok");
|
|
118
|
+
toast(`Save refused: ${err}`, "error");
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- **`revealRow`** - land on one row of a settings list. `expandableRow` takes a
|
|
122
|
+
`name` and stamps it on the row; `revealRow(within, name)` opens that row's
|
|
123
|
+
details, brings it to the middle of its scroller and lights it for a moment.
|
|
124
|
+
"Go to definition" in both apps opened the page a property is declared on and
|
|
125
|
+
stopped there, with the row off screen. It returns false when no row carries
|
|
126
|
+
the name, so a host whose page fills in late asks again on a later frame.
|
|
127
|
+
Brings nothing new: the light is in `settings.css`.
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
list.append(expandableRow({ line, details, name: decl.name }));
|
|
131
|
+
revealRow(document, "mood");
|
|
132
|
+
```
|
|
133
|
+
|
|
109
134
|
- **`--ok`** joins `--danger` and `--warn` in `tokens.css`, with a `light-dark()`
|
|
110
135
|
default every palette should override in its own `theme.css`. It is the only
|
|
111
136
|
colour in the grammar layer, and it is there because it kept not being
|
package/dist/index.cjs
CHANGED
|
@@ -151,23 +151,23 @@ function initTooltips(opts = {}) {
|
|
|
151
151
|
|
|
152
152
|
// src/dom.ts
|
|
153
153
|
function el(tag, classNameOrProps, ...children) {
|
|
154
|
-
const
|
|
154
|
+
const node2 = document.createElement(tag);
|
|
155
155
|
const props = typeof classNameOrProps === "string" ? { className: classNameOrProps } : classNameOrProps ?? {};
|
|
156
|
-
if (props.className)
|
|
157
|
-
if (props.text !== void 0 && props.text !== null)
|
|
158
|
-
if (props.title !== void 0)
|
|
156
|
+
if (props.className) node2.className = props.className;
|
|
157
|
+
if (props.text !== void 0 && props.text !== null) node2.textContent = props.text;
|
|
158
|
+
if (props.title !== void 0) node2.title = props.title;
|
|
159
159
|
if (props.tip !== void 0) {
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
node2.dataset["tip"] = props.tip;
|
|
161
|
+
node2.setAttribute("aria-label", props.tip);
|
|
162
162
|
ensureTooltipHost();
|
|
163
163
|
}
|
|
164
|
-
if (props.onClick)
|
|
164
|
+
if (props.onClick) node2.addEventListener("click", props.onClick);
|
|
165
165
|
for (const child of children) {
|
|
166
166
|
if (child === null || child === void 0) continue;
|
|
167
|
-
|
|
167
|
+
node2.append(child);
|
|
168
168
|
}
|
|
169
169
|
checkTooltipHost();
|
|
170
|
-
return
|
|
170
|
+
return node2;
|
|
171
171
|
}
|
|
172
172
|
function iconBtn(glyph, title, onClick, disabled = false, danger = false) {
|
|
173
173
|
const b = el("button", `shell-icon${danger ? " danger" : ""}`);
|
|
@@ -199,7 +199,7 @@ function tagChips(holder, onChange) {
|
|
|
199
199
|
const wrap = el("div", "shell-tags");
|
|
200
200
|
const input = el("input", "shell-tag-input");
|
|
201
201
|
input.type = "text";
|
|
202
|
-
input.placeholder = "
|
|
202
|
+
input.placeholder = "Add value";
|
|
203
203
|
input.spellcheck = false;
|
|
204
204
|
const makeChip = (v) => {
|
|
205
205
|
const chip = el("span", "shell-tag", v);
|
|
@@ -486,6 +486,7 @@ var PANE_MENU = {
|
|
|
486
486
|
// src/settings.ts
|
|
487
487
|
function expandableRow(opts) {
|
|
488
488
|
const row = el("div", "set-row");
|
|
489
|
+
if (opts.name !== void 0) row.dataset.name = opts.name;
|
|
489
490
|
const line = el("div", "set-rowline");
|
|
490
491
|
if (opts.details && opts.details.length) {
|
|
491
492
|
const details = el("div", "set-details");
|
|
@@ -511,6 +512,19 @@ function expandableRow(opts) {
|
|
|
511
512
|
}
|
|
512
513
|
return row;
|
|
513
514
|
}
|
|
515
|
+
function revealRow(within, name) {
|
|
516
|
+
const row = [...within.querySelectorAll(".set-row")].find((r) => r.dataset.name === name);
|
|
517
|
+
if (!row) return false;
|
|
518
|
+
const toggle = row.querySelector(".set-rowline > .set-expand");
|
|
519
|
+
if (toggle && toggle.getAttribute("aria-expanded") !== "true") toggle.click();
|
|
520
|
+
const still = typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
521
|
+
row.scrollIntoView({ block: "center", behavior: still ? "auto" : "smooth" });
|
|
522
|
+
row.classList.remove("landed");
|
|
523
|
+
void row.offsetWidth;
|
|
524
|
+
row.classList.add("landed");
|
|
525
|
+
row.addEventListener("animationend", () => row.classList.remove("landed"), { once: true });
|
|
526
|
+
return true;
|
|
527
|
+
}
|
|
514
528
|
function focusNewRow(listEl) {
|
|
515
529
|
const last = listEl?.lastElementChild;
|
|
516
530
|
if (!(last instanceof HTMLElement)) return;
|
|
@@ -680,14 +694,14 @@ function closeWithExit(element, done) {
|
|
|
680
694
|
if (fired) return;
|
|
681
695
|
fired = true;
|
|
682
696
|
element.removeEventListener("animationend", onEnd);
|
|
683
|
-
clearTimeout(
|
|
697
|
+
clearTimeout(timer3);
|
|
684
698
|
done();
|
|
685
699
|
};
|
|
686
700
|
const onEnd = (e) => {
|
|
687
701
|
if (e.target === element) finish();
|
|
688
702
|
};
|
|
689
703
|
element.addEventListener("animationend", onEnd);
|
|
690
|
-
const
|
|
704
|
+
const timer3 = setTimeout(finish, seconds * 1e3 + 120);
|
|
691
705
|
}
|
|
692
706
|
|
|
693
707
|
// src/confirm.ts
|
|
@@ -1530,7 +1544,7 @@ function createSaveController(opts) {
|
|
|
1530
1544
|
let auto = true;
|
|
1531
1545
|
let dirty = false;
|
|
1532
1546
|
let dirtySince = 0;
|
|
1533
|
-
let
|
|
1547
|
+
let timer3;
|
|
1534
1548
|
let inFlight;
|
|
1535
1549
|
const setStatus = (next) => {
|
|
1536
1550
|
if (next === status) return;
|
|
@@ -1538,17 +1552,17 @@ function createSaveController(opts) {
|
|
|
1538
1552
|
opts.onStatus?.(status);
|
|
1539
1553
|
};
|
|
1540
1554
|
const clearTimer = () => {
|
|
1541
|
-
if (
|
|
1542
|
-
clearTimeout(
|
|
1543
|
-
|
|
1555
|
+
if (timer3 === void 0) return;
|
|
1556
|
+
clearTimeout(timer3);
|
|
1557
|
+
timer3 = void 0;
|
|
1544
1558
|
};
|
|
1545
1559
|
const arm = () => {
|
|
1546
1560
|
clearTimer();
|
|
1547
1561
|
if (!auto) return;
|
|
1548
1562
|
const deadline = dirtySince + maxWaitMs;
|
|
1549
1563
|
const wait = Math.max(0, Math.min(delayMs, deadline - Date.now()));
|
|
1550
|
-
|
|
1551
|
-
|
|
1564
|
+
timer3 = setTimeout(() => {
|
|
1565
|
+
timer3 = void 0;
|
|
1552
1566
|
void run();
|
|
1553
1567
|
}, wait);
|
|
1554
1568
|
};
|
|
@@ -1622,13 +1636,13 @@ var WORDS = {
|
|
|
1622
1636
|
unsaved: "Unsaved"
|
|
1623
1637
|
};
|
|
1624
1638
|
function saveIndicator(initial = "saved") {
|
|
1625
|
-
const
|
|
1639
|
+
const node2 = el("span");
|
|
1626
1640
|
const set = (status) => {
|
|
1627
|
-
|
|
1628
|
-
|
|
1641
|
+
node2.className = `savestat ${status}`;
|
|
1642
|
+
node2.textContent = WORDS[status];
|
|
1629
1643
|
};
|
|
1630
1644
|
set(initial);
|
|
1631
|
-
return { el:
|
|
1645
|
+
return { el: node2, set };
|
|
1632
1646
|
}
|
|
1633
1647
|
|
|
1634
1648
|
// src/stale.ts
|
|
@@ -1649,6 +1663,43 @@ function staleBar(opts) {
|
|
|
1649
1663
|
);
|
|
1650
1664
|
}
|
|
1651
1665
|
|
|
1666
|
+
// src/toast.ts
|
|
1667
|
+
var DURATION = { info: 4e3, ok: 4e3, error: 7e3 };
|
|
1668
|
+
var node;
|
|
1669
|
+
var timer2 = 0;
|
|
1670
|
+
var seq = 0;
|
|
1671
|
+
function mount() {
|
|
1672
|
+
if (node && node.isConnected) return node;
|
|
1673
|
+
node = el("div", { className: "shell-toast" });
|
|
1674
|
+
node.setAttribute("role", "status");
|
|
1675
|
+
node.setAttribute("aria-live", "polite");
|
|
1676
|
+
node.hidden = true;
|
|
1677
|
+
document.body.append(node);
|
|
1678
|
+
return node;
|
|
1679
|
+
}
|
|
1680
|
+
function toast(message, kind = "info", opts = {}) {
|
|
1681
|
+
const t = mount();
|
|
1682
|
+
const id = ++seq;
|
|
1683
|
+
t.textContent = message;
|
|
1684
|
+
t.className = `shell-toast ${kind}`;
|
|
1685
|
+
t.hidden = false;
|
|
1686
|
+
window.clearTimeout(timer2);
|
|
1687
|
+
timer2 = window.setTimeout(() => {
|
|
1688
|
+
closeWithExit(t, () => {
|
|
1689
|
+
if (seq === id) t.hidden = true;
|
|
1690
|
+
});
|
|
1691
|
+
}, opts.duration ?? DURATION[kind]);
|
|
1692
|
+
}
|
|
1693
|
+
function dismissToast() {
|
|
1694
|
+
if (!node || node.hidden) return;
|
|
1695
|
+
window.clearTimeout(timer2);
|
|
1696
|
+
const id = seq;
|
|
1697
|
+
const t = node;
|
|
1698
|
+
closeWithExit(t, () => {
|
|
1699
|
+
if (seq === id) t.hidden = true;
|
|
1700
|
+
});
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1652
1703
|
// src/stepper.ts
|
|
1653
1704
|
function renderStepperBar(host, opts) {
|
|
1654
1705
|
const { items } = opts;
|
|
@@ -1789,6 +1840,7 @@ exports.colourIndex = colourIndex;
|
|
|
1789
1840
|
exports.confirmDialog = confirmDialog;
|
|
1790
1841
|
exports.createNavHistory = createNavHistory;
|
|
1791
1842
|
exports.createSaveController = createSaveController;
|
|
1843
|
+
exports.dismissToast = dismissToast;
|
|
1792
1844
|
exports.dupGuard = dupGuard;
|
|
1793
1845
|
exports.el = el;
|
|
1794
1846
|
exports.expandableRow = expandableRow;
|
|
@@ -1824,12 +1876,14 @@ exports.propertyNameify = propertyNameify;
|
|
|
1824
1876
|
exports.propertyRefProblem = propertyRefProblem;
|
|
1825
1877
|
exports.renderStepperBar = renderStepperBar;
|
|
1826
1878
|
exports.revalidatePropertyRefs = revalidatePropertyRefs;
|
|
1879
|
+
exports.revealRow = revealRow;
|
|
1827
1880
|
exports.saveIndicator = saveIndicator;
|
|
1828
1881
|
exports.showAbout = showAbout;
|
|
1829
1882
|
exports.staleBar = staleBar;
|
|
1830
1883
|
exports.tagChips = tagChips;
|
|
1831
1884
|
exports.tipAt = tipAt;
|
|
1832
1885
|
exports.tipBold = tipBold;
|
|
1886
|
+
exports.toast = toast;
|
|
1833
1887
|
exports.vcBadgeFor = vcBadgeFor;
|
|
1834
1888
|
//# sourceMappingURL=index.cjs.map
|
|
1835
1889
|
//# sourceMappingURL=index.cjs.map
|