vue#VNode TypeScript Examples

The following examples show how to use vue#VNode. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: types.ts    From am-editor with MIT License 6 votes vote down vote up
collapseItemProps = {
	name: buttonProps.name,
	engine: buttonProps.engine,
	icon: buttonProps.icon,
	title: buttonProps.title,
	search: String,
	description: buttonProps.content,
	disabled: buttonProps.disabled,
	prompt: [String, Function, Object] as PropType<
		string | (() => string) | VNode
	>,
	command: buttonProps.command,
	autoExecute: buttonProps.autoExecute,
	className: buttonProps.className,
	placement: buttonProps.placement,
	onClick: Function as PropType<
		(
			event: MouseEvent,
			name: string,
			engine?: EngineInterface,
		) => boolean | void
	>,
	onMouseDown: Function as PropType<
		(event: MouseEvent, engine?: EngineInterface) => void
	>,
}
Example #2
Source File: directive.ts    From vue3-gettext with MIT License 6 votes vote down vote up
updateTranslation = (language: Language, el: HTMLElement, binding: DirectiveBinding, vnode: VNode) => {
  const attrs = vnode.props || {};
  const msgid = el.dataset.msgid!;
  const translateContext = attrs["translate-context"];
  const translateN = attrs["translate-n"];
  const translatePlural = attrs["translate-plural"];
  const isPlural = translateN !== undefined && translatePlural !== undefined;
  const disableHtmlEscaping = attrs["render-html"] === "true";

  if (!isPlural && (translateN || translatePlural)) {
    throw new Error("`translate-n` and `translate-plural` attributes must be used together:" + msgid + ".");
  }

  if (!language.silent && attrs["translate-params"]) {
    console.warn(
      `\`translate-params\` is required as an expression for v-translate directive. Please change to \`v-translate='params'\`: ${msgid}`,
    );
  }

  const translation = translate(language).getTranslation(
    msgid,
    translateN,
    translateContext,
    isPlural ? translatePlural : null,
    language.current,
  );

  const context = Object.assign(binding.instance, binding.value);
  const msg = interpolate(language)(translation, context, disableHtmlEscaping, null);

  el.innerHTML = msg;
}
Example #3
Source File: provider.ts    From fect with MIT License 6 votes vote down vote up
flattenVNodes = (children: VNodeNormalizedChildren) => {
  const result: VNode[] = []
  const traverse = (children: VNodeNormalizedChildren) => {
    if (Array.isArray(children)) {
      children.forEach((child) => {
        if (isVNode(child)) {
          result.push(child)
          if (child.component?.subTree) {
            traverse(child.component.subTree.children)
          }
          if (child.children) {
            traverse(child.children)
          }
        }
      })
    }
  }
  traverse(children)
  return result
}
Example #4
Source File: leaf.tsx    From slate-vue with MIT License 5 votes vote down vote up
Leaf = tsx.component({
  props: {
    text: {
      type: Object as PropType<Text>
    },
    leaf:  {
      type: Object as PropType<Text>
    },
  },
  inject: ['renderLeaf'],
  components: {
    string,
    fragment
  },
  // For types
  data(): Pick<providedByEditable, 'renderLeaf'> {
    return {}
  },
  render(h): VNode {
    const { renderLeaf = DefaultLeaf, text, leaf} = this;
    let children =  (
      <string text={text} editor={this.$editor} leaf={leaf}/>
      );
    if ((leaf as any)[PLACEHOLDER_SYMBOL]) {
      children = (
        <fragment>
          <span
            contenteditable={false}
            style={{
              pointerEvents: 'none',
              display: 'inline-block',
              verticalAlign: 'text-top',
              width: '0',
              maxWidth: '100%',
              whiteSpace: 'nowrap',
              opacity: '0.333',
            }}
          >
            {(leaf as any).placeholder}
          </span>
          {children}
        </fragment>
      )
    }

    const attributes: {
     'data-slate-leaf': true
    } = {
     'data-slate-leaf': true,
    };
    const renderChildren = renderLeaf({
      children,
      attributes,
      leaf,
      text
    })
    return h(renderChildren)
  }
})
Example #5
Source File: RouteLayoutSource.ts    From convue with MIT License 5 votes vote down vote up
export function createRouterLayout(
  resolve: (layoutName: string) => Promise<Component | { default: Component }>,
) {
  return defineComponent({
    name: 'RouterLayout',

    async beforeRouteEnter(to, _from, next) {
      const name = to.meta.layout || 'default'
      const layoutComp = name
        ? ((await resolve(name)) as any).default
        : undefined

      next((vm: any) => {
        vm.layoutName = name
        if (name && layoutComp)
          vm.layouts[name] = layoutComp
      })
    },

    async beforeRouteUpdate(to, _from, next) {
      try {
        const name = to.meta.layout || 'default'
        if (name && !this.layouts[name])
          this.layouts[name] = ((await resolve(name)) as any).default

        this.layoutName = name
        next()
      }
      catch (error) {
        next(error)
      }
    },

    data() {
      return {
        layoutName: undefined as string | undefined,
        layouts: shallowReactive(
          Object.create(null) as Record<string, Component>,
        ),
      }
    },

    render(): VNode {
      const layout = this.layoutName && this.layouts[this.layoutName]
      if (!layout)
        return h('span')

      return h(layout as ConcreteComponent, {
        key: this.layoutName,
      })
    },
  })
}
Example #6
Source File: InfoWindow.ts    From x5-gmaps with MIT License 5 votes vote down vote up
public render(h: CreateElement): VNode {
    return h('div', this.$slots.default);
  }
Example #7
Source File: Data.ts    From x5-gmaps with MIT License 5 votes vote down vote up
public render(h: CreateElement): VNode {
    return h('div', this.$slots.default);
  }
Example #8
Source File: uplot-vue3-example.tsx    From uplot-wrappers with MIT License 5 votes vote down vote up
app = createApp({
    name: 'UplotVueExample',
    components: {uplotvue: UplotVue},
    // @ts-ignore
    data() {
        return {
            options: {
                title: 'Chart', width: 400, height: 300,
                series: [{
                    label: 'Date'
                }, {
                    label: '',
                    points: {show: false},
                    stroke: 'blue',
                    fill: 'blue'
                }],
                plugins: [dummyPlugin()],
                scales: {x: {time: false}}
            },
            target: null as unknown as HTMLElement
        };
    },
    beforeMount() {
        // Initialize data inside mounted hook, to prevent Vue from adding watchers, otherwise performance becomes unbearable
        this.data = [[...new Array(100000)].map((_, i) => i), [...new Array(100000)].map((_, i) => i % 1000)];
    },
    mounted() {
        this.target = this.$refs.root as HTMLElement;
        setInterval(() => {
            const options = {
                ...this.options,
                title: (this.$refs.root as HTMLElement).id ? 'Rendered with template' : 'Rendered with function'
            };
            const data: uPlot.AlignedData = [
                [...this.data[0], this.data[0].length],
                [...this.data[1], this.data[0].length % 1000]
            ];
            this.data = data;
            // Since we disabled reactivity for data above
            this.$forceUpdate();
            this.options = options;
        }, 100);
    },
    render(): VNode {
        // @ts-ignore
        return (<div ref='root'>
            <UplotVue
                key="render-key"
                // @ts-ignore
                options={this.options}
                data={this.data}
                // Uncomment the line below to use predefined target
                // target={this.target}
                onDelete={(/* chart: uPlot */) => console.log('Deleted from render function')}
                onCreate={(/* chart: uPlot */) => console.log('Created from render function')}
            />
        </div>);
    }
})
Example #9
Source File: uplot-vue-example.tsx    From uplot-wrappers with MIT License 5 votes vote down vote up
App = Vue.extend<
    {options: uPlot.Options, data: uPlot.AlignedData, target: HTMLElement},
    {onCreateFromTemplate: (chart: uPlot) => void, onDeleteFromTemplate: (chart: uPlot) => void},
    Record<string, never>, Record<string, never>
>({
    name: 'UplotVueExample',
    components: {uplotvue: UplotVue},
    // @ts-ignore
    data() {
        return {
            options: {
                title: 'Chart', width: 400, height: 300,
                series: [{
                    label: 'Date'
                }, {
                    label: '',
                    points: {show: false},
                    stroke: 'blue',
                    fill: 'blue'
                }],
                plugins: [dummyPlugin()],
                scales: {x: {time: false}}
            },
            target: null as unknown as HTMLElement
        };
    },
    beforeMount() {
        // Initialize data inside mounted hook, to prevent Vue from adding watchers, otherwise performance becomes unbearable
        this.data = [[...new Array(100000)].map((_, i) => i), [...new Array(100000)].map((_, i) => i % 1000)];
    },
    mounted() {
        this.target = this.$refs.root as HTMLElement;
        setInterval(() => {
            const options = {
                ...this.options,
                title: (this.$refs.root as HTMLElement).id ? 'Rendered with template' : 'Rendered with function'
            };
            const data: uPlot.AlignedData = [
                [...this.data[0], this.data[0].length],
                [...this.data[1], this.data[0].length % 1000]
            ];
            this.data = data;
            // Since we disabled reactivity for data above
            this.$forceUpdate();
            this.options = options;
        }, 100);
    },
    methods: {
        onCreateFromTemplate(/* chart: uPlot */) {
            console.log('Created from template');
        },
        onDeleteFromTemplate(/* chart: uPlot */) {
            console.log('Deleted from template');
        }
    },
    render(h: CreateElement): VNode {
        // @ts-ignore
        return (<div ref='root'>
            <UplotVue
                // @ts-ignore
                key="render-key"
                // @ts-ignore
                options={this.options}
                data={this.data}
                // Uncomment the line below to use predefined target
                // target={this.target}
                onDelete={(/* chart: uPlot */) => console.log('Deleted from render function')}
                onCreate={(/* chart: uPlot */) => console.log('Created from render function')}
            />
        </div>);
    }
})
Example #10
Source File: index.ts    From gitmars with GNU General Public License v3.0 5 votes vote down vote up
instance: VNode
Example #11
Source File: utils.ts    From vue3-datagrid with MIT License 5 votes vote down vote up
defineContainer = <Props>(name: string, [...componentProps]: string[] = [], componentOptions: ComponentOptions = {}) => {
  const { modelProp, modelUpdateEvent } = componentOptions;

  /**
  * Create a Vue component wrapper around a Web Component.
  * Note: The `props` here are not all properties on a component.
  * They refer to whatever properties are set on an instance of a component.
  */
  const Container = defineComponent<Props & InputProps>((props, { attrs, slots, emit }) => {
    let modelPropValue = (props as any)[modelProp];
    const containerRef = ref<HTMLElement>();
    const classes = new Set(getComponentClasses(attrs.class));
    const onVnodeBeforeMount = (vnode: VNode) => {
      // Add a listener to tell Vue to update the v-model
      if (vnode.el) {
        vnode.el.addEventListener(modelUpdateEvent.toLowerCase(), (e: Event) => {
          modelPropValue = (e?.target as any)[modelProp];
          emit(UPDATE_VALUE_EVENT, modelPropValue);

          /**
           * We need to emit the change event here
           * rather than on the web component to ensure
           * that any v-model bindings have been updated.
           * Otherwise, the developer will listen on the
           * native web component, but the v-model will
           * not have been updated yet.
           */
          emit(modelUpdateEvent, e);
          e.stopImmediatePropagation();
        });
      }
    };

    const currentInstance = getCurrentInstance();
    const hasRouter = currentInstance?.appContext?.provides[NAV_MANAGER];
    const navManager: NavManager | undefined = hasRouter ? inject(NAV_MANAGER) : undefined;
    const handleRouterLink = (ev: Event) => {
      const { routerLink } = props as any;
      if (!routerLink) return;

      const routerProps = Object.keys(props).filter(p => p.startsWith(ROUTER_PROP_REFIX));

      if (navManager !== undefined) {
        let navigationPayload: any = { event: ev };
        routerProps.forEach(prop => {
          navigationPayload[prop] = (props as any)[prop];
        });
        navManager.navigate(navigationPayload);
      } else {
        console.warn('Tried to navigate, but no router was found. Make sure you have mounted Vue Router.');
      }
    }

    return () => {
      getComponentClasses(attrs.class).forEach(value => {
        classes.add(value);
      });

      const oldClick = (props as any).onClick;
      const handleClick = (ev: Event) => {
        if (oldClick !== undefined) {
          oldClick(ev);
        }
        if (!ev.defaultPrevented) {
          handleRouterLink(ev);
        }
      }

      let propsToAdd = {
        ref: containerRef,
        class: getElementClasses(containerRef, classes),
        onClick: handleClick,
        onVnodeBeforeMount: (modelUpdateEvent) ? onVnodeBeforeMount : undefined
      };

      for (const [prop, value] of Object.entries(props)) {
        if (value !== EMPTY_SENTINEL) {
          propsToAdd[prop] = value;
        }
      }

      if (modelProp) {
        propsToAdd = {
          ...propsToAdd,
          [modelProp]: props.modelValue !== EMPTY_SENTINEL ? props.modelValue : modelPropValue
        }
      }

      return h(name, propsToAdd, slots.default && slots.default());
    }
  });

  Container.displayName = name;
  componentProps.push(ROUTER_LINK_VALUE);
  if (modelProp) {
    componentProps.push(MODEL_VALUE);
    Container.emits = [UPDATE_VALUE_EVENT, modelUpdateEvent];
  }

  Container.props = {};
  for (const componentProp of componentProps) {
	Container.props[componentProp] = { default: EMPTY_SENTINEL };
  }

  return Container;
}
Example #12
Source File: types.ts    From am-editor with MIT License 5 votes vote down vote up
buttonProps = {
	engine: Object as PropType<EngineInterface | undefined>,
	name: {
		type: String,
		required: true,
	} as const,
	icon: String,
	content: [String, Function] as PropType<
		string | ((engine?: EngineInterface) => string) | VNode
	>,
	title: String,
	placement: String as PropType<Placement>,
	hotkey: [String, Object] as PropType<boolean | string | undefined>,
	command: Object as PropType<Command>,
	autoExecute: {
		type: [Boolean, undefined] as PropType<boolean | undefined>,
		default: undefined,
	},
	className: String,
	active: {
		type: [Boolean, undefined] as PropType<boolean | undefined>,
		default: undefined,
	},
	disabled: {
		type: [Boolean, undefined] as PropType<boolean | undefined>,
		default: undefined,
	},
	onClick: Function as PropType<
		(event: MouseEvent, engine?: EngineInterface) => void | boolean
	>,
	onMouseDown: Function as PropType<
		(event: MouseEvent, engine?: EngineInterface) => void | boolean
	>,
	onMouseEnter: Function as PropType<
		(event: MouseEvent, engine?: EngineInterface) => void | boolean
	>,
	onMouseLevel: Function as PropType<
		(event: MouseEvent, engine?: EngineInterface) => void | boolean
	>,
}
Example #13
Source File: weak-maps.ts    From slate-vue with MIT License 5 votes vote down vote up
KEY_TO_VNODE = new Map<Object, VNode>()
Example #14
Source File: directive.ts    From vue3-gettext with MIT License 5 votes vote down vote up
/**
 * A directive to translate content according to the current language.
 *
 * Use this directive instead of the component if you need to translate HTML content.
 * It's too tricky to support HTML content within the component because we cannot get the raw HTML to use as `msgid`.
 *
 * This directive has a similar interface to the <translate> component, supporting
 * `translate-comment`, `translate-context`, `translate-plural`, `translate-n`.
 *
 * `<p v-translate translate-comment='Good stuff'>This is <strong class='txt-primary'>Sparta</strong>!</p>`
 *
 * If you need interpolation, you must add an expression that outputs binding value that changes with each of the
 * context variable:
 * `<p v-translate="fullName + location">I am %{ fullName } and from %{ location }</p>`
 * @deprecated
 */
export default function directive(language: Language): ObjectDirective<HTMLElement, any> {
  const update = (el: HTMLElement, binding: DirectiveBinding, vnode: VNode) => {
    // Store the current language in the element's dataset.
    el.dataset.currentLanguage = language.current;
    updateTranslation(language, el, binding, vnode);
  };
  return {
    beforeMount(el: HTMLElement, binding: DirectiveBinding, vnode: VNode) {
      // Get the raw HTML and store it in the element's dataset (as advised in Vue's official guide).
      if (!el.dataset.msgid) {
        el.dataset.msgid = el.innerHTML;
      }

      watch(language, () => {
        update(el, binding, vnode);
      });

      update(el, binding, vnode);
    },
    updated(el: HTMLElement, binding: DirectiveBinding, vnode: VNode) {
      update(el, binding, vnode);
    },
  };
}
Example #15
Source File: param.ts    From jz-gantt with MIT License 5 votes vote down vote up
private __sn: VNode | null;
Example #16
Source File: param.ts    From jz-gantt with MIT License 5 votes vote down vote up
/**
   * 拦截所有插槽内容节点,处理后统一使用。
   * @param nodes
   * @returns
   */
  setNodes(nodes: VNode[] | null) {
    if (!isArray(nodes)) return;

    let colVNodeKey = 0;

    // 拦截所有插槽,做一下筛选和处理。保留指定插槽
    (nodes as VNode[])
      .filter(v => {
        const type = (v.type as Component)?.name;

        return (
          // 接收自定义组件,不接受原生元素
          type &&
          ParamData.__isComponent(v) &&
          // 接受 JGanttColumn 插槽,并且该插槽需要携带 label 属性
          ((ParamData.__checkType(type, Variables.name.column) &&
            !!v.props?.label) ||
            // 或者接受一个 JGanttSlider 组件。多个 JGanttSlider 保留最后一个
            ParamData.__checkType(type, Variables.name.slider))
        );
      })
      .forEach(v => {
        const type = (v.type as Component).name as string;

        // 分别对不同组件进行整理
        if (ParamData.__checkType(type, Variables.name.column)) {
          // 添加唯一 key
          // eslint-disable-next-line no-param-reassign
          v.key = colVNodeKey;
          Object.assign(v.props, { __key: colVNodeKey });

          const label: string = v.props?.label;
          const width = parseNumber(
            v.props?.width,
            Variables.size.defaultTableColumnWidth
          );

          // 添加 merge 方法,忽略第一行
          let mergeOps = v.props?.merge;
          if (v.key === 0) mergeOps = undefined;

          this.__addTHeader(
            new TableHeader().initData({
              key: colVNodeKey,
              label,
              text: v.props?.name || label,
              width
            })
          );

          this.__addCNode(
            new ColumnNode().initData({
              key: colVNodeKey,
              label,
              node: v,
              merge: mergeOps
            })
          );

          colVNodeKey += 1;
        } else if (ParamData.__checkType(type, Variables.name.slider)) {
          this.__sn = v;
        }
      });
  }
Example #17
Source File: columnNode.ts    From jz-gantt with MIT License 5 votes vote down vote up
/**
   * 节点内容
   */
  node: VNode | null;
Example #18
Source File: formatRenderer.ts    From vue-i18n-next with MIT License 5 votes vote down vote up
function isVNode(target: unknown): target is VNode[] {
  return isArray(target) && !isString(target[0])
}
Example #19
Source File: utils.ts    From elements with MIT License 5 votes vote down vote up
defineContainer = <Props>(
  name: string,
  defineCustomElement: any,
  componentProps: string[] = [],
  modelProp?: string,
  modelUpdateEvent?: string,
  externalModelUpdateEvent?: string
) => {
  /**
  * Create a Vue component wrapper around a Web Component.
  * Note: The `props` here are not all properties on a component.
  * They refer to whatever properties are set on an instance of a component.
  */

  if (defineCustomElement !== undefined) {
    defineCustomElement();
  }

  const Container = defineComponent<Props & InputProps>((props: any, { attrs, slots, emit }) => {
    let modelPropValue = props[modelProp];
    const containerRef = ref<HTMLElement>();
    const classes = new Set(getComponentClasses(attrs.class));
    const onVnodeBeforeMount = (vnode: VNode) => {
      // Add a listener to tell Vue to update the v-model
      if (vnode.el) {
        const eventsNames = Array.isArray(modelUpdateEvent) ? modelUpdateEvent : [modelUpdateEvent];
        eventsNames.forEach((eventName: string) => {
          vnode.el.addEventListener(eventName.toLowerCase(), (e: Event) => {
            modelPropValue = (e as CustomEvent).detail;
            emit(UPDATE_VALUE_EVENT, modelPropValue);

            /**
             * We need to emit the change event here
             * rather than on the web component to ensure
             * that any v-model bindings have been updated.
             * Otherwise, the developer will listen on the
             * native web component, but the v-model will
             * not have been updated yet.
             */
            if (externalModelUpdateEvent) {
              emit(externalModelUpdateEvent, e);
            }
          });
        });
      }
    };

    const currentInstance = getCurrentInstance();
    const hasRouter = currentInstance?.appContext?.provides[NAV_MANAGER];
    const navManager: NavManager | undefined = hasRouter ? inject(NAV_MANAGER) : undefined;
    const handleRouterLink = (ev: Event) => {
      const { routerLink } = props;
      if (routerLink === EMPTY_PROP) return;

      if (navManager !== undefined) {
        let navigationPayload: any = { event: ev };
        for (const key in props) {
          const value = props[key];
          if (props.hasOwnProperty(key) && key.startsWith(ROUTER_PROP_PREFIX) && value !== EMPTY_PROP) {
            navigationPayload[key] = value;
          }
        }

        navManager.navigate(navigationPayload);
      } else {
        console.warn('Tried to navigate, but no router was found. Make sure you have mounted Vue Router.');
      }
    }

    return () => {
      modelPropValue = props[modelProp];

      getComponentClasses(attrs.class).forEach(value => {
        classes.add(value);
      });

      const oldClick = props.onClick;
      const handleClick = (ev: Event) => {
        if (oldClick !== undefined) {
          oldClick(ev);
        }
        if (!ev.defaultPrevented) {
          handleRouterLink(ev);
        }
      }

      let propsToAdd: any = {
        ref: containerRef,
        class: getElementClasses(containerRef, classes),
        onClick: handleClick,
        onVnodeBeforeMount: (modelUpdateEvent) ? onVnodeBeforeMount : undefined
      };

      /**
       * We can use Object.entries here
       * to avoid the hasOwnProperty check,
       * but that would require 2 iterations
       * where as this only requires 1.
       */
      for (const key in props) {
        const value = props[key];
        if (props.hasOwnProperty(key) && value !== EMPTY_PROP) {
          propsToAdd[key] = value;
        }
      }

      if (modelProp) {
        /**
         * If form value property was set using v-model
         * then we should use that value.
         * Otherwise, check to see if form value property
         * was set as a static value (i.e. no v-model).
         */
        if (props[MODEL_VALUE] !== EMPTY_PROP) {
          propsToAdd = {
            ...propsToAdd,
            [modelProp]: props[MODEL_VALUE]
          }
        } else if (modelPropValue !== EMPTY_PROP) {
          propsToAdd = {
            ...propsToAdd,
            [modelProp]: modelPropValue
          }
        }
      }

      return h(name, propsToAdd, slots.default && slots.default());
    }
  });

  Container.displayName = name;

  Container.props = {
    [ROUTER_LINK_VALUE]: DEFAULT_EMPTY_PROP
  };

  componentProps.forEach(componentProp => {
    Container.props[componentProp] = DEFAULT_EMPTY_PROP;
  });

  if (modelProp) {
    Container.props[MODEL_VALUE] = DEFAULT_EMPTY_PROP;
    Container.emits = [UPDATE_VALUE_EVENT, externalModelUpdateEvent];
  }

  return Container;
}
Example #20
Source File: serve.ts    From fower with MIT License 5 votes vote down vote up
new Vue({
  render: (h): VNode => h(Dev),
}).$mount('#app')
Example #21
Source File: text.tsx    From slate-vue with MIT License 4 votes vote down vote up
Text = tsx.component({
  props: {
    text: {
      type: Object as PropType<SlateText>
    },
    isLast: Boolean,
    parent: {
      type: Object as PropType<Element>
    },
    decorations: {
      type: Array as PropType<Array<Range>>
    },
  },
  components: {
    leaf
  },
  inject: ['decorate', 'placeholder'],
  provide(): object {
    return {
      'text': this.text,
      'isLast': this.isLast,
      'parent': this.parent
    }
  },
  data(): Pick<providedByEditable, 'placeholder' | 'decorate'> & UseRef {
    return {
      ref: null
    }
  },
  hooks() {
    const ref = this.ref = useRef(null);
    const {text} = this;
    const editor = this.$editor;
    const key = VueEditor.findKey(editor, text)
    const initRef = () => {
      useEffect(()=>{
        if (ref.current) {
          KEY_TO_ELEMENT.set(key, ref.current)
          NODE_TO_ELEMENT.set(text, ref.current)
          ELEMENT_TO_NODE.set(ref.current, text)
        } else {
          KEY_TO_ELEMENT.delete(key)
          NODE_TO_ELEMENT.delete(text)
        }
      })
    };

    initRef()
  },
  render(h, ctx): VNode {
    const { text, placeholder } = this
    let decorations: Array<any> = this.decorations;
    if(!decorations) {
      const editor = this.$editor
      const p = VueEditor.findPath(editor, text)
      if(this.decorate) {
        decorations = this.decorate([text, p])
      }

      // init placeholder
      if (
        placeholder &&
        editor.children.length === 1 &&
        Array.from(Node.texts(editor)).length === 1 &&
        Node.string(editor) === ''
      ) {
        const start = Editor.start(editor, [])
        decorations.push({
          [PLACEHOLDER_SYMBOL]: true,
          placeholder,
          anchor: start,
          focus: start,
        })
      }
    }
    const leaves = SlateText.decorations(text, decorations)
    const children = []
    for (let i = 0; i < leaves.length; i++) {
      const leaf = leaves[i];
      children.push(
        <leaf
          leaf={leaf}
        />
        )
    }
    return (
      <span data-slate-node="text" ref={this.ref!.id}>
        {children}
      </span>
    )
  }
})
Example #22
Source File: element.tsx    From slate-vue with MIT License 4 votes vote down vote up
Element = tsx.component({
  props: {
    element: {
      type: Object as PropType<SlateElement>
    }
  },
  inject: ['readOnly', 'renderElement'],
  components:{
    Children
  },
  // For types
  data(): Pick<providedByEditable, 'readOnly' | 'renderElement'> & UseRef {
    return {
      ref: null
    }
  },
  mounted() {
    elementWatcherPlugin(this, 'element')
  },
  hooks() {
    const ref = this.ref = useRef(null);
    const element = this.element
    const key = VueEditor.findKey(this.$editor, element)

    useEffect(()=>{
      if (ref.current) {
        KEY_TO_ELEMENT.set(key, ref.current)
        NODE_TO_ELEMENT.set(element, ref.current)
        ELEMENT_TO_NODE.set(ref.current, element)
      } else {
        KEY_TO_ELEMENT.delete(key)
        NODE_TO_ELEMENT.delete(element)
      }
    })
  },
  render(h): VNode {
    // call renderElement with children, attribute and element
    const {element, renderElement = DefaultElement, ref} = this;
    const editor = this.$editor
    const isInline = editor.isInline(element)
    let children: VueTsxSupport.JSX.Element | null = (
      <Children
        node={element}
      />
    )
    const attributes: RenderElementAttributes = {
      'data-slate-node': 'element'
    };
    if (isInline) {
      attributes['data-slate-inline'] = true
    }

    // If it's a block node with inline children, add the proper `dir` attribute
    // for text direction.
    if (!isInline && Editor.hasInlines(editor, element)) {
      const text = Node.string(element)
      const dir = getDirection(text)

      if (dir === 'rtl') {
        attributes.dir = dir
      }
    }

    // If it's a void node, wrap the children in extra void-specific elements.
    if (Editor.isVoid(editor, element)) {
      attributes['data-slate-void'] = true

      if (!this.readOnly && isInline) {
        attributes.contentEditable = false
      }

      const Tag = isInline ? 'span' : 'div'
      const [[text]] = Node.texts(element)

      children = this.readOnly ? null : (
        <Tag
          data-slate-spacer
          style={{
            height: '0',
            color: 'transparent',
            outline: 'none',
            position: 'absolute',
          }}
        >
          <Text decorations={[]} isLast={false} parent={element} text={text} />
        </Tag>
      )

      NODE_TO_INDEX.set(text, 0)
      NODE_TO_PARENT.set(text, element)
    }

    return h(renderElement({
      element,
      attributes,
      children
    }), {ref: ref!.id})
  }
})
Example #23
Source File: helper.ts    From vue-i18n-next with MIT License 4 votes vote down vote up
export function mount(
  targetComponent: Parameters<typeof createApp>[0],
  i18n: I18n,
  options: Partial<MountOptions> = {}
): Promise<Wrapper> {
  const TargetComponent = targetComponent
  const installI18n = isBoolean(options.installI18n)
    ? options.installI18n
    : true
  return new Promise((resolve, reject) => {
    // NOTE: only supports props as an object
    const propsData = reactive(
      assign(
        // @ts-ignore
        initialProps(TargetComponent.props || {}),
        options.propsData
      )
    )

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    function setProps(partialProps: Record<string, any>) {
      assign(propsData, partialProps)
      return nextTick()
    }

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const slots: Record<string, (propsData: any) => VNode> = {}

    const Wrapper = defineComponent({
      emits: ['ready'],
      setup(_props, { emit }) {
        const componentInstanceRef = shallowRef<ComponentPublicInstance>()
        onErrorCaptured(err => {
          reject(err)
          return true
        })
        return () => {
          return h(
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            TargetComponent as any,
            {
              ref: componentInstanceRef,
              onVnodeMounted() {
                emit('ready', componentInstanceRef.value)
              },
              ...propsData
            },
            slots
          )
        }
      }
    })

    const app = createApp(Wrapper, {
      onReady: (instance: ComponentPublicInstance) => {
        resolve({ app, vm: instance, rootEl, setProps, html, find })
      }
    })

    if (options.provide) {
      const keys = getKeys(options.provide)

      for (const key of keys) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        app.provide(key, options.provide[key as any])
      }
    }

    if (options.components) {
      for (const key in options.components) {
        app.component(key, options.components[key])
      }
    }

    if (options.slots) {
      for (const key in options.slots) {
        slots[key] = compileSlot(options.slots[key])
      }
    }

    installI18n && app.use(i18n)

    const rootEl = document.createElement('div')
    document.body.appendChild(rootEl)

    try {
      app.mount(rootEl)
    } catch (e) {
      return reject(e)
    }

    function html() {
      return rootEl.innerHTML
    }

    function find(selector: string) {
      return rootEl.querySelector(selector)
    }

    activeWrapperRemovers.push(() => {
      app.unmount()
      rootEl.remove()
    })
  })
}
Example #24
Source File: composer.ts    From vue-i18n-next with MIT License 4 votes vote down vote up
/**
 * Create composer interface factory
 *
 * @internal
 */
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function createComposer(options: any = {}, VueI18nLegacy?: any): any {
  type Message = VueMessageType
  const { __root } = options as ComposerInternalOptions<
    LocaleMessages<LocaleMessage<Message>>,
    DateTimeFormatsType,
    NumberFormatsType
  >
  const _isGlobal = __root === undefined

  let _inheritLocale = isBoolean(options.inheritLocale)
    ? options.inheritLocale
    : true

  const _locale = ref<Locale>(
    // prettier-ignore
    __root && _inheritLocale
      ? __root.locale.value
      : isString(options.locale)
        ? options.locale
        : DEFAULT_LOCALE
  )

  const _fallbackLocale = ref<FallbackLocale>(
    // prettier-ignore
    __root && _inheritLocale
      ? __root.fallbackLocale.value
      : isString(options.fallbackLocale) ||
        isArray(options.fallbackLocale) ||
        isPlainObject(options.fallbackLocale) ||
        options.fallbackLocale === false
        ? options.fallbackLocale
        : _locale.value
  )

  const _messages = ref<LocaleMessages<LocaleMessage<Message>>>(
    getLocaleMessages<LocaleMessages<LocaleMessage<Message>>>(
      _locale.value as Locale,
      options
    )
  )

  // prettier-ignore
  const _datetimeFormats = !__LITE__
    ? ref<DateTimeFormatsType>(
        isPlainObject(options.datetimeFormats)
          ? options.datetimeFormats
          : { [_locale.value]: {} }
      )
    : /* #__PURE__*/ ref<DateTimeFormatsType>({})

  // prettier-ignore
  const _numberFormats = !__LITE__
    ? ref<NumberFormatsType>(
        isPlainObject(options.numberFormats)
          ? options.numberFormats
          : { [_locale.value]: {} }
      )
    : /* #__PURE__*/ ref<NumberFormatsType>({})

  // warning suppress options
  // prettier-ignore
  let _missingWarn = __root
    ? __root.missingWarn
    : isBoolean(options.missingWarn) || isRegExp(options.missingWarn)
      ? options.missingWarn
      : true

  // prettier-ignore
  let _fallbackWarn = __root
    ? __root.fallbackWarn
    : isBoolean(options.fallbackWarn) || isRegExp(options.fallbackWarn)
      ? options.fallbackWarn
      : true

  // prettier-ignore
  let _fallbackRoot = __root
    ? __root.fallbackRoot
    : isBoolean(options.fallbackRoot)
      ? options.fallbackRoot
      : true

  // configure fall back to root
  let _fallbackFormat = !!options.fallbackFormat

  // runtime missing
  let _missing = isFunction(options.missing) ? options.missing : null
  let _runtimeMissing = isFunction(options.missing)
    ? defineCoreMissingHandler(options.missing)
    : null

  // postTranslation handler
  let _postTranslation = isFunction(options.postTranslation)
    ? options.postTranslation
    : null

  // prettier-ignore
  let _warnHtmlMessage = __root
    ? __root.warnHtmlMessage
    : isBoolean(options.warnHtmlMessage)
      ? options.warnHtmlMessage
      : true

  let _escapeParameter = !!options.escapeParameter

  // custom linked modifiers
  // prettier-ignore
  const _modifiers = __root
    ? __root.modifiers
    : isPlainObject(options.modifiers)
      ? options.modifiers
      : {} as LinkedModifiers<Message>

  // pluralRules
  let _pluralRules = options.pluralRules || (__root && __root.pluralRules)

  // for bridge
  let __legacy: any
  if (__BRIDGE__) {
    if (!isLegacyVueI18n(VueI18nLegacy)) {
      createI18nError(I18nErrorCodes.NOT_COMPATIBLE_LEGACY_VUE_I18N)
    }
    const legacyOptions = {
      locale: _locale.value,
      fallbackLocale: _fallbackLocale.value,
      messages: _messages.value,
      dateTimeFormats: _datetimeFormats.value,
      numberFormats: _numberFormats.value,
      modifiers: _modifiers,
      missing: _missing,
      fallbackRoot: _fallbackRoot,
      postTranslation: _postTranslation,
      pluralizationRules: _pluralRules,
      escapeParameterHtml: _escapeParameter,
      sync: _inheritLocale,
      silentFallbackWarn: isBoolean(_fallbackWarn)
        ? !_fallbackWarn
        : _fallbackWarn,
      silentTranslationWarn: isBoolean(_missingWarn)
        ? !_missingWarn
        : _missingWarn,
      formatFallbackMessages: isBoolean(_fallbackFormat)
        ? !_fallbackFormat
        : _fallbackFormat,
      warnHtmlInMessage: isBoolean(_warnHtmlMessage)
        ? _warnHtmlMessage
          ? 'warn'
          : 'off'
        : 'off',
      __VUE_I18N_BRIDGE__
    }
    __legacy = new VueI18nLegacy(legacyOptions)
  }

  // runtime context
  // eslint-disable-next-line prefer-const
  let _context: CoreContext

  function getCoreContext(): CoreContext {
    _isGlobal && setFallbackContext(null)

    const ctxOptions = {
      version: VERSION,
      locale: _locale.value,
      fallbackLocale: _fallbackLocale.value,
      messages: _messages.value,
      modifiers: _modifiers,
      pluralRules: _pluralRules,
      missing: _runtimeMissing === null ? undefined : _runtimeMissing,
      missingWarn: _missingWarn,
      fallbackWarn: _fallbackWarn,
      fallbackFormat: _fallbackFormat,
      unresolving: true,
      postTranslation: _postTranslation === null ? undefined : _postTranslation,
      warnHtmlMessage: _warnHtmlMessage,
      escapeParameter: _escapeParameter,
      messageResolver: options.messageResolver,
      __meta: { framework: 'vue' }
    }

    if (!__LITE__) {
      ;(ctxOptions as any).datetimeFormats = _datetimeFormats.value
      ;(ctxOptions as any).numberFormats = _numberFormats.value
      ;(ctxOptions as any).__datetimeFormatters = isPlainObject(_context)
        ? (_context as unknown as CoreInternalContext).__datetimeFormatters
        : undefined
      ;(ctxOptions as any).__numberFormatters = isPlainObject(_context)
        ? (_context as unknown as CoreInternalContext).__numberFormatters
        : undefined
    }
    if (!__BRIDGE__ && __DEV__) {
      ;(ctxOptions as any).__v_emitter = isPlainObject(_context)
        ? (_context as unknown as CoreInternalContext).__v_emitter
        : undefined
    }

    const ctx = createCoreContext(ctxOptions as any)
    _isGlobal && setFallbackContext(ctx)

    return ctx
  }

  _context = getCoreContext()
  updateFallbackLocale(_context, _locale.value, _fallbackLocale.value)

  // track reactivity
  function trackReactivityValues() {
    return !__LITE__
      ? [
          _locale.value,
          _fallbackLocale.value,
          _messages.value,
          _datetimeFormats.value,
          _numberFormats.value
        ]
      : [_locale.value, _fallbackLocale.value, _messages.value]
  }

  // locale
  const locale = computed({
    get: () => _locale.value,
    set: val => {
      _locale.value = val
      if (__BRIDGE__) {
        if (__legacy && !_isGlobal) {
          __legacy.locale = val
        }
      }
      _context.locale = _locale.value
    }
  })

  // fallbackLocale
  const fallbackLocale = computed({
    get: () => _fallbackLocale.value,
    set: val => {
      _fallbackLocale.value = val
      if (__BRIDGE__) {
        if (__legacy && !_isGlobal) {
          __legacy.fallbackLocale = val
        }
      }
      _context.fallbackLocale = _fallbackLocale.value
      updateFallbackLocale(_context, _locale.value, val)
    }
  })

  // messages
  const messages = computed<LocaleMessages<LocaleMessage<Message>, Message>>(
    () => _messages.value as any
  )

  // datetimeFormats
  const datetimeFormats = /* #__PURE__*/ computed<DateTimeFormatsType>(
    () => _datetimeFormats.value
  )

  // numberFormats
  const numberFormats = /* #__PURE__*/ computed<NumberFormatsType>(
    () => _numberFormats.value
  )

  // getPostTranslationHandler
  function getPostTranslationHandler(): PostTranslationHandler<Message> | null {
    return isFunction(_postTranslation) ? _postTranslation : null
  }

  // setPostTranslationHandler
  function setPostTranslationHandler(
    handler: PostTranslationHandler | null
  ): void {
    _postTranslation = handler
    _context.postTranslation = handler
  }

  // getMissingHandler
  function getMissingHandler(): MissingHandler | null {
    return _missing
  }

  // setMissingHandler
  function setMissingHandler(handler: MissingHandler | null): void {
    if (handler !== null) {
      _runtimeMissing = defineCoreMissingHandler(handler)
    }
    _missing = handler
    _context.missing = _runtimeMissing
  }

  function isResolvedTranslateMessage(
    type: ComposerWarnType,
    arg: any // eslint-disable-line @typescript-eslint/no-explicit-any
  ): boolean {
    return type !== 'translate' || !arg.resolvedMessage
  }

  function wrapWithDeps<T, U = T>(
    fn: (context: unknown) => unknown,
    argumentParser: () => unknown[],
    warnType: ComposerWarnType,
    fallbackSuccess: (root: Composer<T> & ComposerInternal) => U,
    fallbackFail: (key: unknown) => U,
    successCondition: (val: unknown) => boolean
  ): U {
    trackReactivityValues() // track reactive dependency
    // NOTE: experimental !!
    let ret: unknown
    if (__DEV__ || __FEATURE_PROD_INTLIFY_DEVTOOLS__) {
      try {
        setAdditionalMeta(getMetaInfo())
        if (!_isGlobal) {
          _context.fallbackContext = __root
            ? (getFallbackContext() as any)
            : undefined
        }
        ret = fn(_context)
      } finally {
        setAdditionalMeta(null)
        if (!_isGlobal) {
          _context.fallbackContext = undefined
        }
      }
    } else {
      ret = fn(_context)
    }
    if (isNumber(ret) && ret === NOT_REOSLVED) {
      const [key, arg2] = argumentParser()
      if (
        __DEV__ &&
        __root &&
        isString(key) &&
        isResolvedTranslateMessage(warnType, arg2)
      ) {
        if (
          _fallbackRoot &&
          (isTranslateFallbackWarn(_fallbackWarn, key) ||
            isTranslateMissingWarn(_missingWarn, key))
        ) {
          warn(
            getWarnMessage(I18nWarnCodes.FALLBACK_TO_ROOT, {
              key,
              type: warnType
            })
          )
        }
        // for vue-devtools timeline event
        if (!__BRIDGE__ && __DEV__) {
          const { __v_emitter: emitter } =
            _context as unknown as CoreInternalContext
          if (emitter && _fallbackRoot) {
            emitter.emit(VueDevToolsTimelineEvents.FALBACK, {
              type: warnType,
              key,
              to: 'global',
              groupId: `${warnType}:${key}`
            })
          }
        }
      }
      return __root && _fallbackRoot
        ? fallbackSuccess(__root as unknown as Composer<T> & ComposerInternal)
        : fallbackFail(key)
    } else if (successCondition(ret)) {
      return ret as U
    } else {
      /* istanbul ignore next */
      throw createI18nError(I18nErrorCodes.UNEXPECTED_RETURN_TYPE)
    }
  }

  // t
  function t(...args: unknown[]): string {
    return wrapWithDeps<string>(
      context => Reflect.apply(translate, null, [context, ...args]) as string,
      () => parseTranslateArgs(...args),
      'translate',
      root => Reflect.apply(root.t, root, [...args]),
      key => key as string,
      val => isString(val)
    )
  }

  // rt
  function rt(...args: unknown[]): string {
    const [arg1, arg2, arg3] = args
    if (arg3 && !isObject(arg3)) {
      throw createI18nError(I18nErrorCodes.INVALID_ARGUMENT)
    }
    return t(...[arg1, arg2, assign({ resolvedMessage: true }, arg3 || {})])
  }

  // d
  function d(...args: unknown[]): string {
    return wrapWithDeps<string>(
      context => Reflect.apply(datetime, null, [context, ...args]) as string,
      () => parseDateTimeArgs(...args),
      'datetime format',
      root => Reflect.apply(root.d, root, [...args]),
      () => MISSING_RESOLVE_VALUE,
      val => isString(val)
    )
  }

  // n
  function n(...args: unknown[]): string {
    return wrapWithDeps<string>(
      context => Reflect.apply(number, null, [context, ...args]) as string,
      () => parseNumberArgs(...args),
      'number format',
      root => Reflect.apply(root.n, root, [...args]),
      () => MISSING_RESOLVE_VALUE,
      val => isString(val)
    )
  }

  // for custom processor
  function normalize(
    values: MessageType<string | VNode>[]
  ): MessageType<VNode>[] {
    return values.map(val => (isString(val) ? createTextNode(val) : val))
  }
  const interpolate = (val: unknown): MessageType<VNode> => val as VNode
  const processor = {
    normalize,
    interpolate,
    type: 'vnode'
  } as MessageProcessor<VNode>

  // transrateVNode, using for `i18n-t` component
  function transrateVNode(...args: unknown[]): VNodeArrayChildren {
    return wrapWithDeps<VNode, VNodeArrayChildren>(
      context => {
        let ret: unknown
        const _context = context as CoreContext<
          VNode,
          LocaleMessages<LocaleMessage<Message>>
        >
        try {
          _context.processor = processor
          ret = Reflect.apply(translate, null, [_context, ...args])
        } finally {
          _context.processor = null
        }
        return ret
      },
      () => parseTranslateArgs(...args),
      'translate',
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      root => (root as any)[TransrateVNodeSymbol](...args),
      key => [createTextNode(key as string)],
      val => isArray(val)
    )
  }

  // numberParts, using for `i18n-n` component
  function numberParts(...args: unknown[]): string | Intl.NumberFormatPart[] {
    return wrapWithDeps<string | Intl.NumberFormatPart[]>(
      context => Reflect.apply(number, null, [context, ...args]),
      () => parseNumberArgs(...args),
      'number format',
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      root => (root as any)[NumberPartsSymbol](...args),
      () => [],
      val => isString(val) || isArray(val)
    )
  }

  // datetimeParts, using for `i18n-d` component
  function datetimeParts(
    ...args: unknown[]
  ): string | Intl.DateTimeFormatPart[] {
    return wrapWithDeps<string | Intl.DateTimeFormatPart[]>(
      context => Reflect.apply(datetime, null, [context, ...args]),
      () => parseDateTimeArgs(...args),
      'datetime format',
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      root => (root as any)[DatetimePartsSymbol](...args),
      () => [],
      val => isString(val) || isArray(val)
    )
  }

  function setPluralRules(rules: PluralizationRules): void {
    _pluralRules = rules
    _context.pluralRules = _pluralRules
  }

  // te
  function te(key: Path, locale?: Locale): boolean {
    const targetLocale = isString(locale) ? locale : _locale.value
    const message = getLocaleMessage(targetLocale)
    return _context.messageResolver(message, key) !== null
  }

  function resolveMessages(key: Path): LocaleMessageValue<Message> | null {
    let messages: LocaleMessageValue<Message> | null = null
    const locales = fallbackWithLocaleChain(
      _context,
      _fallbackLocale.value,
      _locale.value
    )
    for (let i = 0; i < locales.length; i++) {
      const targetLocaleMessages = _messages.value[locales[i]] || {}
      const messageValue = _context.messageResolver(targetLocaleMessages, key)
      if (messageValue != null) {
        messages = messageValue as LocaleMessageValue<Message>
        break
      }
    }
    return messages
  }

  // tm
  function tm(key: Path): LocaleMessageValue<Message> | {} {
    const messages = resolveMessages(key)
    // prettier-ignore
    return messages != null
      ? messages
      : __root
        ? __root.tm(key) as LocaleMessageValue<Message> || {}
        : {}
  }

  // getLocaleMessage
  function getLocaleMessage(locale: Locale): LocaleMessage<Message> {
    return (_messages.value[locale] || {}) as LocaleMessage<Message>
  }

  // setLocaleMessage
  function setLocaleMessage(locale: Locale, message: LocaleMessage<Message>) {
    _messages.value[locale] = message
    if (__BRIDGE__) {
      __legacy && __legacy.setLocaleMessage(locale, message)
    }
    _context.messages = _messages.value as typeof _context.messages
  }

  // mergeLocaleMessage
  function mergeLocaleMessage(
    locale: Locale,
    message: LocaleMessageDictionary<Message>
  ): void {
    _messages.value[locale] = _messages.value[locale] || {}
    if (__BRIDGE__) {
      __legacy && __legacy.mergeLocaleMessage(locale, message)
    }
    deepCopy(message, _messages.value[locale])
    _context.messages = _messages.value as typeof _context.messages
  }

  // getDateTimeFormat
  function getDateTimeFormat(locale: Locale): DateTimeFormat {
    return _datetimeFormats.value[locale] || {}
  }

  // setDateTimeFormat
  function setDateTimeFormat(locale: Locale, format: DateTimeFormat): void {
    _datetimeFormats.value[locale] = format
    if (__BRIDGE__) {
      __legacy && __legacy.setDateTimeFormat(locale, format)
    }
    _context.datetimeFormats = _datetimeFormats.value
    clearDateTimeFormat(_context, locale, format)
  }

  // mergeDateTimeFormat
  function mergeDateTimeFormat(locale: Locale, format: DateTimeFormat): void {
    _datetimeFormats.value[locale] = assign(
      _datetimeFormats.value[locale] || {},
      format
    )
    if (__BRIDGE__) {
      __legacy && __legacy.mergeDateTimeFormat(locale, format)
    }
    _context.datetimeFormats = _datetimeFormats.value
    clearDateTimeFormat(_context, locale, format)
  }

  // getNumberFormat
  function getNumberFormat(locale: Locale): NumberFormat {
    return _numberFormats.value[locale] || {}
  }

  // setNumberFormat
  function setNumberFormat(locale: Locale, format: NumberFormat): void {
    _numberFormats.value[locale] = format
    if (__BRIDGE__) {
      __legacy && __legacy.setNumberFormat(locale, format)
    }
    _context.numberFormats = _numberFormats.value
    clearNumberFormat(_context, locale, format)
  }

  // mergeNumberFormat
  function mergeNumberFormat(locale: Locale, format: NumberFormat): void {
    _numberFormats.value[locale] = assign(
      _numberFormats.value[locale] || {},
      format
    )
    if (__BRIDGE__) {
      __legacy && __legacy.mergeNumberFormat(locale, format)
    }
    _context.numberFormats = _numberFormats.value
    clearNumberFormat(_context, locale, format)
  }

  // for debug
  composerID++

  // watch root locale & fallbackLocale
  if (__root && inBrowser) {
    watch(__root.locale, (val: Locale) => {
      if (_inheritLocale) {
        _locale.value = val
        if (__BRIDGE__) {
          if (__legacy && !_isGlobal) {
            __legacy.locale = val
          }
        }
        _context.locale = val
        updateFallbackLocale(_context, _locale.value, _fallbackLocale.value)
      }
    })
    watch(__root.fallbackLocale, (val: FallbackLocale) => {
      if (_inheritLocale) {
        _fallbackLocale.value = val
        if (__BRIDGE__) {
          if (__legacy && !_isGlobal) {
            __legacy.fallbackLocale = val
          }
        }
        _context.fallbackLocale = val
        updateFallbackLocale(_context, _locale.value, _fallbackLocale.value)
      }
    })
  }

  // define basic composition API!
  const composer = {
    id: composerID,
    locale,
    fallbackLocale,
    get inheritLocale(): boolean {
      return _inheritLocale
    },
    set inheritLocale(val: boolean) {
      _inheritLocale = val
      if (__BRIDGE__) {
        if (__legacy) {
          __legacy._sync = val
        }
      }
      if (val && __root) {
        _locale.value = __root.locale.value as Locale
        _fallbackLocale.value = __root.fallbackLocale.value
        if (__BRIDGE__) {
          if (__legacy) {
            __legacy.locale = __root.locale.value as Locale
            __legacy.fallbackLocale = __root.fallbackLocale.value
          }
        }
        updateFallbackLocale(_context, _locale.value, _fallbackLocale.value)
      }
    },
    get availableLocales(): Locale[] {
      return Object.keys(_messages.value).sort()
    },
    messages,
    get modifiers(): LinkedModifiers<Message> {
      return _modifiers
    },
    get pluralRules(): PluralizationRules {
      return _pluralRules || {}
    },
    get isGlobal(): boolean {
      return _isGlobal
    },
    get missingWarn(): boolean | RegExp {
      return _missingWarn
    },
    set missingWarn(val: boolean | RegExp) {
      _missingWarn = val
      _context.missingWarn = _missingWarn
    },
    get fallbackWarn(): boolean | RegExp {
      return _fallbackWarn
    },
    set fallbackWarn(val: boolean | RegExp) {
      _fallbackWarn = val
      _context.fallbackWarn = _fallbackWarn
    },
    get fallbackRoot(): boolean {
      return _fallbackRoot
    },
    set fallbackRoot(val: boolean) {
      _fallbackRoot = val
    },
    get fallbackFormat(): boolean {
      return _fallbackFormat
    },
    set fallbackFormat(val: boolean) {
      _fallbackFormat = val
      _context.fallbackFormat = _fallbackFormat
    },
    get warnHtmlMessage(): boolean {
      return _warnHtmlMessage
    },
    set warnHtmlMessage(val: boolean) {
      _warnHtmlMessage = val
      _context.warnHtmlMessage = val
    },
    get escapeParameter(): boolean {
      return _escapeParameter
    },
    set escapeParameter(val: boolean) {
      _escapeParameter = val
      _context.escapeParameter = val
    },
    t,
    getLocaleMessage,
    setLocaleMessage,
    mergeLocaleMessage,
    getPostTranslationHandler,
    setPostTranslationHandler,
    getMissingHandler,
    setMissingHandler,
    [SetPluralRulesSymbol]: setPluralRules
  }

  if (!__LITE__) {
    ;(composer as any).datetimeFormats = datetimeFormats
    ;(composer as any).numberFormats = numberFormats
    ;(composer as any).rt = rt
    ;(composer as any).te = te
    ;(composer as any).tm = tm
    ;(composer as any).d = d
    ;(composer as any).n = n
    ;(composer as any).getDateTimeFormat = getDateTimeFormat
    ;(composer as any).setDateTimeFormat = setDateTimeFormat
    ;(composer as any).mergeDateTimeFormat = mergeDateTimeFormat
    ;(composer as any).getNumberFormat = getNumberFormat
    ;(composer as any).setNumberFormat = setNumberFormat
    ;(composer as any).mergeNumberFormat = mergeNumberFormat
    ;(composer as any)[InejctWithOption] = options.__injectWithOption
    ;(composer as any)[TransrateVNodeSymbol] = transrateVNode
    ;(composer as any)[DatetimePartsSymbol] = datetimeParts
    ;(composer as any)[NumberPartsSymbol] = numberParts
  }
  if (__BRIDGE__) {
    ;(composer as any)[LegacyInstanceSymbol] = __legacy
  }

  // for vue-devtools timeline event
  if (!__BRIDGE__ && __DEV__) {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    ;(composer as any)[EnableEmitter] = (emitter: VueDevToolsEmitter): void => {
      ;(_context as unknown as CoreInternalContext).__v_emitter = emitter
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    ;(composer as any)[DisableEmitter] = (): void => {
      ;(_context as unknown as CoreInternalContext).__v_emitter = undefined
    }
  }

  return composer
}