@oscarpalmer/abydon 0.12.0 → 0.13.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.
Files changed (54) hide show
  1. package/dist/abydon.full.js +1247 -0
  2. package/dist/fragment.js +60 -0
  3. package/dist/helpers/dom.js +28 -0
  4. package/dist/helpers/index.js +11 -0
  5. package/dist/index.js +6 -911
  6. package/dist/node/attribute/index.js +34 -0
  7. package/dist/node/attribute/value.js +58 -0
  8. package/dist/node/event.js +32 -0
  9. package/dist/node/index.js +52 -0
  10. package/dist/node/value.js +93 -0
  11. package/dist/parse.js +21 -0
  12. package/package.json +41 -28
  13. package/src/fragment.ts +13 -14
  14. package/src/helpers/dom.ts +2 -1
  15. package/src/helpers/index.ts +0 -9
  16. package/src/index.ts +11 -2
  17. package/src/models.ts +6 -8
  18. package/src/node/attribute/index.ts +4 -3
  19. package/src/node/attribute/value.ts +8 -15
  20. package/src/node/event.ts +1 -1
  21. package/src/node/index.ts +4 -3
  22. package/src/node/value.ts +6 -7
  23. package/src/{html.ts → parse.ts} +5 -14
  24. package/types/fragment.d.cts +27 -0
  25. package/types/helpers/dom.d.cts +7 -0
  26. package/types/helpers/index.d.cts +29 -0
  27. package/types/helpers/index.d.ts +0 -3
  28. package/types/index.d.cts +278 -2
  29. package/types/index.d.ts +4 -2
  30. package/types/models.d.cts +107 -0
  31. package/types/models.d.ts +6 -7
  32. package/types/node/attribute/index.d.cts +109 -0
  33. package/types/node/attribute/index.d.ts +2 -1
  34. package/types/node/attribute/value.d.cts +109 -0
  35. package/types/node/attribute/value.d.ts +2 -1
  36. package/types/node/event.d.cts +7 -0
  37. package/types/node/event.d.ts +1 -1
  38. package/types/node/index.d.cts +108 -0
  39. package/types/node/value.d.cts +108 -0
  40. package/types/node/value.d.ts +2 -2
  41. package/types/parse.d.cts +108 -0
  42. package/types/parse.d.ts +2 -0
  43. package/dist/fragment.mjs +0 -75
  44. package/dist/helpers/dom.mjs +0 -44
  45. package/dist/helpers/index.mjs +0 -25
  46. package/dist/html.mjs +0 -36
  47. package/dist/index.mjs +0 -6
  48. package/dist/node/attribute/index.mjs +0 -40
  49. package/dist/node/attribute/value.mjs +0 -89
  50. package/dist/node/event.mjs +0 -38
  51. package/dist/node/index.mjs +0 -60
  52. package/dist/node/value.mjs +0 -123
  53. package/types/html.d.ts +0 -4
  54. /package/dist/{models.mjs → models.js} +0 -0
@@ -0,0 +1,34 @@
1
+ import { mapEvent } from "../event.js";
2
+ import { setAttribute } from "./value.js";
3
+ import { computed, isReactive } from "@oscarpalmer/mora";
4
+ var commentExpression = /^<!--abydon\.(\d+)-->$/;
5
+ function getValue(data, original) {
6
+ const matches = commentExpression.exec(original ?? "");
7
+ return matches == null ? original : data.values[+matches[1]];
8
+ }
9
+ function mapAttributes(data, element) {
10
+ const attributes = [...element.attributes];
11
+ const { length } = attributes;
12
+ for (let index = 0; index < length; index += 1) {
13
+ const { name, value } = attributes[index];
14
+ const actual = getValue(data, value);
15
+ if (name.startsWith("@")) mapEvent(element, name, actual);
16
+ else if (name.includes(".") || typeof value === "function" || isReactive(actual)) mapValue(data, element, name, actual);
17
+ }
18
+ }
19
+ function mapValue(data, element, name, value) {
20
+ switch (true) {
21
+ case typeof value === "function":
22
+ setComputedAttribute(data, element, name, value);
23
+ break;
24
+ default:
25
+ setAttribute(data, element, name, value);
26
+ break;
27
+ }
28
+ }
29
+ function setComputedAttribute(data, element, name, callback) {
30
+ const value = computed(callback);
31
+ data.mora.values.add(value);
32
+ setAttribute(data, element, name, value);
33
+ }
34
+ export { mapAttributes };
@@ -0,0 +1,58 @@
1
+ import { isReactive } from "@oscarpalmer/mora";
2
+ import { getString } from "@oscarpalmer/atoms/string";
3
+ import { isBooleanAttribute, setAttribute as setAttribute$1 } from "@oscarpalmer/toretto/attribute";
4
+ var classExpression = /^class\./;
5
+ var styleFullExpression = /^style\.([\w-]+)(?:\.([\w-]+))?$/;
6
+ var stylePrefixExpression = /^style\./;
7
+ function setAttribute(data, element, name, value) {
8
+ element.removeAttribute(name);
9
+ switch (true) {
10
+ case classExpression.test(name):
11
+ setClasses(data, element, name, value);
12
+ return;
13
+ case stylePrefixExpression.test(name):
14
+ setStyle(data, element, name, value);
15
+ return;
16
+ default:
17
+ setValue(data, element, name, value);
18
+ break;
19
+ }
20
+ }
21
+ function setClasses(data, element, name, value) {
22
+ function update(value$1) {
23
+ if (value$1 === true) element.classList.add(...classes);
24
+ else element.classList.remove(...classes);
25
+ }
26
+ const classes = name.slice(6).split(".");
27
+ if (isReactive(value)) data.mora.subscribers.add(value.subscribe(update));
28
+ else update(value);
29
+ }
30
+ function setStyle(data, element, name, value) {
31
+ function update(value$1) {
32
+ if (value$1 == null || value$1 === false || value$1 === true && unit == null) element.style.removeProperty(property);
33
+ else element.style.setProperty(property, value$1 === true ? unit : getString(value$1));
34
+ }
35
+ const [, property, unit] = styleFullExpression.exec(name) ?? [];
36
+ if (property != null) if (isReactive(value)) data.mora.subscribers.add(value.subscribe(update));
37
+ else update(value);
38
+ }
39
+ function setValue(data, element, name, value) {
40
+ const callback = isBooleanAttribute(name) && name in element ? name === "selected" ? updateSelected : updateProperty : setAttribute$1;
41
+ if (isReactive(value)) data.mora.subscribers.add(value.subscribe((next) => {
42
+ callback(element, name, next);
43
+ }));
44
+ else callback(element, name, value);
45
+ }
46
+ function triggerSelectChange(select) {
47
+ if (select != null) select.dispatchEvent(new Event("change", { bubbles: true }));
48
+ }
49
+ function updateProperty(element, name, value) {
50
+ element[name] = value === true;
51
+ }
52
+ function updateSelected(element, name, value) {
53
+ const select = element.closest("select");
54
+ const options = [...select?.options ?? []];
55
+ if (select != null && options.includes(element)) triggerSelectChange(select);
56
+ updateProperty(element, name, value);
57
+ }
58
+ export { setAttribute };
@@ -0,0 +1,32 @@
1
+ var controllers = /* @__PURE__ */ new WeakMap();
2
+ var eventNamePattern = /^@([\w-]+)(?::([a-z:]+))?$/i;
3
+ var reason = "Event removed as element was removed from document by Abydon";
4
+ function getController(element) {
5
+ let controller = controllers.get(element);
6
+ if (controller == null) {
7
+ controller = new AbortController();
8
+ controllers.set(element, controller);
9
+ }
10
+ return controller;
11
+ }
12
+ function getOptions(options) {
13
+ const parts = options.split(":");
14
+ return {
15
+ capture: parts.includes("c") || parts.includes("capture"),
16
+ once: parts.includes("o") || parts.includes("once"),
17
+ passive: !parts.includes("a") && !parts.includes("active")
18
+ };
19
+ }
20
+ function mapEvent(element, name, value) {
21
+ element.removeAttribute(name);
22
+ const [, type, options] = eventNamePattern.exec(name) ?? [];
23
+ if (typeof value === "function" && type != null) element.addEventListener(type, value, {
24
+ ...getOptions(options ?? ""),
25
+ signal: getController(element).signal
26
+ });
27
+ }
28
+ function removeEvents(element) {
29
+ controllers.get(element)?.abort(reason);
30
+ controllers.delete(element);
31
+ }
32
+ export { mapEvent, removeEvents };
@@ -0,0 +1,52 @@
1
+ import { isFragment } from "../helpers/index.js";
2
+ import { createNodes } from "../helpers/dom.js";
3
+ import { mapAttributes } from "./attribute/index.js";
4
+ import { setReactiveValue } from "./value.js";
5
+ import { computed, isReactive } from "@oscarpalmer/mora";
6
+ import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
7
+ var commentExpression = /^abydon\.(\d+)$/;
8
+ function mapNode(data, comment) {
9
+ const matches = commentExpression.exec(comment.textContent ?? "");
10
+ const value = matches == null ? null : data.values[+matches[1]];
11
+ if (value != null) mapValue(data, comment, value);
12
+ }
13
+ function mapNodes(data, nodes) {
14
+ const { length } = nodes;
15
+ for (let index = 0; index < length; index += 1) {
16
+ const node = nodes[index];
17
+ if (node instanceof Comment) {
18
+ mapNode(data, node);
19
+ continue;
20
+ }
21
+ if (isHTMLOrSVGElement(node)) mapAttributes(data, node);
22
+ if (node.hasChildNodes()) mapNodes(data, [...node.childNodes]);
23
+ }
24
+ }
25
+ function mapValue(data, comment, value) {
26
+ switch (true) {
27
+ case typeof value === "function":
28
+ setComputedValue(data, comment, value);
29
+ break;
30
+ case isReactive(value):
31
+ setReactiveValue(data, comment, value);
32
+ break;
33
+ default:
34
+ replaceComment(data, comment, value);
35
+ break;
36
+ }
37
+ }
38
+ function replaceComment(data, comment, value) {
39
+ const item = data.items.find((item$1) => item$1.nodes.includes(comment));
40
+ const nodes = createNodes(value);
41
+ if (item != null) {
42
+ item.fragments = isFragment(value) ? [value] : void 0;
43
+ item.nodes = nodes;
44
+ }
45
+ comment.replaceWith(...nodes);
46
+ }
47
+ function setComputedValue(data, comment, callback) {
48
+ const value = computed(callback);
49
+ data.mora.values.add(value);
50
+ setReactiveValue(data, comment, value);
51
+ }
52
+ export { mapNodes };
@@ -0,0 +1,93 @@
1
+ import { compareArrays, isFragment } from "../helpers/index.js";
2
+ import { createNodes, replaceNodes } from "../helpers/dom.js";
3
+ import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
4
+ import { getString } from "@oscarpalmer/atoms/string";
5
+ import { isChildNode } from "@oscarpalmer/toretto/is";
6
+ function removeFragments(fragments) {
7
+ if (fragments != null) {
8
+ const { length } = fragments;
9
+ for (let index = 0; index < length; index += 1) fragments[index].remove();
10
+ }
11
+ }
12
+ function setArray(fragments, nodes, comment, text, value) {
13
+ if (value.length === 0) return { nodes: setText(fragments, nodes, comment, text, value) };
14
+ let templates = value.filter((item) => isFragment(item) && item.identifier != null);
15
+ const identifiers = templates.map((fragment) => fragment.identifier);
16
+ const oldIdentifiers = fragments?.map((fragment) => fragment.identifier) ?? [];
17
+ if (new Set(identifiers).size !== templates.length) templates = [];
18
+ const noTemplates = templates.length === 0;
19
+ if (noTemplates || nodes == null || oldIdentifiers.some((identifier) => identifier == null)) return {
20
+ fragments: noTemplates ? void 0 : templates,
21
+ nodes: setNodes(fragments, nodes, comment, text, noTemplates ? value.flatMap((item) => createNodes(item)) : templates.flatMap((template) => template.get()))
22
+ };
23
+ const next = templates.map((template) => fragments?.find((fragment) => fragment.identifier === template.identifier) ?? template);
24
+ const comparison = compareArrays(fragments ?? [], templates);
25
+ if (comparison !== "removed") {
26
+ let position = nodes[0];
27
+ const before = comparison === "added" && !oldIdentifiers.includes(templates[0].identifier);
28
+ const items = next.flatMap((fragment) => fragment.get().flatMap((node) => ({
29
+ identifier: fragment.identifier,
30
+ value: node
31
+ })));
32
+ const { length: length$1 } = items;
33
+ for (let index = 0; index < length$1; index += 1) {
34
+ const item = items[index];
35
+ if (comparison === "dissimilar" || !oldIdentifiers.includes(item.identifier)) if (index === 0 && before) position.before(item.value);
36
+ else position.after(item.value);
37
+ position = item.value;
38
+ }
39
+ }
40
+ const toRemove = fragments?.filter((fragment) => !identifiers.includes(fragment.identifier)) ?? [];
41
+ const { length } = toRemove;
42
+ for (let index = 0; index < length; index += 1) toRemove[index].remove();
43
+ return {
44
+ fragments: next,
45
+ nodes: next.flatMap((fragment) => fragment.get())
46
+ };
47
+ }
48
+ function setNodes(fragments, nodes, comment, text, next) {
49
+ if (nodes == null) {
50
+ if (comment.parentNode != null) replaceNodes([comment], next);
51
+ else if (text.parentNode != null) replaceNodes([text], next);
52
+ } else replaceNodes(nodes, next);
53
+ removeFragments(fragments);
54
+ return next;
55
+ }
56
+ function setReactiveValue(data, comment, reactive) {
57
+ const item = data.items.find((item$1) => item$1.nodes.includes(comment));
58
+ const text = new Text();
59
+ let fragments;
60
+ let nodes;
61
+ data.mora.subscribers.add(reactive.subscribe((value) => {
62
+ if (Array.isArray(value)) {
63
+ const result = setArray(fragments, nodes, comment, text, value);
64
+ fragments = typeof result === "boolean" ? void 0 : result?.fragments;
65
+ nodes = typeof result === "boolean" ? result ? [text] : void 0 : result?.nodes;
66
+ } else {
67
+ const valueIsFragment = isFragment(value);
68
+ fragments = valueIsFragment ? [value] : void 0;
69
+ if (valueIsFragment || isChildNode(value)) nodes = setNodes(fragments, nodes, comment, text, createNodes(value));
70
+ else nodes = setText(fragments, nodes, comment, text, value);
71
+ }
72
+ if (item != null) {
73
+ item.fragments = fragments;
74
+ item.nodes = [...nodes ?? [comment]];
75
+ }
76
+ }));
77
+ }
78
+ function setText(fragments, nodes, comment, text, value) {
79
+ const isNullable = isNullableOrWhitespace(value);
80
+ text.textContent = isNullable ? "" : getString(value);
81
+ let result = false;
82
+ if (nodes != null) {
83
+ replaceNodes(nodes, [isNullable ? comment : text]);
84
+ result = !isNullable;
85
+ } else if (isNullable && comment.parentNode == null) text.replaceWith(comment);
86
+ else if (!isNullable && text.parentNode == null) {
87
+ comment.replaceWith(text);
88
+ result = true;
89
+ }
90
+ removeFragments(fragments);
91
+ return result ? [text] : void 0;
92
+ }
93
+ export { setReactiveValue };
package/dist/parse.js ADDED
@@ -0,0 +1,21 @@
1
+ import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
2
+ function handleExpression(data, prefix, expression) {
3
+ if (Array.isArray(expression)) {
4
+ const { length } = expression;
5
+ let expressions = "";
6
+ for (let index = 0; index < length; index += 1) expressions += handleExpression(data, "", expression[index]);
7
+ return `${prefix}${expressions}`;
8
+ }
9
+ if (typeof expression === "function" || typeof expression === "object" && expression != null) {
10
+ const index = data.values.push(expression) - 1;
11
+ return `${prefix}<!--abydon.${index}-->`;
12
+ }
13
+ return isNullableOrWhitespace(expression) ? prefix : `${prefix}${expression}`;
14
+ }
15
+ function parse(data) {
16
+ const { length } = data.strings;
17
+ let template = "";
18
+ for (let index = 0; index < length; index += 1) template += handleExpression(data, data.strings[index], data.expressions[index]);
19
+ return template;
20
+ }
21
+ export { parse };
package/package.json CHANGED
@@ -4,48 +4,61 @@
4
4
  "url": "https://oscarpalmer.se"
5
5
  },
6
6
  "dependencies": {
7
- "@oscarpalmer/atoms": "^0.71.0",
8
- "@oscarpalmer/sentinel": "^0.23.0",
9
- "@oscarpalmer/toretto": "0.12.1"
7
+ "@oscarpalmer/atoms": "^0.108",
8
+ "@oscarpalmer/mora": "^0.21",
9
+ "@oscarpalmer/toretto": "^0.22"
10
10
  },
11
11
  "devDependencies": {
12
- "@biomejs/biome": "^1.8.3",
13
- "@types/bun": "^1.1.8",
14
- "bun": "^1.1.27",
15
- "dts-bundle-generator": "^9.5.1",
16
- "typescript": "^5.5.4"
12
+ "@biomejs/biome": "^2.2",
13
+ "@oscarpalmer/oui": "^0.17",
14
+ "@rollup/plugin-node-resolve": "^16",
15
+ "@rollup/plugin-typescript": "^12.1",
16
+ "@types/node": "^24.3",
17
+ "@vitest/coverage-istanbul": "^3.2",
18
+ "dts-bundle-generator": "^9.5",
19
+ "glob": "^11",
20
+ "jsdom": "^26.1",
21
+ "rollup": "^4.50",
22
+ "tslib": "^2.8",
23
+ "typescript": "^5.9",
24
+ "vite": "npm:rolldown-vite@latest",
25
+ "vitest": "^3.2"
17
26
  },
18
27
  "exports": {
28
+ "./package.json": "./package.json",
19
29
  ".": {
20
- "bun": "./src/index.ts",
21
- "import": {
22
- "types": "./types/index.d.ts",
23
- "default": "./dist/index.mjs"
24
- },
25
- "require": {
26
- "types": "./types/index.d.cts",
27
- "default": "./dist/index.js"
28
- }
30
+ "types": "./types/index.d.ts",
31
+ "default": "./dist/index.js"
29
32
  }
30
33
  },
31
- "files": ["dist/index.js", "dist/**/*.mjs", "src", "types"],
34
+ "files": ["dist", "src", "types"],
35
+ "keywords": [
36
+ "components",
37
+ "dom",
38
+ "library",
39
+ "literals",
40
+ "reactive",
41
+ "signal",
42
+ "template",
43
+ "vanilla"
44
+ ],
32
45
  "license": "MIT",
33
- "main": "dist/index.js",
34
- "module": "dist/index.mjs",
46
+ "module": "dist/index.js",
35
47
  "name": "@oscarpalmer/abydon",
36
48
  "repository": {
37
49
  "type": "git",
38
50
  "url": "git+https://github.com/oscarpalmer/abydon.git"
39
51
  },
40
52
  "scripts": {
41
- "build": "bun run clean && bunx bun ./.bun.ts && bunx bun ./.bun.ts --mjs && bun run types",
42
- "clean": "rm -rf ./dist && rm -rf ./types && rm -rf ./tsconfig.tsbuildinfo",
43
- "types": "bun run types:cjs && bun run types:esm",
44
- "types:cjs": "bunx dts-bundle-generator --out-file ./types/index.d.cts --no-check --silent ./src/index.ts",
45
- "types:esm": "bunx tsc -p ./tsconfig.json",
46
- "watch": "bun build ./src/index.ts --outfile ./dist/index.js --watch"
53
+ "build": "npm run clean && npx vite build && npm run rollup:build && npm run types",
54
+ "clean": "rm -rf ./dist && rm -rf ./types && rm -f ./tsconfig.tsbuildinfo",
55
+ "rollup:build": "npx rollup -c",
56
+ "rollup:watch": "npx rollup -c --watch",
57
+ "test": "npx vitest --coverage",
58
+ "types": "npx tsc && npx dts-bundle-generator --config ./dts.config.cts --silent",
59
+ "watch": "npx vite build --watch"
47
60
  },
48
61
  "type": "module",
49
- "types": "types/index.d.ts",
50
- "version": "0.12.0"
62
+ "types": "types/index.d.cts",
63
+ "version": "0.13.0"
51
64
  }
package/src/fragment.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import type {Key} from '@oscarpalmer/atoms/models';
2
2
  import {html} from '@oscarpalmer/toretto/html';
3
- import {parse} from './html';
3
+ import {removeNodes} from './helpers/dom';
4
4
  import type {FragmentData} from './models';
5
5
  import {mapNodes} from './node';
6
- import {removeNodes} from './helpers/dom';
6
+ import {parse} from './parse';
7
7
 
8
8
  export class Fragment {
9
9
  private readonly $fragment = true;
@@ -18,8 +18,8 @@ export class Fragment {
18
18
  expressions,
19
19
  strings,
20
20
  items: [],
21
- sentinel: {
22
- effects: new Set(),
21
+ mora: {
22
+ subscribers: new Set(),
23
23
  values: new Set(),
24
24
  },
25
25
  values: [],
@@ -41,7 +41,7 @@ export class Fragment {
41
41
  const parsed = parse(this.data);
42
42
 
43
43
  const templated = html(parsed, {
44
- sanitiseBooleanAttributes: false,
44
+ sanitizeBooleanAttributes: false,
45
45
  });
46
46
 
47
47
  this.data.items.splice(
@@ -84,7 +84,7 @@ export class Fragment {
84
84
  }
85
85
 
86
86
  function removeFragment(data: FragmentData): void {
87
- removeSentinels(data);
87
+ removeMora(data);
88
88
 
89
89
  const {length} = data.items;
90
90
 
@@ -102,14 +102,13 @@ function removeFragment(data: FragmentData): void {
102
102
  data.items.splice(0, length);
103
103
  }
104
104
 
105
- function removeSentinels(data: FragmentData): void {
106
- const sentinels = [...data.sentinel.effects, ...data.sentinel.values];
107
- const {length} = sentinels;
105
+ function removeMora(data: FragmentData): void {
106
+ const unsubscribers = [...data.mora.subscribers];
108
107
 
109
- for (let index = 0; index < length; index += 1) {
110
- sentinels[index].stop();
111
- }
108
+ data.mora.subscribers.clear();
109
+ data.mora.values.clear();
112
110
 
113
- data.sentinel.effects.clear();
114
- data.sentinel.values.clear();
111
+ for (const unsubscribe of unsubscribers) {
112
+ unsubscribe();
113
+ }
115
114
  }
@@ -1,6 +1,7 @@
1
1
  import {getString} from '@oscarpalmer/atoms/string';
2
- import {isChildNode, isFragment, isHTMLOrSVGElement} from './index';
2
+ import {isChildNode, isHTMLOrSVGElement} from '@oscarpalmer/toretto/is';
3
3
  import {removeEvents} from '../node/event';
4
+ import {isFragment} from './index';
4
5
 
5
6
  export function createNodes(value: unknown): ChildNode[] {
6
7
  if (isFragment(value)) {
@@ -1,5 +1,4 @@
1
1
  import type {Fragment} from '../fragment';
2
- import type {HTMLOrSVGElement} from '../models';
3
2
 
4
3
  export function compareArrays(
5
4
  first: unknown[],
@@ -20,10 +19,6 @@ export function compareArrays(
20
19
  return firstIsLarger ? 'removed' : 'added';
21
20
  }
22
21
 
23
- export function isChildNode(value: unknown): value is ChildNode {
24
- return value instanceof CharacterData || value instanceof Element;
25
- }
26
-
27
22
  export function isFragment(value: unknown): value is Fragment {
28
23
  return (
29
24
  typeof value === 'object' &&
@@ -32,7 +27,3 @@ export function isFragment(value: unknown): value is Fragment {
32
27
  value.$fragment === true
33
28
  );
34
29
  }
35
-
36
- export function isHTMLOrSVGElement(value: unknown): value is HTMLOrSVGElement {
37
- return value instanceof HTMLElement || value instanceof SVGElement;
38
- }
package/src/index.ts CHANGED
@@ -1,3 +1,12 @@
1
- import '@oscarpalmer/sentinel';
1
+ import '@oscarpalmer/mora';
2
+ import {Fragment} from './fragment';
3
+
4
+ export function html(
5
+ strings: TemplateStringsArray,
6
+ ...values: unknown[]
7
+ ): Fragment {
8
+ return new Fragment(strings, values);
9
+ }
10
+
11
+ export * from '@oscarpalmer/mora';
2
12
  export type {Fragment} from './fragment';
3
- export {html} from './html';
package/src/models.ts CHANGED
@@ -1,24 +1,22 @@
1
1
  import type {Key} from '@oscarpalmer/atoms/models';
2
- import type {Effect, Reactive} from '@oscarpalmer/sentinel';
2
+ import type {Reactive} from '@oscarpalmer/mora';
3
3
  import type {Fragment} from './fragment';
4
4
 
5
5
  export type FragmentData = {
6
6
  expressions: unknown[];
7
7
  identifier?: Key;
8
8
  items: FragmentItem[];
9
- sentinel: FragmentDataSentinel;
9
+ mora: MoraData;
10
10
  strings: TemplateStringsArray;
11
11
  values: unknown[];
12
12
  };
13
13
 
14
- type FragmentDataSentinel = {
15
- effects: Set<Effect>;
16
- values: Set<Reactive>;
17
- };
18
-
19
14
  export type FragmentItem = {
20
15
  fragments?: Fragment[];
21
16
  nodes: ChildNode[];
22
17
  };
23
18
 
24
- export type HTMLOrSVGElement = HTMLElement | SVGElement;
19
+ type MoraData = {
20
+ subscribers: Set<() => void>;
21
+ values: Set<Reactive<unknown>>;
22
+ };
@@ -1,6 +1,7 @@
1
1
  import type {GenericCallback} from '@oscarpalmer/atoms/models';
2
- import {computed, isReactive} from '@oscarpalmer/sentinel';
3
- import type {FragmentData, HTMLOrSVGElement} from '../../models';
2
+ import {computed, isReactive} from '@oscarpalmer/mora';
3
+ import type {HTMLOrSVGElement} from '@oscarpalmer/toretto/models';
4
+ import type {FragmentData} from '../../models';
4
5
  import {mapEvent} from '../event';
5
6
  import {setAttribute} from './value';
6
7
 
@@ -61,7 +62,7 @@ function setComputedAttribute(
61
62
  ): void {
62
63
  const value = computed(callback);
63
64
 
64
- data.sentinel.values.add(value);
65
+ data.mora.values.add(value);
65
66
 
66
67
  setAttribute(data, element, name, value);
67
68
  }
@@ -1,11 +1,12 @@
1
1
  import type {PlainObject} from '@oscarpalmer/atoms/models';
2
2
  import {getString} from '@oscarpalmer/atoms/string';
3
- import {effect, isReactive} from '@oscarpalmer/sentinel';
3
+ import {isReactive} from '@oscarpalmer/mora';
4
4
  import {
5
5
  isBooleanAttribute,
6
6
  setAttribute as setAttr,
7
7
  } from '@oscarpalmer/toretto/attribute';
8
- import type {FragmentData, HTMLOrSVGElement} from '../../models';
8
+ import type {HTMLOrSVGElement} from '@oscarpalmer/toretto/models';
9
+ import type {FragmentData} from '../../models';
9
10
 
10
11
  const classExpression = /^class\./;
11
12
  const styleFullExpression = /^style\.([\w-]+)(?:\.([\w-]+))?$/;
@@ -51,11 +52,7 @@ function setClasses(
51
52
  const classes = name.slice(6).split('.');
52
53
 
53
54
  if (isReactive(value)) {
54
- data.sentinel.effects.add(
55
- effect(() => {
56
- update(value.get());
57
- }),
58
- );
55
+ data.mora.subscribers.add(value.subscribe(update));
59
56
  } else {
60
57
  update(value);
61
58
  }
@@ -82,11 +79,7 @@ function setStyle(
82
79
 
83
80
  if (property != null) {
84
81
  if (isReactive(value)) {
85
- data.sentinel.effects.add(
86
- effect(() => {
87
- update(value.get());
88
- }),
89
- );
82
+ data.mora.subscribers.add(value.subscribe(update));
90
83
  } else {
91
84
  update(value);
92
85
  }
@@ -107,9 +100,9 @@ function setValue(
107
100
  : setAttr;
108
101
 
109
102
  if (isReactive(value)) {
110
- data.sentinel.effects.add(
111
- effect(() => {
112
- callback(element, name, value.get());
103
+ data.mora.subscribers.add(
104
+ value.subscribe(next => {
105
+ callback(element, name, next);
113
106
  }),
114
107
  );
115
108
  } else {
package/src/node/event.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type {HTMLOrSVGElement} from '../models';
1
+ import type {HTMLOrSVGElement} from '@oscarpalmer/toretto/models';
2
2
 
3
3
  const controllers = new WeakMap<HTMLOrSVGElement, AbortController>();
4
4
 
package/src/node/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type {GenericCallback} from '@oscarpalmer/atoms/models';
2
- import {computed, isReactive} from '@oscarpalmer/sentinel';
3
- import {isFragment, isHTMLOrSVGElement} from '../helpers';
2
+ import {computed, isReactive} from '@oscarpalmer/mora';
3
+ import {isHTMLOrSVGElement} from '@oscarpalmer/toretto/is';
4
+ import {isFragment} from '../helpers';
4
5
  import {createNodes} from '../helpers/dom';
5
6
  import type {FragmentData} from '../models';
6
7
  import {mapAttributes} from './attribute';
@@ -78,7 +79,7 @@ function setComputedValue(
78
79
  ): void {
79
80
  const value = computed(callback);
80
81
 
81
- data.sentinel.values.add(value);
82
+ data.mora.values.add(value);
82
83
 
83
84
  setReactiveValue(data, comment, value);
84
85
  }
package/src/node/value.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
2
2
  import type {Key} from '@oscarpalmer/atoms/models';
3
3
  import {getString} from '@oscarpalmer/atoms/string';
4
- import {type Reactive, effect} from '@oscarpalmer/sentinel';
4
+ import type {Reactive} from '@oscarpalmer/mora';
5
+ import {isChildNode} from '@oscarpalmer/toretto/is';
5
6
  import type {Fragment} from '../fragment';
6
- import {compareArrays, isChildNode, isFragment} from '../helpers';
7
+ import {compareArrays, isFragment} from '../helpers';
7
8
  import {createNodes, replaceNodes} from '../helpers/dom';
8
9
  import type {FragmentData, FragmentItem} from '../models';
9
10
 
@@ -147,7 +148,7 @@ function setNodes(
147
148
  export function setReactiveValue(
148
149
  data: FragmentData,
149
150
  comment: Comment,
150
- reactive: Reactive,
151
+ reactive: Reactive<unknown>,
151
152
  ): void {
152
153
  const item = data.items.find(item => item.nodes.includes(comment));
153
154
  const text = new Text();
@@ -155,10 +156,8 @@ export function setReactiveValue(
155
156
  let fragments: Fragment[] | undefined;
156
157
  let nodes: ChildNode[] | undefined;
157
158
 
158
- data.sentinel.effects.add(
159
- effect(() => {
160
- const value = reactive.get();
161
-
159
+ data.mora.subscribers.add(
160
+ reactive.subscribe(value => {
162
161
  if (Array.isArray(value)) {
163
162
  const result = setArray(fragments, nodes, comment, text, value);
164
163