@scripso-homepad/ui 0.4.9 → 0.4.11

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.
Files changed (48) hide show
  1. package/dist/index.cjs +245 -127
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +4 -2
  4. package/dist/index.d.ts +4 -2
  5. package/dist/index.js +247 -129
  6. package/dist/index.js.map +1 -1
  7. package/dist/web/index.cjs +451 -48
  8. package/dist/web/index.cjs.map +1 -1
  9. package/dist/web/index.css +161 -0
  10. package/dist/web/index.css.map +1 -1
  11. package/dist/web/index.d.cts +50 -2
  12. package/dist/web/index.d.ts +50 -2
  13. package/dist/web/index.js +444 -49
  14. package/dist/web/index.js.map +1 -1
  15. package/package.json +10 -3
  16. package/src/components/Calendar.tsx +10 -2
  17. package/src/components/DatePicker.tsx +40 -6
  18. package/src/components/Select.tsx +133 -38
  19. package/src/theme/select.ts +1 -1
  20. package/src/utils/calendarDays.ts +15 -6
  21. package/src/web/components/Badge.tsx +1 -1
  22. package/src/web/components/ConfirmModal.tsx +2 -2
  23. package/src/web/components/Drawer.stories.tsx +234 -0
  24. package/src/web/components/Drawer.tsx +169 -0
  25. package/src/web/components/HistoryTimeline.tsx +46 -0
  26. package/src/web/components/Modal.stories.tsx +1 -1
  27. package/src/web/components/Modal.tsx +30 -13
  28. package/src/web/components/Pagination.tsx +2 -2
  29. package/src/web/components/TableActionButton.tsx +4 -4
  30. package/src/web/components/TableActionsMenu.tsx +1 -1
  31. package/src/web/components/TableIconText.tsx +1 -1
  32. package/src/web/components/Toaster.stories.tsx +106 -0
  33. package/src/web/components/Toaster.tsx +92 -0
  34. package/src/web/components/ToasterProvider.tsx +6 -0
  35. package/src/web/components/drawer-scroll.css +41 -0
  36. package/src/web/components/sonner-toast.css +141 -0
  37. package/src/web/components/table/constants.ts +2 -2
  38. package/src/web/icons/TimelineCheckIcon.tsx +24 -0
  39. package/src/web/icons/ToastIcons.tsx +119 -0
  40. package/src/web/index.ts +20 -0
  41. package/src/web/layout/AppHeader.tsx +1 -1
  42. package/src/web/layout/BuildingSelect.tsx +2 -2
  43. package/src/web/layout/DashboardLayout.stories.tsx +1 -1
  44. package/src/web/layout/SidebarNavItem.tsx +1 -1
  45. package/src/web/layout/SidebarUserCard.tsx +3 -3
  46. package/src/web/mutation-toast.ts +33 -0
  47. package/src/web/styles/typography.css +99 -0
  48. package/src/web/toast.ts +1 -0
@@ -0,0 +1,141 @@
1
+ .homepad-toaster {
2
+ --width: 409px;
3
+ --gap: 12px;
4
+ --border-radius: 20px;
5
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
6
+ }
7
+
8
+ .homepad-toaster [data-sonner-toast][data-styled='true'] {
9
+ align-items: center;
10
+ gap: 16px;
11
+ width: 409px;
12
+ min-height: 72px;
13
+ height: auto;
14
+ padding: 12px 44px 12px 12px;
15
+ background: #fff;
16
+ border: 1px solid var(--color-storm-gray-50, #eceef0);
17
+ border-radius: 20px;
18
+ box-shadow: 0 0 20px 0 #0000000d;
19
+ color: var(--color-slate-blue, #182e3c);
20
+ overflow: visible;
21
+ }
22
+
23
+ .homepad-toaster [data-sonner-toast][data-styled='true'][data-front='true'] {
24
+ height: auto !important;
25
+ }
26
+
27
+ .homepad-toaster
28
+ [data-sonner-toast][data-styled='true'][data-mounted='true'][data-expanded='true'] {
29
+ height: auto !important;
30
+ }
31
+
32
+ .homepad-toaster [data-sonner-toast][data-styled='true'] [data-icon] {
33
+ width: auto;
34
+ height: auto;
35
+ margin: 0;
36
+ }
37
+
38
+ .homepad-toaster [data-sonner-toast][data-styled='true'] [data-content] {
39
+ gap: 2px;
40
+ min-width: 0;
41
+ flex: 1;
42
+ align-self: center;
43
+ overflow: visible;
44
+ }
45
+
46
+ .homepad-toaster .homepad-toast__title {
47
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
48
+ font-size: 14px;
49
+ font-weight: 700;
50
+ line-height: 22px;
51
+ letter-spacing: 0;
52
+ color: var(--color-slate-blue, #182e3c);
53
+ }
54
+
55
+ .homepad-toaster .homepad-toast__description {
56
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
57
+ font-size: 12px;
58
+ font-weight: 400;
59
+ line-height: 1.4;
60
+ letter-spacing: 0;
61
+ color: var(--color-slate-blue, #182e3c);
62
+ }
63
+
64
+ .homepad-toaster .homepad-toast__icon-badge {
65
+ display: flex;
66
+ width: 48px;
67
+ height: 48px;
68
+ flex-shrink: 0;
69
+ align-items: center;
70
+ justify-content: center;
71
+ padding: 12px;
72
+ border-radius: 12px;
73
+ box-sizing: border-box;
74
+ }
75
+
76
+ .homepad-toaster .homepad-toast__icon-badge svg {
77
+ width: 24px;
78
+ height: 24px;
79
+ margin: 0;
80
+ flex-shrink: 0;
81
+ }
82
+
83
+ .homepad-toaster .homepad-toast__icon-badge--success {
84
+ background: var(--color-emerald-green-0, #f0fbf5);
85
+ }
86
+
87
+ .homepad-toaster .homepad-toast__icon-badge--error {
88
+ background: var(--color-ruby-red-0, #fff5f6);
89
+ }
90
+
91
+ .homepad-toaster .homepad-toast__icon-badge--warning {
92
+ background: #f2a8001a;
93
+ }
94
+
95
+ .homepad-toaster .homepad-toast__icon-badge--info,
96
+ .homepad-toaster .homepad-toast__icon-badge--default {
97
+ background: #0f52c71a;
98
+ }
99
+
100
+ .homepad-toaster [data-sonner-toast][data-styled='true'] [data-close-button] {
101
+ top: 50%;
102
+ right: 12px;
103
+ left: auto;
104
+ width: 20px;
105
+ height: 20px;
106
+ transform: translateY(-50%);
107
+ border: 0;
108
+ background: transparent;
109
+ box-shadow: none;
110
+ cursor: pointer;
111
+ }
112
+
113
+ .homepad-toaster [data-sonner-toast][data-styled='true']:hover [data-close-button]:hover {
114
+ background: transparent;
115
+ border-color: transparent;
116
+ cursor: pointer;
117
+ }
118
+
119
+ .homepad-toaster [data-sonner-toast][data-styled='true'] [data-close-button] svg {
120
+ width: 20px;
121
+ height: 20px;
122
+ }
123
+
124
+ @media (max-width: 767px) {
125
+ .homepad-toaster {
126
+ --width: calc(100vw - 16px);
127
+ }
128
+
129
+ .homepad-toaster[data-sonner-toaster] {
130
+ right: var(--mobile-offset-right, 8px);
131
+ left: var(--mobile-offset-left, 8px);
132
+ width: calc(100vw - 16px);
133
+ max-width: calc(100vw - 16px);
134
+ }
135
+
136
+ .homepad-toaster [data-sonner-toast][data-styled='true'] {
137
+ right: 0;
138
+ left: 0;
139
+ width: 100%;
140
+ }
141
+ }
@@ -21,10 +21,10 @@ export const tableShellClassName = 'flex flex-col overflow-hidden border bg-stor
21
21
  export const tableFooterShellClassName = 'overflow-hidden rounded-b-xl border bg-storm-gray-0';
22
22
 
23
23
  export const tableHeaderClassName =
24
- 'bg-storm-gray-0 font-sans text-xs font-normal leading-none tracking-normal text-storm-gray-400';
24
+ 'bg-storm-gray-0 typography-12 font-normal tracking-normal text-storm-gray-400';
25
25
 
26
26
  export const tableBodyClassName =
27
- 'bg-white font-sans text-sm font-medium leading-none tracking-normal text-storm-gray-900';
27
+ 'bg-white typography-14 font-medium tracking-normal text-storm-gray-900';
28
28
 
29
29
  export const tableAlignClasses = {
30
30
  left: '',
@@ -0,0 +1,24 @@
1
+ import type { SVGProps } from 'react';
2
+
3
+ export function TimelineCheckIcon({ className, ...props }: SVGProps<SVGSVGElement>) {
4
+ return (
5
+ <svg
6
+ width="16"
7
+ height="16"
8
+ viewBox="0 0 16 16"
9
+ fill="none"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ className={className}
12
+ aria-hidden
13
+ {...props}
14
+ >
15
+ <path
16
+ d="M13.3346 4L6.0013 11.3333L2.66797 8"
17
+ stroke="#279D54"
18
+ strokeWidth="1.5"
19
+ strokeLinecap="round"
20
+ strokeLinejoin="round"
21
+ />
22
+ </svg>
23
+ );
24
+ }
@@ -0,0 +1,119 @@
1
+ import type { SVGProps } from 'react';
2
+
3
+ function ToastCloseIcon(props: SVGProps<SVGSVGElement>) {
4
+ return (
5
+ <svg
6
+ width="20"
7
+ height="20"
8
+ viewBox="0 0 20 20"
9
+ fill="none"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ aria-hidden
12
+ {...props}
13
+ >
14
+ <path
15
+ d="M15 5L5 15M5 5L15 15"
16
+ stroke="#B5BCC1"
17
+ strokeWidth="2"
18
+ strokeLinecap="round"
19
+ strokeLinejoin="round"
20
+ />
21
+ </svg>
22
+ );
23
+ }
24
+
25
+ function ToastSuccessIcon(props: SVGProps<SVGSVGElement>) {
26
+ return (
27
+ <svg
28
+ width="24"
29
+ height="24"
30
+ viewBox="0 0 24 24"
31
+ fill="none"
32
+ xmlns="http://www.w3.org/2000/svg"
33
+ aria-hidden
34
+ {...props}
35
+ >
36
+ <path
37
+ d="M20 6L9 17L4 12"
38
+ stroke="#279D54"
39
+ strokeWidth="2"
40
+ strokeLinecap="round"
41
+ strokeLinejoin="round"
42
+ />
43
+ </svg>
44
+ );
45
+ }
46
+
47
+ function ToastErrorIcon(props: SVGProps<SVGSVGElement>) {
48
+ return (
49
+ <svg
50
+ width="24"
51
+ height="24"
52
+ viewBox="0 0 24 24"
53
+ fill="none"
54
+ xmlns="http://www.w3.org/2000/svg"
55
+ aria-hidden
56
+ {...props}
57
+ >
58
+ <path
59
+ d="M18 6L6 18M6 6L18 18"
60
+ stroke="#AE0011"
61
+ strokeWidth="2"
62
+ strokeLinecap="round"
63
+ strokeLinejoin="round"
64
+ />
65
+ </svg>
66
+ );
67
+ }
68
+
69
+ function ToastWarningIcon(props: SVGProps<SVGSVGElement>) {
70
+ return (
71
+ <svg
72
+ width="24"
73
+ height="24"
74
+ viewBox="0 0 24 24"
75
+ fill="none"
76
+ xmlns="http://www.w3.org/2000/svg"
77
+ aria-hidden
78
+ {...props}
79
+ >
80
+ <path
81
+ d="M12.0001 9.00022V13.0002M12.0001 17.0002H12.0101M21.7301 18.0002L13.7301 4.00022C13.5556 3.69243 13.3027 3.43641 12.997 3.25829C12.6913 3.08017 12.3438 2.98633 11.9901 2.98633C11.6363 2.98633 11.2888 3.08017 10.9831 3.25829C10.6774 3.43641 10.4245 3.69243 10.2501 4.00022L2.25005 18.0002C2.07373 18.3056 1.98128 18.6521 1.98206 19.0047C1.98284 19.3573 2.07683 19.7035 2.2545 20.008C2.43217 20.3126 2.6872 20.5648 2.99375 20.7391C3.30029 20.9133 3.64746 21.0034 4.00005 21.0002H20.0001C20.351 20.9999 20.6956 20.9072 20.9993 20.7315C21.3031 20.5558 21.5553 20.3033 21.7306 19.9993C21.9059 19.6954 21.9981 19.3506 21.998 18.9997C21.9979 18.6488 21.9055 18.3041 21.7301 18.0002Z"
82
+ stroke="#F2A800"
83
+ strokeWidth="2"
84
+ strokeLinecap="round"
85
+ strokeLinejoin="round"
86
+ />
87
+ </svg>
88
+ );
89
+ }
90
+
91
+ function ToastInfoIcon(props: SVGProps<SVGSVGElement>) {
92
+ return (
93
+ <svg
94
+ width="24"
95
+ height="24"
96
+ viewBox="0 0 24 24"
97
+ fill="none"
98
+ xmlns="http://www.w3.org/2000/svg"
99
+ aria-hidden
100
+ {...props}
101
+ >
102
+ <path
103
+ d="M12 16V12M12 8H12.01M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12Z"
104
+ stroke="#0F52C7"
105
+ strokeWidth="2"
106
+ strokeLinecap="round"
107
+ strokeLinejoin="round"
108
+ />
109
+ </svg>
110
+ );
111
+ }
112
+
113
+ export {
114
+ ToastCloseIcon,
115
+ ToastErrorIcon,
116
+ ToastInfoIcon,
117
+ ToastSuccessIcon,
118
+ ToastWarningIcon,
119
+ };
package/src/web/index.ts CHANGED
@@ -99,6 +99,26 @@ export type { TableIconTextProps } from './components/TableIconText';
99
99
  export { Modal } from './components/Modal';
100
100
  export type { ModalFooterAlign, ModalFooterLayout, ModalProps } from './components/Modal';
101
101
 
102
+ export { Drawer } from './components/Drawer';
103
+ export type { DrawerProps } from './components/Drawer';
104
+
105
+ export { HistoryTimeline } from './components/HistoryTimeline';
106
+ export type { HistoryTimelineItem, HistoryTimelineProps } from './components/HistoryTimeline';
107
+
108
+ export { Toaster } from './components/Toaster';
109
+ export type { HomepadToasterProps } from './components/Toaster';
110
+
111
+ export { ToasterProvider } from './components/ToasterProvider';
112
+
113
+ export { toast } from './toast';
114
+
115
+ export {
116
+ runMutationWithToast,
117
+ type MutationToastMessages,
118
+ type MutationToastResult,
119
+ type RunMutationWithToastOptions,
120
+ } from './mutation-toast';
121
+
102
122
  export { ConfirmModal } from './components/ConfirmModal';
103
123
  export type { ConfirmModalProps } from './components/ConfirmModal';
104
124
 
@@ -72,7 +72,7 @@ export function AppHeader({
72
72
  className,
73
73
  )}
74
74
  >
75
- <h1 className="truncate text-xl font-bold text-slate-blue">{title}</h1>
75
+ <h1 className="truncate typography-title text-slate-blue">{title}</h1>
76
76
 
77
77
  <div className="flex shrink-0 items-center gap-3">
78
78
  {hasBuildingSelect ? (
@@ -141,7 +141,7 @@ export function BuildingSelect({
141
141
  )}
142
142
  >
143
143
  {buildingIcon ?? <BuildingIcon className="shrink-0 text-navy" />}
144
- <span className="min-w-0 flex-1 truncate text-sm font-medium text-slate-blue">
144
+ <span className="min-w-0 flex-1 truncate typography-14 font-medium text-slate-blue">
145
145
  {displayLabel}
146
146
  </span>
147
147
  {chevronIcon ?? (
@@ -190,7 +190,7 @@ export function BuildingSelect({
190
190
  }}
191
191
  onClick={() => selectOption(option)}
192
192
  className={cn(
193
- 'flex w-full rounded-lg px-3 py-2.5 text-left text-sm font-medium text-slate-blue transition-colors',
193
+ 'flex w-full rounded-lg px-3 py-2.5 text-left typography-14 font-medium text-slate-blue transition-colors',
194
194
  !option.disabled && 'cursor-pointer hover:bg-storm-gray-50',
195
195
  (isSelected || isHighlighted) && !option.disabled && 'bg-storm-gray-50',
196
196
  option.disabled && 'cursor-not-allowed opacity-50',
@@ -69,7 +69,7 @@ function DashboardLayoutDemo() {
69
69
  }}
70
70
  >
71
71
  <div className="rounded-xl border border-storm-gray-50 bg-white p-6">
72
- <p className="text-sm text-storm-gray-500">Page content goes here.</p>
72
+ <p className="typography-14 text-storm-gray-500">Page content goes here.</p>
73
73
  </div>
74
74
  </DashboardLayout>
75
75
  </WebLayoutCanvas>
@@ -47,7 +47,7 @@ export function SidebarNavItem({ item, isOpen, onNavigate }: SidebarNavItemProps
47
47
  <span className="flex size-5 shrink-0 items-center justify-center">{item.icon}</span>
48
48
  <span
49
49
  className={cn(
50
- 'overflow-hidden text-sm font-semibold whitespace-nowrap transition-[max-width,opacity] duration-300 ease-in-out',
50
+ 'overflow-hidden typography-14 font-semibold whitespace-nowrap transition-[max-width,opacity] duration-300 ease-in-out',
51
51
  isOpen ? 'max-w-[180px] opacity-100' : 'max-w-0 opacity-0',
52
52
  )}
53
53
  >
@@ -41,7 +41,7 @@ export function SidebarUserCard({
41
41
  )}
42
42
  >
43
43
  <div
44
- className="flex size-11 shrink-0 items-center justify-center rounded-full bg-white/5 text-sm font-bold text-white"
44
+ className="flex size-11 shrink-0 items-center justify-center rounded-full bg-white/5 typography-14 font-bold text-white"
45
45
  aria-hidden
46
46
  >
47
47
  {initials}
@@ -49,8 +49,8 @@ export function SidebarUserCard({
49
49
  {isOpen ? (
50
50
  <>
51
51
  <div className="flex min-w-0 flex-1 flex-col overflow-hidden">
52
- <p className="truncate text-sm font-bold text-white">{user.fullName}</p>
53
- <p className="truncate text-xs text-storm-gray-100">{user.email}</p>
52
+ <p className="truncate typography-14 font-bold text-white">{user.fullName}</p>
53
+ <p className="truncate typography-12 text-storm-gray-100">{user.email}</p>
54
54
  </div>
55
55
  <button
56
56
  type="button"
@@ -0,0 +1,33 @@
1
+ import { toast } from './toast';
2
+
3
+ export type MutationToastMessages = {
4
+ success: string;
5
+ error: string;
6
+ };
7
+
8
+ export type MutationToastResult = {
9
+ success: boolean;
10
+ errorMessage?: string;
11
+ };
12
+
13
+ export type RunMutationWithToastOptions = {
14
+ getErrorMessage?: (error: unknown) => string;
15
+ };
16
+
17
+ export async function runMutationWithToast(
18
+ action: () => Promise<unknown>,
19
+ messages: MutationToastMessages,
20
+ options?: RunMutationWithToastOptions,
21
+ ): Promise<MutationToastResult> {
22
+ try {
23
+ await action();
24
+ toast.success(messages.success);
25
+
26
+ return { success: true };
27
+ } catch (error) {
28
+ const errorMessage = options?.getErrorMessage?.(error) ?? messages.error;
29
+ toast.error(errorMessage);
30
+
31
+ return { success: false, errorMessage };
32
+ }
33
+ }
@@ -0,0 +1,99 @@
1
+ @layer components {
2
+ .typography-12 {
3
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
4
+ font-size: 12px;
5
+ line-height: 16px;
6
+ letter-spacing: 0;
7
+ }
8
+
9
+ .typography-14 {
10
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
11
+ font-size: 14px;
12
+ line-height: 19px;
13
+ letter-spacing: 0;
14
+ }
15
+
16
+ .typography-18 {
17
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
18
+ font-size: 18px;
19
+ line-height: 24px;
20
+ letter-spacing: 0;
21
+ }
22
+
23
+ .typography-20 {
24
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
25
+ font-size: 20px;
26
+ line-height: 27px;
27
+ letter-spacing: 0;
28
+ }
29
+
30
+ .typography-24 {
31
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
32
+ font-size: 24px;
33
+ line-height: 25px;
34
+ letter-spacing: 0;
35
+ }
36
+
37
+ .typography-32 {
38
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
39
+ font-size: 32px;
40
+ line-height: 34px;
41
+ letter-spacing: 0;
42
+ }
43
+
44
+ .typography-body {
45
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
46
+ font-size: 14px;
47
+ line-height: 19px;
48
+ letter-spacing: 0;
49
+ font-weight: 400;
50
+ }
51
+
52
+ .typography-body-medium {
53
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
54
+ font-size: 14px;
55
+ line-height: 19px;
56
+ letter-spacing: 0;
57
+ font-weight: 500;
58
+ }
59
+
60
+ .typography-caption {
61
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
62
+ font-size: 12px;
63
+ line-height: 16px;
64
+ letter-spacing: 0;
65
+ font-weight: 400;
66
+ }
67
+
68
+ .typography-title-sm {
69
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
70
+ font-size: 18px;
71
+ line-height: 24px;
72
+ letter-spacing: 0;
73
+ font-weight: 700;
74
+ }
75
+
76
+ .typography-title {
77
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
78
+ font-size: 20px;
79
+ line-height: 27px;
80
+ letter-spacing: 0;
81
+ font-weight: 700;
82
+ }
83
+
84
+ .typography-title-lg {
85
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
86
+ font-size: 24px;
87
+ line-height: 25px;
88
+ letter-spacing: 0;
89
+ font-weight: 700;
90
+ }
91
+
92
+ .typography-display {
93
+ font-family: var(--font-sans, 'Noto Sans Armenian', ui-sans-serif, system-ui, sans-serif);
94
+ font-size: 32px;
95
+ line-height: 34px;
96
+ letter-spacing: 0;
97
+ font-weight: 700;
98
+ }
99
+ }
@@ -0,0 +1 @@
1
+ export { toast } from 'sonner';