* Hydrate node and its children * * @param node - A FormKitNode | FormKitNode * @param context - A FormKitContext | FormKitContext * * @returns A FormKitNode | FormKitNode * * @internal
(node: FormKitNode, context: FormKitContext)
| 2003 | * @internal |
| 2004 | */ |
| 2005 | function hydrate(node: FormKitNode, context: FormKitContext): FormKitNode { |
| 2006 | const _value = context._value as KeyedValue |
| 2007 | // For "synced" lists the underlying nodes need to be synced to their values |
| 2008 | // before hydration. |
| 2009 | if (node.type === 'list' && node.sync) syncListNodes(node, context) |
| 2010 | // Frameworks can briefly mount a same-name replacement before unmounting the |
| 2011 | // old node. In that overlap, the children remain the source of truth. |
| 2012 | const duplicateNames = new Set<PropertyKey>() |
| 2013 | if (node.type !== 'list') { |
| 2014 | const childNames = new Set<PropertyKey>() |
| 2015 | context.children.forEach((child) => { |
| 2016 | if (childNames.has(child.name)) duplicateNames.add(child.name) |
| 2017 | childNames.add(child.name) |
| 2018 | }) |
| 2019 | } |
| 2020 | context.children.forEach((child) => { |
| 2021 | if (typeof _value !== 'object') return |
| 2022 | if (duplicateNames.has(child.name) && !child.props.mergeStrategy) { |
| 2023 | partial(context, { name: child.name, value: child.value }) |
| 2024 | return |
| 2025 | } |
| 2026 | if (child.name in _value) { |
| 2027 | // In this case, the parent has a value to give to the child, so we |
| 2028 | // perform a down-tree synchronous input which will cascade values down |
| 2029 | // and then ultimately back up. |
| 2030 | const childValue = |
| 2031 | child.type !== 'input' || |
| 2032 | (_value[child.name] && typeof _value[child.name] === 'object') |
| 2033 | ? init(_value[child.name]) |
| 2034 | : _value[child.name] |
| 2035 | // If the two are already equal or the child is currently disturbed then |
| 2036 | // don’t send the value down since it will squash the child’s value. |
| 2037 | if ( |
| 2038 | !child.isSettled || |
| 2039 | ((!isObject(childValue) || child.props.mergeStrategy) && |
| 2040 | eq(childValue, child._value)) |
| 2041 | ) |
| 2042 | return |
| 2043 | |
| 2044 | // If there is a change to the child, push the new value down. |
| 2045 | child.input(childValue, false) |
| 2046 | } else { |
| 2047 | if (node.type !== 'list' || typeof child.name === 'number') { |
| 2048 | // In this case, the parent’s values have no knowledge of the child |
| 2049 | // value — this typically occurs on the commit at the end of addChild() |
| 2050 | // we need to create a value reservation for this node’s name. This is |
| 2051 | // especially important when dealing with lists where index matters. |
| 2052 | partial(context, { name: child.name, value: child.value }) |
| 2053 | } |
| 2054 | if (!_value.__init) { |
| 2055 | // In this case, someone has explicitly set the value to an empty object |
| 2056 | // with node.input({}) so we do not define the __init property: |
| 2057 | if (child.type === 'group') child.input({}, false) |
| 2058 | else if (child.type === 'list') child.input([], false) |
| 2059 | else child.input(undefined, false) |
| 2060 | } |
| 2061 | } |
| 2062 | }) |
nothing calls this directly
no test coverage detected