@lindaui/blocks 0.0.2
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/LICENSE +21 -0
- package/README.md +41 -0
- package/dist/area-chart.d.ts +11 -0
- package/dist/area-chart.d.ts.map +1 -0
- package/dist/area-chart.js +65 -0
- package/dist/auth-layout.d.ts +26 -0
- package/dist/auth-layout.d.ts.map +1 -0
- package/dist/auth-layout.js +85 -0
- package/dist/auth-provider.d.ts +13 -0
- package/dist/auth-provider.d.ts.map +1 -0
- package/dist/auth-provider.js +20 -0
- package/dist/bar-chart.d.ts +11 -0
- package/dist/bar-chart.d.ts.map +1 -0
- package/dist/bar-chart.js +64 -0
- package/dist/chart-card.d.ts +11 -0
- package/dist/chart-card.d.ts.map +1 -0
- package/dist/chart-card.js +43 -0
- package/dist/confirm-dialog.d.ts +19 -0
- package/dist/confirm-dialog.d.ts.map +1 -0
- package/dist/confirm-dialog.js +57 -0
- package/dist/detail-panel.d.ts +25 -0
- package/dist/detail-panel.d.ts.map +1 -0
- package/dist/detail-panel.js +116 -0
- package/dist/document-panel.d.ts +15 -0
- package/dist/document-panel.d.ts.map +1 -0
- package/dist/document-panel.js +80 -0
- package/dist/document-reader.d.ts +5 -0
- package/dist/document-reader.d.ts.map +1 -0
- package/dist/document-reader.js +27 -0
- package/dist/field-array-form.d.ts +30 -0
- package/dist/field-array-form.d.ts.map +1 -0
- package/dist/field-array-form.js +132 -0
- package/dist/image-viewer.d.ts +14 -0
- package/dist/image-viewer.d.ts.map +1 -0
- package/dist/image-viewer.js +108 -0
- package/dist/line-chart.d.ts +11 -0
- package/dist/line-chart.d.ts.map +1 -0
- package/dist/line-chart.js +44 -0
- package/dist/list-item.d.ts +16 -0
- package/dist/list-item.d.ts.map +1 -0
- package/dist/list-item.js +50 -0
- package/dist/list-pane.d.ts +27 -0
- package/dist/list-pane.d.ts.map +1 -0
- package/dist/list-pane.js +136 -0
- package/dist/login-form.d.ts +18 -0
- package/dist/login-form.d.ts.map +1 -0
- package/dist/login-form.js +109 -0
- package/dist/pie-chart.d.ts +12 -0
- package/dist/pie-chart.d.ts.map +1 -0
- package/dist/pie-chart.js +49 -0
- package/dist/radar-chart.d.ts +11 -0
- package/dist/radar-chart.d.ts.map +1 -0
- package/dist/radar-chart.js +37 -0
- package/dist/radial-chart.d.ts +12 -0
- package/dist/radial-chart.d.ts.map +1 -0
- package/dist/radial-chart.js +91 -0
- package/dist/recording-overlay.d.ts +13 -0
- package/dist/recording-overlay.d.ts.map +1 -0
- package/dist/recording-overlay.js +128 -0
- package/dist/split-workspace.d.ts +9 -0
- package/dist/split-workspace.d.ts.map +1 -0
- package/dist/split-workspace.js +50 -0
- package/dist/stat-card.d.ts +27 -0
- package/dist/stat-card.d.ts.map +1 -0
- package/dist/stat-card.js +166 -0
- package/dist/stats-grid.d.ts +8 -0
- package/dist/stats-grid.d.ts.map +1 -0
- package/dist/stats-grid.js +15 -0
- package/package.json +149 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import { FileText } from 'lucide-react';
|
|
4
|
+
import { Button } from '@lindaui/ui/button';
|
|
5
|
+
import { Card } from '@lindaui/ui/card';
|
|
6
|
+
import { Divider } from '@lindaui/ui/divider';
|
|
7
|
+
|
|
8
|
+
function DetailPanel({ selected = false, emptyTitle = "Seleccioná un elemento", emptyDescription, emptyIcon, title, subtitle, badges, media, meta, action }) {
|
|
9
|
+
if (!selected || title === undefined) {
|
|
10
|
+
return /*#__PURE__*/ jsx("div", {
|
|
11
|
+
className: "grid h-full place-items-center p-6 sm:p-10",
|
|
12
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
13
|
+
className: "max-w-[280px] text-center",
|
|
14
|
+
children: [
|
|
15
|
+
/*#__PURE__*/ jsx("div", {
|
|
16
|
+
className: "mx-auto grid h-14 w-14 place-items-center rounded-2xl bg-secondary",
|
|
17
|
+
children: emptyIcon ?? /*#__PURE__*/ jsx(FileText, {
|
|
18
|
+
className: "h-7 w-7 text-muted-foreground",
|
|
19
|
+
strokeWidth: 1.6
|
|
20
|
+
})
|
|
21
|
+
}),
|
|
22
|
+
/*#__PURE__*/ jsx("h3", {
|
|
23
|
+
className: "mt-4 text-[15px] font-semibold",
|
|
24
|
+
children: emptyTitle
|
|
25
|
+
}),
|
|
26
|
+
emptyDescription && /*#__PURE__*/ jsx("p", {
|
|
27
|
+
className: "mt-1.5 text-sm text-muted-foreground",
|
|
28
|
+
children: emptyDescription
|
|
29
|
+
})
|
|
30
|
+
]
|
|
31
|
+
})
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return /*#__PURE__*/ jsx("div", {
|
|
35
|
+
className: "h-full overflow-y-auto px-4 py-5 sm:px-8 sm:py-7",
|
|
36
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
37
|
+
className: "mx-auto max-w-2xl",
|
|
38
|
+
children: [
|
|
39
|
+
/*#__PURE__*/ jsxs("div", {
|
|
40
|
+
children: [
|
|
41
|
+
badges && /*#__PURE__*/ jsx("div", {
|
|
42
|
+
className: "flex flex-wrap items-center gap-2.5",
|
|
43
|
+
children: badges
|
|
44
|
+
}),
|
|
45
|
+
/*#__PURE__*/ jsx("h1", {
|
|
46
|
+
className: "mt-3 text-xl font-semibold tracking-tight sm:text-2xl",
|
|
47
|
+
children: title
|
|
48
|
+
}),
|
|
49
|
+
subtitle && /*#__PURE__*/ jsx("p", {
|
|
50
|
+
className: "mt-1 text-sm text-muted-foreground",
|
|
51
|
+
children: subtitle
|
|
52
|
+
})
|
|
53
|
+
]
|
|
54
|
+
}),
|
|
55
|
+
(media || meta && meta.length > 0) && // Mobile-first: stack (media arriba, meta abajo). Desde `sm` y solo
|
|
56
|
+
// cuando hay media, split en dos columnas (media fija 200px + meta
|
|
57
|
+
// 1fr). Sin media la Card de metadata ocupa todo el ancho siempre
|
|
58
|
+
// (si no, queda atrapada en la columna 1fr con un gutter vacío).
|
|
59
|
+
/*#__PURE__*/ jsxs("div", {
|
|
60
|
+
className: media ? "mt-6 flex flex-col gap-4 sm:grid sm:grid-cols-[200px_1fr] sm:gap-6" : "mt-6",
|
|
61
|
+
children: [
|
|
62
|
+
media && /*#__PURE__*/ jsx("div", {
|
|
63
|
+
children: media
|
|
64
|
+
}),
|
|
65
|
+
meta && meta.length > 0 && /*#__PURE__*/ jsx(Card, {
|
|
66
|
+
children: /*#__PURE__*/ jsx("div", {
|
|
67
|
+
className: "px-4 py-1",
|
|
68
|
+
children: meta.map((row, i)=>/*#__PURE__*/ jsxs("div", {
|
|
69
|
+
children: [
|
|
70
|
+
i > 0 && /*#__PURE__*/ jsx(Divider, {}),
|
|
71
|
+
/*#__PURE__*/ jsxs("div", {
|
|
72
|
+
className: "flex items-start gap-2.5 py-2.5",
|
|
73
|
+
children: [
|
|
74
|
+
row.icon && /*#__PURE__*/ jsx("div", {
|
|
75
|
+
className: "mt-0.5 h-4 w-4 shrink-0 text-muted-foreground",
|
|
76
|
+
children: row.icon
|
|
77
|
+
}),
|
|
78
|
+
/*#__PURE__*/ jsxs("div", {
|
|
79
|
+
className: "flex flex-1 justify-between gap-3",
|
|
80
|
+
children: [
|
|
81
|
+
/*#__PURE__*/ jsx("span", {
|
|
82
|
+
className: "text-sm text-muted-foreground",
|
|
83
|
+
children: row.label
|
|
84
|
+
}),
|
|
85
|
+
/*#__PURE__*/ jsx("span", {
|
|
86
|
+
className: "text-right text-sm font-medium",
|
|
87
|
+
children: row.value
|
|
88
|
+
})
|
|
89
|
+
]
|
|
90
|
+
})
|
|
91
|
+
]
|
|
92
|
+
})
|
|
93
|
+
]
|
|
94
|
+
}, i))
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
]
|
|
98
|
+
}),
|
|
99
|
+
action && /*#__PURE__*/ jsx("div", {
|
|
100
|
+
className: "mt-6",
|
|
101
|
+
children: /*#__PURE__*/ jsxs(Button, {
|
|
102
|
+
size: "lg",
|
|
103
|
+
onPress: action.onPress,
|
|
104
|
+
className: "w-full sm:w-auto",
|
|
105
|
+
children: [
|
|
106
|
+
action.icon,
|
|
107
|
+
action.label
|
|
108
|
+
]
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
]
|
|
112
|
+
})
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export { DetailPanel };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface DocumentPanelProps {
|
|
3
|
+
title: string;
|
|
4
|
+
subtitle?: ReactNode;
|
|
5
|
+
meta?: ReactNode;
|
|
6
|
+
statusBadge?: ReactNode;
|
|
7
|
+
state: "empty" | "loading" | "ready";
|
|
8
|
+
emptyContent?: ReactNode;
|
|
9
|
+
loadingLabel?: string;
|
|
10
|
+
notices?: ReactNode;
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
footer?: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
export declare function DocumentPanel({ title, subtitle, meta, statusBadge, state, emptyContent, loadingLabel, notices, children, footer, }: DocumentPanelProps): import("react").JSX.Element;
|
|
15
|
+
//# sourceMappingURL=document-panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-panel.d.ts","sourceRoot":"","sources":["../src/document-panel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAMvC,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;IACrC,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,WAAW,EACX,KAAK,EACL,YAAY,EACZ,YAA0B,EAC1B,OAAO,EACP,QAAQ,EACR,MAAM,GACP,EAAE,kBAAkB,+BAqDpB"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { Divider } from '@lindaui/ui/divider';
|
|
3
|
+
import { Skeleton } from '@lindaui/ui/skeleton';
|
|
4
|
+
|
|
5
|
+
function DocumentPanel({ title, subtitle, meta, statusBadge, state, emptyContent, loadingLabel = "Cargando…", notices, children, footer }) {
|
|
6
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
7
|
+
className: "flex flex-col h-full",
|
|
8
|
+
children: [
|
|
9
|
+
/*#__PURE__*/ jsxs("div", {
|
|
10
|
+
className: "flex flex-wrap items-start justify-between gap-3 px-4 pb-3 pt-4 flex-none sm:px-5",
|
|
11
|
+
children: [
|
|
12
|
+
/*#__PURE__*/ jsxs("div", {
|
|
13
|
+
className: "min-w-0",
|
|
14
|
+
children: [
|
|
15
|
+
/*#__PURE__*/ jsx("h2", {
|
|
16
|
+
className: "truncate text-lg font-bold leading-tight tracking-tight sm:text-xl",
|
|
17
|
+
children: title
|
|
18
|
+
}),
|
|
19
|
+
subtitle && /*#__PURE__*/ jsx("p", {
|
|
20
|
+
className: "mt-0.5 text-sm text-muted-foreground",
|
|
21
|
+
children: subtitle
|
|
22
|
+
}),
|
|
23
|
+
meta && /*#__PURE__*/ jsx("p", {
|
|
24
|
+
className: "mt-0.5 text-xs text-muted-foreground tabular-nums",
|
|
25
|
+
children: meta
|
|
26
|
+
})
|
|
27
|
+
]
|
|
28
|
+
}),
|
|
29
|
+
statusBadge && /*#__PURE__*/ jsx("div", {
|
|
30
|
+
className: "flex-none",
|
|
31
|
+
children: statusBadge
|
|
32
|
+
})
|
|
33
|
+
]
|
|
34
|
+
}),
|
|
35
|
+
/*#__PURE__*/ jsx(Divider, {}),
|
|
36
|
+
/*#__PURE__*/ jsxs("div", {
|
|
37
|
+
className: "flex-1 overflow-y-auto px-4 py-4 sm:px-5",
|
|
38
|
+
children: [
|
|
39
|
+
state === "empty" && emptyContent,
|
|
40
|
+
state === "loading" && /*#__PURE__*/ jsxs("div", {
|
|
41
|
+
role: "status",
|
|
42
|
+
className: "flex flex-col gap-3",
|
|
43
|
+
children: [
|
|
44
|
+
/*#__PURE__*/ jsx("span", {
|
|
45
|
+
className: "text-sm text-muted-foreground",
|
|
46
|
+
children: loadingLabel
|
|
47
|
+
}),
|
|
48
|
+
/*#__PURE__*/ jsx(Skeleton, {
|
|
49
|
+
className: "h-3 w-full"
|
|
50
|
+
}),
|
|
51
|
+
/*#__PURE__*/ jsx(Skeleton, {
|
|
52
|
+
className: "h-3 w-full"
|
|
53
|
+
}),
|
|
54
|
+
/*#__PURE__*/ jsx(Skeleton, {
|
|
55
|
+
className: "h-3 w-3/4"
|
|
56
|
+
})
|
|
57
|
+
]
|
|
58
|
+
}),
|
|
59
|
+
state === "ready" && /*#__PURE__*/ jsxs(Fragment, {
|
|
60
|
+
children: [
|
|
61
|
+
notices,
|
|
62
|
+
children
|
|
63
|
+
]
|
|
64
|
+
})
|
|
65
|
+
]
|
|
66
|
+
}),
|
|
67
|
+
footer && /*#__PURE__*/ jsxs(Fragment, {
|
|
68
|
+
children: [
|
|
69
|
+
/*#__PURE__*/ jsx(Divider, {}),
|
|
70
|
+
/*#__PURE__*/ jsx("div", {
|
|
71
|
+
className: "flex-none flex flex-wrap gap-2 p-4",
|
|
72
|
+
children: footer
|
|
73
|
+
})
|
|
74
|
+
]
|
|
75
|
+
})
|
|
76
|
+
]
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export { DocumentPanel };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-reader.d.ts","sourceRoot":"","sources":["../src/document-reader.tsx"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,EAAE,mBAAmB,+BAsB9D"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
function DocumentReader({ content }) {
|
|
4
|
+
const blocks = content.trim().split(/\n\s*\n/);
|
|
5
|
+
return /*#__PURE__*/ jsx("div", {
|
|
6
|
+
className: "flex flex-col gap-4",
|
|
7
|
+
children: blocks.map((block, i)=>{
|
|
8
|
+
const lines = block.split("\n");
|
|
9
|
+
const heading = lines[0];
|
|
10
|
+
const body = lines.slice(1).join(" ");
|
|
11
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
12
|
+
children: [
|
|
13
|
+
/*#__PURE__*/ jsx("div", {
|
|
14
|
+
className: "text-xs font-semibold tracking-widest uppercase text-muted-foreground",
|
|
15
|
+
children: heading
|
|
16
|
+
}),
|
|
17
|
+
body && /*#__PURE__*/ jsx("p", {
|
|
18
|
+
className: "mt-1.5 text-[13px] leading-relaxed text-pretty sm:text-sm",
|
|
19
|
+
children: body
|
|
20
|
+
})
|
|
21
|
+
]
|
|
22
|
+
}, i);
|
|
23
|
+
})
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { DocumentReader };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export interface FieldArrayFormValues {
|
|
3
|
+
category: string;
|
|
4
|
+
name: string;
|
|
5
|
+
entries: {
|
|
6
|
+
key: string;
|
|
7
|
+
value: string;
|
|
8
|
+
}[];
|
|
9
|
+
}
|
|
10
|
+
export interface FieldArrayFormProps {
|
|
11
|
+
onSubmit: (values: FieldArrayFormValues) => void | Promise<void>;
|
|
12
|
+
options: {
|
|
13
|
+
value: string;
|
|
14
|
+
label: string;
|
|
15
|
+
}[];
|
|
16
|
+
categoryLabel?: string;
|
|
17
|
+
nameLabel?: string;
|
|
18
|
+
namePlaceholder?: string;
|
|
19
|
+
entriesLabel?: string;
|
|
20
|
+
addLabel?: string;
|
|
21
|
+
removeLabel?: string;
|
|
22
|
+
keyPlaceholder?: string;
|
|
23
|
+
valuePlaceholder?: string;
|
|
24
|
+
emptyHint?: ReactNode;
|
|
25
|
+
submitLabel?: string;
|
|
26
|
+
loading?: boolean;
|
|
27
|
+
defaultValues?: Partial<FieldArrayFormValues>;
|
|
28
|
+
}
|
|
29
|
+
export declare function FieldArrayForm({ onSubmit, options, categoryLabel, nameLabel, namePlaceholder, entriesLabel, addLabel, removeLabel, keyPlaceholder, valuePlaceholder, emptyHint, submitLabel, loading, defaultValues, }: FieldArrayFormProps): import("react").JSX.Element;
|
|
30
|
+
//# sourceMappingURL=field-array-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-array-form.d.ts","sourceRoot":"","sources":["../src/field-array-form.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAOvC,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC3C;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC/C;AAED,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,OAAO,EACP,aAA2B,EAC3B,SAAoB,EACpB,eAAe,EACf,YAAyB,EACzB,QAA4B,EAC5B,WAAgC,EAChC,cAAwB,EACxB,gBAA0B,EAC1B,SAAS,EACT,WAAuB,EACvB,OAAe,EACf,aAAa,GACd,EAAE,mBAAmB,+BAmHrB"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import { useForm, useFieldArray, Controller } from 'react-hook-form';
|
|
4
|
+
import { X, Plus } from 'lucide-react';
|
|
5
|
+
import { Button } from '@lindaui/ui/button';
|
|
6
|
+
import { Input } from '@lindaui/ui/input';
|
|
7
|
+
import { Select } from '@lindaui/ui/select';
|
|
8
|
+
|
|
9
|
+
function FieldArrayForm({ onSubmit, options, categoryLabel = "Categoría", nameLabel = "Nombre", namePlaceholder, entriesLabel = "Entradas", addLabel = "Agregar entrada", removeLabel = "Eliminar entrada", keyPlaceholder = "Clave", valuePlaceholder = "Valor", emptyHint, submitLabel = "Guardar", loading = false, defaultValues }) {
|
|
10
|
+
const { control, handleSubmit } = useForm({
|
|
11
|
+
defaultValues: {
|
|
12
|
+
category: defaultValues?.category ?? options[0]?.value ?? "",
|
|
13
|
+
name: defaultValues?.name ?? "",
|
|
14
|
+
entries: defaultValues?.entries ?? []
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
const { fields, append, remove } = useFieldArray({
|
|
18
|
+
control,
|
|
19
|
+
name: "entries"
|
|
20
|
+
});
|
|
21
|
+
return /*#__PURE__*/ jsx("form", {
|
|
22
|
+
onSubmit: handleSubmit(onSubmit),
|
|
23
|
+
noValidate: true,
|
|
24
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
25
|
+
className: "flex flex-col gap-4 px-4 py-4 sm:px-6 sm:py-5",
|
|
26
|
+
children: [
|
|
27
|
+
/*#__PURE__*/ jsxs("div", {
|
|
28
|
+
children: [
|
|
29
|
+
/*#__PURE__*/ jsx("label", {
|
|
30
|
+
className: "text-sm font-medium",
|
|
31
|
+
children: categoryLabel
|
|
32
|
+
}),
|
|
33
|
+
/*#__PURE__*/ jsx(Controller, {
|
|
34
|
+
control: control,
|
|
35
|
+
name: "category",
|
|
36
|
+
render: ({ field })=>/*#__PURE__*/ jsx(Select, {
|
|
37
|
+
items: options,
|
|
38
|
+
value: field.value,
|
|
39
|
+
onChange: (val)=>field.onChange(val)
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
]
|
|
43
|
+
}),
|
|
44
|
+
/*#__PURE__*/ jsx(Controller, {
|
|
45
|
+
control: control,
|
|
46
|
+
name: "name",
|
|
47
|
+
render: ({ field })=>/*#__PURE__*/ jsx(Input, {
|
|
48
|
+
label: nameLabel,
|
|
49
|
+
placeholder: namePlaceholder,
|
|
50
|
+
value: field.value,
|
|
51
|
+
onChange: field.onChange,
|
|
52
|
+
onBlur: field.onBlur,
|
|
53
|
+
name: field.name
|
|
54
|
+
})
|
|
55
|
+
}),
|
|
56
|
+
/*#__PURE__*/ jsxs("div", {
|
|
57
|
+
className: "flex flex-col gap-2",
|
|
58
|
+
children: [
|
|
59
|
+
/*#__PURE__*/ jsx("p", {
|
|
60
|
+
className: "text-sm font-medium",
|
|
61
|
+
children: entriesLabel
|
|
62
|
+
}),
|
|
63
|
+
fields.length === 0 && emptyHint && /*#__PURE__*/ jsx("div", {
|
|
64
|
+
className: "text-sm text-muted-foreground",
|
|
65
|
+
children: emptyHint
|
|
66
|
+
}),
|
|
67
|
+
fields.map((field, index)=>/*#__PURE__*/ jsxs("div", {
|
|
68
|
+
className: "flex flex-col gap-2 sm:flex-row sm:items-start",
|
|
69
|
+
children: [
|
|
70
|
+
/*#__PURE__*/ jsx(Controller, {
|
|
71
|
+
control: control,
|
|
72
|
+
name: `entries.${index}.key`,
|
|
73
|
+
render: ({ field: f })=>/*#__PURE__*/ jsx(Input, {
|
|
74
|
+
placeholder: keyPlaceholder,
|
|
75
|
+
"aria-label": `${keyPlaceholder} ${index + 1}`,
|
|
76
|
+
value: f.value,
|
|
77
|
+
onChange: f.onChange,
|
|
78
|
+
onBlur: f.onBlur,
|
|
79
|
+
name: f.name,
|
|
80
|
+
className: "min-w-0 w-full"
|
|
81
|
+
})
|
|
82
|
+
}),
|
|
83
|
+
/*#__PURE__*/ jsx(Controller, {
|
|
84
|
+
control: control,
|
|
85
|
+
name: `entries.${index}.value`,
|
|
86
|
+
render: ({ field: f })=>/*#__PURE__*/ jsx(Input, {
|
|
87
|
+
placeholder: valuePlaceholder,
|
|
88
|
+
"aria-label": `${valuePlaceholder} ${index + 1}`,
|
|
89
|
+
value: f.value,
|
|
90
|
+
onChange: f.onChange,
|
|
91
|
+
onBlur: f.onBlur,
|
|
92
|
+
name: f.name,
|
|
93
|
+
className: "min-w-0 w-full"
|
|
94
|
+
})
|
|
95
|
+
}),
|
|
96
|
+
/*#__PURE__*/ jsx(Button, {
|
|
97
|
+
variant: "ghost",
|
|
98
|
+
onPress: ()=>remove(index),
|
|
99
|
+
"aria-label": removeLabel,
|
|
100
|
+
className: "w-full sm:w-auto",
|
|
101
|
+
children: /*#__PURE__*/ jsx(X, {
|
|
102
|
+
size: 16
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
]
|
|
106
|
+
}, field.id)),
|
|
107
|
+
/*#__PURE__*/ jsxs(Button, {
|
|
108
|
+
variant: "secondary",
|
|
109
|
+
onPress: ()=>append({
|
|
110
|
+
key: "",
|
|
111
|
+
value: ""
|
|
112
|
+
}),
|
|
113
|
+
children: [
|
|
114
|
+
/*#__PURE__*/ jsx(Plus, {
|
|
115
|
+
size: 16
|
|
116
|
+
}),
|
|
117
|
+
addLabel
|
|
118
|
+
]
|
|
119
|
+
})
|
|
120
|
+
]
|
|
121
|
+
}),
|
|
122
|
+
/*#__PURE__*/ jsx(Button, {
|
|
123
|
+
type: "submit",
|
|
124
|
+
isDisabled: loading,
|
|
125
|
+
children: submitLabel
|
|
126
|
+
})
|
|
127
|
+
]
|
|
128
|
+
})
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export { FieldArrayForm };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface ImageViewerProps {
|
|
3
|
+
src?: string;
|
|
4
|
+
alt?: string;
|
|
5
|
+
annotations?: ReactNode;
|
|
6
|
+
caption?: string;
|
|
7
|
+
placeholderLabel?: string;
|
|
8
|
+
dim?: number;
|
|
9
|
+
showControls?: boolean;
|
|
10
|
+
minZoom?: number;
|
|
11
|
+
maxZoom?: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function ImageViewer({ src, alt, annotations, caption, placeholderLabel, dim, showControls, minZoom, maxZoom, }: ImageViewerProps): import("react").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=image-viewer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-viewer.d.ts","sourceRoot":"","sources":["../src/image-viewer.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,WAAW,CAAC,EAC1B,GAAG,EACH,GAAQ,EACR,WAAW,EACX,OAAO,EACP,gBAAgB,EAChB,GAAO,EACP,YAAoB,EACpB,OAAW,EACX,OAAa,GACd,EAAE,gBAAgB,+BAoGlB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Scan, ZoomOut, ZoomIn, Frame } from 'lucide-react';
|
|
5
|
+
|
|
6
|
+
function ImageViewer({ src, alt = "", annotations, caption, placeholderLabel, dim = 0, showControls = false, minZoom = 1, maxZoom = 2.6 }) {
|
|
7
|
+
const [zoom, setZoom] = useState(1);
|
|
8
|
+
const [imgOk, setImgOk] = useState(false);
|
|
9
|
+
const showPlaceholder = !src || !imgOk;
|
|
10
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
11
|
+
className: "absolute inset-0 overflow-hidden bg-viewer-bg text-viewer-foreground",
|
|
12
|
+
children: [
|
|
13
|
+
/*#__PURE__*/ jsxs("div", {
|
|
14
|
+
className: "absolute inset-0 grid place-items-center transition-transform duration-300",
|
|
15
|
+
style: {
|
|
16
|
+
transform: `scale(${zoom})`
|
|
17
|
+
},
|
|
18
|
+
children: [
|
|
19
|
+
src && /*#__PURE__*/ jsx("img", {
|
|
20
|
+
src: src,
|
|
21
|
+
alt: alt,
|
|
22
|
+
onLoad: ()=>setImgOk(true),
|
|
23
|
+
onError: ()=>setImgOk(false),
|
|
24
|
+
className: "max-h-full max-w-full object-contain",
|
|
25
|
+
style: {
|
|
26
|
+
display: imgOk ? "block" : "none"
|
|
27
|
+
}
|
|
28
|
+
}),
|
|
29
|
+
showPlaceholder && /*#__PURE__*/ jsx("div", {
|
|
30
|
+
className: "grid place-items-center rounded-lg border border-dashed",
|
|
31
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
32
|
+
className: "text-center p-4",
|
|
33
|
+
children: [
|
|
34
|
+
/*#__PURE__*/ jsx(Scan, {
|
|
35
|
+
className: "mx-auto opacity-50",
|
|
36
|
+
style: {
|
|
37
|
+
width: 40,
|
|
38
|
+
height: 40
|
|
39
|
+
},
|
|
40
|
+
strokeWidth: 1.3
|
|
41
|
+
}),
|
|
42
|
+
placeholderLabel && /*#__PURE__*/ jsx("div", {
|
|
43
|
+
className: "mt-3 font-mono text-xs tracking-widest opacity-70",
|
|
44
|
+
children: placeholderLabel
|
|
45
|
+
})
|
|
46
|
+
]
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
]
|
|
50
|
+
}),
|
|
51
|
+
annotations && /*#__PURE__*/ jsx("div", {
|
|
52
|
+
className: "absolute right-4 top-4 z-10",
|
|
53
|
+
children: annotations
|
|
54
|
+
}),
|
|
55
|
+
caption && /*#__PURE__*/ jsx("div", {
|
|
56
|
+
className: "absolute bottom-3.5 left-4 font-mono text-[9px] opacity-40 sm:text-[10px]",
|
|
57
|
+
children: caption
|
|
58
|
+
}),
|
|
59
|
+
showControls && /*#__PURE__*/ jsxs("div", {
|
|
60
|
+
className: "absolute bottom-4 left-3 z-20 flex items-center gap-1.5 sm:bottom-5 sm:left-4 sm:gap-2",
|
|
61
|
+
children: [
|
|
62
|
+
/*#__PURE__*/ jsx("button", {
|
|
63
|
+
type: "button",
|
|
64
|
+
onClick: ()=>setZoom((z)=>Math.max(minZoom, +(z - 0.2).toFixed(2))),
|
|
65
|
+
className: "h-10 w-10 rounded-[10px] flex items-center justify-center sm:h-9 sm:w-9",
|
|
66
|
+
"aria-label": "Reducir zoom",
|
|
67
|
+
children: /*#__PURE__*/ jsx(ZoomOut, {
|
|
68
|
+
className: "h-[17px] w-[17px]"
|
|
69
|
+
})
|
|
70
|
+
}),
|
|
71
|
+
/*#__PURE__*/ jsxs("span", {
|
|
72
|
+
className: "self-center min-w-9 text-center font-mono text-[11px] opacity-75",
|
|
73
|
+
children: [
|
|
74
|
+
Math.round(zoom * 100),
|
|
75
|
+
"%"
|
|
76
|
+
]
|
|
77
|
+
}),
|
|
78
|
+
/*#__PURE__*/ jsx("button", {
|
|
79
|
+
type: "button",
|
|
80
|
+
onClick: ()=>setZoom((z)=>Math.min(maxZoom, +(z + 0.2).toFixed(2))),
|
|
81
|
+
className: "h-10 w-10 rounded-[10px] flex items-center justify-center sm:h-9 sm:w-9",
|
|
82
|
+
"aria-label": "Ampliar zoom",
|
|
83
|
+
children: /*#__PURE__*/ jsx(ZoomIn, {
|
|
84
|
+
className: "h-[17px] w-[17px]"
|
|
85
|
+
})
|
|
86
|
+
}),
|
|
87
|
+
/*#__PURE__*/ jsx("button", {
|
|
88
|
+
type: "button",
|
|
89
|
+
onClick: ()=>setZoom(1),
|
|
90
|
+
className: "h-10 w-10 rounded-[10px] flex items-center justify-center sm:h-9 sm:w-9",
|
|
91
|
+
"aria-label": "Encuadrar",
|
|
92
|
+
children: /*#__PURE__*/ jsx(Frame, {
|
|
93
|
+
className: "h-4 w-4"
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
]
|
|
97
|
+
}),
|
|
98
|
+
dim > 0 && /*#__PURE__*/ jsx("div", {
|
|
99
|
+
className: "absolute inset-0 transition-opacity duration-300",
|
|
100
|
+
style: {
|
|
101
|
+
background: `color-mix(in oklch, var(--viewer-bg) ${Math.round(dim * 100)}%, transparent)`
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
]
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export { ImageViewer };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ChartConfig } from "@lindaui/ui/chart";
|
|
2
|
+
export interface LineChartProps {
|
|
3
|
+
data: Array<Record<string, string | number>>;
|
|
4
|
+
config: ChartConfig;
|
|
5
|
+
categoryKey: string;
|
|
6
|
+
series: string[];
|
|
7
|
+
variant?: "default" | "dots";
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function LineChart({ data, config, categoryKey, series, variant, className, }: LineChartProps): import("react").JSX.Element;
|
|
11
|
+
//# sourceMappingURL=line-chart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"line-chart.d.ts","sourceRoot":"","sources":["../src/line-chart.tsx"],"names":[],"mappings":"AACA,OAAO,EAML,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAS3B,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;IAC7C,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,MAAM,EACN,WAAW,EACX,MAAM,EACN,OAAmB,EACnB,SAAS,GACV,EAAE,cAAc,+BAwBhB"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import { ChartContainer, ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent } from '@lindaui/ui/chart';
|
|
4
|
+
import { LineChart as LineChart$1, CartesianGrid, XAxis, YAxis, Line } from 'recharts';
|
|
5
|
+
|
|
6
|
+
function LineChart({ data, config, categoryKey, series, variant = "default", className }) {
|
|
7
|
+
const showDots = variant === "dots";
|
|
8
|
+
return /*#__PURE__*/ jsx(ChartContainer, {
|
|
9
|
+
config: config,
|
|
10
|
+
className: className,
|
|
11
|
+
children: /*#__PURE__*/ jsxs(LineChart$1, {
|
|
12
|
+
data: data,
|
|
13
|
+
children: [
|
|
14
|
+
/*#__PURE__*/ jsx(CartesianGrid, {
|
|
15
|
+
vertical: false
|
|
16
|
+
}),
|
|
17
|
+
/*#__PURE__*/ jsx(XAxis, {
|
|
18
|
+
dataKey: categoryKey,
|
|
19
|
+
tickLine: false,
|
|
20
|
+
axisLine: false
|
|
21
|
+
}),
|
|
22
|
+
/*#__PURE__*/ jsx(YAxis, {
|
|
23
|
+
tickLine: false,
|
|
24
|
+
axisLine: false
|
|
25
|
+
}),
|
|
26
|
+
/*#__PURE__*/ jsx(ChartTooltip, {
|
|
27
|
+
content: /*#__PURE__*/ jsx(ChartTooltipContent, {})
|
|
28
|
+
}),
|
|
29
|
+
series.length > 1 && /*#__PURE__*/ jsx(ChartLegend, {
|
|
30
|
+
content: /*#__PURE__*/ jsx(ChartLegendContent, {})
|
|
31
|
+
}),
|
|
32
|
+
series.map((key)=>/*#__PURE__*/ jsx(Line, {
|
|
33
|
+
dataKey: key,
|
|
34
|
+
stroke: `var(--color-${key})`,
|
|
35
|
+
strokeWidth: 2,
|
|
36
|
+
dot: showDots,
|
|
37
|
+
type: "monotone"
|
|
38
|
+
}, key))
|
|
39
|
+
]
|
|
40
|
+
})
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { LineChart };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface ListItemProps {
|
|
3
|
+
title: string;
|
|
4
|
+
subtitle?: ReactNode;
|
|
5
|
+
meta?: ReactNode;
|
|
6
|
+
leading?: ReactNode;
|
|
7
|
+
badge?: {
|
|
8
|
+
label: string;
|
|
9
|
+
variant?: "default" | "success" | "warning" | "danger" | "info";
|
|
10
|
+
};
|
|
11
|
+
selected?: boolean;
|
|
12
|
+
onSelect?: () => void;
|
|
13
|
+
showChevron?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function ListItem({ title, subtitle, meta, leading, badge, selected, onSelect, showChevron, }: ListItemProps): import("react").JSX.Element;
|
|
16
|
+
//# sourceMappingURL=list-item.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-item.d.ts","sourceRoot":"","sources":["../src/list-item.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAA;KAAE,CAAC;IAC3F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,KAAK,EACL,QAAgB,EAChB,QAAQ,EACR,WAAmB,GACpB,EAAE,aAAa,+BAqCf"}
|