Skip to content

Commit

Permalink
feat: support svg elements (#60)
Browse files Browse the repository at this point in the history
* feat: support svg elements

* chore: fix lint and add notes
  • Loading branch information
Rongyan Chen authored Apr 21, 2022
1 parent 979bcc4 commit 9e2bc7d
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 9 deletions.
26 changes: 19 additions & 7 deletions packages/pwc/src/elements/__tests__/commitAttributes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe('Set element attribute/property/event handler', () => {
},
];
const div = document.createElement('div');
commitAttributes(div, attrs, true);
commitAttributes(div, attrs, { isInitial: true });
expect(div.getAttribute('data-index')).toEqual('1');
expect(div.dataset.index).toEqual('1');
expect(div.getAttribute('class')).toEqual('container');
Expand All @@ -39,7 +39,7 @@ describe('Set element attribute/property/event handler', () => {
},
];
const parent1 = document.createElement('div');
commitAttributes(parent1, parent1Attrs, true);
commitAttributes(parent1, parent1Attrs, { isInitial: true });

// Parent2 element
const parent2ClickHandler = jest.fn().mockImplementation(() => {
Expand All @@ -57,7 +57,7 @@ describe('Set element attribute/property/event handler', () => {
},
];
const parent2 = document.createElement('div');
commitAttributes(parent2, parent2Attrs, true);
commitAttributes(parent2, parent2Attrs, { isInitial: true });

const childClickHandler = jest.fn().mockImplementation(() => {
parent1ClickState = 'child clicked';
Expand All @@ -70,7 +70,7 @@ describe('Set element attribute/property/event handler', () => {
},
];
const child = document.createElement('div');
commitAttributes(child, childAttrs, true);
commitAttributes(child, childAttrs, { isInitial: true });

document.body.appendChild(parent1);
document.body.appendChild(parent2);
Expand Down Expand Up @@ -113,7 +113,7 @@ describe('Set element attribute/property/event handler', () => {
},
];

commitAttributes(customElement, attrs, true);
commitAttributes(customElement, attrs, { isInitial: true });

expect(customElement.getAttribute('data-index')).toEqual('1');
expect(customElement.dataset.index).toEqual('1');
Expand All @@ -133,11 +133,23 @@ describe('Set element attribute/property/event handler', () => {
capture: true,
}
];
commitAttributes(div, attrs, true);
commitAttributes(div, attrs, { isInitial: true });
div.click();
expect(mockClickHandler).toBeCalledTimes(1);
commitAttributes(div, attrs, false);
commitAttributes(div, attrs);
div.click();
expect(mockClickHandler).toBeCalledTimes(2);
});

it('Svg elements should be set as attributes', () => {
const svg = document.createElement('svg');
const attrs = [{
name: 'width',
value: '200'
}];

commitAttributes(svg, attrs, { isInitial: true });

expect(svg.getAttribute('width')).toEqual('200');
});
});
15 changes: 14 additions & 1 deletion packages/pwc/src/elements/commitAttributes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@ import type { Attributes, PWCElement } from '../type';
import { isFunction, toRaw } from '../utils';
import { warning } from '../error';

export function commitAttributes(element: Element, attrs: Attributes, isInitial, rootElement?: PWCElement) {
export function commitAttributes(element: Element, attrs: Attributes, opt?: {
isInitial?: boolean;
rootElement?: PWCElement;
isSVG?: boolean;
}) {
const {
isInitial = false,
isSVG = false,
rootElement,
} = opt || {};
for (const attr of attrs) {
const { name, value } = attr;
if (isEventName(name)) {
Expand All @@ -21,6 +30,10 @@ export function commitAttributes(element: Element, attrs: Attributes, isInitial,
// If capture is true, the event should be triggered when capture stage
// Bind the rootElement to ensure the handler context is the element itself
element.addEventListener(eventName, value.bind(rootElement), capture);
} else if (isSVG) {
// https://svgwg.org/svg2-draft/struct.html#InterfaceSVGSVGElement
// Svg elements must be set as attributes, all properties is read only
element.setAttribute(name, value);
} else if (name in element) {
// Verify that there is a target property on the element
element[name] = toRaw(value);
Expand Down
8 changes: 7 additions & 1 deletion packages/pwc/src/elements/reactiveNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ export class AttributedNode implements ReactiveNode {
#el: Element;
#root: PWCElement;
#elIsCustom: boolean;
#elIsSvg: boolean;

constructor(commentNode: Comment, initialAttrs: Attributes, rootNode: PWCElement) {
this.#el = commentNode.nextSibling as Element;
this.#root = rootNode;
this.#elIsCustom = Boolean(window.customElements.get(this.#el.localName));
this.#elIsSvg = this.#el instanceof SVGElement;
this.#commitAttributes(initialAttrs, true);
}

Expand All @@ -41,6 +43,10 @@ export class AttributedNode implements ReactiveNode {
}

#commitAttributes(value: Attributes, isInitial = false) {
commitAttributes(this.#el, value, isInitial, this.#root);
commitAttributes(this.#el, value, {
isInitial,
isSVG: this.#elIsSvg,
rootElement: this.#root,
});
}
}

0 comments on commit 9e2bc7d

Please sign in to comment.