npm.io
1.1.0 • Published 52m ago

@mk/film

Licence
MIT
Version
1.1.0
Deps
2
Size
1.0 MB
Vulns
0
Weekly
0

Film

The Film Design Language — an opinionated, modern web component library built with Lit. Its layout components follow the Every Layout primitives, and every size is a step on a single modular scale so the whole UI stays in proportion.

Install

npm i @mk/film lit

Usage

import '@mk/film'          // registers every <film-*> element
import '@mk/film/css/themes/default/index.css'
<film-stack>
  <film-box>
    <p>A box in a stack.</p>
  </film-box>
  <film-button>Click me</film-button>
</film-stack>
Individual imports (tree-shaking)

The package ships as preserved ES modules, so you can import only what you use:

import '@mk/film/actions/button'   // registers just <film-button>
import '@mk/film/layout/stack'
React

Typed React wrappers (generated with @lit/react) are available at @mk/film/react:

import { FilmButton, FilmDialog } from '@mk/film/react'

<FilmButton invert onClick={save}>Save</FilmButton>
Tooling

A Custom Elements Manifest (custom-elements.json) is published for IDE autocomplete and documentation tooling.

Components

Layout (src/layout)

Element Purpose
film-stack Even, scale-based vertical spacing between children.
film-box Padded, bordered box (invert).
film-center Horizontally centres content within --measure.
film-cluster Wrapping row of items with an even gap.
film-sidebar Two-part sidebar/content layout that collapses when tight. scroll="start|end|both" gives a pane its own scrollbar (needs a bounded host height).
film-grid Auto-fit responsive grid (min, space).
film-switcher Row that flips to a stack below a threshold (or limit).
film-cover Fills a min height and centres content, with top/bottom.
film-frame Crops slotted media to a fixed ratio.
film-reel Horizontally scrolling, snap-aligned strip.
film-imposter Overlays content centred on a positioned ancestor.
film-icon Sizes a slotted SVG to the adjacent text.
film-split-panel Two panes with a draggable, keyboard-operable divider.

Actions (src/actions) — film-button, film-button-group, film-icon-button, film-link, film-copy-button.

Typography (src/typography) — film-heading, film-text, film-prose, film-divider, film-visually-hidden, film-kbd.

Forms (src/forms) — form-associated controls (participate in a native <form> via ElementInternals): film-input, film-textarea, film-number-input, film-search, film-select / film-select-option, film-combobox, film-checkbox, film-radio / film-radio-group, film-switch, film-range, film-slider, film-color-picker, film-date-picker / film-calendar, film-file-input. Plus film-field (label/hint/error wrapper) and film-form (validation + submit).

Navigation (src/navigation) — film-breadcrumb / film-breadcrumb-item, film-menu / film-menu-item (with flyout submenus), film-menu-bar / film-menu-bar-item, film-tabs / film-tab / film-tab-panel, film-tree / film-tree-item, film-pagination, film-steps / film-step, film-nav / film-nav-item.

Overlays (src/overlays) — film-dialog and film-drawer (native <dialog> top layer), film-dropdown, film-tooltip, film-popover and film-popconfirm (Popover API + a hand-rolled positioning helper).

Windowing (src/windowing) — film-window (non-modal, stackable, draggable/resizable panel, not top-layer) and film-workspace (its container: z-order, focus, floating with drag-to-snap, and grid or recursive-BSP tiling). Built on the exported DragController.

Data (src/data) — film-card (with media / footer slots), film-avatar, film-details, film-accordion / film-accordion-item, film-list / film-list-item, film-code, film-table (data-driven, with optional sorting / selection / sticky header / row virtualisation).

Feedback (src/feedback) — film-alert, film-badge, film-tag (variant, removable), film-progress-bar, film-spinner, film-skeleton, plus film-toast + the imperative toast(message, options) helper.

See ROADMAP.md for planned components and features.

Modular scale

Sizes come from CSS custom properties --s-5--s5, generated from a single --ratio. The scale uses the CSS pow() function where supported and falls back to a calc() chain everywhere else. Override the whole system by setting --ratio and --s0 on :root.

Theming

Film is themed entirely through CSS custom properties — because custom properties inherit through the shadow DOM, anything you set on :root (or any subtree) reaches every component. All colours are authored in oklch.

There are three layers:

  1. Palette (--film-palette-*) — raw oklch primitives. Internal; don't reference these directly.
  2. Semantic tokens (--film-*) — the theming API. Components only ever read from this layer.
  3. Components — consume the semantic tokens.

To retheme, override the semantic tokens:

:root {
  --film-color-primary: oklch(0.72 0.15 250);
  --film-color-link: oklch(0.55 0.16 250);
  --film-color-danger: oklch(0.9 0.06 25);
  --film-radius: 0.25rem;      /* squarer corners everywhere */
  --film-font-sans: "Inter", system-ui, sans-serif;
}

The main tokens:

Token Purpose
--film-color-text / --film-color-text-muted Body text / secondary text
--film-color-background / --film-color-surface Page / component surfaces
--film-color-border Borders and dividers
--film-color-primary (-hover / -active / -text) Buttons / accents
--film-color-inverted-surface / --film-color-inverted-text Dark-on-light pairs (inverted Box, tooltips, badges…)
--film-color-link / --film-color-focus Links / focus rings
--film-color-info / -success / -warning / -danger Status surfaces
--film-radius-sm / --film-radius / --film-radius-lg / --film-radius-pill Corner radii
--film-shadow-1 / --film-shadow-2 (--film-shadow-color) Elevation for floating surfaces
--film-overlay-scrim Modal/drawer backdrop
--film-disabled-opacity Disabled-state opacity
--film-z-sticky / --film-z-overlay / --film-z-toast Stacking scale (non-top-layer elements)
--film-duration-fast / --film-duration / --film-ease Motion
--film-font-sans / -serif / -mono Font families
Dark mode

The theme ships light and dark values via the CSS light-dark() function, so it follows the OS preference automatically. Force a scheme on any subtree with a data attribute:

<html data-theme="dark">   <!-- or "light" -->
Palettes

Colour palettes live in css/themes/default/application/palettes.css and are selected with data-film-theme (independent of the light/dark scheme). The default is paper; the rest are period film stocks:

data-film-theme Look
paper (default) Warm neutral + terracotta accent
classic The original pastel cream + teal
kodachrome '60s Kodak — warm, saturated reds & golds
polaroid '70s SX-70 — faded creamy warmth, soft rounded corners
ektachrome '80s Kodak — cool crisp cyan-blue, sharp corners
velvia '90s Fujichrome — ultra-saturated emerald + punchy chroma
<html data-film-theme="kodachrome" data-theme="dark">

Each palette only overrides the --film-color-* roles (and, for some, the corner radius), so adding a new one is a single CSS block. That file is the config a theme picker can enumerate.

Development

npm install
npm run dev        # start the Vite dev server (demo site)
npm run typecheck  # type-check with tsc
npm run build      # build the demo site into dist/
npm run build:lib  # build the publishable library into dist/

Written in TypeScript with Lit decorators. The library source lives in src/ (grouped into layout, actions, typography, forms, navigation, overlays, data, feedback, with shared internals in internal), the demo site in demo/, and the theme/scale CSS in css/ (palette in definitions/colors.css, semantic tokens in application/theme.css). Every component extends FilmElement; form controls extend FilmFormControl.

Keywords