@modern-admin/ui 0.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.
Files changed (268) hide show
  1. package/dist/components/accordion.d.ts +7 -0
  2. package/dist/components/accordion.d.ts.map +1 -0
  3. package/dist/components/accordion.jsx +19 -0
  4. package/dist/components/accordion.jsx.map +1 -0
  5. package/dist/components/alert-dialog.d.ts +22 -0
  6. package/dist/components/alert-dialog.d.ts.map +1 -0
  7. package/dist/components/alert-dialog.jsx +27 -0
  8. package/dist/components/alert-dialog.jsx.map +1 -0
  9. package/dist/components/audit-timeline.d.ts +24 -0
  10. package/dist/components/audit-timeline.d.ts.map +1 -0
  11. package/dist/components/audit-timeline.jsx +60 -0
  12. package/dist/components/audit-timeline.jsx.map +1 -0
  13. package/dist/components/avatar.d.ts +6 -0
  14. package/dist/components/avatar.d.ts.map +1 -0
  15. package/dist/components/avatar.jsx +10 -0
  16. package/dist/components/avatar.jsx.map +1 -0
  17. package/dist/components/badge.d.ts +10 -0
  18. package/dist/components/badge.d.ts.map +1 -0
  19. package/dist/components/badge.jsx +19 -0
  20. package/dist/components/badge.jsx.map +1 -0
  21. package/dist/components/breadcrumb.d.ts +17 -0
  22. package/dist/components/breadcrumb.d.ts.map +1 -0
  23. package/dist/components/breadcrumb.jsx +27 -0
  24. package/dist/components/breadcrumb.jsx.map +1 -0
  25. package/dist/components/button.d.ts +12 -0
  26. package/dist/components/button.d.ts.map +1 -0
  27. package/dist/components/button.jsx +37 -0
  28. package/dist/components/button.jsx.map +1 -0
  29. package/dist/components/calendar.d.ts +9 -0
  30. package/dist/components/calendar.d.ts.map +1 -0
  31. package/dist/components/calendar.jsx +102 -0
  32. package/dist/components/calendar.jsx.map +1 -0
  33. package/dist/components/card.d.ts +8 -0
  34. package/dist/components/card.d.ts.map +1 -0
  35. package/dist/components/card.jsx +18 -0
  36. package/dist/components/card.jsx.map +1 -0
  37. package/dist/components/chart.d.ts +97 -0
  38. package/dist/components/chart.d.ts.map +1 -0
  39. package/dist/components/chart.jsx +233 -0
  40. package/dist/components/chart.jsx.map +1 -0
  41. package/dist/components/checkbox.d.ts +4 -0
  42. package/dist/components/checkbox.d.ts.map +1 -0
  43. package/dist/components/checkbox.jsx +11 -0
  44. package/dist/components/checkbox.jsx.map +1 -0
  45. package/dist/components/combobox.d.ts +46 -0
  46. package/dist/components/combobox.d.ts.map +1 -0
  47. package/dist/components/combobox.jsx +145 -0
  48. package/dist/components/combobox.jsx.map +1 -0
  49. package/dist/components/command.d.ts +80 -0
  50. package/dist/components/command.d.ts.map +1 -0
  51. package/dist/components/command.jsx +32 -0
  52. package/dist/components/command.jsx.map +1 -0
  53. package/dist/components/date-picker.d.ts +24 -0
  54. package/dist/components/date-picker.d.ts.map +1 -0
  55. package/dist/components/date-picker.jsx +149 -0
  56. package/dist/components/date-picker.jsx.map +1 -0
  57. package/dist/components/date-range-input.d.ts +22 -0
  58. package/dist/components/date-range-input.d.ts.map +1 -0
  59. package/dist/components/date-range-input.jsx +202 -0
  60. package/dist/components/date-range-input.jsx.map +1 -0
  61. package/dist/components/dialog.d.ts +19 -0
  62. package/dist/components/dialog.d.ts.map +1 -0
  63. package/dist/components/dialog.jsx +30 -0
  64. package/dist/components/dialog.jsx.map +1 -0
  65. package/dist/components/diff-view.d.ts +24 -0
  66. package/dist/components/diff-view.d.ts.map +1 -0
  67. package/dist/components/diff-view.jsx +69 -0
  68. package/dist/components/diff-view.jsx.map +1 -0
  69. package/dist/components/dropdown-menu.d.ts +27 -0
  70. package/dist/components/dropdown-menu.d.ts.map +1 -0
  71. package/dist/components/dropdown-menu.jsx +48 -0
  72. package/dist/components/dropdown-menu.jsx.map +1 -0
  73. package/dist/components/empty.d.ts +15 -0
  74. package/dist/components/empty.d.ts.map +1 -0
  75. package/dist/components/empty.jsx +27 -0
  76. package/dist/components/empty.jsx.map +1 -0
  77. package/dist/components/field.d.ts +23 -0
  78. package/dist/components/field.d.ts.map +1 -0
  79. package/dist/components/field.jsx +60 -0
  80. package/dist/components/field.jsx.map +1 -0
  81. package/dist/components/file-input.d.ts +50 -0
  82. package/dist/components/file-input.d.ts.map +1 -0
  83. package/dist/components/file-input.jsx +104 -0
  84. package/dist/components/file-input.jsx.map +1 -0
  85. package/dist/components/form.d.ts +20 -0
  86. package/dist/components/form.d.ts.map +1 -0
  87. package/dist/components/form.jsx +66 -0
  88. package/dist/components/form.jsx.map +1 -0
  89. package/dist/components/info-tooltip.d.ts +11 -0
  90. package/dist/components/info-tooltip.d.ts.map +1 -0
  91. package/dist/components/info-tooltip.jsx +17 -0
  92. package/dist/components/info-tooltip.jsx.map +1 -0
  93. package/dist/components/input.d.ts +13 -0
  94. package/dist/components/input.d.ts.map +1 -0
  95. package/dist/components/input.jsx +19 -0
  96. package/dist/components/input.jsx.map +1 -0
  97. package/dist/components/json-editor.d.ts +23 -0
  98. package/dist/components/json-editor.d.ts.map +1 -0
  99. package/dist/components/json-editor.jsx +143 -0
  100. package/dist/components/json-editor.jsx.map +1 -0
  101. package/dist/components/kbd.d.ts +15 -0
  102. package/dist/components/kbd.d.ts.map +1 -0
  103. package/dist/components/kbd.jsx +23 -0
  104. package/dist/components/kbd.jsx.map +1 -0
  105. package/dist/components/key-value-editor.d.ts +92 -0
  106. package/dist/components/key-value-editor.d.ts.map +1 -0
  107. package/dist/components/key-value-editor.jsx +187 -0
  108. package/dist/components/key-value-editor.jsx.map +1 -0
  109. package/dist/components/keyboard-shortcuts-help.d.ts +17 -0
  110. package/dist/components/keyboard-shortcuts-help.d.ts.map +1 -0
  111. package/dist/components/keyboard-shortcuts-help.jsx +97 -0
  112. package/dist/components/keyboard-shortcuts-help.jsx.map +1 -0
  113. package/dist/components/label.d.ts +5 -0
  114. package/dist/components/label.d.ts.map +1 -0
  115. package/dist/components/label.jsx +8 -0
  116. package/dist/components/label.jsx.map +1 -0
  117. package/dist/components/media-preview.d.ts +30 -0
  118. package/dist/components/media-preview.d.ts.map +1 -0
  119. package/dist/components/media-preview.jsx +189 -0
  120. package/dist/components/media-preview.jsx.map +1 -0
  121. package/dist/components/multi-file-input.d.ts +76 -0
  122. package/dist/components/multi-file-input.d.ts.map +1 -0
  123. package/dist/components/multi-file-input.jsx +131 -0
  124. package/dist/components/multi-file-input.jsx.map +1 -0
  125. package/dist/components/password-input.d.ts +10 -0
  126. package/dist/components/password-input.d.ts.map +1 -0
  127. package/dist/components/password-input.jsx +18 -0
  128. package/dist/components/password-input.jsx.map +1 -0
  129. package/dist/components/popover.d.ts +7 -0
  130. package/dist/components/popover.d.ts.map +1 -0
  131. package/dist/components/popover.jsx +11 -0
  132. package/dist/components/popover.jsx.map +1 -0
  133. package/dist/components/revision-timeline.d.ts +30 -0
  134. package/dist/components/revision-timeline.d.ts.map +1 -0
  135. package/dist/components/revision-timeline.jsx +42 -0
  136. package/dist/components/revision-timeline.jsx.map +1 -0
  137. package/dist/components/richtext-editor.d.ts +43 -0
  138. package/dist/components/richtext-editor.d.ts.map +1 -0
  139. package/dist/components/richtext-editor.jsx +319 -0
  140. package/dist/components/richtext-editor.jsx.map +1 -0
  141. package/dist/components/richtext-mode.d.ts +23 -0
  142. package/dist/components/richtext-mode.d.ts.map +1 -0
  143. package/dist/components/richtext-mode.js +36 -0
  144. package/dist/components/richtext-mode.js.map +1 -0
  145. package/dist/components/richtext-render.d.ts +8 -0
  146. package/dist/components/richtext-render.d.ts.map +1 -0
  147. package/dist/components/richtext-render.jsx +33 -0
  148. package/dist/components/richtext-render.jsx.map +1 -0
  149. package/dist/components/richtext-sync.d.ts +37 -0
  150. package/dist/components/richtext-sync.d.ts.map +1 -0
  151. package/dist/components/richtext-sync.js +46 -0
  152. package/dist/components/richtext-sync.js.map +1 -0
  153. package/dist/components/scroll-area.d.ts +5 -0
  154. package/dist/components/scroll-area.d.ts.map +1 -0
  155. package/dist/components/scroll-area.jsx +16 -0
  156. package/dist/components/scroll-area.jsx.map +1 -0
  157. package/dist/components/select.d.ts +36 -0
  158. package/dist/components/select.d.ts.map +1 -0
  159. package/dist/components/select.jsx +87 -0
  160. package/dist/components/select.jsx.map +1 -0
  161. package/dist/components/separator.d.ts +4 -0
  162. package/dist/components/separator.d.ts.map +1 -0
  163. package/dist/components/separator.jsx +6 -0
  164. package/dist/components/separator.jsx.map +1 -0
  165. package/dist/components/sheet.d.ts +29 -0
  166. package/dist/components/sheet.d.ts.map +1 -0
  167. package/dist/components/sheet.jsx +44 -0
  168. package/dist/components/sheet.jsx.map +1 -0
  169. package/dist/components/sidebar.d.ts +70 -0
  170. package/dist/components/sidebar.d.ts.map +1 -0
  171. package/dist/components/sidebar.jsx +245 -0
  172. package/dist/components/sidebar.jsx.map +1 -0
  173. package/dist/components/skeleton.d.ts +3 -0
  174. package/dist/components/skeleton.d.ts.map +1 -0
  175. package/dist/components/skeleton.jsx +6 -0
  176. package/dist/components/skeleton.jsx.map +1 -0
  177. package/dist/components/sonner.d.ts +6 -0
  178. package/dist/components/sonner.d.ts.map +1 -0
  179. package/dist/components/sonner.jsx +29 -0
  180. package/dist/components/sonner.jsx.map +1 -0
  181. package/dist/components/switch.d.ts +4 -0
  182. package/dist/components/switch.d.ts.map +1 -0
  183. package/dist/components/switch.jsx +8 -0
  184. package/dist/components/switch.jsx.map +1 -0
  185. package/dist/components/table.d.ts +10 -0
  186. package/dist/components/table.d.ts.map +1 -0
  187. package/dist/components/table.jsx +21 -0
  188. package/dist/components/table.jsx.map +1 -0
  189. package/dist/components/tabs.d.ts +7 -0
  190. package/dist/components/tabs.d.ts.map +1 -0
  191. package/dist/components/tabs.jsx +14 -0
  192. package/dist/components/tabs.jsx.map +1 -0
  193. package/dist/components/textarea.d.ts +4 -0
  194. package/dist/components/textarea.d.ts.map +1 -0
  195. package/dist/components/textarea.jsx +5 -0
  196. package/dist/components/textarea.jsx.map +1 -0
  197. package/dist/components/tooltip.d.ts +7 -0
  198. package/dist/components/tooltip.d.ts.map +1 -0
  199. package/dist/components/tooltip.jsx +11 -0
  200. package/dist/components/tooltip.jsx.map +1 -0
  201. package/dist/index.d.ts +52 -0
  202. package/dist/index.d.ts.map +1 -0
  203. package/dist/index.js +72 -0
  204. package/dist/index.js.map +1 -0
  205. package/dist/lib/theme.d.ts +11 -0
  206. package/dist/lib/theme.d.ts.map +1 -0
  207. package/dist/lib/theme.js +44 -0
  208. package/dist/lib/theme.js.map +1 -0
  209. package/dist/lib/utils.d.ts +3 -0
  210. package/dist/lib/utils.d.ts.map +1 -0
  211. package/dist/lib/utils.js +6 -0
  212. package/dist/lib/utils.js.map +1 -0
  213. package/dist/styles.css +242 -0
  214. package/package.json +85 -0
  215. package/src/components/accordion.tsx +48 -0
  216. package/src/components/alert-dialog.tsx +113 -0
  217. package/src/components/audit-timeline.tsx +102 -0
  218. package/src/components/avatar.tsx +42 -0
  219. package/src/components/badge.tsx +34 -0
  220. package/src/components/breadcrumb.tsx +99 -0
  221. package/src/components/button.tsx +58 -0
  222. package/src/components/calendar.tsx +176 -0
  223. package/src/components/card.tsx +60 -0
  224. package/src/components/chart.tsx +558 -0
  225. package/src/components/checkbox.tsx +23 -0
  226. package/src/components/combobox.tsx +264 -0
  227. package/src/components/command.tsx +120 -0
  228. package/src/components/date-picker.tsx +221 -0
  229. package/src/components/date-range-input.tsx +295 -0
  230. package/src/components/dialog.tsx +94 -0
  231. package/src/components/diff-view.tsx +182 -0
  232. package/src/components/dropdown-menu.tsx +165 -0
  233. package/src/components/empty.tsx +100 -0
  234. package/src/components/field.tsx +168 -0
  235. package/src/components/file-input.tsx +233 -0
  236. package/src/components/form.tsx +152 -0
  237. package/src/components/info-tooltip.tsx +40 -0
  238. package/src/components/input.tsx +55 -0
  239. package/src/components/json-editor.tsx +210 -0
  240. package/src/components/kbd.tsx +35 -0
  241. package/src/components/key-value-editor.tsx +423 -0
  242. package/src/components/keyboard-shortcuts-help.tsx +136 -0
  243. package/src/components/label.tsx +16 -0
  244. package/src/components/media-preview.tsx +278 -0
  245. package/src/components/multi-file-input.tsx +315 -0
  246. package/src/components/password-input.tsx +50 -0
  247. package/src/components/popover.tsx +26 -0
  248. package/src/components/revision-timeline.tsx +93 -0
  249. package/src/components/richtext-editor.tsx +624 -0
  250. package/src/components/richtext-mode.ts +39 -0
  251. package/src/components/richtext-render.tsx +51 -0
  252. package/src/components/richtext-sync.ts +57 -0
  253. package/src/components/scroll-area.tsx +41 -0
  254. package/src/components/select.tsx +200 -0
  255. package/src/components/separator.tsx +21 -0
  256. package/src/components/sheet.tsx +109 -0
  257. package/src/components/sidebar.tsx +660 -0
  258. package/src/components/skeleton.tsx +9 -0
  259. package/src/components/sonner.tsx +45 -0
  260. package/src/components/switch.tsx +24 -0
  261. package/src/components/table.tsx +93 -0
  262. package/src/components/tabs.tsx +57 -0
  263. package/src/components/textarea.tsx +18 -0
  264. package/src/components/tooltip.tsx +25 -0
  265. package/src/index.ts +342 -0
  266. package/src/lib/theme.ts +45 -0
  267. package/src/lib/utils.ts +6 -0
  268. package/src/styles.css +242 -0
@@ -0,0 +1,187 @@
1
+ // KeyValueEditor + KeyValueView — a friendly alternative to JsonEditor for
2
+ // JSON columns with a *fixed* set of keys.
3
+ //
4
+ // Instead of showing the raw JSON (`{ "locale": "en", "featured": true }`)
5
+ // the editor renders one row per declared key, each with a normal form
6
+ // input typed appropriately (string, number, boolean, textarea, select).
7
+ // No braces, no quotes, no parse errors — the user just edits the values.
8
+ //
9
+ // The component is i18n-unaware: it accepts an optional `labels` prop with
10
+ // English fallbacks so it works standalone in tests/Storybook. The
11
+ // `packages/react` layer translates and feeds them in.
12
+ //
13
+ // Mobile-first: each row stacks label-above-input on narrow screens and
14
+ // switches to a two-column label/input layout from `sm:` upwards.
15
+ import * as React from 'react';
16
+ import { cn } from '../lib/utils.js';
17
+ import { Input } from './input.js';
18
+ import { Textarea } from './textarea.js';
19
+ import { Switch } from './switch.js';
20
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from './select.js';
21
+ import { Combobox } from './combobox.js';
22
+ import { InfoTooltip } from './info-tooltip.js';
23
+ const defaultLabels = {
24
+ emptyOption: '—',
25
+ fieldLabelFallback: (key) => key,
26
+ };
27
+ const toRecord = (value) => {
28
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
29
+ return value;
30
+ }
31
+ return {};
32
+ };
33
+ const normaliseAvailableValues = (raw) => {
34
+ if (!raw)
35
+ return [];
36
+ return raw.map((v) => (typeof v === 'string' ? { value: v, label: v } : v));
37
+ };
38
+ const SENTINEL_EMPTY = '__kv_empty__';
39
+ export function KeyValueEditor({ fields, value, onChange, onBlur, disabled, className, labels, suggestionsByKey, suggestionsLoadingByKey, }) {
40
+ const l = { ...defaultLabels, ...labels };
41
+ const obj = toRecord(value);
42
+ // Replace `key` with `next` and emit a brand-new object so callers using
43
+ // referential equality (e.g. RHF) detect the change.
44
+ const set = (key, next) => {
45
+ const out = { ...obj };
46
+ if (next === null || next === undefined) {
47
+ delete out[key];
48
+ }
49
+ else {
50
+ out[key] = next;
51
+ }
52
+ onChange(out);
53
+ };
54
+ return (<div className={cn('divide-y divide-border rounded-md border border-border bg-card', className)}>
55
+ {fields.map((f) => {
56
+ const fieldType = f.type ?? 'string';
57
+ const label = f.label ?? l.fieldLabelFallback(f.key);
58
+ const inputId = `kv-${f.key}`;
59
+ const raw = obj[f.key];
60
+ let control;
61
+ if (fieldType === 'boolean') {
62
+ control = (<Switch id={inputId} checked={Boolean(raw)} onCheckedChange={(v) => set(f.key, Boolean(v))} disabled={disabled} aria-label={label}/>);
63
+ }
64
+ else if (fieldType === 'number') {
65
+ control = (<Input id={inputId} type="number" inputMode="decimal" value={raw == null ? '' : String(raw)} placeholder={f.placeholder} disabled={disabled} onBlur={onBlur} onChange={(e) => {
66
+ const v = e.target.value;
67
+ if (v === '')
68
+ return set(f.key, null);
69
+ const n = Number(v);
70
+ set(f.key, Number.isFinite(n) ? n : v);
71
+ }} aria-label={label}/>);
72
+ }
73
+ else if (fieldType === 'textarea') {
74
+ control = (<Textarea id={inputId} value={raw == null ? '' : String(raw)} placeholder={f.placeholder} disabled={disabled} onBlur={onBlur} onChange={(e) => set(f.key, e.target.value === '' ? null : e.target.value)} rows={3} aria-label={label}/>);
75
+ }
76
+ else if (fieldType === 'select') {
77
+ const opts = normaliseAvailableValues(f.availableValues);
78
+ const current = raw == null || raw === '' ? SENTINEL_EMPTY : String(raw);
79
+ control = (<Select value={current} onValueChange={(v) => set(f.key, v === SENTINEL_EMPTY ? null : v)} disabled={disabled}>
80
+ <SelectTrigger id={inputId} aria-label={label}>
81
+ <SelectValue placeholder={l.emptyOption}/>
82
+ </SelectTrigger>
83
+ <SelectContent>
84
+ <SelectItem value={SENTINEL_EMPTY}>{l.emptyOption}</SelectItem>
85
+ {opts.map((opt) => (<SelectItem key={opt.value} value={opt.value}>
86
+ {opt.label}
87
+ </SelectItem>))}
88
+ </SelectContent>
89
+ </Select>);
90
+ }
91
+ else if (fieldType === 'autocomplete') {
92
+ // Combine static `availableValues` declared on the field with
93
+ // any dynamic values pre-loaded by the parent (e.g. distinct
94
+ // values from a DB column). Dedupe by `value` so a static hint
95
+ // and a DB row that share a value collapse to a single item.
96
+ const fromStatic = normaliseAvailableValues(f.availableValues);
97
+ const fromDynamic = suggestionsByKey?.[f.key] ?? [];
98
+ const seen = new Set();
99
+ const merged = [];
100
+ for (const s of [...fromStatic, ...fromDynamic]) {
101
+ const v = typeof s === 'string' ? s : s.value;
102
+ if (seen.has(v))
103
+ continue;
104
+ seen.add(v);
105
+ merged.push(s);
106
+ }
107
+ control = (<Combobox id={inputId} value={raw == null ? '' : String(raw)} onChange={(v) => set(f.key, v === '' ? null : v)} onBlur={onBlur} suggestions={merged} loading={suggestionsLoadingByKey?.[f.key]} disabled={disabled} placeholder={f.placeholder} aria-label={label} labels={labels?.combobox}/>);
108
+ }
109
+ else {
110
+ // string (default)
111
+ control = (<Input id={inputId} type="text" value={raw == null ? '' : String(raw)} placeholder={f.placeholder} disabled={disabled} onBlur={onBlur} onChange={(e) => set(f.key, e.target.value === '' ? null : e.target.value)} aria-label={label}/>);
112
+ }
113
+ return (<div key={f.key} className="flex flex-col gap-1.5 p-3 sm:flex-row sm:items-start sm:gap-4">
114
+ <label htmlFor={inputId} className="flex shrink-0 items-center gap-1 text-sm font-medium text-foreground sm:w-44 sm:pt-2">
115
+ <span className="truncate">{label}</span>
116
+ {f.description ? (<InfoTooltip content={f.description} ariaLabel={f.description}/>) : null}
117
+ {f.isRequired ? (<span aria-hidden="true" className="text-destructive">
118
+ *
119
+ </span>) : null}
120
+ </label>
121
+ <div className="min-w-0 flex-1">
122
+ {control}
123
+ </div>
124
+ </div>);
125
+ })}
126
+ </div>);
127
+ }
128
+ const defaultViewLabels = {
129
+ emptyValue: '—',
130
+ fieldLabelFallback: (key) => key,
131
+ trueLabel: 'Yes',
132
+ falseLabel: 'No',
133
+ };
134
+ const stringifyDisplay = (raw, field, l) => {
135
+ if (raw == null || raw === '')
136
+ return l.emptyValue;
137
+ if (field.type === 'boolean')
138
+ return raw ? l.trueLabel : l.falseLabel;
139
+ if ((field.type === 'select' || field.type === 'autocomplete') &&
140
+ field.availableValues) {
141
+ const opts = normaliseAvailableValues(field.availableValues);
142
+ const match = opts.find((o) => o.value === String(raw));
143
+ return match?.label ?? String(raw);
144
+ }
145
+ if (typeof raw === 'object') {
146
+ try {
147
+ return JSON.stringify(raw);
148
+ }
149
+ catch {
150
+ return String(raw);
151
+ }
152
+ }
153
+ return String(raw);
154
+ };
155
+ export function KeyValueView({ fields, value, className, variant = 'block', labels, }) {
156
+ const l = { ...defaultViewLabels, ...labels };
157
+ const obj = toRecord(value);
158
+ if (variant === 'inline') {
159
+ const parts = fields
160
+ .map((f) => {
161
+ const raw = obj[f.key];
162
+ if (raw == null || raw === '')
163
+ return null;
164
+ const label = f.label ?? l.fieldLabelFallback(f.key);
165
+ return `${label}: ${stringifyDisplay(raw, f, l)}`;
166
+ })
167
+ .filter((s) => s !== null);
168
+ return (<span className={cn('line-clamp-1 max-w-[24rem] truncate text-xs text-muted-foreground', className)} title={parts.join(', ') || undefined}>
169
+ {parts.length > 0 ? parts.join(', ') : l.emptyValue}
170
+ </span>);
171
+ }
172
+ return (<dl className={cn('divide-y divide-border rounded-md border border-border bg-muted/30 text-sm', className)}>
173
+ {fields.map((f) => {
174
+ const label = f.label ?? l.fieldLabelFallback(f.key);
175
+ const text = stringifyDisplay(obj[f.key], f, l);
176
+ return (<div key={f.key} className="flex flex-col gap-0.5 p-3 sm:flex-row sm:items-baseline sm:gap-4">
177
+ <dt className="shrink-0 text-xs font-medium uppercase tracking-wide text-muted-foreground sm:w-44">
178
+ {label}
179
+ </dt>
180
+ <dd className="min-w-0 flex-1 break-words text-foreground">
181
+ {text}
182
+ </dd>
183
+ </div>);
184
+ })}
185
+ </dl>);
186
+ }
187
+ //# sourceMappingURL=key-value-editor.jsx.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-value-editor.jsx","sourceRoot":"","sources":["../../src/components/key-value-editor.tsx"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,2CAA2C;AAC3C,EAAE;AACF,2EAA2E;AAC3E,uEAAuE;AACvE,yEAAyE;AACzE,0EAA0E;AAC1E,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,uDAAuD;AACvD,EAAE;AACF,wEAAwE;AACxE,kEAAkE;AAElE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAA;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EACL,MAAM,EACN,aAAa,EACb,UAAU,EACV,aAAa,EACb,WAAW,GACZ,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,QAAQ,EAAgD,MAAM,eAAe,CAAA;AACtF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AA0E/C,MAAM,aAAa,GACwB;IACvC,WAAW,EAAE,GAAG;IAChB,kBAAkB,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG;CACjC,CAAA;AAEH,MAAM,QAAQ,GAAG,CAAC,KAAc,EAA2B,EAAE;IAC3D,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChE,OAAO,KAAgC,CAAA;IACzC,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC,CAAA;AAED,MAAM,wBAAwB,GAAG,CAC/B,GAAyC,EACA,EAAE;IAC3C,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAA;IACnB,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAC7E,CAAC,CAAA;AAED,MAAM,cAAc,GAAG,cAAc,CAAA;AAErC,MAAM,UAAU,cAAc,CAAC,EAC7B,MAAM,EACN,KAAK,EACL,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,SAAS,EACT,MAAM,EACN,gBAAgB,EAChB,uBAAuB,GACH;IACpB,MAAM,CAAC,GAAG,EAAE,GAAG,aAAa,EAAE,GAAG,MAAM,EAAE,CAAA;IACzC,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE3B,yEAAyE;IACzE,qDAAqD;IACrD,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,IAAa,EAAQ,EAAE;QAC/C,MAAM,GAAG,GAA4B,EAAE,GAAG,GAAG,EAAE,CAAA;QAC/C,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACxC,OAAO,GAAG,CAAC,GAAG,CAAC,CAAA;QACjB,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAA;QACjB,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,CAAA;IACf,CAAC,CAAA;IAED,OAAO,CACL,CAAC,GAAG,CACF,SAAS,CAAC,CAAC,EAAE,CACX,gEAAgE,EAChE,SAAS,CACV,CAAC,CAEF;MAAA,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YAChB,MAAM,SAAS,GAAsB,CAAC,CAAC,IAAI,IAAI,QAAQ,CAAA;YACvD,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;YACpD,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE,CAAA;YAC7B,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;YAEtB,IAAI,OAA2B,CAAA;YAC/B,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,OAAO,GAAG,CACR,CAAC,MAAM,CACL,EAAE,CAAC,CAAC,OAAO,CAAC,CACZ,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CACtB,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAC/C,QAAQ,CAAC,CAAC,QAAQ,CAAC,CACnB,UAAU,CAAC,CAAC,KAAK,CAAC,EAClB,CACH,CAAA;YACH,CAAC;iBAAM,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;gBAClC,OAAO,GAAG,CACR,CAAC,KAAK,CACJ,EAAE,CAAC,CAAC,OAAO,CAAC,CACZ,IAAI,CAAC,QAAQ,CACb,SAAS,CAAC,SAAS,CACnB,KAAK,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CACtC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAC3B,QAAQ,CAAC,CAAC,QAAQ,CAAC,CACnB,MAAM,CAAC,CAAC,MAAM,CAAC,CACf,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;wBACd,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAA;wBACxB,IAAI,CAAC,KAAK,EAAE;4BAAE,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;wBACrC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;wBACnB,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;oBACxC,CAAC,CAAC,CACF,UAAU,CAAC,CAAC,KAAK,CAAC,EAClB,CACH,CAAA;YACH,CAAC;iBAAM,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;gBACpC,OAAO,GAAG,CACR,CAAC,QAAQ,CACP,EAAE,CAAC,CAAC,OAAO,CAAC,CACZ,KAAK,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CACtC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAC3B,QAAQ,CAAC,CAAC,QAAQ,CAAC,CACnB,MAAM,CAAC,CAAC,MAAM,CAAC,CACf,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CACd,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAC1D,CAAC,CACD,IAAI,CAAC,CAAC,CAAC,CAAC,CACR,UAAU,CAAC,CAAC,KAAK,CAAC,EAClB,CACH,CAAA;YACH,CAAC;iBAAM,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;gBAClC,MAAM,IAAI,GAAG,wBAAwB,CAAC,CAAC,CAAC,eAAe,CAAC,CAAA;gBACxD,MAAM,OAAO,GAAG,GAAG,IAAI,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;gBACxE,OAAO,GAAG,CACR,CAAC,MAAM,CACL,KAAK,CAAC,CAAC,OAAO,CAAC,CACf,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAClE,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAEnB;cAAA,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAC5C;gBAAA,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAC1C;cAAA,EAAE,aAAa,CACf;cAAA,CAAC,aAAa,CACZ;gBAAA,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,UAAU,CAC9D;gBAAA,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAC3C;oBAAA,CAAC,GAAG,CAAC,KAAK,CACZ;kBAAA,EAAE,UAAU,CAAC,CACd,CAAC,CACJ;cAAA,EAAE,aAAa,CACjB;YAAA,EAAE,MAAM,CAAC,CACV,CAAA;YACH,CAAC;iBAAM,IAAI,SAAS,KAAK,cAAc,EAAE,CAAC;gBACxC,8DAA8D;gBAC9D,6DAA6D;gBAC7D,+DAA+D;gBAC/D,6DAA6D;gBAC7D,MAAM,UAAU,GAAG,wBAAwB,CAAC,CAAC,CAAC,eAAe,CAAC,CAAA;gBAC9D,MAAM,WAAW,GAAG,gBAAgB,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;gBACnD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;gBAC9B,MAAM,MAAM,GAAyB,EAAE,CAAA;gBACvC,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,UAAU,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC;oBAChD,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;oBAC7C,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;wBAAE,SAAQ;oBACzB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;oBACX,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;gBAChB,CAAC;gBACD,OAAO,GAAG,CACR,CAAC,QAAQ,CACP,EAAE,CAAC,CAAC,OAAO,CAAC,CACZ,KAAK,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CACtC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CACjD,MAAM,CAAC,CAAC,MAAM,CAAC,CACf,WAAW,CAAC,CAAC,MAAM,CAAC,CACpB,OAAO,CAAC,CAAC,uBAAuB,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAC1C,QAAQ,CAAC,CAAC,QAAQ,CAAC,CACnB,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAC3B,UAAU,CAAC,CAAC,KAAK,CAAC,CAClB,MAAM,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,EACzB,CACH,CAAA;YACH,CAAC;iBAAM,CAAC;gBACN,mBAAmB;gBACnB,OAAO,GAAG,CACR,CAAC,KAAK,CACJ,EAAE,CAAC,CAAC,OAAO,CAAC,CACZ,IAAI,CAAC,MAAM,CACX,KAAK,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CACtC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAC3B,QAAQ,CAAC,CAAC,QAAQ,CAAC,CACnB,MAAM,CAAC,CAAC,MAAM,CAAC,CACf,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CACd,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAC1D,CAAC,CACD,UAAU,CAAC,CAAC,KAAK,CAAC,EAClB,CACH,CAAA;YACH,CAAC;YAED,OAAO,CACL,CAAC,GAAG,CACF,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CACX,SAAS,CAAC,+DAA+D,CAEzE;YAAA,CAAC,KAAK,CACJ,OAAO,CAAC,CAAC,OAAO,CAAC,CACjB,SAAS,CAAC,sFAAsF,CAEhG;cAAA,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,CACxC;cAAA,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CACf,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAG,CAClE,CAAC,CAAC,CAAC,IAAI,CACR;cAAA,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CACd,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,kBAAkB,CACnD;;gBACF,EAAE,IAAI,CAAC,CACR,CAAC,CAAC,CAAC,IAAI,CACV;YAAA,EAAE,KAAK,CACP;YAAA,CAAC,GAAG,CAAC,SAAS,CAAC,gBAAgB,CAC7B;cAAA,CAAC,OAAO,CACV;YAAA,EAAE,GAAG,CACP;UAAA,EAAE,GAAG,CAAC,CACP,CAAA;QACH,CAAC,CAAC,CACJ;IAAA,EAAE,GAAG,CAAC,CACP,CAAA;AACH,CAAC;AA4BD,MAAM,iBAAiB,GAAiC;IACtD,UAAU,EAAE,GAAG;IACf,kBAAkB,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG;IAChC,SAAS,EAAE,KAAK;IAChB,UAAU,EAAE,IAAI;CACjB,CAAA;AAED,MAAM,gBAAgB,GAAG,CACvB,GAAY,EACZ,KAAwB,EACxB,CAA+B,EACvB,EAAE;IACV,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO,CAAC,CAAC,UAAU,CAAA;IAClD,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAA;IACrE,IACE,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC;QAC1D,KAAK,CAAC,eAAe,EACrB,CAAC;QACD,MAAM,IAAI,GAAG,wBAAwB,CAAC,KAAK,CAAC,eAAe,CAAC,CAAA;QAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;QACvD,OAAO,KAAK,EAAE,KAAK,IAAI,MAAM,CAAC,GAAG,CAAC,CAAA;IACpC,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,MAAM,CAAC,GAAG,CAAC,CAAA;QACpB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAA;AACpB,CAAC,CAAA;AAED,MAAM,UAAU,YAAY,CAAC,EAC3B,MAAM,EACN,KAAK,EACL,SAAS,EACT,OAAO,GAAG,OAAO,EACjB,MAAM,GACY;IAClB,MAAM,CAAC,GAAG,EAAE,GAAG,iBAAiB,EAAE,GAAG,MAAM,EAAE,CAAA;IAC7C,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE3B,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,MAAM;aACjB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;YACtB,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,KAAK,EAAE;gBAAE,OAAO,IAAI,CAAA;YAC1C,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;YACpD,OAAO,GAAG,KAAK,KAAK,gBAAgB,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;QACnD,CAAC,CAAC;aACD,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAA;QACzC,OAAO,CACL,CAAC,IAAI,CACH,SAAS,CAAC,CAAC,EAAE,CACX,mEAAmE,EACnE,SAAS,CACV,CAAC,CACF,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,CAErC;QAAA,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CACrD;MAAA,EAAE,IAAI,CAAC,CACR,CAAA;IACH,CAAC;IAED,OAAO,CACL,CAAC,EAAE,CACD,SAAS,CAAC,CAAC,EAAE,CACX,4EAA4E,EAC5E,SAAS,CACV,CAAC,CAEF;MAAA,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YAChB,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;YACpD,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;YAC/C,OAAO,CACL,CAAC,GAAG,CACF,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CACX,SAAS,CAAC,kEAAkE,CAE5E;YAAA,CAAC,EAAE,CAAC,SAAS,CAAC,oFAAoF,CAChG;cAAA,CAAC,KAAK,CACR;YAAA,EAAE,EAAE,CACJ;YAAA,CAAC,EAAE,CAAC,SAAS,CAAC,4CAA4C,CACxD;cAAA,CAAC,IAAI,CACP;YAAA,EAAE,EAAE,CACN;UAAA,EAAE,GAAG,CAAC,CACP,CAAA;QACH,CAAC,CAAC,CACJ;IAAA,EAAE,EAAE,CAAC,CACN,CAAA;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ import * as React from 'react';
2
+ export interface KeyboardShortcutItem {
3
+ /** Combo in `useHotkey` syntax, e.g. `mod+s`, `shift+/`, `esc`. */
4
+ keys: string;
5
+ description: string;
6
+ group?: string;
7
+ }
8
+ export interface KeyboardShortcutsHelpProps {
9
+ open: boolean;
10
+ onOpenChange: (open: boolean) => void;
11
+ items: KeyboardShortcutItem[];
12
+ title?: React.ReactNode;
13
+ description?: React.ReactNode;
14
+ emptyMessage?: React.ReactNode;
15
+ }
16
+ export declare function KeyboardShortcutsHelp({ open, onOpenChange, items, title, description, emptyMessage, }: KeyboardShortcutsHelpProps): React.ReactElement;
17
+ //# sourceMappingURL=keyboard-shortcuts-help.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard-shortcuts-help.d.ts","sourceRoot":"","sources":["../../src/components/keyboard-shortcuts-help.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAU9B,MAAM,WAAW,oBAAoB;IACnC,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,KAAK,EAAE,oBAAoB,EAAE,CAAA;IAC7B,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC/B;AA6BD,wBAAgB,qBAAqB,CAAC,EACpC,IAAI,EACJ,YAAY,EACZ,KAAK,EACL,KAAK,EACL,WAAW,EACX,YAAY,GACb,EAAE,0BAA0B,GAAG,KAAK,CAAC,YAAY,CAqEjD"}
@@ -0,0 +1,97 @@
1
+ // Presentational dialog that lists keyboard shortcuts. Pass `items`;
2
+ // each entry's `keys` is a `+`-separated combo string (e.g. `mod+s`)
3
+ // and gets rendered as <Kbd> caps. `mod` resolves to ⌘ on macOS / Ctrl
4
+ // elsewhere via `getModKeyLabel()`. Items can optionally be grouped via
5
+ // `group` and the dialog sorts groups in insertion order.
6
+ import * as React from 'react';
7
+ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from './dialog.js';
8
+ import { Kbd, getModKeyLabel } from './kbd.js';
9
+ function chordParts(combo, modLabel) {
10
+ // Pick the first alternative (`a|b`) — the help dialog shows one
11
+ // canonical chord per entry.
12
+ const first = combo.split('|')[0] ?? '';
13
+ return first
14
+ .split('+')
15
+ .map((s) => s.trim().toLowerCase())
16
+ .filter(Boolean)
17
+ .map((p) => {
18
+ if (p === 'mod' || p === 'ctrl' || p === 'meta' || p === 'cmd')
19
+ return modLabel;
20
+ if (p === 'shift')
21
+ return 'Shift';
22
+ if (p === 'alt' || p === 'option')
23
+ return 'Alt';
24
+ if (p === 'esc' || p === 'escape')
25
+ return 'Esc';
26
+ if (p === 'space' || p === ' ' || p === 'spacebar')
27
+ return 'Space';
28
+ if (p === 'enter' || p === 'return')
29
+ return 'Enter';
30
+ if (p === 'tab')
31
+ return 'Tab';
32
+ if (p === 'backspace')
33
+ return '⌫';
34
+ if (p === 'delete' || p === 'del')
35
+ return 'Del';
36
+ if (p === 'arrowup')
37
+ return '↑';
38
+ if (p === 'arrowdown')
39
+ return '↓';
40
+ if (p === 'arrowleft')
41
+ return '←';
42
+ if (p === 'arrowright')
43
+ return '→';
44
+ if (p.length === 1)
45
+ return p.toUpperCase();
46
+ return p.charAt(0).toUpperCase() + p.slice(1);
47
+ });
48
+ }
49
+ export function KeyboardShortcutsHelp({ open, onOpenChange, items, title, description, emptyMessage, }) {
50
+ const modLabel = getModKeyLabel();
51
+ // Group preserving insertion order.
52
+ const groups = React.useMemo(() => {
53
+ const m = new Map();
54
+ for (const it of items) {
55
+ const key = it.group ?? '';
56
+ const list = m.get(key);
57
+ if (list)
58
+ list.push(it);
59
+ else
60
+ m.set(key, [it]);
61
+ }
62
+ return Array.from(m.entries());
63
+ }, [items]);
64
+ return (<Dialog open={open} onOpenChange={onOpenChange}>
65
+ {/* aria-describedby={undefined} explicitly suppresses Radix's missing-
66
+ description warning for dialogs where no <DialogDescription> is
67
+ rendered. When `description` is provided the prop is omitted so
68
+ Radix can wire its context-based aria-describedby automatically. */}
69
+ <DialogContent className="max-w-md" {...(!description ? { 'aria-describedby': undefined } : {})}>
70
+ <DialogHeader>
71
+ <DialogTitle>{title ?? 'Keyboard shortcuts'}</DialogTitle>
72
+ {description && <DialogDescription>{description}</DialogDescription>}
73
+ </DialogHeader>
74
+ {items.length === 0 ? (<p className="text-sm text-muted-foreground">
75
+ {emptyMessage ?? 'No shortcuts available on this screen.'}
76
+ </p>) : (<div className="flex flex-col gap-4">
77
+ {groups.map(([groupName, list]) => (<div key={groupName || '__default__'} className="flex flex-col gap-2">
78
+ {groupName && (<h3 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
79
+ {groupName}
80
+ </h3>)}
81
+ <ul className="flex flex-col divide-y divide-border rounded-md border border-border">
82
+ {list.map((it, idx) => (<li key={`${it.keys}:${idx}`} className="flex items-center justify-between gap-3 px-3 py-2">
83
+ <span className="text-sm">{it.description}</span>
84
+ <span className="inline-flex shrink-0 items-center gap-1">
85
+ {chordParts(it.keys, modLabel).map((part, i, arr) => (<React.Fragment key={i}>
86
+ <Kbd>{part}</Kbd>
87
+ {i < arr.length - 1 && (<span className="text-muted-foreground">+</span>)}
88
+ </React.Fragment>))}
89
+ </span>
90
+ </li>))}
91
+ </ul>
92
+ </div>))}
93
+ </div>)}
94
+ </DialogContent>
95
+ </Dialog>);
96
+ }
97
+ //# sourceMappingURL=keyboard-shortcuts-help.jsx.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard-shortcuts-help.jsx","sourceRoot":"","sources":["../../src/components/keyboard-shortcuts-help.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import * as React from 'react';
2
+ import * as LabelPrimitive from '@radix-ui/react-label';
3
+ import { type VariantProps } from 'class-variance-authority';
4
+ export declare const Label: React.ForwardRefExoticComponent<Omit<LabelPrimitive.LabelProps & React.RefAttributes<HTMLLabelElement>, "ref"> & VariantProps<(props?: import("class-variance-authority/types").ClassProp | undefined) => string> & React.RefAttributes<HTMLLabelElement>>;
5
+ //# sourceMappingURL=label.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../../src/components/label.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAOjE,eAAO,MAAM,KAAK,4PAKhB,CAAA"}
@@ -0,0 +1,8 @@
1
+ import * as React from 'react';
2
+ import * as LabelPrimitive from '@radix-ui/react-label';
3
+ import { cva } from 'class-variance-authority';
4
+ import { cn } from '../lib/utils.js';
5
+ const labelVariants = cva('text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70');
6
+ export const Label = React.forwardRef(({ className, ...props }, ref) => (<LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props}/>));
7
+ Label.displayName = LabelPrimitive.Root.displayName;
8
+ //# sourceMappingURL=label.jsx.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"label.jsx","sourceRoot":"","sources":["../../src/components/label.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,GAAG,EAAqB,MAAM,0BAA0B,CAAA;AACjE,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAA;AAEpC,MAAM,aAAa,GAAG,GAAG,CACvB,4FAA4F,CAC7F,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAGnC,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAClC,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,EAAG,CACxF,CAAC,CAAA;AACF,KAAK,CAAC,WAAW,GAAG,cAAc,CAAC,IAAI,CAAC,WAAW,CAAA"}
@@ -0,0 +1,30 @@
1
+ import * as React from 'react';
2
+ export type MediaKind = 'image' | 'video' | 'audio' | 'unknown';
3
+ export declare function detectMediaKind(url: string): MediaKind;
4
+ export interface MediaPreviewProps {
5
+ /** Media URL. Should be a fully-qualified HTTP(S) URL. */
6
+ url: string;
7
+ /** Optional override for the auto-detected media kind. */
8
+ kind?: MediaKind;
9
+ /** Suggested file name for the download. Falls back to URL pathname. */
10
+ downloadName?: string;
11
+ /** Strings (already-translated) to render in the UI. */
12
+ labels?: {
13
+ preview?: string;
14
+ download?: string;
15
+ downloadError?: string;
16
+ openInNewTab?: string;
17
+ title?: string;
18
+ description?: string;
19
+ cannotPreview?: string;
20
+ };
21
+ /** Show the URL as secondary text next to the trigger. */
22
+ showUrl?: boolean;
23
+ /** Variant of the trigger button. Defaults to 'outline'. */
24
+ triggerVariant?: 'default' | 'outline' | 'secondary' | 'ghost' | 'link';
25
+ /** Size of the trigger button. Defaults to 'sm'. */
26
+ triggerSize?: 'default' | 'sm' | 'lg' | 'icon';
27
+ className?: string;
28
+ }
29
+ export declare function MediaPreview({ url, kind: kindProp, downloadName, labels, showUrl, triggerVariant, triggerSize, className, }: MediaPreviewProps): React.ReactElement;
30
+ //# sourceMappingURL=media-preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-preview.d.ts","sourceRoot":"","sources":["../../src/components/media-preview.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAa9B,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAA;AAM/D,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAMtD;AA0ED,MAAM,WAAW,iBAAiB;IAChC,0DAA0D;IAC1D,GAAG,EAAE,MAAM,CAAA;IACX,0DAA0D;IAC1D,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,wDAAwD;IACxD,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,aAAa,CAAC,EAAE,MAAM,CAAA;KACvB,CAAA;IACD,0DAA0D;IAC1D,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,4DAA4D;IAC5D,cAAc,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,MAAM,CAAA;IACvE,oDAAoD;IACpD,WAAW,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAA;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,YAAY,CAAC,EAC3B,GAAG,EACH,IAAI,EAAE,QAAQ,EACd,YAAY,EACZ,MAAM,EACN,OAAe,EACf,cAA0B,EAC1B,WAAkB,EAClB,SAAS,GACV,EAAE,iBAAiB,GAAG,KAAK,CAAC,YAAY,CA2IxC"}
@@ -0,0 +1,189 @@
1
+ // MediaPreview — opens a dialog with an image/video preview and a download
2
+ // button. Used by the `previewMedia` property type to render HTTP(S) URLs to
3
+ // remote photos/videos as a "Preview" button instead of raw text.
4
+ import * as React from 'react';
5
+ import { Download, Eye, ExternalLink, Loader2, AlertCircle } from 'lucide-react';
6
+ import { cn } from '../lib/utils.js';
7
+ import { Button } from './button.js';
8
+ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from './dialog.js';
9
+ const IMAGE_EXT = /\.(jpe?g|png|gif|webp|avif|bmp|svg|ico|heic|heif)(\?|#|$)/i;
10
+ const VIDEO_EXT = /\.(mp4|webm|mov|m4v|ogv|avi|mkv)(\?|#|$)/i;
11
+ const AUDIO_EXT = /\.(mp3|wav|ogg|m4a|aac|flac)(\?|#|$)/i;
12
+ export function detectMediaKind(url) {
13
+ if (!url)
14
+ return 'unknown';
15
+ if (IMAGE_EXT.test(url))
16
+ return 'image';
17
+ if (VIDEO_EXT.test(url))
18
+ return 'video';
19
+ if (AUDIO_EXT.test(url))
20
+ return 'audio';
21
+ return 'unknown';
22
+ }
23
+ /**
24
+ * Probes the Content-Type of `url` when extension-based detection returns
25
+ * 'unknown'. Runs only when `enabled` is true (dialog has been opened).
26
+ *
27
+ * Strategy:
28
+ * 1. HEAD request — reads Content-Type header (works for same-origin or
29
+ * CORS-enabled APIs like public avatar services).
30
+ * 2. Image constructor fallback — handles servers that block HEAD but allow
31
+ * img GET (bypasses CORS for image fetches by design).
32
+ *
33
+ * Returns [resolvedKind, isLoading].
34
+ */
35
+ function useProbeMediaKind(url, kindOverride, enabled) {
36
+ const byExt = React.useMemo(() => detectMediaKind(url), [url]);
37
+ const [kind, setKind] = React.useState(kindOverride ?? byExt);
38
+ const [loading, setLoading] = React.useState(false);
39
+ // Keep kind in sync when url or kindOverride changes (e.g. parent re-renders).
40
+ React.useEffect(() => {
41
+ setKind(kindOverride ?? detectMediaKind(url));
42
+ setLoading(false);
43
+ }, [url, kindOverride]);
44
+ React.useEffect(() => {
45
+ if (!enabled)
46
+ return;
47
+ if (kindOverride)
48
+ return;
49
+ if (byExt !== 'unknown')
50
+ return;
51
+ if (!url.startsWith('http'))
52
+ return;
53
+ let cancelled = false;
54
+ const controller = new AbortController();
55
+ setLoading(true);
56
+ const resolve = (k) => {
57
+ if (cancelled)
58
+ return;
59
+ setKind(k);
60
+ setLoading(false);
61
+ };
62
+ // Image constructor fallback — works even when HEAD is CORS-blocked.
63
+ const tryImage = () => {
64
+ const img = new window.Image();
65
+ img.onload = () => resolve('image');
66
+ img.onerror = () => resolve('unknown');
67
+ img.src = url;
68
+ };
69
+ fetch(url, { method: 'HEAD', signal: controller.signal })
70
+ .then((res) => {
71
+ const ct = res.headers.get('content-type') ?? '';
72
+ if (ct.startsWith('image/'))
73
+ resolve('image');
74
+ else if (ct.startsWith('video/'))
75
+ resolve('video');
76
+ else if (ct.startsWith('audio/'))
77
+ resolve('audio');
78
+ else
79
+ tryImage();
80
+ })
81
+ .catch(() => {
82
+ if (!cancelled)
83
+ tryImage();
84
+ });
85
+ return () => {
86
+ cancelled = true;
87
+ controller.abort();
88
+ };
89
+ }, [url, kindOverride, byExt, enabled]);
90
+ return [kind, loading];
91
+ }
92
+ export function MediaPreview({ url, kind: kindProp, downloadName, labels, showUrl = false, triggerVariant = 'outline', triggerSize = 'sm', className, }) {
93
+ const [open, setOpen] = React.useState(false);
94
+ const [kind, kindLoading] = useProbeMediaKind(url, kindProp, open);
95
+ const [downloading, setDownloading] = React.useState(false);
96
+ const [downloadError, setDownloadError] = React.useState(false);
97
+ const previewLabel = labels?.preview ?? 'Preview';
98
+ const downloadLabel = labels?.download ?? 'Download';
99
+ const openLabel = labels?.openInNewTab ?? 'Open in new tab';
100
+ const titleLabel = labels?.title ?? previewLabel;
101
+ const cannotLabel = labels?.cannotPreview ?? 'Preview is unavailable for this media type.';
102
+ const inferredName = React.useMemo(() => {
103
+ if (downloadName)
104
+ return downloadName;
105
+ try {
106
+ const u = new URL(url);
107
+ const last = u.pathname.split('/').filter(Boolean).pop();
108
+ return last || 'download';
109
+ }
110
+ catch {
111
+ return 'download';
112
+ }
113
+ }, [downloadName, url]);
114
+ // Force a file download via fetch → blob → blob URL. The <a download> attribute
115
+ // is silently ignored by browsers for cross-origin URLs, so we always use the
116
+ // blob approach. Falls back to window.open if fetch fails (e.g. no CORS).
117
+ const handleDownload = async () => {
118
+ setDownloadError(false);
119
+ setDownloading(true);
120
+ try {
121
+ const res = await fetch(url);
122
+ const blob = await res.blob();
123
+ const blobUrl = URL.createObjectURL(blob);
124
+ const a = document.createElement('a');
125
+ a.href = blobUrl;
126
+ a.download = inferredName;
127
+ document.body.appendChild(a);
128
+ a.click();
129
+ document.body.removeChild(a);
130
+ URL.revokeObjectURL(blobUrl);
131
+ }
132
+ catch {
133
+ setDownloadError(true);
134
+ }
135
+ finally {
136
+ setDownloading(false);
137
+ }
138
+ };
139
+ // Stop click propagation so that events from the Dialog portal (which bubble
140
+ // through the React component tree, not the DOM) do not reach parent row
141
+ // click handlers and trigger unintended navigation (e.g. list-page TableRow
142
+ // opening edit on backdrop/dialog click).
143
+ const stopClick = (e) => e.stopPropagation();
144
+ return (<div className={cn('inline-flex items-center gap-2', className)} onClick={stopClick}>
145
+ <Button type="button" variant={triggerVariant} size={triggerSize} onClick={() => setOpen(true)} disabled={!url}>
146
+ <Eye className="size-4"/>
147
+ <span>{previewLabel}</span>
148
+ </Button>
149
+
150
+ {showUrl && url ? (<span className="max-w-[24rem] truncate text-xs text-muted-foreground" title={url}>
151
+ {url}
152
+ </span>) : null}
153
+
154
+ <Dialog open={open} onOpenChange={setOpen}>
155
+ <DialogContent className="max-w-3xl">
156
+ <DialogHeader>
157
+ <DialogTitle>{titleLabel}</DialogTitle>
158
+ {labels?.description ? (<DialogDescription>{labels.description}</DialogDescription>) : (<DialogDescription className="break-all text-xs">{url}</DialogDescription>)}
159
+ </DialogHeader>
160
+
161
+ <div className="flex max-h-[70vh] items-center justify-center overflow-auto rounded-md border border-border bg-muted/30 p-2">
162
+ {kindLoading ? (<Loader2 className="size-8 animate-spin text-muted-foreground"/>) : kind === 'image' ? (<img src={url} alt={inferredName} className="max-h-[68vh] w-auto max-w-full object-contain"/>) : kind === 'video' ? (<video src={url} controls className="max-h-[68vh] w-full max-w-full"/>) : kind === 'audio' ? (<audio src={url} controls className="w-full"/>) : (<div className="p-6 text-center text-sm text-muted-foreground">
163
+ {cannotLabel}
164
+ </div>)}
165
+ </div>
166
+
167
+ <DialogFooter>
168
+ {downloadError && (<span className="flex items-center gap-1.5 text-xs text-destructive">
169
+ <AlertCircle className="size-3.5"/>
170
+ {labels?.downloadError ?? 'Download failed'}
171
+ </span>)}
172
+ <Button asChild variant="ghost" size="sm">
173
+ <a href={url} target="_blank" rel="noopener noreferrer">
174
+ <ExternalLink className="size-4"/>
175
+ <span>{openLabel}</span>
176
+ </a>
177
+ </Button>
178
+ <Button variant="default" size="sm" disabled={downloading} onClick={() => { void handleDownload(); }}>
179
+ {downloading
180
+ ? <Loader2 className="size-4 animate-spin"/>
181
+ : <Download className="size-4"/>}
182
+ <span>{downloadLabel}</span>
183
+ </Button>
184
+ </DialogFooter>
185
+ </DialogContent>
186
+ </Dialog>
187
+ </div>);
188
+ }
189
+ //# sourceMappingURL=media-preview.jsx.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-preview.jsx","sourceRoot":"","sources":["../../src/components/media-preview.tsx"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,6EAA6E;AAC7E,kEAAkE;AAElE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAChF,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAA;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EACL,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,WAAW,GACZ,MAAM,aAAa,CAAA;AAIpB,MAAM,SAAS,GAAG,4DAA4D,CAAA;AAC9E,MAAM,SAAS,GAAG,2CAA2C,CAAA;AAC7D,MAAM,SAAS,GAAG,uCAAuC,CAAA;AAEzD,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAA;IAC1B,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,OAAO,CAAA;IACvC,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,OAAO,CAAA;IACvC,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,OAAO,CAAA;IACvC,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,iBAAiB,CACxB,GAAW,EACX,YAAmC,EACnC,OAAgB;IAEhB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;IAC9D,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAY,YAAY,IAAI,KAAK,CAAC,CAAA;IACxE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAEnD,+EAA+E;IAC/E,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,OAAO,CAAC,YAAY,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC,CAAA;QAC7C,UAAU,CAAC,KAAK,CAAC,CAAA;IACnB,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAA;IAEvB,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,CAAC,OAAO;YAAE,OAAM;QACpB,IAAI,YAAY;YAAE,OAAM;QACxB,IAAI,KAAK,KAAK,SAAS;YAAE,OAAM;QAC/B,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAM;QAEnC,IAAI,SAAS,GAAG,KAAK,CAAA;QACrB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,UAAU,CAAC,IAAI,CAAC,CAAA;QAEhB,MAAM,OAAO,GAAG,CAAC,CAAY,EAAE,EAAE;YAC/B,IAAI,SAAS;gBAAE,OAAM;YACrB,OAAO,CAAC,CAAC,CAAC,CAAA;YACV,UAAU,CAAC,KAAK,CAAC,CAAA;QACnB,CAAC,CAAA;QAED,qEAAqE;QACrE,MAAM,QAAQ,GAAG,GAAG,EAAE;YACpB,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,KAAK,EAAE,CAAA;YAC9B,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;YACnC,GAAG,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;YACtC,GAAG,CAAC,GAAG,GAAG,GAAG,CAAA;QACf,CAAC,CAAA;QAED,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC;aACtD,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YACZ,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAA;YAChD,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;gBAAE,OAAO,CAAC,OAAO,CAAC,CAAA;iBACxC,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;gBAAE,OAAO,CAAC,OAAO,CAAC,CAAA;iBAC7C,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;gBAAE,OAAO,CAAC,OAAO,CAAC,CAAA;;gBAC7C,QAAQ,EAAE,CAAA;QACjB,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,IAAI,CAAC,SAAS;gBAAE,QAAQ,EAAE,CAAA;QAC5B,CAAC,CAAC,CAAA;QAEJ,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAA;YAChB,UAAU,CAAC,KAAK,EAAE,CAAA;QACpB,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAA;IAEvC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;AACxB,CAAC;AA4BD,MAAM,UAAU,YAAY,CAAC,EAC3B,GAAG,EACH,IAAI,EAAE,QAAQ,EACd,YAAY,EACZ,MAAM,EACN,OAAO,GAAG,KAAK,EACf,cAAc,GAAG,SAAS,EAC1B,WAAW,GAAG,IAAI,EAClB,SAAS,GACS;IAClB,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7C,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,GAAG,iBAAiB,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAA;IAClE,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3D,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE/D,MAAM,YAAY,GAAG,MAAM,EAAE,OAAO,IAAI,SAAS,CAAA;IACjD,MAAM,aAAa,GAAG,MAAM,EAAE,QAAQ,IAAI,UAAU,CAAA;IACpD,MAAM,SAAS,GAAG,MAAM,EAAE,YAAY,IAAI,iBAAiB,CAAA;IAC3D,MAAM,UAAU,GAAG,MAAM,EAAE,KAAK,IAAI,YAAY,CAAA;IAChD,MAAM,WAAW,GAAG,MAAM,EAAE,aAAa,IAAI,6CAA6C,CAAA;IAE1F,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACtC,IAAI,YAAY;YAAE,OAAO,YAAY,CAAA;QACrC,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;YACtB,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAA;YACxD,OAAO,IAAI,IAAI,UAAU,CAAA;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,UAAU,CAAA;QACnB,CAAC;IACH,CAAC,EAAE,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,CAAA;IAEvB,gFAAgF;IAChF,8EAA8E;IAC9E,0EAA0E;IAC1E,MAAM,cAAc,GAAG,KAAK,IAAI,EAAE;QAChC,gBAAgB,CAAC,KAAK,CAAC,CAAA;QACvB,cAAc,CAAC,IAAI,CAAC,CAAA;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAA;YAC5B,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;YAC7B,MAAM,OAAO,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;YACzC,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAA;YACrC,CAAC,CAAC,IAAI,GAAG,OAAO,CAAA;YAChB,CAAC,CAAC,QAAQ,GAAG,YAAY,CAAA;YACzB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAA;YAC5B,CAAC,CAAC,KAAK,EAAE,CAAA;YACT,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAA;YAC5B,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB,CAAC,IAAI,CAAC,CAAA;QACxB,CAAC;gBAAS,CAAC;YACT,cAAc,CAAC,KAAK,CAAC,CAAA;QACvB,CAAC;IACH,CAAC,CAAA;IAED,6EAA6E;IAC7E,yEAAyE;IACzE,4EAA4E;IAC5E,0CAA0C;IAC1C,MAAM,SAAS,GAAG,CAAC,CAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,CAAA;IAE9D,OAAO,CACL,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,gCAAgC,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAClF;MAAA,CAAC,MAAM,CACL,IAAI,CAAC,QAAQ,CACb,OAAO,CAAC,CAAC,cAAc,CAAC,CACxB,IAAI,CAAC,CAAC,WAAW,CAAC,CAClB,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAC7B,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAEf;QAAA,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,EACvB;QAAA,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,EAAE,IAAI,CAC5B;MAAA,EAAE,MAAM,CAER;;MAAA,CAAC,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAChB,CAAC,IAAI,CACH,SAAS,CAAC,sDAAsD,CAChE,KAAK,CAAC,CAAC,GAAG,CAAC,CAEX;UAAA,CAAC,GAAG,CACN;QAAA,EAAE,IAAI,CAAC,CACR,CAAC,CAAC,CAAC,IAAI,CAER;;MAAA,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CACxC;QAAA,CAAC,aAAa,CAAC,SAAS,CAAC,WAAW,CAClC;UAAA,CAAC,YAAY,CACX;YAAA,CAAC,WAAW,CAAC,CAAC,UAAU,CAAC,EAAE,WAAW,CACtC;YAAA,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CACrB,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,iBAAiB,CAAC,CAC5D,CAAC,CAAC,CAAC,CACF,CAAC,iBAAiB,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,EAAE,iBAAiB,CAAC,CAC3E,CACH;UAAA,EAAE,YAAY,CAEd;;UAAA,CAAC,GAAG,CAAC,SAAS,CAAC,6GAA6G,CAC1H;YAAA,CAAC,WAAW,CAAC,CAAC,CAAC,CACb,CAAC,OAAO,CAAC,SAAS,CAAC,2CAA2C,EAAG,CAClE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CACrB,CAAC,GAAG,CACF,GAAG,CAAC,CAAC,GAAG,CAAC,CACT,GAAG,CAAC,CAAC,YAAY,CAAC,CAClB,SAAS,CAAC,+CAA+C,EACzD,CACH,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CACrB,CAAC,KAAK,CACJ,GAAG,CAAC,CAAC,GAAG,CAAC,CACT,QAAQ,CACR,SAAS,CAAC,gCAAgC,EAC1C,CACH,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CACrB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAG,CAChD,CAAC,CAAC,CAAC,CACF,CAAC,GAAG,CAAC,SAAS,CAAC,+CAA+C,CAC5D;gBAAA,CAAC,WAAW,CACd;cAAA,EAAE,GAAG,CAAC,CACP,CACH;UAAA,EAAE,GAAG,CAEL;;UAAA,CAAC,YAAY,CACX;YAAA,CAAC,aAAa,IAAI,CAChB,CAAC,IAAI,CAAC,SAAS,CAAC,oDAAoD,CAClE;gBAAA,CAAC,WAAW,CAAC,SAAS,CAAC,UAAU,EACjC;gBAAA,CAAC,MAAM,EAAE,aAAa,IAAI,iBAAiB,CAC7C;cAAA,EAAE,IAAI,CAAC,CACR,CACD;YAAA,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CACvC;cAAA,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,qBAAqB,CACrD;gBAAA,CAAC,YAAY,CAAC,SAAS,CAAC,QAAQ,EAChC;gBAAA,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,EAAE,IAAI,CACzB;cAAA,EAAE,CAAC,CACL;YAAA,EAAE,MAAM,CACR;YAAA,CAAC,MAAM,CACL,OAAO,CAAC,SAAS,CACjB,IAAI,CAAC,IAAI,CACT,QAAQ,CAAC,CAAC,WAAW,CAAC,CACtB,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,KAAK,cAAc,EAAE,CAAA,CAAC,CAAC,CAAC,CAEzC;cAAA,CAAC,WAAW;YACV,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,qBAAqB,EAAG;YAC7C,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAG,CACnC;cAAA,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,CAC7B;YAAA,EAAE,MAAM,CACV;UAAA,EAAE,YAAY,CAChB;QAAA,EAAE,aAAa,CACjB;MAAA,EAAE,MAAM,CACV;IAAA,EAAE,GAAG,CAAC,CACP,CAAA;AACH,CAAC"}