@estjs/template 0.0.16-beta.1 → 0.0.16-beta.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.
@@ -1,5 +1,5 @@
1
1
  import { getActiveScope, runWithScope, onCleanup, __objRest, createScope, disposeScope, __async } from './chunk-3E4EK64L.dev.esm.js';
2
- import { normalizeClassName, isObject, warn, isSpecialBooleanAttr, isBooleanAttr, includeBooleanAttr, isSymbol, isString, isArray, camelCase, capitalize, isBrowser, error, isPromise, isFunction, isOn, isNull, isUndefined, isNumber, isBoolean, coerceArray, isHTMLElement, isPrimitive, isFalsy } from '@estjs/shared';
2
+ import { normalizeClassName, isObject, warn, isSpecialBooleanAttr, isBooleanAttr, includeBooleanAttr, isSymbol, isString, isArray, camelCase, capitalize, isBrowser, error, isPromise, isFunction, isOn, coerceArray } from '@estjs/shared';
3
3
  import { effect, shallowReactive, isSignal, isComputed, signal } from '@estjs/signals';
4
4
 
5
5
  // src/constants.ts
@@ -59,7 +59,7 @@ function patchAttr(el, key, prev, next2) {
59
59
  const elementIsSVG = (el == null ? void 0 : el.namespaceURI) === SVG_NAMESPACE;
60
60
  const isXlink = elementIsSVG && key.startsWith("xlink:");
61
61
  const isXmlns = elementIsSVG && key.startsWith("xmlns:");
62
- const isBoolean2 = isSpecialBooleanAttr(key) || isBooleanAttr(key);
62
+ const isBoolean = isSpecialBooleanAttr(key) || isBooleanAttr(key);
63
63
  if (prev === next2) {
64
64
  return;
65
65
  }
@@ -84,7 +84,7 @@ function patchAttr(el, key, prev, next2) {
84
84
  }
85
85
  return;
86
86
  }
87
- if (isBoolean2) {
87
+ if (isBoolean) {
88
88
  if (includeBooleanAttr(next2)) {
89
89
  el.setAttribute(key, "");
90
90
  } else {
@@ -528,13 +528,19 @@ function insertNode(parent, child2, before) {
528
528
  }
529
529
  }
530
530
  function normalizeNode(node) {
531
- if (isHTMLElement(node)) {
532
- return node;
533
- }
534
- if (isPrimitive(node)) {
535
- return document.createTextNode(isFalsy(node) ? "" : String(node));
531
+ if (node instanceof Node) return node;
532
+ if (isComponent(node)) return node;
533
+ const t = typeof node;
534
+ if (node == null || t === "string" || t === "number" || t === "boolean" || t === "symbol") {
535
+ return document.createTextNode(node === false || node == null ? "" : String(node));
536
+ }
537
+ if (isObject(node)) {
538
+ warn(
539
+ "Rendering a plain object as a node is not recommended. The object will be converted to its string representation.",
540
+ node
541
+ );
536
542
  }
537
- return node;
543
+ return document.createTextNode(String(node));
538
544
  }
539
545
  function insert(parent, nodeFactory, before) {
540
546
  if (!parent) return;
@@ -543,7 +549,9 @@ function insert(parent, nodeFactory, before) {
543
549
  let isFirstRun = true;
544
550
  const resolveNodes = (raw) => {
545
551
  if (raw instanceof Node) return [raw];
546
- if (isNull(raw) || isUndefined(raw) || isString(raw) || isNumber(raw) || isBoolean(raw)) {
552
+ if (isComponent(raw)) return [raw];
553
+ const t = typeof raw;
554
+ if (raw == null || t === "string" || t === "number" || t === "boolean") {
547
555
  return [normalizeNode(raw)];
548
556
  }
549
557
  return coerceArray(raw).map((item) => isFunction(item) ? item() : item).flatMap((i) => i).map(normalizeNode);
@@ -1082,154 +1090,144 @@ function addEventListener(element, event, handler, options) {
1082
1090
  }
1083
1091
 
1084
1092
  // src/binding.ts
1085
- var INPUT_CHECKBOX_CHECKED = {
1093
+ function writeValue(el, v) {
1094
+ const target = el;
1095
+ const next2 = v == null ? "" : String(v);
1096
+ if (target.value !== next2) target.value = next2;
1097
+ }
1098
+ var CHECKBOX = {
1086
1099
  event: "change",
1087
- forceChangeEvent: true,
1088
- read: (n) => n.checked,
1089
- write: (n, v) => {
1090
- const el = n;
1100
+ forceChange: true,
1101
+ read: (el) => el.checked,
1102
+ write(el, v) {
1103
+ const e = el;
1091
1104
  const next2 = Boolean(v);
1092
- if (el.checked !== next2) el.checked = next2;
1105
+ if (e.checked !== next2) e.checked = next2;
1093
1106
  }
1094
1107
  };
1095
- var INPUT_RADIO_CHECKED = {
1108
+ var RADIO = {
1096
1109
  event: "change",
1097
- forceChangeEvent: true,
1098
- read: (n) => {
1099
- const el = n;
1100
- return el.checked ? el.value : "";
1110
+ forceChange: true,
1111
+ read(el) {
1112
+ const e = el;
1113
+ return e.checked ? e.value : "";
1101
1114
  },
1102
- write: (n, v) => {
1103
- const el = n;
1104
- const next2 = String(v) === el.value;
1105
- if (el.checked !== next2) el.checked = next2;
1115
+ write(el, v) {
1116
+ const e = el;
1117
+ const next2 = String(v) === e.value;
1118
+ if (e.checked !== next2) e.checked = next2;
1106
1119
  }
1107
1120
  };
1108
- var INPUT_FILE_FILES = {
1121
+ var FILE = {
1109
1122
  event: "change",
1110
- forceChangeEvent: true,
1111
- read: (n) => n.files,
1112
- // Browsers do not allow programmatic writes to <input type="file">.
1113
- write: () => {
1123
+ forceChange: true,
1124
+ read: (el) => el.files,
1125
+ write() {
1114
1126
  }
1127
+ // browsers forbid programmatic writes to file inputs
1115
1128
  };
1116
- var INPUT_VALUE = {
1129
+ var TEXT = {
1117
1130
  event: "input",
1118
- needsComposition: true,
1119
- read: (n) => n.value,
1120
- write: (n, v) => {
1121
- const el = n;
1122
- const next2 = v == null ? "" : String(v);
1123
- if (el.value !== next2) el.value = next2;
1124
- }
1131
+ ime: true,
1132
+ read: (el) => el.value,
1133
+ write: writeValue
1125
1134
  };
1126
- var SELECT_VALUE = {
1135
+ var TEXTAREA = {
1136
+ event: "input",
1137
+ ime: true,
1138
+ read: (el) => el.value,
1139
+ write: writeValue
1140
+ };
1141
+ var SELECT = {
1127
1142
  event: "change",
1128
- forceChangeEvent: true,
1129
- read: (n) => {
1130
- const s = n;
1143
+ forceChange: true,
1144
+ read(el) {
1145
+ const s = el;
1131
1146
  return s.multiple ? Array.from(s.selectedOptions, (o) => o.value) : s.value;
1132
1147
  },
1133
- write: (n, v) => {
1134
- const s = n;
1148
+ write(el, v) {
1149
+ const s = el;
1135
1150
  if (s.multiple) {
1136
- const set = new Set((Array.isArray(v) ? v : []).map(String));
1137
- for (const opt of Array.from(s.options)) opt.selected = set.has(opt.value);
1151
+ const selected = new Set((Array.isArray(v) ? v : []).map(String));
1152
+ for (const opt of Array.from(s.options)) opt.selected = selected.has(opt.value);
1138
1153
  } else {
1139
- const next2 = v == null ? "" : String(v);
1140
- if (s.value !== next2) s.value = next2;
1154
+ writeValue(el, v);
1141
1155
  }
1142
1156
  }
1143
1157
  };
1144
- var TEXTAREA_VALUE = {
1145
- event: "input",
1146
- needsComposition: true,
1147
- read: (n) => n.value,
1148
- write: (n, v) => {
1149
- const el = n;
1150
- const next2 = v == null ? "" : String(v);
1151
- if (el.value !== next2) el.value = next2;
1158
+ function resolve(node, prop) {
1159
+ switch (node.nodeName) {
1160
+ case "INPUT":
1161
+ if (prop === "checked") return node.type === "radio" ? RADIO : CHECKBOX;
1162
+ if (prop === "files") return FILE;
1163
+ return TEXT;
1164
+ case "SELECT":
1165
+ return SELECT;
1166
+ case "TEXTAREA":
1167
+ return TEXTAREA;
1168
+ default:
1169
+ return {
1170
+ event: "input",
1171
+ read: (el) => el[prop],
1172
+ write(el, v) {
1173
+ el[prop] = v;
1174
+ }
1175
+ };
1152
1176
  }
1153
- };
1154
- function resolveStrategy(node, prop) {
1155
- const tag = node.nodeName;
1156
- if (tag === "INPUT") {
1157
- const type = node.type;
1158
- if (prop === "checked") {
1159
- return type === "radio" ? INPUT_RADIO_CHECKED : INPUT_CHECKBOX_CHECKED;
1160
- }
1161
- if (prop === "files") return INPUT_FILE_FILES;
1162
- return INPUT_VALUE;
1163
- }
1164
- if (tag === "SELECT") return SELECT_VALUE;
1165
- if (tag === "TEXTAREA") return TEXTAREA_VALUE;
1166
- return {
1167
- event: "input",
1168
- read: (n) => n[prop],
1169
- write: (n, v) => {
1170
- n[prop] = v;
1171
- }
1172
- };
1173
1177
  }
1174
- function castValue(val, trim, number) {
1175
- if (!isString(val)) return val;
1176
- if (trim) val = val.trim();
1177
- if (number && val !== "") {
1178
- const parsed = Number(val);
1179
- if (!Number.isNaN(parsed)) return parsed;
1178
+ function applyModifiers(v, trim, toNum) {
1179
+ if (!isString(v)) return v;
1180
+ let s = v;
1181
+ if (trim) s = s.trim();
1182
+ if (toNum && s !== "") {
1183
+ const n = Number(s);
1184
+ if (!Number.isNaN(n)) return n;
1180
1185
  }
1181
- return val;
1186
+ return s;
1182
1187
  }
1183
- function isFocused(node) {
1184
- const root = node.getRootNode();
1185
- return (root instanceof Document || root instanceof ShadowRoot) && root.activeElement === node;
1188
+ function isFocused(el) {
1189
+ const root = el.getRootNode();
1190
+ return (root instanceof Document || root instanceof ShadowRoot) && root.activeElement === el;
1186
1191
  }
1187
1192
  function bindElement(node, prop, getter, setter, modifiers = {}) {
1188
1193
  if (!node) return;
1189
- const strategy = resolveStrategy(node, prop);
1190
- const { trim, number, lazy } = modifiers;
1191
- const isFiles = prop === "files";
1192
- const readModel = () => isFunction(getter) ? getter() : getter;
1193
- const transform = (v) => isFiles ? v : castValue(v, trim, number);
1194
- const eventName = lazy || strategy.forceChangeEvent ? "change" : strategy.event;
1194
+ const { event, read, write, forceChange, ime } = resolve(node, prop);
1195
+ const trim = modifiers.trim === true;
1196
+ const toNum = modifiers.number === true;
1197
+ const lazy = modifiers.lazy === true;
1198
+ const shouldCast = (trim || toNum) && prop !== "files";
1199
+ const getModel = isFunction(getter) ? getter : () => getter;
1200
+ const cast = shouldCast ? (v) => applyModifiers(v, trim, toNum) : (v) => v;
1195
1201
  let composing = false;
1196
- const syncFromDom = () => {
1202
+ const eventName = lazy || forceChange ? "change" : event;
1203
+ const syncToModel = () => {
1197
1204
  if (composing) return;
1198
- const raw = strategy.read(node);
1205
+ const raw = read(node);
1199
1206
  if (raw === void 0) return;
1200
- if (isFiles) {
1201
- setter(raw);
1202
- return;
1203
- }
1204
- const next2 = transform(raw);
1205
- if (!Object.is(readModel(), next2)) {
1206
- setter(next2);
1207
- }
1207
+ const next2 = cast(raw);
1208
+ if (!Object.is(getModel(), next2)) setter(next2);
1208
1209
  };
1209
- addEventListener(node, eventName, syncFromDom);
1210
- if (!lazy && !isFiles && (trim || number) && eventName !== "change") {
1211
- addEventListener(node, "change", () => {
1212
- strategy.write(node, transform(strategy.read(node)));
1213
- });
1210
+ addEventListener(node, eventName, syncToModel);
1211
+ if (!lazy && shouldCast && eventName !== "change") {
1212
+ addEventListener(node, "change", () => write(node, cast(read(node))));
1214
1213
  }
1215
- if (strategy.needsComposition && !lazy) {
1214
+ if (ime && !lazy) {
1216
1215
  addEventListener(node, "compositionstart", () => {
1217
1216
  composing = true;
1218
1217
  });
1219
1218
  addEventListener(node, "compositionend", () => {
1220
1219
  if (!composing) return;
1221
1220
  composing = false;
1222
- syncFromDom();
1221
+ syncToModel();
1223
1222
  });
1224
1223
  }
1225
1224
  const runner = effect(() => {
1226
- const value = readModel();
1227
- if (strategy.needsComposition && !lazy && isFocused(node)) {
1225
+ const value = getModel();
1226
+ if (ime && !lazy && isFocused(node)) {
1228
1227
  if (composing) return;
1229
- const current = transform(strategy.read(node));
1230
- if (Object.is(current, value)) return;
1228
+ if (Object.is(cast(read(node)), value)) return;
1231
1229
  }
1232
- strategy.write(node, value);
1230
+ write(node, value);
1233
1231
  });
1234
1232
  if (getActiveScope()) {
1235
1233
  onCleanup(() => runner.stop());