Skip to content

Commit

Permalink
feat: add a Themes support (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
drozdzynski authored Nov 15, 2023
1 parent 341f896 commit 9a8a884
Show file tree
Hide file tree
Showing 13 changed files with 141 additions and 14 deletions.
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,49 @@ const Button = component.button<{}>`
`
```

## Theme

Example how to use themes.

```typescript
// Main component inside application (`App.svelte`)
<script context="module" lang="ts">
export type CustomTheme = {
fontColor: string,
}
</script>
<script lang="ts">
import ThemeProvider from '../src/ThemeProvider.svelte'
import { Component } from './theme'

export let theme: CustomTheme = {
fontColor: 'red',
}
</script>

<ThemeProvider {theme}>
<Component>Some test text</Component>
</ThemeProvider>

// Component with theme usage
import component from '@teiler/svelte'

const Component = component.div`
color: ${({ theme }) => theme.fontColor};
`

export { Component }
```

To add typing for Typescript applications you need to add `extend` inside declaration file (`d.ts`)
```typescript
import type { CustomTheme } from "./App.svelte";

declare module '@teiler/core' {
export interface DefaultTheme extends CustomTheme {}
}
```

## Sew a Pattern

This tool simplifies the creation of consistent and reusable visual styles for components across various web frameworks. It provides a pattern-based approach, where patterns serve as blueprints for defining the visual style of components.
Expand Down
10 changes: 5 additions & 5 deletions packages/core/src/constructor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,18 @@ describe('component', () => {
const styleSheet = createStyleSheet({})
const test = jest.fn(component)

test(styleSheet, [[['color: red;'], []]], [])
test(styleSheet, [[['color: red;'], []]], {})

expect(test).toHaveReturnedWith(['teiler-wq229y'])
})

test('should create style from styles with props', () => {
const styleSheet = createStyleSheet({})
const test = jest.fn(component)
const test = jest.fn(component<{ color: string }>)

test(styleSheet, [[['color: ', ';'], [({ color }) => color]]], [{ color: 'red' }])
test(styleSheet, [[['color: ', ';'], [({ color }) => color]]], { color: 'blue' })

expect(test).toHaveReturnedWith(['teiler-10upe3l'])
expect(test).toHaveReturnedWith(['teiler-1r77qux'])
})
})

Expand All @@ -77,7 +77,7 @@ describe('global', () => {

test('should create style from styles with props', () => {
const styleSheet = createStyleSheet({})
const test = jest.fn(global)
const test = jest.fn(global<{ color: string }>)

test(styleSheet, [[['body { color: ', '; }'], [({ color }) => color]]], { color: 'blue' })

Expand Down
14 changes: 10 additions & 4 deletions packages/core/src/constructor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import type { Sheet } from './sheet'
import { compile, transpile } from './css'
import hash from './hash'

type Expression<Props> = (props: Props) => string | boolean
type DefaultTheme = {[key: string]: string | boolean}

type Arguments<Props> = {
theme?: DefaultTheme
} & Props

type Expression<Props> = (props: Arguments<Props>) => string | boolean
type StyleDefinition = {
id: string
name: string
Expand Down Expand Up @@ -60,7 +66,7 @@ function insert(sheet: Sheet, definitions: StyleDefinition[]): string[] {
}, [])
}

function component<Props>(sheet: Sheet, styles: Array<Style<Props>>, props: Props): string[] {
function component<Props>(sheet: Sheet, styles: Array<Style<Props>>, props: Arguments<Props>): string[] {
const {css, definitions} = compile(styles, props)

const id = hash(css)
Expand All @@ -74,7 +80,7 @@ function component<Props>(sheet: Sheet, styles: Array<Style<Props>>, props: Prop
return insert(sheet, [...definitions, definition])
}

function global<Props>(sheet: Sheet, styles: Array<Style<Props>>, props: Props): void {
function global<Props>(sheet: Sheet, styles: Array<Style<Props>>, props: Arguments<Props>): void {
const {css, definitions} = compile(styles, props)

const id = hash(css)
Expand All @@ -98,5 +104,5 @@ function keyframes(strings: ReadonlyArray<string>, ...properties: Raw[]): StyleD
return { id, name, css: `@keyframes ${name} { ${css} }`, type: 'keyframes' }
}

export type { Compile, Properties, Sheet, Style, StyleDefinition, TeilerComponent, Target }
export type { Arguments, Compile, DefaultTheme, Properties, Sheet, Style, StyleDefinition, TeilerComponent, Target }
export { keyframes, component, global, styled }
3 changes: 2 additions & 1 deletion packages/core/src/css.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Arguments } from './constructor'
import type { Style, StyleDefinition } from '.'

import { middleware, prefixer, rulesheet, serialize, stringify, compile as stylisCompile } from 'stylis'
Expand All @@ -9,7 +10,7 @@ type CompileResult = {
definitions: StyleDefinition[]
}

function compile<Props>(styles: Array<Style<Props>>, props: Props): CompileResult {
function compile<Props>(styles: Array<Style<Props>>, props: Arguments<Props>): CompileResult {
return styles.reduce<CompileResult>((result, [strings, properties]) => {
const compiled = strings
.reduce((acc, strings, index) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type { Compile, Properties, Sheet, Style, StyleDefinition, TeilerComponent, Target } from './constructor'
export type { Compile, DefaultTheme, Properties, Sheet, Style, StyleDefinition, TeilerComponent, Target } from './constructor'

export { default as createStyleSheet } from './sheet'
export { pattern, sew } from './pattern'
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/pattern.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe('pattern', () => {
})

test('should create a pattern with params', () => {
const button = pattern.button`background: ${({ color }) => color};`
const button = pattern.button<{color: string}>`background: ${({ color }) => color};`
expect(button).toMatchObject({
styles: [[['background: ', ';'], [expect.any(Function)]]],
tag: 'button',
Expand Down
6 changes: 5 additions & 1 deletion packages/svelte/src/Styled.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<script lang="ts">
import { type Style, type Compile, type Sheet } from '@teiler/core'
import { getStyleSheet } from './sheet'
import { getContext } from 'svelte'
import { context } from './ThemeProvider.svelte'
export let tag: string = 'div'
Expand All @@ -9,7 +11,9 @@
const sheet: Sheet = getStyleSheet()
$: classes = compile(sheet, styles, $$restProps) as string[]
const theme = getContext(context);
$: classes = compile(sheet, styles, {...$$restProps, theme}) as string[]
$: filtredPropsEntries = Object.entries($$restProps).filter(([key, _value]) => key[0] !== "_")
$: filtredProps = Object.fromEntries(filtredPropsEntries)
Expand Down
14 changes: 14 additions & 0 deletions packages/svelte/src/ThemeProvider.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script context="module">
export const context = 'THEME'
</script>

<script lang="ts">
import type { DefaultTheme } from '@teiler/core'
import { setContext } from 'svelte'
export let theme: DefaultTheme
setContext<DefaultTheme>(context, theme)
</script>

<slot />
29 changes: 29 additions & 0 deletions packages/svelte/stories/Theme.stories.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script lang="ts">
import { Meta, Template, Story } from "@storybook/addon-svelte-csf";
import Theme from "./Theme.svelte";
</script>

<Meta
title="Svelte/Theme"
component={Theme}
argTypes={{
label: { control: "text" },
}}
/>

<Template let:args>
<Theme {...args} on:click={args.onClick} />
</Template>

<Story
name="Default"
/>

<Story
name="Provide options"
args={{
theme: {
fontColor: 'green',
}
}}
/>
17 changes: 17 additions & 0 deletions packages/svelte/stories/Theme.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script context="module" lang="ts">
export type CustomTheme = {
fontColor: string,
}
</script>
<script lang="ts">
import ThemeProvider from '../src/ThemeProvider.svelte'
import { Component } from './theme'
export let theme: CustomTheme = {
fontColor: 'red',
}
</script>

<ThemeProvider {theme}>
<Component>Some test text</Component>
</ThemeProvider>
5 changes: 5 additions & 0 deletions packages/svelte/stories/stories.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { CustomTheme } from "./Theme.svelte";

declare module '@teiler/core' {
export interface DefaultTheme extends CustomTheme {}
}
7 changes: 7 additions & 0 deletions packages/svelte/stories/theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import component from '@teiler/svelte'

const Component = component.div`
color: ${({ theme }) => theme.fontColor};
`

export { Component }
3 changes: 2 additions & 1 deletion packages/svelte/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"include": [
"src/**/*"
"src/**/*",
"stories/stories.d.ts"
],
"exclude": [
"node_modules"
Expand Down

0 comments on commit 9a8a884

Please sign in to comment.