@scripso-homepad/ui 0.4.2 → 0.4.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/dist/{chunk-WDSMJWKC.js → chunk-66WR57JJ.js} +35 -3
- package/dist/chunk-66WR57JJ.js.map +1 -0
- package/dist/index.cjs +2258 -384
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +134 -1
- package/dist/index.d.ts +134 -1
- package/dist/index.js +1959 -97
- package/dist/index.js.map +1 -1
- package/dist/web/index.cjs +30650 -1009
- package/dist/web/index.cjs.map +1 -1
- package/dist/web/index.css +78 -0
- package/dist/web/index.css.map +1 -0
- package/dist/web/index.d.cts +267 -6
- package/dist/web/index.d.ts +267 -6
- package/dist/web/index.js +30179 -601
- package/dist/web/index.js.map +1 -1
- package/package.json +5 -4
- package/src/components/Calendar.stories.tsx +337 -0
- package/src/components/Calendar.tsx +441 -0
- package/src/components/DatePicker.stories.tsx +219 -0
- package/src/components/DatePicker.tsx +366 -0
- package/src/components/Select.stories.tsx +134 -0
- package/src/components/Select.tsx +465 -0
- package/src/css.d.ts +1 -0
- package/src/icons/CalendarIcon.tsx +28 -0
- package/src/icons/CalendarIcon.web.tsx +34 -0
- package/src/icons/ChevronDownIcon.tsx +11 -4
- package/src/icons/ChevronDownIcon.web.tsx +6 -4
- package/src/icons/ChevronNavIcons.tsx +44 -0
- package/src/icons/ChevronNavIcons.web.tsx +57 -0
- package/src/icons/calendarIconPaths.ts +2 -0
- package/src/icons/chevronDownPath.ts +1 -0
- package/src/icons/chevronNavPaths.ts +2 -0
- package/src/index.ts +41 -0
- package/src/theme/calendar.ts +357 -0
- package/src/theme/select.ts +247 -0
- package/src/utils/calendarDays.ts +273 -0
- package/src/utils/calendarLocaleContext.tsx +95 -0
- package/src/utils/calendarLocalization.ts +187 -0
- package/src/utils/countryDropdownScrollStyles.ts +53 -13
- package/src/utils/formatMultiSelectDisplay.ts +56 -0
- package/src/web/components/Badge.stories.tsx +43 -0
- package/src/web/components/Badge.tsx +35 -0
- package/src/web/components/Pagination.stories.tsx +78 -0
- package/src/web/components/Pagination.tsx +153 -0
- package/src/web/components/StatusBadge.tsx +20 -0
- package/src/web/components/Table.stories.tsx +415 -0
- package/src/web/components/Table.tsx +3 -0
- package/src/web/components/TableActionButton.tsx +67 -0
- package/src/web/components/TableActionsMenu.tsx +208 -0
- package/src/web/components/TableIconText.tsx +23 -0
- package/src/web/components/TableRowStatusActions.tsx +33 -0
- package/src/web/components/TableStatusActionsCell.tsx +29 -0
- package/src/web/components/pagination-utils.ts +39 -0
- package/src/web/components/table/DataTable.tsx +123 -0
- package/src/web/components/table/TablePrimitives.tsx +214 -0
- package/src/web/components/table/TableScrollArea.tsx +51 -0
- package/src/web/components/table/constants.ts +59 -0
- package/src/web/components/table/data-table-class-names.ts +26 -0
- package/src/web/components/table/index.ts +44 -0
- package/src/web/components/table/table-row-context.tsx +19 -0
- package/src/web/components/table/use-horizontal-scroll-state.ts +72 -0
- package/src/web/components/table-scroll.css +81 -0
- package/src/web/hooks/useOnClickOutside.ts +20 -5
- package/src/web/icons/TableMenuActivateIcon.tsx +27 -0
- package/src/web/icons/TableMenuCheckIcon.tsx +27 -0
- package/src/web/icons/TableMenuCloseIcon.tsx +27 -0
- package/src/web/icons/TableMenuEditIcon.tsx +27 -0
- package/src/web/icons/TableMenuInfoIcon.tsx +27 -0
- package/src/web/icons/TableMenuRefreshIcon.tsx +27 -0
- package/src/web/icons/TableMenuSuspendIcon.tsx +34 -0
- package/src/web/icons/TableMenuTrashIcon.tsx +27 -0
- package/src/web/icons/TableMoreIcon.tsx +41 -0
- package/src/web/icons/TableSortIcon.tsx +37 -0
- package/src/web/index.ts +74 -0
- package/src/web/layout/AppHeader.stories.tsx +2 -0
- package/src/web/layout/AppHeader.tsx +18 -14
- package/src/web/layout/DashboardLayout.stories.tsx +1 -0
- package/src/web/layout/DashboardLayout.tsx +4 -4
- package/src/web/layout/story-helpers.tsx +10 -2
- package/dist/chunk-WDSMJWKC.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.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Cross-platform UI components for Homepad (React Web + React Native)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
"prepublishOnly": "npm run build"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
+
"lucide-react": ">=0.400",
|
|
49
50
|
"react": ">=18",
|
|
50
51
|
"react-native": ">=0.74",
|
|
51
52
|
"react-native-svg": ">=13",
|
|
52
53
|
"react-native-web": ">=0.19",
|
|
53
|
-
"react-router-dom": ">=6"
|
|
54
|
-
"lucide-react": ">=0.400"
|
|
54
|
+
"react-router-dom": ">=6"
|
|
55
55
|
},
|
|
56
56
|
"peerDependenciesMeta": {
|
|
57
57
|
"react-native-svg": {
|
|
@@ -79,16 +79,17 @@
|
|
|
79
79
|
"@tailwindcss/postcss": "^4.1.13",
|
|
80
80
|
"@tailwindcss/vite": "^4.1.13",
|
|
81
81
|
"@types/react": "^18.3.18",
|
|
82
|
+
"@types/react-dom": "^18.3.7",
|
|
82
83
|
"eslint": "^9.17.0",
|
|
83
84
|
"eslint-plugin-react-hooks": "^5.1.0",
|
|
84
85
|
"globals": "^15.14.0",
|
|
85
86
|
"lucide-react": "^0.563.0",
|
|
86
87
|
"react": "^18.3.1",
|
|
87
88
|
"react-dom": "^18.3.1",
|
|
88
|
-
"react-router-dom": "^7.9.1",
|
|
89
89
|
"react-native": "^0.76.5",
|
|
90
90
|
"react-native-svg": "^15.11.2",
|
|
91
91
|
"react-native-web": "^0.19.13",
|
|
92
|
+
"react-router-dom": "^7.9.1",
|
|
92
93
|
"storybook": "^8.4.7",
|
|
93
94
|
"tailwindcss": "^4.1.13",
|
|
94
95
|
"tsup": "^8.3.5",
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { StyleSheet, Text, View } from "react-native";
|
|
4
|
+
import { CalendarIcon } from "../icons/CalendarIcon";
|
|
5
|
+
import {
|
|
6
|
+
CALENDAR_DROPDOWN_GAP,
|
|
7
|
+
CALENDAR_FIELD_ICON_SIZE,
|
|
8
|
+
calendarFieldMetrics,
|
|
9
|
+
calendarFieldPlaceholderTypography,
|
|
10
|
+
calendarFieldTypography,
|
|
11
|
+
} from "../theme/calendar";
|
|
12
|
+
import { getSelectFieldStyles, resolveInputVisualState } from "../theme/select";
|
|
13
|
+
import { colors } from "../theme/tokens";
|
|
14
|
+
import { formatCalendarDate } from "../utils/calendarDays";
|
|
15
|
+
import { formatLocalizedCalendarMonthYear } from "../utils/calendarLocalization";
|
|
16
|
+
import {
|
|
17
|
+
Calendar,
|
|
18
|
+
type CalendarLabels,
|
|
19
|
+
type CalendarRangeProps,
|
|
20
|
+
type CalendarSingleProps,
|
|
21
|
+
type DateRange,
|
|
22
|
+
} from "./Calendar";
|
|
23
|
+
import { DatePicker, type DatePickerRangeProps } from "./DatePicker";
|
|
24
|
+
|
|
25
|
+
const figmaViewDate = new Date(2026, 5, 1);
|
|
26
|
+
const figmaSampleDate = new Date(2026, 5, 25);
|
|
27
|
+
|
|
28
|
+
function getCurrentMonthStart() {
|
|
29
|
+
const now = new Date();
|
|
30
|
+
return new Date(now.getFullYear(), now.getMonth(), 1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getSampleRange(): DateRange {
|
|
34
|
+
const now = new Date();
|
|
35
|
+
return {
|
|
36
|
+
start: new Date(now.getFullYear(), now.getMonth(), 20),
|
|
37
|
+
end: new Date(now.getFullYear(), now.getMonth(), 28),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const figmaLabels: CalendarLabels = {
|
|
42
|
+
weekdays: ["ԵՐ", "ԵՔ", "ՉՐ", "ՀՆ", "ՈՒՐ", "ՇԲ", "ԿՐ"],
|
|
43
|
+
formatMonthYear: (date) => formatLocalizedCalendarMonthYear(date, "hy-AM"),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const sharedCalendarArgs = {
|
|
47
|
+
mode: "single" as const,
|
|
48
|
+
locale: "hy-AM" as const,
|
|
49
|
+
defaultViewDate: getCurrentMonthStart(),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const figmaCalendarArgs = {
|
|
53
|
+
...sharedCalendarArgs,
|
|
54
|
+
today: figmaSampleDate,
|
|
55
|
+
defaultViewDate: figmaViewDate,
|
|
56
|
+
labels: figmaLabels,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
function FullCalendarDemo({
|
|
60
|
+
initialValue,
|
|
61
|
+
placeholder = "Ընտրել ամսաթիվ",
|
|
62
|
+
calendarProps = sharedCalendarArgs,
|
|
63
|
+
}: {
|
|
64
|
+
initialValue?: Date;
|
|
65
|
+
placeholder?: string;
|
|
66
|
+
calendarProps?: CalendarSingleProps;
|
|
67
|
+
}) {
|
|
68
|
+
const [value, setValue] = useState<Date | undefined>(initialValue);
|
|
69
|
+
const fieldStyles = getSelectFieldStyles(resolveInputVisualState({}));
|
|
70
|
+
const displayText = value
|
|
71
|
+
? formatCalendarDate(value, calendarProps.locale ?? "hy-AM")
|
|
72
|
+
: placeholder;
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<View style={styles.full}>
|
|
76
|
+
<View style={fieldStyles.outline}>
|
|
77
|
+
<View style={[calendarFieldMetrics.container, fieldStyles.container]}>
|
|
78
|
+
<Text
|
|
79
|
+
style={[
|
|
80
|
+
calendarFieldMetrics.value,
|
|
81
|
+
value
|
|
82
|
+
? { ...calendarFieldTypography, color: fieldStyles.value.color }
|
|
83
|
+
: calendarFieldPlaceholderTypography,
|
|
84
|
+
]}
|
|
85
|
+
numberOfLines={1}
|
|
86
|
+
>
|
|
87
|
+
{displayText}
|
|
88
|
+
</Text>
|
|
89
|
+
<View style={styles.iconSlot}>
|
|
90
|
+
<CalendarIcon
|
|
91
|
+
size={CALENDAR_FIELD_ICON_SIZE}
|
|
92
|
+
color={colors.stormGray150}
|
|
93
|
+
/>
|
|
94
|
+
</View>
|
|
95
|
+
</View>
|
|
96
|
+
</View>
|
|
97
|
+
|
|
98
|
+
<Calendar
|
|
99
|
+
{...calendarProps}
|
|
100
|
+
value={value}
|
|
101
|
+
onChange={setValue}
|
|
102
|
+
style={styles.calendarPanel}
|
|
103
|
+
/>
|
|
104
|
+
</View>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const meta = {
|
|
109
|
+
title: "Components/Calendar",
|
|
110
|
+
component: Calendar,
|
|
111
|
+
parameters: {
|
|
112
|
+
layout: "centered",
|
|
113
|
+
},
|
|
114
|
+
args: sharedCalendarArgs,
|
|
115
|
+
} satisfies Meta<CalendarSingleProps>;
|
|
116
|
+
|
|
117
|
+
export default meta;
|
|
118
|
+
type Story = StoryObj<typeof meta>;
|
|
119
|
+
|
|
120
|
+
/** Full UI — click field to open calendar (range DatePicker). */
|
|
121
|
+
export const Full = {
|
|
122
|
+
render: function FullDatePickerStory() {
|
|
123
|
+
const [value, setValue] = useState<DateRange | undefined>(getSampleRange);
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<View style={styles.full}>
|
|
127
|
+
<DatePicker
|
|
128
|
+
mode="range"
|
|
129
|
+
locale={sharedCalendarArgs.locale}
|
|
130
|
+
defaultViewDate={sharedCalendarArgs.defaultViewDate}
|
|
131
|
+
placeholder="Ընտրել ժամանակահատված"
|
|
132
|
+
value={value}
|
|
133
|
+
onChange={setValue}
|
|
134
|
+
/>
|
|
135
|
+
</View>
|
|
136
|
+
);
|
|
137
|
+
},
|
|
138
|
+
} satisfies StoryObj<DatePickerRangeProps>;
|
|
139
|
+
|
|
140
|
+
/** Static preview — field + calendar always visible (Figma layout). */
|
|
141
|
+
export const FullStatic: Story = {
|
|
142
|
+
render: () => (
|
|
143
|
+
<FullCalendarDemo
|
|
144
|
+
calendarProps={figmaCalendarArgs}
|
|
145
|
+
initialValue={figmaSampleDate}
|
|
146
|
+
/>
|
|
147
|
+
),
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export const FullWithSelectedDate: Story = {
|
|
151
|
+
render: () => (
|
|
152
|
+
<FullCalendarDemo
|
|
153
|
+
calendarProps={figmaCalendarArgs}
|
|
154
|
+
initialValue={figmaSampleDate}
|
|
155
|
+
/>
|
|
156
|
+
),
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export const WithSelectedDay: Story = {
|
|
160
|
+
render: function SelectedDayStory() {
|
|
161
|
+
const [value, setValue] = useState<Date | undefined>(new Date(2026, 5, 26));
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<View style={styles.panel}>
|
|
165
|
+
<Calendar {...figmaCalendarArgs} value={value} onChange={setValue} />
|
|
166
|
+
</View>
|
|
167
|
+
);
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
export const PanelOnly: Story = {
|
|
172
|
+
render: function PanelOnlyStory() {
|
|
173
|
+
const [value, setValue] = useState<Date | undefined>();
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<View style={styles.panel}>
|
|
177
|
+
<Calendar {...sharedCalendarArgs} value={value} onChange={setValue} />
|
|
178
|
+
</View>
|
|
179
|
+
);
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export const Interactive: Story = {
|
|
184
|
+
render: function InteractiveCalendarStory() {
|
|
185
|
+
const [value, setValue] = useState<Date | undefined>();
|
|
186
|
+
|
|
187
|
+
return (
|
|
188
|
+
<View style={styles.panel}>
|
|
189
|
+
<Calendar {...sharedCalendarArgs} value={value} onChange={setValue} />
|
|
190
|
+
</View>
|
|
191
|
+
);
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export const WithMinDate: Story = {
|
|
196
|
+
render: function MinDateCalendarStory() {
|
|
197
|
+
const minDate = new Date();
|
|
198
|
+
const [value, setValue] = useState<Date | undefined>(minDate);
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
<View style={styles.panel}>
|
|
202
|
+
<Calendar
|
|
203
|
+
{...sharedCalendarArgs}
|
|
204
|
+
value={value}
|
|
205
|
+
onChange={setValue}
|
|
206
|
+
minDate={minDate}
|
|
207
|
+
/>
|
|
208
|
+
</View>
|
|
209
|
+
);
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export const Range = {
|
|
214
|
+
render: function RangeCalendarStory() {
|
|
215
|
+
const [value, setValue] = useState<DateRange | undefined>(getSampleRange);
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
<View style={styles.panel}>
|
|
219
|
+
<Calendar
|
|
220
|
+
locale="en-US"
|
|
221
|
+
defaultViewDate={getCurrentMonthStart()}
|
|
222
|
+
mode="range"
|
|
223
|
+
value={value}
|
|
224
|
+
onChange={setValue}
|
|
225
|
+
/>
|
|
226
|
+
</View>
|
|
227
|
+
);
|
|
228
|
+
},
|
|
229
|
+
} satisfies StoryObj<CalendarRangeProps>;
|
|
230
|
+
|
|
231
|
+
export const RangeInteractive = {
|
|
232
|
+
render: function RangeInteractiveCalendarStory() {
|
|
233
|
+
const [value, setValue] = useState<DateRange | undefined>(getSampleRange);
|
|
234
|
+
|
|
235
|
+
return (
|
|
236
|
+
<View style={styles.panel}>
|
|
237
|
+
<Calendar
|
|
238
|
+
locale="en-US"
|
|
239
|
+
defaultViewDate={getCurrentMonthStart()}
|
|
240
|
+
mode="range"
|
|
241
|
+
value={value}
|
|
242
|
+
onChange={setValue}
|
|
243
|
+
/>
|
|
244
|
+
</View>
|
|
245
|
+
);
|
|
246
|
+
},
|
|
247
|
+
} satisfies StoryObj<CalendarRangeProps>;
|
|
248
|
+
|
|
249
|
+
/** Click the header to open month picker, then click the year for year picker. */
|
|
250
|
+
export const MonthYearPicker: Story = {
|
|
251
|
+
render: function MonthYearPickerStory() {
|
|
252
|
+
const [value, setValue] = useState<Date | undefined>();
|
|
253
|
+
|
|
254
|
+
return (
|
|
255
|
+
<View style={styles.panel}>
|
|
256
|
+
<Calendar {...sharedCalendarArgs} value={value} onChange={setValue} />
|
|
257
|
+
</View>
|
|
258
|
+
);
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
export const EnglishLocale: Story = {
|
|
263
|
+
render: function EnglishCalendarStory() {
|
|
264
|
+
const [value, setValue] = useState<Date | undefined>();
|
|
265
|
+
|
|
266
|
+
return (
|
|
267
|
+
<View style={styles.panel}>
|
|
268
|
+
<Calendar
|
|
269
|
+
mode="single"
|
|
270
|
+
locale="en-US"
|
|
271
|
+
defaultViewDate={getCurrentMonthStart()}
|
|
272
|
+
value={value}
|
|
273
|
+
onChange={setValue}
|
|
274
|
+
/>
|
|
275
|
+
</View>
|
|
276
|
+
);
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
export const ArmenianLocale: Story = {
|
|
281
|
+
render: function ArmenianCalendarStory() {
|
|
282
|
+
const [value, setValue] = useState<Date | undefined>();
|
|
283
|
+
|
|
284
|
+
return (
|
|
285
|
+
<View style={styles.panel}>
|
|
286
|
+
<Calendar
|
|
287
|
+
mode="single"
|
|
288
|
+
locale="hy-AM"
|
|
289
|
+
defaultViewDate={getCurrentMonthStart()}
|
|
290
|
+
value={value}
|
|
291
|
+
onChange={setValue}
|
|
292
|
+
/>
|
|
293
|
+
</View>
|
|
294
|
+
);
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
export const RussianLocale: Story = {
|
|
299
|
+
render: function RussianCalendarStory() {
|
|
300
|
+
const [value, setValue] = useState<Date | undefined>();
|
|
301
|
+
|
|
302
|
+
return (
|
|
303
|
+
<View style={styles.panel}>
|
|
304
|
+
<Calendar
|
|
305
|
+
mode="single"
|
|
306
|
+
locale="ru-RU"
|
|
307
|
+
defaultViewDate={getCurrentMonthStart()}
|
|
308
|
+
value={value}
|
|
309
|
+
onChange={setValue}
|
|
310
|
+
/>
|
|
311
|
+
</View>
|
|
312
|
+
);
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const styles = StyleSheet.create({
|
|
317
|
+
full: {
|
|
318
|
+
width: 296,
|
|
319
|
+
maxWidth: "100%",
|
|
320
|
+
gap: CALENDAR_DROPDOWN_GAP,
|
|
321
|
+
},
|
|
322
|
+
iconSlot: {
|
|
323
|
+
width: CALENDAR_FIELD_ICON_SIZE,
|
|
324
|
+
height: CALENDAR_FIELD_ICON_SIZE,
|
|
325
|
+
alignItems: "center",
|
|
326
|
+
justifyContent: "center",
|
|
327
|
+
flexShrink: 0,
|
|
328
|
+
},
|
|
329
|
+
calendarPanel: {
|
|
330
|
+
width: "100%",
|
|
331
|
+
minWidth: 0,
|
|
332
|
+
},
|
|
333
|
+
panel: {
|
|
334
|
+
width: 296,
|
|
335
|
+
maxWidth: "100%",
|
|
336
|
+
},
|
|
337
|
+
});
|