CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vue--composition-api

Provides Vue 3 Composition API compatibility for Vue 2 applications with reactive state management and lifecycle hooks.

Pending
Overview
Eval results
Files

component-utilities.mddocs/

Component Utilities

Utilities for component definition, setup context access, and Vue 3 compatibility features. These utilities provide enhanced component creation with better TypeScript support and composition API integration.

Capabilities

Component Definition

Enhanced component definition with better TypeScript inference and composition API support.

/**
 * Defines a component with enhanced type inference for the composition API
 * @param setup - Setup function or component options with setup
 * @returns Component options with proper typing
 */
function defineComponent<Props, RawBindings = object>(
  setup: SetupFunction<Props, RawBindings>
): ComponentOptions<Vue>;

/**
 * Defines a component with options object
 * @param options - Component options including setup function
 * @returns Component options with proper typing
 */
function defineComponent<
  Props = {},
  RawBindings = {},
  D = {},
  C extends ComputedOptions = {},
  M extends MethodOptions = {}
>(options: ComponentOptionsWithoutProps<Props, RawBindings, D, C, M>): ComponentOptions<Vue>;

/**
 * Defines an async component with lazy loading
 * @param source - Async component loader function
 * @returns Async component definition
 */
function defineAsyncComponent<T extends Component = any>(
  source: AsyncComponentLoader<T>
): T;

/**
 * Defines an async component with options
 * @param options - Async component options
 * @returns Async component definition
 */
function defineAsyncComponent<T extends Component = any>(
  options: AsyncComponentOptions<T>
): T;

types SetupFunction<Props, RawBindings> = (
  props: Readonly<Props>,
  ctx: SetupContext
) => RawBindings | (() => VNode | null) | void;

Usage Examples:

import { defineComponent, ref, computed } from "@vue/composition-api";

// Simple setup function
const MyComponent = defineComponent({
  props: {
    message: {
      type: String,
      required: true,
    },
    count: {
      type: Number,
      default: 0,
    },
  },
  setup(props, { emit }) {
    const localCount = ref(props.count);
    
    const doubleCount = computed(() => localCount.value * 2);
    
    const increment = () => {
      localCount.value++;
      emit("update:count", localCount.value);
    };
    
    return {
      localCount,
      doubleCount,
      increment,
    };
  },
});

// Component with render function
const RenderComponent = defineComponent({
  props: {
    tag: {
      type: String,
      default: "div",
    },
  },
  setup(props, { slots }) {
    return () => {
      const Tag = props.tag;
      return <Tag>{slots.default?.()}</Tag>;
    };
  },
});

// Async component
const AsyncComponent = defineAsyncComponent(() => import("./HeavyComponent.vue"));

// Async component with options
const AsyncComponentWithOptions = defineAsyncComponent({
  loader: () => import("./HeavyComponent.vue"),
  loadingComponent: LoadingSpinner,
  errorComponent: ErrorDisplay,
  delay: 200,
  timeout: 3000,
});

Instance Context

Access to the current component instance and setup context utilities.

/**
 * Gets the current component instance (only available during setup)
 * @returns Current component instance or null
 */
function getCurrentInstance(): ComponentInternalInstance | null;

/**
 * Accesses component attributes in setup function
 * @returns Component attrs object
 */
function useAttrs(): SetupContext["attrs"];

/**
 * Accesses component slots in setup function
 * @returns Component slots object
 */
function useSlots(): SetupContext["slots"];

interface ComponentInternalInstance {
  proxy: ComponentInstance | null;
  setupState: Record<string, any>;
  ctx: Record<string, any>;
  scope: EffectScope;
}

interface SetupContext<E extends EmitsOptions = {}> {
  attrs: Record<string, any>;
  slots: Slots;
  emit: EmitFn<E>;
}

Usage Examples:

import { defineComponent, getCurrentInstance, useAttrs, useSlots } from "@vue/composition-api";

export default defineComponent({
  setup() {
    // Get current instance
    const instance = getCurrentInstance();
    
    if (instance) {
      console.log("Component name:", instance.proxy?.$options.name);
    }
    
    // Access attrs reactively
    const attrs = useAttrs();
    
    // Access slots
    const slots = useSlots();
    
    const hasDefaultSlot = computed(() => !!slots.default);
    const hasHeaderSlot = computed(() => !!slots.header);
    
    return {
      attrs,
      hasDefaultSlot,
      hasHeaderSlot,
    };
  },
});

DOM and Timing Utilities

Utilities for DOM manipulation timing and element creation.

/**
 * Defers callback execution to the next DOM update cycle
 * @param callback - Optional callback to execute
 * @returns Promise that resolves after next DOM update
 */
function nextTick(callback?: () => void): Promise<void>;

/**
 * Creates virtual DOM elements (alias for createElement)
 * @param tag - Element tag or component
 * @param props - Element props
 * @param children - Element children
 * @returns Virtual DOM node
 */
function h(
  tag: string | Component,
  props?: Record<string, any> | null,
  children?: any
): VNode;

/**
 * Development warning utility
 * @param message - Warning message
 * @param args - Additional arguments
 */
function warn(message: string, ...args: any[]): void;

Usage Examples:

import { defineComponent, ref, nextTick, h } from "@vue/composition-api";

export default defineComponent({
  setup() {
    const showMessage = ref(false);
    const messageEl = ref<HTMLElement | null>(null);
    
    const toggleMessage = async () => {
      showMessage.value = !showMessage.value;
      
      // Wait for DOM update
      await nextTick();
      
      if (showMessage.value && messageEl.value) {
        messageEl.value.focus();
      }
    };
    
    // Using h() for render function
    return () => h("div", [
      h("button", { onClick: toggleMessage }, "Toggle Message"),
      showMessage.value
        ? h("p", { ref: messageEl, tabindex: -1 }, "Hello World!")
        : null,
    ]);
  },
});

// NextTick with callback
export default defineComponent({
  setup() {
    const updateData = () => {
      // Update reactive data
      someData.value = newValue;
      
      // Execute after DOM update
      nextTick(() => {
        console.log("DOM has been updated");
        document.getElementById("updated-element")?.scrollIntoView();
      });
    };
    
    return {
      updateData,
    };
  },
});

CSS Modules Integration

Access to CSS modules within composition API setup functions.

/**
 * Accesses CSS module classes
 * @param name - Optional CSS module name
 * @returns Object mapping class names to CSS module classes
 */
function useCssModule(name?: string): Record<string, string>;

/**
 * Alternative spelling for useCssModule
 * @param name - Optional CSS module name
 * @returns Object mapping class names to CSS module classes
 */
function useCSSModule(name?: string): Record<string, string>;

Usage Examples:

import { defineComponent, useCssModule } from "@vue/composition-api";

export default defineComponent({
  setup() {
    // Access default CSS module
    const styles = useCssModule();
    
    // Access named CSS module
    const buttonStyles = useCssModule("button");
    
    return {
      styles,
      buttonStyles,
    };
  },
  
  template: `
    <div :class="styles.container">
      <button :class="buttonStyles.primary">
        Click me
      </button>
    </div>
  `,
});

// In component with CSS modules
// styles.module.css
/*
.container {
  padding: 1rem;
}
*/

// button.module.css
/*
.primary {
  background: blue;
  color: white;
}
*/

Props Type Utilities

Utilities for working with component props and type extraction.

/**
 * Extracts prop types from props definition
 */
type ExtractPropTypes<O> = O extends object
  ? { [K in keyof O]?: O[K] extends PropOptions<infer T> ? T : any }
  : {};

/**
 * Extracts default prop types from props definition
 */
type ExtractDefaultPropTypes<O> = O extends object
  ? { [K in keyof O]: O[K] extends { default: infer D } ? D : never }
  : {};

interface PropOptions<T = any> {
  type?: PropType<T> | true | null;
  required?: boolean;
  default?: T | null | undefined | (() => T | null | undefined);
  validator?(value: T): boolean;
}

type PropType<T> = { new (...args: any[]): T & object } | { (): T } | PropType<T>[];

Usage Examples:

import { defineComponent, PropType } from "@vue/composition-api";

interface User {
  id: number;
  name: string;
  email: string;
}

export default defineComponent({
  props: {
    user: {
      type: Object as PropType<User>,
      required: true,
    },
    theme: {
      type: String as PropType<"light" | "dark">,
      default: "light",
    },
    count: {
      type: Number,
      default: 0,
      validator: (value: number) => value >= 0,
    },
  },
  setup(props) {
    // props are fully typed based on the props definition
    console.log(props.user.name); // TypeScript knows this is string
    console.log(props.theme); // TypeScript knows this is "light" | "dark"
    console.log(props.count); // TypeScript knows this is number
    
    return {};
  },
});

// Type extraction utility
type MyComponentProps = ExtractPropTypes<{
  user: { type: PropType<User>; required: true };
  theme: { type: PropType<"light" | "dark">; default: "light" };
  count: { type: Number; default: 0 };
}>;

// MyComponentProps is:
// {
//   user?: User;
//   theme?: "light" | "dark";
//   count?: number;
// }

Event Handling

Enhanced event handling with TypeScript support.

type EmitsOptions = ObjectEmitsOptions | string[];

type ObjectEmitsOptions = Record<
  string,
  ((...args: any[]) => any) | null
>;

type EmitFn<
  Options = ObjectEmitsOptions,
  Event extends keyof Options = keyof Options
> = Options extends Array<infer V>
  ? (event: V, ...args: any[]) => void
  : {} extends Options
  ? (event: string, ...args: any[]) => void
  : Options extends ObjectEmitsOptions
  ? {
      [K in Event]: Options[K] extends (...args: infer Args) => any
        ? (event: K, ...args: Args) => void
        : (event: K, ...args: any[]) => void;
    }[Event]
  : never;

Usage Examples:

import { defineComponent } from "@vue/composition-api";

export default defineComponent({
  emits: {
    // Typed event with validation
    click: (payload: { x: number; y: number }) => {
      return payload.x >= 0 && payload.y >= 0;
    },
    // Simple event
    close: null,
    // Event with multiple arguments
    update: (id: string, value: any) => true,
  },
  setup(props, { emit }) {
    const handleClick = (event: MouseEvent) => {
      // emit is fully typed based on emits definition
      emit("click", { x: event.clientX, y: event.clientY });
    };
    
    const handleClose = () => {
      emit("close");
    };
    
    const handleUpdate = () => {
      emit("update", "item-id", { data: "new value" });
    };
    
    return {
      handleClick,
      handleClose,
      handleUpdate,
    };
  },
});

Types

interface ComponentOptions<V extends Vue> {
  name?: string;
  props?: ComponentPropsOptions<Data>;
  setup?: SetupFunction<Data, Data>;
  data?: ComponentOptionsData<V>;
  computed?: Accessors<V>;
  methods?: Methods<V>;
  watch?: ComponentWatchOptions<V>;
  // ... other Vue component options
}

interface ComponentInternalInstance {
  proxy: ComponentInstance | null;
  setupState: Record<string, any>;
  ctx: Record<string, any>;
  scope: EffectScope;
}

interface SetupContext<E extends EmitsOptions = {}> {
  attrs: Record<string, any>;
  slots: Slots;
  emit: EmitFn<E>;
}

type Slots = Readonly<InternalSlots>;

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

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

type AsyncComponentLoader<T = any> = () => Promise<T>;

interface AsyncComponentOptions<T = any> {
  loader: AsyncComponentLoader<T>;
  loadingComponent?: Component;
  errorComponent?: Component;
  delay?: number;
  timeout?: number;
  suspensible?: boolean;
  onError?(error: Error, retry: () => void, fail: () => void, attempts: number): any;
}

type Component<
  Props = any,
  RawBindings = any,
  D = any,
  C extends ComputedOptions = ComputedOptions,
  M extends MethodOptions = MethodOptions
> = ComponentOptions<Vue, Props, RawBindings, D, C, M> | ComponentConstructor<Vue>;

Install with Tessl CLI

npx tessl i tessl/npm-vue--composition-api

docs

advanced-features.md

component-utilities.md

computed.md

dependency-injection.md

index.md

lifecycle.md

reactive-state.md

types.md

watchers.md

tile.json