Skip to content

Commit

Permalink
feat: rewrite HTML tags, modify svelte exports
Browse files Browse the repository at this point in the history
  • Loading branch information
drozdzynski committed Nov 15, 2023
1 parent f0f49b3 commit 4627990
Show file tree
Hide file tree
Showing 12 changed files with 95 additions and 233 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Join our community on our [Discord Server](https://discord.gg/J6Sv9sQ64t) to sta
### Example

```typescript
import component from '@teiler/svelte'
import { component } from '@teiler/svelte'

const Button = component.button<{
_primary: boolean
Expand Down Expand Up @@ -50,7 +50,7 @@ These are the frameworks we are currently working on and planning to support in
## Keyframes

```typescript
import component, { keyframes } from '@teiler/svelte'
import { component, keyframes } from '@teiler/svelte'

const bouncing = keyframes`
from, 20%, 53%, 80%, to {
Expand Down Expand Up @@ -106,7 +106,7 @@ Example how to use themes.
</ThemeProvider>

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

const Component = component.div`
color: ${({ theme }) => theme.fontColor};
Expand Down
15 changes: 7 additions & 8 deletions packages/core/src/constructor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Sheet } from './sheet'
import type { HTMLElements } from './tags'

import { compile, transpile } from './css'
import hash from './hash'
Expand All @@ -20,27 +21,25 @@ type Raw = string | number
type Properties<Props> = Expression<Props> | StyleDefinition | Raw
type Style<Props> = [string[], Properties<Props>[]]

type Target = string

type TeilerComponent<Target, Props> = {
styles: Array<Style<Props>>
tag: Target
}

type CreateCallback<Props, Type extends TeilerComponent<Target, Props>> = (styles: Array<Style<Props>>) => Type
type ExtendCallback<Props, Type extends TeilerComponent<Target, Props>> = (string: ReadonlyArray<string>, ...properties: Properties<Props>[]) => Type
type CreateCallback<Props, Type extends TeilerComponent<HTMLElements, Props>> = (styles: Array<Style<Props>>) => Type
type ExtendCallback<Props, Type extends TeilerComponent<HTMLElements, Props>> = (string: ReadonlyArray<string>, ...properties: Properties<Props>[]) => Type

function styled<Props, Type extends TeilerComponent<Target, Props>>(
function styled<Props, Type extends TeilerComponent<HTMLElements, Props>>(
createComponent: CreateCallback<Props, Type>,
stringOrBinded: TeilerComponent<Target, Props> | ReadonlyArray<string>,
stringOrBinded: TeilerComponent<HTMLElements, Props> | ReadonlyArray<string>,
...properties: Properties<Props>[]
): ExtendCallback<Props, Type> | Type {
if (Array.isArray(stringOrBinded)) {
const strings = stringOrBinded as ReadonlyArray<string>
const style: Style<Props> = [Array.from(strings), properties]
return createComponent([style])
} else {
const binded = stringOrBinded as TeilerComponent<Target, Props>
const binded = stringOrBinded as TeilerComponent<HTMLElements, Props>
return (strings: ReadonlyArray<string>, ...properties: Expression<Props>[]) => {
const style: Style<Props> = [Array.from(strings), properties]
return createComponent([...binded.styles, style])
Expand Down Expand Up @@ -104,5 +103,5 @@ function keyframes(strings: ReadonlyArray<string>, ...properties: Raw[]): StyleD
return { id, name, css: `@keyframes ${name} { ${css} }`, type: 'keyframes' }
}

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

export { default as tags } from './tags'
export { default as createStyleSheet } from './sheet'
export { pattern, sew } from './pattern'
export { component, global, keyframes, styled } from './constructor'
19 changes: 10 additions & 9 deletions packages/core/src/pattern.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import type { Compile, Properties, Style, Target, TeilerComponent } from './constructor'
import type { Compile, Properties, Style, TeilerComponent } from './constructor'
import type { HTMLElements } from './tags'

import { component, global } from './constructor'
import tags from './tags'

type Pattern<Target, Props> = { styles: Style<Props>[]; tag: Target; __teiler__: true }
type ExtendCallback<Target, Props> = <Component>(string: ReadonlyArray<string>, ...properties: Properties<Inter<Component, Props>>[]) => Pattern<Target, Inter<Component, Props>>
type Pattern<Target extends HTMLElements, Props> = { styles: Style<Props>[]; tag: Target; __teiler__: true }
type ExtendCallback<Target extends HTMLElements, Props> = <Component>(string: ReadonlyArray<string>, ...properties: Properties<Inter<Component, Props>>[]) => Pattern<Target, Inter<Component, Props>>

type Constructor<Target> = {
type Constructor<Target extends HTMLElements> = {
<Props>(pattern: Pattern<Target, Props>): ExtendCallback<Target, Props>
<Props>(string: ReadonlyArray<string>, ...properties: Properties<Props>[]): Pattern<Target, Props>
}

type ConstructorWithTags = Constructor<'div'> & { [K in (typeof tags)[number]]: Constructor<K> } & { global: Constructor<null> }
type ConstructorWithTags = Constructor<'div'> & { [K in HTMLElements]: Constructor<K> } & { global: Constructor<null> }

type Inter<Component, Props> = Component extends Pattern<Target, infer P> ? P & Props : Props
type Inter<Component, Props> = Component extends Pattern<HTMLElements, infer P> ? P & Props : Props

const construct = (tag: string) => {
return <Props>(stringOrPattern: Pattern<Target, Props> | ReadonlyArray<string>, ...properties: Properties<Props>[]): Pattern<Target, Props> | ExtendCallback<Target, Props> => {
const construct = (tag: HTMLElements) => {
return <Props>(stringOrPattern: Pattern<HTMLElements, Props> | ReadonlyArray<string>, ...properties: Properties<Props>[]): Pattern<HTMLElements, Props> | ExtendCallback<HTMLElements, Props> => {
if ('__teiler__' in stringOrPattern) {
return <Component>(strings: ReadonlyArray<string>, ...properties: Properties<Inter<Component, Props>>[]) => {
const style: Style<Props> = [Array.from(strings), properties]
Expand All @@ -42,7 +43,7 @@ const binded = pattern as ConstructorWithTags

type CreateFunction<Target, Props, Type extends TeilerComponent<Target, Props>> = (compile: Compile, tag: Target, styles: Array<Style<Props>>) => Type

function sew<Target, Props, Type extends TeilerComponent<Target, Props>>(pattern: Pattern<Target, Props>, createComponent: CreateFunction<Target, Props, Type>): Type {
function sew<Target extends HTMLElements, Props, Type extends TeilerComponent<Target, Props>>(pattern: Pattern<Target, Props>, createComponent: CreateFunction<Target, Props, Type>): Type {
const compiler = pattern.tag === null ? global : component
return createComponent(compiler, pattern.tag, pattern.styles)
}
Expand Down
16 changes: 7 additions & 9 deletions packages/core/src/tags.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const tags = [
const elements = [
'a',
'abbr',
'address',
Expand Down Expand Up @@ -44,7 +44,6 @@ const tags = [
'h4',
'h5',
'h6',
'head',
'header',
'hgroup',
'hr',
Expand All @@ -63,7 +62,6 @@ const tags = [
'main',
'map',
'mark',
'marquee',
'menu',
'menuitem',
'meta',
Expand Down Expand Up @@ -105,16 +103,14 @@ const tags = [
'th',
'thead',
'time',
'title',
'tr',
'track',
'u',
'ul',
'use',
'var',
'video',
'wbr',

// SVG
'wbr', // SVG
'circle',
'clipPath',
'defs',
Expand All @@ -124,6 +120,7 @@ const tags = [
'image',
'line',
'linearGradient',
'marker',
'mask',
'path',
'pattern',
Expand All @@ -135,6 +132,7 @@ const tags = [
'svg',
'text',
'tspan',
] as const
] as const;

export default tags
export default new Set(elements);
export type HTMLElements = (typeof elements)[number];
59 changes: 59 additions & 0 deletions packages/svelte/src/component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import type { Compile, HTMLElements, Properties, Style, TeilerComponent } from '@teiler/core'
import type { ComponentType, SvelteComponent } from 'svelte'

import { component, global, keyframes, styled, tags } from '@teiler/core'
import Styled from './Styled.svelte'

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

const createComponent = <Target extends HTMLElements, Props>(compile: Compile, tag: Target, styles: Array<Style<Props>>): SvelteTeilerComponent<Target, Props> => {
return class extends Styled {
static styles = styles
static tag = tag

constructor(options) {
super({
...options,
props: {
...options.props,
compile,
tag,
styles,
},
})
}
}
}

type InferProps<Component, Props> = Component extends SvelteTeilerComponent<HTMLElements, infer P> ? P & Props : Props
type InferComponent<Component, Props> = Component extends SvelteTeilerComponent<infer E, infer P> ? SvelteTeilerComponent<E, Props & P> : SvelteTeilerComponent<HTMLElements, Props>

type Component<Target extends HTMLElements> = {
<Props extends object = {}>(string: TemplateStringsArray, ...properties: Properties<Props>[]): SvelteTeilerComponent<Target, Props>
<Component>(binded: Component): <Props extends object = {}>(string: TemplateStringsArray, ...properties: Properties<InferProps<Component, Props>>[]) => InferComponent<Component, Props>
}

type Global = {
<Props extends object = {}>(string: TemplateStringsArray, ...properties: Properties<Props>[]): SvelteTeilerComponent<unknown, Props>
}

type ComponentWithTags = Component<'div'> & { [K in HTMLElements]: Component<K> }

const construct = <Target extends HTMLElements>(tag: Target, compile: Compile) => {
return <Props extends object = {}>(stringOrBinded: TeilerComponent<Target, Props> | TemplateStringsArray, ...properties: Properties<Props>[]) => {
const binded = createComponent.bind(null, compile, (stringOrBinded as TeilerComponent<Target, Props>).tag || tag)
return styled<Props, SvelteTeilerComponent<Target, Props>>(binded, stringOrBinded, ...properties)
}
}

const baseComponent = construct('div', component)

tags.forEach((tag) => {
baseComponent[tag] = construct(tag, component)
})

const svelteComponent = baseComponent as ComponentWithTags

const svelteGlobal = construct(null, global) as Global

export { svelteComponent as component, svelteGlobal as global, keyframes, createComponent }
61 changes: 2 additions & 59 deletions packages/svelte/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,2 @@
import type { Compile, Properties, Style, Target, TeilerComponent } from '@teiler/core'
import type { ComponentType, SvelteComponent } from 'svelte'

import { component, global, keyframes, styled } from '@teiler/core'
import Styled from './Styled.svelte'
import tags from './tags'

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

const createComponent = <Target, Props>(compile: Compile, tag: Target, styles: Array<Style<Props>>): SvelteTeilerComponent<Target, Props> => {
return class extends Styled {
static styles = styles
static tag = tag

constructor(options) {
super({
...options,
props: {
...options.props,
compile,
tag,
styles,
},
})
}
}
}

type InferProps<Component, Props> = Component extends SvelteTeilerComponent<Target, infer P> ? P & Props : Props
type InferComponent<Component, Props> = Component extends SvelteTeilerComponent<infer E, infer P> ? SvelteTeilerComponent<E, Props & P> : SvelteTeilerComponent<Target, Props>

type Component<Target> = {
<Props extends object = {}>(string: TemplateStringsArray, ...properties: Properties<Props>[]): SvelteTeilerComponent<Target, Props>
<Component>(binded: Component): <Props extends object = {}>(string: TemplateStringsArray, ...properties: Properties<InferProps<Component, Props>>[]) => InferComponent<Component, Props>
}

type Global = {
<Props extends object = {}>(string: TemplateStringsArray, ...properties: Properties<Props>[]): SvelteTeilerComponent<unknown, Props>
}

type ComponentWithTags = Component<'div'> & { [K in (typeof tags)[number]]: Component<K> }

const construct = (tag: string, compile: Compile) => {
return <Props extends object = {}>(stringOrBinded: TeilerComponent<Target, Props> | TemplateStringsArray, ...properties: Properties<Props>[]) => {
const binded = createComponent.bind(null, compile, (stringOrBinded as TeilerComponent<Target, Props>).tag || tag)
return styled<Props, SvelteTeilerComponent<Target, Props>>(binded, stringOrBinded, ...properties)
}
}

const svelteComponent = construct('div', component)

tags.forEach((tag) => {
svelteComponent[tag] = construct(tag, component)
})

const svelteGlobal = construct(null, global) as Global

export { svelteGlobal as global, keyframes, createComponent }
export default svelteComponent as ComponentWithTags
export { component, global, keyframes, createComponent } from './component'
export { default as ThemeProvider } from './ThemeProvider.svelte'
Loading

0 comments on commit 4627990

Please sign in to comment.