@fictjs/runtime 0.0.13 → 0.0.14
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/dist/advanced.cjs +79 -0
- package/dist/advanced.cjs.map +1 -0
- package/dist/advanced.d.cts +50 -0
- package/dist/advanced.d.ts +50 -0
- package/dist/advanced.js +79 -0
- package/dist/advanced.js.map +1 -0
- package/dist/chunk-624QY53A.cjs +45 -0
- package/dist/chunk-624QY53A.cjs.map +1 -0
- package/dist/chunk-F3AIYQB7.js +45 -0
- package/dist/chunk-F3AIYQB7.js.map +1 -0
- package/dist/chunk-GJTYOFMO.cjs +109 -0
- package/dist/chunk-GJTYOFMO.cjs.map +1 -0
- package/dist/chunk-IUZXKAAY.js +109 -0
- package/dist/chunk-IUZXKAAY.js.map +1 -0
- package/dist/chunk-PMF6MWEV.cjs +3301 -0
- package/dist/chunk-PMF6MWEV.cjs.map +1 -0
- package/dist/chunk-RY4WDS6R.js +3301 -0
- package/dist/chunk-RY4WDS6R.js.map +1 -0
- package/dist/context-B7UYnfzM.d.ts +153 -0
- package/dist/context-UXySaqI_.d.cts +153 -0
- package/dist/effect-Auji1rz9.d.cts +350 -0
- package/dist/effect-Auji1rz9.d.ts +350 -0
- package/dist/index.cjs +98 -3558
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -1358
- package/dist/index.d.ts +5 -1358
- package/dist/index.dev.js +240 -1698
- package/dist/index.dev.js.map +1 -1
- package/dist/index.js +63 -3435
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +901 -0
- package/dist/internal.cjs.map +1 -0
- package/dist/internal.d.cts +158 -0
- package/dist/internal.d.ts +158 -0
- package/dist/internal.js +901 -0
- package/dist/internal.js.map +1 -0
- package/dist/{jsx-dev-runtime.d.ts → props-CrOMYbLv.d.cts} +107 -18
- package/dist/{jsx-dev-runtime.d.cts → props-ES0Ag_Wd.d.ts} +107 -18
- package/dist/scope-DKYzWfTn.d.cts +55 -0
- package/dist/scope-S6eAzBJZ.d.ts +55 -0
- package/package.json +11 -1
- package/src/advanced.ts +101 -0
- package/src/constants.ts +3 -26
- package/src/context.ts +300 -0
- package/src/delegated-events.ts +24 -0
- package/src/index.ts +41 -112
- package/src/internal.ts +130 -0
- package/src/props.ts +48 -46
- package/src/store.ts +47 -7
- package/src/versioned-signal.ts +3 -3
- package/dist/jsx-runtime.d.cts +0 -671
- package/dist/jsx-runtime.d.ts +0 -671
package/src/props.ts
CHANGED
|
@@ -122,38 +122,46 @@ export function mergeProps<T extends Record<string, unknown>>(
|
|
|
122
122
|
return unwrapProps(value as T)
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
const hasProp = (prop: string | symbol) => {
|
|
126
|
+
for (const src of validSources) {
|
|
127
|
+
const raw = resolveSource(src)
|
|
128
|
+
if (raw && prop in raw) {
|
|
129
|
+
return true
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return false
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const readProp = (prop: string | symbol) => {
|
|
136
|
+
// Only return undefined if no source has this Symbol property
|
|
137
|
+
// Search sources in reverse order (last wins)
|
|
138
|
+
for (let i = validSources.length - 1; i >= 0; i--) {
|
|
139
|
+
const src = validSources[i]!
|
|
140
|
+
const raw = resolveSource(src)
|
|
141
|
+
if (!raw || !(prop in raw)) continue
|
|
142
|
+
|
|
143
|
+
const value = (raw as Record<string | symbol, unknown>)[prop]
|
|
144
|
+
// Preserve prop getters - let child component's createPropsProxy unwrap lazily
|
|
145
|
+
// Note: For Symbol properties, we still wrap in getter if source is dynamic
|
|
146
|
+
if (typeof src === 'function' && !isPropGetter(value)) {
|
|
147
|
+
return __fictProp(() => {
|
|
148
|
+
const latest = resolveSource(src)
|
|
149
|
+
if (!latest || !(prop in latest)) return undefined
|
|
150
|
+
return (latest as Record<string | symbol, unknown>)[prop]
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
return value
|
|
154
|
+
}
|
|
155
|
+
return undefined
|
|
156
|
+
}
|
|
157
|
+
|
|
125
158
|
return new Proxy({} as Record<string, unknown>, {
|
|
126
159
|
get(_, prop) {
|
|
127
|
-
|
|
128
|
-
// Search sources in reverse order (last wins)
|
|
129
|
-
for (let i = validSources.length - 1; i >= 0; i--) {
|
|
130
|
-
const src = validSources[i]!
|
|
131
|
-
const raw = resolveSource(src)
|
|
132
|
-
if (!raw || !(prop in raw)) continue
|
|
133
|
-
|
|
134
|
-
const value = (raw as Record<string | symbol, unknown>)[prop]
|
|
135
|
-
// Preserve prop getters - let child component's createPropsProxy unwrap lazily
|
|
136
|
-
// Note: For Symbol properties, we still wrap in getter if source is dynamic
|
|
137
|
-
if (typeof src === 'function' && !isPropGetter(value)) {
|
|
138
|
-
return __fictProp(() => {
|
|
139
|
-
const latest = resolveSource(src)
|
|
140
|
-
if (!latest || !(prop in latest)) return undefined
|
|
141
|
-
return (latest as Record<string | symbol, unknown>)[prop]
|
|
142
|
-
})
|
|
143
|
-
}
|
|
144
|
-
return value
|
|
145
|
-
}
|
|
146
|
-
return undefined
|
|
160
|
+
return readProp(prop)
|
|
147
161
|
},
|
|
148
162
|
|
|
149
163
|
has(_, prop) {
|
|
150
|
-
|
|
151
|
-
const raw = resolveSource(src)
|
|
152
|
-
if (raw && prop in raw) {
|
|
153
|
-
return true
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return false
|
|
164
|
+
return hasProp(prop)
|
|
157
165
|
},
|
|
158
166
|
|
|
159
167
|
ownKeys() {
|
|
@@ -170,21 +178,12 @@ export function mergeProps<T extends Record<string, unknown>>(
|
|
|
170
178
|
},
|
|
171
179
|
|
|
172
180
|
getOwnPropertyDescriptor(_, prop) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
configurable: true,
|
|
179
|
-
get: () => {
|
|
180
|
-
const value = (raw as Record<string | symbol, unknown>)[prop]
|
|
181
|
-
// Preserve prop getters - let child component's createPropsProxy unwrap lazily
|
|
182
|
-
return value
|
|
183
|
-
},
|
|
184
|
-
}
|
|
185
|
-
}
|
|
181
|
+
if (!hasProp(prop)) return undefined
|
|
182
|
+
return {
|
|
183
|
+
enumerable: true,
|
|
184
|
+
configurable: true,
|
|
185
|
+
get: () => readProp(prop),
|
|
186
186
|
}
|
|
187
|
-
return undefined
|
|
188
187
|
},
|
|
189
188
|
})
|
|
190
189
|
}
|
|
@@ -192,19 +191,22 @@ export function mergeProps<T extends Record<string, unknown>>(
|
|
|
192
191
|
export type PropGetter<T> = (() => T) & { __fictProp: true }
|
|
193
192
|
/**
|
|
194
193
|
* Memoize a prop getter to cache expensive computations.
|
|
195
|
-
* Use when prop expressions involve heavy calculations.
|
|
194
|
+
* Use when prop expressions involve heavy calculations or you need lazy, reactive props.
|
|
196
195
|
*
|
|
197
196
|
* @example
|
|
198
197
|
* ```tsx
|
|
199
|
-
* // Without
|
|
198
|
+
* // Without prop - recomputes on every access
|
|
200
199
|
* <Child data={expensiveComputation(list, filter)} />
|
|
201
200
|
*
|
|
202
|
-
* // With
|
|
203
|
-
* const memoizedData =
|
|
201
|
+
* // With prop - cached until dependencies change, auto-unwrapped by props proxy
|
|
202
|
+
* const memoizedData = prop(() => expensiveComputation(list, filter))
|
|
204
203
|
* <Child data={memoizedData} />
|
|
205
204
|
* ```
|
|
206
205
|
*/
|
|
207
|
-
export function
|
|
206
|
+
export function prop<T>(getter: () => T): PropGetter<T> {
|
|
207
|
+
if (isPropGetter(getter)) {
|
|
208
|
+
return getter as PropGetter<T>
|
|
209
|
+
}
|
|
208
210
|
// Wrap in prop so component props proxy auto-unwraps when passed down.
|
|
209
211
|
return __fictProp(createMemo(getter)) as PropGetter<T>
|
|
210
212
|
}
|
package/src/store.ts
CHANGED
|
@@ -152,7 +152,13 @@ function getLastValue(target: any, prop: string | symbol) {
|
|
|
152
152
|
*/
|
|
153
153
|
function reconcile(target: any, value: any) {
|
|
154
154
|
if (target === value) return
|
|
155
|
-
if (value === null || typeof value !== 'object')
|
|
155
|
+
if (value === null || typeof value !== 'object') {
|
|
156
|
+
throw new Error(
|
|
157
|
+
`[Fict] Cannot replace store with primitive value: ${String(
|
|
158
|
+
value,
|
|
159
|
+
)}. setStore should return an object/array to merge.`,
|
|
160
|
+
)
|
|
161
|
+
}
|
|
156
162
|
|
|
157
163
|
const realTarget = unwrap(target)
|
|
158
164
|
const realValue = unwrap(value)
|
|
@@ -166,6 +172,11 @@ function reconcile(target: any, value: any) {
|
|
|
166
172
|
target[key] = realValue[key] // Triggers proxy trap
|
|
167
173
|
}
|
|
168
174
|
}
|
|
175
|
+
|
|
176
|
+
// Fix array length if needed
|
|
177
|
+
if (Array.isArray(target) && target.length !== realValue.length) {
|
|
178
|
+
target.length = realValue.length
|
|
179
|
+
}
|
|
169
180
|
}
|
|
170
181
|
|
|
171
182
|
// ============================================================================
|
|
@@ -180,6 +191,29 @@ function reconcile(target: any, value: any) {
|
|
|
180
191
|
export function createDiffingSignal<T extends object>(initialValue: T) {
|
|
181
192
|
let currentValue = unwrap(initialValue)
|
|
182
193
|
const signals = new Map<string | symbol, SignalAccessor<any>>()
|
|
194
|
+
let iterateSignal: SignalAccessor<number> | undefined
|
|
195
|
+
|
|
196
|
+
const getPropSignal = (prop: string | symbol) => {
|
|
197
|
+
let s = signals.get(prop)
|
|
198
|
+
if (!s) {
|
|
199
|
+
s = signal((currentValue as any)[prop])
|
|
200
|
+
signals.set(prop, s)
|
|
201
|
+
}
|
|
202
|
+
return s
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const trackIterate = () => {
|
|
206
|
+
if (!iterateSignal) {
|
|
207
|
+
iterateSignal = signal(Reflect.ownKeys(currentValue).length)
|
|
208
|
+
}
|
|
209
|
+
iterateSignal()
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const updateIterate = (value: T) => {
|
|
213
|
+
if (iterateSignal) {
|
|
214
|
+
iterateSignal(Reflect.ownKeys(value).length)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
183
217
|
|
|
184
218
|
// The stable proxy we return
|
|
185
219
|
const proxy = new Proxy({} as T, {
|
|
@@ -188,17 +222,21 @@ export function createDiffingSignal<T extends object>(initialValue: T) {
|
|
|
188
222
|
if (prop === TARGET) return currentValue
|
|
189
223
|
|
|
190
224
|
// Subscribe to property
|
|
191
|
-
|
|
192
|
-
if (!s) {
|
|
193
|
-
// Initialize signal with current property value
|
|
194
|
-
s = signal((currentValue as any)[prop])
|
|
195
|
-
signals.set(prop, s)
|
|
196
|
-
}
|
|
225
|
+
const s = getPropSignal(prop)
|
|
197
226
|
return s()
|
|
198
227
|
},
|
|
199
228
|
ownKeys() {
|
|
229
|
+
trackIterate()
|
|
200
230
|
return Reflect.ownKeys(currentValue)
|
|
201
231
|
},
|
|
232
|
+
has(target, prop) {
|
|
233
|
+
getPropSignal(prop)()
|
|
234
|
+
return Reflect.has(currentValue, prop)
|
|
235
|
+
},
|
|
236
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
237
|
+
getPropSignal(prop)()
|
|
238
|
+
return Reflect.getOwnPropertyDescriptor(currentValue, prop)
|
|
239
|
+
},
|
|
202
240
|
})
|
|
203
241
|
|
|
204
242
|
const read = () => proxy
|
|
@@ -215,6 +253,7 @@ export function createDiffingSignal<T extends object>(initialValue: T) {
|
|
|
215
253
|
const newVal = (next as any)[prop]
|
|
216
254
|
s(newVal)
|
|
217
255
|
}
|
|
256
|
+
updateIterate(next)
|
|
218
257
|
return
|
|
219
258
|
}
|
|
220
259
|
|
|
@@ -228,6 +267,7 @@ export function createDiffingSignal<T extends object>(initialValue: T) {
|
|
|
228
267
|
s(newVal)
|
|
229
268
|
}
|
|
230
269
|
}
|
|
270
|
+
updateIterate(next)
|
|
231
271
|
|
|
232
272
|
// Note: If new properties appeared that weren't tracked, we don't care
|
|
233
273
|
// because no one is listening.
|
package/src/versioned-signal.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createSignal } from './signal'
|
|
1
|
+
import { createSignal, untrack } from './signal'
|
|
2
2
|
|
|
3
3
|
export interface VersionedSignalOptions<T> {
|
|
4
4
|
equals?: (prev: T, next: T) => boolean
|
|
@@ -52,7 +52,7 @@ export function createVersionedSignal<T>(
|
|
|
52
52
|
force: () => {
|
|
53
53
|
bumpVersion()
|
|
54
54
|
},
|
|
55
|
-
peekVersion: () => version(),
|
|
56
|
-
peekValue: () => value(),
|
|
55
|
+
peekVersion: () => untrack(() => version()),
|
|
56
|
+
peekValue: () => untrack(() => value()),
|
|
57
57
|
}
|
|
58
58
|
}
|