import { mergeIfNotShallowEqual } from '@tamagui/is-equal-shallow' import { getMediaState } from '../hooks/useMedia' import type { ComponentSetStateShallow, DisposeFn, AllGroupContexts } from '../types' type SubscribeToContextGroupProps = { setStateShallow: ComponentSetStateShallow pseudoGroups?: Set mediaGroups?: Set groupContext: AllGroupContexts } export const subscribeToContextGroup = (props: SubscribeToContextGroupProps) => { const { pseudoGroups, mediaGroups, groupContext } = props if (pseudoGroups || mediaGroups) { if (process.env.NODE_ENV === 'development' && !groupContext) { console.debug(`No context group found`) } const disposables = new Set() if (pseudoGroups) { for (const name of pseudoGroups) { disposables.add(createGroupListener(name, props)) } } if (mediaGroups) { for (const name of mediaGroups) { disposables.add(createGroupListener(name, props)) } } return () => { disposables.forEach((d) => d()) } } } const createGroupListener = ( name: string, { setStateShallow, pseudoGroups, mediaGroups, groupContext, }: SubscribeToContextGroupProps ): DisposeFn => { const parent = groupContext?.[name] if (!parent) { return () => {} } const dispose = parent.subscribe(({ layout, pseudo }) => { setStateShallow((prev) => { let didChange = false const group = prev.group?.[name] || { pseudo: {}, media: {}, } if (pseudo && pseudoGroups?.has(name)) { group.pseudo ||= {} const next = mergeIfNotShallowEqual(group.pseudo, pseudo) if (next !== group.pseudo) { Object.assign(group.pseudo, pseudo) didChange = true } } else if (layout && mediaGroups) { group.media ||= {} const mediaState = getMediaState(mediaGroups, layout) const next = mergeIfNotShallowEqual(group.media, mediaState) if (next !== group.media) { Object.assign(group.media, next) didChange = true } } if (didChange) { return { group: { ...prev.group, [name]: group, }, } } return prev }) }) return () => { dispose() // we no longer have any active group, need to remove state so the style updates setStateShallow({ group: {}, }) } }