@expressive/ui 0.0.0-stage → 0.1.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.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +48 -2
  3. package/dist/button/base.d.ts +63 -0
  4. package/dist/button/base.js +90 -0
  5. package/dist/button/base.js.map +1 -0
  6. package/dist/button/button.d.ts +56 -0
  7. package/dist/button/button.js +138 -0
  8. package/dist/button/button.js.map +1 -0
  9. package/dist/calendar/base.d.ts +112 -0
  10. package/dist/calendar/base.js +235 -0
  11. package/dist/calendar/base.js.map +1 -0
  12. package/dist/calendar/calendar.d.ts +78 -0
  13. package/dist/calendar/calendar.js +145 -0
  14. package/dist/calendar/calendar.js.map +1 -0
  15. package/dist/calendar/date.js +56 -0
  16. package/dist/calendar/date.js.map +1 -0
  17. package/dist/dialog/base.d.ts +74 -0
  18. package/dist/dialog/base.js +143 -0
  19. package/dist/dialog/base.js.map +1 -0
  20. package/dist/dialog/dialog.d.ts +69 -0
  21. package/dist/dialog/dialog.js +108 -0
  22. package/dist/dialog/dialog.js.map +1 -0
  23. package/dist/dom.d.ts +16 -0
  24. package/dist/dom.js +17 -0
  25. package/dist/dropzone/base.d.ts +77 -0
  26. package/dist/dropzone/base.js +159 -0
  27. package/dist/dropzone/base.js.map +1 -0
  28. package/dist/dropzone/dropzone.d.ts +38 -0
  29. package/dist/dropzone/dropzone.js +92 -0
  30. package/dist/dropzone/dropzone.js.map +1 -0
  31. package/dist/form/base.d.ts +157 -0
  32. package/dist/form/base.js +243 -0
  33. package/dist/form/base.js.map +1 -0
  34. package/dist/form/form.d.ts +123 -0
  35. package/dist/form/form.js +179 -0
  36. package/dist/form/form.js.map +1 -0
  37. package/dist/icons/caret.d.ts +8 -0
  38. package/dist/icons/caret.js +16 -0
  39. package/dist/icons/caret.js.map +1 -0
  40. package/dist/icons/check.d.ts +8 -0
  41. package/dist/icons/check.js +16 -0
  42. package/dist/icons/check.js.map +1 -0
  43. package/dist/icons/cross.d.ts +8 -0
  44. package/dist/icons/cross.js +16 -0
  45. package/dist/icons/cross.js.map +1 -0
  46. package/dist/icons/icon.js +16 -0
  47. package/dist/icons/icon.js.map +1 -0
  48. package/dist/icons/spinner.d.ts +8 -0
  49. package/dist/icons/spinner.js +27 -0
  50. package/dist/icons/spinner.js.map +1 -0
  51. package/dist/icons/upload.d.ts +8 -0
  52. package/dist/icons/upload.js +16 -0
  53. package/dist/icons/upload.js.map +1 -0
  54. package/dist/index.d.ts +11 -0
  55. package/dist/index.js +12 -0
  56. package/dist/layout/base.d.ts +88 -0
  57. package/dist/layout/base.js +158 -0
  58. package/dist/layout/base.js.map +1 -0
  59. package/dist/layout/layout.d.ts +53 -0
  60. package/dist/layout/layout.js +80 -0
  61. package/dist/layout/layout.js.map +1 -0
  62. package/dist/piece.js +13 -0
  63. package/dist/piece.js.map +1 -0
  64. package/dist/popover/base.d.ts +94 -0
  65. package/dist/popover/base.js +176 -0
  66. package/dist/popover/base.js.map +1 -0
  67. package/dist/popover/place.d.ts +12 -0
  68. package/dist/popover/place.js +32 -0
  69. package/dist/popover/place.js.map +1 -0
  70. package/dist/popover/popover.d.ts +52 -0
  71. package/dist/popover/popover.js +104 -0
  72. package/dist/popover/popover.js.map +1 -0
  73. package/dist/select/base.d.ts +196 -0
  74. package/dist/select/base.js +409 -0
  75. package/dist/select/base.js.map +1 -0
  76. package/dist/select/select.d.ts +119 -0
  77. package/dist/select/select.js +219 -0
  78. package/dist/select/select.js.map +1 -0
  79. package/dist/table/base.d.ts +96 -0
  80. package/dist/table/base.js +154 -0
  81. package/dist/table/base.js.map +1 -0
  82. package/dist/table/column.d.ts +53 -0
  83. package/dist/table/column.js +29 -0
  84. package/dist/table/column.js.map +1 -0
  85. package/dist/table/table.d.ts +41 -0
  86. package/dist/table/table.js +101 -0
  87. package/dist/table/table.js.map +1 -0
  88. package/package.json +76 -4
@@ -0,0 +1,235 @@
1
+ import { missing } from "../piece.js";
2
+ import { addDays, addMonths, addYears, endOfMonth, endOfWeek, isSameDay, isSameMonth, startOfDay, startOfMonth, startOfWeek } from "./date.js";
3
+ import { Component, set } from "@expressive/mvc";
4
+ import { jsx, jsxs } from "@expressive/mvc/jsx-runtime";
5
+
6
+ //#region src/calendar/base.tsx
7
+ /**
8
+ * Month grid date picker behavior without a look: bounds, keyboard navigation, roving focus and ARIA, assembled
9
+ * from pieces.
10
+ *
11
+ * Every piece is a placeholder that throws when rendered - a skin assigns each one. Pieces spread the matching
12
+ * `*Props` getter onto their element to stay accessible. ARIA a skin writes itself: `role="row"` on `Row`,
13
+ * `role="columnheader"` on `Weekday`, and `aria-live="polite"` around the month title in `Header`.
14
+ */
15
+ var Calendar = class Calendar extends Component {
16
+ static months = [
17
+ "January",
18
+ "February",
19
+ "March",
20
+ "April",
21
+ "May",
22
+ "June",
23
+ "July",
24
+ "August",
25
+ "September",
26
+ "October",
27
+ "November",
28
+ "December"
29
+ ];
30
+ static weekdays = [
31
+ "Sunday",
32
+ "Monday",
33
+ "Tuesday",
34
+ "Wednesday",
35
+ "Thursday",
36
+ "Friday",
37
+ "Saturday"
38
+ ];
39
+ value = void 0;
40
+ onChange = void 0;
41
+ /** The day holding keyboard focus; its month is the one shown. Starts at `value` or today, within `min`/`max`. */
42
+ focus = set(() => clamp(new Date(this.value || /* @__PURE__ */ new Date()), this.min, this.max), () => {});
43
+ min = void 0;
44
+ max = void 0;
45
+ Root = missing("Calendar.Root");
46
+ Header = missing("Calendar.Header");
47
+ Grid = missing("Calendar.Grid");
48
+ Row = missing("Calendar.Row");
49
+ Weekday = missing("Calendar.Weekday");
50
+ Day = missing("Calendar.Day");
51
+ /** Month and year shown, e.g. "January 2024". */
52
+ get title() {
53
+ const { focus } = this;
54
+ return `${Calendar.months[focus.getMonth()]} ${focus.getFullYear()}`;
55
+ }
56
+ /** `false` when the step would cross a bound. */
57
+ get backMonth() {
58
+ const prev = addMonths(this.focus, -1);
59
+ const floor = bound(this.min);
60
+ if (floor && startOfMonth(prev) < startOfMonth(floor)) return false;
61
+ return () => this.focus = prev;
62
+ }
63
+ get nextMonth() {
64
+ const next = addMonths(this.focus, 1);
65
+ const ceil = bound(this.max);
66
+ if (ceil && startOfMonth(next) > ceil) return false;
67
+ return () => this.focus = next;
68
+ }
69
+ /** Whole weeks covering the focused month. */
70
+ get days() {
71
+ const { focus, value } = this;
72
+ const floor = bound(this.min);
73
+ const ceil = bound(this.max);
74
+ const end = endOfWeek(endOfMonth(focus));
75
+ const now = /* @__PURE__ */ new Date();
76
+ const days = [];
77
+ for (let d = startOfWeek(startOfMonth(focus)); d <= end; d = addDays(d, 1)) {
78
+ const at = d;
79
+ const disabled = floor && at < startOfDay(floor) || ceil && at > ceil || false;
80
+ days.push({
81
+ date: at,
82
+ display: at.getDate(),
83
+ isCurrentMonth: isSameMonth(at, focus),
84
+ isToday: isSameDay(at, now),
85
+ isPast: at < startOfDay(now),
86
+ focused: isSameDay(at, focus),
87
+ select: disabled ? false : () => this.select(at),
88
+ selected: value && isSameDay(value, at) || false
89
+ });
90
+ }
91
+ return days;
92
+ }
93
+ get months() {
94
+ const floor = bound(this.min);
95
+ const ceil = bound(this.max);
96
+ const year = this.focus.getFullYear();
97
+ return Calendar.months.map((label, value) => {
98
+ const date = new Date(year, value);
99
+ return {
100
+ value,
101
+ label,
102
+ disabled: floor && date < startOfMonth(floor) || ceil && date > ceil || false
103
+ };
104
+ });
105
+ }
106
+ get years() {
107
+ const start = bound(this.min) || addYears(/* @__PURE__ */ new Date(), -20);
108
+ const end = bound(this.max) || addYears(/* @__PURE__ */ new Date(), 20);
109
+ const from = start.getFullYear();
110
+ const to = end.getFullYear();
111
+ return Array.from({ length: Math.max(to + 1 - from, 0) }, (_, i) => ({
112
+ value: from + i,
113
+ label: String(from + i),
114
+ disabled: false
115
+ }));
116
+ }
117
+ get backProps() {
118
+ const { backMonth } = this;
119
+ return {
120
+ type: "button",
121
+ "aria-label": "Previous month",
122
+ disabled: !backMonth,
123
+ onClick: backMonth || void 0
124
+ };
125
+ }
126
+ get nextProps() {
127
+ const { nextMonth } = this;
128
+ return {
129
+ type: "button",
130
+ "aria-label": "Next month",
131
+ disabled: !nextMonth,
132
+ onClick: nextMonth || void 0
133
+ };
134
+ }
135
+ get gridProps() {
136
+ const { title } = this;
137
+ return {
138
+ role: "grid",
139
+ "aria-label": title,
140
+ onKeyDown: this.keyDown
141
+ };
142
+ }
143
+ /** For a day's element, with `outside`, `today` and `selected` for styling. Binds `claim` on the focused day. */
144
+ get dayProps() {
145
+ return (day) => {
146
+ const { date, select, selected, focused, isCurrentMonth, isToday } = day;
147
+ return {
148
+ outside: !isCurrentMonth,
149
+ today: isToday,
150
+ selected,
151
+ props: {
152
+ type: "button",
153
+ role: "gridcell",
154
+ "aria-label": date.toDateString(),
155
+ "aria-selected": selected,
156
+ "aria-current": isToday ? "date" : void 0,
157
+ tabIndex: focused ? 0 : -1,
158
+ ref: focused ? this.claim : void 0,
159
+ disabled: !select,
160
+ onClick: select || void 0
161
+ }
162
+ };
163
+ };
164
+ }
165
+ select(date) {
166
+ this.value = date;
167
+ this.focus = date;
168
+ if (this.onChange) this.onChange(date);
169
+ }
170
+ /** Move focus to `date`, clamped to `min`/`max`. */
171
+ move(date) {
172
+ this.focus = clamp(date, this.min, this.max);
173
+ }
174
+ keyDown(event) {
175
+ const { focus } = this;
176
+ const page = event.shiftKey ? 12 : 1;
177
+ switch (event.key) {
178
+ case "ArrowLeft":
179
+ this.move(addDays(focus, -1));
180
+ break;
181
+ case "ArrowRight":
182
+ this.move(addDays(focus, 1));
183
+ break;
184
+ case "ArrowUp":
185
+ this.move(addDays(focus, -7));
186
+ break;
187
+ case "ArrowDown":
188
+ this.move(addDays(focus, 7));
189
+ break;
190
+ case "Home":
191
+ this.move(startOfWeek(focus));
192
+ break;
193
+ case "End":
194
+ this.move(startOfDay(endOfWeek(focus)));
195
+ break;
196
+ case "PageUp":
197
+ this.move(addMonths(focus, -page));
198
+ break;
199
+ case "PageDown":
200
+ this.move(addMonths(focus, page));
201
+ break;
202
+ case "Enter":
203
+ case " ":
204
+ if (this.days.find((day) => day.focused).select) this.select(focus);
205
+ break;
206
+ default: return;
207
+ }
208
+ event.preventDefault();
209
+ NAVIGATING.add(this);
210
+ }
211
+ /** Ref for the focused day; moves focus to it after keyboard navigation. `dayProps` binds it. */
212
+ claim(element) {
213
+ if (element && NAVIGATING.delete(this)) element.focus();
214
+ }
215
+ render() {
216
+ const { days } = this;
217
+ const weeks = Array.from({ length: days.length / 7 }, (_, i) => days.slice(i * 7, i * 7 + 7));
218
+ return /* @__PURE__ */ jsxs(this.Root, { children: [/* @__PURE__ */ jsx(this.Header, {}), /* @__PURE__ */ jsxs(this.Grid, { children: [/* @__PURE__ */ jsx(this.Row, { children: Calendar.weekdays.map((name) => /* @__PURE__ */ jsx(this.Weekday, { name }, name)) }), weeks.map((week) => /* @__PURE__ */ jsx(this.Row, { children: week.map((day) => /* @__PURE__ */ jsx(this.Day, { day }, day.date.getTime())) }, week[0].date.getTime()))] })] });
219
+ }
220
+ };
221
+ const NAVIGATING = /* @__PURE__ */ new WeakSet();
222
+ function bound(from) {
223
+ return from === true ? /* @__PURE__ */ new Date() : from || void 0;
224
+ }
225
+ function clamp(date, min, max) {
226
+ const floor = bound(min);
227
+ const ceil = bound(max);
228
+ if (floor && date < startOfDay(floor)) return startOfDay(floor);
229
+ if (ceil && date > ceil) return startOfDay(ceil);
230
+ return date;
231
+ }
232
+
233
+ //#endregion
234
+ export { Calendar };
235
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","names":[],"sources":["../../src/calendar/base.tsx"],"sourcesContent":["import { Component, set } from '@expressive/mvc';\n\nimport { missing } from '../piece';\nimport {\n addDays,\n addMonths,\n addYears,\n endOfMonth,\n endOfWeek,\n isSameDay,\n isSameMonth,\n startOfDay,\n startOfMonth,\n startOfWeek\n} from './date';\n\ndeclare namespace Calendar {\n interface Day {\n date: Date;\n display: number;\n isCurrentMonth: boolean;\n isToday: boolean;\n isPast: boolean;\n selected: boolean;\n /** Holds keyboard focus within the grid. */\n focused: boolean;\n /** `false` when out of range. */\n select: false | (() => void);\n }\n\n interface Option {\n value: number;\n label: string;\n disabled: boolean;\n }\n\n /** A boundary date, or `true` for \"today\". */\n type Bound = Date | boolean | undefined;\n\n type Key = Pick<KeyboardEvent, 'key' | 'shiftKey' | 'preventDefault'>;\n\n type Wrap = (props: { children: Component.Node }) => Component.Node;\n type Each = (props: { day: Day }) => Component.Node;\n type Label = (props: { name: string }) => Component.Node;\n type Part = () => Component.Node;\n}\n\n/**\n * Month grid date picker behavior without a look: bounds, keyboard navigation, roving focus and ARIA, assembled\n * from pieces.\n *\n * Every piece is a placeholder that throws when rendered - a skin assigns each one. Pieces spread the matching\n * `*Props` getter onto their element to stay accessible. ARIA a skin writes itself: `role=\"row\"` on `Row`,\n * `role=\"columnheader\"` on `Weekday`, and `aria-live=\"polite\"` around the month title in `Header`.\n */\nclass Calendar extends Component {\n static months = [\n 'January', 'February', 'March', 'April', 'May', 'June',\n 'July', 'August', 'September', 'October', 'November', 'December'\n ];\n\n static weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n\n value?: Date = undefined;\n onChange?: (date: Date) => void = undefined;\n\n /** The day holding keyboard focus; its month is the one shown. Starts at `value` or today, within `min`/`max`. */\n focus = set(\n () => clamp(new Date(this.value || new Date()), this.min, this.max),\n () => {}\n );\n\n min: Calendar.Bound = undefined;\n max: Calendar.Bound = undefined;\n\n Root: Calendar.Wrap = missing('Calendar.Root');\n Header: Calendar.Part = missing('Calendar.Header');\n Grid: Calendar.Wrap = missing('Calendar.Grid');\n Row: Calendar.Wrap = missing('Calendar.Row');\n Weekday: Calendar.Label = missing('Calendar.Weekday');\n Day: Calendar.Each = missing('Calendar.Day');\n\n /** Month and year shown, e.g. \"January 2024\". */\n get title(): string {\n const { focus } = this;\n\n return `${Calendar.months[focus.getMonth()]} ${focus.getFullYear()}`;\n }\n\n /** `false` when the step would cross a bound. */\n get backMonth(): false | (() => void) {\n const prev = addMonths(this.focus, -1);\n const floor = bound(this.min);\n\n if (floor && startOfMonth(prev) < startOfMonth(floor)) return false;\n\n return () => (this.focus = prev);\n }\n\n get nextMonth(): false | (() => void) {\n const next = addMonths(this.focus, 1);\n const ceil = bound(this.max);\n\n if (ceil && startOfMonth(next) > ceil) return false;\n\n return () => (this.focus = next);\n }\n\n /** Whole weeks covering the focused month. */\n get days(): Calendar.Day[] {\n const { focus, value } = this;\n const floor = bound(this.min);\n const ceil = bound(this.max);\n const end = endOfWeek(endOfMonth(focus));\n const now = new Date();\n const days: Calendar.Day[] = [];\n\n for (let d = startOfWeek(startOfMonth(focus)); d <= end; d = addDays(d, 1)) {\n const at = d;\n const disabled = (floor && at < startOfDay(floor)) || (ceil && at > ceil) || false;\n\n days.push({\n date: at,\n display: at.getDate(),\n isCurrentMonth: isSameMonth(at, focus),\n isToday: isSameDay(at, now),\n isPast: at < startOfDay(now),\n focused: isSameDay(at, focus),\n select: disabled ? false : () => this.select(at),\n selected: (value && isSameDay(value, at)) || false\n });\n }\n\n return days;\n }\n\n get months(): Calendar.Option[] {\n const floor = bound(this.min);\n const ceil = bound(this.max);\n const year = this.focus.getFullYear();\n\n return Calendar.months.map((label, value) => {\n const date = new Date(year, value);\n\n return {\n value,\n label,\n disabled: (floor && date < startOfMonth(floor)) || (ceil && date > ceil) || false\n };\n });\n }\n\n get years(): Calendar.Option[] {\n const start = bound(this.min) || addYears(new Date(), -20);\n const end = bound(this.max) || addYears(new Date(), 20);\n const from = start.getFullYear();\n const to = end.getFullYear();\n\n return Array.from({ length: Math.max(to + 1 - from, 0) }, (_, i) => ({\n value: from + i,\n label: String(from + i),\n disabled: false\n }));\n }\n\n get backProps() {\n const { backMonth } = this;\n\n return {\n type: 'button',\n 'aria-label': 'Previous month',\n disabled: !backMonth,\n onClick: backMonth || undefined\n } as const;\n }\n\n get nextProps() {\n const { nextMonth } = this;\n\n return {\n type: 'button',\n 'aria-label': 'Next month',\n disabled: !nextMonth,\n onClick: nextMonth || undefined\n } as const;\n }\n\n get gridProps() {\n const { title } = this;\n\n return { role: 'grid', 'aria-label': title, onKeyDown: this.keyDown } as const;\n }\n\n /** For a day's element, with `outside`, `today` and `selected` for styling. Binds `claim` on the focused day. */\n get dayProps() {\n return (day: Calendar.Day) => {\n const { date, select, selected, focused, isCurrentMonth, isToday } = day;\n\n return {\n outside: !isCurrentMonth,\n today: isToday,\n selected,\n props: {\n type: 'button',\n role: 'gridcell',\n 'aria-label': date.toDateString(),\n 'aria-selected': selected,\n 'aria-current': isToday ? 'date' : undefined,\n tabIndex: focused ? 0 : -1,\n ref: focused ? this.claim : undefined,\n disabled: !select,\n onClick: select || undefined\n } as const\n };\n };\n }\n\n select(date: Date) {\n this.value = date;\n this.focus = date;\n\n if (this.onChange) this.onChange(date);\n }\n\n /** Move focus to `date`, clamped to `min`/`max`. */\n move(date: Date) {\n this.focus = clamp(date, this.min, this.max);\n }\n\n keyDown(event: Calendar.Key) {\n const { focus } = this;\n const page = event.shiftKey ? 12 : 1;\n\n switch (event.key) {\n case 'ArrowLeft': this.move(addDays(focus, -1)); break;\n case 'ArrowRight': this.move(addDays(focus, 1)); break;\n case 'ArrowUp': this.move(addDays(focus, -7)); break;\n case 'ArrowDown': this.move(addDays(focus, 7)); break;\n case 'Home': this.move(startOfWeek(focus)); break;\n case 'End': this.move(startOfDay(endOfWeek(focus))); break;\n case 'PageUp': this.move(addMonths(focus, -page)); break;\n case 'PageDown': this.move(addMonths(focus, page)); break;\n case 'Enter':\n case ' ': {\n const enabled = this.days.find((day) => day.focused)!.select;\n\n if (enabled) this.select(focus);\n break;\n }\n default:\n return;\n }\n\n event.preventDefault();\n NAVIGATING.add(this);\n }\n\n /** Ref for the focused day; moves focus to it after keyboard navigation. `dayProps` binds it. */\n claim(element: HTMLElement | null) {\n if (element && NAVIGATING.delete(this)) element.focus();\n }\n\n render(): Component.Node {\n const { days } = this;\n const weeks = Array.from({ length: days.length / 7 }, (_, i) => days.slice(i * 7, i * 7 + 7));\n\n return (\n <this.Root>\n <this.Header />\n <this.Grid>\n <this.Row>\n {Calendar.weekdays.map((name) => <this.Weekday key={name} name={name} />)}\n </this.Row>\n {weeks.map((week) => (\n <this.Row key={week[0].date.getTime()}>\n {week.map((day) => <this.Day key={day.date.getTime()} day={day} />)}\n </this.Row>\n ))}\n </this.Grid>\n </this.Root>\n );\n }\n}\n\nconst NAVIGATING = new WeakSet<Calendar>();\n\nfunction bound(from: Calendar.Bound) {\n return from === true ? new Date() : from || undefined;\n}\n\nfunction clamp(date: Date, min: Calendar.Bound, max: Calendar.Bound) {\n const floor = bound(min);\n const ceil = bound(max);\n\n if (floor && date < startOfDay(floor)) return startOfDay(floor);\n if (ceil && date > ceil) return startOfDay(ceil);\n\n return date;\n}\n\nexport { Calendar };\n"],"mappings":";;;;;;;;;;;;;;AAuDA,IAAM,WAAN,MAAM,iBAAiB,UAAU;CAC/B,OAAO,SAAS;EACd;EAAW;EAAY;EAAS;EAAS;EAAO;EAChD;EAAQ;EAAU;EAAa;EAAW;EAAY;EACvD;CAED,OAAO,WAAW;EAAC;EAAU;EAAU;EAAW;EAAa;EAAY;EAAU;EAAW;CAEhG,QAAe;CACf,WAAkC;;CAGlC,QAAQ,UACA,MAAM,IAAI,KAAK,KAAK,yBAAS,IAAI,MAAM,CAAC,EAAE,KAAK,KAAK,KAAK,IAAI,QAC7D,GACP;CAED,MAAsB;CACtB,MAAsB;CAEtB,OAAsB,QAAQ,gBAAgB;CAC9C,SAAwB,QAAQ,kBAAkB;CAClD,OAAsB,QAAQ,gBAAgB;CAC9C,MAAqB,QAAQ,eAAe;CAC5C,UAA0B,QAAQ,mBAAmB;CACrD,MAAqB,QAAQ,eAAe;;CAG5C,IAAI,QAAgB;EAClB,MAAM,EAAE,UAAU;AAElB,SAAO,GAAG,SAAS,OAAO,MAAM,UAAU,EAAE,GAAG,MAAM,aAAa;;;CAIpE,IAAI,YAAkC;EACpC,MAAM,OAAO,UAAU,KAAK,OAAO,GAAG;EACtC,MAAM,QAAQ,MAAM,KAAK,IAAI;AAE7B,MAAI,SAAS,aAAa,KAAK,GAAG,aAAa,MAAM,CAAE,QAAO;AAE9D,eAAc,KAAK,QAAQ;;CAG7B,IAAI,YAAkC;EACpC,MAAM,OAAO,UAAU,KAAK,OAAO,EAAE;EACrC,MAAM,OAAO,MAAM,KAAK,IAAI;AAE5B,MAAI,QAAQ,aAAa,KAAK,GAAG,KAAM,QAAO;AAE9C,eAAc,KAAK,QAAQ;;;CAI7B,IAAI,OAAuB;EACzB,MAAM,EAAE,OAAO,UAAU;EACzB,MAAM,QAAQ,MAAM,KAAK,IAAI;EAC7B,MAAM,OAAO,MAAM,KAAK,IAAI;EAC5B,MAAM,MAAM,UAAU,WAAW,MAAM,CAAC;EACxC,MAAM,sBAAM,IAAI,MAAM;EACtB,MAAM,OAAuB,EAAE;AAE/B,OAAK,IAAI,IAAI,YAAY,aAAa,MAAM,CAAC,EAAE,KAAK,KAAK,IAAI,QAAQ,GAAG,EAAE,EAAE;GAC1E,MAAM,KAAK;GACX,MAAM,WAAY,SAAS,KAAK,WAAW,MAAM,IAAM,QAAQ,KAAK,QAAS;AAE7E,QAAK,KAAK;IACR,MAAM;IACN,SAAS,GAAG,SAAS;IACrB,gBAAgB,YAAY,IAAI,MAAM;IACtC,SAAS,UAAU,IAAI,IAAI;IAC3B,QAAQ,KAAK,WAAW,IAAI;IAC5B,SAAS,UAAU,IAAI,MAAM;IAC7B,QAAQ,WAAW,cAAc,KAAK,OAAO,GAAG;IAChD,UAAW,SAAS,UAAU,OAAO,GAAG,IAAK;IAC9C,CAAC;;AAGJ,SAAO;;CAGT,IAAI,SAA4B;EAC9B,MAAM,QAAQ,MAAM,KAAK,IAAI;EAC7B,MAAM,OAAO,MAAM,KAAK,IAAI;EAC5B,MAAM,OAAO,KAAK,MAAM,aAAa;AAErC,SAAO,SAAS,OAAO,KAAK,OAAO,UAAU;GAC3C,MAAM,OAAO,IAAI,KAAK,MAAM,MAAM;AAElC,UAAO;IACL;IACA;IACA,UAAW,SAAS,OAAO,aAAa,MAAM,IAAM,QAAQ,OAAO,QAAS;IAC7E;IACD;;CAGJ,IAAI,QAA2B;EAC7B,MAAM,QAAQ,MAAM,KAAK,IAAI,IAAI,yBAAS,IAAI,MAAM,EAAE,IAAI;EAC1D,MAAM,MAAM,MAAM,KAAK,IAAI,IAAI,yBAAS,IAAI,MAAM,EAAE,GAAG;EACvD,MAAM,OAAO,MAAM,aAAa;EAChC,MAAM,KAAK,IAAI,aAAa;AAE5B,SAAO,MAAM,KAAK,EAAE,QAAQ,KAAK,IAAI,KAAK,IAAI,MAAM,EAAE,EAAE,GAAG,GAAG,OAAO;GACnE,OAAO,OAAO;GACd,OAAO,OAAO,OAAO,EAAE;GACvB,UAAU;GACX,EAAE;;CAGL,IAAI,YAAY;EACd,MAAM,EAAE,cAAc;AAEtB,SAAO;GACL,MAAM;GACN,cAAc;GACd,UAAU,CAAC;GACX,SAAS,aAAa;GACvB;;CAGH,IAAI,YAAY;EACd,MAAM,EAAE,cAAc;AAEtB,SAAO;GACL,MAAM;GACN,cAAc;GACd,UAAU,CAAC;GACX,SAAS,aAAa;GACvB;;CAGH,IAAI,YAAY;EACd,MAAM,EAAE,UAAU;AAElB,SAAO;GAAE,MAAM;GAAQ,cAAc;GAAO,WAAW,KAAK;GAAS;;;CAIvE,IAAI,WAAW;AACb,UAAQ,QAAsB;GAC5B,MAAM,EAAE,MAAM,QAAQ,UAAU,SAAS,gBAAgB,YAAY;AAErE,UAAO;IACL,SAAS,CAAC;IACV,OAAO;IACP;IACA,OAAO;KACL,MAAM;KACN,MAAM;KACN,cAAc,KAAK,cAAc;KACjC,iBAAiB;KACjB,gBAAgB,UAAU,SAAS;KACnC,UAAU,UAAU,IAAI;KACxB,KAAK,UAAU,KAAK,QAAQ;KAC5B,UAAU,CAAC;KACX,SAAS,UAAU;KACpB;IACF;;;CAIL,OAAO,MAAY;AACjB,OAAK,QAAQ;AACb,OAAK,QAAQ;AAEb,MAAI,KAAK,SAAU,MAAK,SAAS,KAAK;;;CAIxC,KAAK,MAAY;AACf,OAAK,QAAQ,MAAM,MAAM,KAAK,KAAK,KAAK,IAAI;;CAG9C,QAAQ,OAAqB;EAC3B,MAAM,EAAE,UAAU;EAClB,MAAM,OAAO,MAAM,WAAW,KAAK;AAEnC,UAAQ,MAAM,KAAd;GACE,KAAK;AAAa,SAAK,KAAK,QAAQ,OAAO,GAAG,CAAC;AAAE;GACjD,KAAK;AAAc,SAAK,KAAK,QAAQ,OAAO,EAAE,CAAC;AAAE;GACjD,KAAK;AAAW,SAAK,KAAK,QAAQ,OAAO,GAAG,CAAC;AAAE;GAC/C,KAAK;AAAa,SAAK,KAAK,QAAQ,OAAO,EAAE,CAAC;AAAE;GAChD,KAAK;AAAQ,SAAK,KAAK,YAAY,MAAM,CAAC;AAAE;GAC5C,KAAK;AAAO,SAAK,KAAK,WAAW,UAAU,MAAM,CAAC,CAAC;AAAE;GACrD,KAAK;AAAU,SAAK,KAAK,UAAU,OAAO,CAAC,KAAK,CAAC;AAAE;GACnD,KAAK;AAAY,SAAK,KAAK,UAAU,OAAO,KAAK,CAAC;AAAE;GACpD,KAAK;GACL,KAAK;AAGH,QAFgB,KAAK,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAE,OAEzC,MAAK,OAAO,MAAM;AAC/B;GAEF,QACE;;AAGJ,QAAM,gBAAgB;AACtB,aAAW,IAAI,KAAK;;;CAItB,MAAM,SAA6B;AACjC,MAAI,WAAW,WAAW,OAAO,KAAK,CAAE,SAAQ,OAAO;;CAGzD,SAAyB;EACvB,MAAM,EAAE,SAAS;EACjB,MAAM,QAAQ,MAAM,KAAK,EAAE,QAAQ,KAAK,SAAS,GAAG,GAAG,GAAG,MAAM,KAAK,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;AAE7F,SACE,qBAAC,KAAK,mBACJ,oBAAC,KAAK,WAAS,EACf,qBAAC,KAAK,mBACJ,oBAAC,KAAK,iBACH,SAAS,SAAS,KAAK,SAAS,oBAAC,KAAK,WAAyB,QAAZ,KAAoB,CAAC,GAChE,EACV,MAAM,KAAK,SACV,oBAAC,KAAK,iBACH,KAAK,KAAK,QAAQ,oBAAC,KAAK,OAAkC,OAAzB,IAAI,KAAK,SAAS,CAAc,CAAC,IADtD,KAAK,GAAG,KAAK,SAAS,CAE1B,CACX,IACQ,IACF;;;AAKlB,MAAM,6BAAa,IAAI,SAAmB;AAE1C,SAAS,MAAM,MAAsB;AACnC,QAAO,SAAS,uBAAO,IAAI,MAAM,GAAG,QAAQ;;AAG9C,SAAS,MAAM,MAAY,KAAqB,KAAqB;CACnE,MAAM,QAAQ,MAAM,IAAI;CACxB,MAAM,OAAO,MAAM,IAAI;AAEvB,KAAI,SAAS,OAAO,WAAW,MAAM,CAAE,QAAO,WAAW,MAAM;AAC/D,KAAI,QAAQ,OAAO,KAAM,QAAO,WAAW,KAAK;AAEhD,QAAO"}
@@ -0,0 +1,78 @@
1
+ import { Calendar as Calendar$1 } from "./base.js";
2
+ import { Component } from "@expressive/mvc";
3
+
4
+ //#region src/calendar/calendar.d.ts
5
+ declare namespace Calendar {
6
+ type Day = Calendar$1.Day;
7
+ type Option = Calendar$1.Option;
8
+ type Bound = Calendar$1.Bound;
9
+ type Key = Calendar$1.Key;
10
+ }
11
+ /**
12
+ * Month grid date picker with bounds and keyboard navigation.
13
+ *
14
+ * Arrows move a day or a week, Home/End to the week's edge, PageUp/PageDown a month (a year with Shift); Enter or
15
+ * Space selects. Pieces - `Root`, `Header`, `Grid`, `Row`, `Weekday`, `Day` - are function components reading
16
+ * `Calendar.get()`, each styled on its own; pass one as a prop or assign it in a subclass to replace it. Stock
17
+ * pieces are statics. A replacement `Day` spreads `dayProps(day).props` to keep roving focus.
18
+ *
19
+ * @example
20
+ * <Calendar min value={this.date} onChange={(date) => (this.date = date)} />
21
+ */
22
+ declare class Calendar extends Calendar$1 {
23
+ static Root: ({
24
+ children
25
+ }: {
26
+ children: Component.Node;
27
+ }) => Component.Node;
28
+ static Header: () => Component.Node;
29
+ static Grid: ({
30
+ children
31
+ }: {
32
+ children: Component.Node;
33
+ }) => Component.Node;
34
+ static Row: ({
35
+ children
36
+ }: {
37
+ children: Component.Node;
38
+ }) => Component.Node;
39
+ static Weekday: ({
40
+ name
41
+ }: {
42
+ name: string;
43
+ }) => Component.Node;
44
+ static Day: ({
45
+ day
46
+ }: {
47
+ day: Calendar.Day;
48
+ }) => Component.Node;
49
+ Root: ({
50
+ children
51
+ }: {
52
+ children: Component.Node;
53
+ }) => Component.Node;
54
+ Header: () => Component.Node;
55
+ Grid: ({
56
+ children
57
+ }: {
58
+ children: Component.Node;
59
+ }) => Component.Node;
60
+ Row: ({
61
+ children
62
+ }: {
63
+ children: Component.Node;
64
+ }) => Component.Node;
65
+ Weekday: ({
66
+ name
67
+ }: {
68
+ name: string;
69
+ }) => Component.Node;
70
+ Day: ({
71
+ day
72
+ }: {
73
+ day: Calendar.Day;
74
+ }) => Component.Node;
75
+ }
76
+ //#endregion
77
+ export { Calendar };
78
+ //# sourceMappingURL=calendar.d.ts.map
@@ -0,0 +1,145 @@
1
+ import { Calendar as Calendar$1 } from "./base.js";
2
+ import { Caret } from "../icons/caret.js";
3
+ import { style } from "@expressive/dom";
4
+ import { jsx, jsxs } from "@expressive/dom/jsx-runtime";
5
+
6
+ //#region src/calendar/calendar.tsx
7
+ const Root = ({ children }) => /* @__PURE__ */ jsx("div", { children });
8
+ style(Root, {
9
+ display: "inline-flex",
10
+ flexDirection: "column",
11
+ gap: "8px",
12
+ padding: "12px",
13
+ background: "var(--ui-surface, #fff)",
14
+ border: "1px solid var(--ui-line, #ccc)",
15
+ borderRadius: "8px",
16
+ userSelect: "none"
17
+ });
18
+ const square = {
19
+ display: "grid",
20
+ placeItems: "center",
21
+ width: "36px",
22
+ height: "36px",
23
+ padding: "0",
24
+ border: "0",
25
+ borderRadius: "4px",
26
+ background: "none",
27
+ color: "inherit",
28
+ font: "inherit"
29
+ };
30
+ const Header = () => {
31
+ const { title, backProps, nextProps } = Calendar$1.get();
32
+ return /* @__PURE__ */ jsxs("div", { children: [
33
+ /* @__PURE__ */ jsx("button", {
34
+ ...backProps,
35
+ children: /* @__PURE__ */ jsx(Caret, { _back: true })
36
+ }),
37
+ /* @__PURE__ */ jsx("span", {
38
+ "aria-live": "polite",
39
+ children: title
40
+ }),
41
+ /* @__PURE__ */ jsx("button", {
42
+ ...nextProps,
43
+ children: /* @__PURE__ */ jsx(Caret, { _next: true })
44
+ })
45
+ ] });
46
+ };
47
+ style(Header, {
48
+ display: "flex",
49
+ alignItems: "center",
50
+ justifyContent: "space-between",
51
+ fontWeight: "600",
52
+ _button: [square, {
53
+ cursor: "pointer",
54
+ color: "var(--ui-muted, #999)",
55
+ ":disabled": {
56
+ opacity: "0.3",
57
+ cursor: "default"
58
+ }
59
+ }],
60
+ _back: { transform: "rotate(90deg)" },
61
+ _next: { transform: "rotate(-90deg)" }
62
+ });
63
+ const Grid = ({ children }) => /* @__PURE__ */ jsx("div", {
64
+ ...Calendar$1.get().gridProps,
65
+ children
66
+ });
67
+ const Row = ({ children }) => /* @__PURE__ */ jsx("div", {
68
+ role: "row",
69
+ children
70
+ });
71
+ style(Row, {
72
+ display: "grid",
73
+ gridTemplateColumns: "repeat(7, 36px)",
74
+ gap: "2px"
75
+ });
76
+ const Weekday = ({ name }) => /* @__PURE__ */ jsx("abbr", {
77
+ role: "columnheader",
78
+ title: name,
79
+ children: name.slice(0, 2)
80
+ });
81
+ style(Weekday, {
82
+ display: "grid",
83
+ placeItems: "center",
84
+ height: "28px",
85
+ color: "var(--ui-muted, #999)",
86
+ fontSize: "12px",
87
+ textDecoration: "none"
88
+ });
89
+ const Day = ({ day }) => {
90
+ const { outside, today, selected, props } = Calendar$1.get().dayProps(day);
91
+ return /* @__PURE__ */ jsx("button", {
92
+ ...props,
93
+ _outside: outside,
94
+ _today: today,
95
+ _selected: selected,
96
+ children: day.display
97
+ });
98
+ };
99
+ style(Day, square, {
100
+ cursor: "pointer",
101
+ ":hover": { background: "var(--ui-highlight, #deebff)" },
102
+ _outside: { opacity: "0.45" },
103
+ _today: {
104
+ fontWeight: "700",
105
+ boxShadow: "inset 0 0 0 1px var(--ui-line, #ccc)"
106
+ },
107
+ _selected: {
108
+ background: "var(--ui-accent, #2684ff)",
109
+ color: "#fff"
110
+ },
111
+ ":disabled": {
112
+ opacity: "0.3",
113
+ cursor: "default",
114
+ background: "none"
115
+ }
116
+ });
117
+ /**
118
+ * Month grid date picker with bounds and keyboard navigation.
119
+ *
120
+ * Arrows move a day or a week, Home/End to the week's edge, PageUp/PageDown a month (a year with Shift); Enter or
121
+ * Space selects. Pieces - `Root`, `Header`, `Grid`, `Row`, `Weekday`, `Day` - are function components reading
122
+ * `Calendar.get()`, each styled on its own; pass one as a prop or assign it in a subclass to replace it. Stock
123
+ * pieces are statics. A replacement `Day` spreads `dayProps(day).props` to keep roving focus.
124
+ *
125
+ * @example
126
+ * <Calendar min value={this.date} onChange={(date) => (this.date = date)} />
127
+ */
128
+ var Calendar = class extends Calendar$1 {
129
+ static Root = Root;
130
+ static Header = Header;
131
+ static Grid = Grid;
132
+ static Row = Row;
133
+ static Weekday = Weekday;
134
+ static Day = Day;
135
+ Root = Root;
136
+ Header = Header;
137
+ Grid = Grid;
138
+ Row = Row;
139
+ Weekday = Weekday;
140
+ Day = Day;
141
+ };
142
+
143
+ //#endregion
144
+ export { Calendar };
145
+ //# sourceMappingURL=calendar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calendar.js","names":["Base.Calendar"],"sources":["../../src/calendar/calendar.tsx"],"sourcesContent":["/** @jsxImportSource @expressive/dom */\nimport { Component } from '@expressive/mvc';\nimport { style } from '@expressive/dom';\n\nimport { Caret } from '../icons';\nimport * as Base from './base';\n\ndeclare namespace Calendar {\n type Day = Base.Calendar.Day;\n type Option = Base.Calendar.Option;\n type Bound = Base.Calendar.Bound;\n type Key = Base.Calendar.Key;\n}\n\nconst Root = ({ children }: { children: Component.Node }): Component.Node => <div>{children}</div>;\n\nstyle(Root, {\n display: 'inline-flex',\n flexDirection: 'column',\n gap: '8px',\n padding: '12px',\n background: 'var(--ui-surface, #fff)',\n border: '1px solid var(--ui-line, #ccc)',\n borderRadius: '8px',\n userSelect: 'none'\n});\n\nconst square = {\n display: 'grid',\n placeItems: 'center',\n width: '36px',\n height: '36px',\n padding: '0',\n border: '0',\n borderRadius: '4px',\n background: 'none',\n color: 'inherit',\n font: 'inherit'\n};\n\nconst Header = (): Component.Node => {\n const { title, backProps, nextProps } = Base.Calendar.get();\n\n return (\n <div>\n <button {...backProps}>\n <Caret _back />\n </button>\n <span aria-live=\"polite\">{title}</span>\n <button {...nextProps}>\n <Caret _next />\n </button>\n </div>\n );\n};\n\nstyle(Header, {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n fontWeight: '600',\n _button: [square, {\n cursor: 'pointer',\n color: 'var(--ui-muted, #999)',\n ':disabled': {\n opacity: '0.3',\n cursor: 'default'\n }\n }],\n _back: {\n transform: 'rotate(90deg)'\n },\n _next: {\n transform: 'rotate(-90deg)'\n }\n});\n\nconst Grid = ({ children }: { children: Component.Node }): Component.Node => (\n <div {...Base.Calendar.get().gridProps}>{children}</div>\n);\n\nconst Row = ({ children }: { children: Component.Node }): Component.Node => (\n <div role=\"row\">{children}</div>\n);\n\nstyle(Row, {\n display: 'grid',\n gridTemplateColumns: 'repeat(7, 36px)',\n gap: '2px'\n});\n\nconst Weekday = ({ name }: { name: string }): Component.Node => (\n <abbr role=\"columnheader\" title={name}>{name.slice(0, 2)}</abbr>\n);\n\nstyle(Weekday, {\n display: 'grid',\n placeItems: 'center',\n height: '28px',\n color: 'var(--ui-muted, #999)',\n fontSize: '12px',\n textDecoration: 'none'\n});\n\nconst Day = ({ day }: { day: Calendar.Day }): Component.Node => {\n const { outside, today, selected, props } = Base.Calendar.get().dayProps(day);\n\n return (\n <button {...props} _outside={outside} _today={today} _selected={selected}>\n {day.display}\n </button>\n );\n};\n\nstyle(Day, square, {\n cursor: 'pointer',\n ':hover': {\n background: 'var(--ui-highlight, #deebff)'\n },\n _outside: {\n opacity: '0.45'\n },\n _today: {\n fontWeight: '700',\n boxShadow: 'inset 0 0 0 1px var(--ui-line, #ccc)'\n },\n _selected: {\n background: 'var(--ui-accent, #2684ff)',\n color: '#fff'\n },\n ':disabled': {\n opacity: '0.3',\n cursor: 'default',\n background: 'none'\n }\n});\n\n/**\n * Month grid date picker with bounds and keyboard navigation.\n *\n * Arrows move a day or a week, Home/End to the week's edge, PageUp/PageDown a month (a year with Shift); Enter or\n * Space selects. Pieces - `Root`, `Header`, `Grid`, `Row`, `Weekday`, `Day` - are function components reading\n * `Calendar.get()`, each styled on its own; pass one as a prop or assign it in a subclass to replace it. Stock\n * pieces are statics. A replacement `Day` spreads `dayProps(day).props` to keep roving focus.\n *\n * @example\n * <Calendar min value={this.date} onChange={(date) => (this.date = date)} />\n */\nclass Calendar extends Base.Calendar {\n static Root = Root;\n static Header = Header;\n static Grid = Grid;\n static Row = Row;\n static Weekday = Weekday;\n static Day = Day;\n\n Root = Root;\n Header = Header;\n Grid = Grid;\n Row = Row;\n Weekday = Weekday;\n Day = Day;\n}\n\nexport { Calendar, Day, Grid, Header, Root, Row, Weekday };\n"],"mappings":";;;;;;AAcA,MAAM,QAAQ,EAAE,eAA6D,oBAAC,SAAK,WAAe;AAElG,MAAM,MAAM;CACV,SAAS;CACT,eAAe;CACf,KAAK;CACL,SAAS;CACT,YAAY;CACZ,QAAQ;CACR,cAAc;CACd,YAAY;CACb,CAAC;AAEF,MAAM,SAAS;CACb,SAAS;CACT,YAAY;CACZ,OAAO;CACP,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,cAAc;CACd,YAAY;CACZ,OAAO;CACP,MAAM;CACP;AAED,MAAM,eAA+B;CACnC,MAAM,EAAE,OAAO,WAAW,yBAA4B,KAAK;AAE3D,QACE,qBAAC;EACC,oBAAC;GAAO,GAAI;aACV,oBAAC,SAAM,cAAQ;IACR;EACT,oBAAC;GAAK,aAAU;aAAU;IAAa;EACvC,oBAAC;GAAO,GAAI;aACV,oBAAC,SAAM,cAAQ;IACR;KACL;;AAIV,MAAM,QAAQ;CACZ,SAAS;CACT,YAAY;CACZ,gBAAgB;CAChB,YAAY;CACZ,SAAS,CAAC,QAAQ;EAChB,QAAQ;EACR,OAAO;EACP,aAAa;GACX,SAAS;GACT,QAAQ;GACT;EACF,CAAC;CACF,OAAO,EACL,WAAW,iBACZ;CACD,OAAO,EACL,WAAW,kBACZ;CACF,CAAC;AAEF,MAAM,QAAQ,EAAE,eACd,oBAAC;CAAI,cAAkB,KAAK,CAAC;CAAY;EAAe;AAG1D,MAAM,OAAO,EAAE,eACb,oBAAC;CAAI,MAAK;CAAO;EAAe;AAGlC,MAAM,KAAK;CACT,SAAS;CACT,qBAAqB;CACrB,KAAK;CACN,CAAC;AAEF,MAAM,WAAW,EAAE,WACjB,oBAAC;CAAK,MAAK;CAAe,OAAO;WAAO,KAAK,MAAM,GAAG,EAAE;EAAQ;AAGlE,MAAM,SAAS;CACb,SAAS;CACT,YAAY;CACZ,QAAQ;CACR,OAAO;CACP,UAAU;CACV,gBAAgB;CACjB,CAAC;AAEF,MAAM,OAAO,EAAE,UAAiD;CAC9D,MAAM,EAAE,SAAS,OAAO,UAAU,qBAAwB,KAAK,CAAC,SAAS,IAAI;AAE7E,QACE,oBAAC;EAAO,GAAI;EAAO,UAAU;EAAS,QAAQ;EAAO,WAAW;YAC7D,IAAI;GACE;;AAIb,MAAM,KAAK,QAAQ;CACjB,QAAQ;CACR,UAAU,EACR,YAAY,gCACb;CACD,UAAU,EACR,SAAS,QACV;CACD,QAAQ;EACN,YAAY;EACZ,WAAW;EACZ;CACD,WAAW;EACT,YAAY;EACZ,OAAO;EACR;CACD,aAAa;EACX,SAAS;EACT,QAAQ;EACR,YAAY;EACb;CACF,CAAC;;;;;;;;;;;;AAaF,IAAM,WAAN,cAAuBA,WAAc;CACnC,OAAO,OAAO;CACd,OAAO,SAAS;CAChB,OAAO,OAAO;CACd,OAAO,MAAM;CACb,OAAO,UAAU;CACjB,OAAO,MAAM;CAEb,OAAO;CACP,SAAS;CACT,OAAO;CACP,MAAM;CACN,UAAU;CACV,MAAM"}
@@ -0,0 +1,56 @@
1
+ //#region src/calendar/date.ts
2
+ function startOfDay(from) {
3
+ const date = new Date(from);
4
+ date.setHours(0, 0, 0, 0);
5
+ return date;
6
+ }
7
+ function startOfMonth(from) {
8
+ const date = startOfDay(from);
9
+ date.setDate(1);
10
+ return date;
11
+ }
12
+ function endOfMonth(from) {
13
+ const date = startOfMonth(from);
14
+ date.setMonth(date.getMonth() + 1);
15
+ return /* @__PURE__ */ new Date(date.getTime() - 1);
16
+ }
17
+ function startOfWeek(from) {
18
+ const date = startOfDay(from);
19
+ date.setDate(date.getDate() - date.getDay());
20
+ return date;
21
+ }
22
+ function endOfWeek(from) {
23
+ const date = startOfWeek(from);
24
+ date.setDate(date.getDate() + 7);
25
+ return /* @__PURE__ */ new Date(date.getTime() - 1);
26
+ }
27
+ function addDays(from, count) {
28
+ const date = new Date(from);
29
+ date.setDate(date.getDate() + count);
30
+ return date;
31
+ }
32
+ /** Clamps to the last valid day when the target month is shorter. */
33
+ function addMonths(from, count) {
34
+ const date = new Date(from);
35
+ const day = date.getDate();
36
+ date.setDate(1);
37
+ date.setMonth(date.getMonth() + count);
38
+ date.setDate(Math.min(day, daysInMonth(date)));
39
+ return date;
40
+ }
41
+ function addYears(from, count) {
42
+ return addMonths(from, count * 12);
43
+ }
44
+ function isSameDay(a, b) {
45
+ return startOfDay(a).getTime() === startOfDay(b).getTime();
46
+ }
47
+ function isSameMonth(a, b) {
48
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();
49
+ }
50
+ function daysInMonth(of) {
51
+ return new Date(of.getFullYear(), of.getMonth() + 1, 0).getDate();
52
+ }
53
+
54
+ //#endregion
55
+ export { addDays, addMonths, addYears, endOfMonth, endOfWeek, isSameDay, isSameMonth, startOfDay, startOfMonth, startOfWeek };
56
+ //# sourceMappingURL=date.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date.js","names":[],"sources":["../../src/calendar/date.ts"],"sourcesContent":["export function startOfDay(from: Date) {\n const date = new Date(from);\n date.setHours(0, 0, 0, 0);\n return date;\n}\n\nexport function startOfMonth(from: Date) {\n const date = startOfDay(from);\n date.setDate(1);\n return date;\n}\n\nexport function endOfMonth(from: Date) {\n const date = startOfMonth(from);\n date.setMonth(date.getMonth() + 1);\n return new Date(date.getTime() - 1);\n}\n\nexport function startOfWeek(from: Date) {\n const date = startOfDay(from);\n date.setDate(date.getDate() - date.getDay());\n return date;\n}\n\nexport function endOfWeek(from: Date) {\n const date = startOfWeek(from);\n date.setDate(date.getDate() + 7);\n return new Date(date.getTime() - 1);\n}\n\nexport function addDays(from: Date, count: number) {\n const date = new Date(from);\n date.setDate(date.getDate() + count);\n return date;\n}\n\n/** Clamps to the last valid day when the target month is shorter. */\nexport function addMonths(from: Date, count: number) {\n const date = new Date(from);\n const day = date.getDate();\n\n date.setDate(1);\n date.setMonth(date.getMonth() + count);\n date.setDate(Math.min(day, daysInMonth(date)));\n\n return date;\n}\n\nexport function addYears(from: Date, count: number) {\n return addMonths(from, count * 12);\n}\n\nexport function isSameDay(a: Date, b: Date) {\n return startOfDay(a).getTime() === startOfDay(b).getTime();\n}\n\nexport function isSameMonth(a: Date, b: Date) {\n return (\n a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth()\n );\n}\n\nfunction daysInMonth(of: Date) {\n return new Date(of.getFullYear(), of.getMonth() + 1, 0).getDate();\n}\n"],"mappings":";AAAA,SAAgB,WAAW,MAAY;CACrC,MAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,MAAK,SAAS,GAAG,GAAG,GAAG,EAAE;AACzB,QAAO;;AAGT,SAAgB,aAAa,MAAY;CACvC,MAAM,OAAO,WAAW,KAAK;AAC7B,MAAK,QAAQ,EAAE;AACf,QAAO;;AAGT,SAAgB,WAAW,MAAY;CACrC,MAAM,OAAO,aAAa,KAAK;AAC/B,MAAK,SAAS,KAAK,UAAU,GAAG,EAAE;AAClC,wBAAO,IAAI,KAAK,KAAK,SAAS,GAAG,EAAE;;AAGrC,SAAgB,YAAY,MAAY;CACtC,MAAM,OAAO,WAAW,KAAK;AAC7B,MAAK,QAAQ,KAAK,SAAS,GAAG,KAAK,QAAQ,CAAC;AAC5C,QAAO;;AAGT,SAAgB,UAAU,MAAY;CACpC,MAAM,OAAO,YAAY,KAAK;AAC9B,MAAK,QAAQ,KAAK,SAAS,GAAG,EAAE;AAChC,wBAAO,IAAI,KAAK,KAAK,SAAS,GAAG,EAAE;;AAGrC,SAAgB,QAAQ,MAAY,OAAe;CACjD,MAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,MAAK,QAAQ,KAAK,SAAS,GAAG,MAAM;AACpC,QAAO;;;AAIT,SAAgB,UAAU,MAAY,OAAe;CACnD,MAAM,OAAO,IAAI,KAAK,KAAK;CAC3B,MAAM,MAAM,KAAK,SAAS;AAE1B,MAAK,QAAQ,EAAE;AACf,MAAK,SAAS,KAAK,UAAU,GAAG,MAAM;AACtC,MAAK,QAAQ,KAAK,IAAI,KAAK,YAAY,KAAK,CAAC,CAAC;AAE9C,QAAO;;AAGT,SAAgB,SAAS,MAAY,OAAe;AAClD,QAAO,UAAU,MAAM,QAAQ,GAAG;;AAGpC,SAAgB,UAAU,GAAS,GAAS;AAC1C,QAAO,WAAW,EAAE,CAAC,SAAS,KAAK,WAAW,EAAE,CAAC,SAAS;;AAG5D,SAAgB,YAAY,GAAS,GAAS;AAC5C,QACE,EAAE,aAAa,KAAK,EAAE,aAAa,IAAI,EAAE,UAAU,KAAK,EAAE,UAAU;;AAIxE,SAAS,YAAY,IAAU;AAC7B,QAAO,IAAI,KAAK,GAAG,aAAa,EAAE,GAAG,UAAU,GAAG,GAAG,EAAE,CAAC,SAAS"}
@@ -0,0 +1,74 @@
1
+ import { Component, Model } from "@expressive/mvc";
2
+
3
+ //#region src/dialog/base.d.ts
4
+ declare namespace Dialog {
5
+ type Wrap = (props: {
6
+ children: Component.Node;
7
+ }) => Component.Node;
8
+ type Part = () => Component.Node;
9
+ type Key = Pick<KeyboardEvent, 'key' | 'shiftKey' | 'preventDefault'>;
10
+ }
11
+ /**
12
+ * Modal dialog behavior without a look: focus trap and restore, scroll lock, dismissal and ARIA, assembled from pieces.
13
+ *
14
+ * Every visible piece is a placeholder that throws when rendered - a skin assigns each one it renders. `Layer` renders
15
+ * in place by default; a skin replaces it to move the dialog out of the page. Pieces spread the matching `*Props`
16
+ * getter onto their element to stay accessible.
17
+ */
18
+ declare class Dialog extends Component {
19
+ open: boolean;
20
+ onClose?: () => void;
21
+ /** Heading, and the dialog's accessible name. */
22
+ title?: string;
23
+ /** Whether Escape, the backdrop and the close button dismiss. */
24
+ dismissible: boolean;
25
+ /** Prefixes the heading id. */
26
+ id: string;
27
+ Layer: Dialog.Wrap;
28
+ Backdrop: Dialog.Wrap;
29
+ Panel: Dialog.Wrap;
30
+ Header: Dialog.Wrap;
31
+ Title: Dialog.Part;
32
+ Close: Dialog.Part;
33
+ constructor(...args: Model.Args);
34
+ /** For the backdrop: a press that starts and ends on it closes. */
35
+ get backdropProps(): {
36
+ onMouseDown: (event: MouseEvent) => void;
37
+ onClick: (event: MouseEvent) => void;
38
+ };
39
+ get panelProps(): {
40
+ readonly ref: (panel: HTMLElement | null) => void;
41
+ readonly id: `${string}-panel`;
42
+ readonly role: "dialog";
43
+ readonly 'aria-modal': "true";
44
+ readonly 'aria-labelledby': string | undefined;
45
+ readonly tabIndex: -1;
46
+ };
47
+ get titleProps(): {
48
+ id: string;
49
+ };
50
+ get closeProps(): {
51
+ readonly type: "button";
52
+ readonly 'aria-label': "Close";
53
+ readonly onClick: () => void;
54
+ };
55
+ /** Ask to close; ignored unless `dismissible`. */
56
+ close(): void;
57
+ /** Escape closes; Tab goes to `trap`. Ignored unless this is the topmost open dialog. */
58
+ protected keyDown(event: Dialog.Key): void;
59
+ /** Send keys pressed anywhere to `keyDown` while open; returns the release. Defaults to `document`. */
60
+ protected listen(): () => void;
61
+ /** Stop the page behind from scrolling while open; returns the release. Defaults to the body's `overflow`. */
62
+ protected lock(): () => void;
63
+ /** Keep Tab focus inside the panel, wrapping at either end. Defaults to the DOM's focusable elements. */
64
+ protected trap(event: Dialog.Key): void;
65
+ private enter;
66
+ /** Ref for the panel, in `panelProps`; focuses it, or its `autofocus` element. */
67
+ focusIn(panel: HTMLElement | null): void;
68
+ render(props: {
69
+ children?: Component.Node;
70
+ }): Component.Node;
71
+ }
72
+ //#endregion
73
+ export { Dialog };
74
+ //# sourceMappingURL=base.d.ts.map