From 5d86cb8d1f113b1a6970920ab9685f16249876e8 Mon Sep 17 00:00:00 2001 From: William Wong Date: Sat, 26 Oct 2024 07:18:21 +0000 Subject: [PATCH] Generalize custom element registration --- .../CustomElements/CustomElementsComposer.tsx | 31 +++++++++++++++++-- ...ckCopyButton.ts => CodeBlockCopyButton.ts} | 20 +----------- 2 files changed, 29 insertions(+), 22 deletions(-) rename packages/component/src/providers/CustomElements/customElements/{registerCodeBlockCopyButton.ts => CodeBlockCopyButton.ts} (83%) diff --git a/packages/component/src/providers/CustomElements/CustomElementsComposer.tsx b/packages/component/src/providers/CustomElements/CustomElementsComposer.tsx index 4802d8a4ad..c352f2dbb1 100644 --- a/packages/component/src/providers/CustomElements/CustomElementsComposer.tsx +++ b/packages/component/src/providers/CustomElements/CustomElementsComposer.tsx @@ -1,6 +1,6 @@ import mathRandom from 'math-random'; -import React, { memo, useMemo, type ReactNode } from 'react'; -import registerCodeBlockCopyButton from './customElements/registerCodeBlockCopyButton'; +import React, { memo, useCallback, useMemo, type ReactNode } from 'react'; +import CodeBlockCopyButtonElement from './customElements/CodeBlockCopyButton'; import CustomElementsContext from './private/CustomElementsContext'; type CustomElementsComposerProps = Readonly<{ @@ -11,7 +11,32 @@ const CustomElementsComposer = ({ children }: CustomElementsComposerProps) => { // eslint-disable-next-line no-magic-numbers const hash = useMemo(() => mathRandom().toString(36).substring(2, 7), []); - const codeBlockCopyButtonTagName = useMemo(() => registerCodeBlockCopyButton(hash), [hash]); + const registerCustomElement = useCallback( + (tagName: string, customElementConstructor: CustomElementConstructor): string => { + const fullTagName = `webchat-${hash}--${tagName}` as const; + + customElements.define( + fullTagName, + class extends customElementConstructor { + static get observedAttributes(): readonly string[] { + return Object.freeze( + 'observedAttributes' in customElementConstructor + ? (customElementConstructor.observedAttributes as string[]) + : [] + ); + } + } + ); + + return fullTagName; + }, + [hash] + ); + + const codeBlockCopyButtonTagName = useMemo( + () => registerCustomElement('code-block-copy-button', CodeBlockCopyButtonElement), + [registerCustomElement] + ); const context = useMemo(() => Object.freeze({ codeBlockCopyButtonTagName }), [codeBlockCopyButtonTagName]); diff --git a/packages/component/src/providers/CustomElements/customElements/registerCodeBlockCopyButton.ts b/packages/component/src/providers/CustomElements/customElements/CodeBlockCopyButton.ts similarity index 83% rename from packages/component/src/providers/CustomElements/customElements/registerCodeBlockCopyButton.ts rename to packages/component/src/providers/CustomElements/customElements/CodeBlockCopyButton.ts index 152de96f6c..e3613f0564 100644 --- a/packages/component/src/providers/CustomElements/customElements/registerCodeBlockCopyButton.ts +++ b/packages/component/src/providers/CustomElements/customElements/CodeBlockCopyButton.ts @@ -4,7 +4,7 @@ type ObservedAttributes = 'class' | 'data-alt-copied' | 'data-alt-copy'; const observedAttributes: readonly ObservedAttributes[] = Object.freeze(['class', 'data-alt-copied', 'data-alt-copy']); -class CodeBlockCopyButtonElement extends HTMLElement { +export default class CodeBlockCopyButtonElement extends HTMLElement { static get observedAttributes(): readonly ObservedAttributes[] { return observedAttributes; } @@ -99,21 +99,3 @@ class CodeBlockCopyButtonElement extends HTMLElement { } } } - -export default function registerCodeBlockCopyButton(hash: string): string { - // Allowed tag names are specified here, https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define#valid_custom_element_names - const name = `webchat-${hash}--code-block-copy-button`; - - customElements.define( - name, - // Using anonymous class because one class can only be registered with one tag name. - // Web Components enforce 1:1 relationship. - class extends CodeBlockCopyButtonElement { - static get observedAttributes(): readonly ObservedAttributes[] { - return observedAttributes; - } - } - ); - - return name; -}