@htmlbricks/hb-calendar-events 0.71.35 → 0.71.37

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/README.md CHANGED
@@ -1,45 +1,185 @@
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
+ | `date` | `Date` (optional) | Month anchor; default start of **current** month. Prefer a real `Date` instance. |
72
+ | `events` | `IEvent[]` or JSON **string** | Events to show as chips; optional. Parsed from string when needed. |
73
+ | `selected` | `Date` or parseable **string** (optional) | Highlights the matching day (including padding months). |
74
+ | `disable_header` | `boolean` or string (optional) | When true, the entire header block (nav + slots) is omitted. |
75
+
76
+ ### `IEvent` shape (each item in `events`)
77
+
78
+ | Field | Required | Notes |
79
+ |-------|----------|--------|
80
+ | `date` | yes | Event occurrence; matched by month/year/day for chip placement. |
81
+ | `label` | yes | Chip button text. |
82
+ | `id` | yes | Passed back as `eventId` in **`calendarEventClick`**. |
83
+ | `link` | no | Typing only; not rendered. |
84
+ | `icon` | no | Typing only; not rendered. |
85
+ | `color` | no | If set, applied as inline `background-color` on the chip. |
86
+
87
+ ---
88
+
89
+ ## Events (host `CustomEvent`)
90
+
91
+ 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.
92
+
93
+ | Event name | `detail` (TypeScript) | When |
94
+ |------------|------------------------|------|
95
+ | `calendarEventClick` | `{ eventId: string }` | User activates an event chip (`id` → `eventId`). |
96
+ | `changeCalendarDate` | `{ date: Date }` | Visible month changes (prev/next). |
97
+ | `changeSelectedDate` | `{ selectedDate: Date }` | User selects a day cell (any row, including padding). |
98
+
99
+ ---
100
+
101
+ ## CSS custom properties
102
+
103
+ Documented in **`extra/docs.ts`** (`styleSetup.vars`); defaults in **`styles/webcomponent.scss`** fall back to Bulma tokens.
104
+
105
+ | Variable | Role |
106
+ |----------|------|
107
+ | `--hb-calendar-event-button-color` | Default background for event chips (default: `--bulma-link`). |
108
+ | `--hb-calendar-cell-border` | 1px cell border color (default: `--bulma-border`). |
109
+ | `--hb-calendar-hover` | `<td>` hover background (default: `--bulma-background-lighter`). |
110
+ | `--hb-calendar-selected` | Selected cell background (default: `--bulma-info`). |
111
+ | `--hb-calendar-today` | “Today” day number color (default: `--bulma-primary`). |
112
+ | `--bulma-radius` | Chip border radius (docs default `0.375rem`; SCSS fallback `0.25rem`). |
113
+ | `--bulma-white-bis` | Chip text on default chip background. |
114
+ | `--bulma-text-weak` | Muted weekday header tone. |
115
+
116
+ ---
117
+
118
+ ## CSS parts (`::part`)
119
+
120
+ | Part | Target |
121
+ |------|--------|
122
+ | `calendar-header` | Outer header strip (month navigation area). |
123
+ | `calendar-current-time-header` | Inner span wrapping the default month/year line (and `calendar_month` slot). |
124
+ | `cell` | Each day `<td>` in the grid (current, padding, selected, today). |
125
+
126
+ ---
127
+
128
+ ## Slots
129
+
130
+ Names and descriptions match **`extra/docs.ts`** (`htmlSlots`).
131
+
132
+ | Slot | Purpose |
133
+ |------|---------|
134
+ | `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. |
135
+ | `calendar_month` | Replace the default **month name + year** text inside the title span. |
136
+ | `header_month_icon_prev` | Replace default **previous month** control (default: small `˂` button). |
137
+ | `header_month_icon_next` | Replace default **next month** control (default: small `˃` button). |
138
+
139
+ ---
140
+
141
+ ## Typings
142
+
143
+ Authoring types for consumers and wrappers live in:
144
+
145
+ `src/wc/calendar-events/types/webcomponent.type.d.ts`
146
+
147
+ - **`IEvent`** — one calendar entry (date, label, id, optional link/icon/color).
148
+ - **`Component`** — props: `id`, `date`, `events`, `selected`, `disable_header`.
149
+ - **`Events`** — maps custom event names to their `detail` shapes: `calendarEventClick`, `changeCalendarDate`, `changeSelectedDate`.
150
+
151
+ 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.
152
+
153
+ ---
154
+
155
+ ## Minimal example
40
156
 
41
157
  ```html
42
158
  <hb-calendar-events
43
- events='[{"id":"a","label":"Launch","date":"2026-03-01T09:00:00.000Z","color":"#0d6efd"}]'
159
+ events='[{"id":"launch","label":"Launch","date":"2026-03-15T10:00:00.000Z"}]'
44
160
  ></hb-calendar-events>
45
161
  ```
162
+
163
+ With **explicit month anchor**, **selection**, **no header**, and a listener (vanilla JS):
164
+
165
+ ```html
166
+ <hb-calendar-events
167
+ id="cal-1"
168
+ disable_header="yes"
169
+ date="2026-03-01T00:00:00.000Z"
170
+ selected="2026-03-15T00:00:00.000Z"
171
+ events='[{"id":"a","label":"Ship","date":"2026-03-15T12:00:00.000Z","color":"#2574fc"}]'
172
+ ></hb-calendar-events>
173
+
174
+ <script>
175
+ const el = document.getElementById("cal-1");
176
+ el.addEventListener("changeSelectedDate", (e) => {
177
+ console.log("selected", e.detail.selectedDate);
178
+ });
179
+ el.addEventListener("calendarEventClick", (e) => {
180
+ console.log("event", e.detail.eventId);
181
+ });
182
+ </script>
183
+ ```
184
+
185
+ Adjust attribute serialization (`yes`/`no`, JSON escaping) to match how your **custom element** layer maps host attributes to component props.
package/manifest.json CHANGED
@@ -81,9 +81,6 @@
81
81
  "selected": {
82
82
  "format": "date-time",
83
83
  "type": "string"
84
- },
85
- "style": {
86
- "type": "string"
87
84
  }
88
85
  },
89
86
  "type": "object"
@@ -158,49 +155,84 @@
158
155
  {
159
156
  "name": "--hb-calendar-event-button-color",
160
157
  "valueType": "color",
161
- "defaultValue": ""
158
+ "defaultValue": "(from `--bulma-link`)",
159
+ "description": "Background for event chips inside day cells; defaults to `--bulma-link` on `:host`."
160
+ },
161
+ {
162
+ "name": "--hb-calendar-cell-border",
163
+ "valueType": "color",
164
+ "defaultValue": "(from `--bulma-border`)",
165
+ "description": "1px border around each day cell in the month grid."
162
166
  },
163
167
  {
164
168
  "name": "--hb-calendar-hover",
165
- "valueType": "string",
166
- "defaultValue": ""
169
+ "valueType": "color",
170
+ "defaultValue": "(from `--bulma-background-lighter`)",
171
+ "description": "Background when hovering a selectable day cell."
167
172
  },
168
173
  {
169
174
  "name": "--hb-calendar-selected",
170
- "valueType": "string",
171
- "defaultValue": ""
175
+ "valueType": "color",
176
+ "defaultValue": "(from `--bulma-info`)",
177
+ "description": "Background for the currently selected day cell."
172
178
  },
173
179
  {
174
180
  "name": "--hb-calendar-today",
175
- "valueType": "string",
176
- "defaultValue": ""
181
+ "valueType": "color",
182
+ "defaultValue": "(from `--bulma-primary`)",
183
+ "description": "Accent color for the “today” day number in the grid."
184
+ },
185
+ {
186
+ "name": "--bulma-radius",
187
+ "valueType": "number",
188
+ "defaultValue": "0.375rem",
189
+ "description": "Corner radius for event chips inside cells."
190
+ },
191
+ {
192
+ "name": "--bulma-white-bis",
193
+ "valueType": "color",
194
+ "defaultValue": "(theme)",
195
+ "description": "Chip text color on top of `--hb-calendar-event-button-color`."
196
+ },
197
+ {
198
+ "name": "--bulma-text-weak",
199
+ "valueType": "color",
200
+ "defaultValue": "(theme)",
201
+ "description": "Muted weekday labels in the week header row."
177
202
  }
178
203
  ],
179
204
  "parts": [
180
205
  {
181
- "name": "calendar-header"
206
+ "name": "calendar-header",
207
+ "description": "Outer header strip (month navigation and title); same part name as the appointments calendar."
182
208
  },
183
209
  {
184
- "name": "calendar-current-time-header"
210
+ "name": "calendar-current-time-header",
211
+ "description": "Month label row and navigation slot targets."
185
212
  },
186
213
  {
187
- "name": "cell"
214
+ "name": "cell",
215
+ "description": "Individual day cell in the grid (padding days, current month, today, and selected states)."
188
216
  }
189
217
  ]
190
218
  },
191
219
  "contributors": [],
192
220
  "htmlSlots": [
193
221
  {
194
- "name": "header_month_icon_prev"
222
+ "name": "header_month_icon_prev",
223
+ "description": "Custom “previous month” control in the header."
195
224
  },
196
225
  {
197
- "name": "header_month_icon_next"
226
+ "name": "header_month_icon_next",
227
+ "description": "Custom “next month” control in the header."
198
228
  },
199
229
  {
200
- "name": "header"
230
+ "name": "header",
231
+ "description": "Optional content above the month line in the header."
201
232
  },
202
233
  {
203
- "name": "calendar_month"
234
+ "name": "calendar_month",
235
+ "description": "Custom month / year label next to navigation controls."
204
236
  }
205
237
  ],
206
238
  "i18n": [],
@@ -216,12 +248,12 @@
216
248
  "data": {
217
249
  "events": [
218
250
  {
219
- "date": "2026-04-16T23:22:18.402Z",
251
+ "date": "2026-04-17T00:28:07.320Z",
220
252
  "id": "test",
221
253
  "label": "thetest"
222
254
  },
223
255
  {
224
- "date": "2026-03-30T23:22:18.402Z",
256
+ "date": "2026-03-31T00:28:07.320Z",
225
257
  "id": "test2",
226
258
  "label": "thetest start",
227
259
  "color": "red"
@@ -242,12 +274,12 @@
242
274
  "data": {
243
275
  "events": [
244
276
  {
245
- "date": "2026-04-16T23:22:18.402Z",
277
+ "date": "2026-04-17T00:28:07.320Z",
246
278
  "id": "test",
247
279
  "label": "thetest"
248
280
  },
249
281
  {
250
- "date": "2026-03-30T23:22:18.402Z",
282
+ "date": "2026-03-31T00:28:07.320Z",
251
283
  "id": "test2",
252
284
  "label": "thetest start",
253
285
  "color": "red"
@@ -277,5 +309,5 @@
277
309
  "size": {},
278
310
  "iifePath": "main.iife.js",
279
311
  "repoName": "@htmlbricks/hb-calendar-events",
280
- "version": "0.71.35"
312
+ "version": "0.71.37"
281
313
  }
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.37",
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": [
@@ -24,9 +24,6 @@
24
24
  "selected": {
25
25
  "format": "date-time",
26
26
  "type": "string"
27
- },
28
- "style": {
29
- "type": "string"
30
27
  }
31
28
  },
32
29
  "type": "object"
@@ -8,7 +8,6 @@ export interface IEvent {
8
8
  }
9
9
  export type Component = {
10
10
  id?: string;
11
- style?: string;
12
11
  date?: Date;
13
12
  events?: IEvent[];
14
13
  selected?: Date;