typed-dom
Advanced tools
Comparing version 0.0.260 to 0.0.261
@@ -1,2 +0,2 @@ | ||
/*! typed-dom v0.0.260 https://github.com/falsandtru/typed-dom | (c) 2016, falsandtru | (Apache-2.0 AND MPL-2.0) License */ | ||
/*! typed-dom v0.0.261 https://github.com/falsandtru/typed-dom | (c) 2016, falsandtru | (Apache-2.0 AND MPL-2.0) License */ | ||
require = function () { | ||
@@ -44,9 +44,2 @@ function r(e, n, t) { | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
}, | ||
{} | ||
], | ||
4: [ | ||
function (_dereq_, module, exports) { | ||
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
exports.isArray = exports.ObjectValues = exports.ObjectSetPrototypeOf = exports.ObjectSeal = exports.ObjectPreventExtensions = exports.ObjectKeys = exports.isSealed = exports.isFrozen = exports.isExtensible = exports.ObjectIs = exports.ObjectGetPrototypeOf = exports.ObjectGetOwnPropertySymbols = exports.ObjectGetOwnPropertyNames = exports.ObjectGetOwnPropertyDescriptors = exports.ObjectGetOwnPropertyDescriptor = exports.ObjectFromEntries = exports.ObjectFreeze = exports.ObjectEntries = exports.ObjectDefineProperty = exports.ObjectDefineProperties = exports.ObjectCreate = exports.ObjectAssign = exports.toString = exports.isEnumerable = exports.isPrototypeOf = exports.hasOwnProperty = exports.SymbolKeyFor = exports.SymbolFor = exports.sign = exports.round = exports.random = exports.min = exports.max = exports.floor = exports.ceil = exports.abs = exports.parseInt = exports.parseFloat = exports.isSafeInteger = exports.isNaN = exports.isInteger = exports.isFinite = exports.NaN = void 0; | ||
@@ -86,3 +79,3 @@ exports.NaN = Number.NaN, exports.isFinite = Number.isFinite, exports.isInteger = Number.isInteger, exports.isNaN = Number.isNaN, exports.isSafeInteger = Number.isSafeInteger, exports.parseFloat = Number.parseFloat, exports.parseInt = Number.parseInt; | ||
], | ||
5: [ | ||
4: [ | ||
function (_dereq_, module, exports) { | ||
@@ -99,3 +92,3 @@ 'use strict'; | ||
], | ||
6: [ | ||
5: [ | ||
function (_dereq_, module, exports) { | ||
@@ -122,5 +115,5 @@ 'use strict'; | ||
}, | ||
{ './noop': 9 } | ||
{ './noop': 8 } | ||
], | ||
7: [ | ||
6: [ | ||
function (_dereq_, module, exports) { | ||
@@ -134,3 +127,3 @@ 'use strict'; | ||
], | ||
8: [ | ||
7: [ | ||
function (_dereq_, module, exports) { | ||
@@ -192,8 +185,8 @@ 'use strict'; | ||
{ | ||
'./alias': 4, | ||
'./compare': 5, | ||
'./global': 7 | ||
'./alias': 3, | ||
'./compare': 4, | ||
'./global': 6 | ||
} | ||
], | ||
9: [ | ||
8: [ | ||
function (_dereq_, module, exports) { | ||
@@ -209,3 +202,3 @@ 'use strict'; | ||
], | ||
10: [ | ||
9: [ | ||
function (_dereq_, module, exports) { | ||
@@ -556,8 +549,8 @@ 'use strict'; | ||
{ | ||
'./alias': 4, | ||
'./global': 7, | ||
'./noop': 9 | ||
'./alias': 3, | ||
'./global': 6, | ||
'./noop': 8 | ||
} | ||
], | ||
11: [ | ||
10: [ | ||
function (_dereq_, module, exports) { | ||
@@ -652,5 +645,5 @@ 'use strict'; | ||
}, | ||
{ './global': 7 } | ||
{ './global': 6 } | ||
], | ||
12: [ | ||
11: [ | ||
function (_dereq_, module, exports) { | ||
@@ -664,3 +657,3 @@ 'use strict'; | ||
const dom_1 = _dereq_('./util/dom'); | ||
function API(baseFactory, formatter = el => el) { | ||
function API(baseFactory, formatter) { | ||
return new Proxy(() => void 0, handle(baseFactory, formatter)); | ||
@@ -677,5 +670,5 @@ } | ||
}, | ||
get: (target, prop) => target[prop] || prop in target || typeof prop !== 'string' ? target[prop] : target[prop] = builder(prop, baseFactory) | ||
get: (target, prop) => target[prop] || prop in target || typeof prop !== 'string' ? target[prop] : target[prop] = builder(prop) | ||
}; | ||
function builder(tag, baseFactory) { | ||
function builder(tag) { | ||
return function build(attrs, children, factory) { | ||
@@ -689,36 +682,35 @@ if (typeof children === 'function') | ||
attrs !== null && attrs !== void 0 ? attrs : attrs = {}; | ||
const el = elem(factory, attrs, children); | ||
const node = formatter(el); | ||
return node !== el && 'host' in node ? new proxy_1.Elem(el, attrs, children, node) : new proxy_1.Elem(el, attrs, children); | ||
const el = elem(tag, factory, attrs, children); | ||
return new proxy_1.Elem(tag, el, attrs, children, formatter === null || formatter === void 0 ? void 0 : formatter(el)); | ||
}; | ||
function isElChildren(param) { | ||
if (param === void 0) | ||
return false; | ||
if (param[global_1.Symbol.iterator]) | ||
return true; | ||
for (const name in param) { | ||
if (!(0, alias_1.hasOwnProperty)(param, name)) | ||
continue; | ||
const p = param[name]; | ||
return !!p && typeof p === 'object'; | ||
} | ||
return true; | ||
} | ||
function elem(factory, attrs, children) { | ||
const el = factory ? (0, dom_1.define)(factory(baseFactory, tag, attrs, children), attrs) : baseFactory(tag, attrs); | ||
if (tag.toLowerCase() !== el.tagName.toLowerCase()) | ||
throw new Error(`TypedDOM: Expected tag name is "${ tag.toLowerCase() }" but actually "${ el.tagName.toLowerCase() }".`); | ||
return el; | ||
} | ||
} | ||
function elem(tag, factory, attrs, children) { | ||
const el = factory ? (0, dom_1.define)(factory(baseFactory, tag, attrs, children), attrs) : baseFactory(tag, attrs); | ||
if (tag.toLowerCase() !== el.tagName.toLowerCase()) | ||
throw new Error(`TypedDOM: Expected tag name is "${ tag.toLowerCase() }" but actually "${ el.tagName.toLowerCase() }".`); | ||
return el; | ||
} | ||
} | ||
function isElChildren(param) { | ||
if (param === void 0) | ||
return false; | ||
if (param[global_1.Symbol.iterator]) | ||
return true; | ||
for (const name in param) { | ||
if (!(0, alias_1.hasOwnProperty)(param, name)) | ||
continue; | ||
const value = param[name]; | ||
return !!value && typeof value === 'object'; | ||
} | ||
return true; | ||
} | ||
}, | ||
{ | ||
'./proxy': 13, | ||
'./util/dom': 14, | ||
'spica/alias': 4, | ||
'spica/global': 7 | ||
'./proxy': 12, | ||
'./util/dom': 13, | ||
'spica/alias': 3, | ||
'spica/global': 6 | ||
} | ||
], | ||
13: [ | ||
12: [ | ||
function (_dereq_, module, exports) { | ||
@@ -751,3 +743,5 @@ 'use strict'; | ||
class Elem { | ||
constructor(element, attrs, children, container = element) { | ||
constructor(tag, element, attrs, children, container = element) { | ||
var _f, _g, _h; | ||
this.tag = tag; | ||
this.element = element; | ||
@@ -764,5 +758,5 @@ this[_a] = { | ||
const events = this[privates.events]; | ||
events.mutate = (attrs === null || attrs === void 0 ? void 0 : attrs['onmutate']) != null; | ||
events.connect = (attrs === null || attrs === void 0 ? void 0 : attrs['onconnect']) != null; | ||
events.disconnect = (attrs === null || attrs === void 0 ? void 0 : attrs['ondisconnect']) != null; | ||
events.mutate = ((_f = attrs === null || attrs === void 0 ? void 0 : attrs['onmutate']) !== null && _f !== void 0 ? _f : attrs === null || attrs === void 0 ? void 0 : attrs['onMutate']) != null; | ||
events.connect = ((_g = attrs === null || attrs === void 0 ? void 0 : attrs['onconnect']) !== null && _g !== void 0 ? _g : attrs === null || attrs === void 0 ? void 0 : attrs['onConnect']) != null; | ||
events.disconnect = ((_h = attrs === null || attrs === void 0 ? void 0 : attrs['ondisconnect']) !== null && _h !== void 0 ? _h : attrs === null || attrs === void 0 ? void 0 : attrs['onDisconnect']) != null; | ||
this[privates.children] = children; | ||
@@ -814,3 +808,3 @@ this[privates.container] = container; | ||
this[privates.id_] = this.element.id; | ||
if (/^[\w-]+$/.test(this[privates.id_])) | ||
if (/^[a-z][\w-]*$/i.test(this[privates.id_])) | ||
return this[privates.id_]; | ||
@@ -838,8 +832,8 @@ if (counter === 999) { | ||
[privates.scope](child) { | ||
if (child.element.tagName.toUpperCase() !== 'STYLE') | ||
if (child.tag.toUpperCase() !== 'STYLE') | ||
return; | ||
const source = child.element.innerHTML; | ||
if (!source.includes('$scope')) | ||
if (!source.includes(':scope')) | ||
return; | ||
const scope = /(^|[>~+,}/])(\s*)\$scope(?!\w)(?=\s*[A-Za-z#.:[>~+,{/])/g; | ||
const scope = /(^|[>~+,}/])(\s*)\:scope(?!\w)(?=\s*[A-Za-z#.:[>~+,{/])/g; | ||
const style = source.replace(scope, (...$) => `${ $[1] }${ $[2] }${ this[privates.query] }`); | ||
@@ -892,4 +886,5 @@ if (style === source) | ||
case 1: { | ||
if (!this[privates.events].mutate) { | ||
if (this[privates.isInit] || !this[privates.events].mutate) { | ||
container.textContent = children; | ||
isMutated = true; | ||
break; | ||
@@ -899,6 +894,6 @@ } | ||
const oldText = this.children; | ||
if (!this[privates.isInit] && newText === oldText) | ||
return; | ||
if (newText === oldText) | ||
break; | ||
container.textContent = newText; | ||
isMutated = true; | ||
container.textContent = newText; | ||
break; | ||
@@ -945,6 +940,6 @@ } | ||
throwErrorIfNotUsable(newChild, this[privates.container]); | ||
isMutated = true; | ||
this[privates.scope](newChild); | ||
container.appendChild(newChild.element); | ||
((_h = events(newChild)) === null || _h === void 0 ? void 0 : _h.connect) && addedChildren.push(newChild); | ||
container.appendChild(newChild.element); | ||
isMutated = true; | ||
} | ||
@@ -967,7 +962,6 @@ break; | ||
throwErrorIfNotUsable(newChild, this[privates.container]); | ||
isMutated = true; | ||
if (newChild !== oldChild && newChild.element.parentNode !== oldChild.element.parentNode) { | ||
this[privates.scope](newChild); | ||
container.replaceChild(newChild.element, oldChild.element); | ||
((_j = events(newChild)) === null || _j === void 0 ? void 0 : _j.connect) && addedChildren.push(newChild); | ||
container.replaceChild(newChild.element, oldChild.element); | ||
((_k = events(oldChild)) === null || _k === void 0 ? void 0 : _k.disconnect) && removedChildren.push(oldChild); | ||
@@ -979,2 +973,3 @@ } else { | ||
} | ||
isMutated = true; | ||
this[privates.isObserverUpdate] = true; | ||
@@ -1021,8 +1016,8 @@ targetChildren[name] = newChild; | ||
{ | ||
'./util/identity': 15, | ||
'spica/alias': 4, | ||
'spica/global': 7 | ||
'./util/identity': 14, | ||
'spica/alias': 3, | ||
'spica/global': 6 | ||
} | ||
], | ||
14: [ | ||
13: [ | ||
function (_dereq_, module, exports) { | ||
@@ -1159,8 +1154,8 @@ 'use strict'; | ||
{ | ||
'spica/alias': 4, | ||
'spica/global': 7, | ||
'spica/memoize': 8 | ||
'spica/alias': 3, | ||
'spica/global': 6, | ||
'spica/memoize': 7 | ||
} | ||
], | ||
15: [ | ||
14: [ | ||
function (_dereq_, module, exports) { | ||
@@ -1177,7 +1172,7 @@ 'use strict'; | ||
{ | ||
'spica/global': 7, | ||
'spica/random': 11 | ||
'spica/global': 6, | ||
'spica/random': 10 | ||
} | ||
], | ||
16: [ | ||
15: [ | ||
function (_dereq_, module, exports) { | ||
@@ -1233,8 +1228,8 @@ 'use strict'; | ||
{ | ||
'spica/function': 6, | ||
'spica/noop': 9, | ||
'spica/promise': 10 | ||
'spica/function': 5, | ||
'spica/noop': 8, | ||
'spica/promise': 9 | ||
} | ||
], | ||
17: [ | ||
16: [ | ||
function (_dereq_, module, exports) { | ||
@@ -1254,3 +1249,3 @@ 'use strict'; | ||
}, | ||
{ './dom': 14 } | ||
{ './dom': 13 } | ||
], | ||
@@ -1390,8 +1385,8 @@ 'typed-dom': [ | ||
{ | ||
'./src/builder': 12, | ||
'./src/util/dom': 14, | ||
'./src/util/identity': 15, | ||
'./src/util/listener': 16, | ||
'./src/util/query': 17, | ||
'spica/global': 7 | ||
'./src/builder': 11, | ||
'./src/util/dom': 13, | ||
'./src/util/identity': 14, | ||
'./src/util/listener': 15, | ||
'./src/util/query': 16, | ||
'spica/global': 6 | ||
} | ||
@@ -1402,4 +1397,3 @@ ] | ||
2, | ||
'typed-dom', | ||
3 | ||
'typed-dom' | ||
]); | ||
@@ -1406,0 +1400,0 @@ (function (root, factory) { |
@@ -5,3 +5,3 @@ import 'spica/global'; | ||
export { El } from './src/proxy'; | ||
export { NS, shadow, frag, html, svg, text, element, define, defrag } from './src/util/dom'; | ||
export { NS, Attrs, Children, Factory, shadow, frag, html, svg, text, element, define, defrag } from './src/util/dom'; | ||
export { listen, delegate, bind, once, wait, currentTarget } from './src/util/listener'; | ||
@@ -8,0 +8,0 @@ export { apply } from './src/util/query'; |
{ | ||
"name": "typed-dom", | ||
"version": "0.0.260", | ||
"version": "0.0.261", | ||
"description": "A value-level and type-level DOM builder.", | ||
@@ -5,0 +5,0 @@ "private": false, |
@@ -143,2 +143,5 @@ # typed-dom | ||
- NS | ||
- Attrs | ||
- Children | ||
- Factory | ||
- shadow | ||
@@ -161,3 +164,3 @@ - frag | ||
Build a typed DOM component with styling. | ||
APIs replace the `$scope` selector with `:host`, `#<id>`, or `.<generated-id>`. | ||
APIs replace the `:scope` selector with `:host`, `#<id>`, or `.<generated-id>`. | ||
@@ -168,3 +171,3 @@ ```ts | ||
const dom = HTML.article({ | ||
style: HTML.style(`$scope { color: red; }`), | ||
style: HTML.style(`:scope { color: red; }`), | ||
title: HTML.h1(`Title`), | ||
@@ -193,3 +196,3 @@ content: HTML.ul([ | ||
> { | ||
readonly tag?: string; | ||
readonly tag: string; | ||
readonly element: E; | ||
@@ -262,3 +265,3 @@ get children(): El.Getter<C>; | ||
private readonly dom = HTML.section({ | ||
style: HTML.style(`$scope { color: red; }`), | ||
style: HTML.style(`:scope { color: red; }`), | ||
content: HTML.ul([ | ||
@@ -268,3 +271,3 @@ HTML.li(`item`), | ||
}); | ||
public readonly tag: typeof this.dom.tag; | ||
public readonly tag = this.dom.tag; | ||
public readonly element = this.dom.element; | ||
@@ -281,3 +284,3 @@ public get children() { | ||
private readonly dom = Shadow.section({ | ||
style: HTML.style(`$scope { color: red; }`), | ||
style: HTML.style(`:scope { color: red; }`), | ||
content: HTML.ul([ | ||
@@ -287,3 +290,3 @@ HTML.li(`item`), | ||
}); | ||
public readonly tag: typeof this.dom.tag; | ||
public readonly tag = this.dom.tag; | ||
public readonly element = this.dom.element; | ||
@@ -315,3 +318,3 @@ public get children() { | ||
private readonly dom = Shadow.section({ | ||
style: HTML.style(`$scope { color: red; }`), | ||
style: HTML.style(`:scope { color: red; }`), | ||
content: HTML.ul([ | ||
@@ -321,3 +324,3 @@ HTML.li(`item`), | ||
}); | ||
public readonly tag: typeof this.dom.tag; | ||
public readonly tag = this.dom.tag; | ||
public readonly element = this.dom.element; | ||
@@ -338,4 +341,3 @@ public get children() { | ||
```ts | ||
import { API, html } from 'typed-dom'; | ||
import { Attrs } from 'typed-dom/internal'; | ||
import { API, Attrs, html } from 'typed-dom'; | ||
@@ -347,29 +349,29 @@ const i18n = i18next.createInstance({ | ||
translation: { | ||
"a": "{{data}}", | ||
} | ||
} | ||
} | ||
'Greeting': 'Hello, {{name}}.', | ||
}, | ||
}, | ||
}, | ||
}); | ||
interface TransDataMap { | ||
'a': { data: string; }; | ||
'Greeting': { name: string; }; | ||
} | ||
const Trans = API<HTMLElementTagNameMap>(html); | ||
const bind = <K extends keyof TransDataMap>(data: TransDataMap[K]) => | ||
<T extends string, E extends Element>( | ||
factory: (tag: T, attrs: Attrs, children: K) => E, | ||
<T extends keyof HTMLElementTagNameMap>( | ||
factory: (tag: T, attrs?: Attrs) => HTMLElementTagNameMap[T], | ||
tag: T, | ||
attrs: Attrs, | ||
children: K, | ||
): E => | ||
factory(tag, Object.assign<Attrs, Attrs>(attrs, { | ||
) => | ||
factory(tag, void Object.assign<Attrs, Attrs>(attrs, { | ||
onmutate: ev => | ||
i18n.init((err, t) => | ||
void i18n.init((err, t) => | ||
(ev.target as HTMLElement).textContent = err | ||
? 'Failed to init i18next.' | ||
: t(children, data)), | ||
}), children); | ||
? '{% Failed to initialize the translator. %}' | ||
: t(children, data) ?? `{% Failed to translate "${children}". %}`), | ||
})); | ||
const el = Trans.span('a', bind({ data: 'A' })); | ||
assert(el.children === 'A'); | ||
assert(el.element.textContent === 'A'); | ||
const el = Trans.span('Greeting', bind({ name: 'world' })); | ||
assert(el.children === 'Hello, world.'); | ||
assert(el.element.textContent === 'Hello, world.'); | ||
``` | ||
@@ -376,0 +378,0 @@ |
@@ -9,6 +9,6 @@ import { Symbol } from 'spica/global'; | ||
BuilderFunction<M, F> & | ||
{ readonly [P in K<M>]: BuilderMethod<M, F, P, E<M[P]>>; }; | ||
{ readonly [P in K<M>]: BuilderMethod<M, F, P>; }; | ||
export function API | ||
<M extends TagNameMap, F extends Factory<M> = Factory<M>> | ||
(baseFactory: F, formatter: <E extends Element>(el: E) => E | ShadowRoot = el => el) | ||
(baseFactory: F, formatter?: <E extends Element>(el: E) => E | ShadowRoot) | ||
: API<M, F> { | ||
@@ -23,3 +23,2 @@ return new Proxy<API<M, F>>((() => void 0) as any, handle(baseFactory, formatter)); | ||
type Empty = readonly []; | ||
type ElFactory<M extends TagNameMap, F extends Factory<M>, T extends K<M>, C extends El.Children, E extends Element> = (baseFactory: F, tag: T, attrs: Attrs, children: C) => E; | ||
type K<M> = keyof M & string; | ||
@@ -29,25 +28,25 @@ type E<V> = Extract<V, Element>; | ||
interface BuilderFunction<M extends TagNameMap, F extends Factory<M>> { | ||
<T extends K<M>, C extends El.Children.Void >(tag: T, factory?: ElFactory<M, F, T, C, E<M[T]>>): El<T, E<M[T]>, El.Children>; | ||
<T extends K<M>, C extends Empty >(tag: T, children?: C, factory?: ElFactory<M, F, T, C, E<M[T]>>): El<T, E<M[T]>, El.Children.Array>; | ||
<T extends K<M>, C extends El.Children.Text >(tag: T, children?: C, factory?: ElFactory<M, F, T, C, E<M[T]>>): El<T, E<M[T]>, El.Children.Text>; | ||
<T extends K<M>, C extends El.Children.Array >(tag: T, children?: C, factory?: ElFactory<M, F, T, C, E<M[T]>>): El<T, E<M[T]>, Readonly<C>>; | ||
<T extends K<M>, C extends El.Children.Struct>(tag: T, children?: C, factory?: ElFactory<M, F, T, C, E<M[T]>>): El<T, E<M[T]>, C>; | ||
<T extends K<M>, C extends El.Children.Void >(tag: T, attrs?: Attrs, factory?: ElFactory<M, F, T, C, E<M[T]>>): El<T, E<M[T]>, El.Children>; | ||
<T extends K<M>, C extends Empty >(tag: T, attrs?: Attrs, children?: C, factory?: ElFactory<M, F, T, C, E<M[T]>>): El<T, E<M[T]>, El.Children.Array>; | ||
<T extends K<M>, C extends El.Children.Text >(tag: T, attrs?: Attrs, children?: C, factory?: ElFactory<M, F, T, C, E<M[T]>>): El<T, E<M[T]>, El.Children.Text>; | ||
<T extends K<M>, C extends El.Children.Array >(tag: T, attrs?: Attrs, children?: C, factory?: ElFactory<M, F, T, C, E<M[T]>>): El<T, E<M[T]>, Readonly<C>>; | ||
<T extends K<M>, C extends El.Children.Struct>(tag: T, attrs?: Attrs, children?: C, factory?: ElFactory<M, F, T, C, E<M[T]>>): El<T, E<M[T]>, C>; | ||
<T extends K<M>, C extends El.Children.Void >(tag: T, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, El.Children>; | ||
<T extends K<M>, C extends Empty >(tag: T, children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, El.Children.Array>; | ||
<T extends K<M>, C extends El.Children.Text >(tag: T, children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, El.Children.Text>; | ||
<T extends K<M>, C extends El.Children.Array >(tag: T, children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, Readonly<C>>; | ||
<T extends K<M>, C extends El.Children.Struct>(tag: T, children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, C>; | ||
<T extends K<M>, C extends El.Children.Void >(tag: T, attrs?: Attrs, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, El.Children>; | ||
<T extends K<M>, C extends Empty >(tag: T, attrs?: Attrs, children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, El.Children.Array>; | ||
<T extends K<M>, C extends El.Children.Text >(tag: T, attrs?: Attrs, children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, El.Children.Text>; | ||
<T extends K<M>, C extends El.Children.Array >(tag: T, attrs?: Attrs, children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, Readonly<C>>; | ||
<T extends K<M>, C extends El.Children.Struct>(tag: T, attrs?: Attrs, children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, C>; | ||
} | ||
interface BuilderMethod<M extends TagNameMap, F extends Factory<M>, T extends K<M>, E extends Element> { | ||
<C extends El.Children.Void >( factory?: ElFactory<M, F, T, C, E> ): El<T, E, El.Children>; | ||
<C extends Empty >( children?: C, factory?: ElFactory<M, F, T, C, E> ): El<T, E, El.Children.Array>; | ||
<C extends El.Children.Text >( children?: C, factory?: ElFactory<M, F, T, C, E> ): El<T, E, El.Children.Text>; | ||
<C extends El.Children.Array >( children?: C, factory?: ElFactory<M, F, T, C, E> ): El<T, E, Readonly<C>>; | ||
<C extends El.Children.Struct>( children?: C, factory?: ElFactory<M, F, T, C, E> ): El<T, E, C>; | ||
<C extends El.Children.Void >( attrs?: Attrs, factory?: ElFactory<M, F, T, C, E> ): El<T, E, El.Children>; | ||
<C extends Empty >( attrs?: Attrs, children?: C, factory?: ElFactory<M, F, T, C, E> ): El<T, E, El.Children.Array>; | ||
<C extends El.Children.Text >( attrs?: Attrs, children?: C, factory?: ElFactory<M, F, T, C, E> ): El<T, E, El.Children.Text>; | ||
<C extends El.Children.Array >( attrs?: Attrs, children?: C, factory?: ElFactory<M, F, T, C, E> ): El<T, E, Readonly<C>>; | ||
<C extends El.Children.Struct>( attrs?: Attrs, children?: C, factory?: ElFactory<M, F, T, C, E> ): El<T, E, C>; | ||
interface BuilderMethod<M extends TagNameMap, F extends Factory<M>, T extends K<M>> { | ||
<C extends El.Children.Void >( factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, El.Children>; | ||
<C extends Empty >( children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, El.Children.Array>; | ||
<C extends El.Children.Text >( children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, El.Children.Text>; | ||
<C extends El.Children.Array >( children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, Readonly<C>>; | ||
<C extends El.Children.Struct>( children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, C>; | ||
<C extends El.Children.Void >( attrs?: Attrs, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, El.Children>; | ||
<C extends Empty >( attrs?: Attrs, children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, El.Children.Array>; | ||
<C extends El.Children.Text >( attrs?: Attrs, children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, El.Children.Text>; | ||
<C extends El.Children.Array >( attrs?: Attrs, children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, Readonly<C>>; | ||
<C extends El.Children.Struct>( attrs?: Attrs, children?: C, factory?: El.Factory<M, F, T, C>): El<T, E<M[T]>, C>; | ||
} | ||
@@ -57,3 +56,3 @@ | ||
<M extends TagNameMap, F extends Factory<M>> | ||
(baseFactory: F, formatter: <E extends Element>(el: E) => E | ShadowRoot, | ||
(baseFactory: F, formatter?: <E extends Element>(el: E) => E | ShadowRoot, | ||
): ProxyHandler<API<M, F>> { | ||
@@ -67,7 +66,7 @@ return { | ||
? target[prop] | ||
: target[prop] = builder(prop as keyof M & string, baseFactory), | ||
: target[prop] = builder(prop as keyof M & string), | ||
}; | ||
function builder(tag: keyof M & string, baseFactory: F): (attrs?: Attrs, children?: El.Children, factory?: () => Element) => El { | ||
return function build(attrs?: Attrs | El.Children, children?: El.Children, factory?: ElFactory<M, F, keyof M & string, El.Children, Element>): El { | ||
function builder(tag: keyof M & string) { | ||
return function build(attrs?: Attrs | El.Children, children?: El.Children, factory?: El.Factory<M, F, keyof M & string, El.Children>): El { | ||
if (typeof children === 'function') return build(attrs, void 0, children); | ||
@@ -77,30 +76,25 @@ if (typeof attrs === 'function') return build(void 0, void 0, attrs); | ||
attrs ??= {} as typeof attrs; | ||
const el = elem(factory, attrs, children); | ||
const node = formatter(el); | ||
return node !== el && 'host' in node | ||
// Shadow | ||
? new Elem(el, attrs, children, node) | ||
// Element | ||
: new Elem(el, attrs, children); | ||
const el = elem(tag, factory, attrs, children); | ||
return new Elem(tag, el, attrs, children, formatter?.(el)); | ||
}; | ||
} | ||
function isElChildren(param: Attrs | El.Children): param is El.Children { | ||
if (param === void 0) return false; | ||
if (param[Symbol.iterator]) return true; | ||
for (const name in param as Attrs) { | ||
if (!hasOwnProperty(param, name)) continue; | ||
const p = param[name]; | ||
return !!p && typeof p === 'object'; | ||
} | ||
return true; | ||
} | ||
function elem(tag: keyof M & string, factory: El.Factory<M, F, keyof M & string, El.Children> | undefined, attrs: Attrs, children: El.Children): Element { | ||
const el = factory | ||
? define(factory(baseFactory, tag, attrs, children) as unknown as Element, attrs) | ||
: baseFactory(tag, attrs) as unknown as Element; | ||
if (tag.toLowerCase() !== el.tagName.toLowerCase()) throw new Error(`TypedDOM: Expected tag name is "${tag.toLowerCase()}" but actually "${el.tagName.toLowerCase()}".`); | ||
return el; | ||
} | ||
} | ||
function elem(factory: ElFactory<M, F, keyof M & string, El.Children, Element> | undefined, attrs: Attrs, children: El.Children): Element { | ||
const el = factory | ||
? define(factory(baseFactory as F, tag, attrs, children), attrs) | ||
: baseFactory(tag, attrs) as unknown as Element; | ||
if (tag.toLowerCase() !== el.tagName.toLowerCase()) throw new Error(`TypedDOM: Expected tag name is "${tag.toLowerCase()}" but actually "${el.tagName.toLowerCase()}".`); | ||
return el; | ||
} | ||
function isElChildren(param: Attrs | El.Children): param is El.Children { | ||
if (param === void 0) return false; | ||
if (param[Symbol.iterator]) return true; | ||
for (const name in param as Attrs | El.Children.Struct) { | ||
if (!hasOwnProperty(param, name)) continue; | ||
const value = param[name]; | ||
return !!value && typeof value === 'object'; | ||
} | ||
return true; | ||
} |
import { Event } from 'spica/global'; | ||
import { isArray, hasOwnProperty, ObjectDefineProperties, ObjectKeys } from 'spica/alias'; | ||
import { Attrs } from './util/dom'; | ||
import { TagNameMap, Attrs, Factory as BaseFactory } from './util/dom'; | ||
import { identity } from './util/identity'; | ||
@@ -13,3 +13,3 @@ | ||
> { | ||
readonly tag?: T; | ||
readonly tag: T; | ||
readonly element: E; | ||
@@ -38,2 +38,5 @@ //get children(): C; | ||
Partial<C>; | ||
// Bug: TypeScript: Type U must not affect Type C | ||
//export type Factory<M extends TagNameMap, F extends BaseFactory<M> = BaseFactory<M>, T extends keyof M & string = keyof M & string, C extends El.Children = El.Children> = <U extends T>(baseFactory: F, tag: U, attrs: Attrs, children: C) => M[U]; | ||
export type Factory<M extends TagNameMap, F extends BaseFactory<M> = BaseFactory<M>, T extends keyof M & string = keyof M & string, C extends El.Children = El.Children> = (baseFactory: F, tag: T, attrs: Attrs, children: C) => M[T]; | ||
} | ||
@@ -71,2 +74,3 @@ const enum ElChildType { | ||
constructor( | ||
public readonly tag: T, | ||
public readonly element: E, | ||
@@ -78,5 +82,5 @@ attrs: Attrs, | ||
const events = this[privates.events]; | ||
events.mutate = attrs?.['onmutate'] != null; | ||
events.connect = attrs?.['onconnect'] != null; | ||
events.disconnect = attrs?.['ondisconnect'] != null; | ||
events.mutate = (attrs?.['onmutate'] ?? attrs?.['onMutate']) != null; | ||
events.connect = (attrs?.['onconnect'] ?? attrs?.['onConnect']) != null; | ||
events.disconnect = (attrs?.['ondisconnect'] ?? attrs?.['onDisconnect']) != null; | ||
this[privates.children] = children; | ||
@@ -124,3 +128,2 @@ this[privates.container] = container; | ||
} | ||
public readonly tag?: T; | ||
private readonly [privates.events] = { | ||
@@ -135,3 +138,3 @@ mutate: false, | ||
this[privates.id_] = this.element.id; | ||
if (/^[\w-]+$/.test(this[privates.id_])) return this[privates.id_]; | ||
if (/^[a-z][\w-]*$/i.test(this[privates.id_])) return this[privates.id_]; | ||
if (counter === 999) { | ||
@@ -159,6 +162,6 @@ id = identity(); | ||
private [privates.scope](child: El): void { | ||
if (child.element.tagName.toUpperCase() !== 'STYLE') return; | ||
if (child.tag.toUpperCase() !== 'STYLE') return; | ||
const source = child.element.innerHTML; | ||
if (!source.includes('$scope')) return; | ||
const scope = /(^|[>~+,}/])(\s*)\$scope(?!\w)(?=\s*[A-Za-z#.:[>~+,{/])/g; | ||
if (!source.includes(':scope')) return; | ||
const scope = /(^|[>~+,}/])(\s*)\:scope(?!\w)(?=\s*[A-Za-z#.:[>~+,{/])/g; | ||
const style = source.replace(scope, (...$) => `${$[1]}${$[2]}${this[privates.query]}`); | ||
@@ -218,4 +221,5 @@ assert(!this[privates.query_] || style !== source); | ||
case ElChildType.Text: { | ||
if (!this[privates.events].mutate) { | ||
if (this[privates.isInit] || !this[privates.events].mutate) { | ||
container.textContent = children as El.Children.Text; | ||
isMutated = true; | ||
break; | ||
@@ -225,5 +229,5 @@ } | ||
const oldText = this.children; | ||
if (!this[privates.isInit] && newText === oldText) return; | ||
if (newText === oldText) break; | ||
container.textContent = newText as El.Children.Text; | ||
isMutated = true; | ||
container.textContent = newText as El.Children.Text; | ||
break; | ||
@@ -275,7 +279,7 @@ } | ||
throwErrorIfNotUsable(newChild, this[privates.container]); | ||
isMutated = true; | ||
this[privates.scope](newChild); | ||
container.appendChild(newChild.element); | ||
assert(!addedChildren.includes(newChild)); | ||
events(newChild)?.connect && addedChildren.push(newChild); | ||
container.appendChild(newChild.element); | ||
isMutated = true; | ||
} | ||
@@ -294,9 +298,8 @@ break; | ||
throwErrorIfNotUsable(newChild, this[privates.container]); | ||
isMutated = true; | ||
if (newChild !== oldChild && newChild.element.parentNode !== oldChild.element.parentNode) { | ||
this[privates.scope](newChild); | ||
container.replaceChild(newChild.element, oldChild.element); | ||
assert(!oldChild.element.parentNode); | ||
assert(!addedChildren.includes(newChild)); | ||
events(newChild)?.connect && addedChildren.push(newChild); | ||
container.replaceChild(newChild.element, oldChild.element); | ||
assert(!oldChild.element.parentNode); | ||
assert(!removedChildren.includes(oldChild)); | ||
@@ -311,2 +314,3 @@ events(oldChild)?.disconnect && removedChildren.push(oldChild); | ||
} | ||
isMutated = true; | ||
this[privates.isObserverUpdate] = true; | ||
@@ -313,0 +317,0 @@ targetChildren[name] = newChild; |
@@ -1,5 +0,4 @@ | ||
import { API, Shadow, HTML, SVG, El, shadow, html } from '../..'; | ||
import { API, Shadow, HTML, SVG, El, Attrs, shadow, html } from '../..'; | ||
import { Coroutine } from 'spica/coroutine'; | ||
import { Sequence } from 'spica/sequence'; | ||
import { Attrs } from '../../internal'; | ||
@@ -292,25 +291,25 @@ declare global { | ||
const template = [ | ||
'$scope{}', | ||
'$scope:empty {}', | ||
'$scope[id] {}', | ||
'$scope#id {}', | ||
'$scope.class {}', | ||
'$scope div {}', | ||
'$scope>div {}', | ||
'$scope,$scope {}', | ||
'$scope{}$scope{}', | ||
'$scope/* */ {}', | ||
'/* */$scope {}', | ||
' $scope {}', | ||
':scope{}', | ||
':scope:empty {}', | ||
':scope[id] {}', | ||
':scope#id {}', | ||
':scope.class {}', | ||
':scope div {}', | ||
':scope>div {}', | ||
':scope,:scope {}', | ||
':scope{}:scope{}', | ||
':scope/* */ {}', | ||
'/* */:scope {}', | ||
' :scope {}', | ||
].join('\n'); | ||
const id = 'id'; | ||
const style = template.replace(/\$scope/g, `#${id}`); | ||
const style = template.replace(/\:scope/g, `#${id}`); | ||
assert(HTML.div({ id }, [HTML.style(template)]).children[0].element.innerHTML === style); | ||
assert(HTML.div({ id }, { style: HTML.style(template) }).children.style.element.innerHTML === style); | ||
assert(HTML.div([HTML.style('$scope {}')]).element.className.match(/^rnd-\w+-\d+$/)); | ||
assert(Shadow.div([HTML.style('$scope {}')]).element.outerHTML === '<div></div>'); | ||
assert(Shadow.div([HTML.style('$scope {}')]).children[0].element.innerHTML === ':host {}'); | ||
assert(Shadow.div([HTML.style('/* $scope */$scope/* $scope */{content:" $scope "}')]).children[0].element.innerHTML === '/* $scope */:host/* $scope */{content:" $scope "}'); | ||
assert(HTML.div([HTML.style(':scope {}')]).element.className.match(/^rnd-\w+-\d+$/)); | ||
assert(Shadow.div([HTML.style(':scope {}')]).element.outerHTML === '<div></div>'); | ||
assert(Shadow.div([HTML.style(':scope {}')]).children[0].element.innerHTML === ':host {}'); | ||
assert(Shadow.div([HTML.style('/* :scope */:scope/* :scope */{content:" :scope "}')]).children[0].element.innerHTML === '/* :scope */:host/* :scope */{content:" :scope "}'); | ||
assert(HTML.div([HTML.style(`<script>`)]).children[0].element.children.length === 0); | ||
assert(HTML.div([HTML.style(`$scope{}<script>`)]).children[0].element.children.length === 0); | ||
assert(HTML.div([HTML.style(`:scope{}<script>`)]).children[0].element.children.length === 0); | ||
}); | ||
@@ -475,3 +474,3 @@ | ||
private readonly dom = HTML.section({ | ||
style: HTML.style(`$scope { color: red; }`), | ||
style: HTML.style(`:scope { color: red; }`), | ||
content: HTML.ul([ | ||
@@ -481,3 +480,3 @@ HTML.li(`item`) | ||
}); | ||
public readonly tag: typeof this.dom.tag; | ||
public readonly tag = this.dom.tag; | ||
public readonly element = this.dom.element; | ||
@@ -508,3 +507,3 @@ public get children() { | ||
private readonly dom = Shadow.section({ | ||
style: HTML.style(`$scope { color: red; }`), | ||
style: HTML.style(`:scope { color: red; }`), | ||
content: HTML.ul([ | ||
@@ -514,3 +513,3 @@ HTML.li(`item`) | ||
}); | ||
public readonly tag: typeof this.dom.tag; | ||
public readonly tag = this.dom.tag; | ||
public readonly element = this.dom.element; | ||
@@ -551,3 +550,3 @@ public get children() { | ||
private readonly dom = Shadow.section({ | ||
style: HTML.style(`$scope { color: red; }`), | ||
style: HTML.style(`:scope { color: red; }`), | ||
content: HTML.ul([ | ||
@@ -557,3 +556,3 @@ HTML.li(`item`) | ||
}); | ||
public readonly tag: typeof this.dom.tag; | ||
public readonly tag = this.dom.tag; | ||
public readonly element = this.dom.element; | ||
@@ -583,29 +582,33 @@ public get children() { | ||
translation: { | ||
"a": "{{data}}", | ||
} | ||
} | ||
} | ||
'Greeting': 'Hello, {{name}}.', | ||
}, | ||
}, | ||
}, | ||
}); | ||
interface TransDataMap { | ||
'a': { data: string; }; | ||
'Greeting': { name: string; }; | ||
} | ||
const Trans = API<HTMLElementTagNameMap>(html); | ||
const bind = <K extends keyof TransDataMap>(data: TransDataMap[K]) => | ||
<T extends string, E extends Element>( | ||
factory: (tag: T, attrs: Attrs, children: K) => E, | ||
<T extends keyof HTMLElementTagNameMap>( | ||
factory: (tag: T, attrs?: Attrs) => HTMLElementTagNameMap[T], | ||
tag: T, | ||
attrs: Attrs, | ||
children: K, | ||
): E => | ||
factory(tag, Object.assign<Attrs, Attrs>(attrs, { | ||
) => | ||
factory(tag, void Object.assign<Attrs, Attrs>(attrs, { | ||
onmutate: ev => | ||
i18n.init((err, t) => | ||
void i18n.init((err, t) => | ||
(ev.target as HTMLElement).textContent = err | ||
? 'Failed to init i18next.' | ||
: t(children, data)), | ||
}), children); | ||
? '{% Failed to initialize the translator. %}' | ||
: t(children, data) ?? `{% Failed to translate "${children}". %}`), | ||
})); | ||
const el = Trans.span('a', bind({ data: 'A' })); | ||
assert(el.children === 'A'); | ||
assert(el.element.textContent === 'A'); | ||
const el = Trans.span('Greeting', bind({ name: 'world' })); | ||
assert(el.children === 'Hello, world.'); | ||
assert(el.element.textContent === 'Hello, world.'); | ||
// @ts-expect-error | ||
Trans.span('', bind({ name: 'world' })); | ||
// @ts-expect-error | ||
Trans.span('Greeting', bind({})); | ||
}); | ||
@@ -612,0 +615,0 @@ |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
661047
370
32
15624