@keenmate/pure-css 1.0.6 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/README.md +5 -4
- package/dist/css/pure-css.css +25 -9
- package/package.json +1 -1
- package/src/scss/_icon-hover.scss +64 -0
- package/src/scss/_sidebar.scss +0 -12
- package/src/scss/pure-css.scss +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,41 @@
|
|
|
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.0] — 2026-09-26 [PUBLISHED]
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
|
|
10
|
+
- **Sidebar link / submenu-toggle hover is now instant (removed `transition: all`).**
|
|
11
|
+
`.pc-sidebar__link`, the submenu toggle, and the sidebar search trigger animated
|
|
12
|
+
their hover with `transition: all $transition-fast`, which swept in `color` /
|
|
13
|
+
`background-color` — so the hover tint *faded in* and felt sluggish. Their hover
|
|
14
|
+
only changes colours (no motion), so the transition was pure colour animation,
|
|
15
|
+
against the "colours snap; transitions are motion-only" rule. Removed it; hover
|
|
16
|
+
colours now snap. The genuine motion transitions are kept — the submenu chevron
|
|
17
|
+
rotation (`transform`) and the icon-collapse label fade (`opacity` / `width`).
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **Icon hover affordance (foundation) — `_icon-hover.scss`.** Inside an enabled
|
|
22
|
+
interactive control on `:hover`, icons react with no JS and no SVG computation,
|
|
23
|
+
driven by convention + marker classes a wrapper stamps:
|
|
24
|
+
- masked `.pa-icon` glyphs that declared `--pa-icon-src-hover` swap to the
|
|
25
|
+
filled source (automatic; no-op for outline-only sets like Lucide);
|
|
26
|
+
- Font Awesome `<i>` marked `.pc-icon-hover-fill` flips regular → solid via the
|
|
27
|
+
`font-weight` axis (needs the `far` face, i.e. FA Pro);
|
|
28
|
+
- outline icons marked `.pc-icon-hover-highlight` recolour to
|
|
29
|
+
`--pc-icon-hover-color` (default: `--pc-accent`) — the hover cue for sets with
|
|
30
|
+
no solid form.
|
|
31
|
+
|
|
32
|
+
Applied to the shell contexts the foundation owns (`.pc-sidebar__link:hover` and
|
|
33
|
+
the submenu `.pc-sidebar__toggle:hover`, so submenu parents match plain/child
|
|
34
|
+
items) and a generic opt-in wrapper `.pc-icon-hover` for any enabled control. The behaviour
|
|
35
|
+
is exposed as the `pc-icon-hover-effects` mixin so component layers (pure-admin
|
|
36
|
+
core on `.pa-btn` / `.pa-tabs__item`, etc.) can apply the same effects to their
|
|
37
|
+
own selectors without redefining them. Additive; no change to existing output.
|
|
38
|
+
(Two-asset outline↔solid toggle for Heroicons / Fluent is a follow-up, wired
|
|
39
|
+
when a wrapper renders both layers.) See `pure-admin/docs/icon-hover-fill-design.md`.
|
|
40
|
+
|
|
6
41
|
## [1.0.6] — 2026-09-20 [PUBLISHED]
|
|
7
42
|
|
|
8
43
|
### Added
|
package/README.md
CHANGED
|
@@ -12,13 +12,14 @@ 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.0
|
|
15
|
+
## What's New in 1.1.0
|
|
16
16
|
|
|
17
|
-
- **Icons —
|
|
17
|
+
- **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
|
+
- **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`).
|
|
18
19
|
|
|
19
|
-
## What's New in 1.0.
|
|
20
|
+
## What's New in 1.0.6
|
|
20
21
|
|
|
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).
|
|
22
23
|
|
|
23
24
|
## Why
|
|
24
25
|
|
package/dist/css/pure-css.css
CHANGED
|
@@ -2413,9 +2413,6 @@ body.pc-layout--sticky .pc-layout__sidebar {
|
|
|
2413
2413
|
font-weight: 500;
|
|
2414
2414
|
border-inline-end: 3px solid transparent;
|
|
2415
2415
|
}
|
|
2416
|
-
body.loaded .pc-sidebar__link {
|
|
2417
|
-
transition: all 0.1s ease-out;
|
|
2418
|
-
}
|
|
2419
2416
|
.pc-sidebar__link:hover {
|
|
2420
2417
|
color: var(--pc-sidebar-text, var(--base-text-color-1));
|
|
2421
2418
|
background-color: var(--pc-accent-light);
|
|
@@ -2445,9 +2442,6 @@ body.loaded .pc-sidebar__link {
|
|
|
2445
2442
|
.pc-sidebar__search[hidden] {
|
|
2446
2443
|
display: none;
|
|
2447
2444
|
}
|
|
2448
|
-
body.loaded .pc-sidebar__search {
|
|
2449
|
-
transition: all 0.1s ease-out;
|
|
2450
|
-
}
|
|
2451
2445
|
.pc-sidebar__search:hover {
|
|
2452
2446
|
border-color: #0ea5e9;
|
|
2453
2447
|
color: var(--base-input-color);
|
|
@@ -2513,9 +2507,6 @@ body.loaded .pc-sidebar__search {
|
|
|
2513
2507
|
font-weight: 500;
|
|
2514
2508
|
cursor: pointer;
|
|
2515
2509
|
}
|
|
2516
|
-
body.loaded .pc-sidebar__toggle {
|
|
2517
|
-
transition: all 0.1s ease-out;
|
|
2518
|
-
}
|
|
2519
2510
|
.pc-sidebar__toggle:hover {
|
|
2520
2511
|
color: var(--pc-sidebar-text, var(--base-text-color-1));
|
|
2521
2512
|
background-color: var(--pc-accent-light);
|
|
@@ -3133,6 +3124,31 @@ body.pc-layout--sticky .pc-layout__inner {
|
|
|
3133
3124
|
border-top: 1px solid var(--pc-border-color);
|
|
3134
3125
|
}
|
|
3135
3126
|
|
|
3127
|
+
.pc-sidebar__link:not([aria-disabled=true]):not(.is-disabled):hover .pa-icon,
|
|
3128
|
+
.pc-sidebar__toggle:not([aria-disabled=true]):not(.is-disabled):hover .pa-icon {
|
|
3129
|
+
-webkit-mask-image: var(--pa-icon-src-hover, var(--pa-icon-src));
|
|
3130
|
+
mask-image: var(--pa-icon-src-hover, var(--pa-icon-src));
|
|
3131
|
+
}
|
|
3132
|
+
.pc-sidebar__link:not([aria-disabled=true]):not(.is-disabled):hover .pc-icon-hover-fill,
|
|
3133
|
+
.pc-sidebar__toggle:not([aria-disabled=true]):not(.is-disabled):hover .pc-icon-hover-fill {
|
|
3134
|
+
font-weight: 900;
|
|
3135
|
+
}
|
|
3136
|
+
.pc-sidebar__link:not([aria-disabled=true]):not(.is-disabled):hover .pc-icon-hover-highlight,
|
|
3137
|
+
.pc-sidebar__toggle:not([aria-disabled=true]):not(.is-disabled):hover .pc-icon-hover-highlight {
|
|
3138
|
+
color: var(--pc-icon-hover-color, var(--pc-accent));
|
|
3139
|
+
}
|
|
3140
|
+
|
|
3141
|
+
.pc-icon-hover:not([disabled]):not([aria-disabled=true]):not(.is-disabled):hover .pa-icon {
|
|
3142
|
+
-webkit-mask-image: var(--pa-icon-src-hover, var(--pa-icon-src));
|
|
3143
|
+
mask-image: var(--pa-icon-src-hover, var(--pa-icon-src));
|
|
3144
|
+
}
|
|
3145
|
+
.pc-icon-hover:not([disabled]):not([aria-disabled=true]):not(.is-disabled):hover .pc-icon-hover-fill {
|
|
3146
|
+
font-weight: 900;
|
|
3147
|
+
}
|
|
3148
|
+
.pc-icon-hover:not([disabled]):not([aria-disabled=true]):not(.is-disabled):hover .pc-icon-hover-highlight {
|
|
3149
|
+
color: var(--pc-icon-hover-color, var(--pc-accent));
|
|
3150
|
+
}
|
|
3151
|
+
|
|
3136
3152
|
.font-family-system {
|
|
3137
3153
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
3138
3154
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keenmate/pure-css",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
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
5
|
"style": "dist/css/pure-css.css",
|
|
6
6
|
"exports": {
|
|
@@ -0,0 +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
|
+
}
|
package/src/scss/_sidebar.scss
CHANGED
|
@@ -159,10 +159,6 @@ body.pc-layout--sticky .pc-layout__sidebar {
|
|
|
159
159
|
font-weight: $font-weight-medium;
|
|
160
160
|
border-inline-end: $border-width-thick solid transparent; // RTL: flips to border-left
|
|
161
161
|
|
|
162
|
-
body.loaded & {
|
|
163
|
-
transition: all $transition-fast $easing-snappy;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
162
|
&:hover {
|
|
167
163
|
color: var(--pc-sidebar-text, var(--base-text-color-1));
|
|
168
164
|
background-color: var(--pc-accent-light);
|
|
@@ -212,10 +208,6 @@ body.pc-layout--sticky .pc-layout__sidebar {
|
|
|
212
208
|
display: none;
|
|
213
209
|
}
|
|
214
210
|
|
|
215
|
-
body.loaded & {
|
|
216
|
-
transition: all $transition-fast $easing-snappy;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
211
|
&:hover {
|
|
220
212
|
// $accent-color (foundation) — was $input-focus-border-color, an exact
|
|
221
213
|
// alias; inlined so the shell no longer depends on the component layer
|
|
@@ -335,10 +327,6 @@ body.pc-layout--sticky .pc-layout__sidebar {
|
|
|
335
327
|
font-weight: $font-weight-medium;
|
|
336
328
|
cursor: pointer;
|
|
337
329
|
|
|
338
|
-
body.loaded & {
|
|
339
|
-
transition: all $transition-fast $easing-snappy;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
330
|
&:hover {
|
|
343
331
|
color: var(--pc-sidebar-text, var(--base-text-color-1));
|
|
344
332
|
background-color: var(--pc-accent-light);
|