Skip to content

libraz/formulon-cell

Repository files navigation

formulon-cell

CI codecov npm npm — react npm — vue License TypeScript

Spreadsheet UI library for the formulon WASM calc engine. Desktop-spreadsheet-style chrome, canvas-rendered grid, extension-based feature composition, runtime i18n.

β (beta). formulon-cell is built primarily as a demonstration host for formulon — a headless, Excel-compatible calculation engine in C++17 that ships a single WASM / Python / CLI core. Engine docs live at formulon.libraz.net. The UI surface is still evolving; pin a version range you can upgrade on purpose.

Packages

package npm what it is
@libraz/formulon-cell npm Vanilla TS / DOM core
@libraz/formulon-cell-react npm React 18+ component, hooks, and ribbon toolbar
@libraz/formulon-cell-vue npm Vue 3 component, composables, and ribbon toolbar

Install

npm install @libraz/formulon-cell zustand
# or yarn / pnpm

zustand is a peer dependency — exposed because consumers can read from the same store the chrome subscribes to.

The WASM engine ships pthread-enabled and requires a crossOriginIsolated context (Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corp). Without it, formulon-cell falls back to an in-memory stub engine — the UI keeps working, formulas degrade gracefully.

Quick Start

import { Spreadsheet, WorkbookHandle, presets } from '@libraz/formulon-cell';
import '@libraz/formulon-cell/styles.css';

const host = document.getElementById('sheet')!;
const wb = await WorkbookHandle.createDefault();
const sheet = await Spreadsheet.mount(host, {
  workbook: wb,
  features: presets.full(),
  locale: 'en',
});

sheet.i18n.setLocale('ja');     // runtime locale swap
sheet.setTheme('ink');           // dark mode

Bundler integration

formulon-cell re-uses @libraz/formulon's pthread-enabled WASM module, so the bundler hygiene rules from the engine package apply here too. Four things matter:

1. Workers must ship as ES modules. The recalc scheduler runs on Web Workers spawned by Emscripten with new Worker(new URL(...), { type: 'module' }). Bundlers default to classic (IIFE) workers and must be told otherwise:

// vite.config.ts
export default defineConfig({
  worker: { format: 'es' },
});

webpack 5 picks up { type: 'module' } automatically when output.module: true. esbuild needs --format=esm for the worker chunk.

2. Top-level await + dynamic node imports need an es2022 target. The engine factory uses TLA and conditional await import('node:...'). Lift both the main and worker target:

// vite.config.ts
export default defineConfig({
  build: { target: 'es2022' },
});

3. Keep the engine out of dependency pre-bundling. formulon-cell imports @libraz/formulon, whose Emscripten wrapper owns the worker/WASM asset resolution. Keep both packages out of dependency pre-bundling so those assets stay under the app bundler's control:

// vite.config.ts
export default defineConfig({
  optimizeDeps: { exclude: ['@libraz/formulon-cell', '@libraz/formulon'] },
});

4. SharedArrayBuffer requires cross-origin isolation. Serve your page with Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corp. Without these headers, SharedArrayBuffer is undefined and formulon-cell drops to an in-memory stub engine: the canvas, formula bar, and editing affordances all keep working, but formula evaluation, recalc, and xlsx round-trip degrade to no-ops. Detect at runtime via crossOriginIsolated or via isUsingStub() after WorkbookHandle.createDefault():

import { WorkbookHandle, isUsingStub } from '@libraz/formulon-cell';

const wb = await WorkbookHandle.createDefault();
if (isUsingStub()) {
  console.warn('formulon-cell: running on stub engine — recalc disabled');
}

Features

  • Desktop-spreadsheet-style chrome out of the box (formula bar, status bar, context menu, sheet tabs, View toolbar).
  • Canvas-rendered grid with theme tokens — paper (light) and ink (dark) ship in the box; bring your own with the documented CSS variables.
  • Extension-based API: built-ins are controlled with feature flags, and replaceable pieces (find/replace, format dialog, paste-special, hyperlink dialog, hover comments, View toolbar, Quick Analysis, PivotTable creation, …) are available as extension factories you can compose into the mount call.
  • Runtime i18n — swap locales without re-mounting; ja and en ship by default, register more at runtime.
  • Headless option — keep just the canvas + store and provide your own chrome.

Presets

preset what's in it
presets.minimal() formula bar, status bar, basic keymap
presets.standard() + View toolbar, Quick Analysis, session chart overlays, workbook object inspector, context menu, find/replace, clipboard, format painter, wheel scroll
presets.full() + format dialog, paste-special, conditional formatting, iterative calculation settings, Go To Special, page setup, named ranges, hyperlink dialog, PivotTable creation, validation, autocomplete, hover comments, spreadsheet keymap

i18n

import { Spreadsheet } from '@libraz/formulon-cell';

const sheet = await Spreadsheet.mount(host, { locale: 'en' });

// Swap locale at runtime — every label updates in place.
sheet.i18n.setLocale('ja');

// Override a few strings without forking the dictionary.
sheet.i18n.extend('ja', { contextMenu: { copy: 'コピーする' } });

// Register a brand new locale.
import fr from './fr.js';
sheet.i18n.register('fr', fr);
sheet.i18n.setLocale('fr');

Demo apps

app run what it shows
apps/playground yarn dev Vanilla DOM playground (spreadsheet keymap)
apps/react-demo yarn dev:react Same surface as <Spreadsheet> React component
apps/vue-demo yarn dev:vue Same surface as <Spreadsheet> Vue component

Framework Ribbon Toolbars

The React and Vue packages publish the demo ribbon as reusable framework chrome. Both implementations expose the same ribbon tab model and command surface; import the matching toolbar CSS alongside the component.

import { SpreadsheetToolbar, type RibbonTab } from '@libraz/formulon-cell-react';
import '@libraz/formulon-cell-react/toolbar.css';
<script setup lang="ts">
import { type RibbonTab } from '@libraz/formulon-cell-vue';
import SpreadsheetToolbar from '@libraz/formulon-cell-vue/toolbar.vue';
import '@libraz/formulon-cell-vue/toolbar.css';
</script>

Releasing

See docs/releasing.md for the manual tag-based release flow.

License

Apache-2.0

About

Spreadsheet UI library for the formulon WASM calc engine — extension-based, i18n-aware, canvas-rendered grid

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors