hazo_config 2.0.0 → 2.1.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/README.md +62 -0
- package/dist/components/app_config_list_editor/app_config_list_editor.d.ts +7 -0
- package/dist/components/app_config_list_editor/app_config_list_editor.d.ts.map +1 -0
- package/dist/components/app_config_list_editor/app_config_list_editor.js +129 -0
- package/dist/components/app_config_list_editor/components/color_swatch_picker.d.ts +9 -0
- package/dist/components/app_config_list_editor/components/color_swatch_picker.d.ts.map +1 -0
- package/dist/components/app_config_list_editor/components/color_swatch_picker.js +15 -0
- package/dist/components/app_config_list_editor/components/delete_dialog.d.ts +10 -0
- package/dist/components/app_config_list_editor/components/delete_dialog.d.ts.map +1 -0
- package/dist/components/app_config_list_editor/components/delete_dialog.js +9 -0
- package/dist/components/app_config_list_editor/components/edit_modal.d.ts +19 -0
- package/dist/components/app_config_list_editor/components/edit_modal.d.ts.map +1 -0
- package/dist/components/app_config_list_editor/components/edit_modal.js +97 -0
- package/dist/components/app_config_list_editor/components/empty_state.d.ts +8 -0
- package/dist/components/app_config_list_editor/components/empty_state.d.ts.map +1 -0
- package/dist/components/app_config_list_editor/components/empty_state.js +8 -0
- package/dist/components/app_config_list_editor/components/import_export_buttons.d.ts +12 -0
- package/dist/components/app_config_list_editor/components/import_export_buttons.d.ts.map +1 -0
- package/dist/components/app_config_list_editor/components/import_export_buttons.js +74 -0
- package/dist/components/app_config_list_editor/components/list_item_row.d.ts +14 -0
- package/dist/components/app_config_list_editor/components/list_item_row.d.ts.map +1 -0
- package/dist/components/app_config_list_editor/components/list_item_row.js +14 -0
- package/dist/components/app_config_list_editor/components/save_status_indicator.d.ts +7 -0
- package/dist/components/app_config_list_editor/components/save_status_indicator.d.ts.map +1 -0
- package/dist/components/app_config_list_editor/components/save_status_indicator.js +25 -0
- package/dist/components/app_config_list_editor/components/search_bar.d.ts +10 -0
- package/dist/components/app_config_list_editor/components/search_bar.d.ts.map +1 -0
- package/dist/components/app_config_list_editor/components/search_bar.js +8 -0
- package/dist/components/app_config_list_editor/index.d.ts +4 -0
- package/dist/components/app_config_list_editor/index.d.ts.map +1 -0
- package/dist/components/app_config_list_editor/index.js +3 -0
- package/dist/components/app_config_list_editor/types.d.ts +102 -0
- package/dist/components/app_config_list_editor/types.d.ts.map +1 -0
- package/dist/components/app_config_list_editor/types.js +14 -0
- package/dist/components/app_config_list_editor/utils/json_import_export.d.ts +26 -0
- package/dist/components/app_config_list_editor/utils/json_import_export.d.ts.map +1 -0
- package/dist/components/app_config_list_editor/utils/json_import_export.js +112 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +3 -0
- package/dist/components/ui/alert-dialog.d.ts +21 -0
- package/dist/components/ui/alert-dialog.d.ts.map +1 -0
- package/dist/components/ui/alert-dialog.js +26 -0
- package/dist/components/ui/button.d.ts +12 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.js +33 -0
- package/dist/components/ui/dialog.d.ts +20 -0
- package/dist/components/ui/dialog.d.ts.map +1 -0
- package/dist/components/ui/dialog.js +22 -0
- package/dist/components/ui/input.d.ts +4 -0
- package/dist/components/ui/input.d.ts.map +1 -0
- package/dist/components/ui/input.js +8 -0
- package/package.json +7 -1
- package/MIGRATION_V2.md +0 -531
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Search bar component
|
|
3
|
+
// Pill-shaped search input with icon, clear button, and item count
|
|
4
|
+
import { Search, X } from 'lucide-react';
|
|
5
|
+
import { cn } from '../../../lib/utils.js';
|
|
6
|
+
export function SearchBar({ value, on_change, item_count, item_label, className, }) {
|
|
7
|
+
return (_jsxs("div", { className: cn('cls_search_bar flex items-center gap-3', className), children: [_jsxs("div", { className: "relative flex-1", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" }), _jsx("input", { type: "text", value: value, onChange: (e) => on_change(e.target.value), placeholder: `Search ${item_label}...`, className: "w-full pl-9 pr-8 py-2 text-sm rounded-full border border-gray-200 bg-white focus:outline-none focus:ring-2 focus:ring-violet-500/20 focus:border-violet-300 transition-colors", "aria-label": `Search ${item_label}` }), value && (_jsx("button", { type: "button", onClick: () => on_change(''), className: "absolute right-2.5 top-1/2 -translate-y-1/2 w-5 h-5 flex items-center justify-center rounded-full text-gray-400 hover:text-gray-600 hover:bg-gray-100", "aria-label": "Clear search", children: _jsx(X, { className: "w-3.5 h-3.5" }) }))] }), _jsxs("span", { className: "text-sm text-gray-500 whitespace-nowrap", children: [item_count, " ", item_label] })] }));
|
|
8
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { AppConfigListEditor } from './app_config_list_editor.js';
|
|
2
|
+
export type { AppConfigListEditorProps, ColumnDef, ImportResult } from './types.js';
|
|
3
|
+
export { validate_import_data, merge_items, export_items_to_json, generate_export_filename, } from './utils/json_import_export.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/app_config_list_editor/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACjE,YAAY,EAAE,wBAAwB,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACnF,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,+BAA+B,CAAA"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Column/field definition for list display and edit form
|
|
4
|
+
*/
|
|
5
|
+
export interface ColumnDef<T> {
|
|
6
|
+
/** The field key in the item */
|
|
7
|
+
field: keyof T & string;
|
|
8
|
+
/** Display label for the form */
|
|
9
|
+
label: string;
|
|
10
|
+
/** Column type determines the input control */
|
|
11
|
+
type: 'text' | 'textarea' | 'color_swatch' | 'select' | 'number' | 'toggle';
|
|
12
|
+
/** Placeholder text */
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
/** Whether this field is required */
|
|
15
|
+
required?: boolean;
|
|
16
|
+
/** Show in the list view (default: true for text, false for textarea) */
|
|
17
|
+
show_in_list?: boolean;
|
|
18
|
+
/** How to display in list view */
|
|
19
|
+
list_display?: 'primary' | 'secondary' | 'badge' | 'hidden';
|
|
20
|
+
/** Options for 'select' type */
|
|
21
|
+
options?: {
|
|
22
|
+
value: string;
|
|
23
|
+
label: string;
|
|
24
|
+
}[];
|
|
25
|
+
/** Options for 'color_swatch' type */
|
|
26
|
+
color_options?: string[];
|
|
27
|
+
/** Validation function - returns error message or null */
|
|
28
|
+
validate?: (value: unknown, item: T) => string | null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Props for the AppConfigListEditor component
|
|
32
|
+
*/
|
|
33
|
+
export interface AppConfigListEditorProps<T extends Record<string, unknown>> {
|
|
34
|
+
/** The array of items to display and edit */
|
|
35
|
+
items: T[];
|
|
36
|
+
/** Called when items change (add, edit, delete, reorder) */
|
|
37
|
+
on_items_change: (items: T[]) => void;
|
|
38
|
+
/** Column/field definitions for the list and edit form */
|
|
39
|
+
columns: ColumnDef<T>[];
|
|
40
|
+
/** Unique key field in each item (e.g., 'tag_id', 'type_id') */
|
|
41
|
+
id_field: keyof T & string;
|
|
42
|
+
/** Optional: field to auto-generate ID from (e.g., 'tag_label' -> auto-generates tag_id) */
|
|
43
|
+
auto_id_from?: keyof T & string;
|
|
44
|
+
/** Title shown above the list */
|
|
45
|
+
title?: string;
|
|
46
|
+
/** Subtitle/description */
|
|
47
|
+
description?: string;
|
|
48
|
+
/** Whether to allow drag-and-drop reordering (v2 feature) */
|
|
49
|
+
enable_reorder?: boolean;
|
|
50
|
+
/** Whether to show a search/filter input for long lists */
|
|
51
|
+
enable_search?: boolean;
|
|
52
|
+
/** Search threshold - only show search if item count exceeds this (default: 8) */
|
|
53
|
+
search_threshold?: number;
|
|
54
|
+
/** Custom render for each list item (overrides default rendering) */
|
|
55
|
+
render_item?: (item: T, index: number) => React.ReactNode;
|
|
56
|
+
/** Custom render for the item's leading visual (icon, color dot, avatar, etc.) */
|
|
57
|
+
render_item_indicator?: (item: T) => React.ReactNode;
|
|
58
|
+
/** Custom render for item preview/badge (shown in edit form) */
|
|
59
|
+
render_preview?: (item: T) => React.ReactNode;
|
|
60
|
+
/** Confirmation message for delete (null = no confirmation) */
|
|
61
|
+
delete_confirmation?: string | ((item: T) => string);
|
|
62
|
+
/** Max items allowed (null = unlimited) */
|
|
63
|
+
max_items?: number;
|
|
64
|
+
/** Whether the ID field is editable after creation (default: false) */
|
|
65
|
+
id_editable_after_create?: boolean;
|
|
66
|
+
/** Additional className */
|
|
67
|
+
className?: string;
|
|
68
|
+
/** Save status indicator */
|
|
69
|
+
save_status?: 'idle' | 'saving' | 'saved' | 'error';
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Internal state for the edit modal
|
|
73
|
+
*/
|
|
74
|
+
export interface EditModalState<T> {
|
|
75
|
+
mode: 'create' | 'edit';
|
|
76
|
+
item: Partial<T>;
|
|
77
|
+
original_item?: T;
|
|
78
|
+
errors: Map<string, string>;
|
|
79
|
+
user_touched_id: boolean;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Internal state for the delete confirmation dialog
|
|
83
|
+
*/
|
|
84
|
+
export interface DeleteDialogState<T> {
|
|
85
|
+
item: T;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Result of a JSON import merge operation
|
|
89
|
+
*/
|
|
90
|
+
export interface ImportResult<T> {
|
|
91
|
+
merged_items: T[];
|
|
92
|
+
added_count: number;
|
|
93
|
+
skipped_count: number;
|
|
94
|
+
errors: string[];
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Slugify a string for auto-ID generation.
|
|
98
|
+
* Converts to lowercase, replaces non-alphanumeric chars with underscores,
|
|
99
|
+
* collapses consecutive underscores, and trims leading/trailing underscores.
|
|
100
|
+
*/
|
|
101
|
+
export declare function slugify(value: string): string;
|
|
102
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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,14 @@
|
|
|
1
|
+
// Type definitions for AppConfigListEditor component
|
|
2
|
+
// Defines column configuration, component props, and internal state types
|
|
3
|
+
/**
|
|
4
|
+
* Slugify a string for auto-ID generation.
|
|
5
|
+
* Converts to lowercase, replaces non-alphanumeric chars with underscores,
|
|
6
|
+
* collapses consecutive underscores, and trims leading/trailing underscores.
|
|
7
|
+
*/
|
|
8
|
+
export function slugify(value) {
|
|
9
|
+
return value
|
|
10
|
+
.toLowerCase()
|
|
11
|
+
.replace(/[^a-z0-9]+/g, '_')
|
|
12
|
+
.replace(/^_+|_+$/g, '')
|
|
13
|
+
.replace(/_+/g, '_');
|
|
14
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ColumnDef, ImportResult } from '../types.js';
|
|
2
|
+
export type { ColumnDef, ImportResult };
|
|
3
|
+
/**
|
|
4
|
+
* Validate parsed JSON data against column definitions.
|
|
5
|
+
* Returns valid items and a list of error messages.
|
|
6
|
+
*/
|
|
7
|
+
export declare function validate_import_data<T extends Record<string, unknown>>(data: unknown, columns: ColumnDef<T>[], id_field: keyof T & string): {
|
|
8
|
+
valid_items: T[];
|
|
9
|
+
errors: string[];
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Merge incoming items with existing items.
|
|
13
|
+
* Skips items whose ID already exists in the existing list.
|
|
14
|
+
* Respects max_items cap.
|
|
15
|
+
*/
|
|
16
|
+
export declare function merge_items<T extends Record<string, unknown>>(existing: T[], incoming: T[], id_field: keyof T & string, max_items?: number): ImportResult<T>;
|
|
17
|
+
/**
|
|
18
|
+
* Trigger a browser download of items as a JSON file.
|
|
19
|
+
*/
|
|
20
|
+
export declare function export_items_to_json<T>(items: T[], filename: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Generate a snake_case filename from a title string.
|
|
23
|
+
* e.g. "Classification Tags" -> "classification_tags.json"
|
|
24
|
+
*/
|
|
25
|
+
export declare function generate_export_filename(title?: string): string;
|
|
26
|
+
//# sourceMappingURL=json_import_export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json_import_export.d.ts","sourceRoot":"","sources":["../../../../src/components/app_config_list_editor/utils/json_import_export.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1D,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,CAAA;AAEvC;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpE,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,EACvB,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,GACzB;IAAE,WAAW,EAAE,CAAC,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAwDxC;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3D,QAAQ,EAAE,CAAC,EAAE,EACb,QAAQ,EAAE,CAAC,EAAE,EACb,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,EAC1B,SAAS,CAAC,EAAE,MAAM,GACjB,YAAY,CAAC,CAAC,CAAC,CA0BjB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAW1E;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAQ/D"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// JSON import/export utilities for AppConfigListEditor
|
|
2
|
+
// Pure functions for validating, merging, and exporting config item arrays
|
|
3
|
+
/**
|
|
4
|
+
* Validate parsed JSON data against column definitions.
|
|
5
|
+
* Returns valid items and a list of error messages.
|
|
6
|
+
*/
|
|
7
|
+
export function validate_import_data(data, columns, id_field) {
|
|
8
|
+
const errors = [];
|
|
9
|
+
const valid_items = [];
|
|
10
|
+
if (!Array.isArray(data)) {
|
|
11
|
+
return { valid_items: [], errors: ['Expected a JSON array'] };
|
|
12
|
+
}
|
|
13
|
+
if (data.length === 0) {
|
|
14
|
+
return { valid_items: [], errors: ['JSON array is empty'] };
|
|
15
|
+
}
|
|
16
|
+
for (let i = 0; i < data.length; i++) {
|
|
17
|
+
const item = data[i];
|
|
18
|
+
const item_errors = [];
|
|
19
|
+
if (item === null || typeof item !== 'object' || Array.isArray(item)) {
|
|
20
|
+
errors.push(`Item ${i + 1}: not a valid object`);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const record = item;
|
|
24
|
+
// Check id_field exists and is non-empty
|
|
25
|
+
if (!(id_field in record) || record[id_field] === '' || record[id_field] === null || record[id_field] === undefined) {
|
|
26
|
+
item_errors.push(`missing required field "${id_field}"`);
|
|
27
|
+
}
|
|
28
|
+
// Check required fields and basic type compatibility
|
|
29
|
+
for (const col of columns) {
|
|
30
|
+
const val = record[col.field];
|
|
31
|
+
if (col.required && (val === undefined || val === null || val === '')) {
|
|
32
|
+
item_errors.push(`missing required field "${col.field}"`);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (val === undefined || val === null)
|
|
36
|
+
continue;
|
|
37
|
+
// Basic type checks
|
|
38
|
+
if (col.type === 'number' && typeof val !== 'number') {
|
|
39
|
+
item_errors.push(`"${col.field}" should be a number`);
|
|
40
|
+
}
|
|
41
|
+
if (col.type === 'toggle' && typeof val !== 'boolean') {
|
|
42
|
+
item_errors.push(`"${col.field}" should be a boolean`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (item_errors.length > 0) {
|
|
46
|
+
errors.push(`Item ${i + 1}: ${item_errors.join(', ')}`);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
valid_items.push(record);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { valid_items, errors };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Merge incoming items with existing items.
|
|
56
|
+
* Skips items whose ID already exists in the existing list.
|
|
57
|
+
* Respects max_items cap.
|
|
58
|
+
*/
|
|
59
|
+
export function merge_items(existing, incoming, id_field, max_items) {
|
|
60
|
+
const existing_ids = new Set(existing.map((item) => String(item[id_field])));
|
|
61
|
+
let skipped_count = 0;
|
|
62
|
+
const to_add = [];
|
|
63
|
+
for (const item of incoming) {
|
|
64
|
+
const id = String(item[id_field]);
|
|
65
|
+
if (existing_ids.has(id)) {
|
|
66
|
+
skipped_count++;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
// Respect max_items cap
|
|
70
|
+
if (max_items !== undefined && max_items !== null && existing.length + to_add.length >= max_items) {
|
|
71
|
+
skipped_count++;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
to_add.push(item);
|
|
75
|
+
existing_ids.add(id);
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
merged_items: [...existing, ...to_add],
|
|
79
|
+
added_count: to_add.length,
|
|
80
|
+
skipped_count,
|
|
81
|
+
errors: [],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Trigger a browser download of items as a JSON file.
|
|
86
|
+
*/
|
|
87
|
+
export function export_items_to_json(items, filename) {
|
|
88
|
+
const json = JSON.stringify(items, null, 2);
|
|
89
|
+
const blob = new Blob([json], { type: 'application/json' });
|
|
90
|
+
const url = URL.createObjectURL(blob);
|
|
91
|
+
const a = document.createElement('a');
|
|
92
|
+
a.href = url;
|
|
93
|
+
a.download = filename;
|
|
94
|
+
document.body.appendChild(a);
|
|
95
|
+
a.click();
|
|
96
|
+
document.body.removeChild(a);
|
|
97
|
+
URL.revokeObjectURL(url);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Generate a snake_case filename from a title string.
|
|
101
|
+
* e.g. "Classification Tags" -> "classification_tags.json"
|
|
102
|
+
*/
|
|
103
|
+
export function generate_export_filename(title) {
|
|
104
|
+
if (!title)
|
|
105
|
+
return 'config_items.json';
|
|
106
|
+
const slug = title
|
|
107
|
+
.toLowerCase()
|
|
108
|
+
.replace(/[^a-z0-9]+/g, '_')
|
|
109
|
+
.replace(/^_+|_+$/g, '')
|
|
110
|
+
.replace(/_+/g, '_');
|
|
111
|
+
return `${slug}.json`;
|
|
112
|
+
}
|
|
@@ -8,4 +8,7 @@ export { useConfigSections, is_sensitive_field, mask_value, DEFAULT_SENSITIVE_PA
|
|
|
8
8
|
export type { UseConfigSectionsResult } from './use_config_sections.js';
|
|
9
9
|
export { useAppConfig } from './use_app_config.js';
|
|
10
10
|
export type { UseAppConfigResult } from '../lib/app_config_types.js';
|
|
11
|
+
export { AppConfigListEditor } from './app_config_list_editor/index.js';
|
|
12
|
+
export type { AppConfigListEditorProps, ColumnDef, ImportResult } from './app_config_list_editor/index.js';
|
|
13
|
+
export { validate_import_data, merge_items, export_items_to_json, generate_export_filename, } from './app_config_list_editor/index.js';
|
|
11
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,YAAY,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAGhE,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,0BAA0B,EAC3B,MAAM,0BAA0B,CAAA;AACjC,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAEvE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,YAAY,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAGhE,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,0BAA0B,EAC3B,MAAM,0BAA0B,CAAA;AACjC,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAEvE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAGpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAA;AACvE,YAAY,EAAE,wBAAwB,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAA;AAC1G,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,mCAAmC,CAAA"}
|
package/dist/components/index.js
CHANGED
|
@@ -6,3 +6,6 @@ export { AppConfig } from './app_config.js';
|
|
|
6
6
|
// Hook exports
|
|
7
7
|
export { useConfigSections, is_sensitive_field, mask_value, DEFAULT_SENSITIVE_PATTERNS } from './use_config_sections.js';
|
|
8
8
|
export { useAppConfig } from './use_app_config.js';
|
|
9
|
+
// AppConfigListEditor exports
|
|
10
|
+
export { AppConfigListEditor } from './app_config_list_editor/index.js';
|
|
11
|
+
export { validate_import_data, merge_items, export_items_to_json, generate_export_filename, } from './app_config_list_editor/index.js';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
|
3
|
+
declare const AlertDialog: React.FC<AlertDialogPrimitive.AlertDialogProps>;
|
|
4
|
+
declare const AlertDialogTrigger: React.ForwardRefExoticComponent<AlertDialogPrimitive.AlertDialogTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
5
|
+
declare const AlertDialogPortal: React.FC<AlertDialogPrimitive.AlertDialogPortalProps>;
|
|
6
|
+
declare const AlertDialogOverlay: React.ForwardRefExoticComponent<Omit<AlertDialogPrimitive.AlertDialogOverlayProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
7
|
+
declare const AlertDialogContent: React.ForwardRefExoticComponent<Omit<AlertDialogPrimitive.AlertDialogContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
8
|
+
declare const AlertDialogHeader: {
|
|
9
|
+
({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
displayName: string;
|
|
11
|
+
};
|
|
12
|
+
declare const AlertDialogFooter: {
|
|
13
|
+
({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
displayName: string;
|
|
15
|
+
};
|
|
16
|
+
declare const AlertDialogTitle: React.ForwardRefExoticComponent<Omit<AlertDialogPrimitive.AlertDialogTitleProps & React.RefAttributes<HTMLHeadingElement>, "ref"> & React.RefAttributes<HTMLHeadingElement>>;
|
|
17
|
+
declare const AlertDialogDescription: React.ForwardRefExoticComponent<Omit<AlertDialogPrimitive.AlertDialogDescriptionProps & React.RefAttributes<HTMLParagraphElement>, "ref"> & React.RefAttributes<HTMLParagraphElement>>;
|
|
18
|
+
declare const AlertDialogAction: React.ForwardRefExoticComponent<Omit<AlertDialogPrimitive.AlertDialogActionProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
19
|
+
declare const AlertDialogCancel: React.ForwardRefExoticComponent<Omit<AlertDialogPrimitive.AlertDialogCancelProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
20
|
+
export { AlertDialog, AlertDialogPortal, AlertDialogOverlay, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogFooter, AlertDialogTitle, AlertDialogDescription, AlertDialogAction, AlertDialogCancel, };
|
|
21
|
+
//# sourceMappingURL=alert-dialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert-dialog.d.ts","sourceRoot":"","sources":["../../../src/components/ui/alert-dialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,oBAAoB,MAAM,8BAA8B,CAAA;AAKpE,QAAA,MAAM,WAAW,iDAA4B,CAAA;AAE7C,QAAA,MAAM,kBAAkB,wHAA+B,CAAA;AAEvD,QAAA,MAAM,iBAAiB,uDAA8B,CAAA;AAErD,QAAA,MAAM,kBAAkB,wKAYtB,CAAA;AAGF,QAAA,MAAM,kBAAkB,wKAetB,CAAA;AAGF,QAAA,MAAM,iBAAiB;8BAGpB,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;;CAQtC,CAAA;AAGD,QAAA,MAAM,iBAAiB;8BAGpB,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;;CAQtC,CAAA;AAGD,QAAA,MAAM,gBAAgB,8KASpB,CAAA;AAGF,QAAA,MAAM,sBAAsB,wLAS1B,CAAA;AAIF,QAAA,MAAM,iBAAiB,6KASrB,CAAA;AAGF,QAAA,MAAM,iBAAiB,6KAarB,CAAA;AAGF,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,GAClB,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
import { buttonVariants } from "./button.js";
|
|
6
|
+
const AlertDialog = AlertDialogPrimitive.Root;
|
|
7
|
+
const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
|
|
8
|
+
const AlertDialogPortal = AlertDialogPrimitive.Portal;
|
|
9
|
+
const AlertDialogOverlay = React.forwardRef(({ className, ...props }, ref) => (_jsx(AlertDialogPrimitive.Overlay, { className: cn("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", className), ...props, ref: ref })));
|
|
10
|
+
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
|
|
11
|
+
const AlertDialogContent = React.forwardRef(({ className, ...props }, ref) => (_jsxs(AlertDialogPortal, { children: [_jsx(AlertDialogOverlay, {}), _jsx(AlertDialogPrimitive.Content, { ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", className), ...props })] })));
|
|
12
|
+
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
|
|
13
|
+
const AlertDialogHeader = ({ className, ...props }) => (_jsx("div", { className: cn("flex flex-col space-y-2 text-center sm:text-left", className), ...props }));
|
|
14
|
+
AlertDialogHeader.displayName = "AlertDialogHeader";
|
|
15
|
+
const AlertDialogFooter = ({ className, ...props }) => (_jsx("div", { className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className), ...props }));
|
|
16
|
+
AlertDialogFooter.displayName = "AlertDialogFooter";
|
|
17
|
+
const AlertDialogTitle = React.forwardRef(({ className, ...props }, ref) => (_jsx(AlertDialogPrimitive.Title, { ref: ref, className: cn("text-lg font-semibold", className), ...props })));
|
|
18
|
+
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
|
|
19
|
+
const AlertDialogDescription = React.forwardRef(({ className, ...props }, ref) => (_jsx(AlertDialogPrimitive.Description, { ref: ref, className: cn("text-sm text-muted-foreground", className), ...props })));
|
|
20
|
+
AlertDialogDescription.displayName =
|
|
21
|
+
AlertDialogPrimitive.Description.displayName;
|
|
22
|
+
const AlertDialogAction = React.forwardRef(({ className, ...props }, ref) => (_jsx(AlertDialogPrimitive.Action, { ref: ref, className: cn(buttonVariants(), className), ...props })));
|
|
23
|
+
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
|
|
24
|
+
const AlertDialogCancel = React.forwardRef(({ className, ...props }, ref) => (_jsx(AlertDialogPrimitive.Cancel, { ref: ref, className: cn(buttonVariants({ variant: "outline" }), "mt-2 sm:mt-0", className), ...props })));
|
|
25
|
+
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
|
|
26
|
+
export { AlertDialog, AlertDialogPortal, AlertDialogOverlay, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogFooter, AlertDialogTitle, AlertDialogDescription, AlertDialogAction, AlertDialogCancel, };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
declare const buttonVariants: (props?: ({
|
|
4
|
+
variant?: "default" | "link" | "secondary" | "destructive" | "outline" | "ghost" | null | undefined;
|
|
5
|
+
size?: "default" | "sm" | "lg" | "icon" | null | undefined;
|
|
6
|
+
} & import("class-variance-authority/dist/types.js").ClassProp) | undefined) => string;
|
|
7
|
+
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
8
|
+
asChild?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
11
|
+
export { Button, buttonVariants };
|
|
12
|
+
//# sourceMappingURL=button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../src/components/ui/button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAIjE,QAAA,MAAM,cAAc;;;sFA2BnB,CAAA;AAED,MAAM,WAAW,WACf,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EACnD,YAAY,CAAC,OAAO,cAAc,CAAC;IACrC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,QAAA,MAAM,MAAM,uFAWX,CAAA;AAGD,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
4
|
+
import { cva } from "class-variance-authority";
|
|
5
|
+
import { cn } from "../../lib/utils.js";
|
|
6
|
+
const buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", {
|
|
7
|
+
variants: {
|
|
8
|
+
variant: {
|
|
9
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
10
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
11
|
+
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
12
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
13
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
14
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
15
|
+
},
|
|
16
|
+
size: {
|
|
17
|
+
default: "h-10 px-4 py-2",
|
|
18
|
+
sm: "h-9 rounded-md px-3",
|
|
19
|
+
lg: "h-11 rounded-md px-8",
|
|
20
|
+
icon: "h-10 w-10",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: {
|
|
24
|
+
variant: "default",
|
|
25
|
+
size: "default",
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
29
|
+
const Comp = asChild ? Slot : "button";
|
|
30
|
+
return (_jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref: ref, ...props }));
|
|
31
|
+
});
|
|
32
|
+
Button.displayName = "Button";
|
|
33
|
+
export { Button, buttonVariants };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
3
|
+
declare const Dialog: React.FC<DialogPrimitive.DialogProps>;
|
|
4
|
+
declare const DialogTrigger: React.ForwardRefExoticComponent<DialogPrimitive.DialogTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
5
|
+
declare const DialogPortal: React.FC<DialogPrimitive.DialogPortalProps>;
|
|
6
|
+
declare const DialogClose: React.ForwardRefExoticComponent<DialogPrimitive.DialogCloseProps & React.RefAttributes<HTMLButtonElement>>;
|
|
7
|
+
declare const DialogOverlay: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogOverlayProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
8
|
+
declare const DialogContent: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
9
|
+
declare const DialogHeader: {
|
|
10
|
+
({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
displayName: string;
|
|
12
|
+
};
|
|
13
|
+
declare const DialogFooter: {
|
|
14
|
+
({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
displayName: string;
|
|
16
|
+
};
|
|
17
|
+
declare const DialogTitle: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogTitleProps & React.RefAttributes<HTMLHeadingElement>, "ref"> & React.RefAttributes<HTMLHeadingElement>>;
|
|
18
|
+
declare const DialogDescription: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogDescriptionProps & React.RefAttributes<HTMLParagraphElement>, "ref"> & React.RefAttributes<HTMLParagraphElement>>;
|
|
19
|
+
export { Dialog, DialogPortal, DialogOverlay, DialogClose, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, };
|
|
20
|
+
//# sourceMappingURL=dialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../src/components/ui/dialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAA;AAKzD,QAAA,MAAM,MAAM,uCAAuB,CAAA;AAEnC,QAAA,MAAM,aAAa,8GAA0B,CAAA;AAE7C,QAAA,MAAM,YAAY,6CAAyB,CAAA;AAE3C,QAAA,MAAM,WAAW,4GAAwB,CAAA;AAEzC,QAAA,MAAM,aAAa,8JAYjB,CAAA;AAGF,QAAA,MAAM,aAAa,8JAqBjB,CAAA;AAGF,QAAA,MAAM,YAAY;8BAGf,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;;CAQtC,CAAA;AAGD,QAAA,MAAM,YAAY;8BAGf,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;;CAQtC,CAAA;AAGD,QAAA,MAAM,WAAW,oKAYf,CAAA;AAGF,QAAA,MAAM,iBAAiB,8KASrB,CAAA;AAGF,OAAO,EACL,MAAM,EACN,YAAY,EACZ,aAAa,EACb,WAAW,EACX,aAAa,EACb,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
4
|
+
import { X } from "lucide-react";
|
|
5
|
+
import { cn } from "../../lib/utils.js";
|
|
6
|
+
const Dialog = DialogPrimitive.Root;
|
|
7
|
+
const DialogTrigger = DialogPrimitive.Trigger;
|
|
8
|
+
const DialogPortal = DialogPrimitive.Portal;
|
|
9
|
+
const DialogClose = DialogPrimitive.Close;
|
|
10
|
+
const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => (_jsx(DialogPrimitive.Overlay, { ref: ref, className: cn("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", className), ...props })));
|
|
11
|
+
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
12
|
+
const DialogContent = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", className), ...props, children: [children, _jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [_jsx(X, { className: "h-4 w-4" }), _jsx("span", { className: "sr-only", children: "Close" })] })] })] })));
|
|
13
|
+
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
14
|
+
const DialogHeader = ({ className, ...props }) => (_jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props }));
|
|
15
|
+
DialogHeader.displayName = "DialogHeader";
|
|
16
|
+
const DialogFooter = ({ className, ...props }) => (_jsx("div", { className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className), ...props }));
|
|
17
|
+
DialogFooter.displayName = "DialogFooter";
|
|
18
|
+
const DialogTitle = React.forwardRef(({ className, ...props }, ref) => (_jsx(DialogPrimitive.Title, { ref: ref, className: cn("text-lg font-semibold leading-none tracking-tight", className), ...props })));
|
|
19
|
+
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
20
|
+
const DialogDescription = React.forwardRef(({ className, ...props }, ref) => (_jsx(DialogPrimitive.Description, { ref: ref, className: cn("text-sm text-muted-foreground", className), ...props })));
|
|
21
|
+
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
22
|
+
export { Dialog, DialogPortal, DialogOverlay, DialogClose, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
declare const Input: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
3
|
+
export { Input };
|
|
4
|
+
//# sourceMappingURL=input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../src/components/ui/input.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,QAAA,MAAM,KAAK,8KAcV,CAAA;AAGD,OAAO,EAAE,KAAK,EAAE,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
|
+
const Input = React.forwardRef(({ className, type, ...props }, ref) => {
|
|
5
|
+
return (_jsx("input", { type: type, className: cn("flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", className), ref: ref, ...props }));
|
|
6
|
+
});
|
|
7
|
+
Input.displayName = "Input";
|
|
8
|
+
export { Input };
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hazo_config",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Config wrapper with error handling",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
8
11
|
"exports": {
|
|
9
12
|
".": {
|
|
10
13
|
"types": "./dist/index.d.ts",
|
|
@@ -52,6 +55,9 @@
|
|
|
52
55
|
},
|
|
53
56
|
"homepage": "https://github.com/pub12/hazo_config#readme",
|
|
54
57
|
"dependencies": {
|
|
58
|
+
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
59
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
60
|
+
"@radix-ui/react-slot": "^1.2.4",
|
|
55
61
|
"class-variance-authority": "^0.7.0",
|
|
56
62
|
"clsx": "^2.1.0",
|
|
57
63
|
"ini": "^4.1.0",
|