@djangocfg/ui-core 2.1.462 → 2.1.464

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/ui-core",
3
- "version": "2.1.462",
3
+ "version": "2.1.464",
4
4
  "description": "Pure React UI component library without Next.js dependencies - for Electron, Vite, CRA apps",
5
5
  "keywords": [
6
6
  "ui-components",
@@ -127,7 +127,7 @@
127
127
  "check": "tsc --noEmit"
128
128
  },
129
129
  "peerDependencies": {
130
- "@djangocfg/i18n": "^2.1.462",
130
+ "@djangocfg/i18n": "^2.1.464",
131
131
  "consola": "^3.4.2",
132
132
  "lucide-react": "^0.545.0",
133
133
  "moment": "^2.30.1",
@@ -205,8 +205,8 @@
205
205
  "@chenglou/pretext": "*"
206
206
  },
207
207
  "devDependencies": {
208
- "@djangocfg/i18n": "^2.1.462",
209
- "@djangocfg/typescript-config": "^2.1.462",
208
+ "@djangocfg/i18n": "^2.1.464",
209
+ "@djangocfg/typescript-config": "^2.1.464",
210
210
  "@types/node": "^25.2.3",
211
211
  "@types/react": "^19.2.15",
212
212
  "@types/react-dom": "^19.2.3",
@@ -123,6 +123,11 @@ export function renderItems(
123
123
  key={option.id}
124
124
  value={option.value}
125
125
  disabled={option.disabled}
126
+ onSelect={(event) => {
127
+ // closeOnSelect=false → keep the menu open so the selection
128
+ // can reveal more of the same menu (e.g. an engine preview).
129
+ if (item.closeOnSelect === false) event.preventDefault();
130
+ }}
126
131
  >
127
132
  <MenuIndicatorRow
128
133
  icon={option.icon}
@@ -66,6 +66,11 @@ export interface MenuRadioGroup {
66
66
  value: string;
67
67
  onValueChange: (value: string) => void;
68
68
  options: MenuRadioOption[];
69
+ /** Keep the menu OPEN after a selection (default: false = close, Radix's
70
+ * default). Use for a radio group whose pick reveals more of the SAME menu
71
+ * (e.g. an engine row that previews that engine's models below it) rather
72
+ * than being a terminal choice. */
73
+ closeOnSelect?: boolean;
69
74
  }
70
75
 
71
76
  /** Visual divider. */
@@ -37,6 +37,9 @@ styles/
37
37
  There are deliberately no TypeScript color maps and no runtime CSS generator.
38
38
  Do not add a second palette in React or TypeScript.
39
39
 
40
+ `styles/presets/` contains only the TypeScript preset names and ordering used by
41
+ the public API. The actual values always live in `styles/css/presets/*.css`.
42
+
40
43
  ## Consumer contract
41
44
 
42
45
  Import the golden path first, then exactly one product preset:
@@ -62,6 +65,69 @@ For a product-specific adjustment, add a small override after the preset:
62
65
  Do not create a `theme-preset.ts`, append a `<style>` tag, or call a token
63
66
  builder during application startup.
64
67
 
68
+ ### Import order
69
+
70
+ Keep the application entrypoint minimal and deterministic:
71
+
72
+ ```css
73
+ @import "@djangocfg/ui-core/styles/full";
74
+ @plugin "tailwindcss-animate";
75
+ @import "@djangocfg/ui-core/styles/presets/macos";
76
+ @import "@djangocfg/layouts/styles";
77
+ @import "@djangocfg/ui-tools/styles";
78
+ ```
79
+
80
+ `full.css` already imports Tailwind, the theme tokens, base styles, and
81
+ ui-core utilities. Do not add a second `@import "tailwindcss"`, `base.css`,
82
+ or `utilities.css` in the consumer. Load the preset after `full.css`, so its
83
+ `:root` and `.dark` variables win over defaults. Keep application overrides
84
+ after the preset.
85
+
86
+ The `tailwindcss-animate` plugin is registered once by the consumer. It
87
+ provides classes such as `animate-in`, `fade-in-0`, and `zoom-in-95`; the
88
+ package's component source uses those classes but does not register the
89
+ plugin itself.
90
+
91
+ ### Tailwind source scanning
92
+
93
+ `css/sources.css` is part of the `full` entry and must scan the package source
94
+ root from its own location:
95
+
96
+ ```css
97
+ @source "../../**/*.{ts,tsx}";
98
+ ```
99
+
100
+ This is important. Scanning only `../` scans `src/styles` and silently drops
101
+ utilities used by components, including `bg-overlay` and state/animation
102
+ utilities. A consumer may add extra `@source` directives for local packages,
103
+ but should not replace the ui-core source directive.
104
+
105
+ ### Overlays and glass surfaces
106
+
107
+ Dialog, alert-dialog, sheet, and drawer backdrops use the semantic
108
+ `bg-overlay` class. The class gets its color from `--overlay` and its frosting
109
+ from `--overlay-blur` (the default is `5px`):
110
+
111
+ ```css
112
+ .bg-overlay {
113
+ background: var(--overlay);
114
+ backdrop-filter: blur(var(--overlay-blur));
115
+ }
116
+ ```
117
+
118
+ Glass surfaces must have a translucent background; an opaque `bg-card` or
119
+ `bg-popover` makes the blur invisible. A dropdown rendered inside an ancestor
120
+ that already has `backdrop-filter` is also unable to blur the page behind that
121
+ ancestor because it becomes a backdrop root. PublicLayout desktop dropdowns
122
+ are therefore rendered through a body portal and positioned from the trigger.
123
+ Use the same pattern for new floating surfaces that must blur content outside
124
+ their parent stacking context.
125
+
126
+ For custom glass utilities, prefer a Tailwind utility such as
127
+ `backdrop-blur-[5px]` when the consuming build must emit the standard
128
+ `backdrop-filter` declaration. Keep the visual token (`--overlay-blur`) in
129
+ CSS rather than duplicating a pixel value in React.
130
+
65
131
  ## Token format
66
132
 
67
133
  Color variables are complete CSS colors, never bare HSL triplets:
@@ -86,7 +152,7 @@ Typography variables are ordinary CSS values:
86
152
 
87
153
  ## Preset rules
88
154
 
89
- - Presets are authored directly in `presets/css/`.
155
+ - Presets are authored directly in `styles/css/presets/`.
90
156
  - Every preset must define valid `hsl(...)`, `color-mix(...)`, or other complete
91
157
  CSS color values.
92
158
  - Keep light and dark pairs together in the same file.
@@ -104,3 +170,18 @@ pnpm check
104
170
  At the consumer, build the app that imports the preset and verify both modes.
105
171
  The important invariant is that changing a preset requires editing one CSS
106
172
  file, and no React runtime code is involved in applying it.
173
+
174
+ For a local cross-repository change, use the consumer's sync command and
175
+ restart its dev server afterward:
176
+
177
+ ```bash
178
+ pnpm sync:cfg:one ui-core
179
+ pnpm sync:cfg:one layouts
180
+ pnpm sync:cfg:one i18n # required peer when ui-core is synced locally
181
+ rm -rf apps/web/.next
182
+ ```
183
+
184
+ Do not delete `pnpm-lock.yaml` to force a package update. Update the package
185
+ range with pnpm, then let the lockfile record the resolved version. A clean
186
+ install restores published packages and therefore requires publishing a new
187
+ package version for source changes to survive.
@@ -23,7 +23,7 @@
23
23
  * / sheet) blurs the page behind it. Theme-agnostic (same both modes);
24
24
  * a preset can override for a heavier/lighter frost, or set `0px` to disable
25
25
  * the blur while keeping the `--overlay` dimming scrim. 2px = a subtle frost. */
26
- --overlay-blur: 2px;
26
+ --overlay-blur: 5px;
27
27
 
28
28
  /* Typography tokens — overridable per preset */
29
29
  --font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
@@ -6,4 +6,5 @@
6
6
  *
7
7
  * Scans all TypeScript files recursively from package root.
8
8
  */
9
- @source "../**/*.{ts,tsx}";
9
+ /* This file lives in src/styles/css; ../../ reaches the package src root. */
10
+ @source "../../**/*.{ts,tsx}";
@@ -34,6 +34,8 @@
34
34
  /* Recessed surface — below the page (Claude bg-200), for input rest / chips. */
35
35
  --muted: hsl(30 3.3% 11.8%);
36
36
  --muted-foreground: hsl(48 5% 59%);
37
+ /* Neutral interaction surface: a quiet lift above the current dark page. */
38
+ --surface-hover: color-mix(in oklab, var(--card) 96%, var(--foreground));
37
39
  /* Hover/active surface (rails, menus, tabs) — a quiet warm lift above the page. */
38
40
  --accent: hsl(48 3% 24%);
39
41
  --accent-foreground: hsl(48 33% 97%);
@@ -24,6 +24,10 @@
24
24
  --secondary-foreground: hsl(0 0% 98%);
25
25
  --muted: hsl(0 0% 96%);
26
26
  --muted-foreground: hsl(0 0% 45%);
27
+ /* Neutral interaction surface: a quiet step below the current light canvas.
28
+ * It deliberately keys off --background, not white --card, so hover remains
29
+ * visible on translucent menus and on plain pages alike. */
30
+ --surface-hover: color-mix(in oklab, var(--background) 96%, var(--foreground));
27
31
  /* Neutral hover/active surface — quiet gray lift, no hue tint
28
32
  * (Claude/macOS settings convention). */
29
33
  --accent: hsl(0 0% 94%);
@@ -38,6 +38,7 @@
38
38
  --color-secondary-foreground: var(--secondary-foreground);
39
39
  --color-muted: var(--muted);
40
40
  --color-muted-foreground: var(--muted-foreground);
41
+ --color-surface-hover: var(--surface-hover);
41
42
  --color-accent: var(--accent);
42
43
  --color-accent-foreground: var(--accent-foreground);
43
44
  --color-destructive: var(--destructive);
@@ -10,3 +10,8 @@
10
10
  .rounded-control {
11
11
  border-radius: var(--radius-control);
12
12
  }
13
+
14
+ /* Static package utility: do not depend on a consumer Tailwind source scan. */
15
+ .surface-hover:hover {
16
+ background-color: var(--surface-hover);
17
+ }
@@ -55,3 +55,19 @@
55
55
  -webkit-backdrop-filter: blur(8px) saturate(160%);
56
56
  background-color: color-mix(in oklab, var(--background) 80%, transparent);
57
57
  }
58
+
59
+ /**
60
+ * PublicLayout desktop navigation dropdown.
61
+ * Keep this as a package utility instead of relying on a consumer's Tailwind
62
+ * source scan: the layout is distributed code, while the dropdown must still
63
+ * frost whatever page is underneath it.
64
+ */
65
+ .nav-dropdown-glass {
66
+ backdrop-filter: blur(var(--overlay-blur, 5px)) saturate(150%);
67
+ -webkit-backdrop-filter: blur(var(--overlay-blur, 5px)) saturate(150%);
68
+ background-color: color-mix(in oklab, var(--background) 55%, transparent);
69
+ }
70
+
71
+ .dark .nav-dropdown-glass {
72
+ background-color: color-mix(in oklab, var(--card) 55%, transparent);
73
+ }