@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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +41 -0
  3. package/dist/area-chart.d.ts +11 -0
  4. package/dist/area-chart.d.ts.map +1 -0
  5. package/dist/area-chart.js +65 -0
  6. package/dist/auth-layout.d.ts +26 -0
  7. package/dist/auth-layout.d.ts.map +1 -0
  8. package/dist/auth-layout.js +85 -0
  9. package/dist/auth-provider.d.ts +13 -0
  10. package/dist/auth-provider.d.ts.map +1 -0
  11. package/dist/auth-provider.js +20 -0
  12. package/dist/bar-chart.d.ts +11 -0
  13. package/dist/bar-chart.d.ts.map +1 -0
  14. package/dist/bar-chart.js +64 -0
  15. package/dist/chart-card.d.ts +11 -0
  16. package/dist/chart-card.d.ts.map +1 -0
  17. package/dist/chart-card.js +43 -0
  18. package/dist/confirm-dialog.d.ts +19 -0
  19. package/dist/confirm-dialog.d.ts.map +1 -0
  20. package/dist/confirm-dialog.js +57 -0
  21. package/dist/detail-panel.d.ts +25 -0
  22. package/dist/detail-panel.d.ts.map +1 -0
  23. package/dist/detail-panel.js +116 -0
  24. package/dist/document-panel.d.ts +15 -0
  25. package/dist/document-panel.d.ts.map +1 -0
  26. package/dist/document-panel.js +80 -0
  27. package/dist/document-reader.d.ts +5 -0
  28. package/dist/document-reader.d.ts.map +1 -0
  29. package/dist/document-reader.js +27 -0
  30. package/dist/field-array-form.d.ts +30 -0
  31. package/dist/field-array-form.d.ts.map +1 -0
  32. package/dist/field-array-form.js +132 -0
  33. package/dist/image-viewer.d.ts +14 -0
  34. package/dist/image-viewer.d.ts.map +1 -0
  35. package/dist/image-viewer.js +108 -0
  36. package/dist/line-chart.d.ts +11 -0
  37. package/dist/line-chart.d.ts.map +1 -0
  38. package/dist/line-chart.js +44 -0
  39. package/dist/list-item.d.ts +16 -0
  40. package/dist/list-item.d.ts.map +1 -0
  41. package/dist/list-item.js +50 -0
  42. package/dist/list-pane.d.ts +27 -0
  43. package/dist/list-pane.d.ts.map +1 -0
  44. package/dist/list-pane.js +136 -0
  45. package/dist/login-form.d.ts +18 -0
  46. package/dist/login-form.d.ts.map +1 -0
  47. package/dist/login-form.js +109 -0
  48. package/dist/pie-chart.d.ts +12 -0
  49. package/dist/pie-chart.d.ts.map +1 -0
  50. package/dist/pie-chart.js +49 -0
  51. package/dist/radar-chart.d.ts +11 -0
  52. package/dist/radar-chart.d.ts.map +1 -0
  53. package/dist/radar-chart.js +37 -0
  54. package/dist/radial-chart.d.ts +12 -0
  55. package/dist/radial-chart.d.ts.map +1 -0
  56. package/dist/radial-chart.js +91 -0
  57. package/dist/recording-overlay.d.ts +13 -0
  58. package/dist/recording-overlay.d.ts.map +1 -0
  59. package/dist/recording-overlay.js +128 -0
  60. package/dist/split-workspace.d.ts +9 -0
  61. package/dist/split-workspace.d.ts.map +1 -0
  62. package/dist/split-workspace.js +50 -0
  63. package/dist/stat-card.d.ts +27 -0
  64. package/dist/stat-card.d.ts.map +1 -0
  65. package/dist/stat-card.js +166 -0
  66. package/dist/stats-grid.d.ts +8 -0
  67. package/dist/stats-grid.d.ts.map +1 -0
  68. package/dist/stats-grid.js +15 -0
  69. 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,5 @@
1
+ export interface DocumentReaderProps {
2
+ content: string;
3
+ }
4
+ export declare function DocumentReader({ content }: DocumentReaderProps): import("react").JSX.Element;
5
+ //# sourceMappingURL=document-reader.d.ts.map
@@ -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"}