Skip to content

Commit

Permalink
fiber: add utils/withContext
Browse files Browse the repository at this point in the history
a utility function to wrap children in context without having to use JSX.

see solidjs-community/solid-primitives#464
  • Loading branch information
bigmistqke committed Jul 19, 2023
1 parent c034bd7 commit ba231d3
Showing 1 changed file with 92 additions and 0 deletions.
92 changes: 92 additions & 0 deletions packages/fiber/src/utils/withContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { Accessor, Context, JSX } from 'solid-js'

export type ContextProviderProps = {
children?: JSX.Element
} & Record<string, unknown>
export type ContextProvider<T extends ContextProviderProps> = (props: { children: JSX.Element } & T) => JSX.Element
/**
* A utility-function to provide context to components.
*
* @param children Accessor of Children
* @param context Context<T>
* @param value T
*
* @example
* ```tsx
* const NumberContext = createContext<number>
*
* const children = withContext(
* () => props.children,
* NumberContext,
* 1
* )
* ```
*/

export function withContext<T>(children: Accessor<JSX.Element | JSX.Element[]>, context: Context<T>, value: T) {
let result: JSX.Element | JSX.Element[]

context.Provider({
value,
children: (() => {
result = children()
return ''
}) as any as JSX.Element,
})

return () => result
}

/*
Type validation of the `values` array thanks to the amazing @otonashixav (https://github.com/otonashixav)
*/

/**
* A utility-function to provide multiple context to components.
*
* @param children Accessor of Children
* @param values Array of tuples of `[Context<T>, value T]`.
*
* @example
* ```tsx
* const NumberContext = createContext<number>
* const StringContext = createContext<string>
* const children = withContext(
* () => props.children,
* [
* [NumberContext, 1],
* [StringContext, "string"]
* ]
* )
* ```
*/

export function withMultiContexts<T extends readonly [unknown?, ...unknown[]]>(
children: Accessor<JSX.Element | JSX.Element[]>,
values: {
[K in keyof T]: readonly [Context<T[K]>, [T[K]][T extends unknown ? 0 : never]]
},
) {
let result: JSX.Element | JSX.Element[]

const fn = (index: number) => {
const [context, value] = values[index]!
context.Provider({
value,
children: (() => {
if (index < values.length - 1) {
fn(index + 1)
} else {
result = children()
}
return ''
}) as any as JSX.Element,
})
}

fn(0)

return () => result
}

0 comments on commit ba231d3

Please sign in to comment.