@miethe/ui 0.3.0 → 0.6.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.
Files changed (168) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +776 -9
  3. package/dist/components/content-viewer/ArticleViewer.d.ts +42 -0
  4. package/dist/components/content-viewer/ArticleViewer.d.ts.map +1 -0
  5. package/dist/components/content-viewer/ArticleViewer.js +321 -0
  6. package/dist/components/content-viewer/ArticleViewer.js.map +1 -0
  7. package/dist/components/content-viewer/FrontmatterHeader.d.ts +32 -0
  8. package/dist/components/content-viewer/FrontmatterHeader.d.ts.map +1 -0
  9. package/dist/components/content-viewer/FrontmatterHeader.js +95 -0
  10. package/dist/components/content-viewer/FrontmatterHeader.js.map +1 -0
  11. package/dist/components/content-viewer/callouts/Callout.d.ts +43 -0
  12. package/dist/components/content-viewer/callouts/Callout.d.ts.map +1 -0
  13. package/dist/components/content-viewer/callouts/Callout.js +86 -0
  14. package/dist/components/content-viewer/callouts/Callout.js.map +1 -0
  15. package/dist/components/content-viewer/callouts/index.d.ts +2 -0
  16. package/dist/components/content-viewer/callouts/index.d.ts.map +1 -0
  17. package/dist/components/content-viewer/callouts/index.js +2 -0
  18. package/dist/components/content-viewer/callouts/index.js.map +1 -0
  19. package/dist/components/content-viewer/index.d.ts +21 -0
  20. package/dist/components/content-viewer/index.d.ts.map +1 -0
  21. package/dist/components/content-viewer/index.js +29 -0
  22. package/dist/components/content-viewer/index.js.map +1 -0
  23. package/dist/components/content-viewer/plugins/index.d.ts +5 -0
  24. package/dist/components/content-viewer/plugins/index.d.ts.map +1 -0
  25. package/dist/components/content-viewer/plugins/index.js +5 -0
  26. package/dist/components/content-viewer/plugins/index.js.map +1 -0
  27. package/dist/components/content-viewer/plugins/lowlightLoader.d.ts +63 -0
  28. package/dist/components/content-viewer/plugins/lowlightLoader.d.ts.map +1 -0
  29. package/dist/components/content-viewer/plugins/lowlightLoader.js +120 -0
  30. package/dist/components/content-viewer/plugins/lowlightLoader.js.map +1 -0
  31. package/dist/components/content-viewer/plugins/rehypeCodeHighlight.d.ts +44 -0
  32. package/dist/components/content-viewer/plugins/rehypeCodeHighlight.d.ts.map +1 -0
  33. package/dist/components/content-viewer/plugins/rehypeCodeHighlight.js +122 -0
  34. package/dist/components/content-viewer/plugins/rehypeCodeHighlight.js.map +1 -0
  35. package/dist/components/content-viewer/plugins/rehypeExternalLinks.d.ts +59 -0
  36. package/dist/components/content-viewer/plugins/rehypeExternalLinks.d.ts.map +1 -0
  37. package/dist/components/content-viewer/plugins/rehypeExternalLinks.js +79 -0
  38. package/dist/components/content-viewer/plugins/rehypeExternalLinks.js.map +1 -0
  39. package/dist/components/content-viewer/plugins/rehypeHeadingIds.d.ts +37 -0
  40. package/dist/components/content-viewer/plugins/rehypeHeadingIds.d.ts.map +1 -0
  41. package/dist/components/content-viewer/plugins/rehypeHeadingIds.js +82 -0
  42. package/dist/components/content-viewer/plugins/rehypeHeadingIds.js.map +1 -0
  43. package/dist/components/content-viewer/plugins/remarkCallouts.d.ts +39 -0
  44. package/dist/components/content-viewer/plugins/remarkCallouts.d.ts.map +1 -0
  45. package/dist/components/content-viewer/plugins/remarkCallouts.js +77 -0
  46. package/dist/components/content-viewer/plugins/remarkCallouts.js.map +1 -0
  47. package/dist/components/content-viewer/plugins/slugify.d.ts +24 -0
  48. package/dist/components/content-viewer/plugins/slugify.d.ts.map +1 -0
  49. package/dist/components/content-viewer/plugins/slugify.js +31 -0
  50. package/dist/components/content-viewer/plugins/slugify.js.map +1 -0
  51. package/dist/components/content-viewer/sanitize.d.ts +75 -0
  52. package/dist/components/content-viewer/sanitize.d.ts.map +1 -0
  53. package/dist/components/content-viewer/sanitize.js +252 -0
  54. package/dist/components/content-viewer/sanitize.js.map +1 -0
  55. package/dist/components/content-viewer/types.d.ts +315 -0
  56. package/dist/components/content-viewer/types.d.ts.map +1 -0
  57. package/dist/components/content-viewer/types.js +8 -0
  58. package/dist/components/content-viewer/types.js.map +1 -0
  59. package/dist/components/content-viewer/variants.d.ts +71 -0
  60. package/dist/components/content-viewer/variants.d.ts.map +1 -0
  61. package/dist/components/content-viewer/variants.js +105 -0
  62. package/dist/components/content-viewer/variants.js.map +1 -0
  63. package/dist/content-viewer/ContentPane.d.ts +44 -1
  64. package/dist/content-viewer/ContentPane.d.ts.map +1 -1
  65. package/dist/content-viewer/ContentPane.js +139 -5
  66. package/dist/content-viewer/ContentPane.js.map +1 -1
  67. package/dist/content-viewer/FileTree.d.ts +23 -1
  68. package/dist/content-viewer/FileTree.d.ts.map +1 -1
  69. package/dist/content-viewer/FileTree.js +20 -5
  70. package/dist/content-viewer/FileTree.js.map +1 -1
  71. package/dist/content-viewer/index.d.ts +2 -0
  72. package/dist/content-viewer/index.d.ts.map +1 -1
  73. package/dist/content-viewer/index.js +2 -0
  74. package/dist/content-viewer/index.js.map +1 -1
  75. package/dist/diff/DiffViewer.js +3 -3
  76. package/dist/diff/DiffViewer.js.map +1 -1
  77. package/dist/discovery/discovery-card.d.ts +25 -0
  78. package/dist/discovery/discovery-card.d.ts.map +1 -0
  79. package/dist/discovery/discovery-card.js +265 -0
  80. package/dist/discovery/discovery-card.js.map +1 -0
  81. package/dist/discovery/index.d.ts +3 -0
  82. package/dist/discovery/index.d.ts.map +1 -0
  83. package/dist/discovery/index.js +3 -0
  84. package/dist/discovery/index.js.map +1 -0
  85. package/dist/display/ContextInfoCard.d.ts +61 -0
  86. package/dist/display/ContextInfoCard.d.ts.map +1 -0
  87. package/dist/display/ContextInfoCard.js +45 -0
  88. package/dist/display/ContextInfoCard.js.map +1 -0
  89. package/dist/display/index.d.ts +2 -0
  90. package/dist/display/index.d.ts.map +1 -1
  91. package/dist/display/index.js +1 -0
  92. package/dist/display/index.js.map +1 -1
  93. package/dist/editor/CodeEditor.d.ts +39 -0
  94. package/dist/editor/CodeEditor.d.ts.map +1 -0
  95. package/dist/editor/CodeEditor.js +114 -0
  96. package/dist/editor/CodeEditor.js.map +1 -0
  97. package/dist/editor/MarkdownEditor.d.ts +3 -2
  98. package/dist/editor/MarkdownEditor.d.ts.map +1 -1
  99. package/dist/editor/MarkdownEditor.js +32 -80
  100. package/dist/editor/MarkdownEditor.js.map +1 -1
  101. package/dist/editor/SplitPreview.d.ts +10 -1
  102. package/dist/editor/SplitPreview.d.ts.map +1 -1
  103. package/dist/editor/SplitPreview.js +4 -2
  104. package/dist/editor/SplitPreview.js.map +1 -1
  105. package/dist/editor/codeLanguages.d.ts +28 -0
  106. package/dist/editor/codeLanguages.d.ts.map +1 -0
  107. package/dist/editor/codeLanguages.js +54 -0
  108. package/dist/editor/codeLanguages.js.map +1 -0
  109. package/dist/editor/index.d.ts +2 -0
  110. package/dist/editor/index.d.ts.map +1 -1
  111. package/dist/editor/index.js +6 -0
  112. package/dist/editor/index.js.map +1 -1
  113. package/dist/editor/theme.d.ts +16 -0
  114. package/dist/editor/theme.d.ts.map +1 -0
  115. package/dist/editor/theme.js +82 -0
  116. package/dist/editor/theme.js.map +1 -0
  117. package/dist/filters/filter-bar.d.ts +14 -0
  118. package/dist/filters/filter-bar.d.ts.map +1 -0
  119. package/dist/filters/filter-bar.js +47 -0
  120. package/dist/filters/filter-bar.js.map +1 -0
  121. package/dist/filters/filter-slot-config.d.ts +239 -0
  122. package/dist/filters/filter-slot-config.d.ts.map +1 -0
  123. package/dist/filters/filter-slot-config.js +24 -0
  124. package/dist/filters/filter-slot-config.js.map +1 -0
  125. package/dist/filters/index.d.ts +2 -0
  126. package/dist/filters/index.d.ts.map +1 -1
  127. package/dist/filters/index.js +1 -0
  128. package/dist/filters/index.js.map +1 -1
  129. package/dist/primitives/Card.d.ts +28 -0
  130. package/dist/primitives/Card.d.ts.map +1 -0
  131. package/dist/primitives/Card.js +30 -0
  132. package/dist/primitives/Card.js.map +1 -0
  133. package/dist/primitives/CollectionPicker.d.ts +47 -0
  134. package/dist/primitives/CollectionPicker.d.ts.map +1 -0
  135. package/dist/primitives/CollectionPicker.js +105 -0
  136. package/dist/primitives/CollectionPicker.js.map +1 -0
  137. package/dist/primitives/CreateEntityDialog.d.ts +144 -0
  138. package/dist/primitives/CreateEntityDialog.d.ts.map +1 -0
  139. package/dist/primitives/CreateEntityDialog.js +379 -0
  140. package/dist/primitives/CreateEntityDialog.js.map +1 -0
  141. package/dist/primitives/FormField.d.ts +29 -0
  142. package/dist/primitives/FormField.d.ts.map +1 -0
  143. package/dist/primitives/FormField.js +27 -0
  144. package/dist/primitives/FormField.js.map +1 -0
  145. package/dist/primitives/Label.d.ts +20 -0
  146. package/dist/primitives/Label.d.ts.map +1 -0
  147. package/dist/primitives/Label.js +21 -0
  148. package/dist/primitives/Label.js.map +1 -0
  149. package/dist/primitives/SecretField.d.ts +28 -0
  150. package/dist/primitives/SecretField.d.ts.map +1 -0
  151. package/dist/primitives/SecretField.js +65 -0
  152. package/dist/primitives/SecretField.js.map +1 -0
  153. package/dist/primitives/Spinner.d.ts +16 -0
  154. package/dist/primitives/Spinner.d.ts.map +1 -0
  155. package/dist/primitives/Spinner.js +34 -0
  156. package/dist/primitives/Spinner.js.map +1 -0
  157. package/dist/primitives/Switch.d.ts +32 -0
  158. package/dist/primitives/Switch.d.ts.map +1 -0
  159. package/dist/primitives/Switch.js +43 -0
  160. package/dist/primitives/Switch.js.map +1 -0
  161. package/dist/primitives/index.d.ts +16 -0
  162. package/dist/primitives/index.d.ts.map +1 -1
  163. package/dist/primitives/index.js +9 -0
  164. package/dist/primitives/index.js.map +1 -1
  165. package/dist/utils/type-colors.d.ts.map +1 -1
  166. package/dist/utils/type-colors.js +4 -0
  167. package/dist/utils/type-colors.js.map +1 -1
  168. package/package.json +40 -6
@@ -0,0 +1,105 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ /**
4
+ * CollectionPicker — @miethe/ui primitive
5
+ *
6
+ * A self-contained collection selection control for use inside creation
7
+ * dialogs. Renders a searchable combobox to pick which collection an artifact
8
+ * belongs to, with optional collapsible wrapping and auto-select when only one
9
+ * collection is available.
10
+ *
11
+ * The component is purely presentational: it accepts a pre-fetched `collections`
12
+ * list and delegates selection state upward via `onChange`. Pre-filling from the
13
+ * active collection context is the consumer's responsibility (pass the resolved
14
+ * ID as `defaultCollectionId`).
15
+ *
16
+ * @example Basic usage
17
+ * ```tsx
18
+ * <CollectionPicker
19
+ * config={{ enabled: true, required: true, collapsible: true }}
20
+ * collections={collections}
21
+ * value={selectedId}
22
+ * onChange={setSelectedId}
23
+ * defaultCollectionId={currentCollectionId}
24
+ * />
25
+ * ```
26
+ */
27
+ import * as React from 'react';
28
+ import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
29
+ import { ChevronDown, ChevronRight, Library } from 'lucide-react';
30
+ import { SearchableCombobox } from './SearchableCombobox';
31
+ import { cn } from './utils';
32
+ // ============================================================================
33
+ // Internal helpers
34
+ // ============================================================================
35
+ /** Filter collections by a search query (case-insensitive name/description match) */
36
+ function filterCollections(items, query) {
37
+ if (!query.trim())
38
+ return items;
39
+ const lower = query.toLowerCase();
40
+ return items.filter((c) => c.name.toLowerCase().includes(lower) ||
41
+ (c.description?.toLowerCase().includes(lower) ?? false));
42
+ }
43
+ function CollectionCombobox({ collections, value, onChange, required, disabled, labelId, }) {
44
+ const [query, setQuery] = React.useState('');
45
+ const filtered = React.useMemo(() => filterCollections(collections, query), [collections, query]);
46
+ const selectedCollection = value ? collections.find((c) => c.id === value) : undefined;
47
+ return (_jsxs("div", { className: "flex flex-col gap-1.5", children: [selectedCollection && (_jsxs("div", { className: cn('flex items-center gap-2 rounded-md border border-border bg-muted/40 px-3 py-2', 'text-sm text-foreground'), "aria-live": "polite", children: [_jsx(Library, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground", "aria-hidden": "true" }), _jsx("span", { className: "truncate font-medium", children: selectedCollection.name }), selectedCollection.description && (_jsxs("span", { className: "truncate text-muted-foreground", children: ["\u2014 ", selectedCollection.description] })), !disabled && (_jsx("button", { type: "button", onClick: () => {
48
+ onChange('');
49
+ setQuery('');
50
+ }, className: cn('ml-auto shrink-0 rounded-sm text-muted-foreground', 'hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring'), "aria-label": "Clear collection selection", children: _jsx("span", { "aria-hidden": "true", className: "text-xs leading-none", children: "\u00D7" }) }))] })), !disabled && (_jsx(SearchableCombobox, { items: filtered, onSearch: setQuery, onSelect: (item) => {
51
+ onChange(item.id);
52
+ setQuery('');
53
+ }, renderItem: (item) => (_jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("span", { className: "font-medium", children: item.name }), item.description && (_jsx("span", { className: "text-xs text-muted-foreground", children: item.description }))] })), getItemKey: (item) => item.id, placeholder: "Search collections\u2026", emptyMessage: "No matching collections", "aria-label": "Select collection", "aria-required": required, "aria-labelledby": labelId })), disabled && !selectedCollection && (_jsx("p", { className: "text-xs text-muted-foreground", children: "No collections available." }))] }));
54
+ }
55
+ // ============================================================================
56
+ // CollectionPicker
57
+ // ============================================================================
58
+ export function CollectionPicker({ config, value, onChange, defaultCollectionId, collections, className, }) {
59
+ const required = config.required ?? true;
60
+ const collapsible = config.collapsible ?? true;
61
+ // Auto-select: apply defaultCollectionId on first render if no value is set
62
+ const hasAppliedDefault = React.useRef(false);
63
+ React.useEffect(() => {
64
+ if (!hasAppliedDefault.current && !value && defaultCollectionId) {
65
+ const match = collections.find((c) => c.id === defaultCollectionId);
66
+ if (match) {
67
+ onChange(defaultCollectionId);
68
+ }
69
+ hasAppliedDefault.current = true;
70
+ }
71
+ }, [value, defaultCollectionId, collections, onChange]);
72
+ // When only one collection exists, auto-select and render read-only
73
+ const isSingleCollection = collections.length === 1;
74
+ React.useEffect(() => {
75
+ if (isSingleCollection && !value && collections[0]) {
76
+ onChange(collections[0].id);
77
+ }
78
+ }, [isSingleCollection, value, collections, onChange]);
79
+ // Collapsible open state — starts open when a value is already set
80
+ const [isOpen, setIsOpen] = React.useState(() => !collapsible || Boolean(value));
81
+ React.useEffect(() => {
82
+ // Open automatically if a default gets applied
83
+ if (value && collapsible && !isOpen) {
84
+ setIsOpen(true);
85
+ }
86
+ // eslint-disable-next-line react-hooks/exhaustive-deps
87
+ }, [value]);
88
+ // Stable ID for aria-labelledby wiring
89
+ const labelId = React.useId();
90
+ const combobox = (_jsx(CollectionCombobox, { collections: collections, value: value, onChange: onChange, required: required, disabled: isSingleCollection, labelId: labelId }));
91
+ // ── Non-collapsible layout ──────────────────────────────────────────────────
92
+ if (!collapsible) {
93
+ return (_jsxs("section", { className: cn('flex flex-col gap-2 rounded-lg border border-border p-4', className), "aria-label": "Collection selection", children: [_jsx(SectionLabel, { id: labelId, required: required }), combobox] }));
94
+ }
95
+ // ── Collapsible layout ──────────────────────────────────────────────────────
96
+ return (_jsxs(CollapsiblePrimitive.Root, { open: isOpen, onOpenChange: setIsOpen, className: cn('rounded-lg border border-border', className), children: [_jsx(CollapsiblePrimitive.Trigger, { asChild: true, children: _jsxs("button", { type: "button", className: cn('flex w-full items-center justify-between px-4 py-3 text-sm font-medium', 'rounded-t-lg text-left', 'hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring', 'transition-colors', !isOpen && 'rounded-b-lg'), "aria-expanded": isOpen, "aria-controls": `${labelId}-content`, children: [_jsx(SectionLabel, { id: labelId, required: required, asSpan: true }), isOpen ? (_jsx(ChevronDown, { className: "h-4 w-4 shrink-0 text-muted-foreground", "aria-hidden": "true" })) : (_jsx(ChevronRight, { className: "h-4 w-4 shrink-0 text-muted-foreground", "aria-hidden": "true" }))] }) }), _jsx(CollapsiblePrimitive.Content, { id: `${labelId}-content`, className: cn('overflow-hidden px-4 pb-4 pt-1', 'data-[state=open]:animate-collapsible-down', 'data-[state=closed]:animate-collapsible-up'), children: combobox })] }));
97
+ }
98
+ function SectionLabel({ id, required, asSpan = false }) {
99
+ const content = (_jsxs(_Fragment, { children: [_jsx(Library, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground", "aria-hidden": "true" }), _jsxs("span", { children: ["Collection", required && (_jsx("span", { className: "ml-1 text-destructive", "aria-hidden": "true", children: "*" })), required && _jsx("span", { className: "sr-only", children: "(required)" })] })] }));
100
+ if (asSpan) {
101
+ return (_jsx("span", { id: id, className: "flex items-center gap-2 font-medium", children: content }));
102
+ }
103
+ return (_jsx("label", { id: id, className: "flex items-center gap-2 text-sm font-medium", children: content }));
104
+ }
105
+ //# sourceMappingURL=CollectionPicker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CollectionPicker.js","sourceRoot":"","sources":["../../src/primitives/CollectionPicker.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * CreateEntityDialog — @miethe/ui primitive
3
+ *
4
+ * A schema-driven creation dialog for any entity type.
5
+ * Dynamically renders form fields from an `EntityFormSchema` definition using
6
+ * react-hook-form for state management and per-field validation.
7
+ *
8
+ * Only the `simple` mode is fully implemented here. `tabs` and `composite`
9
+ * modes render a placeholder until PRIM-003 / PRIM-004 are complete.
10
+ *
11
+ * @example Simple usage
12
+ * ```tsx
13
+ * <CreateEntityDialog
14
+ * open={isOpen}
15
+ * onOpenChange={setIsOpen}
16
+ * schema={{
17
+ * mode: 'simple',
18
+ * fields: [
19
+ * { name: 'name', label: 'Name', type: 'text', required: true },
20
+ * { name: 'description', label: 'Description', type: 'textarea' },
21
+ * ],
22
+ * }}
23
+ * onSubmit={async (values) => { await create(values); }}
24
+ * title="Create Skill"
25
+ * description="Add a new skill to your collection"
26
+ * />
27
+ * ```
28
+ */
29
+ import * as React from 'react';
30
+ import { type UseFormReturn } from 'react-hook-form';
31
+ export interface FieldOption {
32
+ label: string;
33
+ value: string;
34
+ }
35
+ export type FieldType = 'text' | 'textarea' | 'select' | 'multiselect' | 'number' | 'boolean' | 'tags';
36
+ export interface FieldDef {
37
+ name: string;
38
+ label: string;
39
+ type: FieldType;
40
+ required?: boolean;
41
+ placeholder?: string;
42
+ description?: string;
43
+ options?: FieldOption[];
44
+ defaultValue?: unknown;
45
+ /** Optional Zod schema — used for `.parse()` based validation when provided */
46
+ validation?: {
47
+ safeParse: (v: unknown) => {
48
+ success: boolean;
49
+ error?: {
50
+ issues: Array<{
51
+ message: string;
52
+ }>;
53
+ };
54
+ };
55
+ };
56
+ }
57
+ export interface CollectionPickerConfig {
58
+ enabled: boolean;
59
+ required?: boolean;
60
+ collapsible?: boolean;
61
+ defaultCollectionId?: string;
62
+ }
63
+ export interface SimpleFormSchema {
64
+ mode: 'simple';
65
+ fields: FieldDef[];
66
+ collection?: CollectionPickerConfig;
67
+ }
68
+ export interface TabDef {
69
+ id: string;
70
+ label: string;
71
+ /** Optional Lucide-compatible icon component */
72
+ icon?: React.ComponentType<{
73
+ className?: string;
74
+ }>;
75
+ fields: FieldDef[];
76
+ /** Escape hatch: when provided, bypasses field-list rendering for this tab */
77
+ renderTabContent?: (form: UseFormReturn<Record<string, unknown>>) => React.ReactNode;
78
+ }
79
+ export interface TabsFormSchema {
80
+ mode: 'tabs';
81
+ tabs: TabDef[];
82
+ collection?: CollectionPickerConfig;
83
+ }
84
+ export interface MemberPickerConfig {
85
+ entityType: string;
86
+ label: string;
87
+ validateMin?: number;
88
+ validateMax?: number;
89
+ }
90
+ export interface CompositeFormSchema {
91
+ mode: 'composite';
92
+ tabs: TabDef[];
93
+ members: MemberPickerConfig;
94
+ /**
95
+ * Optional custom review step rendered as the final tab.
96
+ * When omitted, a default summary of fields + selected members is shown.
97
+ */
98
+ renderReviewStep?: (ctx: {
99
+ values: Record<string, unknown>;
100
+ memberIds: string[];
101
+ }) => React.ReactNode;
102
+ collection?: CollectionPickerConfig;
103
+ }
104
+ export type EntityFormSchema = SimpleFormSchema | TabsFormSchema | CompositeFormSchema;
105
+ export interface CollectionItem {
106
+ id: string;
107
+ name: string;
108
+ description?: string;
109
+ }
110
+ export interface CreateEntityDialogProps {
111
+ /** Whether the dialog is open */
112
+ open: boolean;
113
+ /** Called when the dialog open state changes */
114
+ onOpenChange: (open: boolean) => void;
115
+ /** Schema that drives field rendering and validation */
116
+ schema: EntityFormSchema;
117
+ /** Called with form values on submit */
118
+ onSubmit: (values: Record<string, unknown>) => void | Promise<void>;
119
+ /** Dialog title */
120
+ title: string;
121
+ /** Optional subtitle shown below the title */
122
+ description?: string;
123
+ /** Label for the submit button (default: "Create") */
124
+ submitLabel?: string;
125
+ /** When true, submit button shows loading state */
126
+ isSubmitting?: boolean;
127
+ /** Inline error message shown as an alert banner */
128
+ error?: string;
129
+ /** Available collections for the collection picker */
130
+ collections?: CollectionItem[];
131
+ /** Pre-selected collection ID */
132
+ defaultCollectionId?: string;
133
+ /**
134
+ * Controlled member IDs for composite mode.
135
+ * When provided, the composite member picker uses this as the initial value.
136
+ */
137
+ memberIds?: string[];
138
+ /**
139
+ * Called when the member IDs change in composite mode.
140
+ */
141
+ onMemberIdsChange?: (ids: string[]) => void;
142
+ }
143
+ export declare function CreateEntityDialog({ open, onOpenChange, schema, onSubmit, title, description, submitLabel, isSubmitting, error, collections, defaultCollectionId, memberIds: controlledMemberIds, onMemberIdsChange: onControlledMemberIdsChange, }: CreateEntityDialogProps): import("react/jsx-runtime").JSX.Element;
144
+ //# sourceMappingURL=CreateEntityDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreateEntityDialog.d.ts","sourceRoot":"","sources":["../../src/primitives/CreateEntityDialog.tsx"],"names":[],"mappings":"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"}