Skip to content

Commit

Permalink
refactor(nanoviews): node property to method
Browse files Browse the repository at this point in the history
  • Loading branch information
dangreen committed Sep 3, 2024
1 parent 4fbd3a3 commit 4421326
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 63 deletions.
6 changes: 3 additions & 3 deletions packages/nanoviews/src/internals/block.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe('nanoviews', () => {
block.c()
block.m(root, anchor)

expect(block.n).toBe(node)
expect(block.n()).toBe(node)
expect(root.firstChild).toBe(node)

block.m(root)
Expand Down Expand Up @@ -60,8 +60,8 @@ describe('nanoviews', () => {
block.c()
block.m(root, anchor)

expect(block.n).toBe(node)
expect(childBlock.n).toBe(childNode)
expect(block.n()).toBe(node)
expect(childBlock.n()).toBe(childNode)
expect(root.firstChild).toBe(node)
expect(node.firstChild).toBe(childNode)

Expand Down
53 changes: 33 additions & 20 deletions packages/nanoviews/src/internals/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import type {
MountBlock,
Effect,
Destroy,
DestroyBlock
DestroyBlock,
GetNode
} from './types/index.js'
import { isBlockSymbol } from './types/block.js'
import { isFunction } from './utils.js'
Expand All @@ -22,24 +23,26 @@ export function isBlock(value: unknown): value is Block {
* @param mount - Function to mount block to target
* @param effect - Function to run effects
* @param destroy - Function to destroy block
* @param getNode - Function to get node
* @returns Block object
*/
export function createBlock<TNode extends Node>(
create: CreateBlock,
mount: MountBlock<TNode>,
effect: Effect<void>,
destroy: DestroyBlock
destroy: DestroyBlock,
getNode?: GetNode<TNode>
) {
let destroyEffect: Destroy | EmptyValue
let node: TNode | null = null
const block: Block<TNode> = {
[isBlockSymbol]: true,
k: null,
n: null,
c: create,
m(node, anchor) {
block.n = mount(node, anchor)
m(target, anchor) {
node = mount(target, anchor)

return block.n
return node
},
e() {
destroyEffect = effect()
Expand All @@ -48,9 +51,9 @@ export function createBlock<TNode extends Node>(
destroyEffect?.()
destroy()
destroyEffect = null
block.k = null
block.n = null
}
node = null
},
n: getNode || (() => node)
}

return block
Expand All @@ -69,7 +72,7 @@ export function createLazyBlock<TNode extends Node>(getBlock: () => Block<TNode>
block = getBlock()
block.c()
},
(parentNode, anchor) => block!.m(parentNode, anchor) || null,
(parentNode, anchor) => block!.m(parentNode, anchor),
() => block!.e(),
() => {
block!.d()
Expand Down Expand Up @@ -98,7 +101,7 @@ export function createBlockFromNode<TNode extends Node>(
(parentNode, anchor) => {
childBlock?.m(node!)
parentNode.insertBefore(node!, anchor || null)
return node!
return node
},
() => childBlock?.e(),
() => {
Expand All @@ -117,29 +120,39 @@ function getBlocks(blocksOrGetter: BlockOrGetter) {

function createBlocksLifesycle(
blocksOrGetter: BlockOrGetter,
lifecycle: (block: Block) => void
lifecycle: (block: Block) => void,
cleanup?: () => void
) {
return () => getBlocks(blocksOrGetter)?.forEach(lifecycle)
return () => {
getBlocks(blocksOrGetter)?.forEach(lifecycle)
cleanup?.()
}
}

function createBlocksMount(blocksOrGetter: BlockOrGetter) {
return (parentNode: Node, anchor?: Node | null | undefined) => {
getBlocks(blocksOrGetter)?.forEach(block => block.m(parentNode, anchor))

return parentNode.firstChild as Node
}
return (
parentNode: Node,
anchor?: Node | null | undefined
) => getBlocks(blocksOrGetter)?.map(
block => block.m(parentNode, anchor)
)[0] || null
}

/**
* Create block from blocks or blocks getter
* @param blocksOrGetter - Blocks or blocks getter function
* @param destroy - Destroy function
* @returns Block of blocks
*/
export function createBlockFromBlocks(blocksOrGetter: BlockOrGetter) {
export function createBlockFromBlocks(
blocksOrGetter: BlockOrGetter,
destroy?: Destroy
) {
return createBlock(
createBlocksLifesycle(blocksOrGetter, block => block.c()),
createBlocksMount(blocksOrGetter),
createBlocksLifesycle(blocksOrGetter, block => block.e()),
createBlocksLifesycle(blocksOrGetter, block => block.d())
createBlocksLifesycle(blocksOrGetter, block => block.d(), destroy),
() => getBlocks(blocksOrGetter)?.[0]?.n() || null
)
}
17 changes: 5 additions & 12 deletions packages/nanoviews/src/internals/logic/async.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,31 +107,24 @@ export function createAsyncList(

if (!isEmpty(child)) {
blocks!.splice(-1, 0, swap(footer!, childToBlock(child), insertMode))
// eslint-disable-next-line @typescript-eslint/no-use-before-define
proxyBlock.n = blocks![0].n
}
}
const setFooter = (getFooterBlock: GetChild = noop) => {
const block = childToBlock(provideContext(context, getFooterBlock))

// eslint-disable-next-line no-multi-assign
blocks![blocks!.length - 1] = footer = swap(footer!, block)
// eslint-disable-next-line @typescript-eslint/no-use-before-define
proxyBlock.n = blocks![0].n
}
const reset = (getFooterBlock?: GetChild) => {
blocks!.splice(0, blocks!.length - 1).forEach(block => block.d())
setFooter(getFooterBlock)
}
const proxyBlock = addEffects(
[
() => mutator(add, setFooter, reset),
() => () => {
footer = null
blocks = null
}
],
createBlockFromBlocks(() => blocks)
() => mutator(add, setFooter, reset),
createBlockFromBlocks(() => blocks, () => {
footer = null
blocks = null
})
)

return proxyBlock
Expand Down
2 changes: 1 addition & 1 deletion packages/nanoviews/src/internals/logic/effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function addEffects<T extends Block>(

block.e = () => {
superEffect()
destroy = effect(block.n! as PickBlockNode<T>)
destroy = effect(block.n()! as PickBlockNode<T>)
}

block.d = () => {
Expand Down
21 changes: 11 additions & 10 deletions packages/nanoviews/src/internals/logic/swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ export function swap(
return prevBlock
}

const prevNode = prevBlock.n
const prevNode = prevBlock.n()!
const anchor = insertOnlyMode as number > 0
? prevNode!.nextSibling
? prevNode.nextSibling
: prevNode

nextBlock.c()
nextBlock.m(prevNode!.parentNode!, anchor)
nextBlock.m(prevNode.parentNode!, anchor)

if (!insertOnlyMode) {
prevBlock.d()
Expand All @@ -57,12 +57,12 @@ export function createSwapper(
const context = getCurrentContextStack()
let childBlock: Block | null = childToBlock(initial)
const swapNextBlock = (getNextChild: GetChild = noop) => {
childBlock = swap(
childBlock!,
childToBlock(provideContext(context, getNextChild))
)
// eslint-disable-next-line @typescript-eslint/no-use-before-define
proxyBlock.n = childBlock.n
if (childBlock) {
childBlock = swap(
childBlock,
childToBlock(provideContext(context, getNextChild))
)
}
}
const proxyBlock = createBlock(
() => childBlock!.c(),
Expand All @@ -75,7 +75,8 @@ export function createSwapper(
() => {
childBlock!.d()
childBlock = null
}
},
() => childBlock!.n()
)

return proxyBlock
Expand Down
10 changes: 6 additions & 4 deletions packages/nanoviews/src/internals/types/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export type RunEffects = () => void
*/
export type DestroyBlock = Destroy

export type GetNode<T extends Node> = () => T | null

/**
* Symbol to mark object as block
*/
Expand All @@ -50,10 +52,6 @@ export interface Block<TNode extends Node = Node> {
* Key
*/
k: unknown
/**
* First node
*/
n: TNode | null
/**
* Create required data
*/
Expand All @@ -73,6 +71,10 @@ export interface Block<TNode extends Node = Node> {
* Destroy block
*/
d: DestroyBlock
/**
* Get node
*/
n: GetNode<TNode>
}

export type PickBlockNode<T extends Block> = T extends Block<infer TNode> ? TNode : never
4 changes: 2 additions & 2 deletions packages/nanoviews/src/internals/types/dom/attributes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ export interface KeygenHTMLAttributes<T extends HTMLElement> extends HTMLAttribu

export interface LabelHTMLAttributes<T extends HTMLElement> extends HTMLAttributes<T> {
form?: ValueOrStore<string | undefined>
htmlFor?: ValueOrStore<string | undefined>
for?: ValueOrStore<string | undefined>
}

export interface LiHTMLAttributes<T extends HTMLElement> extends HTMLAttributes<T> {
Expand Down Expand Up @@ -507,7 +507,7 @@ export interface OptionHTMLAttributes<T extends HTMLElement> extends HTMLAttribu

export interface OutputHTMLAttributes<T extends HTMLElement> extends HTMLAttributes<T> {
form?: ValueOrStore<string | undefined>
htmlFor?: ValueOrStore<string | undefined>
for?: ValueOrStore<string | undefined>
name?: ValueOrStore<string | undefined>
}

Expand Down
20 changes: 9 additions & 11 deletions packages/nanoviews/src/logic/for.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ function sync<T>(
block = trackedEachBlock(nextItems[i], i)
block.c()
effects.push(block.e)
} else {
// update code
}

nextBlocks[i] = block
Expand All @@ -86,7 +88,7 @@ function sync<T>(
const insert = (block: Block) => {
block.m(parentNode, next || null)
lookupMap.set(block.k, block)
next = block.n
next = block.n()
nextItemsCount--
}

Expand All @@ -99,7 +101,7 @@ function sync<T>(

if (nextBlock === prevBlock) {
// do nothing
next = nextBlock.n
next = nextBlock.n()
prevBlocksCount--
nextItemsCount--
} else if (!nextLookupMap.has(prevKey)) {
Expand Down Expand Up @@ -214,25 +216,21 @@ export function for$<T>(
const prevItemsCount = prevItems?.length

if (itemsCount) {
fragment ||= addEffects(
() => () => {
blocksMap.clear()
blocks = null
},
createBlockFromBlocks(() => blocks)
)
fragment ||= createBlockFromBlocks(() => blocks, () => {
blocksMap.clear()
blocks = null
})

if (prevItemsCount) {
// [...n] -> [...n1]
blocks = sync(
fragment.n!.parentNode!,
fragment.n()!.parentNode!,
blocksMap,
tracker,
trackedEachBlock,
blocks!,
items
)
fragment.n = blocks[0].n
} else {
// [] -> [...n]
blocks = createEachBlocks(blocksMap, tracker, trackedEachBlock, items)
Expand Down

0 comments on commit 4421326

Please sign in to comment.