hazo_config 2.2.0 → 2.4.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 CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.4.0 — 2026-06-22
4
+
5
+ ### Added
6
+ - `ColumnDef` gains optional `searchable?: boolean` flag. When `true`, a `select` column renders as a searchable combobox regardless of option count.
7
+ - `select` columns with more than 10 options now automatically render as a searchable combobox (Popover + Command) instead of a native `<select>`.
8
+ - Columns with ≤ 10 options and `searchable` unset render as a styled shadcn `Select` dropdown.
9
+ - New UI primitives added under `src/components/ui/`: `select.tsx` (over `@radix-ui/react-select`), `popover.tsx` (over `@radix-ui/react-popover`), `command.tsx` (over `cmdk`), `combobox.tsx` (self-contained searchable combobox).
10
+
11
+ ## 2.3.0 — 2026-06-19
12
+
13
+ ### Added
14
+ - `ColumnDef` gains `badge_class` for `list_display: 'badge'` columns: a Tailwind class string (or `(value, item) => string` function for per-value coloring) that overrides the default neutral `bg-gray-100 text-gray-600` pill. Lets each badge column render in a distinct color. Backward-compatible — omit it to keep the gray default.
15
+
16
+ ### Changed
17
+ - `AppConfigListEditor` delete confirmations now use `HazoUiConfirmDialog` (hazo_ui) for both single-item and bulk delete. The bulk delete previously fell back to the browser-native `window.confirm`; it now shows a styled destructive confirmation consistent with the single-item dialog. The internal Radix-based `DeleteDialog` is no longer used by the editor. (Was staged as unreleased 2.2.1; never published — folded into 2.3.0.)
18
+
19
+ ## 2.2.0 — 2026-06-19
20
+
21
+ ### Added
22
+ - `AppConfigListEditor` gains opt-in **row selection + bulk actions**: `enable_selection`, `bulk_edit_fields`, `on_bulk_update(ids, patch)`, `on_bulk_delete(ids)`, plus a bulk action bar and a select-all (indeterminate) header checkbox. New `BulkEditModal` lets each bulk-edit field be left unchanged.
23
+ - Optional **async per-item persistence adapter**: `on_item_create`, `on_item_update`, `on_item_delete`, and `on_reload`. When provided, create/edit/delete await these callbacks (with a Saving… state) instead of emitting a whole-array `on_items_change`. Fully backward-compatible — omit them to keep the callback-based behavior.
24
+ - `ColumnDef` gains `type: 'custom'` with `render_edit(value, item, set_value, ctx)` for bespoke edit controls, `format(value, item)` for list-cell display formatting, and `readonly` to render a field non-editable in the edit form.
25
+
3
26
  ## 2.1.11 — 2026-06-14
4
27
 
5
28
  ### Fixed (RSC bundling defect surfaced by hazo_admin)
@@ -1 +1 @@
1
- {"version":3,"file":"app_config_list_editor.d.ts","sourceRoot":"","sources":["../../../src/components/app_config_list_editor/app_config_list_editor.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,wBAAwB,EAAqC,MAAM,YAAY,CAAA;AAU7F;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EACrE,KAAK,EACL,eAAe,EACf,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,KAAK,EACL,WAAW,EACX,aAAqB,EACrB,gBAAoB,EACpB,WAAW,EACX,qBAAqB,EACrB,cAAc,EACd,mBAAmB,EACnB,SAAS,EACT,wBAAgC,EAChC,SAAS,EACT,WAAoB,EACpB,oBAAoB,EAEpB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,cAAc,EAEd,cAAc,EACd,cAAc,EACd,cAAc,EACd,SAAS,GACV,EAAE,wBAAwB,CAAC,CAAC,CAAC,+BAmb7B"}
1
+ {"version":3,"file":"app_config_list_editor.d.ts","sourceRoot":"","sources":["../../../src/components/app_config_list_editor/app_config_list_editor.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,wBAAwB,EAAqC,MAAM,YAAY,CAAA;AAS7F;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EACrE,KAAK,EACL,eAAe,EACf,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,KAAK,EACL,WAAW,EACX,aAAqB,EACrB,gBAAoB,EACpB,WAAW,EACX,qBAAqB,EACrB,cAAc,EACd,mBAAmB,EACnB,SAAS,EACT,wBAAgC,EAChC,SAAS,EACT,WAAoB,EACpB,oBAAoB,EAEpB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,cAAc,EAEd,cAAc,EACd,cAAc,EACd,cAAc,EACd,SAAS,GACV,EAAE,wBAAwB,CAAC,CAAC,CAAC,+BAuc7B"}
@@ -4,12 +4,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
4
  // Generic CRUD list editor for arrays of structured objects stored as JSON config
5
5
  import { useState, useCallback, useMemo } from 'react';
6
6
  import { Plus, Trash2 } from 'lucide-react';
7
- import { cn } from 'hazo_ui';
7
+ import { cn, HazoUiConfirmDialog } from 'hazo_ui';
8
8
  import { ListItemRow } from './components/list_item_row.js';
9
9
  import { EditModal } from './components/edit_modal.js';
10
10
  import { SearchBar } from './components/search_bar.js';
11
11
  import { EmptyState } from './components/empty_state.js';
12
- import { DeleteDialog } from './components/delete_dialog.js';
13
12
  import { SaveStatusIndicator } from './components/save_status_indicator.js';
14
13
  import { ImportExportButtons } from './components/import_export_buttons.js';
15
14
  import { BulkEditModal } from './components/bulk_edit_modal.js';
@@ -27,6 +26,7 @@ on_item_create, on_item_update, on_item_delete, on_reload, }) {
27
26
  const [delete_state, set_delete_state] = useState(null);
28
27
  const [selected_ids, set_selected_ids] = useState(new Set());
29
28
  const [bulk_edit_open, set_bulk_edit_open] = useState(false);
29
+ const [bulk_delete_open, set_bulk_delete_open] = useState(false);
30
30
  const [is_saving, set_is_saving] = useState(false);
31
31
  // Derive a friendly item label from the title (e.g., "Classification Tags" -> "tags")
32
32
  const item_label = useMemo(() => {
@@ -212,17 +212,18 @@ on_item_create, on_item_update, on_item_delete, on_reload, }) {
212
212
  clear_selection();
213
213
  set_bulk_edit_open(false);
214
214
  }, [on_bulk_update, selected_ids, clear_selection]);
215
- const handle_bulk_delete = useCallback(async () => {
215
+ const handle_bulk_delete = useCallback(() => {
216
+ if (selected_ids.size === 0)
217
+ return;
218
+ set_bulk_delete_open(true);
219
+ }, [selected_ids]);
220
+ const handle_bulk_delete_confirm = useCallback(async () => {
216
221
  const ids = Array.from(selected_ids);
217
- if (ids.length > 1) {
218
- const confirmed = window.confirm(`Delete ${ids.length} selected items? This cannot be undone.`);
219
- if (!confirmed)
220
- return;
221
- }
222
222
  if (on_bulk_delete) {
223
223
  await on_bulk_delete(ids);
224
224
  }
225
225
  clear_selection();
226
+ set_bulk_delete_open(false);
226
227
  }, [on_bulk_delete, selected_ids, clear_selection]);
227
228
  // Get delete confirmation message
228
229
  const delete_message = useMemo(() => {
@@ -249,5 +250,7 @@ on_item_create, on_item_update, on_item_delete, on_reload, }) {
249
250
  el.indeterminate = !all_filtered_selected && some_filtered_selected;
250
251
  }, onChange: toggle_select_all, className: "w-4 h-4 rounded border-gray-300 text-violet-600 focus:ring-violet-500", "aria-label": "Select all" })), _jsx("span", { className: "text-xs font-semibold uppercase tracking-wider text-gray-500", children: section_label })] }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(ImportExportButtons, { items: items, on_items_change: on_items_change, columns: columns, id_field: id_field, title: title, max_items: max_items }), _jsxs("button", { type: "button", onClick: handle_add, disabled: is_max_reached, className: cn('inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-full transition-colors', is_max_reached
251
252
  ? 'bg-gray-100 text-gray-400 cursor-not-allowed'
252
- : 'bg-violet-600 hover:bg-violet-700 text-white'), title: is_max_reached ? `Maximum of ${max_items} items reached` : undefined, children: [_jsx(Plus, { className: "w-4 h-4" }), "Add"] })] })] }), enable_selection && selection_count > 0 && (_jsxs("div", { className: "cls_bulk_action_bar flex items-center gap-3 mb-3 px-4 py-2.5 bg-violet-50 border border-violet-200 rounded-xl", children: [_jsxs("span", { className: "text-sm font-medium text-violet-800", children: [selection_count, " selected"] }), _jsx("button", { type: "button", onClick: clear_selection, className: "text-xs text-violet-600 hover:text-violet-800 underline", children: "Clear" }), _jsx("div", { className: "flex-1" }), bulk_edit_fields && bulk_edit_fields.length > 0 && on_bulk_update && (_jsx("button", { type: "button", onClick: () => set_bulk_edit_open(true), className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-full bg-violet-600 hover:bg-violet-700 text-white transition-colors", children: "Edit selected" })), on_bulk_delete && (_jsxs("button", { type: "button", onClick: handle_bulk_delete, className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-full bg-red-600 hover:bg-red-700 text-white transition-colors", children: [_jsx(Trash2, { className: "w-3.5 h-3.5" }), "Delete selected"] }))] })), show_search && (_jsx("div", { className: "mb-3", children: _jsx(SearchBar, { value: search_term, on_change: set_search_term, item_count: filtered_items.length, item_label: item_label }) })), _jsx("div", { className: "cls_list_editor_card rounded-xl border border-gray-200 bg-white overflow-hidden", children: items.length === 0 ? (_jsx(EmptyState, { item_label: item_label, on_add: handle_add })) : filtered_items.length === 0 ? (_jsxs("div", { className: "py-8 text-center text-sm text-gray-500", children: ["No ", item_label, " matching \u201C", search_term, "\u201D"] })) : (_jsx("div", { className: "divide-y divide-gray-100", children: filtered_items.map((item, index) => (_jsx(ListItemRow, { item: item, index: index, columns: columns, render_item: render_item, render_item_indicator: render_item_indicator, on_edit: () => handle_edit(item), on_delete: () => handle_delete_request(item), show_checkbox: enable_selection, is_selected: selected_ids.has(String(item[id_field])), on_toggle_select: () => toggle_row(String(item[id_field])) }, String(item[id_field])))) })) }), is_max_reached && (_jsxs("p", { className: "text-xs text-gray-400 mt-2", children: ["Maximum of ", max_items, " ", item_label, " reached."] })), edit_state && (_jsx(EditModal, { open: true, mode: edit_state.mode, item: edit_state.item, columns: columns, id_field: id_field, auto_id_from: auto_id_from, id_editable_after_create: id_editable_after_create, existing_ids: existing_ids, item_type_label: item_type_label, render_preview: render_preview, on_save: handle_save, on_cancel: handle_cancel_edit, max_width_class: edit_modal_max_width, is_saving: is_saving })), delete_state && (_jsx(DeleteDialog, { open: true, item_name: delete_item_name, message: delete_message, on_confirm: handle_delete_confirm, on_cancel: handle_cancel_delete })), bulk_edit_fields && bulk_edit_fields.length > 0 && (_jsx(BulkEditModal, { open: bulk_edit_open, selected_count: selection_count, columns: columns, bulk_edit_fields: bulk_edit_fields, on_confirm: handle_bulk_edit_confirm, on_cancel: () => set_bulk_edit_open(false) }))] }));
253
+ : 'bg-violet-600 hover:bg-violet-700 text-white'), title: is_max_reached ? `Maximum of ${max_items} items reached` : undefined, children: [_jsx(Plus, { className: "w-4 h-4" }), "Add"] })] })] }), enable_selection && selection_count > 0 && (_jsxs("div", { className: "cls_bulk_action_bar flex items-center gap-3 mb-3 px-4 py-2.5 bg-violet-50 border border-violet-200 rounded-xl", children: [_jsxs("span", { className: "text-sm font-medium text-violet-800", children: [selection_count, " selected"] }), _jsx("button", { type: "button", onClick: clear_selection, className: "text-xs text-violet-600 hover:text-violet-800 underline", children: "Clear" }), _jsx("div", { className: "flex-1" }), bulk_edit_fields && bulk_edit_fields.length > 0 && on_bulk_update && (_jsx("button", { type: "button", onClick: () => set_bulk_edit_open(true), className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-full bg-violet-600 hover:bg-violet-700 text-white transition-colors", children: "Edit selected" })), on_bulk_delete && (_jsxs("button", { type: "button", onClick: handle_bulk_delete, className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-full bg-red-600 hover:bg-red-700 text-white transition-colors", children: [_jsx(Trash2, { className: "w-3.5 h-3.5" }), "Delete selected"] }))] })), show_search && (_jsx("div", { className: "mb-3", children: _jsx(SearchBar, { value: search_term, on_change: set_search_term, item_count: filtered_items.length, item_label: item_label }) })), _jsx("div", { className: "cls_list_editor_card rounded-xl border border-gray-200 bg-white overflow-hidden", children: items.length === 0 ? (_jsx(EmptyState, { item_label: item_label, on_add: handle_add })) : filtered_items.length === 0 ? (_jsxs("div", { className: "py-8 text-center text-sm text-gray-500", children: ["No ", item_label, " matching \u201C", search_term, "\u201D"] })) : (_jsx("div", { className: "divide-y divide-gray-100", children: filtered_items.map((item, index) => (_jsx(ListItemRow, { item: item, index: index, columns: columns, render_item: render_item, render_item_indicator: render_item_indicator, on_edit: () => handle_edit(item), on_delete: () => handle_delete_request(item), show_checkbox: enable_selection, is_selected: selected_ids.has(String(item[id_field])), on_toggle_select: () => toggle_row(String(item[id_field])) }, String(item[id_field])))) })) }), is_max_reached && (_jsxs("p", { className: "text-xs text-gray-400 mt-2", children: ["Maximum of ", max_items, " ", item_label, " reached."] })), edit_state && (_jsx(EditModal, { open: true, mode: edit_state.mode, item: edit_state.item, columns: columns, id_field: id_field, auto_id_from: auto_id_from, id_editable_after_create: id_editable_after_create, existing_ids: existing_ids, item_type_label: item_type_label, render_preview: render_preview, on_save: handle_save, on_cancel: handle_cancel_edit, max_width_class: edit_modal_max_width, is_saving: is_saving })), delete_state && (_jsx(HazoUiConfirmDialog, { open: true, onOpenChange: (is_open) => { if (!is_open)
254
+ handle_cancel_delete(); }, title: `Delete “${delete_item_name}”?`, description: delete_message, variant: "destructive", confirmLabel: "Delete", onConfirm: handle_delete_confirm, onCancel: handle_cancel_delete })), on_bulk_delete && (_jsx(HazoUiConfirmDialog, { open: bulk_delete_open, onOpenChange: (is_open) => { if (!is_open)
255
+ set_bulk_delete_open(false); }, title: `Delete ${selection_count} selected ${selection_count === 1 ? item_type_label.toLowerCase() : item_label}?`, description: "This action cannot be undone.", variant: "destructive", confirmLabel: `Delete ${selection_count}`, onConfirm: handle_bulk_delete_confirm, onCancel: () => set_bulk_delete_open(false) })), bulk_edit_fields && bulk_edit_fields.length > 0 && (_jsx(BulkEditModal, { open: bulk_edit_open, selected_count: selection_count, columns: columns, bulk_edit_fields: bulk_edit_fields, on_confirm: handle_bulk_edit_confirm, on_cancel: () => set_bulk_edit_open(false) }))] }));
253
256
  }
@@ -1 +1 @@
1
- {"version":3,"file":"edit_modal.d.ts","sourceRoot":"","sources":["../../../../src/components/app_config_list_editor/components/edit_modal.tsx"],"names":[],"mappings":"AAKA,OAAO,KAA2C,MAAM,OAAO,CAAA;AAY/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAG5C,UAAU,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxD,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAA;IACvB,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IAChB,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,CAAA;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC,GAAG,MAAM,CAAA;IAC/B,wBAAwB,CAAC,EAAE,OAAO,CAAA;IAClC,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAA;IAC7C,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAA;IAC1B,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,sEAAsE;IACtE,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC3D,IAAI,EACJ,IAAI,EACJ,IAAI,EAAE,YAAY,EAClB,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,wBAAwB,EACxB,YAAY,EACZ,eAAe,EACf,cAAc,EACd,OAAO,EACP,SAAS,EACT,eAAgC,EAChC,SAAiB,GAClB,EAAE,cAAc,CAAC,CAAC,CAAC,qBAoTnB"}
1
+ {"version":3,"file":"edit_modal.d.ts","sourceRoot":"","sources":["../../../../src/components/app_config_list_editor/components/edit_modal.tsx"],"names":[],"mappings":"AAKA,OAAO,KAA2C,MAAM,OAAO,CAAA;AAc/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAG5C,UAAU,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxD,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAA;IACvB,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IAChB,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,CAAA;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC,GAAG,MAAM,CAAA;IAC/B,wBAAwB,CAAC,EAAE,OAAO,CAAA;IAClC,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAA;IAC7C,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAA;IAC1B,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,sEAAsE;IACtE,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC3D,IAAI,EACJ,IAAI,EACJ,IAAI,EAAE,YAAY,EAClB,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,wBAAwB,EACxB,YAAY,EACZ,eAAe,EACf,cAAc,EACd,OAAO,EACP,SAAS,EACT,eAAgC,EAChC,SAAiB,GAClB,EAAE,cAAc,CAAC,CAAC,CAAC,qBAiUnB"}
@@ -8,6 +8,8 @@ import { Input } from '../../ui/input.js';
8
8
  import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from '../../ui/dialog.js';
9
9
  import { Button } from '../../ui/button.js';
10
10
  import { ColorSwatchPicker } from './color_swatch_picker.js';
11
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../ui/select.js';
12
+ import { Combobox } from '../../ui/combobox.js';
11
13
  import { slugify } from '../types.js';
12
14
  export function EditModal({ open, mode, item: initial_item, columns, id_field, auto_id_from, id_editable_after_create, existing_ids, item_type_label, render_preview, on_save, on_cancel, max_width_class = 'sm:max-w-2xl', is_saving = false, }) {
13
15
  const [form_data, set_form_data] = useState({});
@@ -112,7 +114,9 @@ export function EditModal({ open, mode, item: initial_item, columns, id_field, a
112
114
  }
113
115
  return (_jsxs("div", { className: "cls_edit_field space-y-1.5", children: [_jsxs("label", { className: "text-sm font-medium text-gray-700", children: [col.label, col.required && _jsx("span", { className: "text-red-500 ml-0.5", children: "*" })] }), col.type === 'text' && (_jsx(Input, { type: "text", value: String(value ?? ''), onChange: (e) => is_id_field
114
116
  ? handle_id_change(e.target.value)
115
- : update_field(col.field, e.target.value), placeholder: col.placeholder, disabled: is_disabled, className: cn('rounded-lg focus-visible:ring-violet-500/20 focus-visible:ring-offset-0', is_disabled && 'bg-gray-50 text-gray-500', error && 'border-red-400 focus-visible:ring-red-500/20') })), col.type === 'number' && (_jsx(Input, { type: "number", value: value !== undefined && value !== null ? String(value) : '', onChange: (e) => update_field(col.field, e.target.value === '' ? '' : Number(e.target.value)), placeholder: col.placeholder, className: cn('rounded-lg focus-visible:ring-violet-500/20 focus-visible:ring-offset-0', error && 'border-red-400 focus-visible:ring-red-500/20') })), col.type === 'textarea' && (_jsx("textarea", { value: String(value ?? ''), onChange: (e) => update_field(col.field, e.target.value), placeholder: col.placeholder, rows: 3, className: cn('flex w-full rounded-lg border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-500/20 focus-visible:border-violet-300 disabled:cursor-not-allowed disabled:opacity-50', error && 'border-red-400 focus-visible:ring-red-500/20') })), col.type === 'select' && col.options && (_jsxs("select", { value: String(value ?? ''), onChange: (e) => update_field(col.field, e.target.value), className: cn('flex h-10 w-full rounded-lg border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-500/20 focus-visible:border-violet-300', error && 'border-red-400 focus-visible:ring-red-500/20'), children: [_jsx("option", { value: "", children: col.placeholder || 'Select...' }), col.options.map((opt) => (_jsx("option", { value: opt.value, children: opt.label }, opt.value)))] })), col.type === 'color_swatch' && col.color_options && (_jsx(ColorSwatchPicker, { value: String(value ?? ''), options: col.color_options, on_change: (color) => update_field(col.field, color) })), is_id_field && auto_id_from && mode === 'create' && !user_touched_id && (_jsxs("p", { className: "text-xs text-gray-400", children: ["Auto-generated from ", columns.find(c => c.field === auto_id_from)?.label?.toLowerCase() || auto_id_from] })), error && (_jsx("p", { className: "text-xs text-red-600", children: error }))] }, col.field));
117
+ : update_field(col.field, e.target.value), placeholder: col.placeholder, disabled: is_disabled, className: cn('rounded-lg focus-visible:ring-violet-500/20 focus-visible:ring-offset-0', is_disabled && 'bg-gray-50 text-gray-500', error && 'border-red-400 focus-visible:ring-red-500/20') })), col.type === 'number' && (_jsx(Input, { type: "number", value: value !== undefined && value !== null ? String(value) : '', onChange: (e) => update_field(col.field, e.target.value === '' ? '' : Number(e.target.value)), placeholder: col.placeholder, className: cn('rounded-lg focus-visible:ring-violet-500/20 focus-visible:ring-offset-0', error && 'border-red-400 focus-visible:ring-red-500/20') })), col.type === 'textarea' && (_jsx("textarea", { value: String(value ?? ''), onChange: (e) => update_field(col.field, e.target.value), placeholder: col.placeholder, rows: 3, className: cn('flex w-full rounded-lg border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-500/20 focus-visible:border-violet-300 disabled:cursor-not-allowed disabled:opacity-50', error && 'border-red-400 focus-visible:ring-red-500/20') })), col.type === 'select' && col.options && ((col.searchable || col.options.length > 10)
118
+ ? (_jsx(Combobox, { value: String(value ?? ''), onChange: (v) => update_field(col.field, v), options: [{ value: '', label: col.placeholder || 'Select...' }, ...col.options], placeholder: col.placeholder || 'Select...', error: !!error }))
119
+ : (_jsxs(Select, { value: String(value ?? ''), onValueChange: (v) => update_field(col.field, v), children: [_jsx(SelectTrigger, { className: cn(error && 'border-red-400'), children: _jsx(SelectValue, { placeholder: col.placeholder || 'Select...' }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "", children: col.placeholder || 'Select...' }), col.options.map((opt) => (_jsx(SelectItem, { value: opt.value, children: opt.label }, opt.value)))] })] }))), col.type === 'color_swatch' && col.color_options && (_jsx(ColorSwatchPicker, { value: String(value ?? ''), options: col.color_options, on_change: (color) => update_field(col.field, color) })), is_id_field && auto_id_from && mode === 'create' && !user_touched_id && (_jsxs("p", { className: "text-xs text-gray-400", children: ["Auto-generated from ", columns.find(c => c.field === auto_id_from)?.label?.toLowerCase() || auto_id_from] })), error && (_jsx("p", { className: "text-xs text-red-600", children: error }))] }, col.field));
116
120
  };
117
121
  return (_jsx(Dialog, { open: open, onOpenChange: (is_open) => { if (!is_open)
118
122
  on_cancel(); }, children: _jsxs(DialogContent, { className: cn('cls_edit_modal w-[95vw] rounded-2xl p-0 gap-0 overflow-hidden max-h-[90vh] flex flex-col', max_width_class), children: [_jsx(DialogHeader, { className: "px-6 pt-6 pb-4 shrink-0", children: _jsx(DialogTitle, { children: mode === 'create' ? `New ${item_type_label}` : `Edit ${item_type_label}` }) }), _jsxs("div", { className: "px-6 pb-4 space-y-4 overflow-y-auto flex-1 min-h-0", children: [render_preview && Object.keys(form_data).length > 0 && (_jsx("div", { className: "p-3 bg-gray-50 rounded-lg border border-gray-100", children: render_preview(form_data) })), columns.map((col) => render_field(col))] }), _jsxs(DialogFooter, { className: "bg-gray-50 px-6 py-4 border-t border-gray-100 sm:justify-between shrink-0", children: [_jsx(Button, { type: "button", variant: "ghost", onClick: on_cancel, className: "rounded-full", children: "Cancel" }), _jsx(Button, { type: "button", onClick: handle_save, disabled: is_saving, className: "rounded-full bg-violet-600 hover:bg-violet-700 text-white disabled:opacity-50 disabled:cursor-not-allowed", children: is_saving ? 'Saving…' : mode === 'create' ? `Add ${item_type_label}` : 'Save Changes' })] })] }) }));
@@ -1 +1 @@
1
- {"version":3,"file":"list_item_row.d.ts","sourceRoot":"","sources":["../../../../src/components/app_config_list_editor/components/list_item_row.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE5C,UAAU,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1D,IAAI,EAAE,CAAC,CAAA;IACP,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAA;IACvB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAA;IACzD,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAA;IACpD,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAA;CAC9B;AAED,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC7D,IAAI,EACJ,KAAK,EACL,OAAO,EACP,WAAW,EACX,qBAAqB,EACrB,OAAO,EACP,SAAS,EACT,aAAa,EACb,WAAW,EACX,gBAAgB,GACjB,EAAE,gBAAgB,CAAC,CAAC,CAAC,qBAoHrB"}
1
+ {"version":3,"file":"list_item_row.d.ts","sourceRoot":"","sources":["../../../../src/components/app_config_list_editor/components/list_item_row.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE5C,UAAU,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1D,IAAI,EAAE,CAAC,CAAA;IACP,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAA;IACvB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAA;IACzD,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAA;IACpD,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAA;CAC9B;AAED,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC7D,IAAI,EACJ,KAAK,EACL,OAAO,EACP,WAAW,EACX,qBAAqB,EACrB,OAAO,EACP,SAAS,EACT,aAAa,EACb,WAAW,EACX,gBAAgB,GACjB,EAAE,gBAAgB,CAAC,CAAC,CAAC,qBA0HrB"}
@@ -10,5 +10,10 @@ export function ListItemRow({ item, index, columns, render_item, render_item_ind
10
10
  const primary_cols = columns.filter(c => c.list_display === 'primary');
11
11
  const secondary_cols = columns.filter(c => c.list_display === 'secondary');
12
12
  const badge_cols = columns.filter(c => c.list_display === 'badge');
13
- return (_jsxs("div", { className: "cls_list_editor_row flex items-center gap-3 px-4 py-3 hover:bg-gray-50 transition-colors", children: [show_checkbox && (_jsx("input", { type: "checkbox", checked: is_selected ?? false, onChange: on_toggle_select, className: "shrink-0 w-4 h-4 rounded border-gray-300 text-violet-600 focus:ring-violet-500", "aria-label": "Select item" })), render_item_indicator && (_jsx("div", { className: "shrink-0", children: render_item_indicator(item) })), _jsxs("div", { className: "flex-1 min-w-0", children: [primary_cols.map((col) => (_jsx("div", { className: "text-sm font-medium text-gray-900 truncate", children: col.format?.(item[col.field], item) ?? String(item[col.field] ?? '') }, col.field))), secondary_cols.map((col) => (_jsx("div", { className: "text-xs text-gray-500 truncate mt-0.5", children: col.format?.(item[col.field], item) ?? String(item[col.field] ?? '') }, col.field)))] }), badge_cols.length > 0 && (_jsx("div", { className: "flex items-center gap-2 shrink-0", children: badge_cols.map((col) => (_jsx("span", { className: cn('inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-mono', 'bg-gray-100 text-gray-600'), children: col.format?.(item[col.field], item) ?? String(item[col.field] ?? '') }, col.field))) })), _jsxs("div", { className: "flex items-center gap-1 shrink-0", children: [_jsx("button", { type: "button", onClick: on_edit, className: "w-8 h-8 rounded-full flex items-center justify-center text-gray-400 hover:text-gray-700 hover:bg-gray-100 transition-colors", "aria-label": "Edit item", children: _jsx(Pencil, { className: "w-4 h-4" }) }), _jsx("button", { type: "button", onClick: on_delete, className: "w-8 h-8 rounded-full flex items-center justify-center text-gray-400 hover:text-red-600 hover:bg-red-50 transition-colors", "aria-label": "Delete item", children: _jsx(Trash2, { className: "w-4 h-4" }) })] })] }));
13
+ return (_jsxs("div", { className: "cls_list_editor_row flex items-center gap-3 px-4 py-3 hover:bg-gray-50 transition-colors", children: [show_checkbox && (_jsx("input", { type: "checkbox", checked: is_selected ?? false, onChange: on_toggle_select, className: "shrink-0 w-4 h-4 rounded border-gray-300 text-violet-600 focus:ring-violet-500", "aria-label": "Select item" })), render_item_indicator && (_jsx("div", { className: "shrink-0", children: render_item_indicator(item) })), _jsxs("div", { className: "flex-1 min-w-0", children: [primary_cols.map((col) => (_jsx("div", { className: "text-sm font-medium text-gray-900 truncate", children: col.format?.(item[col.field], item) ?? String(item[col.field] ?? '') }, col.field))), secondary_cols.map((col) => (_jsx("div", { className: "text-xs text-gray-500 truncate mt-0.5", children: col.format?.(item[col.field], item) ?? String(item[col.field] ?? '') }, col.field)))] }), badge_cols.length > 0 && (_jsx("div", { className: "flex items-center gap-2 shrink-0", children: badge_cols.map((col) => {
14
+ const badge_class = typeof col.badge_class === 'function'
15
+ ? col.badge_class(item[col.field], item)
16
+ : col.badge_class;
17
+ return (_jsx("span", { className: cn('inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-mono', badge_class || 'bg-gray-100 text-gray-600'), children: col.format?.(item[col.field], item) ?? String(item[col.field] ?? '') }, col.field));
18
+ }) })), _jsxs("div", { className: "flex items-center gap-1 shrink-0", children: [_jsx("button", { type: "button", onClick: on_edit, className: "w-8 h-8 rounded-full flex items-center justify-center text-gray-400 hover:text-gray-700 hover:bg-gray-100 transition-colors", "aria-label": "Edit item", children: _jsx(Pencil, { className: "w-4 h-4" }) }), _jsx("button", { type: "button", onClick: on_delete, className: "w-8 h-8 rounded-full flex items-center justify-center text-gray-400 hover:text-red-600 hover:bg-red-50 transition-colors", "aria-label": "Delete item", children: _jsx(Trash2, { className: "w-4 h-4" }) })] })] }));
14
19
  }
@@ -17,11 +17,20 @@ export interface ColumnDef<T> {
17
17
  show_in_list?: boolean;
18
18
  /** How to display in list view */
19
19
  list_display?: 'primary' | 'secondary' | 'badge' | 'hidden';
20
+ /**
21
+ * Tailwind class(es) controlling the pill color when `list_display: 'badge'`.
22
+ * Overrides the default neutral `bg-gray-100 text-gray-600`. May be a static
23
+ * string or a function of the value/item for per-value coloring. Return a
24
+ * falsy value to fall back to the default.
25
+ */
26
+ badge_class?: string | ((value: unknown, item: T) => string | undefined);
20
27
  /** Options for 'select' type */
21
28
  options?: {
22
29
  value: string;
23
30
  label: string;
24
31
  }[];
32
+ /** When true, a 'select' column always renders as a searchable combobox regardless of option count */
33
+ searchable?: boolean;
25
34
  /** Options for 'tag_picker' type — value is stored, label is displayed */
26
35
  tag_options?: {
27
36
  value: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/app_config_list_editor/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/app_config_list_editor/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import * as React from "react";
2
+ export interface ComboboxOption {
3
+ value: string;
4
+ label: string;
5
+ }
6
+ export interface ComboboxProps {
7
+ value: string;
8
+ onChange: (value: string) => void;
9
+ options: ComboboxOption[];
10
+ placeholder?: string;
11
+ searchPlaceholder?: string;
12
+ emptyText?: string;
13
+ className?: string;
14
+ error?: boolean;
15
+ }
16
+ export declare function Combobox({ value, onChange, options, placeholder, searchPlaceholder, emptyText, className, error, }: ComboboxProps): React.JSX.Element;
17
+ //# sourceMappingURL=combobox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../../src/components/ui/combobox.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,QAAQ,EACR,OAAO,EACP,WAAyB,EACzB,iBAA+B,EAC/B,SAA+B,EAC/B,SAAS,EACT,KAAK,GACN,EAAE,aAAa,qBAiDf"}
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { CheckIcon, ChevronsUpDownIcon } from "lucide-react";
5
+ import { cn } from 'hazo_ui';
6
+ import { Popover, PopoverContent, PopoverTrigger } from './popover.js';
7
+ import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from './command.js';
8
+ export function Combobox({ value, onChange, options, placeholder = 'Select...', searchPlaceholder = 'Search...', emptyText = 'No options found.', className, error, }) {
9
+ const [open, setOpen] = React.useState(false);
10
+ const selected = options.find((o) => o.value === value);
11
+ return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", role: "combobox", "aria-expanded": open, className: cn("flex h-9 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm shadow-xs outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50", !selected && "text-muted-foreground", error && "border-red-400 focus-visible:ring-red-500/20", className), children: [selected ? selected.label : placeholder, _jsx(ChevronsUpDownIcon, { className: "ml-2 size-4 shrink-0 opacity-50" })] }) }), _jsx(PopoverContent, { className: "w-[var(--radix-popover-trigger-width)] p-0", children: _jsxs(Command, { children: [_jsx(CommandInput, { placeholder: searchPlaceholder }), _jsxs(CommandList, { children: [_jsx(CommandEmpty, { children: emptyText }), _jsx(CommandGroup, { children: options.map((opt) => (_jsxs(CommandItem, { value: opt.label, onSelect: () => {
12
+ onChange(opt.value);
13
+ setOpen(false);
14
+ }, children: [_jsx(CheckIcon, { className: cn("mr-2 size-4", opt.value === value ? "opacity-100" : "opacity-0") }), opt.label] }, opt.value))) })] })] }) })] }));
15
+ }
@@ -0,0 +1,10 @@
1
+ import * as React from "react";
2
+ import { Command as CommandPrimitive } from "cmdk";
3
+ declare function Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>): React.JSX.Element;
4
+ declare function CommandInput({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Input>): React.JSX.Element;
5
+ declare function CommandList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>): React.JSX.Element;
6
+ declare function CommandEmpty({ ...props }: React.ComponentProps<typeof CommandPrimitive.Empty>): React.JSX.Element;
7
+ declare function CommandGroup({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Group>): React.JSX.Element;
8
+ declare function CommandItem({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Item>): React.JSX.Element;
9
+ export { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem };
10
+ //# sourceMappingURL=command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../src/components/ui/command.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,MAAM,CAAA;AAIlD,iBAAS,OAAO,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,qBAQtF;AAED,iBAAS,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,KAAK,CAAC,qBAWjG;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,IAAI,CAAC,qBAQ/F;AAED,iBAAS,YAAY,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,KAAK,CAAC,qBAEtF;AAED,iBAAS,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,KAAK,CAAC,qBAWjG;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,IAAI,CAAC,qBAW/F;AAED,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,CAAA"}
@@ -0,0 +1,24 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Command as CommandPrimitive } from "cmdk";
4
+ import { SearchIcon } from "lucide-react";
5
+ import { cn } from 'hazo_ui';
6
+ function Command({ className, ...props }) {
7
+ return (_jsx(CommandPrimitive, { "data-slot": "command", className: cn("bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md", className), ...props }));
8
+ }
9
+ function CommandInput({ className, ...props }) {
10
+ return (_jsxs("div", { "data-slot": "command-input-wrapper", className: "flex h-9 items-center gap-2 border-b px-3", children: [_jsx(SearchIcon, { className: "size-4 shrink-0 opacity-50" }), _jsx(CommandPrimitive.Input, { "data-slot": "command-input", className: cn("placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none disabled:cursor-not-allowed disabled:opacity-50", className), ...props })] }));
11
+ }
12
+ function CommandList({ className, ...props }) {
13
+ return (_jsx(CommandPrimitive.List, { "data-slot": "command-list", className: cn("max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto", className), ...props }));
14
+ }
15
+ function CommandEmpty({ ...props }) {
16
+ return _jsx(CommandPrimitive.Empty, { "data-slot": "command-empty", className: "py-6 text-center text-sm", ...props });
17
+ }
18
+ function CommandGroup({ className, ...props }) {
19
+ return (_jsx(CommandPrimitive.Group, { "data-slot": "command-group", className: cn("text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium", className), ...props }));
20
+ }
21
+ function CommandItem({ className, ...props }) {
22
+ return (_jsx(CommandPrimitive.Item, { "data-slot": "command-item", className: cn("data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50", className), ...props }));
23
+ }
24
+ export { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem };
@@ -0,0 +1,7 @@
1
+ import * as React from "react";
2
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
3
+ declare function Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>): React.JSX.Element;
4
+ declare function PopoverTrigger({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Trigger>): React.JSX.Element;
5
+ declare function PopoverContent({ className, align, sideOffset, ...props }: React.ComponentProps<typeof PopoverPrimitive.Content>): React.JSX.Element;
6
+ export { Popover, PopoverTrigger, PopoverContent };
7
+ //# sourceMappingURL=popover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"popover.d.ts","sourceRoot":"","sources":["../../../src/components/ui/popover.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAA;AAG3D,iBAAS,OAAO,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,IAAI,CAAC,qBAEhF;AAED,iBAAS,cAAc,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,OAAO,CAAC,qBAE1F;AAED,iBAAS,cAAc,CAAC,EACtB,SAAS,EACT,KAAe,EACf,UAAc,EACd,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,OAAO,CAAC,qBAevD;AAED,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,CAAA"}
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
4
+ import { cn } from 'hazo_ui';
5
+ function Popover({ ...props }) {
6
+ return _jsx(PopoverPrimitive.Root, { "data-slot": "popover", ...props });
7
+ }
8
+ function PopoverTrigger({ ...props }) {
9
+ return _jsx(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props });
10
+ }
11
+ function PopoverContent({ className, align = "start", sideOffset = 4, ...props }) {
12
+ return (_jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { "data-slot": "popover-content", align: align, sideOffset: sideOffset, className: cn("bg-popover text-popover-foreground z-[9999] w-72 rounded-md border p-0 shadow-md outline-none", className), ...props }) }));
13
+ }
14
+ export { Popover, PopoverTrigger, PopoverContent };
@@ -0,0 +1,14 @@
1
+ import * as React from "react";
2
+ import * as SelectPrimitive from "@radix-ui/react-select";
3
+ declare function Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>): React.JSX.Element;
4
+ declare function SelectGroup({ ...props }: React.ComponentProps<typeof SelectPrimitive.Group>): React.JSX.Element;
5
+ declare function SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.Value>): React.JSX.Element;
6
+ declare function SelectTrigger({ className, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Trigger>): React.JSX.Element;
7
+ declare function SelectContent({ className, children, position, ...props }: React.ComponentProps<typeof SelectPrimitive.Content>): React.JSX.Element;
8
+ declare function SelectLabel({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Label>): React.JSX.Element;
9
+ declare function SelectItem({ className, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Item>): React.JSX.Element;
10
+ declare function SelectSeparator({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Separator>): React.JSX.Element;
11
+ declare function SelectScrollUpButton({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>): React.JSX.Element;
12
+ declare function SelectScrollDownButton({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>): React.JSX.Element;
13
+ export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, };
14
+ //# sourceMappingURL=select.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../../src/components/ui/select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAA;AAIzD,iBAAS,MAAM,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,qBAE9E;AAED,iBAAS,WAAW,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,qBAEpF;AAED,iBAAS,WAAW,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,qBAEpF;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,OAAO,CAAC,qBAgBtD;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,QAAQ,EACR,QAAmB,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,OAAO,CAAC,qBAqBtD;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,qBAE/F;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,qBAkBvG;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,SAAS,CAAC,qBAEvG;AAED,iBAAS,oBAAoB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,cAAc,CAAC,qBAMjH;AAED,iBAAS,sBAAsB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,gBAAgB,CAAC,qBAMrH;AAED,OAAO,EACL,MAAM,EACN,aAAa,EACb,WAAW,EACX,UAAU,EACV,WAAW,EACX,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,WAAW,GACZ,CAAA"}
@@ -0,0 +1,36 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as SelectPrimitive from "@radix-ui/react-select";
4
+ import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
5
+ import { cn } from 'hazo_ui';
6
+ function Select({ ...props }) {
7
+ return _jsx(SelectPrimitive.Root, { "data-slot": "select", ...props });
8
+ }
9
+ function SelectGroup({ ...props }) {
10
+ return _jsx(SelectPrimitive.Group, { "data-slot": "select-group", ...props });
11
+ }
12
+ function SelectValue({ ...props }) {
13
+ return _jsx(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
14
+ }
15
+ function SelectTrigger({ className, children, ...props }) {
16
+ return (_jsxs(SelectPrimitive.Trigger, { "data-slot": "select-trigger", className: cn("border-input data-[placeholder]:text-muted-foreground flex h-9 w-full items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm shadow-xs outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50", className), ...props, children: [children, _jsx(SelectPrimitive.Icon, { asChild: true, children: _jsx(ChevronDownIcon, { className: "size-4 opacity-50" }) })] }));
17
+ }
18
+ function SelectContent({ className, children, position = "popper", ...props }) {
19
+ return (_jsx(SelectPrimitive.Portal, { children: _jsxs(SelectPrimitive.Content, { "data-slot": "select-content", className: cn("bg-popover text-popover-foreground relative z-[9999] max-h-[var(--radix-select-content-available-height)] min-w-[8rem] overflow-y-auto rounded-md border shadow-lg", position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1", className), position: position, ...props, children: [_jsx(SelectScrollUpButton, {}), _jsx(SelectPrimitive.Viewport, { className: cn("p-1", position === "popper" && "w-full min-w-[var(--radix-select-trigger-width)]"), children: children }), _jsx(SelectScrollDownButton, {})] }) }));
20
+ }
21
+ function SelectLabel({ className, ...props }) {
22
+ return _jsx(SelectPrimitive.Label, { "data-slot": "select-label", className: cn("text-muted-foreground px-2 py-1.5 text-xs", className), ...props });
23
+ }
24
+ function SelectItem({ className, children, ...props }) {
25
+ return (_jsxs(SelectPrimitive.Item, { "data-slot": "select-item", className: cn("focus:bg-accent focus:text-accent-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className), ...props, children: [_jsx("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: _jsx(SelectPrimitive.ItemIndicator, { children: _jsx(CheckIcon, { className: "size-4" }) }) }), _jsx(SelectPrimitive.ItemText, { children: children })] }));
26
+ }
27
+ function SelectSeparator({ className, ...props }) {
28
+ return _jsx(SelectPrimitive.Separator, { "data-slot": "select-separator", className: cn("bg-border -mx-1 my-1 h-px", className), ...props });
29
+ }
30
+ function SelectScrollUpButton({ className, ...props }) {
31
+ return (_jsx(SelectPrimitive.ScrollUpButton, { "data-slot": "select-scroll-up-button", className: cn("flex cursor-default items-center justify-center py-1", className), ...props, children: _jsx(ChevronUpIcon, { className: "size-4" }) }));
32
+ }
33
+ function SelectScrollDownButton({ className, ...props }) {
34
+ return (_jsx(SelectPrimitive.ScrollDownButton, { "data-slot": "select-scroll-down-button", className: cn("flex cursor-default items-center justify-center py-1", className), ...props, children: _jsx(ChevronDownIcon, { className: "size-4" }) }));
35
+ }
36
+ export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hazo_config",
3
- "version": "2.2.0",
3
+ "version": "2.4.0",
4
4
  "description": "Config wrapper with error handling",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -67,8 +67,11 @@
67
67
  "dependencies": {
68
68
  "@radix-ui/react-alert-dialog": "^1.1.15",
69
69
  "@radix-ui/react-dialog": "^1.1.15",
70
+ "@radix-ui/react-popover": "^1.1.15",
71
+ "@radix-ui/react-select": "^2.2.5",
70
72
  "@radix-ui/react-slot": "^1.2.4",
71
73
  "class-variance-authority": "^0.7.0",
74
+ "cmdk": "^1.1.1",
72
75
  "ini": "^4.1.0",
73
76
  "lucide-react": "^0.553.0",
74
77
  "server-only": "^0.0.1"
@@ -101,7 +104,7 @@
101
104
  },
102
105
  "peerDependencies": {
103
106
  "hazo_core": "^1.2.0",
104
- "hazo_ui": "^4.0.0",
107
+ "hazo_ui": "^4.4.0",
105
108
  "react": "^18.0.0 || ^19.0.0",
106
109
  "react-dom": "^18.0.0 || ^19.0.0",
107
110
  "tailwindcss": "^4.0.0"