@trackunit/react-components 3.1.7 → 3.2.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/index.cjs.js +1012 -570
- package/index.esm.js +1011 -571
- package/package.json +6 -6
- package/src/components/AssetIdentity/IdentityCard.d.ts +173 -0
- package/src/components/AssetIdentity/IdentityCard.variants.d.ts +120 -0
- package/src/components/AssetIdentity/IdentityCardSkeleton.d.ts +95 -0
- package/src/components/AssetIdentity/useIdentityImageSize.d.ts +32 -0
- package/src/components/Indicator/Indicator.d.ts +4 -4
- package/src/components/Indicator/Indicator.variants.d.ts +15 -2
- package/src/index.d.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-components",
|
|
3
|
-
"version": "3.1
|
|
3
|
+
"version": "3.2.1",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"migrations": "./migrations.json",
|
|
@@ -14,16 +14,16 @@
|
|
|
14
14
|
"@floating-ui/react": "^0.26.25",
|
|
15
15
|
"string-ts": "^2.0.0",
|
|
16
16
|
"tailwind-merge": "^2.0.0",
|
|
17
|
-
"@trackunit/ui-design-tokens": "1.15.
|
|
18
|
-
"@trackunit/css-class-variance-utilities": "2.0.
|
|
19
|
-
"@trackunit/shared-utils": "1.16.
|
|
20
|
-
"@trackunit/ui-icons": "1.14.
|
|
17
|
+
"@trackunit/ui-design-tokens": "1.15.41",
|
|
18
|
+
"@trackunit/css-class-variance-utilities": "2.0.20",
|
|
19
|
+
"@trackunit/shared-utils": "1.16.55",
|
|
20
|
+
"@trackunit/ui-icons": "1.14.49",
|
|
21
21
|
"es-toolkit": "^1.39.10",
|
|
22
22
|
"@tanstack/react-virtual": "^3.14.3",
|
|
23
23
|
"dequal": "^2.0.3",
|
|
24
24
|
"fflate": "^0.8.2",
|
|
25
25
|
"zod": "^3.25.76",
|
|
26
|
-
"@trackunit/i18n-library-translation": "2.5.
|
|
26
|
+
"@trackunit/i18n-library-translation": "2.5.5"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
29
|
"react": "^19.0.0",
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { tailwindPalette, ThemeColors } from "@trackunit/ui-design-tokens";
|
|
2
|
+
import { MouseEventHandler, ReactElement, ReactNode } from "react";
|
|
3
|
+
import { CommonProps } from "../../common/CommonProps";
|
|
4
|
+
import { Refable } from "../../common/Refable";
|
|
5
|
+
import type { Styleable } from "../../common/Styleable";
|
|
6
|
+
type ThemeColorShades = `${keyof (typeof tailwindPalette)[keyof typeof tailwindPalette]}`;
|
|
7
|
+
export interface IdentityCardProps extends CommonProps, Styleable, Refable<HTMLDivElement> {
|
|
8
|
+
/**
|
|
9
|
+
* Asset name / primary heading. Truncates with an ellipsis when the row
|
|
10
|
+
* is narrow. Required — call-sites without a resolved name should render
|
|
11
|
+
* `IdentityCardSkeleton`, or pass a domain-appropriate fallback string.
|
|
12
|
+
*/
|
|
13
|
+
title: string;
|
|
14
|
+
/**
|
|
15
|
+
* Breadcrumb segments (e.g. `["Trackunit", "Scissorlift", "GS4390"]`).
|
|
16
|
+
* Rendered via the `DetailsList` component. Call-sites should pass a
|
|
17
|
+
* pre-filtered array of strings (e.g. `segments.filter(nonNullable)`);
|
|
18
|
+
* omit the prop entirely to hide the subtitle row.
|
|
19
|
+
*/
|
|
20
|
+
subtitle?: Array<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Optional asset image. Rendered to the left of the title at a 14:9
|
|
23
|
+
* aspect ratio (168/108, matching `AssetPageHeader`); the image height
|
|
24
|
+
* tracks the rendered text stack. Pass an `<img>` or `<OEMModelImage>`
|
|
25
|
+
* inside.
|
|
26
|
+
*
|
|
27
|
+
* Mutually exclusive with `thumbnail` — pass `image` for the "asset
|
|
28
|
+
* photo" shape, `thumbnail` for the ListItem-style colored icon badge
|
|
29
|
+
* (typical for sites / customers / users). If both are supplied, `image`
|
|
30
|
+
* wins.
|
|
31
|
+
*/
|
|
32
|
+
image?: ReactNode;
|
|
33
|
+
/**
|
|
34
|
+
* Optional icon-shaped thumbnail. Use for non-asset entities (sites, customers, users, …)
|
|
35
|
+
* to render a colored icon square.
|
|
36
|
+
*
|
|
37
|
+
* Pair with `thumbnailColor` and `thumbnailBackground` to color the icon
|
|
38
|
+
* and its badge. Mutually exclusive with `image` (which wins if both
|
|
39
|
+
* are supplied).
|
|
40
|
+
*/
|
|
41
|
+
thumbnail?: ReactElement;
|
|
42
|
+
/**
|
|
43
|
+
* Foreground color of the `thumbnail` icon. Applied as
|
|
44
|
+
* `text-${thumbnailColor}` on the badge container.
|
|
45
|
+
*
|
|
46
|
+
* @default "info-600"
|
|
47
|
+
*/
|
|
48
|
+
thumbnailColor?: `${ThemeColors}-${ThemeColorShades}` | `${ThemeColors}`;
|
|
49
|
+
/**
|
|
50
|
+
* Background color of the `thumbnail` badge. Applied as
|
|
51
|
+
* `bg-${thumbnailBackground}` on the badge container.
|
|
52
|
+
*
|
|
53
|
+
* @default "info-100"
|
|
54
|
+
*/
|
|
55
|
+
thumbnailBackground?: `${ThemeColors}-${ThemeColorShades}` | `${ThemeColors}`;
|
|
56
|
+
/**
|
|
57
|
+
* Status indicators row (criticality, activity, rental status, …).
|
|
58
|
+
* Pass domain-specific indicator chips as a fragment. Compose from
|
|
59
|
+
* `CriticalityIndicator` / `ActivityIndicator` / `RentalIndicator`
|
|
60
|
+
* (not `RentalTag`) at the call-site — rental sits in this row as a
|
|
61
|
+
* neutral indicator so it matches the chips beside it.
|
|
62
|
+
*/
|
|
63
|
+
statusIndicators?: ReactNode;
|
|
64
|
+
/**
|
|
65
|
+
* Right-side connectivity slot. Typically the last-GSM (`ChartBar`) and
|
|
66
|
+
* last-GPS (`MapPin`) chips from `AssetPageHeader` — a `Highlight` with
|
|
67
|
+
* `iconName` set to the last-seen icon (`color="clear"` when fresh,
|
|
68
|
+
* warning/danger when stale), or an "Untracked" label when the asset has
|
|
69
|
+
* no telematics device. Any `ReactNode` is accepted; wrap each chip as a
|
|
70
|
+
* single child so the slot's gap sits between chips.
|
|
71
|
+
*/
|
|
72
|
+
connectivity?: ReactNode;
|
|
73
|
+
/**
|
|
74
|
+
* Optional click handler for the card as a whole. When provided the card
|
|
75
|
+
* becomes interactive (hover state, cursor pointer) and a right-side
|
|
76
|
+
* `ChevronRight` icon is rendered as a visual affordance. The card also
|
|
77
|
+
* becomes keyboard-operable: `role="button"`, `tabIndex={0}`, and Enter /
|
|
78
|
+
* Space fire the handler alongside pointer clicks.
|
|
79
|
+
*/
|
|
80
|
+
onClick?: MouseEventHandler<HTMLDivElement>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* IdentityCard is the entity-agnostic, `Card`-wrapped identity component.
|
|
84
|
+
* It renders a slot-based identity strip (14:9 image, title + subtitle,
|
|
85
|
+
* status indicators, connectivity) inside a bordered surface —
|
|
86
|
+
* the compact list-row / drawer-row shape used to *reference* a related
|
|
87
|
+
* entity (an asset, site, customer, user, …) from inside a surface whose
|
|
88
|
+
* real focus is something else (an alert, service ticket, inspection, …).
|
|
89
|
+
*
|
|
90
|
+
* When `onClick` is supplied, the whole card becomes clickable and a
|
|
91
|
+
* `ChevronRight` icon is rendered on the right edge to signal navigation.
|
|
92
|
+
* Clickable cards are meant to route the user to the referenced entity's
|
|
93
|
+
* own surface — pair the handler with the app's navigation hook
|
|
94
|
+
* (`useNavigateInHost` from `@trackunit/react-core-hooks`) rather than
|
|
95
|
+
* treating it as an in-place action. Clickable cards are keyboard-operable
|
|
96
|
+
* out of the box: they receive `role="button"`, join the tab order, and
|
|
97
|
+
* activate on Enter / Space with a visible focus ring.
|
|
98
|
+
*
|
|
99
|
+
* The card stays presentational: it owns layout only; domain hydration
|
|
100
|
+
* (indicator wiring, translations, last-seen formatting,
|
|
101
|
+
* click targets) lives at the call-site. The API stays lean so the
|
|
102
|
+
* inline-reference shape doesn't compete with the surrounding surface's
|
|
103
|
+
* real focus.
|
|
104
|
+
*
|
|
105
|
+
* For the loading placeholder, use the paired `IdentityCardSkeleton`
|
|
106
|
+
* component — it renders the same layout with per-slot skeleton blocks.
|
|
107
|
+
*
|
|
108
|
+
* ### When to use
|
|
109
|
+
* Use `IdentityCard` when the surface you're building is really **about
|
|
110
|
+
* something else** (an alert, a service ticket, an inspection, a scheduled
|
|
111
|
+
* job) and needs to *mention* a related entity in its content, usually
|
|
112
|
+
* with a click-through to that entity's own page.
|
|
113
|
+
*
|
|
114
|
+
* ### When not to use
|
|
115
|
+
* Do not use `IdentityCard` as the header of a surface whose subject
|
|
116
|
+
* **is** the entity (an asset's side panel, an asset overview card, a
|
|
117
|
+
* page-level asset header). The card is a reference that lives *inside*
|
|
118
|
+
* someone else's content.
|
|
119
|
+
*
|
|
120
|
+
* @example Clickable asset reference inside a service ticket panel
|
|
121
|
+
* ```tsx
|
|
122
|
+
* import { IdentityCard, Highlight } from "@trackunit/react-components";
|
|
123
|
+
* import { useNavigateInHost } from "@trackunit/react-core-hooks";
|
|
124
|
+
*
|
|
125
|
+
* const ServicedAssetRow = ({ assetId }: { assetId: string }) => {
|
|
126
|
+
* const { gotoAssetHome } = useNavigateInHost();
|
|
127
|
+
* return (
|
|
128
|
+
* <IdentityCard
|
|
129
|
+
* title="Trackunit-AWP343"
|
|
130
|
+
* subtitle={["Trackunit", "Scissorlift", "GS4390"]}
|
|
131
|
+
* image={<OEMModelImage brandName="Trackunit" model="GS4390" />}
|
|
132
|
+
* statusIndicators={statusChips}
|
|
133
|
+
* connectivity={
|
|
134
|
+
* <>
|
|
135
|
+
* <Highlight color="clear" iconName="ChartBar" size="small">
|
|
136
|
+
* 2h
|
|
137
|
+
* </Highlight>
|
|
138
|
+
* <Highlight color="danger" iconName="MapPin" size="small">
|
|
139
|
+
* 2y
|
|
140
|
+
* </Highlight>
|
|
141
|
+
* </>
|
|
142
|
+
* }
|
|
143
|
+
* onClick={() => gotoAssetHome(assetId)}
|
|
144
|
+
* />
|
|
145
|
+
* );
|
|
146
|
+
* };
|
|
147
|
+
* ```
|
|
148
|
+
* @example Non-clickable (chevron omitted)
|
|
149
|
+
* ```tsx
|
|
150
|
+
* <IdentityCard
|
|
151
|
+
* image={<OEMModelImage brandName="Trackunit" model="GS4390" />}
|
|
152
|
+
* title="Trackunit-AWP343"
|
|
153
|
+
* subtitle={["Trackunit", "Scissorlift", "GS4390"]}
|
|
154
|
+
* />
|
|
155
|
+
* ```
|
|
156
|
+
* @example Non-asset entity (site) with an icon thumbnail
|
|
157
|
+
* ```tsx
|
|
158
|
+
* import { IdentityCard, Icon } from "@trackunit/react-components";
|
|
159
|
+
*
|
|
160
|
+
* <IdentityCard
|
|
161
|
+
* title="Riverside Job Site"
|
|
162
|
+
* subtitle={["Riverside Street 12, Copenhagen, Denmark"]}
|
|
163
|
+
* thumbnail={<Icon name="ConstructionCone" />}
|
|
164
|
+
* thumbnailColor="site_construction_site-500"
|
|
165
|
+
* thumbnailBackground="site_construction_site-100"
|
|
166
|
+
* onClick={() => gotoSiteHome(siteId)}
|
|
167
|
+
* />
|
|
168
|
+
* ```
|
|
169
|
+
* @param {IdentityCardProps} props - The props for the IdentityCard component
|
|
170
|
+
* @returns {ReactElement} IdentityCard component
|
|
171
|
+
*/
|
|
172
|
+
export declare const IdentityCard: ({ title, subtitle, image, thumbnail, thumbnailColor, thumbnailBackground, statusIndicators, connectivity, onClick, className, "data-testid": dataTestId, style, ref, }: IdentityCardProps) => ReactElement;
|
|
173
|
+
export {};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
export declare const cvaCardContentRow: import("cva").CVAComponent<Omit<{
|
|
2
|
+
base: string[];
|
|
3
|
+
}, "defaultVariants"> & {
|
|
4
|
+
variants: unknown;
|
|
5
|
+
defaultVariants: Omit<{}, never>;
|
|
6
|
+
}, unknown>;
|
|
7
|
+
export declare const cvaCardMain: import("cva").CVAComponent<Omit<{
|
|
8
|
+
base: string[];
|
|
9
|
+
variants: {
|
|
10
|
+
singleLine: {
|
|
11
|
+
true: string;
|
|
12
|
+
false: string;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
defaultVariants: {
|
|
16
|
+
singleLine: false;
|
|
17
|
+
};
|
|
18
|
+
}, "defaultVariants"> & {
|
|
19
|
+
variants: {
|
|
20
|
+
singleLine: {
|
|
21
|
+
true: string;
|
|
22
|
+
false: string;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
defaultVariants: Omit<{}, "singleLine"> & {
|
|
26
|
+
singleLine: false;
|
|
27
|
+
};
|
|
28
|
+
}, {
|
|
29
|
+
singleLine: {
|
|
30
|
+
true: string;
|
|
31
|
+
false: string;
|
|
32
|
+
};
|
|
33
|
+
}>;
|
|
34
|
+
export declare const cvaCardImage: import("cva").CVAComponent<Omit<{
|
|
35
|
+
base: string[];
|
|
36
|
+
}, "defaultVariants"> & {
|
|
37
|
+
variants: unknown;
|
|
38
|
+
defaultVariants: Omit<{}, never>;
|
|
39
|
+
}, unknown>;
|
|
40
|
+
export declare const cvaCardThumbnail: import("cva").CVAComponent<Omit<{
|
|
41
|
+
base: string[];
|
|
42
|
+
}, "defaultVariants"> & {
|
|
43
|
+
variants: unknown;
|
|
44
|
+
defaultVariants: Omit<{}, never>;
|
|
45
|
+
}, unknown>;
|
|
46
|
+
export declare const cvaCardTextStack: import("cva").CVAComponent<Omit<{
|
|
47
|
+
base: string[];
|
|
48
|
+
}, "defaultVariants"> & {
|
|
49
|
+
variants: unknown;
|
|
50
|
+
defaultVariants: Omit<{}, never>;
|
|
51
|
+
}, unknown>;
|
|
52
|
+
export declare const cvaCardIdentityGroup: import("cva").CVAComponent<Omit<{
|
|
53
|
+
base: string[];
|
|
54
|
+
variants: {
|
|
55
|
+
singleLine: {
|
|
56
|
+
true: string[];
|
|
57
|
+
false: string;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
defaultVariants: {
|
|
61
|
+
singleLine: false;
|
|
62
|
+
};
|
|
63
|
+
}, "defaultVariants"> & {
|
|
64
|
+
variants: {
|
|
65
|
+
singleLine: {
|
|
66
|
+
true: string[];
|
|
67
|
+
false: string;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
defaultVariants: Omit<{}, "singleLine"> & {
|
|
71
|
+
singleLine: false;
|
|
72
|
+
};
|
|
73
|
+
}, {
|
|
74
|
+
singleLine: {
|
|
75
|
+
true: string[];
|
|
76
|
+
false: string;
|
|
77
|
+
};
|
|
78
|
+
}>;
|
|
79
|
+
export declare const cvaCardTitleRow: import("cva").CVAComponent<Omit<{
|
|
80
|
+
base: string[];
|
|
81
|
+
}, "defaultVariants"> & {
|
|
82
|
+
variants: unknown;
|
|
83
|
+
defaultVariants: Omit<{}, never>;
|
|
84
|
+
}, unknown>;
|
|
85
|
+
export declare const cvaCardTitleCluster: import("cva").CVAComponent<Omit<{
|
|
86
|
+
base: string[];
|
|
87
|
+
}, "defaultVariants"> & {
|
|
88
|
+
variants: unknown;
|
|
89
|
+
defaultVariants: Omit<{}, never>;
|
|
90
|
+
}, unknown>;
|
|
91
|
+
export declare const cvaCardTitle: import("cva").CVAComponent<Omit<{
|
|
92
|
+
base: string[];
|
|
93
|
+
}, "defaultVariants"> & {
|
|
94
|
+
variants: unknown;
|
|
95
|
+
defaultVariants: Omit<{}, never>;
|
|
96
|
+
}, unknown>;
|
|
97
|
+
export declare const cvaCardStatusRow: import("cva").CVAComponent<Omit<{
|
|
98
|
+
base: string[];
|
|
99
|
+
}, "defaultVariants"> & {
|
|
100
|
+
variants: unknown;
|
|
101
|
+
defaultVariants: Omit<{}, never>;
|
|
102
|
+
}, unknown>;
|
|
103
|
+
export declare const cvaCardStatusSkeletonRow: import("cva").CVAComponent<Omit<{
|
|
104
|
+
base: string[];
|
|
105
|
+
}, "defaultVariants"> & {
|
|
106
|
+
variants: unknown;
|
|
107
|
+
defaultVariants: Omit<{}, never>;
|
|
108
|
+
}, unknown>;
|
|
109
|
+
export declare const cvaCardConnectivity: import("cva").CVAComponent<Omit<{
|
|
110
|
+
base: string[];
|
|
111
|
+
}, "defaultVariants"> & {
|
|
112
|
+
variants: unknown;
|
|
113
|
+
defaultVariants: Omit<{}, never>;
|
|
114
|
+
}, unknown>;
|
|
115
|
+
export declare const cvaCardChevron: import("cva").CVAComponent<Omit<{
|
|
116
|
+
base: string[];
|
|
117
|
+
}, "defaultVariants"> & {
|
|
118
|
+
variants: unknown;
|
|
119
|
+
defaultVariants: Omit<{}, never>;
|
|
120
|
+
}, unknown>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { ReactElement } from "react";
|
|
2
|
+
import { CommonProps } from "../../common/CommonProps";
|
|
3
|
+
import { Refable } from "../../common/Refable";
|
|
4
|
+
import type { Styleable } from "../../common/Styleable";
|
|
5
|
+
export interface IdentityCardSkeletonProps extends CommonProps, Styleable, Refable<HTMLDivElement> {
|
|
6
|
+
/**
|
|
7
|
+
* When true, renders an image slot with a size-matched skeleton block. The
|
|
8
|
+
* slot's height tracks the rendered text stack at a 14:9 aspect ratio
|
|
9
|
+
* (168/108, matching `AssetPageHeader`) — same measurement approach as
|
|
10
|
+
* the loaded `IdentityCard` so the skeleton → loaded transition doesn't
|
|
11
|
+
* jump.
|
|
12
|
+
*
|
|
13
|
+
* Mutually exclusive with `hasThumbnail` — `hasImage` wins if both
|
|
14
|
+
* are true (mirrors the loaded card's slot precedence).
|
|
15
|
+
*
|
|
16
|
+
* @default false
|
|
17
|
+
*/
|
|
18
|
+
hasImage?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* When true, renders a 44×44 rounded-md skeleton badge in the thumbnail
|
|
21
|
+
* slot — the loading counterpart to the loaded card's `thumbnail` prop.
|
|
22
|
+
* Use for non-asset entities (sites, customers, users, …).
|
|
23
|
+
*
|
|
24
|
+
* Mutually exclusive with `hasImage` — `hasImage` wins if both are true.
|
|
25
|
+
*
|
|
26
|
+
* @default false
|
|
27
|
+
*/
|
|
28
|
+
hasThumbnail?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* When true, renders a subtitle skeleton line under the title. Kept on by
|
|
31
|
+
* default so `<IdentityCardSkeleton />` with no props renders the
|
|
32
|
+
* canonical compact identity card shape (title + subtitle).
|
|
33
|
+
*
|
|
34
|
+
* @default true
|
|
35
|
+
*/
|
|
36
|
+
hasSubtitle?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* When true, renders a status-row skeleton (two chip placeholders) under
|
|
39
|
+
* the identity group.
|
|
40
|
+
*
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
43
|
+
hasStatusIndicators?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* When true, renders a right-side connectivity skeleton on the title row.
|
|
46
|
+
*
|
|
47
|
+
* @default false
|
|
48
|
+
*/
|
|
49
|
+
hasConnectivity?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* When true, renders the same right-side `ChevronRight` as a clickable
|
|
52
|
+
* `IdentityCard` — the icon is known up front, so it is not skeletoned.
|
|
53
|
+
* Keeps the skeleton → loaded transition from jumping.
|
|
54
|
+
*
|
|
55
|
+
* @default false
|
|
56
|
+
*/
|
|
57
|
+
hasChevron?: boolean;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* IdentityCardSkeleton is the loading placeholder paired with
|
|
61
|
+
* `IdentityCard`. It renders per-slot skeleton blocks (title +
|
|
62
|
+
* optional subtitle / status indicators / image / thumbnail / connectivity)
|
|
63
|
+
* inside the same `Card` shell so the skeleton → loaded
|
|
64
|
+
* transition is visually stable. When `hasChevron` is on, the real
|
|
65
|
+
* `ChevronRight` is shown — that icon does not depend on loaded data.
|
|
66
|
+
*
|
|
67
|
+
* The slot toggles (`hasImage`, `hasThumbnail`, `hasSubtitle`,
|
|
68
|
+
* `hasStatusIndicators`, `hasConnectivity`, `hasChevron`) are the skeleton
|
|
69
|
+
* counterparts to the loaded `IdentityCard`'s slot props / `onClick` —
|
|
70
|
+
* flip on the slots you'll render once the data resolves.
|
|
71
|
+
*
|
|
72
|
+
* ### When to use
|
|
73
|
+
* Use `IdentityCardSkeleton` in place of `IdentityCard` while
|
|
74
|
+
* the referenced entity's data is being fetched.
|
|
75
|
+
*
|
|
76
|
+
* ### When not to use
|
|
77
|
+
* Do not use for generic text loading — use `SkeletonLabel` /
|
|
78
|
+
* `SkeletonBlock` directly. Do not use to represent partial data (some
|
|
79
|
+
* fields loaded, others not); render `IdentityCard` with the fields
|
|
80
|
+
* you have and omit the rest.
|
|
81
|
+
*
|
|
82
|
+
* @example Compact card (title + subtitle)
|
|
83
|
+
* ```tsx
|
|
84
|
+
* import { IdentityCardSkeleton } from "@trackunit/react-components";
|
|
85
|
+
*
|
|
86
|
+
* const Loading = () => <IdentityCardSkeleton />;
|
|
87
|
+
* ```
|
|
88
|
+
* @example Clickable card with image + status + connectivity
|
|
89
|
+
* ```tsx
|
|
90
|
+
* <IdentityCardSkeleton hasImage hasStatusIndicators hasConnectivity hasChevron />
|
|
91
|
+
* ```
|
|
92
|
+
* @param {IdentityCardSkeletonProps} props - The props for the IdentityCardSkeleton component
|
|
93
|
+
* @returns {ReactElement} IdentityCardSkeleton component
|
|
94
|
+
*/
|
|
95
|
+
export declare const IdentityCardSkeleton: ({ hasImage, hasThumbnail, hasSubtitle, hasStatusIndicators, hasConnectivity, hasChevron, className, "data-testid": dataTestId, style, ref, }: IdentityCardSkeletonProps) => ReactElement;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type RefCallback } from "react";
|
|
2
|
+
export declare const IDENTITY_MIN_IMAGE_HEIGHT_PX = 44;
|
|
3
|
+
export declare const IDENTITY_IMAGE_ASPECT_RATIO: number;
|
|
4
|
+
export type IdentityImageSize = {
|
|
5
|
+
readonly height: number;
|
|
6
|
+
readonly width: number;
|
|
7
|
+
};
|
|
8
|
+
export type IdentityImageSizeResult = {
|
|
9
|
+
readonly imageSize: IdentityImageSize | null;
|
|
10
|
+
readonly textStackRef: RefCallback<HTMLDivElement>;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Measures the rendered text-stack height and returns matching image
|
|
14
|
+
* dimensions at a 14:9 (168/108) aspect ratio, clamped to the identity
|
|
15
|
+
* minimum so title-only identities keep a reasonable image footprint. Kept
|
|
16
|
+
* as a shared hook so the loaded `IdentityCard` and its `IdentityCardSkeleton`
|
|
17
|
+
* cannot drift out of sync — the skeleton → loaded transition would jump
|
|
18
|
+
* if the two measurements diverged.
|
|
19
|
+
*
|
|
20
|
+
* Measured in `useLayoutEffect` so the image slot is sized before the
|
|
21
|
+
* browser paints. `useMeasure` is the usual choice here, but it observes
|
|
22
|
+
* in `useEffect` (after paint), which would flash the unsized
|
|
23
|
+
* `aspect-[14/9]` fallback for a frame.
|
|
24
|
+
*
|
|
25
|
+
* Attach `textStackRef` to the text-stack container; subsequent layout
|
|
26
|
+
* changes (title text, subtitle wrap, status row toggling on/off)
|
|
27
|
+
* re-measure automatically.
|
|
28
|
+
*
|
|
29
|
+
* @param enabled - When false, the hook is inert (no measurement). Use this
|
|
30
|
+
* to gate on `showImage` / `hasImage`.
|
|
31
|
+
*/
|
|
32
|
+
export declare const useIdentityImageSize: (enabled: boolean) => IdentityImageSizeResult;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ActivityColors, CriticalityColors, GeneralColors, IntentColors, RentalStatusColors, SitesColors, UtilizationColors } from "@trackunit/ui-design-tokens";
|
|
2
|
-
import { ReactElement } from "react";
|
|
2
|
+
import { ReactElement, ReactNode } from "react";
|
|
3
3
|
import { CommonProps } from "../../common/CommonProps";
|
|
4
|
-
import type { Styleable } from "../../common/Styleable";
|
|
5
4
|
import { Refable } from "../../common/Refable";
|
|
5
|
+
import type { Styleable } from "../../common/Styleable";
|
|
6
6
|
export interface IndicatorProps extends CommonProps, Styleable, Refable<HTMLDivElement> {
|
|
7
7
|
/**
|
|
8
8
|
* The icon to be rendered inside the indicator component
|
|
@@ -21,9 +21,9 @@ export interface IndicatorProps extends CommonProps, Styleable, Refable<HTMLDivE
|
|
|
21
21
|
*/
|
|
22
22
|
weight?: "normal" | "medium";
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
24
|
+
* Content displayed next to the indicator. String labels are capitalized; custom content retains its own casing.
|
|
25
25
|
*/
|
|
26
|
-
label?:
|
|
26
|
+
label?: ReactNode;
|
|
27
27
|
/**
|
|
28
28
|
* A boolean parameter to display or hide icon background, default value is true
|
|
29
29
|
*/
|
|
@@ -11,8 +11,11 @@ export declare const cvaIndicatorIcon: import("cva").CVAComponent<Omit<{
|
|
|
11
11
|
defaultVariants: Omit<{}, never>;
|
|
12
12
|
}, unknown>;
|
|
13
13
|
export declare const cvaIndicatorLabel: import("cva").CVAComponent<Omit<{
|
|
14
|
-
base: string[];
|
|
15
14
|
variants: {
|
|
15
|
+
content: {
|
|
16
|
+
text: string;
|
|
17
|
+
custom: null;
|
|
18
|
+
};
|
|
16
19
|
size: {
|
|
17
20
|
small: string;
|
|
18
21
|
medium: string;
|
|
@@ -27,12 +30,17 @@ export declare const cvaIndicatorLabel: import("cva").CVAComponent<Omit<{
|
|
|
27
30
|
};
|
|
28
31
|
};
|
|
29
32
|
defaultVariants: {
|
|
33
|
+
content: "text";
|
|
30
34
|
size: "medium";
|
|
31
35
|
weight: "medium";
|
|
32
36
|
background: "visible";
|
|
33
37
|
};
|
|
34
38
|
}, "defaultVariants"> & {
|
|
35
39
|
variants: {
|
|
40
|
+
content: {
|
|
41
|
+
text: string;
|
|
42
|
+
custom: null;
|
|
43
|
+
};
|
|
36
44
|
size: {
|
|
37
45
|
small: string;
|
|
38
46
|
medium: string;
|
|
@@ -46,12 +54,17 @@ export declare const cvaIndicatorLabel: import("cva").CVAComponent<Omit<{
|
|
|
46
54
|
hidden: string;
|
|
47
55
|
};
|
|
48
56
|
};
|
|
49
|
-
defaultVariants: Omit<{}, "size" | "weight" | "background"> & {
|
|
57
|
+
defaultVariants: Omit<{}, "content" | "size" | "weight" | "background"> & {
|
|
58
|
+
content: "text";
|
|
50
59
|
size: "medium";
|
|
51
60
|
weight: "medium";
|
|
52
61
|
background: "visible";
|
|
53
62
|
};
|
|
54
63
|
}, {
|
|
64
|
+
content: {
|
|
65
|
+
text: string;
|
|
66
|
+
custom: null;
|
|
67
|
+
};
|
|
55
68
|
size: {
|
|
56
69
|
small: string;
|
|
57
70
|
medium: string;
|
package/src/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export * from "./common/Size";
|
|
|
7
7
|
export * from "./common/StorybookProps";
|
|
8
8
|
export type { Styleable } from "./common/Styleable";
|
|
9
9
|
export * from "./components/Alert/Alert";
|
|
10
|
+
export * from "./components/AssetIdentity/IdentityCard";
|
|
11
|
+
export * from "./components/AssetIdentity/IdentityCardSkeleton";
|
|
10
12
|
export * from "./components/Badge/Badge";
|
|
11
13
|
export * from "./components/Breadcrumb/Breadcrumb";
|
|
12
14
|
export * from "./components/buttons/Button/Button";
|