@torpor/ui 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/dist/Accordion/Accordion.torp +2 -2
- package/dist/Accordion/AccordionContent.torp +2 -2
- package/dist/Accordion/AccordionHeader.torp +2 -2
- package/dist/Accordion/AccordionItem.torp +2 -2
- package/dist/Accordion/AccordionTrigger.torp +2 -2
- package/dist/Accordion/index.d.ts +92 -0
- package/dist/Breadcrumb/Breadcrumb.torp +33 -0
- package/dist/Breadcrumb/BreadcrumbItem.torp +19 -0
- package/dist/Breadcrumb/BreadcrumbSeparator.torp +16 -0
- package/dist/Breadcrumb/index.d.ts +56 -0
- package/dist/Breadcrumb/index.js +14 -0
- package/dist/Calendar/Calendar.torp +265 -0
- package/dist/Calendar/CalendarDay.torp +67 -0
- package/dist/Calendar/CalendarTypes.ts +22 -0
- package/dist/Calendar/index.d.ts +38 -0
- package/dist/Calendar/index.js +10 -0
- package/dist/Calendar/index.js.map +1 -0
- package/dist/Dialog/Dialog.torp +3 -3
- package/dist/Dialog/DialogBody.torp +2 -2
- package/dist/Dialog/DialogButton.torp +2 -2
- package/dist/Dialog/DialogFooter.torp +2 -2
- package/dist/Dialog/DialogHeader.torp +2 -2
- package/dist/Dialog/index.d.ts +92 -0
- package/dist/Disclosure/Disclosure.torp +69 -0
- package/dist/Disclosure/DisclosureContent.torp +36 -0
- package/dist/Disclosure/DisclosureHeader.torp +34 -0
- package/dist/Disclosure/DisclosureTrigger.torp +36 -0
- package/dist/Disclosure/DisclosureTypes.ts +14 -0
- package/dist/Disclosure/index.d.ts +74 -0
- package/dist/Disclosure/index.js +18 -0
- package/dist/Disclosure/index.js.map +1 -0
- package/{src/Offscreen/Offscreen.torp → dist/Drawer/Drawer.torp} +10 -19
- package/dist/Drawer/index.d.ts +20 -0
- package/dist/Drawer/index.js +6 -0
- package/dist/Drawer/index.js.map +1 -0
- package/dist/Menu/Menu.torp +160 -0
- package/dist/Menu/MenuButton.torp +53 -0
- package/dist/Menu/MenuCheck.torp +70 -0
- package/dist/Menu/MenuGroup.torp +19 -0
- package/dist/Menu/MenuIndicator.torp +29 -0
- package/dist/Menu/MenuPopout.torp +71 -0
- package/dist/Menu/MenuPopoutContent.torp +74 -0
- package/dist/Menu/MenuPopoutTrigger.torp +117 -0
- package/dist/Menu/MenuRadio.torp +88 -0
- package/dist/Menu/MenuRadioGroup.torp +86 -0
- package/dist/Menu/MenuSeparator.torp +14 -0
- package/dist/Menu/MenuTypes.ts +58 -0
- package/dist/Menu/index.d.ts +200 -0
- package/dist/Menu/index.js +46 -0
- package/dist/Menu/index.js.map +1 -0
- package/dist/MenuBar/MenuBar.torp +150 -0
- package/dist/MenuBar/MenuBarItem.torp +104 -0
- package/dist/MenuBar/MenuBarItemContent.torp +108 -0
- package/dist/MenuBar/MenuBarItemTrigger.torp +89 -0
- package/dist/MenuBar/MenuBarTypes.ts +36 -0
- package/dist/MenuBar/index.d.ts +74 -0
- package/dist/MenuBar/index.js +18 -0
- package/dist/MenuBar/index.js.map +1 -0
- package/dist/NavMenu/NavMenu.torp +2 -2
- package/dist/NavMenu/NavMenuButton.torp +2 -2
- package/dist/NavMenu/NavMenuElement.torp +2 -2
- package/dist/NavMenu/NavMenuGroup.torp +2 -2
- package/dist/NavMenu/NavMenuGroupHeader.torp +2 -2
- package/dist/NavMenu/NavMenuLink.torp +2 -2
- package/dist/NavMenu/NavMenuPopout.torp +2 -2
- package/dist/NavMenu/NavMenuPopoutButton.torp +3 -3
- package/dist/NavMenu/NavMenuPopoutContent.torp +29 -27
- package/dist/NavMenu/NavMenuSeparator.torp +2 -2
- package/dist/NavMenu/index.d.ts +182 -0
- package/dist/Notification/Notification.torp +48 -0
- package/dist/Notification/NotificationClose.torp +28 -0
- package/dist/Notification/NotificationContainer.torp +14 -0
- package/dist/Notification/NotificationContent.torp +13 -0
- package/dist/Notification/NotificationTypes.ts +5 -0
- package/dist/Notification/index.d.ts +74 -0
- package/dist/Notification/index.js +36 -0
- package/dist/Notification/index.js.map +1 -0
- package/dist/Notification/showNotification.ts +30 -0
- package/dist/Popover/Popover.torp +2 -2
- package/dist/Popover/PopoverContent.torp +31 -28
- package/dist/Popover/PopoverContentAnchored.torp +39 -38
- package/dist/Popover/PopoverContentContextual.torp +39 -36
- package/dist/Popover/PopoverOverlay.torp +3 -3
- package/dist/Popover/PopoverTrigger.torp +2 -2
- package/dist/Popover/PopoverTriggerContextual.torp +2 -2
- package/dist/Popover/PopoverTriggerHover.torp +3 -3
- package/dist/Popover/index.d.ts +146 -0
- package/dist/TabGroup/TabContent.torp +2 -2
- package/dist/TabGroup/TabGroup.torp +2 -2
- package/dist/TabGroup/TabHeader.torp +2 -2
- package/dist/TabGroup/TabList.torp +2 -2
- package/dist/TabGroup/TabTrigger.torp +2 -2
- package/dist/TabGroup/index.d.ts +92 -0
- package/dist/icons/ArrowDown.torp +15 -0
- package/dist/icons/ArrowLeft.torp +15 -0
- package/dist/icons/ArrowRight.torp +15 -0
- package/dist/icons/ArrowUp.torp +15 -0
- package/dist/icons/Bars.torp +17 -0
- package/dist/icons/Check.torp +15 -0
- package/dist/icons/ChevronDown.torp +15 -0
- package/dist/icons/ChevronLeft.torp +15 -0
- package/dist/icons/ChevronRight.torp +15 -0
- package/dist/icons/ChevronUp.torp +15 -0
- package/dist/icons/Cross.torp +16 -0
- package/dist/icons/Loading.torp +16 -0
- package/dist/icons/Minus.torp +15 -0
- package/dist/icons/Plus.torp +16 -0
- package/dist/icons/index.d.ts +254 -0
- package/dist/icons/index.js +58 -0
- package/dist/icons/index.js.map +1 -0
- package/dist/{motion.d.cts → index.d.ts} +2 -2
- package/dist/metafile-esm.json +1 -1
- package/dist/motion/fade.ts +7 -0
- package/dist/motion/index.d.ts +2 -0
- package/dist/{motion.js → motion/index.js} +1 -1
- package/dist/motion/index.js.map +1 -0
- package/dist/mount/index.d.ts +2 -0
- package/dist/utils/dateUtils.ts +244 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/setPopoverPosition.ts +4 -0
- package/package.json +50 -34
- package/scripts/postbuild.ts +42 -5
- package/src/Accordion/Accordion.torp +2 -2
- package/src/Accordion/AccordionContent.torp +2 -2
- package/src/Accordion/AccordionHeader.torp +2 -2
- package/src/Accordion/AccordionItem.torp +2 -2
- package/src/Accordion/AccordionTrigger.torp +2 -2
- package/src/Breadcrumb/Breadcrumb.torp +33 -0
- package/src/Breadcrumb/BreadcrumbItem.torp +19 -0
- package/src/Breadcrumb/BreadcrumbSeparator.torp +16 -0
- package/src/Breadcrumb/index.ts +5 -0
- package/src/Calendar/Calendar.torp +265 -0
- package/src/Calendar/CalendarDay.torp +67 -0
- package/src/Calendar/CalendarTypes.ts +22 -0
- package/src/Calendar/index.ts +4 -0
- package/src/Dialog/Dialog.torp +3 -3
- package/src/Dialog/DialogBody.torp +2 -2
- package/src/Dialog/DialogButton.torp +2 -2
- package/src/Dialog/DialogFooter.torp +2 -2
- package/src/Dialog/DialogHeader.torp +2 -2
- package/src/Disclosure/Disclosure.torp +69 -0
- package/src/Disclosure/DisclosureContent.torp +36 -0
- package/src/Disclosure/DisclosureHeader.torp +34 -0
- package/src/Disclosure/DisclosureTrigger.torp +36 -0
- package/src/Disclosure/DisclosureTypes.ts +14 -0
- package/src/Disclosure/index.ts +6 -0
- package/{dist/Offscreen/Offscreen.torp → src/Drawer/Drawer.torp} +10 -19
- package/src/Drawer/index.ts +3 -0
- package/src/Menu/Menu.torp +160 -0
- package/src/Menu/MenuButton.torp +53 -0
- package/src/Menu/MenuCheck.torp +70 -0
- package/src/Menu/MenuGroup.torp +19 -0
- package/src/Menu/MenuIndicator.torp +29 -0
- package/src/Menu/MenuPopout.torp +71 -0
- package/src/Menu/MenuPopoutContent.torp +74 -0
- package/src/Menu/MenuPopoutTrigger.torp +117 -0
- package/src/Menu/MenuRadio.torp +88 -0
- package/src/Menu/MenuRadioGroup.torp +86 -0
- package/src/Menu/MenuSeparator.torp +14 -0
- package/src/Menu/MenuTypes.ts +58 -0
- package/src/Menu/index.ts +25 -0
- package/src/MenuBar/MenuBar.torp +150 -0
- package/src/MenuBar/MenuBarItem.torp +104 -0
- package/src/MenuBar/MenuBarItemContent.torp +108 -0
- package/src/MenuBar/MenuBarItemTrigger.torp +89 -0
- package/src/MenuBar/MenuBarTypes.ts +36 -0
- package/src/MenuBar/index.ts +6 -0
- package/src/NavMenu/NavMenu.torp +2 -2
- package/src/NavMenu/NavMenuButton.torp +2 -2
- package/src/NavMenu/NavMenuElement.torp +2 -2
- package/src/NavMenu/NavMenuGroup.torp +2 -2
- package/src/NavMenu/NavMenuGroupHeader.torp +2 -2
- package/src/NavMenu/NavMenuLink.torp +2 -2
- package/src/NavMenu/NavMenuPopout.torp +2 -2
- package/src/NavMenu/NavMenuPopoutButton.torp +3 -3
- package/src/NavMenu/NavMenuPopoutContent.torp +29 -27
- package/src/NavMenu/NavMenuSeparator.torp +2 -2
- package/src/Notification/Notification.torp +48 -0
- package/src/Notification/NotificationClose.torp +28 -0
- package/src/Notification/NotificationContainer.torp +14 -0
- package/src/Notification/NotificationContent.torp +13 -0
- package/src/Notification/NotificationTypes.ts +5 -0
- package/src/Notification/index.ts +13 -0
- package/src/Notification/showNotification.ts +30 -0
- package/src/Popover/Popover.torp +2 -2
- package/src/Popover/PopoverContent.torp +31 -28
- package/src/Popover/PopoverContentAnchored.torp +39 -38
- package/src/Popover/PopoverContentContextual.torp +39 -36
- package/src/Popover/PopoverOverlay.torp +3 -3
- package/src/Popover/PopoverTrigger.torp +2 -2
- package/src/Popover/PopoverTriggerContextual.torp +2 -2
- package/src/Popover/PopoverTriggerHover.torp +3 -3
- package/src/Slider/Slider.torp +83 -0
- package/src/Slider/index.ts +3 -0
- package/src/TabGroup/TabContent.torp +2 -2
- package/src/TabGroup/TabGroup.torp +2 -2
- package/src/TabGroup/TabHeader.torp +2 -2
- package/src/TabGroup/TabList.torp +2 -2
- package/src/TabGroup/TabTrigger.torp +2 -2
- package/src/icons/ArrowDown.torp +15 -0
- package/src/icons/ArrowLeft.torp +15 -0
- package/src/icons/ArrowRight.torp +15 -0
- package/src/icons/ArrowUp.torp +15 -0
- package/src/icons/Bars.torp +17 -0
- package/src/icons/Check.torp +15 -0
- package/src/icons/ChevronDown.torp +15 -0
- package/src/icons/ChevronLeft.torp +15 -0
- package/src/icons/ChevronRight.torp +15 -0
- package/src/icons/ChevronUp.torp +15 -0
- package/src/icons/Cross.torp +16 -0
- package/src/icons/Loading.torp +16 -0
- package/src/icons/Minus.torp +15 -0
- package/src/icons/Plus.torp +16 -0
- package/src/icons/index.ts +31 -0
- package/src/motion/fade.ts +2 -2
- package/src/motion/index.ts +3 -0
- package/src/utils/dateUtils.ts +244 -0
- package/src/utils/setPopoverPosition.ts +4 -0
- package/test/Breadcrumb/accessibility.test.ts +29 -0
- package/test/Breadcrumb/basic.test.ts +17 -0
- package/test/Breadcrumb/components/BreadcrumbTest.torp +15 -0
- package/test/Calendar/components/CalendarTest.torp +9 -0
- package/test/Calendar/default.test.ts +18 -0
- package/test/Dialog/components/DialogAccessibility.torp +5 -5
- package/test/Disclosure/accessibility.test.ts +30 -0
- package/test/Disclosure/components/DisclosureTest.torp +17 -0
- package/test/Disclosure/default.test.ts +15 -0
- package/test/Disclosure/toggle.test.ts +19 -0
- package/test/Menu/accessibility.test.ts +82 -0
- package/test/Menu/basic.test.ts +57 -0
- package/test/Menu/components/MenuAccessibility.torp +59 -0
- package/test/Menu/components/MenuBasic.torp +58 -0
- package/test/MenuBar/accessibility.test.ts +86 -0
- package/test/MenuBar/basic.test.ts +21 -0
- package/test/MenuBar/components/MenuBarAccessibility.torp +34 -0
- package/test/MenuBar/components/MenuBarBasic.torp +25 -0
- package/test/Notification/accessibility.test.ts +21 -0
- package/test/Notification/components/CustomNotification.torp +14 -0
- package/test/Notification/components/NotificationAccessibility.torp +14 -0
- package/test/Notification/components/NotificationFunction.torp +20 -0
- package/test/Notification/components/NotificationVariable.torp +22 -0
- package/test/Notification/function.test.ts +25 -0
- package/test/Notification/variable.test.ts +25 -0
- package/test/Popover/components/CustomDialog.torp +25 -0
- package/test/Popover/components/PromptFunction.torp +19 -0
- package/test/Popover/components/PromptVariable.torp +38 -0
- package/test/Popover/function.test.ts +26 -0
- package/test/Popover/variable.test.ts +27 -0
- package/tsup.config.ts +12 -4
- package/dist/Accordion/index.cjs +0 -53
- package/dist/Accordion/index.cjs.map +0 -1
- package/dist/Dialog/index.cjs +0 -53
- package/dist/Dialog/index.cjs.map +0 -1
- package/dist/NavMenu/index.cjs +0 -78
- package/dist/NavMenu/index.cjs.map +0 -1
- package/dist/Offscreen/index.cjs +0 -33
- package/dist/Offscreen/index.cjs.map +0 -1
- package/dist/Offscreen/index.js +0 -6
- package/dist/Popover/index.cjs +0 -222
- package/dist/Popover/index.cjs.map +0 -1
- package/dist/TabGroup/index.cjs +0 -53
- package/dist/TabGroup/index.cjs.map +0 -1
- package/dist/metafile-cjs.json +0 -1
- package/dist/motion.cjs +0 -34
- package/dist/motion.cjs.map +0 -1
- package/dist/motion.d.ts +0 -6
- package/dist/motion.js.map +0 -1
- package/src/Accordion.ts +0 -7
- package/src/Dialog.ts +0 -7
- package/src/NavMenu.ts +0 -23
- package/src/Offscreen/index.ts +0 -3
- package/src/Popover.ts +0 -29
- package/src/TabGroup.ts +0 -7
- package/src/motion.ts +0 -3
- /package/dist/{Offscreen → Breadcrumb}/index.js.map +0 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { ReactiveDate } from "@torpor/view";
|
|
2
|
+
import { areDatesEqual, dayNames, monthNames } from "../utils/dateUtils";
|
|
3
|
+
import CalendarDay from "./CalendarDay.torp";
|
|
4
|
+
import { type CalendarContext, type DayState, type CalendarEvent, CalendarContextName } from "./CalendarTypes";
|
|
5
|
+
import ChevronLeft from "../icons/ChevronLeft.torp";
|
|
6
|
+
import ChevronRight from "../icons/ChevronRight.torp";
|
|
7
|
+
|
|
8
|
+
// TODO: Split this out into Calendar, CalendarHeader, CalendarPreviousTrigger, CalendarGrid etc
|
|
9
|
+
|
|
10
|
+
export default function Calendar() {
|
|
11
|
+
$props.startOfWeek ??= 1;
|
|
12
|
+
$props.selectable ??= false;
|
|
13
|
+
$props.value ??= new Date();
|
|
14
|
+
$props.events ??= [];
|
|
15
|
+
|
|
16
|
+
// Ensure the value is a reactive date
|
|
17
|
+
$props.value = new ReactiveDate($unwrap($props.value));
|
|
18
|
+
|
|
19
|
+
// A note on dates:
|
|
20
|
+
// * value is the selected value
|
|
21
|
+
// * activeDate is the date that is active when the user is navigating via keyboard
|
|
22
|
+
// * visibleDate is the date that is currently being displayed in the calendar (really only the month part is important here)
|
|
23
|
+
|
|
24
|
+
let $state = $watch({
|
|
25
|
+
activeDate: $props.value,
|
|
26
|
+
visibleDate: $props.value,
|
|
27
|
+
//get days() {
|
|
28
|
+
// // TODO: $cache
|
|
29
|
+
// return buildDays($state.visibleDate, $props.startOfWeek)
|
|
30
|
+
//},
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
let visibleStartDate = $props.value;
|
|
34
|
+
let visibleEndDate = $props.value;
|
|
35
|
+
let container: HTMLElement;
|
|
36
|
+
let refocus = false;
|
|
37
|
+
|
|
38
|
+
const context: CalendarContext = {
|
|
39
|
+
registerDay
|
|
40
|
+
};
|
|
41
|
+
$context[CalendarContextName] = context;
|
|
42
|
+
|
|
43
|
+
$run(() => {
|
|
44
|
+
$state.days = buildDays($state.visibleDate, $props.startOfWeek)
|
|
45
|
+
|
|
46
|
+
// HACK: Shouldn't need this
|
|
47
|
+
if (refocus) {
|
|
48
|
+
refocus = false;
|
|
49
|
+
const el = container.getElementsByClassName("active")[0];
|
|
50
|
+
if (el && el.children[0] instanceof HTMLElement) {
|
|
51
|
+
el.children[0].focus();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
function registerDay(date: ReactiveDate, setActive: (value: boolean) => void) {
|
|
57
|
+
const day = $state.days.find((day) => areDatesEqual(day.date, date));
|
|
58
|
+
if (day) {
|
|
59
|
+
day.setActive = setActive;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function buildDays(date: ReactiveDate, start: number): DayState[] {
|
|
64
|
+
const newDays = [];
|
|
65
|
+
|
|
66
|
+
// Set the first day to the start of the week before the first day of
|
|
67
|
+
// the month (e.g. Monday the 28th of the previous month)
|
|
68
|
+
visibleStartDate = new Date();
|
|
69
|
+
visibleStartDate.setFullYear(date.getFullYear(), date.getMonth(), 1);
|
|
70
|
+
visibleStartDate.setDate(
|
|
71
|
+
visibleStartDate.getDate() - ((visibleStartDate.getDay() + 7 - start) % 7)
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
// Set the last day to the end of the week after the last day of the
|
|
75
|
+
// month (e.g. Sunday the 6th of the next month)
|
|
76
|
+
visibleEndDate = new Date();
|
|
77
|
+
visibleEndDate.setFullYear(date.getFullYear(), date.getMonth() + 1, 0);
|
|
78
|
+
visibleEndDate.setDate(
|
|
79
|
+
visibleEndDate.getDate() + ((start - 1 - visibleEndDate.getDay() + 7) % 7)
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const dayDiff =
|
|
83
|
+
Math.round((visibleEndDate.getTime() - visibleStartDate.getTime()) / (1000 * 60 * 60 * 24)) +
|
|
84
|
+
1;
|
|
85
|
+
|
|
86
|
+
for (let i = 0; i < dayDiff; i++) {
|
|
87
|
+
const dayDate = new ReactiveDate();
|
|
88
|
+
dayDate.setFullYear(
|
|
89
|
+
visibleStartDate.getFullYear(),
|
|
90
|
+
visibleStartDate.getMonth(),
|
|
91
|
+
visibleStartDate.getDate() + i
|
|
92
|
+
);
|
|
93
|
+
dayDate.setHours(0);
|
|
94
|
+
dayDate.setMinutes(0);
|
|
95
|
+
dayDate.setSeconds(0);
|
|
96
|
+
dayDate.setMilliseconds(0);
|
|
97
|
+
const newDay: DayState = {
|
|
98
|
+
date: dayDate,
|
|
99
|
+
muted: dayDate.getMonth() !== date.getMonth(),
|
|
100
|
+
active: areDatesEqual(dayDate, $state.activeDate)
|
|
101
|
+
};
|
|
102
|
+
newDays.push(newDay);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return newDays;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function setValue(date: Date) {
|
|
109
|
+
$state.value = new ReactiveDate(date);
|
|
110
|
+
|
|
111
|
+
// Also set the active date so that the user knows where they are
|
|
112
|
+
setActiveDate(date);
|
|
113
|
+
|
|
114
|
+
if ($props.onchange) $props.onchange(value);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function setActiveDate(date: Date) {
|
|
118
|
+
$state.activeDate = new ReactiveDate(date);
|
|
119
|
+
|
|
120
|
+
// If the selected date is outside the visible date range, move the date range
|
|
121
|
+
if (date < visibleStartDate || date > visibleEndDate) {
|
|
122
|
+
refocus = true;
|
|
123
|
+
$state.visibleDate = new ReactiveDate(date);
|
|
124
|
+
if ($props.onchangedate) $props.onchangedate(date);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
$state.days.forEach((day) => {
|
|
128
|
+
const active = areDatesEqual(day.date, new Date(date));
|
|
129
|
+
if (day.setActive) {
|
|
130
|
+
day.setActive(active);
|
|
131
|
+
}
|
|
132
|
+
day.active = active;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function handleFocus(e: FocusEvent & { currentTarget: EventTarget & HTMLElement }) {
|
|
137
|
+
const el = e.currentTarget.getElementsByClassName("active")[0];
|
|
138
|
+
if (el && el.children[0] instanceof HTMLElement) {
|
|
139
|
+
el.children[0].focus();
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function handlePrevMonth(e: Event) {
|
|
145
|
+
e.preventDefault();
|
|
146
|
+
$state.visibleDate.setMonth($state.visibleDate.getMonth() - 1);
|
|
147
|
+
if ($props.onchangedate) $props.onchangedate(visibleDate);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function handleNextMonth(e: Event) {
|
|
151
|
+
e.preventDefault();
|
|
152
|
+
$state.visibleDate.setMonth($state.visibleDate.getMonth() + 1);
|
|
153
|
+
if ($props.onchangedate) $props.onchangedate(visibleDate);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function handleDayClick(date: ReactiveDate) {
|
|
157
|
+
if (!$props.selectable) return;
|
|
158
|
+
|
|
159
|
+
setValue(date);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function handleKey(e: KeyboardEvent) {
|
|
163
|
+
if (!$props.selectable) return;
|
|
164
|
+
|
|
165
|
+
switch (e.key) {
|
|
166
|
+
case "Enter": {
|
|
167
|
+
e.preventDefault();
|
|
168
|
+
setValue($state.activeDate);
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
case "Esc":
|
|
172
|
+
case "Escape": {
|
|
173
|
+
e.preventDefault();
|
|
174
|
+
if ($props.onclose) $props.onclose();
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
case "Left":
|
|
178
|
+
case "ArrowLeft": {
|
|
179
|
+
e.preventDefault();
|
|
180
|
+
// Move to the date one day before
|
|
181
|
+
const newDate = new Date($state.activeDate.getTime() - 1 * 86400000)
|
|
182
|
+
setActiveDate(newDate);
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
case "Up":
|
|
186
|
+
case "ArrowUp": {
|
|
187
|
+
e.preventDefault();
|
|
188
|
+
// Move to the date seven days before
|
|
189
|
+
const newDate = new Date($state.activeDate.getTime() - 7 * 86400000)
|
|
190
|
+
setActiveDate(newDate);
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
case "Right":
|
|
194
|
+
case "ArrowRight": {
|
|
195
|
+
e.preventDefault();
|
|
196
|
+
// Move to the date one day after
|
|
197
|
+
const newDate = new Date($state.activeDate.getTime() + 1 * 86400000)
|
|
198
|
+
setActiveDate(newDate);
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
case "Down":
|
|
202
|
+
case "ArrowDown": {
|
|
203
|
+
e.preventDefault();
|
|
204
|
+
// Move to the date seven days after
|
|
205
|
+
const newDate = new Date($state.activeDate.getTime() + 7 * 86400000)
|
|
206
|
+
setActiveDate(newDate);
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
@render {
|
|
213
|
+
<div
|
|
214
|
+
{$props.id}
|
|
215
|
+
class={`torp-calendar ${$props.class ?? ""}`.trim()}
|
|
216
|
+
&ref={container}
|
|
217
|
+
>
|
|
218
|
+
<div class={`torp-calendar-header ${$props.class ?? ""}`.trim()}>
|
|
219
|
+
<button class={`torp-calendar-previous-trigger ${$props.class ?? ""}`.trim()} onclick={handlePrevMonth}>
|
|
220
|
+
<slot name="prev-button">
|
|
221
|
+
<ChevronLeft />
|
|
222
|
+
</slot>
|
|
223
|
+
</button>
|
|
224
|
+
<span class={`torp-calendar-month-name ${$props.class ?? ""}`.trim()}>
|
|
225
|
+
{monthNames[$state.visibleDate.getMonth()] + " " + $state.visibleDate.getFullYear()}
|
|
226
|
+
</span>
|
|
227
|
+
<button class={`torp-calendar-next-trigger ${$props.class ?? ""}`.trim()} onclick={handleNextMonth}>
|
|
228
|
+
<slot name="next-button">
|
|
229
|
+
<ChevronRight />
|
|
230
|
+
</slot>
|
|
231
|
+
</button>
|
|
232
|
+
</div>
|
|
233
|
+
<div
|
|
234
|
+
class={`torp-calendar-grid ${$props.class ?? ""}`.trim()}
|
|
235
|
+
tabindex={$props.selectable ? 0 : -1}
|
|
236
|
+
onfocus={handleFocus}
|
|
237
|
+
onkeydown={handleKey}
|
|
238
|
+
>
|
|
239
|
+
@for (let index of [0, 1, 2, 3, 4, 5, 6]) {
|
|
240
|
+
<span>
|
|
241
|
+
{dayNames[(Math.abs($props.startOfWeek) + index) % 7].substring(0, 2)}
|
|
242
|
+
</span>
|
|
243
|
+
}
|
|
244
|
+
@for (let day of $state.days) {
|
|
245
|
+
@key = day.date;
|
|
246
|
+
<CalendarDay
|
|
247
|
+
{day.date}
|
|
248
|
+
{day.muted}
|
|
249
|
+
{day.active}
|
|
250
|
+
{$props.selectable}
|
|
251
|
+
events={$props.events.filter((ev) => areDatesEqual(new Date(ev.date), day.date))}
|
|
252
|
+
onclick={handleDayClick}
|
|
253
|
+
/>
|
|
254
|
+
}
|
|
255
|
+
</div>
|
|
256
|
+
</div>
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
@style {
|
|
260
|
+
.torp-calendar-grid {
|
|
261
|
+
display: grid;
|
|
262
|
+
grid-template-columns: repeat(7, 1fr);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { areDatesEqual } from "../utils/dateUtils";
|
|
2
|
+
import { type CalendarContext, type CalendarEvent, CalendarContextName } from "./CalendarTypes";
|
|
3
|
+
|
|
4
|
+
export default function CalendarDay() {
|
|
5
|
+
$props.date ??= new Date();
|
|
6
|
+
$props.selectable ??= false;
|
|
7
|
+
$props.muted ??= false;
|
|
8
|
+
$props.active ??= false;
|
|
9
|
+
$props.events ??= [];
|
|
10
|
+
|
|
11
|
+
// HACK: can't unwrap in @render
|
|
12
|
+
let date = $unwrap($props.date);
|
|
13
|
+
|
|
14
|
+
// Register this item with the parent Calendar, which will handle toggling active for all days
|
|
15
|
+
const { registerDay } = $context[CalendarContextName] as CalendarContext;
|
|
16
|
+
registerDay($props.date, setActive);
|
|
17
|
+
|
|
18
|
+
// This function is called by the parent Calendar to set this item's active value
|
|
19
|
+
function setActive(value: boolean) {
|
|
20
|
+
//if (active !== value) {
|
|
21
|
+
// active = value;
|
|
22
|
+
// dispatch("activeChange", value);
|
|
23
|
+
//}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function isToday() {
|
|
27
|
+
const today = new Date();
|
|
28
|
+
return areDatesEqual(date, today);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function handleClick() {
|
|
32
|
+
//dispatch("click", date);
|
|
33
|
+
if ($props.onclick) $props.onclick($props.date);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function handleKey() {
|
|
37
|
+
//dispatch("click", date);
|
|
38
|
+
if ($props.onkeydown) $props.onkeydown();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@render {
|
|
42
|
+
<div
|
|
43
|
+
{$props.id}
|
|
44
|
+
class={[
|
|
45
|
+
`torp-calendar-day ${$props.class ?? ""}`.trim(),
|
|
46
|
+
{
|
|
47
|
+
muted: $props.muted,
|
|
48
|
+
today: isToday(),
|
|
49
|
+
active: $props.selectable && $props.active
|
|
50
|
+
}
|
|
51
|
+
]}
|
|
52
|
+
>
|
|
53
|
+
@if ($props.selectable) {
|
|
54
|
+
<button type="button" tabindex="-1" onclick={handleClick} onkeydown={handleKey}>
|
|
55
|
+
<span>{date.getDate()}</span>
|
|
56
|
+
</button>
|
|
57
|
+
} else {
|
|
58
|
+
<span>{date.getDate()}</span>
|
|
59
|
+
}
|
|
60
|
+
<ul class={`torp-calendar-day-events ${$props.class ?? ""}`.trim()}>
|
|
61
|
+
@for (ev of $props.events) {
|
|
62
|
+
<li title={ev.content} />
|
|
63
|
+
}
|
|
64
|
+
</ul>
|
|
65
|
+
</div>
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const CalendarContextName = "Calendar";
|
|
2
|
+
|
|
3
|
+
export interface CalendarContext {
|
|
4
|
+
// The registerDay function is called from each CalendarDay to register itself with this
|
|
5
|
+
// Calendar. They pass us a setActive method that we can call
|
|
6
|
+
registerDay: (date: Date, setActive: (value: boolean) => void) => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface DayState {
|
|
10
|
+
date: Date;
|
|
11
|
+
muted: boolean;
|
|
12
|
+
state: {
|
|
13
|
+
active: boolean;
|
|
14
|
+
};
|
|
15
|
+
setActive?: (value: boolean) => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface CalendarEvent {
|
|
19
|
+
date: Date;
|
|
20
|
+
content: string;
|
|
21
|
+
color: string;
|
|
22
|
+
}
|
package/src/Dialog/Dialog.torp
CHANGED
|
@@ -138,7 +138,7 @@ export default function Dialog($props: any) {
|
|
|
138
138
|
|
|
139
139
|
@render {
|
|
140
140
|
<div
|
|
141
|
-
|
|
141
|
+
{$props.id}
|
|
142
142
|
class={`torp-dialog ${$props.class ?? ""}`.trim()}
|
|
143
143
|
tabindex="0"
|
|
144
144
|
role={$props.alert ? "alertdialog" : "dialog"}
|
|
@@ -147,10 +147,10 @@ export default function Dialog($props: any) {
|
|
|
147
147
|
aria-labelledby={!$props.ariaLabel && $state.headerId ? $state.headerId : undefined}
|
|
148
148
|
aria-describedby={$state.bodyId ? $state.bodyId : undefined}
|
|
149
149
|
onkeydown={handleKey}
|
|
150
|
-
|
|
150
|
+
onmount={(el) => trapFocus(el, trapFocusOptions)}
|
|
151
151
|
&ref={div}
|
|
152
152
|
>
|
|
153
|
-
|
|
153
|
+
<slot />
|
|
154
154
|
</div>
|
|
155
155
|
}
|
|
156
156
|
}
|
|
@@ -36,13 +36,13 @@ export default function DialogButton($props: any) {
|
|
|
36
36
|
@render {
|
|
37
37
|
<button
|
|
38
38
|
type="button"
|
|
39
|
-
|
|
39
|
+
{$props.id}
|
|
40
40
|
class={`torp-dialog-button ${$props.class ?? ""}`.trim()}
|
|
41
41
|
disabled={$props.disabled}
|
|
42
42
|
onclick={handleClick}
|
|
43
43
|
&ref={button}
|
|
44
44
|
>
|
|
45
|
-
|
|
45
|
+
<slot />
|
|
46
46
|
</button>
|
|
47
47
|
}
|
|
48
48
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { DisclosureContextName, type DisclosureContext } from "./DisclosureTypes";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* An interactive header that enables users to reveal or hide an associated section of content.
|
|
5
|
+
*
|
|
6
|
+
* See [the WAI ARIA guidelines for Disclosures](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/).
|
|
7
|
+
*
|
|
8
|
+
* The structure of a Disclosure is:
|
|
9
|
+
*
|
|
10
|
+
* ```
|
|
11
|
+
* <Disclosure>
|
|
12
|
+
* <DisclosureHeader>
|
|
13
|
+
* <DisclosureTrigger />
|
|
14
|
+
* </DisclosureHeader>
|
|
15
|
+
* <DisclosureContent />
|
|
16
|
+
* </Disclosure>
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @prop {boolean} [expanded] -- Whether the Disclosure is expanded and its content visible
|
|
20
|
+
* @prop {boolean} [disabled] -- If set to true, the user cannot interact with this Disclosure
|
|
21
|
+
* @prop {(boolean) => void} [ontoggle] -- Raised when this item is opened or closed
|
|
22
|
+
*/
|
|
23
|
+
export default function Disclosure($props: any) {
|
|
24
|
+
$props.expanded ??= false;
|
|
25
|
+
$props.disabled ??= false;
|
|
26
|
+
|
|
27
|
+
let $state: DisclosureState = $watch({
|
|
28
|
+
expanded: $props.expanded && $props.expanded !== "false",
|
|
29
|
+
disabled: $props.disabled,
|
|
30
|
+
get dataState() {
|
|
31
|
+
return this.expanded ? "open" : "closed";
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Update $state with $props
|
|
36
|
+
$run(() => {
|
|
37
|
+
$state.expanded = $props.expanded && $props.expanded !== "false";
|
|
38
|
+
$state.disabled = $props.disabled;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Put stuff into a DisclosureContext
|
|
42
|
+
const itemContext: DisclosureContext = {
|
|
43
|
+
state: $state,
|
|
44
|
+
};
|
|
45
|
+
$context[DisclosureContextName] = itemContext;
|
|
46
|
+
|
|
47
|
+
// Dispatch the toggle event when the value of expanded changes
|
|
48
|
+
let firstToggle = true;
|
|
49
|
+
$run(() => {
|
|
50
|
+
const ev = $props.ontoggle;
|
|
51
|
+
const expanded = $state.expanded;
|
|
52
|
+
if (firstToggle) {
|
|
53
|
+
firstToggle = false;
|
|
54
|
+
} else if (ev) {
|
|
55
|
+
ev(expanded);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
@render {
|
|
60
|
+
<div
|
|
61
|
+
{$props.id}
|
|
62
|
+
class={`torp-disclosure-item ${$props.class ?? ""}`.trim()}
|
|
63
|
+
data-state={$state.dataState}
|
|
64
|
+
data-disabled={$state.dataDisabled}
|
|
65
|
+
>
|
|
66
|
+
<slot />
|
|
67
|
+
</div>
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import getId from "../utils/getId";
|
|
2
|
+
import { DisclosureContextName, type DisclosureContext } from "./DisclosureTypes";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Content for a Disclosure, which can be revealed or hidden by an associated DisclosureTrigger.
|
|
6
|
+
*
|
|
7
|
+
* @prop {string} [id] -- An ID for the DisclosureContent's div container
|
|
8
|
+
* @prop {boolean} [ariaRegion] -- Whether this content should act as a region. Set this when the content contains heading elements or a nested Disclosure
|
|
9
|
+
*/
|
|
10
|
+
export default function DisclosureContent($props: any) {
|
|
11
|
+
$props.id ||= getId();
|
|
12
|
+
|
|
13
|
+
const context = $context[DisclosureContextName] as DisclosureContext;
|
|
14
|
+
if (!context) {
|
|
15
|
+
throw new Error("DisclosureContent must be contained within a Disclosure");
|
|
16
|
+
}
|
|
17
|
+
let $state = $context[DisclosureContextName].state
|
|
18
|
+
|
|
19
|
+
// Set the content ID so that it can be used with aria-controls in DisclosureTrigger
|
|
20
|
+
$state.contentId = $props.id;
|
|
21
|
+
|
|
22
|
+
@render {
|
|
23
|
+
<div
|
|
24
|
+
{$props.id}
|
|
25
|
+
class={`torp-disclosure-content ${$props.class ?? ""}`.trim()}
|
|
26
|
+
role={$props.ariaRegion ? "region" : undefined}
|
|
27
|
+
aria-labelledby={$state.headerId}
|
|
28
|
+
data-state={$state.dataState}
|
|
29
|
+
data-disabled={$state.dataDisabled}
|
|
30
|
+
>
|
|
31
|
+
@if ($state.expanded) {
|
|
32
|
+
<slot />
|
|
33
|
+
}
|
|
34
|
+
</div>
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { DisclosureContextName, type DisclosureContext } from "./DisclosureTypes";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The header for a Disclosure, which contains the DisclosureTrigger.
|
|
5
|
+
*
|
|
6
|
+
* The structure of a DisclosureHeader is:
|
|
7
|
+
*
|
|
8
|
+
* ```
|
|
9
|
+
* <DisclosureHeader>
|
|
10
|
+
* <DisclosureTrigger />
|
|
11
|
+
* </DisclosureHeader>
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* @prop {"h1" | "h2" | "h3" | "h4" | "h5" | "h6"} as -- The type of HTML header to use
|
|
15
|
+
*/
|
|
16
|
+
export default function DisclosureHeader($props: any) {
|
|
17
|
+
const context = $context[DisclosureContextName] as DisclosureContext;
|
|
18
|
+
if (!context) {
|
|
19
|
+
throw new Error("DisclosureHeader must be contained within a Disclosure");
|
|
20
|
+
}
|
|
21
|
+
let $state = $context[DisclosureContextName].state
|
|
22
|
+
|
|
23
|
+
@render {
|
|
24
|
+
@// TODO: $props.as
|
|
25
|
+
<h4
|
|
26
|
+
{$props.id}
|
|
27
|
+
class={`torp-disclosure-header ${$props.class ?? ""}`.trim()}
|
|
28
|
+
data-state={$state.dataState}
|
|
29
|
+
data-disabled={$state.dataDisabled}
|
|
30
|
+
>
|
|
31
|
+
<slot />
|
|
32
|
+
</h4>
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import getId from "../utils/getId";
|
|
2
|
+
import { DisclosureContextName, type DisclosureContext } from "./DisclosureTypes";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A header button for a Disclosure, which can be used to reveal or hide an associated DisclosureContent.
|
|
6
|
+
*/
|
|
7
|
+
export default function DisclosureTrigger() {
|
|
8
|
+
$props.id ||= getId();
|
|
9
|
+
|
|
10
|
+
// Get stuff out of the DisclosureContext
|
|
11
|
+
const context = $context[DisclosureContextName] as DisclosureContext;
|
|
12
|
+
if (!context) {
|
|
13
|
+
throw new Error("DisclosureTrigger must be contained within a Disclosure");
|
|
14
|
+
}
|
|
15
|
+
let $state = $context[DisclosureContextName].state;
|
|
16
|
+
|
|
17
|
+
// Set the header ID so that it can be used with aria-labelledby in DisclosureContent
|
|
18
|
+
$state.headerId = $props.id;
|
|
19
|
+
|
|
20
|
+
@render {
|
|
21
|
+
<button
|
|
22
|
+
type="button"
|
|
23
|
+
{$props.id}
|
|
24
|
+
class={`torp-disclosure-trigger ${$props.class ?? ""}`.trim()}
|
|
25
|
+
disabled={$state.disabled || $state.parentDisabled}
|
|
26
|
+
aria-expanded={$state.expanded.toString()}
|
|
27
|
+
aria-disabled={$state.disabled}
|
|
28
|
+
aria-controls={$state.contentId}
|
|
29
|
+
data-state={$state.dataState}
|
|
30
|
+
data-disabled={$state.disabled}
|
|
31
|
+
onclick={() => $state.expanded = !$state.expanded}
|
|
32
|
+
>
|
|
33
|
+
<slot />
|
|
34
|
+
</button>
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const DisclosureContextName = "Disclosure";
|
|
2
|
+
|
|
3
|
+
export interface DisclosureContext {
|
|
4
|
+
/** The reactive state for a Disclosure */
|
|
5
|
+
state: DisclosureState;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface DisclosureState {
|
|
9
|
+
headerId: string;
|
|
10
|
+
contentId: string;
|
|
11
|
+
expanded: boolean;
|
|
12
|
+
disabled: boolean;
|
|
13
|
+
dataState: "open" | "closed";
|
|
14
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import Disclosure from "./Disclosure.torp";
|
|
2
|
+
import DisclosureContent from "./DisclosureContent.torp";
|
|
3
|
+
import DisclosureHeader from "./DisclosureHeader.torp";
|
|
4
|
+
import DisclosureTrigger from "./DisclosureTrigger.torp";
|
|
5
|
+
|
|
6
|
+
export { Disclosure, DisclosureHeader, DisclosureTrigger, DisclosureContent };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
export default function
|
|
3
|
-
$props.visible
|
|
2
|
+
export default function Drawer($props: any) {
|
|
3
|
+
$props.visible ??= true;
|
|
4
4
|
$props.position ||= "left";
|
|
5
5
|
|
|
6
6
|
let offscreen: HTMLElement | undefined;
|
|
@@ -66,25 +66,16 @@ export default function Offscreen($props: any) {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
function close() {
|
|
70
|
-
$props.visible = false;
|
|
71
|
-
if ($props.onclose) {
|
|
72
|
-
$props.onclose()
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
69
|
@render {
|
|
77
70
|
@if ($props.visible) {
|
|
78
|
-
<div
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
<:slot />
|
|
87
|
-
</div>
|
|
71
|
+
<div
|
|
72
|
+
{$props.id}
|
|
73
|
+
class={`torp-offscreen ${$props.class ?? ""}`.trim()}
|
|
74
|
+
style="position: fixed;"
|
|
75
|
+
transition={transitionArgs()}
|
|
76
|
+
&ref={offscreen}
|
|
77
|
+
>
|
|
78
|
+
<slot />
|
|
88
79
|
</div>
|
|
89
80
|
}
|
|
90
81
|
}
|