Skip to content

Commit

Permalink
* core: support for creating multiple component instances with zui-c…
Browse files Browse the repository at this point in the history
…reate.
  • Loading branch information
catouse committed Jul 9, 2024
1 parent cbe7b44 commit 31edf74
Showing 1 changed file with 85 additions and 17 deletions.
102 changes: 85 additions & 17 deletions lib/core/src/helpers/zui-creator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import {$, Cash, Selector} from '../cash';
import {takeData} from './data';
import {getZData} from './z';

type ZUIComponentOptions = Record<string, unknown>;
type ZUIComponentOptions = {
$update?: boolean;
[x: string]: unknown;
};

declare class ZUIComponentClass {
gid: number;
Expand Down Expand Up @@ -39,18 +42,30 @@ export function getComponent(name?: string): ZUIComponent | undefined {
return name ? componentsMap.get(name.toLowerCase()) : undefined;
}

export function create(name: string, element: HTMLElement, options: ZUIComponentOptions) {
export function create(name: string, element: HTMLElement, options: ZUIComponentOptions = {}) {
const Component = getComponent(name);
if (!Component) {
return null;
}
if (!Component.MULTI_INSTANCE && Component.get(element)) {
console.error(`[ZUI] cannot create component "${name}" on element which already has a component instance.`, {element, options});
return null;
if (!Component.MULTI_INSTANCE) {
const component = Component.get(element);
if (component) {
if (options.$update) {
delete options.$update;
component.render(options);
} else {
console.warn(`[ZUI] cannot create component "${name}" on element which already has a component instance.`, {element, options});
}
return component;
}
}
return new Component(element, options);
}

function createInAnimationFrame(name: string, element: HTMLElement, options: ZUIComponentOptions = {}) {
requestAnimationFrame(() => create(name, element, options));
}

export function defineFn(name?: string) {
if (name) {
const Component = getComponent(name);
Expand All @@ -74,21 +89,74 @@ declare module 'cash-dom' {
}
}

/**
* Create zui component instance from elements which match [zui-create], [data-zui], [data-zui] is deprecated, use [zui-create] instead.
* 为匹配 [zui-create], [data-zui] 的元素创建 zui 组件实例,[data-zui] 被弃用,优先使用 [zui-create]。
*
* @param element - The element to create zui components. 要创建 zui 组件的元素。
* @param options - The options. 选项。
*
* @example
* ```html
* <div zui-create="list" zui-create-list='{"items": [{"text": "item1"}, {"text": "item2"}]}'></div>
* <menu zui-create zui-create-list='{$replace: true, items: [{text: "item1"}, {text: "item2"}], onClickItem: (item) => console.log("click item", item)}'></menu>
* <menu zui-create="list,sortable" zui-create-list='{$replace: true, items: [{"text": "item1"}, {"text": "item2"}]}' zui-create-sortable="{dragShadow: false}">Create multiple components</menu>
*
* <div data-zui="list" data-items='[{"text": "item1"}, {"text": "item2"}]'>Deprecated usage</div>
* ```
*/
function initCreators(element: HTMLElement, options: {update?: boolean} = {}): void {
const $element = $(element);
let createNames = $element.attr('zui-create');
const $update = options.update;
const defaultCreateOptions = {
$update,
$optionsFromDataset: false,
};
if (typeof createNames === 'string') {
createNames = createNames.trim();
const names = createNames.length ? createNames.split(',').map((name) => name.trim()) : [];
const createOptionsMap = getZData(element, {prefix: 'zui-create-', evalValue: true})!;
const createOptionsNames = Object.keys(createOptionsMap);
if (!createOptionsNames.length && names.length === 1) {
createInAnimationFrame(names[0], element, {
...defaultCreateOptions,
...$element.dataset(),
});
} else {
const initedNames = new Set<string>();
[...names, ...createOptionsNames].forEach(name => {
if (initedNames.has(name)) {
return;
}
const createOptions = createOptionsMap[name] as ZUIComponentOptions | undefined;
createInAnimationFrame(name, element, {
...defaultCreateOptions,
...createOptions,
});
delete createOptionsMap[name];
initedNames.add(name);
});
}
} else {
const initOptions = $element.dataset();
const name = initOptions?.zui as string;
if (!name) {
return;
}
console.warn('[ZUI] create component instance with [data-zui] is deprecated, use [zui-create] instead.', {element, options});
delete initOptions!.zui;
createInAnimationFrame(name, element, {
...defaultCreateOptions,
...initOptions,
});
}
}

/** Define the $.fn.zuiInit method. */
$.fn.zuiInit = function (this: Cash) {
this.find('[zui-create],[data-zui]').each(function () {
const $element = $(this);
let options = getZData($element, 'data-')!;
const [name, optionsName] = ((options.zui || $element.attr('zui-create')) as string).split(':');
if ($element.zui(name)) {
return;
}
if (optionsName) {
options = $.share[optionsName] as Record<string, unknown>;
} else {
delete options.zui;
}
requestAnimationFrame(() => create(name, this, options));
initCreators(this);
});
this.find('[zui-init]').each(function () {
const $element = $(this);
Expand Down

0 comments on commit 31edf74

Please sign in to comment.