snice 7.8.0 → 7.9.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.
- package/README.md +1 -1
- package/adapters/react/SniceProvider.js +1 -1
- package/adapters/react/SniceRouter.js +1 -1
- package/adapters/react/matchRoute.js +1 -1
- package/adapters/react/table.d.ts +1 -0
- package/adapters/react/table.d.ts.map +1 -1
- package/adapters/react/table.js +1 -1
- package/adapters/react/table.js.map +1 -1
- package/adapters/react/table.tsx +2 -1
- package/adapters/react/useRequestHandler.js +1 -1
- package/bin/analyzer-contracts.js +17 -1
- package/custom-elements.json +57 -3
- package/dist/cdn/accordion/snice-accordion.js +1 -1
- package/dist/cdn/action-bar/snice-action-bar.js +1 -1
- package/dist/cdn/activity-feed/snice-activity-feed.js +1 -1
- package/dist/cdn/alert/snice-alert.js +1 -1
- package/dist/cdn/app-tiles/snice-app-tiles.js +1 -1
- package/dist/cdn/approval-flow/snice-approval-flow.js +1 -1
- package/dist/cdn/audio-recorder/snice-audio-recorder.js +1 -1
- package/dist/cdn/availability/snice-availability.js +1 -1
- package/dist/cdn/avatar/snice-avatar.js +1 -1
- package/dist/cdn/avatar-group/snice-avatar-group.js +1 -1
- package/dist/cdn/badge/snice-badge.js +1 -1
- package/dist/cdn/banner/snice-banner.js +1 -1
- package/dist/cdn/binpack/snice-binpack.js +1 -1
- package/dist/cdn/book/snice-book.js +1 -1
- package/dist/cdn/booking/snice-booking.js +1 -1
- package/dist/cdn/breadcrumbs/snice-breadcrumbs.js +1 -1
- package/dist/cdn/button/snice-button.js +1 -1
- package/dist/cdn/calendar/README.md +2 -2
- package/dist/cdn/calendar/snice-calendar.js +537 -44
- package/dist/cdn/calendar/snice-calendar.js.map +1 -1
- package/dist/cdn/calendar/snice-calendar.min.js +2 -2
- package/dist/cdn/calendar/snice-calendar.min.js.map +1 -1
- package/dist/cdn/camera/snice-camera.js +1 -1
- package/dist/cdn/camera-annotate/snice-camera-annotate.js +1 -1
- package/dist/cdn/candlestick/snice-candlestick.js +1 -1
- package/dist/cdn/card/snice-card.js +1 -1
- package/dist/cdn/carousel/snice-carousel.js +1 -1
- package/dist/cdn/cart/snice-cart.js +1 -1
- package/dist/cdn/chart/snice-chart.js +1 -1
- package/dist/cdn/chat/snice-chat.js +1 -1
- package/dist/cdn/checkbox/snice-checkbox.js +1 -1
- package/dist/cdn/chip/snice-chip.js +1 -1
- package/dist/cdn/code-block/README.md +2 -2
- package/dist/cdn/code-block/snice-code-block.js +177 -167
- package/dist/cdn/code-block/snice-code-block.js.map +1 -1
- package/dist/cdn/code-block/snice-code-block.min.js +2 -2
- package/dist/cdn/code-block/snice-code-block.min.js.map +1 -1
- package/dist/cdn/color-display/snice-color-display.js +1 -1
- package/dist/cdn/color-picker/snice-color-picker.js +1 -1
- package/dist/cdn/command-palette/README.md +1 -1
- package/dist/cdn/command-palette/snice-command-palette.js +2 -2
- package/dist/cdn/command-palette/snice-command-palette.js.map +1 -1
- package/dist/cdn/command-palette/snice-command-palette.min.js +1 -1
- package/dist/cdn/command-palette/snice-command-palette.min.js.map +1 -1
- package/dist/cdn/comments/snice-comments.js +1 -1
- package/dist/cdn/countdown/snice-countdown.js +1 -1
- package/dist/cdn/cropper/snice-cropper.js +1 -1
- package/dist/cdn/data-card/snice-data-card.js +1 -1
- package/dist/cdn/date-picker/snice-date-picker.js +1 -1
- package/dist/cdn/date-range-picker/snice-date-range-picker.js +1 -1
- package/dist/cdn/date-time-picker/snice-date-time-picker.js +1 -1
- package/dist/cdn/diff/snice-diff.js +1 -1
- package/dist/cdn/divider/snice-divider.js +1 -1
- package/dist/cdn/doc/snice-doc.js +1 -1
- package/dist/cdn/draw/snice-draw.js +1 -1
- package/dist/cdn/drawer/snice-drawer.js +1 -1
- package/dist/cdn/empty-state/snice-empty-state.js +1 -1
- package/dist/cdn/estimate/snice-estimate.js +1 -1
- package/dist/cdn/file-gallery/snice-file-gallery.js +1 -1
- package/dist/cdn/file-upload/snice-file-upload.js +1 -1
- package/dist/cdn/flip-card/snice-flip-card.js +1 -1
- package/dist/cdn/flow/snice-flow.js +1 -1
- package/dist/cdn/form-layout/snice-form-layout.js +1 -1
- package/dist/cdn/funnel/snice-funnel.js +1 -1
- package/dist/cdn/gantt/snice-gantt.js +1 -1
- package/dist/cdn/gauge/snice-gauge.js +1 -1
- package/dist/cdn/grid/snice-grid.js +1 -1
- package/dist/cdn/heatmap/snice-heatmap.js +1 -1
- package/dist/cdn/image/snice-image.js +1 -1
- package/dist/cdn/input/snice-input.js +1 -1
- package/dist/cdn/invoice/snice-invoice.js +1 -1
- package/dist/cdn/kanban/snice-kanban.js +1 -1
- package/dist/cdn/key-value/snice-key-value.js +1 -1
- package/dist/cdn/kpi/snice-kpi.js +1 -1
- package/dist/cdn/layout/snice-layout.js +1 -1
- package/dist/cdn/leaderboard/snice-leaderboard.js +1 -1
- package/dist/cdn/link/snice-link.js +1 -1
- package/dist/cdn/link-preview/snice-link-preview.js +1 -1
- package/dist/cdn/list/snice-list.js +1 -1
- package/dist/cdn/location/snice-location.js +1 -1
- package/dist/cdn/login/snice-login.js +1 -1
- package/dist/cdn/map/snice-map.js +1 -1
- package/dist/cdn/markdown/snice-markdown.js +1 -1
- package/dist/cdn/masonry/snice-masonry.js +1 -1
- package/dist/cdn/menu/snice-menu.js +1 -1
- package/dist/cdn/message-strip/snice-message-strip.js +1 -1
- package/dist/cdn/modal/snice-modal.js +1 -1
- package/dist/cdn/music-player/snice-music-player.js +1 -1
- package/dist/cdn/nav/snice-nav.js +1 -1
- package/dist/cdn/network-graph/snice-network-graph.js +1 -1
- package/dist/cdn/notification-center/snice-notification-center.js +1 -1
- package/dist/cdn/order-tracker/snice-order-tracker.js +1 -1
- package/dist/cdn/org-chart/snice-org-chart.js +1 -1
- package/dist/cdn/pagination/snice-pagination.js +1 -1
- package/dist/cdn/paint/snice-paint.js +1 -1
- package/dist/cdn/pdf-viewer/snice-pdf-viewer.js +1 -1
- package/dist/cdn/permission-matrix/snice-permission-matrix.js +1 -1
- package/dist/cdn/podcast-player/snice-podcast-player.js +1 -1
- package/dist/cdn/popover/snice-popover.js +1 -1
- package/dist/cdn/pricing-table/snice-pricing-table.js +1 -1
- package/dist/cdn/product-card/snice-product-card.js +1 -1
- package/dist/cdn/progress/snice-progress.js +2 -2
- package/dist/cdn/progress/snice-progress.js.map +1 -1
- package/dist/cdn/progress/snice-progress.min.js +1 -1
- package/dist/cdn/progress/snice-progress.min.js.map +1 -1
- package/dist/cdn/progress-ring/snice-progress-ring.js +1 -1
- package/dist/cdn/qr-code/README.md +2 -2
- package/dist/cdn/qr-code/snice-qr-code.js +19 -3
- package/dist/cdn/qr-code/snice-qr-code.js.map +1 -1
- package/dist/cdn/qr-code/snice-qr-code.min.js +2 -2
- package/dist/cdn/qr-code/snice-qr-code.min.js.map +1 -1
- package/dist/cdn/qr-reader/snice-qr-reader.js +1 -1
- package/dist/cdn/radio/snice-radio.js +1 -1
- package/dist/cdn/range-slider/snice-range-slider.js +1 -1
- package/dist/cdn/rating/snice-rating.js +1 -1
- package/dist/cdn/receipt/snice-receipt.js +5 -2
- package/dist/cdn/receipt/snice-receipt.js.map +1 -1
- package/dist/cdn/receipt/snice-receipt.min.js +1 -1
- package/dist/cdn/receipt/snice-receipt.min.js.map +1 -1
- package/dist/cdn/recipe/snice-recipe.js +1 -1
- package/dist/cdn/runtime/snice-runtime.esm.js +4 -4
- package/dist/cdn/runtime/snice-runtime.esm.js.map +1 -1
- package/dist/cdn/runtime/snice-runtime.esm.min.js.map +1 -1
- package/dist/cdn/runtime/snice-runtime.js +4 -4
- package/dist/cdn/runtime/snice-runtime.js.map +1 -1
- package/dist/cdn/runtime/snice-runtime.min.js.map +1 -1
- package/dist/cdn/sankey/snice-sankey.js +1 -1
- package/dist/cdn/segmented-control/snice-segmented-control.js +1 -1
- package/dist/cdn/select/README.md +2 -2
- package/dist/cdn/select/snice-select.js +6 -9
- package/dist/cdn/select/snice-select.js.map +1 -1
- package/dist/cdn/select/snice-select.min.js +2 -2
- package/dist/cdn/select/snice-select.min.js.map +1 -1
- package/dist/cdn/skeleton/snice-skeleton.js +1 -1
- package/dist/cdn/slider/snice-slider.js +1 -1
- package/dist/cdn/sortable/snice-sortable.js +1 -1
- package/dist/cdn/sparkline/snice-sparkline.js +1 -1
- package/dist/cdn/spinner/snice-spinner.js +1 -1
- package/dist/cdn/split-button/snice-split-button.js +1 -1
- package/dist/cdn/split-pane/snice-split-pane.js +1 -1
- package/dist/cdn/spotlight/snice-spotlight.js +1 -1
- package/dist/cdn/stat-group/snice-stat-group.js +1 -1
- package/dist/cdn/step-input/snice-step-input.js +1 -1
- package/dist/cdn/stepper/snice-stepper.js +1 -1
- package/dist/cdn/switch/snice-switch.js +1 -1
- package/dist/cdn/table/README.md +2 -2
- package/dist/cdn/table/snice-table.esm.js +1940 -407
- package/dist/cdn/table/snice-table.esm.js.map +1 -1
- package/dist/cdn/table/snice-table.esm.min.js +242 -53
- package/dist/cdn/table/snice-table.esm.min.js.map +1 -1
- package/dist/cdn/table/snice-table.js +1940 -407
- package/dist/cdn/table/snice-table.js.map +1 -1
- package/dist/cdn/table/snice-table.min.js +234 -45
- package/dist/cdn/table/snice-table.min.js.map +1 -1
- package/dist/cdn/tabs/snice-tabs.js +1 -1
- package/dist/cdn/tag/snice-tag.js +1 -1
- package/dist/cdn/tag-input/snice-tag-input.js +1 -1
- package/dist/cdn/terminal/snice-terminal.js +1 -1
- package/dist/cdn/testimonial/snice-testimonial.js +1 -1
- package/dist/cdn/textarea/snice-textarea.js +1 -1
- package/dist/cdn/time-picker/snice-time-picker.js +1 -1
- package/dist/cdn/time-range-picker/snice-time-range-picker.js +1 -1
- package/dist/cdn/timeline/snice-timeline.js +1 -1
- package/dist/cdn/timer/snice-timer.js +1 -1
- package/dist/cdn/toast/snice-toast.js +1 -1
- package/dist/cdn/tooltip/snice-tooltip.js +1 -1
- package/dist/cdn/tree/snice-tree.js +1 -1
- package/dist/cdn/treemap/snice-treemap.js +1 -1
- package/dist/cdn/user-card/snice-user-card.js +1 -1
- package/dist/cdn/video-player/snice-video-player.js +1 -1
- package/dist/cdn/virtual-scroller/snice-virtual-scroller.js +1 -1
- package/dist/cdn/waterfall/snice-waterfall.js +1 -1
- package/dist/cdn/weather/snice-weather.js +1 -1
- package/dist/cdn/work-order/snice-work-order.js +1 -1
- package/dist/components/calendar/snice-calendar.d.ts +187 -5
- package/dist/components/calendar/snice-calendar.js +537 -44
- package/dist/components/calendar/snice-calendar.js.map +1 -1
- package/dist/components/calendar/snice-calendar.types.d.ts +2 -1
- package/dist/components/code-block/formatter.d.ts +6 -0
- package/dist/components/code-block/formatter.js +174 -164
- package/dist/components/code-block/formatter.js.map +1 -1
- package/dist/components/code-block/grammars/snice.json +1 -1
- package/dist/components/code-block/grammars/typescript.json +1 -1
- package/dist/components/command-palette/snice-command-palette.js +1 -1
- package/dist/components/command-palette/snice-command-palette.js.map +1 -1
- package/dist/components/progress/snice-progress.js +1 -1
- package/dist/components/progress/snice-progress.js.map +1 -1
- package/dist/components/qr-code/qrcode.d.ts +1 -1
- package/dist/components/qr-code/qrcode.js +18 -2
- package/dist/components/qr-code/qrcode.js.map +1 -1
- package/dist/components/receipt/snice-receipt.js +4 -1
- package/dist/components/receipt/snice-receipt.js.map +1 -1
- package/dist/components/select/snice-select.d.ts +1 -1
- package/dist/components/select/snice-select.js +5 -8
- package/dist/components/select/snice-select.js.map +1 -1
- package/dist/components/table/snice-cell-actions.js +1 -1
- package/dist/components/table/snice-cell-actions.js.map +1 -1
- package/dist/components/table/snice-cell-color.js +1 -1
- package/dist/components/table/snice-cell-color.js.map +1 -1
- package/dist/components/table/snice-cell-date.js +20 -8
- package/dist/components/table/snice-cell-date.js.map +1 -1
- package/dist/components/table/snice-cell-email.js +1 -1
- package/dist/components/table/snice-cell-email.js.map +1 -1
- package/dist/components/table/snice-cell-image.js +1 -1
- package/dist/components/table/snice-cell-image.js.map +1 -1
- package/dist/components/table/snice-cell-json.js +1 -1
- package/dist/components/table/snice-cell-json.js.map +1 -1
- package/dist/components/table/snice-cell-link.js +1 -1
- package/dist/components/table/snice-cell-link.js.map +1 -1
- package/dist/components/table/snice-cell-location.js +1 -1
- package/dist/components/table/snice-cell-location.js.map +1 -1
- package/dist/components/table/snice-cell-phone.js +1 -1
- package/dist/components/table/snice-cell-phone.js.map +1 -1
- package/dist/components/table/snice-cell-status.js +1 -1
- package/dist/components/table/snice-cell-status.js.map +1 -1
- package/dist/components/table/snice-cell.d.ts +10 -0
- package/dist/components/table/snice-cell.js +59 -13
- package/dist/components/table/snice-cell.js.map +1 -1
- package/dist/components/table/snice-row.d.ts +0 -1
- package/dist/components/table/snice-row.js +4 -10
- package/dist/components/table/snice-row.js.map +1 -1
- package/dist/components/table/snice-table.d.ts +170 -2
- package/dist/components/table/snice-table.js +868 -189
- package/dist/components/table/snice-table.js.map +1 -1
- package/dist/components/table/snice-table.types.d.ts +17 -0
- package/dist/components/table/table-cell-presentation.d.ts +17 -4
- package/dist/components/table/table-cell-presentation.js +37 -11
- package/dist/components/table/table-cell-presentation.js.map +1 -1
- package/dist/components/table/table-column-manager.d.ts +153 -2
- package/dist/components/table/table-column-manager.js +364 -43
- package/dist/components/table/table-column-manager.js.map +1 -1
- package/dist/components/table/table-date.d.ts +29 -0
- package/dist/components/table/table-date.js +78 -0
- package/dist/components/table/table-date.js.map +1 -0
- package/dist/components/table/table-export.js +6 -2
- package/dist/components/table/table-export.js.map +1 -1
- package/dist/components/table/table-filter-engine.d.ts +9 -0
- package/dist/components/table/table-filter-engine.js +58 -14
- package/dist/components/table/table-filter-engine.js.map +1 -1
- package/dist/components/table/table-keyboard.d.ts +8 -0
- package/dist/components/table/table-keyboard.js +14 -3
- package/dist/components/table/table-keyboard.js.map +1 -1
- package/dist/components/table/table-toolbar.js +1 -0
- package/dist/components/table/table-toolbar.js.map +1 -1
- package/dist/components/table/table-tree-data.d.ts +2 -0
- package/dist/components/table/table-tree-data.js +35 -9
- package/dist/components/table/table-tree-data.js.map +1 -1
- package/dist/components/table/table-virtualizer.d.ts +44 -7
- package/dist/components/table/table-virtualizer.js +101 -54
- package/dist/components/table/table-virtualizer.js.map +1 -1
- package/dist/components/theme/theme.css +9 -0
- package/dist/index.cjs +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.iife.js +1 -1
- package/dist/react/SniceProvider.js +1 -1
- package/dist/react/SniceRouter.js +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/matchRoute.js +1 -1
- package/dist/react/useRequestHandler.js +1 -1
- package/dist/symbols.cjs +1 -1
- package/dist/symbols.esm.js +1 -1
- package/dist/testing-dom.cjs +1 -1
- package/dist/testing-dom.esm.js +1 -1
- package/dist/transitions.cjs +1 -1
- package/dist/transitions.esm.js +1 -1
- package/docs/ai/DEVELOPMENT.md +93 -2
- package/docs/ai/components/calendar.md +113 -10
- package/docs/ai/components/code-block.md +4 -0
- package/docs/ai/components/doc.md +1 -1
- package/docs/ai/components/progress.md +1 -0
- package/docs/ai/components/receipt.md +1 -1
- package/docs/ai/components/table.md +29 -30
- package/docs/ai/components/theme.md +1 -0
- package/docs/ai/events.md +30 -0
- package/docs/ai/theme.md +1 -0
- package/docs/components/calendar.md +171 -11
- package/docs/components/code-block.md +2 -0
- package/docs/components/doc.md +1 -1
- package/docs/components/progress.md +13 -0
- package/docs/components/receipt.md +1 -0
- package/docs/components/table.md +274 -15
- package/docs/components/theme.md +5 -0
- package/docs/events.md +49 -0
- package/docs/plans/2026-03-06-date-range-picker-plan.md +4 -4
- package/docs/plans/2026-03-07-table-mui-parity-design.md +1 -1
- package/docs/plans/2026-03-09-action-bar-plan.md +11 -11
- package/docs/superpowers/specs/2026-07-09-table-incredible-design.md +1 -1
- package/docs/superpowers/specs/2026-07-09-table-phase0-implementation.md +2 -2
- package/package.json +3 -1
- package/vscode.html-custom-data.json +13 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { __runInitializers, __esDecorate } from 'tslib';
|
|
2
|
-
import { element, property, dispatch, styles, ready, request, dispose, watch, css } from 'snice';
|
|
2
|
+
import { element, property, dispatch, styles, ready, request, dispose, watch, observe, css } from 'snice';
|
|
3
3
|
import '../avatar/snice-avatar.js';
|
|
4
4
|
|
|
5
|
-
var cssContent = ":host([hidden]){display:none}:host{display:block;font-family:var(--snice-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif);contain:layout style}.calendar{width:100%;max-width:37.5rem}.calendar__header{font-family:var(--snice-font-family-display, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif);display:flex;align-items:center;justify-content:space-between;padding:var(--snice-spacing-md,1rem);background:var(--snice-color-surface,rgb(255 255 255));border-bottom:1px solid var(--snice-color-border,rgb(226 226 226))}.calendar__title{font-family:var(--snice-font-family-display, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif);font-size:var(--snice-heading-md, 1.125rem);font-weight:var(--snice-font-weight-semibold,600);color:var(--snice-color-text,rgb(23 23 23))}.calendar__nav{display:flex;gap:var(--snice-spacing-xs,.5rem)}.calendar__nav-button{padding:var(--snice-spacing-xs,.5rem) var(--snice-spacing-sm,.75rem);border:1px solid var(--snice-color-border,rgb(226 226 226));background:var(--snice-color-surface,rgb(255 255 255));border-radius:var(--snice-border-radius-md,.25rem);cursor:pointer;transition:background-color var(--snice-transition-fast, 150ms) ease,border-color var(--snice-transition-fast, 150ms) ease;font-size:var(--snice-font-size-sm, .875rem);color:var(--snice-color-text,rgb(23 23 23));font-family:inherit}.calendar__nav-button:hover{background:var(--snice-color-surface-container-low,rgb(250 250 250));border-color:var(--snice-color-border-hover,rgb(204 204 204))}.calendar__nav-button:focus-visible{outline:0;box-shadow:0 0 0 var(--snice-focus-ring-width,2px) var(--snice-focus-ring-color,rgb(59 130 246 / .5))}.calendar__grid{display:grid;grid-template-columns:repeat(7,1fr);background:var(--snice-color-surface,rgb(255 255 255));container-type:inline-size}.calendar__weekday{padding:var(--snice-spacing-sm,.75rem);text-align:center;font-size:var(--snice-font-size-xs, .75rem);font-weight:var(--snice-font-weight-semibold,600);color:var(--snice-color-text-secondary,rgb(82 82 82));text-transform:uppercase;letter-spacing:var(--snice-tracking-widest, .1em);border-bottom:1px solid var(--snice-color-border,rgb(226 226 226))}.calendar__day{box-sizing:border-box;min-width:0;min-height:max(calc(100cqw / 7),3rem,calc(2.125rem + var(--calendar-week-lanes,0) * 1.375rem + var(--calendar-week-more,0rem)));padding:var(--snice-spacing-xs,.5rem);border:1px solid var(--snice-color-border,rgb(226 226 226));border-top:none;border-left:none;cursor:pointer;transition:background-color var(--snice-transition-fast, 150ms) ease;position:relative;background:var(--snice-color-surface,rgb(255 255 255));color:var(--snice-color-text,rgb(23 23 23));overflow:hidden}.calendar__day:hover{background:var(--snice-color-surface-container-low,rgb(250 250 250))}.calendar__day:focus-visible{outline:0;box-shadow:inset 0 0 0 2px var(--snice-focus-ring-color,rgb(59 130 246 / .5))}.calendar__day:nth-child(7n+1){border-left:1px solid var(--snice-color-border,rgb(226 226 226))}.calendar__day--stretch{min-height:max(3rem,calc(2.125rem + var(--calendar-week-lanes,0) * 1.375rem + var(--calendar-week-more,0rem)))}.calendar__day--static{cursor:default}.calendar__day--static:hover{background:var(--snice-color-surface,rgb(255 255 255))}.calendar__day--static.calendar__day--today:hover{background:var(--snice-color-primary-subtle,rgb(239 246 255))}.calendar__day--other-month{background:var(--snice-color-surface,rgb(255 255 255));color:var(--snice-color-text-tertiary,rgb(115 115 115));opacity:.5}.calendar__day--other-month:hover{opacity:.7}.calendar__day--today{background:var(--snice-color-primary-subtle,rgb(239 246 255))}.calendar__day--today:hover{background:var(--snice-color-primary-subtle-hover,rgb(219 234 254))}.calendar__day--selected{background:var(--snice-color-primary,rgb(37 99 235));color:var(--snice-color-text-inverse,rgb(250 250 250))}.calendar__day--selected:hover{background:var(--snice-color-primary-hover,rgb(29 78 216))}.calendar__day--disabled{background:var(--snice-color-surface-container,rgb(241 241 241));color:var(--snice-color-text-tertiary,rgb(115 115 115));opacity:.5;cursor:not-allowed}.calendar__day--disabled:hover{background:var(--snice-color-surface-container,rgb(241 241 241))}.calendar__day-number{font-size:var(--snice-font-size-sm, .875rem);font-weight:var(--snice-font-weight-medium,500);margin-bottom:var(--snice-spacing-2xs,.25rem)}.calendar__day--selected .calendar__day-number{color:var(--snice-color-text-inverse,rgb(250 250 250))}.calendar__event-bar{display:flex;align-items:center;gap:var(--snice-spacing-3xs,.125rem);align-self:start;margin-top:calc(1.875rem + var(--calendar-event-lane,0) * 1.375rem);margin-inline:var(--snice-spacing-3xs,0.125rem);height:1.125rem;line-height:1.125rem;font-size:var(--snice-font-size-2xs, .625rem);padding:0 var(--snice-spacing-2xs,.25rem);border-radius:var(--snice-border-radius-sm,.125rem);background:var(--snice-color-primary,rgb(37 99 235));color:var(--snice-color-text-inverse,rgb(250 250 250));white-space:nowrap;overflow:hidden;cursor:pointer;z-index:1;transition:opacity var(--snice-transition-fast, 150ms) ease}.calendar__event-title{overflow:hidden;text-overflow:ellipsis;min-width:0}.calendar__event-avatar{flex:none;--avatar-size:0.875rem;font-size:.375rem;border-radius:50%;overflow:hidden}.calendar__popover{position:fixed;z-index:var(--snice-z-floating,1000);min-width:14rem;max-width:22rem;padding:var(--snice-spacing-sm,.75rem);border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem);background:var(--snice-color-surface,rgb(255 255 255));color:var(--snice-color-text,rgb(23 23 23));font-size:var(--snice-font-size-sm, .875rem);line-height:1.5;box-shadow:var(--snice-shadow-lg,0 10px 15px -3px rgb(0 0 0 / .1))}.calendar__popover:focus-visible{outline:0;box-shadow:var(--snice-shadow-lg,0 10px 15px -3px rgb(0 0 0 / .1)),0 0 0 var(--snice-focus-ring-width,2px) var(--snice-focus-ring-color,rgb(59 130 246 / .5))}.calendar__popover-loading{color:var(--snice-color-text-secondary,rgb(82 82 82));font-size:var(--snice-font-size-xs, .75rem)}.calendar__tooltip{position:fixed;z-index:var(--snice-z-floating,1000);max-width:18rem;padding:var(--snice-spacing-2xs,.25rem) var(--snice-spacing-xs,.5rem);border-radius:var(--snice-border-radius-md,.25rem);background:var(--snice-tooltip-bg,rgb(51 51 51));color:var(--snice-color-text-inverse,rgb(250 250 250));font-size:var(--snice-font-size-xs, .75rem);line-height:1.4;box-shadow:var(--snice-shadow-md,0 4px 6px -1px rgb(0 0 0 / .1));pointer-events:none}.calendar__event-bar:hover{opacity:.8}.calendar__event-bar--continues-left{border-top-left-radius:0;border-bottom-left-radius:0;margin-inline-start:0}.calendar__event-bar--continues-right{border-top-right-radius:0;border-bottom-right-radius:0;margin-inline-end:0}.calendar__more{position:absolute;bottom:var(--snice-spacing-3xs,.125rem);left:var(--snice-spacing-2xs,.25rem);font-size:var(--snice-font-size-xs, .75rem);font-weight:var(--snice-font-weight-medium,500);color:var(--snice-color-text,rgb(23 23 23));cursor:pointer}.calendar__more:hover{text-decoration:underline}.calendar__more:focus-visible{outline:0;box-shadow:0 0 0 var(--snice-focus-ring-width,2px) var(--snice-focus-ring-color,rgb(59 130 246 / .5))}.calendar__week-number{padding:var(--snice-spacing-sm,.75rem) var(--snice-spacing-xs,.5rem);text-align:center;font-size:var(--snice-font-size-xs, .75rem);color:var(--snice-color-text-tertiary,rgb(115 115 115));background:var(--snice-color-surface-container-low,rgb(250 250 250));border-right:1px solid var(--snice-color-border,rgb(226 226 226))}.calendar--week .calendar__grid{grid-template-columns:repeat(7,1fr)}.calendar--week .calendar__day{min-height:7.5rem}.calendar--day .calendar__grid{grid-template-columns:1fr}.calendar--day .calendar__day{min-height:25rem}@media (prefers-reduced-motion:reduce){*{transition-duration:0s!important;animation-duration:0s!important}}";
|
|
5
|
+
var cssContent = ":host([hidden]){display:none}:host{display:block;font-family:var(--snice-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif);contain:layout style}:host([overlay-open]){position:relative;z-index:var(--snice-z-floating,1000)}.calendar{width:100%;max-width:37.5rem;position:relative;height:100%;display:flex;flex-direction:column}.calendar__header{font-family:var(--snice-font-family-display, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif);display:flex;align-items:center;justify-content:space-between;padding:var(--snice-spacing-md,1rem);background:var(--snice-color-surface,rgb(255 255 255));border-bottom:1px solid var(--snice-color-border,rgb(226 226 226))}.calendar__title{font-family:var(--snice-font-family-display, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif);font-size:var(--snice-heading-md, 1.125rem);font-weight:var(--snice-font-weight-semibold,600);color:var(--snice-color-text,rgb(23 23 23))}.calendar__nav{display:flex;gap:var(--snice-spacing-xs,.5rem)}.calendar__nav-button{padding:var(--snice-spacing-xs,.5rem) var(--snice-spacing-sm,.75rem);border:1px solid var(--snice-color-border,rgb(226 226 226));background:var(--snice-color-surface,rgb(255 255 255));border-radius:var(--snice-border-radius-md,.25rem);cursor:pointer;transition:background-color var(--snice-transition-fast, 150ms) ease,border-color var(--snice-transition-fast, 150ms) ease;font-size:var(--snice-font-size-sm, .875rem);color:var(--snice-color-text,rgb(23 23 23));font-family:inherit}.calendar__nav-button:hover{background:var(--snice-color-surface-container-low,rgb(250 250 250));border-color:var(--snice-color-border-hover,rgb(204 204 204))}.calendar__nav-button:focus-visible{outline:0;box-shadow:0 0 0 var(--snice-focus-ring-width,2px) var(--snice-focus-ring-color,rgb(59 130 246 / .5))}.calendar__grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));grid-template-rows:min-content repeat(6,var(--calendar-row-cap,auto));flex:1 1 auto;position:relative;background:var(--snice-color-surface,rgb(255 255 255));container-type:inline-size}.calendar__weekday{box-sizing:border-box;min-width:0;overflow:hidden;padding:var(--snice-spacing-sm,.75rem);text-align:center;font-size:var(--snice-font-size-xs, .75rem);font-weight:var(--snice-font-weight-semibold,600);color:var(--snice-color-text-secondary,rgb(82 82 82));text-transform:uppercase;letter-spacing:var(--snice-tracking-widest, .1em);border-bottom:1px solid var(--snice-color-border,rgb(226 226 226))}.calendar__day{box-sizing:border-box;min-width:0;min-height:min(max(calc(100cqw / 7),3rem,calc(2.125rem + var(--calendar-week-lanes,0) * 1.375rem + var(--calendar-week-more,0rem))),var(--calendar-row-cap,100000px));padding:var(--snice-spacing-xs,.5rem);border:1px solid var(--snice-color-border,rgb(226 226 226));border-top:none;border-left:none;cursor:pointer;transition:background-color var(--snice-transition-fast, 150ms) ease;position:relative;background:var(--snice-color-surface,rgb(255 255 255));color:var(--snice-color-text,rgb(23 23 23));overflow:hidden}.calendar__day:hover{background:var(--snice-color-surface-container-low,rgb(250 250 250))}.calendar__day:focus-visible{outline:0;box-shadow:inset 0 0 0 2px var(--snice-focus-ring-color,rgb(59 130 246 / .5))}.calendar__day--week-start{border-left:1px solid var(--snice-color-border,rgb(226 226 226))}.calendar--week-numbers .calendar__day--week-start{border-left:none}.calendar__day--stretch{min-height:min(max(3rem,calc(2.125rem + var(--calendar-week-lanes,0) * 1.375rem + var(--calendar-week-more,0rem))),var(--calendar-row-cap,100000px))}.calendar__day--static{cursor:default}.calendar__day--static:hover{background:var(--snice-color-surface,rgb(255 255 255))}.calendar__day--static.calendar__day--today:hover{background:var(--snice-color-primary-subtle,rgb(239 246 255))}.calendar__day--other-month{background:var(--snice-color-surface,rgb(255 255 255));color:var(--snice-color-text-tertiary,rgb(115 115 115));opacity:.5}.calendar__day--other-month:hover{opacity:.7}.calendar__day--today{background:var(--snice-color-primary-subtle,rgb(239 246 255))}.calendar__day--today:hover{background:var(--snice-color-primary-subtle-hover,rgb(219 234 254))}.calendar__day--selected{background:var(--snice-color-primary,rgb(37 99 235));color:var(--snice-color-text-inverse,rgb(250 250 250))}.calendar__day--selected:hover{background:var(--snice-color-primary-hover,rgb(29 78 216))}.calendar__day--disabled{background:var(--snice-color-surface-container,rgb(241 241 241));color:var(--snice-color-text-tertiary,rgb(115 115 115));opacity:.5;cursor:not-allowed}.calendar__day--disabled:hover{background:var(--snice-color-surface-container,rgb(241 241 241))}.calendar__day-number{font-size:var(--snice-font-size-sm, .875rem);font-weight:var(--snice-font-weight-medium,500);margin-bottom:var(--snice-spacing-2xs,.25rem)}.calendar__day--selected .calendar__day-number{color:var(--snice-color-text-inverse,rgb(250 250 250))}.calendar__event-bar{display:flex;align-items:center;gap:var(--snice-spacing-3xs,.125rem);position:absolute;inset:0 0 auto 0;margin-top:calc(1.875rem + var(--calendar-event-lane,0) * 1.375rem);margin-inline:var(--snice-spacing-3xs,0.125rem);height:1.125rem;line-height:1.125rem;font-size:var(--snice-font-size-2xs, .625rem);padding:0 var(--snice-spacing-2xs,.25rem);border-radius:var(--snice-border-radius-sm,.125rem);background:var(--snice-color-primary,rgb(37 99 235));color:var(--snice-color-text-inverse,rgb(250 250 250));white-space:nowrap;overflow:hidden;cursor:pointer;z-index:1;transition:opacity var(--snice-transition-fast, 150ms) ease}.calendar__event-bar--compact{padding-inline:var(--snice-spacing-3xs,0.125rem)}.calendar__event-title{overflow:hidden;text-overflow:ellipsis;min-width:0}.calendar__event-avatar{flex:none;--avatar-size:0.875rem;font-size:.375rem;border-radius:50%;overflow:hidden}.calendar__popover{position:absolute;z-index:var(--snice-z-floating,1000);min-width:14rem;max-width:22rem;padding:var(--snice-spacing-sm,.75rem);border:1px solid var(--snice-color-border,rgb(226 226 226));border-radius:var(--snice-border-radius-md,.25rem);background:var(--snice-color-surface,rgb(255 255 255));color:var(--snice-color-text,rgb(23 23 23));font-size:var(--snice-font-size-sm, .875rem);line-height:1.5;box-shadow:var(--snice-shadow-lg,0 10px 15px -3px rgb(0 0 0 / .1))}.calendar__popover:focus-visible{outline:0;box-shadow:var(--snice-shadow-lg,0 10px 15px -3px rgb(0 0 0 / .1)),0 0 0 var(--snice-focus-ring-width,2px) var(--snice-focus-ring-color,rgb(59 130 246 / .5))}.calendar__popover-loading{color:var(--snice-color-text-secondary,rgb(82 82 82));font-size:var(--snice-font-size-xs, .75rem)}.calendar__more-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--snice-spacing-3xs,.125rem);max-height:15rem;overflow-y:auto}.calendar__more-item{display:flex;align-items:center;gap:var(--snice-spacing-xs,.5rem);width:100%;padding:var(--snice-spacing-2xs,.25rem) var(--snice-spacing-xs,.5rem);border:none;border-radius:var(--snice-border-radius-sm,.125rem);background:0 0;color:var(--snice-color-text,rgb(23 23 23));font-family:inherit;font-size:var(--snice-font-size-sm, .875rem);text-align:start;cursor:pointer;transition:background-color var(--snice-transition-fast, 150ms) ease}.calendar__more-item:hover{background:var(--snice-color-surface-container-low,rgb(250 250 250))}.calendar__more-item:focus-visible{outline:0;box-shadow:0 0 0 var(--snice-focus-ring-width,2px) var(--snice-focus-ring-color,rgb(59 130 246 / .5))}.calendar__more-dot{flex:none;width:.5rem;height:.5rem;border-radius:50%;background:var(--snice-color-primary,rgb(37 99 235))}.calendar__more-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.calendar__more-date{margin:0 0 var(--snice-spacing-2xs,.25rem);font-size:var(--snice-font-size-xs, .75rem);font-weight:var(--snice-font-weight-semibold,600);color:var(--snice-color-text-secondary,rgb(82 82 82))}.calendar__tooltip{position:absolute;z-index:var(--snice-z-floating,1000);max-width:18rem;padding:var(--snice-spacing-2xs,.25rem) var(--snice-spacing-xs,.5rem);border-radius:var(--snice-border-radius-md,.25rem);background:var(--snice-tooltip-bg,rgb(51 51 51));color:var(--snice-tooltip-color,rgb(255 255 255));font-size:var(--snice-font-size-xs, .75rem);line-height:1.4;box-shadow:var(--snice-shadow-md,0 4px 6px -1px rgb(0 0 0 / .1));pointer-events:none}.calendar__event-bar:hover{opacity:.8}.calendar__event-bar--continues-left{border-top-left-radius:0;border-bottom-left-radius:0;margin-inline-start:0}.calendar__event-bar--continues-right{border-top-right-radius:0;border-bottom-right-radius:0;margin-inline-end:0}.calendar__more{position:absolute;bottom:var(--snice-spacing-3xs,.125rem);left:var(--snice-spacing-2xs,.25rem);font-size:var(--snice-font-size-xs, .75rem);font-weight:var(--snice-font-weight-medium,500);color:var(--snice-color-text,rgb(23 23 23));cursor:pointer}.calendar__more:hover{text-decoration:underline}.calendar__more:focus-visible{outline:0;box-shadow:0 0 0 var(--snice-focus-ring-width,2px) var(--snice-focus-ring-color,rgb(59 130 246 / .5))}.calendar--week-numbers .calendar__grid{grid-template-columns:var(--calendar-week-number-width,2.25rem) repeat(7,minmax(0,1fr))}.calendar--week-numbers .calendar__weekday{padding-inline:var(--snice-spacing-2xs,0.25rem)}.calendar--week-numbers .calendar__day{min-height:min(max(calc((100cqw - var(--calendar-week-number-width,2.25rem))/ 7),3rem,calc(2.125rem + var(--calendar-week-lanes,0) * 1.375rem + var(--calendar-week-more,0rem))),var(--calendar-row-cap,100000px))}.calendar__week-number{box-sizing:border-box;display:flex;align-items:flex-start;justify-content:center;padding:var(--snice-spacing-xs,.5rem) var(--snice-spacing-2xs,.25rem);text-align:center;font-size:var(--snice-font-size-xs, .75rem);font-variant-numeric:tabular-nums;color:var(--snice-color-text-tertiary,rgb(115 115 115));background:var(--snice-color-surface-container-low,rgb(250 250 250));border:1px solid var(--snice-color-border,rgb(226 226 226));border-top:none}.calendar__week-number--header{background:var(--snice-color-surface,rgb(255 255 255));border:none;border-bottom:1px solid var(--snice-color-border,rgb(226 226 226))}.calendar--week .calendar__grid{grid-template-columns:repeat(7,1fr)}.calendar--week .calendar__day{min-height:7.5rem}.calendar--day .calendar__grid{grid-template-columns:1fr}.calendar--day .calendar__day{min-height:25rem}@media (prefers-reduced-motion:reduce){*{transition-duration:0s!important;animation-duration:0s!important}}";
|
|
6
6
|
|
|
7
7
|
let SniceCalendar = (() => {
|
|
8
8
|
let _classDecorators = [element('snice-calendar')];
|
|
@@ -55,18 +55,24 @@ let SniceCalendar = (() => {
|
|
|
55
55
|
let _eventPopover_extraInitializers = [];
|
|
56
56
|
let _dispatchChange_decorators;
|
|
57
57
|
let _dispatchEventClick_decorators;
|
|
58
|
-
let _dispatchMoreClick_decorators;
|
|
59
58
|
let _styles_decorators;
|
|
60
59
|
let _initialize_decorators;
|
|
61
60
|
let _requestEventPopoverContent_decorators;
|
|
62
61
|
let _cleanupPopover_decorators;
|
|
63
62
|
let _handlePropertyChange_decorators;
|
|
63
|
+
let _handleCalendarResize_decorators;
|
|
64
64
|
let _handleWeekdayInputsChange_decorators;
|
|
65
65
|
var SniceCalendar = class extends _classSuper {
|
|
66
66
|
static { _classThis = this; }
|
|
67
67
|
constructor() {
|
|
68
68
|
super(...arguments);
|
|
69
|
-
|
|
69
|
+
/**
|
|
70
|
+
* The selected day, or `null` for "nothing selected yet" — the state a
|
|
71
|
+
* calendar starts in. A default of today would paint the selected
|
|
72
|
+
* background over today's own highlight, making `highlight-today` invisible
|
|
73
|
+
* and announcing `aria-selected` for a choice the user never made.
|
|
74
|
+
*/
|
|
75
|
+
this.value = (__runInitializers(this, _instanceExtraInitializers), __runInitializers(this, _value_initializers, null));
|
|
70
76
|
this.view = (__runInitializers(this, _value_extraInitializers), __runInitializers(this, _view_initializers, 'month'));
|
|
71
77
|
this.events = (__runInitializers(this, _view_extraInitializers), __runInitializers(this, _events_initializers, []));
|
|
72
78
|
this.minDate = (__runInitializers(this, _events_extraInitializers), __runInitializers(this, _minDate_initializers, ''));
|
|
@@ -97,6 +103,7 @@ let SniceCalendar = (() => {
|
|
|
97
103
|
this.closeEventPopover({ returnFocus: false });
|
|
98
104
|
};
|
|
99
105
|
this.dayCells = [];
|
|
106
|
+
this.weekNumberCells = [];
|
|
100
107
|
this.focusedDate = null;
|
|
101
108
|
this.handleGridKeydown = (e) => {
|
|
102
109
|
const target = e.target;
|
|
@@ -159,6 +166,12 @@ let SniceCalendar = (() => {
|
|
|
159
166
|
cell?.focus();
|
|
160
167
|
});
|
|
161
168
|
};
|
|
169
|
+
/** True while `--calendar-row-cap` is holding the week rows below the size
|
|
170
|
+
* they would take of their own accord. */
|
|
171
|
+
this.rowCapped = false;
|
|
172
|
+
/** Box the stripes were last laid out against, so a resize that changes
|
|
173
|
+
* nothing (including the one the render itself causes) is a no-op. */
|
|
174
|
+
this.laidOutFor = '';
|
|
162
175
|
}
|
|
163
176
|
static {
|
|
164
177
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
@@ -178,21 +191,21 @@ let SniceCalendar = (() => {
|
|
|
178
191
|
_eventPopover_decorators = [property({ attribute: false })];
|
|
179
192
|
_dispatchChange_decorators = [dispatch('calendar-change', { bubbles: true, composed: true })];
|
|
180
193
|
_dispatchEventClick_decorators = [dispatch('calendar-event-click', { bubbles: true, composed: true })];
|
|
181
|
-
_dispatchMoreClick_decorators = [dispatch('calendar-more-click', { bubbles: true, composed: true })];
|
|
182
194
|
_styles_decorators = [styles()];
|
|
183
195
|
_initialize_decorators = [ready()];
|
|
184
196
|
_requestEventPopoverContent_decorators = [request('calendar/event-popover')];
|
|
185
197
|
_cleanupPopover_decorators = [dispose()];
|
|
186
|
-
_handlePropertyChange_decorators = [watch('value'), watch('events'), watch('eventTooltip'), watch('noDaySelect'), watch('cellSizing')];
|
|
198
|
+
_handlePropertyChange_decorators = [watch('value'), watch('events'), watch('eventTooltip'), watch('noDaySelect'), watch('cellSizing'), watch('showWeekNumbers'), watch('highlightToday')];
|
|
199
|
+
_handleCalendarResize_decorators = [observe('resize', { throttle: 100 })];
|
|
187
200
|
_handleWeekdayInputsChange_decorators = [watch('locale'), watch('firstDayOfWeek')];
|
|
188
201
|
__esDecorate(this, null, _dispatchChange_decorators, { kind: "method", name: "dispatchChange", static: false, private: false, access: { has: obj => "dispatchChange" in obj, get: obj => obj.dispatchChange }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
189
202
|
__esDecorate(this, null, _dispatchEventClick_decorators, { kind: "method", name: "dispatchEventClick", static: false, private: false, access: { has: obj => "dispatchEventClick" in obj, get: obj => obj.dispatchEventClick }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
190
|
-
__esDecorate(this, null, _dispatchMoreClick_decorators, { kind: "method", name: "dispatchMoreClick", static: false, private: false, access: { has: obj => "dispatchMoreClick" in obj, get: obj => obj.dispatchMoreClick }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
191
203
|
__esDecorate(this, null, _styles_decorators, { kind: "method", name: "styles", static: false, private: false, access: { has: obj => "styles" in obj, get: obj => obj.styles }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
192
204
|
__esDecorate(this, null, _initialize_decorators, { kind: "method", name: "initialize", static: false, private: false, access: { has: obj => "initialize" in obj, get: obj => obj.initialize }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
193
205
|
__esDecorate(this, null, _requestEventPopoverContent_decorators, { kind: "method", name: "requestEventPopoverContent", static: false, private: false, access: { has: obj => "requestEventPopoverContent" in obj, get: obj => obj.requestEventPopoverContent }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
194
206
|
__esDecorate(this, null, _cleanupPopover_decorators, { kind: "method", name: "cleanupPopover", static: false, private: false, access: { has: obj => "cleanupPopover" in obj, get: obj => obj.cleanupPopover }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
195
207
|
__esDecorate(this, null, _handlePropertyChange_decorators, { kind: "method", name: "handlePropertyChange", static: false, private: false, access: { has: obj => "handlePropertyChange" in obj, get: obj => obj.handlePropertyChange }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
208
|
+
__esDecorate(this, null, _handleCalendarResize_decorators, { kind: "method", name: "handleCalendarResize", static: false, private: false, access: { has: obj => "handleCalendarResize" in obj, get: obj => obj.handleCalendarResize }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
196
209
|
__esDecorate(this, null, _handleWeekdayInputsChange_decorators, { kind: "method", name: "handleWeekdayInputsChange", static: false, private: false, access: { has: obj => "handleWeekdayInputsChange" in obj, get: obj => obj.handleWeekdayInputsChange }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
197
210
|
__esDecorate(null, null, _value_decorators, { kind: "field", name: "value", static: false, private: false, access: { has: obj => "value" in obj, get: obj => obj.value, set: (obj, value) => { obj.value = value; } }, metadata: _metadata }, _value_initializers, _value_extraInitializers);
|
|
198
211
|
__esDecorate(null, null, _view_decorators, { kind: "field", name: "view", static: false, private: false, access: { has: obj => "view" in obj, get: obj => obj.view, set: (obj, value) => { obj.view = value; } }, metadata: _metadata }, _view_initializers, _view_extraInitializers);
|
|
@@ -212,6 +225,14 @@ let SniceCalendar = (() => {
|
|
|
212
225
|
SniceCalendar = _classThis = _classDescriptor.value;
|
|
213
226
|
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
214
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Columns the day grid is shifted by. The week-number column occupies the
|
|
230
|
+
* grid's first column, so every explicitly-placed child — weekday headers,
|
|
231
|
+
* day cells, event stripes — moves one column right while it is shown.
|
|
232
|
+
*/
|
|
233
|
+
get columnOffset() {
|
|
234
|
+
return this.showWeekNumbers ? 1 : 0;
|
|
235
|
+
}
|
|
215
236
|
computeRovingIndex(days) {
|
|
216
237
|
// Prefer: focused → selected → today → first in-month day
|
|
217
238
|
const same = (a, b) => a.getFullYear() === b.getFullYear() &&
|
|
@@ -242,8 +263,24 @@ let SniceCalendar = (() => {
|
|
|
242
263
|
dispatchEventClick(event) {
|
|
243
264
|
return { event, calendar: this };
|
|
244
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* `calendar-more-click` carries a default action (the built-in day panel),
|
|
268
|
+
* so it is cancelable and the component has to read the result of the
|
|
269
|
+
* dispatch. `@dispatch` accepts `cancelable` — it is EventInit passthrough —
|
|
270
|
+
* but the decorated method returns the detail, not `dispatchEvent`'s
|
|
271
|
+
* boolean, so a cancelable default action cannot be observed through it.
|
|
272
|
+
* Dispatched by hand for that reason, the same way `snice-link`'s `navigate`
|
|
273
|
+
* and `snice-stepper`'s `step-change` are.
|
|
274
|
+
*
|
|
275
|
+
* @returns `false` when a listener called `preventDefault()`.
|
|
276
|
+
*/
|
|
245
277
|
dispatchMoreClick(date, count) {
|
|
246
|
-
return
|
|
278
|
+
return this.dispatchEvent(new CustomEvent('calendar-more-click', {
|
|
279
|
+
detail: { date, count, calendar: this },
|
|
280
|
+
bubbles: true,
|
|
281
|
+
composed: true,
|
|
282
|
+
cancelable: true,
|
|
283
|
+
}));
|
|
247
284
|
}
|
|
248
285
|
styles() {
|
|
249
286
|
return css /*css*/ `${cssContent}`;
|
|
@@ -296,7 +333,7 @@ let SniceCalendar = (() => {
|
|
|
296
333
|
weekdayEl.className = 'calendar__weekday';
|
|
297
334
|
weekdayEl.textContent = day;
|
|
298
335
|
weekdayEl.style.gridRow = '1';
|
|
299
|
-
weekdayEl.style.gridColumn = String(i + 1);
|
|
336
|
+
weekdayEl.style.gridColumn = String(i + 1 + this.columnOffset);
|
|
300
337
|
this.grid.appendChild(weekdayEl);
|
|
301
338
|
});
|
|
302
339
|
// Mark grid for a11y
|
|
@@ -313,13 +350,33 @@ let SniceCalendar = (() => {
|
|
|
313
350
|
// date so today/selected gets the 0.
|
|
314
351
|
dayCell.setAttribute('tabindex', i === 0 ? '0' : '-1');
|
|
315
352
|
dayCell.style.gridRow = String(Math.floor(i / 7) + 2);
|
|
316
|
-
dayCell.style.gridColumn = String((i % 7) + 1);
|
|
353
|
+
dayCell.style.gridColumn = String((i % 7) + 1 + this.columnOffset);
|
|
317
354
|
const dayNumber = document.createElement('div');
|
|
318
355
|
dayNumber.className = 'calendar__day-number';
|
|
319
356
|
dayCell.appendChild(dayNumber);
|
|
320
357
|
this.grid.appendChild(dayCell);
|
|
321
358
|
this.dayCells.push(dayCell);
|
|
322
359
|
}
|
|
360
|
+
// Week-number column: a header corner cell plus one row header per week
|
|
361
|
+
// row, all in the reserved first column. Built once here and attached only
|
|
362
|
+
// while `show-week-numbers` is on, so a calendar without it carries no
|
|
363
|
+
// extra nodes.
|
|
364
|
+
this.weekNumberHeader = document.createElement('div');
|
|
365
|
+
this.weekNumberHeader.className =
|
|
366
|
+
'calendar__week-number calendar__week-number--header';
|
|
367
|
+
this.weekNumberHeader.setAttribute('part', 'week-number-header');
|
|
368
|
+
this.weekNumberHeader.setAttribute('aria-hidden', 'true');
|
|
369
|
+
this.weekNumberHeader.style.gridRow = '1';
|
|
370
|
+
this.weekNumberHeader.style.gridColumn = '1';
|
|
371
|
+
for (let week = 0; week < 6; week++) {
|
|
372
|
+
const weekCell = document.createElement('div');
|
|
373
|
+
weekCell.className = 'calendar__week-number';
|
|
374
|
+
weekCell.setAttribute('part', 'week-number');
|
|
375
|
+
weekCell.setAttribute('role', 'rowheader');
|
|
376
|
+
weekCell.style.gridRow = String(week + 2);
|
|
377
|
+
weekCell.style.gridColumn = '1';
|
|
378
|
+
this.weekNumberCells.push(weekCell);
|
|
379
|
+
}
|
|
323
380
|
// Shared tooltip overlay for event bars — one element, repositioned per
|
|
324
381
|
// bar, so rich content can load lazily without a tooltip instance per bar.
|
|
325
382
|
this.tooltipEl = document.createElement('div');
|
|
@@ -351,20 +408,40 @@ let SniceCalendar = (() => {
|
|
|
351
408
|
async *requestEventPopoverContent(event) {
|
|
352
409
|
return await (yield { event });
|
|
353
410
|
}
|
|
354
|
-
|
|
411
|
+
/**
|
|
412
|
+
* Opens the shared overlay, empty, anchored on `anchor`, and arms its
|
|
413
|
+
* Escape / outside-press dismissal. Both panels the calendar owns — the
|
|
414
|
+
* event popover and the "+N more" day list — go through here, so they share
|
|
415
|
+
* one dismissal contract and one focus-return target.
|
|
416
|
+
*
|
|
417
|
+
* @returns the token identifying this opening; async content must check it
|
|
418
|
+
* against `popoverToken` before painting.
|
|
419
|
+
*/
|
|
420
|
+
beginPopover(anchor, label) {
|
|
355
421
|
const token = ++this.popoverToken;
|
|
356
422
|
this.hideEventTooltip();
|
|
357
|
-
//
|
|
358
|
-
this
|
|
423
|
+
// A trigger that advertises aria-haspopup owes the reader the panel's
|
|
424
|
+
// state too — and the previous anchor is stale the moment this one opens
|
|
425
|
+
// (an entry in the day panel re-anchors the overlay on the same chip).
|
|
426
|
+
this.setAnchorExpanded(this.popoverBar, false);
|
|
427
|
+
this.setAnchorExpanded(anchor, true);
|
|
428
|
+
this.popoverBar = anchor;
|
|
429
|
+
this.popoverEl.setAttribute('aria-label', label);
|
|
359
430
|
this.popoverEl.replaceChildren();
|
|
431
|
+
this.popoverEl.hidden = false;
|
|
432
|
+
this.syncOverlayLift();
|
|
433
|
+
document.addEventListener('keydown', this.boundPopoverEscape, true);
|
|
434
|
+
document.addEventListener('mousedown', this.boundPopoverOutside, true);
|
|
435
|
+
return token;
|
|
436
|
+
}
|
|
437
|
+
async openEventPopover(bar, event) {
|
|
438
|
+
// Anchor + loading shell first, so slow content still feels responsive.
|
|
439
|
+
const token = this.beginPopover(bar, event.title || 'Event details');
|
|
360
440
|
const loading = document.createElement('div');
|
|
361
441
|
loading.className = 'calendar__popover-loading';
|
|
362
442
|
loading.textContent = 'Loading…';
|
|
363
443
|
this.popoverEl.appendChild(loading);
|
|
364
|
-
this.popoverEl.hidden = false;
|
|
365
444
|
this.positionPopover(bar);
|
|
366
|
-
document.addEventListener('keydown', this.boundPopoverEscape, true);
|
|
367
|
-
document.addEventListener('mousedown', this.boundPopoverOutside, true);
|
|
368
445
|
let content;
|
|
369
446
|
try {
|
|
370
447
|
if (event.popover !== true && event.popover) {
|
|
@@ -395,24 +472,133 @@ let SniceCalendar = (() => {
|
|
|
395
472
|
this.positionPopover(bar);
|
|
396
473
|
this.popoverEl.focus();
|
|
397
474
|
}
|
|
475
|
+
/**
|
|
476
|
+
* The "+N more" chip's built-in default action: the day's hidden events,
|
|
477
|
+
* listed in the shared overlay.
|
|
478
|
+
*
|
|
479
|
+
* Wiring `calendar-more-click` is an application concern, but a chip that
|
|
480
|
+
* visibly does nothing when clicked reads as broken, so the component owns a
|
|
481
|
+
* sensible default. It is only a default — the event is cancelable, and
|
|
482
|
+
* `preventDefault()` leaves the day to the app.
|
|
483
|
+
*/
|
|
484
|
+
openMorePanel(chip, date, hidden) {
|
|
485
|
+
const dayLabel = date.toLocaleDateString(this.locale, { dateStyle: 'full' });
|
|
486
|
+
this.beginPopover(chip, `${hidden.length} more event${hidden.length === 1 ? '' : 's'} on ${dayLabel}`);
|
|
487
|
+
const heading = document.createElement('p');
|
|
488
|
+
heading.className = 'calendar__more-date';
|
|
489
|
+
heading.setAttribute('part', 'more-panel-date');
|
|
490
|
+
heading.textContent = dayLabel;
|
|
491
|
+
const list = document.createElement('ul');
|
|
492
|
+
list.className = 'calendar__more-list';
|
|
493
|
+
list.setAttribute('part', 'more-list');
|
|
494
|
+
// Explicit: `list-style: none` drops the implicit list role in WebKit.
|
|
495
|
+
list.setAttribute('role', 'list');
|
|
496
|
+
for (const event of hidden) {
|
|
497
|
+
const item = document.createElement('li');
|
|
498
|
+
const entry = document.createElement('button');
|
|
499
|
+
entry.type = 'button';
|
|
500
|
+
entry.className = 'calendar__more-item';
|
|
501
|
+
entry.setAttribute('part', 'more-item');
|
|
502
|
+
const dot = document.createElement('span');
|
|
503
|
+
dot.className = 'calendar__more-dot';
|
|
504
|
+
dot.setAttribute('part', 'more-dot');
|
|
505
|
+
dot.setAttribute('aria-hidden', 'true');
|
|
506
|
+
if (event.color)
|
|
507
|
+
dot.style.background = event.color;
|
|
508
|
+
const title = document.createElement('span');
|
|
509
|
+
title.className = 'calendar__more-title';
|
|
510
|
+
title.textContent = event.title;
|
|
511
|
+
entry.append(dot, title);
|
|
512
|
+
entry.onclick = (e) => this.handleMorePanelEntry(chip, event, e);
|
|
513
|
+
item.appendChild(entry);
|
|
514
|
+
list.appendChild(item);
|
|
515
|
+
}
|
|
516
|
+
this.popoverEl.append(heading, list);
|
|
517
|
+
this.positionPopover(chip);
|
|
518
|
+
this.popoverEl.focus();
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* A panel entry behaves like the event's own stripe: it reports the click,
|
|
522
|
+
* and drills into the event's popover when it has one. Without popover
|
|
523
|
+
* content there is nothing further to show, so the panel closes and hands
|
|
524
|
+
* focus back to the chip.
|
|
525
|
+
*/
|
|
526
|
+
handleMorePanelEntry(chip, event, e) {
|
|
527
|
+
this.handleEventClick(event, e);
|
|
528
|
+
if (event.popover)
|
|
529
|
+
this.openEventPopover(chip, event);
|
|
530
|
+
else
|
|
531
|
+
this.closeEventPopover();
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Places an overlay at a point given in viewport coordinates.
|
|
535
|
+
*
|
|
536
|
+
* `:host` declares `contain: layout`, which makes the host — not the
|
|
537
|
+
* viewport — the containing block for its `position: fixed` descendants, so
|
|
538
|
+
* viewport coordinates written straight into `left`/`top` land the overlay a
|
|
539
|
+
* whole host-offset down the page. The overlays are `position: absolute`
|
|
540
|
+
* inside `.calendar` instead, and the target is converted into that box
|
|
541
|
+
* here, which is correct with or without the containment.
|
|
542
|
+
*/
|
|
543
|
+
placeOverlay(el, viewportX, viewportY) {
|
|
544
|
+
// The containing block is the container's PADDING box, while the rect is
|
|
545
|
+
// its border box — `clientLeft`/`clientTop` are the border widths between
|
|
546
|
+
// them. They are 0 by default and non-zero only when a consumer borders
|
|
547
|
+
// the documented `::part(base)`, which would otherwise shift both overlays
|
|
548
|
+
// off their bar by that width.
|
|
549
|
+
const origin = this.container.getBoundingClientRect();
|
|
550
|
+
el.style.left = `${viewportX - origin.left - this.container.clientLeft}px`;
|
|
551
|
+
el.style.top = `${viewportY - origin.top - this.container.clientTop}px`;
|
|
552
|
+
}
|
|
553
|
+
/** Gap between a bar and its overlay, and the minimum viewport margin. */
|
|
554
|
+
static { this.OVERLAY_GAP = 6; }
|
|
555
|
+
static { this.OVERLAY_EDGE = 4; }
|
|
556
|
+
/** Clamps an overlay's left edge into the viewport. */
|
|
557
|
+
clampOverlayX(left, width) {
|
|
558
|
+
const edge = SniceCalendar.OVERLAY_EDGE;
|
|
559
|
+
const vw = window.innerWidth || 0;
|
|
560
|
+
return Math.max(edge, vw > 0 ? Math.min(left, vw - width - edge) : left);
|
|
561
|
+
}
|
|
398
562
|
positionPopover(bar) {
|
|
399
563
|
const rect = bar.getBoundingClientRect();
|
|
400
|
-
|
|
401
|
-
this.popoverEl.
|
|
564
|
+
const width = this.popoverEl.offsetWidth;
|
|
565
|
+
const height = this.popoverEl.offsetHeight;
|
|
566
|
+
const gap = SniceCalendar.OVERLAY_GAP;
|
|
567
|
+
const edge = SniceCalendar.OVERLAY_EDGE;
|
|
568
|
+
const vh = window.innerHeight || 0;
|
|
569
|
+
let y = rect.bottom + gap;
|
|
570
|
+
if (vh > 0 && y + height > vh - edge) {
|
|
571
|
+
// No room under the bar — flip above it, or pin to the bottom margin
|
|
572
|
+
// when the panel is taller than either side.
|
|
573
|
+
const above = rect.top - gap - height;
|
|
574
|
+
y = above >= edge ? above : Math.max(edge, vh - height - edge);
|
|
575
|
+
}
|
|
576
|
+
this.placeOverlay(this.popoverEl, this.clampOverlayX(rect.left, width), y);
|
|
402
577
|
}
|
|
403
578
|
closeEventPopover(options = {}) {
|
|
404
579
|
if (!this.popoverBar)
|
|
405
580
|
return;
|
|
406
581
|
this.popoverToken++;
|
|
407
582
|
const bar = this.popoverBar;
|
|
583
|
+
this.setAnchorExpanded(bar, false);
|
|
408
584
|
this.popoverBar = null;
|
|
409
585
|
this.popoverEl.hidden = true;
|
|
410
586
|
this.popoverEl.replaceChildren();
|
|
587
|
+
this.syncOverlayLift();
|
|
411
588
|
document.removeEventListener('keydown', this.boundPopoverEscape, true);
|
|
412
589
|
document.removeEventListener('mousedown', this.boundPopoverOutside, true);
|
|
413
590
|
if (options.returnFocus !== false && bar.isConnected)
|
|
414
591
|
bar.focus();
|
|
415
592
|
}
|
|
593
|
+
/** Keeps a popup trigger's `aria-expanded` in step with the overlay. Guarded
|
|
594
|
+
* on `aria-haspopup` so only the anchors that actually advertise a popup —
|
|
595
|
+
* the "+N more" chip and an event bar carrying popover content — claim the
|
|
596
|
+
* state; a plain bar is not a trigger and must not report one. */
|
|
597
|
+
setAnchorExpanded(anchor, expanded) {
|
|
598
|
+
if (!anchor?.hasAttribute('aria-haspopup'))
|
|
599
|
+
return;
|
|
600
|
+
anchor.setAttribute('aria-expanded', String(expanded));
|
|
601
|
+
}
|
|
416
602
|
cleanupPopover() {
|
|
417
603
|
document.removeEventListener('keydown', this.boundPopoverEscape, true);
|
|
418
604
|
document.removeEventListener('mousedown', this.boundPopoverOutside, true);
|
|
@@ -442,16 +628,34 @@ let SniceCalendar = (() => {
|
|
|
442
628
|
this.tooltipEl.hidden = false;
|
|
443
629
|
this.tooltipBar = bar;
|
|
444
630
|
bar.setAttribute('aria-describedby', this.tooltipEl.id);
|
|
445
|
-
|
|
631
|
+
this.syncOverlayLift();
|
|
632
|
+
this.positionTooltip(bar);
|
|
633
|
+
}
|
|
634
|
+
positionTooltip(bar) {
|
|
446
635
|
const rect = bar.getBoundingClientRect();
|
|
447
|
-
|
|
448
|
-
|
|
636
|
+
const gap = SniceCalendar.OVERLAY_GAP;
|
|
637
|
+
const edge = SniceCalendar.OVERLAY_EDGE;
|
|
638
|
+
// Above the bar, or under it when the top of the viewport is in the way.
|
|
639
|
+
let y = rect.top - this.tooltipEl.offsetHeight - gap;
|
|
640
|
+
if (y < edge)
|
|
641
|
+
y = rect.bottom + gap;
|
|
642
|
+
this.placeOverlay(this.tooltipEl, this.clampOverlayX(rect.left, this.tooltipEl.offsetWidth), y);
|
|
449
643
|
}
|
|
450
644
|
hideEventTooltip() {
|
|
451
645
|
this.tooltipToken++;
|
|
452
646
|
this.tooltipEl.hidden = true;
|
|
453
647
|
this.tooltipBar?.removeAttribute('aria-describedby');
|
|
454
648
|
this.tooltipBar = null;
|
|
649
|
+
this.syncOverlayLift();
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Marks the host while a tooltip or popover is showing. Layout containment
|
|
653
|
+
* makes the host a stacking context, so an overlay can only paint above what
|
|
654
|
+
* follows the calendar if the host itself is lifted — see
|
|
655
|
+
* `:host([overlay-open])` in the stylesheet.
|
|
656
|
+
*/
|
|
657
|
+
syncOverlayLift() {
|
|
658
|
+
this.toggleAttribute('overlay-open', !!this.popoverBar || !!this.tooltipBar);
|
|
455
659
|
}
|
|
456
660
|
updateView() {
|
|
457
661
|
// Update header title
|
|
@@ -462,6 +666,9 @@ let SniceCalendar = (() => {
|
|
|
462
666
|
// Update day cells
|
|
463
667
|
const days = this.getMonthDays();
|
|
464
668
|
const currentMonth = this.displayDate.getMonth();
|
|
669
|
+
// The week-number column shifts every explicitly-placed grid child, so it
|
|
670
|
+
// is resolved before the cells are positioned.
|
|
671
|
+
this.syncWeekNumberColumn(days);
|
|
465
672
|
// Resolve which cell should be tab-stoppable (roving tabindex).
|
|
466
673
|
const rovingIndex = this.computeRovingIndex(days);
|
|
467
674
|
days.forEach((date, i) => {
|
|
@@ -475,6 +682,11 @@ let SniceCalendar = (() => {
|
|
|
475
682
|
const isDisabled = this.isDisabled(date);
|
|
476
683
|
// Update classes (preserving role)
|
|
477
684
|
cell.className = 'calendar__day';
|
|
685
|
+
// The week's first cell draws the grid's left edge. A class, not
|
|
686
|
+
// :nth-child — the week-number column adds siblings that would shift
|
|
687
|
+
// any positional selector.
|
|
688
|
+
if (i % 7 === 0)
|
|
689
|
+
cell.classList.add('calendar__day--week-start');
|
|
478
690
|
if (isOtherMonth)
|
|
479
691
|
cell.classList.add('calendar__day--other-month');
|
|
480
692
|
if (isToday)
|
|
@@ -503,15 +715,221 @@ let SniceCalendar = (() => {
|
|
|
503
715
|
});
|
|
504
716
|
this.renderEventStripes(days);
|
|
505
717
|
}
|
|
506
|
-
/**
|
|
507
|
-
*
|
|
508
|
-
|
|
718
|
+
/**
|
|
719
|
+
* Attaches or detaches the week-number column and re-places every
|
|
720
|
+
* explicitly-positioned grid child for the resulting column offset.
|
|
721
|
+
*/
|
|
722
|
+
syncWeekNumberColumn(days) {
|
|
723
|
+
const show = this.showWeekNumbers;
|
|
724
|
+
this.container.classList.toggle('calendar--week-numbers', show);
|
|
725
|
+
if (show) {
|
|
726
|
+
// Inserted in reading order — the corner cell ahead of the weekday
|
|
727
|
+
// strip, each row header ahead of its week's day cells.
|
|
728
|
+
if (!this.weekNumberHeader.isConnected) {
|
|
729
|
+
this.grid.insertBefore(this.weekNumberHeader, this.grid.firstChild);
|
|
730
|
+
}
|
|
731
|
+
this.weekNumberCells.forEach((cell, week) => {
|
|
732
|
+
if (!cell.isConnected)
|
|
733
|
+
this.grid.insertBefore(cell, this.dayCells[week * 7]);
|
|
734
|
+
const weekNumber = this.getWeekNumber(days[week * 7]);
|
|
735
|
+
cell.textContent = String(weekNumber);
|
|
736
|
+
cell.setAttribute('aria-label', `Week ${weekNumber}`);
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
else {
|
|
740
|
+
this.weekNumberHeader.remove();
|
|
741
|
+
this.weekNumberCells.forEach(cell => cell.remove());
|
|
742
|
+
}
|
|
743
|
+
const offset = this.columnOffset;
|
|
744
|
+
const weekdays = this.grid.querySelectorAll('.calendar__weekday');
|
|
745
|
+
weekdays.forEach((el, i) => {
|
|
746
|
+
el.style.gridColumn = String(i + 1 + offset);
|
|
747
|
+
});
|
|
748
|
+
this.dayCells.forEach((cell, i) => {
|
|
749
|
+
cell.style.gridColumn = String((i % 7) + 1 + offset);
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* Number of the week that starts on `weekStart`.
|
|
754
|
+
*
|
|
755
|
+
* Monday-start calendars use ISO-8601 (week 1 is the week holding the year's
|
|
756
|
+
* first Thursday). Every other start-of-week uses the common civil rule —
|
|
757
|
+
* the week containing January 1 is week 1 — anchored on the year the week
|
|
758
|
+
* ends in, so the turn-of-year week is numbered once, not twice.
|
|
759
|
+
*/
|
|
760
|
+
getWeekNumber(weekStart) {
|
|
761
|
+
const WEEK_MS = 7 * 24 * 60 * 60 * 1000;
|
|
762
|
+
const midnight = (y, m, d) => new Date(y, m, d).getTime();
|
|
763
|
+
if (this.firstDayOfWeek === 1) {
|
|
764
|
+
// The ISO week is named by its Thursday.
|
|
765
|
+
const thursday = new Date(weekStart.getFullYear(), weekStart.getMonth(), weekStart.getDate() + 3);
|
|
766
|
+
const isoYear = thursday.getFullYear();
|
|
767
|
+
// January 4 is always in ISO week 1; walk back to that week's Monday.
|
|
768
|
+
const jan4 = new Date(isoYear, 0, 4);
|
|
769
|
+
const week1Monday = midnight(isoYear, 0, 4 - ((jan4.getDay() + 6) % 7));
|
|
770
|
+
return 1 + Math.round((thursday.getTime() - week1Monday) / WEEK_MS);
|
|
771
|
+
}
|
|
772
|
+
const weekEnd = new Date(weekStart.getFullYear(), weekStart.getMonth(), weekStart.getDate() + 6);
|
|
773
|
+
const year = weekEnd.getFullYear();
|
|
774
|
+
const jan1 = new Date(year, 0, 1);
|
|
775
|
+
const week1Start = midnight(year, 0, 1 - ((jan1.getDay() - this.firstDayOfWeek + 7) % 7));
|
|
776
|
+
return 1 + Math.round((midnight(weekStart.getFullYear(), weekStart.getMonth(), weekStart.getDate())
|
|
777
|
+
- week1Start) / WEEK_MS);
|
|
778
|
+
}
|
|
779
|
+
/** Event-lane geometry in rem — mirrors snice-calendar.css. */
|
|
780
|
+
static { this.LANE_HEIGHT_REM = 1.375; }
|
|
781
|
+
/** Day-number strip above the first lane (the constant in the cell's
|
|
782
|
+
* min-height reservation). */
|
|
783
|
+
static { this.LANE_STACK_TOP_REM = 2.125; }
|
|
784
|
+
/** Strip the "+N more" chip claims when a stack overflows. */
|
|
785
|
+
static { this.MORE_CHIP_REM = 1; }
|
|
786
|
+
/** Intrinsic floor of a `cell-sizing="stretch"` cell. */
|
|
787
|
+
static { this.STRETCH_FLOOR_REM = 3; }
|
|
788
|
+
/** Lane depth used when there is no layout to measure (headless DOM,
|
|
789
|
+
* detached, `display: none`). */
|
|
790
|
+
static { this.DEFAULT_EVENT_LANES = 3; }
|
|
791
|
+
/**
|
|
792
|
+
* Height a single lane physically occupies, measured from the top of the
|
|
793
|
+
* cell: the bar sits 1.875rem down and is 1.125rem tall.
|
|
794
|
+
*
|
|
795
|
+
* LANE_STACK_TOP_REM + LANE_HEIGHT_REM (3.5rem) is the *budgeted* cost of a
|
|
796
|
+
* lane — it carries a bottom gap so the next lane has somewhere to go. This
|
|
797
|
+
* is the smaller number the budget falls back to when the row cannot grow:
|
|
798
|
+
* the point below which a drawn lane would be clipped by its own cell.
|
|
799
|
+
*/
|
|
800
|
+
static { this.LANE_MIN_FIT_REM = 3; }
|
|
801
|
+
/** Height the "+N more" chip itself occupies at the bottom of the cell. */
|
|
802
|
+
static { this.MORE_CHIP_FIT_REM = 1.125; }
|
|
803
|
+
/**
|
|
804
|
+
* Narrowest segment, in rem, that still carries an event avatar.
|
|
805
|
+
*
|
|
806
|
+
* A one-day chip in a 400px month grid is ~57px wide; the avatar, its gap,
|
|
807
|
+
* and the bar padding leave the title three characters ("Des…"). The title
|
|
808
|
+
* is the payload and the avatar is an adornment, so — like every
|
|
809
|
+
* professional calendar — a segment that cannot carry both keeps the title
|
|
810
|
+
* and drops the adornment. 4.5rem is the width at which a default-size
|
|
811
|
+
* title still reads next to the avatar.
|
|
812
|
+
*/
|
|
813
|
+
static { this.AVATAR_MIN_SEGMENT_REM = 4.5; }
|
|
814
|
+
/**
|
|
815
|
+
* How many event lanes fit in a day cell, and how many still fit once the
|
|
816
|
+
* "+N more" chip claims its strip.
|
|
817
|
+
*
|
|
818
|
+
* Measured from the cell's own height with every lane reservation cleared,
|
|
819
|
+
* so the budget follows whatever sizes the cell — the square baseline
|
|
820
|
+
* (`100cqw / 7`), a height the host imposes on the calendar, or the stretch
|
|
821
|
+
* floor — and never feeds back on itself. A `cell-sizing="stretch"` cell the
|
|
822
|
+
* host does not constrain has no budget at all: its row grows to fit every
|
|
823
|
+
* lane, which is what "collapse to content" means.
|
|
824
|
+
*/
|
|
825
|
+
laneBudget() {
|
|
826
|
+
const rem = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
|
|
827
|
+
const height = this.dayCells[0]?.getBoundingClientRect().height ?? 0;
|
|
828
|
+
if (!height) {
|
|
829
|
+
const depth = SniceCalendar.DEFAULT_EVENT_LANES;
|
|
830
|
+
return { fit: depth, withMore: depth, height: 0, rem };
|
|
831
|
+
}
|
|
832
|
+
if (this.cellSizing === 'stretch' && !this.rowCapped
|
|
833
|
+
&& height <= SniceCalendar.STRETCH_FLOOR_REM * rem + 1) {
|
|
834
|
+
return { fit: Infinity, withMore: Infinity, height, rem };
|
|
835
|
+
}
|
|
836
|
+
const lanesIn = (reserve) => {
|
|
837
|
+
const budgeted = Math.floor((height / rem - SniceCalendar.LANE_STACK_TOP_REM - reserve)
|
|
838
|
+
/ SniceCalendar.LANE_HEIGHT_REM);
|
|
839
|
+
if (budgeted >= 1)
|
|
840
|
+
return budgeted;
|
|
841
|
+
// Below the budgeted floor a row that can still grow always draws one
|
|
842
|
+
// lane — the reservation at the end of renderEventStripes buys it the
|
|
843
|
+
// height. A capped row has no such recourse, so the lane is drawn only
|
|
844
|
+
// when it already fits; otherwise the day collapses entirely into its
|
|
845
|
+
// chip rather than painting a stripe its cell will clip.
|
|
846
|
+
if (!this.rowCapped)
|
|
847
|
+
return 1;
|
|
848
|
+
const needed = SniceCalendar.LANE_MIN_FIT_REM
|
|
849
|
+
+ (reserve > 0 ? SniceCalendar.MORE_CHIP_FIT_REM : 0);
|
|
850
|
+
return height / rem >= needed ? 1 : 0;
|
|
851
|
+
};
|
|
852
|
+
return {
|
|
853
|
+
fit: lanesIn(0),
|
|
854
|
+
withMore: lanesIn(SniceCalendar.MORE_CHIP_REM),
|
|
855
|
+
height,
|
|
856
|
+
rem,
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Fits the six week rows inside a host that constrains the calendar's
|
|
861
|
+
* height.
|
|
862
|
+
*
|
|
863
|
+
* The square baseline sizes a week row from the *column width*
|
|
864
|
+
* (`100cqw / 7`), which says nothing about how much height the host has
|
|
865
|
+
* given the grid. A host that hands down a definite height — the components
|
|
866
|
+
* page's `aspect-ratio: 1` card is the reported case — therefore gets a grid
|
|
867
|
+
* whose min-content height exceeds its box: the grid overflows, and whatever
|
|
868
|
+
* clips it (that card's `overflow: hidden`) takes the bottom weeks of the
|
|
869
|
+
* month with it.
|
|
870
|
+
*
|
|
871
|
+
* The room the grid has and the room it wants are both measurable, so the
|
|
872
|
+
* fix is to compare them and publish the per-row ceiling when they disagree.
|
|
873
|
+
* With no constraint the container's height IS its content height, the two
|
|
874
|
+
* agree, and nothing is published — square cells and the growable lane
|
|
875
|
+
* reservation are untouched. Measured with the cap cleared, so it never
|
|
876
|
+
* feeds back on itself.
|
|
877
|
+
*
|
|
878
|
+
* Month view only. The cap divides the room into WEEK_ROWS equal shares and
|
|
879
|
+
* lands as a definite `grid-template-rows` track; the week and day views
|
|
880
|
+
* carry their own taller `min-height` at higher specificity, so a definite
|
|
881
|
+
* track there would leave every cell overflowing its own row and painting
|
|
882
|
+
* over the next one. They keep the pre-cap behaviour — the var stays unset,
|
|
883
|
+
* the tracks stay `auto`.
|
|
884
|
+
*/
|
|
885
|
+
syncRowCap() {
|
|
886
|
+
this.grid.style.removeProperty('--calendar-row-cap');
|
|
887
|
+
this.rowCapped = false;
|
|
888
|
+
if (this.view !== 'month')
|
|
889
|
+
return;
|
|
890
|
+
// The host's own content box, not just the container's: `.calendar`'s
|
|
891
|
+
// `height: 100%` resolves to auto against a host sized by `max-height`,
|
|
892
|
+
// so the container reports the height it WANTED and only the host box is
|
|
893
|
+
// actually clamped. Whichever is smaller is the room there really is.
|
|
894
|
+
const hostStyle = getComputedStyle(this);
|
|
895
|
+
const hostRoom = this.clientHeight
|
|
896
|
+
- parseFloat(hostStyle.paddingTop) - parseFloat(hostStyle.paddingBottom);
|
|
897
|
+
const room = Math.min(this.container.clientHeight, hostRoom)
|
|
898
|
+
- this.header.getBoundingClientRect().height;
|
|
899
|
+
const wanted = this.grid.getBoundingClientRect().height;
|
|
900
|
+
// No layout to measure (headless, detached, display:none) — or the rows
|
|
901
|
+
// already fit, which is every unconstrained calendar.
|
|
902
|
+
if (!(room > 0) || !(wanted > 0) || wanted <= room + 0.5)
|
|
903
|
+
return;
|
|
904
|
+
const weekdayHeight = this.grid.querySelector('.calendar__weekday')?.getBoundingClientRect().height ?? 0;
|
|
905
|
+
// A cell cannot be shorter than its own padding and rules, so a cap below
|
|
906
|
+
// that floor buys no height — it only detaches the rows from their tracks
|
|
907
|
+
// and stacks each week on top of the next. Below the floor the calendar
|
|
908
|
+
// has compressed as far as it physically can: it overflows a host that
|
|
909
|
+
// short, the way it always did, rather than rendering weeks over weeks.
|
|
910
|
+
const cell = this.dayCells[0];
|
|
911
|
+
const cellStyle = cell ? getComputedStyle(cell) : null;
|
|
912
|
+
const cellFloor = cellStyle
|
|
913
|
+
? parseFloat(cellStyle.paddingTop) + parseFloat(cellStyle.paddingBottom)
|
|
914
|
+
+ parseFloat(cellStyle.borderTopWidth)
|
|
915
|
+
+ parseFloat(cellStyle.borderBottomWidth)
|
|
916
|
+
: 0;
|
|
917
|
+
const cap = Math.max((room - weekdayHeight) / SniceCalendar.WEEK_ROWS, cellFloor);
|
|
918
|
+
if (!(cap > 0))
|
|
919
|
+
return;
|
|
920
|
+
this.rowCapped = true;
|
|
921
|
+
this.grid.style.setProperty('--calendar-row-cap', `${cap}px`);
|
|
922
|
+
}
|
|
923
|
+
/** Week rows in a month grid. */
|
|
924
|
+
static { this.WEEK_ROWS = 6; }
|
|
509
925
|
/**
|
|
510
926
|
* Render events as continuous stripes: one bar per (event × week row),
|
|
511
927
|
* spanning the event's days in that week and chopped at week boundaries
|
|
512
928
|
* with continues-left/right styling. Overlapping events stack into lanes
|
|
513
929
|
* per week — earlier start first, longer event first on ties — like
|
|
514
|
-
* professional calendars.
|
|
930
|
+
* professional calendars. How many of those lanes are drawn is the week's
|
|
931
|
+
* share of the day cell's height (see laneBudget); the rest collapse into
|
|
932
|
+
* the day's "+N more" chip.
|
|
515
933
|
*/
|
|
516
934
|
renderEventStripes(days) {
|
|
517
935
|
this.closeEventPopover({ returnFocus: false }); // anchors are re-created
|
|
@@ -521,6 +939,9 @@ let SniceCalendar = (() => {
|
|
|
521
939
|
cell.style.removeProperty('--calendar-week-lanes');
|
|
522
940
|
cell.style.removeProperty('--calendar-week-more');
|
|
523
941
|
});
|
|
942
|
+
// Before anything is measured and regardless of whether this month has
|
|
943
|
+
// events: an empty calendar in a short host overflows too.
|
|
944
|
+
this.syncRowCap();
|
|
524
945
|
if (!this.events || this.events.length === 0)
|
|
525
946
|
return;
|
|
526
947
|
// Local-midnight timestamps for the visible grid; events normalize to the
|
|
@@ -553,14 +974,28 @@ let SniceCalendar = (() => {
|
|
|
553
974
|
});
|
|
554
975
|
});
|
|
555
976
|
resolved.sort((a, b) => a.startTime - b.startTime || b.duration - a.duration || a.order - b.order);
|
|
556
|
-
|
|
977
|
+
// The events each day dropped, in the order they stack — the chip reports
|
|
978
|
+
// the count, and its built-in panel lists them.
|
|
979
|
+
const hiddenPerDay = Array.from({ length: dayTimes.length }, () => []);
|
|
557
980
|
const weekCount = Math.floor(dayTimes.length / 7);
|
|
558
981
|
const weekLaneCounts = new Array(weekCount).fill(0);
|
|
982
|
+
// Measured before a single bar or reservation goes back in, so the budget
|
|
983
|
+
// reflects the room the row has of its own.
|
|
984
|
+
const budget = this.laneBudget();
|
|
985
|
+
// Segment width comes from the same measured cell the lane budget uses, so
|
|
986
|
+
// the avatar decision follows the calendar's real box and is re-taken by
|
|
987
|
+
// the resize observer. No layout to measure → nothing is dropped.
|
|
988
|
+
const cellWidth = this.dayCells[0]?.getBoundingClientRect().width ?? 0;
|
|
989
|
+
const avatarMinWidth = SniceCalendar.AVATAR_MIN_SEGMENT_REM * budget.rem;
|
|
559
990
|
for (let week = 0; week < weekCount; week++) {
|
|
560
991
|
const weekStart = week * 7;
|
|
561
992
|
const weekEnd = weekStart + 6;
|
|
562
993
|
// lanes[lane] holds the occupied [startCol, endCol] ranges in this week.
|
|
563
994
|
const lanes = [];
|
|
995
|
+
const placed = [];
|
|
996
|
+
let stackDepth = 0;
|
|
997
|
+
// Lane assignment first: how deep this week stacks decides whether the
|
|
998
|
+
// "+N more" chip is needed at all, and the chip costs a strip of height.
|
|
564
999
|
for (const item of resolved) {
|
|
565
1000
|
if (item.endIdx < weekStart || item.startIdx > weekEnd)
|
|
566
1001
|
continue;
|
|
@@ -572,22 +1007,35 @@ let SniceCalendar = (() => {
|
|
|
572
1007
|
while (lanes[lane]?.some(([s, e]) => startCol <= e && endCol >= s))
|
|
573
1008
|
lane++;
|
|
574
1009
|
(lanes[lane] ??= []).push([startCol, endCol]);
|
|
575
|
-
|
|
576
|
-
|
|
1010
|
+
placed.push({ item, lane, segStart, segEnd });
|
|
1011
|
+
stackDepth = Math.max(stackDepth, lane + 1);
|
|
1012
|
+
}
|
|
1013
|
+
const visibleLanes = stackDepth <= budget.fit ? stackDepth : budget.withMore;
|
|
1014
|
+
weekLaneCounts[week] = Math.min(stackDepth, visibleLanes);
|
|
1015
|
+
for (const { item, lane, segStart, segEnd } of placed) {
|
|
1016
|
+
if (lane >= visibleLanes) {
|
|
577
1017
|
for (let i = segStart; i <= segEnd; i++)
|
|
578
|
-
hiddenPerDay[i]
|
|
1018
|
+
hiddenPerDay[i].push(item.event);
|
|
579
1019
|
continue;
|
|
580
1020
|
}
|
|
1021
|
+
const startCol = segStart - weekStart;
|
|
1022
|
+
const endCol = segEnd - weekStart;
|
|
581
1023
|
const continuesLeft = segStart > item.startIdx
|
|
582
1024
|
|| (segStart === item.startIdx && item.startsBeforeGrid);
|
|
583
1025
|
const continuesRight = segEnd < item.endIdx
|
|
584
1026
|
|| (segEnd === item.endIdx && item.endsAfterGrid);
|
|
1027
|
+
// A segment too narrow for an avatar plus a legible title runs
|
|
1028
|
+
// compact: title only, tighter inline padding.
|
|
1029
|
+
const compact = cellWidth > 0
|
|
1030
|
+
&& cellWidth * (endCol - startCol + 1) < avatarMinWidth;
|
|
585
1031
|
const bar = document.createElement('div');
|
|
586
1032
|
bar.className = 'calendar__event-bar';
|
|
587
1033
|
if (continuesLeft)
|
|
588
1034
|
bar.classList.add('calendar__event-bar--continues-left');
|
|
589
1035
|
if (continuesRight)
|
|
590
1036
|
bar.classList.add('calendar__event-bar--continues-right');
|
|
1037
|
+
if (compact)
|
|
1038
|
+
bar.classList.add('calendar__event-bar--compact');
|
|
591
1039
|
// A custom className rides along on both the class list and the part
|
|
592
1040
|
// attribute, so events are styleable from outside via
|
|
593
1041
|
// ::part(<className>).
|
|
@@ -599,11 +1047,12 @@ let SniceCalendar = (() => {
|
|
|
599
1047
|
bar.setAttribute('data-event-id', String(item.event.id));
|
|
600
1048
|
bar.setAttribute('data-lane', String(lane));
|
|
601
1049
|
bar.style.gridRow = String(week + 2); // row 1 is the weekday header
|
|
602
|
-
bar.style.gridColumn =
|
|
1050
|
+
bar.style.gridColumn =
|
|
1051
|
+
`${startCol + 1 + this.columnOffset} / ${endCol + 2 + this.columnOffset}`;
|
|
603
1052
|
bar.style.setProperty('--calendar-event-lane', String(lane));
|
|
604
1053
|
if (item.event.color)
|
|
605
1054
|
bar.style.background = item.event.color;
|
|
606
|
-
if (item.event.avatar) {
|
|
1055
|
+
if (item.event.avatar && !compact) {
|
|
607
1056
|
const spec = typeof item.event.avatar === 'string'
|
|
608
1057
|
? { src: item.event.avatar }
|
|
609
1058
|
: item.event.avatar;
|
|
@@ -662,7 +1111,8 @@ let SniceCalendar = (() => {
|
|
|
662
1111
|
this.grid.appendChild(bar);
|
|
663
1112
|
}
|
|
664
1113
|
}
|
|
665
|
-
hiddenPerDay.forEach((
|
|
1114
|
+
hiddenPerDay.forEach((hidden, i) => {
|
|
1115
|
+
const count = hidden.length;
|
|
666
1116
|
if (count === 0)
|
|
667
1117
|
return;
|
|
668
1118
|
const cell = this.dayCells[i];
|
|
@@ -673,35 +1123,49 @@ let SniceCalendar = (() => {
|
|
|
673
1123
|
more.className = 'calendar__more';
|
|
674
1124
|
more.setAttribute('part', 'more-chip');
|
|
675
1125
|
more.textContent = `+${count} more`;
|
|
676
|
-
// The chip is its own control: it reports its day and hidden count,
|
|
677
|
-
//
|
|
1126
|
+
// The chip is its own control: it reports its day and hidden count,
|
|
1127
|
+
// opens the day panel unless the app cancels it, and its clicks never
|
|
1128
|
+
// fall through to the day cell's selection handler.
|
|
678
1129
|
more.setAttribute('role', 'button');
|
|
679
1130
|
more.setAttribute('tabindex', '0');
|
|
1131
|
+
more.setAttribute('aria-haspopup', 'dialog');
|
|
1132
|
+
more.setAttribute('aria-expanded', 'false');
|
|
680
1133
|
more.setAttribute('aria-label', `${count} more event${count === 1 ? '' : 's'} on ${date.toLocaleDateString(this.locale, { dateStyle: 'full' })}`);
|
|
681
|
-
more.onclick = (e) => this.handleMoreClick(date,
|
|
1134
|
+
more.onclick = (e) => this.handleMoreClick(date, more, hidden, e);
|
|
682
1135
|
more.onkeydown = (e) => {
|
|
683
1136
|
if (e.key !== 'Enter' && e.key !== ' ')
|
|
684
1137
|
return;
|
|
685
1138
|
e.preventDefault();
|
|
686
|
-
this.handleMoreClick(date,
|
|
1139
|
+
this.handleMoreClick(date, more, hidden, e);
|
|
687
1140
|
};
|
|
688
1141
|
cell.appendChild(more);
|
|
689
1142
|
});
|
|
690
1143
|
// Reserve row height for the lane stack (and the "+N more" chip) so
|
|
691
1144
|
// stripes never spill past their week row — every cell in a week shares
|
|
692
1145
|
// the reservation, since the grid row is as tall as its tallest cell.
|
|
1146
|
+
// The reservation is only a floor: when the row already has the room it is
|
|
1147
|
+
// left off, so the busy week's row stays level with the rest. That covers
|
|
1148
|
+
// every cell tall enough for the stack it shows; the floor still bites
|
|
1149
|
+
// below 3.5rem (the one lane always drawn) or 4.5rem once the chip claims
|
|
1150
|
+
// its strip — square cells are that short on calendars under ~500px wide.
|
|
693
1151
|
for (let week = 0; week < weekCount; week++) {
|
|
694
1152
|
if (weekLaneCounts[week] === 0)
|
|
695
1153
|
continue;
|
|
696
1154
|
const weekHasMore = hiddenPerDay
|
|
697
|
-
.slice(week * 7, week * 7 + 7).some(
|
|
1155
|
+
.slice(week * 7, week * 7 + 7).some(hidden => hidden.length > 0);
|
|
1156
|
+
const needed = (SniceCalendar.LANE_STACK_TOP_REM
|
|
1157
|
+
+ weekLaneCounts[week] * SniceCalendar.LANE_HEIGHT_REM
|
|
1158
|
+
+ (weekHasMore ? SniceCalendar.MORE_CHIP_REM : 0)) * budget.rem;
|
|
1159
|
+
if (budget.height && needed <= budget.height + 0.5)
|
|
1160
|
+
continue;
|
|
698
1161
|
for (let i = week * 7; i < week * 7 + 7; i++) {
|
|
699
1162
|
const cell = this.dayCells[i];
|
|
700
1163
|
if (!cell)
|
|
701
1164
|
continue;
|
|
702
1165
|
cell.style.setProperty('--calendar-week-lanes', String(weekLaneCounts[week]));
|
|
703
|
-
if (weekHasMore)
|
|
704
|
-
cell.style.setProperty('--calendar-week-more',
|
|
1166
|
+
if (weekHasMore) {
|
|
1167
|
+
cell.style.setProperty('--calendar-week-more', `${SniceCalendar.MORE_CHIP_REM}rem`);
|
|
1168
|
+
}
|
|
705
1169
|
}
|
|
706
1170
|
}
|
|
707
1171
|
}
|
|
@@ -775,7 +1239,13 @@ let SniceCalendar = (() => {
|
|
|
775
1239
|
return this.isSameDay(date, new Date());
|
|
776
1240
|
}
|
|
777
1241
|
isSelected(date) {
|
|
1242
|
+
// No value means no selection at all — and an unparseable one selects
|
|
1243
|
+
// nothing rather than throwing out of the render.
|
|
1244
|
+
if (!this.value)
|
|
1245
|
+
return false;
|
|
778
1246
|
const valueDate = typeof this.value === 'string' ? new Date(this.value) : this.value;
|
|
1247
|
+
if (!(valueDate instanceof Date) || isNaN(valueDate.getTime()))
|
|
1248
|
+
return false;
|
|
779
1249
|
return this.isSameDay(date, valueDate);
|
|
780
1250
|
}
|
|
781
1251
|
isDisabled(date) {
|
|
@@ -808,9 +1278,13 @@ let SniceCalendar = (() => {
|
|
|
808
1278
|
e.stopPropagation();
|
|
809
1279
|
this.dispatchEventClick(event);
|
|
810
1280
|
}
|
|
811
|
-
handleMoreClick(date,
|
|
1281
|
+
handleMoreClick(date, chip, hidden, e) {
|
|
812
1282
|
e.stopPropagation();
|
|
813
|
-
|
|
1283
|
+
// The app gets first refusal: preventDefault() means it is opening its own
|
|
1284
|
+
// day view and the built-in panel must stay out of the way.
|
|
1285
|
+
if (!this.dispatchMoreClick(date, hidden.length))
|
|
1286
|
+
return;
|
|
1287
|
+
this.openMorePanel(chip, date, hidden);
|
|
814
1288
|
}
|
|
815
1289
|
getMonthDays() {
|
|
816
1290
|
const year = this.displayDate.getFullYear();
|
|
@@ -843,6 +1317,20 @@ let SniceCalendar = (() => {
|
|
|
843
1317
|
this.updateView();
|
|
844
1318
|
}
|
|
845
1319
|
}
|
|
1320
|
+
/**
|
|
1321
|
+
* The lane budget comes from the cell's height, and that height follows the
|
|
1322
|
+
* calendar's own box — column width in square mode, the host's height when
|
|
1323
|
+
* it has one. Re-stripe when the box actually changes.
|
|
1324
|
+
*/
|
|
1325
|
+
handleCalendarResize(entry) {
|
|
1326
|
+
if (!this.grid)
|
|
1327
|
+
return;
|
|
1328
|
+
const box = `${Math.round(entry.contentRect.width)}x${Math.round(entry.contentRect.height)}`;
|
|
1329
|
+
if (box === this.laidOutFor)
|
|
1330
|
+
return;
|
|
1331
|
+
this.laidOutFor = box;
|
|
1332
|
+
this.updateView();
|
|
1333
|
+
}
|
|
846
1334
|
handleWeekdayInputsChange() {
|
|
847
1335
|
if (!this.grid)
|
|
848
1336
|
return;
|
|
@@ -850,14 +1338,19 @@ let SniceCalendar = (() => {
|
|
|
850
1338
|
const existing = this.grid.querySelectorAll('.calendar__weekday');
|
|
851
1339
|
existing.forEach(el => el.remove());
|
|
852
1340
|
const weekdays = this.getWeekdays();
|
|
1341
|
+
// Anchor on the first day cell rather than a child index: the week-number
|
|
1342
|
+
// column adds siblings ahead of it, so a positional index would interleave
|
|
1343
|
+
// the strip with the grid's other children.
|
|
1344
|
+
const firstRow = this.weekNumberCells[0]?.isConnected
|
|
1345
|
+
? this.weekNumberCells[0] : this.dayCells[0];
|
|
1346
|
+
const anchor = firstRow ?? null;
|
|
853
1347
|
weekdays.forEach((day, i) => {
|
|
854
1348
|
const weekdayEl = document.createElement('div');
|
|
855
1349
|
weekdayEl.className = 'calendar__weekday';
|
|
856
1350
|
weekdayEl.textContent = day;
|
|
857
1351
|
weekdayEl.style.gridRow = '1';
|
|
858
|
-
weekdayEl.style.gridColumn = String(i + 1);
|
|
859
|
-
|
|
860
|
-
this.grid.insertBefore(weekdayEl, this.grid.children[i] || null);
|
|
1352
|
+
weekdayEl.style.gridColumn = String(i + 1 + this.columnOffset);
|
|
1353
|
+
this.grid.insertBefore(weekdayEl, anchor);
|
|
861
1354
|
});
|
|
862
1355
|
this.updateView();
|
|
863
1356
|
}
|