@keenmate/pure-css 1.1.0 → 1.1.1

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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,26 @@
3
3
  All notable changes to `@keenmate/pure-css` are documented here. Format based on
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5
5
 
6
+ ## [1.1.1] — 2026-09-26 [PUBLISHED]
7
+
8
+ ### Fixed
9
+
10
+ - **Themes could not override `$base-*` — `_base-css-variables.scss` now `@import`s
11
+ the variable vocabulary instead of `@use`ing it.** The file pulled its
12
+ `$`-vocabulary in with `@use 'variables/index' as *`, but Sass refuses to expose
13
+ a member whose name already exists in the importing global scope — so any consumer
14
+ that set a `$base-*` value **before** importing (exactly what a theme does, relying
15
+ on the `!default` flags) failed with *"This module and the new module both define a
16
+ variable named $base-accent-color"*. The workflow documented at the top of that
17
+ file therefore worked only for a theme that overrode nothing, and the first real
18
+ downstream theme (`keen-docs-themes/cobalt2`) could not build. Switched to
19
+ `@import 'variables/index'`, which shares the one global scope the `!default`
20
+ mechanism needs (the same reason `variables/_index.scss` uses `@import`). pure-css's
21
+ own `@use 'base-css-variables' as bcv` entry points are unaffected. Behaviour-
22
+ preserving for the prebuilt CSS: all 7 artifacts rebuilt, every emitted `--base-*`
23
+ token name and value identical. Committed as `40b5b88`; it reached `prod` just after
24
+ the 1.1.0 tarball was cut, so 1.1.1 is its first published release.
25
+
6
26
  ## [1.1.0] — 2026-09-26 [PUBLISHED]
7
27
 
8
28
  ### Changed
package/README.md CHANGED
@@ -12,15 +12,15 @@ It's the shared layer the whole Keenmate stack agrees on:
12
12
  top of it, and every Keenmate web/Svelte component reads its colours from the same `--base-*`
13
13
  variables.
14
14
 
15
+ ## What's New in 1.1.1
16
+
17
+ - **Theming — downstream themes can finally override `$base-*` at compile time** — `_base-css-variables.scss` loaded its `$`-vocabulary with `@use 'variables/index' as *`, but Sass won't re-expose a member that already exists in the importing global scope, so any theme that set `$base-*` values *before* importing (the whole point of the `!default` contract) crashed with *"both define a variable named $base-accent-color"* — the workflow documented in that file compiled only when the theme overrode nothing, and the first real theme (`keen-docs-themes/cobalt2`) couldn't build. Switching to `@import 'variables/index'` shares the single global scope the `!default` mechanism relies on (the same reason `variables/_index.scss` uses `@import`), so `$base-*` overrides now land. It's behaviour-preserving for the prebuilt CSS — all seven artifacts rebuilt with every emitted `--base-*` name and value identical — and pure-css's own `@use … as bcv` entry points are unchanged. This landed just after the 1.1.0 tarball was cut, so 1.1.1 is the first release to actually ship it.
18
+
15
19
  ## What's New in 1.1.0
16
20
 
17
21
  - **Icons — hover affordance for interactive controls, no JS (`_icon-hover.scss`)** — icons inside an enabled control now react on `:hover` through pure CSS, driven by convention plus marker classes a wrapper stamps: masked `.pa-icon` glyphs that declared `--pa-icon-src-hover` swap to their filled source (automatic; a no-op for outline-only sets like Lucide), Font Awesome `<i>` marked `.pc-icon-hover-fill` flips regular → solid on the `font-weight` axis (needs the FA Pro `far` face), and outline icons marked `.pc-icon-hover-highlight` recolour to `--pc-icon-hover-color` (default `--pc-accent`) for sets with no solid form. The foundation applies it to the shell context it owns (`.pc-sidebar__link:hover`) and ships a generic opt-in wrapper `.pc-icon-hover` for any enabled control. Crucially the behaviour is exposed as the `pc-icon-hover-effects` SCSS mixin, so component layers (pure-admin core on `.pa-btn` / `.pa-tabs__item`, etc.) apply the exact same effects to their own selectors from one shared definition rather than redefining them. Additive — no change to existing output.
18
22
  - **Sidebar — hover colours snap instead of fading** — `.pc-sidebar__link`, the submenu toggle, and the sidebar search trigger animated their hover with `transition: all $transition-fast`, which swept `color` / `background-color` so the hover tint faded in and felt sluggish. Their hover changes colours only (no motion), so per the "colours snap; transitions are motion-only" rule the transition was pure colour animation and has been removed — hover colours now snap. The genuine motion transitions are untouched: the submenu chevron rotation (`transform`) and the icon-collapse label fade (`opacity` / `width`).
19
23
 
20
- ## What's New in 1.0.6
21
-
22
- - **Icons — `--base-icon-check-size` turns the selection glyph's scale into a theme knob** — the check mark (`--base-icon-check`) and the indeterminate dash (`--base-icon-indeterminate`) share one mask box, but the size that box was painted at used to be hard-coded downstream. This adds a single `--base-icon-check-size` token (`68%` default, authored as `$base-icon-check-size` in `variables/_base.scss` and emitted from `output-base-css-variables`) that both pure-admin and every Keenmate web component read, so overriding the check glyph **and** its scale now re-sizes the mark in lockstep across the whole stack — drop in an edge-to-edge glyph such as a star and shrink it from this one knob. `68%` leaves breathing room inside the box, and because indeterminate shares the mask box it re-sizes too. Both `base.css` and the `pure-css.css` bundle emit it, and it mirrors the canonical `@keenmate/base-css-variables` contract (parity guard green).
23
-
24
24
  ## Why
25
25
 
26
26
  pure-css is a **standalone foundation** you drop onto any surface — a docs site, a marketing page, a
package/package.json CHANGED
@@ -1,83 +1,83 @@
1
- {
2
- "name": "@keenmate/pure-css",
3
- "version": "1.1.0",
4
- "description": "The Keenmate CSS foundation — --base-* theming contract, PureCSS grid and utility classes. Extracted from pure-admin-core so docs sites, standalone pages and every web/svelte component share one theming layer.",
5
- "style": "dist/css/pure-css.css",
6
- "exports": {
7
- ".": "./dist/css/pure-css.css",
8
- "./css": "./dist/css/pure-css.css",
9
- "./css/*": "./dist/css/*",
10
- "./base": "./dist/css/base.css",
11
- "./reboot": "./dist/css/reboot.css",
12
- "./component-reset": "./dist/css/component-reset.css",
13
- "./scrollbars": "./dist/css/scrollbars.css",
14
- "./grid": "./dist/css/grid.css",
15
- "./utilities": "./dist/css/utilities.css",
16
- "./scss": "./src/scss/pure-css.scss",
17
- "./scss/*": "./src/scss/*",
18
- "./js": "./src/js/pure-css.js",
19
- "./js/*": "./src/js/*"
20
- },
21
- "files": [
22
- "dist/",
23
- "src/scss/",
24
- "src/js/",
25
- "README.md",
26
- "CHANGELOG.md",
27
- "LICENSE"
28
- ],
29
- "scripts": {
30
- "build:bundle": "sass src/scss/pure-css.scss dist/css/pure-css.css --no-source-map --silence-deprecation=import",
31
- "build:base": "sass src/scss/base.scss dist/css/base.css --no-source-map --silence-deprecation=import",
32
- "build:reboot": "sass src/scss/reboot.scss dist/css/reboot.css --no-source-map --silence-deprecation=import",
33
- "build:component-reset": "sass src/scss/component-reset.scss dist/css/component-reset.css --no-source-map --silence-deprecation=import",
34
- "build:scrollbars": "sass src/scss/scrollbars.scss dist/css/scrollbars.css --no-source-map --silence-deprecation=import",
35
- "build:grid": "sass src/scss/grid.scss dist/css/grid.css --no-source-map --silence-deprecation=import",
36
- "build:utilities": "sass src/scss/utilities.scss dist/css/utilities.css --no-source-map --silence-deprecation=import",
37
- "build": "npm run build:bundle && npm run build:base && npm run build:reboot && npm run build:component-reset && npm run build:scrollbars && npm run build:grid && npm run build:utilities",
38
- "watch": "sass --watch src/scss/pure-css.scss:dist/css/pure-css.css --silence-deprecation=import",
39
- "dev": "vite --port 12500",
40
- "test": "npm run test:e2e",
41
- "test:e2e": "playwright test",
42
- "test:e2e:ui": "playwright test --ui",
43
- "test:e2e:headed": "playwright test --headed",
44
- "test:e2e:install": "playwright install chromium",
45
- "prepublishOnly": "npm run build"
46
- },
47
- "keywords": [
48
- "css",
49
- "scss",
50
- "purecss",
51
- "grid",
52
- "utilities",
53
- "css-variables",
54
- "theming",
55
- "keenmate",
56
- "pure-admin"
57
- ],
58
- "author": "Keenmate",
59
- "license": "MIT",
60
- "peerDependencies": {
61
- "sass": "^1.0.0"
62
- },
63
- "devDependencies": {
64
- "@playwright/test": "^1.60.0",
65
- "sass": "^1.70.0",
66
- "vite": "^5.4.0"
67
- },
68
- "repository": {
69
- "type": "git",
70
- "url": "git+https://github.com/Keenmate/pure-css.git"
71
- },
72
- "bugs": {
73
- "url": "https://github.com/Keenmate/pure-css/issues"
74
- },
75
- "homepage": "https://github.com/Keenmate/pure-css#readme",
76
- "publishConfig": {
77
- "access": "public"
78
- },
79
- "allowScripts": {
80
- "esbuild@0.21.5": true,
81
- "@parcel/watcher@2.6.0": true
82
- }
83
- }
1
+ {
2
+ "name": "@keenmate/pure-css",
3
+ "version": "1.1.1",
4
+ "description": "The Keenmate CSS foundation — --base-* theming contract, PureCSS grid and utility classes. Extracted from pure-admin-core so docs sites, standalone pages and every web/svelte component share one theming layer.",
5
+ "style": "dist/css/pure-css.css",
6
+ "exports": {
7
+ ".": "./dist/css/pure-css.css",
8
+ "./css": "./dist/css/pure-css.css",
9
+ "./css/*": "./dist/css/*",
10
+ "./base": "./dist/css/base.css",
11
+ "./reboot": "./dist/css/reboot.css",
12
+ "./component-reset": "./dist/css/component-reset.css",
13
+ "./scrollbars": "./dist/css/scrollbars.css",
14
+ "./grid": "./dist/css/grid.css",
15
+ "./utilities": "./dist/css/utilities.css",
16
+ "./scss": "./src/scss/pure-css.scss",
17
+ "./scss/*": "./src/scss/*",
18
+ "./js": "./src/js/pure-css.js",
19
+ "./js/*": "./src/js/*"
20
+ },
21
+ "files": [
22
+ "dist/",
23
+ "src/scss/",
24
+ "src/js/",
25
+ "README.md",
26
+ "CHANGELOG.md",
27
+ "LICENSE"
28
+ ],
29
+ "scripts": {
30
+ "build:bundle": "sass src/scss/pure-css.scss dist/css/pure-css.css --no-source-map --silence-deprecation=import",
31
+ "build:base": "sass src/scss/base.scss dist/css/base.css --no-source-map --silence-deprecation=import",
32
+ "build:reboot": "sass src/scss/reboot.scss dist/css/reboot.css --no-source-map --silence-deprecation=import",
33
+ "build:component-reset": "sass src/scss/component-reset.scss dist/css/component-reset.css --no-source-map --silence-deprecation=import",
34
+ "build:scrollbars": "sass src/scss/scrollbars.scss dist/css/scrollbars.css --no-source-map --silence-deprecation=import",
35
+ "build:grid": "sass src/scss/grid.scss dist/css/grid.css --no-source-map --silence-deprecation=import",
36
+ "build:utilities": "sass src/scss/utilities.scss dist/css/utilities.css --no-source-map --silence-deprecation=import",
37
+ "build": "npm run build:bundle && npm run build:base && npm run build:reboot && npm run build:component-reset && npm run build:scrollbars && npm run build:grid && npm run build:utilities",
38
+ "watch": "sass --watch src/scss/pure-css.scss:dist/css/pure-css.css --silence-deprecation=import",
39
+ "dev": "vite --port 12500",
40
+ "test": "npm run test:e2e",
41
+ "test:e2e": "playwright test",
42
+ "test:e2e:ui": "playwright test --ui",
43
+ "test:e2e:headed": "playwright test --headed",
44
+ "test:e2e:install": "playwright install chromium",
45
+ "prepublishOnly": "npm run build"
46
+ },
47
+ "keywords": [
48
+ "css",
49
+ "scss",
50
+ "purecss",
51
+ "grid",
52
+ "utilities",
53
+ "css-variables",
54
+ "theming",
55
+ "keenmate",
56
+ "pure-admin"
57
+ ],
58
+ "author": "Keenmate",
59
+ "license": "MIT",
60
+ "peerDependencies": {
61
+ "sass": "^1.0.0"
62
+ },
63
+ "devDependencies": {
64
+ "@playwright/test": "^1.60.0",
65
+ "sass": "^1.70.0",
66
+ "vite": "^5.4.0"
67
+ },
68
+ "repository": {
69
+ "type": "git",
70
+ "url": "git+https://github.com/Keenmate/pure-css.git"
71
+ },
72
+ "bugs": {
73
+ "url": "https://github.com/Keenmate/pure-css/issues"
74
+ },
75
+ "homepage": "https://github.com/Keenmate/pure-css#readme",
76
+ "publishConfig": {
77
+ "access": "public"
78
+ },
79
+ "allowScripts": {
80
+ "esbuild@0.21.5": true,
81
+ "@parcel/watcher@2.6.0": true
82
+ }
83
+ }
@@ -14,11 +14,18 @@
14
14
  // --ms-accent-color: var(--base-accent-color, #3b82f6);
15
15
  // ============================================================================
16
16
 
17
- // Make variables resolvable when this file is loaded as a @use module
18
- // (e.g. from main.scss). Legacy @import callers (themes) are unaffected —
19
- // Sass places @use'd members into the importing file's global scope, where
20
- // theme-set overrides already live.
21
- @use 'variables/index' as *;
17
+ // Make the $-vocabulary resolvable here.
18
+ //
19
+ // MUST be @import, not `@use 'variables/index' as *`. A theme's whole job is to set
20
+ // $base-* BEFORE pulling this file in (the !default flags then keep those values) --
21
+ // but `@use ... as *` REFUSES to expose a member whose name already exists in the
22
+ // importing global scope, so every theme died on
23
+ // "This module and the new module both define a variable named $base-accent-color".
24
+ // That made the usage documented at the top of this file impossible: it worked only
25
+ // for a theme that overrode nothing. @import shares one global scope and is what the
26
+ // !default mechanism needs. pure-css's own `@use 'base-css-variables' as bcv` entries
27
+ // are unaffected -- a module that @imports still exports its members normally.
28
+ @import 'variables/index';
22
29
 
23
30
  @mixin output-base-css-variables {
24
31
  // === Accent Colors ===
@@ -1,64 +1,64 @@
1
- // ── Icon hover affordance (foundation) ────────────────────────────────────────
2
- // See pure-admin/docs/icon-hover-fill-design.md.
3
- //
4
- // Inside an ENABLED interactive control on :hover, icons react — no JS, no SVG
5
- // computation, driven by convention + marker classes the wrapper stamps:
6
- //
7
- // • Masked `.pa-icon` glyphs that declared a filled source on
8
- // `--pa-icon-src-hover` swap their mask to it. NO-OP for outline-only glyphs
9
- // (e.g. Lucide ships no solid), and no marker needed — it's automatic.
10
- // • Font Awesome `<i>` marked `.pc-icon-hover-fill` flips regular → solid via the
11
- // font-weight axis (same codepoint). Needs the `far` regular face present
12
- // (largely FA Pro), else there's nothing lighter to flip from.
13
- // • Outline icons marked `.pc-icon-hover-highlight` recolour to
14
- // `--pc-icon-hover-color` (default: the accent). This is the answer for sets
15
- // with no solid form (Lucide): a real hover cue without a fill.
16
- //
17
- // The behaviour lives here (foundation) so every consumer — pure-admin core,
18
- // keen, svelte, the web components — shares ONE definition. Wrappers only stamp
19
- // the marker classes. `pc-icon-hover-effects` is a mixin so component layers can
20
- // apply the same effects to their own enabled-control selectors (e.g. core on
21
- // `.pa-btn` / `.pa-tabs__item`) without redefining them.
22
- //
23
- // Deliberately NOT here yet: the two-asset outline↔solid toggle for Heroicons /
24
- // Fluent (render both layers, swap visibility) — that needs a wrapper markup
25
- // contract, so it's wired when a wrapper renders both layers.
26
-
27
- @mixin pc-icon-hover-effects {
28
- // Masked icons: swap to the filled mask source if one was declared. Set the
29
- // longhand directly (not --pa-icon-src) so the var(--pa-icon-src) fallback
30
- // stays non-cyclic — reassigning --pa-icon-src to reference itself would
31
- // compute to invalid and wipe the mask to a solid box.
32
- .pa-icon {
33
- -webkit-mask-image: var(--pa-icon-src-hover, var(--pa-icon-src));
34
- mask-image: var(--pa-icon-src-hover, var(--pa-icon-src));
35
- }
36
-
37
- // Font Awesome regular → solid (weight axis). No transition — a font-weight
38
- // swap is instant, matching the mask swap.
39
- .pc-icon-hover-fill {
40
- font-weight: 900;
41
- }
42
-
43
- // Outline-only sets (Lucide): recolour the stroke instead of filling. Works
44
- // because Lucide SVGs are stroke="currentColor".
45
- .pc-icon-hover-highlight {
46
- color: var(--pc-icon-hover-color, var(--pc-accent));
47
- }
48
- }
49
-
50
- // Shell contexts owned by the foundation: sidebar nav links AND submenu toggles,
51
- // so a submenu parent's icon reacts identically to a plain/child link (not just
52
- // to the toggle's own hover colour).
53
- .pc-sidebar__link:not([aria-disabled='true']):not(.is-disabled):hover,
54
- .pc-sidebar__toggle:not([aria-disabled='true']):not(.is-disabled):hover {
55
- @include pc-icon-hover-effects;
56
- }
57
-
58
- // Generic opt-in: put `.pc-icon-hover` on any enabled control/element to get the
59
- // behaviour without depending on a component class (a bare link, a custom
60
- // button, a list row, …). Disabled opt-outs are excluded so only actionable
61
- // controls react.
62
- .pc-icon-hover:not([disabled]):not([aria-disabled='true']):not(.is-disabled):hover {
63
- @include pc-icon-hover-effects;
64
- }
1
+ // ── Icon hover affordance (foundation) ────────────────────────────────────────
2
+ // See pure-admin/docs/icon-hover-fill-design.md.
3
+ //
4
+ // Inside an ENABLED interactive control on :hover, icons react — no JS, no SVG
5
+ // computation, driven by convention + marker classes the wrapper stamps:
6
+ //
7
+ // • Masked `.pa-icon` glyphs that declared a filled source on
8
+ // `--pa-icon-src-hover` swap their mask to it. NO-OP for outline-only glyphs
9
+ // (e.g. Lucide ships no solid), and no marker needed — it's automatic.
10
+ // • Font Awesome `<i>` marked `.pc-icon-hover-fill` flips regular → solid via the
11
+ // font-weight axis (same codepoint). Needs the `far` regular face present
12
+ // (largely FA Pro), else there's nothing lighter to flip from.
13
+ // • Outline icons marked `.pc-icon-hover-highlight` recolour to
14
+ // `--pc-icon-hover-color` (default: the accent). This is the answer for sets
15
+ // with no solid form (Lucide): a real hover cue without a fill.
16
+ //
17
+ // The behaviour lives here (foundation) so every consumer — pure-admin core,
18
+ // keen, svelte, the web components — shares ONE definition. Wrappers only stamp
19
+ // the marker classes. `pc-icon-hover-effects` is a mixin so component layers can
20
+ // apply the same effects to their own enabled-control selectors (e.g. core on
21
+ // `.pa-btn` / `.pa-tabs__item`) without redefining them.
22
+ //
23
+ // Deliberately NOT here yet: the two-asset outline↔solid toggle for Heroicons /
24
+ // Fluent (render both layers, swap visibility) — that needs a wrapper markup
25
+ // contract, so it's wired when a wrapper renders both layers.
26
+
27
+ @mixin pc-icon-hover-effects {
28
+ // Masked icons: swap to the filled mask source if one was declared. Set the
29
+ // longhand directly (not --pa-icon-src) so the var(--pa-icon-src) fallback
30
+ // stays non-cyclic — reassigning --pa-icon-src to reference itself would
31
+ // compute to invalid and wipe the mask to a solid box.
32
+ .pa-icon {
33
+ -webkit-mask-image: var(--pa-icon-src-hover, var(--pa-icon-src));
34
+ mask-image: var(--pa-icon-src-hover, var(--pa-icon-src));
35
+ }
36
+
37
+ // Font Awesome regular → solid (weight axis). No transition — a font-weight
38
+ // swap is instant, matching the mask swap.
39
+ .pc-icon-hover-fill {
40
+ font-weight: 900;
41
+ }
42
+
43
+ // Outline-only sets (Lucide): recolour the stroke instead of filling. Works
44
+ // because Lucide SVGs are stroke="currentColor".
45
+ .pc-icon-hover-highlight {
46
+ color: var(--pc-icon-hover-color, var(--pc-accent));
47
+ }
48
+ }
49
+
50
+ // Shell contexts owned by the foundation: sidebar nav links AND submenu toggles,
51
+ // so a submenu parent's icon reacts identically to a plain/child link (not just
52
+ // to the toggle's own hover colour).
53
+ .pc-sidebar__link:not([aria-disabled='true']):not(.is-disabled):hover,
54
+ .pc-sidebar__toggle:not([aria-disabled='true']):not(.is-disabled):hover {
55
+ @include pc-icon-hover-effects;
56
+ }
57
+
58
+ // Generic opt-in: put `.pc-icon-hover` on any enabled control/element to get the
59
+ // behaviour without depending on a component class (a bare link, a custom
60
+ // button, a list row, …). Disabled opt-outs are excluded so only actionable
61
+ // controls react.
62
+ .pc-icon-hover:not([disabled]):not([aria-disabled='true']):not(.is-disabled):hover {
63
+ @include pc-icon-hover-effects;
64
+ }