@wildwinter/app-shell 0.36.0 → 0.37.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 CHANGED
@@ -106,6 +106,18 @@ 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
+
109
121
  - **`--ok`** joins `--danger` and `--warn` in `tokens.css`, with a `light-dark()`
110
122
  default every palette should override in its own `theme.css`. It is the only
111
123
  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 node = document.createElement(tag);
154
+ const node2 = document.createElement(tag);
155
155
  const props = typeof classNameOrProps === "string" ? { className: classNameOrProps } : classNameOrProps ?? {};
156
- if (props.className) node.className = props.className;
157
- if (props.text !== void 0 && props.text !== null) node.textContent = props.text;
158
- if (props.title !== void 0) node.title = props.title;
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
- node.dataset["tip"] = props.tip;
161
- node.setAttribute("aria-label", props.tip);
160
+ node2.dataset["tip"] = props.tip;
161
+ node2.setAttribute("aria-label", props.tip);
162
162
  ensureTooltipHost();
163
163
  }
164
- if (props.onClick) node.addEventListener("click", 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
- node.append(child);
167
+ node2.append(child);
168
168
  }
169
169
  checkTooltipHost();
170
- return node;
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 = "add value";
202
+ input.placeholder = "Add value";
203
203
  input.spellcheck = false;
204
204
  const makeChip = (v) => {
205
205
  const chip = el("span", "shell-tag", v);
@@ -680,14 +680,14 @@ function closeWithExit(element, done) {
680
680
  if (fired) return;
681
681
  fired = true;
682
682
  element.removeEventListener("animationend", onEnd);
683
- clearTimeout(timer2);
683
+ clearTimeout(timer3);
684
684
  done();
685
685
  };
686
686
  const onEnd = (e) => {
687
687
  if (e.target === element) finish();
688
688
  };
689
689
  element.addEventListener("animationend", onEnd);
690
- const timer2 = setTimeout(finish, seconds * 1e3 + 120);
690
+ const timer3 = setTimeout(finish, seconds * 1e3 + 120);
691
691
  }
692
692
 
693
693
  // src/confirm.ts
@@ -1530,7 +1530,7 @@ function createSaveController(opts) {
1530
1530
  let auto = true;
1531
1531
  let dirty = false;
1532
1532
  let dirtySince = 0;
1533
- let timer2;
1533
+ let timer3;
1534
1534
  let inFlight;
1535
1535
  const setStatus = (next) => {
1536
1536
  if (next === status) return;
@@ -1538,17 +1538,17 @@ function createSaveController(opts) {
1538
1538
  opts.onStatus?.(status);
1539
1539
  };
1540
1540
  const clearTimer = () => {
1541
- if (timer2 === void 0) return;
1542
- clearTimeout(timer2);
1543
- timer2 = void 0;
1541
+ if (timer3 === void 0) return;
1542
+ clearTimeout(timer3);
1543
+ timer3 = void 0;
1544
1544
  };
1545
1545
  const arm = () => {
1546
1546
  clearTimer();
1547
1547
  if (!auto) return;
1548
1548
  const deadline = dirtySince + maxWaitMs;
1549
1549
  const wait = Math.max(0, Math.min(delayMs, deadline - Date.now()));
1550
- timer2 = setTimeout(() => {
1551
- timer2 = void 0;
1550
+ timer3 = setTimeout(() => {
1551
+ timer3 = void 0;
1552
1552
  void run();
1553
1553
  }, wait);
1554
1554
  };
@@ -1622,13 +1622,13 @@ var WORDS = {
1622
1622
  unsaved: "Unsaved"
1623
1623
  };
1624
1624
  function saveIndicator(initial = "saved") {
1625
- const node = el("span");
1625
+ const node2 = el("span");
1626
1626
  const set = (status) => {
1627
- node.className = `savestat ${status}`;
1628
- node.textContent = WORDS[status];
1627
+ node2.className = `savestat ${status}`;
1628
+ node2.textContent = WORDS[status];
1629
1629
  };
1630
1630
  set(initial);
1631
- return { el: node, set };
1631
+ return { el: node2, set };
1632
1632
  }
1633
1633
 
1634
1634
  // src/stale.ts
@@ -1649,6 +1649,43 @@ function staleBar(opts) {
1649
1649
  );
1650
1650
  }
1651
1651
 
1652
+ // src/toast.ts
1653
+ var DURATION = { info: 4e3, ok: 4e3, error: 7e3 };
1654
+ var node;
1655
+ var timer2 = 0;
1656
+ var seq = 0;
1657
+ function mount() {
1658
+ if (node && node.isConnected) return node;
1659
+ node = el("div", { className: "shell-toast" });
1660
+ node.setAttribute("role", "status");
1661
+ node.setAttribute("aria-live", "polite");
1662
+ node.hidden = true;
1663
+ document.body.append(node);
1664
+ return node;
1665
+ }
1666
+ function toast(message, kind = "info", opts = {}) {
1667
+ const t = mount();
1668
+ const id = ++seq;
1669
+ t.textContent = message;
1670
+ t.className = `shell-toast ${kind}`;
1671
+ t.hidden = false;
1672
+ window.clearTimeout(timer2);
1673
+ timer2 = window.setTimeout(() => {
1674
+ closeWithExit(t, () => {
1675
+ if (seq === id) t.hidden = true;
1676
+ });
1677
+ }, opts.duration ?? DURATION[kind]);
1678
+ }
1679
+ function dismissToast() {
1680
+ if (!node || node.hidden) return;
1681
+ window.clearTimeout(timer2);
1682
+ const id = seq;
1683
+ const t = node;
1684
+ closeWithExit(t, () => {
1685
+ if (seq === id) t.hidden = true;
1686
+ });
1687
+ }
1688
+
1652
1689
  // src/stepper.ts
1653
1690
  function renderStepperBar(host, opts) {
1654
1691
  const { items } = opts;
@@ -1789,6 +1826,7 @@ exports.colourIndex = colourIndex;
1789
1826
  exports.confirmDialog = confirmDialog;
1790
1827
  exports.createNavHistory = createNavHistory;
1791
1828
  exports.createSaveController = createSaveController;
1829
+ exports.dismissToast = dismissToast;
1792
1830
  exports.dupGuard = dupGuard;
1793
1831
  exports.el = el;
1794
1832
  exports.expandableRow = expandableRow;
@@ -1830,6 +1868,7 @@ exports.staleBar = staleBar;
1830
1868
  exports.tagChips = tagChips;
1831
1869
  exports.tipAt = tipAt;
1832
1870
  exports.tipBold = tipBold;
1871
+ exports.toast = toast;
1833
1872
  exports.vcBadgeFor = vcBadgeFor;
1834
1873
  //# sourceMappingURL=index.cjs.map
1835
1874
  //# sourceMappingURL=index.cjs.map