From adae397d31a78a9b239a023df886af54e27c7e7e Mon Sep 17 00:00:00 2001 From: Andrey Polischuk Date: Fri, 23 Aug 2024 13:07:01 +0300 Subject: [PATCH] feat(widget-element)!: parse attributes to element fields BREAKING CHANGES: the params getter has been removed, now attributes are added as element fields --- .size-limit.json | 2 +- packages/widget-element/index.test.ts | 5 +-- packages/widget-element/index.ts | 50 ++++++++++++++++++--------- packages/widget-element/utils.ts | 25 -------------- 4 files changed, 38 insertions(+), 44 deletions(-) delete mode 100644 packages/widget-element/utils.ts diff --git a/.size-limit.json b/.size-limit.json index 13531d3..b063be1 100644 --- a/.size-limit.json +++ b/.size-limit.json @@ -5,6 +5,6 @@ }, { "path": "packages/widget-element/dist/index.js", - "limit": "1.05 KB" + "limit": "950 B" } ] diff --git a/packages/widget-element/index.test.ts b/packages/widget-element/index.test.ts index 08017da..44817c8 100644 --- a/packages/widget-element/index.test.ts +++ b/packages/widget-element/index.test.ts @@ -2,6 +2,7 @@ import {WidgetElement} from '.' class TestWidget extends WidgetElement { root: ShadowRoot + testId: string ready = false changed = false @@ -65,7 +66,7 @@ test('widget attribute is changed', async () => { widget.setAttribute('test-id', '123') expect(widget.changed).toBe(false) - expect(widget.params).toEqual({testId: '123', provider: widget}) + expect(widget.testId).toBe('123') document.body.append(widget) widget.setAttribute('test-id', '456') @@ -73,7 +74,7 @@ test('widget attribute is changed', async () => { await Promise.resolve() expect(widget.changed).toBe(true) - expect(widget.params).toEqual({testId: '456', provider: widget}) + expect(widget.testId).toBe('456') }) test('widget is destroyed', async () => { diff --git a/packages/widget-element/index.ts b/packages/widget-element/index.ts index b0aca62..757985a 100644 --- a/packages/widget-element/index.ts +++ b/packages/widget-element/index.ts @@ -1,5 +1,4 @@ /* eslint-disable import/no-unused-modules */ -import {getAttributesFromElement, createElementFromHtml} from './utils' /** * Custom Element that helps you to create widgets. @@ -10,18 +9,16 @@ import {getAttributesFromElement, createElementFromHtml} from './utils' * import {createApp} from './app' * * class CustomWidget extends WidgetElement { - * static get observedAttributes() { - * return ['app-id'] - * } + * static observedAttributes = ['app-id'] * * async initialize(shadowRoot: ShadowRoot) { - * const {appId} = this.params + * const {appId} = this * this.app = createApp(shadowRoot) * await this.app.render({appId}) * } * * attributeChanged() { - * const {appId} = this.params + * const {appId} = this * this.app.render({appId}) * } * @@ -71,22 +68,17 @@ export class WidgetElement extends HTMLElement { } } - /** Widget params (an attributes map with names given in the camelCase) */ - get params(): Record { - const params = getAttributesFromElement(this) - - return {...params, provider: this} - } - async connectedCallback() { - this.#fallback = createElementFromHtml(this.fallback) - this.#shadowRoot = this.attachShadow({mode: 'closed'}) + this.#shadowRoot = this.#createRoot() + this.#fallback = this.#createFallback() await this.initialize(this.#shadowRoot) this.emit('ready') } - attributeChangedCallback() { + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + this.#updateAttribute(name, oldValue, newValue) + if (this.#shadowRoot) { this.attributeChanged() } @@ -97,6 +89,32 @@ export class WidgetElement extends HTMLElement { this.emit('destroy') } + #createRoot() { + return this.attachShadow({mode: 'closed'}) + } + + #createFallback() { + const template = document.createElement('template') + + template.innerHTML = this.fallback + + return template.content.firstElementChild as HTMLElement + } + + #updateAttribute(name: string, oldValue: string, newValue: string) { + if (newValue !== oldValue) { + const key = name.replace(/-(\w)/g, (_, char) => + char.toUpperCase() + ) as keyof this + + if (typeof newValue === 'undefined') { + delete this[key] + } else { + this[key] = newValue as any + } + } + } + /** Widget is initialized, and shadow root is attached */ // eslint-disable-next-line no-empty-function initialize(_shadowRoot: ShadowRoot) {} diff --git a/packages/widget-element/utils.ts b/packages/widget-element/utils.ts deleted file mode 100644 index 3af2614..0000000 --- a/packages/widget-element/utils.ts +++ /dev/null @@ -1,25 +0,0 @@ -export function createElementFromHtml(html: string) { - const template = document.createElement('template') - - template.innerHTML = html - - return template.content.firstElementChild as HTMLElement -} - -export function getAttributesFromElement({attributes}: HTMLElement) { - const params: Record = {} - - for (let i = 0; i < attributes.length; i++) { - const node = attributes.item(i) - - if (node != null) { - const nodeName = node.nodeName.replace(/-(\w)/g, (_, char) => - char.toUpperCase() - ) - - params[nodeName] = node.nodeValue - } - } - - return params -}