@use-voltra/core 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,40 @@
1
+ import { Context } from 'react'
2
+
3
+ declare module 'react' {
4
+ interface Context<T> {
5
+ _currentValue: T
6
+ }
7
+ }
8
+
9
+ export type ContextRegistry = {
10
+ pushProvider: <T>(context: Context<T>, value: T) => void
11
+ popProvider: <T>(context: Context<T>) => void
12
+ readContext: <T>(context: Context<T>) => T
13
+ }
14
+
15
+ export const getContextRegistry = (): ContextRegistry => {
16
+ const contextMap = new Map()
17
+
18
+ return {
19
+ pushProvider: <T>(context: Context<T>, value: T) => {
20
+ const stack = contextMap.get(context) || []
21
+ stack.push(value)
22
+ contextMap.set(context, stack)
23
+ },
24
+ popProvider: <T>(context: Context<T>) => {
25
+ const stack = contextMap.get(context)
26
+ if (stack) {
27
+ stack.pop()
28
+ }
29
+ },
30
+ readContext: <T>(context: Context<T>) => {
31
+ const stack = contextMap.get(context)
32
+
33
+ if (stack && stack.length > 0) {
34
+ return stack[stack.length - 1]
35
+ }
36
+
37
+ return context._currentValue
38
+ },
39
+ }
40
+ }
@@ -0,0 +1,105 @@
1
+ import React, { Context, ReactDispatcher, ReactHooksDispatcher } from 'react'
2
+
3
+ import { ContextRegistry } from './context-registry.js'
4
+
5
+ const REACT_CONTEXT_TYPE = Symbol.for('react.context')
6
+ const REACT_MEMO_CACHE_SENTINEL = Symbol.for('react.memo_cache_sentinel')
7
+
8
+ declare module 'react' {
9
+ type HookFn = (...args: any[]) => any
10
+
11
+ export type ReactHooksDispatcher = {
12
+ useState: HookFn
13
+ useReducer: HookFn
14
+ useEffect: HookFn
15
+ useLayoutEffect: HookFn
16
+ useInsertionEffect: HookFn
17
+ useCallback: HookFn
18
+ useMemo: HookFn
19
+ useRef: HookFn
20
+ useContext: HookFn
21
+ useId: HookFn
22
+ useImperativeHandle: HookFn
23
+ useDebugValue: HookFn
24
+ useDeferredValue: HookFn
25
+ useTransition: HookFn
26
+ useSyncExternalStore: HookFn
27
+ use: HookFn
28
+ useActionState: HookFn
29
+ useOptimistic: HookFn
30
+ useEffectEvent: HookFn
31
+ useMemoCache: HookFn
32
+ useCacheRefresh: HookFn
33
+ }
34
+
35
+ export type ReactDispatcher = {
36
+ H: ReactHooksDispatcher
37
+ }
38
+
39
+ let __CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE: ReactDispatcher
40
+ }
41
+
42
+ export const getHooksDispatcher = (registry: ContextRegistry): ReactHooksDispatcher => ({
43
+ useContext: <T>(context: Context<T>) => registry.readContext(context),
44
+ use: <T>(usable: React.Usable<T>): T => {
45
+ if (
46
+ usable !== null &&
47
+ typeof usable === 'object' &&
48
+ (usable as { $$typeof?: symbol }).$$typeof === REACT_CONTEXT_TYPE
49
+ ) {
50
+ return registry.readContext(usable as unknown as Context<T>)
51
+ }
52
+
53
+ if (
54
+ usable !== null &&
55
+ (typeof usable === 'object' || typeof usable === 'function') &&
56
+ typeof (usable as { then?: unknown }).then === 'function'
57
+ ) {
58
+ throw new Error(
59
+ 'use() with promises is not supported in Voltra. Async data fetching is not available in this synchronous renderer.'
60
+ )
61
+ }
62
+
63
+ throw new Error(`An unsupported type was passed to use(): ${String(usable)}`)
64
+ },
65
+ useState: <S>(initial?: S | (() => S)) => [
66
+ typeof initial === 'function' ? (initial as () => S)() : initial,
67
+ () => {},
68
+ ],
69
+ useReducer: <S, I, A extends React.AnyActionArg>(
70
+ _: (prevState: S, ...args: A) => S,
71
+ initialArg: I,
72
+ init?: (i: I) => S
73
+ ): [S, React.ActionDispatch<A>] => {
74
+ const state = init ? init(initialArg) : initialArg
75
+ return [state as S, () => {}]
76
+ },
77
+ useMemo: (factory) => factory(),
78
+ useCallback: (cb) => cb,
79
+ useRef: (initial) => ({ current: initial }),
80
+ useEffect: () => {},
81
+ useLayoutEffect: () => {},
82
+ useInsertionEffect: () => {},
83
+ useId: () => Math.random().toString(36).substr(2, 9),
84
+ useDebugValue: () => {},
85
+ useImperativeHandle: () => {},
86
+ useDeferredValue: <T>(value: T) => value,
87
+ useTransition: () => [false, (func: () => void) => func()],
88
+ useSyncExternalStore: (_, getSnapshot) => getSnapshot(),
89
+ useActionState: <S>(_: unknown, initialState: S, _permalink?: string) =>
90
+ [initialState, () => {}, false] as [S, () => void, boolean],
91
+ useOptimistic: <T>(passthrough: T) => [passthrough, () => {}] as [T, (action: unknown) => void],
92
+ useEffectEvent: <T extends Function>(callback: T): T => callback,
93
+ useMemoCache: (size: number) => {
94
+ const data = new Array<unknown>(size)
95
+ for (let i = 0; i < size; i++) {
96
+ data[i] = REACT_MEMO_CACHE_SENTINEL
97
+ }
98
+ return data
99
+ },
100
+ useCacheRefresh: () => () => {},
101
+ })
102
+
103
+ export const getReactCurrentDispatcher = (): ReactDispatcher => {
104
+ return React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE
105
+ }
@@ -0,0 +1,69 @@
1
+ import { ReactNode } from 'react'
2
+
3
+ import { VoltraNodeJson } from '../types.js'
4
+
5
+ export type ElementRegistry = {
6
+ isRegistered: (element: ReactNode) => number | undefined
7
+ register: (element: ReactNode, rendered: VoltraNodeJson) => number
8
+ getElements: () => VoltraNodeJson[]
9
+ }
10
+
11
+ export const createElementRegistry = (): ElementRegistry => {
12
+ const elementToIndex = new Map<ReactNode, number>()
13
+ const elements: VoltraNodeJson[] = []
14
+
15
+ return {
16
+ isRegistered: (element: ReactNode): number | undefined => {
17
+ return elementToIndex.get(element)
18
+ },
19
+ register: (element: ReactNode, rendered: VoltraNodeJson): number => {
20
+ const index = elements.length
21
+ elementToIndex.set(element, index)
22
+ elements.push(rendered)
23
+ return index
24
+ },
25
+ getElements: (): VoltraNodeJson[] => elements,
26
+ }
27
+ }
28
+
29
+ export const preScanForDuplicates = (element: ReactNode): Set<ReactNode> => {
30
+ const seen = new Set<ReactNode>()
31
+ const duplicates = new Set<ReactNode>()
32
+
33
+ const scan = (node: ReactNode): void => {
34
+ if (node === null || node === undefined || typeof node !== 'object') {
35
+ return
36
+ }
37
+
38
+ if (Array.isArray(node)) {
39
+ for (const child of node) {
40
+ scan(child)
41
+ }
42
+ return
43
+ }
44
+
45
+ if (seen.has(node)) {
46
+ duplicates.add(node)
47
+ } else {
48
+ seen.add(node)
49
+ }
50
+
51
+ if ('props' in node) {
52
+ const props = (node as { props: Record<string, unknown> }).props
53
+ if (props) {
54
+ if (props.children !== undefined) {
55
+ scan(props.children as ReactNode)
56
+ }
57
+
58
+ for (const [key, value] of Object.entries(props)) {
59
+ if (key !== 'children' && value && typeof value === 'object' && 'type' in value && 'props' in value) {
60
+ scan(value as ReactNode)
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
66
+
67
+ scan(element)
68
+ return duplicates
69
+ }
@@ -0,0 +1,24 @@
1
+ type StyleProp<T> = T | T[] | null | undefined | false
2
+
3
+ type FlatStyleProp<T> = T extends (infer U)[] ? FlatStyleProp<U> : T
4
+
5
+ export const flattenStyle = <T extends StyleProp<unknown>>(style: T | null | undefined): FlatStyleProp<T> | null => {
6
+ if (!style) {
7
+ return null
8
+ }
9
+
10
+ if (!Array.isArray(style)) {
11
+ return style as FlatStyleProp<T>
12
+ }
13
+
14
+ const result: Record<string, unknown> = {}
15
+ for (let i = 0, styleLength = style.length; i < styleLength; ++i) {
16
+ const computedStyle = flattenStyle(style[i])
17
+ if (computedStyle) {
18
+ for (const key in computedStyle) {
19
+ result[key] = computedStyle[key]
20
+ }
21
+ }
22
+ }
23
+ return result as FlatStyleProp<T>
24
+ }
@@ -0,0 +1,14 @@
1
+ export { type ContextRegistry, getContextRegistry } from './context-registry.js'
2
+ export { getHooksDispatcher, getReactCurrentDispatcher } from './dispatcher.js'
3
+ export { createElementRegistry, type ElementRegistry, preScanForDuplicates } from './element-registry.js'
4
+ export { flattenStyle } from './flatten-styles.js'
5
+ export { getRenderCache, type RenderCache } from './render-cache.js'
6
+ export {
7
+ type ComponentRegistry,
8
+ createVoltraRenderer,
9
+ renderVariantToJson,
10
+ transformProps,
11
+ VOLTRA_PAYLOAD_VERSION,
12
+ } from './renderer.js'
13
+ export { createStylesheetRegistry, type StylesheetRegistry } from './stylesheet-registry.js'
14
+ export type { VoltraVariantRenderer } from './types.js'
@@ -0,0 +1,27 @@
1
+ import { ReactNode } from 'react'
2
+
3
+ import { VoltraNodeJson } from '../types.js'
4
+ import { VoltraVariantRenderer } from './types.js'
5
+
6
+ export type RenderCache = {
7
+ getOrRender: VoltraVariantRenderer
8
+ }
9
+
10
+ export const getRenderCache = (renderer: VoltraVariantRenderer): RenderCache => {
11
+ const renderCache = new Map<ReactNode, VoltraNodeJson>()
12
+
13
+ return {
14
+ getOrRender: (node: ReactNode): VoltraNodeJson => {
15
+ const cached = renderCache.get(node)
16
+
17
+ if (cached) {
18
+ return cached
19
+ }
20
+
21
+ const result = renderer(node)
22
+ renderCache.set(node, result)
23
+
24
+ return result
25
+ },
26
+ }
27
+ }