vue#markRaw TypeScript Examples

The following examples show how to use vue#markRaw. 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: createInput.ts    From formkit with MIT License 6 votes vote down vote up
/**
 * Creates a new input from schema or a Vue component with the "standard"
 * FormKit features in place such as labels, help text, validation messages, and
 * class support.
 *
 * @param schemaOrComponent - The actual schema of the input.
 * @public
 */
export function createInput(
  schemaOrComponent: FormKitInputSchema | Component,
  definitionOptions: Partial<FormKitTypeDefinition> = {}
): FormKitTypeDefinition {
  const definition: FormKitTypeDefinition = {
    type: 'input',
    ...definitionOptions,
  }
  let schema: FormKitInputSchema | undefined = undefined
  if (isComponent(schemaOrComponent)) {
    const cmpName = `SchemaComponent${totalCreated++}`
    schema = () => ({
      $cmp: cmpName,
      props: {
        context: '$node.context',
      },
    })
    definition.library = { [cmpName]: markRaw(schemaOrComponent) }
  } else {
    schema = schemaOrComponent
  }

  // Use the default wrapping schema
  definition.schema = useSchema(schema || 'Schema undefined')
  return definition
}
Example #2
Source File: index.ts    From hexon with GNU General Public License v3.0 6 votes vote down vote up
export function createModalPlugin(): ModalController {
  const modals = ref<IModalItem[]>([])
  function create(component: Component) {
    const id = uuid()
    const item = {
      id,
      component: markRaw(component),
      close: () => {
        modals.value = modals.value.filter((item) => item.id !== id)
      },
    }
    modals.value.push(item)
    return item
  }
  return {
    modals,
    create,
    install(app: App) {
      const controller = this
      app.provide(key, controller)
    },
  }
}
Example #3
Source File: app.ts    From vite-plugin-ssr with MIT License 5 votes vote down vote up
function createApp(pageContext: PageContext) {
  const { Page } = pageContext

  let rootComponent: Component
  const PageWithWrapper = defineComponent({
    data: () => ({
      Page: markRaw(Page),
      pageProps: markRaw(pageContext.pageProps || {}),
    }),
    created() {
      rootComponent = this
    },
    render() {
      return h(
        PageShell,
        {},
        {
          default: () => {
            return h(this.Page, this.pageProps)
          },
        },
      )
    },
  })

  const app = createSSRApp(PageWithWrapper)

  // We use `app.changePage()` to do Client Routing, see `_default.page.client.js`
  objectAssign(app, {
    changePage: (pageContext: PageContext) => {
      Object.assign(pageContextReactive, pageContext)
      rootComponent.Page = markRaw(pageContext.Page)
      rootComponent.pageProps = markRaw(pageContext.pageProps || {})
    },
  })

  // When doing Client Routing, we mutate pageContext (see usage of `app.changePage()` in `_default.page.client.js`).
  // We therefore use a reactive pageContext.
  const pageContextReactive = reactive(pageContext)

  // Make `pageContext` accessible from any Vue component
  setPageContext(app, pageContextReactive)

  return app
}
Example #4
Source File: nav-config.ts    From hexon with GNU General Public License v3.0 5 votes vote down vote up
export function useNavConfig() {
  const vars = useThemeVars()
  const config = [
    {
      type: "item" as const,
      text: "用户",
      icon: HIconName.Contact,
      color: vars.value.colorSuccess,
      key: "user" as const,
      comp: markRaw(UserView),
    },
    {
      type: "item" as const,
      text: "安全",
      icon: HIconName.ReportHacked,
      color: vars.value.colorPrimary,
      key: "security" as const,
      comp: markRaw(SecurityView),
    },
    {
      type: "item" as const,
      text: "样式",
      icon: HIconName.OEM,
      color: vars.value.colorWarning,
      key: "style" as const,
      comp: markRaw(StyleView),
    },
    {
      type: "item" as const,
      text: "关于",
      icon: HIconName.Info,
      color: vars.value.textColorSecondary,
      key: "about" as const,
      comp: markRaw(AboutView),
    },
    {
      type: "item" as const,
      text: "帮助",
      icon: HIconName.EaseOfAccess,
      color: vars.value.textColorSecondary,
      key: "help" as const,
      comp: markRaw(HelpView),
    },
  ]
  const fullConfig = computed(() => {
    return config.map((value, idx) => ({ idx, ...value }))
  })
  function getConfig(key: typeof fullConfig.value[number]["key"]) {
    return fullConfig.value.find((item) => item.key === key)!
  }
  return { config: fullConfig, getConfig }
}
Example #5
Source File: document-element.ts    From quantum-sheet with GNU General Public License v3.0 5 votes vote down vote up
constructor(options: QuantumElementCreationOptions) {
    markRaw(this) // Prevents this from accidentally becoming reactive and stops the variables from being unwrapped
    if (options.position) this.position.value = options.position
    if (options.resizable) this.resizable.value = options.resizable
    if (options.size) this.size.value = options.size
    if (options.scope) this.scope.value = options.scope
    if (options.id && uuidValidate(options.id)) this.id = options.id
  }
Example #6
Source File: index.ts    From vue3-ace-editor with MIT License 4 votes vote down vote up
VAceEditor = defineComponent({
  props: {
    value: {
      type: String,
      required: true,
    },
    lang: {
      type: String,
      default: 'text',
    },
    theme: {
      type: String,
      default: 'chrome',
    },
    options: Object,
    placeholder: String,
    readonly: Boolean,
    wrap: Boolean,
    printMargin: {
      type: [Boolean, Number],
      default: true,
    },
    minLines: Number,
    maxLines: Number,
  },
  emits: ['update:value', 'init', ...Events],
  render(this: VAceEditorInstance) {
    return h('div');
  },
  mounted(this: VAceEditorInstance) {
    const editor = this._editor = markRaw(ace.edit(this.$el, {
      placeholder: this.placeholder,
      readOnly: this.readonly,
      value: this.value,
      mode: 'ace/mode/' + this.lang,
      theme: 'ace/theme/' + this.theme,
      wrap: this.wrap,
      printMargin: this.printMargin,
      useWorker: false,
      minLines: this.minLines,
      maxLines: this.maxLines,
      ...this.options,
    }));
    this._contentBackup = this.value;
    this._isSettingContent = false;
    editor.on('change', () => {
      // ref: https://github.com/CarterLi/vue3-ace-editor/issues/11
      if (this._isSettingContent) return;
      const content = editor.getValue();
      this._contentBackup = content;
      this.$emit('update:value', content);
    });
    Events.forEach(x => {
      const eventName = 'on' + capitalize(x);
      if (typeof this.$.vnode.props![eventName] === 'function') {
        editor.on(x as any, this.$emit.bind(this, x));
      }
    });
    this._ro = new ResizeObserver(() => editor.resize());
    this._ro.observe(this.$el);
    this.$emit('init', editor);
  },
  beforeUnmount(this: VAceEditorInstance) {
    this._ro?.disconnect();
    this._editor?.destroy();
  },
  methods: {
    focus(this: VAceEditorInstance) {
      this._editor.focus();
    },
    blur(this: VAceEditorInstance) {
      this._editor.blur();
    },
    selectAll(this: VAceEditorInstance) {
      this._editor.selectAll();
    },
  },
  watch: {
    value(this: VAceEditorInstance, val: string) {
      if (this._contentBackup !== val) {
        try {
          this._isSettingContent = true;
          this._editor.setValue(val, 1);
        } finally {
          this._isSettingContent = false;
        }
        this._contentBackup = val;
      }
    },
    theme(this: VAceEditorInstance, val: string) {
      this._editor.setTheme('ace/theme/' + val);
    },
    options(this: VAceEditorInstance, val: Partial<Ace.EditorOptions>) {
      this._editor.setOptions(val);
    },
    readonly(this: VAceEditorInstance, val: boolean) {
      this._editor.setReadOnly(val);
    },
    placeholder(this: VAceEditorInstance, val: string) {
      this._editor.setOption('placeholder', val);
    },
    wrap(this: VAceEditorInstance, val: boolean) {
      this._editor.setWrapBehavioursEnabled(val);
    },
    printMargin(this: VAceEditorInstance, val: boolean | number) {
      this._editor.setOption('printMargin', val);
    },
    lang(this: VAceEditorInstance, val: string) {
      this._editor.setOption('mode', 'ace/mode/' + val);
    },
    minLines(this: VAceEditorInstance, val: number) {
      this._editor.setOption('minLines', val);
    },
    maxLines(this: VAceEditorInstance, val: number) {
      this._editor.setOption('maxLines', val);
    },
  }
})
Example #7
Source File: FormKitSchema.spec.ts    From formkit with MIT License 4 votes vote down vote up
describe('rendering components', () => {
  it('can render component with props', () => {
    const cmp = defineComponent({
      props: {
        foobar: String,
      },
      template: `<span>{{ foobar }}</span>`,
    })
    const wrapper = mount(FormKitSchema, {
      props: {
        schema: [
          {
            $cmp: 'MyCmp',
            props: {
              foobar: 'world',
            },
          },
        ],
        library: markRaw({
          MyCmp: cmp,
        }),
      },
    })
    expect(wrapper.html()).toBe('<span>world</span>')
  })

  it('can render children in the default slot with scoped data', async () => {
    const MyComponent = defineComponent({
      name: 'MyComponent',
      props: {
        action: {
          type: String,
        },
      },
      data() {
        return {
          content: {
            price: 13.99,
            quantity: 1,
          },
        }
      },
      template:
        '<button @click="() => content.quantity++">{{ action }}{{ content.quantity }} for <slot v-bind="content"></slot></button>',
    })

    const library = markRaw({
      MyComponent,
    })

    const schema: FormKitSchemaNode[] = [
      {
        $cmp: 'MyComponent',
        props: {
          action: 'Purchase ',
        },
        children: '$price * $quantity',
      },
    ]

    const wrapper = mount(FormKitSchema, {
      props: {
        schema,
        library,
      },
    })

    expect(wrapper.html()).toBe('<button>Purchase 1 for 13.99</button>')
    wrapper.find('button').trigger('click')
    await nextTick()
    expect(wrapper.html()).toBe('<button>Purchase 2 for 27.98</button>')
  })

  it('can react when a schema’s function tail changes', async () => {
    const ctx = reactive<Record<string, number | undefined>>({
      price: 100,
    })
    const data = reactive({
      grab: () => ctx,
    })
    const wrapper = mount(FormKitSchema, {
      props: {
        data,
        schema: ['$: 13 + $grab().price'],
      },
    })
    expect(wrapper.html()).toBe('113')
    ctx.price = 200
    await nextTick()
    expect(wrapper.html()).toBe('213')
  })

  it('can re-parse a schema with components when new object', async () => {
    const schema: FormKitSchemaNode[] = reactive([
      {
        $cmp: 'FormKit',
        props: {
          type: 'text',
          label: 'Text input',
        },
      },
    ])

    const wrapper = mount(FormKitSchema, {
      props: {
        schema: schema,
      },
      global: {
        plugins: [[plugin, defaultConfig]],
      },
    })
    expect(wrapper.findAll('.formkit-outer').length).toBe(1)
    wrapper.setProps({
      schema: [
        ...schema,
        {
          $cmp: 'FormKit',
          props: {
            type: 'checkbox',
            label: 'Checkbox input',
          },
        },
      ],
    })
    await nextTick()
    expect(wrapper.findAll('.formkit-outer').length).toBe(2)
  })

  it('can re-parse a schema with components when deep update', async () => {
    const schema: FormKitSchemaNode[] = reactive([
      {
        $cmp: 'FormKit',
        props: {
          type: 'text',
          label: 'Text input',
        },
      },
    ])

    const wrapper = mount(FormKitSchema, {
      props: {
        schema: schema,
      },
      global: {
        plugins: [[plugin, defaultConfig]],
      },
    })
    expect(wrapper.findAll('.formkit-outer').length).toBe(1)
    schema.push({
      $cmp: 'FormKit',
      props: {
        type: 'checkbox',
        label: 'Checkbox input',
      },
    })
    await nextTick()
    expect(wrapper.findAll('.formkit-outer').length).toBe(2)
  })

  it('can use shorthand for $formkit', () => {
    const data = reactive({ value: 11 })
    const wrapper = mount(FormKitSchema, {
      props: {
        data,
        schema: [
          {
            $formkit: 'select',
            id: 'where_waldo',
            if: '$value > 10',
            name: 'foobar',
            options: {
              hello: 'Hello',
              world: 'World',
            },
          },
        ],
      },
      global: {
        plugins: [[plugin, defaultConfig]],
      },
    })
    expect(wrapper.html())
      .toContain(`<select id="where_waldo" class=\"formkit-input\" name=\"foobar\">
        <option class=\"formkit-option\" value=\"hello\">Hello</option>
        <option class=\"formkit-option\" value=\"world\">World</option>
      </select>`)
  })

  it('does not let $get to bogard a select list placeholder', async () => {
    const wrapper = mount(FormKitSchema, {
      props: {
        schema: [
          {
            $cmp: 'FormKit',
            props: {
              type: 'select',
              id: 'drink',
              label: 'Drink',
              placeholder: 'Pick your drink',
              options: { coffee: 'Coffee', espresso: 'Espresso', tea: 'Tea' },
              validation: 'required',
            },
          },
          '$get(drink).value',
        ],
      },
      global: {
        plugins: [[plugin, defaultConfig]],
      },
    })
    await nextTick()
    expect(wrapper.html()).toContain(
      '<option hidden="" disabled="" data-is-placeholder="true" class="formkit-option" value="">Pick your drink</option>'
    )
  })

  it('can access content from original data inside default slot', () => {
    const wrapper = mount(FormKitSchema, {
      props: {
        data: {
          doodle: 'Poodle',
        },
        schema: [
          {
            $formkit: 'group',
            children: ['$doodle'],
          },
        ],
      },
      global: {
        plugins: [[plugin, defaultConfig]],
      },
    })
    expect(wrapper.html()).toBe('Poodle')
  })

  it('can access content from original data inside deeply nested slot', () => {
    const wrapper = mount(FormKitSchema, {
      props: {
        data: {
          doodle: 'Poodle',
        },
        schema: [
          {
            $formkit: 'group',
            children: [
              {
                $formkit: 'list',
                children: [
                  {
                    $formkit: 'button',
                    children: '$doodle',
                  },
                ],
              },
            ],
          },
        ],
      },
      global: {
        plugins: [[plugin, defaultConfig]],
      },
    })
    expect(wrapper.find('button').text()).toBe('Poodle')
  })

  it('parses props containing schema by default', () => {
    const wrapper = mount(FormKitSchema, {
      props: {
        schema: [
          {
            $formkit: 'text',
            label: 'foobar',
            help: 'text',
            id: 'foobar',
            sectionsSchema: {
              help: {
                $el: 'h1',
                children: '$label',
              },
            },
          },
        ],
      },
      global: {
        plugins: [[plugin, defaultConfig]],
      },
    })
    // We expect the h1 to be empty here because '$label' does not exist in the
    // parent scope — but it does exist in the child scope. This indicates the
    // value $label was pared by the parent instead of the child.
    expect(wrapper.html()).toContain(
      '<h1 id="help-foobar" class="formkit-help"></h1>'
    )
  })

  it('does not parses props containing __raw__ prefix', () => {
    const wrapper = mount(FormKitSchema, {
      props: {
        schema: [
          {
            $formkit: 'text',
            label: 'foobar',
            help: 'text',
            id: 'foobar',
            __raw__sectionsSchema: {
              help: {
                $el: 'h1',
                children: '$label',
              },
            },
          },
        ],
      },
      global: {
        plugins: [[plugin, defaultConfig]],
      },
    })
    // We expect the h1 to contain the value of the label defined in the child,
    // this would indicate that sectionsSchema was parsed by the child.
    expect(wrapper.html()).toContain(
      '<h1 id="help-foobar" class="formkit-help">foobar</h1>'
    )
  })
})
Example #8
Source File: bindings.ts    From formkit with MIT License 4 votes vote down vote up
vueBindings: FormKitPlugin = function vueBindings(node) {
  /**
   * Start a validity counter on all blocking messages.
   */
  node.ledger.count('blocking', (m) => m.blocking)
  const isValid = ref<boolean>(!node.ledger.value('blocking'))
  /**
   * Start an error message counter.
   */
  node.ledger.count('errors', (m) => m.type === 'error')
  const hasErrors = ref<boolean>(!!node.ledger.value('errors'))

  /**
   * Keep track of the first time a Vue tick cycle has passed.
   */
  let hasTicked = false
  nextTick(() => {
    hasTicked = true
  })

  /**
   * All messages with the visibility state set to true.
   */
  const availableMessages = reactive<Record<string, FormKitMessage>>(
    node.store.reduce((store, message) => {
      if (message.visible) {
        store[message.key] = message
      }
      return store
    }, {} as Record<string, FormKitMessage>)
  )
  /**
   * A flag that determines when validation messages should be displayed.
   */
  const validationVisibility = ref<string>(
    node.props.validationVisibility || 'blur'
  )
  node.on('prop:validationVisibility', ({ payload }) => {
    validationVisibility.value = payload
  })

  /**
   * Keep track of if this input has ever shown validation errors.
   */
  const hasShownErrors = ref(validationVisibility.value === 'live')

  /**
   * The current visibility state of validation messages.
   */
  const validationVisible = computed<boolean>(() => {
    if (context.state.submitted) return true
    if (!hasShownErrors.value && !context.state.settled) {
      return false
    }
    switch (validationVisibility.value) {
      case 'live':
        return true
      case 'blur':
        return context.state.blurred
      case 'dirty':
        return context.state.dirty
      default:
        return false
    }
  })

  /**
   * Determines if the input should be considered "complete".
   */
  const isComplete = computed<boolean>(() => {
    return hasValidation.value
      ? isValid.value && !hasErrors.value
      : context.state.dirty && !empty(context.value)
  })

  /**
   * If the input has validation rules or not.
   */
  const hasValidation = ref<boolean>(
    Array.isArray(node.props.parsedRules) && node.props.parsedRules.length > 0
  )
  node.on('prop:parsedRules', ({ payload: rules }) => {
    hasValidation.value = Array.isArray(rules) && rules.length > 0
  })

  /**
   * All messages that are currently on display to an end user. This changes
   * based on the current message type visibility, like errorVisibility.
   */
  const messages = computed<Record<string, FormKitMessage>>(() => {
    const visibleMessages: Record<string, FormKitMessage> = {}
    for (const key in availableMessages) {
      const message = availableMessages[key]
      if (message.type !== 'validation' || validationVisible.value) {
        visibleMessages[key] = message
      }
    }
    return visibleMessages
  })

  /**
   * UI Messages.
   */
  const ui = reactive(
    node.store.reduce((messages, message) => {
      if (message.type === 'ui' && message.visible)
        messages[message.key] = message
      return messages
    }, {} as Record<string, FormKitMessage>)
  )

  /**
   * This is the reactive data object that is provided to all schemas and
   * forms. It is a subset of data in the core node object.
   */
  const cachedClasses = reactive({})
  const classes = new Proxy(cachedClasses as Record<PropertyKey, string>, {
    get(...args) {
      const [target, property] = args
      let className = Reflect.get(...args)
      if (!className && typeof property === 'string') {
        if (!has(target, property) && !property.startsWith('__v')) {
          const observedNode = createObserver(node)
          observedNode.watch((node) => {
            const rootClasses =
              typeof node.config.rootClasses === 'function'
                ? node.config.rootClasses(property, node)
                : {}
            const globalConfigClasses = node.config.classes
              ? createClasses(property, node, node.config.classes[property])
              : {}
            const classesPropClasses = createClasses(
              property,
              node,
              node.props[`_${property}Class`]
            )
            const sectionPropClasses = createClasses(
              property,
              node,
              node.props[`${property}Class`]
            )
            className = generateClassList(
              node,
              property,
              rootClasses,
              globalConfigClasses,
              classesPropClasses,
              sectionPropClasses
            )
            target[property] = className
          })
        }
      }
      return className
    },
  })

  const describedBy = computed<string | undefined>(() => {
    const describers = []
    if (context.help) {
      describers.push(`help-${node.props.id}`)
    }
    for (const key in messages.value) {
      describers.push(`${node.props.id}-${key}`)
    }
    return describers.length ? describers.join(' ') : undefined
  })

  const value = ref(node.value)
  const _value = ref(node.value)

  const context: FormKitFrameworkContext = reactive({
    _value,
    attrs: node.props.attrs,
    disabled: node.props.disabled,
    describedBy,
    fns: {
      length: (obj: Record<PropertyKey, any>) => Object.keys(obj).length,
      number: (value: any) => Number(value),
      string: (value: any) => String(value),
      json: (value: any) => JSON.stringify(value),
      eq,
    },
    handlers: {
      blur: () =>
        node.store.set(
          createMessage({ key: 'blurred', visible: false, value: true })
        ),
      touch: () => {
        node.store.set(
          createMessage({ key: 'dirty', visible: false, value: true })
        )
      },
      DOMInput: (e: Event) => {
        node.input((e.target as HTMLInputElement).value)
        node.emit('dom-input-event', e)
      },
    },
    help: node.props.help,
    id: node.props.id as string,
    label: node.props.label,
    messages,
    node: markRaw(node),
    options: node.props.options,
    state: {
      blurred: false,
      complete: isComplete,
      dirty: false,
      submitted: false,
      settled: node.isSettled,
      valid: isValid,
      errors: hasErrors,
      rules: hasValidation,
      validationVisible,
    },
    type: node.props.type,
    ui,
    value,
    classes,
  })

  /**
   * Ensure the context object is properly configured after booting up.
   */
  node.on('created', () => {
    if (!eq(context.value, node.value)) {
      _value.value = node.value
      value.value = node.value
      triggerRef(value)
      triggerRef(_value)
    }
  })

  /**
   * Sets the settled state.
   */
  node.on('settled', ({ payload: isSettled }) => {
    context.state.settled = isSettled
  })

  /**
   * Observes node.props properties explicitly and updates them in the context
   * object.
   * @param observe - Props to observe and register as context data.
   */
  function observeProps(observe: string[]) {
    observe.forEach((prop) => {
      prop = camel(prop)
      if (!has(context, prop) && has(node.props, prop)) {
        context[prop] = node.props[prop]
      }
      node.on(`prop:${prop}`, ({ payload }) => {
        context[prop as keyof FormKitFrameworkContext] = payload
      })
    })
  }

  /**
   * We use a node observer to individually observe node props.
   */
  const rootProps = [
    'help',
    'label',
    'disabled',
    'options',
    'type',
    'attrs',
    'preserve',
    'preserveErrors',
    'id',
  ]
  observeProps(rootProps)

  /**
   * Once the input is defined, deal with it.
   * @param definition - Type definition.
   */
  function definedAs(definition: FormKitTypeDefinition) {
    if (definition.props) observeProps(definition.props)
  }

  node.props.definition && definedAs(node.props.definition)

  /**
   * When new props are added to the core node as "props" (ie not attrs) then
   * we automatically need to start tracking them here.
   */
  node.on('added-props', ({ payload }) => observeProps(payload))

  /**
   * Watch for input events from core.
   */
  node.on('input', ({ payload }) => {
    _value.value = payload
    triggerRef(_value)
  })

  /**
   * Watch for input commits from core.
   */
  node.on('commit', ({ payload }) => {
    value.value = _value.value = payload
    triggerRef(value)
    node.emit('modelUpdated')
    // The input is dirty after a value has been input by a user
    if (!context.state.dirty && node.isCreated && hasTicked)
      context.handlers.touch()
    if (
      isComplete &&
      node.type === 'input' &&
      hasErrors.value &&
      !undefine(node.props.preserveErrors)
    ) {
      node.store.filter(
        (message) =>
          !(message.type === 'error' && message.meta?.autoClear === true)
      )
    }
  })

  /**
   * Update the local state in response to messages.
   * @param message - A formkit message
   */
  const updateState = async (message: FormKitMessage) => {
    if (
      message.type === 'ui' &&
      message.visible &&
      !message.meta.showAsMessage
    ) {
      ui[message.key] = message
    } else if (message.visible) {
      availableMessages[message.key] = message
    } else if (message.type === 'state') {
      // await node.settled
      context.state[message.key] = !!message.value
    }
  }

  /**
   * Listen to message events and modify the local message data values.
   */
  node.on('message-added', (e) => updateState(e.payload))
  node.on('message-updated', (e) => updateState(e.payload))
  node.on('message-removed', ({ payload: message }) => {
    delete ui[message.key]
    delete availableMessages[message.key]
    delete context.state[message.key]
  })
  node.on('settled:blocking', () => {
    isValid.value = true
  })
  node.on('unsettled:blocking', () => {
    isValid.value = false
  })
  node.on('settled:errors', () => {
    hasErrors.value = false
  })
  node.on('unsettled:errors', () => {
    hasErrors.value = true
  })

  /**
   * Watch the validation visible prop and set the hasShownErrors state.
   */
  watch(validationVisible, (value) => {
    if (value) {
      hasShownErrors.value = true
    }
  })

  node.context = context

  // The context is complete
  node.emit('context', node, false)
}