snice 5.2.2 → 6.0.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 +5 -8
- package/adapters/react/SniceProvider.js +1 -1
- package/adapters/react/SniceRouter.js +1 -1
- package/adapters/react/audio-recorder.d.ts +0 -4
- package/adapters/react/audio-recorder.d.ts.map +1 -1
- package/adapters/react/audio-recorder.js +1 -1
- package/adapters/react/audio-recorder.js.map +1 -1
- package/adapters/react/audio-recorder.tsx +1 -5
- package/adapters/react/avatar.d.ts +0 -1
- package/adapters/react/avatar.d.ts.map +1 -1
- package/adapters/react/avatar.js +1 -1
- package/adapters/react/avatar.js.map +1 -1
- package/adapters/react/avatar.tsx +1 -2
- package/adapters/react/breadcrumbs.d.ts +0 -1
- package/adapters/react/breadcrumbs.d.ts.map +1 -1
- package/adapters/react/breadcrumbs.js +1 -1
- package/adapters/react/breadcrumbs.js.map +1 -1
- package/adapters/react/breadcrumbs.tsx +1 -2
- package/adapters/react/camera-annotate.d.ts +0 -5
- package/adapters/react/camera-annotate.d.ts.map +1 -1
- package/adapters/react/camera-annotate.js +1 -1
- package/adapters/react/camera-annotate.js.map +1 -1
- package/adapters/react/camera-annotate.tsx +1 -6
- package/adapters/react/card.d.ts +0 -2
- package/adapters/react/card.d.ts.map +1 -1
- package/adapters/react/card.js +1 -1
- package/adapters/react/card.js.map +1 -1
- package/adapters/react/card.tsx +1 -3
- package/adapters/react/carousel.d.ts +0 -1
- package/adapters/react/carousel.d.ts.map +1 -1
- package/adapters/react/carousel.js +1 -1
- package/adapters/react/carousel.js.map +1 -1
- package/adapters/react/carousel.tsx +1 -2
- package/adapters/react/cart.d.ts +0 -1
- package/adapters/react/cart.d.ts.map +1 -1
- package/adapters/react/cart.js +1 -1
- package/adapters/react/cart.js.map +1 -1
- package/adapters/react/cart.tsx +1 -2
- package/adapters/react/chart.d.ts +0 -5
- package/adapters/react/chart.d.ts.map +1 -1
- package/adapters/react/chart.js +1 -1
- package/adapters/react/chart.js.map +1 -1
- package/adapters/react/chart.tsx +1 -6
- package/adapters/react/chat.d.ts +4 -1
- package/adapters/react/chat.d.ts.map +1 -1
- package/adapters/react/chat.js +2 -2
- package/adapters/react/chat.js.map +1 -1
- package/adapters/react/chat.tsx +6 -3
- package/adapters/react/chip.d.ts +0 -1
- package/adapters/react/chip.d.ts.map +1 -1
- package/adapters/react/chip.js +1 -1
- package/adapters/react/chip.js.map +1 -1
- package/adapters/react/chip.tsx +1 -2
- package/adapters/react/command-palette.d.ts +0 -4
- package/adapters/react/command-palette.d.ts.map +1 -1
- package/adapters/react/command-palette.js +1 -1
- package/adapters/react/command-palette.js.map +1 -1
- package/adapters/react/command-palette.tsx +1 -5
- package/adapters/react/comments.d.ts +0 -1
- package/adapters/react/comments.d.ts.map +1 -1
- package/adapters/react/comments.js +1 -1
- package/adapters/react/comments.js.map +1 -1
- package/adapters/react/comments.tsx +1 -2
- package/adapters/react/countdown.d.ts +0 -4
- package/adapters/react/countdown.d.ts.map +1 -1
- package/adapters/react/countdown.js +1 -1
- package/adapters/react/countdown.js.map +1 -1
- package/adapters/react/countdown.tsx +1 -5
- package/adapters/react/date-time-picker.d.ts +0 -1
- package/adapters/react/date-time-picker.d.ts.map +1 -1
- package/adapters/react/date-time-picker.js +1 -1
- package/adapters/react/date-time-picker.js.map +1 -1
- package/adapters/react/date-time-picker.tsx +1 -2
- package/adapters/react/file-upload.d.ts +0 -2
- package/adapters/react/file-upload.d.ts.map +1 -1
- package/adapters/react/file-upload.js +1 -1
- package/adapters/react/file-upload.js.map +1 -1
- package/adapters/react/file-upload.tsx +1 -3
- package/adapters/react/heatmap.d.ts +0 -4
- package/adapters/react/heatmap.d.ts.map +1 -1
- package/adapters/react/heatmap.js +1 -1
- package/adapters/react/heatmap.js.map +1 -1
- package/adapters/react/heatmap.tsx +1 -5
- package/adapters/react/image.d.ts +0 -2
- package/adapters/react/image.d.ts.map +1 -1
- package/adapters/react/image.js +1 -1
- package/adapters/react/image.js.map +1 -1
- package/adapters/react/image.tsx +1 -3
- package/adapters/react/kanban.d.ts +0 -4
- package/adapters/react/kanban.d.ts.map +1 -1
- package/adapters/react/kanban.js +1 -1
- package/adapters/react/kanban.js.map +1 -1
- package/adapters/react/kanban.tsx +1 -5
- package/adapters/react/key-value.d.ts +0 -2
- package/adapters/react/key-value.d.ts.map +1 -1
- package/adapters/react/key-value.js +1 -1
- package/adapters/react/key-value.js.map +1 -1
- package/adapters/react/key-value.tsx +1 -3
- package/adapters/react/leaderboard.d.ts +0 -1
- package/adapters/react/leaderboard.d.ts.map +1 -1
- package/adapters/react/leaderboard.js +1 -1
- package/adapters/react/leaderboard.js.map +1 -1
- package/adapters/react/leaderboard.tsx +1 -2
- package/adapters/react/map.d.ts +0 -3
- package/adapters/react/map.d.ts.map +1 -1
- package/adapters/react/map.js +1 -1
- package/adapters/react/map.js.map +1 -1
- package/adapters/react/map.tsx +1 -4
- package/adapters/react/markdown.d.ts +1 -1
- package/adapters/react/markdown.d.ts.map +1 -1
- package/adapters/react/markdown.js +1 -1
- package/adapters/react/markdown.js.map +1 -1
- package/adapters/react/markdown.tsx +2 -2
- package/adapters/react/matchRoute.d.ts +1 -1
- package/adapters/react/matchRoute.js +38 -4
- package/adapters/react/matchRoute.js.map +1 -1
- package/adapters/react/message-strip.d.ts +1 -1
- package/adapters/react/message-strip.js +1 -1
- package/adapters/react/message-strip.tsx +2 -2
- package/adapters/react/music-player.d.ts +0 -1
- package/adapters/react/music-player.d.ts.map +1 -1
- package/adapters/react/music-player.js +1 -1
- package/adapters/react/music-player.js.map +1 -1
- package/adapters/react/music-player.tsx +1 -2
- package/adapters/react/org-chart.d.ts +0 -1
- package/adapters/react/org-chart.d.ts.map +1 -1
- package/adapters/react/org-chart.js +1 -1
- package/adapters/react/org-chart.js.map +1 -1
- package/adapters/react/org-chart.tsx +1 -2
- package/adapters/react/paint.d.ts +0 -1
- package/adapters/react/paint.d.ts.map +1 -1
- package/adapters/react/paint.js +1 -1
- package/adapters/react/paint.js.map +1 -1
- package/adapters/react/paint.tsx +1 -2
- package/adapters/react/podcast-player.d.ts +0 -2
- package/adapters/react/podcast-player.d.ts.map +1 -1
- package/adapters/react/podcast-player.js +1 -1
- package/adapters/react/podcast-player.js.map +1 -1
- package/adapters/react/podcast-player.tsx +1 -3
- package/adapters/react/product-card.d.ts +0 -3
- package/adapters/react/product-card.d.ts.map +1 -1
- package/adapters/react/product-card.js +1 -1
- package/adapters/react/product-card.js.map +1 -1
- package/adapters/react/product-card.tsx +1 -4
- package/adapters/react/qr-reader.d.ts +0 -4
- package/adapters/react/qr-reader.d.ts.map +1 -1
- package/adapters/react/qr-reader.js +1 -1
- package/adapters/react/qr-reader.js.map +1 -1
- package/adapters/react/qr-reader.tsx +1 -5
- package/adapters/react/recipe.d.ts +0 -5
- package/adapters/react/recipe.d.ts.map +1 -1
- package/adapters/react/recipe.js +1 -1
- package/adapters/react/recipe.js.map +1 -1
- package/adapters/react/recipe.tsx +1 -6
- package/adapters/react/route-specificity.d.ts +1 -0
- package/adapters/react/spotlight.d.ts +0 -2
- package/adapters/react/spotlight.d.ts.map +1 -1
- package/adapters/react/spotlight.js +1 -1
- package/adapters/react/spotlight.js.map +1 -1
- package/adapters/react/spotlight.tsx +1 -3
- package/adapters/react/tag-input.d.ts +0 -4
- package/adapters/react/tag-input.d.ts.map +1 -1
- package/adapters/react/tag-input.js +1 -1
- package/adapters/react/tag-input.js.map +1 -1
- package/adapters/react/tag-input.tsx +1 -5
- package/adapters/react/terminal.d.ts +0 -1
- package/adapters/react/terminal.d.ts.map +1 -1
- package/adapters/react/terminal.js +1 -1
- package/adapters/react/terminal.js.map +1 -1
- package/adapters/react/terminal.tsx +1 -2
- package/adapters/react/time-picker.d.ts +0 -1
- package/adapters/react/time-picker.d.ts.map +1 -1
- package/adapters/react/time-picker.js +1 -1
- package/adapters/react/time-picker.js.map +1 -1
- package/adapters/react/time-picker.tsx +1 -2
- package/adapters/react/timer.d.ts +0 -1
- package/adapters/react/timer.d.ts.map +1 -1
- package/adapters/react/timer.js +1 -1
- package/adapters/react/timer.js.map +1 -1
- package/adapters/react/timer.tsx +1 -2
- package/adapters/react/useRequestHandler.js +1 -1
- package/adapters/react/video-player.d.ts +0 -6
- package/adapters/react/video-player.d.ts.map +1 -1
- package/adapters/react/video-player.js +1 -1
- package/adapters/react/video-player.js.map +1 -1
- package/adapters/react/video-player.tsx +1 -7
- package/adapters/react/virtual-scroller.d.ts +0 -1
- package/adapters/react/virtual-scroller.d.ts.map +1 -1
- package/adapters/react/virtual-scroller.js +1 -1
- package/adapters/react/virtual-scroller.js.map +1 -1
- package/adapters/react/virtual-scroller.tsx +1 -2
- package/bin/templates/default/tests/services/jwt.test.ts +8 -1
- package/bin/templates/react/tests/services/jwt.test.ts +10 -3
- package/dist/cdn/accordion/snice-accordion.js +1 -1
- package/dist/cdn/accordion/snice-accordion.min.js +1 -1
- package/dist/cdn/action-bar/README.md +2 -2
- package/dist/cdn/action-bar/snice-action-bar.js +2 -2
- package/dist/cdn/action-bar/snice-action-bar.js.map +1 -1
- package/dist/cdn/action-bar/snice-action-bar.min.js +2 -2
- package/dist/cdn/action-bar/snice-action-bar.min.js.map +1 -1
- package/dist/cdn/activity-feed/snice-activity-feed.js +1 -1
- package/dist/cdn/activity-feed/snice-activity-feed.min.js +1 -1
- package/dist/cdn/alert/snice-alert.js +1 -1
- package/dist/cdn/alert/snice-alert.js.map +1 -1
- package/dist/cdn/alert/snice-alert.min.js +1 -1
- package/dist/cdn/alert/snice-alert.min.js.map +1 -1
- package/dist/cdn/app-tiles/snice-app-tiles.js +1 -1
- package/dist/cdn/app-tiles/snice-app-tiles.min.js +1 -1
- package/dist/cdn/approval-flow/snice-approval-flow.js +1 -1
- package/dist/cdn/approval-flow/snice-approval-flow.js.map +1 -1
- package/dist/cdn/approval-flow/snice-approval-flow.min.js +1 -1
- package/dist/cdn/approval-flow/snice-approval-flow.min.js.map +1 -1
- package/dist/cdn/audio-recorder/snice-audio-recorder.js +1 -1
- package/dist/cdn/audio-recorder/snice-audio-recorder.min.js +1 -1
- package/dist/cdn/availability/snice-availability.js +1 -1
- package/dist/cdn/availability/snice-availability.min.js +1 -1
- package/dist/cdn/avatar/snice-avatar.js +1 -1
- package/dist/cdn/avatar/snice-avatar.min.js +1 -1
- package/dist/cdn/avatar-group/snice-avatar-group.js +1 -1
- package/dist/cdn/avatar-group/snice-avatar-group.min.js +1 -1
- package/dist/cdn/badge/snice-badge.js +1 -1
- package/dist/cdn/badge/snice-badge.js.map +1 -1
- package/dist/cdn/badge/snice-badge.min.js +1 -1
- package/dist/cdn/badge/snice-badge.min.js.map +1 -1
- package/dist/cdn/banner/README.md +1 -1
- package/dist/cdn/banner/snice-banner.js +2 -2
- package/dist/cdn/banner/snice-banner.js.map +1 -1
- package/dist/cdn/banner/snice-banner.min.js +2 -2
- package/dist/cdn/banner/snice-banner.min.js.map +1 -1
- package/dist/cdn/binpack/snice-binpack.js +1 -1
- package/dist/cdn/binpack/snice-binpack.min.js +1 -1
- package/dist/cdn/book/snice-book.js +1 -1
- package/dist/cdn/book/snice-book.min.js +1 -1
- package/dist/cdn/booking/snice-booking.js +1 -1
- package/dist/cdn/booking/snice-booking.min.js +1 -1
- package/dist/cdn/breadcrumbs/snice-breadcrumbs.js +1 -1
- package/dist/cdn/breadcrumbs/snice-breadcrumbs.js.map +1 -1
- package/dist/cdn/breadcrumbs/snice-breadcrumbs.min.js +1 -1
- package/dist/cdn/breadcrumbs/snice-breadcrumbs.min.js.map +1 -1
- package/dist/cdn/button/snice-button.js +1 -1
- package/dist/cdn/button/snice-button.js.map +1 -1
- package/dist/cdn/button/snice-button.min.js +1 -1
- package/dist/cdn/button/snice-button.min.js.map +1 -1
- package/dist/cdn/calendar/snice-calendar.js +1 -1
- package/dist/cdn/calendar/snice-calendar.min.js +1 -1
- package/dist/cdn/camera/snice-camera.js +1 -1
- package/dist/cdn/camera/snice-camera.min.js +1 -1
- package/dist/cdn/camera-annotate/snice-camera-annotate.js +1 -1
- package/dist/cdn/camera-annotate/snice-camera-annotate.min.js +1 -1
- package/dist/cdn/candlestick/snice-candlestick.js +1 -1
- package/dist/cdn/candlestick/snice-candlestick.min.js +1 -1
- package/dist/cdn/card/snice-card.js +1 -1
- package/dist/cdn/card/snice-card.min.js +1 -1
- package/dist/cdn/carousel/snice-carousel.js +1 -1
- package/dist/cdn/carousel/snice-carousel.min.js +1 -1
- package/dist/cdn/cart/snice-cart.js +1 -1
- package/dist/cdn/cart/snice-cart.min.js +1 -1
- package/dist/cdn/chart/snice-chart.js +1 -1
- package/dist/cdn/chart/snice-chart.js.map +1 -1
- package/dist/cdn/chart/snice-chart.min.js +1 -1
- package/dist/cdn/chart/snice-chart.min.js.map +1 -1
- package/dist/cdn/chat/README.md +2 -2
- package/dist/cdn/chat/snice-chat.js +785 -89
- package/dist/cdn/chat/snice-chat.js.map +1 -1
- package/dist/cdn/chat/snice-chat.min.js +71 -75
- package/dist/cdn/chat/snice-chat.min.js.map +1 -1
- package/dist/cdn/checkbox/snice-checkbox.js +1 -1
- package/dist/cdn/checkbox/snice-checkbox.min.js +1 -1
- package/dist/cdn/chip/snice-chip.js +1 -1
- package/dist/cdn/chip/snice-chip.js.map +1 -1
- package/dist/cdn/chip/snice-chip.min.js +1 -1
- package/dist/cdn/chip/snice-chip.min.js.map +1 -1
- package/dist/cdn/code-block/snice-code-block.js +1 -1
- package/dist/cdn/code-block/snice-code-block.min.js +1 -1
- package/dist/cdn/color-display/snice-color-display.js +1 -1
- package/dist/cdn/color-display/snice-color-display.min.js +1 -1
- package/dist/cdn/color-picker/snice-color-picker.js +1 -1
- package/dist/cdn/color-picker/snice-color-picker.min.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 +2 -2
- 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/comments/snice-comments.min.js +1 -1
- package/dist/cdn/countdown/snice-countdown.js +1 -1
- package/dist/cdn/countdown/snice-countdown.min.js +1 -1
- package/dist/cdn/cropper/snice-cropper.js +1 -1
- package/dist/cdn/cropper/snice-cropper.min.js +1 -1
- package/dist/cdn/data-card/snice-data-card.js +1 -1
- package/dist/cdn/data-card/snice-data-card.js.map +1 -1
- package/dist/cdn/data-card/snice-data-card.min.js +1 -1
- package/dist/cdn/data-card/snice-data-card.min.js.map +1 -1
- package/dist/cdn/date-picker/snice-date-picker.js +1 -1
- package/dist/cdn/date-picker/snice-date-picker.min.js +1 -1
- package/dist/cdn/date-range-picker/snice-date-range-picker.js +1 -1
- package/dist/cdn/date-range-picker/snice-date-range-picker.min.js +1 -1
- package/dist/cdn/date-time-picker/snice-date-time-picker.js +1 -1
- package/dist/cdn/date-time-picker/snice-date-time-picker.min.js +1 -1
- package/dist/cdn/diff/snice-diff.js +1 -1
- package/dist/cdn/diff/snice-diff.min.js +1 -1
- package/dist/cdn/divider/snice-divider.js +1 -1
- package/dist/cdn/divider/snice-divider.min.js +1 -1
- package/dist/cdn/doc/snice-doc.js +1 -1
- package/dist/cdn/doc/snice-doc.min.js +1 -1
- package/dist/cdn/draw/snice-draw.js +1 -1
- package/dist/cdn/draw/snice-draw.min.js +1 -1
- package/dist/cdn/drawer/snice-drawer.js +1 -1
- package/dist/cdn/drawer/snice-drawer.js.map +1 -1
- package/dist/cdn/drawer/snice-drawer.min.js +1 -1
- package/dist/cdn/drawer/snice-drawer.min.js.map +1 -1
- package/dist/cdn/empty-state/snice-empty-state.js +1 -1
- package/dist/cdn/empty-state/snice-empty-state.js.map +1 -1
- package/dist/cdn/empty-state/snice-empty-state.min.js +1 -1
- package/dist/cdn/empty-state/snice-empty-state.min.js.map +1 -1
- package/dist/cdn/estimate/snice-estimate.js +1 -1
- package/dist/cdn/estimate/snice-estimate.min.js +1 -1
- package/dist/cdn/file-gallery/snice-file-gallery.js +1 -1
- package/dist/cdn/file-gallery/snice-file-gallery.min.js +1 -1
- package/dist/cdn/file-upload/snice-file-upload.js +1 -1
- package/dist/cdn/file-upload/snice-file-upload.min.js +1 -1
- package/dist/cdn/flip-card/snice-flip-card.js +1 -1
- package/dist/cdn/flip-card/snice-flip-card.min.js +1 -1
- package/dist/cdn/flow/snice-flow.js +1 -1
- package/dist/cdn/flow/snice-flow.min.js +1 -1
- package/dist/cdn/form-layout/snice-form-layout.js +1 -1
- package/dist/cdn/form-layout/snice-form-layout.min.js +1 -1
- package/dist/cdn/funnel/snice-funnel.js +1 -1
- package/dist/cdn/funnel/snice-funnel.js.map +1 -1
- package/dist/cdn/funnel/snice-funnel.min.js +1 -1
- package/dist/cdn/funnel/snice-funnel.min.js.map +1 -1
- package/dist/cdn/gantt/snice-gantt.js +1 -1
- package/dist/cdn/gantt/snice-gantt.min.js +1 -1
- package/dist/cdn/gauge/snice-gauge.js +1 -1
- package/dist/cdn/gauge/snice-gauge.min.js +1 -1
- package/dist/cdn/grid/snice-grid.js +1 -1
- package/dist/cdn/grid/snice-grid.min.js +1 -1
- package/dist/cdn/heatmap/snice-heatmap.js +1 -1
- package/dist/cdn/heatmap/snice-heatmap.min.js +1 -1
- package/dist/cdn/image/snice-image.js +1 -1
- package/dist/cdn/image/snice-image.js.map +1 -1
- package/dist/cdn/image/snice-image.min.js +1 -1
- package/dist/cdn/image/snice-image.min.js.map +1 -1
- package/dist/cdn/input/snice-input.js +1 -1
- package/dist/cdn/input/snice-input.js.map +1 -1
- package/dist/cdn/input/snice-input.min.js +1 -1
- package/dist/cdn/input/snice-input.min.js.map +1 -1
- package/dist/cdn/invoice/README.md +1 -1
- package/dist/cdn/invoice/snice-invoice.js +2 -2
- package/dist/cdn/invoice/snice-invoice.js.map +1 -1
- package/dist/cdn/invoice/snice-invoice.min.js +2 -2
- package/dist/cdn/invoice/snice-invoice.min.js.map +1 -1
- package/dist/cdn/kanban/snice-kanban.js +1 -1
- package/dist/cdn/kanban/snice-kanban.min.js +1 -1
- package/dist/cdn/key-value/snice-key-value.js +1 -1
- package/dist/cdn/key-value/snice-key-value.min.js +1 -1
- package/dist/cdn/kpi/snice-kpi.js +1 -1
- package/dist/cdn/kpi/snice-kpi.js.map +1 -1
- package/dist/cdn/kpi/snice-kpi.min.js +1 -1
- package/dist/cdn/kpi/snice-kpi.min.js.map +1 -1
- package/dist/cdn/layout/snice-layout.js +1 -1
- package/dist/cdn/layout/snice-layout.min.js +1 -1
- package/dist/cdn/leaderboard/snice-leaderboard.js +1 -1
- package/dist/cdn/leaderboard/snice-leaderboard.min.js +1 -1
- package/dist/cdn/link/snice-link.js +1 -1
- package/dist/cdn/link/snice-link.min.js +1 -1
- package/dist/cdn/link-preview/snice-link-preview.js +1 -1
- package/dist/cdn/link-preview/snice-link-preview.min.js +1 -1
- package/dist/cdn/list/snice-list.js +1 -1
- package/dist/cdn/list/snice-list.js.map +1 -1
- package/dist/cdn/list/snice-list.min.js +1 -1
- package/dist/cdn/list/snice-list.min.js.map +1 -1
- package/dist/cdn/location/snice-location.js +1 -1
- package/dist/cdn/location/snice-location.js.map +1 -1
- package/dist/cdn/location/snice-location.min.js +1 -1
- package/dist/cdn/location/snice-location.min.js.map +1 -1
- package/dist/cdn/login/snice-login.js +3 -1
- package/dist/cdn/login/snice-login.js.map +1 -1
- package/dist/cdn/login/snice-login.min.js +1 -1
- package/dist/cdn/login/snice-login.min.js.map +1 -1
- package/dist/cdn/map/snice-map.js +1 -1
- package/dist/cdn/map/snice-map.min.js +1 -1
- package/dist/cdn/markdown/README.md +2 -2
- package/dist/cdn/markdown/snice-markdown.js +16 -3
- package/dist/cdn/markdown/snice-markdown.js.map +1 -1
- package/dist/cdn/markdown/snice-markdown.min.js +3 -3
- package/dist/cdn/markdown/snice-markdown.min.js.map +1 -1
- package/dist/cdn/masonry/snice-masonry.js +1 -1
- package/dist/cdn/masonry/snice-masonry.min.js +1 -1
- package/dist/cdn/menu/snice-menu.js +2 -2
- package/dist/cdn/menu/snice-menu.js.map +1 -1
- package/dist/cdn/menu/snice-menu.min.js +2 -2
- package/dist/cdn/menu/snice-menu.min.js.map +1 -1
- package/dist/cdn/message-strip/snice-message-strip.js +9 -9
- package/dist/cdn/message-strip/snice-message-strip.js.map +1 -1
- package/dist/cdn/message-strip/snice-message-strip.min.js +3 -3
- package/dist/cdn/message-strip/snice-message-strip.min.js.map +1 -1
- package/dist/cdn/metric-table/snice-metric-table.js +1 -1
- package/dist/cdn/metric-table/snice-metric-table.min.js +1 -1
- package/dist/cdn/modal/snice-modal.js +1 -1
- package/dist/cdn/modal/snice-modal.js.map +1 -1
- package/dist/cdn/modal/snice-modal.min.js +1 -1
- package/dist/cdn/modal/snice-modal.min.js.map +1 -1
- package/dist/cdn/music-player/snice-music-player.js +1 -1
- package/dist/cdn/music-player/snice-music-player.min.js +1 -1
- package/dist/cdn/nav/snice-nav.js +1 -1
- package/dist/cdn/nav/snice-nav.min.js +1 -1
- package/dist/cdn/network-graph/snice-network-graph.js +1 -1
- package/dist/cdn/network-graph/snice-network-graph.js.map +1 -1
- package/dist/cdn/network-graph/snice-network-graph.min.js +1 -1
- package/dist/cdn/network-graph/snice-network-graph.min.js.map +1 -1
- package/dist/cdn/notification-center/snice-notification-center.js +1 -1
- package/dist/cdn/notification-center/snice-notification-center.js.map +1 -1
- package/dist/cdn/notification-center/snice-notification-center.min.js +1 -1
- package/dist/cdn/notification-center/snice-notification-center.min.js.map +1 -1
- package/dist/cdn/order-tracker/snice-order-tracker.js +1 -1
- package/dist/cdn/order-tracker/snice-order-tracker.min.js +1 -1
- package/dist/cdn/org-chart/snice-org-chart.js +1 -1
- package/dist/cdn/org-chart/snice-org-chart.min.js +1 -1
- package/dist/cdn/pagination/snice-pagination.js +1 -1
- package/dist/cdn/pagination/snice-pagination.min.js +1 -1
- package/dist/cdn/paint/snice-paint.js +1 -1
- package/dist/cdn/paint/snice-paint.min.js +1 -1
- package/dist/cdn/pdf-viewer/snice-pdf-viewer.js +1 -1
- package/dist/cdn/pdf-viewer/snice-pdf-viewer.min.js +1 -1
- package/dist/cdn/permission-matrix/snice-permission-matrix.js +1 -1
- package/dist/cdn/permission-matrix/snice-permission-matrix.min.js +1 -1
- package/dist/cdn/podcast-player/snice-podcast-player.js +1 -1
- package/dist/cdn/podcast-player/snice-podcast-player.min.js +1 -1
- package/dist/cdn/popover/snice-popover.js +1 -1
- package/dist/cdn/popover/snice-popover.min.js +1 -1
- package/dist/cdn/pricing-table/snice-pricing-table.js +1 -1
- package/dist/cdn/pricing-table/snice-pricing-table.min.js +1 -1
- package/dist/cdn/product-card/snice-product-card.js +3 -3
- package/dist/cdn/product-card/snice-product-card.js.map +1 -1
- package/dist/cdn/product-card/snice-product-card.min.js +3 -3
- package/dist/cdn/product-card/snice-product-card.min.js.map +1 -1
- package/dist/cdn/progress/README.md +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 +2 -2
- package/dist/cdn/progress/snice-progress.min.js.map +1 -1
- package/dist/cdn/progress-ring/snice-progress-ring.js +2 -2
- package/dist/cdn/progress-ring/snice-progress-ring.js.map +1 -1
- package/dist/cdn/progress-ring/snice-progress-ring.min.js +2 -2
- package/dist/cdn/progress-ring/snice-progress-ring.min.js.map +1 -1
- package/dist/cdn/qr-code/snice-qr-code.js +1 -1
- package/dist/cdn/qr-code/snice-qr-code.min.js +1 -1
- package/dist/cdn/qr-reader/snice-qr-reader.js +1 -1
- package/dist/cdn/qr-reader/snice-qr-reader.min.js +1 -1
- package/dist/cdn/radio/snice-radio.js +1 -1
- package/dist/cdn/radio/snice-radio.min.js +1 -1
- package/dist/cdn/range-slider/snice-range-slider.js +1 -1
- package/dist/cdn/range-slider/snice-range-slider.min.js +1 -1
- package/dist/cdn/rating/snice-rating.js +1 -1
- package/dist/cdn/rating/snice-rating.min.js +1 -1
- package/dist/cdn/receipt/snice-receipt.js +1 -1
- package/dist/cdn/receipt/snice-receipt.min.js +1 -1
- package/dist/cdn/recipe/snice-recipe.js +1 -1
- package/dist/cdn/recipe/snice-recipe.min.js +1 -1
- package/dist/cdn/runtime/README.md +2 -2
- package/dist/cdn/runtime/snice-runtime.esm.js +644 -172
- package/dist/cdn/runtime/snice-runtime.esm.js.map +1 -1
- package/dist/cdn/runtime/snice-runtime.esm.min.js +8 -8
- package/dist/cdn/runtime/snice-runtime.esm.min.js.map +1 -1
- package/dist/cdn/runtime/snice-runtime.js +644 -172
- package/dist/cdn/runtime/snice-runtime.js.map +1 -1
- package/dist/cdn/runtime/snice-runtime.min.js +8 -8
- package/dist/cdn/runtime/snice-runtime.min.js.map +1 -1
- package/dist/cdn/sankey/snice-sankey.js +1 -1
- package/dist/cdn/sankey/snice-sankey.js.map +1 -1
- package/dist/cdn/sankey/snice-sankey.min.js +1 -1
- package/dist/cdn/sankey/snice-sankey.min.js.map +1 -1
- package/dist/cdn/segmented-control/snice-segmented-control.js +1 -1
- package/dist/cdn/segmented-control/snice-segmented-control.min.js +1 -1
- package/dist/cdn/select/snice-select.js +1 -1
- package/dist/cdn/select/snice-select.min.js +1 -1
- package/dist/cdn/skeleton/snice-skeleton.js +1 -1
- package/dist/cdn/skeleton/snice-skeleton.min.js +1 -1
- package/dist/cdn/slider/snice-slider.js +1 -1
- package/dist/cdn/slider/snice-slider.min.js +1 -1
- package/dist/cdn/sortable/snice-sortable.js +1 -1
- package/dist/cdn/sortable/snice-sortable.min.js +1 -1
- package/dist/cdn/sparkline/snice-sparkline.js +1 -1
- package/dist/cdn/sparkline/snice-sparkline.min.js +1 -1
- package/dist/cdn/spinner/snice-spinner.js +1 -1
- package/dist/cdn/spinner/snice-spinner.min.js +1 -1
- package/dist/cdn/split-button/snice-split-button.js +1 -1
- package/dist/cdn/split-button/snice-split-button.js.map +1 -1
- package/dist/cdn/split-button/snice-split-button.min.js +1 -1
- package/dist/cdn/split-button/snice-split-button.min.js.map +1 -1
- package/dist/cdn/split-pane/snice-split-pane.js +1 -1
- package/dist/cdn/split-pane/snice-split-pane.min.js +1 -1
- package/dist/cdn/spotlight/snice-spotlight.js +1 -1
- package/dist/cdn/spotlight/snice-spotlight.min.js +1 -1
- package/dist/cdn/stat-group/snice-stat-group.js +1 -1
- package/dist/cdn/stat-group/snice-stat-group.min.js +1 -1
- package/dist/cdn/step-input/snice-step-input.js +1 -1
- package/dist/cdn/step-input/snice-step-input.min.js +1 -1
- package/dist/cdn/stepper/snice-stepper.js +1 -1
- package/dist/cdn/stepper/snice-stepper.min.js +1 -1
- package/dist/cdn/switch/snice-switch.js +1 -1
- package/dist/cdn/switch/snice-switch.min.js +1 -1
- package/dist/cdn/table/README.md +1 -1
- package/dist/cdn/table/snice-table.js +14 -4
- package/dist/cdn/table/snice-table.js.map +1 -1
- package/dist/cdn/table/snice-table.min.js +14 -4
- package/dist/cdn/table/snice-table.min.js.map +1 -1
- package/dist/cdn/tabs/snice-tabs.js +1 -1
- package/dist/cdn/tabs/snice-tabs.min.js +1 -1
- package/dist/cdn/tag/snice-tag.js +1 -1
- package/dist/cdn/tag/snice-tag.min.js +1 -1
- package/dist/cdn/tag-input/snice-tag-input.js +2 -2
- package/dist/cdn/tag-input/snice-tag-input.js.map +1 -1
- package/dist/cdn/tag-input/snice-tag-input.min.js +2 -2
- package/dist/cdn/tag-input/snice-tag-input.min.js.map +1 -1
- package/dist/cdn/terminal/snice-terminal.js +1 -1
- package/dist/cdn/terminal/snice-terminal.min.js +1 -1
- package/dist/cdn/testimonial/snice-testimonial.js +1 -1
- package/dist/cdn/testimonial/snice-testimonial.min.js +1 -1
- package/dist/cdn/textarea/snice-textarea.js +1 -1
- package/dist/cdn/textarea/snice-textarea.min.js +1 -1
- package/dist/cdn/time-picker/README.md +1 -1
- package/dist/cdn/time-picker/snice-time-picker.js +18 -13
- package/dist/cdn/time-picker/snice-time-picker.js.map +1 -1
- package/dist/cdn/time-picker/snice-time-picker.min.js +3 -3
- package/dist/cdn/time-picker/snice-time-picker.min.js.map +1 -1
- package/dist/cdn/time-range-picker/snice-time-range-picker.js +1 -1
- package/dist/cdn/time-range-picker/snice-time-range-picker.min.js +1 -1
- package/dist/cdn/timeline/snice-timeline.js +1 -1
- package/dist/cdn/timeline/snice-timeline.js.map +1 -1
- package/dist/cdn/timeline/snice-timeline.min.js +1 -1
- package/dist/cdn/timeline/snice-timeline.min.js.map +1 -1
- package/dist/cdn/timer/snice-timer.js +1 -1
- package/dist/cdn/timer/snice-timer.min.js +1 -1
- package/dist/cdn/toast/snice-toast.js +1 -1
- package/dist/cdn/toast/snice-toast.js.map +1 -1
- package/dist/cdn/toast/snice-toast.min.js +1 -1
- package/dist/cdn/toast/snice-toast.min.js.map +1 -1
- package/dist/cdn/tooltip/snice-tooltip.js +1 -1
- package/dist/cdn/tooltip/snice-tooltip.min.js +1 -1
- package/dist/cdn/tree/snice-tree.js +1 -1
- package/dist/cdn/tree/snice-tree.min.js +1 -1
- package/dist/cdn/treemap/snice-treemap.js +1 -1
- package/dist/cdn/treemap/snice-treemap.js.map +1 -1
- package/dist/cdn/treemap/snice-treemap.min.js +1 -1
- package/dist/cdn/treemap/snice-treemap.min.js.map +1 -1
- package/dist/cdn/user-card/snice-user-card.js +1 -1
- package/dist/cdn/user-card/snice-user-card.min.js +1 -1
- package/dist/cdn/video-player/snice-video-player.js +1 -1
- package/dist/cdn/video-player/snice-video-player.min.js +1 -1
- package/dist/cdn/virtual-scroller/snice-virtual-scroller.js +1 -1
- package/dist/cdn/virtual-scroller/snice-virtual-scroller.min.js +1 -1
- package/dist/cdn/waterfall/snice-waterfall.js +1 -1
- package/dist/cdn/waterfall/snice-waterfall.min.js +1 -1
- package/dist/cdn/weather/snice-weather.js +1 -1
- package/dist/cdn/weather/snice-weather.min.js +1 -1
- package/dist/cdn/work-order/snice-work-order.js +1 -1
- package/dist/cdn/work-order/snice-work-order.min.js +1 -1
- package/dist/components/action-bar/snice-action-bar.js +1 -1
- package/dist/components/action-bar/snice-action-bar.js.map +1 -1
- package/dist/components/banner/snice-banner.js +1 -1
- package/dist/components/banner/snice-banner.js.map +1 -1
- package/dist/components/chat/snice-chat-message.d.ts +32 -0
- package/dist/components/chat/snice-chat-message.js +127 -0
- package/dist/components/chat/snice-chat-message.js.map +1 -0
- package/dist/components/chat/snice-chat-message.types.d.ts +30 -0
- package/dist/components/chat/snice-chat.d.ts +31 -4
- package/dist/components/chat/snice-chat.js +363 -90
- package/dist/components/chat/snice-chat.js.map +1 -1
- package/dist/components/chat/snice-chat.types.d.ts +34 -3
- 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/icons/index.d.ts +4 -0
- package/dist/components/icons/index.js +5 -1
- package/dist/components/icons/index.js.map +1 -1
- package/dist/components/invoice/snice-invoice.js +1 -1
- package/dist/components/invoice/snice-invoice.js.map +1 -1
- package/dist/components/login/snice-login.d.ts +2 -2
- package/dist/components/login/snice-login.js +2 -0
- package/dist/components/login/snice-login.js.map +1 -1
- package/dist/components/login/snice-login.types.d.ts +4 -0
- package/dist/components/markdown/snice-markdown.d.ts +1 -0
- package/dist/components/markdown/snice-markdown.js +15 -2
- package/dist/components/markdown/snice-markdown.js.map +1 -1
- package/dist/components/menu/snice-menu.js +1 -1
- package/dist/components/menu/snice-menu.js.map +1 -1
- package/dist/components/message-strip/snice-message-strip.d.ts +1 -1
- package/dist/components/message-strip/snice-message-strip.js +8 -8
- package/dist/components/message-strip/snice-message-strip.types.d.ts +1 -1
- package/dist/components/product-card/snice-product-card.js +2 -2
- package/dist/components/product-card/snice-product-card.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/progress-ring/snice-progress-ring.js +1 -1
- package/dist/components/progress-ring/snice-progress-ring.js.map +1 -1
- package/dist/components/table/snice-table.js +13 -3
- package/dist/components/table/snice-table.js.map +1 -1
- package/dist/components/tag-input/snice-tag-input.js +1 -1
- package/dist/components/tag-input/snice-tag-input.js.map +1 -1
- package/dist/components/time-picker/snice-time-picker.js +17 -12
- package/dist/components/time-picker/snice-time-picker.js.map +1 -1
- package/dist/components/utils.d.ts +6 -0
- package/dist/components/utils.js +1 -1
- package/dist/components/utils.js.map +1 -1
- package/dist/element.d.ts +2 -1
- package/dist/events.d.ts +6 -0
- package/dist/index.cjs +641 -169
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +641 -169
- package/dist/index.esm.js.map +1 -1
- package/dist/index.iife.js +641 -169
- package/dist/index.iife.js.map +1 -1
- package/dist/parts.d.ts +1 -8
- 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.d.ts +1 -1
- package/dist/react/matchRoute.js +38 -4
- package/dist/react/matchRoute.js.map +1 -1
- package/dist/react/route-specificity.d.ts +1 -0
- package/dist/react/useRequestHandler.js +1 -1
- package/dist/render.d.ts +7 -0
- package/dist/route-specificity.d.ts +1 -0
- package/dist/symbols.cjs +14 -1
- package/dist/symbols.cjs.map +1 -1
- package/dist/symbols.d.ts +3 -0
- package/dist/symbols.esm.js +12 -2
- package/dist/symbols.esm.js.map +1 -1
- package/dist/transitions.cjs +1 -1
- package/dist/transitions.esm.js +1 -1
- package/dist/types/context.d.ts +5 -2
- package/dist/types/dispatch-options.d.ts +7 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/on-options.d.ts +14 -0
- package/dist/types/watch-options.d.ts +9 -0
- package/dist/utils.d.ts +26 -0
- package/docs/ai/DEVELOPMENT.md +1 -1
- package/docs/ai/README.md +11 -0
- package/docs/ai/api.md +24 -5
- package/docs/ai/cdn.md +31 -0
- package/docs/ai/components/chat.md +57 -1
- package/docs/ai/components/message-strip.md +3 -3
- package/docs/ai/decorators.md +44 -5
- package/docs/cdn.md +56 -0
- package/docs/components/chat.md +108 -2
- package/docs/components/message-strip.md +8 -8
- package/docs/elements.md +21 -0
- package/docs/events.md +88 -0
- package/docs/superpowers/specs/2026-05-26-chat-styling-design.md +155 -0
- package/docs/superpowers/specs/2026-05-27-chat-theming-REMAINING.md +83 -0
- package/docs/superpowers/specs/2026-06-09-chat-custom-content-design.md +233 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* snice
|
|
2
|
+
* snice v6.0.0
|
|
3
3
|
* A decorator-driven web component library with differential rendering, routing, controllers, and 130+ ready-made UI components. Use as much or as little as you want. Zero dependencies, works anywhere.
|
|
4
4
|
* (c) 2024
|
|
5
5
|
* Released under the MIT License.
|
|
@@ -8,7 +8,7 @@ var Snice = (function (exports) {
|
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
10
|
/*!
|
|
11
|
-
* snice v5.2.
|
|
11
|
+
* snice v5.2.3
|
|
12
12
|
* A decorator-driven web component library with differential rendering, routing, controllers, and 130+ ready-made UI components. Use as much or as little as you want. Zero dependencies, works anywhere.
|
|
13
13
|
* (c) 2024
|
|
14
14
|
* Released under the MIT License.
|
|
@@ -42,6 +42,12 @@ var Snice = (function (exports) {
|
|
|
42
42
|
// Internal element state symbols
|
|
43
43
|
const READY_PROMISE = getSymbol('ready-promise');
|
|
44
44
|
const READY_RESOLVE = getSymbol('ready-resolve');
|
|
45
|
+
// Set when a render is requested but dropped because the element was
|
|
46
|
+
// disconnected; consumed on reconnect to replay exactly the missed render.
|
|
47
|
+
const PENDING_RECONNECT_RENDER = getSymbol('pending-reconnect-render');
|
|
48
|
+
// Per-element synchronous render-nesting depth, used to cap runaway re-entry
|
|
49
|
+
// without a shared global counter that one element could exhaust for others.
|
|
50
|
+
const RENDER_DEPTH = getSymbol('render-depth');
|
|
45
51
|
const CONTROLLER = getSymbol('controller');
|
|
46
52
|
const INITIALIZED = getSymbol('initialized');
|
|
47
53
|
// Controller symbols
|
|
@@ -113,6 +119,10 @@ var Snice = (function (exports) {
|
|
|
113
119
|
// Controller attach-abort — set to an AbortController while attachController
|
|
114
120
|
// is awaiting element.ready, so detachController can short-circuit the wait.
|
|
115
121
|
const CONTROLLER_ABORT = getSymbol('controller-abort');
|
|
122
|
+
// Set on a controller instance once it has gotten past element.ready and is
|
|
123
|
+
// being attached, so detachController knows not to run detach() on a controller
|
|
124
|
+
// whose attach() was aborted before it ever ran.
|
|
125
|
+
const CONTROLLER_ATTACHED = getSymbol('controller-attached');
|
|
116
126
|
const PROPERTY_DEFINERS = getSymbol('property-definers');
|
|
117
127
|
|
|
118
128
|
/**
|
|
@@ -233,11 +243,23 @@ var Snice = (function (exports) {
|
|
|
233
243
|
this[REGISTERED_ELEMENTS_SET].add(element);
|
|
234
244
|
}
|
|
235
245
|
/**
|
|
236
|
-
* Unregister an element from receiving context updates
|
|
246
|
+
* Unregister an element from receiving context updates. With a methodName,
|
|
247
|
+
* removes only that one handler (so a `once` handler tearing itself down
|
|
248
|
+
* doesn't kill the element's other @context handlers); without one, removes
|
|
249
|
+
* the element entirely (used on disconnect).
|
|
237
250
|
* @internal Used by @context decorator cleanup
|
|
238
251
|
*/
|
|
239
|
-
[CONTEXT_UNREGISTER](element) {
|
|
240
|
-
this[REGISTERED_ELEMENTS]
|
|
252
|
+
[CONTEXT_UNREGISTER](element, methodName) {
|
|
253
|
+
const map = this[REGISTERED_ELEMENTS];
|
|
254
|
+
if (methodName !== undefined) {
|
|
255
|
+
const names = map.get(element);
|
|
256
|
+
if (!names)
|
|
257
|
+
return;
|
|
258
|
+
names.delete(methodName);
|
|
259
|
+
if (names.size > 0)
|
|
260
|
+
return; // other handlers remain — keep the element
|
|
261
|
+
}
|
|
262
|
+
map.delete(element);
|
|
241
263
|
this[REGISTERED_ELEMENTS_SET].delete(element);
|
|
242
264
|
}
|
|
243
265
|
/**
|
|
@@ -402,11 +424,23 @@ var Snice = (function (exports) {
|
|
|
402
424
|
* @param initialValue - The default value assigned to the property field (used for type detection)
|
|
403
425
|
* @returns The string representation for the HTML attribute, or null if value should remove attribute
|
|
404
426
|
*/
|
|
427
|
+
/**
|
|
428
|
+
* Default property dirty-check: has the value changed? Like `!==`, but treats
|
|
429
|
+
* NaN → NaN as unchanged (NaN !== NaN would otherwise re-fire forever).
|
|
430
|
+
*/
|
|
431
|
+
function notEqual(value, old) {
|
|
432
|
+
// Changed unless strictly equal, or both are NaN (each self-unequal).
|
|
433
|
+
return value !== old && (value === value || old === old);
|
|
434
|
+
}
|
|
405
435
|
/**
|
|
406
436
|
* Extract attribute name from property options
|
|
407
437
|
*/
|
|
408
438
|
function getAttrName(opts, propName) {
|
|
409
|
-
|
|
439
|
+
// Lowercase always: the DOM stores attribute names lowercase, so an explicit
|
|
440
|
+
// camelCase `attribute:` would otherwise never match observedAttributes and
|
|
441
|
+
// attributeChangedCallback would never fire. get/setAttribute are already
|
|
442
|
+
// case-insensitive, so this is safe for every caller.
|
|
443
|
+
return (typeof opts.attribute === 'string' ? opts.attribute : propName).toLowerCase();
|
|
410
444
|
}
|
|
411
445
|
/**
|
|
412
446
|
* Escape HTML text-node content. Use for text that will be interpolated
|
|
@@ -553,6 +587,42 @@ var Snice = (function (exports) {
|
|
|
553
587
|
}
|
|
554
588
|
}
|
|
555
589
|
}
|
|
590
|
+
/**
|
|
591
|
+
* Fire the one-time initialization call for `@watch(..., { immediate: true })`
|
|
592
|
+
* handlers. Runs once per declared property after the element is initialized,
|
|
593
|
+
* passing the effective initial value with `oldValue` undefined. Non-immediate
|
|
594
|
+
* watchers are untouched — they only react to later changes.
|
|
595
|
+
*/
|
|
596
|
+
function invokeImmediateWatchers(instance, constructor) {
|
|
597
|
+
const watchers = constructor[PROPERTY_WATCHERS];
|
|
598
|
+
const properties = constructor[PROPERTIES];
|
|
599
|
+
if (!watchers || !properties)
|
|
600
|
+
return;
|
|
601
|
+
for (const [propName, propOptions] of properties) {
|
|
602
|
+
// A watcher may be registered under the JS name, the explicit `attribute:`
|
|
603
|
+
// name, or the `*` wildcard; fire each immediate one exactly once, keyed to
|
|
604
|
+
// this property's current value.
|
|
605
|
+
const keys = [propName];
|
|
606
|
+
const attrName = propOptions && typeof propOptions.attribute === 'string' ? propOptions.attribute : null;
|
|
607
|
+
if (attrName && attrName !== propName)
|
|
608
|
+
keys.push(attrName);
|
|
609
|
+
keys.push('*');
|
|
610
|
+
for (const key of keys) {
|
|
611
|
+
if (!watchers.has(key))
|
|
612
|
+
continue;
|
|
613
|
+
for (const w of watchers.get(key)) {
|
|
614
|
+
if (!w.immediate)
|
|
615
|
+
continue;
|
|
616
|
+
try {
|
|
617
|
+
w.method.call(instance, undefined, instance[propName], propName);
|
|
618
|
+
}
|
|
619
|
+
catch (e) {
|
|
620
|
+
console.error(`Error in @watch('${key}') method ${w.methodName}:`, e);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
556
626
|
/**
|
|
557
627
|
* Create a debounced version of a function
|
|
558
628
|
*/
|
|
@@ -586,6 +656,41 @@ var Snice = (function (exports) {
|
|
|
586
656
|
}
|
|
587
657
|
};
|
|
588
658
|
}
|
|
659
|
+
/**
|
|
660
|
+
* Resolve a scope option to a concrete EventTarget.
|
|
661
|
+
*
|
|
662
|
+
* - undefined → host element (default behavior)
|
|
663
|
+
* - 'global' → `document`
|
|
664
|
+
* - string → `host.closest(selector)` (nearest matching ancestor)
|
|
665
|
+
* - EventTarget instance → that target directly
|
|
666
|
+
* - resolver function → called with host as `this`, returns target or null
|
|
667
|
+
*
|
|
668
|
+
* Returns null when the scope cannot be resolved (e.g. selector matches no
|
|
669
|
+
* ancestor, resolver returns null). Caller decides how to handle null —
|
|
670
|
+
* typically warn in dev and skip listener attachment.
|
|
671
|
+
*/
|
|
672
|
+
function resolveScope(host, scope) {
|
|
673
|
+
if (scope === undefined || scope === null)
|
|
674
|
+
return host;
|
|
675
|
+
if (scope === 'global')
|
|
676
|
+
return typeof document !== 'undefined' ? document : null;
|
|
677
|
+
if (typeof scope === 'function') {
|
|
678
|
+
try {
|
|
679
|
+
return scope.call(host) || null;
|
|
680
|
+
}
|
|
681
|
+
catch {
|
|
682
|
+
return null;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
if (typeof scope === 'string') {
|
|
686
|
+
return host.closest?.(scope) || null;
|
|
687
|
+
}
|
|
688
|
+
// Direct EventTarget instance.
|
|
689
|
+
if (scope && typeof scope.addEventListener === 'function') {
|
|
690
|
+
return scope;
|
|
691
|
+
}
|
|
692
|
+
return null;
|
|
693
|
+
}
|
|
589
694
|
function valueToAttribute(value, propertyOptions, initialValue) {
|
|
590
695
|
// Handle null/undefined/false values and empty arrays
|
|
591
696
|
if (value === null || value === undefined || value === false ||
|
|
@@ -1003,13 +1108,11 @@ var Snice = (function (exports) {
|
|
|
1003
1108
|
return finalValue;
|
|
1004
1109
|
}
|
|
1005
1110
|
catch (error) {
|
|
1006
|
-
//
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
throw generatorError;
|
|
1012
|
-
}
|
|
1111
|
+
// Drive the generator's own catch block and return whatever it recovers
|
|
1112
|
+
// with (e.g. a cached fallback). If the generator re-throws instead,
|
|
1113
|
+
// generator.throw rejects and the error propagates to the caller.
|
|
1114
|
+
const { value: recovered } = await generator.throw(error);
|
|
1115
|
+
return recovered;
|
|
1013
1116
|
}
|
|
1014
1117
|
}; // Close actualRequest function
|
|
1015
1118
|
// Debounce
|
|
@@ -1033,9 +1136,21 @@ var Snice = (function (exports) {
|
|
|
1033
1136
|
const now = Date.now();
|
|
1034
1137
|
const remaining = options.throttle - (now - throttleLastCall);
|
|
1035
1138
|
if (remaining <= 0) {
|
|
1139
|
+
// Cancelling the scheduled trailing call must not orphan the promises
|
|
1140
|
+
// queued for it — settle them with this fresh result. Also reset
|
|
1141
|
+
// throttleTimeout so later within-window calls don't attach to a dead
|
|
1142
|
+
// timer and hang.
|
|
1036
1143
|
clearTimeout(throttleTimeout);
|
|
1144
|
+
throttleTimeout = null;
|
|
1037
1145
|
throttleLastCall = now;
|
|
1038
|
-
|
|
1146
|
+
const orphaned = throttleTrailingResolvers.splice(0);
|
|
1147
|
+
const p = actualRequest();
|
|
1148
|
+
if (orphaned.length) {
|
|
1149
|
+
p.then((r) => { for (const x of orphaned)
|
|
1150
|
+
x.resolve(r); }, (e) => { for (const x of orphaned)
|
|
1151
|
+
x.reject(e); });
|
|
1152
|
+
}
|
|
1153
|
+
return p;
|
|
1039
1154
|
}
|
|
1040
1155
|
// Throttle: already has pending trailing call — attach to it
|
|
1041
1156
|
if (throttleTimeout) {
|
|
@@ -1136,10 +1251,20 @@ var Snice = (function (exports) {
|
|
|
1136
1251
|
const now = Date.now();
|
|
1137
1252
|
const remaining = handler.options.throttle - (now - throttleLastCall);
|
|
1138
1253
|
if (remaining <= 0) {
|
|
1254
|
+
// Same as the @request side: settle any queued trailing callers with
|
|
1255
|
+
// this fresh result rather than orphaning their promises.
|
|
1139
1256
|
clearTimeout(throttleTimeout);
|
|
1140
1257
|
throttleTimeout = null;
|
|
1141
1258
|
throttleLastCall = now;
|
|
1142
|
-
|
|
1259
|
+
const orphaned = throttleTrailingResolvers.splice(0);
|
|
1260
|
+
throttleLatestArgs = null;
|
|
1261
|
+
const result = originalMethod(...args);
|
|
1262
|
+
if (orphaned.length) {
|
|
1263
|
+
Promise.resolve(result).then((r) => { for (const x of orphaned)
|
|
1264
|
+
x.resolve(r); }, (e) => { for (const x of orphaned)
|
|
1265
|
+
x.reject(e); });
|
|
1266
|
+
}
|
|
1267
|
+
return result;
|
|
1143
1268
|
}
|
|
1144
1269
|
// Remember the LATEST args so the trailing call uses fresh input,
|
|
1145
1270
|
// and queue every suppressed caller's resolver so they all receive
|
|
@@ -1246,7 +1371,10 @@ var Snice = (function (exports) {
|
|
|
1246
1371
|
// Combine strings and values into final CSS text
|
|
1247
1372
|
let cssText = strings[0];
|
|
1248
1373
|
for (let i = 0; i < values.length; i++) {
|
|
1249
|
-
|
|
1374
|
+
// Inline a nested css`` result by its text so style fragments compose;
|
|
1375
|
+
// String() on a CSSResult object would yield "[object Object]".
|
|
1376
|
+
const value = values[i];
|
|
1377
|
+
cssText += (isCSSResult(value) ? value.cssText : String(value)) + strings[i + 1];
|
|
1250
1378
|
}
|
|
1251
1379
|
const result = {
|
|
1252
1380
|
_$litType$: CSS_RESULT,
|
|
@@ -1397,6 +1525,20 @@ var Snice = (function (exports) {
|
|
|
1397
1525
|
const attrStrings = value.split(marker);
|
|
1398
1526
|
// Number of expressions = number of markers = attrStrings.length - 1
|
|
1399
1527
|
const expressionCount = attrStrings.length - 1;
|
|
1528
|
+
// Property/boolean/event bindings take a SINGLE expression — they
|
|
1529
|
+
// can't concatenate static text (a `.prop` is an object, not a
|
|
1530
|
+
// string). They consume the first expression; any static text or
|
|
1531
|
+
// extra expressions are ignored. But the value index must still
|
|
1532
|
+
// advance by the true marker count, or every later binding shifts.
|
|
1533
|
+
const isSingleExpressionBinding = /^@@?|^[.?]/.test(originalName);
|
|
1534
|
+
if (isSingleExpressionBinding) {
|
|
1535
|
+
const hasStaticText = attrStrings.some((s) => s !== '');
|
|
1536
|
+
if (expressionCount > 1 || hasStaticText) {
|
|
1537
|
+
console.warn(`snice: binding "${originalName}" takes a single expression; ` +
|
|
1538
|
+
`static text and extra interpolations are ignored. ` +
|
|
1539
|
+
`Use a plain attribute for string interpolation.`);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1400
1542
|
if (originalName.startsWith('@@')) {
|
|
1401
1543
|
// Escaped event binding for events with @ in the name (e.g., @@snice/event -> @snice/event)
|
|
1402
1544
|
this.parts.push({
|
|
@@ -1405,7 +1547,7 @@ var Snice = (function (exports) {
|
|
|
1405
1547
|
name: originalName.slice(1), // Keep the @ in the event name
|
|
1406
1548
|
element
|
|
1407
1549
|
});
|
|
1408
|
-
partIndex +=
|
|
1550
|
+
partIndex += expressionCount;
|
|
1409
1551
|
}
|
|
1410
1552
|
else if (originalName.startsWith('@')) {
|
|
1411
1553
|
// Event binding (single value only)
|
|
@@ -1415,7 +1557,7 @@ var Snice = (function (exports) {
|
|
|
1415
1557
|
name: originalName.slice(1),
|
|
1416
1558
|
element
|
|
1417
1559
|
});
|
|
1418
|
-
partIndex +=
|
|
1560
|
+
partIndex += expressionCount;
|
|
1419
1561
|
}
|
|
1420
1562
|
else if (originalName.startsWith('.')) {
|
|
1421
1563
|
// Property binding (single value only)
|
|
@@ -1425,7 +1567,7 @@ var Snice = (function (exports) {
|
|
|
1425
1567
|
name: originalName.slice(1),
|
|
1426
1568
|
element
|
|
1427
1569
|
});
|
|
1428
|
-
partIndex +=
|
|
1570
|
+
partIndex += expressionCount;
|
|
1429
1571
|
}
|
|
1430
1572
|
else if (originalName.startsWith('?')) {
|
|
1431
1573
|
// Boolean attribute (single value only)
|
|
@@ -1435,7 +1577,7 @@ var Snice = (function (exports) {
|
|
|
1435
1577
|
name: originalName.slice(1),
|
|
1436
1578
|
element
|
|
1437
1579
|
});
|
|
1438
|
-
partIndex +=
|
|
1580
|
+
partIndex += expressionCount;
|
|
1439
1581
|
}
|
|
1440
1582
|
else {
|
|
1441
1583
|
// Regular attribute - supports multiple interpolations
|
|
@@ -1910,7 +2052,13 @@ var Snice = (function (exports) {
|
|
|
1910
2052
|
* Commit unsafe HTML string
|
|
1911
2053
|
*/
|
|
1912
2054
|
_commitUnsafeHTML(value) {
|
|
1913
|
-
//
|
|
2055
|
+
// Can't diff arbitrary HTML, but when the STRING is unchanged the DOM is
|
|
2056
|
+
// already correct — skip the clear+reparse so live state (typed input
|
|
2057
|
+
// values, focus, scroll) inside the block survives unrelated re-renders.
|
|
2058
|
+
const prev = this._committedValue;
|
|
2059
|
+
if (isUnsafeHTML(prev) && prev.html === value.html) {
|
|
2060
|
+
return;
|
|
2061
|
+
}
|
|
1914
2062
|
this._clear();
|
|
1915
2063
|
const temp = document.createElement('template');
|
|
1916
2064
|
temp.innerHTML = value.html;
|
|
@@ -2095,7 +2243,9 @@ var Snice = (function (exports) {
|
|
|
2095
2243
|
// Supports both dot notation (@keydown.enter) and colon notation (@keydown:Enter) to match @on decorator
|
|
2096
2244
|
// Only parse colons for keyboard events, not custom events
|
|
2097
2245
|
const isKeyboardEvent = ['keydown', 'keyup', 'keypress'].includes(eventName.split('.')[0].split(':')[0]);
|
|
2098
|
-
|
|
2246
|
+
// Only keyboard events split on `.`/`:` into a key filter — a custom event
|
|
2247
|
+
// name may legitimately contain a dot (e.g. `app.ready`) and must be kept whole.
|
|
2248
|
+
const dotIndex = isKeyboardEvent ? eventName.indexOf('.') : -1;
|
|
2099
2249
|
const colonIndex = isKeyboardEvent ? eventName.indexOf(':') : -1;
|
|
2100
2250
|
// Use whichever delimiter comes first (dot or colon)
|
|
2101
2251
|
const delimiterIndex = dotIndex > 0 && colonIndex > 0
|
|
@@ -2109,6 +2259,7 @@ var Snice = (function (exports) {
|
|
|
2109
2259
|
}
|
|
2110
2260
|
else {
|
|
2111
2261
|
this.eventName = eventName;
|
|
2262
|
+
warnIfModifierMisuse(eventName);
|
|
2112
2263
|
}
|
|
2113
2264
|
}
|
|
2114
2265
|
commit(value) {
|
|
@@ -2134,17 +2285,19 @@ var Snice = (function (exports) {
|
|
|
2134
2285
|
}
|
|
2135
2286
|
if (typeof value !== 'function')
|
|
2136
2287
|
return;
|
|
2137
|
-
// Auto-bind to host element (the custom element with shadow root)
|
|
2138
|
-
if (!this.host) {
|
|
2139
|
-
const rootNode = this.element.getRootNode();
|
|
2140
|
-
this.host = rootNode.host || null;
|
|
2141
|
-
}
|
|
2142
|
-
const context = this.host || null;
|
|
2143
2288
|
const keyFilter = this.keyFilter;
|
|
2144
2289
|
this.listener = ((event) => {
|
|
2145
2290
|
if (keyFilter && !matchesKeyboardFilter(event, keyFilter))
|
|
2146
2291
|
return;
|
|
2147
|
-
|
|
2292
|
+
// Resolve the host (the custom element owning the shadow root) at dispatch
|
|
2293
|
+
// time, not bind time: a binding inside an initially-hidden <if>/<case>
|
|
2294
|
+
// branch commits while off-DOM, where getRootNode() has no host — caching
|
|
2295
|
+
// that null permanently would call the handler with `this = null` once the
|
|
2296
|
+
// branch is shown. By the time an event fires, the element is in the DOM.
|
|
2297
|
+
if (!this.host) {
|
|
2298
|
+
this.host = this.element.getRootNode().host || null;
|
|
2299
|
+
}
|
|
2300
|
+
value.call(this.host || null, event);
|
|
2148
2301
|
});
|
|
2149
2302
|
this.element.addEventListener(this.eventName, this.listener);
|
|
2150
2303
|
}
|
|
@@ -2163,6 +2316,25 @@ var Snice = (function (exports) {
|
|
|
2163
2316
|
* "ctrl+shift+s" -> { key: "s", ctrl: true, shift: true }
|
|
2164
2317
|
* "~enter" -> { key: "Enter", anyModifiers: true }
|
|
2165
2318
|
*/
|
|
2319
|
+
// once/preventDefault/stopPropagation/capture/passive are @on() OPTIONS, not
|
|
2320
|
+
// template modifiers. A dotted non-keyboard event whose suffix is one of these
|
|
2321
|
+
// is almost certainly a mistake (e.g. `@click.once`) — it binds a listener for
|
|
2322
|
+
// an event type the DOM never dispatches. Warn instead of failing silently. A
|
|
2323
|
+
// legitimate custom event name like `app.ready` won't match and stays quiet.
|
|
2324
|
+
const MODIFIER_WORDS = new Set([
|
|
2325
|
+
'once', 'prevent', 'preventdefault', 'stop', 'stoppropagation', 'capture', 'passive',
|
|
2326
|
+
]);
|
|
2327
|
+
function warnIfModifierMisuse(eventName) {
|
|
2328
|
+
const dot = eventName.lastIndexOf('.');
|
|
2329
|
+
if (dot < 0)
|
|
2330
|
+
return;
|
|
2331
|
+
const suffix = eventName.slice(dot + 1).toLowerCase();
|
|
2332
|
+
if (!MODIFIER_WORDS.has(suffix))
|
|
2333
|
+
return;
|
|
2334
|
+
console.warn(`snice: "@${eventName}" is not a valid modifier — once/preventDefault/` +
|
|
2335
|
+
`stopPropagation/capture are @on() options, not template modifiers. ` +
|
|
2336
|
+
`This registers a listener for event "${eventName}", which never fires.`);
|
|
2337
|
+
}
|
|
2166
2338
|
function parseKeyboardFilter(spec) {
|
|
2167
2339
|
// Handle ~ prefix for matching regardless of modifiers
|
|
2168
2340
|
const anyModifiers = spec.startsWith('~');
|
|
@@ -2265,9 +2437,14 @@ var Snice = (function (exports) {
|
|
|
2265
2437
|
// Insert markers where <if> is
|
|
2266
2438
|
parent.insertBefore(this.startNode, ifElement);
|
|
2267
2439
|
parent.insertBefore(this.endNode, ifElement.nextSibling);
|
|
2268
|
-
//
|
|
2440
|
+
// Park <if>'s children in an off-DOM fragment immediately, rather than
|
|
2441
|
+
// leaving them in the live template fragment. Otherwise a branch that is
|
|
2442
|
+
// hidden on first render would still connect its children (when the
|
|
2443
|
+
// template mounts) and then disconnect them (on the first commit) — firing
|
|
2444
|
+
// mount side effects spuriously. commit(true) inserts them when shown.
|
|
2445
|
+
this.childFragment = document.createDocumentFragment();
|
|
2269
2446
|
while (ifElement.firstChild) {
|
|
2270
|
-
|
|
2447
|
+
this.childFragment.appendChild(ifElement.firstChild);
|
|
2271
2448
|
}
|
|
2272
2449
|
// Remove the <if> element from DOM
|
|
2273
2450
|
parent.removeChild(ifElement);
|
|
@@ -2348,16 +2525,24 @@ var Snice = (function (exports) {
|
|
|
2348
2525
|
parent.removeChild(caseElement);
|
|
2349
2526
|
}
|
|
2350
2527
|
commit(value) {
|
|
2351
|
-
|
|
2528
|
+
// Dirty-check on the SELECTED BRANCH, not the raw value. A value whose type
|
|
2529
|
+
// changed but stringifies the same (number 1 vs string '1' — e.g. a numeric
|
|
2530
|
+
// default replaced by a router param, which is always a string) selects the
|
|
2531
|
+
// same branch, so tearing it down and re-inserting it would needlessly
|
|
2532
|
+
// restart media/animations and lose focus inside it.
|
|
2533
|
+
const valueStr = String(value);
|
|
2534
|
+
const hasBranch = this.branches.has(valueStr);
|
|
2535
|
+
const nextKey = hasBranch ? valueStr : (this.defaultBranch ? '__default__' : null);
|
|
2536
|
+
if (this.currentKey === nextKey) {
|
|
2537
|
+
this.value = value;
|
|
2352
2538
|
return;
|
|
2539
|
+
}
|
|
2353
2540
|
this.value = value;
|
|
2354
|
-
const valueStr = String(value);
|
|
2355
2541
|
// Move current content back to its fragment
|
|
2356
2542
|
this._collectCurrent();
|
|
2357
2543
|
// Insert matching branch
|
|
2358
|
-
const hasBranch = this.branches.has(valueStr);
|
|
2359
2544
|
const matchingFragment = hasBranch ? this.branches.get(valueStr) : this.defaultBranch;
|
|
2360
|
-
this.currentKey =
|
|
2545
|
+
this.currentKey = nextKey;
|
|
2361
2546
|
if (matchingFragment && matchingFragment.hasChildNodes()) {
|
|
2362
2547
|
this.startNode.parentNode.insertBefore(matchingFragment, this.endNode);
|
|
2363
2548
|
}
|
|
@@ -2535,7 +2720,9 @@ var Snice = (function (exports) {
|
|
|
2535
2720
|
// Supports both dot notation (@keydown.enter) and colon notation (@keydown:Enter)
|
|
2536
2721
|
// Only parse colons for keyboard events, not custom events
|
|
2537
2722
|
const isKeyboardEvent = ['keydown', 'keyup', 'keypress'].includes(handler.eventName.split('.')[0].split(':')[0]);
|
|
2538
|
-
|
|
2723
|
+
// Only keyboard events split on `.`/`:` into a key filter — a custom event
|
|
2724
|
+
// name may legitimately contain a dot (e.g. `app.ready`) and must be kept whole.
|
|
2725
|
+
const dotIndex = isKeyboardEvent ? handler.eventName.indexOf('.') : -1;
|
|
2539
2726
|
const colonIndex = isKeyboardEvent ? handler.eventName.indexOf(':') : -1;
|
|
2540
2727
|
const delimiterIndex = dotIndex > 0 && colonIndex > 0
|
|
2541
2728
|
? Math.min(dotIndex, colonIndex)
|
|
@@ -2546,6 +2733,8 @@ var Snice = (function (exports) {
|
|
|
2546
2733
|
const keyModifier = delimiterIndex > 0
|
|
2547
2734
|
? handler.eventName.substring(delimiterIndex + 1)
|
|
2548
2735
|
: null;
|
|
2736
|
+
if (delimiterIndex <= 0)
|
|
2737
|
+
warnIfModifierMisuse(handler.eventName);
|
|
2549
2738
|
// Apply debounce (takes precedence over throttle)
|
|
2550
2739
|
if (handlerOptions.debounce && handlerOptions.debounce > 0) {
|
|
2551
2740
|
boundMethod = createDebounced(boundMethod, handlerOptions.debounce);
|
|
@@ -2572,10 +2761,27 @@ var Snice = (function (exports) {
|
|
|
2572
2761
|
};
|
|
2573
2762
|
// Apply key modifier wrapper
|
|
2574
2763
|
const keyModifierMethod = createKeyModifierHandler(boundMethod);
|
|
2764
|
+
// Resolve scope: explicit `scope` option redirects the listener target
|
|
2765
|
+
// to document / ancestor / arbitrary EventTarget. Default = host element.
|
|
2766
|
+
const hasExplicitScope = handlerOptions.scope !== undefined;
|
|
2767
|
+
let scopedTarget = null;
|
|
2768
|
+
if (hasExplicitScope) {
|
|
2769
|
+
scopedTarget = resolveScope(targetElement, handlerOptions.scope);
|
|
2770
|
+
if (!scopedTarget) {
|
|
2771
|
+
// Dev warning — listener silently dropped when scope cannot resolve.
|
|
2772
|
+
// Skip attachment so we don't bind to the wrong target.
|
|
2773
|
+
console.warn(`[snice/@on] scope did not resolve for "${handler.eventName}" on ${handler.methodName} — listener skipped.`);
|
|
2774
|
+
continue;
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2575
2777
|
// Main event handler with error handling and event delegation
|
|
2576
2778
|
if (handler.selector) {
|
|
2577
|
-
// Delegated event handling
|
|
2578
|
-
|
|
2779
|
+
// Delegated event handling.
|
|
2780
|
+
// - Default eventRoot: shadow root if present, else host element.
|
|
2781
|
+
// - With explicit scope: attach to the scoped target instead.
|
|
2782
|
+
const eventRoot = hasExplicitScope
|
|
2783
|
+
? scopedTarget
|
|
2784
|
+
: (targetElement.shadowRoot || targetElement);
|
|
2579
2785
|
const delegatedHandler = (event) => {
|
|
2580
2786
|
const target = event.target;
|
|
2581
2787
|
const matchingElement = (target.matches && target.matches(handler.selector) && target) ||
|
|
@@ -2615,10 +2821,11 @@ var Snice = (function (exports) {
|
|
|
2615
2821
|
});
|
|
2616
2822
|
}
|
|
2617
2823
|
else {
|
|
2618
|
-
// Direct event handling
|
|
2619
|
-
//
|
|
2620
|
-
//
|
|
2621
|
-
|
|
2824
|
+
// Direct event handling.
|
|
2825
|
+
// - Default: shadow root + host element (so events inside shadow and on
|
|
2826
|
+
// the host itself both fire). A per-handler Symbol dedupes.
|
|
2827
|
+
// - With explicit scope: attach to the scoped target ONLY (no duplication).
|
|
2828
|
+
const shadowRoot = hasExplicitScope ? null : targetElement.shadowRoot;
|
|
2622
2829
|
// Per-handler private Symbol so dedup is scoped to THIS handler's two
|
|
2623
2830
|
// listeners (shadowRoot + host). Using Symbol.for() with the method name
|
|
2624
2831
|
// would collide across components that share a method name (e.g. a parent
|
|
@@ -2646,6 +2853,16 @@ var Snice = (function (exports) {
|
|
|
2646
2853
|
once: handlerOptions.once || false,
|
|
2647
2854
|
passive: handlerOptions.passive || false,
|
|
2648
2855
|
};
|
|
2856
|
+
if (hasExplicitScope) {
|
|
2857
|
+
scopedTarget.addEventListener(baseEventName, wrappedMethod, listenerOptions);
|
|
2858
|
+
instance[CLEANUP].events.push({
|
|
2859
|
+
target: scopedTarget,
|
|
2860
|
+
eventName: baseEventName,
|
|
2861
|
+
handler: wrappedMethod,
|
|
2862
|
+
options: listenerOptions,
|
|
2863
|
+
});
|
|
2864
|
+
continue;
|
|
2865
|
+
}
|
|
2649
2866
|
if (shadowRoot) {
|
|
2650
2867
|
// Listen on shadow root for events inside shadow DOM
|
|
2651
2868
|
shadowRoot.addEventListener(baseEventName, wrappedMethod, listenerOptions);
|
|
@@ -2808,11 +3025,25 @@ var Snice = (function (exports) {
|
|
|
2808
3025
|
}),
|
|
2809
3026
|
]);
|
|
2810
3027
|
}
|
|
3028
|
+
catch (error) {
|
|
3029
|
+
// Attach never got past `ready` (aborted or deadline). Roll back the stored
|
|
3030
|
+
// references so nothing is left pointing at a controller that never
|
|
3031
|
+
// attached — otherwise a later attach short-circuits as "already attached"
|
|
3032
|
+
// and a detach would run detach() on it.
|
|
3033
|
+
if (element[CONTROLLER_KEY] === controllerInstance) {
|
|
3034
|
+
delete element[CONTROLLER_KEY];
|
|
3035
|
+
delete element[CONTROLLER_NAME_KEY];
|
|
3036
|
+
delete element[CONTROLLER_OPERATIONS];
|
|
3037
|
+
}
|
|
3038
|
+
throw error;
|
|
3039
|
+
}
|
|
2811
3040
|
finally {
|
|
2812
3041
|
if (element[CONTROLLER_ABORT] === abort) {
|
|
2813
3042
|
delete element[CONTROLLER_ABORT];
|
|
2814
3043
|
}
|
|
2815
3044
|
}
|
|
3045
|
+
// Past `ready` — mark the controller so detach knows attach was actually run.
|
|
3046
|
+
controllerInstance[CONTROLLER_ATTACHED] = true;
|
|
2816
3047
|
// Run attach in the controller's scope
|
|
2817
3048
|
await scope.runOperation(async () => {
|
|
2818
3049
|
await controllerInstance.attach(element);
|
|
@@ -2843,6 +3074,19 @@ var Snice = (function (exports) {
|
|
|
2843
3074
|
if (!controllerInstance) {
|
|
2844
3075
|
return;
|
|
2845
3076
|
}
|
|
3077
|
+
// Claim the controller immediately — before any await — so a second detach
|
|
3078
|
+
// that overlaps this one (e.g. disconnect's fire-and-forget detach racing a
|
|
3079
|
+
// controller reassignment) finds no instance and returns, instead of running
|
|
3080
|
+
// detach() a second time on the same controller. The rest of this function
|
|
3081
|
+
// works off the locals captured above.
|
|
3082
|
+
delete element[CONTROLLER_KEY];
|
|
3083
|
+
delete element[CONTROLLER_NAME_KEY];
|
|
3084
|
+
delete element[CONTROLLER_OPERATIONS];
|
|
3085
|
+
// A controller whose attach() was aborted before it ever ran must not have
|
|
3086
|
+
// detach() (or the teardown/event) run on it.
|
|
3087
|
+
if (!controllerInstance[CONTROLLER_ATTACHED]) {
|
|
3088
|
+
return;
|
|
3089
|
+
}
|
|
2846
3090
|
// Run detach in the controller's scope
|
|
2847
3091
|
if (scope) {
|
|
2848
3092
|
await scope.runOperation(async () => {
|
|
@@ -2865,9 +3109,6 @@ var Snice = (function (exports) {
|
|
|
2865
3109
|
}
|
|
2866
3110
|
// Clean up router context reference
|
|
2867
3111
|
delete controllerInstance[ROUTER_CONTEXT];
|
|
2868
|
-
delete element[CONTROLLER_KEY];
|
|
2869
|
-
delete element[CONTROLLER_NAME_KEY];
|
|
2870
|
-
delete element[CONTROLLER_OPERATIONS];
|
|
2871
3112
|
element.dispatchEvent(new CustomEvent('controller-detached', {
|
|
2872
3113
|
detail: { name: controllerName, controller: controllerInstance }
|
|
2873
3114
|
}));
|
|
@@ -3030,19 +3271,23 @@ var Snice = (function (exports) {
|
|
|
3030
3271
|
const wrappedMethodName = `__wrapped_${methodName}`;
|
|
3031
3272
|
// Create wrapped method with timing controls
|
|
3032
3273
|
element[wrappedMethodName] = function (context) {
|
|
3033
|
-
//
|
|
3034
|
-
|
|
3274
|
+
// `once` is tracked PER method (not a single element-level flag) so
|
|
3275
|
+
// multiple once handlers on the same element each fire.
|
|
3276
|
+
const called = element[CONTEXT_CALLED] ||
|
|
3277
|
+
(element[CONTEXT_CALLED] = new Set());
|
|
3278
|
+
if (options.once && called.has(methodName)) {
|
|
3035
3279
|
return;
|
|
3036
3280
|
}
|
|
3037
3281
|
const callMethod = () => {
|
|
3038
3282
|
method.call(element, context);
|
|
3039
3283
|
// Handle once option
|
|
3040
3284
|
if (options.once) {
|
|
3041
|
-
|
|
3042
|
-
// Unregister
|
|
3285
|
+
called.add(methodName);
|
|
3286
|
+
// Unregister ONLY this handler, not the whole element — otherwise the
|
|
3287
|
+
// element's other @context handlers would stop receiving updates.
|
|
3043
3288
|
const ctx = element[NAVIGATION_CONTEXT_INSTANCE];
|
|
3044
3289
|
if (ctx && typeof ctx[CONTEXT_UNREGISTER] === 'function') {
|
|
3045
|
-
ctx[CONTEXT_UNREGISTER](element);
|
|
3290
|
+
ctx[CONTEXT_UNREGISTER](element, wrappedMethodName);
|
|
3046
3291
|
}
|
|
3047
3292
|
}
|
|
3048
3293
|
};
|
|
@@ -3145,9 +3390,14 @@ var Snice = (function (exports) {
|
|
|
3145
3390
|
this.pending.clear();
|
|
3146
3391
|
this.scheduled = false;
|
|
3147
3392
|
for (const element of elements) {
|
|
3148
|
-
// Skip elements that were disconnected between scheduling and flush
|
|
3149
|
-
|
|
3393
|
+
// Skip elements that were disconnected between scheduling and flush, but
|
|
3394
|
+
// remember the dropped render so reconnect can replay it — otherwise the
|
|
3395
|
+
// shadow DOM stays stale for a property changed while detached. The flag
|
|
3396
|
+
// lives on the element, so it's GC'd with it (no leak if never reattached).
|
|
3397
|
+
if (!element.isConnected) {
|
|
3398
|
+
element[PENDING_RECONNECT_RENDER] = true;
|
|
3150
3399
|
continue;
|
|
3400
|
+
}
|
|
3151
3401
|
const options = element[RENDER_OPTIONS] || {};
|
|
3152
3402
|
performRender(element, options);
|
|
3153
3403
|
}
|
|
@@ -3166,6 +3416,19 @@ var Snice = (function (exports) {
|
|
|
3166
3416
|
element[RENDER_CALLBACKS] = [];
|
|
3167
3417
|
cbs.forEach(cb => cb());
|
|
3168
3418
|
}
|
|
3419
|
+
/**
|
|
3420
|
+
* Backstop against a render() that mutates an observed property, which makes
|
|
3421
|
+
* the property setter request another render from inside the current one. In
|
|
3422
|
+
* `sync` mode that re-enters performRender synchronously and, unchecked,
|
|
3423
|
+
* recurses to a stack overflow. The counter caps synchronous nesting and turns
|
|
3424
|
+
* a silent crash into an actionable error. Normal renders never nest (child
|
|
3425
|
+
* renders defer to a microtask), so this stays at depth 1 in the common case.
|
|
3426
|
+
*
|
|
3427
|
+
* The depth is tracked PER ELEMENT (on RENDER_DEPTH), not globally: a runaway
|
|
3428
|
+
* component must not consume a shared budget and reject an unrelated component
|
|
3429
|
+
* that happens to render inside its call stack.
|
|
3430
|
+
*/
|
|
3431
|
+
const MAX_RENDER_DEPTH = 50;
|
|
3169
3432
|
/**
|
|
3170
3433
|
* Perform the actual render of an element
|
|
3171
3434
|
*/
|
|
@@ -3177,6 +3440,14 @@ var Snice = (function (exports) {
|
|
|
3177
3440
|
if (options.once && element[RENDER_INSTANCE]) {
|
|
3178
3441
|
return;
|
|
3179
3442
|
}
|
|
3443
|
+
const depth = (element[RENDER_DEPTH] ?? 0);
|
|
3444
|
+
if (depth >= MAX_RENDER_DEPTH) {
|
|
3445
|
+
const tag = element.tagName ? element.tagName.toLowerCase() : 'element';
|
|
3446
|
+
console.error(`snice: maximum render depth (${MAX_RENDER_DEPTH}) exceeded for <${tag}>. ` +
|
|
3447
|
+
`render() is mutating an observed property, causing an infinite render loop.`);
|
|
3448
|
+
return;
|
|
3449
|
+
}
|
|
3450
|
+
element[RENDER_DEPTH] = depth + 1;
|
|
3180
3451
|
try {
|
|
3181
3452
|
const result = precomputedResult !== undefined ? precomputedResult : renderMethod.call(element);
|
|
3182
3453
|
if (!element.shadowRoot)
|
|
@@ -3202,14 +3473,18 @@ var Snice = (function (exports) {
|
|
|
3202
3473
|
flushRenderCallbacks(element);
|
|
3203
3474
|
return;
|
|
3204
3475
|
}
|
|
3205
|
-
// Different template or first render.
|
|
3206
|
-
//
|
|
3207
|
-
//
|
|
3476
|
+
// Different template or first render. Keep only the framework's own
|
|
3477
|
+
// fallback <style> tags (marked data-snice-style) so the @styles path
|
|
3478
|
+
// (Safari <=16 / jsdom / SSR — no adoptedStyleSheets) survives a template
|
|
3479
|
+
// switch; template-emitted <style> tags are removed and re-created by the
|
|
3480
|
+
// new instance, so they don't accumulate.
|
|
3208
3481
|
if (instance) {
|
|
3209
3482
|
const root = element.shadowRoot;
|
|
3210
3483
|
const toRemove = [];
|
|
3211
3484
|
for (const child of Array.from(root.childNodes)) {
|
|
3212
|
-
if (child.nodeType === 1 &&
|
|
3485
|
+
if (child.nodeType === 1 &&
|
|
3486
|
+
child.tagName === 'STYLE' &&
|
|
3487
|
+
child.hasAttribute('data-snice-style'))
|
|
3213
3488
|
continue;
|
|
3214
3489
|
toRemove.push(child);
|
|
3215
3490
|
}
|
|
@@ -3225,6 +3500,9 @@ var Snice = (function (exports) {
|
|
|
3225
3500
|
catch (error) {
|
|
3226
3501
|
console.error('Error rendering element:', error);
|
|
3227
3502
|
}
|
|
3503
|
+
finally {
|
|
3504
|
+
element[RENDER_DEPTH] = depth;
|
|
3505
|
+
}
|
|
3228
3506
|
}
|
|
3229
3507
|
/**
|
|
3230
3508
|
* Request a render for an element
|
|
@@ -3278,6 +3556,33 @@ var Snice = (function (exports) {
|
|
|
3278
3556
|
// Normal rendering (with microtask batching unless sync)
|
|
3279
3557
|
renderScheduler.schedule(element, options);
|
|
3280
3558
|
}
|
|
3559
|
+
/**
|
|
3560
|
+
* Clear any pending debounce/throttle render timers on an element (e.g. on
|
|
3561
|
+
* disconnect, so they don't fire on a dead element and retain it until they
|
|
3562
|
+
* expire). Returns true if a render was actually pending, so the caller can
|
|
3563
|
+
* arrange a replay on reconnect via PENDING_RECONNECT_RENDER.
|
|
3564
|
+
*/
|
|
3565
|
+
function clearRenderTimers(element) {
|
|
3566
|
+
const timers = element[RENDER_TIMERS];
|
|
3567
|
+
if (!timers)
|
|
3568
|
+
return false;
|
|
3569
|
+
let hadPending = false;
|
|
3570
|
+
if (timers.debounce) {
|
|
3571
|
+
clearTimeout(timers.debounce);
|
|
3572
|
+
timers.debounce = null;
|
|
3573
|
+
hadPending = true;
|
|
3574
|
+
}
|
|
3575
|
+
if (timers.throttleTimer) {
|
|
3576
|
+
clearTimeout(timers.throttleTimer);
|
|
3577
|
+
timers.throttleTimer = null;
|
|
3578
|
+
hadPending = true;
|
|
3579
|
+
}
|
|
3580
|
+
// Deliberately do NOT reset timers.lastThrottle: a plain DOM move is a
|
|
3581
|
+
// disconnect+reconnect, and zeroing the cooldown would let the next render
|
|
3582
|
+
// fire inside the throttle window. Preserving it keeps throttle honest
|
|
3583
|
+
// across moves; on a true disconnect the element is discarded anyway.
|
|
3584
|
+
return hadPending;
|
|
3585
|
+
}
|
|
3281
3586
|
/**
|
|
3282
3587
|
* @render decorator for component rendering
|
|
3283
3588
|
*
|
|
@@ -3400,9 +3705,12 @@ var Snice = (function (exports) {
|
|
|
3400
3705
|
element.shadowRoot.adoptedStyleSheets = allResults.map(r => r.styleSheet);
|
|
3401
3706
|
return;
|
|
3402
3707
|
}
|
|
3403
|
-
// Fallback — one <style> tag per stylesheet, preserving cascade order
|
|
3708
|
+
// Fallback — one <style> tag per stylesheet, preserving cascade order.
|
|
3709
|
+
// Marked so the template-switch cleanup keeps these (framework styles) but
|
|
3710
|
+
// still removes template-emitted <style> tags (which would otherwise pile up).
|
|
3404
3711
|
for (const r of allResults) {
|
|
3405
3712
|
const style = document.createElement('style');
|
|
3713
|
+
style.setAttribute('data-snice-style', '');
|
|
3406
3714
|
style.textContent = r.cssText;
|
|
3407
3715
|
element.shadowRoot.appendChild(style);
|
|
3408
3716
|
}
|
|
@@ -3412,6 +3720,125 @@ var Snice = (function (exports) {
|
|
|
3412
3720
|
}
|
|
3413
3721
|
}
|
|
3414
3722
|
|
|
3723
|
+
// @dispatch decorator - auto-dispatches custom events from method return values
|
|
3724
|
+
/**
|
|
3725
|
+
* Decorator that automatically dispatches a custom event after a method is called.
|
|
3726
|
+
* The return value of the method becomes the event detail.
|
|
3727
|
+
*
|
|
3728
|
+
* @param eventName The name of the event to dispatch
|
|
3729
|
+
* @param options Optional configuration extending EventInit
|
|
3730
|
+
*/
|
|
3731
|
+
function dispatch(eventName, options) {
|
|
3732
|
+
return function (originalMethod, _context) {
|
|
3733
|
+
return function (...args) {
|
|
3734
|
+
// Create timing wrappers for dispatch (per-instance)
|
|
3735
|
+
if (!this[DISPATCH_TIMERS]) {
|
|
3736
|
+
this[DISPATCH_TIMERS] = new Map();
|
|
3737
|
+
}
|
|
3738
|
+
const timerKey = `${eventName}_${_context.name}`;
|
|
3739
|
+
if (!this[DISPATCH_TIMERS].has(timerKey)) {
|
|
3740
|
+
this[DISPATCH_TIMERS].set(timerKey, {
|
|
3741
|
+
debounceTimeout: null,
|
|
3742
|
+
throttleLastCall: 0,
|
|
3743
|
+
throttleTimeout: null
|
|
3744
|
+
});
|
|
3745
|
+
}
|
|
3746
|
+
const timers = this[DISPATCH_TIMERS].get(timerKey);
|
|
3747
|
+
// Call the original method with preserved this context
|
|
3748
|
+
const result = originalMethod.apply(this, args);
|
|
3749
|
+
// Helper to dispatch the event
|
|
3750
|
+
const doDispatch = (detail) => {
|
|
3751
|
+
// Skip dispatch if result is undefined and dispatchOnUndefined is false
|
|
3752
|
+
if (detail === undefined && options?.dispatchOnUndefined === false) {
|
|
3753
|
+
return;
|
|
3754
|
+
}
|
|
3755
|
+
// Create event with spread operator for options
|
|
3756
|
+
const event = new CustomEvent(eventName, {
|
|
3757
|
+
bubbles: true, // Default to true for component events
|
|
3758
|
+
composed: true, // Allow crossing shadow DOM boundaries
|
|
3759
|
+
...options, // Spread all EventInit options
|
|
3760
|
+
detail
|
|
3761
|
+
});
|
|
3762
|
+
// Resolve scope target. Default is `this` (host element).
|
|
3763
|
+
// Explicit scope dispatches the event on another target — useful for
|
|
3764
|
+
// 'global' bus events on document, or routing through an ancestor.
|
|
3765
|
+
if (options?.scope !== undefined) {
|
|
3766
|
+
const target = resolveScope(this, options.scope);
|
|
3767
|
+
if (!target) {
|
|
3768
|
+
console.warn(`[snice/@dispatch] scope did not resolve for "${eventName}" — event not dispatched.`);
|
|
3769
|
+
return;
|
|
3770
|
+
}
|
|
3771
|
+
target.dispatchEvent(event);
|
|
3772
|
+
return;
|
|
3773
|
+
}
|
|
3774
|
+
this.dispatchEvent(event);
|
|
3775
|
+
};
|
|
3776
|
+
// Helper to handle timed dispatch
|
|
3777
|
+
const timedDispatch = (detail) => {
|
|
3778
|
+
if (options?.debounce) {
|
|
3779
|
+
clearTimeout(timers.debounceTimeout);
|
|
3780
|
+
timers.debounceTimeout = setTimeout(() => doDispatch(detail), options.debounce);
|
|
3781
|
+
return;
|
|
3782
|
+
}
|
|
3783
|
+
if (!options?.throttle) {
|
|
3784
|
+
doDispatch(detail);
|
|
3785
|
+
return;
|
|
3786
|
+
}
|
|
3787
|
+
const now = Date.now();
|
|
3788
|
+
const remaining = options.throttle - (now - timers.throttleLastCall);
|
|
3789
|
+
if (remaining <= 0) {
|
|
3790
|
+
clearTimeout(timers.throttleTimeout);
|
|
3791
|
+
timers.throttleLastCall = now;
|
|
3792
|
+
doDispatch(detail);
|
|
3793
|
+
return;
|
|
3794
|
+
}
|
|
3795
|
+
// Record the LATEST detail so the trailing dispatch carries fresh
|
|
3796
|
+
// data, not the first-suppressed-call detail captured by closure.
|
|
3797
|
+
timers.latestDetail = detail;
|
|
3798
|
+
if (!timers.throttleTimeout) {
|
|
3799
|
+
timers.throttleTimeout = setTimeout(() => {
|
|
3800
|
+
timers.throttleLastCall = Date.now();
|
|
3801
|
+
timers.throttleTimeout = null;
|
|
3802
|
+
const d = timers.latestDetail;
|
|
3803
|
+
timers.latestDetail = undefined;
|
|
3804
|
+
doDispatch(d);
|
|
3805
|
+
}, remaining);
|
|
3806
|
+
}
|
|
3807
|
+
};
|
|
3808
|
+
// Handle async methods
|
|
3809
|
+
if (result instanceof Promise) {
|
|
3810
|
+
return result.then((resolvedResult) => {
|
|
3811
|
+
timedDispatch(resolvedResult);
|
|
3812
|
+
return resolvedResult;
|
|
3813
|
+
});
|
|
3814
|
+
}
|
|
3815
|
+
// Sync method
|
|
3816
|
+
timedDispatch(result);
|
|
3817
|
+
return result;
|
|
3818
|
+
};
|
|
3819
|
+
};
|
|
3820
|
+
}
|
|
3821
|
+
/**
|
|
3822
|
+
* Clear any pending debounce/throttle dispatch timers on an instance (e.g. on
|
|
3823
|
+
* disconnect, so a queued event doesn't fire into a detached node). A dispatch
|
|
3824
|
+
* is a one-shot signal, so pending ones are dropped, not replayed.
|
|
3825
|
+
*/
|
|
3826
|
+
function clearDispatchTimers(instance) {
|
|
3827
|
+
const timers = instance[DISPATCH_TIMERS];
|
|
3828
|
+
if (!timers)
|
|
3829
|
+
return;
|
|
3830
|
+
for (const t of timers.values()) {
|
|
3831
|
+
if (t.debounceTimeout)
|
|
3832
|
+
clearTimeout(t.debounceTimeout);
|
|
3833
|
+
if (t.throttleTimeout)
|
|
3834
|
+
clearTimeout(t.throttleTimeout);
|
|
3835
|
+
t.debounceTimeout = null;
|
|
3836
|
+
t.throttleTimeout = null;
|
|
3837
|
+
t.throttleLastCall = 0;
|
|
3838
|
+
t.latestDetail = undefined;
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
|
|
3415
3842
|
/**
|
|
3416
3843
|
* Method decorators for common patterns
|
|
3417
3844
|
* @debounce, @throttle, @once, @memoize
|
|
@@ -3838,6 +4265,14 @@ var Snice = (function (exports) {
|
|
|
3838
4265
|
}
|
|
3839
4266
|
}
|
|
3840
4267
|
}
|
|
4268
|
+
// Replay a render that was dropped while disconnected. The scheduler
|
|
4269
|
+
// sets this flag when it skips a detached element, so a property changed
|
|
4270
|
+
// while detached still reaches the DOM on reattach. A plain move (no
|
|
4271
|
+
// pending render) leaves the flag unset, so we don't re-render needlessly.
|
|
4272
|
+
if (this[RENDER_METHOD] && this[PENDING_RECONNECT_RENDER]) {
|
|
4273
|
+
this[PENDING_RECONNECT_RENDER] = false;
|
|
4274
|
+
requestRender(this);
|
|
4275
|
+
}
|
|
3841
4276
|
return;
|
|
3842
4277
|
}
|
|
3843
4278
|
// Mark that properties are being initialized from attributes
|
|
@@ -3885,6 +4320,9 @@ var Snice = (function (exports) {
|
|
|
3885
4320
|
setupResponseHandlers(this, this);
|
|
3886
4321
|
setupContextHandler(this);
|
|
3887
4322
|
this[INITIALIZED] = true;
|
|
4323
|
+
// Now that the initial value is settled, give @watch immediate handlers
|
|
4324
|
+
// their one init call (before the first render, so derived state is ready).
|
|
4325
|
+
invokeImmediateWatchers(this, constructor);
|
|
3888
4326
|
if (originalConnectedCallback) {
|
|
3889
4327
|
originalConnectedCallback.call(this);
|
|
3890
4328
|
}
|
|
@@ -3979,6 +4417,17 @@ var Snice = (function (exports) {
|
|
|
3979
4417
|
// Cleanup pending @debounce / @throttle timers so they don't fire on a dead element
|
|
3980
4418
|
clearDebounceTimers(this);
|
|
3981
4419
|
clearThrottleTimers(this);
|
|
4420
|
+
// The render/dispatch debounce-throttle timers live in separate stores.
|
|
4421
|
+
// A pending render is replayed on reconnect (same flag the scheduler
|
|
4422
|
+
// uses); a pending dispatch is a one-shot signal, so it's dropped.
|
|
4423
|
+
if (clearRenderTimers(this)) {
|
|
4424
|
+
this[PENDING_RECONNECT_RENDER] = true;
|
|
4425
|
+
}
|
|
4426
|
+
clearDispatchTimers(this);
|
|
4427
|
+
// @moved / @adopted debounce-throttle timers, likewise dropped so they
|
|
4428
|
+
// don't fire on a dead element.
|
|
4429
|
+
clearLifecycleTimers(this, MOVED_TIMERS);
|
|
4430
|
+
clearLifecycleTimers(this, ADOPTED_TIMERS);
|
|
3982
4431
|
};
|
|
3983
4432
|
constructor.prototype.attributeChangedCallback = function (name, oldValue, newValue) {
|
|
3984
4433
|
originalAttributeChangedCallback?.call(this, name, oldValue, newValue);
|
|
@@ -3994,13 +4443,27 @@ var Snice = (function (exports) {
|
|
|
3994
4443
|
if (attributeName.toLowerCase() !== name.toLowerCase())
|
|
3995
4444
|
continue;
|
|
3996
4445
|
const currentValue = this[PROPERTY_VALUES]?.[propName];
|
|
3997
|
-
|
|
3998
|
-
|
|
4446
|
+
// A removed attribute reverts the property to its field default. Read it
|
|
4447
|
+
// back through the getter (attribute is already gone at this point) so the
|
|
4448
|
+
// watcher's newValue and PROPERTY_VALUES match what this[propName] now
|
|
4449
|
+
// returns — parseAttributeValue(null) would diverge to null for String/Number.
|
|
4450
|
+
const parsedValue = newValue === null
|
|
4451
|
+
? this[propName]
|
|
4452
|
+
: parseAttributeValue(newValue, propOptions, currentValue, undefined);
|
|
4453
|
+
const changed = propOptions?.hasChanged
|
|
4454
|
+
? propOptions.hasChanged(parsedValue, currentValue)
|
|
4455
|
+
: notEqual(parsedValue, currentValue);
|
|
4456
|
+
if (!changed)
|
|
3999
4457
|
break;
|
|
4000
4458
|
ensureSet(this, EXPLICITLY_SET_PROPERTIES).add(propName);
|
|
4001
4459
|
ensureObj(this, PROPERTY_VALUES)[propName] = parsedValue;
|
|
4002
4460
|
if (!this[SETTING_FROM_PROPERTY]?.has(name.toLowerCase())) {
|
|
4003
|
-
|
|
4461
|
+
// Watchers react to changes only. During upgrade the initial value
|
|
4462
|
+
// is not a change, so suppress until INITIALIZED; @watch immediate
|
|
4463
|
+
// handlers get their one init call from invokeImmediateWatchers.
|
|
4464
|
+
if (this[INITIALIZED]) {
|
|
4465
|
+
invokeWatchers(this, constructor, propName, currentValue, parsedValue);
|
|
4466
|
+
}
|
|
4004
4467
|
if (this[RENDER_METHOD] && this[INITIALIZED]) {
|
|
4005
4468
|
requestRender(this);
|
|
4006
4469
|
}
|
|
@@ -4010,12 +4473,14 @@ var Snice = (function (exports) {
|
|
|
4010
4473
|
};
|
|
4011
4474
|
// Add connectedMoveCallback for handling DOM moves
|
|
4012
4475
|
constructor.prototype.connectedMoveCallback = async function () {
|
|
4013
|
-
// Call @moved handlers
|
|
4476
|
+
// Call @moved handlers via the prototype method (the debounce/throttle
|
|
4477
|
+
// wrapper), not the raw handler — otherwise @moved({debounce}) options
|
|
4478
|
+
// are ignored for real moves and only work when called directly.
|
|
4014
4479
|
const movedHandlers = constructor[MOVED_HANDLERS];
|
|
4015
4480
|
if (movedHandlers) {
|
|
4016
4481
|
for (const handler of movedHandlers) {
|
|
4017
4482
|
try {
|
|
4018
|
-
await handler.
|
|
4483
|
+
await this[handler.methodName]();
|
|
4019
4484
|
}
|
|
4020
4485
|
catch (error) {
|
|
4021
4486
|
console.error(`Error in @moved handler ${handler.methodName}:`, error);
|
|
@@ -4025,12 +4490,13 @@ var Snice = (function (exports) {
|
|
|
4025
4490
|
};
|
|
4026
4491
|
// Add adoptedCallback for handling document adoption
|
|
4027
4492
|
constructor.prototype.adoptedCallback = async function () {
|
|
4028
|
-
// Call @adopted handlers
|
|
4493
|
+
// Call @adopted handlers via the prototype method (the debounce/throttle
|
|
4494
|
+
// wrapper), not the raw handler — same reason as connectedMoveCallback.
|
|
4029
4495
|
const adoptedHandlers = constructor[ADOPTED_HANDLERS];
|
|
4030
4496
|
if (adoptedHandlers) {
|
|
4031
4497
|
for (const handler of adoptedHandlers) {
|
|
4032
4498
|
try {
|
|
4033
|
-
await handler.
|
|
4499
|
+
await this[handler.methodName]();
|
|
4034
4500
|
}
|
|
4035
4501
|
catch (error) {
|
|
4036
4502
|
console.error(`Error in @adopted handler ${handler.methodName}:`, error);
|
|
@@ -4195,7 +4661,12 @@ var Snice = (function (exports) {
|
|
|
4195
4661
|
},
|
|
4196
4662
|
set(newValue) {
|
|
4197
4663
|
const oldValue = this[propertyKey];
|
|
4198
|
-
|
|
4664
|
+
// A custom hasChanged comparator overrides the default === check
|
|
4665
|
+
// (e.g. deep-equal objects, or forcing an update on a mutated ref).
|
|
4666
|
+
const changed = finalOptions?.hasChanged
|
|
4667
|
+
? finalOptions.hasChanged(newValue, oldValue)
|
|
4668
|
+
: notEqual(newValue, oldValue);
|
|
4669
|
+
if (!changed)
|
|
4199
4670
|
return;
|
|
4200
4671
|
// Pre-init: store for later, don't reflect to DOM yet
|
|
4201
4672
|
if (!this[PROPERTIES_INITIALIZED]) {
|
|
@@ -4212,18 +4683,27 @@ var Snice = (function (exports) {
|
|
|
4212
4683
|
const attributeName = getAttrName(finalOptions, propertyKey);
|
|
4213
4684
|
const attributeValue = valueToAttribute(newValue, finalOptions, initialValue);
|
|
4214
4685
|
ensureSet(this, EXPLICITLY_SET_PROPERTIES).add(propertyKey);
|
|
4215
|
-
|
|
4686
|
+
const attrKey = attributeName.toLowerCase();
|
|
4687
|
+
ensureSet(this, SETTING_FROM_PROPERTY).add(attrKey);
|
|
4688
|
+
// attributeChangedCallback runs synchronously inside setAttribute /
|
|
4689
|
+
// removeAttribute (custom element reactions are synchronous), so the
|
|
4690
|
+
// guard only needs to bracket this one reflection. Clear it right
|
|
4691
|
+
// after — not on a microtask — otherwise an external attribute change
|
|
4692
|
+
// in the same tick is mistaken for our own echo and silently dropped.
|
|
4216
4693
|
if (attributeValue === null) {
|
|
4217
4694
|
this.removeAttribute?.(attributeName);
|
|
4218
4695
|
}
|
|
4219
4696
|
else {
|
|
4220
4697
|
this.setAttribute?.(attributeName, attributeValue);
|
|
4221
4698
|
}
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4699
|
+
this[SETTING_FROM_PROPERTY].delete(attrKey);
|
|
4700
|
+
}
|
|
4701
|
+
// See attributeChangedCallback: the initial value is not a change,
|
|
4702
|
+
// so suppress watchers until INITIALIZED. @watch immediate handlers
|
|
4703
|
+
// get their one init call from invokeImmediateWatchers.
|
|
4704
|
+
if (this[INITIALIZED]) {
|
|
4705
|
+
invokeWatchers(this, this.constructor, propertyKey, oldValue, newValue);
|
|
4225
4706
|
}
|
|
4226
|
-
invokeWatchers(this, this.constructor, propertyKey, oldValue, newValue);
|
|
4227
4707
|
if (this[RENDER_METHOD] && this[INITIALIZED]) {
|
|
4228
4708
|
requestRender(this);
|
|
4229
4709
|
}
|
|
@@ -4293,7 +4773,12 @@ var Snice = (function (exports) {
|
|
|
4293
4773
|
};
|
|
4294
4774
|
};
|
|
4295
4775
|
}
|
|
4296
|
-
function watch(...
|
|
4776
|
+
function watch(...args) {
|
|
4777
|
+
// A trailing options object is separated from the watched property names.
|
|
4778
|
+
const propertyNames = args.filter((a) => typeof a === 'string');
|
|
4779
|
+
const options = args.find((a) => typeof a === 'object' && a !== null);
|
|
4780
|
+
// Fire on init by default; opt out of the init call with { immediate: false }.
|
|
4781
|
+
const immediate = options?.immediate !== false;
|
|
4297
4782
|
return function (target, context) {
|
|
4298
4783
|
const methodName = context.name;
|
|
4299
4784
|
context.addInitializer(function () {
|
|
@@ -4333,7 +4818,8 @@ var Snice = (function (exports) {
|
|
|
4333
4818
|
}
|
|
4334
4819
|
constructor[PROPERTY_WATCHERS].get(propertyName).push({
|
|
4335
4820
|
methodName,
|
|
4336
|
-
method: target
|
|
4821
|
+
method: target,
|
|
4822
|
+
immediate
|
|
4337
4823
|
});
|
|
4338
4824
|
}
|
|
4339
4825
|
});
|
|
@@ -4442,6 +4928,24 @@ var Snice = (function (exports) {
|
|
|
4442
4928
|
registerHandler(RECONNECT_HANDLERS, RECONNECT_METHODS, target, context);
|
|
4443
4929
|
};
|
|
4444
4930
|
}
|
|
4931
|
+
/**
|
|
4932
|
+
* Clear any pending @moved / @adopted debounce/throttle timers on an instance
|
|
4933
|
+
* (e.g. on disconnect), so they don't fire on a dead element.
|
|
4934
|
+
*/
|
|
4935
|
+
function clearLifecycleTimers(instance, timersSymbol) {
|
|
4936
|
+
const map = instance[timersSymbol];
|
|
4937
|
+
if (!map)
|
|
4938
|
+
return;
|
|
4939
|
+
for (const t of map.values()) {
|
|
4940
|
+
if (t.debounceTimer)
|
|
4941
|
+
clearTimeout(t.debounceTimer);
|
|
4942
|
+
if (t.throttleTimer)
|
|
4943
|
+
clearTimeout(t.throttleTimer);
|
|
4944
|
+
t.debounceTimer = null;
|
|
4945
|
+
t.throttleTimer = null;
|
|
4946
|
+
t.lastThrottleCall = 0;
|
|
4947
|
+
}
|
|
4948
|
+
}
|
|
4445
4949
|
function createLifecycleDecorator(handlersSymbol, timersSymbol, methodsSymbol) {
|
|
4446
4950
|
return function (options = {}) {
|
|
4447
4951
|
return function (originalMethod, context) {
|
|
@@ -4455,9 +4959,23 @@ var Snice = (function (exports) {
|
|
|
4455
4959
|
}
|
|
4456
4960
|
const timers = this[timersSymbol].get(methodName);
|
|
4457
4961
|
const exec = (...a) => originalMethod.apply(this, a);
|
|
4962
|
+
// Deferred (debounce/throttle) calls run inside a setTimeout, outside
|
|
4963
|
+
// the caller's try/catch — so catch their sync throws and async
|
|
4964
|
+
// rejections here and log, rather than surface an uncaught error.
|
|
4965
|
+
const execDeferred = (...a) => {
|
|
4966
|
+
try {
|
|
4967
|
+
const result = originalMethod.apply(this, a);
|
|
4968
|
+
if (result && typeof result.then === 'function') {
|
|
4969
|
+
result.catch((error) => console.error(`Error in deferred lifecycle handler ${methodName}:`, error));
|
|
4970
|
+
}
|
|
4971
|
+
}
|
|
4972
|
+
catch (error) {
|
|
4973
|
+
console.error(`Error in deferred lifecycle handler ${methodName}:`, error);
|
|
4974
|
+
}
|
|
4975
|
+
};
|
|
4458
4976
|
if (options.debounce > 0) {
|
|
4459
4977
|
clearTimeout(timers.debounceTimer);
|
|
4460
|
-
timers.debounceTimer = setTimeout(() =>
|
|
4978
|
+
timers.debounceTimer = setTimeout(() => execDeferred(...args), options.debounce);
|
|
4461
4979
|
return undefined;
|
|
4462
4980
|
}
|
|
4463
4981
|
if (options.throttle > 0) {
|
|
@@ -4471,7 +4989,7 @@ var Snice = (function (exports) {
|
|
|
4471
4989
|
timers.throttleTimer = setTimeout(() => {
|
|
4472
4990
|
timers.throttleTimer = null;
|
|
4473
4991
|
timers.lastThrottleCall = Date.now();
|
|
4474
|
-
|
|
4992
|
+
execDeferred(...args);
|
|
4475
4993
|
}, remaining);
|
|
4476
4994
|
}
|
|
4477
4995
|
return undefined;
|
|
@@ -5103,6 +5621,40 @@ var Snice = (function (exports) {
|
|
|
5103
5621
|
}
|
|
5104
5622
|
}
|
|
5105
5623
|
|
|
5624
|
+
/**
|
|
5625
|
+
* Score a route pattern by specificity so that more specific routes are tried
|
|
5626
|
+
* first. Scoring is per-segment by ROLE, not by string length: a static segment
|
|
5627
|
+
* outweighs a dynamic (`:param`) segment, which outweighs a wildcard (`*` /
|
|
5628
|
+
* `*name`). So `/post/new` beats `/post/:id`, and a splat always ranks last —
|
|
5629
|
+
* regardless of how long the pattern string happens to be. This mirrors the
|
|
5630
|
+
* segment-scoring model mainstream routers (React Router, Remix) use.
|
|
5631
|
+
*
|
|
5632
|
+
* Sort callers descending by this score (highest = most specific = first).
|
|
5633
|
+
*
|
|
5634
|
+
* NOTE: mirrored in `src/react/route-specificity.ts` for the isolated React
|
|
5635
|
+
* bundle — keep the two in sync.
|
|
5636
|
+
*/
|
|
5637
|
+
const STATIC_SEGMENT = 10;
|
|
5638
|
+
const DYNAMIC_SEGMENT = 3;
|
|
5639
|
+
const WILDCARD_SEGMENT = -2;
|
|
5640
|
+
function routeSpecificity(spec) {
|
|
5641
|
+
const segments = spec.split('/').filter(Boolean);
|
|
5642
|
+
// Base on segment count so a deeper path outranks a shallower one on ties.
|
|
5643
|
+
let score = segments.length;
|
|
5644
|
+
for (const segment of segments) {
|
|
5645
|
+
if (segment.startsWith('*')) {
|
|
5646
|
+
score += WILDCARD_SEGMENT;
|
|
5647
|
+
}
|
|
5648
|
+
else if (segment.startsWith(':')) {
|
|
5649
|
+
score += DYNAMIC_SEGMENT;
|
|
5650
|
+
}
|
|
5651
|
+
else {
|
|
5652
|
+
score += STATIC_SEGMENT;
|
|
5653
|
+
}
|
|
5654
|
+
}
|
|
5655
|
+
return score;
|
|
5656
|
+
}
|
|
5657
|
+
|
|
5106
5658
|
/**
|
|
5107
5659
|
* Generic transition system for animating between elements
|
|
5108
5660
|
*/
|
|
@@ -5370,7 +5922,7 @@ var Snice = (function (exports) {
|
|
|
5370
5922
|
}
|
|
5371
5923
|
const needsSorting = !is_sorted;
|
|
5372
5924
|
if (needsSorting) {
|
|
5373
|
-
routes.sort((a, b) => b.route.spec
|
|
5925
|
+
routes.sort((a, b) => routeSpecificity(b.route.spec) - routeSpecificity(a.route.spec));
|
|
5374
5926
|
is_sorted = true;
|
|
5375
5927
|
}
|
|
5376
5928
|
// Collect placards from registered routes
|
|
@@ -5441,7 +5993,7 @@ var Snice = (function (exports) {
|
|
|
5441
5993
|
</div>`;
|
|
5442
5994
|
return container;
|
|
5443
5995
|
}
|
|
5444
|
-
async function checkGuards(guards, params, target) {
|
|
5996
|
+
async function checkGuards(guards, params, target, stale) {
|
|
5445
5997
|
const hasGuards = !!guards;
|
|
5446
5998
|
if (!hasGuards) {
|
|
5447
5999
|
return true;
|
|
@@ -5449,8 +6001,11 @@ var Snice = (function (exports) {
|
|
|
5449
6001
|
const guardsArray = Array.isArray(guards) ? guards : [guards];
|
|
5450
6002
|
let spinner = null;
|
|
5451
6003
|
let spinnerTimer = null;
|
|
5452
|
-
// Show spinner after a short delay (avoids flash for fast sync guards)
|
|
6004
|
+
// Show spinner after a short delay (avoids flash for fast sync guards).
|
|
6005
|
+
// Skip if a newer navigation has already superseded this one.
|
|
5453
6006
|
spinnerTimer = setTimeout(() => {
|
|
6007
|
+
if (stale && stale())
|
|
6008
|
+
return;
|
|
5454
6009
|
spinner = createLoadingSpinner();
|
|
5455
6010
|
target.appendChild(spinner);
|
|
5456
6011
|
}, 50);
|
|
@@ -5458,7 +6013,11 @@ var Snice = (function (exports) {
|
|
|
5458
6013
|
for (const guard of guardsArray) {
|
|
5459
6014
|
const allowed = await guard(context, params);
|
|
5460
6015
|
if (!allowed) {
|
|
5461
|
-
|
|
6016
|
+
// Don't stomp the current page with a 403 if a newer navigation
|
|
6017
|
+
// already took over while this guard was resolving.
|
|
6018
|
+
if (!stale || !stale()) {
|
|
6019
|
+
renderForbiddenPage(target);
|
|
6020
|
+
}
|
|
5462
6021
|
return false;
|
|
5463
6022
|
}
|
|
5464
6023
|
}
|
|
@@ -5494,14 +6053,14 @@ var Snice = (function (exports) {
|
|
|
5494
6053
|
div.innerHTML = /*html*/ `<h1>404</h1><p>Page not found</p>`;
|
|
5495
6054
|
return { element: div, transition: undefined, layout: undefined };
|
|
5496
6055
|
}
|
|
5497
|
-
async function resolveRoute(path, target) {
|
|
6056
|
+
async function resolveRoute(path, target, stale) {
|
|
5498
6057
|
for (const route of routes) {
|
|
5499
6058
|
const params = route.route.match(path);
|
|
5500
6059
|
const isMatch = params !== false;
|
|
5501
6060
|
if (!isMatch) {
|
|
5502
6061
|
continue;
|
|
5503
6062
|
}
|
|
5504
|
-
const guardsAllowed = await checkGuards(route.guards, params, target);
|
|
6063
|
+
const guardsAllowed = await checkGuards(route.guards, params, target, stale);
|
|
5505
6064
|
if (!guardsAllowed) {
|
|
5506
6065
|
return { result: RouteResult.GUARDS_FAILED };
|
|
5507
6066
|
}
|
|
@@ -5629,7 +6188,7 @@ var Snice = (function (exports) {
|
|
|
5629
6188
|
const isHomePath = (path?.trim() === '' || path === '/') && !!home;
|
|
5630
6189
|
if (isHomePath) {
|
|
5631
6190
|
const homeRoute = routes.find(r => r.route.match('/'));
|
|
5632
|
-
if (!(await checkGuards(homeRoute?.guards, {}, target)))
|
|
6191
|
+
if (!(await checkGuards(homeRoute?.guards, {}, target, stale)))
|
|
5633
6192
|
return;
|
|
5634
6193
|
if (stale())
|
|
5635
6194
|
return;
|
|
@@ -5641,7 +6200,7 @@ var Snice = (function (exports) {
|
|
|
5641
6200
|
if (!path)
|
|
5642
6201
|
return;
|
|
5643
6202
|
// Resolve route
|
|
5644
|
-
const routeResult = await resolveRoute(path, target);
|
|
6203
|
+
const routeResult = await resolveRoute(path, target, stale);
|
|
5645
6204
|
if (stale())
|
|
5646
6205
|
return;
|
|
5647
6206
|
// Guards failed (403 already rendered by checkGuards)
|
|
@@ -5655,7 +6214,7 @@ var Snice = (function (exports) {
|
|
|
5655
6214
|
}
|
|
5656
6215
|
// 404 fallthrough
|
|
5657
6216
|
const { element, transition, layout } = create404Element();
|
|
5658
|
-
await renderPage(target, element, transition, layout, path, {});
|
|
6217
|
+
await renderPage(target, element, transition, layout, path, {}, stale);
|
|
5659
6218
|
}
|
|
5660
6219
|
async function performTransition$1(container, oldElement, newElement, transition, atGen = navGeneration) {
|
|
5661
6220
|
// `isStale` returns true when a newer navigate() has been kicked off.
|
|
@@ -5672,93 +6231,6 @@ var Snice = (function (exports) {
|
|
|
5672
6231
|
};
|
|
5673
6232
|
}
|
|
5674
6233
|
|
|
5675
|
-
// @dispatch decorator - auto-dispatches custom events from method return values
|
|
5676
|
-
/**
|
|
5677
|
-
* Decorator that automatically dispatches a custom event after a method is called.
|
|
5678
|
-
* The return value of the method becomes the event detail.
|
|
5679
|
-
*
|
|
5680
|
-
* @param eventName The name of the event to dispatch
|
|
5681
|
-
* @param options Optional configuration extending EventInit
|
|
5682
|
-
*/
|
|
5683
|
-
function dispatch(eventName, options) {
|
|
5684
|
-
return function (originalMethod, _context) {
|
|
5685
|
-
return function (...args) {
|
|
5686
|
-
// Create timing wrappers for dispatch (per-instance)
|
|
5687
|
-
if (!this[DISPATCH_TIMERS]) {
|
|
5688
|
-
this[DISPATCH_TIMERS] = new Map();
|
|
5689
|
-
}
|
|
5690
|
-
const timerKey = `${eventName}_${_context.name}`;
|
|
5691
|
-
if (!this[DISPATCH_TIMERS].has(timerKey)) {
|
|
5692
|
-
this[DISPATCH_TIMERS].set(timerKey, {
|
|
5693
|
-
debounceTimeout: null,
|
|
5694
|
-
throttleLastCall: 0,
|
|
5695
|
-
throttleTimeout: null
|
|
5696
|
-
});
|
|
5697
|
-
}
|
|
5698
|
-
const timers = this[DISPATCH_TIMERS].get(timerKey);
|
|
5699
|
-
// Call the original method with preserved this context
|
|
5700
|
-
const result = originalMethod.apply(this, args);
|
|
5701
|
-
// Helper to dispatch the event
|
|
5702
|
-
const doDispatch = (detail) => {
|
|
5703
|
-
// Skip dispatch if result is undefined and dispatchOnUndefined is false
|
|
5704
|
-
if (detail === undefined && options?.dispatchOnUndefined === false) {
|
|
5705
|
-
return;
|
|
5706
|
-
}
|
|
5707
|
-
// Create event with spread operator for options
|
|
5708
|
-
const event = new CustomEvent(eventName, {
|
|
5709
|
-
bubbles: true, // Default to true for component events
|
|
5710
|
-
composed: true, // Allow crossing shadow DOM boundaries
|
|
5711
|
-
...options, // Spread all EventInit options
|
|
5712
|
-
detail
|
|
5713
|
-
});
|
|
5714
|
-
this.dispatchEvent(event);
|
|
5715
|
-
};
|
|
5716
|
-
// Helper to handle timed dispatch
|
|
5717
|
-
const timedDispatch = (detail) => {
|
|
5718
|
-
if (options?.debounce) {
|
|
5719
|
-
clearTimeout(timers.debounceTimeout);
|
|
5720
|
-
timers.debounceTimeout = setTimeout(() => doDispatch(detail), options.debounce);
|
|
5721
|
-
return;
|
|
5722
|
-
}
|
|
5723
|
-
if (!options?.throttle) {
|
|
5724
|
-
doDispatch(detail);
|
|
5725
|
-
return;
|
|
5726
|
-
}
|
|
5727
|
-
const now = Date.now();
|
|
5728
|
-
const remaining = options.throttle - (now - timers.throttleLastCall);
|
|
5729
|
-
if (remaining <= 0) {
|
|
5730
|
-
clearTimeout(timers.throttleTimeout);
|
|
5731
|
-
timers.throttleLastCall = now;
|
|
5732
|
-
doDispatch(detail);
|
|
5733
|
-
return;
|
|
5734
|
-
}
|
|
5735
|
-
// Record the LATEST detail so the trailing dispatch carries fresh
|
|
5736
|
-
// data, not the first-suppressed-call detail captured by closure.
|
|
5737
|
-
timers.latestDetail = detail;
|
|
5738
|
-
if (!timers.throttleTimeout) {
|
|
5739
|
-
timers.throttleTimeout = setTimeout(() => {
|
|
5740
|
-
timers.throttleLastCall = Date.now();
|
|
5741
|
-
timers.throttleTimeout = null;
|
|
5742
|
-
const d = timers.latestDetail;
|
|
5743
|
-
timers.latestDetail = undefined;
|
|
5744
|
-
doDispatch(d);
|
|
5745
|
-
}, remaining);
|
|
5746
|
-
}
|
|
5747
|
-
};
|
|
5748
|
-
// Handle async methods
|
|
5749
|
-
if (result instanceof Promise) {
|
|
5750
|
-
return result.then((resolvedResult) => {
|
|
5751
|
-
timedDispatch(resolvedResult);
|
|
5752
|
-
return resolvedResult;
|
|
5753
|
-
});
|
|
5754
|
-
}
|
|
5755
|
-
// Sync method
|
|
5756
|
-
timedDispatch(result);
|
|
5757
|
-
return result;
|
|
5758
|
-
};
|
|
5759
|
-
};
|
|
5760
|
-
}
|
|
5761
|
-
|
|
5762
6234
|
/**
|
|
5763
6235
|
* createRequestHandler — vanilla JS utility for handling @request channels
|
|
5764
6236
|
* outside of the Snice element/controller decorator system.
|
|
@@ -6104,7 +6576,7 @@ var Snice = (function (exports) {
|
|
|
6104
6576
|
}
|
|
6105
6577
|
|
|
6106
6578
|
/*!
|
|
6107
|
-
* snice v5.2.
|
|
6579
|
+
* snice v5.2.3
|
|
6108
6580
|
* A decorator-driven web component library with differential rendering, routing, controllers, and 130+ ready-made UI components. Use as much or as little as you want. Zero dependencies, works anywhere.
|
|
6109
6581
|
* (c) 2024
|
|
6110
6582
|
* Released under the MIT License.
|
|
@@ -6123,7 +6595,7 @@ var Snice = (function (exports) {
|
|
|
6123
6595
|
}
|
|
6124
6596
|
|
|
6125
6597
|
/*!
|
|
6126
|
-
* snice v5.2.
|
|
6598
|
+
* snice v5.2.3
|
|
6127
6599
|
* A decorator-driven web component library with differential rendering, routing, controllers, and 130+ ready-made UI components. Use as much or as little as you want. Zero dependencies, works anywhere.
|
|
6128
6600
|
* (c) 2024
|
|
6129
6601
|
* Released under the MIT License.
|