@stll/workspace-ui 0.13.1 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -32,6 +32,25 @@ import { SortChips } from "@stll/workspace-ui/sorts";
32
32
  import { WorkspaceViewSwitcher } from "@stll/workspace-ui/view-switcher";
33
33
  ```
34
34
 
35
+ ## Formatting locale
36
+
37
+ Field values and column calculations format numbers, money and dates in the
38
+ reader's formatting locale, which can differ from the UI language that
39
+ `use-intl`'s `IntlProvider` serves messages in (an English interface with
40
+ German number formatting, say). Render them inside
41
+ `WorkspaceUiFormattingProvider`; without it they throw rather than fall back
42
+ to the UI language.
43
+
44
+ ```tsx
45
+ import { WorkspaceUiFormattingProvider } from "@stll/workspace-ui/formatting";
46
+
47
+ <IntlProvider locale="en" messages={messages} timeZone="Europe/Prague">
48
+ <WorkspaceUiFormattingProvider locale="de-DE" timeZone="Europe/Prague">
49
+ {children}
50
+ </WorkspaceUiFormattingProvider>
51
+ </IntlProvider>;
52
+ ```
53
+
35
54
  The package also exposes a root entry for code that uses several workspace
36
55
  surfaces together. Focused modules, including the responsive action toolbar,
37
56
  are intentionally available through explicit subpaths; use those subpaths to
@@ -1,6 +1,6 @@
1
1
  import { formatCalculationResult } from "./calculation-format.js";
2
2
  import { applyCalculationSelection } from "./calculation-selection.js";
3
- import { useFormatter, useLocale } from "use-intl";
3
+ import { useFormatter, useFormattingLocale } from "./formatting.js";
4
4
  import { runCalculation } from "@stll/calculations";
5
5
  import { formatMoneyCents } from "@stll/money";
6
6
  import { Button } from "@stll/ui/button";
@@ -95,7 +95,7 @@ const useCalculation = ({ kind, labels, values, scopeValues }) => {
95
95
  const ColumnCalculation = (params) => /* @__PURE__ */ jsx(CalculationSummary, { calculation: useCalculation(params) });
96
96
  const useCalculationFormatters = () => {
97
97
  const format = useFormatter();
98
- const locale = useLocale();
98
+ const locale = useFormattingLocale();
99
99
  return {
100
100
  number: (value) => format.number(value),
101
101
  money: (amountCents, currency) => formatMoneyCents({
@@ -0,0 +1,20 @@
1
+ //#region src/column-sort.d.ts
2
+ /**
3
+ * The vocabulary a table column's order is described in: which kind of value
4
+ * it orders by, and which way. The kind decides how a header names each
5
+ * direction (a date oldest first, a name A to Z, a count lowest first).
6
+ */
7
+ export declare const COLUMN_SORT_KINDS: readonly ["text", "date", "number"];
8
+ export type ColumnSortKind = (typeof COLUMN_SORT_KINDS)[number];
9
+ /** The two ways a column orders its rows. */
10
+ export declare const SORT_DIRECTIONS: readonly ["asc", "desc"];
11
+ export type SortDirection = (typeof SORT_DIRECTIONS)[number];
12
+ /**
13
+ * What each direction of each kind is called, in the reader's language: total
14
+ * over both, so every place that names an order (a header's sort items, a
15
+ * view's sort chips) reads its wording from one record the caller translates.
16
+ */
17
+ export type SortDirectionLabels = Record<ColumnSortKind, Record<SortDirection, string>>;
18
+ /** The direction a stored `desc` flag orders in. */
19
+ export declare const sortDirectionOf: (desc: boolean) => SortDirection;
20
+ //#endregion
@@ -0,0 +1,17 @@
1
+ //#region src/column-sort.ts
2
+ /**
3
+ * The vocabulary a table column's order is described in: which kind of value
4
+ * it orders by, and which way. The kind decides how a header names each
5
+ * direction (a date oldest first, a name A to Z, a count lowest first).
6
+ */
7
+ const COLUMN_SORT_KINDS = [
8
+ "text",
9
+ "date",
10
+ "number"
11
+ ];
12
+ /** The two ways a column orders its rows. */
13
+ const SORT_DIRECTIONS = ["asc", "desc"];
14
+ /** The direction a stored `desc` flag orders in. */
15
+ const sortDirectionOf = (desc) => desc ? "desc" : "asc";
16
+ //#endregion
17
+ export { COLUMN_SORT_KINDS, SORT_DIRECTIONS, sortDirectionOf };
@@ -2,9 +2,9 @@ import { appendChild, asGroup, buildLeaf, isConditionOperator, isMultiValue, lea
2
2
  import { panic } from "better-result";
3
3
  import { Button } from "@stll/ui/button";
4
4
  import { PlusIcon, XIcon } from "@stll/ui/icons";
5
+ import { createContext, use } from "react";
5
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
7
  import { cn } from "@stll/ui/utils";
7
- import { createContext, use } from "react";
8
8
  import { DatePickerPopover } from "@stll/ui/date-picker-popover";
9
9
  import { Input } from "@stll/ui/input";
10
10
  import { Select, SelectItem, SelectPopup, SelectSeparator, SelectTrigger, SelectValue } from "@stll/ui/select";
@@ -1,5 +1,5 @@
1
1
  import { GenericProperty, WorkspaceFieldContent } from "./types.js";
2
- import { useFormatter } from "use-intl";
2
+ import { useFormatter } from "./formatting.js";
3
3
  //#region src/field-value.d.ts
4
4
  export type FieldValueVariant = "default" | "table" | "kanban";
5
5
  type PropertyContentType = GenericProperty["content"]["type"];
@@ -68,5 +68,5 @@ type PendingSkeletonProps = {
68
68
  };
69
69
  export declare const PendingSkeleton: ({ contentType }: PendingSkeletonProps) => import("react").JSX.Element;
70
70
  export declare const getSelectPropertyColor: (property: GenericProperty, option: string | null) => import("@stll/ui/option-color").ColorVariants | undefined;
71
- export declare const getIntClassName: (variant: FieldValueVariant) => "text-muted-foreground bg-muted/60 rounded px-1.5 py-0.5 text-xs leading-none tabular-nums" | "block max-w-full min-w-0 truncate text-start tabular-nums" | "block min-w-0 max-w-full truncate text-start text-sm tabular-nums";
71
+ export declare const getIntClassName: (variant: FieldValueVariant) => "block max-w-full min-w-0 truncate text-start tabular-nums" | "block min-w-0 max-w-full truncate text-start text-sm tabular-nums" | "text-muted-foreground bg-muted/60 rounded px-1.5 py-0.5 text-xs leading-none tabular-nums";
72
72
  //#endregion
@@ -1,11 +1,12 @@
1
+ import { useFormatter, useFormattingLocale } from "./formatting.js";
1
2
  import { emptyColor, resolveOptionColor } from "./colors.js";
2
3
  import { getClipFieldValueLabel } from "./field-value-logic.js";
3
4
  import { Result } from "better-result";
4
- import { useFormatter, useLocale, useTranslations } from "use-intl";
5
5
  import { formatMoneyCents } from "@stll/money";
6
6
  import { SquareMinusIcon } from "@stll/ui/icons";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { Temporal } from "temporal-polyfill/full";
9
+ import { useTranslations } from "use-intl";
9
10
  import { BidiText } from "@stll/ui/bidi-text";
10
11
  import { Skeleton } from "@stll/ui/skeleton";
11
12
  import { cn } from "@stll/ui/utils";
@@ -84,7 +85,7 @@ const formatIntFieldValue = ({ content, format }) => {
84
85
  })).unwrapOr(`${format.number(content.value)} ${currency}`);
85
86
  };
86
87
  const MoneyFieldValue = ({ content, variant }) => {
87
- const locale = useLocale();
88
+ const locale = useFormattingLocale();
88
89
  return /* @__PURE__ */ jsx("span", {
89
90
  className: cn(getIntClassName(variant ?? "default")),
90
91
  children: formatMoneyCents({
@@ -0,0 +1,22 @@
1
+ import { PropsWithChildren } from "react";
2
+ import { createFormatter } from "use-intl/core";
3
+ //#region src/formatting.d.ts
4
+ type Formatter = ReturnType<typeof createFormatter>;
5
+ export type WorkspaceUiFormattingProviderProps = PropsWithChildren<{
6
+ /**
7
+ * The reader's formatting locale (region, calendar, numbering system and
8
+ * week start as `-u-` extensions), which may differ from the UI language
9
+ * the host's `IntlProvider` serves messages in.
10
+ */
11
+ locale: string;
12
+ timeZone: string;
13
+ }>;
14
+ /**
15
+ * Supplies the locale this package formats numbers, money and dates in.
16
+ * Components that format read it here rather than from `use-intl`, whose
17
+ * locale is the UI language.
18
+ */
19
+ export declare const WorkspaceUiFormattingProvider: ({ children, locale, timeZone }: WorkspaceUiFormattingProviderProps) => import("react").JSX.Element;
20
+ export declare const useFormatter: () => Formatter;
21
+ export declare const useFormattingLocale: () => string;
22
+ //#endregion
@@ -0,0 +1,33 @@
1
+ import { panic } from "better-result";
2
+ import { createContext, useContext, useMemo } from "react";
3
+ import { createFormatter } from "use-intl/core";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/formatting.tsx
6
+ const FormattingContext = createContext(void 0);
7
+ /**
8
+ * Supplies the locale this package formats numbers, money and dates in.
9
+ * Components that format read it here rather than from `use-intl`, whose
10
+ * locale is the UI language.
11
+ */
12
+ const WorkspaceUiFormattingProvider = ({ children, locale, timeZone }) => {
13
+ const formatting = useMemo(() => ({
14
+ formatter: createFormatter({
15
+ locale,
16
+ timeZone
17
+ }),
18
+ locale
19
+ }), [locale, timeZone]);
20
+ return /* @__PURE__ */ jsx(FormattingContext, {
21
+ value: formatting,
22
+ children
23
+ });
24
+ };
25
+ const useFormatting = () => {
26
+ const formatting = useContext(FormattingContext);
27
+ if (!formatting) panic("@stll/workspace-ui formats numbers and dates in the host's formatting locale; render this component inside WorkspaceUiFormattingProvider");
28
+ return formatting;
29
+ };
30
+ const useFormatter = () => useFormatting().formatter;
31
+ const useFormattingLocale = () => useFormatting().locale;
32
+ //#endregion
33
+ export { WorkspaceUiFormattingProvider, useFormatter, useFormattingLocale };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { WorkspaceViewSwitcher, WorkspaceViewSwitcherEditing, WorkspaceViewSwitcherItem, WorkspaceViewSwitcherProps, WorkspaceViewSwitcherReorder } from "./view-switcher.js";
1
2
  import { CalculationFormatters, CalculationLabels, FormatCalculationParams, FormattedCalculation, formatCalculationResult } from "./calculation-format.js";
2
3
  import { ApplyCalculationSelectionParams, CalculationSelection, applyCalculationSelection } from "./calculation-selection.js";
3
4
  import { CalculationKindPicker, CalculationKindPickerProps, CalculationPicker, CalculationPickerProps, CalculationProperty, CalculationResult, CalculationSummary, CalculationSummaryProps, ColumnCalculation, UseCalculationParams, WorkspaceCalculationLabels, useCalculation } from "./calculations.js";
@@ -7,11 +8,11 @@ import { PropertyIcon, PropertyIconType } from "./property-icon.js";
7
8
  import { CONDITION_OPERATORS, ConditionOperator, FieldOption, FieldOptionChoice, FieldValueType, ValueEditorKind, appendChild, asGroup, buildLeaf, fieldForNode, isConditionOperator, isMultiValue, leafFromField, leafOperand, leafOperator, leafValueList, leafValueString, operandsEqual, operatorsFor, removeChild, replaceChild, valueEditorFor } from "./conditions/logic.js";
8
9
  import { ConditionBuilder, ConditionBuilderLabels, ConditionCapabilities, FormulaCellRenderCtx, ValueEditorRenderCtx } from "./conditions/builder.js";
9
10
  import { getClipFieldValueLabel } from "./field-value-logic.js";
11
+ import { WorkspaceUiFormattingProvider, WorkspaceUiFormattingProviderProps } from "./formatting.js";
10
12
  import { FieldValue, IntFieldValue, MoneyFieldValue, PersonFieldValue } from "./field-value.js";
11
- import { SortChips, SortChipsLabels, SortChipsProps, SortDescriptor, SortableProperty, sortDirectionHint } from "./sorts.js";
13
+ import { SortChips, SortChipsLabels, SortChipsProps, SortDescriptor, SortableProperty } from "./sorts.js";
12
14
  import { TableSkeletonRows } from "./table-skeleton-rows.js";
13
15
  import { CreateWorkspaceKanbanSchemaParams, KANBAN_EMPTY_GROUP_VISIBILITIES, KANBAN_SAVED_VIEW_STATE_VERSION, KanbanBoardPresentation, KanbanEmptyGroupVisibility, KanbanPresentedBand, KanbanPresentedLane, KanbanSavedAxisState, KanbanSavedGroupAxisState, KanbanSavedGroupReference, KanbanSavedSubgroupState, KanbanSavedViewState, KanbanSavedViewStateV1, ResolveWorkspaceKanbanViewParams, ResolvedWorkspaceKanbanView, WorkspaceKanbanBuiltInGroupLabel, WorkspaceKanbanGroupingChoice, WorkspaceKanbanGroupingPickerLabels, WorkspaceKanbanGroupingPickerProps, WorkspaceKanbanProperty, createWorkspaceKanbanSchema, getWorkspaceKanbanGroupingChoices, normalizeKanbanSavedViewState, presentKanbanBoard, resolveWorkspaceKanbanView } from "./kanban-view.js";
14
16
  import { WorkspaceKanbanGroupingPicker } from "./kanban-grouping-picker.js";
15
- import { WorkspaceViewSwitcher, WorkspaceViewSwitcherEditing, WorkspaceViewSwitcherItem, WorkspaceViewSwitcherProps, WorkspaceViewSwitcherReorder } from "./view-switcher.js";
16
17
  import { WorkspaceFrame, WorkspaceFrameEndRail, WorkspaceFrameInspector, WorkspaceFrameNavigation, WorkspaceFrameNavigationItem, WorkspaceFrameProps, WorkspaceFrameTopBar } from "./workspace-frame.js";
17
- 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, 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, replaceChild, resolveOptionColor, resolveWorkspaceKanbanView, sortDirectionHint, useCalculation, valueEditorFor };
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, WorkspaceUiFormattingProvider, type WorkspaceUiFormattingProviderProps, 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, replaceChild, resolveOptionColor, resolveWorkspaceKanbanView, useCalculation, valueEditorFor };
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { formatCalculationResult } from "./calculation-format.js";
2
2
  import { applyCalculationSelection } from "./calculation-selection.js";
3
+ import { WorkspaceUiFormattingProvider } from "./formatting.js";
3
4
  import { CalculationKindPicker, CalculationPicker, CalculationSummary, ColumnCalculation, useCalculation } from "./calculations.js";
4
5
  import { emptyColor, optionColors, resolveOptionColor } from "./colors.js";
5
6
  import { getClipFieldValueLabel } from "./field-value-logic.js";
@@ -7,11 +8,11 @@ import { FieldValue, IntFieldValue, MoneyFieldValue, PersonFieldValue } from "./
7
8
  import { CONDITION_OPERATORS, appendChild, asGroup, buildLeaf, fieldForNode, isConditionOperator, isMultiValue, leafFromField, leafOperand, leafOperator, leafValueList, leafValueString, operandsEqual, operatorsFor, removeChild, replaceChild, valueEditorFor } from "./conditions/logic.js";
8
9
  import { ConditionBuilder } from "./conditions/builder.js";
9
10
  import { PropertyIcon } from "./property-icon.js";
10
- import { SortChips, sortDirectionHint } from "./sorts.js";
11
+ import { SortChips } from "./sorts.js";
11
12
  import { TableSkeletonRows } from "./table-skeleton-rows.js";
12
13
  import { FIELD_CONTENT_TYPES } from "./types.js";
13
14
  import { KANBAN_EMPTY_GROUP_VISIBILITIES, KANBAN_SAVED_VIEW_STATE_VERSION, createWorkspaceKanbanSchema, getWorkspaceKanbanGroupingChoices, normalizeKanbanSavedViewState, presentKanbanBoard, resolveWorkspaceKanbanView } from "./kanban-view.js";
14
15
  import { WorkspaceKanbanGroupingPicker } from "./kanban-grouping-picker.js";
15
16
  import { WorkspaceViewSwitcher } from "./view-switcher.js";
16
17
  import { WorkspaceFrame } from "./workspace-frame.js";
17
- 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, replaceChild, resolveOptionColor, resolveWorkspaceKanbanView, sortDirectionHint, useCalculation, valueEditorFor };
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, WorkspaceUiFormattingProvider, WorkspaceViewSwitcher, appendChild, applyCalculationSelection, asGroup, buildLeaf, createWorkspaceKanbanSchema, emptyColor, fieldForNode, formatCalculationResult, getClipFieldValueLabel, getWorkspaceKanbanGroupingChoices, isConditionOperator, isMultiValue, leafFromField, leafOperand, leafOperator, leafValueList, leafValueString, normalizeKanbanSavedViewState, operandsEqual, operatorsFor, optionColors, presentKanbanBoard, removeChild, replaceChild, resolveOptionColor, resolveWorkspaceKanbanView, useCalculation, valueEditorFor };
package/dist/sorts.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { ColumnSortKind, SortDirectionLabels } from "./column-sort.js";
1
2
  import { PropertyIconType } from "./property-icon.js";
2
3
  //#region src/sorts.d.ts
3
4
  /** One sort a view carries. */
@@ -10,12 +11,16 @@ export type SortableProperty = {
10
11
  id: string;
11
12
  name: string;
12
13
  type: PropertyIconType;
14
+ /** What the property orders by, which decides what its chip calls each direction. */
15
+ sortKind: ColumnSortKind;
13
16
  };
14
17
  export type SortChipsLabels = {
15
18
  /** Accessible name of the "add a sort" trigger. */
16
19
  add: string;
17
20
  /** Accessible name of a chip's remove button. */
18
21
  remove: string;
22
+ /** What a chip calls its direction, per kind: the header menu's wording. */
23
+ directions: SortDirectionLabels;
19
24
  };
20
25
  export type SortChipsProps = {
21
26
  sorts: readonly SortDescriptor[];
@@ -37,10 +42,4 @@ export type SortChipsProps = {
37
42
  * draws.
38
43
  */
39
44
  export declare const SortChips: ({ sorts, properties, onUpdate, labels, maxSorts }: SortChipsProps) => import("react").JSX.Element;
40
- /**
41
- * What ascending means depends on what is being sorted: A→Z for words, 1→9 for
42
- * numbers, an arrow for dates. A type with no idiom falls back to the arrow
43
- * icon, which is why this returns null rather than a default string.
44
- */
45
- export declare const sortDirectionHint: (propertyType: string | undefined, desc: boolean) => string | null;
46
45
  //#endregion
package/dist/sorts.js CHANGED
@@ -1,6 +1,7 @@
1
+ import { sortDirectionOf } from "./column-sort.js";
1
2
  import { PropertyIcon } from "./property-icon.js";
2
3
  import { Button } from "@stll/ui/button";
3
- import { ArrowDownIcon, ArrowUpDownIcon, ArrowUpIcon, XIcon } from "@stll/ui/icons";
4
+ import { ArrowUpDownIcon, XIcon } from "@stll/ui/icons";
4
5
  import { Menu, MenuItem, MenuPopup, MenuTrigger } from "@stll/ui/menu";
5
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
7
  //#region src/sorts.tsx
@@ -27,7 +28,7 @@ const SortChips = ({ sorts, properties, onUpdate, labels, maxSorts }) => /* @__P
27
28
  } : candidate));
28
29
  },
29
30
  propertyName: property.name,
30
- propertyType: property.type
31
+ sortKind: property.sortKind
31
32
  }, sort.propertyId);
32
33
  }), /* @__PURE__ */ jsx(AddSortButton, {
33
34
  disabled: maxSorts !== void 0 && sorts.length >= maxSorts,
@@ -36,51 +37,24 @@ const SortChips = ({ sorts, properties, onUpdate, labels, maxSorts }) => /* @__P
36
37
  properties,
37
38
  sortedPropertyIds: new Set(sorts.map((sort) => sort.propertyId))
38
39
  })] });
39
- /**
40
- * What ascending means depends on what is being sorted: A→Z for words, 1→9 for
41
- * numbers, an arrow for dates. A type with no idiom falls back to the arrow
42
- * icon, which is why this returns null rather than a default string.
43
- */
44
- const sortDirectionHint = (propertyType, desc) => {
45
- if (!propertyType) return null;
46
- switch (propertyType) {
47
- case "text":
48
- case "single-select":
49
- case "multi-select":
50
- case "file":
51
- case "person": return desc ? "Z→A" : "A→Z";
52
- case "int":
53
- case "money": return desc ? "9→1" : "1→9";
54
- case "date": return desc ? "↓" : "↑";
55
- default: return null;
56
- }
57
- };
58
- const SortChip = ({ propertyName, propertyType, desc, onToggle, onRemove, labels }) => {
59
- const SortIcon = desc ? ArrowDownIcon : ArrowUpIcon;
60
- const hint = sortDirectionHint(propertyType, desc);
61
- return /* @__PURE__ */ jsxs("div", {
62
- className: "bg-muted/50 flex items-center rounded-md border",
63
- children: [/* @__PURE__ */ jsxs(Button, {
64
- onClick: onToggle,
65
- size: "xs",
66
- variant: "ghost",
67
- children: [
68
- !hint && /* @__PURE__ */ jsx(SortIcon, {}),
69
- propertyName,
70
- hint && /* @__PURE__ */ jsx("span", {
71
- className: "text-muted-foreground",
72
- children: hint
73
- })
74
- ]
75
- }), /* @__PURE__ */ jsx(Button, {
76
- "aria-label": labels.remove,
77
- onClick: onRemove,
78
- size: "icon-xs",
79
- variant: "ghost",
80
- children: /* @__PURE__ */ jsx(XIcon, {})
40
+ const SortChip = ({ propertyName, sortKind, desc, onToggle, onRemove, labels }) => /* @__PURE__ */ jsxs("div", {
41
+ className: "bg-muted/50 flex items-center rounded-md border",
42
+ children: [/* @__PURE__ */ jsxs(Button, {
43
+ onClick: onToggle,
44
+ size: "xs",
45
+ variant: "ghost",
46
+ children: [propertyName, /* @__PURE__ */ jsx("span", {
47
+ className: "text-muted-foreground",
48
+ children: labels.directions[sortKind][sortDirectionOf(desc)]
81
49
  })]
82
- });
83
- };
50
+ }), /* @__PURE__ */ jsx(Button, {
51
+ "aria-label": labels.remove,
52
+ onClick: onRemove,
53
+ size: "icon-xs",
54
+ variant: "ghost",
55
+ children: /* @__PURE__ */ jsx(XIcon, {})
56
+ })]
57
+ });
84
58
  const AddSortButton = ({ properties, sortedPropertyIds, onAdd, labels, disabled }) => /* @__PURE__ */ jsxs(Menu, { children: [/* @__PURE__ */ jsx(MenuTrigger, {
85
59
  "aria-label": labels.add,
86
60
  disabled,
@@ -98,4 +72,4 @@ const AddSortButton = ({ properties, sortedPropertyIds, onAdd, labels, disabled
98
72
  children: [/* @__PURE__ */ jsx(PropertyIcon, { type: property.type }), property.name]
99
73
  }, property.id)) })] });
100
74
  //#endregion
101
- export { SortChips, sortDirectionHint };
75
+ export { SortChips };
@@ -2,9 +2,9 @@
2
2
  import { Button } from "@stll/ui/button";
3
3
  import { EllipsisVerticalIcon } from "@stll/ui/icons";
4
4
  import { Menu, MenuPopup, MenuTrigger } from "@stll/ui/menu";
5
+ import { useCallback, useEffect, useRef, useState } from "react";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  import { cn } from "@stll/ui/utils";
7
- import { useCallback, useEffect, useRef, useState } from "react";
8
8
  import { attachClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge/attach-closest-edge";
9
9
  import { extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge/extract-closest-edge";
10
10
  import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/adapter/element-adapter";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stll/workspace-ui",
3
- "version": "0.13.1",
3
+ "version": "0.14.1",
4
4
  "description": "Reusable workspace presentation components and view helpers for Stella.",
5
5
  "keywords": [
6
6
  "calculations",
@@ -47,6 +47,10 @@
47
47
  "types": "./dist/colors.d.ts",
48
48
  "import": "./dist/colors.js"
49
49
  },
50
+ "./column-sort": {
51
+ "types": "./dist/column-sort.d.ts",
52
+ "import": "./dist/column-sort.js"
53
+ },
50
54
  "./conditions": {
51
55
  "types": "./dist/conditions/index.d.ts",
52
56
  "import": "./dist/conditions/index.js"
@@ -63,6 +67,10 @@
63
67
  "types": "./dist/field-value-logic.d.ts",
64
68
  "import": "./dist/field-value-logic.js"
65
69
  },
70
+ "./formatting": {
71
+ "types": "./dist/formatting.d.ts",
72
+ "import": "./dist/formatting.js"
73
+ },
66
74
  "./kanban-grouping-picker": {
67
75
  "types": "./dist/kanban-grouping-picker.d.ts",
68
76
  "import": "./dist/kanban-grouping-picker.js"
@@ -122,7 +130,7 @@
122
130
  "@stll/calculations": "^0.1.3",
123
131
  "@stll/conditions": "^0.4.0",
124
132
  "@stll/money": "^0.3.1",
125
- "@stll/ui": "^0.52.0",
133
+ "@stll/ui": "^0.54.0",
126
134
  "better-result": "3.0.1",
127
135
  "temporal-polyfill": "1.0.5",
128
136
  "use-intl": "4.14.9"
@@ -130,7 +138,7 @@
130
138
  "devDependencies": {
131
139
  "@atlaskit/pragmatic-drag-and-drop": "^4.0.0",
132
140
  "@atlaskit/pragmatic-drag-and-drop-hitbox": "^3.0.0",
133
- "@base-ui/react": "1.8.0",
141
+ "@base-ui/react": "1.9.0",
134
142
  "@stll/property-testing": "0.0.0",
135
143
  "@stll/typescript-config": "0.0.0",
136
144
  "@tanstack/react-table": "9.3.1",
@@ -141,7 +149,8 @@
141
149
  "react": "^19.3.0",
142
150
  "react-dom": "^19.3.0",
143
151
  "tailwindcss": "4.3.3",
144
- "tsdown": "0.23.0"
152
+ "tsdown": "0.23.0",
153
+ "tsrs": "0.18.0-ts7.1.0-dev.20260929"
145
154
  },
146
155
  "peerDependencies": {
147
156
  "@atlaskit/pragmatic-drag-and-drop": "^4.0.0",