@x12i/fieldkit 1.0.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/dist/index.js ADDED
@@ -0,0 +1,609 @@
1
+ // src/theme.tsx
2
+ import * as React from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ var TONE_PALETTE = {
5
+ neutral: "#8B96A3",
6
+ amber: "#E8A33D",
7
+ rose: "#E2564F",
8
+ green: "#59B87B",
9
+ blue: "#6FA8DC",
10
+ violet: "#9B8CDB",
11
+ teal: "#4FB6A8"
12
+ };
13
+ var HASHABLE_TONES = ["amber", "rose", "green", "blue", "violet", "teal"];
14
+ function hashTone(value) {
15
+ let h = 0;
16
+ for (let i = 0; i < value.length; i++) h = h * 31 + value.charCodeAt(i) >>> 0;
17
+ return HASHABLE_TONES[h % HASHABLE_TONES.length];
18
+ }
19
+ var defaultTheme = {
20
+ colors: {
21
+ background: "#0A0E13",
22
+ surface: "#10161D",
23
+ surfaceMuted: "#0D1218",
24
+ border: "rgba(255,255,255,0.07)",
25
+ textPrimary: "#F4F6F8",
26
+ textSecondary: "#C7CDD3",
27
+ textMuted: "#5B6672",
28
+ accent: "#4FB6A8"
29
+ },
30
+ fonts: {
31
+ heading: "'Space Grotesk', ui-sans-serif, sans-serif",
32
+ body: "'IBM Plex Sans', ui-sans-serif, sans-serif",
33
+ mono: "'IBM Plex Mono', ui-monospace, monospace"
34
+ },
35
+ radii: { sm: "5px", md: "8px", lg: "14px", pill: "999px" },
36
+ tonePalette: TONE_PALETTE
37
+ };
38
+ function mergeTheme(base2, override) {
39
+ if (!override) return base2;
40
+ return {
41
+ colors: { ...base2.colors, ...override.colors },
42
+ fonts: { ...base2.fonts, ...override.fonts },
43
+ radii: { ...base2.radii, ...override.radii },
44
+ tonePalette: { ...base2.tonePalette, ...override.tonePalette }
45
+ };
46
+ }
47
+ var ThemeContext = React.createContext(defaultTheme);
48
+ function FieldKitProvider({ theme, children }) {
49
+ const parent = React.useContext(ThemeContext);
50
+ const merged = React.useMemo(() => mergeTheme(parent, theme), [parent, theme]);
51
+ return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: merged, children });
52
+ }
53
+ function useFieldKitTheme() {
54
+ return React.useContext(ThemeContext);
55
+ }
56
+ function toneHex(theme, toneKey) {
57
+ var _a, _b;
58
+ if (!toneKey) return (_a = theme.tonePalette.neutral) != null ? _a : TONE_PALETTE.neutral;
59
+ return (_b = theme.tonePalette[toneKey]) != null ? _b : TONE_PALETTE.neutral;
60
+ }
61
+
62
+ // src/infer.ts
63
+ function labelFromKey(key) {
64
+ const spaced = key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/_/g, " ").toLowerCase();
65
+ return spaced.split(" ").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
66
+ }
67
+ var defaultClassifySignal = (text) => {
68
+ const t = text.toLowerCase();
69
+ const flagged = t.includes("unresolved") || t.includes("unknown") || t.includes("missing");
70
+ return flagged ? "warn" : "info";
71
+ };
72
+ var ENUM_LIKE = /^[A-Z0-9]+(_[A-Z0-9]+)*$/;
73
+ function inferRule(key, value) {
74
+ const label = labelFromKey(key);
75
+ const as = (() => {
76
+ if (value === null || value === void 0 || value === "") return "empty";
77
+ if (typeof value === "boolean") return "flag";
78
+ if (typeof value === "number") return "stat";
79
+ if (typeof value === "string") {
80
+ if (ENUM_LIKE.test(value)) return "pill";
81
+ if (value.length > 70 || /[.!?]\s/.test(value)) return "lead";
82
+ if (!value.includes(" ") && value.length > 12) return "mono";
83
+ return "text";
84
+ }
85
+ if (Array.isArray(value)) {
86
+ if (value.length === 0) return "empty";
87
+ if (value.every((v) => typeof v === "string")) {
88
+ if (value.every((v) => /\?\s*$/.test(v))) return "qa";
89
+ if (value.some((v) => v.split(" ").length > 6)) return "bullets";
90
+ return "tags";
91
+ }
92
+ return "json";
93
+ }
94
+ return "json";
95
+ })();
96
+ return { label, as };
97
+ }
98
+
99
+ // src/resolve.ts
100
+ function resolveTone(value, toneMap) {
101
+ var _a;
102
+ return (_a = toneMap == null ? void 0 : toneMap[value]) != null ? _a : hashTone(value);
103
+ }
104
+ function resolveField(key, value, rule, options = {}) {
105
+ var _a, _b, _c;
106
+ const label = (_a = rule.label) != null ? _a : labelFromKey(key);
107
+ const classifySignal = (_b = options.classifySignal) != null ? _b : defaultClassifySignal;
108
+ const base2 = {
109
+ key,
110
+ label,
111
+ kind: rule.as,
112
+ isLeftover: (_c = options.isLeftover) != null ? _c : false
113
+ };
114
+ switch (rule.as) {
115
+ case "lead":
116
+ return { ...base2, text: String(value != null ? value : "") };
117
+ case "bullets":
118
+ return { ...base2, items: (value != null ? value : []).map((t) => ({ text: t })) };
119
+ case "signals":
120
+ return {
121
+ ...base2,
122
+ items: (value != null ? value : []).map((t) => {
123
+ const s = classifySignal(t);
124
+ return { text: t, warn: s === "warn", info: s === "info" };
125
+ })
126
+ };
127
+ case "qa":
128
+ return { ...base2, items: (value != null ? value : []).map((t) => ({ text: t })) };
129
+ case "pill": {
130
+ const raw = String(value != null ? value : "");
131
+ return { ...base2, pillText: labelFromKey(raw.toLowerCase()), toneKey: resolveTone(raw, options.toneMap) };
132
+ }
133
+ case "mono":
134
+ return { ...base2, value: String(value != null ? value : "") };
135
+ case "text":
136
+ return { ...base2, value: String(value != null ? value : "") };
137
+ case "flag":
138
+ return { ...base2, flagOn: !!value, flagText: value ? "Yes" : "No" };
139
+ case "stat":
140
+ return { ...base2, value: String(value != null ? value : "") };
141
+ case "tags":
142
+ return { ...base2, items: (value != null ? value : []).map((t) => ({ text: t })) };
143
+ case "empty":
144
+ return base2;
145
+ case "json":
146
+ default:
147
+ return { ...base2, kind: "json", value: JSON.stringify(value, null, 2) };
148
+ }
149
+ }
150
+
151
+ // src/icons.tsx
152
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
153
+ var base = (size, color, style) => ({
154
+ width: size,
155
+ height: size,
156
+ viewBox: "0 0 24 24",
157
+ fill: "none",
158
+ stroke: color,
159
+ strokeWidth: 1.8,
160
+ strokeLinecap: "round",
161
+ strokeLinejoin: "round",
162
+ style
163
+ });
164
+ function CheckIcon({ size = 15, color = "currentColor", style }) {
165
+ return /* @__PURE__ */ jsxs("svg", { ...base(size, color, style), children: [
166
+ /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "12", r: "9" }),
167
+ /* @__PURE__ */ jsx2("path", { d: "M8 12.3l2.6 2.6L16 9.3" })
168
+ ] });
169
+ }
170
+ function WarningIcon({ size = 15, color = "#E8A33D", style }) {
171
+ return /* @__PURE__ */ jsxs("svg", { ...base(size, color, style), children: [
172
+ /* @__PURE__ */ jsx2("path", { d: "M12 3 2 21h20L12 3z" }),
173
+ /* @__PURE__ */ jsx2("path", { d: "M12 9.5v5" }),
174
+ /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "17.2", r: "0.9", fill: color, stroke: "none" })
175
+ ] });
176
+ }
177
+ function InfoIcon({ size = 15, color = "#7C8894", style }) {
178
+ return /* @__PURE__ */ jsxs("svg", { ...base(size, color, style), children: [
179
+ /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "12", r: "9" }),
180
+ /* @__PURE__ */ jsx2("line", { x1: "12", y1: "10.5", x2: "12", y2: "16.2" }),
181
+ /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "7.6", r: "0.9", fill: color, stroke: "none" })
182
+ ] });
183
+ }
184
+ function QuestionIcon({ size = 15, color = "currentColor", style }) {
185
+ return /* @__PURE__ */ jsxs("svg", { ...base(size, color, style), children: [
186
+ /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "12", r: "9" }),
187
+ /* @__PURE__ */ jsx2("path", { d: "M9.5 9.3a2.5 2.5 0 1 1 3.5 2.3c-.9.5-1 1-1 1.9" }),
188
+ /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "17", r: "0.9", fill: color, stroke: "none" })
189
+ ] });
190
+ }
191
+ function ChevronDownIcon({ size = 14, color = "currentColor", style }) {
192
+ return /* @__PURE__ */ jsx2("svg", { ...base(size, color, style), children: /* @__PURE__ */ jsx2("path", { d: "M6 9l6 6 6-6" }) });
193
+ }
194
+
195
+ // src/components/FieldRenderer.tsx
196
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
197
+ function assertNever(x) {
198
+ throw new Error("Unhandled FieldKind: " + JSON.stringify(x));
199
+ }
200
+ function FieldRenderer({ field, variant = "compact", showLabel = true }) {
201
+ var _a, _b, _c, _d, _e;
202
+ const theme = useFieldKitTheme();
203
+ const isContent = variant === "content";
204
+ const labelNode = showLabel ? /* @__PURE__ */ jsx3(
205
+ "span",
206
+ {
207
+ style: {
208
+ fontFamily: theme.fonts.heading,
209
+ fontSize: isContent ? 11.5 : 10.5,
210
+ fontWeight: 600,
211
+ letterSpacing: "0.08em",
212
+ textTransform: "uppercase",
213
+ color: theme.colors.textMuted
214
+ },
215
+ children: field.label
216
+ }
217
+ ) : null;
218
+ let body;
219
+ switch (field.kind) {
220
+ case "lead":
221
+ body = /* @__PURE__ */ jsx3(
222
+ "p",
223
+ {
224
+ style: {
225
+ margin: 0,
226
+ fontSize: isContent ? 15 : 13,
227
+ lineHeight: 1.6,
228
+ color: isContent ? theme.colors.textSecondary : theme.colors.textMuted
229
+ },
230
+ children: field.text
231
+ }
232
+ );
233
+ break;
234
+ case "bullets":
235
+ body = /* @__PURE__ */ jsx3("div", { style: { display: "flex", flexDirection: "column", gap: isContent ? 10 : 6 }, children: (_a = field.items) == null ? void 0 : _a.map(
236
+ (item, i) => isContent ? /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 10, alignItems: "flex-start" }, children: [
237
+ /* @__PURE__ */ jsx3(CheckIcon, { size: 15, color: theme.colors.accent, style: { flexShrink: 0, marginTop: 3 } }),
238
+ /* @__PURE__ */ jsx3("span", { style: { fontSize: 14, lineHeight: 1.55, color: theme.colors.textSecondary }, children: item.text })
239
+ ] }, i) : /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 8, alignItems: "flex-start" }, children: [
240
+ /* @__PURE__ */ jsx3("span", { style: { color: theme.colors.textMuted, fontSize: 13 }, children: "\u2013" }),
241
+ /* @__PURE__ */ jsx3("span", { style: { fontSize: 13, lineHeight: 1.5, color: theme.colors.textMuted }, children: item.text })
242
+ ] }, i)
243
+ ) });
244
+ break;
245
+ case "signals":
246
+ body = /* @__PURE__ */ jsx3("div", { style: { display: "flex", flexDirection: "column", gap: isContent ? 8 : 6 }, children: (_b = field.items) == null ? void 0 : _b.map((item, i) => /* @__PURE__ */ jsxs2(
247
+ "div",
248
+ {
249
+ style: {
250
+ display: "flex",
251
+ gap: 10,
252
+ alignItems: "flex-start",
253
+ background: theme.colors.surfaceMuted,
254
+ border: `1px solid ${theme.colors.border}`,
255
+ borderRadius: isContent ? 8 : 6,
256
+ padding: isContent ? "12px 14px" : "8px 10px"
257
+ },
258
+ children: [
259
+ item.warn && /* @__PURE__ */ jsx3(WarningIcon, { size: isContent ? 15 : 13, style: { flexShrink: 0, marginTop: 2 } }),
260
+ item.info && /* @__PURE__ */ jsx3(InfoIcon, { size: isContent ? 15 : 13, style: { flexShrink: 0, marginTop: 2 } }),
261
+ /* @__PURE__ */ jsx3(
262
+ "span",
263
+ {
264
+ style: {
265
+ fontSize: isContent ? 13.5 : 13,
266
+ lineHeight: 1.55,
267
+ color: isContent ? theme.colors.textSecondary : theme.colors.textMuted
268
+ },
269
+ children: item.text
270
+ }
271
+ )
272
+ ]
273
+ },
274
+ i
275
+ )) });
276
+ break;
277
+ case "qa":
278
+ body = /* @__PURE__ */ jsx3(
279
+ "div",
280
+ {
281
+ style: isContent ? {
282
+ display: "flex",
283
+ flexDirection: "column",
284
+ gap: 12,
285
+ background: `${theme.colors.accent}12`,
286
+ border: `1px solid ${theme.colors.accent}33`,
287
+ borderRadius: 10,
288
+ padding: "14px 16px"
289
+ } : { display: "flex", flexDirection: "column", gap: 6 },
290
+ children: (_c = field.items) == null ? void 0 : _c.map((item, i) => /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: isContent ? 10 : 8, alignItems: "flex-start" }, children: [
291
+ isContent ? /* @__PURE__ */ jsx3(QuestionIcon, { size: 15, color: theme.colors.accent, style: { flexShrink: 0, marginTop: 2 } }) : /* @__PURE__ */ jsx3("span", { style: { color: theme.colors.accent, fontSize: 13, fontWeight: 600 }, children: "?" }),
292
+ /* @__PURE__ */ jsx3(
293
+ "span",
294
+ {
295
+ style: {
296
+ fontSize: isContent ? 14 : 13,
297
+ lineHeight: 1.55,
298
+ color: isContent ? theme.colors.textSecondary : theme.colors.textMuted
299
+ },
300
+ children: item.text
301
+ }
302
+ )
303
+ ] }, i))
304
+ }
305
+ );
306
+ break;
307
+ case "pill": {
308
+ const hex = toneHex(theme, field.toneKey);
309
+ body = /* @__PURE__ */ jsx3(
310
+ "span",
311
+ {
312
+ style: {
313
+ alignSelf: "flex-start",
314
+ padding: "3px 9px",
315
+ borderRadius: theme.radii.sm,
316
+ fontSize: 11,
317
+ fontWeight: 600,
318
+ fontFamily: theme.fonts.heading,
319
+ textTransform: "uppercase",
320
+ background: `${hex}24`,
321
+ color: hex,
322
+ border: `1px solid ${hex}55`
323
+ },
324
+ children: field.pillText
325
+ }
326
+ );
327
+ break;
328
+ }
329
+ case "mono":
330
+ body = /* @__PURE__ */ jsx3("span", { style: { fontFamily: theme.fonts.mono, fontSize: isContent ? 13 : 12.5, color: theme.colors.textMuted }, children: field.value });
331
+ break;
332
+ case "text":
333
+ body = /* @__PURE__ */ jsx3(
334
+ "span",
335
+ {
336
+ style: {
337
+ fontSize: isContent ? 14 : 13,
338
+ lineHeight: 1.55,
339
+ color: isContent ? theme.colors.textSecondary : theme.colors.textMuted
340
+ },
341
+ children: field.value
342
+ }
343
+ );
344
+ break;
345
+ case "flag": {
346
+ const hex = field.flagOn ? (_d = theme.tonePalette.green) != null ? _d : "#59B87B" : theme.colors.textMuted;
347
+ body = /* @__PURE__ */ jsx3(
348
+ "span",
349
+ {
350
+ style: {
351
+ alignSelf: "flex-start",
352
+ padding: "3px 9px",
353
+ borderRadius: theme.radii.sm,
354
+ fontSize: 11,
355
+ fontWeight: 600,
356
+ fontFamily: theme.fonts.heading,
357
+ textTransform: "uppercase",
358
+ background: `${hex}24`,
359
+ color: hex,
360
+ border: `1px solid ${hex}55`
361
+ },
362
+ children: field.flagText
363
+ }
364
+ );
365
+ break;
366
+ }
367
+ case "stat":
368
+ body = /* @__PURE__ */ jsx3("span", { style: { fontFamily: theme.fonts.mono, fontSize: isContent ? 16 : 15, color: theme.colors.textSecondary }, children: field.value });
369
+ break;
370
+ case "tags":
371
+ body = /* @__PURE__ */ jsx3("div", { style: { display: "flex", gap: 6, flexWrap: "wrap" }, children: (_e = field.items) == null ? void 0 : _e.map((item, i) => /* @__PURE__ */ jsx3(
372
+ "span",
373
+ {
374
+ style: {
375
+ background: theme.colors.surfaceMuted,
376
+ color: theme.colors.textMuted,
377
+ border: `1px solid ${theme.colors.border}`,
378
+ padding: "3px 9px",
379
+ borderRadius: theme.radii.sm,
380
+ fontSize: 11.5
381
+ },
382
+ children: item.text
383
+ },
384
+ i
385
+ )) });
386
+ break;
387
+ case "empty":
388
+ body = /* @__PURE__ */ jsx3("span", { style: { fontSize: 13, color: theme.colors.textMuted, opacity: 0.6 }, children: "\u2014 not provided \u2014" });
389
+ break;
390
+ case "json":
391
+ body = /* @__PURE__ */ jsx3(
392
+ "pre",
393
+ {
394
+ style: {
395
+ margin: 0,
396
+ fontFamily: theme.fonts.mono,
397
+ fontSize: 11.5,
398
+ color: theme.colors.textMuted,
399
+ whiteSpace: "pre-wrap",
400
+ background: theme.colors.background,
401
+ border: `1px solid ${theme.colors.border}`,
402
+ borderRadius: theme.radii.sm,
403
+ padding: "10px 12px"
404
+ },
405
+ children: field.value
406
+ }
407
+ );
408
+ break;
409
+ default:
410
+ return assertNever(field.kind);
411
+ }
412
+ return /* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: isContent ? 12 : 6 }, children: [
413
+ labelNode,
414
+ body
415
+ ] });
416
+ }
417
+
418
+ // src/components/RecordView.tsx
419
+ import * as React2 from "react";
420
+ import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
421
+ function RecordView({
422
+ record,
423
+ fieldRules,
424
+ contentKeys,
425
+ diagnosticKeys,
426
+ identityKeys = [],
427
+ header,
428
+ banner,
429
+ classifySignal,
430
+ toneMap,
431
+ defaultDiagnosticsOpen = false,
432
+ diagnosticsLabel = "Diagnostics",
433
+ diagnosticsHint = "Every other field this record reports, curated and unmapped alike",
434
+ style
435
+ }) {
436
+ var _a, _b, _c;
437
+ const theme = useFieldKitTheme();
438
+ const [open, setOpen] = React2.useState(defaultDiagnosticsOpen);
439
+ const contentFields = React2.useMemo(
440
+ () => contentKeys.map((key) => resolveField(key, record[key], fieldRules[key], { classifySignal, toneMap })),
441
+ [record, fieldRules, contentKeys, classifySignal, toneMap]
442
+ );
443
+ const diagnosticFields = React2.useMemo(
444
+ () => diagnosticKeys.map((key) => resolveField(key, record[key], fieldRules[key], { classifySignal, toneMap })),
445
+ [record, fieldRules, diagnosticKeys, classifySignal, toneMap]
446
+ );
447
+ const leftoverFields = React2.useMemo(() => {
448
+ const known = /* @__PURE__ */ new Set([...Object.keys(fieldRules), ...identityKeys]);
449
+ return Object.keys(record).filter((k) => !known.has(k)).map((k) => resolveField(k, record[k], inferRule(k, record[k]), { isLeftover: true, classifySignal, toneMap }));
450
+ }, [record, fieldRules, identityKeys, classifySignal, toneMap]);
451
+ const bannerContent = banner ? banner(record) : null;
452
+ return /* @__PURE__ */ jsxs3(
453
+ "div",
454
+ {
455
+ style: {
456
+ background: theme.colors.surface,
457
+ border: `1px solid ${theme.colors.border}`,
458
+ borderRadius: theme.radii.lg,
459
+ padding: "36px 40px",
460
+ display: "flex",
461
+ flexDirection: "column",
462
+ gap: 26,
463
+ fontFamily: theme.fonts.body,
464
+ color: theme.colors.textPrimary,
465
+ ...style
466
+ },
467
+ children: [
468
+ header == null ? void 0 : header(record),
469
+ bannerContent && /* @__PURE__ */ jsxs3(
470
+ "div",
471
+ {
472
+ style: {
473
+ background: `${(_a = theme.tonePalette.rose) != null ? _a : "#E2564F"}14`,
474
+ border: `1px solid ${(_b = theme.tonePalette.rose) != null ? _b : "#E2564F"}48`,
475
+ borderRadius: 10,
476
+ padding: "16px 18px",
477
+ display: "flex",
478
+ gap: 12,
479
+ alignItems: "flex-start"
480
+ },
481
+ children: [
482
+ /* @__PURE__ */ jsx4(WarningIcon, { size: 19, color: (_c = theme.tonePalette.rose) != null ? _c : "#E2564F", style: { flexShrink: 0, marginTop: 2 } }),
483
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", gap: 7 }, children: [
484
+ /* @__PURE__ */ jsx4("span", { style: { fontFamily: theme.fonts.heading, fontSize: 14, fontWeight: 600, color: theme.colors.textPrimary }, children: bannerContent.title }),
485
+ /* @__PURE__ */ jsx4("span", { style: { fontSize: 13.5, lineHeight: 1.55, color: theme.colors.textSecondary }, children: bannerContent.body }),
486
+ bannerContent.tags && bannerContent.tags.length > 0 && /* @__PURE__ */ jsx4("div", { style: { display: "flex", gap: 6, marginTop: 2, flexWrap: "wrap" }, children: bannerContent.tags.map((t, i) => {
487
+ var _a2, _b2, _c2;
488
+ return /* @__PURE__ */ jsx4(
489
+ "span",
490
+ {
491
+ style: {
492
+ background: `${(_a2 = theme.tonePalette.rose) != null ? _a2 : "#E2564F"}24`,
493
+ color: (_b2 = theme.tonePalette.rose) != null ? _b2 : "#E2564F",
494
+ border: `1px solid ${(_c2 = theme.tonePalette.rose) != null ? _c2 : "#E2564F"}55`,
495
+ padding: "3px 8px",
496
+ borderRadius: 5,
497
+ fontFamily: theme.fonts.heading,
498
+ fontSize: 10.5,
499
+ fontWeight: 600,
500
+ letterSpacing: "0.04em",
501
+ textTransform: "uppercase"
502
+ },
503
+ children: t
504
+ },
505
+ i
506
+ );
507
+ }) })
508
+ ] })
509
+ ]
510
+ }
511
+ ),
512
+ contentFields.map((field) => /* @__PURE__ */ jsx4(FieldRenderer, { field, variant: "content" }, field.key)),
513
+ (diagnosticFields.length > 0 || leftoverFields.length > 0) && /* @__PURE__ */ jsxs3(Fragment, { children: [
514
+ /* @__PURE__ */ jsx4("div", { style: { height: 1, background: theme.colors.border } }),
515
+ /* @__PURE__ */ jsxs3(
516
+ "button",
517
+ {
518
+ onClick: () => setOpen((v) => !v),
519
+ style: {
520
+ all: "unset",
521
+ cursor: "pointer",
522
+ display: "flex",
523
+ alignItems: "center",
524
+ justifyContent: "space-between",
525
+ width: "100%",
526
+ boxSizing: "border-box"
527
+ },
528
+ children: [
529
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", gap: 2 }, children: [
530
+ /* @__PURE__ */ jsx4("span", { style: { fontFamily: theme.fonts.heading, fontSize: 12.5, fontWeight: 600, letterSpacing: "0.04em", color: theme.colors.textSecondary }, children: diagnosticsLabel }),
531
+ /* @__PURE__ */ jsx4("span", { style: { fontSize: 11.5, color: theme.colors.textMuted }, children: diagnosticsHint })
532
+ ] }),
533
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
534
+ /* @__PURE__ */ jsx4("span", { style: { fontSize: 12, color: theme.colors.textMuted }, children: open ? "Hide" : "Show" }),
535
+ /* @__PURE__ */ jsx4(
536
+ ChevronDownIcon,
537
+ {
538
+ size: 14,
539
+ color: theme.colors.textMuted,
540
+ style: { transform: open ? "rotate(180deg)" : "rotate(0deg)", transition: "transform 120ms ease" }
541
+ }
542
+ )
543
+ ] })
544
+ ]
545
+ }
546
+ ),
547
+ open && /* @__PURE__ */ jsxs3(
548
+ "div",
549
+ {
550
+ style: {
551
+ background: theme.colors.surfaceMuted,
552
+ border: `1px solid ${theme.colors.border}`,
553
+ borderRadius: theme.radii.md,
554
+ padding: "20px 22px",
555
+ display: "flex",
556
+ flexDirection: "column",
557
+ gap: 18
558
+ },
559
+ children: [
560
+ diagnosticFields.length > 0 && /* @__PURE__ */ jsx4("div", { style: { display: "flex", flexDirection: "column", gap: 14 }, children: diagnosticFields.map((field) => /* @__PURE__ */ jsx4(FieldRenderer, { field, variant: "compact" }, field.key)) }),
561
+ leftoverFields.length > 0 && /* @__PURE__ */ jsxs3(Fragment, { children: [
562
+ /* @__PURE__ */ jsx4("div", { style: { height: 1, borderTop: `1px dashed ${theme.colors.border}` } }),
563
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", gap: 3 }, children: [
564
+ /* @__PURE__ */ jsx4(
565
+ "span",
566
+ {
567
+ style: {
568
+ fontFamily: theme.fonts.heading,
569
+ fontSize: 10.5,
570
+ fontWeight: 600,
571
+ letterSpacing: "0.08em",
572
+ textTransform: "uppercase",
573
+ color: theme.colors.textMuted
574
+ },
575
+ children: "Additional Fields"
576
+ }
577
+ ),
578
+ /* @__PURE__ */ jsx4("span", { style: { fontSize: 11, color: theme.colors.textMuted, opacity: 0.7 }, children: "Not in fieldRules yet \u2014 rendered generically from each value's shape" })
579
+ ] }),
580
+ /* @__PURE__ */ jsx4("div", { style: { display: "flex", flexDirection: "column", gap: 14 }, children: leftoverFields.map((field) => /* @__PURE__ */ jsx4(FieldRenderer, { field, variant: "compact" }, field.key)) })
581
+ ] })
582
+ ]
583
+ }
584
+ )
585
+ ] })
586
+ ]
587
+ }
588
+ );
589
+ }
590
+ export {
591
+ CheckIcon,
592
+ ChevronDownIcon,
593
+ FieldKitProvider,
594
+ FieldRenderer,
595
+ InfoIcon,
596
+ QuestionIcon,
597
+ RecordView,
598
+ TONE_PALETTE,
599
+ WarningIcon,
600
+ defaultClassifySignal,
601
+ defaultTheme,
602
+ hashTone,
603
+ inferRule,
604
+ labelFromKey,
605
+ resolveField,
606
+ toneHex,
607
+ useFieldKitTheme
608
+ };
609
+ //# sourceMappingURL=index.js.map