@lightspeed/crane-api
v2.5.1
Published
Lightweight runtime API package for building custom sections and templates with `@lightspeed/crane`.
Keywords
Readme
@lightspeed/crane-api
Lightweight runtime API package for building custom sections and templates with @lightspeed/crane.
This package provides Vue 3 composables and TypeScript types needed for custom sections and templates, without CLI or build tools.
Installation
npm install @lightspeed/crane-apiNote: This package is automatically included when using
@lightspeed/crane. Install separately only if you need the API without the CLI.
Overview
The package exports:
- App Creation —
createVueServerApp,createVueClientAppfor SSR/hydration - Content Composables — Access user-editable content (text, images, buttons, etc.)
- Design Composables — Access styling settings (colors, fonts, backgrounds)
- Types — TypeScript definitions for data structures
App Entry Points
Every section requires two entry points for SSR and client hydration:
// server.ts — SSR rendering
import { createVueServerApp } from '@lightspeed/crane-api';
import Section from './Section.vue';
import type { ContentType, DesignType } from './type';
export default createVueServerApp<ContentType, DesignType>(Section);// client.ts — Client hydration
import { createVueClientApp } from '@lightspeed/crane-api';
import Section from './Section.vue';
import type { ContentType, DesignType } from './type';
export default createVueClientApp<ContentType, DesignType>(Section);UI Helpers
Higher-level composables and utilities that reduce boilerplate in template development. Import from @lightspeed/crane-api:
import {
useCurrentLanguage,
useBackgroundStyle,
useButtonStyles,
createTextStyle,
getColorHex,
getBackgroundStyle,
getContrastTextColor,
isColorDark,
} from '@lightspeed/crane-api';Composables
useCurrentLanguage()
Returns the current language code from site context with fallback chain: selected → main → 'en'.
const { currentLanguage } = useCurrentLanguage();
// currentLanguage.value === 'en' | 'nl' | 'fr' | ...useBackgroundStyle(backgroundDesign, options?)
Creates reactive CSS background styles from BackgroundDesignData. Supports solid colors and gradients.
const bg = useBackgroundElementDesign<DesignType>('section_bg');
const bgStyle = useBackgroundStyle(bg, { direction: 'to bottom' });
// <div :style="bgStyle">useButtonStyles(buttonDesign, options?)
Generates button CSS styles from ButtonDesignData. Handles size, appearance, shape, and auto contrast text color for solid buttons.
Note:
fontWeightis always set to'400'. UnlikecreateTextStyle, button styles intentionally ignore any bold-related properties — weight is expected to be controlled by the component's own CSS.
const btn = useButtonElementDesign<DesignType>('cta_button');
const btnStyle = useButtonStyles(btn, {
sizes: { large: { fontSize: '20px', padding: '16px 32px' } },
});
// <button :style="btnStyle">Content Composables
Access content defined in settings/content.ts:
| Composable | Editor Type | Return Type |
|------------|-------------|-------------|
| useInputboxElementContent | INPUTBOX | Reactive<InputBoxContent> |
| useTextareaElementContent | TEXTAREA | Reactive<TextAreaContent> |
| useButtonElementContent | BUTTON | Reactive<ButtonContentData> |
| useImageElementContent | IMAGE | Reactive<ImageContent> |
| useToggleElementContent | TOGGLE | Reactive<ToggleContent> |
| useSelectboxElementContent | SELECTBOX | Reactive<SelectBoxContent> |
| useDeckElementContent | DECK | Reactive<DeckContent> |
| useCategorySelectorElementContent | CATEGORY_SELECTOR | Reactive<CategorySelector> |
| useProductSelectorElementContent | PRODUCT_SELECTOR | Reactive<ProductSelector> |
| useLogoElementContent | LOGO | Reactive<LogoContent> |
| useMenuElementContent | MENU | Reactive<MenuContent> |
| useNavigationMenuElementContent | NAVIGATION_MENU | Reactive<MenuContent> |
| useTranslation | — | Translation helper |
Example
import { useInputboxElementContent, useImageElementContent } from '@lightspeed/crane-api';
import type { ContentType } from './type';
const title = useInputboxElementContent<ContentType>('title');
const image = useImageElementContent<ContentType>('hero_image');
Design Composables
Access design settings defined in settings/design.ts:
| Composable | Editor Type | Return Type |
|------------|-------------|-------------|
| useTextElementDesign | TEXT | Reactive<TextDesignData> |
| useTextareaElementDesign | TEXTAREA | Reactive<TextareaDesignData> |
| useButtonElementDesign | BUTTON | Reactive<ButtonDesignData> |
| useBackgroundElementDesign | BACKGROUND | Reactive<BackgroundDesignData> |
| useImageElementDesign | IMAGE | Reactive<ImageDesignData> |
| useToggleElementDesign | TOGGLE | Reactive<ToggleDesignData> |
| useSelectboxElementDesign | SELECTBOX | Reactive<SelectboxDesignData> |
| useLayoutElementDesign | — | Reactive<LayoutDesignData> |
| useLogoElementDesign | LOGO | ComputedRef<LogoDesignData> |
Example
import { useTextElementDesign, useBackgroundElementDesign } from '@lightspeed/crane-api';
import type { DesignType } from './type';
const titleStyle = useTextElementDesign<DesignType>('title_style');
const background = useBackgroundElementDesign<DesignType>('section_background');
Working with DECK
DECK allows collections of cards. Use getReactiveRef to access card fields:
import { useDeckElementContent, EditorTypes } from '@lightspeed/crane-api';
import type { ContentType } from './type';
const slides = useDeckElementContent<ContentType>('slides');
slides.cards?.forEach(card => {
const title = slides.getReactiveRef(card, EditorTypes.INPUTBOX, 'title');
const image = slides.getReactiveRef(card, EditorTypes.IMAGE, 'background');
const button = slides.getReactiveRef(card, EditorTypes.BUTTON, 'cta');
});Utility Functions
| Function | Arguments | Description |
|----------|-----------|--------------------------------------------------------------------------------------------|
| createTextStyle(design, options?) | design: TextDesignData; options?: style defaults/overrides | Creates CSS properties from TextDesignData (font, size, color, bold, italic, visibility) |
| getColorHex(color, fallback?) | color: color-like value; fallback?: hex fallback | Extracts hex string from a Color object, string, or undefined |
| getBackgroundStyle(design, options?) | design: BackgroundDesignData; options?: gradient direction/fallbacks | Returns CSS background style object |
| isColorDark(color) | color: color-like value | Returns true when the color is considered dark |
| getContrastTextColor(backgroundColor, darkTextColor?, lightTextColor?) | backgroundColor: required; darkTextColor?: text for light backgrounds; lightTextColor?: text for dark backgrounds | Returns a readable contrast text color for the given background |
| getCurrentLanguageCode(languages) | languages: Language[] \| undefined | Returns current language code from an array of site languages. Fallback chain: selected → main → 'en' |
// createTextStyle — use inside computed for reactivity
const titleDesign = useTextElementDesign<DesignType>('title');
const titleStyle = computed(() => createTextStyle(titleDesign, {
defaultFont: 'Inter',
defaultSize: 24,
}));
// contrast helpers
const dark = isColorDark('#1a1a2e'); // true
const textColor = getContrastTextColor('#1a2e1a'); // '#FFFFFF'
const textColorCustom = getContrastTextColor('#1a2e1a', '#111111', '#FAFAFA');Requirements
- Node.js >= 20
- Vue >= 3.4
