@calliopelabs/ui 0.7.0 → 0.12.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/README.md +266 -3
- package/dist/appearance/AppearancePicker.js +4 -2
- package/dist/appearance/AppearanceProvider.d.ts +10 -2
- package/dist/appearance/AppearanceProvider.js +6 -2
- package/dist/appearance/AppearanceScript.d.ts +15 -4
- package/dist/appearance/AppearanceScript.js +11 -5
- package/dist/appearance/appearance.js +1 -1
- package/dist/appearance/boot.d.ts +13 -2
- package/dist/appearance/boot.js +35 -5
- package/dist/appearance/product.d.ts +13 -0
- package/dist/appearance/product.js +2 -2
- package/dist/appearance/runtime-brand.d.ts +106 -0
- package/dist/appearance/runtime-brand.js +420 -0
- package/dist/css/appearance.js +147 -0
- package/dist/css/calliope.css +1221 -0
- package/dist/css/components.css +729 -0
- package/dist/css/tokens.css +491 -0
- package/dist/data/DefinitionList.d.ts +16 -0
- package/dist/data/DefinitionList.js +9 -0
- package/dist/data/Stat.d.ts +25 -0
- package/dist/data/Stat.js +19 -0
- package/dist/data/Tag.d.ts +21 -0
- package/dist/data/Tag.js +18 -0
- package/dist/data/types.d.ts +3 -2
- package/dist/data/use-local-table.d.ts +36 -0
- package/dist/data/use-local-table.js +127 -0
- package/dist/index.d.ts +44 -3
- package/dist/index.js +40 -1
- package/dist/nav/Nav.d.ts +2 -1
- package/dist/nav/Nav.js +34 -15
- package/dist/nav/model.d.ts +21 -0
- package/dist/page/PageHeader.d.ts +5 -3
- package/dist/page/PageHeader.js +5 -4
- package/dist/page/Panel.d.ts +19 -0
- package/dist/page/Panel.js +12 -0
- package/dist/primitives/Avatar.d.ts +37 -0
- package/dist/primitives/Avatar.js +43 -0
- package/dist/primitives/Field.d.ts +33 -0
- package/dist/primitives/Field.js +30 -0
- package/dist/primitives/Segmented.d.ts +30 -0
- package/dist/primitives/Segmented.js +20 -0
- package/dist/primitives/Select.d.ts +40 -0
- package/dist/primitives/Select.js +47 -0
- package/dist/primitives/Switch.d.ts +7 -0
- package/dist/primitives/Switch.js +8 -0
- package/dist/primitives/Textarea.d.ts +3 -0
- package/dist/primitives/Textarea.js +6 -0
- package/dist/provider/messages.d.ts +430 -0
- package/dist/provider/messages.js +666 -0
- package/dist/shell/BrandMark.d.ts +25 -3
- package/dist/shell/BrandMark.js +34 -4
- package/dist/shell/RailPanel.js +2 -2
- package/dist/shell/RailTree.js +2 -2
- package/dist/shell/Sidebar.d.ts +9 -2
- package/dist/shell/Sidebar.js +10 -4
- package/dist/shell/UserMenu.d.ts +3 -1
- package/dist/shell/UserMenu.js +3 -11
- package/dist/shell/rail-boot.d.ts +28 -0
- package/dist/shell/rail-boot.js +45 -0
- package/dist/shell/rail-state.d.ts +6 -1
- package/dist/shell/rail-state.js +18 -2
- package/dist/styles/preset.css +4 -0
- package/dist/styles/theme.css +36 -13
- package/dist/theme/css-layer.d.ts +19 -0
- package/dist/theme/css-layer.js +171 -0
- package/dist/theme/css.d.ts +1 -0
- package/dist/theme/css.js +45 -9
- package/dist/workflow/ArtifactCard.d.ts +47 -0
- package/dist/workflow/ArtifactCard.js +45 -0
- package/dist/workflow/DocumentReview.d.ts +74 -0
- package/dist/workflow/DocumentReview.js +54 -0
- package/dist/workflow/FormReview.d.ts +53 -0
- package/dist/workflow/FormReview.js +83 -0
- package/dist/workflow/GateBadge.d.ts +11 -0
- package/dist/workflow/GateBadge.js +14 -0
- package/dist/workflow/MediaReview.d.ts +63 -0
- package/dist/workflow/MediaReview.js +166 -0
- package/dist/workflow/ReviewPanel.d.ts +41 -0
- package/dist/workflow/ReviewPanel.js +59 -0
- package/dist/workflow/RunTimeline.d.ts +25 -0
- package/dist/workflow/RunTimeline.js +56 -0
- package/dist/workflow/WorkflowCard.d.ts +39 -0
- package/dist/workflow/WorkflowCard.js +56 -0
- package/dist/workflow/WorkflowGallery.d.ts +43 -0
- package/dist/workflow/WorkflowGallery.js +69 -0
- package/dist/workflow/WorkflowQuestionCard.d.ts +18 -0
- package/dist/workflow/WorkflowQuestionCard.js +78 -0
- package/dist/workflow/canvas/WorkflowCanvas.d.ts +39 -0
- package/dist/workflow/canvas/WorkflowCanvas.js +648 -0
- package/dist/workflow/definition.d.ts +408 -0
- package/dist/workflow/definition.js +411 -0
- package/dist/workflow/editor/WorkflowDiff.d.ts +17 -0
- package/dist/workflow/editor/WorkflowDiff.js +25 -0
- package/dist/workflow/editor/WorkflowImportPreview.d.ts +19 -0
- package/dist/workflow/editor/WorkflowImportPreview.js +50 -0
- package/dist/workflow/editor/WorkflowInspector.d.ts +40 -0
- package/dist/workflow/editor/WorkflowInspector.js +349 -0
- package/dist/workflow/editor/WorkflowJsonView.d.ts +16 -0
- package/dist/workflow/editor/WorkflowJsonView.js +40 -0
- package/dist/workflow/editor/WorkflowPalette.d.ts +16 -0
- package/dist/workflow/editor/WorkflowPalette.js +36 -0
- package/dist/workflow/editor/WorkflowProblems.d.ts +20 -0
- package/dist/workflow/editor/WorkflowProblems.js +51 -0
- package/dist/workflow/editor/WorkflowWorkspace.d.ts +49 -0
- package/dist/workflow/editor/WorkflowWorkspace.js +154 -0
- package/dist/workflow/gallery.d.ts +21 -0
- package/dist/workflow/gallery.js +29 -0
- package/dist/workflow/layout.d.ts +49 -0
- package/dist/workflow/layout.js +162 -0
- package/dist/workflow/model.d.ts +50 -0
- package/dist/workflow/model.js +7 -0
- package/dist/workflow/palette.d.ts +34 -0
- package/dist/workflow/palette.js +70 -0
- package/dist/workflow/portable.d.ts +162 -0
- package/dist/workflow/portable.js +547 -0
- package/dist/workflow/problems.d.ts +38 -0
- package/dist/workflow/problems.js +409 -0
- package/dist/workflow/question.d.ts +26 -0
- package/dist/workflow/question.js +1 -0
- package/dist/workflow/run.d.ts +94 -0
- package/dist/workflow/run.js +31 -0
- package/dist/workflow/workspace.d.ts +33 -0
- package/dist/workflow/workspace.js +17 -0
- package/package.json +6 -1
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { DEFAULT_PAGE_SIZE, PAGE_SIZES, } from "./types.js";
|
|
4
|
+
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: "base" });
|
|
5
|
+
function compareValues(a, b) {
|
|
6
|
+
if (a instanceof Date)
|
|
7
|
+
a = a.getTime();
|
|
8
|
+
if (b instanceof Date)
|
|
9
|
+
b = b.getTime();
|
|
10
|
+
if (typeof a === "string" && typeof b === "string")
|
|
11
|
+
return collator.compare(a, b);
|
|
12
|
+
if (typeof a === "number" && typeof b === "number")
|
|
13
|
+
return a - b;
|
|
14
|
+
if (typeof a === "boolean" && typeof b === "boolean")
|
|
15
|
+
return Number(a) - Number(b);
|
|
16
|
+
return collator.compare(String(a), String(b));
|
|
17
|
+
}
|
|
18
|
+
function toList(sort) {
|
|
19
|
+
if (!sort)
|
|
20
|
+
return [];
|
|
21
|
+
return Array.isArray(sort) ? [...sort] : [sort];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A TableController over rows already in memory, for DataTable: search,
|
|
25
|
+
* the app's filters, sort and paging, all over the whole set, so a page
|
|
26
|
+
* boundary is never wrong. For a list the server pages, implement the
|
|
27
|
+
* controller over the server (Astrolift's `useCursorTable`) instead.
|
|
28
|
+
*/
|
|
29
|
+
export function useLocalTable(rows, options = {}) {
|
|
30
|
+
const { sortBy, initialSort, searchText, filter, onClearFilters, pageSizes, loading = false, error = null, retry, } = options;
|
|
31
|
+
const [search, setSearchState] = React.useState("");
|
|
32
|
+
const [sorts, setSorts] = React.useState(() => toList(initialSort));
|
|
33
|
+
const [pageSize, setPageSizeState] = React.useState(options.pageSize ?? DEFAULT_PAGE_SIZE);
|
|
34
|
+
const [page, setPage] = React.useState(0);
|
|
35
|
+
const matched = React.useMemo(() => {
|
|
36
|
+
const needle = search.trim().toLowerCase();
|
|
37
|
+
return rows.filter((row) => (!filter || filter(row)) &&
|
|
38
|
+
(!needle || !searchText || searchText(row).toLowerCase().includes(needle)));
|
|
39
|
+
}, [rows, search, searchText, filter]);
|
|
40
|
+
const sorted = React.useMemo(() => {
|
|
41
|
+
const active = sorts.filter((s) => sortBy?.[s.key]);
|
|
42
|
+
if (active.length === 0)
|
|
43
|
+
return matched;
|
|
44
|
+
return [...matched].sort((x, y) => {
|
|
45
|
+
for (const { key, dir } of active) {
|
|
46
|
+
const read = sortBy[key];
|
|
47
|
+
const [a, b] = [read(x), read(y)];
|
|
48
|
+
const aMissing = a === null || a === undefined;
|
|
49
|
+
const bMissing = b === null || b === undefined;
|
|
50
|
+
if (aMissing || bMissing) {
|
|
51
|
+
if (aMissing && bMissing)
|
|
52
|
+
continue;
|
|
53
|
+
return aMissing ? 1 : -1;
|
|
54
|
+
}
|
|
55
|
+
const order = compareValues(a, b);
|
|
56
|
+
if (order !== 0)
|
|
57
|
+
return dir === "asc" ? order : -order;
|
|
58
|
+
}
|
|
59
|
+
return 0;
|
|
60
|
+
});
|
|
61
|
+
}, [matched, sorts, sortBy]);
|
|
62
|
+
const pages = Math.max(1, Math.ceil(sorted.length / pageSize));
|
|
63
|
+
// Rows can shrink under the page on screen (a refetch, a filter): hold it in range.
|
|
64
|
+
const pageIndex = Math.min(page, pages - 1);
|
|
65
|
+
const pageRows = React.useMemo(() => sorted.slice(pageIndex * pageSize, (pageIndex + 1) * pageSize), [sorted, pageIndex, pageSize]);
|
|
66
|
+
const isFiltered = Boolean(filter) || (Boolean(searchText) && search.trim() !== "");
|
|
67
|
+
const state = loading
|
|
68
|
+
? "loading"
|
|
69
|
+
: error
|
|
70
|
+
? "error"
|
|
71
|
+
: sorted.length > 0
|
|
72
|
+
? "ready"
|
|
73
|
+
: isFiltered
|
|
74
|
+
? "emptyFiltered"
|
|
75
|
+
: "empty";
|
|
76
|
+
const setSearch = React.useCallback((next) => {
|
|
77
|
+
setSearchState(next);
|
|
78
|
+
setPage(0);
|
|
79
|
+
}, []);
|
|
80
|
+
const setPageSize = React.useCallback((size) => {
|
|
81
|
+
setPageSizeState(size);
|
|
82
|
+
setPage(0);
|
|
83
|
+
}, []);
|
|
84
|
+
const toggleSort = React.useCallback((key, additive) => {
|
|
85
|
+
setSorts((current) => {
|
|
86
|
+
const at = current.findIndex((s) => s.key === key);
|
|
87
|
+
if (additive) {
|
|
88
|
+
if (at === -1)
|
|
89
|
+
return [...current, { key, dir: "asc" }];
|
|
90
|
+
return current.map((s, i) => i === at ? { key, dir: s.dir === "asc" ? "desc" : "asc" } : s);
|
|
91
|
+
}
|
|
92
|
+
const primary = current[0];
|
|
93
|
+
if (primary?.key === key)
|
|
94
|
+
return [{ key, dir: primary.dir === "asc" ? "desc" : "asc" }];
|
|
95
|
+
return [{ key, dir: "asc" }];
|
|
96
|
+
});
|
|
97
|
+
setPage(0);
|
|
98
|
+
}, []);
|
|
99
|
+
const clearFilters = React.useCallback(() => {
|
|
100
|
+
setSearch("");
|
|
101
|
+
onClearFilters?.();
|
|
102
|
+
}, [setSearch, onClearFilters]);
|
|
103
|
+
return {
|
|
104
|
+
rows: state === "ready" ? pageRows : [],
|
|
105
|
+
state,
|
|
106
|
+
error,
|
|
107
|
+
retry: retry ?? (() => { }),
|
|
108
|
+
totalCount: loading || error ? null : sorted.length,
|
|
109
|
+
pageIndex,
|
|
110
|
+
hasNext: pageIndex < pages - 1,
|
|
111
|
+
hasPrev: pageIndex > 0,
|
|
112
|
+
next: () => setPage(Math.min(pageIndex + 1, pages - 1)),
|
|
113
|
+
prev: () => setPage(Math.max(pageIndex - 1, 0)),
|
|
114
|
+
pageSize,
|
|
115
|
+
pageSizes: pageSizes ?? PAGE_SIZES,
|
|
116
|
+
setPageSize,
|
|
117
|
+
search,
|
|
118
|
+
setSearch,
|
|
119
|
+
searchEnabled: Boolean(searchText),
|
|
120
|
+
isStale: false,
|
|
121
|
+
sort: sorts.length === 0 ? undefined : sorts.length === 1 ? sorts[0] : sorts,
|
|
122
|
+
toggleSort,
|
|
123
|
+
sortEnabled: Boolean(sortBy && Object.keys(sortBy).length > 0),
|
|
124
|
+
isFiltered,
|
|
125
|
+
clearFilters,
|
|
126
|
+
};
|
|
127
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,17 +10,19 @@ export { MIN_NON_TEXT_CONTRAST, MIN_TEXT_CONTRAST, contrastRatio, luminance, } f
|
|
|
10
10
|
export { CORNERS, defineProduct, type BrandAccent, type Corners, type Product, type ProductAccent, type ProductConfig, type ProductTheme, } from "./appearance/product.js";
|
|
11
11
|
export { astroliftBrand, chatStudioBrand, cykickBrand, loadrBrand, workbenchBrand, zentinelleBrand, } from "./appearance/brands.js";
|
|
12
12
|
export { accentContrast, appearanceFromServer, applyAppearance, clearAppearance, inkFor, isCustomAccent, modeFor, normalize, normalizePartial, parseCustomAccent, readAppearance, resolveAppearance, writeAppearance, type Appearance, type CustomAccent, type OrgAppearancePolicy, type ResolvedAppearance, } from "./appearance/appearance.js";
|
|
13
|
-
export { appearanceScript, productStyles } from "./appearance/boot.js";
|
|
13
|
+
export { appearanceScript, bootConfig, productStyles, type BootConfig } from "./appearance/boot.js";
|
|
14
|
+
export { BRAND_ACCENT_KEY, brandStyleVars, brandStyles, htmlAttributes, resolveRuntimeBrand, withBrand, type ResolvedRuntimeBrand, type RuntimeBrand, } from "./appearance/runtime-brand.js";
|
|
14
15
|
export { AppearanceScript, type AppearanceScriptProps } from "./appearance/AppearanceScript.js";
|
|
15
16
|
export { AppearanceProvider, useAppearance, useDensity, useProduct, type AppearanceContextValue, type AppearanceProviderProps, } from "./appearance/AppearanceProvider.js";
|
|
16
17
|
export { AppearancePicker, CustomAccentField, type CustomAccentFieldProps, } from "./appearance/AppearancePicker.js";
|
|
17
|
-
export { activeFor, areaSwitcher, localizeNav, visibleNav, type CrumbSwitchOption, type NavActive, type NavArea, type NavFunction, type NavGroup, type NavIcon, type NavModel, } from "./nav/model.js";
|
|
18
|
+
export { activeFor, areaSwitcher, localizeNav, visibleNav, type CrumbSwitchOption, type NavActive, type NavArea, type NavBadge, type NavFunction, type NavGroup, type NavIcon, type NavModel, } from "./nav/model.js";
|
|
18
19
|
export { Nav, type NavProps } from "./nav/Nav.js";
|
|
19
20
|
export { AppShell, type AppShellProps } from "./shell/AppShell.js";
|
|
20
21
|
export { Sidebar, type SidebarProps } from "./shell/Sidebar.js";
|
|
21
|
-
export { BrandMark, type BrandMarkProps } from "./shell/BrandMark.js";
|
|
22
|
+
export { BrandMark, type BrandLogo, type BrandMarkProps } from "./shell/BrandMark.js";
|
|
22
23
|
export { UserMenu, type UserMenuItem, type UserMenuProps } from "./shell/UserMenu.js";
|
|
23
24
|
export { RailPanel, type RailPanelProps } from "./shell/RailPanel.js";
|
|
25
|
+
export { railAttribute, railStyles, type RailBoot } from "./shell/rail-boot.js";
|
|
24
26
|
export { RailTree, type RailTreeGroup, type RailTreeItem, type RailTreeProps, } from "./shell/RailTree.js";
|
|
25
27
|
export { useRailState, useRailWidth } from "./shell/rail-state.js";
|
|
26
28
|
export { PageFrame, type PageFrameProps } from "./page/PageFrame.js";
|
|
@@ -28,9 +30,14 @@ export { PageHeader, type PageHeaderProps } from "./page/PageHeader.js";
|
|
|
28
30
|
export { Breadcrumbs, type BreadcrumbsProps, type Crumb } from "./page/Breadcrumbs.js";
|
|
29
31
|
export { TabNav, type TabNavItem, type TabNavProps } from "./page/TabNav.js";
|
|
30
32
|
export { Section, type SectionProps } from "./page/Section.js";
|
|
33
|
+
export { Panel, type PanelProps } from "./page/Panel.js";
|
|
31
34
|
export { DataTable, type DataTableProps } from "./data/DataTable.js";
|
|
32
35
|
export { List, ListItem, type ListItemProps, type ListProps } from "./data/List.js";
|
|
33
36
|
export { useRowSelection, type RowSelection } from "./data/use-row-selection.js";
|
|
37
|
+
export { useLocalTable, type LocalTableOptions, type SortValue } from "./data/use-local-table.js";
|
|
38
|
+
export { Stat, StatGrid, type StatProps } from "./data/Stat.js";
|
|
39
|
+
export { Tag, TagList, type TagProps } from "./data/Tag.js";
|
|
40
|
+
export { DefinitionList, type Definition, type DefinitionListProps, } from "./data/DefinitionList.js";
|
|
34
41
|
export { DEFAULT_PAGE_SIZE, PAGE_SIZES, type Column, type EmptyStateSpec, type PageState, type SortDirection, type SortState, type TableController, } from "./data/types.js";
|
|
35
42
|
export { StatusBadge, type StatusBadgeProps } from "./status/StatusBadge.js";
|
|
36
43
|
export { StatusDot, type StatusDotProps } from "./status/StatusDot.js";
|
|
@@ -45,7 +52,41 @@ export { ConfirmDialog, type ConfirmDialogProps, type ConfirmReason, } from "./o
|
|
|
45
52
|
export { Button, buttonVariants, type ButtonProps } from "./primitives/Button.js";
|
|
46
53
|
export { Input } from "./primitives/Input.js";
|
|
47
54
|
export { Checkbox } from "./primitives/Checkbox.js";
|
|
55
|
+
export { Textarea } from "./primitives/Textarea.js";
|
|
56
|
+
export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, type SelectOption, type SelectProps, } from "./primitives/Select.js";
|
|
57
|
+
export { Switch, type SwitchProps } from "./primitives/Switch.js";
|
|
58
|
+
export { Avatar, AvatarStack, initials, type AvatarProps, type AvatarSize, type AvatarStackPerson, type AvatarStackProps, type AvatarSurface, } from "./primitives/Avatar.js";
|
|
59
|
+
export { Segmented, type SegmentedOption, type SegmentedProps } from "./primitives/Segmented.js";
|
|
60
|
+
export { Field, type FieldControlProps, type FieldProps } from "./primitives/Field.js";
|
|
48
61
|
export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "./primitives/DropdownMenu.js";
|
|
49
62
|
export { Popover, PopoverAnchor, PopoverContent, PopoverHeader, PopoverTrigger, } from "./primitives/Popover.js";
|
|
50
63
|
export { Tabs, TabsContent, TabsList, TabsTrigger } from "./primitives/Tabs.js";
|
|
51
64
|
export { Skeleton } from "./primitives/Skeleton.js";
|
|
65
|
+
export type { WorkflowAction, WorkflowAvailability, WorkflowModule, WorkflowPermissions, WorkflowScope, WorkflowStatus, WorkflowSummary, } from "./workflow/model.js";
|
|
66
|
+
export { WorkflowCard, WorkflowCardSkeleton, type WorkflowCardActions, type WorkflowCardProps, } from "./workflow/WorkflowCard.js";
|
|
67
|
+
export { WorkflowQuestionCard, type WorkflowQuestionCardProps, } from "./workflow/WorkflowQuestionCard.js";
|
|
68
|
+
export type { WorkflowQuestion, WorkflowQuestionField, WorkflowQuestionState, WorkflowQuestionAnswers, WorkflowQuestionSubmission, } from "./workflow/question.js";
|
|
69
|
+
export { ANY_FILTER, DEFAULT_WORKFLOW_FILTERS, filterWorkflows, isFiltered, type WorkflowGalleryFilters, } from "./workflow/gallery.js";
|
|
70
|
+
export { WorkflowGallery, type WorkflowGalleryProps, type WorkflowGalleryView, } from "./workflow/WorkflowGallery.js";
|
|
71
|
+
export { ARTIFACT_TONE, GATE_TONE, RUN_STAGE_TONE, VERDICT_TONE, type Artifact, type ArtifactStatus, type Gate, type GateStatus, type ReviewComment, type ReviewDecision, type ReviewVerdict, type RunStage, type RunStageStatus, type RunValue, } from "./workflow/run.js";
|
|
72
|
+
export { RunTimeline, type RunTimelineProps } from "./workflow/RunTimeline.js";
|
|
73
|
+
export { GateBadge, type GateBadgeProps } from "./workflow/GateBadge.js";
|
|
74
|
+
export { ArtifactCard, ArtifactList, type ArtifactCardProps, type ArtifactListProps, } from "./workflow/ArtifactCard.js";
|
|
75
|
+
export { ReviewPanel, type ReviewPanelProps } from "./workflow/ReviewPanel.js";
|
|
76
|
+
export { MediaReview, formatTimecode, type MediaAnchor, type MediaCaptionTrack, type MediaComment, type MediaRegion, type MediaReviewProps, } from "./workflow/MediaReview.js";
|
|
77
|
+
export { DocumentReview, type DocumentAnnotation, type DocumentBlock, type DocumentPage, type DocumentReviewProps, type DocumentSegment, type DocumentSignOff, type SignOffStatus, } from "./workflow/DocumentReview.js";
|
|
78
|
+
export { FormReview, type FormField, type FormFieldBox, type FormFieldStatus, type FormReviewProps, type FormSourcePage, } from "./workflow/FormReview.js";
|
|
79
|
+
export { IN, LOOP_IN, LOOP_OUT, OUT, WORKFLOW_DEFINITION_VERSION, WORKFLOW_NODE_KINDS, WORKFLOW_SELECTORS, addNode, canConnect, createNode, dataTypes, downstream, edgeId, exitLabel, exitsOf, findFact, findGateKind, findPreset, freshId, inputsOf, isJudge, moveNode, operatorsFor, outputsOf, portOf, removeEdge, removeNode, startOf, typeAccepts, updateEdge, updateNode, upstream, withFlow, type WorkflowCase, type WorkflowCheckNode, type WorkflowClassifierNode, type WorkflowClassifierOption, type WorkflowCondition, type WorkflowConditionNode, type WorkflowConnectReason, type WorkflowConnectResult, type WorkflowConnection, type WorkflowDataType, type WorkflowDefinition, type WorkflowEdge, type WorkflowEvaluatorNode, type WorkflowFact, type WorkflowFactType, type WorkflowFanoutNode, type WorkflowFlow, type WorkflowGateField, type WorkflowGateKind, type WorkflowGateNode, type WorkflowGatePolicy, type WorkflowGotoNode, type WorkflowJoinNode, type WorkflowJudgeNode, type WorkflowModuleSpec, type WorkflowNode, type WorkflowNodeKind, type WorkflowNodeOf, type WorkflowNodeTemplate, type WorkflowOperator, type WorkflowOption, type WorkflowPort, type WorkflowPosition, type WorkflowRegistry, type WorkflowSelection, type WorkflowSelector, type WorkflowStepNode, type WorkflowStepPreset, type WorkflowSubflowNode, type WorkflowVariant, type WorkflowVariantsNode, } from "./workflow/definition.js";
|
|
80
|
+
export { WORKFLOW_PROBLEM_CODES, blockingProblems, checkDefinition, definitionAvailability, nodeAvailability, type WorkflowProblem, type WorkflowProblemCode, type WorkflowProblemLevel, } from "./workflow/problems.js";
|
|
81
|
+
export { WORKFLOW_PACKAGE_FORMAT, WORKFLOW_PACKAGE_VERSION, diffDefinitions, exportWorkflowPackage, previewWorkflowImport, readWorkflowDefinition, readWorkflowPackage, requirementsOf, sameDefinition, type WorkflowDefinitionDiff, type WorkflowDiffEdge, type WorkflowDiffItem, type WorkflowDisabledNode, type WorkflowFlowDiff, type WorkflowImportSummary, type WorkflowModuleGap, type WorkflowPackage, type WorkflowReadError, type WorkflowReadResult, type WorkflowRequirements, } from "./workflow/portable.js";
|
|
82
|
+
export { NODE_HEADER, NODE_WIDTH, PORT_ROW, arrangeFlow, layoutFlow, nodeSize, portRows, ranksOf, regionsOf, type WorkflowRegion, } from "./workflow/layout.js";
|
|
83
|
+
export { insertPaletteItem, paletteOf, type WorkflowPaletteGroup, type WorkflowPaletteItem, } from "./workflow/palette.js";
|
|
84
|
+
export { READABLE_ZOOM, WorkflowCanvas, type WorkflowCanvasProps, } from "./workflow/canvas/WorkflowCanvas.js";
|
|
85
|
+
export { WorkflowPalette, type WorkflowPaletteProps } from "./workflow/editor/WorkflowPalette.js";
|
|
86
|
+
export { WorkflowProblems, problemTarget, type WorkflowProblemsProps, } from "./workflow/editor/WorkflowProblems.js";
|
|
87
|
+
export { ConditionEditor, GatePolicyEditor, WorkflowInspector, type WorkflowInspectorProps, } from "./workflow/editor/WorkflowInspector.js";
|
|
88
|
+
export { WorkflowJsonView, type WorkflowJsonViewProps, } from "./workflow/editor/WorkflowJsonView.js";
|
|
89
|
+
export { documentStatus, type WorkflowDocumentStatus, type WorkflowRevision, } from "./workflow/workspace.js";
|
|
90
|
+
export { WorkflowDiff, type WorkflowDiffProps } from "./workflow/editor/WorkflowDiff.js";
|
|
91
|
+
export { WorkflowImportPreview, type WorkflowImportPreviewProps, } from "./workflow/editor/WorkflowImportPreview.js";
|
|
92
|
+
export { WorkflowWorkspace, type WorkflowWorkspaceProps, } from "./workflow/editor/WorkflowWorkspace.js";
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,8 @@ export { MIN_NON_TEXT_CONTRAST, MIN_TEXT_CONTRAST, contrastRatio, luminance, } f
|
|
|
13
13
|
export { CORNERS, defineProduct, } from "./appearance/product.js";
|
|
14
14
|
export { astroliftBrand, chatStudioBrand, cykickBrand, loadrBrand, workbenchBrand, zentinelleBrand, } from "./appearance/brands.js";
|
|
15
15
|
export { accentContrast, appearanceFromServer, applyAppearance, clearAppearance, inkFor, isCustomAccent, modeFor, normalize, normalizePartial, parseCustomAccent, readAppearance, resolveAppearance, writeAppearance, } from "./appearance/appearance.js";
|
|
16
|
-
export { appearanceScript, productStyles } from "./appearance/boot.js";
|
|
16
|
+
export { appearanceScript, bootConfig, productStyles } from "./appearance/boot.js";
|
|
17
|
+
export { BRAND_ACCENT_KEY, brandStyleVars, brandStyles, htmlAttributes, resolveRuntimeBrand, withBrand, } from "./appearance/runtime-brand.js";
|
|
17
18
|
export { AppearanceScript } from "./appearance/AppearanceScript.js";
|
|
18
19
|
export { AppearanceProvider, useAppearance, useDensity, useProduct, } from "./appearance/AppearanceProvider.js";
|
|
19
20
|
export { AppearancePicker, CustomAccentField, } from "./appearance/AppearancePicker.js";
|
|
@@ -26,6 +27,7 @@ export { Sidebar } from "./shell/Sidebar.js";
|
|
|
26
27
|
export { BrandMark } from "./shell/BrandMark.js";
|
|
27
28
|
export { UserMenu } from "./shell/UserMenu.js";
|
|
28
29
|
export { RailPanel } from "./shell/RailPanel.js";
|
|
30
|
+
export { railAttribute, railStyles } from "./shell/rail-boot.js";
|
|
29
31
|
export { RailTree, } from "./shell/RailTree.js";
|
|
30
32
|
export { useRailState, useRailWidth } from "./shell/rail-state.js";
|
|
31
33
|
// Page
|
|
@@ -34,10 +36,15 @@ export { PageHeader } from "./page/PageHeader.js";
|
|
|
34
36
|
export { Breadcrumbs } from "./page/Breadcrumbs.js";
|
|
35
37
|
export { TabNav } from "./page/TabNav.js";
|
|
36
38
|
export { Section } from "./page/Section.js";
|
|
39
|
+
export { Panel } from "./page/Panel.js";
|
|
37
40
|
// Data
|
|
38
41
|
export { DataTable } from "./data/DataTable.js";
|
|
39
42
|
export { List, ListItem } from "./data/List.js";
|
|
40
43
|
export { useRowSelection } from "./data/use-row-selection.js";
|
|
44
|
+
export { useLocalTable } from "./data/use-local-table.js";
|
|
45
|
+
export { Stat, StatGrid } from "./data/Stat.js";
|
|
46
|
+
export { Tag, TagList } from "./data/Tag.js";
|
|
47
|
+
export { DefinitionList, } from "./data/DefinitionList.js";
|
|
41
48
|
export { DEFAULT_PAGE_SIZE, PAGE_SIZES, } from "./data/types.js";
|
|
42
49
|
// Status
|
|
43
50
|
export { StatusBadge } from "./status/StatusBadge.js";
|
|
@@ -56,7 +63,39 @@ export { ConfirmDialog, } from "./overlays/ConfirmDialog.js";
|
|
|
56
63
|
export { Button, buttonVariants } from "./primitives/Button.js";
|
|
57
64
|
export { Input } from "./primitives/Input.js";
|
|
58
65
|
export { Checkbox } from "./primitives/Checkbox.js";
|
|
66
|
+
export { Textarea } from "./primitives/Textarea.js";
|
|
67
|
+
export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, } from "./primitives/Select.js";
|
|
68
|
+
export { Switch } from "./primitives/Switch.js";
|
|
69
|
+
export { Avatar, AvatarStack, initials, } from "./primitives/Avatar.js";
|
|
70
|
+
export { Segmented } from "./primitives/Segmented.js";
|
|
71
|
+
export { Field } from "./primitives/Field.js";
|
|
59
72
|
export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "./primitives/DropdownMenu.js";
|
|
60
73
|
export { Popover, PopoverAnchor, PopoverContent, PopoverHeader, PopoverTrigger, } from "./primitives/Popover.js";
|
|
61
74
|
export { Tabs, TabsContent, TabsList, TabsTrigger } from "./primitives/Tabs.js";
|
|
62
75
|
export { Skeleton } from "./primitives/Skeleton.js";
|
|
76
|
+
export { WorkflowCard, WorkflowCardSkeleton, } from "./workflow/WorkflowCard.js";
|
|
77
|
+
export { WorkflowQuestionCard, } from "./workflow/WorkflowQuestionCard.js";
|
|
78
|
+
export { ANY_FILTER, DEFAULT_WORKFLOW_FILTERS, filterWorkflows, isFiltered, } from "./workflow/gallery.js";
|
|
79
|
+
export { WorkflowGallery, } from "./workflow/WorkflowGallery.js";
|
|
80
|
+
export { ARTIFACT_TONE, GATE_TONE, RUN_STAGE_TONE, VERDICT_TONE, } from "./workflow/run.js";
|
|
81
|
+
export { RunTimeline } from "./workflow/RunTimeline.js";
|
|
82
|
+
export { GateBadge } from "./workflow/GateBadge.js";
|
|
83
|
+
export { ArtifactCard, ArtifactList, } from "./workflow/ArtifactCard.js";
|
|
84
|
+
export { ReviewPanel } from "./workflow/ReviewPanel.js";
|
|
85
|
+
export { MediaReview, formatTimecode, } from "./workflow/MediaReview.js";
|
|
86
|
+
export { DocumentReview, } from "./workflow/DocumentReview.js";
|
|
87
|
+
export { FormReview, } from "./workflow/FormReview.js";
|
|
88
|
+
export { IN, LOOP_IN, LOOP_OUT, OUT, WORKFLOW_DEFINITION_VERSION, WORKFLOW_NODE_KINDS, WORKFLOW_SELECTORS, addNode, canConnect, createNode, dataTypes, downstream, edgeId, exitLabel, exitsOf, findFact, findGateKind, findPreset, freshId, inputsOf, isJudge, moveNode, operatorsFor, outputsOf, portOf, removeEdge, removeNode, startOf, typeAccepts, updateEdge, updateNode, upstream, withFlow, } from "./workflow/definition.js";
|
|
89
|
+
export { WORKFLOW_PROBLEM_CODES, blockingProblems, checkDefinition, definitionAvailability, nodeAvailability, } from "./workflow/problems.js";
|
|
90
|
+
export { WORKFLOW_PACKAGE_FORMAT, WORKFLOW_PACKAGE_VERSION, diffDefinitions, exportWorkflowPackage, previewWorkflowImport, readWorkflowDefinition, readWorkflowPackage, requirementsOf, sameDefinition, } from "./workflow/portable.js";
|
|
91
|
+
export { NODE_HEADER, NODE_WIDTH, PORT_ROW, arrangeFlow, layoutFlow, nodeSize, portRows, ranksOf, regionsOf, } from "./workflow/layout.js";
|
|
92
|
+
export { insertPaletteItem, paletteOf, } from "./workflow/palette.js";
|
|
93
|
+
export { READABLE_ZOOM, WorkflowCanvas, } from "./workflow/canvas/WorkflowCanvas.js";
|
|
94
|
+
export { WorkflowPalette } from "./workflow/editor/WorkflowPalette.js";
|
|
95
|
+
export { WorkflowProblems, problemTarget, } from "./workflow/editor/WorkflowProblems.js";
|
|
96
|
+
export { ConditionEditor, GatePolicyEditor, WorkflowInspector, } from "./workflow/editor/WorkflowInspector.js";
|
|
97
|
+
export { WorkflowJsonView, } from "./workflow/editor/WorkflowJsonView.js";
|
|
98
|
+
export { documentStatus, } from "./workflow/workspace.js";
|
|
99
|
+
export { WorkflowDiff } from "./workflow/editor/WorkflowDiff.js";
|
|
100
|
+
export { WorkflowImportPreview, } from "./workflow/editor/WorkflowImportPreview.js";
|
|
101
|
+
export { WorkflowWorkspace, } from "./workflow/editor/WorkflowWorkspace.js";
|
package/dist/nav/Nav.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export interface NavProps {
|
|
|
16
16
|
* is a heading that folds, over its groups and rows; a flat area (Home,
|
|
17
17
|
* Overview) is just its rows. Collapsed, each area is an icon, and hovering,
|
|
18
18
|
* focusing or pressing it opens its rows as a flyout. The current row is the
|
|
19
|
-
* one lit row:
|
|
19
|
+
* one lit row: a tint and a 2px edge in the sidebar's marker colour
|
|
20
|
+
* (`--sidebar-primary`, the accent unless a brand sets one).
|
|
20
21
|
*/
|
|
21
22
|
export declare function Nav({ nav, active, collapsed, onNavigate, className }: NavProps): React.JSX.Element;
|
package/dist/nav/Nav.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx,
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { ChevronDownIcon } from "lucide-react";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { cn } from "../lib/cn.js";
|
|
@@ -10,20 +10,33 @@ import { useUI } from "../provider/UIProvider.js";
|
|
|
10
10
|
* is a heading that folds, over its groups and rows; a flat area (Home,
|
|
11
11
|
* Overview) is just its rows. Collapsed, each area is an icon, and hovering,
|
|
12
12
|
* focusing or pressing it opens its rows as a flyout. The current row is the
|
|
13
|
-
* one lit row:
|
|
13
|
+
* one lit row: a tint and a 2px edge in the sidebar's marker colour
|
|
14
|
+
* (`--sidebar-primary`, the accent unless a brand sets one).
|
|
14
15
|
*/
|
|
15
16
|
export function Nav({ nav, active, collapsed = false, onNavigate, className }) {
|
|
16
17
|
return (_jsx("div", { className: cn("flex flex-col", collapsed ? "items-center gap-1" : "gap-2", className), children: nav.map((area) => collapsed ? (_jsx(CollapsedArea, { area: area, active: active, onNavigate: onNavigate }, area.key)) : (_jsx(ExpandedArea, { area: area, active: active, onNavigate: onNavigate }, area.key))) }));
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
+
/** A count past 99 reads "99+". */
|
|
20
|
+
function badgeText(value) {
|
|
21
|
+
return typeof value === "number" && value > 99 ? "99+" : String(value);
|
|
22
|
+
}
|
|
23
|
+
/** The visible badge; hidden from the accessibility tree, which hears `label` instead. */
|
|
24
|
+
function Badge({ badge, className }) {
|
|
25
|
+
return (_jsx("span", { "aria-hidden": true, className: cn("inline-flex h-4 min-w-4 shrink-0 items-center justify-center rounded-full px-1 font-mono text-2xs leading-none font-medium tabular-nums", badge.tone === "attention"
|
|
26
|
+
? "bg-sidebar-primary/25 text-sidebar-foreground ring-1 ring-sidebar-primary/70"
|
|
27
|
+
: "bg-sidebar-foreground/10 text-sidebar-foreground/80", className), children: badgeText(badge.value) }));
|
|
28
|
+
}
|
|
29
|
+
function FunctionLink({ fn, isActive, flyout, onNavigate, }) {
|
|
19
30
|
const { Link } = useUI();
|
|
20
31
|
const Icon = fn.icon;
|
|
21
32
|
return (_jsxs(Link, { href: fn.href, onClick: onNavigate, "aria-current": isActive ? "page" : undefined, ...fn.attributes, className: cn("flex h-8 min-w-0 items-center gap-2 rounded-lg px-2 text-sm focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none", isActive
|
|
22
|
-
?
|
|
23
|
-
|
|
33
|
+
? flyout
|
|
34
|
+
? "bg-primary/15 font-medium text-sidebar-foreground shadow-[inset_2px_0_0_var(--primary)]"
|
|
35
|
+
: "bg-sidebar-primary/15 font-medium text-sidebar-foreground shadow-[inset_2px_0_0_var(--sidebar-primary)]"
|
|
36
|
+
: "text-sidebar-foreground/80 hover:bg-sidebar-accent/60 hover:text-sidebar-foreground"), children: [Icon && _jsx(Icon, { className: "size-4 shrink-0 opacity-80", "aria-hidden": true }), _jsx("span", { className: "truncate", children: fn.label }), (fn.badge || fn.trailing) && " ", (fn.badge || fn.trailing) && (_jsxs("span", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [fn.trailing, fn.badge && (_jsxs(_Fragment, { children: [" ", _jsx("span", { className: "sr-only", children: fn.badge.label }), _jsx(Badge, { badge: fn.badge })] }))] }))] }));
|
|
24
37
|
}
|
|
25
|
-
function Rows({ area, active, onNavigate, }) {
|
|
26
|
-
return (_jsx(_Fragment, { children: area.groups.map((group, i) => (_jsxs("div", { className: "flex flex-col gap-0.5", children: [group.label && (_jsx("div", { className: "px-2 pt-2 pb-1 text-2xs text-muted-foreground", children: group.label })), group.functions.map((fn) => (_jsx(FunctionLink, { fn: fn, isActive: active?.area === area.key && active.fn === fn.key, onNavigate: onNavigate }, fn.key)))] }, group.key ?? group.label ?? i))) }));
|
|
38
|
+
function Rows({ area, active, flyout = false, onNavigate, }) {
|
|
39
|
+
return (_jsx(_Fragment, { children: area.groups.map((group, i) => (_jsxs("div", { className: "flex flex-col gap-0.5", children: [group.label && (_jsx("div", { className: cn("px-2 pt-2 pb-1 text-2xs", flyout ? "text-muted-foreground" : "text-sidebar-muted-foreground"), children: group.label })), group.functions.map((fn) => (_jsx(FunctionLink, { fn: fn, isActive: active?.area === area.key && active.fn === fn.key, flyout: flyout, onNavigate: onNavigate }, fn.key)))] }, group.key ?? group.label ?? i))) }));
|
|
27
40
|
}
|
|
28
41
|
function ExpandedArea({ area, active, onNavigate, }) {
|
|
29
42
|
const [open, setOpen] = React.useState(true);
|
|
@@ -31,12 +44,12 @@ function ExpandedArea({ area, active, onNavigate, }) {
|
|
|
31
44
|
if (area.flat) {
|
|
32
45
|
return (_jsx("div", { className: "flex flex-col gap-0.5", children: _jsx(Rows, { area: area, active: active, onNavigate: onNavigate }) }));
|
|
33
46
|
}
|
|
34
|
-
return (_jsxs("div", { className: "flex flex-col", children: [_jsxs("button", { type: "button", onClick: () => setOpen((o) => !o), "aria-expanded": open, "aria-controls": regionId, className: "flex h-7 w-full items-center justify-between rounded-lg px-2 text-2xs font-semibold tracking-wider text-muted-foreground uppercase hover:text-sidebar-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none", children: [area.label, _jsx(ChevronDownIcon, { className: cn("size-3 transition-transform", !open && "-rotate-90"), "aria-hidden": true })] }), _jsx("div", { id: regionId, hidden: !open, className: "flex flex-col gap-0.5", children: _jsx(Rows, { area: area, active: active, onNavigate: onNavigate }) })] }));
|
|
47
|
+
return (_jsxs("div", { className: "flex flex-col", children: [_jsxs("button", { type: "button", onClick: () => setOpen((o) => !o), "aria-expanded": open, "aria-controls": regionId, className: "flex h-7 w-full items-center justify-between rounded-lg px-2 text-2xs font-semibold tracking-wider text-sidebar-muted-foreground uppercase hover:text-sidebar-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none", children: [area.label, _jsx(ChevronDownIcon, { className: cn("size-3 transition-transform", !open && "-rotate-90"), "aria-hidden": true })] }), _jsx("div", { id: regionId, hidden: !open, className: "flex flex-col gap-0.5", children: _jsx(Rows, { area: area, active: active, onNavigate: onNavigate }) })] }));
|
|
35
48
|
}
|
|
36
49
|
/** How long the pointer may be away from a flyout before it closes. */
|
|
37
50
|
const FLYOUT_GRACE_MS = 150;
|
|
38
51
|
function CollapsedArea({ area, active, onNavigate, }) {
|
|
39
|
-
const { Link } = useUI();
|
|
52
|
+
const { Link, messages } = useUI();
|
|
40
53
|
const [open, setOpen] = React.useState(false);
|
|
41
54
|
const pointerOpened = React.useRef(false);
|
|
42
55
|
const closeTimer = React.useRef(null);
|
|
@@ -52,12 +65,18 @@ function CollapsedArea({ area, active, onNavigate, }) {
|
|
|
52
65
|
clearTimeout(timer.current);
|
|
53
66
|
};
|
|
54
67
|
}, []);
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
68
|
+
const badged = area.groups.some((group) => group.functions.some((fn) => fn.badge));
|
|
69
|
+
const onlyBadge = only?.badge;
|
|
70
|
+
const tile = (_jsxs("span", { className: cn("relative flex size-8 items-center justify-center rounded-lg", isActive
|
|
71
|
+
? "bg-sidebar-primary/15 text-sidebar-foreground shadow-[inset_2px_0_0_var(--sidebar-primary)]"
|
|
72
|
+
: "text-sidebar-foreground/80 hover:bg-sidebar-accent/60"), children: [_jsx(Icon, { className: "size-4", "aria-hidden": true }), onlyBadge ? (_jsx(Badge, { badge: onlyBadge, className: "absolute -top-1 -right-1.5 h-3.5 min-w-3.5 px-0.5" })) : (badged && (_jsx("span", { "aria-hidden": true, className: "absolute top-1 right-1 size-1.5 rounded-full bg-sidebar-primary ring-2 ring-sidebar" })))] }));
|
|
58
73
|
// One row: the icon is that row's link, no flyout needed.
|
|
59
74
|
if (only) {
|
|
60
|
-
return (_jsx(Link, { href: only.href, onClick: onNavigate, "aria-label":
|
|
75
|
+
return (_jsx(Link, { href: only.href, onClick: onNavigate, "aria-label": onlyBadge
|
|
76
|
+
? messages.nav.withBadge(area.flat ? only.label : area.label, onlyBadge.label)
|
|
77
|
+
: area.flat
|
|
78
|
+
? only.label
|
|
79
|
+
: area.label, title: area.flat ? only.label : area.label, "aria-current": isActive ? "page" : undefined, ...only.attributes, className: "flex rounded-lg focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none", children: tile }));
|
|
61
80
|
}
|
|
62
81
|
const cancelClose = () => {
|
|
63
82
|
if (closeTimer.current)
|
|
@@ -72,7 +91,7 @@ function CollapsedArea({ area, active, onNavigate, }) {
|
|
|
72
91
|
if (!next)
|
|
73
92
|
pointerOpened.current = false;
|
|
74
93
|
setOpen(next);
|
|
75
|
-
}, children: [_jsx(PopoverTrigger, { "aria-label": area.label, title: area.label, className: "flex rounded-lg focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none", onPointerEnter: (event) => {
|
|
94
|
+
}, children: [_jsx(PopoverTrigger, { "aria-label": badged ? messages.nav.areaWithBadges(area.label) : area.label, title: area.label, className: "flex rounded-lg focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none", onPointerEnter: (event) => {
|
|
76
95
|
if (event.pointerType !== "mouse")
|
|
77
96
|
return;
|
|
78
97
|
cancelClose();
|
|
@@ -90,7 +109,7 @@ function CollapsedArea({ area, active, onNavigate, }) {
|
|
|
90
109
|
}, onPointerEnter: cancelClose, onPointerLeave: (event) => {
|
|
91
110
|
if (event.pointerType === "mouse")
|
|
92
111
|
scheduleClose();
|
|
93
|
-
}, children: [_jsx("div", { className: "px-2 pb-1 text-2xs font-semibold tracking-wider text-muted-foreground uppercase", children: area.label }), _jsx(Rows, { area: area, active: active, onNavigate: () => {
|
|
112
|
+
}, children: [_jsx("div", { className: "px-2 pb-1 text-2xs font-semibold tracking-wider text-muted-foreground uppercase", children: area.label }), _jsx(Rows, { area: area, active: active, flyout: true, onNavigate: () => {
|
|
94
113
|
setOpen(false);
|
|
95
114
|
onNavigate?.();
|
|
96
115
|
} })] })] }));
|
package/dist/nav/model.d.ts
CHANGED
|
@@ -12,6 +12,19 @@ export type NavIcon = React.ComponentType<{
|
|
|
12
12
|
className?: string;
|
|
13
13
|
"aria-hidden"?: boolean;
|
|
14
14
|
}>;
|
|
15
|
+
/**
|
|
16
|
+
* A count or a short word beside a row: unread items, things needing
|
|
17
|
+
* attention, "new". `label` is what a screen reader hears in place of the
|
|
18
|
+
* visible value ("3 unread"), so say what it counts.
|
|
19
|
+
*/
|
|
20
|
+
export interface NavBadge {
|
|
21
|
+
/** A count (shown as "99+" past 99) or a short word. */
|
|
22
|
+
value: number | string;
|
|
23
|
+
/** The accessible text: "3 unread", "2 need attention". */
|
|
24
|
+
label: string;
|
|
25
|
+
/** `attention` draws it in the sidebar's marker colour; `neutral` (the default) is quiet. */
|
|
26
|
+
tone?: "neutral" | "attention";
|
|
27
|
+
}
|
|
15
28
|
export interface NavFunction {
|
|
16
29
|
key: string;
|
|
17
30
|
label: string;
|
|
@@ -27,6 +40,14 @@ export interface NavFunction {
|
|
|
27
40
|
also?: readonly string[];
|
|
28
41
|
/** Extra attributes on the row's link, such as a tour anchor (`data-tour`). */
|
|
29
42
|
attributes?: Readonly<Record<`data-${string}`, string>>;
|
|
43
|
+
/** A count or short word after the label, in expanded rows and the collapsed flyout; collapsed, the area's icon carries a mark. */
|
|
44
|
+
badge?: NavBadge;
|
|
45
|
+
/**
|
|
46
|
+
* Anything else after the label: presence avatars, a status dot. Inside
|
|
47
|
+
* the row's link, so nothing interactive; decorative unless it names
|
|
48
|
+
* itself. Not shown on the collapsed icon.
|
|
49
|
+
*/
|
|
50
|
+
trailing?: React.ReactNode;
|
|
30
51
|
}
|
|
31
52
|
export interface NavGroup {
|
|
32
53
|
key?: string;
|
|
@@ -3,6 +3,8 @@ import { type Crumb } from "./Breadcrumbs.js";
|
|
|
3
3
|
import { type TabNavItem } from "./TabNav.js";
|
|
4
4
|
export interface PageHeaderProps {
|
|
5
5
|
crumbs?: readonly Crumb[];
|
|
6
|
+
/** A short line above the title: the kind of thing (a project, a run) or the section it sits in. */
|
|
7
|
+
eyebrow?: React.ReactNode;
|
|
6
8
|
title: React.ReactNode;
|
|
7
9
|
/** A status badge beside the title. */
|
|
8
10
|
status?: React.ReactNode;
|
|
@@ -28,7 +30,7 @@ export interface PageHeaderProps {
|
|
|
28
30
|
}
|
|
29
31
|
/**
|
|
30
32
|
* Every page's header, in three rows (Astrolift spec 44 §4.4): the
|
|
31
|
-
* breadcrumb, the title row
|
|
32
|
-
* most one row of tabs. Pure.
|
|
33
|
+
* breadcrumb, the title row (an optional eyebrow over the title) with its
|
|
34
|
+
* status, context and actions, and at most one row of tabs. Pure.
|
|
33
35
|
*/
|
|
34
|
-
export declare function PageHeader({ crumbs, title, status, context, description, primaryAction, menu, tabs, tabsLabel, tabsClassName, className, }: PageHeaderProps): React.JSX.Element;
|
|
36
|
+
export declare function PageHeader({ crumbs, eyebrow, title, status, context, description, primaryAction, menu, tabs, tabsLabel, tabsClassName, className, }: PageHeaderProps): React.JSX.Element;
|
package/dist/page/PageHeader.js
CHANGED
|
@@ -5,9 +5,10 @@ import { Breadcrumbs } from "./Breadcrumbs.js";
|
|
|
5
5
|
import { TabNav } from "./TabNav.js";
|
|
6
6
|
/**
|
|
7
7
|
* Every page's header, in three rows (Astrolift spec 44 §4.4): the
|
|
8
|
-
* breadcrumb, the title row
|
|
9
|
-
* most one row of tabs. Pure.
|
|
8
|
+
* breadcrumb, the title row (an optional eyebrow over the title) with its
|
|
9
|
+
* status, context and actions, and at most one row of tabs. Pure.
|
|
10
10
|
*/
|
|
11
|
-
export function PageHeader({ crumbs, title, status, context, description, primaryAction, menu, tabs, tabsLabel = "Page", tabsClassName, className, }) {
|
|
12
|
-
|
|
11
|
+
export function PageHeader({ crumbs, eyebrow, title, status, context, description, primaryAction, menu, tabs, tabsLabel = "Page", tabsClassName, className, }) {
|
|
12
|
+
const heading = _jsx("h1", { className: "min-w-0 truncate font-head text-xl font-semibold", children: title });
|
|
13
|
+
return (_jsxs("header", { "data-slot": "page-header", className: cn("flex min-w-0 flex-col gap-3", className), children: [crumbs && crumbs.length > 0 && _jsx(Breadcrumbs, { crumbs: crumbs }), _jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-x-3 gap-y-2", children: [eyebrow ? (_jsxs("hgroup", { className: "flex min-w-0 flex-col", children: [_jsx("p", { className: "truncate font-mono text-2xs font-medium tracking-wider text-muted-foreground uppercase", children: eyebrow }), heading] })) : (heading), status, context && (_jsx("span", { className: "min-w-0 truncate text-sm text-muted-foreground", children: context })), (primaryAction || menu) && (_jsxs("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: [primaryAction, menu] }))] }), description && (_jsx("div", { className: "max-w-2xl text-sm [overflow-wrap:anywhere] text-muted-foreground", children: description })), tabs && tabs.length > 0 && (_jsx(TabNav, { tabs: tabs, label: tabsLabel, className: cn("-mx-3 md:-mx-6", tabsClassName) }))] }));
|
|
13
14
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
export interface PanelProps extends Omit<React.ComponentProps<"div">, "title"> {
|
|
3
|
+
/** A short heading inside the box. */
|
|
4
|
+
title?: React.ReactNode;
|
|
5
|
+
/** A line over the title: what kind of thing the panel holds. */
|
|
6
|
+
eyebrow?: React.ReactNode;
|
|
7
|
+
/** Controls beside the title (a link, a small button). */
|
|
8
|
+
actions?: React.ReactNode;
|
|
9
|
+
/** For the document outline. Defaults to h3, under a page's h1 and a Section's h2. */
|
|
10
|
+
headingLevel?: "h2" | "h3" | "h4";
|
|
11
|
+
/** No padding around the body, for a table or a list that runs to the edges. */
|
|
12
|
+
flush?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The bordered surface of `PageFrame > Section > Panel`: a card with an
|
|
16
|
+
* optional heading row, padded by the density (`--panel-pad`). The second
|
|
17
|
+
* container level, so it never holds a Section or another Panel.
|
|
18
|
+
*/
|
|
19
|
+
export declare function Panel({ title, eyebrow, actions, headingLevel, flush, className, children, ...props }: PanelProps): React.JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
/**
|
|
4
|
+
* The bordered surface of `PageFrame > Section > Panel`: a card with an
|
|
5
|
+
* optional heading row, padded by the density (`--panel-pad`). The second
|
|
6
|
+
* container level, so it never holds a Section or another Panel.
|
|
7
|
+
*/
|
|
8
|
+
export function Panel({ title, eyebrow, actions, headingLevel = "h3", flush = false, className, children, ...props }) {
|
|
9
|
+
const Heading = headingLevel;
|
|
10
|
+
const hasHeader = Boolean(title || eyebrow || actions);
|
|
11
|
+
return (_jsxs("div", { "data-slot": "panel", className: cn("flex min-w-0 flex-col overflow-hidden rounded-lg border bg-card text-card-foreground", className), ...props, children: [hasHeader && (_jsxs("div", { className: cn("flex min-w-0 items-start justify-between gap-3 px-(--panel-pad) pt-(--panel-pad)", flush && "border-b pb-3"), children: [_jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [eyebrow && (_jsx("p", { className: "truncate font-mono text-2xs font-medium tracking-wider text-muted-foreground uppercase", children: eyebrow })), title && (_jsx(Heading, { className: "text-sm font-medium [overflow-wrap:anywhere]", children: title }))] }), actions && _jsx("div", { className: "flex shrink-0 flex-wrap items-center gap-2", children: actions })] })), _jsx("div", { className: cn("flex min-w-0 flex-col gap-3", !flush && "p-(--panel-pad)", !flush && hasHeader && "pt-3"), children: children })] }));
|
|
12
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** Up to two initials from a name, upper case; "?" for a name with none. */
|
|
2
|
+
export declare function initials(name: string): string;
|
|
3
|
+
export type AvatarSize = "sm" | "md" | "lg";
|
|
4
|
+
/** What the avatar's ring separates it from, in a stack. */
|
|
5
|
+
export type AvatarSurface = "background" | "card" | "sidebar";
|
|
6
|
+
export interface AvatarProps {
|
|
7
|
+
/** The person's name: the initials, and the accessible name unless `decorative`. */
|
|
8
|
+
name: string;
|
|
9
|
+
/** A picture; the initials show until it loads, and if it fails. */
|
|
10
|
+
src?: string;
|
|
11
|
+
size?: AvatarSize;
|
|
12
|
+
/** The name is already visible beside it: hide the avatar from assistive tech. */
|
|
13
|
+
decorative?: boolean;
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
/** A person: their picture, or their initials on a neutral disc. */
|
|
17
|
+
export declare function Avatar({ name, src, size, decorative, className }: AvatarProps): import("react").JSX.Element;
|
|
18
|
+
export interface AvatarStackPerson {
|
|
19
|
+
name: string;
|
|
20
|
+
src?: string;
|
|
21
|
+
/** Stable identity when names repeat. */
|
|
22
|
+
id?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface AvatarStackProps {
|
|
25
|
+
people: readonly AvatarStackPerson[];
|
|
26
|
+
/** How many avatars show before "+n". Defaults to 3. */
|
|
27
|
+
max?: number;
|
|
28
|
+
size?: AvatarSize;
|
|
29
|
+
/** The surface behind the stack, for the ring between avatars. Defaults to the page background. */
|
|
30
|
+
surface?: AvatarSurface;
|
|
31
|
+
className?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Several people, overlapping: who is here, who owns it. Read as one phrase
|
|
35
|
+
* ("Leo Mata, Ana Ruiz and 2 more"), from `messages.avatar.people`.
|
|
36
|
+
*/
|
|
37
|
+
export declare function AvatarStack({ people, max, size, surface, className, }: AvatarStackProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Avatar as AvatarPrimitive } from "radix-ui";
|
|
4
|
+
import { cn } from "../lib/cn.js";
|
|
5
|
+
import { useUI } from "../provider/UIProvider.js";
|
|
6
|
+
/** Up to two initials from a name, upper case; "?" for a name with none. */
|
|
7
|
+
export function initials(name) {
|
|
8
|
+
return (name
|
|
9
|
+
.trim()
|
|
10
|
+
.split(/\s+/)
|
|
11
|
+
.map((part) => part[0])
|
|
12
|
+
.filter(Boolean)
|
|
13
|
+
.slice(0, 2)
|
|
14
|
+
.join("")
|
|
15
|
+
.toUpperCase() || "?");
|
|
16
|
+
}
|
|
17
|
+
const SIZE = {
|
|
18
|
+
sm: "size-5 text-2xs",
|
|
19
|
+
md: "size-7 text-xs",
|
|
20
|
+
lg: "size-9 text-sm",
|
|
21
|
+
};
|
|
22
|
+
const RING = {
|
|
23
|
+
background: "ring-2 ring-background",
|
|
24
|
+
card: "ring-2 ring-card",
|
|
25
|
+
sidebar: "ring-2 ring-sidebar",
|
|
26
|
+
};
|
|
27
|
+
/** A person: their picture, or their initials on a neutral disc. */
|
|
28
|
+
export function Avatar({ name, src, size = "md", decorative = false, className }) {
|
|
29
|
+
return (_jsxs(AvatarPrimitive.Root, { "data-slot": "avatar", "data-size": size, role: decorative ? undefined : "img", "aria-label": decorative ? undefined : name, "aria-hidden": decorative || undefined, title: decorative ? undefined : name, className: cn("relative flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-muted font-mono font-medium text-foreground select-none", SIZE[size], className), children: [src && (_jsx(AvatarPrimitive.Image, { src: src, alt: "", className: "size-full rounded-full object-cover" })), _jsx(AvatarPrimitive.Fallback, { children: initials(name) })] }));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Several people, overlapping: who is here, who owns it. Read as one phrase
|
|
33
|
+
* ("Leo Mata, Ana Ruiz and 2 more"), from `messages.avatar.people`.
|
|
34
|
+
*/
|
|
35
|
+
export function AvatarStack({ people, max = 3, size = "md", surface = "background", className, }) {
|
|
36
|
+
const { messages } = useUI();
|
|
37
|
+
if (people.length === 0)
|
|
38
|
+
return null;
|
|
39
|
+
// "+1" would take the place of the one avatar it hides: show that one instead.
|
|
40
|
+
const shown = people.length > max + 1 ? people.slice(0, max) : people;
|
|
41
|
+
const more = people.length - shown.length;
|
|
42
|
+
return (_jsxs("div", { "data-slot": "avatar-stack", role: "img", "aria-label": messages.avatar.people(shown.map((p) => p.name), more), title: people.map((p) => p.name).join(", "), className: cn("flex min-w-0 items-center -space-x-1.5", className), children: [shown.map((person, i) => (_jsx(Avatar, { name: person.name, src: person.src, size: size, decorative: true, className: RING[surface] }, person.id ?? `${person.name}-${i}`))), more > 0 && (_jsxs("span", { "aria-hidden": true, className: cn("relative flex shrink-0 items-center justify-center rounded-full bg-secondary font-mono font-medium text-muted-foreground tabular-nums", SIZE[size], RING[surface]), children: ["+", more] }))] }));
|
|
43
|
+
}
|