@g4rcez/components 4.1.1 → 4.1.3
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/components/core/button.d.ts +77 -0
- package/dist/components/core/button.d.ts.map +1 -0
- package/dist/components/core/button.jsx +79 -0
- package/dist/components/core/heading.d.ts +3 -0
- package/dist/components/core/heading.d.ts.map +1 -0
- package/dist/components/core/heading.jsx +4 -0
- package/dist/components/core/polymorph.d.ts +10 -0
- package/dist/components/core/polymorph.d.ts.map +1 -0
- package/dist/components/core/polymorph.jsx +5 -0
- package/dist/components/core/render-on-view.d.ts +7 -0
- package/dist/components/core/render-on-view.d.ts.map +1 -0
- package/dist/components/core/render-on-view.jsx +31 -0
- package/dist/components/core/resizable.d.ts +3 -0
- package/dist/components/core/resizable.d.ts.map +1 -0
- package/dist/components/core/resizable.jsx +51 -0
- package/dist/components/core/slot.d.ts +16 -0
- package/dist/components/core/slot.d.ts.map +1 -0
- package/dist/components/core/slot.jsx +156 -0
- package/dist/components/core/tag.d.ts +35 -0
- package/dist/components/core/tag.d.ts.map +1 -0
- package/dist/components/core/tag.jsx +51 -0
- package/dist/components/core/typography.d.ts +25 -0
- package/dist/components/core/typography.d.ts.map +1 -0
- package/dist/components/core/typography.jsx +18 -0
- package/dist/components/display/alert.d.ts +28 -0
- package/dist/components/display/alert.d.ts.map +1 -0
- package/dist/components/display/alert.jsx +61 -0
- package/dist/components/display/calendar.d.ts +42 -0
- package/dist/components/display/calendar.d.ts.map +1 -0
- package/dist/components/display/calendar.jsx +299 -0
- package/dist/components/display/card.d.ts +29 -0
- package/dist/components/display/card.d.ts.map +1 -0
- package/dist/components/display/card.jsx +43 -0
- package/dist/components/display/empty.d.ts +8 -0
- package/dist/components/display/empty.d.ts.map +1 -0
- package/dist/components/display/empty.jsx +11 -0
- package/dist/components/display/list.d.ts +16 -0
- package/dist/components/display/list.d.ts.map +1 -0
- package/dist/components/display/list.jsx +81 -0
- package/dist/components/display/notifications.d.ts +27 -0
- package/dist/components/display/notifications.d.ts.map +1 -0
- package/dist/components/display/notifications.jsx +126 -0
- package/dist/components/display/progress.d.ts +13 -0
- package/dist/components/display/progress.d.ts.map +1 -0
- package/dist/components/display/progress.jsx +11 -0
- package/dist/components/display/shortcut.d.ts +4 -0
- package/dist/components/display/shortcut.d.ts.map +1 -0
- package/dist/components/display/shortcut.jsx +23 -0
- package/dist/components/display/skeleton.d.ts +12 -0
- package/dist/components/display/skeleton.d.ts.map +1 -0
- package/dist/components/display/skeleton.jsx +19 -0
- package/dist/components/display/spinner.d.ts +5 -0
- package/dist/components/display/spinner.d.ts.map +1 -0
- package/dist/components/display/spinner.jsx +11 -0
- package/dist/components/display/stats.d.ts +12 -0
- package/dist/components/display/stats.d.ts.map +1 -0
- package/dist/components/display/stats.jsx +20 -0
- package/dist/components/display/step.d.ts +24 -0
- package/dist/components/display/step.d.ts.map +1 -0
- package/dist/components/display/step.jsx +131 -0
- package/dist/components/display/tabs.d.ts +24 -0
- package/dist/components/display/tabs.d.ts.map +1 -0
- package/dist/components/display/tabs.jsx +125 -0
- package/dist/components/display/timeline.d.ts +10 -0
- package/dist/components/display/timeline.d.ts.map +1 -0
- package/dist/components/display/timeline.jsx +25 -0
- package/dist/components/floating/command-palette.d.ts +49 -0
- package/dist/components/floating/command-palette.d.ts.map +1 -0
- package/dist/components/floating/command-palette.jsx +197 -0
- package/dist/components/floating/dropdown.d.ts +15 -0
- package/dist/components/floating/dropdown.d.ts.map +1 -0
- package/dist/components/floating/dropdown.jsx +56 -0
- package/dist/components/floating/expand.d.ts +11 -0
- package/dist/components/floating/expand.d.ts.map +1 -0
- package/dist/components/floating/expand.jsx +44 -0
- package/dist/components/floating/menu.d.ts +52 -0
- package/dist/components/floating/menu.d.ts.map +1 -0
- package/dist/components/floating/menu.jsx +147 -0
- package/dist/components/floating/modal.d.ts +60 -0
- package/dist/components/floating/modal.d.ts.map +1 -0
- package/dist/components/floating/modal.jsx +301 -0
- package/dist/components/floating/toolbar.d.ts +6 -0
- package/dist/components/floating/toolbar.d.ts.map +1 -0
- package/dist/components/floating/toolbar.jsx +5 -0
- package/dist/components/floating/tooltip.d.ts +17 -0
- package/dist/components/floating/tooltip.d.ts.map +1 -0
- package/dist/components/floating/tooltip.jsx +58 -0
- package/dist/components/floating/wizard.d.ts +26 -0
- package/dist/components/floating/wizard.d.ts.map +1 -0
- package/dist/components/floating/wizard.jsx +161 -0
- package/dist/components/form/autocomplete.d.ts +16 -0
- package/dist/components/form/autocomplete.d.ts.map +1 -0
- package/dist/components/form/autocomplete.jsx +278 -0
- package/dist/components/form/checkbox.d.ts +12 -0
- package/dist/components/form/checkbox.d.ts.map +1 -0
- package/dist/components/form/checkbox.jsx +12 -0
- package/dist/components/form/date-picker.d.ts +10 -0
- package/dist/components/form/date-picker.d.ts.map +1 -0
- package/dist/components/form/date-picker.jsx +115 -0
- package/dist/components/form/file-upload.d.ts +15 -0
- package/dist/components/form/file-upload.d.ts.map +1 -0
- package/dist/components/form/file-upload.jsx +134 -0
- package/dist/components/form/form.d.ts +3 -0
- package/dist/components/form/form.d.ts.map +1 -0
- package/dist/components/form/form.jsx +10 -0
- package/dist/components/form/formReset.d.ts +2 -0
- package/dist/components/form/formReset.d.ts.map +1 -0
- package/dist/components/form/formReset.jsx +17 -0
- package/dist/components/form/free-text.d.ts +11 -0
- package/dist/components/form/free-text.d.ts.map +1 -0
- package/dist/components/form/free-text.jsx +41 -0
- package/dist/components/form/input-field.d.ts +34 -0
- package/dist/components/form/input-field.d.ts.map +1 -0
- package/dist/components/form/input-field.jsx +58 -0
- package/dist/components/form/input.d.ts +52 -0
- package/dist/components/form/input.d.ts.map +1 -0
- package/dist/components/form/input.jsx +36 -0
- package/dist/components/form/multi-select.d.ts +19 -0
- package/dist/components/form/multi-select.d.ts.map +1 -0
- package/dist/components/form/multi-select.jsx +336 -0
- package/dist/components/form/radiobox.d.ts +7 -0
- package/dist/components/form/radiobox.d.ts.map +1 -0
- package/dist/components/form/radiobox.jsx +6 -0
- package/dist/components/form/select.d.ts +13 -0
- package/dist/components/form/select.d.ts.map +1 -0
- package/dist/components/form/select.jsx +42 -0
- package/dist/components/form/slider.d.ts +7 -0
- package/dist/components/form/slider.d.ts.map +1 -0
- package/dist/components/form/slider.jsx +45 -0
- package/dist/components/form/switch.d.ts +9 -0
- package/dist/components/form/switch.d.ts.map +1 -0
- package/dist/components/form/switch.jsx +46 -0
- package/dist/components/form/task-list.d.ts +3 -0
- package/dist/components/form/task-list.d.ts.map +1 -0
- package/dist/components/form/task-list.jsx +26 -0
- package/dist/components/form/textarea.d.ts +6 -0
- package/dist/components/form/textarea.d.ts.map +1 -0
- package/dist/components/form/textarea.jsx +12 -0
- package/dist/components/index.d.ts +45 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +44 -0
- package/dist/components/page-calendar/calendar-header.d.ts +16 -0
- package/dist/components/page-calendar/calendar-header.d.ts.map +1 -0
- package/dist/components/page-calendar/calendar-header.jsx +83 -0
- package/dist/components/page-calendar/day-view.d.ts +12 -0
- package/dist/components/page-calendar/day-view.d.ts.map +1 -0
- package/dist/components/page-calendar/day-view.jsx +94 -0
- package/dist/components/page-calendar/event-pill.d.ts +9 -0
- package/dist/components/page-calendar/event-pill.d.ts.map +1 -0
- package/dist/components/page-calendar/event-pill.jsx +25 -0
- package/dist/components/page-calendar/index.d.ts +4 -0
- package/dist/components/page-calendar/index.d.ts.map +1 -0
- package/dist/components/page-calendar/index.js +2 -0
- package/dist/components/page-calendar/month-view.d.ts +11 -0
- package/dist/components/page-calendar/month-view.d.ts.map +1 -0
- package/dist/components/page-calendar/month-view.jsx +46 -0
- package/dist/components/page-calendar/page-calendar.d.ts +18 -0
- package/dist/components/page-calendar/page-calendar.d.ts.map +1 -0
- package/dist/components/page-calendar/page-calendar.jsx +41 -0
- package/dist/components/page-calendar/page-calendar.types.d.ts +18 -0
- package/dist/components/page-calendar/page-calendar.types.d.ts.map +1 -0
- package/dist/components/page-calendar/page-calendar.types.js +1 -0
- package/dist/components/page-calendar/page-calendar.utils.d.ts +24 -0
- package/dist/components/page-calendar/page-calendar.utils.d.ts.map +1 -0
- package/dist/components/page-calendar/page-calendar.utils.js +93 -0
- package/dist/components/page-calendar/week-view.d.ts +11 -0
- package/dist/components/page-calendar/week-view.d.ts.map +1 -0
- package/dist/components/page-calendar/week-view.jsx +71 -0
- package/dist/components/table/filter.d.ts +42 -0
- package/dist/components/table/filter.d.ts.map +1 -0
- package/dist/components/table/filter.jsx +141 -0
- package/dist/components/table/group.d.ts +17 -0
- package/dist/components/table/group.d.ts.map +1 -0
- package/dist/components/table/group.jsx +68 -0
- package/dist/components/table/index.d.ts +19 -0
- package/dist/components/table/index.d.ts.map +1 -0
- package/dist/components/table/index.jsx +60 -0
- package/dist/components/table/inner-table.d.ts +29 -0
- package/dist/components/table/inner-table.d.ts.map +1 -0
- package/dist/components/table/inner-table.jsx +102 -0
- package/dist/components/table/metadata.d.ts +4 -0
- package/dist/components/table/metadata.d.ts.map +1 -0
- package/dist/components/table/metadata.jsx +36 -0
- package/dist/components/table/pagination.d.ts +5 -0
- package/dist/components/table/pagination.d.ts.map +1 -0
- package/dist/components/table/pagination.jsx +74 -0
- package/dist/components/table/row.d.ts +11 -0
- package/dist/components/table/row.d.ts.map +1 -0
- package/dist/components/table/row.jsx +49 -0
- package/dist/components/table/sort.d.ts +28 -0
- package/dist/components/table/sort.d.ts.map +1 -0
- package/dist/components/table/sort.jsx +109 -0
- package/dist/components/table/table-lib.d.ts +135 -0
- package/dist/components/table/table-lib.d.ts.map +1 -0
- package/dist/components/table/table-lib.js +83 -0
- package/dist/components/table/table.context.d.ts +10 -0
- package/dist/components/table/table.context.d.ts.map +1 -0
- package/dist/components/table/table.context.jsx +4 -0
- package/dist/components/table/thead.d.ts +9 -0
- package/dist/components/table/thead.d.ts.map +1 -0
- package/dist/components/table/thead.jsx +103 -0
- package/dist/config/context.d.ts +21 -0
- package/dist/config/context.d.ts.map +1 -0
- package/dist/config/context.js +12 -0
- package/dist/config/default-translations.d.ts +94 -0
- package/dist/config/default-translations.d.ts.map +1 -0
- package/dist/config/default-translations.jsx +87 -0
- package/dist/config/default-tweaks.d.ts +13 -0
- package/dist/config/default-tweaks.d.ts.map +1 -0
- package/dist/config/default-tweaks.js +4 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +2 -0
- package/dist/hooks/use-click-outside.d.ts +3 -0
- package/dist/hooks/use-click-outside.d.ts.map +1 -0
- package/dist/hooks/use-click-outside.js +17 -0
- package/dist/hooks/use-color-parser.d.ts +2 -0
- package/dist/hooks/use-color-parser.d.ts.map +1 -0
- package/dist/hooks/use-color-parser.js +9 -0
- package/dist/hooks/use-components-provider.d.ts +15 -0
- package/dist/hooks/use-components-provider.d.ts.map +1 -0
- package/dist/hooks/use-components-provider.jsx +22 -0
- package/dist/hooks/use-debounce.d.ts +5 -0
- package/dist/hooks/use-debounce.d.ts.map +1 -0
- package/dist/hooks/use-debounce.js +12 -0
- package/dist/hooks/use-floating-ref.d.ts +2 -0
- package/dist/hooks/use-floating-ref.d.ts.map +1 -0
- package/dist/hooks/use-floating-ref.js +6 -0
- package/dist/hooks/use-form.d.ts +394 -0
- package/dist/hooks/use-form.d.ts.map +1 -0
- package/dist/hooks/use-form.js +563 -0
- package/dist/hooks/use-hover.d.ts +3 -0
- package/dist/hooks/use-hover.d.ts.map +1 -0
- package/dist/hooks/use-hover.js +18 -0
- package/dist/hooks/use-input-id.d.ts +4 -0
- package/dist/hooks/use-input-id.d.ts.map +1 -0
- package/dist/hooks/use-input-id.js +5 -0
- package/dist/hooks/use-is-coarse-device.d.ts +2 -0
- package/dist/hooks/use-is-coarse-device.d.ts.map +1 -0
- package/dist/hooks/use-is-coarse-device.js +12 -0
- package/dist/hooks/use-locale.d.ts +3 -0
- package/dist/hooks/use-locale.d.ts.map +1 -0
- package/dist/hooks/use-locale.js +10 -0
- package/dist/hooks/use-media-query.d.ts +2 -0
- package/dist/hooks/use-media-query.d.ts.map +1 -0
- package/dist/hooks/use-media-query.js +25 -0
- package/dist/hooks/use-on-event.d.ts +4 -0
- package/dist/hooks/use-on-event.d.ts.map +1 -0
- package/dist/hooks/use-on-event.js +7 -0
- package/dist/hooks/use-parent.d.ts +3 -0
- package/dist/hooks/use-parent.d.ts.map +1 -0
- package/dist/hooks/use-parent.js +21 -0
- package/dist/hooks/use-preferences.d.ts +2 -0
- package/dist/hooks/use-preferences.d.ts.map +1 -0
- package/dist/hooks/use-preferences.js +23 -0
- package/dist/hooks/use-previous.d.ts +2 -0
- package/dist/hooks/use-previous.d.ts.map +1 -0
- package/dist/hooks/use-previous.js +9 -0
- package/dist/hooks/use-reactive.d.ts +2 -0
- package/dist/hooks/use-reactive.d.ts.map +1 -0
- package/dist/hooks/use-reactive.js +9 -0
- package/dist/hooks/use-remove-scroll.d.ts +4 -0
- package/dist/hooks/use-remove-scroll.d.ts.map +1 -0
- package/dist/hooks/use-remove-scroll.js +48 -0
- package/dist/hooks/use-resize-observer.d.ts +2 -0
- package/dist/hooks/use-resize-observer.d.ts.map +1 -0
- package/dist/hooks/use-resize-observer.js +17 -0
- package/dist/hooks/use-stable-ref.d.ts +2 -0
- package/dist/hooks/use-stable-ref.d.ts.map +1 -0
- package/dist/hooks/use-stable-ref.js +9 -0
- package/dist/hooks/use-swipe.d.ts +8 -0
- package/dist/hooks/use-swipe.d.ts.map +1 -0
- package/dist/hooks/use-swipe.js +17 -0
- package/dist/hooks/use-translations.d.ts +92 -0
- package/dist/hooks/use-translations.d.ts.map +1 -0
- package/dist/hooks/use-translations.js +9 -0
- package/dist/hooks/use-tweaks.d.ts +3 -0
- package/dist/hooks/use-tweaks.d.ts.map +1 -0
- package/dist/hooks/use-tweaks.js +9 -0
- package/dist/hooks/use-window-size.d.ts +5 -0
- package/dist/hooks/use-window-size.d.ts.map +1 -0
- package/dist/hooks/use-window-size.js +14 -0
- package/dist/index-DDeQW0JW.js.map +1 -1
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -8231
- package/dist/index.js.map +1 -1
- package/dist/lib/combi-keys.d.ts +15 -0
- package/dist/lib/combi-keys.d.ts.map +1 -0
- package/dist/lib/combi-keys.js +60 -0
- package/dist/lib/dict.d.ts +9 -0
- package/dist/lib/dict.d.ts.map +1 -0
- package/dist/lib/dict.js +28 -0
- package/dist/lib/dom.d.ts +20 -0
- package/dist/lib/dom.d.ts.map +1 -0
- package/dist/lib/dom.js +66 -0
- package/dist/lib/fns.d.ts +11 -0
- package/dist/lib/fns.d.ts.map +1 -0
- package/dist/lib/fns.js +46 -0
- package/dist/lib/fzf.d.ts +16 -0
- package/dist/lib/fzf.d.ts.map +1 -0
- package/dist/lib/fzf.js +115 -0
- package/dist/lib/keyboard-area.d.ts +16 -0
- package/dist/lib/keyboard-area.d.ts.map +1 -0
- package/dist/lib/keyboard-area.js +14 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/types.d.ts +26 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CalendarEvent } from "./page-calendar.types";
|
|
2
|
+
type MonthViewProps = {
|
|
3
|
+
days: Date[];
|
|
4
|
+
currentDate: Date;
|
|
5
|
+
onDayClick: (date: Date) => void;
|
|
6
|
+
eventsByDate: Map<string, CalendarEvent[]>;
|
|
7
|
+
onEventClick: (event: CalendarEvent) => void;
|
|
8
|
+
};
|
|
9
|
+
export declare function MonthView({ days, eventsByDate, currentDate, onEventClick, onDayClick }: MonthViewProps): import("react").JSX.Element;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=month-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"month-view.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/month-view.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAK3D,KAAK,cAAc,GAAG;IAClB,IAAI,EAAE,IAAI,EAAE,CAAC;IACb,WAAW,EAAE,IAAI,CAAC;IAClB,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACjC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAC3C,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,EAAE,cAAc,+BA0DtG"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { isSameMonth, isToday } from "date-fns";
|
|
2
|
+
import { useLocale } from "../../hooks/use-locale";
|
|
3
|
+
import { useTranslations } from "../../hooks/use-translations";
|
|
4
|
+
import { EventPill } from "./event-pill";
|
|
5
|
+
import { toDateKey, formatDay, getWeekDays, formatWeekDay, formatFullDate } from "./page-calendar.utils";
|
|
6
|
+
import { useMemo } from "react";
|
|
7
|
+
export function MonthView({ days, eventsByDate, currentDate, onEventClick, onDayClick }) {
|
|
8
|
+
const locale = useLocale();
|
|
9
|
+
const t = useTranslations();
|
|
10
|
+
const WEEKDAY_LABELS = useMemo(() => getWeekDays(new Date()), []);
|
|
11
|
+
return (<div className="flex h-full flex-1 flex-col">
|
|
12
|
+
<ul role="row" aria-hidden="true" className="grid grid-cols-7 border-b border-border">
|
|
13
|
+
{WEEKDAY_LABELS.map((date) => {
|
|
14
|
+
const day = formatWeekDay(date, locale);
|
|
15
|
+
return (<li key={day} className="py-2 text-center text-xs font-medium text-muted-foreground">
|
|
16
|
+
{day}
|
|
17
|
+
</li>);
|
|
18
|
+
})}
|
|
19
|
+
</ul>
|
|
20
|
+
<div role="grid" aria-label={t.pageCalendarMonthGrid} className="grid flex-1 auto-rows-fr grid-cols-7">
|
|
21
|
+
{days.map((day, idx) => {
|
|
22
|
+
const key = toDateKey(day);
|
|
23
|
+
const events = eventsByDate.get(key) || [];
|
|
24
|
+
const isCurrentMonth = isSameMonth(day, currentDate);
|
|
25
|
+
const isCurrentDay = isToday(day);
|
|
26
|
+
return (<button key={idx} type="button" onClick={() => onDayClick(day)} aria-label={`${formatFullDate(day, locale)}${events.length > 0 ? `, ${t.pageCalendarEventCount(events.length)}` : ""}`} className={`group flex min-h-32 cursor-pointer flex-col gap-1 border-b border-r border-border p-2 transition-colors hover:bg-muted hover:bg-opacity-20 ${!isCurrentMonth ? "opacity-50" : ""}`}>
|
|
27
|
+
<div className="flex items-center justify-between">
|
|
28
|
+
<span className={`flex h-6 w-6 items-center justify-center rounded-full text-xs font-medium ${isCurrentDay ? "bg-primary text-primary-foreground" : "text-foreground"}`}>
|
|
29
|
+
{formatDay(day, locale)}
|
|
30
|
+
</span>
|
|
31
|
+
<span aria-hidden="true" className="text-lg leading-none text-muted-foreground opacity-0 transition-opacity group-hover:opacity-40">
|
|
32
|
+
+
|
|
33
|
+
</span>
|
|
34
|
+
</div>
|
|
35
|
+
<div className="min-h-0 flex-1 overflow-y-auto">
|
|
36
|
+
<div className="flex flex-col gap-0.5">
|
|
37
|
+
{events.map((event) => (<div key={event.id} onClick={(e) => e.stopPropagation()}>
|
|
38
|
+
<EventPill compact event={event} onClick={() => onEventClick(event)}/>
|
|
39
|
+
</div>))}
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</button>);
|
|
43
|
+
})}
|
|
44
|
+
</div>
|
|
45
|
+
</div>);
|
|
46
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { CalendarEvent, CalendarEventBase, CalendarFilter, ViewMode } from "./page-calendar.types";
|
|
3
|
+
type PageCalendarProps<T extends CalendarEventBase> = {
|
|
4
|
+
defaultDate?: Date;
|
|
5
|
+
defaultView?: ViewMode;
|
|
6
|
+
filterArea?: ReactNode;
|
|
7
|
+
onAddEvent?: () => void;
|
|
8
|
+
getFilterId?: () => void;
|
|
9
|
+
events: CalendarEvent<T>[];
|
|
10
|
+
filters?: CalendarFilter[];
|
|
11
|
+
onSlotClick?: (date: Date) => void;
|
|
12
|
+
onEventClick?: (event: CalendarEvent) => void;
|
|
13
|
+
renderEvent?: (event: CalendarEvent<T>) => ReactNode;
|
|
14
|
+
onChangeFilters?: (filters: CalendarFilter[]) => void;
|
|
15
|
+
};
|
|
16
|
+
export declare function PageCalendar<T extends CalendarEventBase>({ events, filterArea, onAddEvent, defaultDate, onSlotClick, getFilterId, renderEvent, onEventClick, filters, defaultView, onChangeFilters: onActiveFiltersChange, }: PageCalendarProps<T>): import("react").JSX.Element;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=page-calendar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-calendar.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/page-calendar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAOxG,KAAK,iBAAiB,CAAC,CAAC,SAAS,iBAAiB,IAAI;IAClD,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;IACrD,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,IAAI,CAAC;CACzD,CAAC;AAIF,wBAAgB,YAAY,CAAC,CAAC,SAAS,iBAAiB,EAAE,EACtD,MAAM,EACN,UAAU,EACV,UAAU,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,EACX,YAAY,EACZ,OAAc,EACd,WAAqB,EACrB,eAAe,EAAE,qBAAqB,GACzC,EAAE,iBAAiB,CAAC,CAAC,CAAC,+BAyEtB"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useMemo, useState } from "react";
|
|
2
|
+
import { useTranslations } from "../../hooks/use-translations";
|
|
3
|
+
import { groupEventsByDate, getMonthDays, getWeekDays } from "./page-calendar.utils";
|
|
4
|
+
import { CalendarHeader } from "./calendar-header";
|
|
5
|
+
import { MonthView } from "./month-view";
|
|
6
|
+
import { WeekView } from "./week-view";
|
|
7
|
+
import { DayView } from "./day-view";
|
|
8
|
+
const noop = [];
|
|
9
|
+
export function PageCalendar({ events, filterArea, onAddEvent, defaultDate, onSlotClick, getFilterId, renderEvent, onEventClick, filters = noop, defaultView = "month", onChangeFilters: onActiveFiltersChange, }) {
|
|
10
|
+
const t = useTranslations();
|
|
11
|
+
const [currentView, setCurrentView] = useState(defaultView);
|
|
12
|
+
const [currentDate, setCurrentDate] = useState(() => defaultDate ?? new Date());
|
|
13
|
+
const [internalFilters, setInternalFilters] = useState(filters);
|
|
14
|
+
const toggleFilter = (id) => {
|
|
15
|
+
setInternalFilters((prev) => {
|
|
16
|
+
const next = prev.map((f) => (f.id === id ? { ...f, enabled: !f.enabled } : f));
|
|
17
|
+
onActiveFiltersChange?.(next);
|
|
18
|
+
return next;
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
const filteredEvents = useMemo(() => {
|
|
22
|
+
if (filters.length === 0)
|
|
23
|
+
return events;
|
|
24
|
+
const get = getFilterId ?? ((e) => e?.filterId);
|
|
25
|
+
return events.filter((e) => internalFilters.find((f) => f.id === get(e))?.enabled ?? true);
|
|
26
|
+
}, [events, internalFilters, filters]);
|
|
27
|
+
const eventsByDate = useMemo(() => groupEventsByDate(filteredEvents), [filteredEvents]);
|
|
28
|
+
const monthDays = useMemo(() => getMonthDays(currentDate), [currentDate]);
|
|
29
|
+
const weekDays = useMemo(() => getWeekDays(currentDate), [currentDate]);
|
|
30
|
+
const handleEventClick = (event) => onEventClick?.(event);
|
|
31
|
+
const handleDayClick = (date) => {
|
|
32
|
+
setCurrentDate(date);
|
|
33
|
+
setCurrentView("day");
|
|
34
|
+
};
|
|
35
|
+
return (<div role="application" aria-label={t.pageCalendarLabel} className="flex h-full w-full flex-grow flex-col gap-4">
|
|
36
|
+
<CalendarHeader filters={internalFilters} filterArea={filterArea} onAddEvent={onAddEvent} currentDate={currentDate} currentView={currentView} setCurrentDate={setCurrentDate} setCurrentView={setCurrentView} onToggleFilter={toggleFilter}/>
|
|
37
|
+
{currentView === "month" && (<MonthView days={monthDays} currentDate={currentDate} eventsByDate={eventsByDate} onDayClick={handleDayClick} onEventClick={handleEventClick}/>)}
|
|
38
|
+
{currentView === "week" && (<WeekView days={weekDays} currentDate={currentDate} onSlotClick={onSlotClick} eventsByDate={eventsByDate} onEventClick={handleEventClick}/>)}
|
|
39
|
+
{currentView === "day" && (<DayView currentDate={currentDate} onSlotClick={onSlotClick} renderEvent={renderEvent} eventsByDate={eventsByDate} onDateChange={setCurrentDate} onEventClick={handleEventClick}/>)}
|
|
40
|
+
</div>);
|
|
41
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TagProps } from "../core/tag";
|
|
2
|
+
export type ViewMode = "month" | "week" | "day";
|
|
3
|
+
export type CalendarEventBase = {
|
|
4
|
+
date: Date;
|
|
5
|
+
id: string;
|
|
6
|
+
};
|
|
7
|
+
export type CalendarEvent<T extends CalendarEventBase = CalendarEventBase> = T & {
|
|
8
|
+
title: string;
|
|
9
|
+
filterId?: string;
|
|
10
|
+
className?: string;
|
|
11
|
+
};
|
|
12
|
+
export type CalendarFilter = {
|
|
13
|
+
id: string;
|
|
14
|
+
label: string;
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
theme: TagProps["theme"];
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=page-calendar.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-calendar.types.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/page-calendar.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAEhD,MAAM,MAAM,iBAAiB,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,iBAAiB,GAAG,iBAAiB,IAAI,CAAC,GAAG;IAC7E,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;CAC5B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CalendarEvent, CalendarEventBase } from "./page-calendar.types";
|
|
2
|
+
export declare function toDateKey(d: Date): string;
|
|
3
|
+
export declare function groupEventsByDate<T extends CalendarEventBase>(events: CalendarEvent<T>[]): Map<string, CalendarEvent<T>[]>;
|
|
4
|
+
export declare function getMonthDays(date: Date): Date[];
|
|
5
|
+
export declare function getWeekDays(date: Date): Date[];
|
|
6
|
+
export declare function getHourSlots(): number[];
|
|
7
|
+
export declare function formatEventTime(date: Date, locale?: string): string;
|
|
8
|
+
export declare function formatDay(date: Date, locale?: string): string;
|
|
9
|
+
export declare function formatWeekDay(date: Date, locale?: string): string;
|
|
10
|
+
export declare function formatWeekdayLong(date: Date, locale?: string): string;
|
|
11
|
+
export declare function formatWeekdayShort(date: Date, locale?: string): string;
|
|
12
|
+
export declare function formatMonthYear(date: Date, locale?: string): string;
|
|
13
|
+
export declare function formatMonthShort(date: Date, locale?: string): string;
|
|
14
|
+
export declare function formatHourLabel(hour: number, locale?: string): string;
|
|
15
|
+
export declare function formatFullDate(date: Date, locale?: string): string;
|
|
16
|
+
export declare function formatTime(date: Date, locale?: string): string;
|
|
17
|
+
export declare function getWeekNumber(date: Date): number;
|
|
18
|
+
export type EventColumn<T extends CalendarEventBase> = {
|
|
19
|
+
event: CalendarEvent<T>;
|
|
20
|
+
columnIndex: number;
|
|
21
|
+
columnCount: number;
|
|
22
|
+
};
|
|
23
|
+
export declare function computeEventColumns<T extends CalendarEventBase>(events: CalendarEvent<T>[]): EventColumn<T>[];
|
|
24
|
+
//# sourceMappingURL=page-calendar.utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-calendar.utils.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/page-calendar.utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE9E,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAEzC;AAED,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,iBAAiB,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAY1H;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,CAQ/C;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,CAO9C;AAED,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAEvC;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAEhD;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,iBAAiB,IAAI;IACnD,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,iBAAiB,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,CAoB7G"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { addDays, startOfMonth, startOfWeek, getISOWeek } from "date-fns";
|
|
2
|
+
export function toDateKey(d) {
|
|
3
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
4
|
+
}
|
|
5
|
+
export function groupEventsByDate(events) {
|
|
6
|
+
const map = new Map();
|
|
7
|
+
for (const event of events) {
|
|
8
|
+
const key = toDateKey(event.date);
|
|
9
|
+
const existing = map.get(key);
|
|
10
|
+
if (existing) {
|
|
11
|
+
existing.push(event);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
map.set(key, [event]);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return map;
|
|
18
|
+
}
|
|
19
|
+
export function getMonthDays(date) {
|
|
20
|
+
const monthStart = startOfMonth(date);
|
|
21
|
+
const gridStart = startOfWeek(monthStart, { weekStartsOn: 1 });
|
|
22
|
+
const days = [];
|
|
23
|
+
for (let i = 0; i < 42; i++) {
|
|
24
|
+
days.push(addDays(gridStart, i));
|
|
25
|
+
}
|
|
26
|
+
return days;
|
|
27
|
+
}
|
|
28
|
+
export function getWeekDays(date) {
|
|
29
|
+
const weekStart = startOfWeek(date, { weekStartsOn: 1 });
|
|
30
|
+
const days = [];
|
|
31
|
+
for (let i = 0; i < 7; i++) {
|
|
32
|
+
days.push(addDays(weekStart, i));
|
|
33
|
+
}
|
|
34
|
+
return days;
|
|
35
|
+
}
|
|
36
|
+
export function getHourSlots() {
|
|
37
|
+
return Array.from({ length: 24 }, (_, i) => i);
|
|
38
|
+
}
|
|
39
|
+
export function formatEventTime(date, locale) {
|
|
40
|
+
return new Intl.DateTimeFormat(locale, { hour: "2-digit", minute: "2-digit", hour12: false }).format(new Date(date));
|
|
41
|
+
}
|
|
42
|
+
export function formatDay(date, locale) {
|
|
43
|
+
return new Intl.DateTimeFormat(locale, { day: "numeric" }).format(date);
|
|
44
|
+
}
|
|
45
|
+
export function formatWeekDay(date, locale) {
|
|
46
|
+
return new Intl.DateTimeFormat(locale, { weekday: "short" }).format(date);
|
|
47
|
+
}
|
|
48
|
+
export function formatWeekdayLong(date, locale) {
|
|
49
|
+
return new Intl.DateTimeFormat(locale, { weekday: "long" }).format(date);
|
|
50
|
+
}
|
|
51
|
+
export function formatWeekdayShort(date, locale) {
|
|
52
|
+
return new Intl.DateTimeFormat(locale, { weekday: "short" }).format(date);
|
|
53
|
+
}
|
|
54
|
+
export function formatMonthYear(date, locale) {
|
|
55
|
+
return new Intl.DateTimeFormat(locale, { month: "long", year: "numeric" }).format(date);
|
|
56
|
+
}
|
|
57
|
+
export function formatMonthShort(date, locale) {
|
|
58
|
+
return new Intl.DateTimeFormat(locale, { month: "short" }).format(date);
|
|
59
|
+
}
|
|
60
|
+
export function formatHourLabel(hour, locale) {
|
|
61
|
+
return new Intl.DateTimeFormat(locale, { hour: "2-digit", minute: "2-digit", hour12: false }).format(new Date(0, 0, 0, hour));
|
|
62
|
+
}
|
|
63
|
+
export function formatFullDate(date, locale) {
|
|
64
|
+
return new Intl.DateTimeFormat(locale, { weekday: "long", month: "short", day: "numeric", year: "numeric" }).format(date);
|
|
65
|
+
}
|
|
66
|
+
export function formatTime(date, locale) {
|
|
67
|
+
return new Intl.DateTimeFormat(locale, { hour: "2-digit", minute: "2-digit", hour12: false }).format(date);
|
|
68
|
+
}
|
|
69
|
+
export function getWeekNumber(date) {
|
|
70
|
+
return getISOWeek(date);
|
|
71
|
+
}
|
|
72
|
+
export function computeEventColumns(events) {
|
|
73
|
+
const sorted = [...events].sort((a, b) => a.date.getTime() - b.date.getTime());
|
|
74
|
+
const hourGroups = new Map();
|
|
75
|
+
for (const event of sorted) {
|
|
76
|
+
const hour = event.date.getHours();
|
|
77
|
+
const group = hourGroups.get(hour);
|
|
78
|
+
if (group) {
|
|
79
|
+
group.push(event);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
hourGroups.set(hour, [event]);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const result = [];
|
|
86
|
+
for (const group of hourGroups.values()) {
|
|
87
|
+
const columnCount = group.length;
|
|
88
|
+
group.forEach((event, columnIndex) => {
|
|
89
|
+
result.push({ event, columnIndex, columnCount });
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CalendarEvent } from "./page-calendar.types";
|
|
2
|
+
type WeekViewProps = {
|
|
3
|
+
days: Date[];
|
|
4
|
+
eventsByDate: Map<string, CalendarEvent[]>;
|
|
5
|
+
currentDate: Date;
|
|
6
|
+
onEventClick: (event: CalendarEvent) => void;
|
|
7
|
+
onSlotClick?: (date: Date) => void;
|
|
8
|
+
};
|
|
9
|
+
export declare function WeekView({ days, eventsByDate, onEventClick, onSlotClick }: WeekViewProps): import("react").JSX.Element;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=week-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"week-view.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/week-view.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAM3D,KAAK,aAAa,GAAG;IACjB,IAAI,EAAE,IAAI,EAAE,CAAC;IACb,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAC3C,WAAW,EAAE,IAAI,CAAC;IAClB,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CACtC,CAAC;AAQF,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,aAAa,+BA6FxF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { isToday } from "date-fns";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
import { useLocale } from "../../hooks/use-locale";
|
|
4
|
+
import { EventPill } from "./event-pill";
|
|
5
|
+
import { getHourSlots, toDateKey, formatWeekdayShort, formatDay, formatHourLabel, formatFullDate, computeEventColumns } from "./page-calendar.utils";
|
|
6
|
+
const HOUR_HEIGHT = 48;
|
|
7
|
+
function getTopOffset(event) {
|
|
8
|
+
const hour = event.date.getHours();
|
|
9
|
+
const minutes = event.date.getMinutes();
|
|
10
|
+
return hour * HOUR_HEIGHT + (minutes / 60) * HOUR_HEIGHT;
|
|
11
|
+
}
|
|
12
|
+
export function WeekView({ days, eventsByDate, onEventClick, onSlotClick }) {
|
|
13
|
+
const locale = useLocale();
|
|
14
|
+
const currentHourRef = useRef(null);
|
|
15
|
+
const scrollBodyRef = useRef(null);
|
|
16
|
+
const hours = getHourSlots();
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (scrollBodyRef.current && currentHourRef.current) {
|
|
19
|
+
const top = currentHourRef.current.offsetTop;
|
|
20
|
+
scrollBodyRef.current.scrollTop = top - scrollBodyRef.current.clientHeight / 2;
|
|
21
|
+
}
|
|
22
|
+
}, []);
|
|
23
|
+
return (<div className="flex flex-1 flex-col overflow-hidden">
|
|
24
|
+
<div className="flex flex-shrink-0 border-b border-border">
|
|
25
|
+
<div className="w-[60px] flex-shrink-0"/>
|
|
26
|
+
{days.map((day, idx) => {
|
|
27
|
+
const isCurrentDay = isToday(day);
|
|
28
|
+
return (<div key={idx} aria-label={formatFullDate(day, locale)} className="flex-1 py-2 text-center text-xs font-medium text-muted-foreground">
|
|
29
|
+
<span className="block">{formatWeekdayShort(day, locale)}</span>
|
|
30
|
+
<span className={`inline-flex h-6 w-6 items-center justify-center rounded-full text-sm font-bold ${isCurrentDay ? "bg-primary text-primary-foreground" : "text-foreground"}`}>
|
|
31
|
+
{formatDay(day, locale)}
|
|
32
|
+
</span>
|
|
33
|
+
</div>);
|
|
34
|
+
})}
|
|
35
|
+
</div>
|
|
36
|
+
<div ref={scrollBodyRef} className="flex flex-1 items-start overflow-y-auto">
|
|
37
|
+
<div className="w-[60px] flex-shrink-0">
|
|
38
|
+
{hours.map((hour) => (<div key={hour} className="relative" style={{ height: HOUR_HEIGHT }}>
|
|
39
|
+
<span className="absolute -top-2.5 right-2 text-[10px] text-muted-foreground">
|
|
40
|
+
{hour === 0 ? "" : formatHourLabel(hour, locale)}
|
|
41
|
+
</span>
|
|
42
|
+
{hour === new Date().getHours() && <div ref={currentHourRef}/>}
|
|
43
|
+
</div>))}
|
|
44
|
+
</div>
|
|
45
|
+
{days.map((day, dayIdx) => {
|
|
46
|
+
const key = toDateKey(day);
|
|
47
|
+
const events = eventsByDate.get(key) || [];
|
|
48
|
+
return (<div key={dayIdx} className="relative flex-1 border-l border-card-border">
|
|
49
|
+
{hours.map((hour) => {
|
|
50
|
+
const slotDate = new Date(day);
|
|
51
|
+
slotDate.setHours(hour, 0, 0, 0);
|
|
52
|
+
return (<div key={hour} role="button" tabIndex={0} aria-label={formatHourLabel(hour, locale)} className="cursor-pointer border-b border-border/50 hover:bg-muted/20" style={{ height: HOUR_HEIGHT }} onClick={() => onSlotClick?.(slotDate)} onKeyDown={(e) => {
|
|
53
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
onSlotClick?.(slotDate);
|
|
56
|
+
}
|
|
57
|
+
}}/>);
|
|
58
|
+
})}
|
|
59
|
+
{computeEventColumns(events).map(({ event, columnIndex, columnCount }) => (<div key={event.id} className="absolute" style={{
|
|
60
|
+
top: getTopOffset(event),
|
|
61
|
+
height: HOUR_HEIGHT,
|
|
62
|
+
left: `calc(${(columnIndex / columnCount) * 100}% + 1px)`,
|
|
63
|
+
width: `calc(${100 / columnCount}% - 2px)`,
|
|
64
|
+
}} onClick={(e) => e.stopPropagation()}>
|
|
65
|
+
<EventPill event={event} onClick={() => onEventClick(event)}/>
|
|
66
|
+
</div>))}
|
|
67
|
+
</div>);
|
|
68
|
+
})}
|
|
69
|
+
</div>
|
|
70
|
+
</div>);
|
|
71
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { AllPaths } from "sidekicker";
|
|
3
|
+
import { Any, Label } from "../../types";
|
|
4
|
+
import { OptionProps } from "../form/select";
|
|
5
|
+
import { Col, ColType, TableConfiguration } from "./table-lib";
|
|
6
|
+
type Operators = {
|
|
7
|
+
value: string;
|
|
8
|
+
label: string;
|
|
9
|
+
symbol: string;
|
|
10
|
+
"data-default"?: string;
|
|
11
|
+
};
|
|
12
|
+
type OperatorTypes = "contains" | "is" | "isNot" | "notContains" | "lessThan" | "greaterThan" | "startsWith" | "endsWith";
|
|
13
|
+
type Operations = Record<OperatorTypes, Operators>;
|
|
14
|
+
type OperationOptions = Partial<Record<ColType, OptionProps[]>>;
|
|
15
|
+
type FilterValue = string | number | string[] | boolean;
|
|
16
|
+
export type FilterConfig<T extends object = object> = {
|
|
17
|
+
id: string;
|
|
18
|
+
label: Label;
|
|
19
|
+
name: AllPaths<T>;
|
|
20
|
+
type: ColType;
|
|
21
|
+
operation: Operators;
|
|
22
|
+
value: FilterValue;
|
|
23
|
+
};
|
|
24
|
+
type Props<T extends object> = TableConfiguration<T, {
|
|
25
|
+
cols: Col<T>[];
|
|
26
|
+
filters: FilterConfig<T>[];
|
|
27
|
+
set: React.Dispatch<React.SetStateAction<FilterConfig<T>[]>>;
|
|
28
|
+
}>;
|
|
29
|
+
export declare const createFilterFromCol: <T extends Any>(f: Col<T>, options: OperationOptions, operations: Operations, rest?: Partial<FilterConfig<T>>) => FilterConfig<T>;
|
|
30
|
+
export declare const useOperators: () => {
|
|
31
|
+
options: Partial<Record<ColType, OptionProps[]>>;
|
|
32
|
+
operations: Operations;
|
|
33
|
+
};
|
|
34
|
+
export declare const Filter: <T extends object>(props: Props<T>) => React.JSX.Element;
|
|
35
|
+
type ColumnHeaderFilterProps<T extends object> = {
|
|
36
|
+
filter: FilterConfig<T>;
|
|
37
|
+
onDelete: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
|
38
|
+
set: React.Dispatch<React.SetStateAction<FilterConfig<T>[]>>;
|
|
39
|
+
};
|
|
40
|
+
export declare const ColumnHeaderFilter: <T extends object>({ filter, onDelete, set }: ColumnHeaderFilterProps<T>) => React.JSX.Element;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../../src/components/table/filter.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA4B,MAAM,OAAO,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGzC,OAAO,EAAE,WAAW,EAAU,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,GAAG,EAAE,OAAO,EAAY,kBAAkB,EAAiB,MAAM,aAAa,CAAC;AAExF,KAAK,SAAS,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3F,KAAK,aAAa,GAAG,UAAU,GAAG,IAAI,GAAG,OAAO,GAAG,aAAa,GAAG,UAAU,GAAG,aAAa,GAAG,YAAY,GAAG,UAAU,CAAC;AAE1H,KAAK,UAAU,GAAG,MAAM,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;AAEnD,KAAK,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;AAEhE,KAAK,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;AAExD,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI;IAClD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,KAAK,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,KAAK,KAAK,CAAC,CAAC,SAAS,MAAM,IAAI,kBAAkB,CAC7C,CAAC,EACD;IACI,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACf,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3B,GAAG,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAChE,CACJ,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,CAAC,SAAS,GAAG,EAC7C,GAAG,GAAG,CAAC,CAAC,CAAC,EACT,SAAS,gBAAgB,EACzB,YAAY,UAAU,EACtB,OAAM,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAM,KACpC,YAAY,CAAC,CAAC,CAOhB,CAAC;AAEF,eAAO,MAAM,YAAY;;;CA0CxB,CAAC;AAEF,eAAO,MAAM,MAAM,GAAI,CAAC,SAAS,MAAM,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC,sBA0GvD,CAAC;AAEF,KAAK,uBAAuB,CAAC,CAAC,SAAS,MAAM,IAAI;IAC7C,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IACxB,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IAC3D,GAAG,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAChE,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,CAAC,SAAS,MAAM,EAAE,2BAA2B,uBAAuB,CAAC,CAAC,CAAC,sBAiDzG,CAAC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { FunnelIcon, PlusIcon, TrashIcon } from "@phosphor-icons/react";
|
|
2
|
+
import React, { Fragment, useMemo } from "react";
|
|
3
|
+
import { useTranslations } from "../../hooks/use-translations";
|
|
4
|
+
import { uuid } from "../../lib/fns";
|
|
5
|
+
import { Dropdown } from "../floating/dropdown";
|
|
6
|
+
import { Input } from "../form/input";
|
|
7
|
+
import { Select } from "../form/select";
|
|
8
|
+
import { ColType, getLabel, valueFromType } from "./table-lib";
|
|
9
|
+
export const createFilterFromCol = (f, options, operations, rest = {}) => {
|
|
10
|
+
const name = f.id;
|
|
11
|
+
const type = f.type ?? ColType.Text;
|
|
12
|
+
const typeOptions = options[type] ?? [];
|
|
13
|
+
const operatorId = (typeOptions.find((x) => x["data-default"])?.value ?? typeOptions[0]?.value);
|
|
14
|
+
const operation = operations[operatorId];
|
|
15
|
+
return { id: uuid(), operation, label: getLabel(f), name, type, value: "", ...rest };
|
|
16
|
+
};
|
|
17
|
+
export const useOperators = () => {
|
|
18
|
+
const translation = useTranslations();
|
|
19
|
+
const operations = useMemo(() => ({
|
|
20
|
+
contains: {
|
|
21
|
+
value: "contains",
|
|
22
|
+
label: translation.tableFilterTypeContains,
|
|
23
|
+
symbol: "includes",
|
|
24
|
+
"data-default": "true",
|
|
25
|
+
},
|
|
26
|
+
is: { value: "is", label: translation.tableFilterTypeIs, symbol: "is" },
|
|
27
|
+
isNot: { value: "isNot", label: translation.tableFilterTypeIsNot, symbol: "!==" },
|
|
28
|
+
notContains: {
|
|
29
|
+
value: "notContains",
|
|
30
|
+
label: translation.tableFilterTypeNotContains,
|
|
31
|
+
symbol: "notIncludes",
|
|
32
|
+
},
|
|
33
|
+
lessThan: { value: "lessThan", label: translation.tableFilterTypeLessThan, symbol: "<=" },
|
|
34
|
+
greaterThan: { value: "greaterThan", label: translation.tableFilterTypeGreaterThan, symbol: ">=" },
|
|
35
|
+
startsWith: { value: "startsWith", label: translation.tableFilterTypeStartsWith, symbol: "startsWith" },
|
|
36
|
+
endsWith: { value: "endsWith", label: translation.tableFilterTypeEndsWith, symbol: "endsWith" },
|
|
37
|
+
}), [translation]);
|
|
38
|
+
const options = useMemo(() => ({
|
|
39
|
+
[ColType.Text]: [
|
|
40
|
+
operations.is,
|
|
41
|
+
operations.isNot,
|
|
42
|
+
operations.contains,
|
|
43
|
+
operations.notContains,
|
|
44
|
+
operations.startsWith,
|
|
45
|
+
operations.endsWith,
|
|
46
|
+
],
|
|
47
|
+
[ColType.Boolean]: [operations.is, operations.isNot],
|
|
48
|
+
[ColType.Number]: [operations.is, operations.isNot, operations.greaterThan, operations.lessThan],
|
|
49
|
+
}), [operations]);
|
|
50
|
+
return { options, operations };
|
|
51
|
+
};
|
|
52
|
+
export const Filter = (props) => {
|
|
53
|
+
const translation = useTranslations();
|
|
54
|
+
const operators = useOperators();
|
|
55
|
+
const onAddFilter = () => {
|
|
56
|
+
const col = props.cols.at(0);
|
|
57
|
+
props.set((prev) => [...prev, createFilterFromCol(col, operators.options, operators.operations)]);
|
|
58
|
+
};
|
|
59
|
+
const onSelectProperty = (e) => {
|
|
60
|
+
const changedId = e.target.dataset.id || "";
|
|
61
|
+
const newId = e.target.value;
|
|
62
|
+
props.set((prev) => prev.map((x) => {
|
|
63
|
+
if (changedId !== x.id)
|
|
64
|
+
return x;
|
|
65
|
+
const col = props.cols.find((x) => newId === x.id);
|
|
66
|
+
return createFilterFromCol(col, operators.options, operators.operations, { value: "" });
|
|
67
|
+
}));
|
|
68
|
+
};
|
|
69
|
+
const onSelectOperation = (e) => {
|
|
70
|
+
const id = e.target.dataset.id || "";
|
|
71
|
+
const operator = e.target.value;
|
|
72
|
+
props.set((prev) => prev.map((x) => x.id === id
|
|
73
|
+
? {
|
|
74
|
+
...x,
|
|
75
|
+
operation: operators.operations[operator],
|
|
76
|
+
}
|
|
77
|
+
: x));
|
|
78
|
+
};
|
|
79
|
+
const onDelete = (e) => {
|
|
80
|
+
const id = e.currentTarget.dataset.id || "";
|
|
81
|
+
props.set((prev) => prev.filter((x) => x.id !== id));
|
|
82
|
+
};
|
|
83
|
+
const onChangeValue = (e) => {
|
|
84
|
+
const id = e.target.dataset.id || "";
|
|
85
|
+
const value = valueFromType(e.target);
|
|
86
|
+
props.set((prev) => prev.map((x) => (x.id === id ? { ...x, value } : x)));
|
|
87
|
+
};
|
|
88
|
+
return (<Fragment>
|
|
89
|
+
<Dropdown arrow title={translation.tableFilterDropdownTitle} trigger={<span className="flex items-center gap-1 proportional-nums">
|
|
90
|
+
<FunnelIcon size={14}/>
|
|
91
|
+
{translation.tableFilterLabel} {props.filters.length === 0 ? "" : ` (${props.filters.length})`}
|
|
92
|
+
</span>}>
|
|
93
|
+
<ul className="mt-4 space-y-2">
|
|
94
|
+
{props.filters.map((filter) => {
|
|
95
|
+
const options = operators.options[filter.type];
|
|
96
|
+
return (<li key={`filter-select-${filter.id}`} className="flex flex-nowrap gap-3">
|
|
97
|
+
<Select options={props.options} title={translation.tableFilterColumnTitle} placeholder={translation.tableFilterColumnPlaceholder} value={filter.name} data-id={filter.id} onChange={onSelectProperty}/>
|
|
98
|
+
<Select data-id={filter.id} onChange={onSelectOperation} value={filter.operation.value} options={options} title={translation.tableFilterOperatorTitle} placeholder={translation.tableFilterOperatorPlaceholder}/>
|
|
99
|
+
<Input optionalText="" data-id={filter.id} onChange={onChangeValue} value={filter.value} type={filter.type} title={translation.tableFilterValueTitle} placeholder={translation.tableFilterValuePlaceholder}/>
|
|
100
|
+
<div className="mt-5 flex items-center justify-center">
|
|
101
|
+
<button data-id={filter.id} type="button" onClick={onDelete}>
|
|
102
|
+
<TrashIcon className="text-danger" size={16}/>
|
|
103
|
+
</button>
|
|
104
|
+
</div>
|
|
105
|
+
</li>);
|
|
106
|
+
})}
|
|
107
|
+
<li>
|
|
108
|
+
<button type="button" onClick={onAddFilter} className="flex items-center gap-1 text-primary">
|
|
109
|
+
<PlusIcon size={14}/> {translation.tableFilterNewFilter}
|
|
110
|
+
</button>
|
|
111
|
+
</li>
|
|
112
|
+
</ul>
|
|
113
|
+
</Dropdown>
|
|
114
|
+
</Fragment>);
|
|
115
|
+
};
|
|
116
|
+
export const ColumnHeaderFilter = ({ filter, onDelete, set }) => {
|
|
117
|
+
const translation = useTranslations();
|
|
118
|
+
const operators = useOperators();
|
|
119
|
+
const onSelectOperation = (e) => {
|
|
120
|
+
const operator = e.target.value;
|
|
121
|
+
const id = e.target.dataset.id || "";
|
|
122
|
+
set((prev) => prev.map((x) => x.id === id
|
|
123
|
+
? {
|
|
124
|
+
...x,
|
|
125
|
+
operation: operators.operations[operator],
|
|
126
|
+
}
|
|
127
|
+
: x));
|
|
128
|
+
};
|
|
129
|
+
const onChangeValue = (e) => {
|
|
130
|
+
const id = e.target.dataset.id || "";
|
|
131
|
+
const value = valueFromType(e.target);
|
|
132
|
+
set((prev) => prev.map((x) => (x.id === id ? { ...x, value } : x)));
|
|
133
|
+
};
|
|
134
|
+
return (<div className="flex flex-nowrap items-center gap-4 py-2">
|
|
135
|
+
<Select data-id={filter.id} onChange={onSelectOperation} value={filter.operation.value} options={operators.options[filter.type]} title={translation.tableFilterColumnTitle} placeholder={translation.tableFilterColumnPlaceholder}/>
|
|
136
|
+
<Input optionalText=" " data-id={filter.id} onChange={onChangeValue} value={filter.value} type={filter.type} title={translation.tableFilterValueTitle} placeholder={translation.tableFilterValueTitle}/>
|
|
137
|
+
<button onClick={onDelete} data-id={filter.id} type="button" className="mt-4">
|
|
138
|
+
<TrashIcon className="text-danger" size={14}/>
|
|
139
|
+
</button>
|
|
140
|
+
</div>);
|
|
141
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Col, TableConfiguration } from "./table-lib";
|
|
3
|
+
export type GroupItem<T extends object> = Col<T> & {
|
|
4
|
+
rows: T[];
|
|
5
|
+
index: number;
|
|
6
|
+
groupId: string;
|
|
7
|
+
groupName: string;
|
|
8
|
+
groupKey: keyof T;
|
|
9
|
+
};
|
|
10
|
+
type Props<T extends object> = TableConfiguration<T, {
|
|
11
|
+
rows: T[];
|
|
12
|
+
groups: GroupItem<T>[];
|
|
13
|
+
setGroups: React.Dispatch<React.SetStateAction<GroupItem<T>[]>>;
|
|
14
|
+
}>;
|
|
15
|
+
export declare const Group: <T extends object>(props: Props<T>) => React.JSX.Element;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=group.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group.d.ts","sourceRoot":"","sources":["../../../src/components/table/group.tsx"],"names":[],"mappings":"AAIA,OAAO,KAA6B,MAAM,OAAO,CAAC;AAOlD,OAAO,EAAE,GAAG,EAAoB,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAExE,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG;IAC/C,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC,CAAC;CACrB,CAAC;AAEF,KAAK,KAAK,CAAC,CAAC,SAAS,MAAM,IAAI,kBAAkB,CAC7C,CAAC,EACD;IACI,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IACvB,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CACnE,CACJ,CAAC;AAqBF,eAAO,MAAM,KAAK,GAAI,CAAC,SAAS,MAAM,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC,sBA4EtD,CAAC"}
|