From d20410adfb5f8e54a05a129620a43ad66e254aea Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Jul 2026 21:23:30 +0000 Subject: [PATCH 1/4] refactor(states)!: rename .sf-is-skeleton to .sf-is-shimmer (#575) Resolve the naming collision between the shipped shimmer *state* (.sf-is-skeleton, applicable to any element) and the planned .sf-skeleton *component* (roadmap / #384 item 8). Renaming the state to .sf-is-shimmer reserves "skeleton" for the component alone, preserves the framework's state/component axis separation (.sf-is-* = state, .sf-* = structural), and makes the class name mirror its driving token, --sf-animation-shimmer. Shipped ahead of the component so this one breaking rename stays out of the otherwise purely additive .sf-skeleton release. Behaviour, tokens, and markup support are unchanged. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_017x2JYaWJoPoHWNCEhDA7NR --- configurator/src/data/classes.generated.json | 6 +++--- core/states.css | 10 +++++++--- demo/index.html | 14 ++++++------- docs/api-audit-checklist.md | 2 +- docs/api-index.json | 6 +++--- docs/api-index.md | 2 +- docs/classes.md | 2 +- docs/migration.md | 21 ++++++++++++++++++++ docs/registry.json | 2 +- docs/roadmap.md | 16 ++++++++------- docs/states.md | 4 ++-- docs/token-annotations.json | 2 +- tests/demo-visual.spec.js | 4 ++-- tests/states-full.spec.js | 4 ++-- 14 files changed, 61 insertions(+), 34 deletions(-) diff --git a/configurator/src/data/classes.generated.json b/configurator/src/data/classes.generated.json index 2f134350..8f93b9a1 100644 --- a/configurator/src/data/classes.generated.json +++ b/configurator/src/data/classes.generated.json @@ -2005,12 +2005,12 @@ "layer": "slashed.states" }, { - "name": "sf-is-skeleton", - "selector": ".sf-is-skeleton", + "name": "sf-is-shimmer", + "selector": ".sf-is-shimmer", "kind": "state", "category": "State classes", "group": "LOADING / ASYNC FEEDBACK", - "description": "Skeleton loading placeholder state. Applies a shimmer animation over the element to indicate that content is loading. Works on both img and non-media elements.", + "description": "Shimmer loading placeholder state. Applies a shimmer animation over the element to indicate that content is loading. Works on both img and non-media elements. (Renamed from .sf-is-skeleton so \"skeleton\" refers only to the planned .sf-skeleton component.)", "optional": false, "layer": "slashed.states" }, diff --git a/core/states.css b/core/states.css index bc073bbd..380aa1dc 100644 --- a/core/states.css +++ b/core/states.css @@ -72,12 +72,16 @@ they filled — [aria-busy="true"] covers the semantic, and the visual is two lines to hand-roll in your own component CSS if you want it. */ - img.sf-is-skeleton, - .sf-is-skeleton img { + /* Shimmer loading placeholder (was .sf-is-skeleton pre-Unreleased; renamed so + "skeleton" names only the planned .sf-skeleton component, not a state — + see docs/migration.md and roadmap.md #575). The class name now mirrors its + driving token, --sf-animation-shimmer. */ + img.sf-is-shimmer, + .sf-is-shimmer img { opacity: 0 !important; } - .sf-is-skeleton { + .sf-is-shimmer { color: transparent !important; background: linear-gradient( 90deg, diff --git a/demo/index.html b/demo/index.html index 444b6af6..39478f40 100644 --- a/demo/index.html +++ b/demo/index.html @@ -1426,11 +1426,11 @@

States (states.css)

-

.sf-is-skeleton

+

.sf-is-shimmer

-
-
-
+
+
+
@@ -4031,8 +4031,8 @@

State classes (.sf-is-*)

-
.sf-is-skeleton public

Skeleton loading placeholder state. Applies a shimmer animation over the element to indicate that content is loading. Works on both img and non-media elements.

-
skeleton
+
.sf-is-shimmer public

Shimmer loading placeholder state. Applies a shimmer animation over the element to indicate that content is loading. Works on both img and non-media elements. (Renamed from .sf-is-shimmer so "skeleton" refers only to the planned .sf-skeleton component.)

+
shimmer
.sf-is-success public

Success status state — applies success color tokens. Use for confirmation messages, completed form steps, and positive feedback.

@@ -5017,7 +5017,7 @@

Design tokens 7
--sf-z-tooltip
- + diff --git a/docs/api-audit-checklist.md b/docs/api-audit-checklist.md index 9d20d159..dbe63db3 100644 --- a/docs/api-audit-checklist.md +++ b/docs/api-audit-checklist.md @@ -218,7 +218,7 @@ Realna wartość; rozważ okrojenie liczby wariantów lub przeniesienie do `full - [x] `.sf-is-selected` — ZOSTAJE `opt` - [x] `.sf-is-highlighted` — ZOSTAJE `opt` - [x] `.sf-is-empty` — ZOSTAJE (bez zmian tej rundy) `opt` -- [x] `.sf-is-skeleton` — ZOSTAJE (świadoma decyzja usera — brak natywnego odpowiednika) `opt` +- [x] `.sf-is-shimmer` (renamed from the former skeleton state, #575) — ZOSTAJE (świadoma decyzja usera — brak natywnego odpowiednika) `opt` **Bilans końcowy:** 28 → **15** w `states.css` + **2** przeniesione do `utilities.css` (17 łącznie zostaje, 11 usuniętych). Kaskadowo usunięte też: tokeny `--sf-current-font-weight`, `--sf-state-pending-opacity`, i 4 rejestracje `@property` (`--sf-is-active/-current/-pressed/-open`) — wszystkie osierocone przez usunięcie jedynego konsumenta. diff --git a/docs/api-index.json b/docs/api-index.json index a97e1ddb..86efe85d 100644 --- a/docs/api-index.json +++ b/docs/api-index.json @@ -23870,16 +23870,16 @@ ] }, { - "name": "sf-is-skeleton", + "name": "sf-is-shimmer", "type": "class", "tier": "PUBLIC", - "selector": ".sf-is-skeleton", + "selector": ".sf-is-shimmer", "prefix": "sf-is", "kind": "state", "category": "State classes", "area": "states", "group": "LOADING / ASYNC FEEDBACK", - "description": "Skeleton loading placeholder state. Applies a shimmer animation over the element to indicate that content is loading. Works on both img and non-media elements.", + "description": "Shimmer loading placeholder state. Applies a shimmer animation over the element to indicate that content is loading. Works on both img and non-media elements. (Renamed from .sf-is-skeleton so \"skeleton\" refers only to the planned .sf-skeleton component.)", "isVariant": false, "baseClass": null, "optional": false, diff --git a/docs/api-index.md b/docs/api-index.md index 9a9f0373..fbe573b8 100644 --- a/docs/api-index.md +++ b/docs/api-index.md @@ -1094,7 +1094,7 @@ and a short description. The machine-readable companion (with all columns) is | `.sf-is-invalid` | PUBLIC | state | VALIDATION / FEEDBACK | Invalid state — applies danger color tokens to form fields with validation failures. Identical visual output to sf-is-error; the name signals form-field context. | | `.sf-is-loading` | PUBLIC | state | LOADING / ASYNC FEEDBACK | Loading state — hides the element's text (color: transparent), removes pointer events, and renders a spinner via ::after. Use for buttons and containers awaiting async results. | | `.sf-is-selected` | PUBLIC | state | SELECTED / HIGHLIGHTED | Selected state — marks an item as selected in a list, table row, or grid cell. Visual specifics (background, border) are applied by component styles. | -| `.sf-is-skeleton` | PUBLIC | state | LOADING / ASYNC FEEDBACK | Skeleton loading placeholder state. Applies a shimmer animation over the element to indicate that content is loading. Works on both img and non-media elements. | +| `.sf-is-shimmer` | PUBLIC | state | LOADING / ASYNC FEEDBACK | Shimmer loading placeholder state. Applies a shimmer animation over the element to indicate that content is loading. Works on both img and non-media elements. (Renamed from .sf-is-skeleton so "skeleton" refers only to the planned .sf-skeleton component.) | | `.sf-is-success` | PUBLIC | state | VALIDATION / FEEDBACK | Success status state — applies success color tokens. Use for confirmation messages, completed form steps, and positive feedback. | | `.sf-is-valid` | PUBLIC | state | VALIDATION / FEEDBACK | Valid state — applies success color tokens to form fields that have passed validation. Visual styling is identical to sf-is-success; the name signals form-field context. | | `.sf-is-warning` | PUBLIC | state | VALIDATION / FEEDBACK | Warning status state — applies warning color tokens. Use for cautionary messages and non-critical alerts. | diff --git a/docs/classes.md b/docs/classes.md index ba5e1ea9..5e2002b1 100644 --- a/docs/classes.md +++ b/docs/classes.md @@ -233,7 +233,7 @@ See [architecture.md](architecture.md) for layer order and naming conventions. | `.sf-is-invalid` | | `.sf-is-loading` | | `.sf-is-selected` | -| `.sf-is-skeleton` | +| `.sf-is-shimmer` | | `.sf-is-success` | | `.sf-is-valid` | | `.sf-is-warning` | diff --git a/docs/migration.md b/docs/migration.md index 895ba496..db3dde1b 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -21,6 +21,27 @@ compatibility alias is provided — see "State-class API reduction" below for why: for a pre-1.0 framework, an alias here would have perpetuated the exact naming collision that motivated the rename. +### `.sf-is-skeleton` renamed to `.sf-is-shimmer` (breaking) + +"Skeleton" was about to name two different things at once: the shipped shimmer +*state* (`.sf-is-skeleton`, applicable to any element) and the planned +`.sf-skeleton` *component* with shape modifiers (roadmap / [#384](https://github.com/codeslash-dev/SLASHED/issues/384) +item 8). Two independently-named "skeleton" concepts stackable on one element is +the same word-on-two-axes trap that motivated the `--secondary` → `--subtle` +rename above ([#575](https://github.com/codeslash-dev/SLASHED/issues/575)). + +The state moves to `.sf-is-shimmer`, which also makes the class name mirror its +driving token, `--sf-animation-shimmer`. "skeleton" is now reserved for the +future component alone, and the state/component axis separation the framework +uses elsewhere (`.sf-is-*` = state, `.sf-*` = structural) is preserved. Doing +the rename now — ahead of the component — keeps this one breaking change out of +the otherwise purely additive `.sf-skeleton` release. Behaviour, tokens, and +markup support (works on `img` and non-media elements alike) are unchanged. + +**What changed for you:** replace `class="sf-is-skeleton"` with +`class="sf-is-shimmer"` anywhere you use it. No compatibility alias is provided, +consistent with the pre-1.0 no-alias stance in the notes above and below. + ### State-class API reduction (breaking) A full audit of every `.sf-is-*` class held each one to the bar "does a native diff --git a/docs/registry.json b/docs/registry.json index 5a5ad77c..58e9e420 100644 --- a/docs/registry.json +++ b/docs/registry.json @@ -1070,7 +1070,7 @@ "sf-is-invalid", "sf-is-loading", "sf-is-selected", - "sf-is-skeleton", + "sf-is-shimmer", "sf-is-success", "sf-is-valid", "sf-is-warning" diff --git a/docs/roadmap.md b/docs/roadmap.md index e1837ef0..35988778 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -53,13 +53,15 @@ non-additive changes; the v0.6.x series focuses on the components layer.* [#384](https://github.com/codeslash-dev/SLASHED/issues/384). **Naming decision (resolved, [#575](https://github.com/codeslash-dev/SLASHED/issues/575)):** `.sf-skeleton` - keeps the industry-standard component name; the shipped shimmer *state* - `.sf-is-skeleton` will be renamed to `.sf-is-shimmer` (a breaking rename - landing together with the `.sf-skeleton` implementation) so "skeleton" means - exactly one thing — the component, which composes with `.sf-is-shimmer` for - the shimmer effect. Shape modifiers must not reuse component names: the - card-like placeholder shape is `--rect` (geometric), never `--card`, to avoid - implying parity with `.sf-card`'s token set. + keeps the industry-standard component name. The shimmer *state* was renamed + `.sf-is-skeleton` → `.sf-is-shimmer` **ahead of** the component (shipped + standalone in Unreleased — see `docs/migration.md`), decoupling that one + breaking rename from the component work so `.sf-skeleton` can land purely + additively. "skeleton" now means exactly one thing — the component, which + will compose with `.sf-is-shimmer` for the shimmer effect. Shape modifiers + must not reuse component names: the card-like placeholder shape is `--rect` + (geometric), never `--card`, to avoid implying parity with `.sf-card`'s token + set. - **Z-index utilities** — expose the named z-index scale as `.sf-z-*` classes (for example `.sf-z-modal` and `.sf-z-tooltip`) in `optional/utilities.css`. - **First component tranche** — `.sf-btn` and `.sf-card` shipped in v0.7.0 diff --git a/docs/states.md b/docs/states.md index 3c96c5f5..c4a60e18 100644 --- a/docs/states.md +++ b/docs/states.md @@ -25,7 +25,7 @@ native pseudo-class, attribute, or ARIA state already gets you there: | a selected class | `[aria-selected]` (custom widgets) | required for accessible custom widgets regardless of framework, so styling off the attribute you must already set avoids toggling two things for one state | `.sf-is-*` earns its place only when **no native mechanism reaches the same -condition** (`.sf-is-loading`'s spinner, `.sf-is-skeleton`'s shimmer, the +condition** (`.sf-is-loading`'s spinner, `.sf-is-shimmer`'s shimmer, the drag-and-drop trio — CSS has no native drag state at all) or when the class is a **token setter** consumed elsewhere in the framework (the validation family writing `--sf-field-*`, read by `optional/forms.css`). Where a class @@ -85,7 +85,7 @@ in the meantime (tests, docs, configurator preview panels, and the |---|---|---|---| | `.sf-is-disabled` | non-interactive, dimmed — for elements that can't take the native `disabled` attribute (e.g. ``) | `aria-disabled="true"` | states | | `.sf-is-loading` | content replaced by a spinner | `aria-busy="true"` | states | -| `.sf-is-skeleton` | placeholder shimmer | — | states | +| `.sf-is-shimmer` | placeholder shimmer | — | states | | `.sf-is-selected` | selected in a set | `aria-selected` | states | | `.sf-is-highlighted` | transient emphasis | — | states | | `.sf-is-valid` / `.sf-is-invalid` | **form-field** validation result | `aria-invalid` | states | diff --git a/docs/token-annotations.json b/docs/token-annotations.json index c40feac3..98471a68 100644 --- a/docs/token-annotations.json +++ b/docs/token-annotations.json @@ -1125,7 +1125,7 @@ "print-color-exact": "Forces exact color rendering in print (print-color-adjust: exact). Use on charts and colored badges that must preserve their fill colors in print.", "print-no-color": "Strips color information in print (print-color-adjust: economy). Defers to the printer's ink-saving mode for backgrounds and non-critical color fills.", "sf-theme-transition": "Opt-in animated light/dark theme crossfade. Apply to (or a subtree) so color tokens transition smoothly when [data-theme] changes. Duration controlled by --sf-theme-transition-duration.", - "sf-is-skeleton": "Skeleton loading placeholder state. Applies a shimmer animation over the element to indicate that content is loading. Works on both img and non-media elements.", + "sf-is-shimmer": "Shimmer loading placeholder state. Applies a shimmer animation over the element to indicate that content is loading. Works on both img and non-media elements. (Renamed from .sf-is-skeleton so \"skeleton\" refers only to the planned .sf-skeleton component.)", "sf-is-valid": "Valid state — applies success color tokens to form fields that have passed validation. Visual styling is identical to sf-is-success; the name signals form-field context.", "print-only": "Hides the element on screen (display: none) but shows it in @media print. Use for print-only headers, footers, and supplementary content not needed on screen.", "sf-bg-layer": "Background layer — absolutely-positioned cover media that sits behind a parent's content. The parent is auto-promoted to a positioned, isolated stacking context via :has(), so .sf-bg-layer composes natively under .sf-scrim (background → scrim gradient → content). Works as a bare or as a wrapper with a nested > img / > video / > picture.", diff --git a/tests/demo-visual.spec.js b/tests/demo-visual.spec.js index 6960449a..cb7c7b70 100644 --- a/tests/demo-visual.spec.js +++ b/tests/demo-visual.spec.js @@ -276,9 +276,9 @@ test.describe('Motion & States', () => { expect(pe).toBe('none'); }); - test('.sf-is-skeleton has shimmer animation', async ({ page }) => { + test('.sf-is-shimmer has shimmer animation', async ({ page }) => { await page.goto(DEMO_URL); - const skeleton = page.locator('#motion .sf-is-skeleton').first(); + const skeleton = page.locator('#motion .sf-is-shimmer').first(); const anim = await getStyle(skeleton, 'animationName'); expect(anim).toContain('sf-shimmer'); }); diff --git a/tests/states-full.spec.js b/tests/states-full.spec.js index ad726a7e..c9503dc9 100644 --- a/tests/states-full.spec.js +++ b/tests/states-full.spec.js @@ -73,8 +73,8 @@ test('.sf-is-loading: colour transparent, position relative, pointer-events none // No .sf-is-busy / .sf-is-pending tests: both classes were removed // (no distinct consumer, trivial to hand-roll — see core/states.css). -test('.sf-is-skeleton: transparent text, shimmer gradient, no pointer-events', async ({ page }) => { - await setup(page, `
Placeholder text
`); +test('.sf-is-shimmer: transparent text, shimmer gradient, no pointer-events', async ({ page }) => { + await setup(page, `
Placeholder text
`); const cs = await page.locator('#t').evaluate(el => ({ color: getComputedStyle(el).color, bgImage: getComputedStyle(el).backgroundImage, From f90b273b045984c27070d7da6f7e604f972a7ab3 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Jul 2026 21:28:46 +0000 Subject: [PATCH 2/4] feat(utilities): add fractional content-width utilities .sf-width-* (#531) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Opt-in helpers to constrain an element to a fraction of the content column (--sf-content-width) with auto-centering, a common quick-constraint on marketing layouts: - .sf-width-10 … .sf-width-90 — max-inline-size: calc(--sf-content-width * fraction) with inline-size:100% + margin-inline:auto, so the element shrinks on narrow parents and centres in normal flow. - Keyword variants .sf-width-full / -auto / -fit / -min / -max mapping to 100%-uncapped / auto / fit-content / min-content / max-content. Logical properties throughout; driven entirely by the existing --sf-content-width token (no new tokens). Documented in the LLM guide and covered in the demo gallery. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_017x2JYaWJoPoHWNCEhDA7NR --- configurator/src/data/classes.generated.json | 140 ++++++++ demo/index.html | 58 +++- docs/api-index.json | 320 ++++++++++++++++++- docs/api-index.md | 22 +- docs/classes.md | 18 +- docs/llm-guide.md | 1 + docs/registry.json | 18 +- optional/utilities.css | 33 ++ 8 files changed, 595 insertions(+), 15 deletions(-) diff --git a/configurator/src/data/classes.generated.json b/configurator/src/data/classes.generated.json index 8f93b9a1..c7654e3f 100644 --- a/configurator/src/data/classes.generated.json +++ b/configurator/src/data/classes.generated.json @@ -3094,6 +3094,146 @@ "optional": true, "layer": "slashed.utilities" }, + { + "name": "sf-width-10", + "selector": ".sf-width-10", + "kind": "utility", + "category": "Utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "optional": true, + "layer": "slashed.utilities" + }, + { + "name": "sf-width-20", + "selector": ".sf-width-20", + "kind": "utility", + "category": "Utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "optional": true, + "layer": "slashed.utilities" + }, + { + "name": "sf-width-30", + "selector": ".sf-width-30", + "kind": "utility", + "category": "Utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "optional": true, + "layer": "slashed.utilities" + }, + { + "name": "sf-width-40", + "selector": ".sf-width-40", + "kind": "utility", + "category": "Utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "optional": true, + "layer": "slashed.utilities" + }, + { + "name": "sf-width-50", + "selector": ".sf-width-50", + "kind": "utility", + "category": "Utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "optional": true, + "layer": "slashed.utilities" + }, + { + "name": "sf-width-60", + "selector": ".sf-width-60", + "kind": "utility", + "category": "Utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "optional": true, + "layer": "slashed.utilities" + }, + { + "name": "sf-width-70", + "selector": ".sf-width-70", + "kind": "utility", + "category": "Utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "optional": true, + "layer": "slashed.utilities" + }, + { + "name": "sf-width-80", + "selector": ".sf-width-80", + "kind": "utility", + "category": "Utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "optional": true, + "layer": "slashed.utilities" + }, + { + "name": "sf-width-90", + "selector": ".sf-width-90", + "kind": "utility", + "category": "Utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "optional": true, + "layer": "slashed.utilities" + }, + { + "name": "sf-width-auto", + "selector": ".sf-width-auto", + "kind": "utility", + "category": "Utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "optional": true, + "layer": "slashed.utilities" + }, + { + "name": "sf-width-fit", + "selector": ".sf-width-fit", + "kind": "utility", + "category": "Utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "optional": true, + "layer": "slashed.utilities" + }, + { + "name": "sf-width-full", + "selector": ".sf-width-full", + "kind": "utility", + "category": "Utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "optional": true, + "layer": "slashed.utilities" + }, + { + "name": "sf-width-max", + "selector": ".sf-width-max", + "kind": "utility", + "category": "Utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "optional": true, + "layer": "slashed.utilities" + }, + { + "name": "sf-width-min", + "selector": ".sf-width-min", + "kind": "utility", + "category": "Utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "optional": true, + "layer": "slashed.utilities" + }, { "name": "skip-link", "selector": ".skip-link", diff --git a/demo/index.html b/demo/index.html index 39478f40..313a407e 100644 --- a/demo/index.html +++ b/demo/index.html @@ -4146,6 +4146,62 @@

Utilities 33.sf-sticky--s public

Sticky positioning with an extra small gap (--sf-space-s) above the header-aware offset.

sticky header
The quick brown fox jumps over the lazy dog while a calm river flows past the old stone bridge and the evening light settles over the quiet valley below. The quick brown fox jumps over the lazy dog while a calm river flows past the old stone bridge and the evening light settles over the quiet valley below.

+
+
.sf-width-10 public

Caps the element at 10% of the content column (--sf-content-width) and centres it; inline-size:100% lets it shrink on narrow parents.

+
10%
+
+
+
.sf-width-20 public

Caps the element at 20% of the content column (--sf-content-width) and centres it; inline-size:100% lets it shrink on narrow parents.

+
20%
+
+
+
.sf-width-30 public

Caps the element at 30% of the content column (--sf-content-width) and centres it; inline-size:100% lets it shrink on narrow parents.

+
30%
+
+
+
.sf-width-40 public

Caps the element at 40% of the content column (--sf-content-width) and centres it; inline-size:100% lets it shrink on narrow parents.

+
40%
+
+
+
.sf-width-50 public

Caps the element at 50% of the content column (--sf-content-width) and centres it; inline-size:100% lets it shrink on narrow parents.

+
50%
+
+
+
.sf-width-60 public

Caps the element at 60% of the content column (--sf-content-width) and centres it; inline-size:100% lets it shrink on narrow parents.

+
60%
+
+
+
.sf-width-70 public

Caps the element at 70% of the content column (--sf-content-width) and centres it; inline-size:100% lets it shrink on narrow parents.

+
70%
+
+
+
.sf-width-80 public

Caps the element at 80% of the content column (--sf-content-width) and centres it; inline-size:100% lets it shrink on narrow parents.

+
80%
+
+
+
.sf-width-90 public

Caps the element at 90% of the content column (--sf-content-width) and centres it; inline-size:100% lets it shrink on narrow parents.

+
90%
+
+
+
.sf-width-full public

Full width (100%), uncapped (max-inline-size: none).

+
full
+
+
+
.sf-width-auto public

Intrinsic auto width (inline-size: auto) — the element sizes to its normal-flow default.

+
auto
+
+
+
.sf-width-fit public

Shrink-to-fit width (fit-content) — as wide as its content, up to the available space.

+
fit-content
+
+
+
.sf-width-min public

Minimum-content width (min-content) — as narrow as the content's longest unbreakable run.

+
min-content
+
+
+
.sf-width-max public

Maximum-content width (max-content) — as wide as the content prefers, without wrapping.

+
max-content
+
.sf-text-2xl public

Applies the 2xl text-size role: font-size, line-height, font-weight, letter-spacing, and measure (max-inline-size) in one class.

.sf-text-2xl
@@ -5017,7 +5073,7 @@

Design tokens 7
--sf-z-tooltip
- + diff --git a/docs/api-index.json b/docs/api-index.json index 86efe85d..fffe2717 100644 --- a/docs/api-index.json +++ b/docs/api-index.json @@ -25,14 +25,14 @@ "optimal" ], "counts": { - "total": 1053, + "total": 1067, "by_type": { - "class": 312, + "class": 326, "token": 741 }, "by_tier": { "INTERNAL": 1, - "PUBLIC": 1003, + "PUBLIC": 1017, "PUBLIC-ADVANCED": 49 }, "by_role": { @@ -40,8 +40,8 @@ "knob": 253 }, "tokens": 741, - "classes": 312, - "sf_classes": 289, + "classes": 326, + "sf_classes": 303, "is_classes": 15, "unprefixed_classes": 8, "by_category": { @@ -58,7 +58,7 @@ "Print": 4, "State classes": 15, "Theme utilities": 3, - "Utilities": 33 + "Utilities": 47 } }, "schema": { @@ -26359,6 +26359,314 @@ "full" ] }, + { + "name": "sf-width-10", + "type": "class", + "tier": "PUBLIC", + "selector": ".sf-width-10", + "prefix": "sf", + "kind": "utility", + "category": "Utilities", + "area": "utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "isVariant": false, + "baseClass": null, + "optional": true, + "layer": "slashed.utilities", + "sourceFiles": [ + "optional/utilities.css" + ], + "bundles": [ + "full" + ] + }, + { + "name": "sf-width-20", + "type": "class", + "tier": "PUBLIC", + "selector": ".sf-width-20", + "prefix": "sf", + "kind": "utility", + "category": "Utilities", + "area": "utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "isVariant": false, + "baseClass": null, + "optional": true, + "layer": "slashed.utilities", + "sourceFiles": [ + "optional/utilities.css" + ], + "bundles": [ + "full" + ] + }, + { + "name": "sf-width-30", + "type": "class", + "tier": "PUBLIC", + "selector": ".sf-width-30", + "prefix": "sf", + "kind": "utility", + "category": "Utilities", + "area": "utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "isVariant": false, + "baseClass": null, + "optional": true, + "layer": "slashed.utilities", + "sourceFiles": [ + "optional/utilities.css" + ], + "bundles": [ + "full" + ] + }, + { + "name": "sf-width-40", + "type": "class", + "tier": "PUBLIC", + "selector": ".sf-width-40", + "prefix": "sf", + "kind": "utility", + "category": "Utilities", + "area": "utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "isVariant": false, + "baseClass": null, + "optional": true, + "layer": "slashed.utilities", + "sourceFiles": [ + "optional/utilities.css" + ], + "bundles": [ + "full" + ] + }, + { + "name": "sf-width-50", + "type": "class", + "tier": "PUBLIC", + "selector": ".sf-width-50", + "prefix": "sf", + "kind": "utility", + "category": "Utilities", + "area": "utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "isVariant": false, + "baseClass": null, + "optional": true, + "layer": "slashed.utilities", + "sourceFiles": [ + "optional/utilities.css" + ], + "bundles": [ + "full" + ] + }, + { + "name": "sf-width-60", + "type": "class", + "tier": "PUBLIC", + "selector": ".sf-width-60", + "prefix": "sf", + "kind": "utility", + "category": "Utilities", + "area": "utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "isVariant": false, + "baseClass": null, + "optional": true, + "layer": "slashed.utilities", + "sourceFiles": [ + "optional/utilities.css" + ], + "bundles": [ + "full" + ] + }, + { + "name": "sf-width-70", + "type": "class", + "tier": "PUBLIC", + "selector": ".sf-width-70", + "prefix": "sf", + "kind": "utility", + "category": "Utilities", + "area": "utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "isVariant": false, + "baseClass": null, + "optional": true, + "layer": "slashed.utilities", + "sourceFiles": [ + "optional/utilities.css" + ], + "bundles": [ + "full" + ] + }, + { + "name": "sf-width-80", + "type": "class", + "tier": "PUBLIC", + "selector": ".sf-width-80", + "prefix": "sf", + "kind": "utility", + "category": "Utilities", + "area": "utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "isVariant": false, + "baseClass": null, + "optional": true, + "layer": "slashed.utilities", + "sourceFiles": [ + "optional/utilities.css" + ], + "bundles": [ + "full" + ] + }, + { + "name": "sf-width-90", + "type": "class", + "tier": "PUBLIC", + "selector": ".sf-width-90", + "prefix": "sf", + "kind": "utility", + "category": "Utilities", + "area": "utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "isVariant": false, + "baseClass": null, + "optional": true, + "layer": "slashed.utilities", + "sourceFiles": [ + "optional/utilities.css" + ], + "bundles": [ + "full" + ] + }, + { + "name": "sf-width-auto", + "type": "class", + "tier": "PUBLIC", + "selector": ".sf-width-auto", + "prefix": "sf", + "kind": "utility", + "category": "Utilities", + "area": "utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "isVariant": false, + "baseClass": null, + "optional": true, + "layer": "slashed.utilities", + "sourceFiles": [ + "optional/utilities.css" + ], + "bundles": [ + "full" + ] + }, + { + "name": "sf-width-fit", + "type": "class", + "tier": "PUBLIC", + "selector": ".sf-width-fit", + "prefix": "sf", + "kind": "utility", + "category": "Utilities", + "area": "utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "isVariant": false, + "baseClass": null, + "optional": true, + "layer": "slashed.utilities", + "sourceFiles": [ + "optional/utilities.css" + ], + "bundles": [ + "full" + ] + }, + { + "name": "sf-width-full", + "type": "class", + "tier": "PUBLIC", + "selector": ".sf-width-full", + "prefix": "sf", + "kind": "utility", + "category": "Utilities", + "area": "utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "isVariant": false, + "baseClass": null, + "optional": true, + "layer": "slashed.utilities", + "sourceFiles": [ + "optional/utilities.css" + ], + "bundles": [ + "full" + ] + }, + { + "name": "sf-width-max", + "type": "class", + "tier": "PUBLIC", + "selector": ".sf-width-max", + "prefix": "sf", + "kind": "utility", + "category": "Utilities", + "area": "utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "isVariant": false, + "baseClass": null, + "optional": true, + "layer": "slashed.utilities", + "sourceFiles": [ + "optional/utilities.css" + ], + "bundles": [ + "full" + ] + }, + { + "name": "sf-width-min", + "type": "class", + "tier": "PUBLIC", + "selector": ".sf-width-min", + "prefix": "sf", + "kind": "utility", + "category": "Utilities", + "area": "utilities", + "group": "CONTENT-WIDTH UTILITIES (.sf-width-*)", + "description": "Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width…", + "isVariant": false, + "baseClass": null, + "optional": true, + "layer": "slashed.utilities", + "sourceFiles": [ + "optional/utilities.css" + ], + "bundles": [ + "full" + ] + }, { "name": "skip-link", "type": "class", diff --git a/docs/api-index.md b/docs/api-index.md index fbe573b8..c13f1616 100644 --- a/docs/api-index.md +++ b/docs/api-index.md @@ -10,11 +10,11 @@ and a short description. The machine-readable companion (with all columns) is [registry.json](registry.json); for the tier contract see [architecture.md](architecture.md). -**1053 elements** — 741 tokens, 312 classes. +**1067 elements** — 741 tokens, 326 classes. | Tier | Count | Meaning | |---|---|---| -| PUBLIC | 1003 | Everyday surface. SemVer-stable. | +| PUBLIC | 1017 | Everyday surface. SemVer-stable. | | PUBLIC-ADVANCED | 49 | Same SemVer guarantee; niche/powerful. | | INTERNAL | 1 | Implementation detail; may change without a major bump. | @@ -781,7 +781,7 @@ and a short description. The machine-readable companion (with all columns) is | `--sf-surface-bg-size` | PUBLIC | knob | surface | `cover` | background-size for the .sf-surface-bg image. Default: cover. | | `--sf-surface-color` | PUBLIC | consumption | surface | `var(--sf-color-base)` | Input for the generic .sf-surface macro. Set any color (including palette shades); the macro derives background, auto-contrast foreground, and the contextual token set from it. | -## Classes (312) +## Classes (326) ### Accessibility (8) @@ -1107,7 +1107,7 @@ and a short description. The machine-readable companion (with all columns) is | `.sf-theme-light` | PUBLIC | theme | — | Forces light colour scheme on the element and its subtree (class alias of [data-theme="light"]). | | `.sf-theme-transition` | PUBLIC | theme | — | Opt-in animated light/dark theme crossfade. Apply to (or a subtree) so color tokens transition smoothly when [data-theme] changes. Duration controlled by --sf-theme-transition-duration. | -### Utilities (33) +### Utilities (47) | Class | Tier | Kind | Group | Description | |---|---|---|---|---| @@ -1144,4 +1144,18 @@ and a short description. The machine-readable companion (with all columns) is | `.sf-text-xl` | PUBLIC | utility | TEXT-SIZE UTILITIES (.sf-text-2xs | Applies the xl text-size role: font-size, line-height, font-weight, letter-spacing, and measure (max-inline-size) in one class. | | `.sf-text-xs` | PUBLIC | utility | TEXT-SIZE UTILITIES (.sf-text-2xs | Applies the xs text-size role: font-size, line-height, font-weight, letter-spacing, and measure (max-inline-size) in one class. | | `.sf-visible` | PUBLIC | utility | VISIBILITY HELPERS (.sf-invisible / .sf-visible) | Visibility helper (optional/utilities.css) — forces the element to be visible (visibility: visible). Use to un-hide an element that inherited visibility: hidden from a parent. | +| `.sf-width-10` | PUBLIC | utility | CONTENT-WIDTH UTILITIES (.sf-width-*) | Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width… | +| `.sf-width-20` | PUBLIC | utility | CONTENT-WIDTH UTILITIES (.sf-width-*) | Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width… | +| `.sf-width-30` | PUBLIC | utility | CONTENT-WIDTH UTILITIES (.sf-width-*) | Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width… | +| `.sf-width-40` | PUBLIC | utility | CONTENT-WIDTH UTILITIES (.sf-width-*) | Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width… | +| `.sf-width-50` | PUBLIC | utility | CONTENT-WIDTH UTILITIES (.sf-width-*) | Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width… | +| `.sf-width-60` | PUBLIC | utility | CONTENT-WIDTH UTILITIES (.sf-width-*) | Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width… | +| `.sf-width-70` | PUBLIC | utility | CONTENT-WIDTH UTILITIES (.sf-width-*) | Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width… | +| `.sf-width-80` | PUBLIC | utility | CONTENT-WIDTH UTILITIES (.sf-width-*) | Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width… | +| `.sf-width-90` | PUBLIC | utility | CONTENT-WIDTH UTILITIES (.sf-width-*) | Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width… | +| `.sf-width-auto` | PUBLIC | utility | CONTENT-WIDTH UTILITIES (.sf-width-*) | Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width… | +| `.sf-width-fit` | PUBLIC | utility | CONTENT-WIDTH UTILITIES (.sf-width-*) | Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width… | +| `.sf-width-full` | PUBLIC | utility | CONTENT-WIDTH UTILITIES (.sf-width-*) | Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width… | +| `.sf-width-max` | PUBLIC | utility | CONTENT-WIDTH UTILITIES (.sf-width-*) | Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width… | +| `.sf-width-min` | PUBLIC | utility | CONTENT-WIDTH UTILITIES (.sf-width-*) | Constrain an element to a fraction of the content column (--sf-content-width) and centre it in normal flow. inline-size:100% lets it shrink below the cap on a narrower parent; margin-inline:auto absorbs the leftover space to centre it. The keyword variants map to CSS width… | diff --git a/docs/classes.md b/docs/classes.md index 5e2002b1..967c76ed 100644 --- a/docs/classes.md +++ b/docs/classes.md @@ -3,7 +3,7 @@ > **Generated** from source by `scripts/gen-class-reference.js` — > run `npm run docs:classes` to refresh. Do not edit by hand. -**289 .sf-classes, 15 .sf-is-classes.** Every `.sf-*` layout/macro class and `.sf-is-*` state class. +**303 .sf-classes, 15 .sf-is-classes.** Every `.sf-*` layout/macro class and `.sf-is-*` state class. See [architecture.md](architecture.md) for layer order and naming conventions. ## Layout primitives (`core/layout.css`) @@ -347,7 +347,7 @@ See [architecture.md](architecture.md) for layer order and naming conventions. ## Utilities (`optional/utilities.css`) -34 classes. +48 classes. | Class | |---| @@ -385,4 +385,18 @@ See [architecture.md](architecture.md) for layer order and naming conventions. | `.sf-text-xl` | | `.sf-text-xs` | | `.sf-visible` | +| `.sf-width-10` | +| `.sf-width-20` | +| `.sf-width-30` | +| `.sf-width-40` | +| `.sf-width-50` | +| `.sf-width-60` | +| `.sf-width-70` | +| `.sf-width-80` | +| `.sf-width-90` | +| `.sf-width-auto` | +| `.sf-width-fit` | +| `.sf-width-full` | +| `.sf-width-max` | +| `.sf-width-min` | diff --git a/docs/llm-guide.md b/docs/llm-guide.md index e2409cb2..aa67adc2 100644 --- a/docs/llm-guide.md +++ b/docs/llm-guide.md @@ -1004,6 +1004,7 @@ Small opt-in helpers (all `optional/utilities.css`): - `.sf-marker--{family}` — colour `::marker` on an arbitrary list, `family` = `primary` / `secondary` / `tertiary` / `action` (brand/action only; set `::marker { color }` yourself for anything else). A `:not(.sf-prose *)` guard leaves `.sf-prose` markers to `--sf-prose-marker-color`. Works on the `

-
.sf-is-shimmer public

Shimmer loading placeholder state. Applies a shimmer animation over the element to indicate that content is loading. Works on both img and non-media elements. (Renamed from .sf-is-shimmer so "skeleton" refers only to the planned .sf-skeleton component.)

+
.sf-is-shimmer public

Shimmer loading placeholder state. Applies a shimmer animation over the element to indicate that content is loading. Works on both img and non-media elements. (Renamed from .sf-is-skeleton so "skeleton" refers only to the planned .sf-skeleton component.)

shimmer
diff --git a/scripts/check-version-sync.js b/scripts/check-version-sync.js index fd666c99..6fc4a7a4 100644 --- a/scripts/check-version-sync.js +++ b/scripts/check-version-sync.js @@ -91,7 +91,9 @@ if (configLockSelf !== undefined && configLockSelf !== version) { // 6. llms.txt "# SLASHED vX.Y.Z" header must match package.json. const llmsTxt = read('llms.txt'); -const llmsMatch = llmsTxt.match(/#\s*SLASHED\s+v([0-9][^\s]*)/); +// Line-anchored (multiline) so only the heading counts — a `# SLASHED v…` +// string appearing inline in prose must not satisfy the check. +const llmsMatch = llmsTxt.match(/^#\s*SLASHED\s+v([0-9][^\s]*)/m); if (!llmsMatch) { errors.push('llms.txt: "# SLASHED vX.Y.Z" header not found'); } else if (llmsMatch[1].trim() !== version) { diff --git a/scripts/version-sync.js b/scripts/version-sync.js index 8fbb130d..5a1fcadf 100644 --- a/scripts/version-sync.js +++ b/scripts/version-sync.js @@ -93,7 +93,10 @@ changed += sync( syncedPaths.push('llms.txt'); changed += sync( 'llms.txt', - new RegExp(`(# SLASHED v)${SEMVER_RE.source}`), + // Anchored to the start of a line (multiline) so only the `# SLASHED vX.Y.Z` + // heading is re-stamped — never a `# SLASHED v…` string that happens to + // appear inline in prose. + new RegExp(`^(# SLASHED v)${SEMVER_RE.source}`, 'm'), `$1${version}`, `llms.txt version = ${version}` ) ? 1 : 0; diff --git a/tests/check-version-sync.test.js b/tests/check-version-sync.test.js index 887bc6e2..928166e7 100644 --- a/tests/check-version-sync.test.js +++ b/tests/check-version-sync.test.js @@ -132,6 +132,19 @@ describe('check-version-sync failure cases', () => { assert.ok(r.stderr.includes('llms.txt'), r.stderr); }); + test('rejects an llms.txt where the version appears only inline in prose, not as the heading', () => { + const dir = buildFixture(); + // Correct version, but only mid-line in prose — the line-anchored check must + // not accept it as the heading (would otherwise mask a missing header). + fs.writeFileSync( + path.join(dir, 'llms.txt'), + '# SLASHED\n\nSee # SLASHED v1.2.3 in the changelog for details.\n', + ); + const r = runChecker(dir); + assert.equal(r.status, 1, 'expected exit 1 when the version is only inline prose'); + assert.ok(r.stderr.includes('llms.txt'), r.stderr); + }); + test('fails when configurator/package.json version differs', () => { const dir = buildFixture(); fs.writeFileSync(