add vh layout
This commit is contained in:
parent
341692f319
commit
9592e9ed3d
@ -3,10 +3,12 @@ package com.github.penfeizhou.doric;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.github.penfeizhou.doric.plugin.ShaderPlugin;
|
import com.github.penfeizhou.doric.plugin.ShaderPlugin;
|
||||||
|
import com.github.penfeizhou.doric.shader.HLayoutNode;
|
||||||
import com.github.penfeizhou.doric.shader.ImageNode;
|
import com.github.penfeizhou.doric.shader.ImageNode;
|
||||||
import com.github.penfeizhou.doric.shader.RootNode;
|
import com.github.penfeizhou.doric.shader.RootNode;
|
||||||
import com.github.penfeizhou.doric.shader.StackNode;
|
import com.github.penfeizhou.doric.shader.StackNode;
|
||||||
import com.github.penfeizhou.doric.shader.TextNode;
|
import com.github.penfeizhou.doric.shader.TextNode;
|
||||||
|
import com.github.penfeizhou.doric.shader.VLayoutNode;
|
||||||
import com.github.penfeizhou.doric.shader.ViewNode;
|
import com.github.penfeizhou.doric.shader.ViewNode;
|
||||||
import com.github.penfeizhou.doric.utils.DoricMetaInfo;
|
import com.github.penfeizhou.doric.utils.DoricMetaInfo;
|
||||||
import com.github.penfeizhou.doric.plugin.DoricJavaPlugin;
|
import com.github.penfeizhou.doric.plugin.DoricJavaPlugin;
|
||||||
@ -47,6 +49,8 @@ public class DoricRegistry {
|
|||||||
this.registerViewNode(TextNode.class);
|
this.registerViewNode(TextNode.class);
|
||||||
this.registerViewNode(ImageNode.class);
|
this.registerViewNode(ImageNode.class);
|
||||||
this.registerViewNode(StackNode.class);
|
this.registerViewNode(StackNode.class);
|
||||||
|
this.registerViewNode(VLayoutNode.class);
|
||||||
|
this.registerViewNode(HLayoutNode.class);
|
||||||
initRegistry(this);
|
initRegistry(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.github.penfeizhou.doric.shader;
|
||||||
|
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import com.github.penfeizhou.doric.DoricContext;
|
||||||
|
import com.github.penfeizhou.doric.extension.bridge.DoricPlugin;
|
||||||
|
import com.github.pengfeizhou.jscore.JSObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: com.github.penfeizhou.doric.shader
|
||||||
|
* @Author: pengfei.zhou
|
||||||
|
* @CreateDate: 2019-07-23
|
||||||
|
*/
|
||||||
|
@DoricPlugin(name = "HLayout")
|
||||||
|
public class HLayoutNode extends LinearNode {
|
||||||
|
public HLayoutNode(DoricContext doricContext) {
|
||||||
|
super(doricContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LinearLayout build(JSObject jsObject) {
|
||||||
|
LinearLayout linearLayout = super.build(jsObject);
|
||||||
|
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
return linearLayout;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
package com.github.penfeizhou.doric.shader;
|
||||||
|
|
||||||
|
import android.graphics.drawable.ShapeDrawable;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import com.github.penfeizhou.doric.DoricContext;
|
||||||
|
import com.github.penfeizhou.doric.utils.DoricUtils;
|
||||||
|
import com.github.pengfeizhou.jscore.JSObject;
|
||||||
|
import com.github.pengfeizhou.jscore.JSValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: com.github.penfeizhou.doric.shader
|
||||||
|
* @Author: pengfei.zhou
|
||||||
|
* @CreateDate: 2019-07-23
|
||||||
|
*/
|
||||||
|
public class LinearNode extends GroupNode<LinearLayout> {
|
||||||
|
public LinearNode(DoricContext doricContext) {
|
||||||
|
super(doricContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LinearLayout build(JSObject jsObject) {
|
||||||
|
return new LinearLayout(getContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void blend(LinearLayout view, String name, JSValue prop) {
|
||||||
|
switch (name) {
|
||||||
|
case "space":
|
||||||
|
ShapeDrawable shapeDrawable;
|
||||||
|
if (view.getDividerDrawable() == null) {
|
||||||
|
shapeDrawable = new ShapeDrawable();
|
||||||
|
shapeDrawable.setAlpha(0);
|
||||||
|
view.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
|
||||||
|
} else {
|
||||||
|
shapeDrawable = (ShapeDrawable) view.getDividerDrawable();
|
||||||
|
view.setDividerDrawable(null);
|
||||||
|
}
|
||||||
|
if (view.getOrientation() == LinearLayout.VERTICAL) {
|
||||||
|
shapeDrawable.setIntrinsicHeight(DoricUtils.dp2px(prop.asNumber().toFloat()));
|
||||||
|
} else {
|
||||||
|
shapeDrawable.setIntrinsicWidth(DoricUtils.dp2px(prop.asNumber().toFloat()));
|
||||||
|
}
|
||||||
|
view.setDividerDrawable(shapeDrawable);
|
||||||
|
break;
|
||||||
|
case "gravity":
|
||||||
|
view.setGravity(prop.asNumber().toInt());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super.blend(view, name, prop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import android.widget.FrameLayout;
|
|||||||
import com.github.penfeizhou.doric.DoricContext;
|
import com.github.penfeizhou.doric.DoricContext;
|
||||||
import com.github.penfeizhou.doric.extension.bridge.DoricPlugin;
|
import com.github.penfeizhou.doric.extension.bridge.DoricPlugin;
|
||||||
import com.github.pengfeizhou.jscore.JSObject;
|
import com.github.pengfeizhou.jscore.JSObject;
|
||||||
|
import com.github.pengfeizhou.jscore.JSValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Description: com.github.penfeizhou.doric.widget
|
* @Description: com.github.penfeizhou.doric.widget
|
||||||
@ -21,4 +22,15 @@ public class StackNode extends GroupNode<FrameLayout> {
|
|||||||
public FrameLayout build(JSObject jsObject) {
|
public FrameLayout build(JSObject jsObject) {
|
||||||
return new FrameLayout(getContext());
|
return new FrameLayout(getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void blend(FrameLayout view, String name, JSValue prop) {
|
||||||
|
switch (name) {
|
||||||
|
case "gravity":
|
||||||
|
view.setForegroundGravity(prop.asNumber().toInt());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super.blend(view, name, prop);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.github.penfeizhou.doric.shader;
|
||||||
|
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import com.github.penfeizhou.doric.DoricContext;
|
||||||
|
import com.github.penfeizhou.doric.extension.bridge.DoricPlugin;
|
||||||
|
import com.github.pengfeizhou.jscore.JSObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: com.github.penfeizhou.doric.shader
|
||||||
|
* @Author: pengfei.zhou
|
||||||
|
* @CreateDate: 2019-07-23
|
||||||
|
*/
|
||||||
|
@DoricPlugin(name = "VLayout")
|
||||||
|
public class VLayoutNode extends LinearNode {
|
||||||
|
public VLayoutNode(DoricContext doricContext) {
|
||||||
|
super(doricContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LinearLayout build(JSObject jsObject) {
|
||||||
|
LinearLayout linearLayout = super.build(jsObject);
|
||||||
|
linearLayout.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
return linearLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -58,10 +58,18 @@ public abstract class ViewNode<T extends View> extends DoricComponent {
|
|||||||
protected void blend(T view, String name, JSValue prop) {
|
protected void blend(T view, String name, JSValue prop) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "width":
|
case "width":
|
||||||
view.getLayoutParams().width = DoricUtils.dp2px(prop.asNumber().toFloat());
|
if (prop.asNumber().toInt() < 0) {
|
||||||
|
view.getLayoutParams().width = prop.asNumber().toInt();
|
||||||
|
} else {
|
||||||
|
view.getLayoutParams().width = DoricUtils.dp2px(prop.asNumber().toFloat());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "height":
|
case "height":
|
||||||
view.getLayoutParams().height = DoricUtils.dp2px(prop.asNumber().toFloat());
|
if (prop.asNumber().toInt() < 0) {
|
||||||
|
view.getLayoutParams().height = prop.asNumber().toInt();
|
||||||
|
} else {
|
||||||
|
view.getLayoutParams().height = DoricUtils.dp2px(prop.asNumber().toFloat());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "x":
|
case "x":
|
||||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
|
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
|
||||||
|
@ -1,35 +1,52 @@
|
|||||||
import { NativeCall, Text, Alignment, Color, VLayout, Panel, log, logw, loge } from "./index"
|
import { Gravity, Mutable, NativeCall, Text, Color, VLayout, Panel, log, logw, loge, Group, Stack, } from "./index"
|
||||||
import { Group } from "./src/ui/view";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Entry
|
@Entry
|
||||||
export class MyPage extends Panel {
|
export class MyPage extends Panel {
|
||||||
state = {
|
|
||||||
count: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
build(rootView: Group): void {
|
build(rootView: Group): void {
|
||||||
|
const state = Mutable.of(1)
|
||||||
const numberView = new Text
|
const numberView = new Text
|
||||||
numberView.width = 100
|
numberView.width = 100
|
||||||
numberView.height = 200
|
numberView.height = 200
|
||||||
numberView.top = 50
|
numberView.top = 50
|
||||||
numberView.text = this.state.count.toString()
|
state.bind((v) => {
|
||||||
|
numberView.text = v.toString()
|
||||||
|
})
|
||||||
numberView.textSize = 40
|
numberView.textSize = 40
|
||||||
numberView.centerX = rootView.width / 2
|
numberView.centerX = rootView.width / 2
|
||||||
rootView.addChild(numberView)
|
rootView.addChild(numberView)
|
||||||
const click = new Text
|
const click = new Text
|
||||||
click.width = click.height = 100
|
|
||||||
click.textSize = 20
|
click.textSize = 20
|
||||||
click.text = '点击计数'
|
click.text = '点击计数'
|
||||||
click.onClick = () => {
|
click.onClick = () => {
|
||||||
this.state.count++
|
state.set(state.get() + 1)
|
||||||
numberView.text = this.state.count.toString()
|
|
||||||
}
|
}
|
||||||
click.centerX = rootView.width / 2
|
|
||||||
click.top = numberView.bottom + 20
|
click.top = numberView.bottom + 20
|
||||||
rootView.addChild(click)
|
rootView.addChild(click)
|
||||||
rootView.bgColor = Color.safeParse('#00ff00')
|
|
||||||
|
const vlayout = new VLayout
|
||||||
|
vlayout.width = this.getRootView().width
|
||||||
|
vlayout.height = 500
|
||||||
|
|
||||||
|
vlayout.top = 50
|
||||||
|
vlayout.centerX = this.getRootView().width / 2
|
||||||
|
vlayout.space = 0
|
||||||
|
vlayout.gravity = (new Gravity()).bottom()
|
||||||
|
const v = [1, 2, 3,].map(e => {
|
||||||
|
const stack = new Stack
|
||||||
|
stack.width = stack.height = 50
|
||||||
|
stack.bgColor = Color.safeParse('#00ff00')
|
||||||
|
vlayout.addChild(stack)
|
||||||
|
stack.onClick = () => {
|
||||||
|
loge('stack:onClick')
|
||||||
|
if (vlayout.space !== undefined) {
|
||||||
|
loge('change space')
|
||||||
|
vlayout.space += 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
rootView.addChild(vlayout)
|
||||||
}
|
}
|
||||||
|
|
||||||
@NativeCall
|
@NativeCall
|
||||||
|
@ -2,4 +2,6 @@ export * from "./src/ui/view"
|
|||||||
export * from "./src/ui/panel"
|
export * from "./src/ui/panel"
|
||||||
export * from "./src/util/color"
|
export * from "./src/util/color"
|
||||||
export * from './src/util/log'
|
export * from './src/util/log'
|
||||||
|
export * from './src/util/types'
|
||||||
|
export * from './src/util/gravity'
|
||||||
export * from './src/runtime/global'
|
export * from './src/runtime/global'
|
@ -5,6 +5,8 @@ function from(obj: Object) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Wrapper {
|
class Wrapper {
|
||||||
val: any
|
val: any
|
||||||
constructor(val: any) {
|
constructor(val: any) {
|
||||||
|
@ -1,18 +1,23 @@
|
|||||||
import { Color, GradientColor } from "../util/color"
|
import { Color, GradientColor } from "../util/color"
|
||||||
import { Modeling, Model, obj2Model } from "../util/types";
|
import { Modeling, Model, obj2Model } from "../util/types";
|
||||||
import { uniqueId } from "../util/uniqueId";
|
import { uniqueId } from "../util/uniqueId";
|
||||||
|
import { Gravity } from "../util/gravity";
|
||||||
import { loge } from "../util/log";
|
import { loge } from "../util/log";
|
||||||
|
|
||||||
|
export const MATCH_PARENT = -1
|
||||||
|
|
||||||
|
export const WRAP_CONTENT = -2
|
||||||
|
|
||||||
export function Property(target: Object, propKey: string) {
|
export function Property(target: Object, propKey: string) {
|
||||||
Reflect.defineMetadata(propKey, true, target)
|
Reflect.defineMetadata(propKey, true, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class View implements Modeling {
|
export abstract class View implements Modeling {
|
||||||
@Property
|
@Property
|
||||||
width: number = 0
|
width: number = WRAP_CONTENT
|
||||||
|
|
||||||
@Property
|
@Property
|
||||||
height: number = 0
|
height: number = WRAP_CONTENT
|
||||||
|
|
||||||
@Property
|
@Property
|
||||||
x: number = 0
|
x: number = 0
|
||||||
@ -146,9 +151,11 @@ export abstract class View implements Modeling {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isDirty() {
|
isDirty() {
|
||||||
return Reflect.ownKeys(this.__dirty_props__).length !== 0
|
return Reflect.ownKeys(this.__dirty_props__).length !== 0
|
||||||
}
|
}
|
||||||
|
|
||||||
responseCallback(id: string, ...args: any) {
|
responseCallback(id: string, ...args: any) {
|
||||||
const f = this.id2Callback(id)
|
const f = this.id2Callback(id)
|
||||||
if (f instanceof Function) {
|
if (f instanceof Function) {
|
||||||
@ -176,20 +183,9 @@ export abstract class View implements Modeling {
|
|||||||
|
|
||||||
@Property
|
@Property
|
||||||
config?: Config
|
config?: Config
|
||||||
}
|
|
||||||
|
|
||||||
export enum Alignment {
|
@Property
|
||||||
center = 0,
|
onClick?: Function
|
||||||
start,
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum Gravity {
|
|
||||||
center = 0,
|
|
||||||
left,
|
|
||||||
right,
|
|
||||||
top,
|
|
||||||
bottom,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
@ -199,14 +195,14 @@ export interface Config {
|
|||||||
top?: number,
|
top?: number,
|
||||||
bottom?: number,
|
bottom?: number,
|
||||||
}
|
}
|
||||||
alignment?: Alignment
|
alignment?: Gravity
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StackConfig extends Config {
|
export interface StackConfig extends Config {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LayoutConfig extends Config {
|
export interface LinearConfig extends Config {
|
||||||
weight?: number
|
weight?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,7 +253,7 @@ export abstract class Group extends View {
|
|||||||
|
|
||||||
export class Stack extends Group {
|
export class Stack extends Group {
|
||||||
@Property
|
@Property
|
||||||
gravity?: number
|
gravity?: Gravity
|
||||||
}
|
}
|
||||||
export class Root extends Stack {
|
export class Root extends Stack {
|
||||||
|
|
||||||
@ -267,7 +263,7 @@ class LinearLayout extends Group {
|
|||||||
space?: number
|
space?: number
|
||||||
|
|
||||||
@Property
|
@Property
|
||||||
gravity?: number
|
gravity?: Gravity
|
||||||
}
|
}
|
||||||
|
|
||||||
export class VLayout extends LinearLayout {
|
export class VLayout extends LinearLayout {
|
||||||
@ -288,9 +284,6 @@ export class Text extends View {
|
|||||||
|
|
||||||
@Property
|
@Property
|
||||||
maxLines?: number
|
maxLines?: number
|
||||||
|
|
||||||
@Property
|
|
||||||
onClick?: Function
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Image extends View {
|
export class Image extends View {
|
||||||
@ -305,3 +298,24 @@ export class List extends View {
|
|||||||
export class Slide extends View {
|
export class Slide extends View {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function stack() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function vlayout(providers: Array<() => View>, config: {
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
space?: number
|
||||||
|
}) {
|
||||||
|
const vlayout = new VLayout
|
||||||
|
vlayout.width = config.width
|
||||||
|
vlayout.height = config.height
|
||||||
|
if (config.space !== undefined) {
|
||||||
|
vlayout.space = config.space
|
||||||
|
}
|
||||||
|
providers.forEach(e => {
|
||||||
|
vlayout.addChild(e())
|
||||||
|
})
|
||||||
|
return vlayout
|
||||||
|
}
|
||||||
|
64
js-framework/src/util/gravity.ts
Normal file
64
js-framework/src/util/gravity.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import { Modeling } from "./types";
|
||||||
|
|
||||||
|
const SPECIFIED = 1
|
||||||
|
const START = 1 << 1
|
||||||
|
const END = 1 << 2
|
||||||
|
|
||||||
|
const SHIFT_X = 0
|
||||||
|
const SHIFT_Y = 4
|
||||||
|
|
||||||
|
export const LEFT = (START | SPECIFIED) << SHIFT_X
|
||||||
|
export const RIGHT = (END | SPECIFIED) << SHIFT_X
|
||||||
|
|
||||||
|
export const TOP = (START | SPECIFIED) << SHIFT_Y
|
||||||
|
export const BOTTOM = (END | SPECIFIED) << SHIFT_Y
|
||||||
|
|
||||||
|
export const CENTER_X = SPECIFIED << SHIFT_X
|
||||||
|
export const CENTER_Y = SPECIFIED << SHIFT_Y
|
||||||
|
|
||||||
|
export const CENTER = CENTER_X | CENTER_Y
|
||||||
|
|
||||||
|
export class Gravity implements Modeling {
|
||||||
|
val = 0
|
||||||
|
|
||||||
|
left() {
|
||||||
|
this.val |= LEFT
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
right() {
|
||||||
|
this.val |= RIGHT
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
top() {
|
||||||
|
this.val |= TOP
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
bottom() {
|
||||||
|
this.val |= BOTTOM
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
center() {
|
||||||
|
this.val |= CENTER
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
centerX() {
|
||||||
|
this.val |= CENTER_X
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
centerY() {
|
||||||
|
this.val |= CENTER_Y
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
toModel() {
|
||||||
|
return this.val
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -15,4 +15,36 @@ export function obj2Model(obj: Model): Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type _M = string | number | boolean | Modeling | { [index: string]: Model | undefined }
|
type _M = string | number | boolean | Modeling | { [index: string]: Model | undefined }
|
||||||
export type Model = _M | Array<_M>
|
export type Model = _M | Array<_M>
|
||||||
|
|
||||||
|
export type Binder<T> = (v: T) => void
|
||||||
|
|
||||||
|
export class Mutable<T>{
|
||||||
|
private val: T
|
||||||
|
|
||||||
|
private binders: Set<Binder<T>> = new Set
|
||||||
|
|
||||||
|
get = () => {
|
||||||
|
return this.val
|
||||||
|
}
|
||||||
|
|
||||||
|
set = (v: T) => {
|
||||||
|
this.val = v
|
||||||
|
this.binders.forEach(e => {
|
||||||
|
Reflect.apply(e, undefined, [this.val])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private constructor(v: T) {
|
||||||
|
this.val = v
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(binder: Binder<T>) {
|
||||||
|
this.binders.add(binder)
|
||||||
|
Reflect.apply(binder, undefined, [this.val])
|
||||||
|
}
|
||||||
|
|
||||||
|
static of<E>(v: E) {
|
||||||
|
return new Mutable(v)
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
let __uniqueId__: number = 0
|
let __uniqueId__ = 0
|
||||||
|
|
||||||
export function uniqueId(prefix: string) {
|
export function uniqueId(prefix: string) {
|
||||||
return `__${prefix}_${__uniqueId__++}__`;
|
return `__${prefix}_${__uniqueId__++}__`;
|
||||||
}
|
}
|
Reference in New Issue
Block a user