CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vue--runtime-core

Vue.js 3 runtime core library providing foundational APIs for building custom renderers and managing reactive component systems

Pending
Overview
Eval results
Files

composition-helpers.mddocs/

Composition Helpers

Vue provides helper utilities for composition API usage including template refs, v-model integration, unique ID generation, and setup context access.

Capabilities

Template References

Create reactive references to template elements and component instances.

/**
 * Creates a template ref for accessing DOM elements or component instances
 * @param key - Template ref key (must match ref attribute in template)
 * @returns Template ref object
 */
function useTemplateRef<T = any>(key: string): TemplateRef<T>;

interface TemplateRef<T = any> extends Ref<T> {
  readonly value: T;
}

Usage Examples:

import { defineComponent, useTemplateRef, onMounted } from "@vue/runtime-core";

const MyComponent = defineComponent({
  setup() {
    // Create template refs
    const inputRef = useTemplateRef<HTMLInputElement>('input');
    const childRef = useTemplateRef<ComponentInstance>('child');
    
    onMounted(() => {
      // Access DOM element
      if (inputRef.value) {
        inputRef.value.focus();
        console.log('Input value:', inputRef.value.value);
      }
      
      // Access child component instance
      if (childRef.value) {
        // Call child component methods
        childRef.value.someMethod();
      }
    });
    
    return {
      inputRef,
      childRef
    };
  },
  
  template: `
    <div>
      <input ref="input" type="text" />
      <ChildComponent ref="child" />
    </div>
  `
});

Model References

Create reactive references for v-model bindings with built-in getter/setter logic.

/**
 * Creates a model ref for v-model integration
 * @param props - Component props object
 * @param name - Model property name
 * @param options - Model configuration options
 * @returns Model ref with getter/setter
 */
function useModel<T>(
  props: Record<string, any>,
  name: string,
  options?: UseModelOptions
): ModelRef<T>;

interface UseModelOptions {
  /**
   * Default value when prop is undefined
   */
  defaultValue?: any;
  
  /**
   * Whether the model should be deeply reactive
   */
  deep?: boolean;
  
  /**
   * Transform function for incoming value
   */
  get?(value: any): any;
  
  /**
   * Transform function for outgoing value
   */
  set?(value: any): any;
}

interface ModelRef<T> extends Ref<T> {
  readonly [ModelRefMarkerSymbol]: true;
}

Usage Examples:

import { defineComponent, useModel } from "@vue/runtime-core";

// Basic v-model component
const CustomInput = defineComponent({
  props: {
    modelValue: String,
    placeholder: String
  },
  emits: ['update:modelValue'],
  
  setup(props, { emit }) {
    // Create model ref that syncs with v-model
    const model = useModel(props, 'modelValue');
    
    return {
      model
    };
  },
  
  template: `
    <input 
      v-model="model" 
      :placeholder="placeholder" 
    />
  `
});

// Multiple v-model support
const MultiModelComponent = defineComponent({
  props: {
    firstName: String,
    lastName: String,
    age: Number
  },
  emits: ['update:firstName', 'update:lastName', 'update:age'],
  
  setup(props) {
    const firstName = useModel(props, 'firstName');
    const lastName = useModel(props, 'lastName');
    const age = useModel(props, 'age', {
      defaultValue: 0,
      get: (value) => Number(value) || 0,
      set: (value) => Math.max(0, Math.floor(value))
    });
    
    return {
      firstName,
      lastName,
      age
    };
  }
});

// Usage:
// <MultiModelComponent 
//   v-model:firstName="user.firstName"
//   v-model:lastName="user.lastName" 
//   v-model:age="user.age"
// />

Unique ID Generation

Generate unique IDs for accessibility and form associations.

/**
 * Generates a unique ID for the current component instance
 * @returns Unique string ID
 */
function useId(): string;

Usage Examples:

import { defineComponent, useId } from "@vue/runtime-core";

const FormField = defineComponent({
  props: {
    label: String,
    required: Boolean
  },
  
  setup(props) {
    const id = useId();
    
    return {
      id,
      inputId: `input-${id}`,
      labelId: `label-${id}`,
      errorId: `error-${id}`
    };
  },
  
  template: `
    <div>
      <label :id="labelId" :for="inputId">
        {{ label }}
        <span v-if="required" aria-label="required">*</span>
      </label>
      <input 
        :id="inputId"
        :aria-labelledby="labelId"
        :aria-describedby="errorId"
        :required="required"
      />
      <div :id="errorId" class="error" aria-live="polite">
        <!-- Error messages -->
      </div>
    </div>
  `
});

// Multiple IDs in one component
const MultiIdComponent = defineComponent({
  setup() {
    const formId = useId();
    const modalId = useId();
    const tabsId = useId();
    
    return {
      formId: `form-${formId}`,
      modalId: `modal-${modalId}`,
      tabsId: `tabs-${tabsId}`
    };
  }
});

Setup Context Access

Access component slots and attributes within setup function.

/**
 * Gets setup context slots
 * @returns Component slots object
 */
function useSlots(): Slots;

/**
 * Gets setup context attrs (non-prop attributes)
 * @returns Component attrs object
 */
function useAttrs(): Data;

interface Slots {
  [name: string]: Slot | undefined;
  default?: Slot;
}

type Slot<T = any> = (...args: any[]) => VNode[];

type Data = Record<string, unknown>;

Usage Examples:

import { defineComponent, useSlots, useAttrs, h } from "@vue/runtime-core";

const WrapperComponent = defineComponent({
  setup() {
    const slots = useSlots();
    const attrs = useAttrs();
    
    // Check available slots
    const hasHeader = !!slots.header;
    const hasFooter = !!slots.footer;
    const hasDefault = !!slots.default;
    
    console.log('Available slots:', Object.keys(slots));
    console.log('Component attrs:', attrs);
    
    return () => h('div', {
      class: 'wrapper',
      ...attrs // Forward all non-prop attributes
    }, [
      hasHeader && h('header', { class: 'header' }, slots.header!()),
      hasDefault && h('main', { class: 'content' }, slots.default!()),
      hasFooter && h('footer', { class: 'footer' }, slots.footer!())
    ]);
  }
});

// Dynamic slot rendering
const DynamicSlots = defineComponent({
  setup() {
    const slots = useSlots();
    
    return () => {
      const slotElements = Object.entries(slots).map(([name, slot]) => {
        if (slot) {
          return h('div', { 
            key: name,
            class: `slot-${name}` 
          }, slot());
        }
        return null;
      }).filter(Boolean);
      
      return h('div', { class: 'dynamic-slots' }, slotElements);
    };
  }
});

// Attrs manipulation
const AttrsComponent = defineComponent({
  props: {
    title: String
  },
  
  setup(props) {
    const attrs = useAttrs();
    
    // Filter out certain attributes
    const filteredAttrs = computed(() => {
      const { class: className, style, ...rest } = attrs;
      return rest;
    });
    
    // Combine with custom attributes
    const combinedAttrs = computed(() => ({
      ...filteredAttrs.value,
      'data-component': 'attrs-component',
      'aria-label': props.title || 'Custom component'
    }));
    
    return {
      combinedAttrs
    };
  }
});

Advanced Patterns

// Composable using multiple helpers
function useFormField(name: string) {
  const id = useId();
  const attrs = useAttrs();
  
  const fieldId = `field-${id}`;
  const labelId = `label-${id}`;
  const errorId = `error-${id}`;
  
  // Extract validation attributes
  const validationAttrs = computed(() => {
    const { required, minlength, maxlength, pattern } = attrs;
    return { required, minlength, maxlength, pattern };
  });
  
  return {
    fieldId,
    labelId, 
    errorId,
    validationAttrs
  };
}

// Ref forwarding pattern
const ForwardRefComponent = defineComponent({
  setup(_, { expose }) {
    const elementRef = useTemplateRef<HTMLElement>('element');
    
    // Expose ref to parent
    expose({
      focus: () => elementRef.value?.focus(),
      blur: () => elementRef.value?.blur(),
      element: elementRef
    });
    
    return {
      elementRef
    };
  }
});

Types

interface TemplateRef<T = any> extends Ref<T> {
  /**
   * Template ref marker for type discrimination
   */
  readonly [TemplateRefSymbol]: true;
}

interface ModelRef<T = any> extends Ref<T> {
  /**
   * Model ref marker for type discrimination
   */
  readonly [ModelRefMarkerSymbol]: true;
}

type UseModelOptions = {
  defaultValue?: unknown;
  deep?: boolean;
  get?(value: unknown): unknown;
  set?(value: unknown): unknown;
};

interface Slots {
  [name: string]: Slot | undefined;
}

type Slot<T extends Record<string, any> = any> = (
  props: T
) => VNode[];

type Data = Record<string, unknown>;

Install with Tessl CLI

npx tessl i tessl/npm-vue--runtime-core

docs

asset-resolution.md

builtin-components.md

components.md

composition-helpers.md

dependency-injection.md

error-handling.md

hydration.md

index.md

internal-render-helpers.md

lifecycle.md

reactivity.md

scheduler-timing.md

ssr-context.md

vdom-rendering.md

watch-effects.md

tile.json