@asteby/metacore-runtime-react 49.1.0 → 49.2.1
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/CHANGELOG.md +37 -0
- package/dist/action-modal-dispatcher.d.ts +1 -0
- package/dist/action-modal-dispatcher.d.ts.map +1 -1
- package/dist/action-modal-dispatcher.js +34 -5
- package/dist/business/document-editor-model.d.ts +27 -1
- package/dist/business/document-editor-model.d.ts.map +1 -1
- package/dist/business/document-editor-model.js +104 -7
- package/dist/business/document-editor-panels.d.ts +18 -0
- package/dist/business/document-editor-panels.d.ts.map +1 -1
- package/dist/business/document-editor-panels.js +9 -0
- package/dist/business/document-editor.d.ts +7 -1
- package/dist/business/document-editor.d.ts.map +1 -1
- package/dist/business/document-editor.js +106 -41
- package/dist/document-form-dialog.d.ts.map +1 -1
- package/dist/document-form-dialog.js +8 -3
- package/dist/dynamic-row-actions.d.ts +6 -0
- package/dist/dynamic-row-actions.d.ts.map +1 -1
- package/dist/dynamic-row-actions.js +9 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/record-mutation-events.d.ts +12 -0
- package/dist/record-mutation-events.d.ts.map +1 -1
- package/dist/record-mutation-events.js +18 -0
- package/package.json +1 -1
- package/src/__tests__/document-editor-model.test.ts +27 -0
- package/src/__tests__/document-editor.test.tsx +60 -0
- package/src/__tests__/invoice-document-editor.test.tsx +267 -0
- package/src/__tests__/r5-self-label-settled.test.ts +57 -0
- package/src/__tests__/r6-editor-source-seeds.test.tsx +137 -0
- package/src/__tests__/row-action-link-navigation.test.ts +10 -6
- package/src/action-modal-dispatcher.tsx +34 -5
- package/src/business/document-editor-model.ts +118 -7
- package/src/business/document-editor-panels.tsx +49 -0
- package/src/business/document-editor.tsx +288 -177
- package/src/document-form-dialog.tsx +13 -4
- package/src/dynamic-row-actions.tsx +12 -4
- package/src/index.ts +2 -0
- package/src/record-mutation-events.ts +23 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# @asteby/metacore-runtime-react
|
|
2
2
|
|
|
3
|
+
## 49.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- c4a7056: «Nota de crédito» / crear-desde: navega con /m/$model + search (abre el editor con la factura, no solo la lista).
|
|
8
|
+
- c4a7056: DocumentEditor: «Cargar desde» venta, OT o cotización deja el cliente elegido y los selectores muestran nombre o folio, no el UUID.
|
|
9
|
+
|
|
10
|
+
- La cabecera del origen (`sources[].header`, p. ej. `customer_id`, y `link_field`) se carga antes que los renglones, así que el cliente y su tarjeta llegan aunque los renglones del origen fallen.
|
|
11
|
+
- Los selectores que el editor llena por código (cliente, documento origen, «Factura a abonar» de la NC) se siembran con la etiqueta que ya conoce: el objeto hermano `{value,label}` que sirve el host, el nombre de la contraparte cargada o el folio del origen. El selector «Cargar desde…» también muestra el folio.
|
|
12
|
+
- La vista previa local muestra esas etiquetas, y un campo con `options` en objeto ya no rompe el resumen.
|
|
13
|
+
|
|
14
|
+
## 49.2.0
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- 4fca0af: DocumentEditor a pantalla completa para documentos con renglones (factura, cotización, pedido, OC).
|
|
19
|
+
|
|
20
|
+
- **Pantalla completa:** DocumentFormDialog abre el editor de un tipo `layout: "editor"` con renglones de venta o compra en un diálogo que ocupa la pantalla (máx. 1440 px). En pantallas anchas va a dos columnas: captura a la izquierda; totales, revisión y vista previa a la derecha. NC y cobro/REP siguen en el diálogo de 960 px.
|
|
21
|
+
- **Divulgación progresiva:** lo obligatorio que el tipo declara queda a la vista aunque sea de extensión (`fiscal_data.metodo_pago`, `fiscal_data.forma_pago` de la factura); las extensiones que llegan del metadata siguen plegadas en «Opciones fiscales».
|
|
22
|
+
- **Tarjeta de la contraparte:** sus filas usan las etiquetas del formulario del modelo de la contraparte (`/metadata/modal/<party.model>`): «RFC», «Régimen fiscal», «Uso CFDI» en vez de `tax_id` o `regimen_receptor`.
|
|
23
|
+
- **«Cargar desde…»:** con varias fuentes, botones por tipo de origen (venta, OT, cotización) en lugar de un `<select>`. Un origen sin dato de impuesto (p. ej. una OT de taller) toma la tasa de la org, como un renglón nuevo.
|
|
24
|
+
- **Vista previa local:** un tipo con renglones y sin acción `preview` del servidor ofrece una vista previa plegada del documento (encabezado, renglones y totales) sin crear borrador.
|
|
25
|
+
- i18n es/en: `documentEditor.source_kind`, `documentEditor.preview`, `documentEditor.advanced`.
|
|
26
|
+
|
|
27
|
+
- 4fca0af: Retest Pitsline r5 (nota de crédito y acciones):
|
|
28
|
+
|
|
29
|
+
- «Crear desde»: un renglón de origen sin descripción propia (InvoiceItem solo
|
|
30
|
+
lleva el producto) se nombra con la etiqueta del producto que resuelve el
|
|
31
|
+
host, y un renglón con producto ya no exige texto para guardar. El fallo de
|
|
32
|
+
`source-lines` (404, 400/500 de un host sin la ruta) cae a la relación.
|
|
33
|
+
- `ActionModalDispatcher` anuncia la mutación ahora y otra vez cuando el
|
|
34
|
+
servidor asienta lo derivado (`emitRecordMutationSettled`,
|
|
35
|
+
`RECORD_MUTATION_SETTLE_DELAYS`): la lista y la pestaña REP se refrescan
|
|
36
|
+
tras timbrar o registrar un pago.
|
|
37
|
+
- Un selector sembrado con el id de la propia fila muestra su folio
|
|
38
|
+
(«Factura a abonar: FAC-00015») y no el UUID.
|
|
39
|
+
|
|
3
40
|
## 49.1.0
|
|
4
41
|
|
|
5
42
|
### Minor Changes
|
|
@@ -106,6 +106,7 @@ export interface FieldDefaultContext {
|
|
|
106
106
|
*/
|
|
107
107
|
export declare function resolveFieldDefault(field: ActionFieldDef, ctx?: FieldDefaultContext): unknown;
|
|
108
108
|
export declare function buildFieldDefaults(fields: ActionFieldDef[], record: any, model?: string, ctx?: FieldDefaultContext): Record<string, any>;
|
|
109
|
+
export declare function seedOptionFromRecord(field: ActionFieldDef, value: any, record?: Record<string, any>): import('./use-options-resolver').ResolvedOption | undefined;
|
|
109
110
|
/** Renders one action field (same widgets as the action modals). Shared with DocumentFormDialog. */
|
|
110
111
|
export declare function renderField(field: ActionFieldDef, value: any, onChange: (value: any) => void, formValues?: Record<string, any>, record?: Record<string, any>, fieldErrors?: Record<string, string>): import("react").JSX.Element;
|
|
111
112
|
//# sourceMappingURL=action-modal-dispatcher.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-modal-dispatcher.d.ts","sourceRoot":"","sources":["../src/action-modal-dispatcher.tsx"],"names":[],"mappings":"AAmDA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AA8B/C,OAAO,KAAK,EAAE,cAAc,EAAmC,MAAM,SAAS,CAAA;AAE9E,OAAO,EACH,KAAK,cAAc,EACnB,KAAK,gBAAgB,EAKxB,MAAM,sBAAsB,CAAA;AAQ7B,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAA;AAiBhD,MAAM,WAAW,WAAW;IACxB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5B,SAAS,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1D;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,WAAW,CAM1D;AAsBD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG,cAAc,CAStE;AAGD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAkB3F;AAYD,MAAM,WAAW,sBAAsB;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAA;CAC1C;AAED,wBAAgB,uBAAuB,CACnC,MAAM,EAAE,cAAc,EAAE,GAAG,SAAS,EACpC,MAAM,EAAE,GAAG,EACX,SAAS,EAAE,KAAK,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,GAC5H,sBAAsB,EAAE,CAyB1B;AASD,MAAM,WAAW,uBAAuB;IACpC,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,WAAW,CAAA;IACjB,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAA;IAChB,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAA;CAChB;AAED,wBAAgB,wBAAwB,CACpC,MAAM,EAAE,cAAc,EAAE,GAAG,SAAS,EACpC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC9B,uBAAuB,EAAE,CAe3B;AAKD,wBAAgB,+BAA+B,CAC3C,GAAG,EAAE,uBAAuB,EAC5B,SAAS,EAAE,KAAK,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,GAC5H;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAA;CAAE,GAAG,IAAI,CActE;AASD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAY1D;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CASjE;AAgBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAMzG;AAYD;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAsBnG;AAED,wBAAgB,qBAAqB,CAAC,EAClC,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,KAAK,EACL,MAAM,EACN,QAAQ,EACR,SAAS,EAAE,aAAa,GAC3B,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"action-modal-dispatcher.d.ts","sourceRoot":"","sources":["../src/action-modal-dispatcher.tsx"],"names":[],"mappings":"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"}
|
|
@@ -15,7 +15,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
15
15
|
//
|
|
16
16
|
// The host injects its axios-like client via <ApiProvider>; we no longer
|
|
17
17
|
// depend on a bundler alias to `@/lib/api`.
|
|
18
|
-
import {
|
|
18
|
+
import { emitRecordMutationSettled } from './record-mutation-events';
|
|
19
19
|
import { Suspense, useState, useCallback, useEffect, useMemo, useRef, useSyncExternalStore } from 'react';
|
|
20
20
|
import { useTranslation } from 'react-i18next';
|
|
21
21
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Button, Input, Textarea, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Switch, } from '@asteby/metacore-ui/primitives';
|
|
@@ -288,9 +288,11 @@ export function scalarDefaultFromRecord(field, record, model) {
|
|
|
288
288
|
export function ActionModalDispatcher({ open, onOpenChange, action, model, record, endpoint, onSuccess: onSuccessProp, }) {
|
|
289
289
|
// Every successful action may have created/updated/deleted a record of
|
|
290
290
|
// `model` (federated component, wizard, generic form or confirmation), so
|
|
291
|
-
// announce it: mounted lists of the model reload on their own (#1020)
|
|
291
|
+
// announce it: mounted lists of the model reload on their own (#1020) —
|
|
292
|
+
// and again once the server's event subscribers had time to write what the
|
|
293
|
+
// action triggers (estado tras timbrar, REP tras un pago).
|
|
292
294
|
const onSuccess = useCallback(() => {
|
|
293
|
-
|
|
295
|
+
emitRecordMutationSettled(model, 'update');
|
|
294
296
|
onSuccessProp?.();
|
|
295
297
|
}, [model, onSuccessProp]);
|
|
296
298
|
// Reactive read: a federated remote usually registers AFTER the first
|
|
@@ -1107,8 +1109,35 @@ function WizardActionModal({ open, onOpenChange, action, model, record, endpoint
|
|
|
1107
1109
|
return (_jsxs(FieldCell, { fullWidth: fullWidth, children: [_jsx(FieldLabel, { htmlFor: field.key, required: field.required, children: tl(field.label) }), renderField(field, formData[field.key], (v) => updateField(field.key, v), formData, record)] }, field.key));
|
|
1108
1110
|
}) })] }), _jsxs(DialogFooter, { className: "shrink-0", children: [stepIndex > 0 ? (_jsx(Button, { variant: "outline", onClick: goBack, disabled: executing, children: t('common.back', { defaultValue: 'Atrás' }) })) : (_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: executing, children: t('common.cancel') })), isLast ? (_jsxs(Button, { onClick: submit, disabled: executing, style: action.color ? { backgroundColor: action.color, color: 'white' } : undefined, children: [executing ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : _jsx(DynamicIcon, { name: action.icon, className: "mr-2 h-4 w-4" }), tl(action.label)] })) : (_jsx(Button, { onClick: goNext, disabled: executing, style: action.color ? { backgroundColor: action.color, color: 'white' } : undefined, children: t('common.next', { defaultValue: 'Siguiente' }) }))] }), reasonPrompt.dialog] }) }));
|
|
1109
1111
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
+
/** Columnas con las que se nombra una fila cuando el selector no declara `options.label`. */
|
|
1113
|
+
const RECORD_LABEL_COLUMNS = ['number', 'folio', 'name', 'title', 'code', 'label'];
|
|
1114
|
+
/**
|
|
1115
|
+
* La etiqueta de la PROPIA fila cuando el campo se sembró con su id
|
|
1116
|
+
* («Factura a abonar» al registrar un pago desde la factura): la columna que el
|
|
1117
|
+
* selector usa de etiqueta (`options.label`) o la primera de nombre que tenga.
|
|
1118
|
+
* Sin esto el selector mostraba el UUID crudo (retest Pitsline r5).
|
|
1119
|
+
*/
|
|
1120
|
+
function selfLabel(field, record) {
|
|
1121
|
+
const opts = field.options;
|
|
1122
|
+
const declared = opts && !Array.isArray(opts) && typeof opts === 'object' ? opts.label : undefined;
|
|
1123
|
+
const cols = typeof declared === 'string' && declared ? [declared, ...RECORD_LABEL_COLUMNS] : RECORD_LABEL_COLUMNS;
|
|
1124
|
+
for (const c of cols) {
|
|
1125
|
+
const v = unwrapRecordScalar(record[c]);
|
|
1126
|
+
if ((typeof v === 'string' && v.trim()) || typeof v === 'number')
|
|
1127
|
+
return String(v);
|
|
1128
|
+
}
|
|
1129
|
+
return '';
|
|
1130
|
+
}
|
|
1131
|
+
export function seedOptionFromRecord(field, value, record) {
|
|
1132
|
+
if (!record)
|
|
1133
|
+
return undefined;
|
|
1134
|
+
const selfId = unwrapRecordScalar(record.id);
|
|
1135
|
+
if (value != null && value !== '' && selfId != null && String(selfId) === String(value)) {
|
|
1136
|
+
const label = selfLabel(field, record);
|
|
1137
|
+
if (label)
|
|
1138
|
+
return { id: String(value), value: String(value), label, name: label };
|
|
1139
|
+
}
|
|
1140
|
+
if (!field.key.endsWith('_id'))
|
|
1112
1141
|
return undefined;
|
|
1113
1142
|
const siblingKey = field.key.replace(/_id$/, '');
|
|
1114
1143
|
const sib = record[siblingKey];
|
|
@@ -11,7 +11,9 @@ export declare function isEditorLayout(type: Pick<DocumentFormType, 'layout' | '
|
|
|
11
11
|
export declare function editorLinesConfig(type: DocumentFormType, forms: Pick<DocumentFormsManifest, 'lines_field'>): EditorLinesConfig | undefined;
|
|
12
12
|
/**
|
|
13
13
|
* Divulgación progresiva: ¿el campo va plegado en «Opciones fiscales»?
|
|
14
|
-
* - campos de extensión (`fiscal_data.*`) que aportan otros addons
|
|
14
|
+
* - campos de extensión (`fiscal_data.*`) que aportan otros addons (los que
|
|
15
|
+
* el propio tipo declara obligatorios, p. ej. método y forma de pago de la
|
|
16
|
+
* factura, se marcan esenciales en splitEditorFields);
|
|
15
17
|
* - `section: "fiscal" | "advanced"`;
|
|
16
18
|
* - catálogos opcionales que ya traen un default (método, serie, relación…):
|
|
17
19
|
* el usuario no necesita tocarlos para guardar.
|
|
@@ -83,7 +85,10 @@ export declare function creditStatus(party: Record<string, any> | null, cols: {
|
|
|
83
85
|
export declare function linesFromSource(rows: unknown, map?: Record<string, string>, opts?: {
|
|
84
86
|
kind?: DocumentFormLines['kind'];
|
|
85
87
|
discountMode?: DocumentFormLines['discount_mode'];
|
|
88
|
+
defaultTaxRate?: number;
|
|
86
89
|
}): LineItem[];
|
|
90
|
+
/** El editor ocupa toda la pantalla: documentos comerciales con renglones (factura, cotización, pedido, OC). */
|
|
91
|
+
export declare function isFullscreenEditor(type: DocumentFormType, forms: Pick<DocumentFormsManifest, 'lines_field'>): boolean;
|
|
87
92
|
/** Cuántos renglones del origen se cargaron y cuántos se omitieron por estar ya cubiertos. */
|
|
88
93
|
export declare function sourceLoadSummary(rows: unknown): {
|
|
89
94
|
loaded: number;
|
|
@@ -91,6 +96,27 @@ export declare function sourceLoadSummary(rows: unknown): {
|
|
|
91
96
|
};
|
|
92
97
|
/** Fuente que precarga desde lo pendiente servido por el host (no desde la relación cruda). */
|
|
93
98
|
export declare function sourceTracksRemaining(src: Pick<DocumentFormSource, 'line_link_field' | 'remaining_qty_field' | 'remaining_endpoint'>): boolean;
|
|
99
|
+
/** Opción ya resuelta de un selector de la cabecera que el editor llenó por código. */
|
|
100
|
+
export interface SeedLabel {
|
|
101
|
+
value: string;
|
|
102
|
+
label: string;
|
|
103
|
+
}
|
|
104
|
+
/** Nombre visible de un registro: la columna declarada por el campo, luego folio/nombre. */
|
|
105
|
+
export declare function recordLabel(rec: Record<string, any> | null | undefined, preferred?: string): string | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* Etiquetas de lo que «Cargar desde…» escribe en la cabecera, para que el
|
|
108
|
+
* selector muestre el nombre y no el UUID sin abrirse:
|
|
109
|
+
* - `header` (`customer_id ← customer_id`): el objeto hermano `{value,label}`
|
|
110
|
+
* que el host sirve junto a la FK (`customer`);
|
|
111
|
+
* - `link_field`: el propio documento origen, con su folio.
|
|
112
|
+
*/
|
|
113
|
+
export declare function sourceHeaderSeeds(src: Pick<DocumentFormSource, 'header' | 'link_field'>, rec: Record<string, any>, id: string, fields?: readonly ActionFieldDef[]): Record<string, SeedLabel>;
|
|
114
|
+
/**
|
|
115
|
+
* Registro para `renderField` con las etiquetas sembradas como objeto hermano
|
|
116
|
+
* (`customer_id` → `customer: {value,label}`), el mismo contrato que sirve el
|
|
117
|
+
* host en una fila. Conserva el registro desde el que se abrió.
|
|
118
|
+
*/
|
|
119
|
+
export declare function seedRecord(seeds: Record<string, SeedLabel>, record?: Record<string, any>): Record<string, any> | undefined;
|
|
94
120
|
export interface EditorIssue {
|
|
95
121
|
field?: string;
|
|
96
122
|
severity: 'error' | 'warning';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-editor-model.d.ts","sourceRoot":"","sources":["../../src/business/document-editor-model.ts"],"names":[],"mappings":"AAMA,OAAO,EAA2B,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAA;AAGrE,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACzF,OAAO,KAAK,EACR,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,yBAAyB,EACzB,qBAAqB,EACrB,gBAAgB,EACnB,MAAM,UAAU,CAAA;AAEjB,eAAO,MAAM,gBAAgB,iBAAiB,CAAA;AAK9C,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAErE,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,GAAG,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAI7G;AAED,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE,aAAa,CAAC,GAAG,iBAAiB,GAAG,SAAS,CAK1I;AAeD
|
|
1
|
+
{"version":3,"file":"document-editor-model.d.ts","sourceRoot":"","sources":["../../src/business/document-editor-model.ts"],"names":[],"mappings":"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"}
|
|
@@ -37,7 +37,9 @@ function declaredDefault(f) {
|
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
39
|
* Divulgación progresiva: ¿el campo va plegado en «Opciones fiscales»?
|
|
40
|
-
* - campos de extensión (`fiscal_data.*`) que aportan otros addons
|
|
40
|
+
* - campos de extensión (`fiscal_data.*`) que aportan otros addons (los que
|
|
41
|
+
* el propio tipo declara obligatorios, p. ej. método y forma de pago de la
|
|
42
|
+
* factura, se marcan esenciales en splitEditorFields);
|
|
41
43
|
* - `section: "fiscal" | "advanced"`;
|
|
42
44
|
* - catálogos opcionales que ya traen un default (método, serie, relación…):
|
|
43
45
|
* el usuario no necesita tocarlos para guardar.
|
|
@@ -55,7 +57,10 @@ export function isAdvancedField(f, essentialKeys = new Set()) {
|
|
|
55
57
|
}
|
|
56
58
|
/** Reparte los campos del tipo (más los de extensión) en grupos de pantalla. */
|
|
57
59
|
export function splitEditorFields(fields, opts = {}) {
|
|
58
|
-
|
|
60
|
+
// Lo obligatorio que el tipo declara siempre está a la vista, aunque sea de
|
|
61
|
+
// extensión (`fiscal_data.metodo_pago`): es lo que el usuario debe decidir.
|
|
62
|
+
// Las extensiones que llegan del metadata (no declaradas) siguen plegadas.
|
|
63
|
+
const essentialKeys = new Set([...(opts.essentialKeys ?? []), ...fields.filter((f) => f.required).map((f) => f.key)]);
|
|
59
64
|
const out = { essential: [], advanced: [], notes: [] };
|
|
60
65
|
const seen = new Set();
|
|
61
66
|
for (const f of [...fields, ...(opts.extensionFields ?? [])]) {
|
|
@@ -168,13 +173,18 @@ export function linesFromSource(rows, map = {}, opts = {}) {
|
|
|
168
173
|
if (!hasValue(rate)) {
|
|
169
174
|
const sub = toAmount(get('subtotal'));
|
|
170
175
|
const tax = toAmount(get('tax_amount'));
|
|
171
|
-
|
|
176
|
+
// Un origen sin dato de impuesto (p. ej. una OT de taller: solo
|
|
177
|
+
// cantidad y precio) toma la tasa de la org, como un renglón nuevo.
|
|
178
|
+
rate = hasValue(get('tax_amount'))
|
|
179
|
+
? sub > 0 ? Math.round((tax / sub) * 10000) / 10000 : 0
|
|
180
|
+
: opts.defaultTaxRate ?? 0;
|
|
172
181
|
}
|
|
173
182
|
const r2 = toAmount(rate);
|
|
183
|
+
const product = get('product_id');
|
|
174
184
|
const line = makeLine({
|
|
175
|
-
product_id:
|
|
185
|
+
product_id: refValue(product),
|
|
176
186
|
sku: get('sku') ?? undefined,
|
|
177
|
-
description: String(get('description') ?? get('product_name') ?? ''),
|
|
187
|
+
description: String(get('description') ?? get('product_name') ?? refLabel(product) ?? refLabel(r.product) ?? ''),
|
|
178
188
|
quantity: qty,
|
|
179
189
|
unit_price: toAmount(get('unit_price')),
|
|
180
190
|
discount: toAmount(get('discount') ?? 0),
|
|
@@ -195,10 +205,38 @@ export function linesFromSource(rows, map = {}, opts = {}) {
|
|
|
195
205
|
return line;
|
|
196
206
|
});
|
|
197
207
|
}
|
|
208
|
+
/** Id de una celda de relación (`{value,label}`, `{id,name}` o el id plano). */
|
|
209
|
+
function refValue(v) {
|
|
210
|
+
if (v == null || v === '')
|
|
211
|
+
return undefined;
|
|
212
|
+
if (typeof v === 'object') {
|
|
213
|
+
const o = v;
|
|
214
|
+
const id = o.value ?? o.id;
|
|
215
|
+
return id == null || id === '' ? undefined : String(id);
|
|
216
|
+
}
|
|
217
|
+
return String(v);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Nombre de una celda de relación ya resuelta por el host (`{label}`/`{name}`).
|
|
221
|
+
* Un renglón de origen sin descripción propia (InvoiceItem solo lleva el
|
|
222
|
+
* producto) se nombra con su producto en vez de entrar en blanco.
|
|
223
|
+
*/
|
|
224
|
+
function refLabel(v) {
|
|
225
|
+
if (!v || typeof v !== 'object')
|
|
226
|
+
return undefined;
|
|
227
|
+
const o = v;
|
|
228
|
+
const l = o.label ?? o.name;
|
|
229
|
+
return typeof l === 'string' && l.trim() ? l : undefined;
|
|
230
|
+
}
|
|
198
231
|
function isFullyConsumed(raw) {
|
|
199
232
|
const r = (raw ?? {});
|
|
200
233
|
return hasValue(r.remaining_quantity) && toAmount(r.remaining_quantity) <= 0;
|
|
201
234
|
}
|
|
235
|
+
/** El editor ocupa toda la pantalla: documentos comerciales con renglones (factura, cotización, pedido, OC). */
|
|
236
|
+
export function isFullscreenEditor(type, forms) {
|
|
237
|
+
const kind = editorLinesConfig(type, forms)?.kind ?? 'sale';
|
|
238
|
+
return !!type.lines && (kind === 'sale' || kind === 'purchase');
|
|
239
|
+
}
|
|
202
240
|
/** Cuántos renglones del origen se cargaron y cuántos se omitieron por estar ya cubiertos. */
|
|
203
241
|
export function sourceLoadSummary(rows) {
|
|
204
242
|
if (!Array.isArray(rows))
|
|
@@ -210,6 +248,62 @@ export function sourceLoadSummary(rows) {
|
|
|
210
248
|
export function sourceTracksRemaining(src) {
|
|
211
249
|
return !!(src.line_link_field || src.remaining_qty_field || src.remaining_endpoint);
|
|
212
250
|
}
|
|
251
|
+
/** Columnas con las que se nombra un documento (folio antes que nombre). */
|
|
252
|
+
const DOCUMENT_LABEL_COLUMNS = ['number', 'folio', 'order_number', 'name', 'title', 'code'];
|
|
253
|
+
function declaredOptionLabel(f) {
|
|
254
|
+
const opts = f?.options;
|
|
255
|
+
const l = opts && !Array.isArray(opts) && typeof opts === 'object' ? opts.label : undefined;
|
|
256
|
+
return typeof l === 'string' && l ? l : undefined;
|
|
257
|
+
}
|
|
258
|
+
/** Nombre visible de un registro: la columna declarada por el campo, luego folio/nombre. */
|
|
259
|
+
export function recordLabel(rec, preferred) {
|
|
260
|
+
if (!rec)
|
|
261
|
+
return undefined;
|
|
262
|
+
for (const c of preferred ? [preferred, ...DOCUMENT_LABEL_COLUMNS] : DOCUMENT_LABEL_COLUMNS) {
|
|
263
|
+
const v = rec[c];
|
|
264
|
+
if ((typeof v === 'string' && v.trim()) || typeof v === 'number')
|
|
265
|
+
return String(v);
|
|
266
|
+
}
|
|
267
|
+
return undefined;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Etiquetas de lo que «Cargar desde…» escribe en la cabecera, para que el
|
|
271
|
+
* selector muestre el nombre y no el UUID sin abrirse:
|
|
272
|
+
* - `header` (`customer_id ← customer_id`): el objeto hermano `{value,label}`
|
|
273
|
+
* que el host sirve junto a la FK (`customer`);
|
|
274
|
+
* - `link_field`: el propio documento origen, con su folio.
|
|
275
|
+
*/
|
|
276
|
+
export function sourceHeaderSeeds(src, rec, id, fields = []) {
|
|
277
|
+
const out = {};
|
|
278
|
+
for (const [to, from] of Object.entries(src.header ?? {})) {
|
|
279
|
+
if (!from.endsWith('_id'))
|
|
280
|
+
continue;
|
|
281
|
+
const v = refValue(rec[from]);
|
|
282
|
+
const label = refLabel(rec[from]) ?? refLabel(rec[from.slice(0, -3)]);
|
|
283
|
+
if (v && label)
|
|
284
|
+
out[to] = { value: v, label };
|
|
285
|
+
}
|
|
286
|
+
if (src.link_field) {
|
|
287
|
+
const label = recordLabel(rec, declaredOptionLabel(fields.find((f) => f.key === src.link_field)));
|
|
288
|
+
if (label)
|
|
289
|
+
out[src.link_field] = { value: id, label };
|
|
290
|
+
}
|
|
291
|
+
return out;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Registro para `renderField` con las etiquetas sembradas como objeto hermano
|
|
295
|
+
* (`customer_id` → `customer: {value,label}`), el mismo contrato que sirve el
|
|
296
|
+
* host en una fila. Conserva el registro desde el que se abrió.
|
|
297
|
+
*/
|
|
298
|
+
export function seedRecord(seeds, record) {
|
|
299
|
+
const keys = Object.keys(seeds).filter((k) => k.endsWith('_id'));
|
|
300
|
+
if (keys.length === 0)
|
|
301
|
+
return record;
|
|
302
|
+
const out = { ...(record ?? {}) };
|
|
303
|
+
for (const k of keys)
|
|
304
|
+
out[k.slice(0, -3)] = seeds[k];
|
|
305
|
+
return out;
|
|
306
|
+
}
|
|
213
307
|
/** Revisión local (instantánea) de los renglones. Sin ruido: solo lo que hay que mirar. */
|
|
214
308
|
export function localIssues(lines, opts = {}) {
|
|
215
309
|
const issues = [];
|
|
@@ -218,8 +312,11 @@ export function localIssues(lines, opts = {}) {
|
|
|
218
312
|
issues.push({ field: 'lines', severity: 'error', message: 'Agrega al menos un renglón.' });
|
|
219
313
|
}
|
|
220
314
|
items.forEach((l, i) => {
|
|
221
|
-
|
|
222
|
-
|
|
315
|
+
// Un renglón con producto se describe con él (el servidor lo nombra
|
|
316
|
+
// desde el catálogo): solo un renglón libre exige texto, como en el
|
|
317
|
+
// editor de renglones (validateLineItems).
|
|
318
|
+
if (!l.description.trim() && !l.product_id)
|
|
319
|
+
issues.push({ field: `lines.${i}`, severity: 'error', message: `Renglón ${i + 1}: elige un producto o escribe la descripción.` });
|
|
223
320
|
if (toAmount(l.unit_price) <= 0)
|
|
224
321
|
issues.push({ field: `lines.${i}`, severity: 'warning', message: `Renglón ${i + 1}: precio en cero.` });
|
|
225
322
|
if (l.max_quantity != null && toAmount(l.quantity) > toAmount(l.max_quantity)) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
import type { CreditStatus, EditorIssue } from './document-editor-model';
|
|
3
3
|
import type { Formatter } from './format';
|
|
4
|
+
import { type LineItem } from './line-items';
|
|
4
5
|
/** Bloque con título discreto y espaciado generoso (sin bordes pesados). */
|
|
5
6
|
export declare function EditorSection({ title, hint, children, slot }: {
|
|
6
7
|
title?: ReactNode;
|
|
@@ -61,4 +62,21 @@ export interface PreviewContent {
|
|
|
61
62
|
export declare function PreviewPanel({ preview }: {
|
|
62
63
|
preview: PreviewContent | null;
|
|
63
64
|
}): import("react").JSX.Element | null;
|
|
65
|
+
export interface DraftPreviewProps {
|
|
66
|
+
title: string;
|
|
67
|
+
party?: string;
|
|
68
|
+
/** Datos del encabezado ya con su etiqueta y valor legibles. */
|
|
69
|
+
header: Array<{
|
|
70
|
+
label: string;
|
|
71
|
+
value: string;
|
|
72
|
+
}>;
|
|
73
|
+
lines: LineItem[];
|
|
74
|
+
totals: TotalsRow[];
|
|
75
|
+
fmt: Formatter;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Vista previa local del documento (sin servidor ni borrador): cómo queda con
|
|
79
|
+
* lo capturado. Para tipos sin acción `preview`; la del servidor (PDF/XML) gana.
|
|
80
|
+
*/
|
|
81
|
+
export declare function DraftPreview({ title, party, header, lines, totals, fmt }: DraftPreviewProps): import("react").JSX.Element;
|
|
64
82
|
//# sourceMappingURL=document-editor-panels.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-editor-panels.d.ts","sourceRoot":"","sources":["../../src/business/document-editor-panels.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAGvD,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"document-editor-panels.d.ts","sourceRoot":"","sources":["../../src/business/document-editor-panels.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAGvD,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACzC,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAA;AAEzD,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,SAAS,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,+BAYzI;AAED,MAAM,WAAW,uBAAuB;IACpC,KAAK,EAAE,SAAS,CAAA;IAChB,qEAAqE;IACrE,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,QAAQ,EAAE,SAAS,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,WAAmB,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,uBAAuB,+BA4BtI;AAED,MAAM,WAAW,cAAc;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC1D,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;IAC5B,GAAG,EAAE,SAAS,CAAA;IACd,QAAQ,CAAC,EAAE,SAAS,CAAA;CACvB;AAED,uFAAuF;AACvF,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,cAAc,+BA4B9E;AAED,MAAM,WAAW,SAAS;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,SAAS,EAAE,CAAA;CAAE,+BAW1D;AAED,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,EAAE,MAAM,EAAE,KAAiC,EAAE,EAAE;IAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,sCAe3H;AAED,MAAM,WAAW,cAAc;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;CAAE,sCAO3E;AAED,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,gEAAgE;IAChE,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC/C,KAAK,EAAE,QAAQ,EAAE,CAAA;IACjB,MAAM,EAAE,SAAS,EAAE,CAAA;IACnB,GAAG,EAAE,SAAS,CAAA;CACjB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,iBAAiB,+BAgC3F"}
|
|
@@ -6,6 +6,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
6
6
|
import { useId, useState } from 'react';
|
|
7
7
|
import { Badge } from '@asteby/metacore-ui/primitives';
|
|
8
8
|
import { AlertTriangle, ChevronDown, XCircle } from 'lucide-react';
|
|
9
|
+
import { computeLine } from './line-items';
|
|
9
10
|
/** Bloque con título discreto y espaciado generoso (sin bordes pesados). */
|
|
10
11
|
export function EditorSection({ title, hint, children, slot }) {
|
|
11
12
|
return (_jsxs("section", { className: "space-y-3", "data-slot": slot, children: [(title || hint) && (_jsxs("header", { className: "flex items-baseline justify-between gap-3", children: [title && _jsx("h3", { className: "text-sm font-semibold", children: title }), hint && _jsx("span", { className: "text-xs text-muted-foreground", children: hint })] })), children] }));
|
|
@@ -56,3 +57,11 @@ export function PreviewPanel({ preview }) {
|
|
|
56
57
|
return _jsx("pre", { className: "max-h-96 overflow-auto rounded bg-muted p-3 text-[11px] leading-tight", "data-slot": "preview-xml", children: preview.xml });
|
|
57
58
|
return null;
|
|
58
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Vista previa local del documento (sin servidor ni borrador): cómo queda con
|
|
62
|
+
* lo capturado. Para tipos sin acción `preview`; la del servidor (PDF/XML) gana.
|
|
63
|
+
*/
|
|
64
|
+
export function DraftPreview({ title, party, header, lines, totals, fmt }) {
|
|
65
|
+
const items = lines.filter((l) => l.kind === 'item');
|
|
66
|
+
return (_jsxs("article", { className: "space-y-3 rounded border bg-background p-4 text-xs", "data-slot": "preview-draft", children: [_jsxs("header", { className: "flex flex-wrap items-baseline justify-between gap-2 border-b pb-2", children: [_jsx("span", { className: "text-sm font-semibold", children: title }), party && _jsx("span", { className: "font-medium", children: party })] }), header.length > 0 && (_jsx("dl", { className: "grid grid-cols-2 gap-x-4 gap-y-1", children: header.map((h) => (_jsxs("div", { className: "min-w-0", children: [_jsx("dt", { className: "text-muted-foreground", children: h.label }), _jsx("dd", { className: "truncate", children: h.value })] }, h.label))) })), _jsx("table", { className: "w-full tabular-nums", children: _jsx("tbody", { children: items.map((l) => (_jsxs("tr", { className: "border-t align-top", children: [_jsx("td", { className: "py-1 pr-2", children: l.description }), _jsx("td", { className: "py-1 pr-2 text-right", children: l.quantity }), _jsx("td", { className: "py-1 text-right", children: fmt.money(computeLine(l).net) })] }, l.key))) }) }), _jsx(TotalsPanel, { rows: totals })] }));
|
|
67
|
+
}
|
|
@@ -22,6 +22,12 @@ export interface DocumentEditorProps {
|
|
|
22
22
|
currency?: string;
|
|
23
23
|
/** Hoy (días de atraso del reparto; inyectable en tests). */
|
|
24
24
|
today?: Date;
|
|
25
|
+
/**
|
|
26
|
+
* Pantalla completa (DocumentFormDialog la pide para documentos con
|
|
27
|
+
* renglones): a dos columnas en pantallas anchas, con totales, revisión y
|
|
28
|
+
* vista previa a la derecha; en una sola columna en móvil.
|
|
29
|
+
*/
|
|
30
|
+
fullscreen?: boolean;
|
|
25
31
|
}
|
|
26
|
-
export declare function DocumentEditor({ model, endpoint, forms, type, record, initialSource, onSaved, onCancel, searchProducts, productModel, defaultTaxRate, currency, today, }: DocumentEditorProps): import("react").JSX.Element;
|
|
32
|
+
export declare function DocumentEditor({ model, endpoint, forms, type, record, initialSource, onSaved, onCancel, searchProducts, productModel, defaultTaxRate, currency, today, fullscreen, }: DocumentEditorProps): import("react").JSX.Element;
|
|
27
33
|
//# sourceMappingURL=document-editor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-editor.d.ts","sourceRoot":"","sources":["../../src/business/document-editor.tsx"],"names":[],"mappings":"AA4BA,OAAO,EAAqB,KAAK,sBAAsB,EAAwB,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"document-editor.d.ts","sourceRoot":"","sources":["../../src/business/document-editor.tsx"],"names":[],"mappings":"AA4BA,OAAO,EAAqB,KAAK,sBAAsB,EAAwB,MAAM,qBAAqB,CAAA;AAgD1G,OAAO,KAAK,EAAsC,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AAE3G,MAAM,WAAW,mBAAmB;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,qBAAqB,CAAA;IAC5B,IAAI,EAAE,gBAAgB,CAAA;IACtB,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC5B,oEAAoE;IACpE,aAAa,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3C,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACpC,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,cAAc,CAAC,EAAE,sBAAsB,CAAC,QAAQ,CAAC,CAAA;IACjD,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,IAAI,CAAA;IACZ;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACvB;AAID,wBAAgB,cAAc,CAAC,EAC3B,KAAK,EACL,QAAQ,EACR,KAAK,EACL,IAAI,EACJ,MAAM,EACN,aAAa,EACb,OAAO,EACP,QAAQ,EACR,cAAc,EACd,YAAY,EACZ,cAAc,EACd,QAAQ,EACR,KAAK,EACL,UAAkB,GACrB,EAAE,mBAAmB,+BA+tBrB"}
|