ilha 0.9.4 → 0.10.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.
@@ -1,4 +1,4 @@
1
- import { __ilhaJsxSlot, html, raw } from "./index.js";
1
+ import { __ilhaJsxEvent, __ilhaJsxSlot, html, raw } from "./index.js";
2
2
 
3
3
  //#region src/jsx-runtime.ts
4
4
  const RAW = Symbol.for("ilha.raw");
@@ -8,6 +8,47 @@ const ISLAND_CALL = Symbol.for("ilha.islandCall");
8
8
  const RENDER_PART = Symbol.for("ilha.renderPart");
9
9
  const SAFE_NAME_RE = /^[A-Za-z_:][A-Za-z0-9:._-]*$/;
10
10
  const SAFE_BIND_LOCAL_RE = /^[A-Za-z][A-Za-z0-9]*$/;
11
+ const SAFE_EVENT_PROP_RE = /^on([a-z][a-z0-9-]*)(?::(abortable|once|capture|passive))?$/;
12
+ const JSX_ATTRIBUTE_ALIASES = {
13
+ className: "class",
14
+ htmlFor: "for",
15
+ acceptCharset: "accept-charset",
16
+ httpEquiv: "http-equiv",
17
+ accentHeight: "accent-height",
18
+ alignmentBaseline: "alignment-baseline",
19
+ baselineShift: "baseline-shift",
20
+ clipPath: "clip-path",
21
+ clipRule: "clip-rule",
22
+ dominantBaseline: "dominant-baseline",
23
+ fillOpacity: "fill-opacity",
24
+ fillRule: "fill-rule",
25
+ floodColor: "flood-color",
26
+ floodOpacity: "flood-opacity",
27
+ fontFamily: "font-family",
28
+ fontSize: "font-size",
29
+ fontStyle: "font-style",
30
+ fontWeight: "font-weight",
31
+ markerEnd: "marker-end",
32
+ markerMid: "marker-mid",
33
+ markerStart: "marker-start",
34
+ stopColor: "stop-color",
35
+ stopOpacity: "stop-opacity",
36
+ strokeDasharray: "stroke-dasharray",
37
+ strokeDashoffset: "stroke-dashoffset",
38
+ strokeLinecap: "stroke-linecap",
39
+ strokeLinejoin: "stroke-linejoin",
40
+ strokeMiterlimit: "stroke-miterlimit",
41
+ strokeOpacity: "stroke-opacity",
42
+ strokeWidth: "stroke-width",
43
+ textAnchor: "text-anchor",
44
+ vectorEffect: "vector-effect",
45
+ xlinkHref: "xlink:href"
46
+ };
47
+ const STRING_BOOLEAN_ATTRIBUTES = /* @__PURE__ */ new Set([
48
+ "contenteditable",
49
+ "draggable",
50
+ "spellcheck"
51
+ ]);
11
52
  const VOID_ELEMENTS = /* @__PURE__ */ new Set([
12
53
  "area",
13
54
  "base",
@@ -82,8 +123,8 @@ function serializeStyle(value) {
82
123
  return `${prop}:${str}`;
83
124
  }).filter(Boolean).join(";");
84
125
  }
85
- function pushJsxAttr(chunks, values, name, value) {
86
- if (value == null || value === false || name === "children" || name === "key") return;
126
+ function pushJsxAttr({ chunks, values, eventSpecs, name, value }) {
127
+ if (value == null || name === "children" || name === "key") return;
87
128
  if (name === "__proto__" || name === "constructor" || name === "prototype") return;
88
129
  if (name.startsWith("bind:")) {
89
130
  const [prefix, localName, ...rest] = name.split(":");
@@ -95,14 +136,28 @@ function pushJsxAttr(chunks, values, name, value) {
95
136
  return;
96
137
  }
97
138
  if (!SAFE_NAME_RE.test(name)) return;
98
- let safeName = name;
99
- if (safeName === "className") safeName = "class";
100
- if (safeName === "htmlFor") safeName = "for";
101
- if (safeName.startsWith("on")) return;
102
- if (safeName === "srcdoc") return;
103
- if (safeName === "class") value = normalizeClass(value);
104
- if (safeName === "style" && value && typeof value === "object") value = serializeStyle(value);
105
- if ((URL_ATTRS.has(safeName) || /:(href|src|action|formaction|cite|data|poster)$/.test(safeName)) && !isSafeUrl(typeof value === "string" ? value : String(value))) return;
139
+ const safeName = JSX_ATTRIBUTE_ALIASES[name] ?? name;
140
+ if (safeName.startsWith("on")) {
141
+ const eventMatch = SAFE_EVENT_PROP_RE.exec(safeName);
142
+ if (typeof value !== "function" || !eventMatch) return;
143
+ const eventName = eventMatch[1];
144
+ const modifier = eventMatch[2];
145
+ const index = __ilhaJsxEvent({
146
+ type: eventName,
147
+ handler: value,
148
+ modifier
149
+ });
150
+ if (index !== void 0) eventSpecs.push(`${eventName}:${index}`);
151
+ return;
152
+ }
153
+ const securityName = safeName.toLowerCase();
154
+ if (securityName === "srcdoc") return;
155
+ const stringBoolean = securityName.startsWith("aria-") || STRING_BOOLEAN_ATTRIBUTES.has(securityName);
156
+ if (typeof value === "boolean" && stringBoolean) value = String(value);
157
+ else if (value === false) return;
158
+ if (safeName === "class" && !isRawHtml(value)) value = normalizeClass(value);
159
+ if (safeName === "style" && value && typeof value === "object" && !isRawHtml(value)) value = serializeStyle(value);
160
+ if ((URL_ATTRS.has(securityName) || /:(href|src|action|formaction|cite|data|poster)$/.test(securityName)) && !isSafeUrl(typeof value === "string" ? value : String(value))) return;
106
161
  if (value === true) {
107
162
  chunks[chunks.length - 1] += ` ${safeName}`;
108
163
  return;
@@ -123,11 +178,25 @@ function injectDataKey(out, key) {
123
178
  const insertAt = m.index + m[0].length;
124
179
  return raw(`${out.value.slice(0, insertAt)} data-key="${escapeAttrValue(key)}"${out.value.slice(insertAt)}`);
125
180
  }
126
- function renderJsxElement(type, props, children, slotKey) {
181
+ function renderJsxElement({ type, props, children, slotKey }) {
127
182
  const chunks = [`<${type}`];
128
183
  const values = [];
129
- if (props) for (const [name, value] of Object.entries(props)) pushJsxAttr(chunks, values, name, value);
130
- if (slotKey !== void 0 && props?.["data-key"] == null) pushJsxAttr(chunks, values, "data-key", slotKey);
184
+ const eventSpecs = [];
185
+ if (props) for (const [name, value] of Object.entries(props)) pushJsxAttr({
186
+ chunks,
187
+ values,
188
+ eventSpecs,
189
+ name,
190
+ value
191
+ });
192
+ if (slotKey !== void 0 && props?.["data-key"] == null) pushJsxAttr({
193
+ chunks,
194
+ values,
195
+ eventSpecs,
196
+ name: "data-key",
197
+ value: slotKey
198
+ });
199
+ if (eventSpecs.length > 0) chunks[chunks.length - 1] += ` data-ilha-on="${eventSpecs.join(",")}"`;
131
200
  chunks[chunks.length - 1] += ">";
132
201
  if (!VOID_ELEMENTS.has(type)) {
133
202
  for (const child of children) {
@@ -155,12 +224,21 @@ function jsx(type, props, maybeKey, ...restChildren) {
155
224
  return html`${out}`;
156
225
  }
157
226
  if (isRawHtml(out)) return slotKey !== void 0 ? injectDataKey(out, slotKey) : out;
158
- if (typeof out === "string" && isIsland(type)) return __ilhaJsxSlot(type, componentProps, slotKey);
227
+ if (typeof out === "string" && isIsland(type)) return __ilhaJsxSlot({
228
+ island: type,
229
+ props: componentProps,
230
+ key: slotKey
231
+ });
159
232
  if (typeof out === "string") return html`${out}`;
160
233
  if (typeof out === "object" && out !== null && Object.getPrototypeOf(out) === Object.prototype && out[RENDER_PART] === true && typeof out.toString === "function") return raw(String(out));
161
234
  return html`${out}`;
162
235
  }
163
- return renderJsxElement(type, props, normalizedChildren, slotKey);
236
+ return renderJsxElement({
237
+ type,
238
+ props,
239
+ children: normalizedChildren,
240
+ slotKey
241
+ });
164
242
  }
165
243
  const jsxs = jsx;
166
244
  function Fragment(props, ...children) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ilha",
3
- "version": "0.9.4",
3
+ "version": "0.10.0",
4
4
  "description": "A tiny, framework-free island architecture library",
5
5
  "keywords": [
6
6
  "framework-free",
@@ -1,37 +0,0 @@
1
- import { y as RawHtml } from "./index-Dx_q_SGo.js";
2
-
3
- //#region src/jsx-types.d.ts
4
- declare namespace JSX {
5
- type Child = unknown;
6
- type ElementType = string | ((props: any) => any);
7
- interface Element extends RawHtml {}
8
- interface ElementChildrenAttribute {
9
- children: {};
10
- }
11
- interface IntrinsicAttributes {
12
- key?: string | number;
13
- }
14
- type IntrinsicElementProps = {
15
- children?: Child;
16
- class?: string | unknown[] | Record<string, boolean>;
17
- className?: string | unknown[] | Record<string, boolean>;
18
- htmlFor?: string;
19
- [name: string]: unknown;
20
- };
21
- interface IntrinsicElements {
22
- [name: string]: IntrinsicElementProps;
23
- }
24
- }
25
- //#endregion
26
- //#region src/jsx-runtime.d.ts
27
- type JsxChild = unknown;
28
- type JsxProps = Record<string, unknown> | null | undefined;
29
- type JsxType = string | ((props: Record<string, unknown>) => unknown);
30
- declare function jsx(type: JsxType, props: JsxProps, maybeKey?: JsxChild | string | number, ...restChildren: JsxChild[]): RawHtml;
31
- declare const jsxs: typeof jsx;
32
- declare function Fragment(props: {
33
- children?: JsxChild;
34
- } | null, ...children: JsxChild[]): RawHtml;
35
- declare function jsxDEV(type: JsxType, props: JsxProps, maybeKey?: string | number, _source?: unknown, _self?: unknown): RawHtml;
36
- //#endregion
37
- export { JSX as a, jsxs as i, jsx as n, jsxDEV as r, Fragment as t };