Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support svg elements #60

Merged
merged 2 commits into from
Apr 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
});
}
}