Skip to content

Commit

Permalink
Generalize custom element registration
Browse files Browse the repository at this point in the history
  • Loading branch information
compulim committed Oct 26, 2024
1 parent b5dbbca commit 5d86cb8
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -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<{
Expand All @@ -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]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}

0 comments on commit 5d86cb8

Please sign in to comment.