hazo_ui 6.8.1 → 6.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 +78 -0
- package/dist/index.cjs +107 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -2
- package/dist/index.d.ts +51 -2
- package/dist/index.js +105 -8
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/CHANGE_LOG.md
CHANGED
|
@@ -5,6 +5,84 @@ 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
|
+
## v6.10.0 (2026-08-15)
|
|
9
|
+
|
|
10
|
+
### Added — `HazoUiKanban.renderColumnHeaderExtra`
|
|
11
|
+
|
|
12
|
+
`renderColumnFooter` already gave consumers a slot under a column's body;
|
|
13
|
+
there was no equivalent for the header. `renderColumnHeaderExtra` fills that
|
|
14
|
+
gap — a render-prop that fires once per rendered copy of a column and returns
|
|
15
|
+
a node placed inline in the header, next to the title and count badge:
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
<HazoUiKanban
|
|
19
|
+
columns={columns}
|
|
20
|
+
items={items}
|
|
21
|
+
renderCard={(item) => <Card item={item} />}
|
|
22
|
+
renderColumnHeaderExtra={({ columnKey, laneKey }) =>
|
|
23
|
+
columnKey !== "todo" ? null : (
|
|
24
|
+
<SegmentedToggle value={view} onChange={setView} options={["All", "Recent"]} />
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
/>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Same lane-scoping caveat as `renderColumnFooter`: on a laned board it fires
|
|
31
|
+
once per (lane, column) pair, and the unmatched-lane sentinel row never gets
|
|
32
|
+
one. The internal `render_column` parameter that gated this (`with_footer`)
|
|
33
|
+
is renamed `with_consumer_callbacks` since it now gates both render-props for
|
|
34
|
+
the same reason — leaking `UNMATCHED_LANE_KEY` to a consumer callback isn't
|
|
35
|
+
specific to the footer.
|
|
36
|
+
|
|
37
|
+
The returned node is wrapped so its pointer/mouse/key events stop
|
|
38
|
+
propagation before reaching dnd-kit, the same guard already used by the
|
|
39
|
+
card's pencil-edit affordance — this matters on a sectioned column, where the
|
|
40
|
+
header is itself a droppable, and is a harmless no-op elsewhere.
|
|
41
|
+
|
|
42
|
+
## v6.9.0 (2026-08-06)
|
|
43
|
+
|
|
44
|
+
### Added — `Badge`, `StatusBadge`, `makeStatusBadge`
|
|
45
|
+
|
|
46
|
+
A generic, token-backed pill component plus a status-mapping layer built on
|
|
47
|
+
top of it:
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import { Badge, StatusBadge, makeStatusBadge } from "hazo_ui";
|
|
51
|
+
|
|
52
|
+
<Badge tone="success" dot>Active</Badge>
|
|
53
|
+
|
|
54
|
+
<StatusBadge
|
|
55
|
+
status={order.status}
|
|
56
|
+
statusMap={{
|
|
57
|
+
pending: { label: "Pending", tone: "warning", dot: true, pulse: true },
|
|
58
|
+
shipped: { label: "Shipped", tone: "info" },
|
|
59
|
+
done: { label: "Done", tone: "success" },
|
|
60
|
+
}}
|
|
61
|
+
fallback={{ label: "Unknown", tone: "neutral" }}
|
|
62
|
+
/>
|
|
63
|
+
|
|
64
|
+
// Pre-bind a statusMap once per status enum:
|
|
65
|
+
const OrderStatusBadge = makeStatusBadge<OrderStatus>(orderStatusMap);
|
|
66
|
+
<OrderStatusBadge status={order.status} />
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`Badge` is a `cva`-driven soft-fill pill (`button.tsx`'s pattern) with 8
|
|
70
|
+
semantic `tone`s (`neutral`/`primary`/`secondary`/`accent`/`success`/
|
|
71
|
+
`warning`/`destructive`/`info`), all mapped to existing theme tokens — no
|
|
72
|
+
hardcoded hex. Optional `dot`/`pulse` render a leading status dot, colored via
|
|
73
|
+
a literal-string tone→class lookup (a templated `bg-${tone}` would compile to
|
|
74
|
+
zero CSS under Tailwind's JIT scanner). `className` passthrough via `cn()`
|
|
75
|
+
lets consumers override pill size or add mono/uppercase/border styling —
|
|
76
|
+
v1 deliberately has no solid/outline `variant` axis.
|
|
77
|
+
|
|
78
|
+
`StatusBadge<S extends string>` resolves `statusMap[status] ?? fallback ??
|
|
79
|
+
{ label: String(status), tone: "neutral" }` and renders a `Badge`.
|
|
80
|
+
`makeStatusBadge(statusMap, fallback?)` pre-binds the map so call sites don't
|
|
81
|
+
repeat it. Generalises kinstripe/seo_monitor's per-app inline status-pill
|
|
82
|
+
duplication. New exports: `Badge`, `StatusBadge`, `makeStatusBadge`,
|
|
83
|
+
`badgeVariants`, and types `BadgeProps`, `BadgeTone`, `StatusBadgeItem`,
|
|
84
|
+
`StatusBadgeProps`.
|
|
85
|
+
|
|
8
86
|
## v6.8.0 (2026-08-03)
|
|
9
87
|
|
|
10
88
|
### Added — text prefixes: `PrefixConfig.insert_as_text` + `CommandItem.insert_text`
|
package/dist/index.cjs
CHANGED
|
@@ -9217,6 +9217,7 @@ function KanbanColumn({
|
|
|
9217
9217
|
renderCard,
|
|
9218
9218
|
emptyColumn,
|
|
9219
9219
|
footer,
|
|
9220
|
+
headerExtra,
|
|
9220
9221
|
cardClassName,
|
|
9221
9222
|
showEdit,
|
|
9222
9223
|
onEditRequest,
|
|
@@ -9277,7 +9278,8 @@ function KanbanColumn({
|
|
|
9277
9278
|
treeKey,
|
|
9278
9279
|
title: column.title,
|
|
9279
9280
|
count: items.length,
|
|
9280
|
-
droppable: sections != null
|
|
9281
|
+
droppable: sections != null,
|
|
9282
|
+
headerExtra
|
|
9281
9283
|
}
|
|
9282
9284
|
),
|
|
9283
9285
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -9332,7 +9334,8 @@ function KanbanColumnHead({
|
|
|
9332
9334
|
treeKey,
|
|
9333
9335
|
title,
|
|
9334
9336
|
count,
|
|
9335
|
-
droppable
|
|
9337
|
+
droppable,
|
|
9338
|
+
headerExtra
|
|
9336
9339
|
}) {
|
|
9337
9340
|
const { setNodeRef, isOver } = core$1.useDroppable({
|
|
9338
9341
|
id: tree_droppable_id("columnhead", treeKey, laneKey, columnKey),
|
|
@@ -9346,13 +9349,25 @@ function KanbanColumnHead({
|
|
|
9346
9349
|
"data-column-key": columnKey,
|
|
9347
9350
|
"data-lane-key": laneKey,
|
|
9348
9351
|
className: cn(
|
|
9349
|
-
"cls_hazo_kanban_column_head mb-2 flex items-center justify-between rounded-sm px-1 text-xs uppercase tracking-wider text-muted-foreground",
|
|
9352
|
+
"cls_hazo_kanban_column_head mb-2 flex items-center justify-between gap-2 rounded-sm px-1 text-xs uppercase tracking-wider text-muted-foreground",
|
|
9350
9353
|
droppable && "py-1",
|
|
9351
9354
|
isOver && "cls_hazo_kanban_column_head_over bg-accent/30 text-foreground ring-1 ring-ring/40"
|
|
9352
9355
|
),
|
|
9353
9356
|
children: [
|
|
9354
|
-
/* @__PURE__ */ jsxRuntime.
|
|
9355
|
-
|
|
9357
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "cls_hazo_kanban_column_head_title_group flex min-w-0 items-center gap-2", children: [
|
|
9358
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "cls_hazo_kanban_column_title truncate", children: title }),
|
|
9359
|
+
headerExtra ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
9360
|
+
"span",
|
|
9361
|
+
{
|
|
9362
|
+
className: "cls_hazo_kanban_column_head_extra shrink-0",
|
|
9363
|
+
onPointerDown: (e) => e.stopPropagation(),
|
|
9364
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
9365
|
+
onKeyDown: (e) => e.stopPropagation(),
|
|
9366
|
+
children: headerExtra
|
|
9367
|
+
}
|
|
9368
|
+
) : null
|
|
9369
|
+
] }),
|
|
9370
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "cls_hazo_kanban_column_count shrink-0 rounded-full bg-muted px-2 py-0.5 text-foreground", children: count })
|
|
9356
9371
|
]
|
|
9357
9372
|
}
|
|
9358
9373
|
);
|
|
@@ -9933,6 +9948,7 @@ function HazoUiKanban({
|
|
|
9933
9948
|
announcements,
|
|
9934
9949
|
emptyColumn = "\u2014",
|
|
9935
9950
|
renderColumnFooter,
|
|
9951
|
+
renderColumnHeaderExtra,
|
|
9936
9952
|
className,
|
|
9937
9953
|
cardClassName,
|
|
9938
9954
|
itemLabel,
|
|
@@ -10186,7 +10202,7 @@ function HazoUiKanban({
|
|
|
10186
10202
|
total += (grouped.get(bucket_key(lane_key, col.key)) ?? []).length;
|
|
10187
10203
|
return total;
|
|
10188
10204
|
}
|
|
10189
|
-
function render_column(col, tree_key, lane_key,
|
|
10205
|
+
function render_column(col, tree_key, lane_key, with_consumer_callbacks = true) {
|
|
10190
10206
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10191
10207
|
KanbanColumn,
|
|
10192
10208
|
{
|
|
@@ -10196,7 +10212,8 @@ function HazoUiKanban({
|
|
|
10196
10212
|
items: grouped.get(bucket_key(lane_key, col.key)) ?? [],
|
|
10197
10213
|
renderCard,
|
|
10198
10214
|
emptyColumn,
|
|
10199
|
-
footer:
|
|
10215
|
+
footer: with_consumer_callbacks ? renderColumnFooter?.({ columnKey: col.key, laneKey: lane_key }) ?? null : null,
|
|
10216
|
+
headerExtra: with_consumer_callbacks ? renderColumnHeaderExtra?.({ columnKey: col.key, laneKey: lane_key }) ?? null : null,
|
|
10200
10217
|
cardClassName,
|
|
10201
10218
|
showEdit: show_edit,
|
|
10202
10219
|
onEditRequest: handle_edit_request
|
|
@@ -12537,6 +12554,86 @@ function useScrollRestore(treeId, viewName, options) {
|
|
|
12537
12554
|
const load = React27.useCallback(() => loadScrollPos(key), [key]);
|
|
12538
12555
|
return { save, load };
|
|
12539
12556
|
}
|
|
12557
|
+
var badgeVariants = classVarianceAuthority.cva(
|
|
12558
|
+
"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium whitespace-nowrap select-none",
|
|
12559
|
+
{
|
|
12560
|
+
variants: {
|
|
12561
|
+
tone: {
|
|
12562
|
+
neutral: "bg-muted text-muted-foreground",
|
|
12563
|
+
primary: "bg-primary/10 text-primary",
|
|
12564
|
+
secondary: "bg-secondary text-secondary-foreground",
|
|
12565
|
+
accent: "bg-accent text-accent-foreground",
|
|
12566
|
+
success: "bg-success/15 text-success",
|
|
12567
|
+
warning: "bg-warning/15 text-warning",
|
|
12568
|
+
destructive: "bg-destructive/15 text-destructive",
|
|
12569
|
+
info: "bg-info/15 text-info"
|
|
12570
|
+
}
|
|
12571
|
+
},
|
|
12572
|
+
defaultVariants: {
|
|
12573
|
+
tone: "neutral"
|
|
12574
|
+
}
|
|
12575
|
+
}
|
|
12576
|
+
);
|
|
12577
|
+
var TONE_DOT_CLASS = {
|
|
12578
|
+
neutral: "bg-muted-foreground",
|
|
12579
|
+
primary: "bg-primary",
|
|
12580
|
+
secondary: "bg-secondary-foreground",
|
|
12581
|
+
accent: "bg-accent-foreground",
|
|
12582
|
+
success: "bg-success",
|
|
12583
|
+
warning: "bg-warning",
|
|
12584
|
+
destructive: "bg-destructive",
|
|
12585
|
+
info: "bg-info"
|
|
12586
|
+
};
|
|
12587
|
+
var Badge = React27__namespace.forwardRef(
|
|
12588
|
+
({ className, tone, dot = false, pulse = false, children, ...props }, ref) => {
|
|
12589
|
+
const resolvedTone = tone ?? "neutral";
|
|
12590
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12591
|
+
"span",
|
|
12592
|
+
{
|
|
12593
|
+
ref,
|
|
12594
|
+
className: cn(badgeVariants({ tone: resolvedTone }), className),
|
|
12595
|
+
...props,
|
|
12596
|
+
children: [
|
|
12597
|
+
dot && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12598
|
+
"span",
|
|
12599
|
+
{
|
|
12600
|
+
"aria-hidden": true,
|
|
12601
|
+
className: cn(
|
|
12602
|
+
"inline-block h-1.5 w-1.5 rounded-full",
|
|
12603
|
+
TONE_DOT_CLASS[resolvedTone],
|
|
12604
|
+
pulse && "animate-pulse"
|
|
12605
|
+
)
|
|
12606
|
+
}
|
|
12607
|
+
),
|
|
12608
|
+
children
|
|
12609
|
+
]
|
|
12610
|
+
}
|
|
12611
|
+
);
|
|
12612
|
+
}
|
|
12613
|
+
);
|
|
12614
|
+
Badge.displayName = "Badge";
|
|
12615
|
+
function StatusBadgeInner({ status, statusMap, fallback, className, ...rest }, ref) {
|
|
12616
|
+
const meta = statusMap[status] ?? fallback ?? { label: String(status), tone: "neutral" };
|
|
12617
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12618
|
+
Badge,
|
|
12619
|
+
{
|
|
12620
|
+
ref,
|
|
12621
|
+
tone: meta.tone,
|
|
12622
|
+
dot: meta.dot,
|
|
12623
|
+
pulse: meta.pulse,
|
|
12624
|
+
className,
|
|
12625
|
+
...rest,
|
|
12626
|
+
children: meta.label
|
|
12627
|
+
}
|
|
12628
|
+
);
|
|
12629
|
+
}
|
|
12630
|
+
StatusBadgeInner.displayName = "StatusBadge";
|
|
12631
|
+
var StatusBadge = React27__namespace.forwardRef(StatusBadgeInner);
|
|
12632
|
+
function makeStatusBadge(statusMap, fallback) {
|
|
12633
|
+
const Component = React27__namespace.forwardRef((props, ref) => /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { ref, ...props, statusMap, fallback }));
|
|
12634
|
+
Component.displayName = "StatusBadge(bound)";
|
|
12635
|
+
return Component;
|
|
12636
|
+
}
|
|
12540
12637
|
|
|
12541
12638
|
Object.defineProperty(exports, "rawToast", {
|
|
12542
12639
|
enumerable: true,
|
|
@@ -12580,6 +12677,7 @@ exports.AlertDialogTitle = AlertDialogTitle;
|
|
|
12580
12677
|
exports.AlertDialogTrigger = AlertDialogTrigger;
|
|
12581
12678
|
exports.AppFooter = AppFooter;
|
|
12582
12679
|
exports.AppHeader = AppHeader;
|
|
12680
|
+
exports.Badge = Badge;
|
|
12583
12681
|
exports.Button = Button;
|
|
12584
12682
|
exports.ButtonGroup = ButtonGroup;
|
|
12585
12683
|
exports.ButtonGroupSeparator = ButtonGroupSeparator;
|
|
@@ -12712,6 +12810,7 @@ exports.Slider = Slider;
|
|
|
12712
12810
|
exports.Sparkline = Sparkline;
|
|
12713
12811
|
exports.Spinner = Spinner;
|
|
12714
12812
|
exports.StackedBars = StackedBars;
|
|
12813
|
+
exports.StatusBadge = StatusBadge;
|
|
12715
12814
|
exports.Switch = Switch;
|
|
12716
12815
|
exports.Table = Table2;
|
|
12717
12816
|
exports.TableBody = TableBody;
|
|
@@ -12748,6 +12847,7 @@ exports.get_hazo_ui_config = get_hazo_ui_config;
|
|
|
12748
12847
|
exports.get_logger = get_logger;
|
|
12749
12848
|
exports.hasUrlParam = hasUrlParam;
|
|
12750
12849
|
exports.isLucideValue = isLucideValue;
|
|
12850
|
+
exports.makeStatusBadge = makeStatusBadge;
|
|
12751
12851
|
exports.median = median;
|
|
12752
12852
|
exports.parse_commands_from_text = parse_commands_from_text;
|
|
12753
12853
|
exports.permissionToast = permissionToast;
|