diff --git a/jsx-runtime/index.d.ts b/jsx-runtime/index.d.ts index 055d91b..b69253a 100644 --- a/jsx-runtime/index.d.ts +++ b/jsx-runtime/index.d.ts @@ -1 +1 @@ -export type * from "../dist/jsx-runtime.d.ts" +export type * from '../dist/jsx-runtime.d.ts' diff --git a/package.json b/package.json index cd46414..61d6f9c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "zeed-dom", "type": "module", - "version": "0.10.7", + "version": "0.10.8", "description": "🌱 Lightweight offline DOM", "author": { "name": "Dirk Holtwick", @@ -68,16 +68,15 @@ "css-what": "^6.1.0" }, "devDependencies": { - "@antfu/eslint-config": "^0.40.2", - "@antfu/ni": "^0.21.5", - "@types/node": "^20.4.9", - "@vitest/coverage-c8": "^0.33.0", - "@vitest/coverage-v8": "^0.34.1", + "@antfu/eslint-config": "^0.43.1", + "@antfu/ni": "^0.21.8", + "@types/node": "^20.7.1", + "@vitest/coverage-v8": "^0.34.5", "c8": "^8.0.1", - "eslint": "^8.47.0", + "eslint": "^8.50.0", "tsup": "^7.2.0", - "typescript": "^5.1.6", + "typescript": "^5.2.2", "vite": "^4.4.9", - "vitest": "^0.34.1" + "vitest": "^0.34.5" } } diff --git a/src/env.d.ts b/src/env.d.ts index 720aaab..db7de5e 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -3,4 +3,4 @@ declare namespace JSX { interface IntrinsicElements { [elemName: string]: any } -} \ No newline at end of file +} diff --git a/src/index.ts b/src/index.ts index 77e61d9..3465551 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,3 +9,4 @@ export { escapeHTML, unescapeHTML } from './encoding' export { tidyDOM } from './tidy' export { CDATA, html } from './html' export { xml } from './xml' +export { handleHTML } from './manipulate' diff --git a/src/manipulate.spec.ts b/src/manipulate.spec.ts new file mode 100644 index 0000000..1961a06 --- /dev/null +++ b/src/manipulate.spec.ts @@ -0,0 +1,34 @@ +// Copyright (c) 2020 Dirk Holtwick. All rights reserved. https://holtwick.de/copyright + +import { handleHTML } from "./manipulate" + +describe("manipulate", () => { + + it("should manipulate html", () => { + const html = ` + + +

+ + + ` + + let rhtml = handleHTML(html, document => { + let img = document.querySelector('.img-wrapper img') + console.log('img', img) + if (img) { + img.setAttribute('title', 'hello') + } + }) + + expect(rhtml).toMatchInlineSnapshot( ` + " + + +

\\"\\"

+ + + " + `) + }) +}) diff --git a/src/manipulate.ts b/src/manipulate.ts new file mode 100644 index 0000000..ac55ad2 --- /dev/null +++ b/src/manipulate.ts @@ -0,0 +1,8 @@ +import type { VDocumentFragment, VHTMLDocument } from './vdom' +import { parseHTML } from './vdomparser' + +export function handleHTML(html: string, handler: (document: VHTMLDocument | VDocumentFragment) => void) { + const document = parseHTML(html) + handler(document) + return document.render() +} diff --git a/src/vcss.ts b/src/vcss.ts index d450c88..a10eac3 100644 --- a/src/vcss.ts +++ b/src/vcss.ts @@ -33,6 +33,7 @@ export function matchSelector( } const handleRules = (element: VElement, rules: any[]) => { + // let pos = 0 let success = false for (const part of rules) { const { type, name, action, value, _ignoreCase = true, data } = part @@ -102,12 +103,18 @@ export function matchSelector( // } else if (type === 'descendant') { // element = element. } + // else if (type === 'descendant') { + // for (const child of element.childNodes) + // handleRules(child, rules.slice(pos)) + // } else { console.warn('Unknown CSS selector type', type, selector, rules) } // log(success, selector, part, element) if (!success) break + + // pos += 1 } return success } diff --git a/src/vdom.spec.tsx b/src/vdom.spec.tsx index 2573dfd..0356f42 100644 --- a/src/vdom.spec.tsx +++ b/src/vdom.spec.tsx @@ -206,13 +206,13 @@ describe("VDOM", () => { it("should handle dataSet stuff", () => { let el =
Test
- expect(el.attributes).toEqual({ "data-lang": "en" }) + expect(el.attributesObject).toEqual({ "data-lang": "en" }) expect(el.render()).toEqual('
Test
') expect(el.querySelector("[data-lang]").textContent).toEqual("Test") let frag = parseHTML(el.render()) - expect(frag.firstChild.attributes).toEqual({ "data-lang": "en" }) + expect(frag.firstChild.attributesObject).toEqual({ "data-lang": "en" }) expect(frag.render()).toEqual('
Test
') }) diff --git a/src/vdom.ts b/src/vdom.ts index 1e1c65c..5725d6c 100644 --- a/src/vdom.ts +++ b/src/vdom.ts @@ -146,11 +146,13 @@ export class VNode { } } + /** Remove node */ remove() { this?.parentNode?.removeChild(this) return this } + /** Replace content of node with text or nodes */ replaceChildren(...nodes: any[]) { this._childNodes = nodes.map(n => typeof n === 'string' ? new VTextNode(n) : n.remove(), @@ -158,6 +160,7 @@ export class VNode { this._fixChildNodesParent() } + /** Replace node itself with nodes */ replaceWith(...nodes: any[]) { const p = this._parentNode if (p) { @@ -176,7 +179,6 @@ export class VNode { _indexInParent() { if (this._parentNode) return this._parentNode.childNodes.indexOf(this) - return -1 } @@ -204,7 +206,6 @@ export class VNode { const i = this._indexInParent() if (i != null) return this.parentNode.childNodes[i + 1] || null - return null } @@ -212,7 +213,6 @@ export class VNode { const i = this._indexInParent() if (i > 0) return this.parentNode.childNodes[i - 1] || null - return null } @@ -220,10 +220,8 @@ export class VNode { const elements: VElement[] = [] if (this instanceof VElement) elements.push(this) - for (const child of this._childNodes) elements.push(...child.flatten()) - return elements } @@ -232,7 +230,6 @@ export class VNode { nodes.push(this) for (const child of this._childNodes) nodes.push(...child.flattenNodes()) - return nodes } @@ -356,6 +353,11 @@ export class VNodeQuery extends VNode { } } +interface Attr { + name: string + value: string +} + export class VElement extends VNodeQuery { _originalTagName: string _nodeName: any @@ -386,8 +388,13 @@ export class VElement extends VNodeQuery { return node } - get attributes() { - return this._attributes + get attributes(): Attr[] { + return Object.entries(this._attributes).map(([name, value]): Attr => ({ name, value })) + // return this._attributes + } + + get attributesObject() { + return { ...this._attributes } } _findAttributeName(name: string) { @@ -451,6 +458,11 @@ export class VElement extends VNodeQuery { return this._nodeName } + /** Private function to easily change the tagName */ + setTagName(name: string) { + this._nodeName = name.toUpperCase() + } + get id(): string | null { return this._attributes.id || null } @@ -549,7 +561,7 @@ export class VElement extends VNodeQuery { render(h = htmlVDOM) { return h( this._originalTagName || this.tagName, - this.attributes, + this._attributes, this._childNodes.map(c => c.render(h)).join(''), // children:string is not escaped again ) } diff --git a/tsconfig.json b/tsconfig.json index f935731..5048ff9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,30 +1,30 @@ { "compilerOptions": { - "baseUrl": ".", "target": "ES2019", - "declaration": true, - "esModuleInterop": true, - "isolatedModules": true, "lib": [ "esnext", "dom", "dom.iterable", "scripthost" ], + "jsx": "react", + "jsxFactory": "h", + "jsxFragmentFactory": "Fragment", "module": "ESNext", "moduleResolution": "Node", - "resolveJsonModule": true, - "sourceMap": true, - "strict": true, - "strictNullChecks": true, + "baseUrl": ".", "types": [ "node", "vitest/globals" ], + "resolveJsonModule": true, "allowJs": true, - "jsx": "react", - "jsxFactory": "h", - "jsxFragmentFactory": "Fragment" + "declaration": true, + "sourceMap": true, + "isolatedModules": true, + "esModuleInterop": true, + "strict": true, + "strictNullChecks": true }, "include": [ "src/**/*",