diff options
author | 2024-08-28 12:41:35 +0200 | |
---|---|---|
committer | 2024-08-28 11:41:35 +0100 | |
commit | 5f2536b51df93bfd51098c48220d647e7ad3954c (patch) | |
tree | 056a91c16866655154ede8173ffebbed022ea46e /packages/integrations/preact/src/signals.ts | |
parent | 26c63a2b07e6298dfb59c0c3178348cbd02c8a73 (diff) | |
download | astro-5f2536b51df93bfd51098c48220d647e7ad3954c.tar.gz astro-5f2536b51df93bfd51098c48220d647e7ad3954c.tar.zst astro-5f2536b51df93bfd51098c48220d647e7ad3954c.zip |
fix: handle preact signals in array correctly (#11834)
* fix: handle preact signals in array correctly
* feat: serialize signals in object
Diffstat (limited to 'packages/integrations/preact/src/signals.ts')
-rw-r--r-- | packages/integrations/preact/src/signals.ts | 55 |
1 files changed, 44 insertions, 11 deletions
diff --git a/packages/integrations/preact/src/signals.ts b/packages/integrations/preact/src/signals.ts index ea022b422..f8bae590f 100644 --- a/packages/integrations/preact/src/signals.ts +++ b/packages/integrations/preact/src/signals.ts @@ -1,6 +1,13 @@ import type { Context } from './context.js'; import { incrementId } from './context.js'; -import type { AstroPreactAttrs, PropNameToSignalMap, SignalLike } from './types.js'; +import type { + ArrayObjectMapping, + AstroPreactAttrs, + PropNameToSignalMap, + SignalLike, + Signals, + SignalToKeyOrIndexMap, +} from './types.js'; function isSignal(x: any): x is SignalLike { return x != null && typeof x === 'object' && typeof x.peek === 'function' && 'value' in x; @@ -28,22 +35,38 @@ export function serializeSignals( map: PropNameToSignalMap, ) { // Check for signals - const signals: Record<string, string> = {}; + const signals: Signals = {}; for (const [key, value] of Object.entries(props)) { - if (isSignal(value)) { + const isPropArray = Array.isArray(value); + const isPropObject = !isSignal(value) && typeof props[key] === 'object' && !isPropArray; + + if (isPropObject || isPropArray) { + const values = isPropObject ? Object.keys(props[key]) : value; + values.forEach((valueKey: number | string, valueIndex: number) => { + const signal = isPropObject ? props[key][valueKey] : valueKey; + if (isSignal(signal)) { + const keyOrIndex = isPropObject ? valueKey.toString() : valueIndex; + + props[key] = isPropObject + ? Object.assign({}, props[key], { [keyOrIndex]: signal.peek() }) + : props[key].map((v: SignalLike, i: number) => + i === valueIndex ? [signal.peek(), i] : v, + ); + + const currentMap = (map.get(key) || []) as SignalToKeyOrIndexMap; + map.set(key, [...currentMap, [signal, keyOrIndex]]); + + const currentSignals = (signals[key] || []) as ArrayObjectMapping; + signals[key] = [...currentSignals, [getSignalId(ctx, signal), keyOrIndex]]; + } + }); + } else if (isSignal(value)) { // Set the value to the current signal value // This mutates the props on purpose, so that it will be serialized correct. props[key] = value.peek(); map.set(key, value); - let id: string; - if (ctx.signals.has(value)) { - id = ctx.signals.get(value)!; - } else { - id = incrementId(ctx); - ctx.signals.set(value, id); - } - signals[key] = id; + signals[key] = getSignalId(ctx, value); } } @@ -51,3 +74,13 @@ export function serializeSignals( attrs['data-preact-signals'] = JSON.stringify(signals); } } + +function getSignalId(ctx: Context, item: SignalLike) { + let id = ctx.signals.get(item); + if (!id) { + id = incrementId(ctx); + ctx.signals.set(item, id); + } + + return id; +} |