diff --git a/src/attr.ts b/src/attr.ts index 07f6a2e3..2d7472fc 100644 --- a/src/attr.ts +++ b/src/attr.ts @@ -1,5 +1,5 @@ import type {CustomElementClass} from './custom-element.js' -import {dasherize} from './dasherize.js' +import {mustDasherize} from './dasherize.js' import {meta} from './core.js' const attrKey = 'attr' @@ -39,10 +39,12 @@ const initialized = new WeakSet() export function initializeAttrs(instance: HTMLElement, names?: Iterable): void { if (initialized.has(instance)) return initialized.add(instance) - if (!names) names = meta(Object.getPrototypeOf(instance), attrKey) + const proto = Object.getPrototypeOf(instance) + const prefix = proto?.constructor?.attrPrefix ?? 'data-' + if (!names) names = meta(proto, attrKey) for (const key of names) { const value = (>(instance))[key] - const name = attrToAttributeName(key) + const name = mustDasherize(`${prefix}${key}`) let descriptor: PropertyDescriptor = { configurable: true, get(this: HTMLElement): string { @@ -80,10 +82,12 @@ export function initializeAttrs(instance: HTMLElement, names?: Iterable) } } -const attrToAttributeName = (name: string) => `data-${dasherize(name)}` - export function defineObservedAttributes(classObject: CustomElementClass): void { let observed = classObject.observedAttributes || [] + + const prefix = classObject.attrPrefix ?? 'data-' + const attrToAttributeName = (name: string) => mustDasherize(`${prefix}${name}`) + Object.defineProperty(classObject, 'observedAttributes', { configurable: true, get() { diff --git a/src/custom-element.ts b/src/custom-element.ts index 74961c64..d7e3f883 100644 --- a/src/custom-element.ts +++ b/src/custom-element.ts @@ -16,4 +16,6 @@ export interface CustomElementClass { observedAttributes?: string[] disabledFeatures?: string[] formAssociated?: boolean + + attrPrefix?: string } diff --git a/test/attr.ts b/test/attr.ts index 211bbdaf..7eab85bf 100644 --- a/test/attr.ts +++ b/test/attr.ts @@ -156,4 +156,25 @@ describe('Attr', () => { expect(instance.getAttributeNames()).to.include('data-clip-x') }) }) + + describe('prefix', () => { + @controller + class PrefixAttrTest extends HTMLElement { + static attrPrefix = 'foo-' + @attr fooBarBazBing = 'a' + @attr URLBar = 'b' + @attr ClipX = 'c' + } + + let instance: PrefixAttrTest + beforeEach(async () => { + instance = await fixture(html``) + }) + + it('respects custom attrPrefix static member', async () => { + expect(instance.getAttributeNames()).to.include('foo-foo-bar-baz-bing') + expect(instance.getAttributeNames()).to.include('foo-url-bar') + expect(instance.getAttributeNames()).to.include('foo-clip-x') + }) + }) })