creates video voice memos from audio clips; with bluesky integration.
trill.ptr.pet
1import { type JSX, createContext, useContext } from 'solid-js'
2import { Dynamic } from 'solid-js/web'
3import { cx } from 'styled-system/css'
4import { isCssProperty, styled } from 'styled-system/jsx'
5import type { ElementType, StyledComponent } from 'styled-system/types'
6
7type Props = Record<string, unknown>
8type Recipe = {
9 (props?: Props): Props
10 splitVariantProps: (props: Props) => [Props, Props]
11}
12
13type Slot<R extends Recipe> = keyof ReturnType<R>
14type Options = { forwardProps?: string[] }
15
16const shouldForwardProp = (prop: string, variantKeys: string[], options: Options = {}) =>
17 options.forwardProps?.includes(prop) || (!variantKeys.includes(prop) && !isCssProperty(prop))
18
19export const createStyleContext = <R extends Recipe>(recipe: R) => {
20 const StyleContext = createContext<Record<Slot<R>, string> | null>(null)
21
22 const withRootProvider = <P extends {}>(Component: ElementType): ((props: P) => JSX.Element) => {
23 const StyledComponent = (props: P) => {
24 const [variantProps, localProps] = recipe.splitVariantProps(props)
25 const slotStyles = recipe(variantProps) as Record<Slot<R>, string>
26
27 return (
28 <StyleContext.Provider value={slotStyles}>
29 <Component {...localProps} />
30 </StyleContext.Provider>
31 )
32 }
33 return StyledComponent
34 }
35
36 const withProvider = <P extends { class?: string }>(
37 Component: ElementType,
38 slot: Slot<R>,
39 options?: Options,
40 ): ((props: P) => JSX.Element) => {
41 const StyledComponent = styled(
42 Component,
43 {},
44 {
45 shouldForwardProp: (prop, variantKeys) => shouldForwardProp(prop, variantKeys, options),
46 },
47 ) as StyledComponent<ElementType>
48
49 return (props: P) => {
50 const [variantProps, localProps] = recipe.splitVariantProps(props)
51 const slotStyles = recipe(variantProps) as Record<Slot<R>, string>
52
53 return (
54 <StyleContext.Provider value={slotStyles}>
55 <Dynamic
56 component={StyledComponent}
57 {...localProps}
58 class={cx(slotStyles?.[slot], props.class)}
59 />
60 </StyleContext.Provider>
61 )
62 }
63 }
64
65 const withContext = <P extends { class?: string }>(
66 Component: ElementType,
67 slot: Slot<R>,
68 ): ((props: P) => JSX.Element) => {
69 const StyledComponent = styled(Component)
70
71 const Foo = (props: P) => {
72 const slotStyles = useContext(StyleContext)
73 return (
74 <Dynamic
75 component={StyledComponent}
76 {...props}
77 class={cx(slotStyles?.[slot], props.class)}
78 />
79 )
80 }
81 return Foo
82 }
83
84 return {
85 withRootProvider,
86 withProvider,
87 withContext,
88 }
89}