ilha 0.15.1 → 0.15.2

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/dist/define.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as mount } from "./mount-DCu8b0hE.js";
1
+ import { t as mount } from "./mount-DKY_jSsG.js";
2
2
 
3
3
  //#region src/define.ts
4
4
  const define = (name, component) => {
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { _ as isString, f as errorView, i as Fragment, m as isFunction, t as h } from "./vnode-BHUY61Rm.js";
2
- import { C as makeFiber, S as getFiber, _ as structuralEqual, b as clearFiberView, d as interpret, f as atom, g as isAtomHandle, h as instr, m as handleOwner, n as unsafe, p as batch, u as runSetup, v as untrack, x as closeFiber, y as wrapHandle } from "./paint-core-D9VO-oUM.js";
3
- import { n as renderToString, t as mount } from "./mount-DCu8b0hE.js";
2
+ import { C as getFiber, S as closeFiber, _ as isAtomHandle, b as wrapHandle, d as runSetup, f as interpret, g as instr, h as handleOwner, m as batch, n as unsafe, p as atom, v as structuralEqual, w as makeFiber, x as clearFiberView, y as untrack } from "./paint-core-B7jENZwS.js";
3
+ import { n as renderToString, t as mount } from "./mount-DKY_jSsG.js";
4
4
  import * as Atom from "effect/reactivity/Atom";
5
5
  import * as Effect from "effect/Effect";
6
6
  import * as Stream from "effect/Stream";
@@ -1,5 +1,5 @@
1
1
  import { _ as isString, c as KEEP, d as defer, g as isObject, m as isFunction, r as isVNode, u as SLOT_ATTR, y as unwrap } from "./vnode-BHUY61Rm.js";
2
- import { T as makeRuntime, a as morphInner, c as bindEvents, i as insertRendered, l as eventTypeFromProp, o as placeChildren, r as committedElement, s as standInFor, t as createPainter, u as runSetup, w as makeRootFiber, x as closeFiber } from "./paint-core-D9VO-oUM.js";
2
+ import { E as makeRuntime, S as closeFiber, T as makeRootFiber, a as markControlled, c as standInFor, d as runSetup, i as insertRendered, l as bindEvents, o as morphInner, r as committedElement, s as placeChildren, t as createPainter, u as eventTypeFromProp } from "./paint-core-B7jENZwS.js";
3
3
 
4
4
  //#region src/paint.ts
5
5
  const noopDisconnect = () => {};
@@ -30,13 +30,19 @@ const core$1 = createPainter({
30
30
  reuseNode: (host) => host instanceof Element && host.isConnected ? standInFor(host) : host,
31
31
  setFormControl: (el, key, v) => {
32
32
  const node = el;
33
+ if (v !== null && v !== void 0) markControlled(el, key);
33
34
  if (key === "value") {
34
- if (v === null || v === void 0) {
35
+ const text = v === null || v === void 0 ? "" : String(v);
36
+ if (el.localName === "textarea") {
37
+ node.defaultValue = text;
38
+ node.value = text;
39
+ } else if (el.localName === "select") node.value = text;
40
+ else if (v === null || v === void 0) {
35
41
  el.removeAttribute("value");
36
42
  node.value = "";
37
43
  } else {
38
- el.setAttribute("value", String(v));
39
- node.value = String(v);
44
+ el.setAttribute("value", text);
45
+ node.value = text;
40
46
  }
41
47
  } else if (key === "checked") {
42
48
  node.checked = Boolean(v);
@@ -344,6 +350,26 @@ const bindSsrEvents = (el, props, fiber) => {
344
350
  el.dataset.ilhaOn = existing ? `${existing},${id}` : id;
345
351
  }
346
352
  };
353
+ const WHITESPACE_RUN = /\s+/gu;
354
+ /**
355
+ * Mark the first option whose value is `value` selected and clear the rest,
356
+ * as setting a live select's `.value` does. Returns whether one matched.
357
+ */
358
+ const selectOption = (parent, value, found) => {
359
+ let matched = found;
360
+ for (const child of parent.children) {
361
+ if (child.kind !== "element") continue;
362
+ if (child.localName === "optgroup") matched = selectOption(child, value, matched);
363
+ else if (child.localName === "option") {
364
+ const optionValue = child.getAttribute("value") ?? child.textContent.trim().replaceAll(WHITESPACE_RUN, " ");
365
+ if (!matched && optionValue === value) {
366
+ child.setAttribute("selected", "");
367
+ matched = true;
368
+ } else child.removeAttribute("selected");
369
+ }
370
+ }
371
+ return matched;
372
+ };
347
373
  const core = createPainter({
348
374
  appendRoot: (root, node) => ssrAs(root).append(node),
349
375
  asElement: (el) => ssrAs(el),
@@ -370,8 +396,13 @@ const core = createPainter({
370
396
  },
371
397
  reuseNode: (host) => ssrAs(host),
372
398
  setFormControl: (el, key, v) => {
373
- if (key === "value") el.setAttribute("value", String(v ?? ""));
374
- else if (v) el.setAttribute(key, "");
399
+ if (key === "value") {
400
+ const text = String(v ?? "");
401
+ if (el.localName === "textarea") el.textContent = text;
402
+ else if (el.localName === "select") {
403
+ if (v !== null && v !== void 0) selectOption(el, text, false);
404
+ } else el.setAttribute("value", text);
405
+ } else if (v) el.setAttribute(key, "");
375
406
  else el.removeAttribute(key);
376
407
  },
377
408
  setStyle: (el, css) => el.setAttribute("style", css)
@@ -836,6 +836,20 @@ const collectKeys = (parent) => {
836
836
  }
837
837
  return keys;
838
838
  };
839
+ /** Rendered elements that carried a non-null form-control prop, per key.
840
+ * `checked={false}`, `selected={false}` and `<select value>` leave no
841
+ * attribute, so presence alone can't tell a controlled render from an
842
+ * uncontrolled one. */
843
+ const controlledBy = {
844
+ checked: /* @__PURE__ */ new WeakSet(),
845
+ selected: /* @__PURE__ */ new WeakSet(),
846
+ value: /* @__PURE__ */ new WeakSet()
847
+ };
848
+ /** Mark a rendered element controlled for `key`: the morph syncs it either way. */
849
+ const markControlled = (el, key) => {
850
+ controlledBy[key].add(el);
851
+ };
852
+ const isControlled = (el, key) => controlledBy[key].has(el);
839
853
  const morphInput = (fromEl, toEl) => {
840
854
  syncAttributes(fromEl, toEl);
841
855
  const from = fromEl;
@@ -845,7 +859,7 @@ const morphInput = (fromEl, toEl) => {
845
859
  if (toChecked) fromEl.setAttribute("checked", "");
846
860
  else fromEl.removeAttribute("checked");
847
861
  }
848
- if (toChecked && from.checked !== to.checked) from.checked = to.checked;
862
+ if ((toChecked || isControlled(toEl, "checked")) && from.checked !== to.checked) from.checked = to.checked;
849
863
  const toValue = toEl.getAttribute("value");
850
864
  if (toValue !== fromEl.getAttribute("value")) {
851
865
  if (toValue === null) fromEl.removeAttribute("value");
@@ -857,14 +871,32 @@ const morphTextarea = (fromEl, toEl) => {
857
871
  syncAttributes(fromEl, toEl);
858
872
  const from = fromEl;
859
873
  const to = toEl;
860
- if (to.textContent !== "" || from.textContent !== to.textContent) {
874
+ if (isControlled(toEl, "value") || to.textContent !== "" || from.textContent !== to.textContent) {
861
875
  if (from.value !== to.value) from.value = to.value;
862
876
  if (from.textContent !== to.textContent) from.textContent = to.textContent;
863
877
  }
864
878
  };
879
+ const isControlledSelect = (select) => {
880
+ if (isControlled(select, "value")) return true;
881
+ for (const o of select.options) if (isControlled(o, "selected")) return true;
882
+ return false;
883
+ };
865
884
  const morphSelect = (fromEl, toEl, api) => {
866
- const before = /* @__PURE__ */ new Map();
867
885
  const fromSelect = fromEl;
886
+ const toSelect = toEl;
887
+ if (isControlledSelect(toSelect)) {
888
+ syncAttributes(fromEl, toEl);
889
+ api.morphChildren(fromEl, toEl);
890
+ const want = toSelect.options;
891
+ let i = 0;
892
+ for (const o of fromSelect.options) {
893
+ const selected = want[i]?.selected ?? false;
894
+ if (o.selected !== selected) o.selected = selected;
895
+ i += 1;
896
+ }
897
+ return;
898
+ }
899
+ const before = /* @__PURE__ */ new Map();
868
900
  for (const o of fromSelect.options) before.set(o, {
869
901
  attr: o.hasAttribute("selected"),
870
902
  live: o.selected
@@ -1592,7 +1624,8 @@ const createPainter = (ops) => {
1592
1624
  const ns = elementNs(lower, parentNsOf(fiber.root));
1593
1625
  const el = ops.createElement(tag, ns);
1594
1626
  if (view.key !== null && view.key !== void 0) el.setAttribute(KEY_ATTR, String(view.key));
1595
- api.applyProps(el, view.props, fiber);
1627
+ const propsAfterChildren = lower === "select";
1628
+ if (!propsAfterChildren) api.applyProps(el, view.props, fiber);
1596
1629
  const childFiber = {
1597
1630
  ...fiber,
1598
1631
  holes: fiber.holes,
@@ -1600,6 +1633,7 @@ const createPainter = (ops) => {
1600
1633
  root: ops.asRoot(el)
1601
1634
  };
1602
1635
  for (const c of view.children) for (const n of api.materialize(c, childFiber)) el.append(n);
1636
+ if (propsAfterChildren) api.applyProps(el, view.props, fiber);
1603
1637
  return [el];
1604
1638
  };
1605
1639
  const materializeVNode = (view, fiber) => {
@@ -1656,4 +1690,4 @@ const createPainter = (ops) => {
1656
1690
  };
1657
1691
 
1658
1692
  //#endregion
1659
- export { makeFiber as C, getFiber as S, makeRuntime as T, structuralEqual as _, morphInner as a, clearFiberView as b, bindEvents as c, interpret as d, atom as f, isAtomHandle as g, instr as h, insertRendered as i, eventTypeFromProp as l, handleOwner as m, unsafe as n, placeChildren as o, batch as p, committedElement as r, standInFor as s, createPainter as t, runSetup as u, untrack as v, makeRootFiber as w, closeFiber as x, wrapHandle as y };
1693
+ export { getFiber as C, makeRuntime as E, closeFiber as S, makeRootFiber as T, isAtomHandle as _, markControlled as a, wrapHandle as b, standInFor as c, runSetup as d, interpret as f, instr as g, handleOwner as h, insertRendered as i, bindEvents as l, batch as m, unsafe as n, morphInner as o, atom as p, committedElement as r, placeChildren as s, createPainter as t, eventTypeFromProp as u, structuralEqual as v, makeFiber as w, clearFiberView as x, untrack as y };
package/dist/renderer.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { d as defer } from "./vnode-BHUY61Rm.js";
2
- import { S as getFiber, T as makeRuntime, c as bindEvents, t as createPainter, u as runSetup, w as makeRootFiber, x as closeFiber } from "./paint-core-D9VO-oUM.js";
2
+ import { C as getFiber, E as makeRuntime, S as closeFiber, T as makeRootFiber, d as runSetup, l as bindEvents, t as createPainter } from "./paint-core-B7jENZwS.js";
3
3
 
4
4
  //#region src/renderer.ts
5
5
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ilha",
3
- "version": "0.15.1",
3
+ "version": "0.15.2",
4
4
  "description": "Generator-first island UI on Effect",
5
5
  "keywords": [
6
6
  "effect",