snice 4.29.0 → 4.30.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -10
- package/adapters/react/SniceProvider.d.ts +71 -0
- package/adapters/react/SniceProvider.js +49 -0
- package/adapters/react/SniceProvider.js.map +1 -0
- package/adapters/react/SniceRouter.d.ts +44 -0
- package/adapters/react/SniceRouter.js +190 -0
- package/adapters/react/SniceRouter.js.map +1 -0
- package/adapters/react/components.d.ts +2 -0
- package/adapters/react/components.d.ts.map +1 -1
- package/adapters/react/components.js +1 -0
- package/adapters/react/components.js.map +1 -1
- package/adapters/react/components.ts +2 -0
- package/adapters/react/grid.d.ts +36 -0
- package/adapters/react/grid.d.ts.map +1 -0
- package/adapters/react/grid.js +24 -0
- package/adapters/react/grid.js.map +1 -0
- package/adapters/react/grid.tsx +44 -0
- package/adapters/react/index.d.ts +5 -0
- package/adapters/react/index.d.ts.map +1 -1
- package/adapters/react/index.js +3 -2
- package/adapters/react/index.js.map +1 -1
- package/adapters/react/index.ts +6 -3
- package/adapters/react/matchRoute.d.ts +16 -0
- package/adapters/react/matchRoute.js +32 -0
- package/adapters/react/matchRoute.js.map +1 -0
- package/adapters/react/types.d.ts +1 -15
- package/adapters/react/types.d.ts.map +1 -1
- package/adapters/react/types.ts +1 -15
- package/adapters/react/useRequestHandler.js +1 -1
- package/adapters/react/useRequestHandler.js.map +1 -1
- package/bin/snice.js +8 -13
- package/bin/templates/{pwa → default}/index.html +1 -1
- package/bin/templates/{pwa → default}/src/components/app-header.ts +36 -18
- package/bin/templates/{pwa → default}/src/components/notification-badge.ts +2 -21
- package/bin/templates/{pwa → default}/src/components/search-bar.ts +12 -12
- package/bin/templates/default/src/context.ts +17 -0
- package/bin/templates/{pwa → default}/src/controllers/notification-controller.ts +10 -15
- package/bin/templates/{pwa → default}/src/daemons/notifications.ts +0 -12
- package/bin/templates/{pwa → default}/src/main.ts +1 -7
- package/bin/templates/{pwa → default}/src/middleware/error.ts +1 -8
- package/bin/templates/{pwa → default}/src/pages/dashboard.ts +17 -18
- package/bin/templates/{pwa → default}/src/pages/data.ts +24 -24
- package/bin/templates/{pwa → default}/src/pages/login.ts +3 -6
- package/bin/templates/{pwa → default}/src/pages/notifications.ts +21 -19
- package/bin/templates/{pwa → default}/src/pages/profile.ts +10 -12
- package/bin/templates/{pwa → default}/src/pages/settings.ts +22 -22
- package/bin/templates/default/src/router.ts +13 -0
- package/bin/templates/default/src/styles/global.css +16 -0
- package/bin/templates/{pwa → default}/tsconfig.json +2 -1
- package/bin/templates/react/README.md +124 -0
- package/bin/templates/react/global.d.ts +10 -0
- package/bin/templates/react/index.html +15 -0
- package/bin/templates/react/package.json +31 -0
- package/bin/templates/react/src/App.tsx +112 -0
- package/bin/templates/react/src/components/AppHeader.tsx +85 -0
- package/bin/templates/react/src/components/AppLayout.tsx +11 -0
- package/bin/templates/react/src/components/NotificationBadge.tsx +13 -0
- package/bin/templates/react/src/components/SearchBar.tsx +63 -0
- package/bin/templates/react/src/daemons/notifications.ts +136 -0
- package/bin/templates/react/src/fetcher.ts +15 -0
- package/bin/templates/react/src/guards/auth.ts +6 -0
- package/bin/templates/react/src/main.tsx +27 -0
- package/bin/templates/react/src/middleware/auth.ts +16 -0
- package/bin/templates/react/src/middleware/error.ts +29 -0
- package/bin/templates/react/src/middleware/retry.ts +31 -0
- package/bin/templates/react/src/pages/DashboardPage.tsx +111 -0
- package/bin/templates/react/src/pages/DataPage.tsx +119 -0
- package/bin/templates/react/src/pages/LoginPage.tsx +46 -0
- package/bin/templates/react/src/pages/NotificationsPage.tsx +119 -0
- package/bin/templates/react/src/pages/ProfilePage.tsx +92 -0
- package/bin/templates/react/src/pages/SettingsPage.tsx +165 -0
- package/bin/templates/react/src/services/auth.ts +48 -0
- package/bin/templates/react/src/services/jwt.ts +35 -0
- package/bin/templates/react/src/services/storage.ts +24 -0
- package/bin/templates/react/src/styles/global.css +382 -0
- package/bin/templates/react/src/types/auth.ts +21 -0
- package/bin/templates/react/src/types/notifications.ts +9 -0
- package/bin/templates/react/tests/helpers/test-utils.ts +79 -0
- package/bin/templates/react/tests/middleware/auth.test.ts +67 -0
- package/bin/templates/react/tests/middleware/error.test.ts +105 -0
- package/bin/templates/react/tests/middleware/retry.test.ts +103 -0
- package/bin/templates/react/tests/services/auth.test.ts +89 -0
- package/bin/templates/react/tests/services/jwt.test.ts +76 -0
- package/bin/templates/react/tests/services/storage.test.ts +69 -0
- package/bin/templates/{base → react}/tsconfig.json +4 -6
- package/bin/templates/react/vite.config.ts +18 -0
- package/bin/templates/react/vitest.config.ts +18 -0
- package/dist/cdn/accordion/snice-accordion.js +1 -1
- package/dist/cdn/accordion/snice-accordion.min.js +1 -1
- package/dist/cdn/action-bar/snice-action-bar.js +1 -1
- package/dist/cdn/action-bar/snice-action-bar.min.js +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.min.js +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.min.js +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.min.js +1 -1
- package/dist/cdn/banner/snice-banner.js +1 -1
- package/dist/cdn/banner/snice-banner.min.js +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.min.js +1 -1
- package/dist/cdn/button/snice-button.js +1 -1
- package/dist/cdn/button/snice-button.min.js +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.min.js +1 -1
- package/dist/cdn/chat/snice-chat.js +1 -1
- package/dist/cdn/chat/snice-chat.min.js +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/README.md +2 -2
- package/dist/cdn/chip/snice-chip.js +2 -2
- package/dist/cdn/chip/snice-chip.js.map +1 -1
- package/dist/cdn/chip/snice-chip.min.js +3 -3
- 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/snice-command-palette.js +1 -1
- package/dist/cdn/command-palette/snice-command-palette.min.js +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.min.js +1 -1
- package/dist/cdn/date-picker/README.md +1 -1
- package/dist/cdn/date-picker/snice-date-picker.js +2 -2
- package/dist/cdn/date-picker/snice-date-picker.js.map +1 -1
- package/dist/cdn/date-picker/snice-date-picker.min.js +2 -2
- package/dist/cdn/date-picker/snice-date-picker.min.js.map +1 -1
- package/dist/cdn/date-range-picker/README.md +1 -1
- package/dist/cdn/date-range-picker/snice-date-range-picker.js +2 -2
- package/dist/cdn/date-range-picker/snice-date-range-picker.js.map +1 -1
- package/dist/cdn/date-range-picker/snice-date-range-picker.min.js +11 -11
- package/dist/cdn/date-range-picker/snice-date-range-picker.min.js.map +1 -1
- package/dist/cdn/date-time-picker/README.md +1 -1
- package/dist/cdn/date-time-picker/snice-date-time-picker.js +2 -2
- package/dist/cdn/date-time-picker/snice-date-time-picker.js.map +1 -1
- package/dist/cdn/date-time-picker/snice-date-time-picker.min.js +2 -2
- package/dist/cdn/date-time-picker/snice-date-time-picker.min.js.map +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/README.md +2 -2
- package/dist/cdn/draw/snice-draw.js +26 -4
- package/dist/cdn/draw/snice-draw.js.map +1 -1
- package/dist/cdn/draw/snice-draw.min.js +3 -3
- package/dist/cdn/draw/snice-draw.min.js.map +1 -1
- package/dist/cdn/drawer/snice-drawer.js +1 -1
- package/dist/cdn/drawer/snice-drawer.min.js +1 -1
- package/dist/cdn/empty-state/snice-empty-state.js +1 -1
- package/dist/cdn/empty-state/snice-empty-state.min.js +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.min.js +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/README.md +27 -0
- package/dist/cdn/grid/snice-grid.js +862 -0
- package/dist/cdn/grid/snice-grid.js.map +1 -0
- package/dist/cdn/grid/snice-grid.min.js +13 -0
- package/dist/cdn/grid/snice-grid.min.js.map +1 -0
- 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.min.js +1 -1
- package/dist/cdn/input/snice-input.js +1 -1
- package/dist/cdn/input/snice-input.min.js +1 -1
- package/dist/cdn/invoice/snice-invoice.js +1 -1
- package/dist/cdn/invoice/snice-invoice.min.js +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.min.js +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.min.js +1 -1
- package/dist/cdn/location/snice-location.js +1 -1
- package/dist/cdn/location/snice-location.min.js +1 -1
- package/dist/cdn/login/snice-login.js +1 -1
- package/dist/cdn/login/snice-login.min.js +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/snice-markdown.js +1 -1
- package/dist/cdn/markdown/snice-markdown.min.js +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 +1 -1
- package/dist/cdn/menu/snice-menu.min.js +1 -1
- package/dist/cdn/message-strip/README.md +2 -2
- package/dist/cdn/message-strip/snice-message-strip.js +2 -2
- package/dist/cdn/message-strip/snice-message-strip.js.map +1 -1
- package/dist/cdn/message-strip/snice-message-strip.min.js +6 -6
- 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.min.js +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.min.js +1 -1
- package/dist/cdn/notification-center/snice-notification-center.js +1 -1
- package/dist/cdn/notification-center/snice-notification-center.min.js +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/README.md +2 -2
- package/dist/cdn/paint/snice-paint.js +26 -3
- package/dist/cdn/paint/snice-paint.js.map +1 -1
- package/dist/cdn/paint/snice-paint.min.js +3 -3
- package/dist/cdn/paint/snice-paint.min.js.map +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/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/README.md +1 -1
- package/dist/cdn/product-card/snice-product-card.js +1 -1
- package/dist/cdn/product-card/snice-product-card.min.js +1 -1
- package/dist/cdn/progress/snice-progress.js +1 -1
- package/dist/cdn/progress/snice-progress.min.js +1 -1
- package/dist/cdn/progress-ring/snice-progress-ring.js +1 -1
- package/dist/cdn/progress-ring/snice-progress-ring.min.js +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 +40 -15
- package/dist/cdn/runtime/snice-runtime.esm.js.map +1 -1
- package/dist/cdn/runtime/snice-runtime.esm.min.js +7 -7
- package/dist/cdn/runtime/snice-runtime.esm.min.js.map +1 -1
- package/dist/cdn/runtime/snice-runtime.js +40 -15
- package/dist/cdn/runtime/snice-runtime.js.map +1 -1
- package/dist/cdn/runtime/snice-runtime.min.js +6 -6
- 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.min.js +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.min.js +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/spreadsheet/snice-spreadsheet.js +1 -1
- package/dist/cdn/spreadsheet/snice-spreadsheet.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/snice-table.js +1 -1
- package/dist/cdn/table/snice-table.min.js +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/README.md +1 -1
- package/dist/cdn/tag/snice-tag.js +2 -2
- package/dist/cdn/tag/snice-tag.js.map +1 -1
- package/dist/cdn/tag/snice-tag.min.js +3 -3
- package/dist/cdn/tag/snice-tag.min.js.map +1 -1
- package/dist/cdn/tag-input/README.md +2 -2
- 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 +2 -2
- package/dist/cdn/time-picker/snice-time-picker.js.map +1 -1
- package/dist/cdn/time-picker/snice-time-picker.min.js +2 -2
- 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.min.js +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/README.md +1 -1
- package/dist/cdn/toast/snice-toast.js +7 -3
- package/dist/cdn/toast/snice-toast.js.map +1 -1
- package/dist/cdn/toast/snice-toast.min.js +6 -6
- 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.min.js +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/README.md +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/chip/snice-chip.js +1 -1
- package/dist/components/chip/snice-chip.js.map +1 -1
- package/dist/components/date-picker/snice-date-picker.js +1 -1
- package/dist/components/date-picker/snice-date-picker.js.map +1 -1
- package/dist/components/date-range-picker/snice-date-range-picker.js +1 -1
- package/dist/components/date-range-picker/snice-date-range-picker.js.map +1 -1
- package/dist/components/date-time-picker/snice-date-time-picker.js +1 -1
- package/dist/components/date-time-picker/snice-date-time-picker.js.map +1 -1
- package/dist/components/draw/snice-draw.d.ts +2 -0
- package/dist/components/draw/snice-draw.js +25 -3
- package/dist/components/draw/snice-draw.js.map +1 -1
- package/dist/components/grid/snice-grid.d.ts +73 -0
- package/dist/components/grid/snice-grid.js +795 -0
- package/dist/components/grid/snice-grid.js.map +1 -0
- package/dist/components/grid/snice-grid.types.d.ts +41 -0
- package/dist/components/message-strip/snice-message-strip.js +1 -1
- package/dist/components/message-strip/snice-message-strip.js.map +1 -1
- package/dist/components/paint/snice-paint.d.ts +2 -0
- package/dist/components/paint/snice-paint.js +25 -2
- package/dist/components/paint/snice-paint.js.map +1 -1
- package/dist/components/tag/snice-tag.js +1 -1
- package/dist/components/tag/snice-tag.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/theme/theme.css +15 -0
- package/dist/components/time-picker/snice-time-picker.js +1 -1
- package/dist/components/time-picker/snice-time-picker.js.map +1 -1
- package/dist/components/toast/snice-toast-container.js +4 -0
- package/dist/components/toast/snice-toast-container.js.map +1 -1
- package/dist/components/toast/snice-toast.js +2 -2
- package/dist/index.cjs +37 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +37 -12
- package/dist/index.esm.js.map +1 -1
- package/dist/index.iife.js +37 -12
- package/dist/index.iife.js.map +1 -1
- package/dist/react/SniceProvider.d.ts +71 -0
- package/dist/react/SniceProvider.js +49 -0
- package/dist/react/SniceProvider.js.map +1 -0
- package/dist/react/SniceRouter.d.ts +44 -0
- package/dist/react/SniceRouter.js +190 -0
- package/dist/react/SniceRouter.js.map +1 -0
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.js +14 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/matchRoute.d.ts +16 -0
- package/dist/react/matchRoute.js +32 -0
- package/dist/react/matchRoute.js.map +1 -0
- package/dist/react/useRequestHandler.js +1 -1
- package/dist/react/useRequestHandler.js.map +1 -1
- package/dist/symbols.cjs +1 -1
- package/dist/symbols.esm.js +1 -1
- package/dist/transitions.cjs +1 -1
- package/dist/transitions.esm.js +1 -1
- package/dist/types/guard.d.ts +4 -11
- package/docs/ai/README.md +7 -7
- package/docs/ai/components/grid.md +116 -0
- package/docs/ai/patterns.md +24 -0
- package/docs/ai/react-integration.md +97 -0
- package/docs/components/grid.md +249 -0
- package/docs/plans/2026-03-10-grid-component-design.md +138 -0
- package/docs/plans/2026-03-10-grid-component-plan.md +716 -0
- package/docs/plans/2026-03-10-react-integration-plan.md +1178 -0
- package/docs/react-integration.md +508 -0
- package/docs/request-response.md +7 -21
- package/package.json +1 -1
- package/bin/templates/base/README.md +0 -33
- package/bin/templates/base/global.d.ts +0 -14
- package/bin/templates/base/index.html +0 -13
- package/bin/templates/base/package.json +0 -21
- package/bin/templates/base/src/components/counter-button.ts +0 -88
- package/bin/templates/base/src/components/counter-button.types.ts +0 -7
- package/bin/templates/base/src/components/feature-card.ts +0 -59
- package/bin/templates/base/src/components/feature-card.types.ts +0 -5
- package/bin/templates/base/src/controllers/counter-controller.ts +0 -24
- package/bin/templates/base/src/main.ts +0 -24
- package/bin/templates/base/src/pages/about-page.ts +0 -68
- package/bin/templates/base/src/pages/home-page.ts +0 -105
- package/bin/templates/base/src/pages/not-found-page.ts +0 -55
- package/bin/templates/base/src/router.ts +0 -9
- package/bin/templates/base/src/styles/global.css +0 -27
- package/bin/templates/base/src/types/api-response.ts +0 -5
- package/bin/templates/base/src/types/status.ts +0 -1
- package/bin/templates/base/src/types/theme.ts +0 -1
- package/bin/templates/base/src/types/user.ts +0 -5
- package/bin/templates/base/vite.config.ts +0 -38
- package/bin/templates/pwa/public/vite.svg +0 -1
- package/bin/templates/pwa/src/router.ts +0 -20
- package/bin/templates/pwa/src/styles/global.css +0 -64
- /package/bin/templates/{pwa → default}/README.md +0 -0
- /package/bin/templates/{pwa → default}/global.d.ts +0 -0
- /package/bin/templates/{pwa → default}/package.json +0 -0
- /package/bin/templates/{pwa → default}/public/icons/.gitkeep +0 -0
- /package/bin/templates/{base → default}/public/vite.svg +0 -0
- /package/bin/templates/{pwa → default}/src/fetcher.ts +0 -0
- /package/bin/templates/{pwa → default}/src/guards/auth.ts +0 -0
- /package/bin/templates/{pwa → default}/src/middleware/auth.ts +0 -0
- /package/bin/templates/{pwa → default}/src/middleware/retry.ts +0 -0
- /package/bin/templates/{pwa → default}/src/services/auth.ts +0 -0
- /package/bin/templates/{pwa → default}/src/services/jwt.ts +0 -0
- /package/bin/templates/{pwa → default}/src/services/storage.ts +0 -0
- /package/bin/templates/{pwa → default}/src/types/auth.ts +0 -0
- /package/bin/templates/{pwa → default}/src/types/notifications.ts +0 -0
- /package/bin/templates/{pwa → default}/tests/helpers/test-utils.ts +0 -0
- /package/bin/templates/{pwa → default}/tests/middleware/auth.test.ts +0 -0
- /package/bin/templates/{pwa → default}/tests/middleware/error.test.ts +0 -0
- /package/bin/templates/{pwa → default}/tests/middleware/retry.test.ts +0 -0
- /package/bin/templates/{pwa → default}/tests/services/auth.test.ts +0 -0
- /package/bin/templates/{pwa → default}/tests/services/jwt.test.ts +0 -0
- /package/bin/templates/{pwa → default}/tests/services/storage.test.ts +0 -0
- /package/bin/templates/{pwa → default}/vite.config.ts +0 -0
- /package/bin/templates/{pwa → default}/vitest.config.ts +0 -0
|
@@ -0,0 +1,716 @@
|
|
|
1
|
+
# Grid Component Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
4
|
+
|
|
5
|
+
**Goal:** Create `snice-grid`, a grid-coordinate-based layout component with animated transitions and drag-and-drop, mirroring binpack's API patterns.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Items declare grid positions via `grid-col`/`grid-row` attributes (and optional `grid-colspan`/`grid-rowspan`). The component translates coordinates to pixel positions. Collision resolution uses push-right-then-down. Drag snaps to nearest grid cell on release. Container uses `overflow: hidden` when `columns`/`rows` are set.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Snice framework (TC39 decorators, shadow DOM), TypeScript, CSS-in-shadow-DOM, Vitest
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
### Task 1: Types File
|
|
14
|
+
|
|
15
|
+
**Files:**
|
|
16
|
+
- Create: `components/grid/snice-grid.types.ts`
|
|
17
|
+
|
|
18
|
+
**Step 1: Write the types file**
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
export interface SniceGridElement extends HTMLElement {
|
|
22
|
+
gap: string;
|
|
23
|
+
columnWidth: number;
|
|
24
|
+
rowHeight: number;
|
|
25
|
+
columns: number;
|
|
26
|
+
rows: number;
|
|
27
|
+
originLeft: boolean;
|
|
28
|
+
originTop: boolean;
|
|
29
|
+
transitionDuration: string;
|
|
30
|
+
stagger: number;
|
|
31
|
+
resize: boolean;
|
|
32
|
+
draggable: boolean;
|
|
33
|
+
dragThrottle: number;
|
|
34
|
+
|
|
35
|
+
layout(): void;
|
|
36
|
+
fit(element: HTMLElement, col?: number, row?: number): void;
|
|
37
|
+
reloadItems(): void;
|
|
38
|
+
getItemElements(): HTMLElement[];
|
|
39
|
+
getLayout(): GridLayout;
|
|
40
|
+
setLayout(layout: GridLayout): void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface GridLayoutEntry {
|
|
44
|
+
col: number;
|
|
45
|
+
row: number;
|
|
46
|
+
colspan?: number;
|
|
47
|
+
rowspan?: number;
|
|
48
|
+
order: number;
|
|
49
|
+
hidden?: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type GridLayout = Record<string, GridLayoutEntry>;
|
|
53
|
+
|
|
54
|
+
export interface GridLayoutCompleteDetail {
|
|
55
|
+
items: HTMLElement[];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface GridDragItemPositionedDetail {
|
|
59
|
+
item: HTMLElement;
|
|
60
|
+
col: number;
|
|
61
|
+
row: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface GridEventMap {
|
|
65
|
+
'grid-layout-complete': CustomEvent<GridLayoutCompleteDetail>;
|
|
66
|
+
'grid-drag-item-positioned': CustomEvent<GridDragItemPositionedDetail>;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Step 2: Commit**
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git add components/grid/snice-grid.types.ts
|
|
74
|
+
git commit -m "feat(grid): add type definitions"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
### Task 2: CSS File
|
|
80
|
+
|
|
81
|
+
**Files:**
|
|
82
|
+
- Create: `components/grid/snice-grid.css`
|
|
83
|
+
|
|
84
|
+
**Step 1: Write the CSS**
|
|
85
|
+
|
|
86
|
+
Mirror binpack's CSS structure. Key differences: `--grid-gap` and `--grid-transition-duration` custom property names, `.grid` container class, `overflow: hidden` on `:host`.
|
|
87
|
+
|
|
88
|
+
```css
|
|
89
|
+
:host {
|
|
90
|
+
display: block;
|
|
91
|
+
position: relative;
|
|
92
|
+
width: 100%;
|
|
93
|
+
font-family: var(--snice-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif);
|
|
94
|
+
contain: layout style;
|
|
95
|
+
--grid-gap: 1rem;
|
|
96
|
+
--grid-transition-duration: 0.4s;
|
|
97
|
+
overflow: hidden;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.grid {
|
|
101
|
+
position: relative;
|
|
102
|
+
width: 100%;
|
|
103
|
+
min-height: 1rem;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
::slotted(*) {
|
|
107
|
+
position: absolute;
|
|
108
|
+
top: 0;
|
|
109
|
+
left: 0;
|
|
110
|
+
box-sizing: border-box;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
::slotted([hidden]) {
|
|
114
|
+
display: none !important;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* Gate transitions behind [ready] to prevent FOUC */
|
|
118
|
+
:host([ready]) ::slotted(*) {
|
|
119
|
+
transition: transform var(--grid-transition-duration) ease;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* Dragging states */
|
|
123
|
+
::slotted(.grid-dragging) {
|
|
124
|
+
z-index: 100;
|
|
125
|
+
opacity: 0.9;
|
|
126
|
+
transition: none !important;
|
|
127
|
+
cursor: grabbing !important;
|
|
128
|
+
user-select: none;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
::slotted(.grid-positioning) {
|
|
132
|
+
z-index: 99;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
:host([draggable]) ::slotted(*) {
|
|
136
|
+
cursor: grab;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* Drop placeholder */
|
|
140
|
+
.grid-drop-placeholder {
|
|
141
|
+
position: absolute;
|
|
142
|
+
top: 0;
|
|
143
|
+
left: 0;
|
|
144
|
+
outline: 3px dashed rgba(128, 128, 128, 0.5);
|
|
145
|
+
outline-offset: -6px;
|
|
146
|
+
border-radius: 4px;
|
|
147
|
+
transition: transform 0.2s ease;
|
|
148
|
+
pointer-events: none;
|
|
149
|
+
display: none;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.grid-drop-placeholder.visible {
|
|
153
|
+
display: block;
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Step 2: Commit**
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
git add components/grid/snice-grid.css
|
|
161
|
+
git commit -m "feat(grid): add component styles"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
### Task 3: Test File — Basic Functionality and Properties
|
|
167
|
+
|
|
168
|
+
**Files:**
|
|
169
|
+
- Create: `tests/components/grid.test.ts`
|
|
170
|
+
|
|
171
|
+
**Step 1: Write failing tests**
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
175
|
+
import { createComponent, removeComponent, wait } from './test-utils';
|
|
176
|
+
import '../../components/grid/snice-grid';
|
|
177
|
+
import type { SniceGridElement } from '../../components/grid/snice-grid.types';
|
|
178
|
+
|
|
179
|
+
describe('snice-grid', () => {
|
|
180
|
+
let el: SniceGridElement;
|
|
181
|
+
|
|
182
|
+
afterEach(() => {
|
|
183
|
+
if (el) {
|
|
184
|
+
removeComponent(el as HTMLElement);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
describe('basic functionality', () => {
|
|
189
|
+
it('should render grid element', async () => {
|
|
190
|
+
el = await createComponent<SniceGridElement>('snice-grid');
|
|
191
|
+
expect(el).toBeTruthy();
|
|
192
|
+
expect(el.tagName).toBe('SNICE-GRID');
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('should have default properties', async () => {
|
|
196
|
+
el = await createComponent<SniceGridElement>('snice-grid');
|
|
197
|
+
expect(el.gap).toBe('1rem');
|
|
198
|
+
expect(el.columnWidth).toBe(80);
|
|
199
|
+
expect(el.rowHeight).toBe(80);
|
|
200
|
+
expect(el.columns).toBe(0);
|
|
201
|
+
expect(el.rows).toBe(0);
|
|
202
|
+
expect(el.originLeft).toBe(true);
|
|
203
|
+
expect(el.originTop).toBe(true);
|
|
204
|
+
expect(el.transitionDuration).toBe('0.4s');
|
|
205
|
+
expect(el.stagger).toBe(0);
|
|
206
|
+
expect(el.resize).toBe(true);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('should render slot element', async () => {
|
|
210
|
+
el = await createComponent<SniceGridElement>('snice-grid');
|
|
211
|
+
const slot = el.shadowRoot?.querySelector('slot');
|
|
212
|
+
expect(slot).toBeTruthy();
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should render container with role=list', async () => {
|
|
216
|
+
el = await createComponent<SniceGridElement>('snice-grid');
|
|
217
|
+
const container = el.shadowRoot?.querySelector('.grid');
|
|
218
|
+
expect(container).toBeTruthy();
|
|
219
|
+
expect(container?.getAttribute('role')).toBe('list');
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('should have part=base on container', async () => {
|
|
223
|
+
el = await createComponent<SniceGridElement>('snice-grid');
|
|
224
|
+
const container = el.shadowRoot?.querySelector('[part="base"]');
|
|
225
|
+
expect(container).toBeTruthy();
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
describe('property reflection', () => {
|
|
230
|
+
it('should reflect gap attribute', async () => {
|
|
231
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
232
|
+
gap: '2rem'
|
|
233
|
+
});
|
|
234
|
+
expect(el.getAttribute('gap')).toBe('2rem');
|
|
235
|
+
expect(el.gap).toBe('2rem');
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('should reflect column-width attribute', async () => {
|
|
239
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
240
|
+
'column-width': 100
|
|
241
|
+
});
|
|
242
|
+
expect(el.columnWidth).toBe(100);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('should reflect row-height attribute', async () => {
|
|
246
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
247
|
+
'row-height': 60
|
|
248
|
+
});
|
|
249
|
+
expect(el.rowHeight).toBe(60);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('should reflect columns attribute', async () => {
|
|
253
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
254
|
+
columns: 5
|
|
255
|
+
});
|
|
256
|
+
expect(el.columns).toBe(5);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('should reflect rows attribute', async () => {
|
|
260
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
261
|
+
rows: 4
|
|
262
|
+
});
|
|
263
|
+
expect(el.rows).toBe(4);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it('should reflect origin-left attribute', async () => {
|
|
267
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
268
|
+
'origin-left': false
|
|
269
|
+
});
|
|
270
|
+
expect(el.originLeft).toBe(false);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should reflect origin-top attribute', async () => {
|
|
274
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
275
|
+
'origin-top': false
|
|
276
|
+
});
|
|
277
|
+
expect(el.originTop).toBe(false);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('should reflect transition-duration attribute', async () => {
|
|
281
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
282
|
+
'transition-duration': '1s'
|
|
283
|
+
});
|
|
284
|
+
expect(el.transitionDuration).toBe('1s');
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('should reflect stagger attribute', async () => {
|
|
288
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
289
|
+
stagger: 50
|
|
290
|
+
});
|
|
291
|
+
expect(el.stagger).toBe(50);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it('should reflect resize attribute', async () => {
|
|
295
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
296
|
+
resize: false
|
|
297
|
+
});
|
|
298
|
+
expect(el.resize).toBe(false);
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
describe('API methods', () => {
|
|
303
|
+
it('should expose layout() method', async () => {
|
|
304
|
+
el = await createComponent<SniceGridElement>('snice-grid');
|
|
305
|
+
expect(typeof el.layout).toBe('function');
|
|
306
|
+
el.layout();
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('should expose fit() method', async () => {
|
|
310
|
+
el = await createComponent<SniceGridElement>('snice-grid');
|
|
311
|
+
expect(typeof el.fit).toBe('function');
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it('should expose reloadItems() method', async () => {
|
|
315
|
+
el = await createComponent<SniceGridElement>('snice-grid');
|
|
316
|
+
expect(typeof el.reloadItems).toBe('function');
|
|
317
|
+
el.reloadItems();
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('should expose getItemElements() method', async () => {
|
|
321
|
+
el = await createComponent<SniceGridElement>('snice-grid');
|
|
322
|
+
expect(typeof el.getItemElements).toBe('function');
|
|
323
|
+
const items = el.getItemElements();
|
|
324
|
+
expect(Array.isArray(items)).toBe(true);
|
|
325
|
+
expect(items).toHaveLength(0);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('should collect slotted items via getItemElements()', async () => {
|
|
329
|
+
el = await createComponent<SniceGridElement>('snice-grid');
|
|
330
|
+
|
|
331
|
+
const item1 = document.createElement('div');
|
|
332
|
+
item1.setAttribute('name', 'a');
|
|
333
|
+
item1.setAttribute('grid-col', '0');
|
|
334
|
+
item1.setAttribute('grid-row', '0');
|
|
335
|
+
const item2 = document.createElement('div');
|
|
336
|
+
item2.setAttribute('name', 'b');
|
|
337
|
+
item2.setAttribute('grid-col', '1');
|
|
338
|
+
item2.setAttribute('grid-row', '0');
|
|
339
|
+
el.appendChild(item1);
|
|
340
|
+
el.appendChild(item2);
|
|
341
|
+
await wait(50);
|
|
342
|
+
|
|
343
|
+
el.reloadItems();
|
|
344
|
+
await wait(50);
|
|
345
|
+
|
|
346
|
+
const items = el.getItemElements();
|
|
347
|
+
expect(items).toHaveLength(2);
|
|
348
|
+
expect(items).toContain(item1);
|
|
349
|
+
expect(items).toContain(item2);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('should position item at grid coordinates via fit()', async () => {
|
|
353
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
354
|
+
'column-width': 80,
|
|
355
|
+
'row-height': 80,
|
|
356
|
+
gap: '0px'
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
const item = document.createElement('div');
|
|
360
|
+
item.setAttribute('name', 'a');
|
|
361
|
+
item.setAttribute('grid-col', '0');
|
|
362
|
+
item.setAttribute('grid-row', '0');
|
|
363
|
+
el.appendChild(item);
|
|
364
|
+
await wait(50);
|
|
365
|
+
el.reloadItems();
|
|
366
|
+
|
|
367
|
+
el.fit(item, 2, 3);
|
|
368
|
+
// col=2, row=3 with columnWidth=80, rowHeight=80, gap=0
|
|
369
|
+
// x = 2 * (80 + 0) = 160, y = 3 * (80 + 0) = 240
|
|
370
|
+
expect(item.style.transform).toContain('160');
|
|
371
|
+
expect(item.style.transform).toContain('240');
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it('should ignore fit() on unknown elements', async () => {
|
|
375
|
+
el = await createComponent<SniceGridElement>('snice-grid');
|
|
376
|
+
const outsider = document.createElement('div');
|
|
377
|
+
el.fit(outsider, 1, 1);
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
describe('grid positioning', () => {
|
|
382
|
+
it('should position items based on grid-col and grid-row attributes', async () => {
|
|
383
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
384
|
+
'column-width': 100,
|
|
385
|
+
'row-height': 50,
|
|
386
|
+
gap: '10px'
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
const item = document.createElement('div');
|
|
390
|
+
item.setAttribute('name', 'a');
|
|
391
|
+
item.setAttribute('grid-col', '2');
|
|
392
|
+
item.setAttribute('grid-row', '1');
|
|
393
|
+
el.appendChild(item);
|
|
394
|
+
await wait(50);
|
|
395
|
+
el.reloadItems();
|
|
396
|
+
el.layout();
|
|
397
|
+
|
|
398
|
+
// x = 2 * (100 + 10) = 220, y = 1 * (50 + 10) = 60
|
|
399
|
+
expect(item.style.transform).toBe('translate(220px, 60px)');
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it('should auto-size items to colspan x rowspan', async () => {
|
|
403
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
404
|
+
'column-width': 80,
|
|
405
|
+
'row-height': 80,
|
|
406
|
+
gap: '8px'
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
const item = document.createElement('div');
|
|
410
|
+
item.setAttribute('name', 'a');
|
|
411
|
+
item.setAttribute('grid-col', '0');
|
|
412
|
+
item.setAttribute('grid-row', '0');
|
|
413
|
+
item.setAttribute('grid-colspan', '2');
|
|
414
|
+
item.setAttribute('grid-rowspan', '3');
|
|
415
|
+
el.appendChild(item);
|
|
416
|
+
await wait(50);
|
|
417
|
+
el.reloadItems();
|
|
418
|
+
el.layout();
|
|
419
|
+
|
|
420
|
+
// width = 2 * 80 + (2 - 1) * 8 = 168
|
|
421
|
+
// height = 3 * 80 + (3 - 1) * 8 = 256
|
|
422
|
+
expect(item.style.width).toBe('168px');
|
|
423
|
+
expect(item.style.height).toBe('256px');
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it('should hide items with hidden attribute', async () => {
|
|
427
|
+
el = await createComponent<SniceGridElement>('snice-grid');
|
|
428
|
+
|
|
429
|
+
const item = document.createElement('div');
|
|
430
|
+
item.setAttribute('name', 'a');
|
|
431
|
+
item.setAttribute('grid-col', '0');
|
|
432
|
+
item.setAttribute('grid-row', '0');
|
|
433
|
+
item.setAttribute('hidden', '');
|
|
434
|
+
el.appendChild(item);
|
|
435
|
+
await wait(50);
|
|
436
|
+
el.reloadItems();
|
|
437
|
+
el.layout();
|
|
438
|
+
|
|
439
|
+
// Hidden items should not be positioned
|
|
440
|
+
expect(item.style.transform).toBe('');
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
describe('collision resolution', () => {
|
|
445
|
+
it('should push item right when position is occupied', async () => {
|
|
446
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
447
|
+
'column-width': 80,
|
|
448
|
+
'row-height': 80,
|
|
449
|
+
gap: '0px'
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
// Two items at the same position — second should be pushed right
|
|
453
|
+
const item1 = document.createElement('div');
|
|
454
|
+
item1.setAttribute('name', 'a');
|
|
455
|
+
item1.setAttribute('grid-col', '0');
|
|
456
|
+
item1.setAttribute('grid-row', '0');
|
|
457
|
+
const item2 = document.createElement('div');
|
|
458
|
+
item2.setAttribute('name', 'b');
|
|
459
|
+
item2.setAttribute('grid-col', '0');
|
|
460
|
+
item2.setAttribute('grid-row', '0');
|
|
461
|
+
el.appendChild(item1);
|
|
462
|
+
el.appendChild(item2);
|
|
463
|
+
await wait(50);
|
|
464
|
+
el.reloadItems();
|
|
465
|
+
el.layout();
|
|
466
|
+
|
|
467
|
+
// item1 at (0,0), item2 pushed to (1,0) → x=80
|
|
468
|
+
expect(item1.style.transform).toBe('translate(0px, 0px)');
|
|
469
|
+
expect(item2.style.transform).toBe('translate(80px, 0px)');
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
it('should push to next row when row is full', async () => {
|
|
473
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
474
|
+
'column-width': 80,
|
|
475
|
+
'row-height': 80,
|
|
476
|
+
gap: '0px',
|
|
477
|
+
columns: 2
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
// 3 items at (0,0) — third should wrap to next row
|
|
481
|
+
const items: HTMLElement[] = [];
|
|
482
|
+
for (let i = 0; i < 3; i++) {
|
|
483
|
+
const item = document.createElement('div');
|
|
484
|
+
item.setAttribute('name', String.fromCharCode(97 + i));
|
|
485
|
+
item.setAttribute('grid-col', '0');
|
|
486
|
+
item.setAttribute('grid-row', '0');
|
|
487
|
+
items.push(item);
|
|
488
|
+
el.appendChild(item);
|
|
489
|
+
}
|
|
490
|
+
await wait(50);
|
|
491
|
+
el.reloadItems();
|
|
492
|
+
el.layout();
|
|
493
|
+
|
|
494
|
+
expect(items[0].style.transform).toBe('translate(0px, 0px)');
|
|
495
|
+
expect(items[1].style.transform).toBe('translate(80px, 0px)');
|
|
496
|
+
expect(items[2].style.transform).toBe('translate(0px, 80px)');
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
it('should handle colspan collision', async () => {
|
|
500
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
501
|
+
'column-width': 80,
|
|
502
|
+
'row-height': 80,
|
|
503
|
+
gap: '0px',
|
|
504
|
+
columns: 4
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
// item1 at (0,0) colspan=2, item2 at (1,0) — overlaps, should push right to col 2
|
|
508
|
+
const item1 = document.createElement('div');
|
|
509
|
+
item1.setAttribute('name', 'a');
|
|
510
|
+
item1.setAttribute('grid-col', '0');
|
|
511
|
+
item1.setAttribute('grid-row', '0');
|
|
512
|
+
item1.setAttribute('grid-colspan', '2');
|
|
513
|
+
const item2 = document.createElement('div');
|
|
514
|
+
item2.setAttribute('name', 'b');
|
|
515
|
+
item2.setAttribute('grid-col', '1');
|
|
516
|
+
item2.setAttribute('grid-row', '0');
|
|
517
|
+
el.appendChild(item1);
|
|
518
|
+
el.appendChild(item2);
|
|
519
|
+
await wait(50);
|
|
520
|
+
el.reloadItems();
|
|
521
|
+
el.layout();
|
|
522
|
+
|
|
523
|
+
expect(item1.style.transform).toBe('translate(0px, 0px)');
|
|
524
|
+
expect(item2.style.transform).toBe('translate(160px, 0px)');
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
describe('layout persistence', () => {
|
|
529
|
+
it('should return layout via getLayout()', async () => {
|
|
530
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
531
|
+
'column-width': 80,
|
|
532
|
+
'row-height': 80,
|
|
533
|
+
gap: '0px'
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
const item = document.createElement('div');
|
|
537
|
+
item.setAttribute('name', 'myitem');
|
|
538
|
+
item.setAttribute('grid-col', '2');
|
|
539
|
+
item.setAttribute('grid-row', '3');
|
|
540
|
+
el.appendChild(item);
|
|
541
|
+
await wait(50);
|
|
542
|
+
el.reloadItems();
|
|
543
|
+
el.layout();
|
|
544
|
+
|
|
545
|
+
const layout = el.getLayout();
|
|
546
|
+
expect(layout['myitem']).toBeDefined();
|
|
547
|
+
expect(layout['myitem'].col).toBe(2);
|
|
548
|
+
expect(layout['myitem'].row).toBe(3);
|
|
549
|
+
expect(layout['myitem'].order).toBe(0);
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
it('should restore layout via setLayout()', async () => {
|
|
553
|
+
el = await createComponent<SniceGridElement>('snice-grid', {
|
|
554
|
+
'column-width': 80,
|
|
555
|
+
'row-height': 80,
|
|
556
|
+
gap: '0px'
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
const item = document.createElement('div');
|
|
560
|
+
item.setAttribute('name', 'myitem');
|
|
561
|
+
item.setAttribute('grid-col', '0');
|
|
562
|
+
item.setAttribute('grid-row', '0');
|
|
563
|
+
el.appendChild(item);
|
|
564
|
+
await wait(50);
|
|
565
|
+
el.reloadItems();
|
|
566
|
+
|
|
567
|
+
el.setLayout({
|
|
568
|
+
myitem: { col: 3, row: 2, order: 0 }
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
// x = 3 * 80 = 240, y = 2 * 80 = 160
|
|
572
|
+
expect(item.style.transform).toBe('translate(240px, 160px)');
|
|
573
|
+
});
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
describe('events', () => {
|
|
577
|
+
it('should fire grid-layout-complete on layout()', async () => {
|
|
578
|
+
el = await createComponent<SniceGridElement>('snice-grid');
|
|
579
|
+
|
|
580
|
+
let eventFired = false;
|
|
581
|
+
(el as HTMLElement).addEventListener('grid-layout-complete', () => {
|
|
582
|
+
eventFired = true;
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
el.layout();
|
|
586
|
+
expect(eventFired).toBe(true);
|
|
587
|
+
});
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
describe('ready attribute', () => {
|
|
591
|
+
it('should set ready attribute after initialization', async () => {
|
|
592
|
+
el = await createComponent<SniceGridElement>('snice-grid');
|
|
593
|
+
await wait(20);
|
|
594
|
+
expect(el.hasAttribute('ready')).toBe(true);
|
|
595
|
+
});
|
|
596
|
+
});
|
|
597
|
+
});
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
**Step 2: Run tests to verify they fail**
|
|
601
|
+
|
|
602
|
+
Run: `npx vitest run tests/components/grid.test.ts`
|
|
603
|
+
Expected: FAIL — module `../../components/grid/snice-grid` not found
|
|
604
|
+
|
|
605
|
+
**Step 3: Commit**
|
|
606
|
+
|
|
607
|
+
```bash
|
|
608
|
+
git add tests/components/grid.test.ts
|
|
609
|
+
git commit -m "test(grid): add failing tests for grid component"
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
---
|
|
613
|
+
|
|
614
|
+
### Task 4: Grid Component — Core Layout Engine
|
|
615
|
+
|
|
616
|
+
**Files:**
|
|
617
|
+
- Create: `components/grid/snice-grid.ts`
|
|
618
|
+
|
|
619
|
+
This is the main implementation file. Structure mirrors binpack exactly:
|
|
620
|
+
1. Imports and types
|
|
621
|
+
2. `OccupancyGrid` helper class (replaces binpack's `Packer`)
|
|
622
|
+
3. `SniceGrid` component class with decorators
|
|
623
|
+
|
|
624
|
+
**Step 1: Write the component**
|
|
625
|
+
|
|
626
|
+
The component has these sections:
|
|
627
|
+
|
|
628
|
+
**OccupancyGrid class** — A 2D boolean grid tracking occupied cells. Methods:
|
|
629
|
+
- `occupy(col, row, colspan, rowspan)` — marks cells as taken
|
|
630
|
+
- `isOccupied(col, row, colspan, rowspan)` — checks if any cell in the range is taken
|
|
631
|
+
- `findNextFree(col, row, colspan, rowspan, maxCols)` — scans right-then-down for open space
|
|
632
|
+
- `grow(col, row)` — expands grid dimensions as needed
|
|
633
|
+
|
|
634
|
+
**SniceGrid class** — Same decorator pattern as binpack:
|
|
635
|
+
- `@element('snice-grid')`, `@property()` for all properties
|
|
636
|
+
- `@query()` for `.grid`, `slot`, `.grid-drop-placeholder`
|
|
637
|
+
- `@ready()` / `@dispose()` lifecycle
|
|
638
|
+
- `@watch()` for property change → relayout
|
|
639
|
+
- `@dispatch()` for events
|
|
640
|
+
- `@render()` template, `@styles()` CSS
|
|
641
|
+
- `performLayout()` — reads item attributes, builds occupancy grid, resolves collisions, positions items
|
|
642
|
+
- Same drag implementation as binpack but snapping to grid cells on release
|
|
643
|
+
|
|
644
|
+
Key implementation details:
|
|
645
|
+
- `performLayout()`: iterate items in DOM order, read `grid-col`/`grid-row`/`grid-colspan`/`grid-rowspan` attributes, check occupancy grid, if collision → `findNextFree()`, set `transform` and `width`/`height`
|
|
646
|
+
- `fit(el, col, row)`: update element's `grid-col`/`grid-row` attributes, call `performLayout()`
|
|
647
|
+
- `getLayout()`: read current resolved positions from item attributes
|
|
648
|
+
- `setLayout()`: set attributes from map, reorder DOM, call `performLayout()`
|
|
649
|
+
- Container sizing: after layout, compute `maxCol`/`maxRow` from placed items, set container width/height. If `columns`/`rows` set, use those for fixed size
|
|
650
|
+
- Drag: on release, compute nearest cell from pixel position, call `fit()` which triggers collision resolution
|
|
651
|
+
|
|
652
|
+
**Step 2: Run tests**
|
|
653
|
+
|
|
654
|
+
Run: `npx vitest run tests/components/grid.test.ts`
|
|
655
|
+
Expected: ALL PASS
|
|
656
|
+
|
|
657
|
+
**Step 3: Commit**
|
|
658
|
+
|
|
659
|
+
```bash
|
|
660
|
+
git add components/grid/snice-grid.ts
|
|
661
|
+
git commit -m "feat(grid): implement core grid layout component"
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
---
|
|
665
|
+
|
|
666
|
+
### Task 5: Demo HTML
|
|
667
|
+
|
|
668
|
+
**Files:**
|
|
669
|
+
- Create: `components/grid/demo.html`
|
|
670
|
+
|
|
671
|
+
**Step 1: Write basic demo page**
|
|
672
|
+
|
|
673
|
+
Simple demo with a few items at various grid positions, some spanning multiple cells. Include controls to toggle draggable, change column/row counts. Follow the pattern from `components/binpack/demo.html`.
|
|
674
|
+
|
|
675
|
+
**Step 2: Manual verification**
|
|
676
|
+
|
|
677
|
+
Run: `npx vite --open components/grid/demo.html`
|
|
678
|
+
Verify: Items appear at correct grid positions, spanning works, collision pushes items right.
|
|
679
|
+
|
|
680
|
+
**Step 3: Commit**
|
|
681
|
+
|
|
682
|
+
```bash
|
|
683
|
+
git add components/grid/demo.html
|
|
684
|
+
git commit -m "feat(grid): add demo page"
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
---
|
|
688
|
+
|
|
689
|
+
### Task 6: Run Full Test Suite
|
|
690
|
+
|
|
691
|
+
**Step 1: Run all tests**
|
|
692
|
+
|
|
693
|
+
Run: `npx vitest run`
|
|
694
|
+
Expected: All tests pass, no regressions.
|
|
695
|
+
|
|
696
|
+
**Step 2: Final commit if any fixes needed**
|
|
697
|
+
|
|
698
|
+
---
|
|
699
|
+
|
|
700
|
+
### Task 7: CDN Build Setup
|
|
701
|
+
|
|
702
|
+
**Files:**
|
|
703
|
+
- Modify: Check if `snice.config.ts` or equivalent needs a grid entry for CDN build
|
|
704
|
+
|
|
705
|
+
**Step 1: Build the component for CDN**
|
|
706
|
+
|
|
707
|
+
```bash
|
|
708
|
+
npm run build:core
|
|
709
|
+
npx snice build-component grid
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
**Step 2: Verify CDN bundle exists**
|
|
713
|
+
|
|
714
|
+
Check `dist/cdn/grid/snice-grid.min.js` exists.
|
|
715
|
+
|
|
716
|
+
**Step 3: Commit if config changes were needed**
|