cssints 0.28.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/docs/API.md +50 -1
  2. package/package.json +2 -2
package/docs/API.md CHANGED
@@ -1792,6 +1792,7 @@ createPanZoom(options?: {
1792
1792
  zoomIn(): void;
1793
1793
  zoomOut(): void;
1794
1794
  setScale(scale: number, origin?: { x: number; y: number }): void; // origin in the viewport's own space, its centre by default
1795
+ panBy(dx: number, dy: number): void; // a relative pan through the same clamp as a drag; a host's glide uses this
1795
1796
  viewportProps: {
1796
1797
  tabindex: 0;
1797
1798
  role: "group";
@@ -1814,7 +1815,7 @@ createPanZoom(options?: {
1814
1815
 
1815
1816
  Wheel zooms **only with `ctrl` / `meta`** held: the browser's pinch gesture arrives that way, and a bare wheel is left to the page so trackpad scrolling still works — a swallowed wheel is never acceptable. Arrows pan the image with the arrow (like a drag), and with `bounds: "clamp"` they are inert at `min`, where there is nothing to reveal. The clamp bounds the offset by half the viewport's scaled overflow, so the image is expected to fill the viewport at `min` (`width: 100%; height: 100%` / `object-fit: cover`); a letterboxed image cannot be held gap-free, and `bounds: "free"` lets it be dragged out of view instead. `valueProps` carries no `hidden` — a `hidden` live region is not announced — so the host hides it visually.
1816
1817
 
1817
- The host owns the box and the look: the viewport's size and `overflow: hidden`, `touch-action: none` if a touch drag should pan, `transform-origin: 50% 50%` (the default this maths assumes), and any transition on the transform. Controlled is `scale` + `onScaleChange`; the offset has no controlled prop, so a host that ignores a scale request also gets the offset resolved for the scale it refused. Not modelled: inertia, rotation, and pinching on platforms without `PointerEvent` (the browser's own pinch is the `ctrl+wheel` path).
1818
+ The host owns the box and the look: the viewport's size and `overflow: hidden`, `touch-action: none` if a touch drag should pan, `transform-origin: 50% 50%` (the default this maths assumes), and any transition on the transform. Controlled is `scale` + `onScaleChange`; the offset has no controlled prop, so a host that ignores a scale request also gets the offset resolved for the scale it refused. A host that moves the pan without a pointer calls `panBy(dx, dy)`: it takes the same bounded `move` as a drag, so the clamp and `onPanChange` hold for an inertial glide and a drag alike (the kit's `Panzoom` glides after a flick this way). Not modelled: rotation, and pinching on platforms without `PointerEvent` (the browser's own pinch is the `ctrl+wheel` path).
1818
1819
 
1819
1820
  ### Headless: `createMenu` (`@cssints/headless`)
1820
1821
 
@@ -3930,6 +3931,54 @@ createPlayer(options: {
3930
3931
  slider does not mirror its arrows under RTL — a time axis does not flip, a deliberate divergence
3931
3932
  from `slider.qnt`.
3932
3933
 
3934
+ ### Stories: `@cssints/stories` (decided 2026-11-02)
3935
+
3936
+ The CSF 3 loader of a storybook, with no DOM, no styles and no chrome: the modules an app globs in, the entries with the ids
3937
+ Storybook builds out, and the controls a story declares. It serves the starters' site, the reactive lab and (the reason it is
3938
+ a package rather than two copies) a native window.
3939
+
3940
+ ```ts skip
3941
+ // src/registry/button/button.stories.tsx — a Storybook CSF 3 file, unchanged
3942
+ import type { Meta, Story } from "@cssints/stories";
3943
+ import { Button, type ButtonProps } from "./button.tsx";
3944
+
3945
+ const meta = {
3946
+ title: "Button",
3947
+ component: Button,
3948
+ args: { children: "Save", tone: "neutral" },
3949
+ argTypes: {
3950
+ tone: { type: "select", options: ["neutral", "accent", "quiet"] },
3951
+ disabled: { type: "boolean" },
3952
+ },
3953
+ } satisfies Meta<ButtonProps>;
3954
+ export default meta;
3955
+
3956
+ export const Default: Story<ButtonProps> = {};
3957
+ export const Publish: Story<ButtonProps> = { args: { tone: "accent", children: "Publish" } };
3958
+ ```
3959
+
3960
+ ```ts skip
3961
+ import { entries, parseHash, storyOfId, type Module } from "@cssints/stories";
3962
+
3963
+ const modules = import.meta.glob<Module>("../registry/*/*.stories.tsx", { eager: true });
3964
+ const stories = entries(modules); // [{ id: "button--default", item: "button", view, args, argTypes, … }]
3965
+ ```
3966
+
3967
+ - **`entries(modules, itemOf?)`** returns `Entry[]`: `id` (`button--publish`, the item's name and the story's,
3968
+ kebab-cased), `item` (the story file's directory, or whatever `itemOf` reads from the path), `title`, `name`, `args` (the
3969
+ meta's with the story's over them), `argTypes`, and `view(args)` — the meta's `component` called through
3970
+ `createComponent`, or the story's own `render`. Entries are sorted by item and then by id; within a file the module
3971
+ namespace's order is what Storybook lists.
3972
+ - **`storyOfId(stories, id)`** finds one entry, and **`parseHash(hash)`** splits `#button--publish` into the page
3973
+ (`button`) and the story, so an app's hash is a link to a story.
3974
+ - **`argTypes`** is the controls model: `{ type: "boolean" }`, `{ type: "select", options }`, `{ type: "text" }`,
3975
+ `{ type: "number", min?, max?, step? }`, `{ type: "range", min, max, step? }`. Storybook infers a control from a
3976
+ component's props; a Solid component carries none at run time, so a story declares what it wants. **The panel is the
3977
+ app's**: the site draws it on the kit's `Field`, `Select`, `Switch` and `Slider`, and a story with no `argTypes` gets no
3978
+ panel.
3979
+ - **`Node`** is a type parameter: `entries<JSX.Element>(modules)` on the web, `entries<NativeNode>(modules)` in
3980
+ `cssints-native`, and the package never names a renderer. `solid-js` is a peer (for `createComponent` alone).
3981
+
3933
3982
  ### Publishing a library (decided 2026-10-02, cssints-0l3f)
3934
3983
 
3935
3984
  A package written on cssints ships JavaScript that still has the attribute, and its `.d.ts`. The app that installs it evaluates the package with its own engine: one sheet, the app's browserslist and themes, and a token, a kernel or an `@property` of the package is made once however many modules use it. Nothing is declared: the engine recognises a file by `with { type: "cssints" }`, the same marker as in app code.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cssints",
3
- "version": "0.28.0",
3
+ "version": "0.29.0",
4
4
  "description": "CSS in TypeScript: typed css.* calls compiled to atomic CSS at build time (a Vite plugin)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -72,7 +72,7 @@
72
72
  }
73
73
  },
74
74
  "dependencies": {
75
- "@cssints/css-grammar": "^0.28.0",
75
+ "@cssints/css-grammar": "^0.29.0",
76
76
  "culori": "^4.0.2",
77
77
  "effect": "4.0.6",
78
78
  "happy-dom": "^20.14.5",