@lateralus-ai/shipping-ui 2.0.0-dev.18 → 2.0.0-dev.19
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/components/ScrollableList.d.ts +22 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/index.cjs +13 -13
- package/dist/index.d.ts +2 -2
- package/dist/index.esm.js +1449 -1404
- package/package.json +1 -1
- package/src/components/ScrollableList.tsx +61 -0
- package/src/components/index.ts +6 -0
- package/src/index.ts +4 -0
- package/src/stories/canvases/ContentCanvas.tsx +132 -2
package/package.json
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type ComponentPropsWithoutRef } from "react";
|
|
2
|
+
import { cn } from "../utils/cn";
|
|
3
|
+
|
|
4
|
+
export type ScrollableListProps = ComponentPropsWithoutRef<"div">;
|
|
5
|
+
export type ScrollableListHeaderProps = ComponentPropsWithoutRef<"div">;
|
|
6
|
+
export type ScrollableListBodyProps = ComponentPropsWithoutRef<"div">;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Fill-height list chrome — Figma `Table` (6154:152285).
|
|
10
|
+
* Outer grey-100 frame + header slot + internally scrolling grey-50 body.
|
|
11
|
+
* Column layout and rows are caller-owned children.
|
|
12
|
+
*/
|
|
13
|
+
function ScrollableListRoot({ className, ...props }: ScrollableListProps) {
|
|
14
|
+
return (
|
|
15
|
+
<div
|
|
16
|
+
className={cn(
|
|
17
|
+
"flex min-h-0 flex-1 flex-col gap-2 overflow-hidden rounded-lg bg-grey-100 p-1",
|
|
18
|
+
className,
|
|
19
|
+
)}
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Column title bar. Default left padding aligns with a 24px leading icon +
|
|
27
|
+
* 8px gap + 8px row padding (Figma). Override `className` when rows have no icon.
|
|
28
|
+
*/
|
|
29
|
+
function ScrollableListHeader({
|
|
30
|
+
className,
|
|
31
|
+
...props
|
|
32
|
+
}: ScrollableListHeaderProps) {
|
|
33
|
+
return (
|
|
34
|
+
<div
|
|
35
|
+
className={cn(
|
|
36
|
+
"flex shrink-0 items-start gap-8 pl-10 pr-2 py-1",
|
|
37
|
+
"text-caption-2-em text-display-on-light-secondary",
|
|
38
|
+
className,
|
|
39
|
+
)}
|
|
40
|
+
{...props}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Internally scrolling row region. */
|
|
46
|
+
function ScrollableListBody({ className, ...props }: ScrollableListBodyProps) {
|
|
47
|
+
return (
|
|
48
|
+
<div
|
|
49
|
+
className={cn(
|
|
50
|
+
"flex min-h-0 flex-1 flex-col gap-1 overflow-y-auto rounded bg-grey-50 p-1",
|
|
51
|
+
className,
|
|
52
|
+
)}
|
|
53
|
+
{...props}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const ScrollableList = Object.assign(ScrollableListRoot, {
|
|
59
|
+
Header: ScrollableListHeader,
|
|
60
|
+
Body: ScrollableListBody,
|
|
61
|
+
});
|
package/src/components/index.ts
CHANGED
|
@@ -25,6 +25,12 @@ export {
|
|
|
25
25
|
type PageHeaderShellProps,
|
|
26
26
|
type PageHeaderBodyProps,
|
|
27
27
|
} from "./PageHeader";
|
|
28
|
+
export {
|
|
29
|
+
ScrollableList,
|
|
30
|
+
type ScrollableListProps,
|
|
31
|
+
type ScrollableListHeaderProps,
|
|
32
|
+
type ScrollableListBodyProps,
|
|
33
|
+
} from "./ScrollableList";
|
|
28
34
|
export { Entry, type EntryProps, type EntryType, type EntryState, type EntryVariant } from "./Entry";
|
|
29
35
|
export { EmptyState, type EmptyStateProps } from "./EmptyState";
|
|
30
36
|
export {
|
package/src/index.ts
CHANGED
|
@@ -36,6 +36,7 @@ export {
|
|
|
36
36
|
PdfViewer,
|
|
37
37
|
ImageViewer,
|
|
38
38
|
DocumentEditor,
|
|
39
|
+
ScrollableList,
|
|
39
40
|
} from "./components";
|
|
40
41
|
|
|
41
42
|
export type {
|
|
@@ -64,6 +65,9 @@ export type {
|
|
|
64
65
|
PageHeaderCrumb,
|
|
65
66
|
PageHeaderShellProps,
|
|
66
67
|
PageHeaderBodyProps,
|
|
68
|
+
ScrollableListProps,
|
|
69
|
+
ScrollableListHeaderProps,
|
|
70
|
+
ScrollableListBodyProps,
|
|
67
71
|
EntryProps,
|
|
68
72
|
EntryType,
|
|
69
73
|
EntryState,
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { Badge, Button, IconButton } from "../../primitives";
|
|
1
|
+
import { Badge, Button, IconButton, Avatar } from "../../primitives";
|
|
2
2
|
import {
|
|
3
3
|
EmptyState,
|
|
4
4
|
Entry,
|
|
5
5
|
Header,
|
|
6
6
|
PageHeader,
|
|
7
|
+
ScrollableList,
|
|
7
8
|
Tab,
|
|
8
9
|
Tabs,
|
|
9
10
|
TabsContent,
|
|
10
11
|
TabsList,
|
|
11
12
|
TabsTrigger,
|
|
12
13
|
} from "../../components";
|
|
13
|
-
import { MoreIcon, ShipIcon, TickIcon } from "../../icons";
|
|
14
|
+
import { FormsIcon, MoreIcon, ShipIcon, TickIcon } from "../../icons";
|
|
14
15
|
import { WorkflowsIllustration } from "../../illustrations";
|
|
15
16
|
import {
|
|
16
17
|
FigmaContent,
|
|
@@ -30,6 +31,116 @@ const demoActions = (
|
|
|
30
31
|
</>
|
|
31
32
|
);
|
|
32
33
|
|
|
34
|
+
type DemoRow = {
|
|
35
|
+
title: string;
|
|
36
|
+
assignee?: string;
|
|
37
|
+
unassigned?: boolean;
|
|
38
|
+
signatures?: number[];
|
|
39
|
+
date: string;
|
|
40
|
+
vessel: string;
|
|
41
|
+
initials: string;
|
|
42
|
+
avatarClassName: string;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const DEMO_ROWS: DemoRow[] = [
|
|
46
|
+
{
|
|
47
|
+
title: "Cargo Tank Cleaning for Grade Change",
|
|
48
|
+
assignee: "Dimitris Konstantinou",
|
|
49
|
+
signatures: [1, 2, 3],
|
|
50
|
+
date: "23/04/2026",
|
|
51
|
+
vessel: "The Coral Explorer",
|
|
52
|
+
initials: "MS",
|
|
53
|
+
avatarClassName: "bg-purple-500 text-white",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
title: "Hot Work in Engine Room",
|
|
57
|
+
assignee: "Dimitris Konstantinou",
|
|
58
|
+
signatures: [1, 2, 3],
|
|
59
|
+
date: "23/04/2026",
|
|
60
|
+
vessel: "Ocean Voyager",
|
|
61
|
+
initials: "PO",
|
|
62
|
+
avatarClassName: "bg-blue-700 text-white",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
title: "Enclosed Space Entry in Ballast Tank",
|
|
66
|
+
assignee: "Yiannis Papadopoulos",
|
|
67
|
+
signatures: [1],
|
|
68
|
+
date: "23/04/2026",
|
|
69
|
+
vessel: "Ocean Voyager",
|
|
70
|
+
initials: "PO",
|
|
71
|
+
avatarClassName: "bg-blue-700 text-white",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
title: "Working at Height on Deck Crane",
|
|
75
|
+
assignee: "Yiannis Papadopoulos",
|
|
76
|
+
date: "23/04/2026",
|
|
77
|
+
vessel: "Albatross Wind",
|
|
78
|
+
initials: "LD",
|
|
79
|
+
avatarClassName: "bg-grey-700 text-white",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
title: "Electrical Isolation for Switchboard Maintenance",
|
|
83
|
+
assignee: "Dimitris Konstantinou",
|
|
84
|
+
signatures: [1, 2, 3],
|
|
85
|
+
date: "23/04/2026",
|
|
86
|
+
vessel: "The Coral Explorer",
|
|
87
|
+
initials: "MS",
|
|
88
|
+
avatarClassName: "bg-purple-500 text-white",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
title: "Pilot Ladder Rigging in High Swell",
|
|
92
|
+
unassigned: true,
|
|
93
|
+
date: "23/04/2026",
|
|
94
|
+
vessel: "Albatross Wind",
|
|
95
|
+
initials: "",
|
|
96
|
+
avatarClassName: "",
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
function DemoListRow({ row }: { row: DemoRow }) {
|
|
101
|
+
return (
|
|
102
|
+
<div className="flex h-12 w-full shrink-0 items-center gap-2 rounded-lg p-2">
|
|
103
|
+
<FormsIcon size="large" className="shrink-0 text-display-on-light-primary" />
|
|
104
|
+
<div className="flex min-w-0 flex-1 items-center gap-8">
|
|
105
|
+
<div className="flex min-w-0 flex-1 items-center gap-2">
|
|
106
|
+
<p className="shrink-0 truncate text-body text-display-on-light-primary">
|
|
107
|
+
{row.title}
|
|
108
|
+
</p>
|
|
109
|
+
<div className="flex shrink-0 items-start gap-1">
|
|
110
|
+
{row.unassigned ? (
|
|
111
|
+
<Badge color="red">Unassigned</Badge>
|
|
112
|
+
) : row.assignee ? (
|
|
113
|
+
<Badge color="grey">{row.assignee}</Badge>
|
|
114
|
+
) : null}
|
|
115
|
+
{row.signatures?.map((n) => (
|
|
116
|
+
<Badge key={n} color="orange" type="icon">
|
|
117
|
+
{n}
|
|
118
|
+
</Badge>
|
|
119
|
+
))}
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
<div className="w-[90px] shrink-0 text-caption-2 text-display-on-light-secondary">
|
|
123
|
+
{row.date}
|
|
124
|
+
</div>
|
|
125
|
+
<div className="w-[150px] shrink-0 truncate text-caption-2 text-display-on-light-secondary">
|
|
126
|
+
{row.vessel}
|
|
127
|
+
</div>
|
|
128
|
+
{row.initials ? (
|
|
129
|
+
<Avatar
|
|
130
|
+
chief="initials"
|
|
131
|
+
size={24}
|
|
132
|
+
initials={row.initials}
|
|
133
|
+
className={row.avatarClassName}
|
|
134
|
+
/>
|
|
135
|
+
) : (
|
|
136
|
+
<span className="size-6 shrink-0" aria-hidden />
|
|
137
|
+
)}
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
33
144
|
export const ContentCanvas = () => (
|
|
34
145
|
<FigmaPage title="Content" width={FIGMA_WIDTHS.content}>
|
|
35
146
|
<FigmaContent>
|
|
@@ -154,6 +265,25 @@ export const ContentCanvas = () => (
|
|
|
154
265
|
</div>
|
|
155
266
|
</FigmaSection>
|
|
156
267
|
|
|
268
|
+
<FigmaSection label="ScrollableList (Table)">
|
|
269
|
+
<FigmaVariant label="Column header + scrolling body">
|
|
270
|
+
<div className="flex h-[420px] w-full max-w-[960px] flex-col">
|
|
271
|
+
<ScrollableList>
|
|
272
|
+
<ScrollableList.Header>
|
|
273
|
+
<span className="min-w-0 flex-1">Title</span>
|
|
274
|
+
<span className="w-[90px] shrink-0">Date</span>
|
|
275
|
+
<span className="w-[210px] shrink-0">Vessel</span>
|
|
276
|
+
</ScrollableList.Header>
|
|
277
|
+
<ScrollableList.Body>
|
|
278
|
+
{DEMO_ROWS.map((row) => (
|
|
279
|
+
<DemoListRow key={row.title} row={row} />
|
|
280
|
+
))}
|
|
281
|
+
</ScrollableList.Body>
|
|
282
|
+
</ScrollableList>
|
|
283
|
+
</div>
|
|
284
|
+
</FigmaVariant>
|
|
285
|
+
</FigmaSection>
|
|
286
|
+
|
|
157
287
|
<FigmaSection label="Header (legacy)">
|
|
158
288
|
<div className="max-w-xl space-y-4">
|
|
159
289
|
<Header title="Fleet overview" />
|