@sincpro/web-ui 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +157 -2
- package/dist/components/assist/AssistMark.d.ts +64 -0
- package/dist/components/assist/AssistMark.js +108 -0
- package/dist/components/assist/AssistPending.d.ts +24 -0
- package/dist/components/assist/AssistPending.js +26 -0
- package/dist/components/assist/AssistSuggestion.d.ts +42 -0
- package/dist/components/assist/AssistSuggestion.js +55 -0
- package/dist/components/assist/ChangeReview.d.ts +56 -0
- package/dist/components/assist/ChangeReview.js +121 -0
- package/dist/components/assist/assist.d.ts +77 -0
- package/dist/components/assist/assist.js +87 -0
- package/dist/components/assist/index.d.ts +5 -0
- package/dist/components/assist/index.js +7 -0
- package/dist/components/chatter/Chatter.d.ts +161 -0
- package/dist/components/chatter/Chatter.js +232 -0
- package/dist/components/chatter/Messages.d.ts +66 -0
- package/dist/components/chatter/Messages.js +43 -0
- package/dist/components/chatter/Timeline.d.ts +21 -0
- package/dist/components/chatter/Timeline.js +30 -0
- package/dist/components/chatter/index.d.ts +3 -0
- package/dist/components/chatter/index.js +4 -0
- package/dist/components/form/Form.d.ts +52 -0
- package/dist/components/form/Form.js +49 -0
- package/dist/components/form/Sheet.d.ts +43 -0
- package/dist/components/form/Sheet.js +83 -0
- package/dist/components/form/index.d.ts +2 -0
- package/dist/components/form/index.js +4 -0
- package/dist/components/frame/Chart.d.ts +13 -0
- package/dist/components/frame/Chart.js +24 -0
- package/dist/components/frame/FrameView.d.ts +33 -0
- package/dist/components/frame/FrameView.js +125 -0
- package/dist/components/frame/index.d.ts +3 -0
- package/dist/components/frame/index.js +3 -0
- package/dist/components/frame/model.d.ts +43 -0
- package/dist/components/frame/model.js +101 -0
- package/dist/components/index.d.ts +10 -0
- package/dist/components/index.js +11 -0
- package/dist/components/lines/LineItems.d.ts +74 -0
- package/dist/components/lines/LineItems.js +229 -0
- package/dist/components/lines/index.d.ts +1 -0
- package/dist/components/lines/index.js +2 -0
- package/dist/components/lines/lines.d.ts +23 -0
- package/dist/components/lines/lines.js +26 -0
- package/dist/components/listing/ColumnsMenu.d.ts +20 -0
- package/dist/components/listing/ColumnsMenu.js +46 -0
- package/dist/components/listing/GroupingLevels.d.ts +35 -0
- package/dist/components/listing/GroupingLevels.js +45 -0
- package/dist/components/listing/Listing.d.ts +27 -0
- package/dist/components/listing/Listing.js +86 -0
- package/dist/components/listing/ListingBar.d.ts +73 -0
- package/dist/components/listing/ListingBar.js +105 -0
- package/dist/components/listing/Pagination.d.ts +36 -0
- package/dist/components/listing/Pagination.js +69 -0
- package/dist/components/listing/RecordCard.d.ts +33 -0
- package/dist/components/listing/RecordCard.js +22 -0
- package/dist/components/listing/RecordLink.d.ts +7 -0
- package/dist/components/listing/RecordLink.js +22 -0
- package/dist/components/listing/Row.d.ts +106 -0
- package/dist/components/listing/Row.js +122 -0
- package/dist/components/listing/SortMenu.d.ts +62 -0
- package/dist/components/listing/SortMenu.js +105 -0
- package/dist/components/listing/ViewSwitcher.d.ts +24 -0
- package/dist/components/listing/ViewSwitcher.js +16 -0
- package/dist/components/listing/columns.d.ts +47 -0
- package/dist/components/listing/columns.js +72 -0
- package/dist/components/listing/grouping.d.ts +35 -0
- package/dist/components/listing/grouping.js +47 -0
- package/dist/components/listing/index.d.ts +17 -0
- package/dist/components/listing/index.js +20 -0
- package/dist/components/listing/modelColumns.d.ts +50 -0
- package/dist/components/listing/modelColumns.js +103 -0
- package/dist/components/listing/pages.d.ts +78 -0
- package/dist/components/listing/pages.js +135 -0
- package/dist/components/listing/selection.d.ts +21 -0
- package/dist/components/listing/selection.js +43 -0
- package/dist/components/listing/set.d.ts +48 -0
- package/dist/components/listing/set.js +24 -0
- package/dist/components/listing/tree.d.ts +28 -0
- package/dist/components/listing/tree.js +23 -0
- package/dist/components/navigation/CommandPalette.d.ts +40 -0
- package/dist/components/navigation/CommandPalette.js +114 -0
- package/dist/components/navigation/NavigationTree.d.ts +31 -0
- package/dist/components/navigation/NavigationTree.js +79 -0
- package/dist/components/navigation/commands.d.ts +30 -0
- package/dist/components/navigation/commands.js +30 -0
- package/dist/components/navigation/index.d.ts +3 -0
- package/dist/components/navigation/index.js +4 -0
- package/dist/components/record/Breadcrumb.d.ts +42 -0
- package/dist/components/record/Breadcrumb.js +98 -0
- package/dist/components/record/DirtyActions.d.ts +26 -0
- package/dist/components/record/DirtyActions.js +22 -0
- package/dist/components/record/Pager.d.ts +18 -0
- package/dist/components/record/Pager.js +33 -0
- package/dist/components/record/RecordHeader.d.ts +71 -0
- package/dist/components/record/RecordHeader.js +72 -0
- package/dist/components/record/RecordSkeleton.d.ts +3 -0
- package/dist/components/record/RecordSkeleton.js +21 -0
- package/dist/components/record/SmartButtons.d.ts +35 -0
- package/dist/components/record/SmartButtons.js +38 -0
- package/dist/components/record/StatusBar.d.ts +51 -0
- package/dist/components/record/StatusBar.js +168 -0
- package/dist/components/record/ThumbBar.d.ts +36 -0
- package/dist/components/record/ThumbBar.js +86 -0
- package/dist/components/record/index.d.ts +6 -0
- package/dist/components/record/index.js +8 -0
- package/dist/components/search/CriteriaBuilder.d.ts +58 -0
- package/dist/components/search/CriteriaBuilder.js +278 -0
- package/dist/components/search/CriteriaChips.d.ts +22 -0
- package/dist/components/search/CriteriaChips.js +64 -0
- package/dist/components/search/FilterBuilder.d.ts +142 -0
- package/dist/components/search/FilterBuilder.js +421 -0
- package/dist/components/search/JoinWord.d.ts +8 -0
- package/dist/components/search/JoinWord.js +47 -0
- package/dist/components/search/JsonEditor.d.ts +19 -0
- package/dist/components/search/JsonEditor.js +78 -0
- package/dist/components/search/SearchBar.d.ts +78 -0
- package/dist/components/search/SearchBar.js +387 -0
- package/dist/components/search/criteria.d.ts +116 -0
- package/dist/components/search/criteria.js +159 -0
- package/dist/components/search/datePeriods.d.ts +122 -0
- package/dist/components/search/datePeriods.js +134 -0
- package/dist/components/search/dateRanges.d.ts +54 -0
- package/dist/components/search/dateRanges.js +89 -0
- package/dist/components/search/index.d.ts +9 -0
- package/dist/components/search/index.js +20 -0
- package/dist/components/search/model.d.ts +54 -0
- package/dist/components/search/model.js +37 -0
- package/dist/components/search/query.d.ts +166 -0
- package/dist/components/search/query.js +436 -0
- package/dist/components/shell/AppFrame.d.ts +14 -0
- package/dist/components/shell/AppFrame.js +80 -0
- package/dist/components/shell/TopBar.d.ts +73 -0
- package/dist/components/shell/TopBar.js +54 -0
- package/dist/components/shell/headerSlot.d.ts +17 -0
- package/dist/components/shell/headerSlot.js +21 -0
- package/dist/components/shell/index.d.ts +2 -0
- package/dist/components/shell/index.js +3 -0
- package/dist/foundations/aria.d.ts +14 -0
- package/dist/foundations/aria.js +18 -0
- package/dist/foundations/calendar.d.ts +28 -0
- package/dist/foundations/calendar.js +183 -0
- package/dist/foundations/copy.d.ts +619 -0
- package/dist/foundations/copy.es.d.ts +2 -0
- package/dist/foundations/copy.es.js +377 -0
- package/dist/foundations/copy.js +472 -0
- package/dist/foundations/density.d.ts +16 -0
- package/dist/foundations/density.js +21 -0
- package/dist/foundations/grouping.d.ts +281 -0
- package/dist/foundations/grouping.js +0 -0
- package/dist/foundations/index.d.ts +14 -0
- package/dist/foundations/index.js +30 -0
- package/dist/foundations/layout.d.ts +9 -0
- package/dist/foundations/layout.js +9 -0
- package/dist/foundations/pivot.d.ts +222 -0
- package/dist/foundations/pivot.js +198 -0
- package/dist/foundations/pivotSheet.d.ts +61 -0
- package/dist/foundations/pivotSheet.js +0 -0
- package/dist/foundations/slots.d.ts +67 -0
- package/dist/foundations/slots.js +63 -0
- package/dist/foundations/sticky.d.ts +53 -0
- package/dist/foundations/sticky.js +150 -0
- package/dist/foundations/surface.d.ts +9 -0
- package/dist/foundations/surface.js +26 -0
- package/dist/foundations/theme.d.ts +42 -0
- package/dist/foundations/theme.js +88 -0
- package/dist/foundations/types.d.ts +23 -0
- package/dist/foundations/types.js +50 -0
- package/dist/foundations/variants.d.ts +19 -0
- package/dist/foundations/variants.js +48 -0
- package/dist/foundations/xlsx.d.ts +86 -0
- package/dist/foundations/xlsx.js +0 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +19 -0
- package/dist/primitives/block/Block.d.ts +66 -0
- package/dist/primitives/block/Block.js +34 -0
- package/dist/primitives/block/Line.d.ts +18 -0
- package/dist/primitives/block/Line.js +45 -0
- package/dist/primitives/block/SectionGrid.d.ts +30 -0
- package/dist/primitives/block/SectionGrid.js +29 -0
- package/dist/primitives/block/Steps.d.ts +76 -0
- package/dist/primitives/block/Steps.js +43 -0
- package/dist/primitives/block/index.d.ts +4 -0
- package/dist/primitives/block/index.js +7 -0
- package/dist/primitives/button/Button.d.ts +137 -0
- package/dist/primitives/button/Button.js +234 -0
- package/dist/primitives/button/index.d.ts +1 -0
- package/dist/primitives/button/index.js +2 -0
- package/dist/primitives/cell/CellStack.d.ts +47 -0
- package/dist/primitives/cell/CellStack.js +33 -0
- package/dist/primitives/cell/index.d.ts +1 -0
- package/dist/primitives/cell/index.js +3 -0
- package/dist/primitives/choice/ComboBox.d.ts +16 -0
- package/dist/primitives/choice/ComboBox.js +52 -0
- package/dist/primitives/choice/RadioGroup.d.ts +18 -0
- package/dist/primitives/choice/RadioGroup.js +50 -0
- package/dist/primitives/choice/SearchField.d.ts +24 -0
- package/dist/primitives/choice/SearchField.js +27 -0
- package/dist/primitives/choice/SegmentedControl.d.ts +16 -0
- package/dist/primitives/choice/SegmentedControl.js +69 -0
- package/dist/primitives/choice/Slider.d.ts +16 -0
- package/dist/primitives/choice/Slider.js +46 -0
- package/dist/primitives/choice/Switch.d.ts +14 -0
- package/dist/primitives/choice/Switch.js +65 -0
- package/dist/primitives/choice/ThemeSwitcher.d.ts +10 -0
- package/dist/primitives/choice/ThemeSwitcher.js +25 -0
- package/dist/primitives/choice/index.d.ts +8 -0
- package/dist/primitives/choice/index.js +11 -0
- package/dist/primitives/choice/options.d.ts +28 -0
- package/dist/primitives/choice/options.js +6 -0
- package/dist/primitives/date/Calendar.d.ts +31 -0
- package/dist/primitives/date/Calendar.js +110 -0
- package/dist/primitives/date/DatePicker.d.ts +34 -0
- package/dist/primitives/date/DatePicker.js +99 -0
- package/dist/primitives/date/index.d.ts +2 -0
- package/dist/primitives/date/index.js +4 -0
- package/dist/primitives/dialog/Dialog.d.ts +118 -0
- package/dist/primitives/dialog/Dialog.js +121 -0
- package/dist/primitives/dialog/index.d.ts +1 -0
- package/dist/primitives/dialog/index.js +2 -0
- package/dist/primitives/disclosure/Disclosure.d.ts +36 -0
- package/dist/primitives/disclosure/Disclosure.js +52 -0
- package/dist/primitives/disclosure/index.d.ts +1 -0
- package/dist/primitives/disclosure/index.js +2 -0
- package/dist/primitives/field/Checks.d.ts +57 -0
- package/dist/primitives/field/Checks.js +72 -0
- package/dist/primitives/field/DropZone.d.ts +42 -0
- package/dist/primitives/field/DropZone.js +52 -0
- package/dist/primitives/field/Field.d.ts +166 -0
- package/dist/primitives/field/Field.js +240 -0
- package/dist/primitives/field/Suggest.d.ts +48 -0
- package/dist/primitives/field/Suggest.js +43 -0
- package/dist/primitives/field/aria.d.ts +61 -0
- package/dist/primitives/field/aria.js +70 -0
- package/dist/primitives/field/context.d.ts +30 -0
- package/dist/primitives/field/context.js +13 -0
- package/dist/primitives/field/index.d.ts +7 -0
- package/dist/primitives/field/index.js +11 -0
- package/dist/primitives/field/layout.d.ts +24 -0
- package/dist/primitives/field/layout.js +10 -0
- package/dist/primitives/field/mode.d.ts +9 -0
- package/dist/primitives/field/mode.js +13 -0
- package/dist/primitives/hint/Hint.d.ts +31 -0
- package/dist/primitives/hint/Hint.js +42 -0
- package/dist/primitives/hint/index.d.ts +1 -0
- package/dist/primitives/hint/index.js +1 -0
- package/dist/primitives/index.d.ts +19 -0
- package/dist/primitives/index.js +20 -0
- package/dist/primitives/menu/Menu.d.ts +100 -0
- package/dist/primitives/menu/Menu.js +59 -0
- package/dist/primitives/menu/index.d.ts +1 -0
- package/dist/primitives/menu/index.js +2 -0
- package/dist/primitives/notice/Callout.d.ts +49 -0
- package/dist/primitives/notice/Callout.js +28 -0
- package/dist/primitives/notice/Notice.d.ts +45 -0
- package/dist/primitives/notice/Notice.js +61 -0
- package/dist/primitives/notice/Toast.d.ts +55 -0
- package/dist/primitives/notice/Toast.js +142 -0
- package/dist/primitives/notice/index.d.ts +3 -0
- package/dist/primitives/notice/index.js +5 -0
- package/dist/primitives/overlay/Popover.d.ts +6 -0
- package/dist/primitives/overlay/Popover.js +27 -0
- package/dist/primitives/overlay/PopoverTrigger.d.ts +55 -0
- package/dist/primitives/overlay/PopoverTrigger.js +38 -0
- package/dist/primitives/overlay/Tooltip.d.ts +38 -0
- package/dist/primitives/overlay/Tooltip.js +74 -0
- package/dist/primitives/overlay/index.d.ts +3 -0
- package/dist/primitives/overlay/index.js +5 -0
- package/dist/primitives/picker/Picker.d.ts +48 -0
- package/dist/primitives/picker/Picker.js +150 -0
- package/dist/primitives/picker/index.d.ts +1 -0
- package/dist/primitives/picker/index.js +2 -0
- package/dist/primitives/surface/Peek.d.ts +60 -0
- package/dist/primitives/surface/Peek.js +71 -0
- package/dist/primitives/surface/index.d.ts +1 -0
- package/dist/primitives/surface/index.js +2 -0
- package/dist/primitives/table/CellEditor.d.ts +14 -0
- package/dist/primitives/table/CellEditor.js +83 -0
- package/dist/primitives/table/DataTable.d.ts +135 -0
- package/dist/primitives/table/DataTable.js +244 -0
- package/dist/primitives/table/EditableTable.d.ts +96 -0
- package/dist/primitives/table/EditableTable.js +423 -0
- package/dist/primitives/table/PivotTable.d.ts +14 -0
- package/dist/primitives/table/PivotTable.js +0 -0
- package/dist/primitives/table/ReportTable.d.ts +38 -0
- package/dist/primitives/table/ReportTable.js +106 -0
- package/dist/primitives/table/RowActions.d.ts +16 -0
- package/dist/primitives/table/RowActions.js +28 -0
- package/dist/primitives/table/SheetTable.d.ts +70 -0
- package/dist/primitives/table/SheetTable.js +197 -0
- package/dist/primitives/table/Table.d.ts +106 -0
- package/dist/primitives/table/Table.js +116 -0
- package/dist/primitives/table/index.d.ts +7 -0
- package/dist/primitives/table/index.js +9 -0
- package/dist/primitives/tabs/Tabs.d.ts +91 -0
- package/dist/primitives/tabs/Tabs.js +56 -0
- package/dist/primitives/tabs/index.d.ts +1 -0
- package/dist/primitives/tabs/index.js +1 -0
- package/dist/primitives/tag/Tag.d.ts +36 -0
- package/dist/primitives/tag/Tag.js +68 -0
- package/dist/primitives/tag/Tags.d.ts +57 -0
- package/dist/primitives/tag/Tags.js +104 -0
- package/dist/primitives/tag/TagsField.d.ts +32 -0
- package/dist/primitives/tag/TagsField.js +182 -0
- package/dist/primitives/tag/choices.d.ts +38 -0
- package/dist/primitives/tag/choices.js +26 -0
- package/dist/primitives/tag/index.d.ts +4 -0
- package/dist/primitives/tag/index.js +8 -0
- package/dist/primitives/toolbar/Toolbar.d.ts +13 -0
- package/dist/primitives/toolbar/Toolbar.js +36 -0
- package/dist/primitives/toolbar/index.d.ts +1 -0
- package/dist/primitives/toolbar/index.js +2 -0
- package/dist/primitives/value/Copyable.d.ts +37 -0
- package/dist/primitives/value/Copyable.js +50 -0
- package/dist/primitives/value/Fecha.d.ts +12 -0
- package/dist/primitives/value/Fecha.js +80 -0
- package/dist/primitives/value/Meter.d.ts +29 -0
- package/dist/primitives/value/Meter.js +46 -0
- package/dist/primitives/value/Metric.d.ts +42 -0
- package/dist/primitives/value/Metric.js +38 -0
- package/dist/primitives/value/Person.d.ts +90 -0
- package/dist/primitives/value/Person.js +208 -0
- package/dist/primitives/value/Relation.d.ts +69 -0
- package/dist/primitives/value/Relation.js +57 -0
- package/dist/primitives/value/Totals.d.ts +26 -0
- package/dist/primitives/value/Totals.js +4 -0
- package/dist/primitives/value/Value.d.ts +77 -0
- package/dist/primitives/value/Value.js +119 -0
- package/dist/primitives/value/index.d.ts +8 -0
- package/dist/primitives/value/index.js +9 -0
- package/dist/tokens.css +1025 -0
- package/dist/views/index.d.ts +2 -0
- package/dist/views/index.js +3 -0
- package/dist/views/list/List.d.ts +113 -0
- package/dist/views/list/List.js +97 -0
- package/dist/views/list/ListView.d.ts +6 -0
- package/dist/views/list/ListView.js +269 -0
- package/dist/views/list/columns.d.ts +18 -0
- package/dist/views/list/columns.js +27 -0
- package/dist/views/list/derive.d.ts +76 -0
- package/dist/views/list/derive.js +181 -0
- package/dist/views/list/index.d.ts +2 -0
- package/dist/views/list/index.js +4 -0
- package/dist/views/list/presentations.d.ts +39 -0
- package/dist/views/list/presentations.js +103 -0
- package/dist/views/list/types.d.ts +272 -0
- package/dist/views/list/types.js +1 -0
- package/dist/views/list/useNarrowList.d.ts +17 -0
- package/dist/views/list/useNarrowList.js +32 -0
- package/dist/views/record/Record.d.ts +126 -0
- package/dist/views/record/Record.js +141 -0
- package/dist/views/record/index.d.ts +1 -0
- package/dist/views/record/index.js +2 -0
- package/package.json +109 -4
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { ListIdentity } from "../../components/listing/ListingBar.js";
|
|
2
|
+
import type { SortField } from "../../components/listing/SortMenu.js";
|
|
3
|
+
import type { Surface } from "../../foundations/types.js";
|
|
4
|
+
import type { DataColumn } from "../../primitives/table/DataTable.js";
|
|
5
|
+
import type { RowAction } from "../../primitives/table/RowActions.js";
|
|
6
|
+
import type { SortState } from "../../primitives/table/Table.js";
|
|
7
|
+
import { type ListCrumb, type ListEmpty, type ListGroup, type ListPivot, type ListPresent, type ListReport, type ListSheet, type RowOf } from "./types.js";
|
|
8
|
+
import type { ReactNode } from "react";
|
|
9
|
+
type BarProps = {
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
};
|
|
12
|
+
type CrumbsProps = {
|
|
13
|
+
crumbs: readonly ListCrumb[];
|
|
14
|
+
};
|
|
15
|
+
type NodeProps = {
|
|
16
|
+
children?: ReactNode;
|
|
17
|
+
};
|
|
18
|
+
type RowsProps<T> = {
|
|
19
|
+
row: (item: T) => RowOf;
|
|
20
|
+
/**
|
|
21
|
+
* Los rótulos de las zonas de una fila, arriba de todas. Sin esto no hay
|
|
22
|
+
* encabezado: una lista de cinco archivos con el nombre y nada más no lo
|
|
23
|
+
* necesita.
|
|
24
|
+
*
|
|
25
|
+
* No son columnas. Una fila tiene un nombre, UNA cadena de `meta` ya formateada
|
|
26
|
+
* y una columna de fichas: eso es lo que se rotula.
|
|
27
|
+
*/
|
|
28
|
+
header?: {
|
|
29
|
+
name: string;
|
|
30
|
+
meta?: string;
|
|
31
|
+
tags?: string;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
type TableProps<T extends object> = {
|
|
35
|
+
columns: readonly DataColumn<T>[];
|
|
36
|
+
/** Cuáles están en pantalla. Las obligatorias se quedan aunque se omitan. */
|
|
37
|
+
visibleColumnIds?: readonly string[];
|
|
38
|
+
onVisibleColumnIdsChange?: (ids: readonly string[]) => void;
|
|
39
|
+
/** El pie con los agregados de las columnas que declararon uno. */
|
|
40
|
+
totals?: boolean;
|
|
41
|
+
/** Lo que se le hace a UNA fila sin entrar. Se dibujan escondidas y aparecen
|
|
42
|
+
* sobre la fila que se está apuntando. */
|
|
43
|
+
rowActions?: (item: T) => readonly RowAction[];
|
|
44
|
+
};
|
|
45
|
+
/** El tablero. Sin `card`, la tarjeta sale de lo que ya dice `List.Rows`: el
|
|
46
|
+
* nombre, el `meta` y las fichas. Escribirla igual es declarar que ESTA lista
|
|
47
|
+
* se puede ver como tablero. */
|
|
48
|
+
type BoardProps<T> = {
|
|
49
|
+
card?: (item: T) => ReactNode;
|
|
50
|
+
};
|
|
51
|
+
/** La planilla. Sin columnas propias, sale de las que declaró `List.Table` — la
|
|
52
|
+
* de datos CRUDOS sí las trae, porque ahí salen del archivo y el código no sabe
|
|
53
|
+
* cuáles son. */
|
|
54
|
+
type SheetProps<T> = Partial<ListSheet<T>>;
|
|
55
|
+
export type ListProps<T extends object> = {
|
|
56
|
+
items: readonly T[];
|
|
57
|
+
keyOf: (item: T) => string;
|
|
58
|
+
/** En qué superficie se apoya la BARRA. `canvas` (el default) es una barra
|
|
59
|
+
* de control clara; `chrome` la convierte en una banda oscura, una opción
|
|
60
|
+
* explícita: la barra de la aplicación es la única banda oscura de la
|
|
61
|
+
* pantalla, igual que el riel de un registro. */
|
|
62
|
+
surface?: Surface;
|
|
63
|
+
/** Cómo se parte el conjunto. Es del CONJUNTO y no de una cara: cambiar de
|
|
64
|
+
* presentación no puede perderlo. */
|
|
65
|
+
group?: ListGroup<T>;
|
|
66
|
+
selection?: {
|
|
67
|
+
has: (id: string) => boolean;
|
|
68
|
+
toggle: (id: string) => void;
|
|
69
|
+
count: number;
|
|
70
|
+
clear: () => void;
|
|
71
|
+
actions?: ReactNode;
|
|
72
|
+
};
|
|
73
|
+
/** El orden, que también es del conjunto. */
|
|
74
|
+
sort?: SortState | null;
|
|
75
|
+
onSortChange?: (next: SortState | null) => void;
|
|
76
|
+
/** Por qué campos se puede ordenar en las caras que NO tienen encabezados
|
|
77
|
+
* donde hacer clic. */
|
|
78
|
+
sortable?: readonly SortField<T>[];
|
|
79
|
+
/** Cuál cara se está mirando. Sin esto, la primera que esté escrita. */
|
|
80
|
+
present?: ListPresent;
|
|
81
|
+
onPresentChange?: (next: ListPresent) => void;
|
|
82
|
+
onOpen?: (item: T) => void;
|
|
83
|
+
onPeek?: (item: T) => void;
|
|
84
|
+
isPeeked?: (item: T) => boolean;
|
|
85
|
+
/** Los tres estados, en un solo lugar. */
|
|
86
|
+
state?: {
|
|
87
|
+
loading?: boolean;
|
|
88
|
+
error?: string | null;
|
|
89
|
+
};
|
|
90
|
+
/** Vacía POR UN FILTRO es otra situación: no falta contenido, sobra un
|
|
91
|
+
* recorte. */
|
|
92
|
+
filtered?: boolean;
|
|
93
|
+
empty?: ListEmpty;
|
|
94
|
+
children?: ReactNode;
|
|
95
|
+
};
|
|
96
|
+
export declare function List<T extends object>({ items, keyOf, surface, group, selection, sort, onSortChange, sortable, present, onPresentChange, onOpen, onPeek, isPeeked, state, filtered, empty, children, }: ListProps<T>): import("react").JSX.Element;
|
|
97
|
+
export declare namespace List {
|
|
98
|
+
var Bar: ((props: BarProps) => ReactNode) & import("../../foundations/slots.js").Slotted<"bar">;
|
|
99
|
+
var Crumbs: ((props: CrumbsProps) => ReactNode) & import("../../foundations/slots.js").Slotted<"crumbs">;
|
|
100
|
+
var Identity: ((props: ListIdentity) => ReactNode) & import("../../foundations/slots.js").Slotted<"identity">;
|
|
101
|
+
var Search: ((props: NodeProps) => ReactNode) & import("../../foundations/slots.js").Slotted<"search">;
|
|
102
|
+
var Actions: ((props: NodeProps) => ReactNode) & import("../../foundations/slots.js").Slotted<"actions">;
|
|
103
|
+
var Pagination: ((props: NodeProps) => ReactNode) & import("../../foundations/slots.js").Slotted<"pagination">;
|
|
104
|
+
var Views: ((props: NodeProps) => ReactNode) & import("../../foundations/slots.js").Slotted<"views">;
|
|
105
|
+
var Metrics: ((props: NodeProps) => ReactNode) & import("../../foundations/slots.js").Slotted<"metrics">;
|
|
106
|
+
var Rows: <T>(props: RowsProps<T>) => ReactNode;
|
|
107
|
+
var Table: <T extends object>(props: TableProps<T>) => ReactNode;
|
|
108
|
+
var Board: <T>(props: BoardProps<T>) => ReactNode;
|
|
109
|
+
var Sheet: <T>(props: SheetProps<T>) => ReactNode;
|
|
110
|
+
var Report: ((props: ListReport) => ReactNode) & import("../../foundations/slots.js").Slotted<"report">;
|
|
111
|
+
var Pivot: <T>(props: ListPivot<T>) => ReactNode;
|
|
112
|
+
}
|
|
113
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { flatten, loose, pick, propsOf, slot, slotOf, } from "../../foundations/slots.js";
|
|
3
|
+
import { ListView } from "./ListView.js";
|
|
4
|
+
import {} from "./types.js";
|
|
5
|
+
/** La barra: todo lo que es del CONJUNTO y no de una fila. Sin ella no hay
|
|
6
|
+
* banda — que es lo que quiere una lista metida adentro de un diálogo. */
|
|
7
|
+
const Bar = slot("bar", (_props) => null);
|
|
8
|
+
/** De dónde vengo. Va arriba de la barra, y sólo cuando la barra es cromo. */
|
|
9
|
+
const Crumbs = slot("crumbs", (_props) => null);
|
|
10
|
+
/** Cómo se llama esta lista y cuánto tiene. */
|
|
11
|
+
const Identity = slot("identity", (_props) => null);
|
|
12
|
+
/** El campo de búsqueda, ya armado: lo arma quien tiene las declaraciones del
|
|
13
|
+
* dominio — el sistema no sabe qué es un NIT. */
|
|
14
|
+
const Search = slot("search", (_props) => null);
|
|
15
|
+
/** Lo que EMPIEZA algo nuevo. Sigue visible cuando hay una selección. */
|
|
16
|
+
const Actions = slot("actions", (_props) => null);
|
|
17
|
+
const Pagination = slot("pagination", (_props) => null);
|
|
18
|
+
/** La escotilla del conmutador: un selector propio. Casi nunca hace falta —
|
|
19
|
+
* las caras escritas ya lo dibujan. */
|
|
20
|
+
const Views = slot("views", (_props) => null);
|
|
21
|
+
/** Las medidas que además RECORTAN: «2 por confirmar». Van debajo de la barra y
|
|
22
|
+
* arriba de las filas, porque son del conjunto y no del marco. */
|
|
23
|
+
const Metrics = slot("metrics", (_props) => null);
|
|
24
|
+
const Rows = slot("rows", (_props) => null);
|
|
25
|
+
const TableSlot = slot("table", (_props) => null);
|
|
26
|
+
const Board = slot("board", (_props) => null);
|
|
27
|
+
const SheetSlot = slot("sheet", (_props) => null);
|
|
28
|
+
const Report = slot("report", (_props) => null);
|
|
29
|
+
const Pivot = slot("pivot", (_props) => null);
|
|
30
|
+
/* El orden en que se OFRECEN cuando están escritas de otra manera. El conmutador
|
|
31
|
+
respeta el orden del árbol; esto sólo nombra a qué presentación corresponde
|
|
32
|
+
cada ranura. */
|
|
33
|
+
const PRESENT_OF = {
|
|
34
|
+
rows: "rows",
|
|
35
|
+
table: "table",
|
|
36
|
+
board: "board",
|
|
37
|
+
sheet: "sheet",
|
|
38
|
+
report: "report",
|
|
39
|
+
pivot: "pivot",
|
|
40
|
+
};
|
|
41
|
+
const FACES = ["rows", "table", "board", "sheet", "report", "pivot"];
|
|
42
|
+
export function List({ items, keyOf, surface, group, selection, sort, onSortChange, sortable, present, onPresentChange, onOpen, onPeek, isPeeked, state, filtered, empty, children, }) {
|
|
43
|
+
const top = flatten(children);
|
|
44
|
+
const bar = flatten(propsOf(pick(top, "bar"))?.children);
|
|
45
|
+
const crumbs = propsOf(pick(bar, "crumbs"))?.crumbs;
|
|
46
|
+
const identity = propsOf(pick(bar, "identity"));
|
|
47
|
+
const search = propsOf(pick(bar, "search"))?.children;
|
|
48
|
+
const actions = propsOf(pick(bar, "actions"))?.children;
|
|
49
|
+
const pagination = propsOf(pick(bar, "pagination"))?.children;
|
|
50
|
+
const views = propsOf(pick(bar, "views"))?.children;
|
|
51
|
+
const metrics = propsOf(pick(top, "metrics"))?.children;
|
|
52
|
+
const rows = propsOf(pick(top, "rows"));
|
|
53
|
+
const table = propsOf(pick(top, "table"));
|
|
54
|
+
const board = propsOf(pick(top, "board"));
|
|
55
|
+
const sheet = propsOf(pick(top, "sheet"));
|
|
56
|
+
const report = propsOf(pick(top, "report"));
|
|
57
|
+
const pivot = propsOf(pick(top, "pivot"));
|
|
58
|
+
/* Las caras que hay son las que están escritas, EN ESE ORDEN. El conmutador
|
|
59
|
+
no puede ofrecer una que no se pueda dibujar, porque la que se dibuja y la
|
|
60
|
+
que se ofrece son el mismo nodo. */
|
|
61
|
+
const presents = top
|
|
62
|
+
.map((node) => FACES.find((face) => slotOf(node) === face))
|
|
63
|
+
.filter((face) => face !== undefined)
|
|
64
|
+
.map((face) => PRESENT_OF[face]);
|
|
65
|
+
/* La escotilla: lo que el arquetipo no previó se dibuja igual, debajo. Que
|
|
66
|
+
aparezca algo acá es la señal de que al arquetipo le falta una pieza. */
|
|
67
|
+
const rest = loose(top, ["bar", "metrics", ...FACES]);
|
|
68
|
+
return (_jsx(ListView, { items: items, keyOf: keyOf, row: rows?.row ?? (() => ({ name: "" })), ...(rows?.header === undefined ? {} : { rowHeader: rows.header }), ...(identity === undefined ? {} : { identity }), ...(crumbs === undefined ? {} : { crumbs }), ...(surface === undefined ? {} : { surface }), ...(search === undefined ? {} : { search }), ...(actions === undefined ? {} : { actions }), ...(pagination === undefined ? {} : { pagination }), ...(views === undefined ? {} : { views }), ...(metrics === undefined ? {} : { metrics }), ...(table === undefined
|
|
69
|
+
? {}
|
|
70
|
+
: {
|
|
71
|
+
columns: table.columns,
|
|
72
|
+
...(table.totals === undefined ? {} : { totals: table.totals }),
|
|
73
|
+
...(table.rowActions === undefined ? {} : { rowActions: table.rowActions }),
|
|
74
|
+
...(table.visibleColumnIds === undefined
|
|
75
|
+
? {}
|
|
76
|
+
: { visibleColumnIds: table.visibleColumnIds }),
|
|
77
|
+
...(table.onVisibleColumnIdsChange === undefined
|
|
78
|
+
? {}
|
|
79
|
+
: { onVisibleColumnIdsChange: table.onVisibleColumnIdsChange }),
|
|
80
|
+
}), ...(board?.card === undefined ? {} : { card: board.card }), ...(sheet?.columns === undefined || sheet.cell === undefined
|
|
81
|
+
? {}
|
|
82
|
+
: { sheet: sheet }), ...(report === undefined ? {} : { report }), ...(pivot === undefined ? {} : { pivot }), ...(presents.length === 0 ? {} : { presents }), ...(present === undefined ? {} : { present }), ...(onPresentChange === undefined ? {} : { onPresentChange }), ...(group === undefined ? {} : { group }), ...(selection === undefined ? {} : { selection }), ...(sort === undefined ? {} : { sort }), ...(onSortChange === undefined ? {} : { onSortChange }), ...(sortable === undefined ? {} : { sortable }), ...(onOpen === undefined ? {} : { onOpen }), ...(onPeek === undefined ? {} : { onPeek }), ...(isPeeked === undefined ? {} : { isPeeked }), ...(state === undefined ? {} : { state }), ...(filtered === undefined ? {} : { filtered }), ...(empty === undefined ? {} : { empty }), children: rest.length === 0 ? undefined : rest }));
|
|
83
|
+
}
|
|
84
|
+
List.Bar = Bar;
|
|
85
|
+
List.Crumbs = Crumbs;
|
|
86
|
+
List.Identity = Identity;
|
|
87
|
+
List.Search = Search;
|
|
88
|
+
List.Actions = Actions;
|
|
89
|
+
List.Pagination = Pagination;
|
|
90
|
+
List.Views = Views;
|
|
91
|
+
List.Metrics = Metrics;
|
|
92
|
+
List.Rows = Rows;
|
|
93
|
+
List.Table = TableSlot;
|
|
94
|
+
List.Board = Board;
|
|
95
|
+
List.Sheet = SheetSlot;
|
|
96
|
+
List.Report = Report;
|
|
97
|
+
List.Pivot = Pivot;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ListViewProps } from "./types.js";
|
|
2
|
+
export declare function ListView<T extends object>({ items, keyOf, identity, crumbs, surface, metrics, search, pagination, views, actions, row, rowHeader, columns, visibleColumnIds, onVisibleColumnIdsChange, card, sheet, report, pivot, present: requested, presents, onPresentChange, sort, onSortChange, sortable, totals, rowActions, group, selection, onOpen, onPeek, state, filtered, empty, children, }: ListViewProps<T>): import("react").JSX.Element;
|
|
3
|
+
/** What a list offers when it fails and can be retried. */
|
|
4
|
+
export declare function RetryAction({ onRetry }: {
|
|
5
|
+
onRetry: () => void;
|
|
6
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useColumnControl, visibleColumns } from "../../components/listing/columns.js";
|
|
4
|
+
import { ColumnsMenu, specsFromColumns, } from "../../components/listing/ColumnsMenu.js";
|
|
5
|
+
import { Listing } from "../../components/listing/Listing.js";
|
|
6
|
+
import { ListingBar } from "../../components/listing/ListingBar.js";
|
|
7
|
+
import { RecordCard } from "../../components/listing/RecordCard.js";
|
|
8
|
+
import { GroupHeader, Row, RowHeader } from "../../components/listing/Row.js";
|
|
9
|
+
import { sortItems, SortMenu, } from "../../components/listing/SortMenu.js";
|
|
10
|
+
import { ViewSwitcher } from "../../components/listing/ViewSwitcher.js";
|
|
11
|
+
import { Breadcrumb } from "../../components/record/Breadcrumb.js";
|
|
12
|
+
import { useUiCopy } from "../../foundations/copy.js";
|
|
13
|
+
import { useDensity } from "../../foundations/density.js";
|
|
14
|
+
import { pathKey, pileIsOpen, pilesOf, } from "../../foundations/grouping.js";
|
|
15
|
+
import { pivotFrom, pivotIsEmpty } from "../../foundations/pivot.js";
|
|
16
|
+
import { Button } from "../../primitives/button/Button.js";
|
|
17
|
+
import { Empty, Failed, Skeleton } from "../../primitives/notice/Notice.js";
|
|
18
|
+
import { PivotTable } from "../../primitives/table/PivotTable.js";
|
|
19
|
+
import { ReportTable } from "../../primitives/table/ReportTable.js";
|
|
20
|
+
import { groupedColumnIds } from "./columns.js";
|
|
21
|
+
import { groupLevelsOf, reportRowsOf, sheetFromColumns, sheetRowsOf, } from "./derive.js";
|
|
22
|
+
import { SheetPresentation, TablePresentation, } from "./presentations.js";
|
|
23
|
+
import { useNarrowList } from "./useNarrowList.js";
|
|
24
|
+
import { Grid3x3, LayoutGrid, List, Sheet, Sigma, Table2 } from "lucide-react";
|
|
25
|
+
import { Fragment, useCallback, useMemo } from "react";
|
|
26
|
+
/**
|
|
27
|
+
* EL DIBUJO de una lista. **La puerta es `List`**, que se escribe como árbol y
|
|
28
|
+
* traduce las ranuras a esto — acá todo entra como props porque acá ya se
|
|
29
|
+
* decidió todo: quién compone no elige entre dos maneras de escribir lo mismo,
|
|
30
|
+
* porque esto no se publica.
|
|
31
|
+
*
|
|
32
|
+
* Context: `invoices.view.tsx` has 349 lines and about 120 of them are
|
|
33
|
+
* re-assembling this: the bar, the search field, the grouping and the three
|
|
34
|
+
* states. Ten views with their own copy are 1,200 lines that drift apart one at
|
|
35
|
+
* a time, one per week — and it already happened: Facturas had a text
|
|
36
|
+
* `<input>` while the modal explorer had facets, filters and grouping. The same
|
|
37
|
+
* list, in two places, with two sets of capabilities.
|
|
38
|
+
*
|
|
39
|
+
* **Grouping, sorting and which columns are on screen belong to the SET;
|
|
40
|
+
* rows, table and board are three PRESENTATIONS of the same set.** Until now
|
|
41
|
+
* grouping only existed inside `DataTable`, so switching presentation lost
|
|
42
|
+
* the grouping; the columns submenu existed only on FrameView, and every
|
|
43
|
+
* column could hide. Odoo splits required vs optional — that split lives in
|
|
44
|
+
* `useColumnControl`. Collapse lives in `useTreeControl`.
|
|
45
|
+
*
|
|
46
|
+
* The escape hatch is `children`: whatever the archetype did not foresee gets
|
|
47
|
+
* drawn anyway, and its appearing there is the signal that the archetype is
|
|
48
|
+
* missing something.
|
|
49
|
+
*/
|
|
50
|
+
const PRESENT_ICONS = [
|
|
51
|
+
{ id: "rows", icon: List },
|
|
52
|
+
{ id: "table", icon: Table2 },
|
|
53
|
+
{ id: "board", icon: LayoutGrid },
|
|
54
|
+
{ id: "sheet", icon: Sheet },
|
|
55
|
+
/* La sigma y no un ícono de tabla: lo que distingue a un informe de las otras
|
|
56
|
+
cuatro es que SUMA. */
|
|
57
|
+
{ id: "report", icon: Sigma },
|
|
58
|
+
/* La cuadrícula: dos ejes, y lo que importa está adentro. */
|
|
59
|
+
{ id: "pivot", icon: Grid3x3 },
|
|
60
|
+
];
|
|
61
|
+
export function ListView({ items, keyOf, identity, crumbs, surface, metrics, search, pagination, views, actions, row, rowHeader, columns, visibleColumnIds, onVisibleColumnIdsChange, card, sheet, report, pivot, present: requested = "rows", presents, onPresentChange, sort, onSortChange, sortable, totals = false, rowActions, group, selection, onOpen, onPeek, state, filtered = false, empty, children, }) {
|
|
62
|
+
const { frame, offered, present } = useNarrowList(presents, requested);
|
|
63
|
+
const density = useDensity();
|
|
64
|
+
const copy = useUiCopy();
|
|
65
|
+
const loading = state?.loading === true;
|
|
66
|
+
const error = state?.error ?? null;
|
|
67
|
+
const columnSpecs = useMemo(() => specsFromColumns(columns ?? [], false), [columns]);
|
|
68
|
+
const columnControl = useColumnControl(columnSpecs, {
|
|
69
|
+
...(visibleColumnIds === undefined ? {} : { visibleIds: visibleColumnIds }),
|
|
70
|
+
/* El nombre tiene que ser el que `useColumnControl` lee. Decía
|
|
71
|
+
`onVisibleColumnIdsChange` —el nombre de la prop de ACÁ— y el hook busca
|
|
72
|
+
`onVisibleIdsChange`, así que nunca entraba en modo controlado: la lista
|
|
73
|
+
ignoraba en silencio las columnas que le pasaran. */
|
|
74
|
+
...(onVisibleColumnIdsChange === undefined
|
|
75
|
+
? {}
|
|
76
|
+
: { onVisibleIdsChange: onVisibleColumnIdsChange }),
|
|
77
|
+
});
|
|
78
|
+
/* Agrupar por una columna escondida dejaría montones cuyo criterio no se ve.
|
|
79
|
+
Con N niveles son N columnas, y se reponen todas. Es lo ÚNICO para lo que
|
|
80
|
+
hace falta saber qué columna contesta por un campo: la tabla ya no agrupa
|
|
81
|
+
por columnas, agrupa por niveles. */
|
|
82
|
+
const groupedIds = group === undefined ? [] : groupedColumnIds(group, columns);
|
|
83
|
+
const tableIds = groupedIds.every((id) => columnControl.visibleIds.includes(id))
|
|
84
|
+
? columnControl.visibleIds
|
|
85
|
+
: [
|
|
86
|
+
...columnControl.visibleIds,
|
|
87
|
+
...groupedIds.filter((id) => !columnControl.visibleIds.includes(id)),
|
|
88
|
+
];
|
|
89
|
+
const shownColumns = columns === undefined ? undefined : visibleColumns(columns, tableIds);
|
|
90
|
+
const groupLevels = useMemo(() => groupLevelsOf(group, columns), [group, columns]);
|
|
91
|
+
const switcher = views ??
|
|
92
|
+
(offered.length > 1 ? (_jsx(ViewSwitcher, { options: PRESENT_ICONS.filter((option) => offered.includes(option.id)).map((option) => ({
|
|
93
|
+
id: option.id,
|
|
94
|
+
label: copy.present[option.id],
|
|
95
|
+
icon: option.icon,
|
|
96
|
+
})), current: present, ...(onPresentChange === undefined
|
|
97
|
+
? {}
|
|
98
|
+
: { onSelect: (id) => onPresentChange(id) }), ...(surface === undefined ? {} : { surface }) })) : undefined);
|
|
99
|
+
const sheetFromDeclared = useMemo(() => sheetFromColumns(shownColumns), [shownColumns]);
|
|
100
|
+
const sheetSpec = sheet ?? sheetFromDeclared;
|
|
101
|
+
/* El menú de columnas vale en `table` y en la planilla DERIVADA —las dos
|
|
102
|
+
dibujan las columnas que declaró el código—, y no en la planilla de datos
|
|
103
|
+
crudos ni en el informe: ahí las columnas salen del archivo o son los
|
|
104
|
+
períodos, y no hay ninguna que el código pueda ofrecer esconder. */
|
|
105
|
+
const columnsMenu = (present === "table" || (present === "sheet" && sheet === undefined)) &&
|
|
106
|
+
columnControl.hasOptional ? (_jsx(ColumnsMenu, { control: columnControl, ...(surface === undefined ? {} : { surface }) })) : null;
|
|
107
|
+
/* ORDENAR. El control va en la barra y no adentro de la tabla porque el orden
|
|
108
|
+
es del CONJUNTO, igual que los niveles y que lo plegado: cambiar de
|
|
109
|
+
presentación no puede perderlo, y en filas, tablero y planilla no hay
|
|
110
|
+
encabezados donde hacer clic.
|
|
111
|
+
|
|
112
|
+
Lo único que NO se ordena es un informe cuyas filas DECLARÓ el dominio: ahí
|
|
113
|
+
el orden es el informe —«Total activos» tiene que quedar después de los
|
|
114
|
+
activos— y reordenarlo por importe lo destruye.
|
|
115
|
+
|
|
116
|
+
Un informe armado a partir de los montones sí se ordena, porque no es una
|
|
117
|
+
jerarquía que alguien escribió: es este mismo conjunto, contado. La regla
|
|
118
|
+
mira `report.rows` y no la presentación, que era la versión gruesa de esto y
|
|
119
|
+
le sacaba el orden a un informe que sí podía tenerlo. */
|
|
120
|
+
const declaredReport = present === "report" && report?.rows !== undefined;
|
|
121
|
+
/* El pivote tampoco se ordena desde la barra, y por una razón propia: sus
|
|
122
|
+
filas no son las filas del conjunto. Cada eje está en el orden de sus
|
|
123
|
+
claves, y ordenar los registros de abajo no ordena los montones de arriba —
|
|
124
|
+
ofrecerlo sería un control que se mueve y no cambia nada. */
|
|
125
|
+
const sortMenu = sortable === undefined ||
|
|
126
|
+
sortable.length === 0 ||
|
|
127
|
+
declaredReport ||
|
|
128
|
+
present === "pivot" ? null : (_jsx(SortMenu, { fields: sortable, sort: sort ?? null, onSortChange: (next) => onSortChange?.(next), ...(surface === undefined ? {} : { surface }) }));
|
|
129
|
+
const rightViews = views ?? switcher;
|
|
130
|
+
const viewsSlot = columnsMenu === null && sortMenu === null && rightViews === undefined ? undefined : (_jsxs(_Fragment, { children: [sortMenu, columnsMenu, rightViews] }));
|
|
131
|
+
const bar = (_jsx(ListingBar, { surface: surface, ...(crumbs === undefined || crumbs.length === 0 || density === "compact"
|
|
132
|
+
? {}
|
|
133
|
+
: {
|
|
134
|
+
crumbs: (_jsx(Breadcrumb, { crumbs: crumbs, ...(surface === undefined ? {} : { surface }) })),
|
|
135
|
+
}), ...(actions === undefined ? {} : { actions }), ...(identity?.title === undefined ? {} : { title: identity.title }), ...(identity?.description === undefined ? {} : { description: identity.description }), ...(identity?.counters === undefined ? {} : { counters: identity.counters }), ...(selection === undefined
|
|
136
|
+
? {}
|
|
137
|
+
: {
|
|
138
|
+
selection: {
|
|
139
|
+
count: selection.count,
|
|
140
|
+
onClear: selection.clear,
|
|
141
|
+
...(selection.actions === undefined ? {} : { actions: selection.actions }),
|
|
142
|
+
},
|
|
143
|
+
}), ...(search === undefined ? {} : { search }), ...(pagination === undefined ? {} : { pagination }), ...(viewsSlot === undefined ? {} : { views: viewsSlot }) }));
|
|
144
|
+
const renderRow = (item) => {
|
|
145
|
+
const d = row(item);
|
|
146
|
+
const id = keyOf(item);
|
|
147
|
+
return (_jsx(Row, { ...(d.icon === undefined ? {} : { icon: d.icon }), name: d.name, ...(d.tags === undefined ? {} : { tags: d.tags }), ...(d.meta === undefined ? {} : { meta: d.meta }), ...(d.actions === undefined ? {} : { actions: d.actions }), ...(onOpen === undefined ? {} : { onOpen: () => onOpen(item) }), ...(onPeek === undefined ? {} : { onPeek: () => onPeek(item) }), ...(selection === undefined
|
|
148
|
+
? {}
|
|
149
|
+
: { selected: selection.has(id), onSelectedChange: () => selection.toggle(id) }), children: d.children }, id));
|
|
150
|
+
};
|
|
151
|
+
/* El orden va ANTES de agrupar y no después, y no es indistinto: agrupar
|
|
152
|
+
preserva el orden de aparición dentro de cada montón, así que ordenar
|
|
153
|
+
primero ordena las filas de cada montón. Al revés habría que reordenar N
|
|
154
|
+
montones y el orden entre ellos quedaría al azar.
|
|
155
|
+
|
|
156
|
+
La tabla ordena adentro —es TanStack— así que ahí se deja pasar: ordenar dos
|
|
157
|
+
veces no rompe nada, pero es trabajo al pedo sobre cada render. */
|
|
158
|
+
const ordered = useMemo(() => present === "table" || sortable === undefined
|
|
159
|
+
? items
|
|
160
|
+
: sortItems(items, sortable, sort ?? null), [items, present, sortable, sort]);
|
|
161
|
+
/**
|
|
162
|
+
* La grilla que hay que dibujar: la que le pasaron plegada, o la que se arma
|
|
163
|
+
* con las filas en la mano.
|
|
164
|
+
*
|
|
165
|
+
* Es la misma decisión que `pilesOf` toma para los montones, y por el mismo
|
|
166
|
+
* motivo: quién plegó no es asunto de esta capa.
|
|
167
|
+
*/
|
|
168
|
+
const pivotShown = useMemo(() => {
|
|
169
|
+
if (pivot?.folded !== undefined)
|
|
170
|
+
return pivot.folded;
|
|
171
|
+
if (pivot?.spec === undefined)
|
|
172
|
+
return undefined;
|
|
173
|
+
return pivotFrom(ordered, pivot.spec);
|
|
174
|
+
}, [pivot, ordered]);
|
|
175
|
+
/**
|
|
176
|
+
* Vacío es no tener NADA que dibujar, y en el pivote eso no se pregunta
|
|
177
|
+
* contando `items`: cuando la grilla la plegó quien guarda los datos, las
|
|
178
|
+
* filas de la pantalla son montones y el conjunto puede no haber bajado
|
|
179
|
+
* nunca. Contar los registros ahí es tapar una grilla entera con «todavía no
|
|
180
|
+
* hay datos».
|
|
181
|
+
*/
|
|
182
|
+
const isEmpty = !loading &&
|
|
183
|
+
error === null &&
|
|
184
|
+
(present === "pivot" && pivotShown !== undefined
|
|
185
|
+
? pivotIsEmpty(pivotShown)
|
|
186
|
+
: items.length === 0);
|
|
187
|
+
/* La única línea que hace agrupable a una vista: el árbol que le pasaron, o el
|
|
188
|
+
que se arma con las filas en la mano. */
|
|
189
|
+
const piles = useMemo(() => pilesOf(ordered, group), [group, ordered]);
|
|
190
|
+
const isOpen = useCallback((pile) => pileIsOpen(pile, group), [group]);
|
|
191
|
+
const sheetRows = useMemo(() => sheetRowsOf(piles, isOpen, columns), [piles, isOpen, columns]);
|
|
192
|
+
/* La forma de una fila de ESTA lista, para que el encabezado reserve los
|
|
193
|
+
mismos espaciadores. Se mira la primera y no todas: el ícono y las acciones
|
|
194
|
+
los decide la vista para la lista entera. */
|
|
195
|
+
const first = items[0];
|
|
196
|
+
const firstRow = first === undefined ? undefined : row(first);
|
|
197
|
+
/** Los montones, con sus filas adentro. Se llama a sí misma porque el árbol
|
|
198
|
+
* tiene N niveles: un montón dibuja su encabezado y, adentro, o bien los
|
|
199
|
+
* montones de abajo o bien las filas — nunca las dos cosas. */
|
|
200
|
+
function renderPiles(list, nodes) {
|
|
201
|
+
return list.map((pile) => {
|
|
202
|
+
const key = pathKey(pile.path);
|
|
203
|
+
const open = isOpen(pile);
|
|
204
|
+
return (_jsxs(Fragment, { children: [_jsx(GroupHeader, { field: pile.field, label: pile.label, count: pile.count, depth: pile.depth, open: open, ...(group?.onToggle === undefined
|
|
205
|
+
? {}
|
|
206
|
+
: { onToggle: () => group.onToggle?.(key) }) }), !open
|
|
207
|
+
? null
|
|
208
|
+
: pile.piles.length > 0
|
|
209
|
+
? renderPiles(pile.piles, nodes)
|
|
210
|
+
: nodes(pile.items)] }, key));
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
const reportRows = useMemo(() => reportRowsOf(piles, columns, row), [piles, columns, row]);
|
|
214
|
+
function wrapGroups(nodes) {
|
|
215
|
+
if (piles === null)
|
|
216
|
+
return nodes(ordered);
|
|
217
|
+
return renderPiles(piles, nodes);
|
|
218
|
+
}
|
|
219
|
+
const renderCard = (item) => {
|
|
220
|
+
if (card !== undefined) {
|
|
221
|
+
return _jsx(Fragment, { children: card(item) }, keyOf(item));
|
|
222
|
+
}
|
|
223
|
+
const d = row(item);
|
|
224
|
+
return (_jsx(RecordCard, { title: d.name, ...(d.tags === undefined ? {} : { tags: d.tags }), ...(d.meta === undefined ? {} : { meta: d.meta }), ...(onOpen === undefined ? {} : { onOpen: () => onOpen(item) }) }, keyOf(item)));
|
|
225
|
+
};
|
|
226
|
+
const body = present === "table" && shownColumns !== undefined ? (
|
|
227
|
+
/* The table receives EVERYTHING that belongs to the set: see `TablePresentation`. */
|
|
228
|
+
_jsx(TablePresentation, { items: items, columns: shownColumns, keyOf: keyOf, levels: groupLevels, ...(sort === undefined ? {} : { sort }), ...(onSortChange === undefined ? {} : { onSortChange }), ...(group === undefined ? {} : { group }), ...(selection === undefined ? {} : { selection }), totals: totals, ...(rowActions === undefined ? {} : { rowActions }), ...(onPeek === undefined ? {} : { onPeek }), ...(onOpen === undefined ? {} : { onOpen }) })) : present === "sheet" && sheetSpec !== undefined ? (
|
|
229
|
+
/* La planilla recibe el conjunto por ÍNDICE y no una matriz ya armada: ver `SheetPresentation`. */
|
|
230
|
+
_jsx(SheetPresentation, { spec: sheetSpec, entries: sheetRows, ordered: ordered, ...(group === undefined ? {} : { group }) })) : present === "report" && report !== undefined ? (
|
|
231
|
+
/* El informe declarado por el dominio no se ORDENA desde la barra: el
|
|
232
|
+
orden ES el informe, y ordenar un balance por importe deja «Total
|
|
233
|
+
Activos» en el medio. Pero sí se AGRUPA cuando las líneas no vienen
|
|
234
|
+
declaradas: ahí el informe es este conjunto contado por los niveles que
|
|
235
|
+
estén puestos. */
|
|
236
|
+
_jsx(ReportTable, { columns: report.columns, rows: report.rows ?? reportRows, ...(report.defaultOpen === undefined ? {} : { defaultOpen: report.defaultOpen }), ...(report.height === undefined ? {} : { height: report.height }) })) : present === "pivot" && pivotShown !== undefined ? (
|
|
237
|
+
/* El pivote recibe la grilla y nada más: no hay selección que pasarle
|
|
238
|
+
—una casilla por montón elegiría cosas que no son registros—, no hay
|
|
239
|
+
orden —cada eje viene en el orden de sus claves— y no hay menú de
|
|
240
|
+
columnas, porque las columnas son un eje y no una lista de campos que
|
|
241
|
+
se puedan esconder de a uno. */
|
|
242
|
+
_jsx(PivotTable, { pivot: pivotShown, ...(pivot?.onCell === undefined ? {} : { onCell: pivot.onCell }), ...(pivot?.height === undefined ? {} : { height: pivot.height }) })) : present === "board" ? (_jsx("div", { className: "flex flex-col", children: wrapGroups((inside) => (_jsx("div", { className: "grid gap-3 p-3 @2xl:grid-cols-2 @5xl:grid-cols-3", children: inside.map(renderCard) }))) })) : (
|
|
243
|
+
/* El encabezado va ANTES de los montones y no adentro de cada uno:
|
|
244
|
+
rotula la fila, y la fila es la misma en los cinco montones. */
|
|
245
|
+
_jsxs(_Fragment, { children: [rowHeader === undefined || items.length === 0 ? null : (_jsx(RowHeader, { name: rowHeader.name, ...(rowHeader.meta === undefined ? {} : { meta: rowHeader.meta }), ...(rowHeader.tags === undefined ? {} : { tags: rowHeader.tags }), withSelection: selection !== undefined,
|
|
246
|
+
/* Los espaciadores se preguntan por la PRIMERA fila: el ícono y las
|
|
247
|
+
acciones son de la lista entera, no de una fila — si la primera no
|
|
248
|
+
tiene ícono, ninguna lo tiene. */
|
|
249
|
+
withIcon: firstRow?.icon !== undefined, withActions: onOpen !== undefined || firstRow?.actions !== undefined })), wrapGroups((inside) => inside.map(renderRow))] }));
|
|
250
|
+
return (
|
|
251
|
+
/* The list is its own container (`@container`: the presentations adapt to the width
|
|
252
|
+
the LIST has, not the window) and fills the space it is given. Before, every page
|
|
253
|
+
wrapped it in a `div` to get both. */
|
|
254
|
+
_jsxs("div", { ref: frame, className: "@container flex min-w-0 flex-1 flex-col bg-surface", children: [_jsxs(Listing, { bar: bar,
|
|
255
|
+
/* La barra se queda arriba: con 187 filas, scrollear para ver la última
|
|
256
|
+
dejaba sin buscador, sin paginador y sin el conmutador. */
|
|
257
|
+
sticky: true, ...(surface === undefined ? {} : { surface }), ...(metrics === undefined
|
|
258
|
+
? {}
|
|
259
|
+
: {
|
|
260
|
+
metrics: _jsx("div", { className: "px-3.5", children: metrics }),
|
|
261
|
+
}), children: [loading ? _jsx(Skeleton, { label: copy.failed.loading }) : null, isEmpty ? (filtered ? (_jsx(Empty, { sentence: empty?.whenFiltered?.sentence ?? copy.list.emptyFiltered, ...(empty?.whenFiltered?.action === undefined
|
|
262
|
+
? {}
|
|
263
|
+
: { action: empty.whenFiltered.action }) })) : (_jsx(Empty, { sentence: empty?.sentence ?? copy.list.empty, ...(empty?.action === undefined ? {} : { action: empty.action }) }))) : null, loading || isEmpty ? null : body] }), error === null ? null : (_jsx("div", { className: "px-3 pt-(--spacing-block)", children: _jsx(Failed, { heading: copy.failed.list, sentence: error }) })), children] }));
|
|
264
|
+
}
|
|
265
|
+
/** What a list offers when it fails and can be retried. */
|
|
266
|
+
export function RetryAction({ onRetry }) {
|
|
267
|
+
const copy = useUiCopy();
|
|
268
|
+
return (_jsx(Button, { role: "secondary", size: "sm", onClick: onRetry, children: copy.failed.retry }));
|
|
269
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ListPresent } from "../../components/listing/set.js";
|
|
2
|
+
import type { DataColumn } from "../../primitives/table/DataTable.js";
|
|
3
|
+
import type { ListGroup } from "./types.js";
|
|
4
|
+
/** Las columnas que una tabla agrupada tiene que MOSTRAR, en orden.
|
|
5
|
+
*
|
|
6
|
+
* No son por las que agrupa —eso lo hacen los niveles, con la clave del motor—
|
|
7
|
+
* sino las que no pueden quedar escondidas: un montón «Septiembre» con la
|
|
8
|
+
* columna «registrado» apagada es un corte cuyo criterio no está en la
|
|
9
|
+
* pantalla.
|
|
10
|
+
*
|
|
11
|
+
* **El nombre de una columna y el de un campo no son el mismo, y suponerlo fue
|
|
12
|
+
* lo que rompió la tabla.** Una columna puede llamarse `registered` y contestar
|
|
13
|
+
* por el `registered_at` del modelo — que es justo lo que declara
|
|
14
|
+
* `DataColumn.field`. Lee las columnas en orden —la que SE LLAMA como el campo,
|
|
15
|
+
* después la que lo declara— y `columnOf` gana si la vista sabe más. */
|
|
16
|
+
export declare function groupedColumnIds<T extends object>(group: ListGroup<T>, columns: readonly DataColumn<T>[] | undefined): string[];
|
|
17
|
+
/** The presentations that need width: a grid of columns. */
|
|
18
|
+
export declare const WIDE_PRESENTS: readonly ListPresent[];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Las columnas que una tabla agrupada tiene que MOSTRAR, en orden.
|
|
2
|
+
*
|
|
3
|
+
* No son por las que agrupa —eso lo hacen los niveles, con la clave del motor—
|
|
4
|
+
* sino las que no pueden quedar escondidas: un montón «Septiembre» con la
|
|
5
|
+
* columna «registrado» apagada es un corte cuyo criterio no está en la
|
|
6
|
+
* pantalla.
|
|
7
|
+
*
|
|
8
|
+
* **El nombre de una columna y el de un campo no son el mismo, y suponerlo fue
|
|
9
|
+
* lo que rompió la tabla.** Una columna puede llamarse `registered` y contestar
|
|
10
|
+
* por el `registered_at` del modelo — que es justo lo que declara
|
|
11
|
+
* `DataColumn.field`. Lee las columnas en orden —la que SE LLAMA como el campo,
|
|
12
|
+
* después la que lo declara— y `columnOf` gana si la vista sabe más. */
|
|
13
|
+
export function groupedColumnIds(group, columns) {
|
|
14
|
+
return group.levels
|
|
15
|
+
.map((level) => group.columnOf?.(level) ?? columnAnswering(level.field, columns))
|
|
16
|
+
.filter((id) => id !== undefined);
|
|
17
|
+
}
|
|
18
|
+
/** The presentations that need width: a grid of columns. */
|
|
19
|
+
export const WIDE_PRESENTS = ["table", "sheet", "report", "pivot"];
|
|
20
|
+
/** The id of the column that answers for a model field, when there is one. */
|
|
21
|
+
function columnAnswering(field, columns) {
|
|
22
|
+
if (columns === undefined)
|
|
23
|
+
return field;
|
|
24
|
+
return (columns.find((one) => one.id === field)?.id ??
|
|
25
|
+
columns.find((one) => one.field === field)?.id ??
|
|
26
|
+
field);
|
|
27
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type Pile } from "../../foundations/grouping.js";
|
|
2
|
+
import { type DataColumn } from "../../primitives/table/DataTable.js";
|
|
3
|
+
import type { ReportRow } from "../../primitives/table/ReportTable.js";
|
|
4
|
+
import type { SheetColumn } from "../../primitives/table/SheetTable.js";
|
|
5
|
+
import type { ListGroup, ListSheet, RowOf } from "./types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Context: what a list DERIVES from its set, as pure functions — the table's group levels,
|
|
8
|
+
* the sheet drawn from the declared columns, the sheet's flattened band/row sequence and
|
|
9
|
+
* the report built from the piles. `ListView` calls them inside `useMemo` with the same
|
|
10
|
+
* dependencies they always had; nothing here knows React.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Los niveles, como los necesita la tabla: uno por NIVEL y no uno por campo.
|
|
14
|
+
*
|
|
15
|
+
* La clave sale de `group.of` —la misma que arman las otras cinco
|
|
16
|
+
* presentaciones— así que los montones de la tabla son los mismos y lo plegado
|
|
17
|
+
* vale para todas. El rótulo sale de la misma regla que el árbol: un nivel no
|
|
18
|
+
* repite lo que el de arriba, del mismo campo, ya dijo.
|
|
19
|
+
*/
|
|
20
|
+
export declare function groupLevelsOf<T extends object>(group: ListGroup<T> | undefined, columns: readonly DataColumn<T>[] | undefined): {
|
|
21
|
+
id: string;
|
|
22
|
+
label: string;
|
|
23
|
+
keyOf: (item: T) => string;
|
|
24
|
+
labelOf: (key: string) => string;
|
|
25
|
+
}[];
|
|
26
|
+
/**
|
|
27
|
+
* La planilla de un conjunto de REGISTROS sale de las columnas que la lista
|
|
28
|
+
* ya declaró. Sin esto, ofrecer `sheet` obligaba a escribir las columnas dos
|
|
29
|
+
* veces —una como `DataColumn` y otra como `SheetColumn`— y entonces nadie la
|
|
30
|
+
* ofrecía: la presentación existía en el arquetipo y no estaba en ninguna
|
|
31
|
+
* pantalla.
|
|
32
|
+
*
|
|
33
|
+
* `sheet` explícita sigue siendo para los DATOS CRUDOS, donde las columnas
|
|
34
|
+
* salen del archivo y el código no sabe cuáles son.
|
|
35
|
+
*/
|
|
36
|
+
export declare function sheetFromColumns<T extends object>(shownColumns: readonly DataColumn<T>[] | undefined): ListSheet<T> | undefined;
|
|
37
|
+
export type SheetEntry<T> = {
|
|
38
|
+
band?: {
|
|
39
|
+
field: string;
|
|
40
|
+
label: string;
|
|
41
|
+
count: number;
|
|
42
|
+
open: boolean;
|
|
43
|
+
key: string;
|
|
44
|
+
depth: number;
|
|
45
|
+
total?: (column: SheetColumn, columnIndex: number) => string | number | null;
|
|
46
|
+
};
|
|
47
|
+
item?: T;
|
|
48
|
+
n?: number;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* La planilla, cuando hay montones: una SECUENCIA donde cada índice es una
|
|
52
|
+
* fila o la cabecera del montón que empieza ahí.
|
|
53
|
+
*
|
|
54
|
+
* **Acá decía que la planilla no agrupa y estaba mal razonado.** El argumento
|
|
55
|
+
* —una banda corre la cuadrícula y mirar datos crudos es seguir una fila a lo
|
|
56
|
+
* ancho— vale para los datos crudos, donde las columnas salen del archivo y
|
|
57
|
+
* no hay ningún eje del dominio por el que agrupar. Pero la planilla DERIVADA
|
|
58
|
+
* es el mismo conjunto de registros que la tabla, con los mismos ejes: que
|
|
59
|
+
* agrupe la tabla y no ella es exactamente el drift que este arquetipo existe
|
|
60
|
+
* para impedir — cambiar de presentación perdía la agrupación.
|
|
61
|
+
*
|
|
62
|
+
* La regla queda en manos de la vista, como corresponde: si declara `group`,
|
|
63
|
+
* agrupa; si no, no hay montones que dibujar.
|
|
64
|
+
*/
|
|
65
|
+
export declare function sheetRowsOf<T extends object>(piles: readonly Pile<T>[] | null, isOpen: (pile: Pile<T>) => boolean, columns: readonly DataColumn<T>[] | undefined): SheetEntry<T>[] | null;
|
|
66
|
+
/**
|
|
67
|
+
* El informe armado a partir de los montones, cuando el dominio no declaró
|
|
68
|
+
* líneas.
|
|
69
|
+
*
|
|
70
|
+
* Cada montón es una línea con los agregados de las columnas que declararon
|
|
71
|
+
* uno, y el nivel más profundo cuelga sus filas. Las columnas del informe las
|
|
72
|
+
* pone `report.columns`; los números salen de las `columns` de la lista, que
|
|
73
|
+
* son las mismas que suma el pie de la tabla — para que el informe y la tabla
|
|
74
|
+
* no digan totales distintos del mismo conjunto.
|
|
75
|
+
*/
|
|
76
|
+
export declare function reportRowsOf<T extends object>(piles: readonly Pile<T>[] | null, columns: readonly DataColumn<T>[] | undefined, row: (item: T) => RowOf): readonly ReportRow[];
|