@stacksjs/stx
Version:
A performant UI Framework. Powered by Bun.
411 lines (394 loc) • 12.6 kB
TypeScript
/**
* Parse @craft-* component directives from stx template
*/
export declare function processCraftComponents(content: string, config?: CraftComponentConfig): string;
/**
* Register a custom Craft component
*/
export declare function registerCraftComponent(name: string, definition: CraftComponentDefinition): void;
/**
* Get all registered Craft components
*/
export declare function getCraftComponents(): Record<string, CraftComponentDefinition>;
/**
* Built-in Craft component definitions
*/
export declare const CRAFT_COMPONENTS: {
// Input Components
button: {
nativeType: 'craft-button';
fallbackTag: 'button';
fallbackClasses: 'craft-button';
nativeProps: readonly ['variant', 'size', 'disabled', 'loading']
};
'text-input': {
nativeType: 'craft-text-input';
fallbackTag: 'input';
fallbackClasses: 'craft-text-input';
nativeProps: readonly ['placeholder', 'value', 'type', 'disabled', 'readonly']
};
textarea: {
nativeType: 'craft-textarea';
fallbackTag: 'textarea';
fallbackClasses: 'craft-textarea';
nativeProps: readonly ['placeholder', 'value', 'rows', 'disabled', 'readonly']
};
checkbox: { nativeType: 'craft-checkbox'; fallbackTag: 'input'; fallbackClasses: 'craft-checkbox'; nativeProps: readonly ['checked', 'disabled', 'label']; render: (props, children) => unknown };
radio: {
nativeType: 'craft-radio';
fallbackTag: 'input';
fallbackClasses: 'craft-radio';
nativeProps: readonly ['checked', 'disabled', 'name', 'value', 'label']
};
select: {
nativeType: 'craft-select';
fallbackTag: 'select';
fallbackClasses: 'craft-select';
nativeProps: readonly ['value', 'disabled', 'options', 'placeholder']
};
slider: { nativeType: 'craft-slider'; fallbackTag: 'input'; fallbackClasses: 'craft-slider'; nativeProps: readonly ['value', 'min', 'max', 'step', 'disabled']; render: (props, _children) => unknown };
// Display Components
label: {
nativeType: 'craft-label';
fallbackTag: 'span';
fallbackClasses: 'craft-label';
nativeProps: readonly ['text', 'for']
};
badge: {
nativeType: 'craft-badge';
fallbackTag: 'span';
fallbackClasses: 'craft-badge';
nativeProps: readonly ['variant', 'size']
};
avatar: { nativeType: 'craft-avatar'; fallbackTag: 'div'; fallbackClasses: 'craft-avatar'; nativeProps: readonly ['src', 'alt', 'size', 'fallback']; render: (props, _children) => unknown };
progress: { nativeType: 'craft-progress'; fallbackTag: 'div'; fallbackClasses: 'craft-progress'; nativeProps: readonly ['value', 'max', 'variant']; render: (props, _children) => unknown };
spinner: { nativeType: 'craft-spinner'; fallbackTag: 'div'; fallbackClasses: 'craft-spinner'; nativeProps: readonly ['size']; render: (props, _children) => unknown };
// Layout Components
card: {
nativeType: 'craft-card';
fallbackTag: 'div';
fallbackClasses: 'craft-card';
nativeProps: readonly ['title', 'subtitle', 'variant']
};
modal: { nativeType: 'craft-modal'; fallbackTag: 'dialog'; fallbackClasses: 'craft-modal'; nativeProps: readonly ['open', 'title', 'closable', 'size']; render: (props, children) => unknown };
tabs: {
nativeType: 'craft-tabs';
fallbackTag: 'div';
fallbackClasses: 'craft-tabs';
nativeProps: readonly ['activeTab', 'tabs']
};
accordion: { nativeType: 'craft-accordion'; fallbackTag: 'details'; fallbackClasses: 'craft-accordion'; nativeProps: readonly ['open', 'title']; render: (props, children) => unknown };
divider: {
nativeType: 'craft-divider';
fallbackTag: 'hr';
fallbackClasses: 'craft-divider';
nativeProps: readonly ['orientation', 'variant']
};
// Data Components
table: {
nativeType: 'craft-table';
fallbackTag: 'table';
fallbackClasses: 'craft-table';
nativeProps: readonly ['columns', 'rows', 'sortable', 'selectable']
};
list: {
nativeType: 'craft-list';
fallbackTag: 'ul';
fallbackClasses: 'craft-list';
nativeProps: readonly ['items', 'selectable']
};
tree: {
nativeType: 'craft-tree';
fallbackTag: 'div';
fallbackClasses: 'craft-tree';
nativeProps: readonly ['nodes', 'expandable', 'selectable']
};
// Feedback Components
alert: { nativeType: 'craft-alert'; fallbackTag: 'div'; fallbackClasses: 'craft-alert'; nativeProps: readonly ['variant', 'title', 'dismissible']; render: (props, children) => unknown };
toast: {
nativeType: 'craft-toast';
fallbackTag: 'div';
fallbackClasses: 'craft-toast';
nativeProps: readonly ['variant', 'duration', 'position']
};
tooltip: { nativeType: 'craft-tooltip'; fallbackTag: 'span'; fallbackClasses: 'craft-tooltip'; nativeProps: readonly ['content', 'position']; render: (props, children) => unknown };
// Navigation Components
menu: {
nativeType: 'craft-menu';
fallbackTag: 'nav';
fallbackClasses: 'craft-menu';
nativeProps: readonly ['items', 'orientation']
};
breadcrumb: {
nativeType: 'craft-breadcrumb';
fallbackTag: 'nav';
fallbackClasses: 'craft-breadcrumb';
nativeProps: readonly ['items', 'separator']
};
pagination: {
nativeType: 'craft-pagination';
fallbackTag: 'nav';
fallbackClasses: 'craft-pagination';
nativeProps: readonly ['total', 'page', 'pageSize']
};
// Advanced Components
'code-editor': {
nativeType: 'craft-code-editor';
fallbackTag: 'textarea';
fallbackClasses: 'craft-code-editor';
nativeProps: readonly ['value', 'language', 'theme', 'readonly', 'lineNumbers']
};
'file-browser': {
nativeType: 'craft-file-browser';
fallbackTag: 'div';
fallbackClasses: 'craft-file-browser';
nativeProps: readonly ['path', 'showHidden', 'selectable']
};
'color-picker': { nativeType: 'craft-color-picker'; fallbackTag: 'input'; fallbackClasses: 'craft-color-picker'; nativeProps: readonly ['value', 'format']; render: (props, _children) => unknown };
'date-picker': { nativeType: 'craft-date-picker'; fallbackTag: 'input'; fallbackClasses: 'craft-date-picker'; nativeProps: readonly ['value', 'min', 'max', 'format']; render: (props, _children) => unknown };
'time-picker': { nativeType: 'craft-time-picker'; fallbackTag: 'input'; fallbackClasses: 'craft-time-picker'; nativeProps: readonly ['value', 'min', 'max', 'step']; render: (props, _children) => unknown }
};
/**
* CSS styles for Craft component fallbacks
*/
export declare const CRAFT_COMPONENT_STYLES: `
<style id="craft-component-styles">
/* Craft Component Base Styles */
.craft-button {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 8px 16px;
border: none;
border-radius: 6px;
font-family: inherit;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
background: var(--craft-primary, #3b82f6);
color: white;
}
.craft-button:hover { opacity: 0.9; }
.craft-button:disabled { opacity: 0.5; cursor: not-allowed; }
.craft-button-secondary { background: var(--craft-secondary, #6b7280); }
.craft-button-outline { background: transparent; border: 1px solid currentColor; color: var(--craft-primary, #3b82f6); }
.craft-text-input, .craft-textarea, .craft-select {
padding: 8px 12px;
border: 1px solid var(--craft-border, #d1d5db);
border-radius: 6px;
font-family: inherit;
font-size: 14px;
background: var(--craft-bg, #fff);
color: var(--craft-text, #1f2937);
transition: border-color 0.2s ease;
}
.craft-text-input:focus, .craft-textarea:focus, .craft-select:focus {
outline: none;
border-color: var(--craft-primary, #3b82f6);
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.craft-checkbox-wrapper {
display: inline-flex;
align-items: center;
gap: 8px;
cursor: pointer;
}
.craft-checkbox {
width: 18px;
height: 18px;
cursor: pointer;
}
.craft-slider {
width: 100%;
height: 6px;
border-radius: 3px;
cursor: pointer;
}
.craft-badge {
display: inline-flex;
align-items: center;
padding: 2px 8px;
border-radius: 9999px;
font-size: 12px;
font-weight: 500;
background: var(--craft-primary, #3b82f6);
color: white;
}
.craft-avatar {
display: inline-flex;
align-items: center;
justify-content: center;
background: var(--craft-secondary, #6b7280);
color: white;
font-weight: 600;
overflow: hidden;
}
.craft-avatar img { width: 100%; height: 100%; object-fit: cover; }
.craft-progress {
width: 100%;
height: 8px;
background: var(--craft-border, #e5e7eb);
border-radius: 4px;
overflow: hidden;
}
.craft-progress-bar {
height: 100%;
background: var(--craft-primary, #3b82f6);
transition: width 0.3s ease;
}
.craft-spinner {
border: 2px solid var(--craft-border, #e5e7eb);
border-top-color: var(--craft-primary, #3b82f6);
border-radius: 50%;
animation: craft-spin 0.8s linear infinite;
}
@keyframes craft-spin { to { transform: rotate(360deg); } }
.craft-card {
background: var(--craft-bg, #fff);
border: 1px solid var(--craft-border, #e5e7eb);
border-radius: 8px;
padding: 16px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.craft-modal {
border: none;
border-radius: 12px;
padding: 0;
max-width: 90vw;
max-height: 90vh;
box-shadow: 0 25px 50px -12px rgba(0,0,0,0.25);
}
.craft-modal::backdrop { background: rgba(0,0,0,0.5); }
.craft-modal-header {
padding: 16px 20px;
border-bottom: 1px solid var(--craft-border, #e5e7eb);
}
.craft-modal-header h2 { margin: 0; font-size: 18px; }
.craft-modal-body { padding: 20px; }
.craft-accordion {
border: 1px solid var(--craft-border, #e5e7eb);
border-radius: 6px;
overflow: hidden;
}
.craft-accordion-header {
padding: 12px 16px;
cursor: pointer;
font-weight: 500;
background: var(--craft-bg-secondary, #f9fafb);
}
.craft-accordion-content { padding: 16px; }
.craft-divider {
border: none;
border-top: 1px solid var(--craft-border, #e5e7eb);
margin: 16px 0;
}
.craft-alert {
padding: 12px 16px;
border-radius: 6px;
border-left: 4px solid;
}
.craft-alert-info { background: #eff6ff; border-color: #3b82f6; color: #1e40af; }
.craft-alert-success { background: #f0fdf4; border-color: #22c55e; color: #166534; }
.craft-alert-warning { background: #fffbeb; border-color: #f59e0b; color: #92400e; }
.craft-alert-error { background: #fef2f2; border-color: #ef4444; color: #991b1b; }
.craft-alert-title { font-weight: 600; margin-bottom: 4px; }
.craft-tooltip {
position: relative;
cursor: help;
}
.craft-tooltip::after {
content: attr(data-tooltip);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
padding: 4px 8px;
background: #1f2937;
color: white;
font-size: 12px;
border-radius: 4px;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: opacity 0.2s;
}
.craft-tooltip:hover::after { opacity: 1; }
.craft-table {
width: 100%;
border-collapse: collapse;
}
.craft-table th, .craft-table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid var(--craft-border, #e5e7eb);
}
.craft-table th { font-weight: 600; background: var(--craft-bg-secondary, #f9fafb); }
.craft-list {
list-style: none;
padding: 0;
margin: 0;
}
.craft-list li {
padding: 12px;
border-bottom: 1px solid var(--craft-border, #e5e7eb);
}
.craft-list li:last-child { border-bottom: none; }
.craft-code-editor {
font-family: 'SF Mono', 'Fira Code', monospace;
font-size: 13px;
line-height: 1.5;
padding: 12px;
background: #1e1e1e;
color: #d4d4d4;
border-radius: 6px;
resize: vertical;
}
/* Dark mode support */
@media (prefers-color-scheme: dark) {
.craft-text-input, .craft-textarea, .craft-select, .craft-card {
background: #1f2937;
color: #f3f4f6;
border-color: #374151;
}
.craft-modal {
background: #1f2937;
color: #f3f4f6;
}
.craft-accordion-header { background: #374151; }
.craft-table th { background: #374151; }
}
</style>
`;
/**
* Craft Native Components for stx
*
* This module provides @craft-* directives that render native components
* when running in a Craft environment, with HTML fallbacks for web browsers.
*
* @example
* ```html
* <@craft-button variant="primary" @click="handleClick">
* Click Me
* </@craft-button>
*
* <@craft-text-input placeholder="Enter name" :value="name" @change="updateName" />
*
* <@craft-modal title="Settings" :open="showSettings">
* Modal content here
* </@craft-modal>
* ```
*/
export declare interface CraftComponentConfig {
preferNative?: boolean
classPrefix?: string
components?: Record<string, CraftComponentDefinition>
}
export declare interface CraftComponentDefinition {
nativeType: string
fallbackTag: string
fallbackClasses?: string
nativeProps?: string[]
render?: (props: Record<string, unknown>, children: string) => string
}
export default craftComponents;