diff --git a/packages/shell/index.ts b/packages/shell/index.ts index a5fdee8..dc7cebf 100644 --- a/packages/shell/index.ts +++ b/packages/shell/index.ts @@ -4,7 +4,7 @@ * @packageDocumentation */ -export * from './src/element/attribute'; -export * from './src/element/component'; -export * from './src/element/jsx-runtime'; +export * from './src/component/attribute'; +export * from './src/component/component'; +export * from './src/component/jsx-runtime'; export * from './src/router/router'; diff --git a/packages/shell/src/element/attribute.ts b/packages/shell/src/component/attribute.ts similarity index 100% rename from packages/shell/src/element/attribute.ts rename to packages/shell/src/component/attribute.ts diff --git a/packages/shell/src/element/component.ts b/packages/shell/src/component/component.ts similarity index 86% rename from packages/shell/src/element/component.ts rename to packages/shell/src/component/component.ts index 7df5d4c..aba0a23 100644 --- a/packages/shell/src/element/component.ts +++ b/packages/shell/src/component/component.ts @@ -1,4 +1,5 @@ -import { elementClose, elementOpen, patch, text } from 'incremental-dom'; +import { patch } from 'incremental-dom'; +import { createElement } from './jsx-runtime'; /** * Interface describing the shape of a component. @@ -107,22 +108,24 @@ export function Component( if (super.renderComponent) { super.renderComponent(); } else if (this.shadowRoot) { - const { styles, template } = this; + const { + styles = [], + template = [] + } = this; - patch(this.shadowRoot, () => { - if (styles) { - elementOpen('style'); - text(styles.join(' ')); - elementClose('style'); - } + if (!template.length) { + template.push(...createElement('slot')); + } - if (template) { - for (const factory of template) { - factory(); - } - } else { - elementOpen('slot'); - elementClose('slot'); + if (styles.length) { + template.push(...createElement('style', { + children: styles + })); + } + + patch(this.shadowRoot, () => { + for (const incrementalDom of template) { + incrementalDom(); } }); } diff --git a/packages/shell/src/element/jsx-runtime.ts b/packages/shell/src/component/jsx-runtime.ts similarity index 66% rename from packages/shell/src/element/jsx-runtime.ts rename to packages/shell/src/component/jsx-runtime.ts index 2697260..6aaffbc 100644 --- a/packages/shell/src/element/jsx-runtime.ts +++ b/packages/shell/src/component/jsx-runtime.ts @@ -1,11 +1,10 @@ import { TypeOf } from '@sgrud/core'; -import { elementClose, elementOpen, Key, text } from 'incremental-dom'; +import { elementClose, elementOpen, text } from 'incremental-dom'; declare global { /** - * Intrinsic JSX namespace containing the list of {@link IntrinsicElements} - * and the JSX {@link Element} type. + * Intrinsic JSX namespace. * * @see https://www.typescriptlang.org/docs/handbook/jsx.html */ @@ -18,12 +17,12 @@ declare global { type Element = (() => Node)[]; /** - * Intrinsic list of JSX elements. Uses the global `HTMLElementTagNameMap` - * while allowing to specify an element rendering key. + * Intrinsic list of known JSX elements, comprised of the global + * `HTMLElementTagNameMap`. */ type IntrinsicElements = { [K in keyof HTMLElementTagNameMap]: Partial & { - key?: Key; + key?: string | number | null; }; }; @@ -35,12 +34,12 @@ declare global { * @param type - Element type. * @param props - Element properties. * @param ref - Element rendering key. - * @returns Array of `incremental-dom` calls. + * @returns Array of bound calls. */ export function createElement( type: keyof JSX.IntrinsicElements | Function, props?: Record, - ref?: Key + ref?: string | number | null ): JSX.Element { if (TypeOf.function(type)) { return type(props); @@ -48,7 +47,7 @@ export function createElement( const attributes = []; const children = []; - const elements = []; + const element = []; for (const key in props) { switch (key) { @@ -70,30 +69,37 @@ export function createElement( } } - elements.push(elementOpen.bind(null, type, ref, null, ...attributes)); + element.push(elementOpen.bind(null, type, ref, null, ...attributes)); for (const child of children) { if (TypeOf.function(child)) { - elements.push(child); + element.push(child); } else { - elements.push(text.bind(null, child)); + element.push(text.bind(null, child)); } } - elements.push(elementClose.bind(null, type)); + element.push(elementClose.bind(null, type)); - return elements; + return element; } /** * @param props - Fragment properties. - * @returns Array of `incremental-dom` calls. + * @returns Array of bound calls. */ export function createFragment(props?: Record): JSX.Element { - return props?.children ? [props.children].flat(Infinity).filter(Boolean) : []; + const fragment = []; + + if (props?.children) { + fragment.push(...[props.children].flat(Infinity).filter(Boolean)); + } + + return fragment; } export { + JSX, createElement as jsx, createElement as jsxs, createFragment as Fragment diff --git a/unittests/shell/element/attribute.test.ts b/unittests/shell/component/attribute.test.ts similarity index 96% rename from unittests/shell/element/attribute.test.ts rename to unittests/shell/component/attribute.test.ts index e3f14a9..048c2c5 100644 --- a/unittests/shell/element/attribute.test.ts +++ b/unittests/shell/component/attribute.test.ts @@ -6,7 +6,7 @@ globalThis.HTMLElement = new Proxy(HTMLElement, { } }); -describe('@sgrud/shell/element/attribute', () => { +describe('@sgrud/shell/component/attribute', () => { class TestClass extends HTMLElement { @Attribute() public attribute?: string; diff --git a/unittests/shell/element/component.test.ts b/unittests/shell/component/component.test.ts similarity index 97% rename from unittests/shell/element/component.test.ts rename to unittests/shell/component/component.test.ts index aa809d1..57310cb 100644 --- a/unittests/shell/element/component.test.ts +++ b/unittests/shell/component/component.test.ts @@ -6,7 +6,7 @@ globalThis.HTMLElement = new Proxy(HTMLElement, { } }); -describe('@sgrud/shell/element/component', () => { +describe('@sgrud/shell/component/component', () => { @Component('class-one') class ClassOne extends HTMLElement { } diff --git a/unittests/shell/element/jsx-runtime.test.ts b/unittests/shell/component/jsx-runtime.test.ts similarity index 94% rename from unittests/shell/element/jsx-runtime.test.ts rename to unittests/shell/component/jsx-runtime.test.ts index f86333d..68341b2 100644 --- a/unittests/shell/element/jsx-runtime.test.ts +++ b/unittests/shell/component/jsx-runtime.test.ts @@ -1,6 +1,6 @@ import { Fragment, jsx } from '@sgrud/shell'; -describe('@sgrud/shell/element/jsx-runtime', () => { +describe('@sgrud/shell/component/jsx-runtime', () => { describe('creating a jsx element', () => { const jsxElement = jsx('main', {