@joewinke/jatui 0.53.0 → 0.54.1
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/CLAUDE.md +2 -2
- package/dist/components/DatePicker.svelte +1 -0
- package/dist/components/DateRangePicker.svelte +1 -0
- package/dist/components/EventCalendar.svelte +1 -0
- package/dist/components/VideoPlayer.svelte +12 -2
- package/dist/components/VideoPlayer.svelte.d.ts +8 -0
- package/dist/components/calendar/MonthGrid.svelte +14 -0
- package/dist/components/calendar/MonthGrid.svelte.d.ts +8 -0
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -59,7 +59,7 @@ Then import:
|
|
|
59
59
|
| `TimeSlotPicker` | Slots grouped morning/afternoon/evening as one `role="radiogroup"` (`role="radio"` + `aria-checked`, full spoken date+time): roving arrows skip unavailable slots, Up/Down jump a visual row, Home/End, Space/Enter choose. Times and grouping follow `timeZone`'s wall clock. | `slots: TimeSlot[]`, `onSelect`, `selectedSlot`, `loading`, `accentColor`, `hourCycle?` ('h12' \| 'h23'), `timeZone?` (IANA), `locale?`, `selectOnFocus?`, `timezone?` (snippet row above the slots) |
|
|
60
60
|
| `BookingScheduler` | Calendly-shaped composition over `CalendarPicker` + `TimeSlotPicker`: details pane (host, duration, location, zone), time-zone select + 12h/24h toggle, slot list, Confirm. Container-query layout (3 panes → 2 → 1). Host supplies data; nothing is booked here. | `getSlots(date, timeZone)` (sync/async, stale responses dropped), `getAvailability?`, `selectedDate`/`selectedSlot`/`timeZone`/`hourCycle` (bindable), `title`, `durationMinutes`, `hostName`, `location`, `description`, `details?` (snippet), `onConfirm(slot, {timeZone})`, `confirming` |
|
|
61
61
|
| `EventCalendar` | Month / week / day / agenda event calendar, engine upstreamed from MOS `CalendarGrid`: one lane allocator per month row (`packWeek`/`computeVisibility`, measured lane capacity), "+N more" expands the week IN PLACE, week/day time grid with side-by-side overlap layout (`layoutDay`) + all-day bar row + now-line, agenda list, month-switcher pill (the shared month panel), details popover snippet, HTML5 drag-to-move, drag- or Shift+arrow range select. Event colours from `--jatui-event-N{,-bg,-fg}`. Generic over your event type. | `events: CalendarEventItem[]` (`{id,title,start,end?,allDay?,color?: 1-6 \| semantic,…}`), `view`/`date` (bindable), `views`, `weekStart`, `locale`, `hourCycle`, `dayStartHour`/`dayEndHour`, `hourHeight`, `height`, `eventDetails?`/`eventContent?`/`toolbarEnd?` (snippets), `moreAction`, `onEventClick`, `onDayClick`, `onCreate(date, hour?)`, `onEventMove(ev, {date, hour?, allDay})`, `onRangeSelect`, `onRangeChange(range, view)` |
|
|
62
|
-
| `CalendarMonthGrid` | The shared month panel every picker uses — exported for custom surfaces. `<table role="grid">`, roving tabindex, range band that bridges cell gaps and rounds at week edges, disabled days stay focusable (`aria-disabled`), `day` snippet + `describeDay` for extra per-day content/name. Pair with `createCalendarGrid()`. | `month`, `focusedDate`, `onFocusDate`, `onSelect`, `selected?`, `range?`, `isDisabled?`, `min`/`max`, `weekStart`, `locale`, `showOutsideDays`, `fixedWeeks`, `size`, `onHover?`, `day?`, `describeDay?` |
|
|
62
|
+
| `CalendarMonthGrid` | The shared month panel every picker uses — exported for custom surfaces. `<table role="grid">`, roving tabindex, range band that bridges cell gaps and rounds at week edges, disabled days stay focusable (`aria-disabled`), `day` snippet + `describeDay` for extra per-day content/name. Pair with `createCalendarGrid()`. | `month`, `focusedDate`, `onFocusDate`, `onSelect`, `selected?`, `range?`, `isDisabled?`, `min`/`max`, `weekStart`, `locale`, `showOutsideDays`, `fixedWeeks`, `size`, `fill?` (true; pass `false` in a `max-content` popover or other shrink-to-fit host — a filling table's max-content is unbounded in Chrome), `onHover?`, `day?`, `describeDay?` |
|
|
63
63
|
| `AvailabilityModal` | Date override editor (modal) | `date`, `overrides`, `onSave`, `onClose` |
|
|
64
64
|
| `BookingForm` | Guest info form for booking | `onSubmit`, `submitting`, `requirePhone`, `accentColor`, `showAttendeeOption` |
|
|
65
65
|
| `CountdownTimer` | Countdown to target date | `targetDate: Date`, `label` |
|
|
@@ -177,7 +177,7 @@ Item-by-item review surfaces (MOS review-ux, design mos-z8vgx). One `VerdictOpti
|
|
|
177
177
|
| `ThumbnailGrid` | Generic thumbnail strip (chimaro port) — image tiles with text-tile fallback, +N overflow counter, remove/add affordances. Decoupled from any media library: pass `{id, url, alt}` items, or a `cell` snippet for full control of tile contents. `removeMode` — `'hover'` (default) reveals the × on hover/focus and keeps it visible on coarse (touch) pointers (ContextMenuTrigger pattern); `'always'` pins it for touch-first flows. `gridCols` (e.g. `'grid-cols-2 sm:grid-cols-4'`) switches the strip to a responsive CSS grid with column-filling tiles. Items take optional `progress` (0–100): an upload ring draws around the tile and a tiny % occupies the remove-× corner, cross-fading into the × at 100 (same slot, no layout shift; per-tile `role="progressbar"`). | `items: ThumbnailItem[]` (`{id, url?, alt, progress?}`), `max`, `size` (`xs\|sm\|md\|lg`), `removable`+`onRemove`, `removeMode` (`hover\|always`), `addable`+`onAdd`, `onSelect`, `gridCols`, `class`, `cell` snippet |
|
|
178
178
|
| `MediaWorkbench` | Full-featured image editor modal — upload, AI generate, AI edit, background removal, annotation canvas. **Preferred over `SmartImageEditor` for new image fields.** Two-column modal: preview left, 4 action tabs right (Generate, Edit, Remove BG, Annotate). Save uploads blob to `uploadEndpoint` or emits `onComplete`. Requires proxy endpoints from jst-23w1l.2. | `value` (bindable `string \| null`), `uploadEndpoint?` (default `/api/media`), `onComplete?`, `accept?` |
|
|
179
179
|
| `MediaLightbox` | Full-screen media preview — z-9040 backdrop, arrow-key paging when given an array, `+/-/0` zoom, download action, Escape/backdrop close. **Use this for the general "just show it big" case** — replaces hand-rolled `fixed inset-0 z-[9040]` modals. For annotated / markup-overlaid image previews, use `ImageLightbox` instead. | `src?`, `filename?`, `kind?: 'image' \| 'video'`, `downloadUrl?`, `items?: MediaItem[]`, `initialIndex?`, `onClose?`, `zIndex?` |
|
|
180
|
-
| `VideoPlayer` | **The default video surface — reach for this over a bare `<video controls>`.** One timeline band carrying a waveform-envelope scrubber, chapter flags (top edge), bookmark diamonds (bottom edge), diarized speaker colouring and scroll-to-zoom, plus an optional transcript pane (click to seek, active line auto-scroll, solo/skip per speaker, `Shift+T` toggle) and a "Talk time" legend (2+ speakers only; one voice gets no legend and no per-row name). **`kind="audio"` renders no stage**, and **`transport="band"`** (the audio default) drops the native `<video controls>` bar for a transport row on the band (play/pause, `now / total`, speed, mute + volume, fullscreen for video), so the band is the ONE timeline. A double-click on the picture toggles fullscreen (band transport; with native controls the browser owns the gesture), a buffering spinner shows while the media is waiting, and volume/mute survive a reload through `settingsStore` (else guarded localStorage). **Every intelligence prop is optional** — a bare mp4 still gets the scrubber, hover-time card, wheel volume and the full keyboard map (Space/K, arrows/J/L, vol/mute, −/= speed + Backspace reset, </> frame step, [/] chapters, B bookmark, t theater, ? help overlay), and each pane lights up as its data arrives (nothing shifts layout when diarization lands late). Wheel means volume over the video (shift = seek, alt = speed; a wheel/keyboard volume change also flashes a clear volume OSD — glyph, level bar and %, "Muted" at 0, opacity-only fade) and zoom over the band; Shift+wheel over the transcript steps line by line (a plain wheel over the transcript scrolls the pane natively — the page is never trapped); `/` opens an in-transcript search (only when a transcript exists and focus is not in a text field; the omnibar yields): matches highlight in place with a live `n / m` count (`aria-live`), Enter/Shift+Enter walk next/previous (seek + the line follows), Esc closes the search first in the Esc layering. Right-click a transcript line (or `Menu` / `Shift+F10` on a focused one) for the **line menu** — Play from here, Copy text, Copy text with timestamp (`[0:02] text`), Copy link at this time when `buildTimeLink` supplies the URL builder (without it the item is absent; `?t=` shape via `buildTimeUrl`); Escape closes and returns focus to the line, the player's keys are dead while it floats, and in fill theater Esc closes the menu without leaving the theater. A QR button on the transport (when `buildTimeLink` exists) opens a **continue-on-phone** card — the deep link at the current second as a scannable SVG QR; clicking the code copies it (jatui-3k7cp). Internals live in `src/lib/video/` (band/keys/rate/deepLink/settings + contracts for audio/night/presence — see that README; gap audit vs the extension: `VIDEO-PLAYER-GAP-AUDIT.md`). | `src`, `kind?` (`'video' \| 'audio'`), `transport?` (`'native' \| 'band'`), `chapters?`, `speakers?`, `transcript?`, `bookmarks?`, `waveform?`, `talkTime?`, `startAt?`, `poster?`, `captionsSrc?`, `crossorigin?` (`'anonymous'` — what frame-reading features need), `syncUrlTime?` (`?t=` deep-link, opt-in), `transcriptPosition?` (`'below' \| 'side'`), `transcriptMaxHeight?` (pane bound — default `min(40vh, 28rem)` below, the player's height beside; the active-line follow scrolls only the pane; only a gesture that actually moves the PANE pauses it — a wheel that scrolls the page doesn't — behind a "Resume following" pill, and it resumes by itself on seek / line or chapter click / play after pause / `followResumeMs` (6000) idle while playing; a hovered chapter fills its whole span in the theme accent with full-height edges), `followResumeMs?`, `transcriptLineMenu?` (true — right-click/`Menu`/`Shift+F10` on a transcript line opens the line menu; `false` leaves transcript lines to the browser's own context menu), `buildTimeLink?` ((sec) → URL for "Copy link at this time"; the host owns the address shape), `qrContinue?` (true — the QR button: the host's `buildTimeLink` at the current second as an SVG QR card, click the code to copy; hidden entirely when no `buildTimeLink` — the player never guesses a URL), `theater?` (bindable — theater mode, NOT fullscreen: control-bar button + `t`, the HOST lays the page out full-width; a side transcript moves below; remembered per viewer as the `player.theater` setting via `settingsStore`, else guarded localStorage), `theaterMode?` (`'width'` default — the host widens its page \| `'fill'` — the player becomes a fixed full-viewport dialog: `role="dialog"` + `aria-modal`, page scroll locked, Tab trapped, Esc/the button exits and returns focus, largest 16:9 stage that fits, transcript beside it ≥64rem else below, z from `--jatui-z-theater`; a remembered theater never fills on load, only a viewer gesture), `theaterButton?` (true), `onTheaterChange?`, `onTimeUpdate?`, `onAddBookmark?`, `onBookmarkContext?` |
|
|
180
|
+
| `VideoPlayer` | **The default video surface — reach for this over a bare `<video controls>`.** One timeline band carrying a waveform-envelope scrubber, chapter flags (top edge), bookmark diamonds (bottom edge), diarized speaker colouring and scroll-to-zoom, plus an optional transcript pane (click to seek, active line auto-scroll, solo/skip per speaker, `Shift+T` toggle) and a "Talk time" legend (2+ speakers only; one voice gets no legend and no per-row name). **`kind="audio"` renders no stage**, and **`transport="band"`** (the audio default) drops the native `<video controls>` bar for a transport row on the band (play/pause, `now / total`, speed, mute + volume, fullscreen for video), so the band is the ONE timeline. A double-click on the picture toggles fullscreen (band transport; with native controls the browser owns the gesture), a buffering spinner shows while the media is waiting, and volume/mute survive a reload through `settingsStore` (else guarded localStorage). **Every intelligence prop is optional** — a bare mp4 still gets the scrubber, hover-time card, wheel volume and the full keyboard map (Space/K, arrows/J/L, vol/mute, −/= speed + Backspace reset, </> frame step, [/] chapters, B bookmark, t theater, ? help overlay), and each pane lights up as its data arrives (nothing shifts layout when diarization lands late). Wheel means volume over the video (shift = seek, alt = speed; a wheel/keyboard volume change also flashes a clear volume OSD — glyph, level bar and %, "Muted" at 0, opacity-only fade) and zoom over the band; Shift+wheel over the transcript steps line by line (a plain wheel over the transcript scrolls the pane natively — the page is never trapped); `/` opens an in-transcript search (only when a transcript exists and focus is not in a text field; the omnibar yields): matches highlight in place with a live `n / m` count (`aria-live`), Enter/Shift+Enter walk next/previous (seek + the line follows), Esc closes the search first in the Esc layering. Right-click a transcript line (or `Menu` / `Shift+F10` on a focused one) for the **line menu** — Play from here, Copy text, Copy text with timestamp (`[0:02] text`), Copy link at this time when `buildTimeLink` supplies the URL builder (without it the item is absent; `?t=` shape via `buildTimeUrl`); Escape closes and returns focus to the line, the player's keys are dead while it floats, and in fill theater Esc closes the menu without leaving the theater. A QR button on the transport (when `buildTimeLink` exists) opens a **continue-on-phone** card — the deep link at the current second as a scannable SVG QR; clicking the code copies it (jatui-3k7cp). Internals live in `src/lib/video/` (band/keys/rate/deepLink/settings + contracts for audio/night/presence — see that README; gap audit vs the extension: `VIDEO-PLAYER-GAP-AUDIT.md`). | `src`, `kind?` (`'video' \| 'audio'`), `transport?` (`'native' \| 'band'`), `chapters?`, `speakers?`, `transcript?`, `bookmarks?`, `waveform?`, `talkTime?`, `startAt?`, `poster?`, `captionsSrc?`, `crossorigin?` (`'anonymous'` — what frame-reading features need), `syncUrlTime?` (`?t=` deep-link, opt-in), `transcriptPosition?` (`'below' \| 'side'`), `transcriptMaxHeight?` (pane bound — default `min(40vh, 28rem)` below, the player's height beside; the active-line follow scrolls only the pane; only a gesture that actually moves the PANE pauses it — a wheel that scrolls the page doesn't — behind a "Resume following" pill, and it resumes by itself on seek / line or chapter click / play after pause / `followResumeMs` (6000) idle while playing; a hovered chapter fills its whole span in the theme accent with full-height edges), `followResumeMs?`, `transcriptLineMenu?` (true — right-click/`Menu`/`Shift+F10` on a transcript line opens the line menu; `false` leaves transcript lines to the browser's own context menu), `buildTimeLink?` ((sec) → URL for "Copy link at this time"; the host owns the address shape), `qrContinue?` (true — the QR button: the host's `buildTimeLink` at the current second as an SVG QR card, click the code to copy; hidden entirely when no `buildTimeLink` — the player never guesses a URL), `theater?` (bindable — theater mode, NOT fullscreen: control-bar button + `t`, the HOST lays the page out full-width; a side transcript moves below; remembered per viewer as the `player.theater` setting via `settingsStore`, else guarded localStorage), `theaterMode?` (`'width'` default — the host widens its page \| `'fill'` — the player becomes a fixed full-viewport dialog: `role="dialog"` + `aria-modal`, page scroll locked, Tab trapped, Esc/the button exits and returns focus, largest 16:9 stage that fits, transcript beside it ≥64rem else below, z from `--jatui-z-theater`; a remembered theater never fills on load, only a viewer gesture), `theaterButton?` (true), `onTheaterChange?`, `onTimeUpdate?`, `onAddBookmark?`, `bookmarkQuickAdd?` (true — with `onAddBookmark` wired, `false` hides only the built-in "+ Bookmark at …" row; the `B` key and its `?` help entry stay, for a host that owns the bookmark UI), `onBookmarkContext?` |
|
|
181
181
|
| `MediaCapture` | One-tap audio/selfie-video/screen(+mic) recording — a host-agnostic PRIMITIVE. Owns permission requests, MIME negotiation, the record/stop state machine, live self-preview, and mixes screen+mic audio into one track via AudioContext. Never uploads anything — hands the finished clip to `onCapture` as a Blob and the host decides what to do with it. `onCapture` may be async; the component shows "processing" until it resolves. | `onCapture: (result: MediaCaptureResult) => void \| Promise<void>`, `modes?` (default all three), `maxDurationMs?` (default 120000), `label?`, `hint?`, `compact?`, `disabled?` |
|
|
182
182
|
| `MultimodalCaptureField` | "Upload a file, or record yourself going over it" as one input surface — composes `FileDropzone` (capped to one file) with `MediaCapture`. File and recording are independent (either, both, or neither); neither half uploads anything, same "validate and hand back" contract as `FileDropzone`. | `onFileSelected?`, `onFileRemoved?`, `onCapture?`, `onRecordingRemoved?`, `accept?`, `maxFileSize?`, `modes?`, `maxDurationMs?`, `file?`/`fileUrl?`/`fileName?`, `recordingSummary?` |
|
|
183
183
|
| `ListenControl` | "Listen to this page" — a compact pill that expands into a TWO-ROW playback bar over the host's PER-SENTENCE audio (TTS): row 1 = play/pause · chapter chip + current sentence (full remaining width) · ONE settings pill ("1.25× · Sarah" → speed 0.75–2× + voice menu) · close; row 2 = prev/next sentence and −15s/+15s · a document-wide progress bar with chapter ticks (a hatched tail marks the not-yet-synthesized part), time, close. The host supplies an async `source` (sentences/paragraphs with ids → audio URLs, streamed page by page so playback starts on the first chunk while the rest synthesizes; pages merge by id so late URLs fill in) and gets `onSegmentChange(id)` at every boundary for highlight + scroll-follow. Media Session (lock-screen/headset controls, one document-wide position), keyboard scoped to the player (Space/K, ←/→ sentences, Shift+←/→ ±15s, [ / ] speed, Escape), speed+voice persisted in localStorage, `bind:api` for hosts wiring their own global keys, reduced-motion aware, token-only theming, never overflows its host (border-box, `max-width: 100%`, `min-width: 0` chain), fixed sticky mini-bar (same two rows) on narrow screens. Internals in `src/lib/listen/` (one timeline across per-sentence files — `buildTimeline` offsets; see `video/` for the doctrine). Demo synthesizes real WAVs locally. | `source`, `voices?`, `voiceId?` (bindable), `chapters?`, `title?`, `triggerLabel?`, `open?` (bindable), `preload?`, `estimateSec?`, `storageKey?`, `onSegmentChange?`, `onOpenChange?`, `api?` (bindable), `class?`, `children?` (custom trigger) |
|
|
@@ -383,6 +383,7 @@
|
|
|
383
383
|
onMarkerClick = undefined,
|
|
384
384
|
onTimeUpdate = undefined,
|
|
385
385
|
onAddBookmark = undefined,
|
|
386
|
+
bookmarkQuickAdd = true,
|
|
386
387
|
onBookmarkContext = undefined,
|
|
387
388
|
night = $bindable(),
|
|
388
389
|
nightDepth = $bindable(NIGHT_DEPTH_DEFAULT),
|
|
@@ -638,6 +639,14 @@
|
|
|
638
639
|
onTimeUpdate?: (video: HTMLVideoElement) => void;
|
|
639
640
|
/** Present ⇒ the band grows an "add bookmark at current time" control. */
|
|
640
641
|
onAddBookmark?: (playbackSec: number, label: string) => void;
|
|
642
|
+
/**
|
|
643
|
+
* Show the built-in quick-add row (the label input + "+ Bookmark at …"
|
|
644
|
+
* button) when `onAddBookmark` is wired — default `true`, so existing
|
|
645
|
+
* hosts see no change. `false` hides ONLY the row: the `B` key and its
|
|
646
|
+
* `?` help entry stay wired to `onAddBookmark`, for a host that owns the
|
|
647
|
+
* bookmark UI itself (MOS's watch page) and just wants the keypress.
|
|
648
|
+
*/
|
|
649
|
+
bookmarkQuickAdd?: boolean;
|
|
641
650
|
/** Right-click on the band. The host owns the panel; this only hit-tests. */
|
|
642
651
|
onBookmarkContext?: (
|
|
643
652
|
sec: number,
|
|
@@ -4703,7 +4712,7 @@
|
|
|
4703
4712
|
</div>
|
|
4704
4713
|
{/if}
|
|
4705
4714
|
|
|
4706
|
-
{#if onAddBookmark}
|
|
4715
|
+
{#if onAddBookmark && bookmarkQuickAdd}
|
|
4707
4716
|
<div class="vp-bookmark-add">
|
|
4708
4717
|
<label for="vp-bookmark-label">Bookmark label</label>
|
|
4709
4718
|
<input
|
|
@@ -6124,7 +6133,8 @@
|
|
|
6124
6133
|
outline-offset: 1px;
|
|
6125
6134
|
}
|
|
6126
6135
|
|
|
6127
|
-
/*
|
|
6136
|
+
/* Quick-add bookmark row — rendered when the host wired onAddBookmark AND
|
|
6137
|
+
did not hide it with bookmarkQuickAdd={false} (the B key still works). */
|
|
6128
6138
|
.vp-bookmark-add {
|
|
6129
6139
|
display: flex;
|
|
6130
6140
|
align-items: center;
|
|
@@ -296,6 +296,14 @@ type $$ComponentProps = {
|
|
|
296
296
|
onTimeUpdate?: (video: HTMLVideoElement) => void;
|
|
297
297
|
/** Present ⇒ the band grows an "add bookmark at current time" control. */
|
|
298
298
|
onAddBookmark?: (playbackSec: number, label: string) => void;
|
|
299
|
+
/**
|
|
300
|
+
* Show the built-in quick-add row (the label input + "+ Bookmark at …"
|
|
301
|
+
* button) when `onAddBookmark` is wired — default `true`, so existing
|
|
302
|
+
* hosts see no change. `false` hides ONLY the row: the `B` key and its
|
|
303
|
+
* `?` help entry stay wired to `onAddBookmark`, for a host that owns the
|
|
304
|
+
* bookmark UI itself (MOS's watch page) and just wants the keypress.
|
|
305
|
+
*/
|
|
306
|
+
bookmarkQuickAdd?: boolean;
|
|
299
307
|
/** Right-click on the band. The host owns the panel; this only hit-tests. */
|
|
300
308
|
onBookmarkContext?: (sec: number, existing: VideoBookmark | null, clientX: number, clientY: number) => void;
|
|
301
309
|
/**
|
|
@@ -38,6 +38,14 @@
|
|
|
38
38
|
/** Tint every enabled in-month day (booking calendars: "these days are open"). */
|
|
39
39
|
highlightEnabled?: boolean;
|
|
40
40
|
size?: 'sm' | 'md' | 'lg';
|
|
41
|
+
/**
|
|
42
|
+
* Stretch to the container's width (default). Pass `false` inside a
|
|
43
|
+
* shrink-to-fit host — a popover with `width: max-content`, a flex item
|
|
44
|
+
* sized by its content: a `width: 100%` table's max-content is unbounded
|
|
45
|
+
* in Chrome, so the host grows to ~670,000px and the days land off-screen
|
|
46
|
+
* (jatui-ewfh3). `false` sizes the grid to seven cells and centres it.
|
|
47
|
+
*/
|
|
48
|
+
fill?: boolean;
|
|
41
49
|
/** Accessible name; defaults to "March 2026". */
|
|
42
50
|
ariaLabel?: string;
|
|
43
51
|
rtl?: boolean;
|
|
@@ -83,6 +91,7 @@
|
|
|
83
91
|
hideWeekdays = false,
|
|
84
92
|
highlightEnabled = false,
|
|
85
93
|
size = 'md',
|
|
94
|
+
fill = true,
|
|
86
95
|
ariaLabel,
|
|
87
96
|
rtl = false,
|
|
88
97
|
onSelect,
|
|
@@ -143,6 +152,7 @@
|
|
|
143
152
|
<table
|
|
144
153
|
bind:this={gridEl}
|
|
145
154
|
class="jatui-month-grid jatui-month-grid--{size} {className}"
|
|
155
|
+
class:jatui-month-grid--intrinsic={!fill}
|
|
146
156
|
role="grid"
|
|
147
157
|
aria-label={label}
|
|
148
158
|
dir={rtl ? 'rtl' : undefined}
|
|
@@ -230,6 +240,10 @@
|
|
|
230
240
|
width: 100%;
|
|
231
241
|
min-width: calc(var(--_cell) * 7);
|
|
232
242
|
}
|
|
243
|
+
.jatui-month-grid--intrinsic {
|
|
244
|
+
width: calc(var(--_cell) * 7);
|
|
245
|
+
margin-inline: auto;
|
|
246
|
+
}
|
|
233
247
|
.jatui-month-grid--sm {
|
|
234
248
|
--_cell: 2rem;
|
|
235
249
|
}
|
|
@@ -35,6 +35,14 @@ export interface MonthGridProps {
|
|
|
35
35
|
/** Tint every enabled in-month day (booking calendars: "these days are open"). */
|
|
36
36
|
highlightEnabled?: boolean;
|
|
37
37
|
size?: 'sm' | 'md' | 'lg';
|
|
38
|
+
/**
|
|
39
|
+
* Stretch to the container's width (default). Pass `false` inside a
|
|
40
|
+
* shrink-to-fit host — a popover with `width: max-content`, a flex item
|
|
41
|
+
* sized by its content: a `width: 100%` table's max-content is unbounded
|
|
42
|
+
* in Chrome, so the host grows to ~670,000px and the days land off-screen
|
|
43
|
+
* (jatui-ewfh3). `false` sizes the grid to seven cells and centres it.
|
|
44
|
+
*/
|
|
45
|
+
fill?: boolean;
|
|
38
46
|
/** Accessible name; defaults to "March 2026". */
|
|
39
47
|
ariaLabel?: string;
|
|
40
48
|
rtl?: boolean;
|