Files
2025-11-30 09:05:04 +08:00

7.0 KiB

  1. Home
  2. Dial
  3. Tutorial

Dial Tutorial: Using dial-cli

Dial CLI Tutorialdial-cliv0.0.22 This tutorial will guide you through using the dial-cli tool to generate UI controls from TypeScript interfaces with Dial annotations.

Using the dial-cli Tool

The dial-cli is now available as a standalone package for generating Dial schemas from TypeScript files, providing a cleaner installation experience without UI dependencies.

Installation

# Install globally (recommended for CLI tools)
npm install -g @vuer-ai/dial-cli
# or
pnpm install -g @vuer-ai/dial-cli

# Check CLI is available
dial-cli --help

Basic Usage

# Generate schemas from a TypeScript file
dial-cli <input-file> [input-file2...]

# Examples:
dial-cli ./src/components/Box.tsx
# Creates schema.dial in ./metadata directory

dial-cli ./src/components/Box.tsx -o ./schemas
# Outputs to specified directory

# Process multiple files
dial-cli Component1.tsx Component2.tsx

# Specify output directory
dial-cli -o ./metadata MyComponent.tsx

What the CLI Does

The dial-cli tool will:

  1. Parse your TypeScript file using the TypeScript compiler API

  2. Extract all interfaces and types with Dial annotations

  3. Process JSDoc comments following the @dial convention

  4. Generate JSON schema files that can be directly used with DialPanel

Output Files

The CLI generates files with a clean directory structure:

Main Output:

  • schema.dial - Combined schemas for all components, ready for UI generation

Debug Output (verbose mode only):

  • debug/component-raw.json - Raw output from react-docgen-typescript

  • debug/component-combined.json - Enhanced metadata with dial schema information

  • debug/component-schemas.json - Individual component schemas for debugging

Local Script

This documentation includes a convenience script for generating metadata:

# From the dial directory
./generate-dial-metadata.sh

This will process the BoxExample.tsx file and output metadata to the metadata/ directory.

Using Generated Schemas

Once you've generated schemas using dial-cli, you can use them in your application. The Dial system consists of three main components:

  1. DialProvider - Manages state for all controls

  2. DialPanel - Converts schemas to UI components

  3. Input Components - Individual control types (number, vector, boolean, etc.)

Component API

DialPanel accepts the following props:

interface DialPanelProps {
  schemas: DialSchema[];        // Array of control schemas
  groups?: DialGroupConfig[];   // Optional group configurations
}

Usage:

// Basic usage with just schemas
<DialPanel schemas={schemas} />

// With group configuration for layout control
<DialPanel schemas={schemas} groups={groups} />

TypeScript Interfaces

The Dial system uses the following main interfaces:

// Schema for individual controls
interface DialSchema {
  name: string;
  dtype: string;
  value?: DialValue;
  min?: number;
  max?: number;
  step?: number;
  options?: Array<string | number | { label: string; value: string | number }>;
  // ... other properties
  tags?: {
    grouping?: string;
    col?: boolean | number;
    row?: number;
    layout?: string;
    labelPosition?: LabelPositionT;
    noWrap?: boolean;
  };
}

// Group configuration for styling and layout
interface DialGroupConfig {
  name: string;
  noWrap?: boolean;
  [key: string]: unknown;
}

// Complete schema with groups (output from dial-cli)
interface DialSchemaGroup {
  component: string;
  schema: DialSchema[];
  groups?: DialGroupConfig[];
}

// Valid value types
type DialValue = string | number | boolean | number[] | string[] | null | undefined;

import { DialProvider, DialPanel } from './dial';

const schemas = [
  {
    name: 'position',
    dtype: 'vector3',
    value: [0, 0, 0],
    min: -10,
    max: 10,
    tags: { grouping: 'transform', col: true }
  },
  // ... more schemas
];

function MyComponent() {
  const handleValueChange = (name, value) => {
    console.log(`${name} changed to`, value);
  };

  return (
    <DialProvider
      schemas={schemas}
      onValueChange={handleValueChange}
    >
      <DialPanel schemas={schemas} />
    </DialProvider>
  );
}

Complete Example with dial-cli

  1. Create a TypeScript file with Dial annotations:
// Box.tsx
interface BoxProps {
  /**
   * Transform properties displayed on single line
   * @dial transform @dial-no-wrap
   */

  /** @dial transform @dial-dtype vector3 */
  position: [number, number, number];

  /** @dial transform @dial-dtype euler */
  rotation: [number, number, number];

  /**
   * Box dimensions
   * @dial geometry
   * @dial-dtype vector3
   * @dial-min 0.1
   * @dial-max 10
   * @dial-step 0.1
   */
  size: [number, number, number];

  /**
   * Box color
   * @dial appearance
   * @dial-dtype color
   */
  color: string;
}

export const Box: React.FC<BoxProps> = ({ size, position, rotation, color }) => {
  // Component implementation
};

  1. Generate the schema:
dial-cli Box.tsx -o ./schemas
# Creates schemas/schema.dial with groups configuration

The generated schema includes group-level settings:

{
  "component": "Box",
  "schema": [
    { "name": "position", "dtype": "vector3", "tags": { "grouping": "transform", "noWrap": true } },
    { "name": "rotation", "dtype": "euler", "tags": { "grouping": "transform", "noWrap": true } },
    { "name": "size", "dtype": "vector3", "tags": { "grouping": "geometry" } },
    { "name": "color", "dtype": "color", "tags": { "grouping": "appearance" } }
  ],
  "groups": [
    { "name": "transform", "noWrap": true }
  ]
}

  1. Use the generated schema in your app:
import { DialProvider, DialPanel, DialSchemaGroup, DialValue } from '@vuer-ai/vuer-uikit';
import allSchemas from './schemas/schema.dial';

// Get the Box component schema from the combined schema file
const boxSchema = allSchemas.find(s => s.component === 'Box');

function App() {
  const [boxProps, setBoxProps] = useState({
    position: [0, 0, 0],
    rotation: [0, 0, 0],
    size: [1, 1, 1],
    color: '#ff0000'
  });

  const handleValueChange = (name: string, value: DialValue) => {
    setBoxProps(prev => ({ ...prev, [name]: value }));
  };

  return (
    <DialProvider
      schemas={[boxSchema]}
      onValueChange={handleValueChange}
    >
      <div style={{ display: 'flex' }}>
        {/* Your 3D scene */}
        <Box {...boxProps} />

        {/* Auto-generated controls with group configuration */}
        <DialPanel schemas={[boxSchema]} />
      </div>
    </DialProvider>
  );
}

Next Steps