adwaveui
Version:
Interactive Web Components inspired by the Gtk Adwaita theme.
543 lines (541 loc) • 15.9 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
// src/components/calendar/calendar.tsx
import "../../base-elements.mjs";
import { sig } from "@ncpa0cpl/vanilla-jsx/signals";
import { Button, Typography } from "adwavecss";
import { customElement } from "wc_toolkit";
import { Dt } from "./date.mjs";
import { Fragment, jsx, jsxs } from "@ncpa0cpl/vanilla-jsx/jsx-runtime";
function Btn({ flat, color, disabled, linked, pill, toggled, shape, ...props }) {
let cls = {};
if (typeof props.class == "object") {
Object.assign(cls, props.class);
} else if (Array.isArray(props.class)) {
for (const elem of props.class) {
cls[elem] = true;
}
} else if (typeof props.class === "string") {
cls[props.class] = true;
}
cls[Button.className({
flat,
color,
disabled,
linked,
pill,
toggled,
shape
})] = true;
return /* @__PURE__ */ jsx(
"button",
{
...props,
class: cls
}
);
}
__name(Btn, "Btn");
function strBool(s) {
return s.derive((s2) => s2 ? "true" : "false");
}
__name(strBool, "strBool");
var DateChangeEvent = class extends Event {
static {
__name(this, "DateChangeEvent");
}
constructor(type, value) {
super("change", {
bubbles: true,
cancelable: true
});
this.value = value;
}
};
var DateModeChangeEvent = class extends Event {
static {
__name(this, "DateModeChangeEvent");
}
constructor(type, value) {
super("modechange", {
bubbles: true,
cancelable: true
});
this.value = value;
}
};
var DateYearSelectEvent = class extends Event {
static {
__name(this, "DateYearSelectEvent");
}
constructor(type, value) {
super("yearselected", {
bubbles: true,
cancelable: true
});
this.value = value;
}
};
var DateMonthSelectEvent = class extends Event {
static {
__name(this, "DateMonthSelectEvent");
}
constructor(type, value) {
super("monthselected", {
bubbles: true,
cancelable: true
});
this.value = value;
}
};
var DateMonthArrowPressEvent = class extends Event {
static {
__name(this, "DateMonthArrowPressEvent");
}
constructor(type, value) {
super("montharrowpress", {
bubbles: true,
cancelable: true
});
this.value = value;
}
};
var { CustomElement } = customElement("adw-calendar").attributes({
value: "string",
defaultValue: "string",
locale: "string",
name: "string",
form: "string"
}).events({
"change": DateChangeEvent,
"yearselected": DateYearSelectEvent,
"monthselected": DateMonthSelectEvent,
"modechange": DateModeChangeEvent,
"montharrowpress": DateMonthArrowPressEvent
}).context((attr) => {
const selectedDate = sig.derive(
attr.value.signal,
attr.locale.signal,
(v, locale) => {
if (v && Dt.isParsable(v)) {
return Dt.parse(v).setLocale(locale ?? navigator.language);
}
return new Dt().setLocale(locale ?? navigator.language);
}
);
return {
selectedDate,
visibleDate: sig(selectedDate.get().clone()),
selectMode: sig("day"),
yearsPage: sig(0)
};
}).methods((api) => {
return {
setYear(y) {
api.context.visibleDate.dispatch((d) => {
d = d.clone();
d.setYear(y);
return d;
});
},
setMonth(m) {
api.context.visibleDate.dispatch((d) => {
d = d.clone();
d.setMonth(m);
return d;
});
},
nextMonth() {
const m = api.context.visibleDate.get().month();
if (m === 12) {
const y = api.context.visibleDate.get().year();
this.setYear(y + 1);
this.setMonth(1);
return;
}
this.setMonth(m + 1);
},
prevMonth() {
const m = api.context.visibleDate.get().month();
if (m === 1) {
const y = api.context.visibleDate.get().year();
this.setYear(y - 1);
this.setMonth(12);
return;
}
this.setMonth(m - 1);
},
nextYearPage() {
api.context.yearsPage.dispatch((p) => p + 1);
},
prevYearPage() {
api.context.yearsPage.dispatch((p) => p - 1);
},
_showYearSelection(e) {
api.emitEvent(
"modechange",
"year"
).onCommit(() => {
e.target.blur();
api.context.yearsPage.dispatch(0);
api.context.selectMode.dispatch("year");
});
},
_showMonthSelection(e) {
api.emitEvent("modechange", "month").onCommit(() => {
e.target.blur();
api.context.selectMode.dispatch("month");
});
},
_updateLocale() {
api.context.visibleDate.dispatch((d) => {
const l = api.attribute.locale.get();
if (l != null) {
return d.clone().setLocale(l);
}
return d;
});
},
_handleDateSelect(date) {
api.emitEvent("change", date.jsDate()).onCommit(() => {
api.attribute.value.set(date.clone().setHour(12, 0, 0).iso());
});
},
_handleYearSelect(e, y) {
api.emitEvent("yearselected", y).onCommit(() => {
e.target.blur();
this.setYear(y);
api.emitEvent("modechange", "day").onCommit(() => {
api.context.selectMode.dispatch("day");
});
});
},
_handleMonthSelect(e, m) {
api.emitEvent("monthselected", m).onCommit(() => {
e.target.blur();
this.setMonth(m);
api.emitEvent("modechange", "day").onCommit(() => {
api.context.selectMode.dispatch("day");
});
});
},
_handlePrevMonthPress(e) {
api.emitEvent("montharrowpress", "prev").onCommit(() => {
this.prevMonth();
});
},
_handleNextMonthPress(e) {
api.emitEvent("montharrowpress", "next").onCommit(() => {
this.nextMonth();
});
}
};
}).connected((api) => {
const { selectedDate, visibleDate } = api.context;
if (api.attribute.value.get() == null && api.attribute.defaultValue.get() != null) {
api.attribute.value.set(api.attribute.defaultValue.get());
}
visibleDate.dispatch(selectedDate.get().clone());
api.method._updateLocale();
api.onChange([api.attribute.locale], () => {
api.method._updateLocale();
});
const year = visibleDate.derive((d) => d.year().toFixed(0));
const month = visibleDate.derive((d) => d.monthString());
const firstDay = visibleDate.derive((d) => {
return d.clone().startOfMonth();
});
const lastDay = visibleDate.derive((d) => {
return d.clone().endOfMonth();
});
const monday = visibleDate.get().clone().minus({
days: visibleDate.get().dayOfWeek() - 1
});
const html = /* @__PURE__ */ jsxs("div", { class: "adw-calendar", role: "application", "aria-label": "Calendar", children: [
/* @__PURE__ */ jsx(
Btn,
{
flat: true,
onclick: api.method._showYearSelection,
class: {
"year-selector": true,
hidden: sig.eq(api.context.selectMode, "year")
},
"aria-label": sig.literal`Current year: ${year}. Click to select a different year.`,
"aria-hidden": strBool(sig.eq(api.context.selectMode, "year")),
children: year
}
),
/* @__PURE__ */ jsxs(
"div",
{
class: {
"month-selector": true,
hidden: api.context.selectMode.derive(
(m) => m === "month" || m === "year"
)
},
role: "toolbar",
"aria-label": "Month Navigation",
"aria-hidden": strBool(api.context.selectMode.derive(
(m) => m === "month" || m === "year"
)),
children: [
/* @__PURE__ */ jsx(
Btn,
{
flat: true,
onclick: api.method._handlePrevMonthPress,
"aria-label": "Previous Month",
title: "Previous Month",
children: "\u25C2"
}
),
/* @__PURE__ */ jsx(
Btn,
{
flat: true,
class: "month-btn",
onclick: api.method._showMonthSelection,
"aria-label": sig.literal`Current month: ${month}. Click to select a different month.`,
children: month
}
),
/* @__PURE__ */ jsx(
Btn,
{
flat: true,
onclick: api.method._handleNextMonthPress,
"aria-label": "Next Month",
title: "Next Month",
children: "\u25B8"
}
)
]
}
),
/* @__PURE__ */ jsxs(
"div",
{
class: {
"days-grid": true,
visible: sig.eq(api.context.selectMode, "day")
},
role: "grid",
"aria-hidden": strBool(sig.not(sig.eq(api.context.selectMode, "day"))),
children: [
Array.from({ length: 7 }, (_, idx) => {
const d = monday.clone().plus({ days: idx });
return /* @__PURE__ */ jsx(
"span",
{
class: [Typography.text, "header-day"],
role: "columnheader",
"aria-label": d.dayOfWeekString("long"),
children: d.dayOfWeekString("narrow")
}
);
}),
firstDay.derive((f) => {
const weekDay = f.dayOfWeek();
return /* @__PURE__ */ jsx("div", { style: { display: "contents" }, children: Array.from(
{ length: weekDay - 1 },
(_, idx) => {
const d = f.clone();
d.minus({ days: weekDay - idx - 1 });
const selected = selectedDate.derive((s) => s.isSameDate(d));
return /* @__PURE__ */ jsx(
Btn,
{
flat: true,
shape: "circular",
class: {
"prev-month-day": true,
selected
},
onclick: () => api.method._handleDateSelect(d),
title: d.localeString(),
"aria-label": d.localeString(),
"aria-selected": strBool(selected),
children: d.dayOfMonth("padded")
}
);
}
) });
}),
visibleDate.derive((date) => {
return Array.from(
{ length: date.countDaysOfThisMonth() },
(_, idx) => {
const d = visibleDate.get().clone();
d.setDay(idx + 1);
const selected = selectedDate.derive(
(s) => s.isSameDate(d)
);
return /* @__PURE__ */ jsx(
Btn,
{
flat: true,
shape: "circular",
class: {
"curr-month-day": true,
selected
},
onclick: () => api.method._handleDateSelect(d),
title: d.localeString(),
"aria-label": d.localeString(),
"aria-selected": strBool(selected),
children: d.dayOfMonth("padded")
}
);
}
);
}),
lastDay.derive((l) => {
const weekDay = l.dayOfWeek();
if (weekDay == 7) {
return /* @__PURE__ */ jsx(Fragment, {});
}
return /* @__PURE__ */ jsx("div", { style: { display: "contents" }, role: "row", children: Array.from(
{ length: 7 - weekDay },
(_, idx) => {
const d = l.clone();
d.plus({ days: idx + 1 });
const selected = selectedDate.derive((s) => s.isSameDate(d));
return /* @__PURE__ */ jsx(
Btn,
{
flat: true,
shape: "circular",
class: {
"next-month-day": true,
selected
},
onclick: () => api.method._handleDateSelect(d),
title: d.localeString(),
"aria-label": d.localeString(),
"aria-selected": strBool(selected),
children: d.dayOfMonth("padded")
}
);
}
) });
})
]
}
),
/* @__PURE__ */ jsx(
"div",
{
class: {
"months-grid": true,
visible: sig.eq(api.context.selectMode, "month")
},
role: "grid",
"aria-label": "Month selection",
"aria-hidden": strBool(
sig.not(sig.eq(api.context.selectMode, "month"))
),
children: api.attribute.locale.signal.derive((locale) => {
return Array.from({ length: 12 }, (_, idx) => {
const d = new Dt(void 0, locale).setMonth(idx + 1);
const selected = selectedDate.derive(
(s) => s.month() == d.month()
);
return /* @__PURE__ */ jsx(
Btn,
{
class: {
selected
},
onclick: (e) => api.method._handleMonthSelect(e, d.month()),
"aria-label": d.monthString(),
"aria-selected": strBool(selected),
children: d.monthString()
}
);
});
})
}
),
/* @__PURE__ */ jsxs(
"div",
{
class: {
"years-controls": true,
visible: sig.eq(api.context.selectMode, "year")
},
role: "toolbar",
"aria-label": "Year navigation",
"aria-hidden": strBool(sig.not(sig.eq(api.context.selectMode, "year"))),
children: [
/* @__PURE__ */ jsx(
Btn,
{
flat: true,
onclick: api.method.prevYearPage,
"aria-label": "Previous 16 years",
children: "\u25C2"
}
),
/* @__PURE__ */ jsx(
Btn,
{
flat: true,
onclick: api.method.nextYearPage,
"aria-label": "Next 16 years",
children: "\u25B8"
}
)
]
}
),
/* @__PURE__ */ jsx(
"div",
{
class: {
"years-grid": true,
visible: sig.eq(api.context.selectMode, "year")
},
role: "grid",
"aria-label": "Year selection",
"aria-hidden": strBool(sig.not(sig.eq(api.context.selectMode, "year"))),
children: api.context.yearsPage.derive((p) => {
const pageStart = visibleDate.get().year() - 8 + p * 16;
return Array.from({ length: 16 }, (_, idx) => {
const year2 = pageStart + idx;
const selected = selectedDate.derive((s) => s.year() == year2);
return /* @__PURE__ */ jsx(
Btn,
{
class: {
selected
},
onclick: (e) => api.method._handleYearSelect(e, year2),
"aria-label": String(year2),
"aria-selected": strBool(selected),
children: String(year2)
}
);
});
})
}
),
/* @__PURE__ */ jsx(
"input",
{
hidden: true,
type: "date",
name: api.attribute.name.signal,
"attribute:form": api.attribute.form.signal,
"attribute:value": api.context.selectedDate.derive((d) => d.isoDate()),
"aria-hidden": "true"
}
)
] });
api.replace(html);
}).register();
var AdwCalendar = CustomElement;
export {
AdwCalendar
};