@t4h.ds/service-conversation-card 0.0.0

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
+ })), 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,41 @@
1
+ {
2
+ "name": "@t4h.ds/service-conversation-card",
3
+ "version": "0.0.0",
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-ed9e491",
21
+ "@t4h.ds/avatar": "^0.0.0",
22
+ "@t4h.ds/core": "^0.0.0",
23
+ "@t4h.ds/pressable": "^0.0.0",
24
+ "@t4h.ds/reanimated": "^0.0.0",
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-ed9e491",
32
+ "@t4h.ds/avatar": "^0.0.0",
33
+ "@t4h.ds/core": "^0.0.0",
34
+ "@t4h.ds/pressable": "^0.0.0",
35
+ "@t4h.ds/reanimated": "^0.0.0",
36
+ "react": "*"
37
+ },
38
+ "optionalDependencies": {
39
+ "react-native": "^0.80.1"
40
+ }
41
+ }