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
package/dist/index.iife.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* snice v5.2.
|
|
2
|
+
* snice v5.2.3
|
|
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.
|
|
@@ -36,6 +36,12 @@ var Snice = (function (exports) {
|
|
|
36
36
|
// Internal element state symbols
|
|
37
37
|
const READY_PROMISE = getSymbol('ready-promise');
|
|
38
38
|
const READY_RESOLVE = getSymbol('ready-resolve');
|
|
39
|
+
// Set when a render is requested but dropped because the element was
|
|
40
|
+
// disconnected; consumed on reconnect to replay exactly the missed render.
|
|
41
|
+
const PENDING_RECONNECT_RENDER = getSymbol('pending-reconnect-render');
|
|
42
|
+
// Per-element synchronous render-nesting depth, used to cap runaway re-entry
|
|
43
|
+
// without a shared global counter that one element could exhaust for others.
|
|
44
|
+
const RENDER_DEPTH = getSymbol('render-depth');
|
|
39
45
|
const CONTROLLER = getSymbol('controller');
|
|
40
46
|
const INITIALIZED = getSymbol('initialized');
|
|
41
47
|
// Controller symbols
|
|
@@ -107,6 +113,10 @@ var Snice = (function (exports) {
|
|
|
107
113
|
// Controller attach-abort — set to an AbortController while attachController
|
|
108
114
|
// is awaiting element.ready, so detachController can short-circuit the wait.
|
|
109
115
|
const CONTROLLER_ABORT = getSymbol('controller-abort');
|
|
116
|
+
// Set on a controller instance once it has gotten past element.ready and is
|
|
117
|
+
// being attached, so detachController knows not to run detach() on a controller
|
|
118
|
+
// whose attach() was aborted before it ever ran.
|
|
119
|
+
const CONTROLLER_ATTACHED = getSymbol('controller-attached');
|
|
110
120
|
const PROPERTY_DEFINERS = getSymbol('property-definers');
|
|
111
121
|
|
|
112
122
|
/**
|
|
@@ -227,11 +237,23 @@ var Snice = (function (exports) {
|
|
|
227
237
|
this[REGISTERED_ELEMENTS_SET].add(element);
|
|
228
238
|
}
|
|
229
239
|
/**
|
|
230
|
-
* Unregister an element from receiving context updates
|
|
240
|
+
* Unregister an element from receiving context updates. With a methodName,
|
|
241
|
+
* removes only that one handler (so a `once` handler tearing itself down
|
|
242
|
+
* doesn't kill the element's other @context handlers); without one, removes
|
|
243
|
+
* the element entirely (used on disconnect).
|
|
231
244
|
* @internal Used by @context decorator cleanup
|
|
232
245
|
*/
|
|
233
|
-
[CONTEXT_UNREGISTER](element) {
|
|
234
|
-
this[REGISTERED_ELEMENTS]
|
|
246
|
+
[CONTEXT_UNREGISTER](element, methodName) {
|
|
247
|
+
const map = this[REGISTERED_ELEMENTS];
|
|
248
|
+
if (methodName !== undefined) {
|
|
249
|
+
const names = map.get(element);
|
|
250
|
+
if (!names)
|
|
251
|
+
return;
|
|
252
|
+
names.delete(methodName);
|
|
253
|
+
if (names.size > 0)
|
|
254
|
+
return; // other handlers remain — keep the element
|
|
255
|
+
}
|
|
256
|
+
map.delete(element);
|
|
235
257
|
this[REGISTERED_ELEMENTS_SET].delete(element);
|
|
236
258
|
}
|
|
237
259
|
/**
|
|
@@ -396,11 +418,23 @@ var Snice = (function (exports) {
|
|
|
396
418
|
* @param initialValue - The default value assigned to the property field (used for type detection)
|
|
397
419
|
* @returns The string representation for the HTML attribute, or null if value should remove attribute
|
|
398
420
|
*/
|
|
421
|
+
/**
|
|
422
|
+
* Default property dirty-check: has the value changed? Like `!==`, but treats
|
|
423
|
+
* NaN → NaN as unchanged (NaN !== NaN would otherwise re-fire forever).
|
|
424
|
+
*/
|
|
425
|
+
function notEqual(value, old) {
|
|
426
|
+
// Changed unless strictly equal, or both are NaN (each self-unequal).
|
|
427
|
+
return value !== old && (value === value || old === old);
|
|
428
|
+
}
|
|
399
429
|
/**
|
|
400
430
|
* Extract attribute name from property options
|
|
401
431
|
*/
|
|
402
432
|
function getAttrName(opts, propName) {
|
|
403
|
-
|
|
433
|
+
// Lowercase always: the DOM stores attribute names lowercase, so an explicit
|
|
434
|
+
// camelCase `attribute:` would otherwise never match observedAttributes and
|
|
435
|
+
// attributeChangedCallback would never fire. get/setAttribute are already
|
|
436
|
+
// case-insensitive, so this is safe for every caller.
|
|
437
|
+
return (typeof opts.attribute === 'string' ? opts.attribute : propName).toLowerCase();
|
|
404
438
|
}
|
|
405
439
|
/**
|
|
406
440
|
* Escape HTML text-node content. Use for text that will be interpolated
|
|
@@ -547,6 +581,42 @@ var Snice = (function (exports) {
|
|
|
547
581
|
}
|
|
548
582
|
}
|
|
549
583
|
}
|
|
584
|
+
/**
|
|
585
|
+
* Fire the one-time initialization call for `@watch(..., { immediate: true })`
|
|
586
|
+
* handlers. Runs once per declared property after the element is initialized,
|
|
587
|
+
* passing the effective initial value with `oldValue` undefined. Non-immediate
|
|
588
|
+
* watchers are untouched — they only react to later changes.
|
|
589
|
+
*/
|
|
590
|
+
function invokeImmediateWatchers(instance, constructor) {
|
|
591
|
+
const watchers = constructor[PROPERTY_WATCHERS];
|
|
592
|
+
const properties = constructor[PROPERTIES];
|
|
593
|
+
if (!watchers || !properties)
|
|
594
|
+
return;
|
|
595
|
+
for (const [propName, propOptions] of properties) {
|
|
596
|
+
// A watcher may be registered under the JS name, the explicit `attribute:`
|
|
597
|
+
// name, or the `*` wildcard; fire each immediate one exactly once, keyed to
|
|
598
|
+
// this property's current value.
|
|
599
|
+
const keys = [propName];
|
|
600
|
+
const attrName = propOptions && typeof propOptions.attribute === 'string' ? propOptions.attribute : null;
|
|
601
|
+
if (attrName && attrName !== propName)
|
|
602
|
+
keys.push(attrName);
|
|
603
|
+
keys.push('*');
|
|
604
|
+
for (const key of keys) {
|
|
605
|
+
if (!watchers.has(key))
|
|
606
|
+
continue;
|
|
607
|
+
for (const w of watchers.get(key)) {
|
|
608
|
+
if (!w.immediate)
|
|
609
|
+
continue;
|
|
610
|
+
try {
|
|
611
|
+
w.method.call(instance, undefined, instance[propName], propName);
|
|
612
|
+
}
|
|
613
|
+
catch (e) {
|
|
614
|
+
console.error(`Error in @watch('${key}') method ${w.methodName}:`, e);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
550
620
|
/**
|
|
551
621
|
* Create a debounced version of a function
|
|
552
622
|
*/
|
|
@@ -580,6 +650,41 @@ var Snice = (function (exports) {
|
|
|
580
650
|
}
|
|
581
651
|
};
|
|
582
652
|
}
|
|
653
|
+
/**
|
|
654
|
+
* Resolve a scope option to a concrete EventTarget.
|
|
655
|
+
*
|
|
656
|
+
* - undefined → host element (default behavior)
|
|
657
|
+
* - 'global' → `document`
|
|
658
|
+
* - string → `host.closest(selector)` (nearest matching ancestor)
|
|
659
|
+
* - EventTarget instance → that target directly
|
|
660
|
+
* - resolver function → called with host as `this`, returns target or null
|
|
661
|
+
*
|
|
662
|
+
* Returns null when the scope cannot be resolved (e.g. selector matches no
|
|
663
|
+
* ancestor, resolver returns null). Caller decides how to handle null —
|
|
664
|
+
* typically warn in dev and skip listener attachment.
|
|
665
|
+
*/
|
|
666
|
+
function resolveScope(host, scope) {
|
|
667
|
+
if (scope === undefined || scope === null)
|
|
668
|
+
return host;
|
|
669
|
+
if (scope === 'global')
|
|
670
|
+
return typeof document !== 'undefined' ? document : null;
|
|
671
|
+
if (typeof scope === 'function') {
|
|
672
|
+
try {
|
|
673
|
+
return scope.call(host) || null;
|
|
674
|
+
}
|
|
675
|
+
catch {
|
|
676
|
+
return null;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
if (typeof scope === 'string') {
|
|
680
|
+
return host.closest?.(scope) || null;
|
|
681
|
+
}
|
|
682
|
+
// Direct EventTarget instance.
|
|
683
|
+
if (scope && typeof scope.addEventListener === 'function') {
|
|
684
|
+
return scope;
|
|
685
|
+
}
|
|
686
|
+
return null;
|
|
687
|
+
}
|
|
583
688
|
function valueToAttribute(value, propertyOptions, initialValue) {
|
|
584
689
|
// Handle null/undefined/false values and empty arrays
|
|
585
690
|
if (value === null || value === undefined || value === false ||
|
|
@@ -997,13 +1102,11 @@ var Snice = (function (exports) {
|
|
|
997
1102
|
return finalValue;
|
|
998
1103
|
}
|
|
999
1104
|
catch (error) {
|
|
1000
|
-
//
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
throw generatorError;
|
|
1006
|
-
}
|
|
1105
|
+
// Drive the generator's own catch block and return whatever it recovers
|
|
1106
|
+
// with (e.g. a cached fallback). If the generator re-throws instead,
|
|
1107
|
+
// generator.throw rejects and the error propagates to the caller.
|
|
1108
|
+
const { value: recovered } = await generator.throw(error);
|
|
1109
|
+
return recovered;
|
|
1007
1110
|
}
|
|
1008
1111
|
}; // Close actualRequest function
|
|
1009
1112
|
// Debounce
|
|
@@ -1027,9 +1130,21 @@ var Snice = (function (exports) {
|
|
|
1027
1130
|
const now = Date.now();
|
|
1028
1131
|
const remaining = options.throttle - (now - throttleLastCall);
|
|
1029
1132
|
if (remaining <= 0) {
|
|
1133
|
+
// Cancelling the scheduled trailing call must not orphan the promises
|
|
1134
|
+
// queued for it — settle them with this fresh result. Also reset
|
|
1135
|
+
// throttleTimeout so later within-window calls don't attach to a dead
|
|
1136
|
+
// timer and hang.
|
|
1030
1137
|
clearTimeout(throttleTimeout);
|
|
1138
|
+
throttleTimeout = null;
|
|
1031
1139
|
throttleLastCall = now;
|
|
1032
|
-
|
|
1140
|
+
const orphaned = throttleTrailingResolvers.splice(0);
|
|
1141
|
+
const p = actualRequest();
|
|
1142
|
+
if (orphaned.length) {
|
|
1143
|
+
p.then((r) => { for (const x of orphaned)
|
|
1144
|
+
x.resolve(r); }, (e) => { for (const x of orphaned)
|
|
1145
|
+
x.reject(e); });
|
|
1146
|
+
}
|
|
1147
|
+
return p;
|
|
1033
1148
|
}
|
|
1034
1149
|
// Throttle: already has pending trailing call — attach to it
|
|
1035
1150
|
if (throttleTimeout) {
|
|
@@ -1130,10 +1245,20 @@ var Snice = (function (exports) {
|
|
|
1130
1245
|
const now = Date.now();
|
|
1131
1246
|
const remaining = handler.options.throttle - (now - throttleLastCall);
|
|
1132
1247
|
if (remaining <= 0) {
|
|
1248
|
+
// Same as the @request side: settle any queued trailing callers with
|
|
1249
|
+
// this fresh result rather than orphaning their promises.
|
|
1133
1250
|
clearTimeout(throttleTimeout);
|
|
1134
1251
|
throttleTimeout = null;
|
|
1135
1252
|
throttleLastCall = now;
|
|
1136
|
-
|
|
1253
|
+
const orphaned = throttleTrailingResolvers.splice(0);
|
|
1254
|
+
throttleLatestArgs = null;
|
|
1255
|
+
const result = originalMethod(...args);
|
|
1256
|
+
if (orphaned.length) {
|
|
1257
|
+
Promise.resolve(result).then((r) => { for (const x of orphaned)
|
|
1258
|
+
x.resolve(r); }, (e) => { for (const x of orphaned)
|
|
1259
|
+
x.reject(e); });
|
|
1260
|
+
}
|
|
1261
|
+
return result;
|
|
1137
1262
|
}
|
|
1138
1263
|
// Remember the LATEST args so the trailing call uses fresh input,
|
|
1139
1264
|
// and queue every suppressed caller's resolver so they all receive
|
|
@@ -1240,7 +1365,10 @@ var Snice = (function (exports) {
|
|
|
1240
1365
|
// Combine strings and values into final CSS text
|
|
1241
1366
|
let cssText = strings[0];
|
|
1242
1367
|
for (let i = 0; i < values.length; i++) {
|
|
1243
|
-
|
|
1368
|
+
// Inline a nested css`` result by its text so style fragments compose;
|
|
1369
|
+
// String() on a CSSResult object would yield "[object Object]".
|
|
1370
|
+
const value = values[i];
|
|
1371
|
+
cssText += (isCSSResult(value) ? value.cssText : String(value)) + strings[i + 1];
|
|
1244
1372
|
}
|
|
1245
1373
|
const result = {
|
|
1246
1374
|
_$litType$: CSS_RESULT,
|
|
@@ -1391,6 +1519,20 @@ var Snice = (function (exports) {
|
|
|
1391
1519
|
const attrStrings = value.split(marker);
|
|
1392
1520
|
// Number of expressions = number of markers = attrStrings.length - 1
|
|
1393
1521
|
const expressionCount = attrStrings.length - 1;
|
|
1522
|
+
// Property/boolean/event bindings take a SINGLE expression — they
|
|
1523
|
+
// can't concatenate static text (a `.prop` is an object, not a
|
|
1524
|
+
// string). They consume the first expression; any static text or
|
|
1525
|
+
// extra expressions are ignored. But the value index must still
|
|
1526
|
+
// advance by the true marker count, or every later binding shifts.
|
|
1527
|
+
const isSingleExpressionBinding = /^@@?|^[.?]/.test(originalName);
|
|
1528
|
+
if (isSingleExpressionBinding) {
|
|
1529
|
+
const hasStaticText = attrStrings.some((s) => s !== '');
|
|
1530
|
+
if (expressionCount > 1 || hasStaticText) {
|
|
1531
|
+
console.warn(`snice: binding "${originalName}" takes a single expression; ` +
|
|
1532
|
+
`static text and extra interpolations are ignored. ` +
|
|
1533
|
+
`Use a plain attribute for string interpolation.`);
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1394
1536
|
if (originalName.startsWith('@@')) {
|
|
1395
1537
|
// Escaped event binding for events with @ in the name (e.g., @@snice/event -> @snice/event)
|
|
1396
1538
|
this.parts.push({
|
|
@@ -1399,7 +1541,7 @@ var Snice = (function (exports) {
|
|
|
1399
1541
|
name: originalName.slice(1), // Keep the @ in the event name
|
|
1400
1542
|
element
|
|
1401
1543
|
});
|
|
1402
|
-
partIndex +=
|
|
1544
|
+
partIndex += expressionCount;
|
|
1403
1545
|
}
|
|
1404
1546
|
else if (originalName.startsWith('@')) {
|
|
1405
1547
|
// Event binding (single value only)
|
|
@@ -1409,7 +1551,7 @@ var Snice = (function (exports) {
|
|
|
1409
1551
|
name: originalName.slice(1),
|
|
1410
1552
|
element
|
|
1411
1553
|
});
|
|
1412
|
-
partIndex +=
|
|
1554
|
+
partIndex += expressionCount;
|
|
1413
1555
|
}
|
|
1414
1556
|
else if (originalName.startsWith('.')) {
|
|
1415
1557
|
// Property binding (single value only)
|
|
@@ -1419,7 +1561,7 @@ var Snice = (function (exports) {
|
|
|
1419
1561
|
name: originalName.slice(1),
|
|
1420
1562
|
element
|
|
1421
1563
|
});
|
|
1422
|
-
partIndex +=
|
|
1564
|
+
partIndex += expressionCount;
|
|
1423
1565
|
}
|
|
1424
1566
|
else if (originalName.startsWith('?')) {
|
|
1425
1567
|
// Boolean attribute (single value only)
|
|
@@ -1429,7 +1571,7 @@ var Snice = (function (exports) {
|
|
|
1429
1571
|
name: originalName.slice(1),
|
|
1430
1572
|
element
|
|
1431
1573
|
});
|
|
1432
|
-
partIndex +=
|
|
1574
|
+
partIndex += expressionCount;
|
|
1433
1575
|
}
|
|
1434
1576
|
else {
|
|
1435
1577
|
// Regular attribute - supports multiple interpolations
|
|
@@ -1904,7 +2046,13 @@ var Snice = (function (exports) {
|
|
|
1904
2046
|
* Commit unsafe HTML string
|
|
1905
2047
|
*/
|
|
1906
2048
|
_commitUnsafeHTML(value) {
|
|
1907
|
-
//
|
|
2049
|
+
// Can't diff arbitrary HTML, but when the STRING is unchanged the DOM is
|
|
2050
|
+
// already correct — skip the clear+reparse so live state (typed input
|
|
2051
|
+
// values, focus, scroll) inside the block survives unrelated re-renders.
|
|
2052
|
+
const prev = this._committedValue;
|
|
2053
|
+
if (isUnsafeHTML(prev) && prev.html === value.html) {
|
|
2054
|
+
return;
|
|
2055
|
+
}
|
|
1908
2056
|
this._clear();
|
|
1909
2057
|
const temp = document.createElement('template');
|
|
1910
2058
|
temp.innerHTML = value.html;
|
|
@@ -2089,7 +2237,9 @@ var Snice = (function (exports) {
|
|
|
2089
2237
|
// Supports both dot notation (@keydown.enter) and colon notation (@keydown:Enter) to match @on decorator
|
|
2090
2238
|
// Only parse colons for keyboard events, not custom events
|
|
2091
2239
|
const isKeyboardEvent = ['keydown', 'keyup', 'keypress'].includes(eventName.split('.')[0].split(':')[0]);
|
|
2092
|
-
|
|
2240
|
+
// Only keyboard events split on `.`/`:` into a key filter — a custom event
|
|
2241
|
+
// name may legitimately contain a dot (e.g. `app.ready`) and must be kept whole.
|
|
2242
|
+
const dotIndex = isKeyboardEvent ? eventName.indexOf('.') : -1;
|
|
2093
2243
|
const colonIndex = isKeyboardEvent ? eventName.indexOf(':') : -1;
|
|
2094
2244
|
// Use whichever delimiter comes first (dot or colon)
|
|
2095
2245
|
const delimiterIndex = dotIndex > 0 && colonIndex > 0
|
|
@@ -2103,6 +2253,7 @@ var Snice = (function (exports) {
|
|
|
2103
2253
|
}
|
|
2104
2254
|
else {
|
|
2105
2255
|
this.eventName = eventName;
|
|
2256
|
+
warnIfModifierMisuse(eventName);
|
|
2106
2257
|
}
|
|
2107
2258
|
}
|
|
2108
2259
|
commit(value) {
|
|
@@ -2128,17 +2279,19 @@ var Snice = (function (exports) {
|
|
|
2128
2279
|
}
|
|
2129
2280
|
if (typeof value !== 'function')
|
|
2130
2281
|
return;
|
|
2131
|
-
// Auto-bind to host element (the custom element with shadow root)
|
|
2132
|
-
if (!this.host) {
|
|
2133
|
-
const rootNode = this.element.getRootNode();
|
|
2134
|
-
this.host = rootNode.host || null;
|
|
2135
|
-
}
|
|
2136
|
-
const context = this.host || null;
|
|
2137
2282
|
const keyFilter = this.keyFilter;
|
|
2138
2283
|
this.listener = ((event) => {
|
|
2139
2284
|
if (keyFilter && !matchesKeyboardFilter(event, keyFilter))
|
|
2140
2285
|
return;
|
|
2141
|
-
|
|
2286
|
+
// Resolve the host (the custom element owning the shadow root) at dispatch
|
|
2287
|
+
// time, not bind time: a binding inside an initially-hidden <if>/<case>
|
|
2288
|
+
// branch commits while off-DOM, where getRootNode() has no host — caching
|
|
2289
|
+
// that null permanently would call the handler with `this = null` once the
|
|
2290
|
+
// branch is shown. By the time an event fires, the element is in the DOM.
|
|
2291
|
+
if (!this.host) {
|
|
2292
|
+
this.host = this.element.getRootNode().host || null;
|
|
2293
|
+
}
|
|
2294
|
+
value.call(this.host || null, event);
|
|
2142
2295
|
});
|
|
2143
2296
|
this.element.addEventListener(this.eventName, this.listener);
|
|
2144
2297
|
}
|
|
@@ -2157,6 +2310,25 @@ var Snice = (function (exports) {
|
|
|
2157
2310
|
* "ctrl+shift+s" -> { key: "s", ctrl: true, shift: true }
|
|
2158
2311
|
* "~enter" -> { key: "Enter", anyModifiers: true }
|
|
2159
2312
|
*/
|
|
2313
|
+
// once/preventDefault/stopPropagation/capture/passive are @on() OPTIONS, not
|
|
2314
|
+
// template modifiers. A dotted non-keyboard event whose suffix is one of these
|
|
2315
|
+
// is almost certainly a mistake (e.g. `@click.once`) — it binds a listener for
|
|
2316
|
+
// an event type the DOM never dispatches. Warn instead of failing silently. A
|
|
2317
|
+
// legitimate custom event name like `app.ready` won't match and stays quiet.
|
|
2318
|
+
const MODIFIER_WORDS = new Set([
|
|
2319
|
+
'once', 'prevent', 'preventdefault', 'stop', 'stoppropagation', 'capture', 'passive',
|
|
2320
|
+
]);
|
|
2321
|
+
function warnIfModifierMisuse(eventName) {
|
|
2322
|
+
const dot = eventName.lastIndexOf('.');
|
|
2323
|
+
if (dot < 0)
|
|
2324
|
+
return;
|
|
2325
|
+
const suffix = eventName.slice(dot + 1).toLowerCase();
|
|
2326
|
+
if (!MODIFIER_WORDS.has(suffix))
|
|
2327
|
+
return;
|
|
2328
|
+
console.warn(`snice: "@${eventName}" is not a valid modifier — once/preventDefault/` +
|
|
2329
|
+
`stopPropagation/capture are @on() options, not template modifiers. ` +
|
|
2330
|
+
`This registers a listener for event "${eventName}", which never fires.`);
|
|
2331
|
+
}
|
|
2160
2332
|
function parseKeyboardFilter(spec) {
|
|
2161
2333
|
// Handle ~ prefix for matching regardless of modifiers
|
|
2162
2334
|
const anyModifiers = spec.startsWith('~');
|
|
@@ -2259,9 +2431,14 @@ var Snice = (function (exports) {
|
|
|
2259
2431
|
// Insert markers where <if> is
|
|
2260
2432
|
parent.insertBefore(this.startNode, ifElement);
|
|
2261
2433
|
parent.insertBefore(this.endNode, ifElement.nextSibling);
|
|
2262
|
-
//
|
|
2434
|
+
// Park <if>'s children in an off-DOM fragment immediately, rather than
|
|
2435
|
+
// leaving them in the live template fragment. Otherwise a branch that is
|
|
2436
|
+
// hidden on first render would still connect its children (when the
|
|
2437
|
+
// template mounts) and then disconnect them (on the first commit) — firing
|
|
2438
|
+
// mount side effects spuriously. commit(true) inserts them when shown.
|
|
2439
|
+
this.childFragment = document.createDocumentFragment();
|
|
2263
2440
|
while (ifElement.firstChild) {
|
|
2264
|
-
|
|
2441
|
+
this.childFragment.appendChild(ifElement.firstChild);
|
|
2265
2442
|
}
|
|
2266
2443
|
// Remove the <if> element from DOM
|
|
2267
2444
|
parent.removeChild(ifElement);
|
|
@@ -2342,16 +2519,24 @@ var Snice = (function (exports) {
|
|
|
2342
2519
|
parent.removeChild(caseElement);
|
|
2343
2520
|
}
|
|
2344
2521
|
commit(value) {
|
|
2345
|
-
|
|
2522
|
+
// Dirty-check on the SELECTED BRANCH, not the raw value. A value whose type
|
|
2523
|
+
// changed but stringifies the same (number 1 vs string '1' — e.g. a numeric
|
|
2524
|
+
// default replaced by a router param, which is always a string) selects the
|
|
2525
|
+
// same branch, so tearing it down and re-inserting it would needlessly
|
|
2526
|
+
// restart media/animations and lose focus inside it.
|
|
2527
|
+
const valueStr = String(value);
|
|
2528
|
+
const hasBranch = this.branches.has(valueStr);
|
|
2529
|
+
const nextKey = hasBranch ? valueStr : (this.defaultBranch ? '__default__' : null);
|
|
2530
|
+
if (this.currentKey === nextKey) {
|
|
2531
|
+
this.value = value;
|
|
2346
2532
|
return;
|
|
2533
|
+
}
|
|
2347
2534
|
this.value = value;
|
|
2348
|
-
const valueStr = String(value);
|
|
2349
2535
|
// Move current content back to its fragment
|
|
2350
2536
|
this._collectCurrent();
|
|
2351
2537
|
// Insert matching branch
|
|
2352
|
-
const hasBranch = this.branches.has(valueStr);
|
|
2353
2538
|
const matchingFragment = hasBranch ? this.branches.get(valueStr) : this.defaultBranch;
|
|
2354
|
-
this.currentKey =
|
|
2539
|
+
this.currentKey = nextKey;
|
|
2355
2540
|
if (matchingFragment && matchingFragment.hasChildNodes()) {
|
|
2356
2541
|
this.startNode.parentNode.insertBefore(matchingFragment, this.endNode);
|
|
2357
2542
|
}
|
|
@@ -2529,7 +2714,9 @@ var Snice = (function (exports) {
|
|
|
2529
2714
|
// Supports both dot notation (@keydown.enter) and colon notation (@keydown:Enter)
|
|
2530
2715
|
// Only parse colons for keyboard events, not custom events
|
|
2531
2716
|
const isKeyboardEvent = ['keydown', 'keyup', 'keypress'].includes(handler.eventName.split('.')[0].split(':')[0]);
|
|
2532
|
-
|
|
2717
|
+
// Only keyboard events split on `.`/`:` into a key filter — a custom event
|
|
2718
|
+
// name may legitimately contain a dot (e.g. `app.ready`) and must be kept whole.
|
|
2719
|
+
const dotIndex = isKeyboardEvent ? handler.eventName.indexOf('.') : -1;
|
|
2533
2720
|
const colonIndex = isKeyboardEvent ? handler.eventName.indexOf(':') : -1;
|
|
2534
2721
|
const delimiterIndex = dotIndex > 0 && colonIndex > 0
|
|
2535
2722
|
? Math.min(dotIndex, colonIndex)
|
|
@@ -2540,6 +2727,8 @@ var Snice = (function (exports) {
|
|
|
2540
2727
|
const keyModifier = delimiterIndex > 0
|
|
2541
2728
|
? handler.eventName.substring(delimiterIndex + 1)
|
|
2542
2729
|
: null;
|
|
2730
|
+
if (delimiterIndex <= 0)
|
|
2731
|
+
warnIfModifierMisuse(handler.eventName);
|
|
2543
2732
|
// Apply debounce (takes precedence over throttle)
|
|
2544
2733
|
if (handlerOptions.debounce && handlerOptions.debounce > 0) {
|
|
2545
2734
|
boundMethod = createDebounced(boundMethod, handlerOptions.debounce);
|
|
@@ -2566,10 +2755,27 @@ var Snice = (function (exports) {
|
|
|
2566
2755
|
};
|
|
2567
2756
|
// Apply key modifier wrapper
|
|
2568
2757
|
const keyModifierMethod = createKeyModifierHandler(boundMethod);
|
|
2758
|
+
// Resolve scope: explicit `scope` option redirects the listener target
|
|
2759
|
+
// to document / ancestor / arbitrary EventTarget. Default = host element.
|
|
2760
|
+
const hasExplicitScope = handlerOptions.scope !== undefined;
|
|
2761
|
+
let scopedTarget = null;
|
|
2762
|
+
if (hasExplicitScope) {
|
|
2763
|
+
scopedTarget = resolveScope(targetElement, handlerOptions.scope);
|
|
2764
|
+
if (!scopedTarget) {
|
|
2765
|
+
// Dev warning — listener silently dropped when scope cannot resolve.
|
|
2766
|
+
// Skip attachment so we don't bind to the wrong target.
|
|
2767
|
+
console.warn(`[snice/@on] scope did not resolve for "${handler.eventName}" on ${handler.methodName} — listener skipped.`);
|
|
2768
|
+
continue;
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2569
2771
|
// Main event handler with error handling and event delegation
|
|
2570
2772
|
if (handler.selector) {
|
|
2571
|
-
// Delegated event handling
|
|
2572
|
-
|
|
2773
|
+
// Delegated event handling.
|
|
2774
|
+
// - Default eventRoot: shadow root if present, else host element.
|
|
2775
|
+
// - With explicit scope: attach to the scoped target instead.
|
|
2776
|
+
const eventRoot = hasExplicitScope
|
|
2777
|
+
? scopedTarget
|
|
2778
|
+
: (targetElement.shadowRoot || targetElement);
|
|
2573
2779
|
const delegatedHandler = (event) => {
|
|
2574
2780
|
const target = event.target;
|
|
2575
2781
|
const matchingElement = (target.matches && target.matches(handler.selector) && target) ||
|
|
@@ -2609,10 +2815,11 @@ var Snice = (function (exports) {
|
|
|
2609
2815
|
});
|
|
2610
2816
|
}
|
|
2611
2817
|
else {
|
|
2612
|
-
// Direct event handling
|
|
2613
|
-
//
|
|
2614
|
-
//
|
|
2615
|
-
|
|
2818
|
+
// Direct event handling.
|
|
2819
|
+
// - Default: shadow root + host element (so events inside shadow and on
|
|
2820
|
+
// the host itself both fire). A per-handler Symbol dedupes.
|
|
2821
|
+
// - With explicit scope: attach to the scoped target ONLY (no duplication).
|
|
2822
|
+
const shadowRoot = hasExplicitScope ? null : targetElement.shadowRoot;
|
|
2616
2823
|
// Per-handler private Symbol so dedup is scoped to THIS handler's two
|
|
2617
2824
|
// listeners (shadowRoot + host). Using Symbol.for() with the method name
|
|
2618
2825
|
// would collide across components that share a method name (e.g. a parent
|
|
@@ -2640,6 +2847,16 @@ var Snice = (function (exports) {
|
|
|
2640
2847
|
once: handlerOptions.once || false,
|
|
2641
2848
|
passive: handlerOptions.passive || false,
|
|
2642
2849
|
};
|
|
2850
|
+
if (hasExplicitScope) {
|
|
2851
|
+
scopedTarget.addEventListener(baseEventName, wrappedMethod, listenerOptions);
|
|
2852
|
+
instance[CLEANUP].events.push({
|
|
2853
|
+
target: scopedTarget,
|
|
2854
|
+
eventName: baseEventName,
|
|
2855
|
+
handler: wrappedMethod,
|
|
2856
|
+
options: listenerOptions,
|
|
2857
|
+
});
|
|
2858
|
+
continue;
|
|
2859
|
+
}
|
|
2643
2860
|
if (shadowRoot) {
|
|
2644
2861
|
// Listen on shadow root for events inside shadow DOM
|
|
2645
2862
|
shadowRoot.addEventListener(baseEventName, wrappedMethod, listenerOptions);
|
|
@@ -2802,11 +3019,25 @@ var Snice = (function (exports) {
|
|
|
2802
3019
|
}),
|
|
2803
3020
|
]);
|
|
2804
3021
|
}
|
|
3022
|
+
catch (error) {
|
|
3023
|
+
// Attach never got past `ready` (aborted or deadline). Roll back the stored
|
|
3024
|
+
// references so nothing is left pointing at a controller that never
|
|
3025
|
+
// attached — otherwise a later attach short-circuits as "already attached"
|
|
3026
|
+
// and a detach would run detach() on it.
|
|
3027
|
+
if (element[CONTROLLER_KEY] === controllerInstance) {
|
|
3028
|
+
delete element[CONTROLLER_KEY];
|
|
3029
|
+
delete element[CONTROLLER_NAME_KEY];
|
|
3030
|
+
delete element[CONTROLLER_OPERATIONS];
|
|
3031
|
+
}
|
|
3032
|
+
throw error;
|
|
3033
|
+
}
|
|
2805
3034
|
finally {
|
|
2806
3035
|
if (element[CONTROLLER_ABORT] === abort) {
|
|
2807
3036
|
delete element[CONTROLLER_ABORT];
|
|
2808
3037
|
}
|
|
2809
3038
|
}
|
|
3039
|
+
// Past `ready` — mark the controller so detach knows attach was actually run.
|
|
3040
|
+
controllerInstance[CONTROLLER_ATTACHED] = true;
|
|
2810
3041
|
// Run attach in the controller's scope
|
|
2811
3042
|
await scope.runOperation(async () => {
|
|
2812
3043
|
await controllerInstance.attach(element);
|
|
@@ -2837,6 +3068,19 @@ var Snice = (function (exports) {
|
|
|
2837
3068
|
if (!controllerInstance) {
|
|
2838
3069
|
return;
|
|
2839
3070
|
}
|
|
3071
|
+
// Claim the controller immediately — before any await — so a second detach
|
|
3072
|
+
// that overlaps this one (e.g. disconnect's fire-and-forget detach racing a
|
|
3073
|
+
// controller reassignment) finds no instance and returns, instead of running
|
|
3074
|
+
// detach() a second time on the same controller. The rest of this function
|
|
3075
|
+
// works off the locals captured above.
|
|
3076
|
+
delete element[CONTROLLER_KEY];
|
|
3077
|
+
delete element[CONTROLLER_NAME_KEY];
|
|
3078
|
+
delete element[CONTROLLER_OPERATIONS];
|
|
3079
|
+
// A controller whose attach() was aborted before it ever ran must not have
|
|
3080
|
+
// detach() (or the teardown/event) run on it.
|
|
3081
|
+
if (!controllerInstance[CONTROLLER_ATTACHED]) {
|
|
3082
|
+
return;
|
|
3083
|
+
}
|
|
2840
3084
|
// Run detach in the controller's scope
|
|
2841
3085
|
if (scope) {
|
|
2842
3086
|
await scope.runOperation(async () => {
|
|
@@ -2859,9 +3103,6 @@ var Snice = (function (exports) {
|
|
|
2859
3103
|
}
|
|
2860
3104
|
// Clean up router context reference
|
|
2861
3105
|
delete controllerInstance[ROUTER_CONTEXT];
|
|
2862
|
-
delete element[CONTROLLER_KEY];
|
|
2863
|
-
delete element[CONTROLLER_NAME_KEY];
|
|
2864
|
-
delete element[CONTROLLER_OPERATIONS];
|
|
2865
3106
|
element.dispatchEvent(new CustomEvent('controller-detached', {
|
|
2866
3107
|
detail: { name: controllerName, controller: controllerInstance }
|
|
2867
3108
|
}));
|
|
@@ -3024,19 +3265,23 @@ var Snice = (function (exports) {
|
|
|
3024
3265
|
const wrappedMethodName = `__wrapped_${methodName}`;
|
|
3025
3266
|
// Create wrapped method with timing controls
|
|
3026
3267
|
element[wrappedMethodName] = function (context) {
|
|
3027
|
-
//
|
|
3028
|
-
|
|
3268
|
+
// `once` is tracked PER method (not a single element-level flag) so
|
|
3269
|
+
// multiple once handlers on the same element each fire.
|
|
3270
|
+
const called = element[CONTEXT_CALLED] ||
|
|
3271
|
+
(element[CONTEXT_CALLED] = new Set());
|
|
3272
|
+
if (options.once && called.has(methodName)) {
|
|
3029
3273
|
return;
|
|
3030
3274
|
}
|
|
3031
3275
|
const callMethod = () => {
|
|
3032
3276
|
method.call(element, context);
|
|
3033
3277
|
// Handle once option
|
|
3034
3278
|
if (options.once) {
|
|
3035
|
-
|
|
3036
|
-
// Unregister
|
|
3279
|
+
called.add(methodName);
|
|
3280
|
+
// Unregister ONLY this handler, not the whole element — otherwise the
|
|
3281
|
+
// element's other @context handlers would stop receiving updates.
|
|
3037
3282
|
const ctx = element[NAVIGATION_CONTEXT_INSTANCE];
|
|
3038
3283
|
if (ctx && typeof ctx[CONTEXT_UNREGISTER] === 'function') {
|
|
3039
|
-
ctx[CONTEXT_UNREGISTER](element);
|
|
3284
|
+
ctx[CONTEXT_UNREGISTER](element, wrappedMethodName);
|
|
3040
3285
|
}
|
|
3041
3286
|
}
|
|
3042
3287
|
};
|
|
@@ -3139,9 +3384,14 @@ var Snice = (function (exports) {
|
|
|
3139
3384
|
this.pending.clear();
|
|
3140
3385
|
this.scheduled = false;
|
|
3141
3386
|
for (const element of elements) {
|
|
3142
|
-
// Skip elements that were disconnected between scheduling and flush
|
|
3143
|
-
|
|
3387
|
+
// Skip elements that were disconnected between scheduling and flush, but
|
|
3388
|
+
// remember the dropped render so reconnect can replay it — otherwise the
|
|
3389
|
+
// shadow DOM stays stale for a property changed while detached. The flag
|
|
3390
|
+
// lives on the element, so it's GC'd with it (no leak if never reattached).
|
|
3391
|
+
if (!element.isConnected) {
|
|
3392
|
+
element[PENDING_RECONNECT_RENDER] = true;
|
|
3144
3393
|
continue;
|
|
3394
|
+
}
|
|
3145
3395
|
const options = element[RENDER_OPTIONS] || {};
|
|
3146
3396
|
performRender(element, options);
|
|
3147
3397
|
}
|
|
@@ -3160,6 +3410,19 @@ var Snice = (function (exports) {
|
|
|
3160
3410
|
element[RENDER_CALLBACKS] = [];
|
|
3161
3411
|
cbs.forEach(cb => cb());
|
|
3162
3412
|
}
|
|
3413
|
+
/**
|
|
3414
|
+
* Backstop against a render() that mutates an observed property, which makes
|
|
3415
|
+
* the property setter request another render from inside the current one. In
|
|
3416
|
+
* `sync` mode that re-enters performRender synchronously and, unchecked,
|
|
3417
|
+
* recurses to a stack overflow. The counter caps synchronous nesting and turns
|
|
3418
|
+
* a silent crash into an actionable error. Normal renders never nest (child
|
|
3419
|
+
* renders defer to a microtask), so this stays at depth 1 in the common case.
|
|
3420
|
+
*
|
|
3421
|
+
* The depth is tracked PER ELEMENT (on RENDER_DEPTH), not globally: a runaway
|
|
3422
|
+
* component must not consume a shared budget and reject an unrelated component
|
|
3423
|
+
* that happens to render inside its call stack.
|
|
3424
|
+
*/
|
|
3425
|
+
const MAX_RENDER_DEPTH = 50;
|
|
3163
3426
|
/**
|
|
3164
3427
|
* Perform the actual render of an element
|
|
3165
3428
|
*/
|
|
@@ -3171,6 +3434,14 @@ var Snice = (function (exports) {
|
|
|
3171
3434
|
if (options.once && element[RENDER_INSTANCE]) {
|
|
3172
3435
|
return;
|
|
3173
3436
|
}
|
|
3437
|
+
const depth = (element[RENDER_DEPTH] ?? 0);
|
|
3438
|
+
if (depth >= MAX_RENDER_DEPTH) {
|
|
3439
|
+
const tag = element.tagName ? element.tagName.toLowerCase() : 'element';
|
|
3440
|
+
console.error(`snice: maximum render depth (${MAX_RENDER_DEPTH}) exceeded for <${tag}>. ` +
|
|
3441
|
+
`render() is mutating an observed property, causing an infinite render loop.`);
|
|
3442
|
+
return;
|
|
3443
|
+
}
|
|
3444
|
+
element[RENDER_DEPTH] = depth + 1;
|
|
3174
3445
|
try {
|
|
3175
3446
|
const result = precomputedResult !== undefined ? precomputedResult : renderMethod.call(element);
|
|
3176
3447
|
if (!element.shadowRoot)
|
|
@@ -3196,14 +3467,18 @@ var Snice = (function (exports) {
|
|
|
3196
3467
|
flushRenderCallbacks(element);
|
|
3197
3468
|
return;
|
|
3198
3469
|
}
|
|
3199
|
-
// Different template or first render.
|
|
3200
|
-
//
|
|
3201
|
-
//
|
|
3470
|
+
// Different template or first render. Keep only the framework's own
|
|
3471
|
+
// fallback <style> tags (marked data-snice-style) so the @styles path
|
|
3472
|
+
// (Safari <=16 / jsdom / SSR — no adoptedStyleSheets) survives a template
|
|
3473
|
+
// switch; template-emitted <style> tags are removed and re-created by the
|
|
3474
|
+
// new instance, so they don't accumulate.
|
|
3202
3475
|
if (instance) {
|
|
3203
3476
|
const root = element.shadowRoot;
|
|
3204
3477
|
const toRemove = [];
|
|
3205
3478
|
for (const child of Array.from(root.childNodes)) {
|
|
3206
|
-
if (child.nodeType === 1 &&
|
|
3479
|
+
if (child.nodeType === 1 &&
|
|
3480
|
+
child.tagName === 'STYLE' &&
|
|
3481
|
+
child.hasAttribute('data-snice-style'))
|
|
3207
3482
|
continue;
|
|
3208
3483
|
toRemove.push(child);
|
|
3209
3484
|
}
|
|
@@ -3219,6 +3494,9 @@ var Snice = (function (exports) {
|
|
|
3219
3494
|
catch (error) {
|
|
3220
3495
|
console.error('Error rendering element:', error);
|
|
3221
3496
|
}
|
|
3497
|
+
finally {
|
|
3498
|
+
element[RENDER_DEPTH] = depth;
|
|
3499
|
+
}
|
|
3222
3500
|
}
|
|
3223
3501
|
/**
|
|
3224
3502
|
* Request a render for an element
|
|
@@ -3272,6 +3550,33 @@ var Snice = (function (exports) {
|
|
|
3272
3550
|
// Normal rendering (with microtask batching unless sync)
|
|
3273
3551
|
renderScheduler.schedule(element, options);
|
|
3274
3552
|
}
|
|
3553
|
+
/**
|
|
3554
|
+
* Clear any pending debounce/throttle render timers on an element (e.g. on
|
|
3555
|
+
* disconnect, so they don't fire on a dead element and retain it until they
|
|
3556
|
+
* expire). Returns true if a render was actually pending, so the caller can
|
|
3557
|
+
* arrange a replay on reconnect via PENDING_RECONNECT_RENDER.
|
|
3558
|
+
*/
|
|
3559
|
+
function clearRenderTimers(element) {
|
|
3560
|
+
const timers = element[RENDER_TIMERS];
|
|
3561
|
+
if (!timers)
|
|
3562
|
+
return false;
|
|
3563
|
+
let hadPending = false;
|
|
3564
|
+
if (timers.debounce) {
|
|
3565
|
+
clearTimeout(timers.debounce);
|
|
3566
|
+
timers.debounce = null;
|
|
3567
|
+
hadPending = true;
|
|
3568
|
+
}
|
|
3569
|
+
if (timers.throttleTimer) {
|
|
3570
|
+
clearTimeout(timers.throttleTimer);
|
|
3571
|
+
timers.throttleTimer = null;
|
|
3572
|
+
hadPending = true;
|
|
3573
|
+
}
|
|
3574
|
+
// Deliberately do NOT reset timers.lastThrottle: a plain DOM move is a
|
|
3575
|
+
// disconnect+reconnect, and zeroing the cooldown would let the next render
|
|
3576
|
+
// fire inside the throttle window. Preserving it keeps throttle honest
|
|
3577
|
+
// across moves; on a true disconnect the element is discarded anyway.
|
|
3578
|
+
return hadPending;
|
|
3579
|
+
}
|
|
3275
3580
|
/**
|
|
3276
3581
|
* @render decorator for component rendering
|
|
3277
3582
|
*
|
|
@@ -3394,9 +3699,12 @@ var Snice = (function (exports) {
|
|
|
3394
3699
|
element.shadowRoot.adoptedStyleSheets = allResults.map(r => r.styleSheet);
|
|
3395
3700
|
return;
|
|
3396
3701
|
}
|
|
3397
|
-
// Fallback — one <style> tag per stylesheet, preserving cascade order
|
|
3702
|
+
// Fallback — one <style> tag per stylesheet, preserving cascade order.
|
|
3703
|
+
// Marked so the template-switch cleanup keeps these (framework styles) but
|
|
3704
|
+
// still removes template-emitted <style> tags (which would otherwise pile up).
|
|
3398
3705
|
for (const r of allResults) {
|
|
3399
3706
|
const style = document.createElement('style');
|
|
3707
|
+
style.setAttribute('data-snice-style', '');
|
|
3400
3708
|
style.textContent = r.cssText;
|
|
3401
3709
|
element.shadowRoot.appendChild(style);
|
|
3402
3710
|
}
|
|
@@ -3406,6 +3714,125 @@ var Snice = (function (exports) {
|
|
|
3406
3714
|
}
|
|
3407
3715
|
}
|
|
3408
3716
|
|
|
3717
|
+
// @dispatch decorator - auto-dispatches custom events from method return values
|
|
3718
|
+
/**
|
|
3719
|
+
* Decorator that automatically dispatches a custom event after a method is called.
|
|
3720
|
+
* The return value of the method becomes the event detail.
|
|
3721
|
+
*
|
|
3722
|
+
* @param eventName The name of the event to dispatch
|
|
3723
|
+
* @param options Optional configuration extending EventInit
|
|
3724
|
+
*/
|
|
3725
|
+
function dispatch(eventName, options) {
|
|
3726
|
+
return function (originalMethod, _context) {
|
|
3727
|
+
return function (...args) {
|
|
3728
|
+
// Create timing wrappers for dispatch (per-instance)
|
|
3729
|
+
if (!this[DISPATCH_TIMERS]) {
|
|
3730
|
+
this[DISPATCH_TIMERS] = new Map();
|
|
3731
|
+
}
|
|
3732
|
+
const timerKey = `${eventName}_${_context.name}`;
|
|
3733
|
+
if (!this[DISPATCH_TIMERS].has(timerKey)) {
|
|
3734
|
+
this[DISPATCH_TIMERS].set(timerKey, {
|
|
3735
|
+
debounceTimeout: null,
|
|
3736
|
+
throttleLastCall: 0,
|
|
3737
|
+
throttleTimeout: null
|
|
3738
|
+
});
|
|
3739
|
+
}
|
|
3740
|
+
const timers = this[DISPATCH_TIMERS].get(timerKey);
|
|
3741
|
+
// Call the original method with preserved this context
|
|
3742
|
+
const result = originalMethod.apply(this, args);
|
|
3743
|
+
// Helper to dispatch the event
|
|
3744
|
+
const doDispatch = (detail) => {
|
|
3745
|
+
// Skip dispatch if result is undefined and dispatchOnUndefined is false
|
|
3746
|
+
if (detail === undefined && options?.dispatchOnUndefined === false) {
|
|
3747
|
+
return;
|
|
3748
|
+
}
|
|
3749
|
+
// Create event with spread operator for options
|
|
3750
|
+
const event = new CustomEvent(eventName, {
|
|
3751
|
+
bubbles: true, // Default to true for component events
|
|
3752
|
+
composed: true, // Allow crossing shadow DOM boundaries
|
|
3753
|
+
...options, // Spread all EventInit options
|
|
3754
|
+
detail
|
|
3755
|
+
});
|
|
3756
|
+
// Resolve scope target. Default is `this` (host element).
|
|
3757
|
+
// Explicit scope dispatches the event on another target — useful for
|
|
3758
|
+
// 'global' bus events on document, or routing through an ancestor.
|
|
3759
|
+
if (options?.scope !== undefined) {
|
|
3760
|
+
const target = resolveScope(this, options.scope);
|
|
3761
|
+
if (!target) {
|
|
3762
|
+
console.warn(`[snice/@dispatch] scope did not resolve for "${eventName}" — event not dispatched.`);
|
|
3763
|
+
return;
|
|
3764
|
+
}
|
|
3765
|
+
target.dispatchEvent(event);
|
|
3766
|
+
return;
|
|
3767
|
+
}
|
|
3768
|
+
this.dispatchEvent(event);
|
|
3769
|
+
};
|
|
3770
|
+
// Helper to handle timed dispatch
|
|
3771
|
+
const timedDispatch = (detail) => {
|
|
3772
|
+
if (options?.debounce) {
|
|
3773
|
+
clearTimeout(timers.debounceTimeout);
|
|
3774
|
+
timers.debounceTimeout = setTimeout(() => doDispatch(detail), options.debounce);
|
|
3775
|
+
return;
|
|
3776
|
+
}
|
|
3777
|
+
if (!options?.throttle) {
|
|
3778
|
+
doDispatch(detail);
|
|
3779
|
+
return;
|
|
3780
|
+
}
|
|
3781
|
+
const now = Date.now();
|
|
3782
|
+
const remaining = options.throttle - (now - timers.throttleLastCall);
|
|
3783
|
+
if (remaining <= 0) {
|
|
3784
|
+
clearTimeout(timers.throttleTimeout);
|
|
3785
|
+
timers.throttleLastCall = now;
|
|
3786
|
+
doDispatch(detail);
|
|
3787
|
+
return;
|
|
3788
|
+
}
|
|
3789
|
+
// Record the LATEST detail so the trailing dispatch carries fresh
|
|
3790
|
+
// data, not the first-suppressed-call detail captured by closure.
|
|
3791
|
+
timers.latestDetail = detail;
|
|
3792
|
+
if (!timers.throttleTimeout) {
|
|
3793
|
+
timers.throttleTimeout = setTimeout(() => {
|
|
3794
|
+
timers.throttleLastCall = Date.now();
|
|
3795
|
+
timers.throttleTimeout = null;
|
|
3796
|
+
const d = timers.latestDetail;
|
|
3797
|
+
timers.latestDetail = undefined;
|
|
3798
|
+
doDispatch(d);
|
|
3799
|
+
}, remaining);
|
|
3800
|
+
}
|
|
3801
|
+
};
|
|
3802
|
+
// Handle async methods
|
|
3803
|
+
if (result instanceof Promise) {
|
|
3804
|
+
return result.then((resolvedResult) => {
|
|
3805
|
+
timedDispatch(resolvedResult);
|
|
3806
|
+
return resolvedResult;
|
|
3807
|
+
});
|
|
3808
|
+
}
|
|
3809
|
+
// Sync method
|
|
3810
|
+
timedDispatch(result);
|
|
3811
|
+
return result;
|
|
3812
|
+
};
|
|
3813
|
+
};
|
|
3814
|
+
}
|
|
3815
|
+
/**
|
|
3816
|
+
* Clear any pending debounce/throttle dispatch timers on an instance (e.g. on
|
|
3817
|
+
* disconnect, so a queued event doesn't fire into a detached node). A dispatch
|
|
3818
|
+
* is a one-shot signal, so pending ones are dropped, not replayed.
|
|
3819
|
+
*/
|
|
3820
|
+
function clearDispatchTimers(instance) {
|
|
3821
|
+
const timers = instance[DISPATCH_TIMERS];
|
|
3822
|
+
if (!timers)
|
|
3823
|
+
return;
|
|
3824
|
+
for (const t of timers.values()) {
|
|
3825
|
+
if (t.debounceTimeout)
|
|
3826
|
+
clearTimeout(t.debounceTimeout);
|
|
3827
|
+
if (t.throttleTimeout)
|
|
3828
|
+
clearTimeout(t.throttleTimeout);
|
|
3829
|
+
t.debounceTimeout = null;
|
|
3830
|
+
t.throttleTimeout = null;
|
|
3831
|
+
t.throttleLastCall = 0;
|
|
3832
|
+
t.latestDetail = undefined;
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
|
|
3409
3836
|
/**
|
|
3410
3837
|
* Method decorators for common patterns
|
|
3411
3838
|
* @debounce, @throttle, @once, @memoize
|
|
@@ -3832,6 +4259,14 @@ var Snice = (function (exports) {
|
|
|
3832
4259
|
}
|
|
3833
4260
|
}
|
|
3834
4261
|
}
|
|
4262
|
+
// Replay a render that was dropped while disconnected. The scheduler
|
|
4263
|
+
// sets this flag when it skips a detached element, so a property changed
|
|
4264
|
+
// while detached still reaches the DOM on reattach. A plain move (no
|
|
4265
|
+
// pending render) leaves the flag unset, so we don't re-render needlessly.
|
|
4266
|
+
if (this[RENDER_METHOD] && this[PENDING_RECONNECT_RENDER]) {
|
|
4267
|
+
this[PENDING_RECONNECT_RENDER] = false;
|
|
4268
|
+
requestRender(this);
|
|
4269
|
+
}
|
|
3835
4270
|
return;
|
|
3836
4271
|
}
|
|
3837
4272
|
// Mark that properties are being initialized from attributes
|
|
@@ -3879,6 +4314,9 @@ var Snice = (function (exports) {
|
|
|
3879
4314
|
setupResponseHandlers(this, this);
|
|
3880
4315
|
setupContextHandler(this);
|
|
3881
4316
|
this[INITIALIZED] = true;
|
|
4317
|
+
// Now that the initial value is settled, give @watch immediate handlers
|
|
4318
|
+
// their one init call (before the first render, so derived state is ready).
|
|
4319
|
+
invokeImmediateWatchers(this, constructor);
|
|
3882
4320
|
if (originalConnectedCallback) {
|
|
3883
4321
|
originalConnectedCallback.call(this);
|
|
3884
4322
|
}
|
|
@@ -3973,6 +4411,17 @@ var Snice = (function (exports) {
|
|
|
3973
4411
|
// Cleanup pending @debounce / @throttle timers so they don't fire on a dead element
|
|
3974
4412
|
clearDebounceTimers(this);
|
|
3975
4413
|
clearThrottleTimers(this);
|
|
4414
|
+
// The render/dispatch debounce-throttle timers live in separate stores.
|
|
4415
|
+
// A pending render is replayed on reconnect (same flag the scheduler
|
|
4416
|
+
// uses); a pending dispatch is a one-shot signal, so it's dropped.
|
|
4417
|
+
if (clearRenderTimers(this)) {
|
|
4418
|
+
this[PENDING_RECONNECT_RENDER] = true;
|
|
4419
|
+
}
|
|
4420
|
+
clearDispatchTimers(this);
|
|
4421
|
+
// @moved / @adopted debounce-throttle timers, likewise dropped so they
|
|
4422
|
+
// don't fire on a dead element.
|
|
4423
|
+
clearLifecycleTimers(this, MOVED_TIMERS);
|
|
4424
|
+
clearLifecycleTimers(this, ADOPTED_TIMERS);
|
|
3976
4425
|
};
|
|
3977
4426
|
constructor.prototype.attributeChangedCallback = function (name, oldValue, newValue) {
|
|
3978
4427
|
originalAttributeChangedCallback?.call(this, name, oldValue, newValue);
|
|
@@ -3988,13 +4437,27 @@ var Snice = (function (exports) {
|
|
|
3988
4437
|
if (attributeName.toLowerCase() !== name.toLowerCase())
|
|
3989
4438
|
continue;
|
|
3990
4439
|
const currentValue = this[PROPERTY_VALUES]?.[propName];
|
|
3991
|
-
|
|
3992
|
-
|
|
4440
|
+
// A removed attribute reverts the property to its field default. Read it
|
|
4441
|
+
// back through the getter (attribute is already gone at this point) so the
|
|
4442
|
+
// watcher's newValue and PROPERTY_VALUES match what this[propName] now
|
|
4443
|
+
// returns — parseAttributeValue(null) would diverge to null for String/Number.
|
|
4444
|
+
const parsedValue = newValue === null
|
|
4445
|
+
? this[propName]
|
|
4446
|
+
: parseAttributeValue(newValue, propOptions, currentValue, undefined);
|
|
4447
|
+
const changed = propOptions?.hasChanged
|
|
4448
|
+
? propOptions.hasChanged(parsedValue, currentValue)
|
|
4449
|
+
: notEqual(parsedValue, currentValue);
|
|
4450
|
+
if (!changed)
|
|
3993
4451
|
break;
|
|
3994
4452
|
ensureSet(this, EXPLICITLY_SET_PROPERTIES).add(propName);
|
|
3995
4453
|
ensureObj(this, PROPERTY_VALUES)[propName] = parsedValue;
|
|
3996
4454
|
if (!this[SETTING_FROM_PROPERTY]?.has(name.toLowerCase())) {
|
|
3997
|
-
|
|
4455
|
+
// Watchers react to changes only. During upgrade the initial value
|
|
4456
|
+
// is not a change, so suppress until INITIALIZED; @watch immediate
|
|
4457
|
+
// handlers get their one init call from invokeImmediateWatchers.
|
|
4458
|
+
if (this[INITIALIZED]) {
|
|
4459
|
+
invokeWatchers(this, constructor, propName, currentValue, parsedValue);
|
|
4460
|
+
}
|
|
3998
4461
|
if (this[RENDER_METHOD] && this[INITIALIZED]) {
|
|
3999
4462
|
requestRender(this);
|
|
4000
4463
|
}
|
|
@@ -4004,12 +4467,14 @@ var Snice = (function (exports) {
|
|
|
4004
4467
|
};
|
|
4005
4468
|
// Add connectedMoveCallback for handling DOM moves
|
|
4006
4469
|
constructor.prototype.connectedMoveCallback = async function () {
|
|
4007
|
-
// Call @moved handlers
|
|
4470
|
+
// Call @moved handlers via the prototype method (the debounce/throttle
|
|
4471
|
+
// wrapper), not the raw handler — otherwise @moved({debounce}) options
|
|
4472
|
+
// are ignored for real moves and only work when called directly.
|
|
4008
4473
|
const movedHandlers = constructor[MOVED_HANDLERS];
|
|
4009
4474
|
if (movedHandlers) {
|
|
4010
4475
|
for (const handler of movedHandlers) {
|
|
4011
4476
|
try {
|
|
4012
|
-
await handler.
|
|
4477
|
+
await this[handler.methodName]();
|
|
4013
4478
|
}
|
|
4014
4479
|
catch (error) {
|
|
4015
4480
|
console.error(`Error in @moved handler ${handler.methodName}:`, error);
|
|
@@ -4019,12 +4484,13 @@ var Snice = (function (exports) {
|
|
|
4019
4484
|
};
|
|
4020
4485
|
// Add adoptedCallback for handling document adoption
|
|
4021
4486
|
constructor.prototype.adoptedCallback = async function () {
|
|
4022
|
-
// Call @adopted handlers
|
|
4487
|
+
// Call @adopted handlers via the prototype method (the debounce/throttle
|
|
4488
|
+
// wrapper), not the raw handler — same reason as connectedMoveCallback.
|
|
4023
4489
|
const adoptedHandlers = constructor[ADOPTED_HANDLERS];
|
|
4024
4490
|
if (adoptedHandlers) {
|
|
4025
4491
|
for (const handler of adoptedHandlers) {
|
|
4026
4492
|
try {
|
|
4027
|
-
await handler.
|
|
4493
|
+
await this[handler.methodName]();
|
|
4028
4494
|
}
|
|
4029
4495
|
catch (error) {
|
|
4030
4496
|
console.error(`Error in @adopted handler ${handler.methodName}:`, error);
|
|
@@ -4189,7 +4655,12 @@ var Snice = (function (exports) {
|
|
|
4189
4655
|
},
|
|
4190
4656
|
set(newValue) {
|
|
4191
4657
|
const oldValue = this[propertyKey];
|
|
4192
|
-
|
|
4658
|
+
// A custom hasChanged comparator overrides the default === check
|
|
4659
|
+
// (e.g. deep-equal objects, or forcing an update on a mutated ref).
|
|
4660
|
+
const changed = finalOptions?.hasChanged
|
|
4661
|
+
? finalOptions.hasChanged(newValue, oldValue)
|
|
4662
|
+
: notEqual(newValue, oldValue);
|
|
4663
|
+
if (!changed)
|
|
4193
4664
|
return;
|
|
4194
4665
|
// Pre-init: store for later, don't reflect to DOM yet
|
|
4195
4666
|
if (!this[PROPERTIES_INITIALIZED]) {
|
|
@@ -4206,18 +4677,27 @@ var Snice = (function (exports) {
|
|
|
4206
4677
|
const attributeName = getAttrName(finalOptions, propertyKey);
|
|
4207
4678
|
const attributeValue = valueToAttribute(newValue, finalOptions, initialValue);
|
|
4208
4679
|
ensureSet(this, EXPLICITLY_SET_PROPERTIES).add(propertyKey);
|
|
4209
|
-
|
|
4680
|
+
const attrKey = attributeName.toLowerCase();
|
|
4681
|
+
ensureSet(this, SETTING_FROM_PROPERTY).add(attrKey);
|
|
4682
|
+
// attributeChangedCallback runs synchronously inside setAttribute /
|
|
4683
|
+
// removeAttribute (custom element reactions are synchronous), so the
|
|
4684
|
+
// guard only needs to bracket this one reflection. Clear it right
|
|
4685
|
+
// after — not on a microtask — otherwise an external attribute change
|
|
4686
|
+
// in the same tick is mistaken for our own echo and silently dropped.
|
|
4210
4687
|
if (attributeValue === null) {
|
|
4211
4688
|
this.removeAttribute?.(attributeName);
|
|
4212
4689
|
}
|
|
4213
4690
|
else {
|
|
4214
4691
|
this.setAttribute?.(attributeName, attributeValue);
|
|
4215
4692
|
}
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4693
|
+
this[SETTING_FROM_PROPERTY].delete(attrKey);
|
|
4694
|
+
}
|
|
4695
|
+
// See attributeChangedCallback: the initial value is not a change,
|
|
4696
|
+
// so suppress watchers until INITIALIZED. @watch immediate handlers
|
|
4697
|
+
// get their one init call from invokeImmediateWatchers.
|
|
4698
|
+
if (this[INITIALIZED]) {
|
|
4699
|
+
invokeWatchers(this, this.constructor, propertyKey, oldValue, newValue);
|
|
4219
4700
|
}
|
|
4220
|
-
invokeWatchers(this, this.constructor, propertyKey, oldValue, newValue);
|
|
4221
4701
|
if (this[RENDER_METHOD] && this[INITIALIZED]) {
|
|
4222
4702
|
requestRender(this);
|
|
4223
4703
|
}
|
|
@@ -4287,7 +4767,12 @@ var Snice = (function (exports) {
|
|
|
4287
4767
|
};
|
|
4288
4768
|
};
|
|
4289
4769
|
}
|
|
4290
|
-
function watch(...
|
|
4770
|
+
function watch(...args) {
|
|
4771
|
+
// A trailing options object is separated from the watched property names.
|
|
4772
|
+
const propertyNames = args.filter((a) => typeof a === 'string');
|
|
4773
|
+
const options = args.find((a) => typeof a === 'object' && a !== null);
|
|
4774
|
+
// Fire on init by default; opt out of the init call with { immediate: false }.
|
|
4775
|
+
const immediate = options?.immediate !== false;
|
|
4291
4776
|
return function (target, context) {
|
|
4292
4777
|
const methodName = context.name;
|
|
4293
4778
|
context.addInitializer(function () {
|
|
@@ -4327,7 +4812,8 @@ var Snice = (function (exports) {
|
|
|
4327
4812
|
}
|
|
4328
4813
|
constructor[PROPERTY_WATCHERS].get(propertyName).push({
|
|
4329
4814
|
methodName,
|
|
4330
|
-
method: target
|
|
4815
|
+
method: target,
|
|
4816
|
+
immediate
|
|
4331
4817
|
});
|
|
4332
4818
|
}
|
|
4333
4819
|
});
|
|
@@ -4436,6 +4922,24 @@ var Snice = (function (exports) {
|
|
|
4436
4922
|
registerHandler(RECONNECT_HANDLERS, RECONNECT_METHODS, target, context);
|
|
4437
4923
|
};
|
|
4438
4924
|
}
|
|
4925
|
+
/**
|
|
4926
|
+
* Clear any pending @moved / @adopted debounce/throttle timers on an instance
|
|
4927
|
+
* (e.g. on disconnect), so they don't fire on a dead element.
|
|
4928
|
+
*/
|
|
4929
|
+
function clearLifecycleTimers(instance, timersSymbol) {
|
|
4930
|
+
const map = instance[timersSymbol];
|
|
4931
|
+
if (!map)
|
|
4932
|
+
return;
|
|
4933
|
+
for (const t of map.values()) {
|
|
4934
|
+
if (t.debounceTimer)
|
|
4935
|
+
clearTimeout(t.debounceTimer);
|
|
4936
|
+
if (t.throttleTimer)
|
|
4937
|
+
clearTimeout(t.throttleTimer);
|
|
4938
|
+
t.debounceTimer = null;
|
|
4939
|
+
t.throttleTimer = null;
|
|
4940
|
+
t.lastThrottleCall = 0;
|
|
4941
|
+
}
|
|
4942
|
+
}
|
|
4439
4943
|
function createLifecycleDecorator(handlersSymbol, timersSymbol, methodsSymbol) {
|
|
4440
4944
|
return function (options = {}) {
|
|
4441
4945
|
return function (originalMethod, context) {
|
|
@@ -4449,9 +4953,23 @@ var Snice = (function (exports) {
|
|
|
4449
4953
|
}
|
|
4450
4954
|
const timers = this[timersSymbol].get(methodName);
|
|
4451
4955
|
const exec = (...a) => originalMethod.apply(this, a);
|
|
4956
|
+
// Deferred (debounce/throttle) calls run inside a setTimeout, outside
|
|
4957
|
+
// the caller's try/catch — so catch their sync throws and async
|
|
4958
|
+
// rejections here and log, rather than surface an uncaught error.
|
|
4959
|
+
const execDeferred = (...a) => {
|
|
4960
|
+
try {
|
|
4961
|
+
const result = originalMethod.apply(this, a);
|
|
4962
|
+
if (result && typeof result.then === 'function') {
|
|
4963
|
+
result.catch((error) => console.error(`Error in deferred lifecycle handler ${methodName}:`, error));
|
|
4964
|
+
}
|
|
4965
|
+
}
|
|
4966
|
+
catch (error) {
|
|
4967
|
+
console.error(`Error in deferred lifecycle handler ${methodName}:`, error);
|
|
4968
|
+
}
|
|
4969
|
+
};
|
|
4452
4970
|
if (options.debounce > 0) {
|
|
4453
4971
|
clearTimeout(timers.debounceTimer);
|
|
4454
|
-
timers.debounceTimer = setTimeout(() =>
|
|
4972
|
+
timers.debounceTimer = setTimeout(() => execDeferred(...args), options.debounce);
|
|
4455
4973
|
return undefined;
|
|
4456
4974
|
}
|
|
4457
4975
|
if (options.throttle > 0) {
|
|
@@ -4465,7 +4983,7 @@ var Snice = (function (exports) {
|
|
|
4465
4983
|
timers.throttleTimer = setTimeout(() => {
|
|
4466
4984
|
timers.throttleTimer = null;
|
|
4467
4985
|
timers.lastThrottleCall = Date.now();
|
|
4468
|
-
|
|
4986
|
+
execDeferred(...args);
|
|
4469
4987
|
}, remaining);
|
|
4470
4988
|
}
|
|
4471
4989
|
return undefined;
|
|
@@ -5097,6 +5615,40 @@ var Snice = (function (exports) {
|
|
|
5097
5615
|
}
|
|
5098
5616
|
}
|
|
5099
5617
|
|
|
5618
|
+
/**
|
|
5619
|
+
* Score a route pattern by specificity so that more specific routes are tried
|
|
5620
|
+
* first. Scoring is per-segment by ROLE, not by string length: a static segment
|
|
5621
|
+
* outweighs a dynamic (`:param`) segment, which outweighs a wildcard (`*` /
|
|
5622
|
+
* `*name`). So `/post/new` beats `/post/:id`, and a splat always ranks last —
|
|
5623
|
+
* regardless of how long the pattern string happens to be. This mirrors the
|
|
5624
|
+
* segment-scoring model mainstream routers (React Router, Remix) use.
|
|
5625
|
+
*
|
|
5626
|
+
* Sort callers descending by this score (highest = most specific = first).
|
|
5627
|
+
*
|
|
5628
|
+
* NOTE: mirrored in `src/react/route-specificity.ts` for the isolated React
|
|
5629
|
+
* bundle — keep the two in sync.
|
|
5630
|
+
*/
|
|
5631
|
+
const STATIC_SEGMENT = 10;
|
|
5632
|
+
const DYNAMIC_SEGMENT = 3;
|
|
5633
|
+
const WILDCARD_SEGMENT = -2;
|
|
5634
|
+
function routeSpecificity(spec) {
|
|
5635
|
+
const segments = spec.split('/').filter(Boolean);
|
|
5636
|
+
// Base on segment count so a deeper path outranks a shallower one on ties.
|
|
5637
|
+
let score = segments.length;
|
|
5638
|
+
for (const segment of segments) {
|
|
5639
|
+
if (segment.startsWith('*')) {
|
|
5640
|
+
score += WILDCARD_SEGMENT;
|
|
5641
|
+
}
|
|
5642
|
+
else if (segment.startsWith(':')) {
|
|
5643
|
+
score += DYNAMIC_SEGMENT;
|
|
5644
|
+
}
|
|
5645
|
+
else {
|
|
5646
|
+
score += STATIC_SEGMENT;
|
|
5647
|
+
}
|
|
5648
|
+
}
|
|
5649
|
+
return score;
|
|
5650
|
+
}
|
|
5651
|
+
|
|
5100
5652
|
/**
|
|
5101
5653
|
* Generic transition system for animating between elements
|
|
5102
5654
|
*/
|
|
@@ -5364,7 +5916,7 @@ var Snice = (function (exports) {
|
|
|
5364
5916
|
}
|
|
5365
5917
|
const needsSorting = !is_sorted;
|
|
5366
5918
|
if (needsSorting) {
|
|
5367
|
-
routes.sort((a, b) => b.route.spec
|
|
5919
|
+
routes.sort((a, b) => routeSpecificity(b.route.spec) - routeSpecificity(a.route.spec));
|
|
5368
5920
|
is_sorted = true;
|
|
5369
5921
|
}
|
|
5370
5922
|
// Collect placards from registered routes
|
|
@@ -5435,7 +5987,7 @@ var Snice = (function (exports) {
|
|
|
5435
5987
|
</div>`;
|
|
5436
5988
|
return container;
|
|
5437
5989
|
}
|
|
5438
|
-
async function checkGuards(guards, params, target) {
|
|
5990
|
+
async function checkGuards(guards, params, target, stale) {
|
|
5439
5991
|
const hasGuards = !!guards;
|
|
5440
5992
|
if (!hasGuards) {
|
|
5441
5993
|
return true;
|
|
@@ -5443,8 +5995,11 @@ var Snice = (function (exports) {
|
|
|
5443
5995
|
const guardsArray = Array.isArray(guards) ? guards : [guards];
|
|
5444
5996
|
let spinner = null;
|
|
5445
5997
|
let spinnerTimer = null;
|
|
5446
|
-
// Show spinner after a short delay (avoids flash for fast sync guards)
|
|
5998
|
+
// Show spinner after a short delay (avoids flash for fast sync guards).
|
|
5999
|
+
// Skip if a newer navigation has already superseded this one.
|
|
5447
6000
|
spinnerTimer = setTimeout(() => {
|
|
6001
|
+
if (stale && stale())
|
|
6002
|
+
return;
|
|
5448
6003
|
spinner = createLoadingSpinner();
|
|
5449
6004
|
target.appendChild(spinner);
|
|
5450
6005
|
}, 50);
|
|
@@ -5452,7 +6007,11 @@ var Snice = (function (exports) {
|
|
|
5452
6007
|
for (const guard of guardsArray) {
|
|
5453
6008
|
const allowed = await guard(context, params);
|
|
5454
6009
|
if (!allowed) {
|
|
5455
|
-
|
|
6010
|
+
// Don't stomp the current page with a 403 if a newer navigation
|
|
6011
|
+
// already took over while this guard was resolving.
|
|
6012
|
+
if (!stale || !stale()) {
|
|
6013
|
+
renderForbiddenPage(target);
|
|
6014
|
+
}
|
|
5456
6015
|
return false;
|
|
5457
6016
|
}
|
|
5458
6017
|
}
|
|
@@ -5488,14 +6047,14 @@ var Snice = (function (exports) {
|
|
|
5488
6047
|
div.innerHTML = /*html*/ `<h1>404</h1><p>Page not found</p>`;
|
|
5489
6048
|
return { element: div, transition: undefined, layout: undefined };
|
|
5490
6049
|
}
|
|
5491
|
-
async function resolveRoute(path, target) {
|
|
6050
|
+
async function resolveRoute(path, target, stale) {
|
|
5492
6051
|
for (const route of routes) {
|
|
5493
6052
|
const params = route.route.match(path);
|
|
5494
6053
|
const isMatch = params !== false;
|
|
5495
6054
|
if (!isMatch) {
|
|
5496
6055
|
continue;
|
|
5497
6056
|
}
|
|
5498
|
-
const guardsAllowed = await checkGuards(route.guards, params, target);
|
|
6057
|
+
const guardsAllowed = await checkGuards(route.guards, params, target, stale);
|
|
5499
6058
|
if (!guardsAllowed) {
|
|
5500
6059
|
return { result: RouteResult.GUARDS_FAILED };
|
|
5501
6060
|
}
|
|
@@ -5623,7 +6182,7 @@ var Snice = (function (exports) {
|
|
|
5623
6182
|
const isHomePath = (path?.trim() === '' || path === '/') && !!home;
|
|
5624
6183
|
if (isHomePath) {
|
|
5625
6184
|
const homeRoute = routes.find(r => r.route.match('/'));
|
|
5626
|
-
if (!(await checkGuards(homeRoute?.guards, {}, target)))
|
|
6185
|
+
if (!(await checkGuards(homeRoute?.guards, {}, target, stale)))
|
|
5627
6186
|
return;
|
|
5628
6187
|
if (stale())
|
|
5629
6188
|
return;
|
|
@@ -5635,7 +6194,7 @@ var Snice = (function (exports) {
|
|
|
5635
6194
|
if (!path)
|
|
5636
6195
|
return;
|
|
5637
6196
|
// Resolve route
|
|
5638
|
-
const routeResult = await resolveRoute(path, target);
|
|
6197
|
+
const routeResult = await resolveRoute(path, target, stale);
|
|
5639
6198
|
if (stale())
|
|
5640
6199
|
return;
|
|
5641
6200
|
// Guards failed (403 already rendered by checkGuards)
|
|
@@ -5649,7 +6208,7 @@ var Snice = (function (exports) {
|
|
|
5649
6208
|
}
|
|
5650
6209
|
// 404 fallthrough
|
|
5651
6210
|
const { element, transition, layout } = create404Element();
|
|
5652
|
-
await renderPage(target, element, transition, layout, path, {});
|
|
6211
|
+
await renderPage(target, element, transition, layout, path, {}, stale);
|
|
5653
6212
|
}
|
|
5654
6213
|
async function performTransition$1(container, oldElement, newElement, transition, atGen = navGeneration) {
|
|
5655
6214
|
// `isStale` returns true when a newer navigate() has been kicked off.
|
|
@@ -5666,93 +6225,6 @@ var Snice = (function (exports) {
|
|
|
5666
6225
|
};
|
|
5667
6226
|
}
|
|
5668
6227
|
|
|
5669
|
-
// @dispatch decorator - auto-dispatches custom events from method return values
|
|
5670
|
-
/**
|
|
5671
|
-
* Decorator that automatically dispatches a custom event after a method is called.
|
|
5672
|
-
* The return value of the method becomes the event detail.
|
|
5673
|
-
*
|
|
5674
|
-
* @param eventName The name of the event to dispatch
|
|
5675
|
-
* @param options Optional configuration extending EventInit
|
|
5676
|
-
*/
|
|
5677
|
-
function dispatch(eventName, options) {
|
|
5678
|
-
return function (originalMethod, _context) {
|
|
5679
|
-
return function (...args) {
|
|
5680
|
-
// Create timing wrappers for dispatch (per-instance)
|
|
5681
|
-
if (!this[DISPATCH_TIMERS]) {
|
|
5682
|
-
this[DISPATCH_TIMERS] = new Map();
|
|
5683
|
-
}
|
|
5684
|
-
const timerKey = `${eventName}_${_context.name}`;
|
|
5685
|
-
if (!this[DISPATCH_TIMERS].has(timerKey)) {
|
|
5686
|
-
this[DISPATCH_TIMERS].set(timerKey, {
|
|
5687
|
-
debounceTimeout: null,
|
|
5688
|
-
throttleLastCall: 0,
|
|
5689
|
-
throttleTimeout: null
|
|
5690
|
-
});
|
|
5691
|
-
}
|
|
5692
|
-
const timers = this[DISPATCH_TIMERS].get(timerKey);
|
|
5693
|
-
// Call the original method with preserved this context
|
|
5694
|
-
const result = originalMethod.apply(this, args);
|
|
5695
|
-
// Helper to dispatch the event
|
|
5696
|
-
const doDispatch = (detail) => {
|
|
5697
|
-
// Skip dispatch if result is undefined and dispatchOnUndefined is false
|
|
5698
|
-
if (detail === undefined && options?.dispatchOnUndefined === false) {
|
|
5699
|
-
return;
|
|
5700
|
-
}
|
|
5701
|
-
// Create event with spread operator for options
|
|
5702
|
-
const event = new CustomEvent(eventName, {
|
|
5703
|
-
bubbles: true, // Default to true for component events
|
|
5704
|
-
composed: true, // Allow crossing shadow DOM boundaries
|
|
5705
|
-
...options, // Spread all EventInit options
|
|
5706
|
-
detail
|
|
5707
|
-
});
|
|
5708
|
-
this.dispatchEvent(event);
|
|
5709
|
-
};
|
|
5710
|
-
// Helper to handle timed dispatch
|
|
5711
|
-
const timedDispatch = (detail) => {
|
|
5712
|
-
if (options?.debounce) {
|
|
5713
|
-
clearTimeout(timers.debounceTimeout);
|
|
5714
|
-
timers.debounceTimeout = setTimeout(() => doDispatch(detail), options.debounce);
|
|
5715
|
-
return;
|
|
5716
|
-
}
|
|
5717
|
-
if (!options?.throttle) {
|
|
5718
|
-
doDispatch(detail);
|
|
5719
|
-
return;
|
|
5720
|
-
}
|
|
5721
|
-
const now = Date.now();
|
|
5722
|
-
const remaining = options.throttle - (now - timers.throttleLastCall);
|
|
5723
|
-
if (remaining <= 0) {
|
|
5724
|
-
clearTimeout(timers.throttleTimeout);
|
|
5725
|
-
timers.throttleLastCall = now;
|
|
5726
|
-
doDispatch(detail);
|
|
5727
|
-
return;
|
|
5728
|
-
}
|
|
5729
|
-
// Record the LATEST detail so the trailing dispatch carries fresh
|
|
5730
|
-
// data, not the first-suppressed-call detail captured by closure.
|
|
5731
|
-
timers.latestDetail = detail;
|
|
5732
|
-
if (!timers.throttleTimeout) {
|
|
5733
|
-
timers.throttleTimeout = setTimeout(() => {
|
|
5734
|
-
timers.throttleLastCall = Date.now();
|
|
5735
|
-
timers.throttleTimeout = null;
|
|
5736
|
-
const d = timers.latestDetail;
|
|
5737
|
-
timers.latestDetail = undefined;
|
|
5738
|
-
doDispatch(d);
|
|
5739
|
-
}, remaining);
|
|
5740
|
-
}
|
|
5741
|
-
};
|
|
5742
|
-
// Handle async methods
|
|
5743
|
-
if (result instanceof Promise) {
|
|
5744
|
-
return result.then((resolvedResult) => {
|
|
5745
|
-
timedDispatch(resolvedResult);
|
|
5746
|
-
return resolvedResult;
|
|
5747
|
-
});
|
|
5748
|
-
}
|
|
5749
|
-
// Sync method
|
|
5750
|
-
timedDispatch(result);
|
|
5751
|
-
return result;
|
|
5752
|
-
};
|
|
5753
|
-
};
|
|
5754
|
-
}
|
|
5755
|
-
|
|
5756
6228
|
/**
|
|
5757
6229
|
* createRequestHandler — vanilla JS utility for handling @request channels
|
|
5758
6230
|
* outside of the Snice element/controller decorator system.
|