Quick Reference

Framework Methods

  • XTool.init() - Initialize framework
  • XTool.directive() - Register directive
  • XTool.registerComponent() - Register component
  • XTool.loadComponents() - Load external components
  • XTool.mountComponent() - Mount programmatically

Component Context

  • this.$el - Root element
  • this.$refs - Element references
  • this.$nextTick() - Next DOM update
  • this.Signals - Emit/connect signals

Type Generics

  • <TData> - Component data type
  • <TMethods> - Methods type
  • <TComputed> - Computed type
  • <T> - Directive value type
Quick Start
import { XTool } from 'fynejs'; XTool.init({ debug: true });

Framework Interface

Core framework methods and configuration options for initializing and customizing FyneJS.

INTERFACE

XToolFramework

Main framework interface providing initialization, directive registration, and component management.

METHOD init
Returns: XToolFramework

Syntax

init(config?: XToolConfig): XToolFramework
Description

Initialize the framework with optional configuration settings.

Parameters
Parameter Type Required Description
config XToolConfig Optional Configuration options for the framework
Example
// Initialize with default settings
XTool.init();

// Initialize with custom configuration
XTool.init({
  container: '.app',
  debug: true,
  staticDirectives: true,
  prefix: 'x',
  delegate: false,
  sandboxExpressions: false,
  allowGlobals: ['Math', 'Date']
});
METHOD directive<T>
Returns: XToolFramework

Syntax

directive<T>(name: string, directive: CustomDirective<T>): XToolFramework
Description

Register a custom directive with bind, update, and unbind lifecycle hooks.

Parameters
Parameter Type Required Description
name string Required Directive name (without prefix)
directive CustomDirective<T> Required Directive definition with lifecycle hooks
Example
XTool.directive('tooltip', {
  bind(element, value, expression, component) {
    element.setAttribute('title', value);
  },
  update(element, value) {
    element.setAttribute('title', value);
  },
  unbind(element) {
    element.removeAttribute('title');
  }
});

METHOD registerComponent(definition): XToolFramework

Register a reusable component with name, template, and lifecycle hooks. Returns the framework instance for chaining.

Syntax
registerComponent(definition: RegisteredComponentDefinition): XToolFramework
Parameters
Parameter Type Required Description
definition RegisteredComponentDefinition Required Component definition with required name and optional template
Example
XTool.registerComponent({
  name: 'counter',
  template: `<div>
    <span x-text="count"></span>
    <button x-on:click="increment">+</button>
  </div>`,
  data: { count: 0 },
  methods: {
    increment() { this.count++; }
  }
});

METHOD loadComponents(sources): Promise<ComponentLoaderResult>

Load external component definitions with different loading strategies. Returns a promise with load results.

Syntax
loadComponents(sources: Array<string | ComponentSource>): Promise<ComponentLoaderResult>
Parameters
Parameter Type Required Description
sources Array<string | ComponentSource> Required Array of component paths or source objects with loading options
Example
// Load components with different modes
await XTool.loadComponents([
  'components/button.js',  // preload (default)
  { path: 'components/modal.js', mode: 'defer' },
  { path: 'components/chart.js', mode: 'lazy', name: 'data-chart' }
]);

// Returns: { settled: 2, failed: 0 }

METHOD mountComponent(name, element, props?): ReactiveComponent | undefined

Programmatically mount a registered component on a DOM element. Returns the component instance or undefined if mounting failed.

Syntax
mountComponent(name: string, element: Element, props?: Record<string, any>): ReactiveComponent | undefined
Parameters
Parameter Type Required Description
name string Required Name of the registered component to mount
element Element Required DOM element to mount the component on
props Record<string, any> Optional Initial props to pass to the component
Example
// Register a component first
XTool.registerComponent({
  name: 'user-card',
  template: '<div><h3 x-text="name"></h3><p x-text="role"></p></div>',
  data: { name: 'Guest', role: 'Viewer' }
});

// Programmatically mount on any element
const container = document.getElementById('dynamic-container');
const component = XTool.mountComponent('user-card', container, {
  name: 'John Doe',
  role: 'Administrator'
});

// Access the mounted component instance
if (component) {
  console.log('Component mounted successfully');
  // Later: component.$destroy() to unmount
}

Use Cases

Perfect for dynamically creating components in response to user actions, integrating with third-party libraries, or building component factories.

Configuration

Framework configuration options for customizing behavior, performance, and security.

INTERFACE

XToolConfig

Configuration interface for framework initialization with type-safe options.

Configuration Properties

Property Type Default Description
container
Optional
string 'body' Container selector for auto-discovery of components
debug
Optional
boolean false Enable debug logging for development
staticDirectives
Optional
boolean true Enable static directive optimization for performance
prefix
Optional
string 'x' Directive prefix for custom attribute names
delegate
Optional
boolean false Enable event delegation for better performance
sandboxExpressions
Optional
boolean false Restrict globals in expressions for security
allowGlobals
Optional
string[] undefined Whitelist of globals when sandboxExpressions is enabled
router
Optional
RouterOptions undefined SPA router configuration for client-side navigation
Configuration Example
// Complete configuration example
XTool.init({
  container: '.app-container',    // Custom container
  debug: true,                  // Enable debugging
  staticDirectives: true,      // Optimize static directives
  prefix: 'data',               // Use 'data-' prefix
  delegate: true,              // Enable event delegation
  sandboxExpressions: true,    // Secure expressions
  allowGlobals: [               // Allowed global objects
    'Math', 'Date', 'JSON', 'console'
  ],
  router: {                     // SPA routing configuration
    enabled: true,            // Enable SPA routing
    transitionName: 'route',  // View transition name
    prefetchOnHover: true,   // Prefetch on hover
    before: async (to, from, info) => {
      // Navigation guard
      return true; // Allow navigation
    },
    after: async (to, from, info) => {
      // Post-navigation hook
      console.log('Navigated to:', to);
    }
  }
});
INTERFACE

RouterOptions

Configuration interface for SPA routing functionality with navigation hooks and transitions.

Router Properties

Property Type Default Description
enabled
Optional
boolean false Enable or disable SPA routing functionality
transitionName
Optional
string 'route' Name for view transitions API transitions
prefetchOnHover
Optional
boolean false Prefetch pages when hovering over links
before
Optional
NavigationHook undefined Hook called before navigation (can cancel)
after
Optional
NavigationHook undefined Hook called after successful navigation
error
Optional
ErrorHook undefined Hook called when navigation fails
Router Hook Types
// Navigation hook signature
type NavigationHook = (
  to: string,        // Destination URL
  from: string,      // Current URL
  info: {              // Navigation context
    source: 'link' | 'popstate' | 'program';
  }
) => boolean | void | Promise<boolean | void>;

// Error hook signature
type ErrorHook = (
  error: unknown,    // Error that occurred
  to: string,        // Attempted destination
  from: string       // Current URL
) => void;

Component Interfaces

TypeScript interfaces for defining components with proper type safety and IntelliSense support.

INTERFACE

TransitionConfig

Configuration object for x-transition directive with class phases, timing, and end hooks.

Configuration Properties

Property Type Description
duration
Optional
number Fallback transition duration in milliseconds (default: 150). Actual duration is computed from CSS transitions/animations.
easing
Optional
string CSS easing function (default: 'ease'). Used for inline fade transitions.
enter
Optional
string Classes applied during entire enter phase (e.g., 'transition ease-out duration-300').
enterFrom
Optional
string Initial state classes for enter (e.g., 'opacity-0 scale-95'). Applied first, then removed before enterTo.
enterTo
Optional
string Target state classes for enter (e.g., 'opacity-100 scale-100'). Applied after enterFrom is removed.
leave
Optional
string Classes applied during entire leave phase (e.g., 'transition ease-in duration-200').
leaveFrom
Optional
string Initial state classes for leave (e.g., 'opacity-100 scale-100').
leaveTo
Optional
string Target state classes for leave (e.g., 'opacity-0 scale-95').
toggle
Optional
string Simple class list added on show and removed on hide (e.g., 'opacity-0 transition-opacity duration-200').
End Hook (.after / .end modifier)

Add .after or .end modifier to run an expression when transition completes naturally (not on cancellation).

x-transition:enter.after="({ el, phase, config }) => ..."

  • el: The transitioned element
  • phase: 'enter' | 'leave'
  • config: This config object with resolved duration (effective ms from CSS) and easing
INTERFACE

ComponentDefinition<TData, TMethods, TComputed>

Base interface for defining reactive components with typed data, methods, and computed properties.

PROPERTY data?: TData

Reactive data object with typed properties that trigger UI updates when changed.

// Define typed data interface
interface UserData {
  name: string;
  email: string;
  isActive: boolean;
}

// Use in component
const component = {
  data: {
    name: 'John Doe',
    email: 'john@example.com',
    isActive: true
  } as UserData
};

PROPERTY methods?: WithThisForMethods<ComponentContext>

Component methods with proper context binding and type safety. Methods have access to component data and the full ComponentContext.

const component = {
  data: { count: 0 },
  methods: {
    increment() {
      this.count++; // 'this' is properly typed
    },
    setCount(value: number) {
      this.count = value;
    }
  }
};

PROPERTY computed?: BindComputed<ComponentContext>

Computed properties with automatic caching and dependency tracking. Values are recalculated only when dependencies change. Computed functions have access to the ComponentContext.

const component = {
  data: { 
    firstName: 'John', 
    lastName: 'Doe' 
  },
  computed: {
    fullName() {
      return `${this.firstName} ${this.lastName}`;
    },
    initials() {
      return `${this.firstName[0]}${this.lastName[0]}`;
    }
  }
};

PROPERTY propEffects?: PropEffectsMap<ComponentContext>

Reactive handlers for component prop changes with old/new value tracking. Handlers receive the new and old values and have access to the ComponentContext.

const component = {
  data: { message: 'Hello' },
  propEffects: {
    userId(newValue, oldValue) {
      console.log(`User changed: ${oldValue} → ${newValue}`);
      this.loadUserData(newValue);
    },
    theme(newTheme) {
      this.updateStyles(newTheme);
    }
  }
};

PROPERTY template?: string | Promise<string> | (() => string | Promise<string>)

Component template for rendering. Supports static strings, promises, or factory functions.

// Static template
const component1 = {
  template: `<div>
    <h1 x-text="title"></h1>
    <p x-text="description"></p>
  </div>`
};

// Async template
const component2 = {
  template: async () => {
    const response = await fetch('/templates/card.html');
    return await response.text();
  }
};

PROPERTY name?: string

Optional component name for registration and debugging. Required for registered components.

const component = {
  name: 'user-card',
  data: { user: null },
  template: `<div class="card">
    <h3 x-text="user?.name"></h3>
  </div>`
};

LIFECYCLE Lifecycle Hooks

Component lifecycle methods with proper context typing and execution order. All lifecycle hooks have access to the full ComponentContext.

Mount Lifecycle
Update Lifecycle
Unmount Lifecycle
Destroy Lifecycle
const component = {
  data: { isReady: false },
  
  // Mount lifecycle
  beforeMount() {
    console.log('About to mount', this.$el);
  },
  mounted() {
    this.isReady = true;
    console.log('Component mounted', this.$el);
  },
  
  // Update lifecycle
  updated() {
    console.log('Component updated');
  },
  
  // Unmount lifecycle
  beforeUnmount() {
    this.cleanup();
  },
  unmounted() {
    console.log('Component unmounted');
  }
};
INTERFACE

RegisteredComponentDefinition<TData, TMethods, TComputed>

Extended component definition for reusable components with required name and additional configuration options.

EXTENDS ComponentDefinition<TData, TMethods, TComputed>

Inherits all properties from ComponentDefinition plus additional required fields.

name: string Required

Unique component name used for registration and template references.

makeData?: (props: Record<string, string>) => Record<string, unknown>

Factory function to generate base data from component props/attributes.

init?: (props: Record<string, any>) => ComponentDefinition | void

Instance augmentation function to customize component per usage.

Registered Component Example
const counterComponent: RegisteredComponentDefinition = {
  name: 'counter',
  template: `<div>
    <span x-text="count"></span>
    <button x-on:click="increment">+</button>
  </div>`,
  data: { count: 0 },
  methods: {
    increment() {
      this.count++;
    }
  },
  makeData(props) {
    return { count: parseInt(props.start) || 0 };
  }
};
INTERFACE

ComponentContext<TData, TMethods, TComputedVals>

Component context available in methods, computed properties, and expressions with proper type safety.

PROPERTIES Special Properties

  • $el - Component's root element
  • $id - Component's unique ID
  • $isMounted - Mount status
  • $isDestroyed - Destruction status
  • $isSealed - Sealed mode status
  • $isFrozen - Frozen status
  • $parent - Parent component
  • $children - Child components

METHODS Utility Methods

  • $destroy() - Destroy component
  • $forceUpdate() - Force re-render
  • $addCleanupFunction() - Add cleanup
  • $nextTick() - Next DOM update
  • $mutate() - Mutate reactive data
  • $seal() - Toggle sealed mode
  • $log() - Debug logging

REFS Element References

  • $refs.name - Access element by x-ref name
  • $ref(name) - Get ref by name (function form)
  • $ref(name, value) - Register any value as a ref

Refs bubble up the component tree—child components can access parent refs.

HELPERS DOM Helpers

  • $attr(name, value) - Set attribute on $target element
  • $attr({ name: value, ... }) - Set multiple attributes
  • $css(prop, value) - Set CSS property on $target element
  • $css({ prop: value, ... }) - Set multiple CSS properties

Supports glob patterns: $attr('[width,height]', 100) sets both attributes.

SIGNALS Component Messaging

  • Signals.emit(name, payload?) - Emit a signal that bubbles up
  • Signals.connect(name, handler) - Listen for a signal
  • Signals.disconnect(name, handler) - Stop listening

Signals bubble from child to parent. Call event.stopPropagation() to stop bubbling.

Component Context Usage
const component = {
  data: { message: 'Hello' },
  methods: {
    logInfo() {
      this.$log('Component ID:', this.$id);
      this.$log('Element:', this.$el);
      this.$log('Is mounted:', this.$isMounted);
    },
    scheduleUpdate() {
      this.$nextTick(() => {
        console.log('DOM updated');
      });
    },
    forceChange() {
      this.$mutate(() => {
        this.message = 'Changed!';
      });
    }
  }
};

Directive Interfaces

Interfaces for creating custom directives with proper lifecycle management and type safety.

INTERFACE

CustomDirective<T>

Interface for defining custom directives with typed value handling and lifecycle management.

METHOD bind?(element, value, expression, component, ...)

Called once when directive is first bound to an element. Use for initial setup and event listeners.

const fadeDirective: CustomDirective<number> = {
  bind(element, value, expression, component) {
    element.style.transition = 'opacity 0.3s';
    element.style.opacity = value.toString();
  }
};

METHOD update?(element, value, expression, component, ...)

Called whenever reactive dependencies change. Use to update the DOM based on new values.

const fadeDirective: CustomDirective<number> = {
  update(element, value) {
    element.style.opacity = value.toString();
  }
};

METHOD unbind?(element, component)

Called when directive is removed (cleanup). Use to remove event listeners and clean up resources.

const fadeDirective: CustomDirective<number> = {
  unbind(element) {
    element.style.transition = '';
    element.style.opacity = '';
  }
};

update?(element, value, expression, component, modifiers?, evaluator?)

Called whenever reactive dependencies change.

const fadeDirective: CustomDirective<number> = {
  update(element, value) {
    element.style.opacity = value.toString();
  }
};

unbind?(element, component)

Called when directive is removed (cleanup).

const fadeDirective: CustomDirective<number> = {
  unbind(element) {
    element.style.transition = '';
    element.style.opacity = '';
  }
};

Complete Example

Full directive implementation with TypeScript.

interface TooltipConfig {
  text: string;
  position?: 'top' | 'bottom' | 'left' | 'right';
  delay?: number;
}

const tooltipDirective: CustomDirective<TooltipConfig> = {
  bind(element, value, expression, component, modifiers) {
    const config = typeof value === 'string' ? { text: value } : value;
    
    // Create tooltip element
    const tooltip = document.createElement('div');
    tooltip.className = 'tooltip';
    tooltip.textContent = config.text;
    
    // Store for cleanup
    (element as any)._tooltip = tooltip;
    
    // Add event listeners
    element.addEventListener('mouseenter', showTooltip);
    element.addEventListener('mouseleave', hideTooltip);
  },
  
  update(element, value) {
    const tooltip = (element as any)._tooltip;
    if (tooltip) {
      const config = typeof value === 'string' ? { text: value } : value;
      tooltip.textContent = config.text;
    }
  },
  
  unbind(element) {
    const tooltip = (element as any)._tooltip;
    if (tooltip) {
      tooltip.remove();
      delete (element as any)._tooltip;
    }
    element.removeEventListener('mouseenter', showTooltip);
    element.removeEventListener('mouseleave', hideTooltip);
  }
};

Event Callback Contexts

Understanding the context and arguments passed to event handlers and directive callbacks.

CONTEXT

Event Directive Context

Event handlers in x-on and @ directives receive both special variables and function arguments.

Special Variables

Available within event handler expressions:

$event The native DOM event object
$target The element that triggered the event (event.target)
<!-- Using special variables -->
<button @click="console.log($event.type, $target.tagName)">
  Click me
</button>

<!-- Preventing default behavior -->
<form @submit="$event.preventDefault(); handleSubmit()">

Function Arguments

When calling methods, the element is automatically passed as an argument:

// Component method signature
methods: {
  handleClick(element) {
    // element is the DOM element that triggered the event
    console.log('Clicked:', element.tagName);
  }
}

<!-- Usage in template -->
<button @click="handleClick">Click</button>
CONTEXT

x-intersect Callback Context

x-intersect directive callbacks receive detailed intersection information.

Callback Arguments

The callback receives a payload object with intersection details:

entry IntersectionObserverEntry object with detailed intersection data
phase 'enter' | 'leave' - which phase triggered the callback
visible Boolean indicating if element is currently visible
before Boolean indicating if element was visible before this change
<!-- Using intersection payload -->
<div x-intersect:enter="handleIntersect">
  Observe me!
</div>

// Component method
methods: {
  handleIntersect(payload) {
    console.log('Phase:', payload.phase);
    console.log('Visible:', payload.visible);
    console.log('Intersection ratio:', payload.entry.intersectionRatio);
  }
}
CONTEXT

Router Hook Context

Router navigation hooks receive detailed navigation context information.

Hook Arguments

All router hooks receive the same three arguments:

to Destination URL (string)
from Current URL (string)
info Navigation context object with source information
// Router configuration with hooks
router: {
  before(to, from, info) {
    console.log('Navigating to:', to);
    console.log('Coming from:', from);
    console.log('Source:', info.source); // 'link', 'popstate', or 'program'
    
    return true; // Allow navigation
  }
}

info.source indicates how the navigation was triggered:
'link' - User clicked a link
'popstate' - Browser back/forward button
'program' - Programmatic navigation

Type Utilities

Advanced TypeScript utilities for enhanced type safety and developer experience.

UTILITIES

Type Helpers

Advanced TypeScript utilities used internally by the framework for enhanced type safety.

TYPE DeepReadonly<T>

Deep readonly utility preventing mutations in computed getters.

// Data is DeepReadonly in computed
computed: {
  summary() {
    // this.users is DeepReadonly<User[]>
    // Prevents: this.users.push(newUser)
    return this.users.length;
  }
}

TYPE ComputedValues<TComputed>

Derives computed value types from getter functions.

const computed = {
  fullName(): string { /* ... */ },
  age(): number { /* ... */ }
};

// ComputedValues<typeof computed> = {
//   fullName: string;
//   age: number;
// }

TYPE WithThisForMethods<TCtx, TMethods>

Injects proper 'this' context into method signatures.

// Original method signature
const methods = {
  updateUser(id: number, data: UserData) { /* ... */ }
};

// With proper 'this' binding:
// (this: ComponentContext, id: number, data: UserData) => void

TYPE HtmlTag

Template literal type for HTML template strings.

import { html } from 'fynejs';

const template = html`
  <div class="${className}">
    <h1>${title}</h1>
    <p>${content}</p>
  </div>
`;

TYPE ComponentSource

Configuration object for component loading with path, mode, and optional name.

interface ComponentSource {
  path: string;                          // Component file path
  mode?: 'preload' | 'defer' | 'lazy';    // Loading strategy
  name?: string;                         // Override component name
}

// Usage in loadComponents
const sources = [
  'components/button.js',                     // string (preload mode)
  { path: 'modal.js', mode: 'defer' },          // ComponentSource
  { path: 'chart.js', mode: 'lazy', name: 'data-chart' }
];

TYPE ComponentLoaderResult

Return type from loadComponents() showing load success counts and failures.

interface ComponentLoaderResult {
  settled: number;    // Successfully loaded (preload + defer modes)
  failed: number;     // Failed immediate loads
}

// Example result
const result = await XTool.loadComponents(['a.js', 'b.js']);
console.log(`Loaded: ${result.settled}, Failed: ${result.failed}`);

Global Declarations

Global types and module declarations for both browser and bundler environments.

BROWSER

Browser Environment

Global declarations available in browser environments via script tags.

Global Window Objects

// Available on window object
declare global {
  interface Window {
    XTool: XToolFramework;
    FyneJS: XToolFramework;  // Alias
  }
}

// Usage in browser
<script src="..."></script>
<script>
  // Both are available
  XTool.init();
  FyneJS.init();  // Same instance
</script>
Note

Both XTool and FyneJS reference the same framework instance.

MODULES

Module Exports

ESM and CommonJS module declarations for modern bundlers and Node.js environments.

ESM ES Module Imports

// Named imports
import { XTool, FyneJS, html } from 'fynejs';
import type { ComponentDefinition, XToolConfig } from 'fynejs';

// Default import
import XTool from 'fynejs';

CJS CommonJS Requires

// Destructured require
const { XTool, FyneJS, html } = require('fynejs');

// Default require
const XTool = require('fynejs').default;

HELPER HTML Template Helper

Tagged template literal for HTML strings with syntax highlighting support in IDEs.

import { html } from 'fynejs';

// Template literal with syntax highlighting
const template = html`
  <div x-data="{ count: 0 }">
    <span x-text="count"></span>
    <button x-on:click="count++">Increment</button>
  </div>
`;