@djangocfg/ui-core 2.1.444 → 2.1.446

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.444",
3
+ "version": "2.1.446",
4
4
  "description": "Pure React UI component library without Next.js dependencies - for Electron, Vite, CRA apps",
5
5
  "keywords": [
6
6
  "ui-components",
@@ -116,7 +116,7 @@
116
116
  "check": "tsc --noEmit"
117
117
  },
118
118
  "peerDependencies": {
119
- "@djangocfg/i18n": "^2.1.444",
119
+ "@djangocfg/i18n": "^2.1.446",
120
120
  "consola": "^3.4.2",
121
121
  "lucide-react": "^0.545.0",
122
122
  "moment": "^2.30.1",
@@ -194,8 +194,8 @@
194
194
  "@chenglou/pretext": "*"
195
195
  },
196
196
  "devDependencies": {
197
- "@djangocfg/i18n": "^2.1.444",
198
- "@djangocfg/typescript-config": "^2.1.444",
197
+ "@djangocfg/i18n": "^2.1.446",
198
+ "@djangocfg/typescript-config": "^2.1.446",
199
199
  "@types/node": "^25.2.3",
200
200
  "@types/react": "^19.2.15",
201
201
  "@types/react-dom": "^19.2.3",
@@ -136,7 +136,9 @@ const ResizableHandle = ({
136
136
  return (
137
137
  <div
138
138
  className={cn(
139
- "bg-border w-px",
139
+ // Separator between panels → `bg-divider` (soft hairline), not the
140
+ // opaque `bg-border` outline weight, so a resize seam stays quiet.
141
+ "bg-divider w-px",
140
142
  "data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full",
141
143
  className
142
144
  )}
@@ -147,7 +149,7 @@ const ResizableHandle = ({
147
149
  return (
148
150
  <ResizablePrimitive.PanelResizeHandle
149
151
  className={cn(
150
- "relative flex items-center justify-center bg-border",
152
+ "relative flex items-center justify-center bg-divider",
151
153
  "w-px h-full",
152
154
  "hover:bg-primary/20 active:bg-primary/30",
153
155
  "transition-colors",
@@ -68,8 +68,8 @@ This makes opacity modifiers (`bg-card/40`, `border-foreground/20`) resolve thro
68
68
  | `bg-primary` / `text-primary-foreground` | `--primary` | Brand CTA (filled buttons, links) — cyan |
69
69
  | `bg-secondary` / `text-secondary-foreground` | `--secondary` | Neutral filled controls |
70
70
  | `bg-destructive` / `text-destructive-foreground` | `--destructive` | Error / delete filled controls |
71
- | `border-border` | `--border` | Card outlines, control borders |
72
- | `border-divider` / `.divider-b` | `--divider` | **Hairline between rows** — deliberately *lighter than `--card`* so it stays visible on elevated surfaces (a `--border` line vanishes on a card) |
71
+ | `border-border` | `--border` | **Outlines only** — card frames, control/input edges. *Not* for separators (see Presets § Border vs divider) |
72
+ | `border-divider` / `.divider-b` / `bg-divider` | `--divider` | **All separators** — columns, header `border-b`, list rows, resize handles. A soft hairline (translucent on dark themes) so the chrome never reads as a heavy grid |
73
73
  | `bg-overlay` | `--overlay` | Modal scrim / backdrop behind dialogs, drawers, sheets — black scrim in both themes, the token owns the opacity |
74
74
  | `bg-input` | `--input` | Input **fill** — a notch off the panel so fields read as real controls (not flush holes). The input *border* uses `--border`, not `--input` |
75
75
  | `ring-ring` | `--ring` | Focus rings, selected outlines — **blue** (system-accent feel), independent of the cyan brand |
@@ -299,6 +299,35 @@ Two families, with different coverage by design:
299
299
  | `dense` | modifier | Smaller radius (0.25rem) — data-heavy admin UIs |
300
300
  | `high-contrast` | modifier | A11y boost — stronger borders, harder text, pure canvas |
301
301
 
302
+ #### Border vs divider — outline weight vs translucent hairline
303
+
304
+ `--border` and `--divider` are **two different roles**, not two shades of one:
305
+
306
+ - **`--border`** — an OUTLINE: opaque, control-weight. Card frames, input
307
+ edges, panel outlines. Use `border-border` / `border border-border`.
308
+ - **`--divider`** — a SEPARATOR: a soft hairline between things. Shell columns,
309
+ header `border-b` rules, list rows, resize handles. Use `border-divider` /
310
+ `.divider-b` / `bg-divider`, or `divide-*` on a `divide-y` stack.
311
+
312
+ On the **dark** themes the separator token is now a **translucent** hairline —
313
+ `hsl(H S 46-48% / 0.18)` — mirroring Apple's own `rgba(84,84,88,0.36)` approach:
314
+ a light grey at low alpha that *dissolves into whatever sits behind it* instead
315
+ of a fixed opaque line. This is deliberate. An opaque separator (even a dim one)
316
+ read as a hard grid on a near-black canvas — every column edge and header rule
317
+ looked heavy. A translucent hairline self-adapts: heavier where it crosses an
318
+ elevated card, lighter on the page. Every dark preset carries it (`macos`,
319
+ `ios`, `windows`, `dense`, `soft`, and the base `dark.css` behind
320
+ `default`/`django-cfg`); **`high-contrast` keeps an opaque divider on purpose**
321
+ (a11y wants the harder line). Light themes keep an opaque divider too — a
322
+ translucent line on white gains nothing.
323
+
324
+ The alpha was tuned by eye in a live cmdop-web session (0.18 is quiet-but-present;
325
+ lower starts to vanish on the page).
326
+
327
+ **If a dark surface looks too contrasty**, the culprit is almost always a
328
+ column/row/header separator wrongly drawn with `--border` (the outline weight)
329
+ instead of `--divider` — move it to `border-divider` / `var(--divider)`.
330
+
302
331
  ### Apply a preset
303
332
 
304
333
  ```tsx
@@ -23,7 +23,7 @@ export const densePreset: ThemePreset = {
23
23
  radius: '0.25rem',
24
24
  border: 'hsl(0 0% 24%)',
25
25
  input: 'hsl(0 0% 24%)',
26
- divider: 'hsl(0 0% 18%)',
26
+ divider: 'hsl(0 0% 46% / 0.18)', // translucent hairline — dissolves into the page
27
27
  muted: 'hsl(0 0% 12%)',
28
28
  card: 'hsl(0 0% 10%)',
29
29
  accent: 'hsl(0 0% 14%)',
@@ -78,7 +78,7 @@ export const iosPreset: ThemePreset = {
78
78
  border: 'hsl(240 5% 27%)', // raised so outlines read on the dark page
79
79
  input: 'hsl(240 5% 22%)',
80
80
  ring: 'hsl(211 100% 55%)',
81
- divider: 'hsl(240 5% 21%)', // hairline, softer than border
81
+ divider: 'hsl(240 5% 48% / 0.18)', // translucent hairline dissolves into the page
82
82
  radius: '0.75rem',
83
83
  // Modal scrim — lighter than base 0.7 so the dark page still reads behind.
84
84
  overlay: 'hsl(0 0% 0% / 0.55)',
@@ -53,9 +53,10 @@ export const macosPreset: ThemePreset = {
53
53
  destructive: 'hsl(2 100% 59%)',
54
54
  'destructive-foreground': 'hsl(0 0% 100%)',
55
55
  // Apple opaque separator: rgba(60,60,67,0.29) on white ≈ #C6C6C8 → HSL 240 3% 78%.
56
- // Nudged a touch darker (78→74) so control/panel outlines actually read on
57
- // white cards the pure hairline vanished on elevated surfaces.
58
- border: 'hsl(240 3% 74%)',
56
+ // Kept at the Apple hairline value (78%). An earlier build nudged this darker
57
+ // (78→74) to force outlines onto white cards, but that over-contrasted every
58
+ // panel/header `border-b` on the grouped canvas — back to the HIG hairline.
59
+ border: 'hsl(240 3% 78%)',
59
60
  input: 'hsl(240 8% 93%)',
60
61
  // Row hairline — a touch lighter than border so it reads on white cards
61
62
  divider: 'hsl(240 4% 83%)',
@@ -128,14 +129,22 @@ export const macosPreset: ThemePreset = {
128
129
  // systemRed dark #FF453A
129
130
  destructive: 'hsl(3 100% 62%)',
130
131
  'destructive-foreground': 'hsl(0 0% 100%)',
131
- // Separator dark: rgba(84,84,88,0.36). Raised 22→28 Apple's hairline is
132
- // authored for content-on-content, but on the near-black #141414 page it was
133
- // invisible, so control/panel outlines had no edge. 28 keeps it a hairline
134
- // while actually drawing against the dark canvas.
135
- border: 'hsl(240 3% 28%)',
132
+ // Control/panel OUTLINE input & card frames, not separators. Opaque 22%
133
+ // reads cleanly as a control edge on card (L15) surfaces. Structural
134
+ // separators (shell columns, headers, list rows) do NOT use this they use
135
+ // `--divider`, which is a softer translucent hairline (see below), so the
136
+ // outline weight here never turns the chrome into a hard grid.
137
+ border: 'hsl(240 3% 22%)',
136
138
  input: 'hsl(240 3% 22%)',
137
- // Row hairline — softer than border so dark rows don't read as a hard rule
138
- divider: 'hsl(240 3% 22%)',
139
+ // Separator hairline — TRANSLUCENT, mirroring Apple's rgba(84,84,88,0.36):
140
+ // a light grey at low alpha that dissolves into whatever sits behind it
141
+ // instead of a fixed opaque line. This is the token for ALL structural
142
+ // separators — shell columns (rail↔list↔chat), header `border-b` rules, and
143
+ // list-row hairlines — deliberately softer than the opaque `--border`
144
+ // outline so the chrome never reads as a hard grid on the near-black canvas.
145
+ // 46% L @ 0.18 alpha picked live in cmdop-web: a quiet, self-adapting
146
+ // hairline (heavier over an elevated card, lighter on the page).
147
+ divider: 'hsl(240 4% 46% / 0.18)',
139
148
  ring: 'hsl(211 100% 58%)',
140
149
  radius: '0.625rem',
141
150
  // Modal scrim — a touch lighter than the base 0.7. The page is already near
@@ -149,8 +158,9 @@ export const macosPreset: ThemePreset = {
149
158
  'sidebar-primary-foreground': 'hsl(0 0% 100%)',
150
159
  'sidebar-accent': 'hsl(211 22% 16%)',
151
160
  'sidebar-accent-foreground': 'hsl(211 100% 72%)',
152
- // Raised 15→22 to match --border: the sidebar edge was lost against the
153
- // near-black rail + page.
161
+ // 22 the sidebar rail floor is #0D0D0F (L5), darker than the page (L8), so
162
+ // its edge needs a touch more lift than the page-calibrated `--border` (18)
163
+ // to read at all. Still a hairline, not the hard rule an outline weight draws.
154
164
  'sidebar-border': 'hsl(240 3% 22%)',
155
165
  'sidebar-ring': 'hsl(211 100% 58%)',
156
166
  // Chart: brighter variants for contrast on dark
@@ -39,7 +39,7 @@ export const softPreset: ThemePreset = {
39
39
  'accent-foreground': 'hsl(0 0% 96%)',
40
40
  border: 'hsl(240 5% 20%)',
41
41
  input: 'hsl(240 5% 20%)',
42
- divider: 'hsl(240 5% 16%)',
42
+ divider: 'hsl(240 5% 48% / 0.18)', // translucent hairline — dissolves into the page
43
43
  radius: '1rem',
44
44
  'sidebar-background': 'hsl(240 6% 6%)',
45
45
  'sidebar-accent': 'hsl(240 5% 14%)',
@@ -115,7 +115,7 @@ export const windowsPreset: ThemePreset = {
115
115
  border: 'hsl(0 0% 28%)',
116
116
  input: 'hsl(0 0% 24%)',
117
117
  // Hairline between rows — softer than border
118
- divider: 'hsl(0 0% 22%)',
118
+ divider: 'hsl(0 0% 46% / 0.18)', // translucent hairline — dissolves into the page
119
119
  ring: 'hsl(200 100% 69%)',
120
120
  // Fluent SmokeFillColorDefault dark — dims the dark page behind the dialog.
121
121
  overlay: 'hsl(0 0% 0% / 0.55)',
@@ -44,9 +44,11 @@
44
44
  --border: hsl(48 3% 28%);
45
45
  /* Input surface — a notch above card so fields read as raised controls. */
46
46
  --input: hsl(48 2.5% 24%);
47
- /* Divider — hairline; slightly softer than --border so rows don't read as a
48
- * hard rule (Claude menus/rows). */
49
- --divider: hsl(48 3% 24%);
47
+ /* Divider — TRANSLUCENT hairline (Apple-style): a light warm-gray at low alpha
48
+ * that dissolves into whatever sits behind it, so structural separators
49
+ * (columns, headers, rows) stay quiet on the dark page instead of reading as a
50
+ * hard opaque rule. Backs default + django-cfg (they don't re-declare it). */
51
+ --divider: hsl(48 4% 46% / 0.18);
50
52
  /* Overlay — modal scrim / backdrop behind dialogs, drawers, sheets. Black in
51
53
  * both themes; slightly darker here so it still reads on the dark page. */
52
54
  --overlay: hsl(0 0% 0% / 0.7);