@scripso-homepad/ui 0.4.8 → 0.4.10
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/{chunk-DAOLVE64.js → chunk-YSDLHEJ7.js} +204 -14
- package/dist/chunk-YSDLHEJ7.js.map +1 -0
- package/dist/index.cjs +130 -87
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +176 -323
- package/dist/index.js.map +1 -1
- package/dist/web/index.cjs +882 -30
- package/dist/web/index.cjs.map +1 -1
- package/dist/web/index.css +161 -0
- package/dist/web/index.css.map +1 -1
- package/dist/web/index.d.cts +90 -3
- package/dist/web/index.d.ts +90 -3
- package/dist/web/index.js +645 -19
- package/dist/web/index.js.map +1 -1
- package/package.json +9 -3
- package/src/components/Button.tsx +10 -3
- package/src/components/DatePicker.tsx +37 -3
- package/src/components/Select.tsx +1 -1
- package/src/web/components/ConfirmModal.stories.tsx +55 -0
- package/src/web/components/ConfirmModal.tsx +116 -0
- package/src/web/components/Drawer.stories.tsx +234 -0
- package/src/web/components/Drawer.tsx +169 -0
- package/src/web/components/HistoryTimeline.tsx +46 -0
- package/src/web/components/Modal.stories.tsx +130 -0
- package/src/web/components/Modal.tsx +162 -0
- package/src/web/components/TableActionButton.tsx +9 -4
- package/src/web/components/Toaster.stories.tsx +106 -0
- package/src/web/components/Toaster.tsx +92 -0
- package/src/web/components/ToasterProvider.tsx +6 -0
- package/src/web/components/drawer-scroll.css +41 -0
- package/src/web/components/sonner-toast.css +141 -0
- package/src/web/icons/TimelineCheckIcon.tsx +24 -0
- package/src/web/icons/ToastIcons.tsx +119 -0
- package/src/web/index.ts +26 -0
- package/src/web/mutation-toast.ts +33 -0
- package/src/web/toast.ts +1 -0
- package/dist/chunk-DAOLVE64.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scripso-homepad/ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Cross-platform UI components for Homepad (React Web + React Native)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"import": "./src/web/index.ts",
|
|
30
30
|
"require": "./dist/web/index.cjs",
|
|
31
31
|
"default": "./src/web/index.ts"
|
|
32
|
-
}
|
|
32
|
+
},
|
|
33
|
+
"./web/table-scroll.css": "./src/web/components/table-scroll.css"
|
|
33
34
|
},
|
|
34
35
|
"files": [
|
|
35
36
|
"dist",
|
|
@@ -51,7 +52,8 @@
|
|
|
51
52
|
"react-native": ">=0.74",
|
|
52
53
|
"react-native-svg": ">=13",
|
|
53
54
|
"react-native-web": ">=0.19",
|
|
54
|
-
"react-router-dom": ">=6"
|
|
55
|
+
"react-router-dom": ">=6",
|
|
56
|
+
"sonner": ">=2.0.0"
|
|
55
57
|
},
|
|
56
58
|
"peerDependenciesMeta": {
|
|
57
59
|
"react-native-svg": {
|
|
@@ -65,6 +67,9 @@
|
|
|
65
67
|
},
|
|
66
68
|
"lucide-react": {
|
|
67
69
|
"optional": true
|
|
70
|
+
},
|
|
71
|
+
"sonner": {
|
|
72
|
+
"optional": true
|
|
68
73
|
}
|
|
69
74
|
},
|
|
70
75
|
"dependencies": {
|
|
@@ -90,6 +95,7 @@
|
|
|
90
95
|
"react-native-svg": "^15.11.2",
|
|
91
96
|
"react-native-web": "^0.19.13",
|
|
92
97
|
"react-router-dom": "^7.9.1",
|
|
98
|
+
"sonner": "^2.0.7",
|
|
93
99
|
"storybook": "^8.4.7",
|
|
94
100
|
"tailwindcss": "^4.1.13",
|
|
95
101
|
"tsup": "^8.3.5",
|
|
@@ -115,14 +115,21 @@ export function Button({
|
|
|
115
115
|
const preset = variantConfig[variant];
|
|
116
116
|
const metrics = sizeConfig[size];
|
|
117
117
|
|
|
118
|
-
useApplyWebClassName(containerRef, className);
|
|
119
|
-
useApplyWebClassName(textRef, textClassName);
|
|
120
|
-
|
|
121
118
|
const label = typeof children !== "undefined" ? children : title;
|
|
122
119
|
const hasCustomChildren = typeof children !== "undefined";
|
|
123
120
|
const customIcon =
|
|
124
121
|
icon != null && typeof icon !== "boolean" ? icon : undefined;
|
|
125
122
|
const hasIcon = showIcon || icon === true || customIcon != null;
|
|
123
|
+
const resolvedContainerClassName = [
|
|
124
|
+
Platform.OS === "web" ? "max-md:px-4!" : "",
|
|
125
|
+
className,
|
|
126
|
+
]
|
|
127
|
+
.filter(Boolean)
|
|
128
|
+
.join(" ");
|
|
129
|
+
|
|
130
|
+
useApplyWebClassName(containerRef, resolvedContainerClassName || undefined);
|
|
131
|
+
useApplyWebClassName(textRef, textClassName);
|
|
132
|
+
|
|
126
133
|
const iconNode =
|
|
127
134
|
customIcon ?? (
|
|
128
135
|
<ArrowUpRightIcon size={metrics.iconSize} color={preset.iconColor} />
|
|
@@ -51,6 +51,8 @@ type DatePickerFieldProps = {
|
|
|
51
51
|
containerStyle?: StyleProp<ViewStyle>;
|
|
52
52
|
className?: string;
|
|
53
53
|
fieldClassName?: string;
|
|
54
|
+
fieldStyle?: StyleProp<ViewStyle>;
|
|
55
|
+
fieldOutlineStyle?: StyleProp<ViewStyle>;
|
|
54
56
|
panelClassName?: string;
|
|
55
57
|
labelClassName?: string;
|
|
56
58
|
errorClassName?: string;
|
|
@@ -95,6 +97,8 @@ export function DatePicker(props: DatePickerProps) {
|
|
|
95
97
|
containerStyle,
|
|
96
98
|
className,
|
|
97
99
|
fieldClassName,
|
|
100
|
+
fieldStyle,
|
|
101
|
+
fieldOutlineStyle,
|
|
98
102
|
panelClassName,
|
|
99
103
|
labelClassName,
|
|
100
104
|
errorClassName,
|
|
@@ -224,22 +228,39 @@ export function DatePicker(props: DatePickerProps) {
|
|
|
224
228
|
}
|
|
225
229
|
}
|
|
226
230
|
|
|
231
|
+
const isFluidField = Boolean(fieldStyle) || Boolean(fieldOutlineStyle);
|
|
232
|
+
|
|
227
233
|
return (
|
|
228
|
-
<View
|
|
234
|
+
<View
|
|
235
|
+
ref={wrapperRef}
|
|
236
|
+
style={[styles.wrapper, isFluidField && styles.wrapperFluid, containerStyle]}
|
|
237
|
+
>
|
|
229
238
|
{label ? (
|
|
230
239
|
<Label disabled={disabled} style={styles.label} className={labelClassName}>
|
|
231
240
|
{label}
|
|
232
241
|
</Label>
|
|
233
242
|
) : null}
|
|
234
243
|
|
|
235
|
-
<View
|
|
244
|
+
<View
|
|
245
|
+
style={[
|
|
246
|
+
fieldStyles.outline,
|
|
247
|
+
styles.fieldOutline,
|
|
248
|
+
isFluidField && styles.fieldOutlineFluid,
|
|
249
|
+
fieldOutlineStyle,
|
|
250
|
+
]}
|
|
251
|
+
>
|
|
236
252
|
<Pressable
|
|
237
253
|
ref={triggerRef}
|
|
238
254
|
accessibilityRole="button"
|
|
239
255
|
accessibilityState={{ disabled, expanded: open }}
|
|
240
256
|
disabled={disabled}
|
|
241
257
|
onPress={openPicker}
|
|
242
|
-
style={[
|
|
258
|
+
style={[
|
|
259
|
+
calendarFieldMetrics.container,
|
|
260
|
+
isFluidField && styles.fieldContainerFluid,
|
|
261
|
+
fieldStyles.container,
|
|
262
|
+
fieldStyle,
|
|
263
|
+
]}
|
|
243
264
|
>
|
|
244
265
|
<Text
|
|
245
266
|
style={[calendarFieldMetrics.value, valueTextStyle]}
|
|
@@ -327,11 +348,24 @@ const styles = StyleSheet.create({
|
|
|
327
348
|
maxWidth: "100%",
|
|
328
349
|
gap: SELECT_LABEL_GAP,
|
|
329
350
|
},
|
|
351
|
+
wrapperFluid: {
|
|
352
|
+
width: "100%",
|
|
353
|
+
},
|
|
330
354
|
fieldOutline: {
|
|
331
355
|
width: CALENDAR_FIELD_WIDTH,
|
|
332
356
|
maxWidth: "100%",
|
|
333
357
|
alignSelf: "flex-start",
|
|
334
358
|
},
|
|
359
|
+
fieldOutlineFluid: {
|
|
360
|
+
width: "100%",
|
|
361
|
+
alignSelf: "stretch",
|
|
362
|
+
},
|
|
363
|
+
fieldContainerFluid: {
|
|
364
|
+
width: "100%",
|
|
365
|
+
minWidth: 0,
|
|
366
|
+
maxWidth: "100%",
|
|
367
|
+
alignSelf: "stretch",
|
|
368
|
+
},
|
|
335
369
|
label: {
|
|
336
370
|
...calendarLabelTypography,
|
|
337
371
|
},
|
|
@@ -176,7 +176,7 @@ export function Select({
|
|
|
176
176
|
() =>
|
|
177
177
|
resolveSelectDropdownContentHeight(options.length, optionHeight) >
|
|
178
178
|
SELECT_DROPDOWN_MAX_HEIGHT - SELECT_DROPDOWN_PADDING * 2,
|
|
179
|
-
[
|
|
179
|
+
[optionHeight, options.length],
|
|
180
180
|
);
|
|
181
181
|
|
|
182
182
|
useApplyWebClassName(wrapperRef, className);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { fn } from '@storybook/test';
|
|
3
|
+
|
|
4
|
+
import { WebLayoutCanvas } from '../layout/story-helpers';
|
|
5
|
+
|
|
6
|
+
import { ConfirmModal } from './ConfirmModal';
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
title: 'Web Components/ConfirmModal',
|
|
10
|
+
component: ConfirmModal,
|
|
11
|
+
parameters: {
|
|
12
|
+
layout: 'fullscreen',
|
|
13
|
+
webLayout: true,
|
|
14
|
+
},
|
|
15
|
+
args: {
|
|
16
|
+
open: true,
|
|
17
|
+
title: 'Կասեցնե՞լ շենքի մուտքը',
|
|
18
|
+
description: (
|
|
19
|
+
<>
|
|
20
|
+
Դուք պատրաստվում եք կասեցնել «Կենտրոն» շենքի մուտքը։
|
|
21
|
+
<br />
|
|
22
|
+
Բոլոր օգտատերերը կկորցնեն հասանելիությունը համակարգին։
|
|
23
|
+
</>
|
|
24
|
+
),
|
|
25
|
+
cancelText: 'Չեղարկել',
|
|
26
|
+
confirmText: 'Կասեցնել',
|
|
27
|
+
onCancel: fn(),
|
|
28
|
+
onConfirm: fn(),
|
|
29
|
+
},
|
|
30
|
+
} satisfies Meta<typeof ConfirmModal>;
|
|
31
|
+
|
|
32
|
+
export default meta;
|
|
33
|
+
type Story = StoryObj<typeof meta>;
|
|
34
|
+
|
|
35
|
+
export const Default: Story = {
|
|
36
|
+
render: (args) => (
|
|
37
|
+
<WebLayoutCanvas className="min-h-screen bg-storm-gray-50 p-6">
|
|
38
|
+
<ConfirmModal {...args} />
|
|
39
|
+
</WebLayoutCanvas>
|
|
40
|
+
),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const RejectRequest: Story = {
|
|
44
|
+
args: {
|
|
45
|
+
title: 'Մերժե՞լ շենքի հայտը',
|
|
46
|
+
description:' Դուք պատրաստվում եք մերժել «Արաբկիր 12» հասցեի շենքի հայտը։ Կազմակերպությունը կտեղեկացվի մերժման մասին։',
|
|
47
|
+
cancelText: 'Չեղարկել',
|
|
48
|
+
confirmText: 'Մերժել',
|
|
49
|
+
},
|
|
50
|
+
render: (args) => (
|
|
51
|
+
<WebLayoutCanvas className="min-h-screen bg-storm-gray-50 p-6">
|
|
52
|
+
<ConfirmModal {...args} />
|
|
53
|
+
</WebLayoutCanvas>
|
|
54
|
+
),
|
|
55
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { useEffect, type ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Button } from '../../components/Button';
|
|
4
|
+
import { cn } from '../utils/cn';
|
|
5
|
+
|
|
6
|
+
export type ConfirmModalProps = {
|
|
7
|
+
open: boolean;
|
|
8
|
+
title: string;
|
|
9
|
+
description: ReactNode;
|
|
10
|
+
cancelText: string;
|
|
11
|
+
confirmText: string;
|
|
12
|
+
onCancel: () => void;
|
|
13
|
+
onConfirm: () => void;
|
|
14
|
+
cancelDisabled?: boolean;
|
|
15
|
+
confirmDisabled?: boolean;
|
|
16
|
+
closeOnBackdrop?: boolean;
|
|
17
|
+
containerClassName?: string;
|
|
18
|
+
buttonClassName?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function ConfirmModal({
|
|
22
|
+
open,
|
|
23
|
+
title,
|
|
24
|
+
description,
|
|
25
|
+
cancelText,
|
|
26
|
+
confirmText,
|
|
27
|
+
onCancel,
|
|
28
|
+
onConfirm,
|
|
29
|
+
cancelDisabled = false,
|
|
30
|
+
confirmDisabled = false,
|
|
31
|
+
closeOnBackdrop = true,
|
|
32
|
+
containerClassName,
|
|
33
|
+
buttonClassName,
|
|
34
|
+
}: ConfirmModalProps) {
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (!open) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
41
|
+
if (event.key === 'Escape') {
|
|
42
|
+
onCancel();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
47
|
+
|
|
48
|
+
return () => {
|
|
49
|
+
window.removeEventListener('keydown', handleKeyDown);
|
|
50
|
+
};
|
|
51
|
+
}, [open, onCancel]);
|
|
52
|
+
|
|
53
|
+
if (!open) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const sharedButtonClassName = cn('btn h-10 min-w-0 flex-1 justify-center!', buttonClassName);
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div
|
|
61
|
+
className="fixed inset-0 z-50 flex items-center justify-center p-4 backdrop-blur-md bg-storm-gray-850/40"
|
|
62
|
+
onClick={closeOnBackdrop ? onCancel : undefined}
|
|
63
|
+
role="presentation"
|
|
64
|
+
>
|
|
65
|
+
<div
|
|
66
|
+
role="dialog"
|
|
67
|
+
aria-modal="true"
|
|
68
|
+
aria-labelledby="homepad-confirm-modal-title"
|
|
69
|
+
aria-describedby="homepad-confirm-modal-description"
|
|
70
|
+
className={cn(
|
|
71
|
+
'flex w-full max-w-md flex-col gap-8 rounded-2xl bg-white p-4 opacity-100 md:p-6',
|
|
72
|
+
containerClassName,
|
|
73
|
+
)}
|
|
74
|
+
onClick={(event) => {
|
|
75
|
+
event.stopPropagation();
|
|
76
|
+
}}
|
|
77
|
+
>
|
|
78
|
+
<header className="flex flex-col gap-3 text-center">
|
|
79
|
+
<h2
|
|
80
|
+
id="homepad-confirm-modal-title"
|
|
81
|
+
className="font-sans text-xl font-bold leading-6.75 tracking-normal text-black"
|
|
82
|
+
>
|
|
83
|
+
{title}
|
|
84
|
+
</h2>
|
|
85
|
+
<div
|
|
86
|
+
id="homepad-confirm-modal-description"
|
|
87
|
+
className="text-center font-sans text-sm font-normal leading-4.75 tracking-normal text-storm-gray-400"
|
|
88
|
+
>
|
|
89
|
+
{description}
|
|
90
|
+
</div>
|
|
91
|
+
</header>
|
|
92
|
+
|
|
93
|
+
<footer className="flex w-full gap-4">
|
|
94
|
+
<Button
|
|
95
|
+
title={cancelText}
|
|
96
|
+
onPress={onCancel}
|
|
97
|
+
variant="gray"
|
|
98
|
+
size='sm'
|
|
99
|
+
disabled={cancelDisabled}
|
|
100
|
+
className={sharedButtonClassName}
|
|
101
|
+
textClassName="text-center!"
|
|
102
|
+
/>
|
|
103
|
+
<Button
|
|
104
|
+
title={confirmText}
|
|
105
|
+
onPress={onConfirm}
|
|
106
|
+
variant="primary"
|
|
107
|
+
size='sm'
|
|
108
|
+
disabled={confirmDisabled}
|
|
109
|
+
className={sharedButtonClassName}
|
|
110
|
+
textClassName="text-center!"
|
|
111
|
+
/>
|
|
112
|
+
</footer>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { fn } from '@storybook/test';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
|
|
5
|
+
import { Button } from '../../components/Button';
|
|
6
|
+
import { WebLayoutCanvas } from '../layout/story-helpers';
|
|
7
|
+
|
|
8
|
+
import { Drawer } from './Drawer';
|
|
9
|
+
import { HistoryTimeline } from './HistoryTimeline';
|
|
10
|
+
import { StatusBadge } from './StatusBadge';
|
|
11
|
+
|
|
12
|
+
const historyEvents = [
|
|
13
|
+
{
|
|
14
|
+
id: 'received',
|
|
15
|
+
title: 'Հայտը ստացվել է',
|
|
16
|
+
timestamp: '24.06.2026, 14:20',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: 'approved',
|
|
20
|
+
title: 'Հայտը հաստատվել է, սպասում է վճարման',
|
|
21
|
+
timestamp: '24.06.2026, 15:05',
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const meta = {
|
|
26
|
+
title: 'Web Components/Drawer',
|
|
27
|
+
component: Drawer,
|
|
28
|
+
parameters: {
|
|
29
|
+
layout: 'fullscreen',
|
|
30
|
+
webLayout: true,
|
|
31
|
+
},
|
|
32
|
+
args: {
|
|
33
|
+
open: true,
|
|
34
|
+
title: 'Հայտ #00042',
|
|
35
|
+
subtitle: 'Ստացվել է 24.06.2026, 14:20',
|
|
36
|
+
closeAriaLabel: 'Փակել',
|
|
37
|
+
onClose: fn(),
|
|
38
|
+
},
|
|
39
|
+
} satisfies Meta<typeof Drawer>;
|
|
40
|
+
|
|
41
|
+
export default meta;
|
|
42
|
+
type Story = StoryObj<typeof meta>;
|
|
43
|
+
|
|
44
|
+
function DetailField({ label, value }: { label: string; value: string }) {
|
|
45
|
+
return (
|
|
46
|
+
<div className="flex items-center justify-between gap-4">
|
|
47
|
+
<span className="min-w-0 flex-1 font-sans text-sm font-medium leading-[19px] tracking-normal text-storm-gray-500">
|
|
48
|
+
{label}
|
|
49
|
+
</span>
|
|
50
|
+
<span className="shrink-0 text-right font-sans text-sm font-medium leading-[14px] tracking-normal text-storm-gray-900">
|
|
51
|
+
{value}
|
|
52
|
+
</span>
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function DetailsSection({ title, children }: { title: string; children: React.ReactNode }) {
|
|
58
|
+
return (
|
|
59
|
+
<section className="flex flex-col gap-3">
|
|
60
|
+
<h3 className="font-sans text-xs font-semibold uppercase leading-4 tracking-normal text-storm-gray-200">
|
|
61
|
+
{title}
|
|
62
|
+
</h3>
|
|
63
|
+
<div className="flex flex-col gap-4">{children}</div>
|
|
64
|
+
</section>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function RequestDetailsBody() {
|
|
69
|
+
return (
|
|
70
|
+
<>
|
|
71
|
+
<div className="flex flex-col gap-8 pb-6">
|
|
72
|
+
<div className="flex items-center justify-between gap-4">
|
|
73
|
+
<span className="font-sans text-sm font-medium leading-[19px] tracking-normal text-storm-gray-500">
|
|
74
|
+
Կարգավիճակ
|
|
75
|
+
</span>
|
|
76
|
+
<StatusBadge tone="warning">Սպասում է վճարման</StatusBadge>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<DetailsSection title="Կազմակերպության տվյալներ">
|
|
80
|
+
<DetailField label="Հասցե" value="Արաբկիր 12" />
|
|
81
|
+
<DetailField label="Կազմակերպություն" value="Manuk's org" />
|
|
82
|
+
<DetailField label="Սակագնային պլան" value="150+ Apartments" />
|
|
83
|
+
<DetailField label="Անհատական գին" value="10 ֏" />
|
|
84
|
+
<DetailField label="Բնակարանների առավելագույն քանակ" value="120" />
|
|
85
|
+
</DetailsSection>
|
|
86
|
+
|
|
87
|
+
<DetailsSection title="Կոնտակտային անձ">
|
|
88
|
+
<DetailField label="Անուն / Ազգանուն" value="Manuk Grigoryan" />
|
|
89
|
+
<DetailField label="Էլ. փոստ" value="manuk@example.com" />
|
|
90
|
+
<DetailField label="Հեռախոսահամար" value="+374 99 000000" />
|
|
91
|
+
</DetailsSection>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<section className="-mx-6 flex flex-col justify-between border-t border-dashed border-storm-gray-50 px-6 pt-6 pb-0">
|
|
95
|
+
<div className="flex flex-col gap-3">
|
|
96
|
+
<h3 className="font-sans text-xs font-semibold uppercase leading-4 tracking-normal text-storm-gray-200">
|
|
97
|
+
Գործողությունների պատմություն
|
|
98
|
+
</h3>
|
|
99
|
+
<HistoryTimeline events={historyEvents} />
|
|
100
|
+
</div>
|
|
101
|
+
</section>
|
|
102
|
+
</>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const footerButton = (
|
|
107
|
+
<div className="w-full">
|
|
108
|
+
<Button
|
|
109
|
+
title="Կրկին ուղարկել վճարման հղումը"
|
|
110
|
+
onPress={fn()}
|
|
111
|
+
variant="primary"
|
|
112
|
+
className="btn shrink-0 justify-center!"
|
|
113
|
+
textClassName="text-center!"
|
|
114
|
+
style={{
|
|
115
|
+
width: '100%',
|
|
116
|
+
height: 52,
|
|
117
|
+
minHeight: 52,
|
|
118
|
+
maxHeight: 52,
|
|
119
|
+
paddingTop: 0,
|
|
120
|
+
paddingBottom: 0,
|
|
121
|
+
}}
|
|
122
|
+
/>
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
function DrawerStoryShell({
|
|
127
|
+
open,
|
|
128
|
+
onClose,
|
|
129
|
+
footer,
|
|
130
|
+
title,
|
|
131
|
+
subtitle,
|
|
132
|
+
}: {
|
|
133
|
+
open: boolean;
|
|
134
|
+
onClose: () => void;
|
|
135
|
+
footer?: React.ReactNode;
|
|
136
|
+
title?: string;
|
|
137
|
+
subtitle?: string;
|
|
138
|
+
}) {
|
|
139
|
+
return (
|
|
140
|
+
<WebLayoutCanvas className="min-h-screen bg-storm-gray-100">
|
|
141
|
+
<Drawer
|
|
142
|
+
open={open}
|
|
143
|
+
title={title ?? 'Հայտ #00042'}
|
|
144
|
+
subtitle={subtitle ?? 'Ստացվել է 24.06.2026, 14:20'}
|
|
145
|
+
closeAriaLabel="Փակել"
|
|
146
|
+
onClose={onClose}
|
|
147
|
+
footer={footer}
|
|
148
|
+
>
|
|
149
|
+
<RequestDetailsBody />
|
|
150
|
+
</Drawer>
|
|
151
|
+
</WebLayoutCanvas>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export const Default: Story = {
|
|
156
|
+
args: {
|
|
157
|
+
children: null,
|
|
158
|
+
},
|
|
159
|
+
render: (args) => (
|
|
160
|
+
<DrawerStoryShell open={args.open} onClose={args.onClose} title={args.title} subtitle={args.subtitle} />
|
|
161
|
+
),
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export const WithFooter: Story = {
|
|
165
|
+
args: {
|
|
166
|
+
children: null,
|
|
167
|
+
},
|
|
168
|
+
render: (args) => (
|
|
169
|
+
<DrawerStoryShell
|
|
170
|
+
open={args.open}
|
|
171
|
+
onClose={args.onClose}
|
|
172
|
+
title={args.title}
|
|
173
|
+
subtitle={args.subtitle}
|
|
174
|
+
footer={footerButton}
|
|
175
|
+
/>
|
|
176
|
+
),
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
export const WithoutSubtitle: Story = {
|
|
180
|
+
args: {
|
|
181
|
+
children: null,
|
|
182
|
+
subtitle: undefined,
|
|
183
|
+
title: 'Կարգավորումներ',
|
|
184
|
+
},
|
|
185
|
+
render: (args) => (
|
|
186
|
+
<WebLayoutCanvas className="min-h-screen bg-storm-gray-100">
|
|
187
|
+
<Drawer
|
|
188
|
+
open={args.open}
|
|
189
|
+
title={args.title}
|
|
190
|
+
closeAriaLabel="Փակել"
|
|
191
|
+
onClose={args.onClose}
|
|
192
|
+
>
|
|
193
|
+
<p className="font-sans text-sm leading-[19px] text-storm-gray-500">
|
|
194
|
+
Drawer content without a subtitle line in the header.
|
|
195
|
+
</p>
|
|
196
|
+
</Drawer>
|
|
197
|
+
</WebLayoutCanvas>
|
|
198
|
+
),
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
function InteractiveDrawerStory() {
|
|
202
|
+
const [open, setOpen] = useState(false);
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<WebLayoutCanvas className="min-h-screen bg-storm-gray-100 p-6">
|
|
206
|
+
<button
|
|
207
|
+
type="button"
|
|
208
|
+
className="rounded-xl border border-storm-gray-50 bg-white px-4 py-2 text-sm font-medium text-slate-blue"
|
|
209
|
+
onClick={() => setOpen(true)}
|
|
210
|
+
>
|
|
211
|
+
Բացել drawer-ը
|
|
212
|
+
</button>
|
|
213
|
+
|
|
214
|
+
<Drawer
|
|
215
|
+
open={open}
|
|
216
|
+
title="Հայտ #00042"
|
|
217
|
+
subtitle="Ստացվել է 24.06.2026, 14:20"
|
|
218
|
+
closeAriaLabel="Փակել"
|
|
219
|
+
onClose={() => setOpen(false)}
|
|
220
|
+
footer={footerButton}
|
|
221
|
+
>
|
|
222
|
+
<RequestDetailsBody />
|
|
223
|
+
</Drawer>
|
|
224
|
+
</WebLayoutCanvas>
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export const Interactive: Story = {
|
|
229
|
+
args: {
|
|
230
|
+
children: null,
|
|
231
|
+
open: false,
|
|
232
|
+
},
|
|
233
|
+
render: () => <InteractiveDrawerStory />,
|
|
234
|
+
};
|