icon

Morainev0.5.0

TypeScript

TypeScript

Use Moraine component props, namespace types, values, items, and callback contexts safely.

View as Markdown

Overview#

Moraine exposes types in two layers:

  • XxxProps — the top-level public props type for each component, exported directly from moraine.
  • XxxT.* — a namespace of component-specific sub-types (items, values, slots, etc.), also exported from moraine.
import type { ButtonProps, SelectProps, SelectT } from 'moraine'

Component Props (XxxProps)#

Every component exports a Props type named after the component (e.g. ButtonProps, SelectProps). Use this when wrapping a component or extending its props interface.

import type { ButtonProps } from 'moraine'
interface PrimaryButtonProps extends ButtonProps {
trackingId?: string
}
function PrimaryButton(props: PrimaryButtonProps) {
// ...
}

Root props#

Every public component owns a documented root element. In the default type mode, that root accepts arbitrary attributes, while component business props stay separate from the DOM surface and ref remains typed to the concrete root element.

<Card aria-describedby="details" data-testid="card" />

Full intrinsic attributes are opt-in because including every HTML attribute in every component makes editor completion slower and allows control props to be mistaken for wrapper props. Enable the expanded surface with a type-only package-root augmentation:

declare module 'moraine' {
interface MoraineTypeConfig {
enableRootAutocomplete: true
}
}

The augmentation has no runtime effect. It enables the exact attributes for the documented root tag, including camelCase Solid handlers, and preserves required props for custom Solid components passed through polymorphic as APIs such as Button, List, FormField, and FileUpload. Lowercase event aliases and Solid directive prefixes remain excluded from the autocomplete surface.

Root attributes are forwarded at runtime even when the expanded type mode is disabled. Generated state metadata is emitted before user rest props, so caller values override data-slot, state data-*, and generated aria-* attributes. Wrapper components forward root props to their wrapper or trigger, while form control props and secondary APIs such as listboxProps stay on their documented internal elements.

Component Namespace (XxxT)#

The XxxT namespace groups all supporting types for a component under a single import. This keeps the top-level exports focused and avoids polluting the global type space.

Item models#

List-like components (e.g. Select, MultiSelect) expose an Item type for their option objects.

import type { SelectT } from 'moraine'
const regionOptions: SelectT.Item[] = [
{ label: 'Asia', value: 'asia' },
{ label: 'Europe', value: 'europe' },
]

Controlled values#

Use XxxT.Value to type state variables that hold a component’s selected or active value.

import type { SelectT } from 'moraine'
let selected: SelectT.Value | null = null

Render callback params#

Prop callbacks often receive component-specific objects. Type them using the appropriate namespace member.

import type { SelectProps } from 'moraine'
const labelRender: SelectProps['labelRender'] = (option) =>
typeof option.label === 'string' ? option.label : (option.key ?? 'Unknown')

Slot types#

XxxT.Slot is an object whose keys are valid slot names used by the classes and styles props. Each key can carry JSDoc describing the slot and its styling attributes.

import type { CardT } from 'moraine'
const overrides: CardT.Classes = {
header: 'bg-gray-100',
}

Namespace Reference#

Each XxxT namespace may expose the following members depending on the component:

Member Description
Slot Object keyed by slot names used by classes and styles
Variant Variant options for visual/style customization
Item Data model for list items or option objects
Value Domain type of the component’s controlled value
Classes Typed map from slot name to CSS class string
Styles Typed map from slot name to inline style object
Base Component-specific business props (internal)
Props Final public props shape (same as XxxProps)

Tips#

  • Use import type for all type-only imports to keep runtime bundles clean.
  • Prefer exported XxxProps and XxxT.* types over importing internal source types directly.
  • When in doubt, start with XxxProps; reach for XxxT.* only when you need a more specific sub-type.