@trackunit/react-compound-components 1.6.92 → 1.7.4

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 CHANGED
@@ -250,6 +250,122 @@ const ImageCollection = (props) => {
250
250
  }, ref: fileInputRef, type: "file" })] }));
251
251
  };
252
252
 
253
+ const cvaPreferenceCard = cssClassVarianceUtilities.cvaMerge(["rounded-lg", "border", "border-neutral-200", "bg-white", "w-full"], {
254
+ variants: {
255
+ disabled: {
256
+ true: [],
257
+ false: "",
258
+ },
259
+ clickable: {
260
+ true: ["cursor-pointer"],
261
+ false: "",
262
+ },
263
+ },
264
+ compoundVariants: [
265
+ {
266
+ disabled: true,
267
+ clickable: true,
268
+ class: "cursor-not-allowed",
269
+ },
270
+ {
271
+ disabled: false,
272
+ clickable: true,
273
+ class: "focus:ring-primary-600 focus:border-primary-600 focus:outline-none focus:ring-1",
274
+ },
275
+ ],
276
+ defaultVariants: {
277
+ disabled: false,
278
+ clickable: false,
279
+ },
280
+ });
281
+ const cvaInputCard = cssClassVarianceUtilities.cvaMerge(["flex", "items-center", "p-4"], {
282
+ variants: {
283
+ disabled: {
284
+ true: "bg-neutral-50",
285
+ false: "",
286
+ },
287
+ checked: {
288
+ true: "",
289
+ false: "",
290
+ },
291
+ },
292
+ compoundVariants: [
293
+ {
294
+ disabled: false,
295
+ checked: true,
296
+ class: "bg-primary-50",
297
+ },
298
+ {
299
+ disabled: false,
300
+ checked: false,
301
+ class: "bg-neutral-50",
302
+ },
303
+ ],
304
+ defaultVariants: {
305
+ disabled: false,
306
+ checked: false,
307
+ },
308
+ });
309
+ const cvaTitleCard = cssClassVarianceUtilities.cvaMerge(["min-w-0", "overflow-hidden", "text-ellipsis", "whitespace-nowrap"], {
310
+ variants: {
311
+ disabled: {
312
+ true: "text-neutral-400",
313
+ false: "text-neutral-900",
314
+ },
315
+ },
316
+ defaultVariants: {
317
+ disabled: false,
318
+ },
319
+ });
320
+ const cvaDescriptionCard = cssClassVarianceUtilities.cvaMerge([], {
321
+ variants: {
322
+ disabled: {
323
+ true: "text-neutral-400",
324
+ false: "text-neutral-600",
325
+ },
326
+ },
327
+ defaultVariants: {
328
+ disabled: false,
329
+ },
330
+ });
331
+ const cvaIconBackground = cssClassVarianceUtilities.cvaMerge(["flex", "h-8", "w-8", "items-center", "justify-center", "rounded-md"], {
332
+ variants: {
333
+ disabled: {
334
+ true: "bg-neutral-200",
335
+ false: "",
336
+ },
337
+ },
338
+ defaultVariants: {
339
+ disabled: false,
340
+ },
341
+ });
342
+
343
+ /**
344
+ * PreferenceCard is a flexible component for displaying add-ons or settings configuration options
345
+ * with various states and visual treatments.
346
+ * It is recommended to be primarily used as an input component, as it supports checkboxes, radio buttons and toggles.
347
+ */
348
+ const PreferenceCard = ({ title, description, icon, input, firstTag, secondTag, disabled = false, loading = false, className, dataTestId, children, onClick, }) => {
349
+ const handleCardClick = react.useCallback(() => {
350
+ if (!disabled && !loading) {
351
+ if (onClick) {
352
+ onClick();
353
+ }
354
+ else if (input && (input.type === "checkbox" || input.type === "toggle")) {
355
+ input.handleInputChange(!input.checked);
356
+ }
357
+ }
358
+ }, [disabled, loading, onClick, input]);
359
+ const handleInputClick = react.useCallback((event) => {
360
+ event.stopPropagation();
361
+ }, []);
362
+ return (jsxRuntime.jsxs("div", { className: tailwindMerge.twMerge(cvaPreferenceCard({
363
+ className,
364
+ disabled,
365
+ clickable: !!(onClick || input),
366
+ }), "overflow-hidden"), "data-testid": dataTestId, onClick: handleCardClick, tabIndex: onClick || input ? (disabled ? -1 : 0) : undefined, children: [jsxRuntime.jsxs("div", { className: "flex items-stretch divide-x divide-gray-200", children: [input ? (jsxRuntime.jsx("div", { className: cvaInputCard({ disabled, checked: input.checked }), onClick: handleInputClick, children: jsxRuntime.jsxs(reactComponents.Tooltip, { disabled: !input.tooltipText, label: input.tooltipText, placement: "top", children: [input.type === "checkbox" ? (jsxRuntime.jsx(reactFormComponents.Checkbox, { checked: input.checked, disabled: disabled, onChange: event => input.handleInputChange(event.target.checked) })) : null, input.type === "radio" ? jsxRuntime.jsx(reactFormComponents.RadioItem, { disabled: disabled, value: title }) : null, input.type === "toggle" ? (jsxRuntime.jsx(reactFormComponents.ToggleSwitch, { disabled: disabled, onChange: toggled => input.handleInputChange(toggled), toggled: input.checked })) : null] }) })) : null, jsxRuntime.jsxs("div", { className: "flex grow px-4 py-3", children: [loading ? (jsxRuntime.jsxs("div", { className: "flex grow items-center gap-3", children: [jsxRuntime.jsx("div", { className: "flex-shrink-0", children: jsxRuntime.jsx(reactComponents.SkeletonLines, { className: "rounded-md", height: 32, lines: 1, width: 32 }) }), jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: jsxRuntime.jsx(reactComponents.SkeletonLines, { height: [11, 12], lines: 2, margin: "4px 0", width: [128, 152] }) })] })) : (jsxRuntime.jsxs("div", { className: "flex grow items-center gap-3", children: [icon ? (jsxRuntime.jsx("div", { className: "flex-shrink-0", children: jsxRuntime.jsx("div", { className: tailwindMerge.twMerge(cvaIconBackground({ disabled }), disabled ? "" : icon.backgroundColor), children: jsxRuntime.jsx(reactComponents.Icon, { color: "white", name: icon.name, size: "small", type: "solid" }) }) })) : null, jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [jsxRuntime.jsx("div", { className: "grid min-w-0 grid-cols-[1fr_auto] items-center gap-2", children: jsxRuntime.jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [jsxRuntime.jsx(reactComponents.Text, { className: cvaTitleCard({ disabled }), size: "medium", weight: "bold", children: title }), firstTag ? (jsxRuntime.jsx(reactComponents.Tag, { className: "shrink-0", color: disabled ? "unknown" : firstTag.color, size: "small", children: firstTag.title })) : null] }) }), jsxRuntime.jsx(reactComponents.Text, { className: cvaDescriptionCard({ disabled }), size: "small", type: "p", children: description })] })] })), secondTag ? (jsxRuntime.jsx(reactComponents.Tag, { className: "shrink-0", color: disabled ? "unknown" : secondTag.color, size: "medium", children: secondTag.title })) : null] })] }), children] }));
367
+ };
368
+
253
369
  /*
254
370
  * ----------------------------
255
371
  * | SETUP TRANSLATIONS START |
@@ -262,6 +378,7 @@ setupLibraryTranslations();
262
378
  exports.ConfirmationDialogContextProvider = ConfirmationDialogContextProvider;
263
379
  exports.IMAGE_ENDPOINT = IMAGE_ENDPOINT;
264
380
  exports.ImageCollection = ImageCollection;
381
+ exports.PreferenceCard = PreferenceCard;
265
382
  exports.createOriginalUrl = createOriginalUrl;
266
383
  exports.createSrcSet = createSrcSet;
267
384
  exports.createThumbnailUrl = createThumbnailUrl;
package/index.esm.js CHANGED
@@ -3,12 +3,12 @@ import { registerTranslations, useNamespaceTranslation } from '@trackunit/i18n-l
3
3
  import { ConfirmationDialogProvider } from '@trackunit/react-core-hooks';
4
4
  import { Modal, useModal } from '@trackunit/react-modal';
5
5
  import { useState, useMemo, useCallback, useRef, useEffect } from 'react';
6
- import { CardHeader, CardBody, CardFooter, Button, useViewportBreakpoints, Icon, Spinner } from '@trackunit/react-components';
6
+ import { CardHeader, CardBody, CardFooter, Button, useViewportBreakpoints, Icon, Spinner, Tooltip, SkeletonLines, Text, Tag } from '@trackunit/react-components';
7
7
  import { cvaMerge } from '@trackunit/css-class-variance-utilities';
8
8
  import ImageGallery from 'react-image-gallery';
9
9
  import { twMerge } from 'tailwind-merge';
10
10
  import { formatDateUtil } from '@trackunit/date-and-time-utils';
11
- import { DropZone } from '@trackunit/react-form-components';
11
+ import { DropZone, Checkbox, RadioItem, ToggleSwitch } from '@trackunit/react-form-components';
12
12
 
13
13
  var defaultTranslations = {
14
14
  "confirmationDialog.default.message": "Are you certain that you wish to proceed with this action?",
@@ -248,6 +248,122 @@ const ImageCollection = (props) => {
248
248
  }, ref: fileInputRef, type: "file" })] }));
249
249
  };
250
250
 
251
+ const cvaPreferenceCard = cvaMerge(["rounded-lg", "border", "border-neutral-200", "bg-white", "w-full"], {
252
+ variants: {
253
+ disabled: {
254
+ true: [],
255
+ false: "",
256
+ },
257
+ clickable: {
258
+ true: ["cursor-pointer"],
259
+ false: "",
260
+ },
261
+ },
262
+ compoundVariants: [
263
+ {
264
+ disabled: true,
265
+ clickable: true,
266
+ class: "cursor-not-allowed",
267
+ },
268
+ {
269
+ disabled: false,
270
+ clickable: true,
271
+ class: "focus:ring-primary-600 focus:border-primary-600 focus:outline-none focus:ring-1",
272
+ },
273
+ ],
274
+ defaultVariants: {
275
+ disabled: false,
276
+ clickable: false,
277
+ },
278
+ });
279
+ const cvaInputCard = cvaMerge(["flex", "items-center", "p-4"], {
280
+ variants: {
281
+ disabled: {
282
+ true: "bg-neutral-50",
283
+ false: "",
284
+ },
285
+ checked: {
286
+ true: "",
287
+ false: "",
288
+ },
289
+ },
290
+ compoundVariants: [
291
+ {
292
+ disabled: false,
293
+ checked: true,
294
+ class: "bg-primary-50",
295
+ },
296
+ {
297
+ disabled: false,
298
+ checked: false,
299
+ class: "bg-neutral-50",
300
+ },
301
+ ],
302
+ defaultVariants: {
303
+ disabled: false,
304
+ checked: false,
305
+ },
306
+ });
307
+ const cvaTitleCard = cvaMerge(["min-w-0", "overflow-hidden", "text-ellipsis", "whitespace-nowrap"], {
308
+ variants: {
309
+ disabled: {
310
+ true: "text-neutral-400",
311
+ false: "text-neutral-900",
312
+ },
313
+ },
314
+ defaultVariants: {
315
+ disabled: false,
316
+ },
317
+ });
318
+ const cvaDescriptionCard = cvaMerge([], {
319
+ variants: {
320
+ disabled: {
321
+ true: "text-neutral-400",
322
+ false: "text-neutral-600",
323
+ },
324
+ },
325
+ defaultVariants: {
326
+ disabled: false,
327
+ },
328
+ });
329
+ const cvaIconBackground = cvaMerge(["flex", "h-8", "w-8", "items-center", "justify-center", "rounded-md"], {
330
+ variants: {
331
+ disabled: {
332
+ true: "bg-neutral-200",
333
+ false: "",
334
+ },
335
+ },
336
+ defaultVariants: {
337
+ disabled: false,
338
+ },
339
+ });
340
+
341
+ /**
342
+ * PreferenceCard is a flexible component for displaying add-ons or settings configuration options
343
+ * with various states and visual treatments.
344
+ * It is recommended to be primarily used as an input component, as it supports checkboxes, radio buttons and toggles.
345
+ */
346
+ const PreferenceCard = ({ title, description, icon, input, firstTag, secondTag, disabled = false, loading = false, className, dataTestId, children, onClick, }) => {
347
+ const handleCardClick = useCallback(() => {
348
+ if (!disabled && !loading) {
349
+ if (onClick) {
350
+ onClick();
351
+ }
352
+ else if (input && (input.type === "checkbox" || input.type === "toggle")) {
353
+ input.handleInputChange(!input.checked);
354
+ }
355
+ }
356
+ }, [disabled, loading, onClick, input]);
357
+ const handleInputClick = useCallback((event) => {
358
+ event.stopPropagation();
359
+ }, []);
360
+ return (jsxs("div", { className: twMerge(cvaPreferenceCard({
361
+ className,
362
+ disabled,
363
+ clickable: !!(onClick || input),
364
+ }), "overflow-hidden"), "data-testid": dataTestId, onClick: handleCardClick, tabIndex: onClick || input ? (disabled ? -1 : 0) : undefined, children: [jsxs("div", { className: "flex items-stretch divide-x divide-gray-200", children: [input ? (jsx("div", { className: cvaInputCard({ disabled, checked: input.checked }), onClick: handleInputClick, children: jsxs(Tooltip, { disabled: !input.tooltipText, label: input.tooltipText, placement: "top", children: [input.type === "checkbox" ? (jsx(Checkbox, { checked: input.checked, disabled: disabled, onChange: event => input.handleInputChange(event.target.checked) })) : null, input.type === "radio" ? jsx(RadioItem, { disabled: disabled, value: title }) : null, input.type === "toggle" ? (jsx(ToggleSwitch, { disabled: disabled, onChange: toggled => input.handleInputChange(toggled), toggled: input.checked })) : null] }) })) : null, jsxs("div", { className: "flex grow px-4 py-3", children: [loading ? (jsxs("div", { className: "flex grow items-center gap-3", children: [jsx("div", { className: "flex-shrink-0", children: jsx(SkeletonLines, { className: "rounded-md", height: 32, lines: 1, width: 32 }) }), jsx("div", { className: "min-w-0 flex-1", children: jsx(SkeletonLines, { height: [11, 12], lines: 2, margin: "4px 0", width: [128, 152] }) })] })) : (jsxs("div", { className: "flex grow items-center gap-3", children: [icon ? (jsx("div", { className: "flex-shrink-0", children: jsx("div", { className: twMerge(cvaIconBackground({ disabled }), disabled ? "" : icon.backgroundColor), children: jsx(Icon, { color: "white", name: icon.name, size: "small", type: "solid" }) }) })) : null, jsxs("div", { className: "min-w-0 flex-1", children: [jsx("div", { className: "grid min-w-0 grid-cols-[1fr_auto] items-center gap-2", children: jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [jsx(Text, { className: cvaTitleCard({ disabled }), size: "medium", weight: "bold", children: title }), firstTag ? (jsx(Tag, { className: "shrink-0", color: disabled ? "unknown" : firstTag.color, size: "small", children: firstTag.title })) : null] }) }), jsx(Text, { className: cvaDescriptionCard({ disabled }), size: "small", type: "p", children: description })] })] })), secondTag ? (jsx(Tag, { className: "shrink-0", color: disabled ? "unknown" : secondTag.color, size: "medium", children: secondTag.title })) : null] })] }), children] }));
365
+ };
366
+
251
367
  /*
252
368
  * ----------------------------
253
369
  * | SETUP TRANSLATIONS START |
@@ -257,4 +373,4 @@ const ImageCollection = (props) => {
257
373
  */
258
374
  setupLibraryTranslations();
259
375
 
260
- export { ConfirmationDialogContextProvider, IMAGE_ENDPOINT, ImageCollection, createOriginalUrl, createSrcSet, createThumbnailUrl };
376
+ export { ConfirmationDialogContextProvider, IMAGE_ENDPOINT, ImageCollection, PreferenceCard, createOriginalUrl, createSrcSet, createThumbnailUrl };
package/package.json CHANGED
@@ -1,21 +1,23 @@
1
1
  {
2
2
  "name": "@trackunit/react-compound-components",
3
- "version": "1.6.92",
3
+ "version": "1.7.4",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "dependencies": {
7
7
  "react": "19.0.0",
8
8
  "tailwind-merge": "^2.0.0",
9
9
  "react-image-gallery": "1.3.0",
10
- "@trackunit/react-core-contexts-api": "1.7.64",
11
- "@trackunit/react-core-hooks": "1.6.66",
12
- "@trackunit/react-components": "1.8.41",
13
- "@trackunit/react-modal": "1.7.24",
14
- "@trackunit/css-class-variance-utilities": "1.6.62",
15
- "@trackunit/date-and-time-utils": "1.6.62",
16
- "@trackunit/react-form-components": "1.7.57",
17
- "@trackunit/i18n-library-translation": "1.6.67",
18
- "@trackunit/react-test-setup": "1.3.62"
10
+ "@trackunit/react-core-contexts-api": "1.8.4",
11
+ "@trackunit/react-core-hooks": "1.7.4",
12
+ "@trackunit/react-components": "1.9.4",
13
+ "@trackunit/react-modal": "1.8.4",
14
+ "@trackunit/css-class-variance-utilities": "1.7.4",
15
+ "@trackunit/date-and-time-utils": "1.7.4",
16
+ "@trackunit/react-form-components": "1.8.4",
17
+ "@trackunit/i18n-library-translation": "1.7.4",
18
+ "@trackunit/react-test-setup": "1.4.4",
19
+ "@trackunit/shared-utils": "1.9.4",
20
+ "@trackunit/ui-icons": "1.7.4"
19
21
  },
20
22
  "engines": {
21
23
  "node": ">=22.x",
@@ -0,0 +1,72 @@
1
+ import { VariantProps } from "@trackunit/css-class-variance-utilities";
2
+ import { CommonProps, TagProps } from "@trackunit/react-components";
3
+ import { MappedOmit } from "@trackunit/shared-utils";
4
+ import { IconName } from "@trackunit/ui-icons";
5
+ import { ReactNode } from "react";
6
+ import { cvaPreferenceCard } from "./PreferenceCard.variants";
7
+ export interface PreferenceCardProps extends CommonProps, MappedOmit<VariantProps<typeof cvaPreferenceCard>, "className"> {
8
+ /**
9
+ * The title of the preference card
10
+ */
11
+ title: string;
12
+ /**
13
+ * The description text for the preference card
14
+ */
15
+ description: string;
16
+ /**
17
+ * The icon details to display in the card
18
+ */
19
+ icon?: {
20
+ name: IconName;
21
+ backgroundColor: string;
22
+ };
23
+ /**
24
+ * Input component to display in the card
25
+ */
26
+ input?: {
27
+ type: "checkbox" | "toggle";
28
+ checked: boolean;
29
+ handleInputChange: (checked: boolean) => void;
30
+ tooltipText?: string;
31
+ } | {
32
+ type: "radio";
33
+ checked: boolean;
34
+ tooltipText?: string;
35
+ };
36
+ /**
37
+ * First tag text next to the title - if provided, shows the tag component
38
+ */
39
+ firstTag?: {
40
+ title: string;
41
+ color: TagProps["color"];
42
+ };
43
+ /**
44
+ * Second tag text at the right end of the title - if provided, shows the tag component
45
+ */
46
+ secondTag?: {
47
+ title: string;
48
+ color: TagProps["color"];
49
+ };
50
+ /**
51
+ * Whether the card is disabled
52
+ */
53
+ disabled?: boolean;
54
+ /**
55
+ * Whether the card is loading
56
+ */
57
+ loading?: boolean;
58
+ /**
59
+ * Extra content to display at the bottom of the card
60
+ */
61
+ children?: ReactNode;
62
+ /**
63
+ * Click handler for the entire card
64
+ */
65
+ onClick?: () => void;
66
+ }
67
+ /**
68
+ * PreferenceCard is a flexible component for displaying add-ons or settings configuration options
69
+ * with various states and visual treatments.
70
+ * It is recommended to be primarily used as an input component, as it supports checkboxes, radio buttons and toggles.
71
+ */
72
+ export declare const PreferenceCard: ({ title, description, icon, input, firstTag, secondTag, disabled, loading, className, dataTestId, children, onClick, }: PreferenceCardProps) => ReactNode;
@@ -0,0 +1,8 @@
1
+ import { Meta, StoryObj } from "@storybook/react-webpack5";
2
+ import { PreferenceCard } from "./PreferenceCard";
3
+ type Story = StoryObj<typeof PreferenceCard>;
4
+ declare const meta: Meta<typeof PreferenceCard>;
5
+ export default meta;
6
+ export declare const packageName: () => import("react/jsx-runtime").JSX.Element;
7
+ export declare const Default: Story;
8
+ export declare const Variants: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,17 @@
1
+ export declare const cvaPreferenceCard: (props?: ({
2
+ disabled?: boolean | null | undefined;
3
+ clickable?: boolean | null | undefined;
4
+ } & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
5
+ export declare const cvaInputCard: (props?: ({
6
+ disabled?: boolean | null | undefined;
7
+ checked?: boolean | null | undefined;
8
+ } & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
9
+ export declare const cvaTitleCard: (props?: ({
10
+ disabled?: boolean | null | undefined;
11
+ } & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
12
+ export declare const cvaDescriptionCard: (props?: ({
13
+ disabled?: boolean | null | undefined;
14
+ } & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
15
+ export declare const cvaIconBackground: (props?: ({
16
+ disabled?: boolean | null | undefined;
17
+ } & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
@@ -0,0 +1,37 @@
1
+ import { CommonProps } from "@trackunit/react-components";
2
+ import { ReactNode } from "react";
3
+ import { PreferenceCardProps } from "./PreferenceCard";
4
+ export interface PreferenceCardGroupProps extends CommonProps {
5
+ /**
6
+ * Loading state for when the data is loading
7
+ */
8
+ loading?: boolean;
9
+ /**
10
+ * Include your card data here to showcase multiple PreferenceCard components
11
+ */
12
+ cards: Array<PreferenceCardProps>;
13
+ /**
14
+ * The currently selected value(s)
15
+ */
16
+ selectedValue: string | Array<string>;
17
+ /**
18
+ * Callback when selection changes
19
+ */
20
+ onSelectionChange: (value: string | Array<string>) => void;
21
+ /**
22
+ * The ID for the group
23
+ */
24
+ groupId: string;
25
+ /**
26
+ * Selection mode - determines if the behavior of the group is radio, allowing one selection, or multiple for other selection types
27
+ */
28
+ isRadioMode?: boolean;
29
+ /**
30
+ * Whether the group is disabled
31
+ */
32
+ disabled?: boolean;
33
+ }
34
+ /**
35
+ * PreferenceCardGroup allows multiple PreferenceCards to work together as a group.
36
+ */
37
+ export declare const PreferenceCardGroup: ({ cards, selectedValue, onSelectionChange, groupId, isRadioMode, disabled, loading, dataTestId, }: PreferenceCardGroupProps) => ReactNode;
@@ -0,0 +1 @@
1
+ export * from "./PreferenceCard";
package/src/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from "./ConfirmationDialog/ConfirmationDialogContextProvider";
2
2
  export * from "./ImageCollection";
3
+ export * from "./PreferenceCard";