@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,42 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export type Theme = "system" | "light" | "dark";
|
|
3
|
+
/** What the palette actually is once `system` has been looked up. */
|
|
4
|
+
export type ResolvedTheme = "light" | "dark";
|
|
5
|
+
export declare const THEMES: readonly Theme[];
|
|
6
|
+
/** The attribute the stylesheet reads. */
|
|
7
|
+
export declare const THEME_ATTRIBUTE = "data-theme";
|
|
8
|
+
/** `system` is the operating system's answer; the other two are themselves. Pure, so it can
|
|
9
|
+
* be tested without a browser. */
|
|
10
|
+
export declare function resolveTheme(theme: Theme, systemPrefersDark: boolean): ResolvedTheme;
|
|
11
|
+
/** True for a string that is one of the three values — what comes out of storage or a URL
|
|
12
|
+
* is `string | null`, and this is the way back to `Theme`. */
|
|
13
|
+
export declare function isTheme(value: unknown): value is Theme;
|
|
14
|
+
/** Writes the choice on an element. `system` REMOVES the attribute: the stylesheet then
|
|
15
|
+
* follows `prefers-color-scheme` by itself, and an attribute saying "system" would be a
|
|
16
|
+
* value no selector reads. Returns nothing; the DOM is the output. */
|
|
17
|
+
export declare function applyTheme(theme: Theme, element?: Element): void;
|
|
18
|
+
type ThemeValue = {
|
|
19
|
+
/** What the app chose. */
|
|
20
|
+
theme: Theme;
|
|
21
|
+
/** What the palette is — `system` already looked up. */
|
|
22
|
+
resolved: ResolvedTheme;
|
|
23
|
+
setTheme: (next: Theme) => void;
|
|
24
|
+
};
|
|
25
|
+
export type ThemeProviderProps = {
|
|
26
|
+
/** Controlled: the app owns the value (and persists it). */
|
|
27
|
+
value?: Theme;
|
|
28
|
+
/** Uncontrolled: the starting choice. */
|
|
29
|
+
defaultValue?: Theme;
|
|
30
|
+
/** Called with every choice, controlled or not — the place to persist it. */
|
|
31
|
+
onChange?: (next: Theme) => void;
|
|
32
|
+
/** Where `data-theme` is written. `<html>` by default; pass an element to theme a subtree
|
|
33
|
+
* (a preview, a story). A portal mounted outside it keeps the document's theme. */
|
|
34
|
+
element?: Element | null;
|
|
35
|
+
children?: ReactNode;
|
|
36
|
+
};
|
|
37
|
+
export declare function ThemeProvider({ value, defaultValue, onChange, element, children, }: ThemeProviderProps): import("react").JSX.Element;
|
|
38
|
+
/** The choice, the palette it resolves to, and the way to change it. Without a provider it
|
|
39
|
+
* still reads (what `<html>` and the OS say) and `setTheme` writes `<html>` directly, so a
|
|
40
|
+
* one-off call site works without wrapping the app. */
|
|
41
|
+
export declare function useTheme(): ThemeValue;
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useState, useSyncExternalStore, } from "react";
|
|
4
|
+
export const THEMES = ["system", "light", "dark"];
|
|
5
|
+
/** The attribute the stylesheet reads. */
|
|
6
|
+
export const THEME_ATTRIBUTE = "data-theme";
|
|
7
|
+
/** `system` is the operating system's answer; the other two are themselves. Pure, so it can
|
|
8
|
+
* be tested without a browser. */
|
|
9
|
+
export function resolveTheme(theme, systemPrefersDark) {
|
|
10
|
+
if (theme === "system")
|
|
11
|
+
return systemPrefersDark ? "dark" : "light";
|
|
12
|
+
return theme;
|
|
13
|
+
}
|
|
14
|
+
/** True for a string that is one of the three values — what comes out of storage or a URL
|
|
15
|
+
* is `string | null`, and this is the way back to `Theme`. */
|
|
16
|
+
export function isTheme(value) {
|
|
17
|
+
return value === "system" || value === "light" || value === "dark";
|
|
18
|
+
}
|
|
19
|
+
/** Writes the choice on an element. `system` REMOVES the attribute: the stylesheet then
|
|
20
|
+
* follows `prefers-color-scheme` by itself, and an attribute saying "system" would be a
|
|
21
|
+
* value no selector reads. Returns nothing; the DOM is the output. */
|
|
22
|
+
export function applyTheme(theme, element = document.documentElement) {
|
|
23
|
+
if (theme === "system")
|
|
24
|
+
element.removeAttribute(THEME_ATTRIBUTE);
|
|
25
|
+
else
|
|
26
|
+
element.setAttribute(THEME_ATTRIBUTE, theme);
|
|
27
|
+
}
|
|
28
|
+
const DARK_QUERY = "(prefers-color-scheme: dark)";
|
|
29
|
+
/** The operating system's preference, live. Server snapshot: light — the same as the
|
|
30
|
+
* stylesheet's default when it cannot ask. */
|
|
31
|
+
function useSystemPrefersDark() {
|
|
32
|
+
return useSyncExternalStore((notify) => {
|
|
33
|
+
const query = window.matchMedia(DARK_QUERY);
|
|
34
|
+
query.addEventListener("change", notify);
|
|
35
|
+
return () => query.removeEventListener("change", notify);
|
|
36
|
+
}, () => window.matchMedia(DARK_QUERY).matches, () => false);
|
|
37
|
+
}
|
|
38
|
+
/** What `<html>` says right now — read for code that has no provider above it (an editor
|
|
39
|
+
* that has to pick a built-in theme) and must still follow a switch made elsewhere. */
|
|
40
|
+
function useRootAttribute() {
|
|
41
|
+
return useSyncExternalStore((notify) => {
|
|
42
|
+
const observer = new MutationObserver(notify);
|
|
43
|
+
observer.observe(document.documentElement, {
|
|
44
|
+
attributes: true,
|
|
45
|
+
attributeFilter: [THEME_ATTRIBUTE],
|
|
46
|
+
});
|
|
47
|
+
return () => observer.disconnect();
|
|
48
|
+
}, () => document.documentElement.getAttribute(THEME_ATTRIBUTE), () => null);
|
|
49
|
+
}
|
|
50
|
+
const Ctx = createContext(null);
|
|
51
|
+
export function ThemeProvider({ value, defaultValue = "system", onChange, element, children, }) {
|
|
52
|
+
const [own, setOwn] = useState(defaultValue);
|
|
53
|
+
const theme = value ?? own;
|
|
54
|
+
const systemDark = useSystemPrefersDark();
|
|
55
|
+
const setTheme = useCallback((next) => {
|
|
56
|
+
setOwn(next);
|
|
57
|
+
onChange?.(next);
|
|
58
|
+
}, [onChange]);
|
|
59
|
+
/* An effect and not a render-time write: the DOM is outside React's tree, and writing it
|
|
60
|
+
during render would run on the server and twice in StrictMode. */
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
const target = element === undefined ? document.documentElement : element;
|
|
63
|
+
if (target === null)
|
|
64
|
+
return;
|
|
65
|
+
applyTheme(theme, target);
|
|
66
|
+
return () => target.removeAttribute(THEME_ATTRIBUTE);
|
|
67
|
+
}, [theme, element]);
|
|
68
|
+
const context = useMemo(() => ({ theme, resolved: resolveTheme(theme, systemDark), setTheme }), [theme, systemDark, setTheme]);
|
|
69
|
+
return _jsx(Ctx.Provider, { value: context, children: children });
|
|
70
|
+
}
|
|
71
|
+
/** The choice, the palette it resolves to, and the way to change it. Without a provider it
|
|
72
|
+
* still reads (what `<html>` and the OS say) and `setTheme` writes `<html>` directly, so a
|
|
73
|
+
* one-off call site works without wrapping the app. */
|
|
74
|
+
export function useTheme() {
|
|
75
|
+
const provided = useContext(Ctx);
|
|
76
|
+
const attribute = useRootAttribute();
|
|
77
|
+
const systemDark = useSystemPrefersDark();
|
|
78
|
+
return useMemo(() => {
|
|
79
|
+
if (provided !== null)
|
|
80
|
+
return provided;
|
|
81
|
+
const theme = isTheme(attribute) ? attribute : "system";
|
|
82
|
+
return {
|
|
83
|
+
theme,
|
|
84
|
+
resolved: resolveTheme(theme, systemDark),
|
|
85
|
+
setTheme: (next) => applyTheme(next),
|
|
86
|
+
};
|
|
87
|
+
}, [provided, attribute, systemDark]);
|
|
88
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Which background something is drawn on.
|
|
2
|
+
*
|
|
3
|
+
* The interface has TWO surfaces and the piece does not behave the same on
|
|
4
|
+
* both: on the canvas, a ghost button uses the navigation blue (8.26:1); on
|
|
5
|
+
* the chrome that blue gives 1.4:1 and the lightened one has to be used.
|
|
6
|
+
*
|
|
7
|
+
* It is a PROP and not a context on purpose — the opposite of `Density`. The
|
|
8
|
+
* color is decided per element and it has to be auditable one at a time; a
|
|
9
|
+
* global theme would resolve it by inheritance and then the decision would not
|
|
10
|
+
* be visible in the calling code. See the long note in `system/density.tsx`. */
|
|
11
|
+
export type Surface = "canvas" | "chrome";
|
|
12
|
+
/** The meaning of a state color. It is NOT a decorative palette.
|
|
13
|
+
*
|
|
14
|
+
* The moment a tag uses a hue because some variety was needed, all six stop
|
|
15
|
+
* meaning anything and you have to read the word anyway — and then the color
|
|
16
|
+
* is redundant. `neutral` is the default precisely because of that: most tags
|
|
17
|
+
* in a catalog are CLASSIFICATIONS, not states. */
|
|
18
|
+
export type Tone = "neutral" | "info" | "good" | "warn" | "bad" | "accent";
|
|
19
|
+
/** The size of a control, tied to `--size-control-*`.
|
|
20
|
+
*
|
|
21
|
+
* Three and not five: a fourth intermediate step gets picked out of habit and
|
|
22
|
+
* stops meaning a place. */
|
|
23
|
+
export type Size = "sm" | "md" | "lg";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/* ==================================================================== *
|
|
2
|
+
* THE SHARED TYPES — and why they live in a single place.
|
|
3
|
+
*
|
|
4
|
+
* `Surface` was defined TWICE, in `button/` and in `record/`. Both copies
|
|
5
|
+
* said the same thing, so the compiler never complained — and that is exactly
|
|
6
|
+
* the problem: the day a third surface appears, one of the two gets updated
|
|
7
|
+
* and the other does not, and nothing catches it until someone passes
|
|
8
|
+
* `"chrome"` to a component that no longer accepts it.
|
|
9
|
+
*
|
|
10
|
+
* What goes in here has a test: **more than one component family uses it AND
|
|
11
|
+
* it belongs to none of them**. A type that only `list/` uses lives in
|
|
12
|
+
* `list/`, even if it is shared across its three files.
|
|
13
|
+
* ==================================================================== */
|
|
14
|
+
export {};
|
|
15
|
+
/* ==================================================================== *
|
|
16
|
+
* THE SYSTEM'S TWO API CONVENTIONS
|
|
17
|
+
*
|
|
18
|
+
* They are here and not in the README because a convention that lives in the
|
|
19
|
+
* documentation breaks in the first component written in a hurry. Here it is
|
|
20
|
+
* read by whoever is going to write the next component.
|
|
21
|
+
*
|
|
22
|
+
* ── 1. How a callback is named ──────────────────────────────────────
|
|
23
|
+
*
|
|
24
|
+
* onXChange the component proposes a NEW value for `x`, and whoever
|
|
25
|
+
* uses it decides whether to accept it. It ALWAYS goes with
|
|
26
|
+
* the `x` prop.
|
|
27
|
+
* → onTermsChange(terms), onSelectedChange(set), onSortChange(sort)
|
|
28
|
+
*
|
|
29
|
+
* onX something happened that is not a value change: an intent.
|
|
30
|
+
* → onClose(), onOpen(), onPromote(), onBrowseAll()
|
|
31
|
+
*
|
|
32
|
+
* The test for knowing which one: **is there a prop with that name next to
|
|
33
|
+
* it?** If `value` exists, it is `onValueChange`. If not, it is an event and
|
|
34
|
+
* goes without a suffix.
|
|
35
|
+
*
|
|
36
|
+
* ── 2. Controlled, always ───────────────────────────────────────────
|
|
37
|
+
*
|
|
38
|
+
* Any state the consumer might want to read, store in the URL or restore on
|
|
39
|
+
* reload is CONTROLLED: `value` + `onValueChange`, with no internal memory.
|
|
40
|
+
* That is what lets the entire workspace live in the hash.
|
|
41
|
+
*
|
|
42
|
+
* The exception, and there is only one: **what dies with the component and
|
|
43
|
+
* nobody cares about afterwards.** An open menu, an expanded filter panel, the
|
|
44
|
+
* half-typed text in the search box. That does keep state inside, because
|
|
45
|
+
* exposing it would force every consumer to declare a `useState` for something
|
|
46
|
+
* they are never going to read.
|
|
47
|
+
*
|
|
48
|
+
* Put another way: if it makes sense to send it to a colleague over chat so
|
|
49
|
+
* they see the same thing, it is controlled.
|
|
50
|
+
* ==================================================================== */
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** The system's `tv`: a recipe of base classes and variants, merged with the scales above. */
|
|
2
|
+
export declare const tv: import("tailwind-variants/config").TV<import("tailwind-variants/config").TVCustomConfig>;
|
|
3
|
+
/** Joins classes, and when two set the same property, the LAST one wins. */
|
|
4
|
+
export declare function cn(...classes: (string | false | null | undefined)[]): string;
|
|
5
|
+
/**
|
|
6
|
+
* The focus ring of every interactive piece: the same outline `Button` draws, driven by
|
|
7
|
+
* React Aria's `isFocusVisible` — keyboard focus shows it, a mouse click does not.
|
|
8
|
+
*/
|
|
9
|
+
export declare const focusRing: import("tailwind-variants/config").TVReturnType<{
|
|
10
|
+
isFocusVisible: {
|
|
11
|
+
false: string;
|
|
12
|
+
true: string;
|
|
13
|
+
};
|
|
14
|
+
}, undefined, "outline-primary outline-offset-2 forced-colors:outline-[Highlight]", undefined, undefined, undefined>;
|
|
15
|
+
/**
|
|
16
|
+
* A React Aria `className` can be a string or a function of the render state. This puts the
|
|
17
|
+
* system's classes first and the consumer's after, so the consumer's win where they fight.
|
|
18
|
+
*/
|
|
19
|
+
export declare function composeClasses<T>(className: string | ((state: T) => string) | undefined, base: string): string | ((state: T) => string);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { composeRenderProps } from "react-aria-components";
|
|
2
|
+
import { cnMerge, createTV } from "tailwind-variants/config";
|
|
3
|
+
/**
|
|
4
|
+
* How a component's classes are composed — the variants of a recipe, and the merge of a
|
|
5
|
+
* consumer's `className` on top of the system's.
|
|
6
|
+
*
|
|
7
|
+
* Context: merging Tailwind classes needs to know which classes fight over the same
|
|
8
|
+
* property. The merger only knows Tailwind's default scales, and this system has its own:
|
|
9
|
+
* `text-meta` is a SIZE and `text-ink` a COLOR, but to a merger that has never heard of
|
|
10
|
+
* `meta`, both are `text-*` colors — and `text-meta text-ink` silently loses one. Every
|
|
11
|
+
* named scale in `tokens.css` is declared here so the merger reads it as what it is.
|
|
12
|
+
* `tests/variants.test.ts` holds each pair that used to collide.
|
|
13
|
+
*/
|
|
14
|
+
const twMergeConfig = {
|
|
15
|
+
extend: {
|
|
16
|
+
theme: {
|
|
17
|
+
text: ["micro", "meta", "body", "lead", "title", "display"],
|
|
18
|
+
radius: ["mark", "control", "box", "panel", "pill"],
|
|
19
|
+
shadow: ["raised", "float", "window"],
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
/** The system's `tv`: a recipe of base classes and variants, merged with the scales above. */
|
|
24
|
+
export const tv = createTV({ twMergeConfig });
|
|
25
|
+
/** Joins classes, and when two set the same property, the LAST one wins. */
|
|
26
|
+
export function cn(...classes) {
|
|
27
|
+
return cnMerge(...classes)({ twMergeConfig }) ?? "";
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The focus ring of every interactive piece: the same outline `Button` draws, driven by
|
|
31
|
+
* React Aria's `isFocusVisible` — keyboard focus shows it, a mouse click does not.
|
|
32
|
+
*/
|
|
33
|
+
export const focusRing = tv({
|
|
34
|
+
base: "outline-primary outline-offset-2 forced-colors:outline-[Highlight]",
|
|
35
|
+
variants: {
|
|
36
|
+
isFocusVisible: {
|
|
37
|
+
false: "outline-0",
|
|
38
|
+
true: "outline-2",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* A React Aria `className` can be a string or a function of the render state. This puts the
|
|
44
|
+
* system's classes first and the consumer's after, so the consumer's win where they fight.
|
|
45
|
+
*/
|
|
46
|
+
export function composeClasses(className, base) {
|
|
47
|
+
return composeRenderProps(className, (own) => cn(base, own));
|
|
48
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESCRIBIR UNA PLANILLA DE EXCEL, sin librería.
|
|
3
|
+
*
|
|
4
|
+
* ── Por qué no hay dependencia ──────────────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* Un `.xlsx` es un ZIP con seis XML adentro, y el ZIP sólo se pone difícil
|
|
7
|
+
* cuando hay que comprimir. **No hay que comprimir**: el formato admite entradas
|
|
8
|
+
* `stored` —método 0, los bytes tal cual— y Excel las abre igual. Lo único que
|
|
9
|
+
* queda del ZIP es un CRC32 y tres encabezados de posiciones fijas.
|
|
10
|
+
*
|
|
11
|
+
* Del otro lado, las librerías del rubro pesan entre medio mega y uno, traen su
|
|
12
|
+
* propio modelo de libro, de estilos y de fórmulas, y este sistema de diseño se
|
|
13
|
+
* publica como fuente para que lo compile quien lo consuma — incluido, algún
|
|
14
|
+
* día, un teléfono. Un mega de escritor de planillas adentro de un paquete de
|
|
15
|
+
* componentes lo carga todo el que importe un botón.
|
|
16
|
+
*
|
|
17
|
+
* ── Qué hace y qué no ───────────────────────────────────────────────
|
|
18
|
+
*
|
|
19
|
+
* Hace lo que una grilla necesita para no mentir al salir: texto y números en su
|
|
20
|
+
* tipo real, celdas combinadas, formato de número por celda, negrita, ancho de
|
|
21
|
+
* columna y paneles congelados. **Una celda ausente no se escribe**, que es como
|
|
22
|
+
* el formato dice «acá no hay nada» — un agujero sigue siendo un agujero
|
|
23
|
+
* adentro del archivo.
|
|
24
|
+
*
|
|
25
|
+
* No hace fórmulas, ni colores, ni bordes, ni varias hojas. El día que alguna de
|
|
26
|
+
* esas haga falta se agrega acá; ninguna cambia la forma de lo que ya está.
|
|
27
|
+
*
|
|
28
|
+
* ── Dónde termina esto y empieza el navegador ───────────────────────
|
|
29
|
+
*
|
|
30
|
+
* `writeXlsx` devuelve BYTES y no un archivo: `Uint8Array` existe en todos
|
|
31
|
+
* lados, y así lo mismo sirve para bajar un archivo, para mandarlo por la red o
|
|
32
|
+
* para escribirlo en una prueba. Bajarlo es `downloadXlsx`, que es la única
|
|
33
|
+
* función de este archivo que necesita un navegador.
|
|
34
|
+
*/
|
|
35
|
+
/** Una celda. La posición va en la celda y no en una matriz porque una grilla
|
|
36
|
+
* con agujeros es mayormente vacío, y una matriz de 288 posiciones para 40
|
|
37
|
+
* valores es una matriz que hay que rellenar con algo. */
|
|
38
|
+
export type XlsxCell = {
|
|
39
|
+
/** Desde cero, como los índices de todo lo demás. */
|
|
40
|
+
row: number;
|
|
41
|
+
column: number;
|
|
42
|
+
/** Un número entra como número: sin eso, Excel recibe texto y no suma, que es
|
|
43
|
+
* la primera cosa que alguien intenta hacer con una planilla exportada. */
|
|
44
|
+
value: string | number;
|
|
45
|
+
bold?: boolean;
|
|
46
|
+
/** El código de formato de Excel —`#,##0.00`, `0.0%`, `#,##0 "Bs."`—, que es
|
|
47
|
+
* otra cosa que una función de JavaScript: un archivo no puede llevarse una
|
|
48
|
+
* función adentro. */
|
|
49
|
+
format?: string;
|
|
50
|
+
};
|
|
51
|
+
/** Una combinación: desde dónde, y cuántas filas y columnas cubre. */
|
|
52
|
+
export type XlsxMerge = {
|
|
53
|
+
row: number;
|
|
54
|
+
column: number;
|
|
55
|
+
rows: number;
|
|
56
|
+
columns: number;
|
|
57
|
+
};
|
|
58
|
+
export type XlsxSheet = {
|
|
59
|
+
/** El nombre de la pestaña. Excel prohíbe `[]:*?/\` y más de 31 caracteres, y
|
|
60
|
+
* un nombre inválido no da un error: da un archivo que no abre. Se recorta
|
|
61
|
+
* acá. */
|
|
62
|
+
name: string;
|
|
63
|
+
cells: readonly XlsxCell[];
|
|
64
|
+
merges?: readonly XlsxMerge[];
|
|
65
|
+
/** El ancho de cada columna, en caracteres. Faltantes = el ancho por omisión. */
|
|
66
|
+
widths?: readonly number[];
|
|
67
|
+
/** Cuántas filas de arriba y columnas de la izquierda se quedan quietas al
|
|
68
|
+
* desplazarse. Es lo mismo que hace `sticky` en la grilla, y por la misma
|
|
69
|
+
* razón: un número sin su rótulo es un número suelto. */
|
|
70
|
+
freeze?: {
|
|
71
|
+
rows: number;
|
|
72
|
+
columns: number;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
/** El nombre de una columna en la notación de Excel: 0 → A, 25 → Z, 26 → AA. */
|
|
76
|
+
export declare function columnName(index: number): string;
|
|
77
|
+
/** Los bytes de un `.xlsx` con una hoja. */
|
|
78
|
+
export declare function writeXlsx(sheet: XlsxSheet): Uint8Array<ArrayBuffer>;
|
|
79
|
+
/**
|
|
80
|
+
* Bajar los bytes como archivo.
|
|
81
|
+
*
|
|
82
|
+
* Es la única función de este archivo que necesita un navegador, y por eso está
|
|
83
|
+
* separada de `writeXlsx`: lo que se escribe y lo que se baja son dos cosas, y
|
|
84
|
+
* del otro lado —el servidor, un teléfono, una prueba— la segunda no existe.
|
|
85
|
+
*/
|
|
86
|
+
export declare function downloadXlsx(name: string, bytes: Uint8Array): void;
|
|
Binary file
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context: the package is four levels, composed bottom-up, and each level only imports
|
|
3
|
+
* from the ones below:
|
|
4
|
+
*
|
|
5
|
+
* foundations the decisions — tokens, copy, density, surfaces, slots
|
|
6
|
+
* primitives a piece that does not know which screen it is on
|
|
7
|
+
* components primitives composed to answer one question of the product
|
|
8
|
+
* views the two macros: one record (`Record`), or N records (`List`)
|
|
9
|
+
*
|
|
10
|
+
* Each level is also its own entry (`@sincpro/web-ui/primitives`, …), so what a level
|
|
11
|
+
* offers is one import away. What a family makes public is what its `index.ts` exports.
|
|
12
|
+
*
|
|
13
|
+
* If something needs to know what an invoice, a dataset or a customer is, it does not
|
|
14
|
+
* belong here: that is domain, and it lives in the application.
|
|
15
|
+
*/
|
|
16
|
+
export * from "./components/index.js";
|
|
17
|
+
export * from "./foundations/index.js";
|
|
18
|
+
export * from "./primitives/index.js";
|
|
19
|
+
export * from "./views/index.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context: the package is four levels, composed bottom-up, and each level only imports
|
|
3
|
+
* from the ones below:
|
|
4
|
+
*
|
|
5
|
+
* foundations the decisions — tokens, copy, density, surfaces, slots
|
|
6
|
+
* primitives a piece that does not know which screen it is on
|
|
7
|
+
* components primitives composed to answer one question of the product
|
|
8
|
+
* views the two macros: one record (`Record`), or N records (`List`)
|
|
9
|
+
*
|
|
10
|
+
* Each level is also its own entry (`@sincpro/web-ui/primitives`, …), so what a level
|
|
11
|
+
* offers is one import away. What a family makes public is what its `index.ts` exports.
|
|
12
|
+
*
|
|
13
|
+
* If something needs to know what an invoice, a dataset or a customer is, it does not
|
|
14
|
+
* belong here: that is domain, and it lives in the application.
|
|
15
|
+
*/
|
|
16
|
+
export * from "./components/index.js";
|
|
17
|
+
export * from "./foundations/index.js";
|
|
18
|
+
export * from "./primitives/index.js";
|
|
19
|
+
export * from "./views/index.js";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Tone } from "../../foundations/types.js";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
/**
|
|
4
|
+
* Context: the diagnosis was not a lack of ornaments, it was that a view was a
|
|
5
|
+
* pile of `<div className="flex flex-col gap-3">` with no hierarchy — the lines,
|
|
6
|
+
* the taxes and the payments floated at the same height and nothing said where one
|
|
7
|
+
* ends and the other begins. In a 1.200 px panel that reads as a loose sheet.
|
|
8
|
+
*
|
|
9
|
+
* The block has an edge (a hair of border and the radius of the scale, not a
|
|
10
|
+
* shadow: over the canvas a shadow alone looks blurry) and its title lives ON the
|
|
11
|
+
* border, not floating above it.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* What state whatever this section asks for or shows is in.
|
|
15
|
+
*
|
|
16
|
+
* Context: it is the only thing worth copying from the old console — each section
|
|
17
|
+
* said «Required» or «(Incomplete)» in its header, so you could see what is
|
|
18
|
+
* missing WITHOUT opening any of them. The system doesn't know what «incomplete»
|
|
19
|
+
* means for an invoice, so the word is put there by whoever composes.
|
|
20
|
+
*/
|
|
21
|
+
export type BlockStatus = {
|
|
22
|
+
label: string;
|
|
23
|
+
tone?: Tone;
|
|
24
|
+
};
|
|
25
|
+
export type BlockProps = {
|
|
26
|
+
/** Without a title the block is only the box: it serves to group without
|
|
27
|
+
* naming. */
|
|
28
|
+
title?: string;
|
|
29
|
+
count?: number;
|
|
30
|
+
aside?: ReactNode;
|
|
31
|
+
/** What can be done with THIS block, to the right of its title. */
|
|
32
|
+
actions?: ReactNode;
|
|
33
|
+
status?: BlockStatus;
|
|
34
|
+
/** Without padding, for whatever already brings its own frame: a table inside a
|
|
35
|
+
* box with borders is two frames arguing. */
|
|
36
|
+
flush?: boolean;
|
|
37
|
+
children: ReactNode;
|
|
38
|
+
};
|
|
39
|
+
export declare function Block({ title, count, aside, actions, status, flush, children, }: BlockProps): import("react").JSX.Element;
|
|
40
|
+
/**
|
|
41
|
+
* A cut in the page: between two groups of fields, or between a sheet of
|
|
42
|
+
* facts and the table that hangs off them.
|
|
43
|
+
*
|
|
44
|
+
* Without a label it is a hairline. With one it is Odoo's separator — the
|
|
45
|
+
* word names what starts, the line says the previous group ended. `FormSection`
|
|
46
|
+
* is a GROUP of fields; this is what goes BETWEEN groups. A block with a
|
|
47
|
+
* border is a third thing: a region, not a cut.
|
|
48
|
+
*/
|
|
49
|
+
export declare function Rule({ label }: {
|
|
50
|
+
label?: string;
|
|
51
|
+
}): import("react").JSX.Element;
|
|
52
|
+
/**
|
|
53
|
+
* `DATOS ── 3`. The title of a section and nothing else.
|
|
54
|
+
*
|
|
55
|
+
* Context: proportional and not monospaced — it is a written title, at the
|
|
56
|
+
* body size, in medium ink. The count is tabular, because it is a figure.
|
|
57
|
+
*
|
|
58
|
+
* The `aside` goes next to the title and not pushed to the opposite edge: with
|
|
59
|
+
* `justify-between`, «El vistazo» and «20 de 1.000 filas» ended up half a screen
|
|
60
|
+
* apart and the phrase read as split in two.
|
|
61
|
+
*/
|
|
62
|
+
export declare function SectionHeader({ title, count, aside, }: {
|
|
63
|
+
title: string;
|
|
64
|
+
count?: number;
|
|
65
|
+
aside?: ReactNode;
|
|
66
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Tag } from "../tag/Tag.js";
|
|
3
|
+
export function Block({ title, count, aside, actions, status, flush = false, children, }) {
|
|
4
|
+
const withHeader = title !== undefined || actions !== undefined || status !== undefined;
|
|
5
|
+
return (_jsxs("section", { className: "min-w-0 rounded-box border border-line bg-surface", children: [!withHeader ? null : (_jsxs("header", { className: "flex min-w-0 flex-wrap items-baseline gap-x-3 gap-y-1 border-b border-line px-3 py-2", children: [title === undefined ? null : (_jsx(SectionHeader, { title: title, count: count, aside: aside })), status === undefined ? null : (_jsx(Tag, { tone: status.tone ?? "neutral", children: status.label })), actions === undefined ? null : (_jsx("div", { className: "ml-auto flex flex-wrap items-center gap-1", children: actions }))] })), _jsx("div", { className: flush ? "" : "px-3 py-2.5", children: children })] }));
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A cut in the page: between two groups of fields, or between a sheet of
|
|
9
|
+
* facts and the table that hangs off them.
|
|
10
|
+
*
|
|
11
|
+
* Without a label it is a hairline. With one it is Odoo's separator — the
|
|
12
|
+
* word names what starts, the line says the previous group ended. `FormSection`
|
|
13
|
+
* is a GROUP of fields; this is what goes BETWEEN groups. A block with a
|
|
14
|
+
* border is a third thing: a region, not a cut.
|
|
15
|
+
*/
|
|
16
|
+
export function Rule({ label }) {
|
|
17
|
+
if (label === undefined) {
|
|
18
|
+
return _jsx("hr", { className: "border-0 border-t border-line" });
|
|
19
|
+
}
|
|
20
|
+
return (_jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [_jsx("span", { className: "shrink-0 text-micro font-medium text-muted", children: label }), _jsx("span", { className: "h-px min-w-0 flex-1 bg-line", "aria-hidden": true })] }));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* `DATOS ── 3`. The title of a section and nothing else.
|
|
24
|
+
*
|
|
25
|
+
* Context: proportional and not monospaced — it is a written title, at the
|
|
26
|
+
* body size, in medium ink. The count is tabular, because it is a figure.
|
|
27
|
+
*
|
|
28
|
+
* The `aside` goes next to the title and not pushed to the opposite edge: with
|
|
29
|
+
* `justify-between`, «El vistazo» and «20 de 1.000 filas» ended up half a screen
|
|
30
|
+
* apart and the phrase read as split in two.
|
|
31
|
+
*/
|
|
32
|
+
export function SectionHeader({ title, count, aside, }) {
|
|
33
|
+
return (_jsxs("div", { className: "flex flex-wrap items-baseline gap-x-3 gap-y-1", children: [_jsxs("h2", { className: "text-meta font-medium text-ink", children: [title, count === undefined ? null : (_jsxs(_Fragment, { children: [_jsx("span", { className: "mx-1.5 text-line-strong", children: "\u2500\u2500" }), _jsx("span", { className: "tabular-nums", children: count })] }))] }), aside === undefined ? null : (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": true, className: "text-meta text-line-strong", children: "\u00B7" }), aside] }))] }));
|
|
34
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export declare function Line({ start, center, end,
|
|
3
|
+
/**
|
|
4
|
+
* Lo que PIDE cada lado antes de que la línea se parta. Los dos piden lo
|
|
5
|
+
* mismo —es lo que centra el centro— así que es un solo valor y no dos.
|
|
6
|
+
*/
|
|
7
|
+
asks,
|
|
8
|
+
/** Lo que pide el centro. `auto` es «lo que mida»; un campo de búsqueda pide
|
|
9
|
+
* su ancho tope, que es lo que hace que no se estire a 700 px. */
|
|
10
|
+
centerAsks, gap, align, }: {
|
|
11
|
+
start?: ReactNode;
|
|
12
|
+
center?: ReactNode;
|
|
13
|
+
end?: ReactNode;
|
|
14
|
+
asks?: string;
|
|
15
|
+
centerAsks?: string;
|
|
16
|
+
gap?: string;
|
|
17
|
+
align?: string;
|
|
18
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/* ==================================================================== *
|
|
3
|
+
* LA LÍNEA DE TRES ZONAS — y por qué el centro se centra contra la LÍNEA.
|
|
4
|
+
*
|
|
5
|
+
* Es la forma de las dos bandas del producto: la del registro —de dónde
|
|
6
|
+
* vengo · lo que cuelga de esto · cuál de ochenta soy— y la de la lista —de
|
|
7
|
+
* dónde vengo · qué estoy buscando · qué página—. Las dos tienen el mismo
|
|
8
|
+
* problema y por eso tienen una sola solución.
|
|
9
|
+
*
|
|
10
|
+
* ── El problema: el centro no estaba en el centro ───────────────────
|
|
11
|
+
*
|
|
12
|
+
* Con `mx-auto`, o con una grilla `auto 1fr max-content`, el centro queda
|
|
13
|
+
* donde SOBRA lugar. Y entonces un nombre de cincuenta caracteres a la
|
|
14
|
+
* izquierda —que en este producto es lo normal— empuja los botones contra el
|
|
15
|
+
* borde derecho, y la misma pantalla con un nombre corto los dibuja en otro
|
|
16
|
+
* lado. Dos registros seguidos ponen sus controles en dos lugares distintos:
|
|
17
|
+
* eso no es un centro, es un resto.
|
|
18
|
+
*
|
|
19
|
+
* ── La regla: los dos lados PIDEN lo mismo ──────────────────────────
|
|
20
|
+
*
|
|
21
|
+
* Los lados piden el mismo ancho y crecen parejo, así que lo que sobra se
|
|
22
|
+
* reparte en dos mitades iguales y el centro cae en el medio de la línea, con
|
|
23
|
+
* o sin migas, con o sin paginador. Lo que no entra en una mitad se recorta
|
|
24
|
+
* adentro de su mitad —para eso `min-w-0`— en vez de empujar al vecino.
|
|
25
|
+
*
|
|
26
|
+
* ── Y se parte sola ─────────────────────────────────────────────────
|
|
27
|
+
*
|
|
28
|
+
* No hay ningún umbral acá: ni consulta de medios, ni de contenedor, ni una
|
|
29
|
+
* rama por densidad. Cada zona declara lo que PIDE y `flex-wrap` decide: en
|
|
30
|
+
* una banda angosta el centro ya no entra al lado de las migas y baja entero
|
|
31
|
+
* al renglón siguiente, con el paginador atrás. Es lo mismo que hace una fila
|
|
32
|
+
* de lista, y por la misma razón: un umbral no sabe si la línea trae tres
|
|
33
|
+
* contadores o nueve.
|
|
34
|
+
* ==================================================================== */
|
|
35
|
+
export function Line({ start, center, end,
|
|
36
|
+
/**
|
|
37
|
+
* Lo que PIDE cada lado antes de que la línea se parta. Los dos piden lo
|
|
38
|
+
* mismo —es lo que centra el centro— así que es un solo valor y no dos.
|
|
39
|
+
*/
|
|
40
|
+
asks = "var(--container-trail)",
|
|
41
|
+
/** Lo que pide el centro. `auto` es «lo que mida»; un campo de búsqueda pide
|
|
42
|
+
* su ancho tope, que es lo que hace que no se estire a 700 px. */
|
|
43
|
+
centerAsks = "auto", gap = "gap-x-4 gap-y-2", align = "items-center", }) {
|
|
44
|
+
return (_jsxs("div", { className: `flex min-w-0 flex-wrap ${align} ${gap}`, children: [_jsx("div", { className: "flex min-w-0 flex-1 items-center", style: { flexBasis: asks }, children: start }), _jsx("div", { className: "flex min-w-0 shrink items-center justify-center", style: { flexBasis: centerAsks, flexGrow: 0 }, children: center }), _jsx("div", { className: "flex min-w-0 flex-1 items-center justify-end", style: { flexBasis: asks }, children: end })] }));
|
|
45
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Context: the rule that decides whether two sections go side by side is
|
|
4
|
+
* DEPENDENCY, not space. Two that don't govern each other —the invoice lines
|
|
5
|
+
* and its payments— go side by side; two that do —choosing the customer and then
|
|
6
|
+
* its price list— go stacked, because the vertical order is the only thing that says which
|
|
7
|
+
* one comes first.
|
|
8
|
+
*
|
|
9
|
+
* That is why it is a grid and not a `flex-wrap`: wrapping arranges by available
|
|
10
|
+
* width, which is a decision about space.
|
|
11
|
+
*
|
|
12
|
+
* And it asks `@container` and not `md:`: with four panels open each one measures
|
|
13
|
+
* 380 px on a 1.600 screen, and a window rule would put two 190 px columns inside
|
|
14
|
+
* each panel. **Whoever mounts the view has to declare `@container` on its
|
|
15
|
+
* container** — the composer already does.
|
|
16
|
+
*/
|
|
17
|
+
export declare function SectionGrid({ children,
|
|
18
|
+
/** A single column until the panel is truly large. For sections with a table
|
|
19
|
+
* inside: two 300 px tables don't read better than one 600 px one. */
|
|
20
|
+
wide, }: {
|
|
21
|
+
children: ReactNode;
|
|
22
|
+
wide?: boolean;
|
|
23
|
+
}): import("react").JSX.Element;
|
|
24
|
+
/** A section that takes up both columns: a wide table, the glance at twelve
|
|
25
|
+
* columns. Without this you would have to take it out of the grid and set up
|
|
26
|
+
* another one below, which is how a screen ends up with three grids and none of
|
|
27
|
+
* them aligned. */
|
|
28
|
+
export declare function FullWidth({ children }: {
|
|
29
|
+
children: ReactNode;
|
|
30
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Context: the rule that decides whether two sections go side by side is
|
|
4
|
+
* DEPENDENCY, not space. Two that don't govern each other —the invoice lines
|
|
5
|
+
* and its payments— go side by side; two that do —choosing the customer and then
|
|
6
|
+
* its price list— go stacked, because the vertical order is the only thing that says which
|
|
7
|
+
* one comes first.
|
|
8
|
+
*
|
|
9
|
+
* That is why it is a grid and not a `flex-wrap`: wrapping arranges by available
|
|
10
|
+
* width, which is a decision about space.
|
|
11
|
+
*
|
|
12
|
+
* And it asks `@container` and not `md:`: with four panels open each one measures
|
|
13
|
+
* 380 px on a 1.600 screen, and a window rule would put two 190 px columns inside
|
|
14
|
+
* each panel. **Whoever mounts the view has to declare `@container` on its
|
|
15
|
+
* container** — the composer already does.
|
|
16
|
+
*/
|
|
17
|
+
export function SectionGrid({ children,
|
|
18
|
+
/** A single column until the panel is truly large. For sections with a table
|
|
19
|
+
* inside: two 300 px tables don't read better than one 600 px one. */
|
|
20
|
+
wide = false, }) {
|
|
21
|
+
return (_jsx("div", { className: `grid min-w-0 gap-(--spacing-block) ${wide ? "@4xl:grid-cols-2" : "@2xl:grid-cols-2"}`, children: children }));
|
|
22
|
+
}
|
|
23
|
+
/** A section that takes up both columns: a wide table, the glance at twelve
|
|
24
|
+
* columns. Without this you would have to take it out of the grid and set up
|
|
25
|
+
* another one below, which is how a screen ends up with three grids and none of
|
|
26
|
+
* them aligned. */
|
|
27
|
+
export function FullWidth({ children }) {
|
|
28
|
+
return _jsx("div", { className: "min-w-0 @2xl:col-span-2", children: children });
|
|
29
|
+
}
|