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: add a Themes support #2

Merged
merged 1 commit into from
Nov 15, 2023
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
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
Loading