@keenmate/pure-css 1.0.4 → 1.0.5

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,19 @@
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.0.5] — 2026-09-18 [PUBLISHED]
7
+
8
+ ### Fixed
9
+
10
+ - **Ordered lists (`<ol>`) regressed to `disc` bullets instead of numbers.** In
11
+ 1.0.4 the `--pc-list-bullet-type` knob was applied to the shared `ul, ol`
12
+ reboot rule with a `disc` default, so every `<ol>` (bare, or `.pa-list-ordered`
13
+ and any consumer's ordered list) rendered filled bullets instead of `decimal`
14
+ numbers. The marker knob is an **unordered** concern, so it now lives on a
15
+ `ul`-only rule; `<ol>` keeps the browser-default `decimal` (ordered-marker
16
+ variants like roman/alpha stay a per-component override). The shared
17
+ margin/padding rule on `ul, ol` is unchanged.
18
+
6
19
  ## [1.0.4] — 2026-09-18 [PUBLISHED]
7
20
 
8
21
  ### Added
package/README.md CHANGED
@@ -1,218 +1,216 @@
1
- # @keenmate/pure-css
2
-
3
- Keenmate's CSS **foundation** — descended from [Yahoo's Pure CSS](https://purecss.io/) and extended into a
4
- more robust, themeable layer for real apps. One small, dependency-free package gives you the
5
- **`--base-*` theming contract** (one block of custom properties re-themes everything at once), a
6
- modern **flexbox grid** (`.pc-row` / `.pc-col`, container-query responsive — replacing Pure's float
7
- grid), a set of **utility classes**, and an optional **app shell + JS runtime** (in the
8
- `pure-css.css` bundle).
9
-
10
- It's the shared layer the whole Keenmate stack agrees on:
11
- [`@keenmate/pure-admin-core`](https://github.com/Keenmate/pure-admin) builds its component library on
12
- top of it, and every Keenmate web/Svelte component reads its colours from the same `--base-*`
13
- variables.
14
-
15
- ## What's New in 1.0.4
16
-
17
- - **Reboot — `--pc-list-bullet-type` turns the list marker into a runtime knob, backed by the `--base-*` contract** — every `ul` / `ol` styled by `reboot.scss` now reads its `list-style-type` from `var(--pc-list-bullet-type, var(--base-list-bullet-type, disc))`, so you can switch a list's marker (`disc` / `circle` / `square` / `none` / `decimal` / …) without a recompile: set `--pc-list-bullet-type` at `:root`, on an ancestor, or per-instance via `style="--pc-list-bullet-type: square"`. The per-instance `--pc-` knob wins when set, else the themeable `--base-list-bullet-type` default (new in `@keenmate/base-css-variables`, emitted at `:root` by `base.css` and the bundle), else the inline browser-default `disc`. The `--pc-` knob itself is deliberately **not** emitted by the `output-*` variable mixins you opt in only where a per-instance marker is wanted. Lists that intentionally drop the marker (`list-style: none` on nav/sidebar menus, `.unstyled`, pure-admin's `--unstyled` / `--bordered` / list modifiers) still win on source order, so this only affects lists that already show a marker.
18
- - **Icons — `download`, `link` and `external-link` glyphs join the `--base-*` contract** — three more mask-friendly Lucide glyphs so every consumer paints the same actions from one theme knob. `--base-icon-download` (a tray + down arrow) is save-to-disk / export, `--base-icon-link` (a chain) is the hyperlink / attach-URL mark, and `--base-icon-external-link` (a diagonal arrow-out-of-box) is its companion for links that open in a new tab / leave the app. All are authored in `variables/_base.scss` and emitted from `output-base-css-variables`, so both the standalone `base.css` and the `pure-css.css` bundle carry them; they mirror the canonical `@keenmate/base-css-variables` contract (parity guard green) and back pure-admin's `--pa-icon-download` / `-link` / `-external-link`, which routed through these names with inline fallbacks until now. Consume via `mask: var(--base-icon-link); background: currentColor`.
19
-
20
- ## What's New in 1.0.3
21
-
22
- - **Icons — seven more glyphs join the `--base-*` contract: config/notification/profile plus the full status family** — three affordance marks and a shared severity family, so every consumer paints them from one theme knob. `--base-icon-settings` (a cog), `--base-icon-bell` (a notification bell) and `--base-icon-user` (a person) cover the preferences / notifications / profile trio, while `--base-icon-info` (circle-i), `--base-icon-success` (circle-check), `--base-icon-warning` (triangle-alert) and `--base-icon-danger` (circle-x) form one severity family so every alert, toast and badge shows the same mark. All are mask-friendly Lucide glyphs authored in `variables/_base.scss` and emitted from `output-base-css-variables`, so both the standalone `base.css` and the `pure-css.css` bundle carry them; they mirror the canonical `@keenmate/base-css-variables` contract (parity guard green) and back pure-admin's `--pa-icon-settings` / `-bell` / `-user` / `-info` / `-success` / `-warning` / `-danger`. Consume via `mask: var(--base-icon-info); background: currentColor`.
23
-
24
- - **Sidebar search — the magnifier is now a themeable masked glyph, not a 🔍 emoji** — `.pc-sidebar__search-icon` previously rendered a literal 🔍 text emoji, which varied by platform and font and couldn't be re-skinned. It's now painted in `currentColor` via `mask: var(--base-icon-search)` — the same technique as `.pc-sidebar__chevron` — so it renders identically everywhere and re-skins from the shared `--base-icon-search` knob, matching the navbar search and pure-admin's `.pa-icon--search`. `font-size: 0` collapses any legacy 🔍 still in markup so it never double-renders, letting consumers drop the emoji from `<button class="pc-sidebar__search-icon">`; the literal Lucide glyph stays the standalone fallback when `base.css` is absent.
25
-
26
- ## Why
27
-
28
- pure-css is a **standalone foundation** you drop onto any surface — a docs site, a marketing page, a
29
- widget host, or a full application. One small, dependency-free package gives you theming, layout and
30
- utilities without buying into a component framework.
31
-
32
- Its heart is a single **`--base-*` theming contract**: override one block of custom properties and
33
- everything re-themes at once the grid, the utilities, the optional app shell, and any component
34
- that reads the same variables. Light and dark are built in via `light-dark()`, there's no build step
35
- to consume it (just link the prebuilt CSS), and it pulls in no runtime dependencies.
36
-
37
- ```
38
- @keenmate/pure-css (this package)
39
- ├─ --base-* theming contract
40
- ├─ .pc-row / .pc-col grid
41
- ├─ utility classes
42
- └─ optional app shell + JS runtime
43
- ▲ consumed directly, as built CSS, by…
44
- ├── docs sites · portals · marketing pages · widget & component hosts
45
- └── @keenmate/pure-admin-core — adds a full component library on top (just one consumer)
46
- ```
47
-
48
- ## Installation
49
-
50
- ```bash
51
- npm install @keenmate/pure-css
52
- ```
53
-
54
- ## Quick Start
55
-
56
- **Prebuilt CSS (simplest):**
57
-
58
- ```html
59
- <link rel="stylesheet" href="node_modules/@keenmate/pure-css/dist/css/pure-css.css">
60
- ```
61
-
62
- or cherry-pick:
63
-
64
- ```html
65
- <link rel="stylesheet" href="…/pure-css/dist/css/base.css"> <!-- variables only -->
66
- <link rel="stylesheet" href="…/pure-css/dist/css/grid.css"> <!-- + grid -->
67
- ```
68
-
69
- **SCSS (customize before compiling):**
70
-
71
- ```scss
72
- // Override the source of truth; everything re-derives.
73
- $base-accent-color: #4f46e5;
74
- $base-page-bg: #0b1020;
75
-
76
- @use '@keenmate/pure-css/scss/pure-css';
77
- ```
78
-
79
- ## What's in it
80
-
81
- | Artifact | Contents | When to link |
82
- | --- | --- | --- |
83
- | `dist/css/pure-css.css` | everything below, in one file | the common case |
84
- | `dist/css/base.css` | only `:root { --base-*; --pc-*; }` | you just need the theming contract (e.g. to theme embedded web components) or a base for a theme override |
85
- | `dist/css/component-reset.css` | a `:host` reset (box-sizing + inherited typography pinned to `--base-*`) — the Shadow-DOM counterpart to reboot | building a web component: adopt it into the shadow root (e.g. `import '@keenmate/pure-css/component-reset?inline'`) so the host page can't bleed styles in; pair with `base` |
86
- | `dist/css/grid.css` | `.pc-row` / `.pc-col-*` (percentage + fraction columns, container-query responsive) | layout only |
87
- | `dist/css/utilities.css` | spacing / flex / display / width-height utilities (`.m-4`, `.d-flex`, `.w-50`, …) | utilities only |
88
-
89
- The `pure-css.css` bundle also includes the **app shell** (navbar, sidebar,
90
- layout container) `base.css` / `grid.css` / `utilities.css` do not.
91
-
92
- ### The app-shell runtime (`./js`)
93
-
94
- The shell's behaviour (nav fit/collapse, dropdowns, drag-to-resize, container
95
- breakpoints) ships as dependency-free source JS via the `./js` export — no
96
- bundler required, drop it in with a `<script>` and call `initAll`:
97
-
98
- ```html
99
- <link rel="stylesheet" href="node_modules/@keenmate/pure-css/dist/css/pure-css.css">
100
- <script src="node_modules/@keenmate/pure-css/src/js/pure-css.js"></script>
101
- <script src="node_modules/@keenmate/pure-css/src/js/fit.js"></script>
102
- <script src="node_modules/@keenmate/pure-css/src/js/navbar-dropdown.js"></script>
103
- <script src="node_modules/@keenmate/pure-css/src/js/sidebar-resize.js"></script>
104
- <script>window.pureCss.components.initAll(document);</script>
105
- ```
106
-
107
- `window.pureCss` also exposes an event bus and live `viewport` / `colorScheme` /
108
- `device` sources. The runtime is optional — shell CSS is authored no-JS-safe, so
109
- the styling stands on its own and the JS only adds the interactive behaviour.
110
-
111
- ### The `--base-*` contract
112
-
113
- `--base-*` is the **single source of truth for theming**. Framework colors, component variables
114
- (`--pc-*`) and web/svelte components all derive from it via fallback chains
115
- (`--ms-accent-color: var(--base-accent-color, #3b82f6)`). Categories: accent, text, background,
116
- border, input, dropdown, tooltip, contextual (success/danger/warning/info), interactive states,
117
- typography, border-radius, spacing/shadow/motion/z-index scales, and icons. The full list is
118
- `src/scss/variables/_base.scss`.
119
-
120
- #### Icons
121
-
122
- `--base-icon-*` are mask-friendly SVG glyphs (Lucide defaults) for the shared UI affordances, so the
123
- pure-css shell, pure-admin components, and the web/svelte components render the **same** marks and a
124
- theme re-skins them in one place. Each is consumed via `mask: var(--base-icon-x); background:
125
- currentColor`, so the glyph inherits text colour — override a token with any mask-friendly `url()` to
126
- swap the icon set.
127
-
128
- | Token | Glyph | Use |
129
- | --- | --- | --- |
130
- | `--base-icon-chevron` | stroked angle `›` | expanders / nav **rotate-one-glyph** disclosure (points right, rotate 90° when open) |
131
- | `--base-icon-caret-down` / `--base-icon-caret-up` | solid triangles `▾` / `▴` | static dropdown / `<select>` affordance (down) and sort-direction / upward-dropdown counterpart (up) a caret never rotates |
132
- | `--base-icon-close` | `✕` | dismiss a transient **surface** (dialog, panel, popover, toast) |
133
- | `--base-icon-clear` | `✕` | clear a **field** distinct purpose, same glyph; **follows** `--base-icon-close`, override alone to diverge |
134
- | `--base-icon-remove` | `✕` | take an **item** out of a collection (chip / tag / row) non-destructive; follows `--base-icon-close` |
135
- | `--base-icon-expand` / `--base-icon-collapse` | `+` / `−` | **swap-two-glyphs** disclosure (tree nodes, accordions): show `+` when collapsed, `−` when open |
136
- | `--base-icon-add` / `--base-icon-edit` / `--base-icon-delete` | `+` / pencil / trash | **CRUD action** verbs — create / modify / **destroy** (delete is a trash can, *not* an ✕, so it reads as destructive) |
137
- | `--base-icon-search` | magnifying glass | search inputs, command palette find **by text** |
138
- | `--base-icon-filter` | funnel | refine / **narrow a list** by criteria (filter toggles, faceted search) distinct from `search` |
139
- | `--base-icon-refresh` | two curved arrows | reload / re-fetch a view or dataset |
140
- | `--base-icon-check` / `--base-icon-indeterminate` | `✓` / `−` | **selection** pair (checkboxes, multiselect, tree nodes): `check` = selected, `indeterminate` = a tri-state parent whose children are a mix |
141
- | `--base-icon-copy` | two overlapping sheets | copy-to-clipboard |
142
- | `--base-icon-ellipsis` | three dots `⋯` | "more / overflow" affordance — **rotate-one-glyph** for the vertical `⋮` variant (rotate 90°) |
143
- | `--base-icon-save` | floppy disk | persist / commit |
144
-
145
- Three intentional distinctions:
146
-
147
- - **Disclosure models:** **chevron rotates one glyph** (sidebar, multiselect), while **expand/collapse swaps
148
- two glyphs** (trees, accordions) a component never rotates a `+` into a `−`.
149
- - **✕ vs trash:** `close` / `clear` / `remove` are three *dismiss* purposes that share the ✕ glyph (and
150
- cascade off `--base-icon-close`), while `delete` is a separate *destructive* action drawn as a trash can.
151
- `add` shares the `+` shape with `expand` but is an independent knob (create ≠ disclosure).
152
- - **Selection ≠ disclosure:** `indeterminate` shares the `−` shape with `collapse` but is its own knob —
153
- a partially-selected checkbox is not a collapsed node.
154
-
155
- ## Theming
156
-
157
- A **theme** is nothing but a set of `--base-*` values. The lightest possible theme is a stylesheet
158
- that redeclares them, loaded *after* `base.css`:
159
-
160
- ```css
161
- :root {
162
- --base-accent-color: #4f46e5;
163
- --base-page-bg: #f6f8fb;
164
- --base-text-color-1: #1a2233;
165
- }
166
- ```
167
-
168
- Because pure-admin-core, the components and any consumer all read the same variables, that one block
169
- re-themes all of them at once. This is the same model as
170
- [`@keenmate/pure-admin-themes`](https://github.com/Keenmate/pure-admin-themes), so the same CLI and
171
- publishing infrastructure applies.
172
-
173
- ### Mode & variant class placement
174
-
175
- Light/dark and colour-variant switching is done by toggling a class — `.pc-mode-light` /
176
- `.pc-mode-dark` and `.pa-color-*`. **Apply these to the `:root` element (`<html>`), not `<body>`.**
177
-
178
- The mode/variant blocks override input tokens (`--pc-*` / `--base-*`). Many themed tokens are
179
- *derived* from those inputs and emitted once at `:root` e.g. core emits
180
- `--pa-btn-info-bg: var(--pc-info)`. CSS resolves a custom property's `var()` **at the element that
181
- declares it**, so a derived token declared on `:root` bakes in `:root`'s input value. If the mode
182
- class sits on a *descendant* (`<body>`), the override comes too late and the derived token stays
183
- frozen at the default-mode value the classic symptom is a role button or surface that doesn't
184
- change colour when you switch modes. Putting the class on `:root` (the same element that declares
185
- the tokens) makes the overrides win and the derived tokens re-resolve.
186
-
187
- pure-css re-emits its own base text-tier tokens at `:root, .pc-mode-light, .pc-mode-dark` to tolerate
188
- either placement, but that does not extend to the pure-admin component layer, hence the `:root` rule.
189
-
190
- To avoid a colour "flash" on switch, disable transitions for one frame during the swap (add a
191
- `transition: none !important` class to `:root`, change the mode/variant class, force a reflow, then
192
- remove it).
193
-
194
- ## Build
195
-
196
- ```bash
197
- make install # sass
198
- make build # src/scss -> dist/css (bundle + base + grid + utilities)
199
- make sizes # show artifact sizes
200
- ```
201
-
202
- `dist/` is committed so consumers can vendor the built CSS without a Sass toolchain.
203
-
204
- ## Provenance
205
-
206
- The SCSS is the foundation extracted from `pure-admin-core`'s `src/scss` the `variables/` modules,
207
- `_base-css-variables.scss`, `utilities.scss`, `_fonts.scss`, and the native grid (`_pa-grid.scss`,
208
- formerly core's `core-components/_grid.scss`). **pure-admin-core now consumes this package** as its
209
- single source for the foundation (thin `@import`/`@forward` shims), so the two no longer drift —
210
- core's compiled `--base-*` values and grid output match pure-css exactly.
211
-
212
- One intentional difference: `utilities.scss` here `@use`s `_fonts.scss` so the generic
213
- `.font-family-*` classes ship with the other utilities, whereas core keeps `_fonts.scss` standalone.
214
- `_rtl-helpers.scss` and the component layer stay in core.
215
-
216
- ## License
217
-
218
- MIT © Keenmate. The grid is derived from [Pure](https://purecss.io/) (Yahoo!, BSD).
1
+ # @keenmate/pure-css
2
+
3
+ Keenmate's CSS **foundation** — descended from [Yahoo's Pure CSS](https://purecss.io/) and extended into a
4
+ more robust, themeable layer for real apps. One small, dependency-free package gives you the
5
+ **`--base-*` theming contract** (one block of custom properties re-themes everything at once), a
6
+ modern **flexbox grid** (`.pc-row` / `.pc-col`, container-query responsive — replacing Pure's float
7
+ grid), a set of **utility classes**, and an optional **app shell + JS runtime** (in the
8
+ `pure-css.css` bundle).
9
+
10
+ It's the shared layer the whole Keenmate stack agrees on:
11
+ [`@keenmate/pure-admin-core`](https://github.com/Keenmate/pure-admin) builds its component library on
12
+ top of it, and every Keenmate web/Svelte component reads its colours from the same `--base-*`
13
+ variables.
14
+
15
+ ## What's New in 1.0.5
16
+
17
+ - **Reboot — ordered lists (`<ol>`) render numbers again** — a 1.0.4 regression applied the new `--pc-list-bullet-type` knob to the shared `ul, ol` rule with a `disc` default, so every ordered list showed filled bullets instead of `decimal` numbers. The marker knob is an unordered concern, so it now sits on a `ul`-only rule; `<ol>` keeps the browser-default `decimal` (roman/alpha ordered variants stay a per-component override). The shared list margin/padding is unchanged, and `--pc-list-bullet-type` / `--base-list-bullet-type` continue to drive `ul` markers exactly as before.
18
+
19
+ ## What's New in 1.0.4
20
+
21
+ - **Reboot — `--pc-list-bullet-type` turns the list marker into a runtime knob, backed by the `--base-*` contract** — every `ul` / `ol` styled by `reboot.scss` now reads its `list-style-type` from `var(--pc-list-bullet-type, var(--base-list-bullet-type, disc))`, so you can switch a list's marker (`disc` / `circle` / `square` / `none` / `decimal` / …) without a recompile: set `--pc-list-bullet-type` at `:root`, on an ancestor, or per-instance via `style="--pc-list-bullet-type: square"`. The per-instance `--pc-` knob wins when set, else the themeable `--base-list-bullet-type` default (new in `@keenmate/base-css-variables`, emitted at `:root` by `base.css` and the bundle), else the inline browser-default `disc`. The `--pc-` knob itself is deliberately **not** emitted by the `output-*` variable mixins — you opt in only where a per-instance marker is wanted. Lists that intentionally drop the marker (`list-style: none` on nav/sidebar menus, `.unstyled`, pure-admin's `--unstyled` / `--bordered` / … list modifiers) still win on source order, so this only affects lists that already show a marker.
22
+ - **Icons — `download`, `link` and `external-link` glyphs join the `--base-*` contract** — three more mask-friendly Lucide glyphs so every consumer paints the same actions from one theme knob. `--base-icon-download` (a tray + down arrow) is save-to-disk / export, `--base-icon-link` (a chain) is the hyperlink / attach-URL mark, and `--base-icon-external-link` (a diagonal arrow-out-of-box) is its companion for links that open in a new tab / leave the app. All are authored in `variables/_base.scss` and emitted from `output-base-css-variables`, so both the standalone `base.css` and the `pure-css.css` bundle carry them; they mirror the canonical `@keenmate/base-css-variables` contract (parity guard green) and back pure-admin's `--pa-icon-download` / `-link` / `-external-link`, which routed through these names with inline fallbacks until now. Consume via `mask: var(--base-icon-link); background: currentColor`.
23
+
24
+ ## Why
25
+
26
+ pure-css is a **standalone foundation** you drop onto any surface — a docs site, a marketing page, a
27
+ widget host, or a full application. One small, dependency-free package gives you theming, layout and
28
+ utilities without buying into a component framework.
29
+
30
+ Its heart is a single **`--base-*` theming contract**: override one block of custom properties and
31
+ everything re-themes at once — the grid, the utilities, the optional app shell, and any component
32
+ that reads the same variables. Light and dark are built in via `light-dark()`, there's no build step
33
+ to consume it (just link the prebuilt CSS), and it pulls in no runtime dependencies.
34
+
35
+ ```
36
+ @keenmate/pure-css (this package)
37
+ ├─ --base-* theming contract
38
+ ├─ .pc-row / .pc-col grid
39
+ ├─ utility classes
40
+ └─ optional app shell + JS runtime
41
+ consumed directly, as built CSS, by…
42
+ ├── docs sites · portals · marketing pages · widget & component hosts
43
+ └── @keenmate/pure-admin-core adds a full component library on top (just one consumer)
44
+ ```
45
+
46
+ ## Installation
47
+
48
+ ```bash
49
+ npm install @keenmate/pure-css
50
+ ```
51
+
52
+ ## Quick Start
53
+
54
+ **Prebuilt CSS (simplest):**
55
+
56
+ ```html
57
+ <link rel="stylesheet" href="node_modules/@keenmate/pure-css/dist/css/pure-css.css">
58
+ ```
59
+
60
+ or cherry-pick:
61
+
62
+ ```html
63
+ <link rel="stylesheet" href="…/pure-css/dist/css/base.css"> <!-- variables only -->
64
+ <link rel="stylesheet" href="…/pure-css/dist/css/grid.css"> <!-- + grid -->
65
+ ```
66
+
67
+ **SCSS (customize before compiling):**
68
+
69
+ ```scss
70
+ // Override the source of truth; everything re-derives.
71
+ $base-accent-color: #4f46e5;
72
+ $base-page-bg: #0b1020;
73
+
74
+ @use '@keenmate/pure-css/scss/pure-css';
75
+ ```
76
+
77
+ ## What's in it
78
+
79
+ | Artifact | Contents | When to link |
80
+ | --- | --- | --- |
81
+ | `dist/css/pure-css.css` | everything below, in one file | the common case |
82
+ | `dist/css/base.css` | only `:root { --base-*; --pc-*; }` | you just need the theming contract (e.g. to theme embedded web components) or a base for a theme override |
83
+ | `dist/css/component-reset.css` | a `:host` reset (box-sizing + inherited typography pinned to `--base-*`) — the Shadow-DOM counterpart to reboot | building a web component: adopt it into the shadow root (e.g. `import '@keenmate/pure-css/component-reset?inline'`) so the host page can't bleed styles in; pair with `base` |
84
+ | `dist/css/grid.css` | `.pc-row` / `.pc-col-*` (percentage + fraction columns, container-query responsive) | layout only |
85
+ | `dist/css/utilities.css` | spacing / flex / display / width-height utilities (`.m-4`, `.d-flex`, `.w-50`, …) | utilities only |
86
+
87
+ The `pure-css.css` bundle also includes the **app shell** (navbar, sidebar,
88
+ layout container) — `base.css` / `grid.css` / `utilities.css` do not.
89
+
90
+ ### The app-shell runtime (`./js`)
91
+
92
+ The shell's behaviour (nav fit/collapse, dropdowns, drag-to-resize, container
93
+ breakpoints) ships as dependency-free source JS via the `./js` export — no
94
+ bundler required, drop it in with a `<script>` and call `initAll`:
95
+
96
+ ```html
97
+ <link rel="stylesheet" href="node_modules/@keenmate/pure-css/dist/css/pure-css.css">
98
+ <script src="node_modules/@keenmate/pure-css/src/js/pure-css.js"></script>
99
+ <script src="node_modules/@keenmate/pure-css/src/js/fit.js"></script>
100
+ <script src="node_modules/@keenmate/pure-css/src/js/navbar-dropdown.js"></script>
101
+ <script src="node_modules/@keenmate/pure-css/src/js/sidebar-resize.js"></script>
102
+ <script>window.pureCss.components.initAll(document);</script>
103
+ ```
104
+
105
+ `window.pureCss` also exposes an event bus and live `viewport` / `colorScheme` /
106
+ `device` sources. The runtime is optional — shell CSS is authored no-JS-safe, so
107
+ the styling stands on its own and the JS only adds the interactive behaviour.
108
+
109
+ ### The `--base-*` contract
110
+
111
+ `--base-*` is the **single source of truth for theming**. Framework colors, component variables
112
+ (`--pc-*`) and web/svelte components all derive from it via fallback chains
113
+ (`--ms-accent-color: var(--base-accent-color, #3b82f6)`). Categories: accent, text, background,
114
+ border, input, dropdown, tooltip, contextual (success/danger/warning/info), interactive states,
115
+ typography, border-radius, spacing/shadow/motion/z-index scales, and icons. The full list is
116
+ `src/scss/variables/_base.scss`.
117
+
118
+ #### Icons
119
+
120
+ `--base-icon-*` are mask-friendly SVG glyphs (Lucide defaults) for the shared UI affordances, so the
121
+ pure-css shell, pure-admin components, and the web/svelte components render the **same** marks and a
122
+ theme re-skins them in one place. Each is consumed via `mask: var(--base-icon-x); background:
123
+ currentColor`, so the glyph inherits text colour override a token with any mask-friendly `url()` to
124
+ swap the icon set.
125
+
126
+ | Token | Glyph | Use |
127
+ | --- | --- | --- |
128
+ | `--base-icon-chevron` | stroked angle `›` | expanders / nav — **rotate-one-glyph** disclosure (points right, rotate 90° when open) |
129
+ | `--base-icon-caret-down` / `--base-icon-caret-up` | solid triangles `▾` / `▴` | static dropdown / `<select>` affordance (down) and sort-direction / upward-dropdown counterpart (up) — a caret never rotates |
130
+ | `--base-icon-close` | `✕` | dismiss a transient **surface** (dialog, panel, popover, toast) |
131
+ | `--base-icon-clear` | `✕` | clear a **field** distinct purpose, same glyph; **follows** `--base-icon-close`, override alone to diverge |
132
+ | `--base-icon-remove` | `✕` | take an **item** out of a collection (chip / tag / row) — non-destructive; follows `--base-icon-close` |
133
+ | `--base-icon-expand` / `--base-icon-collapse` | `+` / `−` | **swap-two-glyphs** disclosure (tree nodes, accordions): show `+` when collapsed, `−` when open |
134
+ | `--base-icon-add` / `--base-icon-edit` / `--base-icon-delete` | `+` / pencil / trash | **CRUD action** verbs — create / modify / **destroy** (delete is a trash can, *not* an ✕, so it reads as destructive) |
135
+ | `--base-icon-search` | magnifying glass | search inputs, command palette find **by text** |
136
+ | `--base-icon-filter` | funnel | refine / **narrow a list** by criteria (filter toggles, faceted search) distinct from `search` |
137
+ | `--base-icon-refresh` | two curved arrows | reload / re-fetch a view or dataset |
138
+ | `--base-icon-check` / `--base-icon-indeterminate` | `✓` / `−` | **selection** pair (checkboxes, multiselect, tree nodes): `check` = selected, `indeterminate` = a tri-state parent whose children are a mix |
139
+ | `--base-icon-copy` | two overlapping sheets | copy-to-clipboard |
140
+ | `--base-icon-ellipsis` | three dots `⋯` | "more / overflow" affordance **rotate-one-glyph** for the vertical `⋮` variant (rotate 90°) |
141
+ | `--base-icon-save` | floppy disk | persist / commit |
142
+
143
+ Three intentional distinctions:
144
+
145
+ - **Disclosure models:** **chevron rotates one glyph** (sidebar, multiselect), while **expand/collapse swaps
146
+ two glyphs** (trees, accordions) — a component never rotates a `+` into a `−`.
147
+ - **✕ vs trash:** `close` / `clear` / `remove` are three *dismiss* purposes that share the ✕ glyph (and
148
+ cascade off `--base-icon-close`), while `delete` is a separate *destructive* action drawn as a trash can.
149
+ `add` shares the `+` shape with `expand` but is an independent knob (create disclosure).
150
+ - **Selection disclosure:** `indeterminate` shares the `−` shape with `collapse` but is its own knob —
151
+ a partially-selected checkbox is not a collapsed node.
152
+
153
+ ## Theming
154
+
155
+ A **theme** is nothing but a set of `--base-*` values. The lightest possible theme is a stylesheet
156
+ that redeclares them, loaded *after* `base.css`:
157
+
158
+ ```css
159
+ :root {
160
+ --base-accent-color: #4f46e5;
161
+ --base-page-bg: #f6f8fb;
162
+ --base-text-color-1: #1a2233;
163
+ }
164
+ ```
165
+
166
+ Because pure-admin-core, the components and any consumer all read the same variables, that one block
167
+ re-themes all of them at once. This is the same model as
168
+ [`@keenmate/pure-admin-themes`](https://github.com/Keenmate/pure-admin-themes), so the same CLI and
169
+ publishing infrastructure applies.
170
+
171
+ ### Mode & variant class placement
172
+
173
+ Light/dark and colour-variant switching is done by toggling a class — `.pc-mode-light` /
174
+ `.pc-mode-dark` and `.pa-color-*`. **Apply these to the `:root` element (`<html>`), not `<body>`.**
175
+
176
+ The mode/variant blocks override input tokens (`--pc-*` / `--base-*`). Many themed tokens are
177
+ *derived* from those inputs and emitted once at `:root` — e.g. core emits
178
+ `--pa-btn-info-bg: var(--pc-info)`. CSS resolves a custom property's `var()` **at the element that
179
+ declares it**, so a derived token declared on `:root` bakes in `:root`'s input value. If the mode
180
+ class sits on a *descendant* (`<body>`), the override comes too late and the derived token stays
181
+ frozen at the default-mode value the classic symptom is a role button or surface that doesn't
182
+ change colour when you switch modes. Putting the class on `:root` (the same element that declares
183
+ the tokens) makes the overrides win and the derived tokens re-resolve.
184
+
185
+ pure-css re-emits its own base text-tier tokens at `:root, .pc-mode-light, .pc-mode-dark` to tolerate
186
+ either placement, but that does not extend to the pure-admin component layer, hence the `:root` rule.
187
+
188
+ To avoid a colour "flash" on switch, disable transitions for one frame during the swap (add a
189
+ `transition: none !important` class to `:root`, change the mode/variant class, force a reflow, then
190
+ remove it).
191
+
192
+ ## Build
193
+
194
+ ```bash
195
+ make install # sass
196
+ make build # src/scss -> dist/css (bundle + base + grid + utilities)
197
+ make sizes # show artifact sizes
198
+ ```
199
+
200
+ `dist/` is committed so consumers can vendor the built CSS without a Sass toolchain.
201
+
202
+ ## Provenance
203
+
204
+ The SCSS is the foundation extracted from `pure-admin-core`'s `src/scss` — the `variables/` modules,
205
+ `_base-css-variables.scss`, `utilities.scss`, `_fonts.scss`, and the native grid (`_pa-grid.scss`,
206
+ formerly core's `core-components/_grid.scss`). **pure-admin-core now consumes this package** as its
207
+ single source for the foundation (thin `@import`/`@forward` shims), so the two no longer drift —
208
+ core's compiled `--base-*` values and grid output match pure-css exactly.
209
+
210
+ One intentional difference: `utilities.scss` here `@use`s `_fonts.scss` so the generic
211
+ `.font-family-*` classes ship with the other utilities, whereas core keeps `_fonts.scss` standalone.
212
+ `_rtl-helpers.scss` and the component layer stay in core.
213
+
214
+ ## License
215
+
216
+ MIT © Keenmate. The grid is derived from [Pure](https://purecss.io/) (Yahoo!, BSD).
@@ -44,12 +44,15 @@ ul, ol {
44
44
  margin: 0 0 1.6rem 0;
45
45
  padding: 0;
46
46
  padding-inline-start: 3.2rem;
47
- list-style-type: var(--pc-list-bullet-type, var(--base-list-bullet-type, disc));
48
47
  }
49
48
  ul li, ol li {
50
49
  margin-bottom: 0.4rem;
51
50
  }
52
51
 
52
+ ul {
53
+ list-style-type: var(--pc-list-bullet-type, var(--base-list-bullet-type, disc));
54
+ }
55
+
53
56
  ul.unstyled, ol.unstyled {
54
57
  list-style: none;
55
58
  padding-inline-start: 0;
@@ -33,12 +33,15 @@ ul, ol {
33
33
  margin: 0 0 1.6rem 0;
34
34
  padding: 0;
35
35
  padding-inline-start: 3.2rem;
36
- list-style-type: var(--pc-list-bullet-type, var(--base-list-bullet-type, disc));
37
36
  }
38
37
  ul li, ol li {
39
38
  margin-bottom: 0.4rem;
40
39
  }
41
40
 
41
+ ul {
42
+ list-style-type: var(--pc-list-bullet-type, var(--base-list-bullet-type, disc));
43
+ }
44
+
42
45
  ul.unstyled, ol.unstyled {
43
46
  list-style: none;
44
47
  padding-inline-start: 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keenmate/pure-css",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
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": {
@@ -64,24 +64,32 @@ ul, ol {
64
64
  margin: $list-margin-top 0 $list-margin-bottom 0;
65
65
  padding: 0;
66
66
  padding-inline-start: $list-padding-left; // RTL: flips to right
67
- // Runtime-overridable marker. Set --pc-list-bullet-type (disc | circle |
68
- // square | none | decimal | …) at :root, on an ancestor, or per-instance
69
- // (style="--pc-list-bullet-type: square") to switch the marker without a
70
- // recompile. It layers over the base contract: --pc-list-bullet-type wins when
71
- // set, else the themeable --base-list-bullet-type default (emitted by
72
- // output-base-css-variables), else the inline browser-default disc. The --pc-
73
- // knob itself is not emitted by the variable mixins — set it only where a
74
- // per-instance marker is wanted. Components that reset the marker
75
- // (list-style: none on nav/sidebar menus, .unstyled, pure-admin's
76
- // --unstyled/--bordered/… list modifiers) win on source order, so this only
77
- // affects lists that still show a marker.
78
- list-style-type: var(--pc-list-bullet-type, var(--base-list-bullet-type, disc));
79
67
 
80
68
  li {
81
69
  margin-bottom: $list-item-margin-bottom;
82
70
  }
83
71
  }
84
72
 
73
+ // Runtime-overridable UNORDERED marker — ul only, so <ol> keeps its numbers
74
+ // (a shared `ul, ol` rule with a `disc` default turned ordered lists into
75
+ // bullets). Set --pc-list-bullet-type (disc | circle | square | none | …) at
76
+ // :root, on an ancestor, or per-instance (style="--pc-list-bullet-type: square")
77
+ // to switch the marker without a recompile. It layers over the base contract:
78
+ // --pc-list-bullet-type wins when set, else the themeable --base-list-bullet-type
79
+ // default (emitted by output-base-css-variables), else the inline browser-default
80
+ // disc. The --pc- knob itself is not emitted by the variable mixins — set it only
81
+ // where a per-instance marker is wanted. Components that reset the marker
82
+ // (list-style: none on nav/sidebar menus, .unstyled, pure-admin's
83
+ // --unstyled/--bordered/… list modifiers) win on source order, so this only
84
+ // affects unordered lists that still show a marker. By design this applies at
85
+ // EVERY nesting depth (a single, controllable marker), so nested <ul>s all use
86
+ // the same marker rather than the browser's disc→circle→square depth cascade —
87
+ // intentional, not a bug: the knob trades depth-varying markers for one uniform,
88
+ // themeable bullet.
89
+ ul {
90
+ list-style-type: var(--pc-list-bullet-type, var(--base-list-bullet-type, disc));
91
+ }
92
+
85
93
  // Lists - unstyled (for navigation, etc.)
86
94
  ul.unstyled, ol.unstyled {
87
95
  list-style: none;