import { genEffects, genOperations } from './operation'
import { genChildren } from './template'
import { toValidAssetId } from '@vue/compiler-dom'
+import { genExpression } from './expression'
export function genBlock(
oper: BlockIRNode,
customReturns?: (returns: CodeFragment[]) => CodeFragment[],
): CodeFragment[] {
const [frag, push] = buildCodeFragment()
- const { dynamic, effect, operation, returns } = block
+ const { dynamic, effect, operation, returns, key } = block
const resetBlock = context.enterBlock(block)
if (root) {
if (dynamic.needsKey) {
for (const child of dynamic.children) {
- push(NEWLINE, `n${child.id}.key = ${JSON.stringify(child.id)}`)
+ const keyValue = key
+ ? genExpression(key, context)
+ : JSON.stringify(child.id)
+ push(NEWLINE, `n${child.id}.key = `, ...keyValue)
}
}
return `_${builtInTag}`
}
return genExpression(
- extend(createSimpleExpression(operation.tag, false), { ast: null }),
+ extend(createSimpleExpression(tag, false), { ast: null }),
context,
)
}
let propsName: string | undefined
let exitScope: (() => void) | undefined
let depth: number | undefined
- const { props } = oper
+ const { props, key } = oper
const idsOfProps = new Set<string>()
if (props) {
? `${propsName}[${JSON.stringify(id)}]`
: null),
)
- const blockFn = context.withId(
+ let blockFn = context.withId(
() => genBlock(oper, context, [propsName]),
idMap,
)
exitScope && exitScope()
+ if (key) {
+ blockFn = [
+ `() => {`,
+ INDENT_START,
+ NEWLINE,
+ `return `,
+ ...genCall(
+ context.helper('createKeyedFragment'),
+ [`() => `, ...genExpression(key, context)],
+ blockFn,
+ ),
+ INDENT_END,
+ NEWLINE,
+ `}`,
+ ]
+ }
+
return blockFn
}
export interface BaseIRNode {
type: IRNodeTypes
+ key?: SimpleExpressionNode | undefined
}
export type CoreHelper = keyof typeof import('packages/runtime-dom/src')
return [branch, exitBlock]
}
-function isInTransition(context: TransformContext<ElementNode>): boolean {
+export function isInTransition(
+ context: TransformContext<ElementNode>,
+): boolean {
const parentNode = context.parent && context.parent.node
- return !!(
- parentNode &&
- parentNode.type === NodeTypes.ELEMENT &&
- (parentNode.tag === 'transition' || parentNode.tag === 'Transition')
+ return !!(parentNode && isTransitionNode(parentNode as ElementNode))
+}
+
+export function isTransitionNode(node: ElementNode): boolean {
+ return (
+ node.type === NodeTypes.ELEMENT &&
+ (node.tag === 'transition' || node.tag === 'Transition')
)
}
type SlotBlockIRNode,
type VaporDirectiveNode,
} from '../ir'
-import { findDir, resolveExpression } from '../utils'
+import { findDir, findProp, resolveExpression } from '../utils'
+import { isTransitionNode } from './vIf'
export const transformVSlot: NodeTransform = (node, context) => {
if (node.type !== NodeTypes.ELEMENT) return
!(n.type === NodeTypes.ELEMENT && n.props.some(isVSlot)),
)
- const [block, onExit] = createSlotBlock(node, dir, context)
+ let slotKey
+ if (isTransitionNode(node)) {
+ const keyProp = findProp(
+ nonSlotTemplateChildren[0] as ElementNode,
+ 'key',
+ ) as VaporDirectiveNode
+ if (keyProp) {
+ slotKey = keyProp.exp
+ }
+ }
+
+ const [block, onExit] = createSlotBlock(node, dir, context, slotKey)
const { slots } = context
slotNode: ElementNode,
dir: VaporDirectiveNode | undefined,
context: TransformContext<ElementNode>,
+ key: SimpleExpressionNode | undefined = undefined,
): [SlotBlockIRNode, () => void] {
const block: SlotBlockIRNode = newBlock(slotNode)
block.props = dir && dir.exp
+ block.key = key
+ if (key) block.dynamic.needsKey = true
const exitBlock = context.enterBlock(block)
return [block, exitBlock]
}
--- /dev/null
+import { type Block, type BlockFn, DynamicFragment } from './block'
+import { renderEffect } from './renderEffect'
+
+export function createKeyedFragment(key: () => any, render: BlockFn): Block {
+ const frag = __DEV__ ? new DynamicFragment('keyed') : new DynamicFragment()
+ renderEffect(() => {
+ frag.update(render, key())
+ })
+ return frag
+}
} from './dom/prop'
export { on, delegate, delegateEvents, setDynamicEvents } from './dom/event'
export { createIf } from './apiCreateIf'
+export { createKeyedFragment } from './apiCreateFragment'
export {
createFor,
createForSlots,