@stll/workspace-ui 0.9.1 → 0.10.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/dist/calculation-format.d.ts +1 -24
- package/dist/calculation-format.js +3 -41
- package/dist/calculations.js +2 -1
- package/dist/field-value.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/kanban-view.js +1 -1
- package/dist/view-switcher.js +15 -6
- package/package.json +6 -6
|
@@ -27,28 +27,5 @@ type FormatCalculationParams = {
|
|
|
27
27
|
labels: CalculationLabels;
|
|
28
28
|
};
|
|
29
29
|
declare const formatCalculationResult: ({ result, formatters, labels }: FormatCalculationParams) => FormattedCalculation;
|
|
30
|
-
/**
|
|
31
|
-
* How many minor units make a major one, for this currency: 100 for CZK, 1 for
|
|
32
|
-
* JPY, 1000 for KWD. It is a property of the currency and not of the reader, so
|
|
33
|
-
* the lookup is deliberately locale-independent.
|
|
34
|
-
*
|
|
35
|
-
* A malformed code makes the `Intl.NumberFormat` constructor throw, before any
|
|
36
|
-
* `?? 2` on its result could help, so the fallback has to wrap the call.
|
|
37
|
-
*/
|
|
38
|
-
declare const currencyMinorUnitDigits: (currency: string) => number;
|
|
39
|
-
type FormatMoneyCentsParams = {
|
|
40
|
-
amountCents: number;
|
|
41
|
-
currency: string;
|
|
42
|
-
locale: string;
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* Money is stored in minor units, and how many of them make a major one is a
|
|
46
|
-
* property of the currency. Ask the currency rather than assuming a hundred.
|
|
47
|
-
*
|
|
48
|
-
* A code `Intl` rejects falls back to the amount beside the raw code: a column
|
|
49
|
-
* showing "1500 A1C" is wrong-looking data, which is the truth, where a thrown
|
|
50
|
-
* RangeError would take the whole board down with it.
|
|
51
|
-
*/
|
|
52
|
-
declare const formatMoneyCents: ({ amountCents, currency, locale }: FormatMoneyCentsParams) => string;
|
|
53
30
|
//#endregion
|
|
54
|
-
export { CalculationFormatters, CalculationLabels, FormatCalculationParams,
|
|
31
|
+
export { CalculationFormatters, CalculationLabels, FormatCalculationParams, FormattedCalculation, formatCalculationResult };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { panic } from "better-result";
|
|
2
2
|
//#region src/calculation-format.ts
|
|
3
3
|
/**
|
|
4
4
|
* Turning a calculation result into the two strings a view shows: the compact
|
|
@@ -22,51 +22,13 @@ const formatCalculationResult = ({ result, formatters, labels }) => {
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
case "unsupported": return line(labels.kind, labels.unavailable);
|
|
25
|
-
default: return result;
|
|
25
|
+
default: return panic(`Unhandled result: ${String(result)}`);
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
|
-
/**
|
|
29
|
-
* Two, the ISO 4217 default, used when a stored code is one `Intl` will not
|
|
30
|
-
* accept. Validation at the API boundary keeps those out, but a row written
|
|
31
|
-
* before that constraint existed must still render rather than throw.
|
|
32
|
-
*/
|
|
33
|
-
const DEFAULT_MINOR_UNIT_DIGITS = 2;
|
|
34
|
-
/**
|
|
35
|
-
* How many minor units make a major one, for this currency: 100 for CZK, 1 for
|
|
36
|
-
* JPY, 1000 for KWD. It is a property of the currency and not of the reader, so
|
|
37
|
-
* the lookup is deliberately locale-independent.
|
|
38
|
-
*
|
|
39
|
-
* A malformed code makes the `Intl.NumberFormat` constructor throw, before any
|
|
40
|
-
* `?? 2` on its result could help, so the fallback has to wrap the call.
|
|
41
|
-
*/
|
|
42
|
-
const currencyMinorUnitDigits = (currency) => {
|
|
43
|
-
const resolved = Result.try(() => new Intl.NumberFormat("en", {
|
|
44
|
-
style: "currency",
|
|
45
|
-
currency
|
|
46
|
-
}).resolvedOptions().maximumFractionDigits);
|
|
47
|
-
if (resolved.isErr()) return DEFAULT_MINOR_UNIT_DIGITS;
|
|
48
|
-
return resolved.value ?? DEFAULT_MINOR_UNIT_DIGITS;
|
|
49
|
-
};
|
|
50
|
-
/**
|
|
51
|
-
* Money is stored in minor units, and how many of them make a major one is a
|
|
52
|
-
* property of the currency. Ask the currency rather than assuming a hundred.
|
|
53
|
-
*
|
|
54
|
-
* A code `Intl` rejects falls back to the amount beside the raw code: a column
|
|
55
|
-
* showing "1500 A1C" is wrong-looking data, which is the truth, where a thrown
|
|
56
|
-
* RangeError would take the whole board down with it.
|
|
57
|
-
*/
|
|
58
|
-
const formatMoneyCents = ({ amountCents, currency, locale }) => {
|
|
59
|
-
const major = amountCents / 10 ** currencyMinorUnitDigits(currency);
|
|
60
|
-
const formatted = Result.try(() => new Intl.NumberFormat(locale, {
|
|
61
|
-
style: "currency",
|
|
62
|
-
currency
|
|
63
|
-
}).format(major));
|
|
64
|
-
return formatted.isErr() ? `${major} ${currency}` : formatted.value;
|
|
65
|
-
};
|
|
66
28
|
const SEPARATOR = " · ";
|
|
67
29
|
const line = (kind, value) => ({
|
|
68
30
|
summary: `${kind} ${value}`,
|
|
69
31
|
breakdown: []
|
|
70
32
|
});
|
|
71
33
|
//#endregion
|
|
72
|
-
export {
|
|
34
|
+
export { formatCalculationResult };
|
package/dist/calculations.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { formatCalculationResult
|
|
1
|
+
import { formatCalculationResult } from "./calculation-format.js";
|
|
2
2
|
import { applyCalculationSelection } from "./calculation-selection.js";
|
|
3
3
|
import { CheckIcon, SigmaIcon } from "lucide-react";
|
|
4
4
|
import { useFormatter, useLocale } from "use-intl";
|
|
5
5
|
import { runCalculation } from "@stll/calculations";
|
|
6
|
+
import { formatMoneyCents } from "@stll/money";
|
|
6
7
|
import { Button } from "@stll/ui/button";
|
|
7
8
|
import { Menu, MenuItem, MenuPopup, MenuSub, MenuSubPopup, MenuSubTrigger, MenuTrigger } from "@stll/ui/menu";
|
|
8
9
|
import { Tooltip, TooltipPopup, TooltipTrigger } from "@stll/ui/tooltip";
|
package/dist/field-value.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { formatMoneyCents } from "./calculation-format.js";
|
|
2
1
|
import { emptyColor, resolveOptionColor } from "./colors.js";
|
|
3
2
|
import { getClipFieldValueLabel } from "./field-value-logic.js";
|
|
4
3
|
import { Result } from "better-result";
|
|
5
4
|
import { Loader2Icon, SquareMinusIcon } from "lucide-react";
|
|
6
5
|
import { useFormatter, useLocale, useTranslations } from "use-intl";
|
|
6
|
+
import { formatMoneyCents } from "@stll/money";
|
|
7
7
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { BidiText } from "@stll/ui/bidi-text";
|
|
9
9
|
import { Skeleton } from "@stll/ui/skeleton";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CalculationFormatters, CalculationLabels, FormatCalculationParams,
|
|
1
|
+
import { CalculationFormatters, CalculationLabels, FormatCalculationParams, FormattedCalculation, formatCalculationResult } from "./calculation-format.js";
|
|
2
2
|
import { ApplyCalculationSelectionParams, CalculationSelection, applyCalculationSelection } from "./calculation-selection.js";
|
|
3
3
|
import { CalculationKindPicker, CalculationKindPickerProps, CalculationPicker, CalculationPickerProps, CalculationProperty, CalculationResult, CalculationSummary, CalculationSummaryProps, ColumnCalculation, UseCalculationParams, WorkspaceCalculationLabels, useCalculation } from "./calculations.js";
|
|
4
4
|
import { ColorVariants, OptionColor, emptyColor, optionColors, resolveOptionColor } from "./colors.js";
|
|
@@ -15,4 +15,4 @@ import { WorkspaceKanbanGroupingPicker } from "./kanban-grouping-picker.js";
|
|
|
15
15
|
import { WorkspaceViewDirection, WorkspaceViewDropPosition, reorderWorkspaceViewIds, toWorkspaceViewDropPosition } from "./view-switcher.logic.js";
|
|
16
16
|
import { WorkspaceViewSwitcher, WorkspaceViewSwitcherEditing, WorkspaceViewSwitcherItem, WorkspaceViewSwitcherProps, WorkspaceViewSwitcherReorder } from "./view-switcher.js";
|
|
17
17
|
import { WorkspaceFrame, WorkspaceFrameEndRail, WorkspaceFrameInspector, WorkspaceFrameNavigation, WorkspaceFrameNavigationItem, WorkspaceFrameProps, WorkspaceFrameTopBar } from "./workspace-frame.js";
|
|
18
|
-
export { type ApplyCalculationSelectionParams, CONDITION_OPERATORS, type CalculationFormatters, CalculationKindPicker, type CalculationKindPickerProps, type CalculationLabels, CalculationPicker, type CalculationPickerProps, type CalculationProperty, type CalculationResult, type CalculationSelection, CalculationSummary, type CalculationSummaryProps, type ColorVariants, ColumnCalculation, ConditionBuilder, type ConditionBuilderLabels, type ConditionCapabilities, type ConditionOperator, type CreateWorkspaceKanbanSchemaParams, FIELD_CONTENT_TYPES, type FieldContent, type FieldOption, type FieldOptionChoice, FieldValue, type FieldValueType, type FormatCalculationParams, type
|
|
18
|
+
export { type ApplyCalculationSelectionParams, CONDITION_OPERATORS, type CalculationFormatters, CalculationKindPicker, type CalculationKindPickerProps, type CalculationLabels, CalculationPicker, type CalculationPickerProps, type CalculationProperty, type CalculationResult, type CalculationSelection, CalculationSummary, type CalculationSummaryProps, type ColorVariants, ColumnCalculation, ConditionBuilder, type ConditionBuilderLabels, type ConditionCapabilities, type ConditionOperator, type CreateWorkspaceKanbanSchemaParams, FIELD_CONTENT_TYPES, type FieldContent, type FieldOption, type FieldOptionChoice, FieldValue, type FieldValueType, type FormatCalculationParams, type FormattedCalculation, type FormulaCellRenderCtx, type GenericProperty, IntFieldValue, KANBAN_EMPTY_GROUP_VISIBILITIES, KANBAN_SAVED_VIEW_STATE_VERSION, type KanbanBoardPresentation, type KanbanEmptyGroupVisibility, type KanbanPresentedBand, type KanbanPresentedLane, type KanbanSavedAxisState, type KanbanSavedGroupAxisState, type KanbanSavedGroupReference, type KanbanSavedSubgroupState, type KanbanSavedViewState, type KanbanSavedViewStateV1, MoneyFieldValue, type OptionColor, PersonFieldValue, PropertyIcon, type PropertyIconType, type ResolveWorkspaceKanbanViewParams, type ResolvedWorkspaceKanbanView, SortChips, type SortChipsLabels, type SortChipsProps, type SortDescriptor, type SortableProperty, TableSkeletonRows, type UseCalculationParams, type ValueEditorKind, type ValueEditorRenderCtx, type WorkspaceCalculationLabels, type WorkspaceFieldContent, WorkspaceFrame, type WorkspaceFrameEndRail, type WorkspaceFrameInspector, type WorkspaceFrameNavigation, type WorkspaceFrameNavigationItem, type WorkspaceFrameProps, type WorkspaceFrameTopBar, type WorkspaceKanbanBuiltInGroupLabel, type WorkspaceKanbanGroupingChoice, WorkspaceKanbanGroupingPicker, type WorkspaceKanbanGroupingPickerLabels, type WorkspaceKanbanGroupingPickerProps, type WorkspaceKanbanProperty, type WorkspaceViewDirection, type WorkspaceViewDropPosition, WorkspaceViewSwitcher, type WorkspaceViewSwitcherEditing, type WorkspaceViewSwitcherItem, type WorkspaceViewSwitcherProps, type WorkspaceViewSwitcherReorder, appendChild, applyCalculationSelection, asGroup, buildLeaf, createWorkspaceKanbanSchema, emptyColor, fieldForNode, formatCalculationResult, getClipFieldValueLabel, getWorkspaceKanbanGroupingChoices, isConditionOperator, isMultiValue, leafFromField, leafOperand, leafOperator, leafValueList, leafValueString, normalizeKanbanSavedViewState, operandsEqual, operatorsFor, optionColors, presentKanbanBoard, removeChild, reorderWorkspaceViewIds, replaceChild, resolveOptionColor, resolveWorkspaceKanbanView, sortDirectionHint, toWorkspaceViewDropPosition, useCalculation, valueEditorFor };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { formatCalculationResult } from "./calculation-format.js";
|
|
2
2
|
import { applyCalculationSelection } from "./calculation-selection.js";
|
|
3
3
|
import { CalculationKindPicker, CalculationPicker, CalculationSummary, ColumnCalculation, useCalculation } from "./calculations.js";
|
|
4
4
|
import { emptyColor, optionColors, resolveOptionColor } from "./colors.js";
|
|
@@ -15,4 +15,4 @@ import { WorkspaceKanbanGroupingPicker } from "./kanban-grouping-picker.js";
|
|
|
15
15
|
import { reorderWorkspaceViewIds, toWorkspaceViewDropPosition } from "./view-switcher.logic.js";
|
|
16
16
|
import { WorkspaceViewSwitcher } from "./view-switcher.js";
|
|
17
17
|
import { WorkspaceFrame } from "./workspace-frame.js";
|
|
18
|
-
export { CONDITION_OPERATORS, CalculationKindPicker, CalculationPicker, CalculationSummary, ColumnCalculation, ConditionBuilder, FIELD_CONTENT_TYPES, FieldValue, IntFieldValue, KANBAN_EMPTY_GROUP_VISIBILITIES, KANBAN_SAVED_VIEW_STATE_VERSION, MoneyFieldValue, PersonFieldValue, PropertyIcon, SortChips, TableSkeletonRows, WorkspaceFrame, WorkspaceKanbanGroupingPicker, WorkspaceViewSwitcher, appendChild, applyCalculationSelection, asGroup, buildLeaf, createWorkspaceKanbanSchema,
|
|
18
|
+
export { CONDITION_OPERATORS, CalculationKindPicker, CalculationPicker, CalculationSummary, ColumnCalculation, ConditionBuilder, FIELD_CONTENT_TYPES, FieldValue, IntFieldValue, KANBAN_EMPTY_GROUP_VISIBILITIES, KANBAN_SAVED_VIEW_STATE_VERSION, MoneyFieldValue, PersonFieldValue, PropertyIcon, SortChips, TableSkeletonRows, WorkspaceFrame, WorkspaceKanbanGroupingPicker, WorkspaceViewSwitcher, appendChild, applyCalculationSelection, asGroup, buildLeaf, createWorkspaceKanbanSchema, emptyColor, fieldForNode, formatCalculationResult, getClipFieldValueLabel, getWorkspaceKanbanGroupingChoices, isConditionOperator, isMultiValue, leafFromField, leafOperand, leafOperator, leafValueList, leafValueString, normalizeKanbanSavedViewState, operandsEqual, operatorsFor, optionColors, presentKanbanBoard, removeChild, reorderWorkspaceViewIds, replaceChild, resolveOptionColor, resolveWorkspaceKanbanView, sortDirectionHint, toWorkspaceViewDropPosition, useCalculation, valueEditorFor };
|
package/dist/kanban-view.js
CHANGED
package/dist/view-switcher.js
CHANGED
|
@@ -21,6 +21,11 @@ const useLatestCallback = (callback) => {
|
|
|
21
21
|
};
|
|
22
22
|
const WorkspaceViewSwitcher = ({ activeViewId, ariaLabel, direction, reorder, views, addControl, editing, onViewChange, onViewContextMenu, onViewDoubleClick, renderActions, renderIcon }) => {
|
|
23
23
|
const canReorder = reorder !== null;
|
|
24
|
+
const viewTabs = views.map((view) => ({
|
|
25
|
+
view,
|
|
26
|
+
actions: renderActions?.(view)
|
|
27
|
+
}));
|
|
28
|
+
const reserveActionSpace = viewTabs.some(({ actions }) => actions !== null && actions !== void 0 && typeof actions !== "boolean");
|
|
24
29
|
const [instanceId] = useState(Symbol);
|
|
25
30
|
const [stripContainer, setStripContainer] = useState(null);
|
|
26
31
|
useEffect(() => {
|
|
@@ -47,25 +52,28 @@ const WorkspaceViewSwitcher = ({ activeViewId, ariaLabel, direction, reorder, vi
|
|
|
47
52
|
className: cn("flex min-w-0 flex-1 items-center gap-1 px-2", TOOLBAR_ROW_HEIGHT),
|
|
48
53
|
dir: direction,
|
|
49
54
|
children: [/* @__PURE__ */ jsx("div", {
|
|
50
|
-
className: "min-w-0 flex-1",
|
|
55
|
+
className: "h-full min-w-0 flex-1",
|
|
51
56
|
ref: setStripContainer,
|
|
52
57
|
children: /* @__PURE__ */ jsx(Tabs, {
|
|
58
|
+
className: "h-full gap-0",
|
|
53
59
|
onValueChange: (value) => {
|
|
54
60
|
if (typeof value === "string") onViewChange(value);
|
|
55
61
|
},
|
|
56
62
|
value: activeViewId,
|
|
57
63
|
children: /* @__PURE__ */ jsx(TabsList, {
|
|
58
64
|
"aria-label": ariaLabel,
|
|
65
|
+
className: "h-full data-[orientation=horizontal]:py-0",
|
|
59
66
|
variant: "underline",
|
|
60
|
-
children:
|
|
67
|
+
children: viewTabs.map(({ view, actions }) => {
|
|
61
68
|
if (editing?.viewId === view.id) return /* @__PURE__ */ jsxs(TabsTab, {
|
|
69
|
+
className: cn("h-full sm:h-full", reserveActionSpace ? "pe-6.5" : void 0),
|
|
62
70
|
nativeButton: false,
|
|
63
71
|
render: /* @__PURE__ */ jsx("div", {}),
|
|
64
72
|
value: view.id,
|
|
65
73
|
children: [renderIcon(view), editing.renderLabel(view)]
|
|
66
74
|
}, view.id);
|
|
67
75
|
return /* @__PURE__ */ jsx(WorkspaceViewTab, {
|
|
68
|
-
actions
|
|
76
|
+
actions,
|
|
69
77
|
canReorder,
|
|
70
78
|
direction,
|
|
71
79
|
getDragData: reorder?.getDragData,
|
|
@@ -76,6 +84,7 @@ const WorkspaceViewSwitcher = ({ activeViewId, ariaLabel, direction, reorder, vi
|
|
|
76
84
|
onDoubleClick: onViewDoubleClick,
|
|
77
85
|
onReorder: handleReorder,
|
|
78
86
|
renderIcon,
|
|
87
|
+
reserveActionSpace,
|
|
79
88
|
view
|
|
80
89
|
}, view.id);
|
|
81
90
|
})
|
|
@@ -84,7 +93,7 @@ const WorkspaceViewSwitcher = ({ activeViewId, ariaLabel, direction, reorder, vi
|
|
|
84
93
|
}), addControl]
|
|
85
94
|
});
|
|
86
95
|
};
|
|
87
|
-
const WorkspaceViewTab = ({ actions, canReorder, direction, getDragData, getDropData, isDragBlocked, instanceId, onContextMenu, onDoubleClick, onReorder, renderIcon, view }) => {
|
|
96
|
+
const WorkspaceViewTab = ({ actions, canReorder, direction, getDragData, getDropData, isDragBlocked, instanceId, onContextMenu, onDoubleClick, onReorder, renderIcon, reserveActionSpace, view }) => {
|
|
88
97
|
const [tabContainer, setTabContainer] = useState(null);
|
|
89
98
|
const [dropPosition, setDropPosition] = useState(null);
|
|
90
99
|
const canDrag = useLatestCallback(() => !isDragBlocked);
|
|
@@ -135,7 +144,7 @@ const WorkspaceViewTab = ({ actions, canReorder, direction, getDragData, getDrop
|
|
|
135
144
|
view.id
|
|
136
145
|
]);
|
|
137
146
|
return /* @__PURE__ */ jsxs("div", {
|
|
138
|
-
className: "relative flex items-center",
|
|
147
|
+
className: "relative flex h-full items-center",
|
|
139
148
|
ref: setTabContainer,
|
|
140
149
|
children: [
|
|
141
150
|
dropPosition !== null && /* @__PURE__ */ jsx("span", {
|
|
@@ -143,7 +152,7 @@ const WorkspaceViewTab = ({ actions, canReorder, direction, getDragData, getDrop
|
|
|
143
152
|
className: cn("bg-primary pointer-events-none absolute inset-y-1 z-20 w-0.5 rounded-full", dropPosition === "before" ? "start-0" : "end-0")
|
|
144
153
|
}),
|
|
145
154
|
/* @__PURE__ */ jsxs(TabsTab, {
|
|
146
|
-
className:
|
|
155
|
+
className: cn("h-full sm:h-full", reserveActionSpace ? "pe-6.5" : void 0),
|
|
147
156
|
onContextMenu: (event) => onContextMenu?.(view, event),
|
|
148
157
|
onDoubleClick: (event) => onDoubleClick?.(view, event),
|
|
149
158
|
value: view.id,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stll/workspace-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Reusable workspace presentation components and view helpers for Stella.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"calculations",
|
|
@@ -116,10 +116,10 @@
|
|
|
116
116
|
"test:property": "bun test --preload @stll/property-testing/preload $(grep -rlF 'fc.assert' src --include='*.test.ts')"
|
|
117
117
|
},
|
|
118
118
|
"dependencies": {
|
|
119
|
-
"@stll/calculations": "^0.1.
|
|
120
|
-
"@stll/conditions": "^0.3.
|
|
121
|
-
"@stll/money": "^0.
|
|
122
|
-
"@stll/ui": "^0.25.
|
|
119
|
+
"@stll/calculations": "^0.1.1",
|
|
120
|
+
"@stll/conditions": "^0.3.1",
|
|
121
|
+
"@stll/money": "^0.2.0",
|
|
122
|
+
"@stll/ui": "^0.25.1",
|
|
123
123
|
"better-result": "3.0.0",
|
|
124
124
|
"lucide-react": "1.30.0",
|
|
125
125
|
"use-intl": "4.13.5"
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
"@tanstack/react-table": "9.2.4",
|
|
134
134
|
"@types/react": "^19.2.17",
|
|
135
135
|
"@types/react-dom": "^19.2.3",
|
|
136
|
-
"bun-types": "1.4.
|
|
136
|
+
"bun-types": "1.4.2",
|
|
137
137
|
"fast-check": "^4.9.0",
|
|
138
138
|
"react": "^19.2.8",
|
|
139
139
|
"react-dom": "^19.2.8",
|