@lateralus-ai/shipping-ui 2.0.0-dev.4 → 2.0.0-dev.6
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/Entry.d.ts +24 -7
- package/dist/components/index.d.ts +1 -1
- package/dist/index.cjs +18 -18
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +1117 -1099
- package/dist/patterns/Search/ResultRow.d.ts +11 -5
- package/package.json +1 -1
- package/src/components/Entry.tsx +98 -44
- package/src/components/Tabs.tsx +22 -14
- package/src/components/index.ts +1 -1
- package/src/index.ts +1 -0
- package/src/patterns/Search/ResultRow.tsx +24 -38
- package/src/stories/canvases/ContentCanvas.tsx +23 -3
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { EntryProps, EntryState, EntryVariant } from '../../components/Entry';
|
|
3
|
+
/** @deprecated Prefer `EntryVariant`. */
|
|
4
|
+
export type ResultRowVariant = EntryVariant;
|
|
5
|
+
/** @deprecated Prefer `EntryState`. */
|
|
6
|
+
export type ResultRowState = EntryState;
|
|
4
7
|
export type ResultRowProps = {
|
|
5
|
-
variant?:
|
|
6
|
-
state?:
|
|
8
|
+
variant?: EntryVariant;
|
|
9
|
+
state?: EntryState;
|
|
7
10
|
title?: ReactNode;
|
|
8
|
-
/** Secondary line — excerpt, metadata, or highlighted query match. */
|
|
9
11
|
subtitle?: ReactNode;
|
|
10
12
|
onClick?: () => void;
|
|
11
13
|
className?: string;
|
|
12
14
|
};
|
|
15
|
+
/**
|
|
16
|
+
* @deprecated Prefer `Entry` — ResultRow is a thin alias for search lists.
|
|
17
|
+
*/
|
|
13
18
|
export declare const ResultRow: ({ variant, state, title, subtitle, onClick, className, }: ResultRowProps) => import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export type { EntryProps };
|
package/package.json
CHANGED
package/src/components/Entry.tsx
CHANGED
|
@@ -1,64 +1,118 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
-
import { ChatIcon, IssuesIcon } from "../icons";
|
|
2
|
+
import { ChatIcon, IssuesIcon, ReportIcon, StatusIcon } from "../icons";
|
|
3
3
|
import { cn } from "../utils/cn";
|
|
4
4
|
|
|
5
|
-
export type
|
|
6
|
-
|
|
5
|
+
export type EntryVariant = "chat" | "issue" | "report";
|
|
6
|
+
/** @deprecated Prefer `EntryVariant`. */
|
|
7
|
+
export type EntryType = EntryVariant;
|
|
8
|
+
export type EntryState = "idle" | "active";
|
|
7
9
|
|
|
8
10
|
export type EntryProps = {
|
|
9
|
-
type
|
|
11
|
+
/** Visual type — drives the default leading icon. */
|
|
12
|
+
variant?: EntryVariant;
|
|
13
|
+
/** @deprecated Use `variant`. */
|
|
14
|
+
type?: EntryVariant;
|
|
10
15
|
state?: EntryState;
|
|
11
|
-
title
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
title?: ReactNode;
|
|
17
|
+
/** Secondary line — excerpt, metadata, or highlighted query match. */
|
|
18
|
+
subtitle?: ReactNode;
|
|
19
|
+
/** Unread count badge in the title row (Figma red pill). */
|
|
20
|
+
count?: number;
|
|
21
|
+
/** Trailing actions (e.g. ellipsis menu). Shown on hover / when forced. */
|
|
22
|
+
trailing?: ReactNode;
|
|
23
|
+
/** Override the default variant icon. */
|
|
24
|
+
icon?: ReactNode;
|
|
14
25
|
onClick?: () => void;
|
|
15
26
|
className?: string;
|
|
27
|
+
/** @deprecated Use `count` or `trailing`. */
|
|
28
|
+
meta?: ReactNode;
|
|
16
29
|
};
|
|
17
30
|
|
|
18
|
-
const
|
|
19
|
-
chat: <ChatIcon
|
|
20
|
-
issue: <
|
|
31
|
+
const variantIcons: Record<EntryVariant, ReactNode> = {
|
|
32
|
+
chat: <ChatIcon className="size-4" />,
|
|
33
|
+
issue: <StatusIcon className="size-4" />,
|
|
34
|
+
report: <ReportIcon className="size-4" />,
|
|
21
35
|
};
|
|
22
36
|
|
|
37
|
+
/**
|
|
38
|
+
* List entry row — Figma `Entry` (389:10001).
|
|
39
|
+
* Shared by search results and activity lists.
|
|
40
|
+
*/
|
|
23
41
|
export const Entry = ({
|
|
42
|
+
variant,
|
|
24
43
|
type,
|
|
25
44
|
state = "idle",
|
|
26
|
-
title,
|
|
45
|
+
title = "Title",
|
|
27
46
|
subtitle,
|
|
28
|
-
|
|
47
|
+
count,
|
|
48
|
+
trailing,
|
|
49
|
+
icon,
|
|
29
50
|
onClick,
|
|
30
51
|
className,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
{typeIcons[type]}
|
|
49
|
-
</span>
|
|
50
|
-
<span className="min-w-0 flex-1">
|
|
51
|
-
<span className="block truncate text-caption-2-em">{title}</span>
|
|
52
|
-
{subtitle && (
|
|
53
|
-
<span className="entry-subtitle mt-0.5 block truncate text-footnote text-display-on-light-tertiary">
|
|
54
|
-
{subtitle}
|
|
55
|
-
</span>
|
|
52
|
+
meta,
|
|
53
|
+
}: EntryProps) => {
|
|
54
|
+
const resolvedVariant: EntryVariant = variant ?? type ?? "chat";
|
|
55
|
+
const isInteractive = typeof onClick === "function";
|
|
56
|
+
const Comp = isInteractive ? "button" : "div";
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<Comp
|
|
60
|
+
{...(isInteractive ? { type: "button" as const } : {})}
|
|
61
|
+
data-variant={resolvedVariant}
|
|
62
|
+
data-state={state}
|
|
63
|
+
onClick={onClick}
|
|
64
|
+
className={cn(
|
|
65
|
+
"group flex w-full items-center gap-4 rounded-control p-2 text-left transition-colors",
|
|
66
|
+
"hover:bg-[rgba(38,36,32,0.04)]",
|
|
67
|
+
state === "active" && "bg-[rgba(38,36,32,0.04)]",
|
|
68
|
+
className,
|
|
56
69
|
)}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
70
|
+
>
|
|
71
|
+
<span className="shrink-0 text-display-on-light-secondary">
|
|
72
|
+
{icon ?? variantIcons[resolvedVariant] ?? (
|
|
73
|
+
<IssuesIcon className="size-4" />
|
|
74
|
+
)}
|
|
61
75
|
</span>
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
76
|
+
|
|
77
|
+
<span className="flex min-w-0 flex-1 flex-col">
|
|
78
|
+
<span className="flex min-h-6 w-full items-center gap-4">
|
|
79
|
+
<span className="min-w-0 flex-1 truncate text-caption-1-em text-display-on-light-primary">
|
|
80
|
+
{title}
|
|
81
|
+
</span>
|
|
82
|
+
{typeof count === "number" && count > 0 && (
|
|
83
|
+
<span
|
|
84
|
+
className="inline-flex min-h-5 min-w-5 shrink-0 items-center justify-center rounded-full bg-red-600 px-0.5 text-footnote-em text-white"
|
|
85
|
+
aria-label={`${count} unread`}
|
|
86
|
+
>
|
|
87
|
+
{count > 99 ? "99+" : count}
|
|
88
|
+
</span>
|
|
89
|
+
)}
|
|
90
|
+
{meta != null && typeof count !== "number" && (
|
|
91
|
+
<span className="shrink-0 text-footnote text-display-on-light-quaternary">
|
|
92
|
+
{meta}
|
|
93
|
+
</span>
|
|
94
|
+
)}
|
|
95
|
+
</span>
|
|
96
|
+
|
|
97
|
+
{(subtitle != null && subtitle !== false) || trailing ? (
|
|
98
|
+
<span className="flex min-h-6 w-full items-center gap-4">
|
|
99
|
+
{subtitle != null && subtitle !== false && (
|
|
100
|
+
<span className="min-w-0 flex-1 truncate text-caption-2 text-display-on-light-secondary">
|
|
101
|
+
{subtitle}
|
|
102
|
+
</span>
|
|
103
|
+
)}
|
|
104
|
+
{trailing != null && (
|
|
105
|
+
<span
|
|
106
|
+
className="shrink-0"
|
|
107
|
+
onClick={(event) => event.stopPropagation()}
|
|
108
|
+
onKeyDown={(event) => event.stopPropagation()}
|
|
109
|
+
>
|
|
110
|
+
{trailing}
|
|
111
|
+
</span>
|
|
112
|
+
)}
|
|
113
|
+
</span>
|
|
114
|
+
) : null}
|
|
115
|
+
</span>
|
|
116
|
+
</Comp>
|
|
117
|
+
);
|
|
118
|
+
};
|
package/src/components/Tabs.tsx
CHANGED
|
@@ -51,7 +51,7 @@ export const TabsList = forwardRef<
|
|
|
51
51
|
ref={ref}
|
|
52
52
|
className={cn(
|
|
53
53
|
"flex items-center",
|
|
54
|
-
type === "tabs" && "gap-
|
|
54
|
+
type === "tabs" && "gap-6 border-b border-divider-primary",
|
|
55
55
|
type === "pills" && "gap-2",
|
|
56
56
|
className,
|
|
57
57
|
)}
|
|
@@ -82,7 +82,7 @@ export const TabsTrigger = forwardRef<
|
|
|
82
82
|
"inline-flex items-center justify-center transition-colors outline-none",
|
|
83
83
|
"disabled:pointer-events-none disabled:opacity-50",
|
|
84
84
|
type === "tabs" && [
|
|
85
|
-
"relative px-
|
|
85
|
+
"relative h-12 gap-2 px-0 py-0 text-caption-2 text-display-on-light-secondary",
|
|
86
86
|
"hover:text-display-on-light-primary",
|
|
87
87
|
"data-[state=active]:text-caption-2-em data-[state=active]:text-display-on-light-primary",
|
|
88
88
|
"data-[state=active]:after:absolute data-[state=active]:after:inset-x-0 data-[state=active]:after:-bottom-px",
|
|
@@ -99,18 +99,26 @@ export const TabsTrigger = forwardRef<
|
|
|
99
99
|
{...props}
|
|
100
100
|
>
|
|
101
101
|
{children}
|
|
102
|
-
{typeof count === "number" &&
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
102
|
+
{typeof count === "number" &&
|
|
103
|
+
(type === "pills" ? (
|
|
104
|
+
<span
|
|
105
|
+
className={cn(
|
|
106
|
+
"inline-flex size-6 shrink-0 items-center justify-center rounded-full text-footnote-em",
|
|
107
|
+
"bg-accent-bg-light text-display-on-light-secondary",
|
|
108
|
+
"group-data-[state=active]:text-display-on-light-tertiary",
|
|
109
|
+
)}
|
|
110
|
+
aria-label={`Count: ${count}`}
|
|
111
|
+
>
|
|
112
|
+
{count > 99 ? "99+" : count}
|
|
113
|
+
</span>
|
|
114
|
+
) : (
|
|
115
|
+
<span
|
|
116
|
+
className="px-1 text-caption-2 text-display-on-light-secondary"
|
|
117
|
+
aria-label={`Count: ${count}`}
|
|
118
|
+
>
|
|
119
|
+
{count > 99 ? "99+" : count}
|
|
120
|
+
</span>
|
|
121
|
+
))}
|
|
114
122
|
</TabsPrimitive.Trigger>
|
|
115
123
|
);
|
|
116
124
|
});
|
package/src/components/index.ts
CHANGED
|
@@ -17,7 +17,7 @@ export {
|
|
|
17
17
|
type TabsType,
|
|
18
18
|
} from "./Tabs";
|
|
19
19
|
export { Header, type HeaderProps, type HeaderVariant } from "./Header";
|
|
20
|
-
export { Entry, type EntryProps, type EntryType, type EntryState } from "./Entry";
|
|
20
|
+
export { Entry, type EntryProps, type EntryType, type EntryState, type EntryVariant } from "./Entry";
|
|
21
21
|
export { EmptyState, type EmptyStateProps } from "./EmptyState";
|
|
22
22
|
export {
|
|
23
23
|
Modal,
|
package/src/index.ts
CHANGED
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
Entry,
|
|
4
|
+
type EntryProps,
|
|
5
|
+
type EntryState,
|
|
6
|
+
type EntryVariant,
|
|
7
|
+
} from "../../components/Entry";
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
export type
|
|
9
|
+
/** @deprecated Prefer `EntryVariant`. */
|
|
10
|
+
export type ResultRowVariant = EntryVariant;
|
|
11
|
+
/** @deprecated Prefer `EntryState`. */
|
|
12
|
+
export type ResultRowState = EntryState;
|
|
7
13
|
|
|
8
14
|
export type ResultRowProps = {
|
|
9
|
-
variant?:
|
|
10
|
-
state?:
|
|
15
|
+
variant?: EntryVariant;
|
|
16
|
+
state?: EntryState;
|
|
11
17
|
title?: ReactNode;
|
|
12
|
-
/** Secondary line — excerpt, metadata, or highlighted query match. */
|
|
13
18
|
subtitle?: ReactNode;
|
|
14
19
|
onClick?: () => void;
|
|
15
20
|
className?: string;
|
|
16
21
|
};
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
issue: <IssuesIcon className="size-4" />,
|
|
22
|
-
};
|
|
23
|
-
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated Prefer `Entry` — ResultRow is a thin alias for search lists.
|
|
25
|
+
*/
|
|
24
26
|
export const ResultRow = ({
|
|
25
27
|
variant = "report",
|
|
26
28
|
state = "idle",
|
|
@@ -29,30 +31,14 @@ export const ResultRow = ({
|
|
|
29
31
|
onClick,
|
|
30
32
|
className,
|
|
31
33
|
}: ResultRowProps) => (
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
state === "active" && "bg-[rgba(38,36,32,0.04)]",
|
|
38
|
-
className,
|
|
39
|
-
)}
|
|
40
|
-
data-variant={variant}
|
|
41
|
-
data-state={state}
|
|
34
|
+
<Entry
|
|
35
|
+
variant={variant}
|
|
36
|
+
state={state}
|
|
37
|
+
title={title}
|
|
38
|
+
subtitle={subtitle}
|
|
42
39
|
onClick={onClick}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
{variantIcons[variant]}
|
|
46
|
-
</span>
|
|
47
|
-
<span className="min-w-0 flex-1">
|
|
48
|
-
<span className="block truncate text-caption-1-em text-display-on-light-primary">
|
|
49
|
-
{title}
|
|
50
|
-
</span>
|
|
51
|
-
{subtitle != null && subtitle !== false && (
|
|
52
|
-
<span className="mt-0.5 block truncate text-caption-2 text-display-on-light-secondary">
|
|
53
|
-
{subtitle}
|
|
54
|
-
</span>
|
|
55
|
-
)}
|
|
56
|
-
</span>
|
|
57
|
-
</button>
|
|
40
|
+
className={className}
|
|
41
|
+
/>
|
|
58
42
|
);
|
|
43
|
+
|
|
44
|
+
export type { EntryProps };
|
|
@@ -82,9 +82,29 @@ export const ContentCanvas = () => (
|
|
|
82
82
|
|
|
83
83
|
<FigmaSection label="Entry">
|
|
84
84
|
<div className="max-w-xl space-y-2">
|
|
85
|
-
<Entry
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
<Entry
|
|
86
|
+
variant="chat"
|
|
87
|
+
title="Hull inspection report"
|
|
88
|
+
subtitle="We’ve got a persistent oil leak from the fuel pump."
|
|
89
|
+
/>
|
|
90
|
+
<Entry
|
|
91
|
+
variant="chat"
|
|
92
|
+
state="active"
|
|
93
|
+
title="Ballast Pump Not Starting"
|
|
94
|
+
subtitle="The fuel pump won’t start consistently."
|
|
95
|
+
trailing={<span className="text-display-on-light-secondary">···</span>}
|
|
96
|
+
/>
|
|
97
|
+
<Entry
|
|
98
|
+
variant="issue"
|
|
99
|
+
title="Excessive Rust on Fuel Pump"
|
|
100
|
+
subtitle="Created by Jake Silva on March 28"
|
|
101
|
+
count={3}
|
|
102
|
+
/>
|
|
103
|
+
<Entry
|
|
104
|
+
variant="report"
|
|
105
|
+
title="Engine Room Oil Leak"
|
|
106
|
+
subtitle="We’ve spotted a steady oil leak near the fuel pump."
|
|
107
|
+
/>
|
|
88
108
|
</div>
|
|
89
109
|
</FigmaSection>
|
|
90
110
|
|