@htmlbricks/hb-calendar-events 0.71.35 → 0.71.36

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 (3) hide show
  1. package/README.md +168 -27
  2. package/manifest.json +54 -19
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,45 +1,186 @@
1
- ## `hb-calendar-events` calendar-events
1
+ # `hb-calendar-events` (calendar-events)
2
2
 
3
- **Category:** calendar | **Tags:** calendar
3
+ **Category:** calendar · **Tags:** calendar · **Package:** `@htmlbricks/hb-calendar-events`
4
4
 
5
- ### What it does
5
+ ## Summary
6
6
 
7
- Classic month grid (7-day week header and variable rows) with selectable cells,todaystyling, and event chips inside each day. Supports adjacent-month padding cells, Italian holidays, JSON `events`, and the same navigation/selection events as the appointments calendar.
7
+ `hb-calendar-events` is a Bulma-styled **month calendar** rendered as a full-width table: a **localized weekday header** (short names, order **Monday → Sunday**), a **variable number of week rows**, and **per-day cells** that can show **muted paddingdays** from the previous/next month. Users can **change the visible month**, **select a day** (current month or padding cells), and **click small event chips** mapped from a JSON `events` list. The component dispatches **`changeCalendarDate`**, **`changeSelectedDate`**, and **`calendarEventClick`** on the host for integration with host apps or sibling calendars.
8
8
 
9
- ### Custom element
9
+ ---
10
10
 
11
- `hb-calendar-events`
11
+ ## Behavior
12
12
 
13
- ### Attributes / props (snake_case)
13
+ - **Visible month** is anchored by the `date` prop: internally, `month`/`year` are derived from that value. The default is **the first day of the current month** (`dayjs().startOf("month")`).
14
+ - **Header** (month title + prev/next controls) is shown unless `disable_header` is enabled. Prev/next call `changeMonth(±1)`, update `date`, and dispatch **`changeCalendarDate`** with `{ date }` (a `Date` for the new month anchor).
15
+ - **Weekday labels** use `Intl.DateTimeFormat` with `weekday: "short"` and the browser’s primary language (`navigator.languages[0]`, falling back to `"en"`). **Column order** is fixed in markup as Mon–Sat from `startOf("week") + 1..6` days and **Sunday** in the last column (`startOf("week")`).
16
+ - **Grid size**: `rows = ceil((daysInMonth + dayOfWeekOfMonthStart) / 7)` where `dayOfWeek` follows **dayjs**’s `day()` (0 = Sunday … 6 = Saturday). The first row mixes **previous-month** padding cells and **current-month** days; the last row mixes **current-month** days and **next-month** padding cells; middle rows are **only** current month.
17
+ - **Day selection**: clicking a `<td>` (cell) sets `selected` to the logical calendar date for that cell and dispatches **`changeSelectedDate`** with `{ selectedDate }`. **Padding cells** select dates in the adjacent month (previous or next), not only the visible month.
18
+ - **Events**: optional `events` array is **filtered per month** for the visible month, previous month, and next month so padding cells can still show chips for events that fall on those dates. For each day, chips match events whose **calendar day** (`DD`) equals the cell’s day number in the **month that cell represents** (current, previous, or next). Each chip is a `<button>`; its click handler dispatches **`calendarEventClick`** with `{ eventId }` (the event’s `id` string). Chip **`onclick` does not stop propagation**; hosts that also listen on the cell should account for possible bubbling if they attach listeners outside the shadow root.
19
+ - **`IEvent.link` and `IEvent.icon`** exist in typings but are **not used** in the current template (no link or icon rendering).
20
+ - **`date-holidays`**: the module is imported and `new Holidays("IT")` is constructed, but **no holiday data is read or displayed** in the current markup—do not rely on Italian public holidays in the UI until that logic is wired.
14
21
 
15
- | Property | Type | Notes |
16
- | --- | --- | --- |
17
- | `id` | string (optional) | Element identifier. |
18
- | `style` | string (optional) | Inline style string. |
19
- | `date` | Date (optional) | Visible month anchor. |
20
- | `events` | array (optional) | JSON array of `{ date: Date; label: string; id: string; link?; icon?; color? }`. |
21
- | `selected` | Date (optional) | Highlighted date. |
22
- | `disable_header` | boolean (optional) | Hide month navigation when true. |
22
+ ### `disable_header` coercion
23
23
 
24
- **Theme:** `--hb-calendar-selected`, `--hb-calendar-hover`, `--hb-calendar-today`. **Parts:** `calendar-header`, `calendar-current-time-header`, `cell`. **Slots:** `header_month_icon_prev`, `header_month_icon_next`, `header`, `calendar_month`.
24
+ Inside `$effect`, if `disable_header` is a string, it is treated as **true** when (case-insensitive) `"true"` or `"yes"`, or when the string is **empty** `""`; otherwise **false**. From HTML attributes, expect the usual **string** forms your custom-element layer maps to this prop.
25
25
 
26
- ### Events (`CustomEvent` names)
26
+ ### `events` and `selected` coercion
27
27
 
28
- - **`calendarEventClick`** `{ eventId: string }`
29
- - **`changeCalendarDate`** `{ date: Date }`
30
- - **`changeSelectedDate`** — `{ selectedDate: Date }`
28
+ - If `events` is a **string**, it is **`JSON.parse`d** into an array (invalid JSON will throw at runtime).
29
+ - If `selected` is a **string**, it is parsed with **`dayjs(selected).toDate()`** (pass a value dayjs understands, e.g. ISO 8601).
31
30
 
32
- ### Usage notes
31
+ ---
33
32
 
34
- - Styling aligns with Bootstrap-themed CSS variables on the host.
35
- - Shares behavior with `hb-calendar-appointments` for events and navigation.
36
- - Shadow DOM + parts allow styling cells and headers.
37
- - No i18n entries in `docs.ts`; holidays skew Italian.
33
+ ## Graphics and layout
38
34
 
39
- ### Minimal HTML example
35
+ - **Structure**: Optional header `div` (`part="calendar-header"`) plus a **single `<table class="table is-fullwidth hb-calendar-table">`** with `<thead>` (weekdays) and `<tbody>` (day rows).
36
+ - **Table**: `width: 100%`, `height: 100%`, `table-layout: fixed`, `min-height: 34.375rem`, `border-collapse: collapse`. Each **day cell** has `vertical-align: baseline`, a **1px** border using `--hb-calendar-cell-border`, and **row height** split evenly via inline `style="height: {100/rows}%;"` on `<td>`.
37
+ - **Header** (when enabled): flex row with spacing (`is-flex`, `is-justify-content-space-between`, etc.), default **month + year** text in a title-sized span, and default **small light buttons** `˂` / `˃` for prev/next unless slots override.
38
+ - **Cells**: day number in a `.cell-date` div; **padding** days use **`.cell-date-muted`**. **Today** adds **`.cell-today`** (accent color + bold). **Selected** adds **`.cell-selected`** (background). **Hover** on any `<td>` uses `--hb-calendar-hover`.
39
+ - **Event chips**: `.cell-event` buttons, full width of the cell, stacked; default background `--hb-calendar-event-button-color` and text `--bulma-white-bis`. If `event.color` is set, inline `background-color` (and transparent border) override the default chip background.
40
+
41
+ ---
42
+
43
+ ## Logic (implementation notes)
44
+
45
+ | Concern | Implementation |
46
+ |--------|------------------|
47
+ | Month navigation | `changeMonth` mutates `date`, then `dispatch("changeCalendarDate", { date })`. |
48
+ | Event lists | `$derived` filters: `monthsEvent`, `previousMonthEvents`, `nextMonthEvents` by `M` + `YYYY` of `f.date`. |
49
+ | Cell click vs chip | Cell `onclick` → `selectDay(...)`; chip `onclick` → `calendarEventClick({ eventId })`. |
50
+ | `id` prop | Normalized in `$effect` to `""` when falsy; used as a conventional element id hook if your layer sets it. |
51
+
52
+ **Note:** The `$effect` block contains `if (typeof date === "string") dayjs(date).startOf("month").toDate();` **without assigning** the result to `date`. Prefer supplying **`date` as a `Date`** (or rely on your framework’s property deserialization) for a predictable visible month.
53
+
54
+ ---
55
+
56
+ ## Custom element tag
57
+
58
+ ```text
59
+ hb-calendar-events
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Properties / attributes (snake_case)
65
+
66
+ From **`types/webcomponent.type.d.ts`**. In plain HTML, **attributes are strings**; booleans are typically **`yes` / `no`** in this project’s web-component conventions—**and** this component’s `$effect` accepts string forms for `disable_header` as described above. **`events`** should be a **JSON string** representing an array of event objects.
67
+
68
+ | Name | Type (authoring) | Role |
69
+ |------|------------------|------|
70
+ | `id` | `string` (optional) | Optional identifier; coerced to `""` when missing in `$effect`. |
71
+ | `style` | `string` (optional) | Standard host inline style passthrough (Svelte / element `style`). |
72
+ | `date` | `Date` (optional) | Month anchor; default start of **current** month. Prefer a real `Date` instance. |
73
+ | `events` | `IEvent[]` or JSON **string** | Events to show as chips; optional. Parsed from string when needed. |
74
+ | `selected` | `Date` or parseable **string** (optional) | Highlights the matching day (including padding months). |
75
+ | `disable_header` | `boolean` or string (optional) | When true, the entire header block (nav + slots) is omitted. |
76
+
77
+ ### `IEvent` shape (each item in `events`)
78
+
79
+ | Field | Required | Notes |
80
+ |-------|----------|--------|
81
+ | `date` | yes | Event occurrence; matched by month/year/day for chip placement. |
82
+ | `label` | yes | Chip button text. |
83
+ | `id` | yes | Passed back as `eventId` in **`calendarEventClick`**. |
84
+ | `link` | no | Typing only; not rendered. |
85
+ | `icon` | no | Typing only; not rendered. |
86
+ | `color` | no | If set, applied as inline `background-color` on the chip. |
87
+
88
+ ---
89
+
90
+ ## Events (host `CustomEvent`)
91
+
92
+ All dispatched on the **custom element host** via `new CustomEvent(name, { detail })`, so by default they **do not bubble** and are **not composed** through the shadow boundary—listen on the **`hb-calendar-events` element** itself.
93
+
94
+ | Event name | `detail` (TypeScript) | When |
95
+ |------------|------------------------|------|
96
+ | `calendarEventClick` | `{ eventId: string }` | User activates an event chip (`id` → `eventId`). |
97
+ | `changeCalendarDate` | `{ date: Date }` | Visible month changes (prev/next). |
98
+ | `changeSelectedDate` | `{ selectedDate: Date }` | User selects a day cell (any row, including padding). |
99
+
100
+ ---
101
+
102
+ ## CSS custom properties
103
+
104
+ Documented in **`extra/docs.ts`** (`styleSetup.vars`); defaults in **`styles/webcomponent.scss`** fall back to Bulma tokens.
105
+
106
+ | Variable | Role |
107
+ |----------|------|
108
+ | `--hb-calendar-event-button-color` | Default background for event chips (default: `--bulma-link`). |
109
+ | `--hb-calendar-cell-border` | 1px cell border color (default: `--bulma-border`). |
110
+ | `--hb-calendar-hover` | `<td>` hover background (default: `--bulma-background-lighter`). |
111
+ | `--hb-calendar-selected` | Selected cell background (default: `--bulma-info`). |
112
+ | `--hb-calendar-today` | “Today” day number color (default: `--bulma-primary`). |
113
+ | `--bulma-radius` | Chip border radius (docs default `0.375rem`; SCSS fallback `0.25rem`). |
114
+ | `--bulma-white-bis` | Chip text on default chip background. |
115
+ | `--bulma-text-weak` | Muted weekday header tone. |
116
+
117
+ ---
118
+
119
+ ## CSS parts (`::part`)
120
+
121
+ | Part | Target |
122
+ |------|--------|
123
+ | `calendar-header` | Outer header strip (month navigation area). |
124
+ | `calendar-current-time-header` | Inner span wrapping the default month/year line (and `calendar_month` slot). |
125
+ | `cell` | Each day `<td>` in the grid (current, padding, selected, today). |
126
+
127
+ ---
128
+
129
+ ## Slots
130
+
131
+ Names and descriptions match **`extra/docs.ts`** (`htmlSlots`).
132
+
133
+ | Slot | Purpose |
134
+ |------|---------|
135
+ | `header` | Wraps default header content: replace entire header row layout while keeping the outer `calendar-header` part on the parent when `disable_header` is false. |
136
+ | `calendar_month` | Replace the default **month name + year** text inside the title span. |
137
+ | `header_month_icon_prev` | Replace default **previous month** control (default: small `˂` button). |
138
+ | `header_month_icon_next` | Replace default **next month** control (default: small `˃` button). |
139
+
140
+ ---
141
+
142
+ ## Typings
143
+
144
+ Authoring types for consumers and wrappers live in:
145
+
146
+ `src/wc/calendar-events/types/webcomponent.type.d.ts`
147
+
148
+ - **`IEvent`** — one calendar entry (date, label, id, optional link/icon/color).
149
+ - **`Component`** — props: `id`, `style`, `date`, `events`, `selected`, `disable_header`.
150
+ - **`Events`** — maps custom event names to their `detail` shapes: `calendarEventClick`, `changeCalendarDate`, `changeSelectedDate`.
151
+
152
+ After a full web-component build, generated DOM / Svelte element typings may also list this tag under `types/html-elements.d.ts` and `types/svelte-elements.d.ts` in the package output.
153
+
154
+ ---
155
+
156
+ ## Minimal example
40
157
 
41
158
  ```html
42
159
  <hb-calendar-events
43
- events='[{"id":"a","label":"Launch","date":"2026-03-01T09:00:00.000Z","color":"#0d6efd"}]'
160
+ events='[{"id":"launch","label":"Launch","date":"2026-03-15T10:00:00.000Z"}]'
44
161
  ></hb-calendar-events>
45
162
  ```
163
+
164
+ With **explicit month anchor**, **selection**, **no header**, and a listener (vanilla JS):
165
+
166
+ ```html
167
+ <hb-calendar-events
168
+ id="cal-1"
169
+ disable_header="yes"
170
+ date="2026-03-01T00:00:00.000Z"
171
+ selected="2026-03-15T00:00:00.000Z"
172
+ events='[{"id":"a","label":"Ship","date":"2026-03-15T12:00:00.000Z","color":"#2574fc"}]'
173
+ ></hb-calendar-events>
174
+
175
+ <script>
176
+ const el = document.getElementById("cal-1");
177
+ el.addEventListener("changeSelectedDate", (e) => {
178
+ console.log("selected", e.detail.selectedDate);
179
+ });
180
+ el.addEventListener("calendarEventClick", (e) => {
181
+ console.log("event", e.detail.eventId);
182
+ });
183
+ </script>
184
+ ```
185
+
186
+ Adjust attribute serialization (`yes`/`no`, JSON escaping) to match how your **custom element** layer maps host attributes to component props.
package/manifest.json CHANGED
@@ -158,49 +158,84 @@
158
158
  {
159
159
  "name": "--hb-calendar-event-button-color",
160
160
  "valueType": "color",
161
- "defaultValue": ""
161
+ "defaultValue": "(from `--bulma-link`)",
162
+ "description": "Background for event chips inside day cells; defaults to `--bulma-link` on `:host`."
163
+ },
164
+ {
165
+ "name": "--hb-calendar-cell-border",
166
+ "valueType": "color",
167
+ "defaultValue": "(from `--bulma-border`)",
168
+ "description": "1px border around each day cell in the month grid."
162
169
  },
163
170
  {
164
171
  "name": "--hb-calendar-hover",
165
- "valueType": "string",
166
- "defaultValue": ""
172
+ "valueType": "color",
173
+ "defaultValue": "(from `--bulma-background-lighter`)",
174
+ "description": "Background when hovering a selectable day cell."
167
175
  },
168
176
  {
169
177
  "name": "--hb-calendar-selected",
170
- "valueType": "string",
171
- "defaultValue": ""
178
+ "valueType": "color",
179
+ "defaultValue": "(from `--bulma-info`)",
180
+ "description": "Background for the currently selected day cell."
172
181
  },
173
182
  {
174
183
  "name": "--hb-calendar-today",
175
- "valueType": "string",
176
- "defaultValue": ""
184
+ "valueType": "color",
185
+ "defaultValue": "(from `--bulma-primary`)",
186
+ "description": "Accent color for the “today” day number in the grid."
187
+ },
188
+ {
189
+ "name": "--bulma-radius",
190
+ "valueType": "number",
191
+ "defaultValue": "0.375rem",
192
+ "description": "Corner radius for event chips inside cells."
193
+ },
194
+ {
195
+ "name": "--bulma-white-bis",
196
+ "valueType": "color",
197
+ "defaultValue": "(theme)",
198
+ "description": "Chip text color on top of `--hb-calendar-event-button-color`."
199
+ },
200
+ {
201
+ "name": "--bulma-text-weak",
202
+ "valueType": "color",
203
+ "defaultValue": "(theme)",
204
+ "description": "Muted weekday labels in the week header row."
177
205
  }
178
206
  ],
179
207
  "parts": [
180
208
  {
181
- "name": "calendar-header"
209
+ "name": "calendar-header",
210
+ "description": "Outer header strip (month navigation and title); same part name as the appointments calendar."
182
211
  },
183
212
  {
184
- "name": "calendar-current-time-header"
213
+ "name": "calendar-current-time-header",
214
+ "description": "Month label row and navigation slot targets."
185
215
  },
186
216
  {
187
- "name": "cell"
217
+ "name": "cell",
218
+ "description": "Individual day cell in the grid (padding days, current month, today, and selected states)."
188
219
  }
189
220
  ]
190
221
  },
191
222
  "contributors": [],
192
223
  "htmlSlots": [
193
224
  {
194
- "name": "header_month_icon_prev"
225
+ "name": "header_month_icon_prev",
226
+ "description": "Custom “previous month” control in the header."
195
227
  },
196
228
  {
197
- "name": "header_month_icon_next"
229
+ "name": "header_month_icon_next",
230
+ "description": "Custom “next month” control in the header."
198
231
  },
199
232
  {
200
- "name": "header"
233
+ "name": "header",
234
+ "description": "Optional content above the month line in the header."
201
235
  },
202
236
  {
203
- "name": "calendar_month"
237
+ "name": "calendar_month",
238
+ "description": "Custom month / year label next to navigation controls."
204
239
  }
205
240
  ],
206
241
  "i18n": [],
@@ -216,12 +251,12 @@
216
251
  "data": {
217
252
  "events": [
218
253
  {
219
- "date": "2026-04-16T23:22:18.402Z",
254
+ "date": "2026-04-17T00:13:27.147Z",
220
255
  "id": "test",
221
256
  "label": "thetest"
222
257
  },
223
258
  {
224
- "date": "2026-03-30T23:22:18.402Z",
259
+ "date": "2026-03-31T00:13:27.147Z",
225
260
  "id": "test2",
226
261
  "label": "thetest start",
227
262
  "color": "red"
@@ -242,12 +277,12 @@
242
277
  "data": {
243
278
  "events": [
244
279
  {
245
- "date": "2026-04-16T23:22:18.402Z",
280
+ "date": "2026-04-17T00:13:27.147Z",
246
281
  "id": "test",
247
282
  "label": "thetest"
248
283
  },
249
284
  {
250
- "date": "2026-03-30T23:22:18.402Z",
285
+ "date": "2026-03-31T00:13:27.147Z",
251
286
  "id": "test2",
252
287
  "label": "thetest start",
253
288
  "color": "red"
@@ -277,5 +312,5 @@
277
312
  "size": {},
278
313
  "iifePath": "main.iife.js",
279
314
  "repoName": "@htmlbricks/hb-calendar-events",
280
- "version": "0.71.35"
315
+ "version": "0.71.36"
281
316
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htmlbricks/hb-calendar-events",
3
- "version": "0.71.35",
3
+ "version": "0.71.36",
4
4
  "contributors": [],
5
5
  "description": "Classic month grid (7-day week header and variable rows) with selectable cells, “today” styling, and event chips inside each day. Supports adjacent-month padding cells, Italian holidays, JSON `events`, and the same navigation/selection events as the appointments calendar (`changeCalendarDate`, `changeSelectedDate`, `calendarEventClick`).",
6
6
  "licenses": [