hazo_ui 4.8.0 → 4.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGE_LOG.md +121 -0
- package/README.md +85 -0
- package/dist/index.cjs +375 -174
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +88 -23
- package/dist/index.d.ts +88 -23
- package/dist/index.js +372 -175
- package/dist/index.js.map +1 -1
- package/dist/index.utils-DZVbQXFR.d.cts +20 -0
- package/dist/index.utils-DZVbQXFR.d.ts +20 -0
- package/dist/index.utils.cjs.map +1 -1
- package/dist/index.utils.d.cts +2 -10
- package/dist/index.utils.d.ts +2 -10
- package/dist/index.utils.js.map +1 -1
- package/dist/test-harness/index.cjs.map +1 -1
- package/dist/test-harness/index.js.map +1 -1
- package/package.json +10 -3
package/CHANGE_LOG.md
CHANGED
|
@@ -5,6 +5,127 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## v4.10.0 (2026-07-09)
|
|
9
|
+
|
|
10
|
+
### New
|
|
11
|
+
- **`Logo`, `AppHeader`, `AppFooter` chrome components** (framework-neutral,
|
|
12
|
+
`"use client"`) — consume hazo_theme's `BrandIdentity` contract (type-only
|
|
13
|
+
import) plus the new `footer-public-*`/`footer-app-*` chrome tokens:
|
|
14
|
+
- `Logo({ logoUrl?, logoUrlDark?, appTitle?, href?, height?, className?,
|
|
15
|
+
imgClassName? })` — renders the light/dark logo image (swapped via
|
|
16
|
+
`dark:hidden`/`dark:block`), falling back to `appTitle` as text when no
|
|
17
|
+
`logoUrl` is set. Prop names intentionally mirror `BrandIdentity`'s fields
|
|
18
|
+
so a caller can spread an identity object directly: `<Logo {...identity}
|
|
19
|
+
/>`.
|
|
20
|
+
- `AppHeader({ identity?, homeHref?, navItems?, actions?, className? })` — a
|
|
21
|
+
`bg-navbar`/`text-navbar-fg` header bar wrapping `Logo` plus nav/actions
|
|
22
|
+
slots.
|
|
23
|
+
- `AppFooter({ variant: 'public' | 'app', footer?, identity?, className? })`
|
|
24
|
+
— `'app'` renders the thin `bg-footer-app` strip (copyright + one link
|
|
25
|
+
row); `'public'` renders the taller multi-column `bg-footer-public` block
|
|
26
|
+
(brand row, link columns, social links), reading from `footer` or falling
|
|
27
|
+
back to `identity.footer[variant]`.
|
|
28
|
+
- All three are new exports from the package root; `hazo_theme` stays an
|
|
29
|
+
optional peer — the components don't import runtime code from it, only
|
|
30
|
+
the `BrandIdentity`/`FooterConfig` types.
|
|
31
|
+
- **`safeHref(url?: string): string | undefined`** exported from the package
|
|
32
|
+
root — scheme-allowlist for admin-configurable hrefs (`http://`, `https://`,
|
|
33
|
+
`mailto:`, or a same-origin `/path` that isn't protocol-relative `//host`;
|
|
34
|
+
anything else, including `javascript:`/`data:`, returns `undefined`). Every
|
|
35
|
+
`<a href>` sink inside the new chrome components (footer links, social
|
|
36
|
+
links) runs through it — XSS hardening for hrefs sourced from
|
|
37
|
+
admin-editable branding data.
|
|
38
|
+
- **`HazoUiDialog` header bar is now token-driven** — the header bar
|
|
39
|
+
background/foreground (previously hardcoded `#1e293b` background / white
|
|
40
|
+
text) now default to hazo_theme's `--dialog-header-bar-bg` /
|
|
41
|
+
`--dialog-header-bar-fg` tokens, and respect the existing per-variant
|
|
42
|
+
tinting (`headerColor`/`kind`) the same way the rest of the dialog does.
|
|
43
|
+
- **`HazoUiDialog` `kind` prop** (PRD hazo_theme §5.7) — orthogonal rendering/behavior
|
|
44
|
+
profile: `'form' | 'confirm' | 'status' | 'content'`. `kind` is a discriminated
|
|
45
|
+
union on `HazoUiDialogProps`: `title` is a required `string` for `'form'`/`'confirm'`,
|
|
46
|
+
and stays optional (defaulting to `"Action required"`) for `'status'`/`'content'`/
|
|
47
|
+
omitted — omitting `kind` entirely is byte-for-byte the pre-existing default
|
|
48
|
+
behavior (regression guard, verified via `npm run build` + `type-check`).
|
|
49
|
+
- `'form'` — comfortable body/label typography via the hazo_theme
|
|
50
|
+
`--dialog-body-size` / `--dialog-label-size` tokens.
|
|
51
|
+
- `'confirm'` — the compact centered-card layout previously hardcoded into
|
|
52
|
+
`HazoUiConfirmDialog` (see below).
|
|
53
|
+
- `'status'` — tinted header (via `--dialog-<variant>-bg/-fg`) with a single
|
|
54
|
+
acknowledge button (`showCancelButton=false`, `actionButtonText="OK"` by
|
|
55
|
+
default); `closeOnConfirm` defaults to `true` (self-closing) for this kind.
|
|
56
|
+
- `'content'` — unchanged sticky header/footer + scrollable body (this was
|
|
57
|
+
already the default structure).
|
|
58
|
+
- Added optional peer dependency `hazo_theme@^0.1.0` (`peerDependenciesMeta.hazo_theme.optional = true`).
|
|
59
|
+
hazo_ui does not import from hazo_theme; the `--dialog-*` CSS custom
|
|
60
|
+
properties referenced below only resolve when the CONSUMING app imports
|
|
61
|
+
`hazo_theme/tokens.css`.
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
- **`HazoUiConfirmDialog` is now a thin wrapper** over `<HazoUiDialog kind="confirm">`.
|
|
65
|
+
Its exported `HazoUiConfirmDialogProps` interface and `ConfirmDialogVariant` type
|
|
66
|
+
are UNCHANGED — zero prop-level breaking changes for existing consumers
|
|
67
|
+
(verified: `hazo_pay`'s `billing_admin_panel.tsx` and `hazo_config`'s
|
|
68
|
+
`app_config_list_editor.tsx` both still build with no changes on their end).
|
|
69
|
+
One documented behavior simplification: the old component allowed
|
|
70
|
+
independently-colored `accentColor` (border) vs. `confirmButtonColor` (button);
|
|
71
|
+
the new wrapper folds both into a single accent (`confirmButtonColor` wins if
|
|
72
|
+
both are set), since no known consumer relied on divergent values.
|
|
73
|
+
- **`VARIANT_PRESETS` (dialog) / `CONFIRM_VARIANT_PRESETS` (confirm dialog,
|
|
74
|
+
now deleted) hardcoded RGB → hazo_theme `--dialog-*` tokens.** This is a
|
|
75
|
+
**visual-only change** — flag it as a **major version bump** on the next
|
|
76
|
+
publish, since dialog/confirm-dialog appearance shifts for any consumer.
|
|
77
|
+
- Consumers that already import `hazo_theme/tokens.css` get the intended,
|
|
78
|
+
theme-consistent look automatically (dark/light + brand theme-sets).
|
|
79
|
+
- Consumers that do NOT import `hazo_theme/tokens.css` degrade gracefully:
|
|
80
|
+
an undefined CSS custom property used inside `hsl(var(--undefined-var))`
|
|
81
|
+
(or referenced directly, for the pre-wrapped `--dialog-<variant>-bg/-fg`
|
|
82
|
+
tokens) produces an invalid color value, which browsers simply ignore —
|
|
83
|
+
falling back to the previous/inherited value (e.g. transparent background,
|
|
84
|
+
inherited text color) rather than crashing or rendering `red`/broken
|
|
85
|
+
styles. Net effect: variant tinting silently disappears, dialogs still
|
|
86
|
+
render and function correctly. **Action for consumers wanting the
|
|
87
|
+
intended look: import `hazo_theme/tokens.css`.**
|
|
88
|
+
- hazo_theme exposes exactly one bg + one fg token per status (no separate
|
|
89
|
+
"header" vs. "description" shade), so the old two-tone split-header effect
|
|
90
|
+
is flattened to a single shade per variant.
|
|
91
|
+
- `kind="status"`/`kind="confirm"` at `variant="default"` (no per-status
|
|
92
|
+
token pair exists for "default") fall back to a neutral tint derived from
|
|
93
|
+
`--dialog-border` / `--dialog-fg` instead of leaving the header untinted.
|
|
94
|
+
|
|
95
|
+
## v4.9.0 (2026-07-06)
|
|
96
|
+
|
|
97
|
+
### New
|
|
98
|
+
- **Theme Kit** — packaged, SSR-safe dark/light theme using the shadcn
|
|
99
|
+
`.dark`-class convention (toggles a `dark` class on `<html>`). New exports:
|
|
100
|
+
- `HazoThemeProvider` — context provider that keeps `<html class="dark">` in
|
|
101
|
+
sync with the resolved theme. Props `defaultTheme` (`"light" | "dark" |
|
|
102
|
+
"system"`, default `"system"`) and `storageKey` (default `"theme"`).
|
|
103
|
+
`window`/`document` are only touched inside `useEffect`, so no hydration
|
|
104
|
+
mismatch.
|
|
105
|
+
- `useTheme()` — `{ theme, setTheme, resolvedTheme, toggleTheme }`; throws
|
|
106
|
+
outside the provider.
|
|
107
|
+
- `ThemeToggle` — accessible Sun/Moon button; renders a stable icon until
|
|
108
|
+
mounted to avoid a first-render hydration mismatch.
|
|
109
|
+
- `ThemeScript` — inline no-flash script for the root `<head>`; sets the
|
|
110
|
+
`dark` class before first paint. Wrapped in try/catch so it can never
|
|
111
|
+
block rendering.
|
|
112
|
+
- Types: `Theme`, `ThemeProviderProps`, `ThemeContextValue`,
|
|
113
|
+
`ThemeScriptProps`, `ThemeToggleProps`.
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
// app/layout.tsx
|
|
117
|
+
import { HazoThemeProvider, ThemeScript } from 'hazo_ui';
|
|
118
|
+
|
|
119
|
+
<html lang="en" suppressHydrationWarning>
|
|
120
|
+
<head><ThemeScript storageKey="theme" /></head>
|
|
121
|
+
<body>
|
|
122
|
+
<HazoThemeProvider defaultTheme="system" storageKey="theme">
|
|
123
|
+
{children}
|
|
124
|
+
</HazoThemeProvider>
|
|
125
|
+
</body>
|
|
126
|
+
</html>
|
|
127
|
+
```
|
|
128
|
+
|
|
8
129
|
## v4.7.0 (2026-07-01)
|
|
9
130
|
|
|
10
131
|
### New
|
package/README.md
CHANGED
|
@@ -214,6 +214,10 @@ The following components support both global config and prop-level color overrid
|
|
|
214
214
|
|
|
215
215
|
- **[Chart Primitives](#chart-primitives-v2170)** (v2.17.0) - Pure-SVG chart components for KPI cards and trend dashboards: `Sparkline`, `InverseSparkline`, `LineChart`, `MultiLineChart`, `StackedBars`, and `DateRangeSelector`. Zero third-party chart deps. Gap-aware paths, hover tooltips, and per-series endpoint markers built in.
|
|
216
216
|
|
|
217
|
+
- **[Theme Kit](#theme-kit-v490)** (v4.9.0) - SSR-safe dark/light theme using the shadcn `.dark`-class convention: `HazoThemeProvider`, `useTheme`, `ThemeToggle`, and a no-flash `ThemeScript`. Persists the chosen mode to `localStorage` and resolves `"system"` against the OS preference.
|
|
218
|
+
|
|
219
|
+
- **[Chrome Components](#chrome-components-v4100)** (v4.10.0) - `Logo`, `AppHeader`, and `AppFooter` — framework-neutral header/footer/logo pieces that consume hazo_theme's `BrandIdentity` contract and its `footer-public-*`/`footer-app-*` chrome tokens. Every admin-configurable `<a href>` inside them runs through the new `safeHref()` scheme allowlist.
|
|
220
|
+
|
|
217
221
|
### State Primitives (v2.10.0)
|
|
218
222
|
|
|
219
223
|
Lightweight, opinionated components for the four ubiquitous async states: **loading**, **empty**, **error**, and **success**.
|
|
@@ -242,6 +246,87 @@ Lightweight, opinionated components for the four ubiquitous async states: **load
|
|
|
242
246
|
import { Slider, InputAffix, HazoUiProgressBar, HazoUiEtaProgress, useEtaProgress } from 'hazo_ui';
|
|
243
247
|
```
|
|
244
248
|
|
|
249
|
+
### Theme Kit (v4.9.0)
|
|
250
|
+
|
|
251
|
+
SSR-safe dark/light theme using the shadcn `.dark`-class convention (toggles a `dark` class on `<html>`). No hydration mismatch: `window`/`document` are only touched inside `useEffect`, and an inline `ThemeScript` sets the class before first paint to avoid a flash.
|
|
252
|
+
|
|
253
|
+
**Exports:** `HazoThemeProvider`, `useTheme`, `ThemeToggle`, `ThemeScript` and types `Theme`, `ThemeProviderProps`, `ThemeContextValue`, `ThemeScriptProps`, `ThemeToggleProps`.
|
|
254
|
+
|
|
255
|
+
### Chrome Components (v4.10.0)
|
|
256
|
+
|
|
257
|
+
`Logo`, `AppHeader`, and `AppFooter` — framework-neutral chrome pieces that consume hazo_theme's
|
|
258
|
+
`BrandIdentity` (type-only import; `hazo_theme` stays an optional peer) plus its
|
|
259
|
+
`footer-public-*`/`footer-app-*` chrome tokens (import `hazo_theme/theme.css` for the tokens to
|
|
260
|
+
resolve).
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
import { AppHeader, AppFooter } from 'hazo_ui';
|
|
264
|
+
import type { BrandIdentity } from 'hazo_theme';
|
|
265
|
+
|
|
266
|
+
const identity: BrandIdentity = {
|
|
267
|
+
logoUrl: '/brand/logo.svg',
|
|
268
|
+
appTitle: 'Acme',
|
|
269
|
+
footer: { app: { copyright: '© 2026 Acme Inc.' } },
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
function Shell({ children }: { children: React.ReactNode }) {
|
|
273
|
+
return (
|
|
274
|
+
<>
|
|
275
|
+
<AppHeader identity={identity} homeHref="/" actions={<UserMenu />} />
|
|
276
|
+
{children}
|
|
277
|
+
<AppFooter variant="app" identity={identity} />
|
|
278
|
+
</>
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
- `Logo({ logoUrl?, logoUrlDark?, appTitle?, href?, height?, className?, imgClassName? })` — logo
|
|
284
|
+
image (swaps light/dark variants via `dark:hidden`/`dark:block`) or text fallback.
|
|
285
|
+
- `AppHeader({ identity?, homeHref?, navItems?, actions?, className? })` — `bg-navbar` header bar.
|
|
286
|
+
- `AppFooter({ variant: 'public' | 'app', footer?, identity?, className? })` — `'app'` renders a
|
|
287
|
+
thin copyright/link strip (`bg-footer-app`); `'public'` renders a taller multi-column footer with
|
|
288
|
+
a brand row and social links (`bg-footer-public`).
|
|
289
|
+
- **`safeHref(url?: string): string | undefined`** — also exported standalone from the package
|
|
290
|
+
root. Allows `http://`, `https://`, `mailto:`, and same-origin `/path` hrefs; returns `undefined`
|
|
291
|
+
for anything else (`javascript:`, `data:`, protocol-relative `//host`, …). Used internally by
|
|
292
|
+
every chrome-component `<a href>` sink; reach for it directly when rendering admin-configurable
|
|
293
|
+
links elsewhere.
|
|
294
|
+
|
|
295
|
+
```tsx
|
|
296
|
+
// app/layout.tsx
|
|
297
|
+
import { HazoThemeProvider, ThemeScript } from 'hazo_ui';
|
|
298
|
+
|
|
299
|
+
export default function RootLayout({ children }) {
|
|
300
|
+
return (
|
|
301
|
+
<html lang="en" suppressHydrationWarning>
|
|
302
|
+
<head>
|
|
303
|
+
<ThemeScript storageKey="theme" />
|
|
304
|
+
</head>
|
|
305
|
+
<body>
|
|
306
|
+
<HazoThemeProvider defaultTheme="system" storageKey="theme">
|
|
307
|
+
{children}
|
|
308
|
+
</HazoThemeProvider>
|
|
309
|
+
</body>
|
|
310
|
+
</html>
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
```tsx
|
|
316
|
+
// anywhere under the provider
|
|
317
|
+
import { ThemeToggle, useTheme } from 'hazo_ui';
|
|
318
|
+
|
|
319
|
+
function Header() {
|
|
320
|
+
const { theme, resolvedTheme, setTheme } = useTheme();
|
|
321
|
+
return <ThemeToggle />; // Sun/Moon button that flips light/dark
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
- `HazoThemeProvider` — context provider; keeps `<html class="dark">` in sync with the resolved theme. Props: `defaultTheme` (`"light" | "dark" | "system"`, default `"system"`), `storageKey` (default `"theme"`).
|
|
326
|
+
- `useTheme()` — `{ theme, setTheme, resolvedTheme, toggleTheme }`. Throws if used outside the provider.
|
|
327
|
+
- `ThemeToggle` — accessible Sun/Moon button; guards against a first-render hydration mismatch by rendering a stable icon until mounted.
|
|
328
|
+
- `ThemeScript` — inline no-flash script; render in the root `<head>` before content, with a `storageKey` matching the provider.
|
|
329
|
+
|
|
245
330
|
### shadcn/ui Primitive Re-exports
|
|
246
331
|
|
|
247
332
|
All shadcn/ui base components are re-exported from hazo_ui, so sibling hazo_* packages (and consumers) can import UI primitives from a single source without installing shadcn/ui separately:
|