@pyreon/ui-core 0.24.5 → 0.25.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.
package/src/render.tsx DELETED
@@ -1,50 +0,0 @@
1
- import type { ComponentFn, Props, VNodeChild } from '@pyreon/core'
2
- import { h } from '@pyreon/core'
3
-
4
- type RenderProps<T extends Record<string, unknown> | undefined> = (props: Partial<T>) => VNodeChild
5
-
6
- /**
7
- * Flexible element renderer that handles multiple content types:
8
- * - Primitives (string, number) — returned as-is
9
- * - Arrays — returned as-is
10
- * - Component functions — created via h()
11
- * - VNode objects — returned as-is (with props merged if provided)
12
- * - Render props (functions) — called with attachProps
13
- * - Falsy values — return null
14
- */
15
- export type Render = <T extends Record<string, any> | undefined>(
16
- content?: ComponentFn | string | VNodeChild | VNodeChild[] | RenderProps<T>,
17
- attachProps?: T,
18
- ) => VNodeChild
19
-
20
- const render: Render = (content, attachProps) => {
21
- if (!content) return null
22
-
23
- const t = typeof content
24
- if (t === 'string' || t === 'number' || t === 'boolean' || t === 'bigint') {
25
- return content as VNodeChild
26
- }
27
-
28
- if (Array.isArray(content)) {
29
- return content as VNodeChild
30
- }
31
-
32
- if (typeof content === 'function') {
33
- // Extract key from props — it's a VNode concept, not a component prop.
34
- // Passing key inside props causes JSX runtime warnings.
35
- if (attachProps && 'key' in attachProps) {
36
- const { key: _key, ...rest } = attachProps
37
- return h(content as string | ComponentFn, rest as Props)
38
- }
39
- return h(content as string | ComponentFn, (attachProps ?? {}) as Props)
40
- }
41
-
42
- // VNode object — return directly
43
- if (typeof content === 'object') {
44
- return content as VNodeChild
45
- }
46
-
47
- return content as VNodeChild
48
- }
49
-
50
- export default render
package/src/types.ts DELETED
@@ -1,5 +0,0 @@
1
- export interface Breakpoints {
2
- [key: string]: number
3
- }
4
-
5
- export type BreakpointKeys = keyof Breakpoints
@@ -1,21 +0,0 @@
1
- import { signal } from '@pyreon/reactivity'
2
- import isEqual from './isEqual'
3
-
4
- /**
5
- * Returns a referentially stable version of `value`. The returned reference
6
- * only changes when the value is no longer deeply equal to the previous one.
7
- *
8
- * Pyreon equivalent of the React useStableValue hook — uses a signal
9
- * internally to hold the stable reference.
10
- */
11
- const useStableValue = <T>(value: T): T => {
12
- const ref = signal(value)
13
-
14
- if (!isEqual(ref.peek(), value)) {
15
- ref.set(value)
16
- }
17
-
18
- return ref.peek()
19
- }
20
-
21
- export default useStableValue
package/src/utils.ts DELETED
@@ -1,187 +0,0 @@
1
- /**
2
- * Returns a copy of `obj` without the specified keys.
3
- *
4
- * Accepts either an array of keys (builds a Set internally) or a
5
- * pre-built `Set<string>` for hot paths where the same key list is
6
- * reused across many calls (avoids per-call Set allocation).
7
- *
8
- * Copies own property DESCRIPTORS (not values) so that getter-shaped
9
- * properties — produced by `makeReactiveProps` in `@pyreon/core` for
10
- * compiler-emitted `<Comp prop={signal()}>` — survive the copy with
11
- * their reactive subscription intact. For data properties the
12
- * behaviour is identical to value-copying.
13
- */
14
- export const omit = <T extends Record<string, any>>(
15
- obj: T | null | undefined,
16
- keys?: readonly (string | keyof T)[] | Set<string>,
17
- ): Partial<T> => {
18
- if (obj == null) return {} as Partial<T>
19
- const descriptors = Object.getOwnPropertyDescriptors(obj)
20
- if (!keys || (keys instanceof Set ? keys.size === 0 : keys.length === 0)) {
21
- return Object.defineProperties({} as Partial<T>, descriptors)
22
- }
23
- const keysSet = keys instanceof Set ? keys : new Set(keys as readonly string[])
24
- const result: Record<string, any> = {}
25
- for (const key of Object.keys(descriptors)) {
26
- if (!keysSet.has(key)) {
27
- Object.defineProperty(result, key, descriptors[key]!)
28
- }
29
- }
30
- return result as Partial<T>
31
- }
32
-
33
- /**
34
- * Returns a copy of `obj` containing only the specified keys.
35
- *
36
- * See `omit` above — same descriptor-preserving semantics: getter-
37
- * shaped properties survive the copy with reactive subscription
38
- * intact. For data properties the behaviour is identical to
39
- * value-copying.
40
- */
41
- export const pick = <T extends Record<string, any>>(
42
- obj: T | null | undefined,
43
- keys?: readonly (string | keyof T)[],
44
- ): Partial<T> => {
45
- if (obj == null) return {} as Partial<T>
46
- if (!keys || keys.length === 0) {
47
- return Object.defineProperties(
48
- {} as Partial<T>,
49
- Object.getOwnPropertyDescriptors(obj),
50
- )
51
- }
52
- const result: Record<string, any> = {}
53
- for (const key of keys) {
54
- const k = key as string
55
- const descriptor = Object.getOwnPropertyDescriptor(obj, k)
56
- if (descriptor) {
57
- Object.defineProperty(result, k, descriptor)
58
- }
59
- }
60
- return result as Partial<T>
61
- }
62
-
63
- const PATH_RE = /[^.[\]]+/g
64
-
65
- const parsePath = (path: string | string[]): string[] => {
66
- if (Array.isArray(path)) return path
67
- const parts = path.match(PATH_RE)
68
- return parts ?? []
69
- }
70
-
71
- const isUnsafeKey = (key: string): boolean =>
72
- key === '__proto__' || key === 'prototype' || key === 'constructor'
73
-
74
- export const get = (obj: any, path: string | string[], defaultValue?: any): any => {
75
- const keys = parsePath(path)
76
- let result = obj
77
- for (const key of keys) {
78
- if (result == null || isUnsafeKey(key)) return defaultValue
79
- result = result[key]
80
- }
81
- return result === undefined ? defaultValue : result
82
- }
83
-
84
- export const set = (
85
- obj: Record<string, any>,
86
- path: string | string[],
87
- value: any,
88
- ): Record<string, any> => {
89
- const keys = parsePath(path)
90
- let current = obj
91
- for (let i = 0; i < keys.length - 1; i++) {
92
- const key = keys[i] as string
93
- if (isUnsafeKey(key)) return obj
94
- const nextKey = keys[i + 1] as string
95
- if (isUnsafeKey(nextKey)) return obj
96
- if (current[key] == null) {
97
- current[key] = /^\d+$/.test(nextKey) ? [] : {}
98
- }
99
- current = current[key]
100
- }
101
- const lastKey = keys[keys.length - 1]
102
- if (lastKey != null && !isUnsafeKey(lastKey)) {
103
- current[lastKey] = value
104
- }
105
- return obj
106
- }
107
-
108
- export const throttle = <T extends (...args: any[]) => any>(
109
- fn: T,
110
- wait: number = 0,
111
- options?: { leading?: boolean; trailing?: boolean },
112
- ): T & { cancel: () => void } => {
113
- const leading = options?.leading !== false
114
- const trailing = options?.trailing !== false
115
- let lastCallTime: number | undefined
116
- let timeoutId: ReturnType<typeof setTimeout> | undefined
117
- let lastArgs: any[] | undefined
118
-
119
- const invoke = (args: any[]) => {
120
- lastCallTime = Date.now()
121
- fn(...args)
122
- }
123
-
124
- const startTrailingTimer = (args: any[], delay: number) => {
125
- lastArgs = args
126
- if (timeoutId !== undefined) return
127
- timeoutId = setTimeout(() => {
128
- timeoutId = undefined
129
- if (lastArgs) {
130
- invoke(lastArgs)
131
- lastArgs = undefined
132
- }
133
- }, delay)
134
- }
135
-
136
- const throttled = (...args: any[]) => {
137
- const now = Date.now()
138
- const elapsed = lastCallTime === undefined ? wait : now - lastCallTime
139
- if (elapsed >= wait) {
140
- if (leading) {
141
- invoke(args)
142
- } else {
143
- lastCallTime = now
144
- if (trailing) startTrailingTimer(args, wait)
145
- }
146
- } else if (trailing) {
147
- startTrailingTimer(args, wait - elapsed)
148
- }
149
- }
150
-
151
- throttled.cancel = () => {
152
- if (timeoutId !== undefined) {
153
- clearTimeout(timeoutId)
154
- timeoutId = undefined
155
- }
156
- lastArgs = undefined
157
- lastCallTime = undefined
158
- }
159
-
160
- return throttled as T & { cancel: () => void }
161
- }
162
-
163
- const isPlainObject = (value: unknown): value is Record<string, any> =>
164
- value !== null &&
165
- typeof value === 'object' &&
166
- !Array.isArray(value) &&
167
- Object.getPrototypeOf(value) === Object.prototype
168
-
169
- export const merge = <T extends Record<string, any>>(
170
- target: T,
171
- ...sources: Record<string, any>[]
172
- ): T => {
173
- for (const source of sources) {
174
- if (source == null) continue
175
- for (const key of Object.keys(source)) {
176
- if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue
177
- const targetVal = (target as Record<string, unknown>)[key]
178
- const sourceVal = source[key]
179
- if (isPlainObject(targetVal) && isPlainObject(sourceVal)) {
180
- ;(target as Record<string, unknown>)[key] = merge({ ...targetVal }, sourceVal)
181
- } else {
182
- ;(target as Record<string, unknown>)[key] = sourceVal
183
- }
184
- }
185
- }
186
- return target
187
- }