diff --git a/README.md b/README.md index 365b483..a4b8ad0 100644 --- a/README.md +++ b/README.md @@ -35,18 +35,16 @@ Simply pass `css` to your [Snabbdom](https://github.com/snabbdom/snabbdom) virtu ``` The **CssModule** is essentially a wrapper around [TypeStyle style](https://typestyle.github.io/#/core/-style-) and accepts the same arguments: Any number of `NestedCssProperties` (or `Style`, which is an alias provided by [snabbdom-typestyle](https://github.com/sklingler93/snabbdom-typestyle)). -Make sure to pass the **CssModule**, along with the **Props** and **Attributes** modules, when initializing [Snabbdom](https://github.com/snabbdom/snabbdom). +Make sure to pass the **CssModule** *before* the **ClassModule** when initializing [Snabbdom](https://github.com/snabbdom/snabbdom). ```js import { init } from 'snabbdom'; - import PropsModule from 'snabbdom/modules/props'; - import AttrsModule from 'snabbdom/modules/attributes'; import CssModule from 'snabbdom-typestyle'; + import ClassModule from 'snabbdom/modules/class'; const modules = [ - PropsModule, - AttrsModule, - CssModule + CssModule, + ClassModule ]; const patch = init(modules); @@ -66,11 +64,8 @@ import modulesForHTML from 'snabbdom-to-html/modules'; import { h } from 'snabbdom'; const modules = [ - modulesForHTML.attributes, - modulesForHTML.props, - modulesForHTML.class, - modulesForHTML.style, - serverSideCssModule + serverSideCssModule, + modulesForHTML.class ]; const patch = init(modules); @@ -87,14 +82,12 @@ Then, on the client-side, pass a selector for the style element rendered by the Doing this avoids duplication of the style element when the application is hydrated. ```js -import PropsModule from 'snabbdom/modules/props'; -import AttrsModule from 'snabbdom/modules/attributes'; import { makeClientSideCssModule } from 'snabbdom-typestyle'; +import ClassModule from 'snabbdom/modules/class'; const modules = [ - PropsModule, - AttrsModule, - makeClientSideCssModule('#styles') + makeClientSideCssModule('#styles'), + ClassModule ]; ``` diff --git a/src/client.ts b/src/client.ts index 79d93a3..b00f38c 100644 --- a/src/client.ts +++ b/src/client.ts @@ -14,10 +14,7 @@ const removeElement = (styleElementSelector: string) => { }; const makeDomUpdater = (styleElementSelector: string | undefined = undefined) => (oldNode: VNode, newNode: VNode): void => { - if (newNode.elm) { - const elm: Element = newNode.elm as Element; - updateVNode(newNode, (name, value) => elm.setAttribute(name, value)); - } + updateVNode(newNode); if (typeof styleElementSelector !== 'undefined') { removeElement(styleElementSelector); diff --git a/src/server.ts b/src/server.ts index 7f48dc3..88c7a82 100644 --- a/src/server.ts +++ b/src/server.ts @@ -6,7 +6,7 @@ import { StyledVNodeData } from './types'; import { updateVNode } from './utils'; export const serverSideCssModule = (node: VNode, attributes: Map): void => - updateVNode(node, (name, value) => attributes.set(name, value)); + updateVNode(node); export const collectStyles = (node: VNode): string => { const instance = createTypeStyle(); diff --git a/src/utils.ts b/src/utils.ts index 504f0f9..0907ee8 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -3,26 +3,12 @@ import { style } from 'typestyle'; import { StyledVNodeData } from './types'; -const makeClassName = (oldClassName: string, newClassName: string): string => { - return `${oldClassName} ${newClassName}`.trim(); -}; - -export const updateVNode = (node: VNode, attributeAccessor: (attribute: string, className: string) => void): void => { - const data: StyledVNodeData = node.data as StyledVNodeData; +export const updateVNode = (vnode: VNode): void => { + const data: StyledVNodeData = vnode.data as StyledVNodeData; if (data.css) { - let previousClassName; - - if (data.props && data.props.className) { - previousClassName = data.props.className; - } else if (node.sel) { - const dotIdx = node.sel.indexOf('.'); - if (dotIdx >= 0) { - previousClassName = node.sel.slice(dotIdx + 1); - } - } - - attributeAccessor('class', makeClassName(previousClassName || '', style(data.css))); + data.class = data.class || {}; + data.class[style(data.css)] = true; } }; diff --git a/test/client.test.ts b/test/client.test.ts index a4b132a..2761042 100644 --- a/test/client.test.ts +++ b/test/client.test.ts @@ -18,14 +18,14 @@ describe('makeModule', () => { it('calls style on create', () => { typestyle.style = jest.fn(typestyle.style); - module.create(mocks.vNodeWithElm(), mocks.vNodeWithElm()); + module.create(mocks.vNode(), mocks.vNode()); expect(typestyle.style.mock.calls.length).toBe(1); }); - it('updates the className on create', () => { - const node = mocks.vNodeWithElm(); - module.create(mocks.vNodeWithElm(), node); - expect(node.elm.class).toBe(mocks.hashedClassName()); + it('updates class on create', () => { + const node = mocks.vNode(); + module.create(mocks.vNode(), node); + expect(node.data.class[mocks.hashedClassName()]).toBe(true); }); it('removes a given style element on create', () => { @@ -33,7 +33,7 @@ describe('makeModule', () => { element.id = mocks.styleElementSelector().replace('#', ''); document.head.appendChild(element); - module.create(mocks.vNodeWithElm(), mocks.vNodeWithElm()); + module.create(mocks.vNode(), mocks.vNode()); expect(document.head.contains(element)).toBe(false); }); }); diff --git a/test/mocks.ts b/test/mocks.ts index b717ea7..5885118 100644 --- a/test/mocks.ts +++ b/test/mocks.ts @@ -2,9 +2,7 @@ import { h } from 'snabbdom'; export const styleElementSelector = () => '#styles'; -export const oldClassName = () => 'oldClassName'; - -export const hashedClassName = () => 'oldClassName f1mb383g'; +export const hashedClassName = () => 'f1mb383g'; export const collectedStyles = () => '.f1jvcvsh{color:red}.f1mb383g{color:blue}'; @@ -12,26 +10,9 @@ export const css = () => ({ color: 'blue' }); -export const blankVNode = () => h('div'); - export const vNode = (alternateCss) => h('div', { - css: alternateCss || css(), - props: { - className: oldClassName() - } - }); - -export const vNodeWithElm = () => { - const node = vNode(); - node.elm = {}; - - node.elm.setAttribute = jest.fn((name, value) => { - node.elm[name] = value; + css: alternateCss || css() }); - - return node; -}; - export const vNodeWithChildren = (childQuantity) => { const node = vNode(); const child = vNode(); diff --git a/test/server.test.ts b/test/server.test.ts index 9825633..1dc9b11 100644 --- a/test/server.test.ts +++ b/test/server.test.ts @@ -2,10 +2,11 @@ import * as server from '../src/server'; import * as mocks from './mocks'; describe('serverSideCssModule', () => { - it('updates the class attribute', () => { + it('updates the class', () => { + const node = mocks.vNode(); const attributes = new Map(); - server.serverSideCssModule(mocks.vNode(), attributes); - expect(attributes.get('class')).toBe(mocks.hashedClassName()); + server.serverSideCssModule(node, attributes); + expect(node.data.class[mocks.hashedClassName()]).toBe(true); }); });