@oscarpalmer/abydon 0.7.0 → 0.9.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,26 +1,17 @@
1
1
  import type {PlainObject} from '@oscarpalmer/atoms/models';
2
2
  import {getString} from '@oscarpalmer/atoms/string';
3
3
  import {effect, isReactive} from '@oscarpalmer/sentinel';
4
- import type {FragmentElement} from '../../models';
5
- import {closest} from '@oscarpalmer/atoms/element';
6
-
7
- const booleanAttributes = new Set([
8
- 'checked',
9
- 'disabled',
10
- 'hidden',
11
- 'inert',
12
- 'multiple',
13
- 'open',
14
- 'readOnly',
15
- 'required',
16
- 'selected',
17
- ]);
4
+ import {
5
+ isBooleanAttribute,
6
+ setAttribute as setAttr,
7
+ } from '@oscarpalmer/toretto/attribute';
8
+ import type {ProperElement} from '../../models';
18
9
 
19
10
  const classPattern = /^class\./;
20
11
  const stylePattern = /^style\./;
21
12
 
22
13
  export function setAttribute(
23
- element: FragmentElement,
14
+ element: ProperElement,
24
15
  name: string,
25
16
  value: unknown,
26
17
  ): void {
@@ -42,7 +33,7 @@ export function setAttribute(
42
33
  }
43
34
 
44
35
  function setClasses(
45
- element: FragmentElement,
36
+ element: ProperElement,
46
37
  name: string,
47
38
  value: unknown,
48
39
  ): void {
@@ -65,11 +56,7 @@ function setClasses(
65
56
  }
66
57
  }
67
58
 
68
- function setStyle(
69
- element: FragmentElement,
70
- name: string,
71
- value: unknown,
72
- ): void {
59
+ function setStyle(element: ProperElement, name: string, value: unknown): void {
73
60
  function update(value: unknown): void {
74
61
  if (value == null || value === false || (value === true && unit == null)) {
75
62
  element.style.removeProperty(property);
@@ -96,17 +83,13 @@ function setStyle(
96
83
  }
97
84
  }
98
85
 
99
- function setValue(
100
- element: FragmentElement,
101
- name: string,
102
- value: unknown,
103
- ): void {
86
+ function setValue(element: ProperElement, name: string, value: unknown): void {
104
87
  const callback =
105
- booleanAttributes.has(name) && name in element
88
+ isBooleanAttribute(name) && name in element
106
89
  ? name === 'selected'
107
- ? updateSelected(element)
90
+ ? updateSelected
108
91
  : updateProperty
109
- : updateAttribute;
92
+ : setAttr;
110
93
 
111
94
  if (isReactive(value)) {
112
95
  effect(() => {
@@ -123,20 +106,8 @@ function triggerSelectChange(select: HTMLSelectElement): void {
123
106
  }
124
107
  }
125
108
 
126
- function updateAttribute(
127
- element: FragmentElement,
128
- name: string,
129
- value: unknown,
130
- ): void {
131
- if (value == null) {
132
- element.removeAttribute(name);
133
- } else {
134
- element.setAttribute(name, getString(value));
135
- }
136
- }
137
-
138
109
  function updateProperty(
139
- element: FragmentElement,
110
+ element: ProperElement,
140
111
  name: string,
141
112
  value: unknown,
142
113
  ): void {
@@ -145,15 +116,17 @@ function updateProperty(
145
116
  );
146
117
  }
147
118
 
148
- function updateSelected(element: FragmentElement) {
149
- const select = closest(element, 'select')[0] as HTMLSelectElement;
119
+ function updateSelected(
120
+ element: ProperElement,
121
+ name: string,
122
+ value: unknown,
123
+ ): void {
124
+ const select = element.closest('select') as HTMLSelectElement;
150
125
  const options = [...(select?.options ?? [])];
151
126
 
152
- return (element: FragmentElement, name: string, value: unknown): void => {
153
- if (select != null && options.includes(element as HTMLOptionElement)) {
154
- triggerSelectChange(select);
155
- }
127
+ if (select != null && options.includes(element as HTMLOptionElement)) {
128
+ triggerSelectChange(select);
129
+ }
156
130
 
157
- updateProperty(element, name, value);
158
- };
131
+ updateProperty(element, name, value);
159
132
  }
package/src/node/event.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type {FragmentElement} from '../models';
1
+ import type {ProperElement} from '../models';
2
2
 
3
3
  function getOptions(options: string): AddEventListenerOptions {
4
4
  const parts = options.split(':');
@@ -11,7 +11,7 @@ function getOptions(options: string): AddEventListenerOptions {
11
11
  }
12
12
 
13
13
  export function mapEvent(
14
- element: FragmentElement,
14
+ element: ProperElement,
15
15
  name: string,
16
16
  value: unknown,
17
17
  ): void {
@@ -26,4 +26,4 @@ export function mapEvent(
26
26
  getOptions(options ?? ''),
27
27
  );
28
28
  }
29
- }
29
+ }
package/src/node/index.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import {isReactive} from '@oscarpalmer/sentinel';
2
- import {isFragmentElement} from '../helpers';
2
+ import {isFragment, isProperElement} from '../helpers';
3
3
  import {createNodes} from '../helpers/dom';
4
- import type {FragmentData} from '../models';
5
- import {setReactiveNode} from './value';
4
+ import type {FragmentData, ProperNode} from '../models';
6
5
  import {mapAttributes} from './attribute';
6
+ import {setReactiveNode} from './value';
7
7
 
8
8
  const commentExpression = /^abydon\.(\d+)$/;
9
9
 
@@ -12,11 +12,11 @@ function mapNode(data: FragmentData, comment: Comment): void {
12
12
  const value = matches == null ? null : data.values[+matches[1]];
13
13
 
14
14
  if (value != null) {
15
- mapValue(comment, value);
15
+ mapValue(data, comment, value);
16
16
  }
17
17
  }
18
18
 
19
- export function mapNodes(data: FragmentData, nodes: Node[]): void {
19
+ export function mapNodes(data: FragmentData, nodes: ProperNode[]): void {
20
20
  const {length} = nodes;
21
21
 
22
22
  for (let index = 0; index < length; index += 1) {
@@ -28,28 +28,44 @@ export function mapNodes(data: FragmentData, nodes: Node[]): void {
28
28
  continue;
29
29
  }
30
30
 
31
- if (isFragmentElement(node)) {
31
+ if (isProperElement(node)) {
32
32
  mapAttributes(data, node);
33
33
  }
34
34
 
35
35
  if (node.hasChildNodes()) {
36
- mapNodes(data, [...node.childNodes]);
36
+ mapNodes(data, [...node.childNodes] as ProperNode[]);
37
37
  }
38
38
  }
39
39
  }
40
40
 
41
- function mapValue(comment: Comment, value: unknown): void {
41
+ function mapValue(data: FragmentData, comment: Comment, value: unknown): void {
42
42
  switch (true) {
43
43
  case typeof value === 'function':
44
- mapValue(comment, value());
44
+ mapValue(data, comment, value());
45
45
  return;
46
46
 
47
47
  case isReactive(value):
48
- setReactiveNode(comment, value);
48
+ setReactiveNode(data, comment, value);
49
49
  break;
50
50
 
51
51
  default:
52
- comment.replaceWith(...createNodes(value));
52
+ replaceComment(data, comment, value);
53
53
  break;
54
54
  }
55
55
  }
56
+
57
+ function replaceComment(
58
+ data: FragmentData,
59
+ comment: Comment,
60
+ value: unknown,
61
+ ): void {
62
+ const item = data.items.find(item => item.nodes.includes(comment));
63
+ const nodes = createNodes(value);
64
+
65
+ if (item != null) {
66
+ item.fragment = isFragment(value) ? value : undefined;
67
+ item.nodes = nodes;
68
+ }
69
+
70
+ comment.replaceWith(...nodes);
71
+ }
package/src/node/value.ts CHANGED
@@ -1,48 +1,87 @@
1
1
  import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
2
2
  import {getString} from '@oscarpalmer/atoms/string';
3
3
  import {type Reactive, effect} from '@oscarpalmer/sentinel';
4
- import {isFragment, isFragmentNode} from '../helpers';
4
+ import type {Fragment} from '../fragment';
5
+ import {isFragment, isProperNode} from '../helpers';
5
6
  import {createNodes, replaceNodes} from '../helpers/dom';
6
- import type {FragmentNode} from '../models';
7
+ import type {FragmentData, ProperNode} from '../models';
7
8
 
8
- export function setReactiveNode(comment: Comment, reactive: Reactive): void {
9
+ function setNodes(
10
+ nodes: ProperNode[] | undefined,
11
+ comment: Comment,
12
+ text: Text,
13
+ value: Fragment | ProperNode,
14
+ ): ProperNode[] {
15
+ const next = createNodes(value);
16
+
17
+ if (nodes == null) {
18
+ if (comment.parentNode != null) {
19
+ replaceNodes([comment], next);
20
+ } else if (text.parentNode != null) {
21
+ replaceNodes([text], next);
22
+ }
23
+ } else {
24
+ replaceNodes(nodes, next);
25
+ }
26
+
27
+ return next;
28
+ }
29
+
30
+ export function setReactiveNode(
31
+ data: FragmentData,
32
+ comment: Comment,
33
+ reactive: Reactive,
34
+ ): void {
35
+ const item = data.items.find(item => item.nodes.includes(comment));
9
36
  const text = new Text();
10
37
 
11
- let nodes: FragmentNode[] | undefined;
38
+ let nodes: ProperNode[] | undefined;
12
39
 
13
40
  effect(() => {
14
41
  const value = reactive.get();
15
42
 
16
- if (isFragment(value) || isFragmentNode(value)) {
17
- const next = createNodes(value);
43
+ const valueIsFragment = isFragment(value);
18
44
 
19
- if (nodes == null) {
20
- if (comment.parentNode != null) {
21
- replaceNodes([comment], next);
22
- } else if (text.parentNode != null) {
23
- replaceNodes([text], next);
24
- }
25
- } else {
26
- replaceNodes(nodes, next);
27
- }
28
-
29
- nodes = next;
45
+ if (valueIsFragment || isProperNode(value)) {
46
+ nodes = setNodes(nodes, comment, text, value);
47
+ } else {
48
+ nodes = setText(nodes, comment, text, value) ? [text] : undefined;
49
+ }
30
50
 
31
- return;
51
+ if (item != null) {
52
+ item.fragment = valueIsFragment ? value : undefined;
53
+ item.nodes = [...(nodes ?? [comment])];
32
54
  }
55
+ });
56
+ }
33
57
 
34
- const isNullable = isNullableOrWhitespace(value);
58
+ function setText(
59
+ nodes: ProperNode[] | undefined,
60
+ comment: Comment,
61
+ text: Text,
62
+ value: unknown,
63
+ ): boolean {
64
+ const isNullable = isNullableOrWhitespace(value);
35
65
 
36
- text.textContent = getString(value);
66
+ text.textContent = isNullable ? '' : getString(value);
37
67
 
38
- if (nodes != null) {
39
- replaceNodes(nodes, [isNullable ? comment : text]);
40
- } else if (isNullable && comment.parentNode == null) {
41
- text.replaceWith(comment);
42
- } else if (!isNullable && text.parentNode == null) {
43
- comment.replaceWith(text);
44
- }
68
+ if (nodes != null) {
69
+ replaceNodes(nodes, [isNullable ? comment : text]);
45
70
 
46
- nodes = undefined;
47
- });
48
- }
71
+ return !isNullable;
72
+ }
73
+
74
+ if (isNullable && comment.parentNode == null) {
75
+ text.replaceWith(comment);
76
+
77
+ return false;
78
+ }
79
+
80
+ if (!isNullable && text.parentNode == null) {
81
+ comment.replaceWith(text);
82
+
83
+ return true;
84
+ }
85
+
86
+ return false;
87
+ }
@@ -1,2 +1,17 @@
1
- import type { Fragment } from './models';
2
- export declare function createFragment(strings: TemplateStringsArray, expressions: unknown[]): Fragment;
1
+ export declare class Fragment {
2
+ private readonly $fragment;
3
+ private readonly data;
4
+ constructor(strings: TemplateStringsArray, expressions: unknown[]);
5
+ /**
6
+ * Appends the fragment to the given element
7
+ */
8
+ appendTo(element: Element): void;
9
+ /**
10
+ * Gets a list of the fragment's nodes
11
+ */
12
+ get(): Node[];
13
+ /**
14
+ * Removes the fragment from the DOM
15
+ */
16
+ remove(): void;
17
+ }
@@ -1,5 +1,3 @@
1
- import type { FragmentNode } from '../models';
2
- export declare function createNodes(value: unknown): FragmentNode[];
3
- export declare function createTemplate(html: string): Node;
4
- export declare function getNodes(node: Node): Node[];
5
- export declare function replaceNodes(from: FragmentNode[], to: FragmentNode[]): void;
1
+ import type { ProperNode } from '../models';
2
+ export declare function createNodes(value: unknown): ProperNode[];
3
+ export declare function replaceNodes(from: ProperNode[], to: ProperNode[]): void;
@@ -1,4 +1,5 @@
1
- import type { Fragment, FragmentElement, FragmentNode } from '../models';
1
+ import type { Fragment } from '../fragment';
2
+ import type { ProperElement, ProperNode } from '../models';
2
3
  export declare function isFragment(value: unknown): value is Fragment;
3
- export declare function isFragmentElement(value: unknown): value is FragmentElement;
4
- export declare function isFragmentNode(value: unknown): value is FragmentNode;
4
+ export declare function isProperElement(value: unknown): value is ProperElement;
5
+ export declare function isProperNode(value: unknown): value is ProperNode;
package/types/html.d.ts CHANGED
@@ -1,3 +1,4 @@
1
- import type { Fragment, FragmentData } from './models';
1
+ import { Fragment } from './fragment';
2
+ import type { FragmentData } from './models';
2
3
  export declare function html(strings: TemplateStringsArray, ...values: unknown[]): Fragment;
3
4
  export declare function parse(data: FragmentData): string;
@@ -0,0 +1,22 @@
1
+ // Generated by dts-bundle-generator v9.5.1
2
+
3
+ export declare class Fragment {
4
+ private readonly $fragment;
5
+ private readonly data;
6
+ constructor(strings: TemplateStringsArray, expressions: unknown[]);
7
+ /**
8
+ * Appends the fragment to the given element
9
+ */
10
+ appendTo(element: Element): void;
11
+ /**
12
+ * Gets a list of the fragment's nodes
13
+ */
14
+ get(): Node[];
15
+ /**
16
+ * Removes the fragment from the DOM
17
+ */
18
+ remove(): void;
19
+ }
20
+ export declare function html(strings: TemplateStringsArray, ...values: unknown[]): Fragment;
21
+
22
+ export {};
package/types/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export type { Fragment } from './models';
1
+ export type { Fragment } from './fragment';
2
2
  export { html } from './html';
package/types/models.d.ts CHANGED
@@ -1,13 +1,13 @@
1
- export type Fragment = {
2
- appendTo(element: Element): void;
3
- get(): FragmentNode[];
4
- remove(): void;
5
- };
1
+ import type { Fragment } from './fragment';
6
2
  export type FragmentData = {
7
3
  expressions: unknown[];
8
- nodes: Node[];
4
+ items: FragmentItem[];
9
5
  strings: TemplateStringsArray;
10
6
  values: unknown[];
11
7
  };
12
- export type FragmentElement = HTMLElement | SVGElement;
13
- export type FragmentNode = Comment | Element | Text;
8
+ export type FragmentItem = {
9
+ fragment?: Fragment;
10
+ nodes: ProperNode[];
11
+ };
12
+ export type ProperElement = HTMLElement | SVGElement;
13
+ export type ProperNode = CharacterData | Element;
@@ -1,3 +1,2 @@
1
- import type { FragmentData, FragmentElement } from '../../models';
2
- export declare function isBadAttribute(name: string, value: string): boolean;
3
- export declare function mapAttributes(data: FragmentData, element: FragmentElement): void;
1
+ import type { FragmentData, ProperElement } from '../../models';
2
+ export declare function mapAttributes(data: FragmentData, element: ProperElement): void;
@@ -1,2 +1,2 @@
1
- import type { FragmentElement } from '../../models';
2
- export declare function setAttribute(element: FragmentElement, name: string, value: unknown): void;
1
+ import type { ProperElement } from '../../models';
2
+ export declare function setAttribute(element: ProperElement, name: string, value: unknown): void;
@@ -1,2 +1,2 @@
1
- import type { FragmentElement } from '../models';
2
- export declare function mapEvent(element: FragmentElement, name: string, value: unknown): void;
1
+ import type { ProperElement } from '../models';
2
+ export declare function mapEvent(element: ProperElement, name: string, value: unknown): void;
@@ -1,2 +1,2 @@
1
- import type { FragmentData } from '../models';
2
- export declare function mapNodes(data: FragmentData, nodes: Node[]): void;
1
+ import type { FragmentData, ProperNode } from '../models';
2
+ export declare function mapNodes(data: FragmentData, nodes: ProperNode[]): void;
@@ -1,2 +1,3 @@
1
1
  import { type Reactive } from '@oscarpalmer/sentinel';
2
- export declare function setReactiveNode(comment: Comment, reactive: Reactive): void;
2
+ import type { FragmentData } from '../models';
3
+ export declare function setReactiveNode(data: FragmentData, comment: Comment, reactive: Reactive): void;
package/.bun.ts DELETED
@@ -1,32 +0,0 @@
1
- import * as fs from 'node:fs/promises';
2
-
3
- const directory = String(__dirname).replace(/\\/g, '/');
4
- const isMjs = process.argv.includes('--mjs');
5
-
6
- async function getFiles(path: string): Promise<string[]> {
7
- const entries = await fs.readdir(path, {withFileTypes: true});
8
-
9
- const files = entries
10
- .filter(entry => entry.isFile() && entry.name.endsWith('.ts'))
11
- .map(file => `${path}/${file.name}`);
12
-
13
- const folders = entries.filter(entry => entry.isDirectory());
14
-
15
- for (const folder of folders) {
16
- files.push(...(await getFiles(`${path}/${folder.name}`)));
17
- }
18
-
19
- return files;
20
- }
21
-
22
- getFiles('./src').then(async files => {
23
- for (const file of files) {
24
- await Bun.build({
25
- entrypoints: [`${directory}/${file}`],
26
- external: isMjs ? ['*'] : [],
27
- naming: isMjs ? '[dir]/[name].mjs' : undefined,
28
- outdir: './dist',
29
- root: './src',
30
- });
31
- }
32
- });
package/.gitattributes DELETED
@@ -1 +0,0 @@
1
- * text=auto eol=lf
package/biome.json DELETED
@@ -1,22 +0,0 @@
1
- {
2
- "$schema": "https://biomejs.dev/schemas/1.4.1/schema.json",
3
- "files": {
4
- "ignore": ["./dist/*"]
5
- },
6
- "javascript": {
7
- "formatter": {
8
- "arrowParentheses": "asNeeded",
9
- "bracketSpacing": false,
10
- "quoteStyle": "single"
11
- }
12
- },
13
- "linter": {
14
- "enabled": true,
15
- "rules": {
16
- "recommended": true
17
- }
18
- },
19
- "organizeImports": {
20
- "enabled": true
21
- }
22
- }
package/bun.lockb DELETED
Binary file
package/tsconfig.json DELETED
@@ -1,23 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "allowImportingTsExtensions": true,
4
- "allowJs": true,
5
- "allowSyntheticDefaultImports": true,
6
- "composite": false,
7
- "declaration": true,
8
- "declarationDir": "./types",
9
- "downlevelIteration": true,
10
- "emitDeclarationOnly": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "jsx": "react-jsx",
13
- "lib": ["DOM", "DOM.Iterable", "ESNext"],
14
- "module": "esnext",
15
- "moduleDetection": "force",
16
- "moduleResolution": "bundler",
17
- "rootDir": "./src",
18
- "skipLibCheck": true,
19
- "strict": true,
20
- "target": "esnext"
21
- },
22
- "exclude": ["dist", "node_modules", "test", "types", "www"]
23
- }