Skip to content

Commit

Permalink
Changed method of compilation to return a single class name
Browse files Browse the repository at this point in the history
  • Loading branch information
drozdzynski committed Oct 20, 2023
1 parent 7cd1cea commit 35287d1
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 57 deletions.
2 changes: 2 additions & 0 deletions packages/core/src/constructor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ describe('keyframes', () => {
css: `@keyframes teiler-keyframes-1ep7axc { from { background-color: red; } to { background-color: green; } }`,
id: '1ep7axc',
name: 'teiler-keyframes-1ep7axc',
type: 'keyframes',
})
})

Expand All @@ -109,6 +110,7 @@ describe('keyframes', () => {
css: '@keyframes teiler-keyframes-14uknit { from { background-color: yellow; } to { background-color: red; } }',
id: '14uknit',
name: 'teiler-keyframes-14uknit',
type: 'keyframes',
})
})
})
55 changes: 43 additions & 12 deletions packages/core/src/constructor.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import type { Sheet } from './sheet'

import { compile, stylis } from './css'
import { compile, transpile } from './css'
import hash from './hash'

type Expression<Props> = (props: Props) => string | boolean
type StyleDefinition = {
id: string
name: string
css: string
type: 'component' | 'global' | 'keyframes'
}
type Raw = string | number
type Properties<Props> = Expression<Props> | StyleDefinition | Raw
Expand Down Expand Up @@ -42,29 +44,58 @@ function styled<Props, Type extends TeilerComponent<Target, Props>>(

type Compile = <Props>(sheet: Sheet, styles: Array<Style<Props>>, props: Props) => string[] | void

function insert(sheet: Sheet, definitions: StyleDefinition[]): string[] {
return definitions.reduce<string[]>((classes, { id, name, css, type }) => {
if (type === 'component') {
const result = transpile(`.${name} { ${css} }`).join(' ')
sheet.insert(id, result)

classes = [...classes, name]
} else {
const result = transpile(css).join(' ')
sheet.insert(id, result)
}

return classes;
}, [])
}

function component<Props>(sheet: Sheet, styles: Array<Style<Props>>, props: Props): string[] {
return compile(styles, props).map(({ id, name, css }) => {
const result = stylis(`.${name} { ${css} }`).join(' ')
sheet.insert(id, result)
const {css, definitions} = compile(styles, props)

return name
})
const id = hash(css)
const definition: StyleDefinition = {
id: id,
name: 'teiler-' + id,
css,
type: 'component'
}

return insert(sheet, [...definitions, definition])
}

function global<Props>(sheet: Sheet, styles: Array<Style<Props>>, props: Props): void {
compile(styles, props).map(({ id, css }) => {
const result = stylis(css).join(' ')
sheet.insert(id, result)
})
const {css, definitions} = compile(styles, props)

const id = hash(css)
const definition: StyleDefinition = {
id: id,
name: 'teiler-' + id,
css,
type: 'global'
}

insert(sheet, [...definitions, definition])
}

function keyframes(strings: ReadonlyArray<string>, ...properties: Raw[]): StyleDefinition {
const style: Style<{}> = [Array.from(strings), properties]

const [{ id, css }] = compile([style], {})
const { css } = compile([style], {})
const id = hash(css)
const name = `teiler-keyframes-${id}`

return { id, name, css: `@keyframes ${name} { ${css} }` }
return { id, name, css: `@keyframes ${name} { ${css} }`, type: 'keyframes' }
}

export type { Compile, Properties, Sheet, Style, StyleDefinition, TeilerComponent, Target }
Expand Down
31 changes: 14 additions & 17 deletions packages/core/src/css.test.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { describe, expect, test } from '@jest/globals'
import { compile, stylis } from './css'
import { Style } from '.'
import { compile, transpile } from './css'
import { Style, StyleDefinition } from '.'

describe('stylis', () => {
describe('transpile', () => {
test('should return an empty array if the CSS string is empty', () => {
const css = ''
const results = stylis(css)
const results = transpile(css)
expect(results).toHaveLength(0)
})

test('should return an array of CSS strings with comments removed', () => {
const css = '/* This is a comment */ p { color: red; } /* This is another comment */'
const results = stylis(css)
const results = transpile(css)
expect(results).toHaveLength(1)
expect(results.at(0)).toBe('p{color:red;}')
})

test('should return button with hover from nasted selector ', () => {
const css = 'button { color: blue; &:hover: { color: red; } }'
const results = stylis(css)
const results = transpile(css)
expect(results).toHaveLength(2)
expect(results).toEqual(['button{color:blue;}', 'button:hover:{color:red;}'])
})
Expand All @@ -29,7 +29,7 @@ describe('compile', () => {
const style: Style<{}> = [['color: blue;'], []]
const compiled = compile<{}>([style], {})

expect(compiled).toEqual([{ id: '1r77qux', name: 'teiler-1r77qux', css: 'color: blue;' }])
expect(compiled).toEqual({ css: 'color: blue;', definitions: [] })
})

test('with props', () => {
Expand All @@ -38,26 +38,23 @@ describe('compile', () => {
const style: Style<Props> = [['color: ', ';'], [({ color }) => color]]
const compiled = compile<Props>([style], { color: 'red' })

expect(compiled).toEqual([{ id: 'wq229y', name: 'teiler-wq229y', css: 'color: red;' }])
expect(compiled).toEqual({ css: 'color: red;', definitions: [] })
})

test('with object', () => {
const keyframes = {
const keyframes: StyleDefinition = {
css: '@keyframes test { from { background-color: yellow; } to { background-color: red; } }',
id: '14uknit',
name: 'teiler-keyframes-14uknit',
type: 'keyframes',
}

const style: Style<{}> = [['animation: ', ' 5s;'], [keyframes]]
const compiled = compile<{}>([style], {})

expect(compiled).toEqual([
keyframes,
{
id: 'd18jjz',
name: 'teiler-d18jjz',
css: 'animation: teiler-keyframes-14uknit 5s;',
},
])
expect(compiled).toEqual({
css: 'animation: teiler-keyframes-14uknit 5s;',
definitions: [keyframes],
})
})
})
41 changes: 19 additions & 22 deletions packages/core/src/css.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,49 @@
import type { Style, StyleDefinition } from '.'

import { middleware, prefixer, rulesheet, serialize, stringify, compile as stylisCompile } from 'stylis'
import hash from './hash'

const isFalsish = (chunk: unknown): chunk is undefined | null | false | '' => chunk === undefined || chunk === null || chunk === false || chunk === ''

function compile<Props>(styles: Array<Style<Props>>, props: Props): StyleDefinition[] {
return styles.reduce((styles: StyleDefinition[], [strings, properties]) => {
type CompileResult = {
css: string,
definitions: StyleDefinition[]
}

function compile<Props>(styles: Array<Style<Props>>, props: Props): CompileResult {
return styles.reduce<CompileResult>((result, [strings, properties]) => {
const compiled = strings
.reduce((acc, strings, index) => {
acc = [...acc, strings]

const property = properties.at(index)

if (property) {
let result = null
let value = null
if (typeof property === 'function') {
result = property(props)
value = property(props)
} else if (typeof property === 'object') {
styles = [...styles, property]
result = property.name
result.definitions = [...result.definitions, property]
value = property.name
} else {
result = property
value = property
}

if (isFalsish(result) === false) {
acc = [...acc, result]
if (isFalsish(value) === false) {
acc = [...acc, value]
}
}

return acc
}, [])
.join('')

const id = hash(compiled)
const name = `teiler-${id}`

const definition = {
id,
name,
css: compiled,
}
result.css = result.css + compiled;

return [...styles, definition]
}, [])
return result
}, {css: '', definitions: []})
}

function stylis(css: string): string[] {
function transpile(css: string): string[] {
const results = []

serialize(
Expand All @@ -63,4 +60,4 @@ function stylis(css: string): string[] {
return results
}

export { stylis, compile }
export { transpile, compile }
4 changes: 0 additions & 4 deletions packages/svelte/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ import tags from './tags'

type SvelteTeilerComponent<Target, Props> = TeilerComponent<Target, Props> & ComponentType<SvelteComponent>

let componentsIds = 0
const createComponent = <Target, Props>(compile: Compile, tag: Target, styles: Array<Style<Props>>): SvelteTeilerComponent<Target, Props> => {
const componentId = componentsIds++;
console.log('create component', componentId)

return class extends Styled {
static styles = styles
static tag = tag
Expand Down
1 change: 0 additions & 1 deletion packages/svelte/stories/Component.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<script lang="ts">
import { Component, ExtendedComponent } from './component'
// import teiler from '@teiler/svelte'
import { createEventDispatcher } from 'svelte'
export let _primary = false
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte/stories/Palette.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@
<Button {_primary} {_size} {_primaryColor} {disabled} on:click={onClick}>
{label}
</Button>
<ExtendedButton {_primary} {_size} {_primaryColor}>Test</ExtendedButton>
<ExtendedButton {_primary} {_size} {_primaryColor} {disabled}>Test</ExtendedButton>

0 comments on commit 35287d1

Please sign in to comment.