{"_id":"@metreeca/tile","_rev":"28-f550ffed8a43f6102a862e4c169c8be7","name":"@metreeca/tile","dist-tags":{"latest":"0.3.0"},"versions":{"4.0.0-3":{"name":"@metreeca/tile","version":"4.0.0-3","author":{"url":"https://www.metreeca.com/","name":"Metreeca","email":"info@metreeca.com"},"license":"Apache-2.0","_id":"@metreeca/tile@4.0.0-3","maintainers":[{"name":"knoan","email":"info@metreeca.com"}],"homepage":"https://github.com/metreeca/tile","bugs":{"url":"https://github.com/metreeca/tile/issues","email":"info@metreeca.com"},"dist":{"shasum":"ce6b05a2402a79f362b23ef58276d36f26e5f052","tarball":"https://registry.npmjs.org/@metreeca/tile/-/tile-4.0.0-3.tgz","fileCount":209,"integrity":"sha512-2Q+wW+5HZiwfO8cUm4wch2p3ikuEi1ibXMFO7A1wxmAl7gcbMi70IWHuGJhzsJ29ZjISLuqZ0giHxyHtNDEDIg==","signatures":[{"sig":"MEUCIQDsN7zNqfX+lXB6phanVaAVaAO9T+TY1KQJClJpWhne3AIgWf4f6908h0AS4s+GTowImnYt96jeIia6b5rSIWNsV08=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":385994},"gitHead":"76f4e131887b45520059e7ef305e2d6b53f81be6","_npmUser":{"name":"knoan","email":"info@metreeca.com"},"deprecated":"Superseded by the @metreeca/tile 0.x line; install @metreeca/tile@latest","repository":{"url":"git+https://github.com/metreeca/tile.git","type":"git"},"_npmVersion":"11.17.0","description":"A model‑driven TypeScript/React framework for rapid REST/JSON‑LD frontend development.","directories":{},"_nodeVersion":"24.19.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/tile_4.0.0-3_1789912606091_0.0014021991191459637","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@metreeca/tile","version":"0.2.0","keywords":["typescript","css","design-system","tokens","ui"],"author":{"url":"https://www.metreeca.com/","name":"Metreeca","email":"info@metreeca.com"},"license":"Apache-2.0","_id":"@metreeca/tile@0.2.0","maintainers":[{"name":"knoan","email":"info@metreeca.com"}],"homepage":"https://metreeca.github.io/tile/","bugs":{"url":"https://github.com/metreeca/tile/issues","email":"info@metreeca.com"},"dist":{"shasum":"baf1ef07cabad4be4ee79cce411b7a55744274d9","tarball":"https://registry.npmjs.org/@metreeca/tile/-/tile-0.2.0.tgz","fileCount":79,"integrity":"sha512-aMu3F0Z+g5GS+mZxrMX5uzmIKTy7QBnrH1KDRMFsB2rVZtCfQVp+yPQ/NyXptc6BY5F9Cvfm+hGfkR1RrXytVg==","signatures":[{"sig":"MEYCIQCRSNFzedV7WHrkbgos+z7TLAT4nLXqO9zpLQUH4JF9YQIhAO4Q+WZDs9zWWUXn302cXBLcYnKwsuv9/RVz4qBn7Bu0","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQDyuk1T4oFe9f3XUmlKVGFvSUb1cAZoq2yH1m065zcv7AIgW5t1/mUcKjrEvJ4Q008Wg7VPLmM5WMRjNbSX6RCBIs8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":217270},"type":"module","engines":{"node":">=22.22.0"},"exports":{".":{"default":"./dist/index.js","@metreeca/source":"./src/index.ts"},"./*":{"default":"./dist/*.js","@metreeca/source":"./src/*.ts"},"./*.css":{"default":"./dist/*.css","@metreeca/source":"./src/*.css"},"./*.core":null},"gitHead":"9920a08ed5caada71c2cb2f00dd2686f7191579b","scripts":{"build":"tsc -b tsconfig.build.json && rsync -a --include=\"*/\" --include=\"*.css\" --exclude=\"*\" src/ dist/","check":"npx vitest --typecheck --passWithNoTests run","clean":"rm -rf dist docs node_modules *.tsbuildinfo"},"_npmUser":{"name":"knoan","email":"info@metreeca.com"},"repository":{"url":"git+https://github.com/metreeca/tile.git","type":"git","directory":"packages/tile"},"_npmVersion":"11.17.0","description":"Design system for Metreeca Tile interfaces.","directories":{},"sideEffects":["*.css"],"_nodeVersion":"24.19.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"^5.0.1","typescript":"^6.0.3","@types/node":"^22.20.4"},"_npmOperationalInternal":{"tmp":"tmp/tile_0.2.0_1790267535406_0.1110146339554845","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"_id":"@metreeca/tile@0.3.0","bugs":{"url":"https://github.com/metreeca/tile/issues","email":"info@metreeca.com"},"dist":{"shasum":"9abee813b2aed0c682ea2fd9b9cd8466290e7794","tarball":"https://registry.npmjs.org/@metreeca/tile/-/tile-0.3.0.tgz","fileCount":79,"integrity":"sha512-Pua0XgAeCiDBK8Ou4En3huWGhMciV84WqbQLmhNccjAbZr2hdQaM/B2Unoky9Kf/uzc4LgWMqBiGpq0sO3GDww==","signatures":[{"sig":"MEUCIQDZh3jXJ65KCV6M88gbD0FDHh9L6flQWi8lmGDW32ifTAIgKNiqPp6CoaAY8l0iAGX/nsdUEW7XdBDTd/dmTPYALHw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCsEx0O0atDg9PmXW7ao317Fz1XUUVoJ20Pe0eoJCAIpwIhAJc1IYfZBYrEBji4oneHgMWNk8aOmDXr/0TQzEVamoP2"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@metreeca%2ftile@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":219497},"name":"@metreeca/tile","type":"module","author":{"url":"https://www.metreeca.com/","name":"Metreeca","email":"info@metreeca.com"},"engines":{"node":">=22.22.0"},"exports":{".":{"default":"./dist/index.js","@metreeca/source":"./src/index.ts"},"./*":{"default":"./dist/*.js","@metreeca/source":"./src/*.ts"},"./*.css":{"default":"./dist/*.css","@metreeca/source":"./src/*.css"},"./*.core":null},"gitHead":"f2e5c4204aae7cf06950e52624c4d4b99ee6a29f","license":"Apache-2.0","scripts":{"build":"tsc -b tsconfig.build.json && rsync -a --include=\"*/\" --include=\"*.css\" --exclude=\"*\" src/ dist/","check":"npx vitest --typecheck --passWithNoTests run","clean":"rm -rf dist docs node_modules *.tsbuildinfo"},"version":"0.3.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"f4da2660-310c-4062-9cd6-59bb98266398"}},"homepage":"https://metreeca.github.io/tile/","keywords":["typescript","css","design-system","tokens","ui"],"repository":{"url":"git+https://github.com/metreeca/tile.git","type":"git","directory":"packages/tile"},"_npmVersion":"12.2.0","description":"Design system for Metreeca Tile interfaces.","directories":{},"maintainers":[{"name":"knoan","email":"info@metreeca.com"}],"sideEffects":["*.css"],"_nodeVersion":"22.23.3","_hasShrinkwrap":false,"devDependencies":{"vitest":"^5.0.1","typescript":"^6.0.3","@types/node":"^22.20.4"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/tile_0.3.0_1790924404528_0.2795281616553209"}}},"time":{"created":"2026-09-20T13:56:45.904Z","modified":"2026-10-02T07:00:04.986Z","0.0.1":"2021-04-03T14:04:29.580Z","0.0.2":"2021-04-24T16:22:31.533Z","0.0.3":"2021-04-25T20:28:39.968Z","0.0.4":"2021-05-06T17:02:34.028Z","0.0.5":"2021-05-11T15:14:18.951Z","0.0.6":"2021-05-16T16:44:35.411Z","0.0.7":"2021-05-20T07:41:04.032Z","0.0.8":"2021-05-21T10:21:23.413Z","0.0.9":"2021-05-22T16:50:19.633Z","0.0.10":"2021-05-23T17:26:20.019Z","0.0.11":"2021-06-10T15:47:27.363Z","0.0.12":"2021-09-06T08:46:25.488Z","0.0.13":"2021-09-14T14:05:59.923Z","0.0.14":"2021-09-14T14:06:53.637Z","0.0.0":"2022-01-30T09:39:47.579Z","0.1.0":"2022-01-30T10:04:03.786Z","0.0.0-0":"2022-10-26T08:58:52.846Z","0.4.0-0":"2025-04-24T06:21:19.694Z","4.0.0-2":"2025-05-26T15:55:07.717Z","4.0.0-3":"2026-09-20T13:56:46.248Z","0.2.0":"2026-09-24T16:32:15.511Z","0.3.0":"2026-10-02T07:00:04.619Z"},"bugs":{"url":"https://github.com/metreeca/tile/issues","email":"info@metreeca.com"},"author":{"url":"https://www.metreeca.com/","name":"Metreeca","email":"info@metreeca.com"},"license":"Apache-2.0","homepage":"https://metreeca.github.io/tile/","keywords":["typescript","css","design-system","tokens","ui"],"repository":{"url":"git+https://github.com/metreeca/tile.git","type":"git","directory":"packages/tile"},"description":"Design system for Metreeca Tile interfaces.","maintainers":[{"name":"knoan","email":"info@metreeca.com"}],"readme":"# @metreeca/tile\n\n[![npm](https://img.shields.io/npm/v/@metreeca/tile)](https://www.npmjs.com/package/@metreeca/tile)\n\nDesign system for [Metreeca Tile](https://github.com/metreeca/tile) interfaces.\n\nAn app includes the stylesheet and gets a coherent look across every Tile component: a token layer defining colour,\ntype, spacing, sizing and focus affordances, and base rules applying them to plain document markup. Redefining a token\nin a later rule restyles everything that reads it, with no component change.\n\nThe palette stands on five colour anchors, every colour a role carries deriving from them, so retuning the anchors\ncarries the whole interface along and the default look follows the platform colour scheme, light or dark, on its own.\nBeside the roles come the colours a chart, a coding or a map reads: ten-step scales, series slots and area classes,\neach holding a separation a reader can rely on.\n\nThe dependency runs one way and stays optional: components carry only the structural styling they need to work, so an\napp that leaves this package out still gets a usable, plainly structured interface. What both sides honour is the token\nnaming contract, published here as typed constants.\n\n# Installation\n\n```shell\nnpm install @metreeca/tile\n```\n\n> [!WARNING]\n>\n> TypeScript consumers must use `\"moduleResolution\": \"nodenext\"/\"node16\"/\"bundler\"` in `tsconfig.json`.\n> The legacy `\"node\"` resolver is not supported.\n\n# Usage\n\n> [!NOTE]\n>\n> This section introduces essential concepts; for complete coverage, see the\n> [API reference](https://metreeca.github.io/tile/modules/_metreeca_tile.html).\n\nInclude the stylesheet once, at the entry point of the app, ahead of the app styles overriding it:\n\n```typescript\nimport \"@metreeca/tile/index.css\";\n```\n\nAn app assembling its own HTML links it in the document head instead: the stylesheet has to reach the document before\nit is painted, or the first frame shows the unstyled markup.\n\nOverride any token to restyle the interface:\n\n```css\n:root {\n    --tile--color-strong: light-dark(#D60, #F80);\n    --tile--font-family: Inter, sans-serif;\n}\n```\n\nThe stylesheet declares its rules in a `tile` cascade layer, so an override written outside a layer wins however the\ntwo stylesheets reach the document; an app whose own rules are layered orders its layer after `tile`.\n\nRetheme by retuning the anchors alone, `--tile--color`, `--tile--background-color`, `--tile--color-subtle`,\n`--tile--color-strong` and the four status colours `--tile--color-info`, `--tile--color-pass`,\n`--tile--color-warn` and `--tile--color-fail`: labels, borders, stripes, focus rings, state fills, notice tints\nand elevation surfaces derive from them and follow. The accents ship brand-agnostic, so an app supplies its own,\na quieter value and a louder one per colour scheme, and rechecks that the text roles still hold AA contrast against\nthe page and the striped row in both. The status four take values of their own rather than derivations of an accent,\nso an outcome keeps reading as itself whatever an app brands with.\n\nA malformed override is caught only where the token has a fixed type: a weight, a duration or an opacity the browser\ncannot parse stays on its default. Most tokens, the colour anchors and the sizes among them, take an override as\nwritten, so a malformed value leaves whatever reads it unstyled rather than on the default.\n\nA colour differing by scheme is stated once, as a `light-dark()` pair, and every scheme and every pinned subtree\nfollows it with no rule restated per scheme:\n\n```html\n<style>\n    :root {\n        --tile--color-subtle: light-dark(#1C275D, #9AB);\n        --tile--color-strong: light-dark(#D60, #F80);\n    }\n</style>\n```\n\nAn override in the document head, as above, is in force from the first frame, so a loader painted before the\nstylesheet arrives already reads the brand; one in an app stylesheet takes effect once that stylesheet loads.\n\nAn interface follows the platform colour scheme on its own. An app that has to pin one sets `data-theme` to `light` or\n`dark`, on the root element or on any subtree that has to differ from the page around it, which a\n`prefers-color-scheme` query cannot express. The pinned subtree takes its side of every `light-dark()` pair, the app's\noverrides included, and the stylesheet states `color-scheme` alongside, so native controls and scrollbars follow it\ntoo.\n\n## Modes\n\nA widget says what it is for through at most two attributes, and they never compete for the same channel.\n\n**`look` — how loud it appears.** Structural, carried by layout, weight and border rather than by colour: `subtle`\nrecedes, `normal` is ordinary, `strong` is larger, earlier, heavier and bounded, and would read as strong in a\nsingle-colour interface. The pair is the one the colour anchors already use, so a single vocabulary names this axis\nthroughout. A widget offers the steps that say something about it and names them in its own documentation, so a tab\nstrip with no form louder than its rule takes `subtle` and `normal` alone, and an area written in a step it does not\noffer lands on the nearest one it does.\n\nA widget stating no `look` takes the one the area around it is written in, from `--tile--look`, which is `normal`\nwhere nothing assigns it. An app quietens a whole toolbar, panel or screen by assigning the token there, and the one\ncontrol in it that asks to be loud still is, since a stated attribute answers to itself alone.\n\n```tsx\n<div style={css({ look: \"subtle\" })}>\n```\n\n**What it means** is colour-coded, and every meaning lands on one four-step scale:\n\n| Step   | Says                   | Token                |\n|--------|------------------------|----------------------|\n| `info` | stated or provisional  | `--tile--color-info` |\n| `pass` | completed as intended  | `--tile--color-pass` |\n| `warn` | completed with caveats | `--tile--color-warn` |\n| `fail` | failed to complete     | `--tile--color-fail` |\n\nThe shape is one unjudged step plus a three-step verdict ramp: `info` is not a milder `pass`, it is the absence of a\nverdict. Four steps is the ceiling, because colour carries no more, so a meaning the scale does not carry is stated in\nwords rather than in a fifth colour.\n\nThree kinds of meaning share the scale, and which one a widget carries follows from what the widget is, so no widget\ncarries two:\n\n- **`level`**, on content: how much attention a passage deserves, set by the author ahead of time\n- **`mode`**, on controls: what activating will do, a consequence not yet incurred\n- **`status`**, on reported things: what the system says happened, at runtime\n\n`normal` is **the default of all three, and it is not a step**: it carries no colour coding at all and leaves the\nordinary page colours, so a widget that states nothing is `normal` and a `level=\"normal\"` passage is not a blue `info`\nadmonition. Only the marked values reach the scale. The widget maps those onto the steps and states that mapping in\nits own documentation.\n\n| Attribute | `normal`            | `info`    | `pass`      | `warn`    | `fail`     |\n|-----------|---------------------|-----------|-------------|-----------|------------|\n| `level`   | an ordinary passage | `info`    | `highlight` | `warning` | `critical` |\n| `mode`    | an ordinary control | `safe`    | `commit`    | `alert`   | `danger`   |\n| `status`  | nothing to report   | `pending` | `success`   | `warning` | `failure`  |\n\nThe two attributes together read as how it appears and what it means:\n\n```tsx\n<Button look=\"subtle\" mode=\"danger\"/>\n<Note   look=\"strong\" level=\"warning\"/>\n```\n\n> [!IMPORTANT]\n>\n> A step is never told by colour alone: an icon and the wording carry the same meaning, since the two ends of the\n> ramp are the pair colour vision deficiency collapses most readily. `--tile--color-warn` is a fill rather than a\n> stroke, so a caution paints a badge and sets its message in the page colour over it.\n\nA thing lifted off the page takes a surface and the shadow that goes with it together, `--tile--background-color-raised`\nwith `--tile--box-shadow-raised` for a card that stays in the flow and `--tile--background-color-overlay` with\n`--tile--box-shadow-overlay` for a menu or a dialog that leaves it. `--tile--z-index-*` settles which of two overlapping\nthings wins, and `--tile--background-color-blanket` dims what a modal covers.\n\nMotion is stated the same way: `--tile--duration-*` says what kind of change a transition carries and\n`--tile--easing-*` how it accelerates, and every duration collapses to zero for a reader who asked for less motion, so\na transition written through the tokens honours the preference with no rule of its own.\n\nWhere a colour stands for a position rather than for a role, take it from a ten-step scale: `--tile--color-gray-*` for\na neutral, `--tile--color-subtle-*` and `--tile--color-strong-*` for a branded one, `--tile--color-heat-*` for a\nmagnitude. The number is the share of the anchor the step carries, `010` the faintest and `100` the anchor itself, so\nthe three derived scales follow a retheme. The heat scale keeps literals of its own and codes by hue, so a step means a\nband a legend names rather than a position on a gradient, and a consumer states the band in text beside the colour.\n\nWhere a colour stands for one thing among others, take it from a slot or a class. `--tile--color-series-1` to\n`--tile--color-series-9` paint a bar, a line or a wedge: taken in sequence and held to the thing each one paints, so a\nfilter dropping a series leaves the survivors their colours. `--tile--color-area-1` to `--tile--color-area-4` fill a\nshape instead, a region on a choropleth or a cell on a grid, and four is the limit: a fifth class is a second map. Both\nfamilies keep one value per slot across colour schemes, and neither follows a rebrand. Nine series hold where only\nneighbours are compared; where every pair is compared, on a scatter, a bubble chart or a map, the first three hold.\nSome of both stay under 3:1 against the light page, so a chart carrying them states its figures in text as well and a\nmap keeps its boundaries drawn and names its classes in the legend.\n\nMeasures are stated in `em`, so a subtree given a size of its own takes its rhythm along. The two ladders answer\ndifferent questions: `--tile--spacing-*` sets a thing apart from what surrounds it, while `--tile--scaling-*` sizes what\nis measured against the text rather than spaced from it, a glyph, a spinner, a swatch or a dot, with\n`--tile--scaling-100` matching the text it sits in.\n\nRadii come both ways: `--tile--border-radius` is a length, rounding a field, a panel or a button by the same amount\nwhatever size it is given, while `--tile--border-radius-*` carries a share of the box, so a mark rounds with its own\nsize and every share above a half draws the same roundel. `--tile--stroke-width` carries a bare number, in the user\nunits of the vector viewport it applies to, so the weight of a glyph holds at any size.\n\nA breakpoint is not a width token, because CSS accepts no custom property in a media feature and\n`@media (min-width: var(--x))` never matches. The design system runs the four queries once and hands the answers on as\n`--tile--viewport-*` tokens, `off` by default and `on` from each width upwards, which a rule branches on through a\nstyle query.\n\n| Token                     | From    | What it answers                                              |\n|---------------------------|---------|--------------------------------------------------------------|\n| `--tile--viewport-small`  | `30rem` | a phone held upright, the one-column floor                   |\n| `--tile--viewport-medium` | `48rem` | a tablet or a split window, where a second column fits       |\n| `--tile--viewport-large`  | `64rem` | a laptop, where navigation becomes a rail                    |\n| `--tile--viewport-xlarge` | `90rem` | a desktop, where the measure is capped rather than stretched |\n\nEvery width is a floor, so the narrow layout is what a rule states unconditionally and each breakpoint only adds to\nit, leaving the narrower flags on; a band pairs the wider flag as `off` with the narrower one as `on`.\n\n```css\n@container style(--tile--viewport-medium: on) {\n    tile-screen {\n        grid-template-columns: 1fr 2fr;\n    }\n}\n```\n\nThe tokens are assigned on the root element and inherit, so every element sits inside a container the query matches\nand no rule declares one of its own. They make a breakpoint reusable rather than retunable: the width stays in the\nstylesheet, so overriding a flag forces it without moving the threshold, and an app wanting thresholds of its own\nwrites its own media queries. Code needing the same answer reads the token through `getComputedStyle`, as it reads any\nother value outside the cascade.\n\nA widget changing shape because of the space it was given states a `@container` size query against its own inline size\ninstead and needs no breakpoint at all.\n\nA component styled against a token it cannot count on, because the stylesheet may not be loaded at all, names its own\nfallback in the reference:\n\n```css\ncolor: var(--tile--color-strong, #06C);\n```\n\nRestyle a single subtree instead by assigning the tokens inline, naming them through the published contract rather than\nas literal strings, so a renamed token breaks the build instead of silently losing its styling:\n\n```tsx\nimport { css } from \"@metreeca/tile\";\n\n<section style={css({ colorStrong: \"#D60\" })}>\n```\n\nRead a token where a single CSS value is written by hand rather than by a rule, in an inline style or a presentation\nattribute. The reference resolves wherever it is read, so it carries whatever the app overrode and whichever colour\nscheme is in force:\n\n```tsx\nimport { css, tile } from \"@metreeca/tile\";\n\n<span style={{ backgroundColor: css.var(tile.colorStrong) }}/>\n```\n\nA component that cannot count on the stylesheet being loaded writes the reference by hand instead, naming in it the\nfallback it wants, as above.\n\nWhere a reference doesn't reach, on a canvas or against an API taking a colour as text, take the value a token resolves\nto for the element it applies to, rather than a copy of the default, and keep whatever the app overrode along with the\ncolour scheme in force:\n\n```typescript\nimport { tile } from \"@metreeca/tile\";\n\ngetComputedStyle(element).getPropertyValue(tile.colorStrong);\n```\n\n# Support\n\n- open an [issue](https://github.com/metreeca/tile/issues) to report a problem or to suggest a new feature\n- start a [discussion](https://github.com/metreeca/tile/discussions) to ask a how-to question or to share an idea\n\n# License\n\nThis project is licensed under the Apache 2.0 License –\nsee [LICENSE](https://github.com/metreeca/tile?tab=Apache-2.0-1-ov-file) file for details.\n","readmeFilename":"README.md"}