@t4h.ds/service-conversation-card 0.0.0-experimental-a8290f4

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.
@@ -0,0 +1,5 @@
1
+ import { PressableProps } from '@t4h.ds/pressable';
2
+ import { ServiceConversationCardContainerProps } from './ServiceConversationCardContainer.js';
3
+ export interface ServiceConversationCardProps extends Omit<PressableProps, 'children'>, Omit<ServiceConversationCardContainerProps, 'isHovered' | 'isPressed'> {
4
+ }
5
+ export declare function ServiceConversationCard(props: ServiceConversationCardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Pressable } from '@t4h.ds/pressable';
3
+ import { ServiceConversationCardContainer, } from './ServiceConversationCardContainer.js';
4
+ export function ServiceConversationCard(props) {
5
+ return (_jsx(Pressable, { ...props, children: ({ isHovered, isPressed }) => (_jsx(ServiceConversationCardContainer, { ...props, isHovered: isHovered, isPressed: isPressed })) }));
6
+ }
@@ -0,0 +1,10 @@
1
+ import { ServiceConversationCardLayoutProps } from './ServiceConversationCardLayout.js';
2
+ export interface ServiceConversationCardContainerProps extends Omit<ServiceConversationCardLayoutProps, 'status' | 'animations' | 'remainingTimeText' | 'showRemainingTimeTextAndUnreadMessageCount'> {
3
+ isHovered?: boolean;
4
+ isPressed?: boolean;
5
+ lastMessageAt: Date;
6
+ timeLimitInSeconds: number;
7
+ isStandby?: boolean;
8
+ isSelected?: boolean;
9
+ }
10
+ export declare function ServiceConversationCardContainer({ isHovered, isPressed, isSelected, lastMessageAt, timeLimitInSeconds, isStandby, ...props }: ServiceConversationCardContainerProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ServiceConversationCardLayout, } from './ServiceConversationCardLayout.js';
3
+ import { useServiceConversationCardState } from './useServiceConversationCardState.js';
4
+ import { useServiceConversationCardAnimation } from './useServiceConversationCardAnimation.js';
5
+ import { ServiceConversationCardStatus } from './ServiceConversationCardStatus.js';
6
+ export function ServiceConversationCardContainer({ isHovered = false, isPressed = false, isSelected = false, lastMessageAt, timeLimitInSeconds, isStandby, ...props }) {
7
+ const { status, remainingTimeText } = useServiceConversationCardState({
8
+ lastMessageAt,
9
+ timeLimitInSeconds,
10
+ isStandby,
11
+ isSelected,
12
+ });
13
+ const animations = useServiceConversationCardAnimation(status, isHovered, isPressed);
14
+ return (_jsx(ServiceConversationCardLayout, { ...props, remainingTimeText: remainingTimeText, status: status, animations: animations, showRemainingTimeTextAndUnreadMessageCount: status !== ServiceConversationCardStatus.Standby && !isSelected, unreadMessageCount: props.unreadMessageCount }));
15
+ }
@@ -0,0 +1,13 @@
1
+ import { UseServiceConversationCardAnimation } from './useServiceConversationCardAnimation.js';
2
+ import { ServiceConversationCardStatus } from './ServiceConversationCardStatus.js';
3
+ import './tokens.js';
4
+ export interface ServiceConversationCardLayoutProps {
5
+ title: string;
6
+ message: string;
7
+ remainingTimeText: string;
8
+ status: ServiceConversationCardStatus;
9
+ animations: UseServiceConversationCardAnimation;
10
+ unreadMessageCount: number;
11
+ showRemainingTimeTextAndUnreadMessageCount: boolean;
12
+ }
13
+ export declare function ServiceConversationCardLayout({ title, message, remainingTimeText, unreadMessageCount, showRemainingTimeTextAndUnreadMessageCount, status, animations, }: ServiceConversationCardLayoutProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from '@t4h.ds/core';
3
+ import { Animated, useAnimatedStyle } from '@t4h.ds/reanimated';
4
+ import { ServiceConversationCardStatus } from './ServiceConversationCardStatus.js';
5
+ import './tokens.js';
6
+ import { Avatar } from '@t4h.ds/avatar';
7
+ const colors = {
8
+ [ServiceConversationCardStatus.Normal]: 'green',
9
+ [ServiceConversationCardStatus.NearBreach]: 'yellow',
10
+ [ServiceConversationCardStatus.Breached]: 'red',
11
+ [ServiceConversationCardStatus.Standby]: 'grey',
12
+ [ServiceConversationCardStatus.Selected]: 'blue',
13
+ };
14
+ export function ServiceConversationCardLayout({ title, message, remainingTimeText, unreadMessageCount, showRemainingTimeTextAndUnreadMessageCount, status, animations, }) {
15
+ return (_jsxs(Box, { as: Animated.View, row: true, rounded: true, overflow: true, p: 'space.150', gap: 'space.150', borderWidth: 1, style: useAnimatedStyle(() => ({
16
+ backgroundColor: animations.backgroundColor.value,
17
+ borderColor: animations.borderColor.value,
18
+ }), [animations.backgroundColor, animations.borderColor]), children: [_jsx(Avatar, { name: title ?? '?', color: colors[status] }), _jsxs(Box, { flex: 1, gap: 'space.050', children: [_jsx(Text, { bold: true, numberOfLines: 1, lineBreakMode: 'tail', color: `service-conversation-card.${status}.color.title`, children: title }), _jsx(Text, { numberOfLines: 1, lineBreakMode: 'tail', color: `service-conversation-card.${status}.color.message`, children: message })] }), showRemainingTimeTextAndUnreadMessageCount && (_jsxs(Box, { children: [_jsx(Box, { children: _jsx(Text, { color: `service-conversation-card.${status}.color.icon`, children: remainingTimeText }) }), !!unreadMessageCount && (_jsx(Box, { ml: 'auto', rounded: 'full', bg: `service-conversation-card.${status}.color.icon`, p: 'space.050', center: true, height: 20, width: 20, children: _jsx(Text, { bold: true, color: '#FFFFFF', fontSize: 'xs', children: unreadMessageCount }) }))] }))] }));
19
+ }
@@ -0,0 +1,7 @@
1
+ export declare enum ServiceConversationCardStatus {
2
+ Selected = "selected",
3
+ Normal = "normal",
4
+ NearBreach = "near-breach",
5
+ Breached = "breached",
6
+ Standby = "standby"
7
+ }
@@ -0,0 +1,8 @@
1
+ export var ServiceConversationCardStatus;
2
+ (function (ServiceConversationCardStatus) {
3
+ ServiceConversationCardStatus["Selected"] = "selected";
4
+ ServiceConversationCardStatus["Normal"] = "normal";
5
+ ServiceConversationCardStatus["NearBreach"] = "near-breach";
6
+ ServiceConversationCardStatus["Breached"] = "breached";
7
+ ServiceConversationCardStatus["Standby"] = "standby";
8
+ })(ServiceConversationCardStatus || (ServiceConversationCardStatus = {}));
@@ -0,0 +1,72 @@
1
+ import { Theme } from '@t4h.ds/core';
2
+ Theme.get()
3
+ .tokens.set({
4
+ 'service-conversation-card.selected.color.icon': '@color.background.brand.bold',
5
+ 'service-conversation-card.selected.color.title': '@color.background.brand.bold',
6
+ 'service-conversation-card.selected.color.message': '#60646C',
7
+ 'service-conversation-card.selected.color.background': '#F7F9FF',
8
+ 'service-conversation-card.selected.hovered.color.background': '#EDF1FF',
9
+ 'service-conversation-card.selected.pressed.color.background': '@service-conversation-card.selected.hovered.color.background',
10
+ 'service-conversation-card.selected.color.icon.background': '#D2DDFF',
11
+ 'service-conversation-card.selected.hovered.color.icon.background': '@service-conversation-card.selected.color.icon.background',
12
+ 'service-conversation-card.selected.pressed.color.icon.background': '@service-conversation-card.selected.hovered.color.icon.background',
13
+ 'service-conversation-card.selected.color.border': '#D2DDFF',
14
+ 'service-conversation-card.selected.hovered.color.border': '@service-conversation-card.selected.color.border',
15
+ 'service-conversation-card.selected.pressed.color.border': '@service-conversation-card.selected.hovered.color.border',
16
+ })
17
+ .set({
18
+ 'service-conversation-card.normal.color.icon': '#2A7E3B',
19
+ 'service-conversation-card.normal.color.title': '#1C2024',
20
+ 'service-conversation-card.normal.color.message': '#60646C',
21
+ 'service-conversation-card.normal.color.background': '#F5FBF5',
22
+ 'service-conversation-card.normal.color.background.hovered': '#E9F6E9',
23
+ 'service-conversation-card.normal.color.background.pressed': '@service-conversation-card.normal.color.background.hovered',
24
+ 'service-conversation-card.normal.color.icon.background': '#B2DDB5',
25
+ 'service-conversation-card.normal.hovered.color.icon.background': '@service-conversation-card.normal.color.icon.background',
26
+ 'service-conversation-card.normal.pressed.color.icon.background': '@service-conversation-card.normal.hovered.color.icon.background',
27
+ 'service-conversation-card.normal.color.border': '#E8E8EC',
28
+ 'service-conversation-card.normal.hovered.color.border': '@service-conversation-card.normal.color.border',
29
+ 'service-conversation-card.normal.pressed.color.border': '@service-conversation-card.normal.hovered.color.border',
30
+ })
31
+ .set({
32
+ 'service-conversation-card.near-breach.color.icon': '#AB6400',
33
+ 'service-conversation-card.near-breach.color.title': '#1C2024',
34
+ 'service-conversation-card.near-breach.color.message': '#60646C',
35
+ 'service-conversation-card.near-breach.color.background': '#FEFBE9',
36
+ 'service-conversation-card.near-breach.hovered.color.background': '#FFF7C2',
37
+ 'service-conversation-card.near-breach.pressed.color.background': '@service-conversation-card.near-breach.hovered.color.background',
38
+ 'service-conversation-card.near-breach.color.icon.background': '#F3D673',
39
+ 'service-conversation-card.near-breach.color.icon.background.hovered': '@service-conversation-card.near-breach.color.icon.background',
40
+ 'service-conversation-card.near-breach.color.icon.background.pressed': '@service-conversation-card.near-breach.color.icon.background.hovered',
41
+ 'service-conversation-card.near-breach.color.border': '#E8E8EC',
42
+ 'service-conversation-card.near-breach.hovered.color.border': '@service-conversation-card.near-breach.color.border',
43
+ 'service-conversation-card.near-breach.pressed.color.border': '@service-conversation-card.near-breach.hovered.color.border',
44
+ })
45
+ .set({
46
+ 'service-conversation-card.breached.color.icon': '#E5484D',
47
+ 'service-conversation-card.breached.color.title': '#1C2024',
48
+ 'service-conversation-card.breached.color.message': '#60646C',
49
+ 'service-conversation-card.breached.color.background': '#FFF7F7',
50
+ 'service-conversation-card.breached.hovered.color.background': '#FEEBEC',
51
+ 'service-conversation-card.breached.pressed.color.background': '@service-conversation-card.breached.hovered.color.background',
52
+ 'service-conversation-card.breached.color.icon.background': '#FDBDBE',
53
+ 'service-conversation-card.breached.hovered.color.icon.background': '@service-conversation-card.breached.color.icon.background',
54
+ 'service-conversation-card.breached.pressed.color.icon.background': '@service-conversation-card.breached.hovered.color.icon.background',
55
+ 'service-conversation-card.breached.color.border': '#E8E8EC',
56
+ 'service-conversation-card.breached.hovered.color.border': '@service-conversation-card.breached.color.border',
57
+ 'service-conversation-card.breached.pressed.color.border': '@service-conversation-card.breached.hovered.color.border',
58
+ })
59
+ .set({
60
+ 'service-conversation-card.standby.color.icon': '#60646C',
61
+ 'service-conversation-card.standby.color.title': '#1C2024',
62
+ 'service-conversation-card.standby.color.message': '#60646C',
63
+ 'service-conversation-card.standby.color.background': '#F9F9FB',
64
+ 'service-conversation-card.standby.hovered.color.background': '@service-conversation-card.standby.color.background',
65
+ 'service-conversation-card.standby.pressed.color.background': '@service-conversation-card.standby.hovered.color.background',
66
+ 'service-conversation-card.standby.color.icon.background': '#D9D9E0',
67
+ 'service-conversation-card.standby.hovered.color.icon.background': '@service-conversation-card.standby.color.icon.background',
68
+ 'service-conversation-card.standby.pressed.color.icon.background': '@service-conversation-card.standby.hovered.color.icon.background',
69
+ 'service-conversation-card.standby.color.border': '#E8E8EC',
70
+ 'service-conversation-card.standby.hovered.color.border': '@service-conversation-card.standby.color.border',
71
+ 'service-conversation-card.standby.pressed.color.border': '@service-conversation-card.standby.hovered.color.border',
72
+ });
@@ -0,0 +1,8 @@
1
+ import { SharedValue } from '@t4h.ds/reanimated';
2
+ import { ServiceConversationCardStatus } from './ServiceConversationCardStatus.js';
3
+ export interface UseServiceConversationCardAnimation {
4
+ backgroundColor: SharedValue<string>;
5
+ borderColor: SharedValue<string>;
6
+ iconBackgroundColor: SharedValue<string>;
7
+ }
8
+ export declare function useServiceConversationCardAnimation(status: ServiceConversationCardStatus, isHovered: boolean, isPressed: boolean): UseServiceConversationCardAnimation;
@@ -0,0 +1,16 @@
1
+ import { useReanimatedTransitionThemeToken, } from '@t4h.ds/reanimated';
2
+ import { useMemo } from 'react';
3
+ export function useServiceConversationCardAnimation(status, isHovered, isPressed) {
4
+ const tag = useMemo(() => {
5
+ const tag = `service-conversation-card.${status}`;
6
+ if (isPressed)
7
+ return `${tag}.pressed`;
8
+ if (isHovered)
9
+ return `${tag}.hovered`;
10
+ return tag;
11
+ }, [status, isPressed, isHovered]);
12
+ const backgroundColor = useReanimatedTransitionThemeToken(`${tag}.color.background`, { duration: 300 });
13
+ const borderColor = useReanimatedTransitionThemeToken(`${tag}.color.border`, { duration: 300 });
14
+ const iconBackgroundColor = useReanimatedTransitionThemeToken(`${tag}.color.icon.background`, { duration: 300 });
15
+ return { backgroundColor, borderColor, iconBackgroundColor };
16
+ }
@@ -0,0 +1,13 @@
1
+ import { ServiceConversationCardStatus } from './ServiceConversationCardStatus.js';
2
+ export interface UseServiceConversationCardState {
3
+ remainingTimeText: string;
4
+ diffInSeconds: number;
5
+ status: ServiceConversationCardStatus;
6
+ }
7
+ export interface UseServiceConversationCardStateProps {
8
+ lastMessageAt: Date;
9
+ timeLimitInSeconds: number;
10
+ isStandby?: boolean;
11
+ isSelected?: boolean;
12
+ }
13
+ export declare function useServiceConversationCardState({ lastMessageAt, timeLimitInSeconds, isStandby, isSelected, }: UseServiceConversationCardStateProps): UseServiceConversationCardState;
@@ -0,0 +1,31 @@
1
+ import { useMemo } from 'react';
2
+ import { useAnimationFrameState } from '@t4h.ds/animation-frame';
3
+ import { ServiceConversationCardStatus } from './ServiceConversationCardStatus.js';
4
+ export function useServiceConversationCardState({ lastMessageAt, timeLimitInSeconds, isStandby, isSelected, }) {
5
+ const [remainingTimeText, diffInSeconds] = useAnimationFrameState(() => {
6
+ const now = new Date();
7
+ const expireAtTime = lastMessageAt.getTime() + timeLimitInSeconds * 1000;
8
+ const nowTime = now.getTime();
9
+ const diffInSeconds = Math.floor((expireAtTime - nowTime) / 1000);
10
+ const minutes = Math.abs(Math.floor(diffInSeconds / 60))
11
+ .toString()
12
+ .padStart(2, '0');
13
+ const seconds = Math.abs(diffInSeconds % 60)
14
+ .toString()
15
+ .padStart(2, '0');
16
+ const display = diffInSeconds < 0 ? `-${minutes}:${seconds}` : `${minutes}:${seconds}`;
17
+ return [display, diffInSeconds];
18
+ }, { maxFps: 3 }, [lastMessageAt, timeLimitInSeconds]);
19
+ const status = useMemo(() => {
20
+ if (isSelected)
21
+ return ServiceConversationCardStatus.Selected;
22
+ if (isStandby)
23
+ return ServiceConversationCardStatus.Standby;
24
+ if (diffInSeconds > timeLimitInSeconds * 0.8)
25
+ return ServiceConversationCardStatus.Normal;
26
+ if (diffInSeconds > timeLimitInSeconds * 0.5)
27
+ return ServiceConversationCardStatus.NearBreach;
28
+ return ServiceConversationCardStatus.Breached;
29
+ }, [isStandby, isSelected, diffInSeconds, timeLimitInSeconds]);
30
+ return useMemo(() => ({ remainingTimeText, status, diffInSeconds }), [remainingTimeText, status, diffInSeconds]);
31
+ }
@@ -0,0 +1 @@
1
+ export * from './components/ServiceConversationCard/ServiceConversationCard.js';
@@ -0,0 +1 @@
1
+ export * from './components/ServiceConversationCard/ServiceConversationCard.js';
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@t4h.ds/service-conversation-card",
3
+ "version": "0.0.0-experimental-a8290f4",
4
+ "author": "Tony <tony.js@zoho.eu>",
5
+ "type": "module",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "module": "./dist/service-conversation-card.js",
10
+ "types": "./dist/service-conversation-card.d.ts",
11
+ "exports": {
12
+ "types": "./dist/service-conversation-card.d.ts",
13
+ "import": "./dist/service-conversation-card.js"
14
+ },
15
+ "scripts": {
16
+ "build": "tsc -p tsconfig.build.json",
17
+ "prepublish": "yarn run build"
18
+ },
19
+ "devDependencies": {
20
+ "@t4h.ds/animation-frame": "^0.0.0-experimental-a8290f4",
21
+ "@t4h.ds/avatar": "^0.0.0-experimental-a8290f4",
22
+ "@t4h.ds/core": "^0.0.0-experimental-a8290f4",
23
+ "@t4h.ds/pressable": "^0.0.0-experimental-a8290f4",
24
+ "@t4h.ds/reanimated": "^0.0.0-experimental-a8290f4",
25
+ "@types/react": "^19",
26
+ "react": "^19.1.0",
27
+ "typescript": "^5.8.3",
28
+ "vitest": "^3.2.4"
29
+ },
30
+ "peerDependencies": {
31
+ "@t4h.ds/animation-frame": "^0.0.0-experimental-a8290f4",
32
+ "@t4h.ds/avatar": "^0.0.0-experimental-a8290f4",
33
+ "@t4h.ds/core": "^0.0.0-experimental-a8290f4",
34
+ "@t4h.ds/pressable": "^0.0.0-experimental-a8290f4",
35
+ "@t4h.ds/reanimated": "^0.0.0-experimental-a8290f4",
36
+ "react": "*"
37
+ },
38
+ "optionalDependencies": {
39
+ "react-native": "^0.80.1"
40
+ },
41
+ "stableVersion": "0.0.0"
42
+ }