Skip to content

Commit

Permalink
Merge pull request #106 from SgLy/feat-always-create-component
Browse files Browse the repository at this point in the history
Always call `createComponent` from wrapper `createCommonElement`
  • Loading branch information
SgLy authored Oct 30, 2023
2 parents fbc40b5 + 9481e14 commit a36f8a5
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 122 deletions.
10 changes: 7 additions & 3 deletions glass-easel/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,11 @@ export const resolvePlaceholder = (
}
}
if (ret) return ret
const comp = space.getGlobalUsingComponent(placeholder) ?? space.getDefaultComponent()
let comp = space.getGlobalUsingComponent(placeholder)
if (comp === null && space._$allowUnusedNativeNode && placeholder !== '') {
comp = placeholder
}
if (!comp) comp = space.getDefaultComponent()
if (!comp) {
throw new Error(
`Cannot find default component for placeholder target "${placeholder}" (on component "${behavior.is}")`,
Expand Down Expand Up @@ -467,7 +471,7 @@ export class Component<
owner: ShadowRoot | null,
backendContext: GeneralBackendContext | null,
genericImpls: { [name: string]: ComponentDefinitionWithPlaceholder } | null,
placeholderHandler: (() => void) | undefined,
placeholderHandlerRemover: (() => void) | undefined,
initPropValues?: (comp: ComponentInstance<TData, TProperty, TMethod>) => void,
): ComponentInstance<TData, TProperty, TMethod> {
if (!def._$detail) def.prepare()
Expand All @@ -487,7 +491,7 @@ export class Component<
// initialize component instance object
const comp = Object.create(proto) as ComponentInstance<TData, TProperty, TMethod>
comp._$genericImpls = genericImpls
comp._$placeholderHandler = placeholderHandler
comp._$placeholderHandlerRemover = placeholderHandlerRemover
comp._$external = external
comp.tagName = tagName
comp._$methodCaller = comp
Expand Down
4 changes: 4 additions & 0 deletions glass-easel/src/component_space.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ export class ComponentSpace {
_$componentWaitingListener:
| ((isPub: boolean, alias: string, owner: GeneralComponent) => void)
| null = null
/** @internal */
_$allowUnusedNativeNode = true

/**
* Create a new component space
Expand All @@ -168,6 +170,7 @@ export class ComponentSpace {
defaultComponent?: string,
baseSpace?: ComponentSpace,
styleScopeManager?: StyleScopeManager,
allowUnusedNativeNode = true,
) {
if (baseSpace) {
Object.assign(this._$list, baseSpace._$pubList)
Expand All @@ -176,6 +179,7 @@ export class ComponentSpace {
this._$defaultComponent = defaultComponent ?? ''
this._$componentOptions = normalizeComponentOptions({}, baseSpace?._$componentOptions)
this.styleScopeManager = styleScopeManager || new StyleScopeManager()
this._$allowUnusedNativeNode = allowUnusedNativeNode
}

/**
Expand Down
6 changes: 3 additions & 3 deletions glass-easel/src/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export class Element implements NodeCast {
/** @internal */
_$inheritSlots: boolean
/** @internal */
_$placeholderHandler: (() => void) | undefined
_$placeholderHandlerRemover: (() => void) | undefined
/** @internal */
_$virtual: boolean
dataset: { [name: string]: unknown }
Expand Down Expand Up @@ -152,7 +152,7 @@ export class Element implements NodeCast {
this._$subtreeSlotStart = null
this._$subtreeSlotEnd = null
this._$inheritSlots = false
this._$placeholderHandler = undefined
this._$placeholderHandlerRemover = undefined
this._$virtual = virtual
this.dataset = {}
this._$marks = null
Expand Down Expand Up @@ -439,7 +439,7 @@ export class Element implements NodeCast {
}
node.childNodes.forEach(callFunc)
if (node instanceof Component) {
const f = node._$placeholderHandler
const f = node._$placeholderHandlerRemover
if (f) f()
const shadowRoot = node.getShadowRoot()
if (shadowRoot) callFunc(shadowRoot)
Expand Down
4 changes: 2 additions & 2 deletions glass-easel/src/native_node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ export class NativeNode extends Element {
tagName: string,
owner: ShadowRoot,
stylingName?: string,
placeholderHandler?: () => void,
placeholderHandlerRemover?: () => void,
): NativeNode {
const node = Object.create(NativeNode.prototype) as NativeNode
node.is = tagName
node._$placeholderHandler = placeholderHandler
node._$placeholderHandlerRemover = placeholderHandlerRemover
const nodeTreeContext = owner._$nodeTreeContext
let backendElement: GeneralBackendElement | null
if (BM.DOMLIKE || (BM.DYNAMIC && owner.getBackendMode() === BackendMode.Domlike)) {
Expand Down
111 changes: 42 additions & 69 deletions glass-easel/src/shadow_root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,6 @@ type AppliedSlotMeta = {
updatePathTree: { [key: string]: true } | undefined
}

const wrapPlaceholderCallback = (
f: (c: GeneralComponentDefinition) => void,
cwp: Exclude<ComponentDefinitionWithPlaceholder, string>,
owner: GeneralComponent,
) => {
const waiting = cwp.waiting
if (waiting) {
waiting.add(f)
waiting.hintUsed(owner)
return () => {
waiting.remove(f)
}
}
return undefined
}

export class ShadowRoot extends VirtualNode {
private _$host: GeneralComponent
/** @internal */
Expand Down Expand Up @@ -133,10 +117,10 @@ export class ShadowRoot extends VirtualNode {
createNativeNodeWithInit(
tagName: string,
stylingName: string,
placeholderHandler: (() => void) | undefined,
placeholderHandlerRemover: (() => void) | undefined,
initPropValues?: (comp: NativeNode) => void,
): NativeNode {
const ret = NativeNode.create(tagName, this, stylingName, placeholderHandler)
const ret = NativeNode.create(tagName, this, stylingName, placeholderHandlerRemover)
initPropValues?.(ret)
return ret
}
Expand All @@ -160,26 +144,39 @@ export class ShadowRoot extends VirtualNode {
const space = beh.ownerSpace
const compName = usingKey === undefined ? tagName : usingKey

// if the target is in using list, then use the one in using list
const using = beh._$using[compName]
if (typeof using === 'string') {
return this.createNativeNodeWithInit(using, tagName, undefined, initPropValues)
}
if (using) {
const possibleComponentDefinitions = [
// if the target is in using list, then use the one in using list
beh._$using[compName],
// if the target is in generics list, then use the one
hostGenericImpls && hostGenericImpls[compName],
]

for (let i = 0; i < possibleComponentDefinitions.length; i += 1) {
const cwp = possibleComponentDefinitions[i]
if (cwp === null || cwp === undefined) continue
if (typeof cwp === 'string') {
return this.createNativeNodeWithInit(cwp, tagName, undefined, initPropValues)
}
let usingTarget: GeneralComponentDefinition | string | undefined
if (using.final) {
usingTarget = using.final
} else if (using.placeholder !== null) {
usingTarget = resolvePlaceholder(using.placeholder, space, using.source, hostGenericImpls)
let placeholderHandlerRemover: (() => void) | undefined
if (cwp.final) {
usingTarget = cwp.final
} else if (cwp.placeholder !== null) {
usingTarget = resolvePlaceholder(cwp.placeholder, space, cwp.source, hostGenericImpls)
const waiting = cwp.waiting
if (placeholderCallback && waiting) {
waiting.add(placeholderCallback)
waiting.hintUsed(host)
placeholderHandlerRemover = () => {
waiting.remove(placeholderCallback)
}
}
}
const placeholderHandler = placeholderCallback
? wrapPlaceholderCallback(placeholderCallback, using, host)
: undefined
if (typeof usingTarget === 'string') {
return this.createNativeNodeWithInit(
usingTarget,
tagName,
placeholderHandler,
placeholderHandlerRemover,
initPropValues,
)
}
Expand All @@ -190,45 +187,18 @@ export class ShadowRoot extends VirtualNode {
this,
null,
convertGenerics(usingTarget, beh, host, genericTargets),
placeholderHandler,
initPropValues,
)
}
}

// if the target is in generics list, then use the one
const g = hostGenericImpls && hostGenericImpls[compName]
if (typeof g === 'string') {
return this.createNativeNodeWithInit(g, tagName, undefined, initPropValues)
}
if (g) {
let genImpl: GeneralComponentDefinition | string | undefined
if (g.final) {
genImpl = g.final
} else if (g.placeholder !== null) {
genImpl = resolvePlaceholder(g.placeholder, space, g.source, hostGenericImpls)
}
const placeholderHandler = placeholderCallback
? wrapPlaceholderCallback(placeholderCallback, g, host)
: undefined
if (typeof genImpl === 'string') {
return this.createNativeNodeWithInit(genImpl, tagName, placeholderHandler, initPropValues)
}
if (genImpl) {
return Component._$advancedCreate(
tagName,
genImpl,
this,
null,
convertGenerics(genImpl, beh, host, genericTargets),
placeholderHandler,
placeholderHandlerRemover,
initPropValues,
)
}
}

// find in the space otherwise
const comp = space.getGlobalUsingComponent(compName) ?? space.getDefaultComponent()
let comp = space.getGlobalUsingComponent(compName)
if (comp === null && space._$allowUnusedNativeNode && compName !== '') {
comp = compName
}
if (!comp) comp = space.getDefaultComponent()
/* istanbul ignore if */
if (!comp) {
throw new Error(`Cannot find component "${compName}"`)
Expand Down Expand Up @@ -280,10 +250,13 @@ export class ShadowRoot extends VirtualNode {
)
}

// use native node otherwise
const node = NativeNode.create(tagName, this)
initPropValues?.(node)
return node
if (space._$allowUnusedNativeNode) {
// use native node otherwise
const node = NativeNode.create(tagName, this)
initPropValues?.(node)
return node
}
throw new Error(`Unknown tag name ${tagName}`)
}

/**
Expand Down
76 changes: 31 additions & 45 deletions glass-easel/src/tmpl/proc_gen_wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -782,8 +782,6 @@ export class ProcGenWrapper {
children: DefineChildren,
dynamicSlotValueNames: string[] | undefined,
): Element {
const placeholding = this.shadowRoot.checkComponentPlaceholder(tagName)
let elem: Element
let dynSlot = false
const initPropValues = (elem: GeneralComponent | NativeNode) => {
const sr =
Expand All @@ -800,55 +798,43 @@ export class ProcGenWrapper {
sr?.applySlotUpdates()
}
}
if (typeof placeholding === 'boolean') {
let placeholderCb: (() => void) | undefined
if (placeholding) {
placeholderCb = () => {
const replacer = this.shadowRoot.createComponent(
tagName,
tagName,
genericImpls,
undefined,
initPropValues,
)
replacer.destroyBackendElementOnDetach()
const replacerShadowRoot = (replacer as GeneralComponent).getShadowRoot()
const elemShadowRoot = elem instanceof Component ? elem.getShadowRoot() : null
const isElemDynamicSlots = elemShadowRoot?.getSlotMode() === SlotMode.Dynamic
const isReplacerDynamicSlots = replacerShadowRoot?.getSlotMode() === SlotMode.Dynamic
if (isReplacerDynamicSlots) {
if (!isElemDynamicSlots) {
throw new Error(
'The "dynamicSlots" option of the component and its placeholder should be the same.',
)
}
elem.parentNode?.replaceChild(replacer, elem)
} else {
if (isElemDynamicSlots) {
throw new Error(
'The "dynamicSlots" option of the component and its placeholder should be the same.',
)
}
elem.selfReplaceWith(replacer)
}
}
}
elem = this.shadowRoot.createComponent(
const placeholderCallback = () => {
const replacer = this.shadowRoot.createComponent(
tagName,
tagName,
genericImpls,
placeholderCb,
undefined,
initPropValues,
)
elem.destroyBackendElementOnDetach()
} else {
elem = this.shadowRoot.createComponentOrNativeNode(
placeholding ?? tagName,
genericImpls,
initPropValues,
)
elem.destroyBackendElementOnDetach()
replacer.destroyBackendElementOnDetach()
const replacerShadowRoot = (replacer as GeneralComponent).getShadowRoot()
const elemShadowRoot = elem instanceof Component ? elem.getShadowRoot() : null
const isElemDynamicSlots = elemShadowRoot?.getSlotMode() === SlotMode.Dynamic
const isReplacerDynamicSlots = replacerShadowRoot?.getSlotMode() === SlotMode.Dynamic
if (isReplacerDynamicSlots) {
if (!isElemDynamicSlots) {
throw new Error(
'The "dynamicSlots" option of the component and its placeholder should be the same.',
)
}
elem.parentNode?.replaceChild(replacer, elem)
} else {
if (isElemDynamicSlots) {
throw new Error(
'The "dynamicSlots" option of the component and its placeholder should be the same.',
)
}
elem.selfReplaceWith(replacer)
}
}
const elem = this.shadowRoot.createComponent(
tagName,
tagName,
genericImpls,
placeholderCallback,
initPropValues,
)
elem.destroyBackendElementOnDetach()
if (dynSlot) {
this.bindingMapDisabled = true // IDEA better binding map disable detection
} else {
Expand Down

0 comments on commit a36f8a5

Please sign in to comment.