@keenmate/pure-css 1.0.3 → 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,48 @@
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
+
19
+ ## [1.0.4] — 2026-09-18 [PUBLISHED]
20
+
21
+ ### Added
22
+
23
+ - **`--pc-list-bullet-type` — runtime list-marker knob on the `ul, ol` reboot,
24
+ backed by the `--base-list-bullet-type` contract.** Switch a list's marker
25
+ (`disc` / `circle` / `square` / `none` / `decimal` / …) without a recompile: set
26
+ `--pc-list-bullet-type` at `:root`, on an ancestor, or per-instance
27
+ (`style="--pc-list-bullet-type: square"`). Applies to every list since it sits on
28
+ the base `ul, ol` reboot. It resolves as
29
+ `var(--pc-list-bullet-type, var(--base-list-bullet-type, disc))` — the per-instance
30
+ `--pc-` knob wins when set, else the themeable `--base-list-bullet-type` default
31
+ (newly added to `@keenmate/base-css-variables`, mirrored as `$base-list-bullet-type`
32
+ and emitted from `output-base-css-variables` in both `base.css` and the bundle),
33
+ else the inline browser-default `disc`. The `--pc-` knob itself is **not** emitted by
34
+ `output-*` mixins — set it only where a per-instance marker is wanted. Lists that
35
+ reset the marker (`list-style: none` on nav/sidebar menus, `.unstyled`, downstream
36
+ `--unstyled` / `--bordered` / … modifiers) still win on source order.
37
+ - **Three action / navigation icon tokens: `--base-icon-download`,
38
+ `--base-icon-link`, `--base-icon-external-link`.** Mask-friendly Lucide glyphs
39
+ (`download` = tray + down arrow for save-to-disk / export; `link` = chain for
40
+ hyperlink / attach-URL; `external-link` = diagonal arrow-out-of-box for links
41
+ that open in a new tab / leave the app), added to `variables/_base.scss` and
42
+ emitted from `output-base-css-variables` (both `base.css` and the `pure-css.css`
43
+ bundle carry them). Consumed by pure-admin's `--pa-icon-download` /
44
+ `--pa-icon-link` / `--pa-icon-external-link` (which fell back to inline glyphs
45
+ until these landed). Mirrors the canonical `@keenmate/base-css-variables`
46
+ contract (parity guard green).
47
+
6
48
  ## [1.0.3] — 2026-09-16 [PUBLISHED]
7
49
 
8
50
  ### Added
package/README.md CHANGED
@@ -1,217 +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.3
16
-
17
- - **Iconsseven 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`.
18
-
19
- - **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.
20
-
21
- ## What's New in 1.0.2
22
-
23
- - **Icons — `copy`, `ellipsis`, `save` and `refresh` glyphs join the shared `--base-*` contract** — four more mask-friendly Lucide glyphs so every consumer paints the same actions from one theme knob. `--base-icon-copy` (two overlapping sheets) is copy-to-clipboard, `--base-icon-ellipsis` (three dots) is the "more / overflow" mark — its vertical `⋮` variant is the *same glyph rotated 90°* (the rotate-one-glyph discipline already used for `chevron`), so there's no separate token to maintain — `--base-icon-save` (a floppy disk) is persist / commit, and `--base-icon-refresh` (two curved arrows, Lucide `refresh-cw`) is reload / re-fetch, sitting alongside `search` and `filter` in the utility-icon row (consumers typically spin it with a CSS animation while a fetch is in flight). The action trio completes the affordance set pure-admin migrated off Font Awesome: its `--pa-icon-copy` / `-ellipsis` / `-save` already routed through these `--base-icon-*` names with inline fallbacks, so they become fully theme-overridable with zero pure-admin change. 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; consume via `mask: var(--base-icon-copy); background: currentColor`.
24
-
25
- ## Why
26
-
27
- pure-css is a **standalone foundation** you drop onto any surface a docs site, a marketing page, a
28
- widget host, or a full application. One small, dependency-free package gives you theming, layout and
29
- utilities without buying into a component framework.
30
-
31
- Its heart is a single **`--base-*` theming contract**: override one block of custom properties and
32
- everything re-themes at once the grid, the utilities, the optional app shell, and any component
33
- that reads the same variables. Light and dark are built in via `light-dark()`, there's no build step
34
- to consume it (just link the prebuilt CSS), and it pulls in no runtime dependencies.
35
-
36
- ```
37
- @keenmate/pure-css (this package)
38
- ├─ --base-* theming contract
39
- ├─ .pc-row / .pc-col grid
40
- ├─ utility classes
41
- └─ optional app shell + JS runtime
42
- ▲ consumed directly, as built CSS, by…
43
- ├── docs sites · portals · marketing pages · widget & component hosts
44
- └── @keenmate/pure-admin-core — adds a full component library on top (just one consumer)
45
- ```
46
-
47
- ## Installation
48
-
49
- ```bash
50
- npm install @keenmate/pure-css
51
- ```
52
-
53
- ## Quick Start
54
-
55
- **Prebuilt CSS (simplest):**
56
-
57
- ```html
58
- <link rel="stylesheet" href="node_modules/@keenmate/pure-css/dist/css/pure-css.css">
59
- ```
60
-
61
- or cherry-pick:
62
-
63
- ```html
64
- <link rel="stylesheet" href="…/pure-css/dist/css/base.css"> <!-- variables only -->
65
- <link rel="stylesheet" href="…/pure-css/dist/css/grid.css"> <!-- + grid -->
66
- ```
67
-
68
- **SCSS (customize before compiling):**
69
-
70
- ```scss
71
- // Override the source of truth; everything re-derives.
72
- $base-accent-color: #4f46e5;
73
- $base-page-bg: #0b1020;
74
-
75
- @use '@keenmate/pure-css/scss/pure-css';
76
- ```
77
-
78
- ## What's in it
79
-
80
- | Artifact | Contents | When to link |
81
- | --- | --- | --- |
82
- | `dist/css/pure-css.css` | everything below, in one file | the common case |
83
- | `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 |
84
- | `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` |
85
- | `dist/css/grid.css` | `.pc-row` / `.pc-col-*` (percentage + fraction columns, container-query responsive) | layout only |
86
- | `dist/css/utilities.css` | spacing / flex / display / width-height utilities (`.m-4`, `.d-flex`, `.w-50`, …) | utilities only |
87
-
88
- The `pure-css.css` bundle also includes the **app shell** (navbar, sidebar,
89
- layout container) — `base.css` / `grid.css` / `utilities.css` do not.
90
-
91
- ### The app-shell runtime (`./js`)
92
-
93
- The shell's behaviour (nav fit/collapse, dropdowns, drag-to-resize, container
94
- breakpoints) ships as dependency-free source JS via the `./js` export — no
95
- bundler required, drop it in with a `<script>` and call `initAll`:
96
-
97
- ```html
98
- <link rel="stylesheet" href="node_modules/@keenmate/pure-css/dist/css/pure-css.css">
99
- <script src="node_modules/@keenmate/pure-css/src/js/pure-css.js"></script>
100
- <script src="node_modules/@keenmate/pure-css/src/js/fit.js"></script>
101
- <script src="node_modules/@keenmate/pure-css/src/js/navbar-dropdown.js"></script>
102
- <script src="node_modules/@keenmate/pure-css/src/js/sidebar-resize.js"></script>
103
- <script>window.pureCss.components.initAll(document);</script>
104
- ```
105
-
106
- `window.pureCss` also exposes an event bus and live `viewport` / `colorScheme` /
107
- `device` sources. The runtime is optional shell CSS is authored no-JS-safe, so
108
- the styling stands on its own and the JS only adds the interactive behaviour.
109
-
110
- ### The `--base-*` contract
111
-
112
- `--base-*` is the **single source of truth for theming**. Framework colors, component variables
113
- (`--pc-*`) and web/svelte components all derive from it via fallback chains
114
- (`--ms-accent-color: var(--base-accent-color, #3b82f6)`). Categories: accent, text, background,
115
- border, input, dropdown, tooltip, contextual (success/danger/warning/info), interactive states,
116
- typography, border-radius, spacing/shadow/motion/z-index scales, and icons. The full list is
117
- `src/scss/variables/_base.scss`.
118
-
119
- #### Icons
120
-
121
- `--base-icon-*` are mask-friendly SVG glyphs (Lucide defaults) for the shared UI affordances, so the
122
- pure-css shell, pure-admin components, and the web/svelte components render the **same** marks and a
123
- theme re-skins them in one place. Each is consumed via `mask: var(--base-icon-x); background:
124
- currentColor`, so the glyph inherits text colour — override a token with any mask-friendly `url()` to
125
- swap the icon set.
126
-
127
- | Token | Glyph | Use |
128
- | --- | --- | --- |
129
- | `--base-icon-chevron` | stroked angle `›` | expanders / nav **rotate-one-glyph** disclosure (points right, rotate 90° when open) |
130
- | `--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 |
131
- | `--base-icon-close` | `✕` | dismiss a transient **surface** (dialog, panel, popover, toast) |
132
- | `--base-icon-clear` | `✕` | clear a **field** distinct purpose, same glyph; **follows** `--base-icon-close`, override alone to diverge |
133
- | `--base-icon-remove` | `✕` | take an **item** out of a collection (chip / tag / row) non-destructive; follows `--base-icon-close` |
134
- | `--base-icon-expand` / `--base-icon-collapse` | `+` / `−` | **swap-two-glyphs** disclosure (tree nodes, accordions): show `+` when collapsed, `−` when open |
135
- | `--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) |
136
- | `--base-icon-search` | magnifying glass | search inputs, command palettefind **by text** |
137
- | `--base-icon-filter` | funnel | refine / **narrow a list** by criteria (filter toggles, faceted search) — distinct from `search` |
138
- | `--base-icon-refresh` | two curved arrows | reload / re-fetch a view or dataset |
139
- | `--base-icon-check` / `--base-icon-indeterminate` | `✓` / `−` | **selection** pair (checkboxes, multiselect, tree nodes): `check` = selected, `indeterminate` = a tri-state parent whose children are a mix |
140
- | `--base-icon-copy` | two overlapping sheets | copy-to-clipboard |
141
- | `--base-icon-ellipsis` | three dots `⋯` | "more / overflow" affordance — **rotate-one-glyph** for the vertical `⋮` variant (rotate 90°) |
142
- | `--base-icon-save` | floppy disk | persist / commit |
143
-
144
- Three intentional distinctions:
145
-
146
- - **Disclosure models:** **chevron rotates one glyph** (sidebar, multiselect), while **expand/collapse swaps
147
- two glyphs** (trees, accordions) a component never rotates a `+` into a `−`.
148
- - **✕ vs trash:** `close` / `clear` / `remove` are three *dismiss* purposes that share the glyph (and
149
- cascade off `--base-icon-close`), while `delete` is a separate *destructive* action drawn as a trash can.
150
- `add` shares the `+` shape with `expand` but is an independent knob (create ≠ disclosure).
151
- - **Selection ≠ disclosure:** `indeterminate` shares the `−` shape with `collapse` but is its own knob
152
- a partially-selected checkbox is not a collapsed node.
153
-
154
- ## Theming
155
-
156
- A **theme** is nothing but a set of `--base-*` values. The lightest possible theme is a stylesheet
157
- that redeclares them, loaded *after* `base.css`:
158
-
159
- ```css
160
- :root {
161
- --base-accent-color: #4f46e5;
162
- --base-page-bg: #f6f8fb;
163
- --base-text-color-1: #1a2233;
164
- }
165
- ```
166
-
167
- Because pure-admin-core, the components and any consumer all read the same variables, that one block
168
- re-themes all of them at once. This is the same model as
169
- [`@keenmate/pure-admin-themes`](https://github.com/Keenmate/pure-admin-themes), so the same CLI and
170
- publishing infrastructure applies.
171
-
172
- ### Mode & variant class placement
173
-
174
- Light/dark and colour-variant switching is done by toggling a class `.pc-mode-light` /
175
- `.pc-mode-dark` and `.pa-color-*`. **Apply these to the `:root` element (`<html>`), not `<body>`.**
176
-
177
- The mode/variant blocks override input tokens (`--pc-*` / `--base-*`). Many themed tokens are
178
- *derived* from those inputs and emitted once at `:root` e.g. core emits
179
- `--pa-btn-info-bg: var(--pc-info)`. CSS resolves a custom property's `var()` **at the element that
180
- declares it**, so a derived token declared on `:root` bakes in `:root`'s input value. If the mode
181
- class sits on a *descendant* (`<body>`), the override comes too late and the derived token stays
182
- frozen at the default-mode value the classic symptom is a role button or surface that doesn't
183
- change colour when you switch modes. Putting the class on `:root` (the same element that declares
184
- the tokens) makes the overrides win and the derived tokens re-resolve.
185
-
186
- pure-css re-emits its own base text-tier tokens at `:root, .pc-mode-light, .pc-mode-dark` to tolerate
187
- either placement, but that does not extend to the pure-admin component layer, hence the `:root` rule.
188
-
189
- To avoid a colour "flash" on switch, disable transitions for one frame during the swap (add a
190
- `transition: none !important` class to `:root`, change the mode/variant class, force a reflow, then
191
- remove it).
192
-
193
- ## Build
194
-
195
- ```bash
196
- make install # sass
197
- make build # src/scss -> dist/css (bundle + base + grid + utilities)
198
- make sizes # show artifact sizes
199
- ```
200
-
201
- `dist/` is committed so consumers can vendor the built CSS without a Sass toolchain.
202
-
203
- ## Provenance
204
-
205
- The SCSS is the foundation extracted from `pure-admin-core`'s `src/scss` the `variables/` modules,
206
- `_base-css-variables.scss`, `utilities.scss`, `_fonts.scss`, and the native grid (`_pa-grid.scss`,
207
- formerly core's `core-components/_grid.scss`). **pure-admin-core now consumes this package** as its
208
- single source for the foundation (thin `@import`/`@forward` shims), so the two no longer drift —
209
- core's compiled `--base-*` values and grid output match pure-css exactly.
210
-
211
- One intentional difference: `utilities.scss` here `@use`s `_fonts.scss` so the generic
212
- `.font-family-*` classes ship with the other utilities, whereas core keeps `_fonts.scss` standalone.
213
- `_rtl-helpers.scss` and the component layer stay in core.
214
-
215
- ## License
216
-
217
- 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
+ - **Rebootordered 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).
package/dist/css/base.css CHANGED
@@ -120,6 +120,7 @@
120
120
  --base-line-height-tight: 1.25;
121
121
  --base-line-height-normal: 1.5;
122
122
  --base-line-height-relaxed: 1.75;
123
+ --base-list-bullet-type: disc;
123
124
  --base-border-radius-sm: 0.4;
124
125
  --base-border-radius-md: 0.6;
125
126
  --base-border-radius-lg: 0.8;
@@ -146,6 +147,9 @@
146
147
  --base-icon-settings: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915%22/%3E%3Ccircle cx=%2212%22 cy=%2212%22 r=%223%22/%3E%3C/svg%3E");
147
148
  --base-icon-bell: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M10.268 21a2 2 0 0 0 3.464 0%22/%3E%3Cpath d=%22M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326%22/%3E%3C/svg%3E");
148
149
  --base-icon-user: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2%22/%3E%3Ccircle cx=%2212%22 cy=%227%22 r=%224%22/%3E%3C/svg%3E");
150
+ --base-icon-download: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M12 15V3%22/%3E%3Cpath d=%22M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4%22/%3E%3Cpath d=%22m7 10 5 5 5-5%22/%3E%3C/svg%3E");
151
+ --base-icon-link: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71%22/%3E%3Cpath d=%22M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71%22/%3E%3C/svg%3E");
152
+ --base-icon-external-link: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M15 3h6v6%22/%3E%3Cpath d=%22M10 14 21 3%22/%3E%3Cpath d=%22M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6%22/%3E%3C/svg%3E");
149
153
  --base-icon-info: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Ccircle cx=%2212%22 cy=%2212%22 r=%2210%22/%3E%3Cpath d=%22M12 16v-4%22/%3E%3Cpath d=%22M12 8h.01%22/%3E%3C/svg%3E");
150
154
  --base-icon-success: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Ccircle cx=%2212%22 cy=%2212%22 r=%2210%22/%3E%3Cpath d=%22m16 9-5.5 5.5L8 12%22/%3E%3C/svg%3E");
151
155
  --base-icon-warning: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3%22/%3E%3Cpath d=%22M12 9v4%22/%3E%3Cpath d=%22M12 17h.01%22/%3E%3C/svg%3E");
@@ -49,6 +49,10 @@ ul li, ol li {
49
49
  margin-bottom: 0.4rem;
50
50
  }
51
51
 
52
+ ul {
53
+ list-style-type: var(--pc-list-bullet-type, var(--base-list-bullet-type, disc));
54
+ }
55
+
52
56
  ul.unstyled, ol.unstyled {
53
57
  list-style: none;
54
58
  padding-inline-start: 0;
@@ -6062,6 +6066,7 @@ body.pc-layout--sticky .pc-layout__inner {
6062
6066
  --base-line-height-tight: 1.25;
6063
6067
  --base-line-height-normal: 1.5;
6064
6068
  --base-line-height-relaxed: 1.75;
6069
+ --base-list-bullet-type: disc;
6065
6070
  --base-border-radius-sm: 0.4;
6066
6071
  --base-border-radius-md: 0.6;
6067
6072
  --base-border-radius-lg: 0.8;
@@ -6088,6 +6093,9 @@ body.pc-layout--sticky .pc-layout__inner {
6088
6093
  --base-icon-settings: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915%22/%3E%3Ccircle cx=%2212%22 cy=%2212%22 r=%223%22/%3E%3C/svg%3E");
6089
6094
  --base-icon-bell: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M10.268 21a2 2 0 0 0 3.464 0%22/%3E%3Cpath d=%22M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326%22/%3E%3C/svg%3E");
6090
6095
  --base-icon-user: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2%22/%3E%3Ccircle cx=%2212%22 cy=%227%22 r=%224%22/%3E%3C/svg%3E");
6096
+ --base-icon-download: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M12 15V3%22/%3E%3Cpath d=%22M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4%22/%3E%3Cpath d=%22m7 10 5 5 5-5%22/%3E%3C/svg%3E");
6097
+ --base-icon-link: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71%22/%3E%3Cpath d=%22M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71%22/%3E%3C/svg%3E");
6098
+ --base-icon-external-link: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M15 3h6v6%22/%3E%3Cpath d=%22M10 14 21 3%22/%3E%3Cpath d=%22M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6%22/%3E%3C/svg%3E");
6091
6099
  --base-icon-info: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Ccircle cx=%2212%22 cy=%2212%22 r=%2210%22/%3E%3Cpath d=%22M12 16v-4%22/%3E%3Cpath d=%22M12 8h.01%22/%3E%3C/svg%3E");
6092
6100
  --base-icon-success: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Ccircle cx=%2212%22 cy=%2212%22 r=%2210%22/%3E%3Cpath d=%22m16 9-5.5 5.5L8 12%22/%3E%3C/svg%3E");
6093
6101
  --base-icon-warning: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3%22/%3E%3Cpath d=%22M12 9v4%22/%3E%3Cpath d=%22M12 17h.01%22/%3E%3C/svg%3E");
@@ -38,6 +38,10 @@ ul li, ol li {
38
38
  margin-bottom: 0.4rem;
39
39
  }
40
40
 
41
+ ul {
42
+ list-style-type: var(--pc-list-bullet-type, var(--base-list-bullet-type, disc));
43
+ }
44
+
41
45
  ul.unstyled, ol.unstyled {
42
46
  list-style: none;
43
47
  padding-inline-start: 0;
package/package.json CHANGED
@@ -1,83 +1,83 @@
1
- {
2
- "name": "@keenmate/pure-css",
3
- "version": "1.0.3",
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.0.5",
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
+ }
@@ -175,6 +175,7 @@
175
175
  --base-line-height-tight: #{$base-line-height-tight};
176
176
  --base-line-height-normal: #{$base-line-height-normal};
177
177
  --base-line-height-relaxed: #{$base-line-height-relaxed};
178
+ --base-list-bullet-type: #{$base-list-bullet-type};
178
179
 
179
180
  // === Border Radius ===
180
181
  --base-border-radius-sm: #{$base-border-radius-sm};
@@ -243,6 +244,11 @@
243
244
  --base-icon-bell: #{$base-icon-bell};
244
245
  // user = person. Consumed by pure-admin's --pa-icon-user.
245
246
  --base-icon-user: #{$base-icon-user};
247
+ // download = tray + down arrow; link = chain; external-link = arrow-out-of-box.
248
+ // Consumed by pure-admin's --pa-icon-download / -link / -external-link.
249
+ --base-icon-download: #{$base-icon-download};
250
+ --base-icon-link: #{$base-icon-link};
251
+ --base-icon-external-link: #{$base-icon-external-link};
246
252
 
247
253
  // === Status / severity icons — shared toast/alert/callout/notification set ===
248
254
  // info = circle-i, success = circle-check, warning = triangle-alert,
@@ -1,134 +1,154 @@
1
- // @keenmate/pure-css — reset & base element styling ("reboot")
2
- // ============================================================================
3
- // The foundation's reset layer. Establishes the 10px rem base that EVERY
4
- // pure-css rem value assumes (see variables/_typography.scss — `$font-size-base:
5
- // 1.6rem` is 16px only when the root is 10px), a border-box reset, and neutral
6
- // base styling for standard HTML elements (headings, paragraphs, links, lists,
7
- // blockquotes, rules, the body font/colour). Analogous to Bootstrap's Reboot.
8
- //
9
- // This lives in pure-css — not in a consuming app — because the 10px base is
10
- // part of the foundation's sizing contract: without it, a standalone consumer
11
- // inherits the browser's 16px root and every rem renders 1.6x too large. Link
12
- // it (or the full `pure-css.css` bundle) and the scale just works.
13
- //
14
- // App-specific base rules (the admin dashboard's decorative body background,
15
- // sidebar overflow handling) intentionally stay in pure-admin-core; a generic
16
- // foundation shouldn't impose them on every consumer.
17
- // ============================================================================
18
-
19
- @use 'variables/index' as *;
20
-
21
- // 10px rem base for intuitive sizing (1rem = 10px)
22
- // This makes calculations simple: 1.5rem = 15px, 3.5rem = 35px
23
- html {
24
- font-size: 10px;
25
- }
26
-
27
- // Reset and base styles
28
- * {
29
- box-sizing: border-box;
30
- }
31
-
32
- // Standard HTML element spacing (using framework variables)
33
- // Headings
34
- h1, h2, h3, h4, h5, h6 {
35
- margin: $heading-margin-top 0 $heading-margin-bottom 0;
36
- padding: 0;
37
- }
38
-
39
- // Paragraphs
40
- p {
41
- margin: $paragraph-margin-top 0 $paragraph-margin-bottom 0;
42
- padding: 0;
43
- }
44
-
45
- // Links — global default. Wrapped in :where() so specificity is 0,
46
- // letting component scopes (alerts, navbar, sidebar) override with even a
47
- // single class without fighting the pseudo-class specificity raise that
48
- // `a:hover` / `a:visited` would otherwise add (0,1,1 vs a class's 0,1,0).
49
- :where(a) {
50
- color: var(--pc-link-color);
51
- text-decoration: underline;
52
- }
53
-
54
- :where(a:hover) {
55
- color: var(--pc-link-color-hover);
56
- }
57
-
58
- :where(a:visited) {
59
- color: var(--pc-link-color-visited);
60
- }
61
-
62
- // Lists - styled lists (default browser styling)
63
- ul, ol {
64
- margin: $list-margin-top 0 $list-margin-bottom 0;
65
- padding: 0;
66
- padding-inline-start: $list-padding-left; // RTL: flips to right
67
-
68
- li {
69
- margin-bottom: $list-item-margin-bottom;
70
- }
71
- }
72
-
73
- // Lists - unstyled (for navigation, etc.)
74
- ul.unstyled, ol.unstyled {
75
- list-style: none;
76
- padding-inline-start: 0; // RTL: flips to right
77
-
78
- li {
79
- margin-bottom: 0;
80
- }
81
- }
82
-
83
- // Definition lists
84
- dl {
85
- margin: $list-margin-top 0 $list-margin-bottom 0;
86
- padding: 0;
87
- }
88
-
89
- dd {
90
- margin: 0;
91
- padding: 0;
92
- }
93
-
94
- // Blockquote
95
- blockquote {
96
- margin: $blockquote-margin-top 0 $blockquote-margin-bottom 0;
97
- padding-inline-start: $blockquote-padding-left; // RTL: flips to right
98
- }
99
-
100
- // Pre/Code blocks
101
- pre {
102
- overflow-x: auto;
103
- }
104
-
105
- // Horizontal rule
106
- hr {
107
- margin: $hr-margin-top 0 $hr-margin-bottom 0;
108
- }
109
-
110
- // Figure
111
- figure {
112
- margin: $figure-margin-top 0 $figure-margin-bottom 0;
113
- padding: 0;
114
- }
115
-
116
- body {
117
- margin: 0;
118
- padding: 0;
119
- font-family: var(--base-font-family);
120
- font-size: 1.6rem; // 16px default text (with 10px rem base)
121
- color: var(--pc-text-color-1);
122
- background-color: var(--pc-page-bg);
123
- line-height: $line-height-base;
124
- }
125
-
126
- // Ensure form elements and labels inherit theme font and size instead of browser defaults
127
- button,
128
- input,
129
- select,
130
- textarea,
131
- label {
132
- font-family: inherit;
133
- font-size: inherit;
134
- }
1
+ // @keenmate/pure-css — reset & base element styling ("reboot")
2
+ // ============================================================================
3
+ // The foundation's reset layer. Establishes the 10px rem base that EVERY
4
+ // pure-css rem value assumes (see variables/_typography.scss — `$font-size-base:
5
+ // 1.6rem` is 16px only when the root is 10px), a border-box reset, and neutral
6
+ // base styling for standard HTML elements (headings, paragraphs, links, lists,
7
+ // blockquotes, rules, the body font/colour). Analogous to Bootstrap's Reboot.
8
+ //
9
+ // This lives in pure-css — not in a consuming app — because the 10px base is
10
+ // part of the foundation's sizing contract: without it, a standalone consumer
11
+ // inherits the browser's 16px root and every rem renders 1.6x too large. Link
12
+ // it (or the full `pure-css.css` bundle) and the scale just works.
13
+ //
14
+ // App-specific base rules (the admin dashboard's decorative body background,
15
+ // sidebar overflow handling) intentionally stay in pure-admin-core; a generic
16
+ // foundation shouldn't impose them on every consumer.
17
+ // ============================================================================
18
+
19
+ @use 'variables/index' as *;
20
+
21
+ // 10px rem base for intuitive sizing (1rem = 10px)
22
+ // This makes calculations simple: 1.5rem = 15px, 3.5rem = 35px
23
+ html {
24
+ font-size: 10px;
25
+ }
26
+
27
+ // Reset and base styles
28
+ * {
29
+ box-sizing: border-box;
30
+ }
31
+
32
+ // Standard HTML element spacing (using framework variables)
33
+ // Headings
34
+ h1, h2, h3, h4, h5, h6 {
35
+ margin: $heading-margin-top 0 $heading-margin-bottom 0;
36
+ padding: 0;
37
+ }
38
+
39
+ // Paragraphs
40
+ p {
41
+ margin: $paragraph-margin-top 0 $paragraph-margin-bottom 0;
42
+ padding: 0;
43
+ }
44
+
45
+ // Links — global default. Wrapped in :where() so specificity is 0,
46
+ // letting component scopes (alerts, navbar, sidebar) override with even a
47
+ // single class without fighting the pseudo-class specificity raise that
48
+ // `a:hover` / `a:visited` would otherwise add (0,1,1 vs a class's 0,1,0).
49
+ :where(a) {
50
+ color: var(--pc-link-color);
51
+ text-decoration: underline;
52
+ }
53
+
54
+ :where(a:hover) {
55
+ color: var(--pc-link-color-hover);
56
+ }
57
+
58
+ :where(a:visited) {
59
+ color: var(--pc-link-color-visited);
60
+ }
61
+
62
+ // Lists - styled lists (default browser styling)
63
+ ul, ol {
64
+ margin: $list-margin-top 0 $list-margin-bottom 0;
65
+ padding: 0;
66
+ padding-inline-start: $list-padding-left; // RTL: flips to right
67
+
68
+ li {
69
+ margin-bottom: $list-item-margin-bottom;
70
+ }
71
+ }
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
+
93
+ // Lists - unstyled (for navigation, etc.)
94
+ ul.unstyled, ol.unstyled {
95
+ list-style: none;
96
+ padding-inline-start: 0; // RTL: flips to right
97
+
98
+ li {
99
+ margin-bottom: 0;
100
+ }
101
+ }
102
+
103
+ // Definition lists
104
+ dl {
105
+ margin: $list-margin-top 0 $list-margin-bottom 0;
106
+ padding: 0;
107
+ }
108
+
109
+ dd {
110
+ margin: 0;
111
+ padding: 0;
112
+ }
113
+
114
+ // Blockquote
115
+ blockquote {
116
+ margin: $blockquote-margin-top 0 $blockquote-margin-bottom 0;
117
+ padding-inline-start: $blockquote-padding-left; // RTL: flips to right
118
+ }
119
+
120
+ // Pre/Code blocks
121
+ pre {
122
+ overflow-x: auto;
123
+ }
124
+
125
+ // Horizontal rule
126
+ hr {
127
+ margin: $hr-margin-top 0 $hr-margin-bottom 0;
128
+ }
129
+
130
+ // Figure
131
+ figure {
132
+ margin: $figure-margin-top 0 $figure-margin-bottom 0;
133
+ padding: 0;
134
+ }
135
+
136
+ body {
137
+ margin: 0;
138
+ padding: 0;
139
+ font-family: var(--base-font-family);
140
+ font-size: 1.6rem; // 16px default text (with 10px rem base)
141
+ color: var(--pc-text-color-1);
142
+ background-color: var(--pc-page-bg);
143
+ line-height: $line-height-base;
144
+ }
145
+
146
+ // Ensure form elements and labels inherit theme font and size instead of browser defaults
147
+ button,
148
+ input,
149
+ select,
150
+ textarea,
151
+ label {
152
+ font-family: inherit;
153
+ font-size: inherit;
154
+ }
@@ -283,6 +283,10 @@ $base-line-height-tight: 1.25 !default;
283
283
  $base-line-height-normal: 1.5 !default;
284
284
  $base-line-height-relaxed: 1.75 !default;
285
285
 
286
+ // List marker — default bullet/number for ul, ol (disc | circle | square | none
287
+ // | decimal | …). Consumed on the base list reboot with an inline `disc` fallback.
288
+ $base-list-bullet-type: disc !default;
289
+
286
290
  // =============================================================================
287
291
  // BORDER RADIUS
288
292
  // Border radius sizes (unitless multipliers for x10px base)
@@ -383,6 +387,12 @@ $base-icon-settings: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2
383
387
  $base-icon-bell: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M10.268 21a2 2 0 0 0 3.464 0%22/%3E%3Cpath d=%22M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326%22/%3E%3C/svg%3E") !default;
384
388
  // user = person (Lucide user): profile trigger button / avatar placeholder.
385
389
  $base-icon-user: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2%22/%3E%3Ccircle cx=%2212%22 cy=%227%22 r=%224%22/%3E%3C/svg%3E") !default;
390
+ // download = tray + down arrow (Lucide download): save-to-disk / export. link =
391
+ // chain (Lucide link): hyperlink / attach-URL; external-link = diagonal
392
+ // arrow-out-of-box (Lucide external-link): opens in a new tab / leaves the app.
393
+ $base-icon-download: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M12 15V3%22/%3E%3Cpath d=%22M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4%22/%3E%3Cpath d=%22m7 10 5 5 5-5%22/%3E%3C/svg%3E") !default;
394
+ $base-icon-link: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71%22/%3E%3Cpath d=%22M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71%22/%3E%3C/svg%3E") !default;
395
+ $base-icon-external-link: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M15 3h6v6%22/%3E%3Cpath d=%22M10 14 21 3%22/%3E%3Cpath d=%22M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6%22/%3E%3C/svg%3E") !default;
386
396
  // Status / severity icons (shared toast/alert/callout/notification set): info =
387
397
  // circle-i, success = circle-check, warning = triangle-alert, danger = circle-x.
388
398
  $base-icon-info: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23000%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Ccircle cx=%2212%22 cy=%2212%22 r=%2210%22/%3E%3Cpath d=%22M12 16v-4%22/%3E%3Cpath d=%22M12 8h.01%22/%3E%3C/svg%3E") !default;