@aceshooting/lyra-ui 3.7.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +109 -3
- package/custom-elements.json +90743 -41052
- package/dist/components/activity-feed/activity-feed.class.d.ts +123 -0
- package/dist/components/activity-feed/activity-feed.class.d.ts.map +1 -0
- package/dist/components/activity-feed/activity-feed.class.js +300 -0
- package/dist/components/activity-feed/activity-feed.class.js.map +1 -0
- package/dist/components/activity-feed/activity-feed.d.ts +2 -0
- package/dist/components/activity-feed/activity-feed.d.ts.map +1 -0
- package/dist/components/activity-feed/activity-feed.js +5 -0
- package/dist/components/activity-feed/activity-feed.js.map +1 -0
- package/dist/components/activity-feed/activity-feed.styles.d.ts +2 -0
- package/dist/components/activity-feed/activity-feed.styles.d.ts.map +1 -0
- package/dist/components/activity-feed/activity-feed.styles.js +147 -0
- package/dist/components/activity-feed/activity-feed.styles.js.map +1 -0
- package/dist/components/animation/animation.class.d.ts +12 -0
- package/dist/components/animation/animation.class.d.ts.map +1 -1
- package/dist/components/animation/animation.class.js +47 -7
- package/dist/components/animation/animation.class.js.map +1 -1
- package/dist/components/app-rail/app-rail.class.d.ts +19 -3
- package/dist/components/app-rail/app-rail.class.d.ts.map +1 -1
- package/dist/components/app-rail/app-rail.class.js +34 -12
- package/dist/components/app-rail/app-rail.class.js.map +1 -1
- package/dist/components/app-rail/app-rail.styles.d.ts.map +1 -1
- package/dist/components/app-rail/app-rail.styles.js +19 -11
- package/dist/components/app-rail/app-rail.styles.js.map +1 -1
- package/dist/components/artifact-panel/artifact-panel.class.d.ts +100 -0
- package/dist/components/artifact-panel/artifact-panel.class.d.ts.map +1 -0
- package/dist/components/artifact-panel/artifact-panel.class.js +254 -0
- package/dist/components/artifact-panel/artifact-panel.class.js.map +1 -0
- package/dist/components/artifact-panel/artifact-panel.d.ts +2 -0
- package/dist/components/artifact-panel/artifact-panel.d.ts.map +1 -0
- package/dist/components/artifact-panel/artifact-panel.js +5 -0
- package/dist/components/artifact-panel/artifact-panel.js.map +1 -0
- package/dist/components/artifact-panel/artifact-panel.styles.d.ts +2 -0
- package/dist/components/artifact-panel/artifact-panel.styles.d.ts.map +1 -0
- package/dist/components/artifact-panel/artifact-panel.styles.js +97 -0
- package/dist/components/artifact-panel/artifact-panel.styles.js.map +1 -0
- package/dist/components/attachment-chip/attachment-chip.class.d.ts +4 -2
- package/dist/components/attachment-chip/attachment-chip.class.d.ts.map +1 -1
- package/dist/components/attachment-chip/attachment-chip.class.js +10 -5
- package/dist/components/attachment-chip/attachment-chip.class.js.map +1 -1
- package/dist/components/attachment-chip/attachment-chip.styles.d.ts.map +1 -1
- package/dist/components/attachment-chip/attachment-chip.styles.js +7 -2
- package/dist/components/attachment-chip/attachment-chip.styles.js.map +1 -1
- package/dist/components/attachment-trigger/attachment-trigger.class.d.ts +17 -12
- package/dist/components/attachment-trigger/attachment-trigger.class.d.ts.map +1 -1
- package/dist/components/attachment-trigger/attachment-trigger.class.js +28 -8
- package/dist/components/attachment-trigger/attachment-trigger.class.js.map +1 -1
- package/dist/components/attachment-trigger/attachment-trigger.styles.d.ts.map +1 -1
- package/dist/components/attachment-trigger/attachment-trigger.styles.js +11 -0
- package/dist/components/attachment-trigger/attachment-trigger.styles.js.map +1 -1
- package/dist/components/audio-visualizer/audio-visualizer.class.d.ts +111 -0
- package/dist/components/audio-visualizer/audio-visualizer.class.d.ts.map +1 -0
- package/dist/components/audio-visualizer/audio-visualizer.class.js +435 -0
- package/dist/components/audio-visualizer/audio-visualizer.class.js.map +1 -0
- package/dist/components/audio-visualizer/audio-visualizer.d.ts +2 -0
- package/dist/components/audio-visualizer/audio-visualizer.d.ts.map +1 -0
- package/dist/components/audio-visualizer/audio-visualizer.js +5 -0
- package/dist/components/audio-visualizer/audio-visualizer.js.map +1 -0
- package/dist/components/audio-visualizer/audio-visualizer.styles.d.ts +2 -0
- package/dist/components/audio-visualizer/audio-visualizer.styles.d.ts.map +1 -0
- package/dist/components/audio-visualizer/audio-visualizer.styles.js +20 -0
- package/dist/components/audio-visualizer/audio-visualizer.styles.js.map +1 -0
- package/dist/components/av-player/av-player.class.d.ts +215 -0
- package/dist/components/av-player/av-player.class.d.ts.map +1 -0
- package/dist/components/av-player/av-player.class.js +590 -0
- package/dist/components/av-player/av-player.class.js.map +1 -0
- package/dist/components/av-player/av-player.d.ts +2 -0
- package/dist/components/av-player/av-player.d.ts.map +1 -0
- package/dist/components/av-player/av-player.js +36 -0
- package/dist/components/av-player/av-player.js.map +1 -0
- package/dist/components/av-player/av-player.styles.d.ts +2 -0
- package/dist/components/av-player/av-player.styles.d.ts.map +1 -0
- package/dist/components/av-player/av-player.styles.js +109 -0
- package/dist/components/av-player/av-player.styles.js.map +1 -0
- package/dist/components/avatar-group/avatar-group.class.d.ts +7 -2
- package/dist/components/avatar-group/avatar-group.class.d.ts.map +1 -1
- package/dist/components/avatar-group/avatar-group.class.js +19 -2
- package/dist/components/avatar-group/avatar-group.class.js.map +1 -1
- package/dist/components/badge/tag.class.d.ts +4 -1
- package/dist/components/badge/tag.class.d.ts.map +1 -1
- package/dist/components/badge/tag.class.js +4 -1
- package/dist/components/badge/tag.class.js.map +1 -1
- package/dist/components/branch-picker/branch-picker.class.d.ts +69 -0
- package/dist/components/branch-picker/branch-picker.class.d.ts.map +1 -0
- package/dist/components/branch-picker/branch-picker.class.js +151 -0
- package/dist/components/branch-picker/branch-picker.class.js.map +1 -0
- package/dist/components/branch-picker/branch-picker.d.ts +3 -0
- package/dist/components/branch-picker/branch-picker.d.ts.map +1 -0
- package/dist/components/branch-picker/branch-picker.js +6 -0
- package/dist/components/branch-picker/branch-picker.js.map +1 -0
- package/dist/components/branch-picker/branch-picker.styles.d.ts +2 -0
- package/dist/components/branch-picker/branch-picker.styles.d.ts.map +1 -0
- package/dist/components/branch-picker/branch-picker.styles.js +64 -0
- package/dist/components/branch-picker/branch-picker.styles.js.map +1 -0
- package/dist/components/browser-frame/browser-frame.class.d.ts +70 -0
- package/dist/components/browser-frame/browser-frame.class.d.ts.map +1 -0
- package/dist/components/browser-frame/browser-frame.class.js +196 -0
- package/dist/components/browser-frame/browser-frame.class.js.map +1 -0
- package/dist/components/browser-frame/browser-frame.d.ts +2 -0
- package/dist/components/browser-frame/browser-frame.d.ts.map +1 -0
- package/dist/components/browser-frame/browser-frame.js +5 -0
- package/dist/components/browser-frame/browser-frame.js.map +1 -0
- package/dist/components/browser-frame/browser-frame.styles.d.ts +2 -0
- package/dist/components/browser-frame/browser-frame.styles.d.ts.map +1 -0
- package/dist/components/browser-frame/browser-frame.styles.js +88 -0
- package/dist/components/browser-frame/browser-frame.styles.js.map +1 -0
- package/dist/components/button/button.class.d.ts +29 -4
- package/dist/components/button/button.class.d.ts.map +1 -1
- package/dist/components/button/button.class.js +40 -7
- package/dist/components/button/button.class.js.map +1 -1
- package/dist/components/button/button.styles.d.ts.map +1 -1
- package/dist/components/button/button.styles.js +17 -0
- package/dist/components/button/button.styles.js.map +1 -1
- package/dist/components/calendar/calendar.class.d.ts +14 -2
- package/dist/components/calendar/calendar.class.d.ts.map +1 -1
- package/dist/components/calendar/calendar.class.js +41 -8
- package/dist/components/calendar/calendar.class.js.map +1 -1
- package/dist/components/calendar/calendar.styles.d.ts.map +1 -1
- package/dist/components/calendar/calendar.styles.js +9 -4
- package/dist/components/calendar/calendar.styles.js.map +1 -1
- package/dist/components/calendar-viewer/calendar-viewer.class.d.ts.map +1 -1
- package/dist/components/calendar-viewer/calendar-viewer.class.js +2 -1
- package/dist/components/calendar-viewer/calendar-viewer.class.js.map +1 -1
- package/dist/components/callout/callout.class.d.ts +5 -1
- package/dist/components/callout/callout.class.d.ts.map +1 -1
- package/dist/components/callout/callout.class.js +6 -2
- package/dist/components/callout/callout.class.js.map +1 -1
- package/dist/components/callout/callout.styles.d.ts.map +1 -1
- package/dist/components/callout/callout.styles.js +11 -3
- package/dist/components/callout/callout.styles.js.map +1 -1
- package/dist/components/carousel/carousel.class.d.ts +9 -1
- package/dist/components/carousel/carousel.class.d.ts.map +1 -1
- package/dist/components/carousel/carousel.class.js +22 -4
- package/dist/components/carousel/carousel.class.js.map +1 -1
- package/dist/components/carousel/carousel.styles.d.ts.map +1 -1
- package/dist/components/carousel/carousel.styles.js +27 -5
- package/dist/components/carousel/carousel.styles.js.map +1 -1
- package/dist/components/chart/box-plot.class.d.ts.map +1 -1
- package/dist/components/chart/box-plot.class.js +3 -2
- package/dist/components/chart/box-plot.class.js.map +1 -1
- package/dist/components/chart/chart.class.d.ts +31 -0
- package/dist/components/chart/chart.class.d.ts.map +1 -1
- package/dist/components/chart/chart.class.js +150 -7
- package/dist/components/chart/chart.class.js.map +1 -1
- package/dist/components/chart/chart.styles.d.ts.map +1 -1
- package/dist/components/chart/chart.styles.js +6 -0
- package/dist/components/chart/chart.styles.js.map +1 -1
- package/dist/components/chart/lite-chart.class.d.ts +15 -1
- package/dist/components/chart/lite-chart.class.d.ts.map +1 -1
- package/dist/components/chart/lite-chart.class.js +87 -26
- package/dist/components/chart/lite-chart.class.js.map +1 -1
- package/dist/components/chart/lite-chart.styles.d.ts.map +1 -1
- package/dist/components/chart/lite-chart.styles.js +4 -0
- package/dist/components/chart/lite-chart.styles.js.map +1 -1
- package/dist/components/chat-composer/chat-composer.class.d.ts +6 -0
- package/dist/components/chat-composer/chat-composer.class.d.ts.map +1 -1
- package/dist/components/chat-composer/chat-composer.class.js +17 -3
- package/dist/components/chat-composer/chat-composer.class.js.map +1 -1
- package/dist/components/chat-message/chat-message.class.d.ts +11 -1
- package/dist/components/chat-message/chat-message.class.d.ts.map +1 -1
- package/dist/components/chat-message/chat-message.class.js +28 -7
- package/dist/components/chat-message/chat-message.class.js.map +1 -1
- package/dist/components/chat-message/chat-message.styles.d.ts.map +1 -1
- package/dist/components/chat-message/chat-message.styles.js +16 -5
- package/dist/components/chat-message/chat-message.styles.js.map +1 -1
- package/dist/components/chat-viewport/chat-viewport.class.d.ts +143 -0
- package/dist/components/chat-viewport/chat-viewport.class.d.ts.map +1 -0
- package/dist/components/chat-viewport/chat-viewport.class.js +521 -0
- package/dist/components/chat-viewport/chat-viewport.class.js.map +1 -0
- package/dist/components/chat-viewport/chat-viewport.d.ts +2 -0
- package/dist/components/chat-viewport/chat-viewport.d.ts.map +1 -0
- package/dist/components/chat-viewport/chat-viewport.js +5 -0
- package/dist/components/chat-viewport/chat-viewport.js.map +1 -0
- package/dist/components/chat-viewport/chat-viewport.styles.d.ts +2 -0
- package/dist/components/chat-viewport/chat-viewport.styles.d.ts.map +1 -0
- package/dist/components/chat-viewport/chat-viewport.styles.js +105 -0
- package/dist/components/chat-viewport/chat-viewport.styles.js.map +1 -0
- package/dist/components/checkbox/checkbox.class.d.ts +2 -1
- package/dist/components/checkbox/checkbox.class.d.ts.map +1 -1
- package/dist/components/checkbox/checkbox.class.js +17 -2
- package/dist/components/checkbox/checkbox.class.js.map +1 -1
- package/dist/components/checkbox-group/checkbox-group.class.d.ts +32 -3
- package/dist/components/checkbox-group/checkbox-group.class.d.ts.map +1 -1
- package/dist/components/checkbox-group/checkbox-group.class.js +70 -18
- package/dist/components/checkbox-group/checkbox-group.class.js.map +1 -1
- package/dist/components/checkpoint/checkpoint.class.d.ts +71 -0
- package/dist/components/checkpoint/checkpoint.class.d.ts.map +1 -0
- package/dist/components/checkpoint/checkpoint.class.js +219 -0
- package/dist/components/checkpoint/checkpoint.class.js.map +1 -0
- package/dist/components/checkpoint/checkpoint.d.ts +2 -0
- package/dist/components/checkpoint/checkpoint.d.ts.map +1 -0
- package/dist/components/checkpoint/checkpoint.js +5 -0
- package/dist/components/checkpoint/checkpoint.js.map +1 -0
- package/dist/components/checkpoint/checkpoint.styles.d.ts +2 -0
- package/dist/components/checkpoint/checkpoint.styles.d.ts.map +1 -0
- package/dist/components/checkpoint/checkpoint.styles.js +123 -0
- package/dist/components/checkpoint/checkpoint.styles.js.map +1 -0
- package/dist/components/chip/chip-group.class.d.ts +7 -2
- package/dist/components/chip/chip-group.class.d.ts.map +1 -1
- package/dist/components/chip/chip-group.class.js +19 -2
- package/dist/components/chip/chip-group.class.js.map +1 -1
- package/dist/components/chip/chip.styles.d.ts.map +1 -1
- package/dist/components/chip/chip.styles.js +12 -3
- package/dist/components/chip/chip.styles.js.map +1 -1
- package/dist/components/chunk-inspector/chunk-inspector.class.d.ts +131 -0
- package/dist/components/chunk-inspector/chunk-inspector.class.d.ts.map +1 -0
- package/dist/components/chunk-inspector/chunk-inspector.class.js +170 -0
- package/dist/components/chunk-inspector/chunk-inspector.class.js.map +1 -0
- package/dist/components/chunk-inspector/chunk-inspector.d.ts +4 -0
- package/dist/components/chunk-inspector/chunk-inspector.d.ts.map +1 -0
- package/dist/components/chunk-inspector/chunk-inspector.js +7 -0
- package/dist/components/chunk-inspector/chunk-inspector.js.map +1 -0
- package/dist/components/chunk-inspector/chunk-inspector.styles.d.ts +2 -0
- package/dist/components/chunk-inspector/chunk-inspector.styles.d.ts.map +1 -0
- package/dist/components/chunk-inspector/chunk-inspector.styles.js +84 -0
- package/dist/components/chunk-inspector/chunk-inspector.styles.js.map +1 -0
- package/dist/components/citation-badge/citation-badge.class.d.ts +7 -2
- package/dist/components/citation-badge/citation-badge.class.d.ts.map +1 -1
- package/dist/components/citation-badge/citation-badge.class.js +15 -3
- package/dist/components/citation-badge/citation-badge.class.js.map +1 -1
- package/dist/components/code-block/code-block-core.class.d.ts +62 -0
- package/dist/components/code-block/code-block-core.class.d.ts.map +1 -1
- package/dist/components/code-block/code-block-core.class.js +229 -42
- package/dist/components/code-block/code-block-core.class.js.map +1 -1
- package/dist/components/code-block/code-block-shared.d.ts +29 -5
- package/dist/components/code-block/code-block-shared.d.ts.map +1 -1
- package/dist/components/code-block/code-block-shared.js +73 -5
- package/dist/components/code-block/code-block-shared.js.map +1 -1
- package/dist/components/code-block/code-block.class.d.ts +62 -0
- package/dist/components/code-block/code-block.class.d.ts.map +1 -1
- package/dist/components/code-block/code-block.class.js +229 -42
- package/dist/components/code-block/code-block.class.js.map +1 -1
- package/dist/components/code-block/code-block.styles.d.ts.map +1 -1
- package/dist/components/code-block/code-block.styles.js +41 -0
- package/dist/components/code-block/code-block.styles.js.map +1 -1
- package/dist/components/code-editor/code-editor.class.d.ts +17 -1
- package/dist/components/code-editor/code-editor.class.d.ts.map +1 -1
- package/dist/components/code-editor/code-editor.class.js +50 -11
- package/dist/components/code-editor/code-editor.class.js.map +1 -1
- package/dist/components/combobox/combobox.class.d.ts +21 -2
- package/dist/components/combobox/combobox.class.d.ts.map +1 -1
- package/dist/components/combobox/combobox.class.js +41 -12
- package/dist/components/combobox/combobox.class.js.map +1 -1
- package/dist/components/combobox/combobox.styles.d.ts.map +1 -1
- package/dist/components/combobox/combobox.styles.js +29 -7
- package/dist/components/combobox/combobox.styles.js.map +1 -1
- package/dist/components/command-palette/command-palette.class.d.ts +14 -0
- package/dist/components/command-palette/command-palette.class.d.ts.map +1 -1
- package/dist/components/command-palette/command-palette.class.js +33 -6
- package/dist/components/command-palette/command-palette.class.js.map +1 -1
- package/dist/components/commit-card/commit-card.class.d.ts +78 -0
- package/dist/components/commit-card/commit-card.class.d.ts.map +1 -0
- package/dist/components/commit-card/commit-card.class.js +209 -0
- package/dist/components/commit-card/commit-card.class.js.map +1 -0
- package/dist/components/commit-card/commit-card.d.ts +2 -0
- package/dist/components/commit-card/commit-card.d.ts.map +1 -0
- package/dist/components/commit-card/commit-card.js +5 -0
- package/dist/components/commit-card/commit-card.js.map +1 -0
- package/dist/components/commit-card/commit-card.styles.d.ts +2 -0
- package/dist/components/commit-card/commit-card.styles.d.ts.map +1 -0
- package/dist/components/commit-card/commit-card.styles.js +69 -0
- package/dist/components/commit-card/commit-card.styles.js.map +1 -0
- package/dist/components/community-card/community-card.class.d.ts +68 -0
- package/dist/components/community-card/community-card.class.d.ts.map +1 -0
- package/dist/components/community-card/community-card.class.js +109 -0
- package/dist/components/community-card/community-card.class.js.map +1 -0
- package/dist/components/community-card/community-card.d.ts +5 -0
- package/dist/components/community-card/community-card.d.ts.map +1 -0
- package/dist/components/community-card/community-card.js +8 -0
- package/dist/components/community-card/community-card.js.map +1 -0
- package/dist/components/community-card/community-card.styles.d.ts +2 -0
- package/dist/components/community-card/community-card.styles.d.ts.map +1 -0
- package/dist/components/community-card/community-card.styles.js +74 -0
- package/dist/components/community-card/community-card.styles.js.map +1 -0
- package/dist/components/compare-panel/compare-panel.class.d.ts +112 -0
- package/dist/components/compare-panel/compare-panel.class.d.ts.map +1 -0
- package/dist/components/compare-panel/compare-panel.class.js +260 -0
- package/dist/components/compare-panel/compare-panel.class.js.map +1 -0
- package/dist/components/compare-panel/compare-panel.d.ts +3 -0
- package/dist/components/compare-panel/compare-panel.d.ts.map +1 -0
- package/dist/components/compare-panel/compare-panel.js +6 -0
- package/dist/components/compare-panel/compare-panel.js.map +1 -0
- package/dist/components/compare-panel/compare-panel.styles.d.ts +2 -0
- package/dist/components/compare-panel/compare-panel.styles.d.ts.map +1 -0
- package/dist/components/compare-panel/compare-panel.styles.js +97 -0
- package/dist/components/compare-panel/compare-panel.styles.js.map +1 -0
- package/dist/components/confirm-bar/confirm-bar.class.d.ts +81 -0
- package/dist/components/confirm-bar/confirm-bar.class.d.ts.map +1 -0
- package/dist/components/confirm-bar/confirm-bar.class.js +193 -0
- package/dist/components/confirm-bar/confirm-bar.class.js.map +1 -0
- package/dist/components/confirm-bar/confirm-bar.d.ts +5 -0
- package/dist/components/confirm-bar/confirm-bar.d.ts.map +1 -0
- package/dist/components/confirm-bar/confirm-bar.js +8 -0
- package/dist/components/confirm-bar/confirm-bar.js.map +1 -0
- package/dist/components/confirm-bar/confirm-bar.styles.d.ts +2 -0
- package/dist/components/confirm-bar/confirm-bar.styles.d.ts.map +1 -0
- package/dist/components/confirm-bar/confirm-bar.styles.js +96 -0
- package/dist/components/confirm-bar/confirm-bar.styles.js.map +1 -0
- package/dist/components/context-meter/context-meter.class.d.ts +8 -1
- package/dist/components/context-meter/context-meter.class.d.ts.map +1 -1
- package/dist/components/context-meter/context-meter.class.js +25 -4
- package/dist/components/context-meter/context-meter.class.js.map +1 -1
- package/dist/components/context-meter/context-meter.styles.d.ts.map +1 -1
- package/dist/components/context-meter/context-meter.styles.js +6 -0
- package/dist/components/context-meter/context-meter.styles.js.map +1 -1
- package/dist/components/conversation-item/conversation-item.class.d.ts +17 -1
- package/dist/components/conversation-item/conversation-item.class.d.ts.map +1 -1
- package/dist/components/conversation-item/conversation-item.class.js +43 -4
- package/dist/components/conversation-item/conversation-item.class.js.map +1 -1
- package/dist/components/conversation-item/conversation-item.styles.d.ts.map +1 -1
- package/dist/components/conversation-item/conversation-item.styles.js +15 -2
- package/dist/components/conversation-item/conversation-item.styles.js.map +1 -1
- package/dist/components/copy-button/copy-button.class.d.ts.map +1 -1
- package/dist/components/copy-button/copy-button.class.js +4 -3
- package/dist/components/copy-button/copy-button.class.js.map +1 -1
- package/dist/components/csv-viewer/csv-viewer.class.d.ts +83 -3
- package/dist/components/csv-viewer/csv-viewer.class.d.ts.map +1 -1
- package/dist/components/csv-viewer/csv-viewer.class.js +204 -6
- package/dist/components/csv-viewer/csv-viewer.class.js.map +1 -1
- package/dist/components/csv-viewer/csv-viewer.js +10 -1
- package/dist/components/csv-viewer/csv-viewer.js.map +1 -1
- package/dist/components/data-grid/data-grid.class.d.ts +2 -1
- package/dist/components/data-grid/data-grid.class.d.ts.map +1 -1
- package/dist/components/data-grid/data-grid.class.js +10 -1
- package/dist/components/data-grid/data-grid.class.js.map +1 -1
- package/dist/components/dataset-viewer/dataset-viewer.class.d.ts +93 -4
- package/dist/components/dataset-viewer/dataset-viewer.class.d.ts.map +1 -1
- package/dist/components/dataset-viewer/dataset-viewer.class.js +212 -14
- package/dist/components/dataset-viewer/dataset-viewer.class.js.map +1 -1
- package/dist/components/dataset-viewer/dataset-viewer.js +11 -6
- package/dist/components/dataset-viewer/dataset-viewer.js.map +1 -1
- package/dist/components/dataset-viewer/dataset-viewer.styles.d.ts.map +1 -1
- package/dist/components/dataset-viewer/dataset-viewer.styles.js +52 -5
- package/dist/components/dataset-viewer/dataset-viewer.styles.js.map +1 -1
- package/dist/components/date-picker/calendar-core.d.ts.map +1 -1
- package/dist/components/date-picker/calendar-core.js +3 -2
- package/dist/components/date-picker/calendar-core.js.map +1 -1
- package/dist/components/date-picker/date-input.class.d.ts +6 -0
- package/dist/components/date-picker/date-input.class.d.ts.map +1 -1
- package/dist/components/date-picker/date-input.class.js +13 -3
- package/dist/components/date-picker/date-input.class.js.map +1 -1
- package/dist/components/date-picker/date-picker.class.d.ts.map +1 -1
- package/dist/components/date-picker/date-picker.class.js +31 -7
- package/dist/components/date-picker/date-picker.class.js.map +1 -1
- package/dist/components/date-picker/date-picker.styles.d.ts.map +1 -1
- package/dist/components/date-picker/date-picker.styles.js +5 -0
- package/dist/components/date-picker/date-picker.styles.js.map +1 -1
- package/dist/components/details/accordion-item.class.d.ts +4 -1
- package/dist/components/details/accordion-item.class.d.ts.map +1 -1
- package/dist/components/details/accordion-item.class.js +4 -1
- package/dist/components/details/accordion-item.class.js.map +1 -1
- package/dist/components/diff-view/diff-line-diff.d.ts +13 -0
- package/dist/components/diff-view/diff-line-diff.d.ts.map +1 -1
- package/dist/components/diff-view/diff-line-diff.js +33 -0
- package/dist/components/diff-view/diff-line-diff.js.map +1 -1
- package/dist/components/diff-view/diff-view.class.d.ts +27 -1
- package/dist/components/diff-view/diff-view.class.d.ts.map +1 -1
- package/dist/components/diff-view/diff-view.class.js +130 -4
- package/dist/components/diff-view/diff-view.class.js.map +1 -1
- package/dist/components/diff-view/diff-view.styles.d.ts.map +1 -1
- package/dist/components/diff-view/diff-view.styles.js +18 -2
- package/dist/components/diff-view/diff-view.styles.js.map +1 -1
- package/dist/components/dock-panel/dock-panel.class.d.ts.map +1 -1
- package/dist/components/dock-panel/dock-panel.class.js +5 -0
- package/dist/components/dock-panel/dock-panel.class.js.map +1 -1
- package/dist/components/dock-panel/dock-panel.styles.d.ts.map +1 -1
- package/dist/components/dock-panel/dock-panel.styles.js +8 -0
- package/dist/components/dock-panel/dock-panel.styles.js.map +1 -1
- package/dist/components/document-preview/document-preview.class.d.ts +32 -0
- package/dist/components/document-preview/document-preview.class.d.ts.map +1 -1
- package/dist/components/document-preview/document-preview.class.js +93 -5
- package/dist/components/document-preview/document-preview.class.js.map +1 -1
- package/dist/components/document-preview/document-preview.styles.d.ts.map +1 -1
- package/dist/components/document-preview/document-preview.styles.js +18 -0
- package/dist/components/document-preview/document-preview.styles.js.map +1 -1
- package/dist/components/document-viewer/anchors.d.ts +89 -0
- package/dist/components/document-viewer/anchors.d.ts.map +1 -0
- package/dist/components/document-viewer/anchors.js +4 -0
- package/dist/components/document-viewer/anchors.js.map +1 -0
- package/dist/components/document-viewer/document-viewer.class.d.ts +23 -0
- package/dist/components/document-viewer/document-viewer.class.d.ts.map +1 -1
- package/dist/components/document-viewer/document-viewer.class.js +72 -3
- package/dist/components/document-viewer/document-viewer.class.js.map +1 -1
- package/dist/components/document-viewer/registry.d.ts +8 -0
- package/dist/components/document-viewer/registry.d.ts.map +1 -1
- package/dist/components/document-viewer/registry.js.map +1 -1
- package/dist/components/docx-viewer/docx-viewer.class.d.ts +128 -2
- package/dist/components/docx-viewer/docx-viewer.class.d.ts.map +1 -1
- package/dist/components/docx-viewer/docx-viewer.class.js +433 -3
- package/dist/components/docx-viewer/docx-viewer.class.js.map +1 -1
- package/dist/components/docx-viewer/docx-viewer.js +1 -0
- package/dist/components/docx-viewer/docx-viewer.js.map +1 -1
- package/dist/components/docx-viewer/docx-viewer.styles.d.ts.map +1 -1
- package/dist/components/docx-viewer/docx-viewer.styles.js +56 -0
- package/dist/components/docx-viewer/docx-viewer.styles.js.map +1 -1
- package/dist/components/ebook-viewer/ebook-viewer-register.js +1 -0
- package/dist/components/ebook-viewer/ebook-viewer-register.js.map +1 -1
- package/dist/components/ebook-viewer/ebook-viewer.class.d.ts +111 -2
- package/dist/components/ebook-viewer/ebook-viewer.class.d.ts.map +1 -1
- package/dist/components/ebook-viewer/ebook-viewer.class.js +289 -4
- package/dist/components/ebook-viewer/ebook-viewer.class.js.map +1 -1
- package/dist/components/ebook-viewer/ebook-viewer.styles.d.ts.map +1 -1
- package/dist/components/ebook-viewer/ebook-viewer.styles.js +6 -2
- package/dist/components/ebook-viewer/ebook-viewer.styles.js.map +1 -1
- package/dist/components/email-viewer/email-viewer.class.d.ts +26 -1
- package/dist/components/email-viewer/email-viewer.class.d.ts.map +1 -1
- package/dist/components/email-viewer/email-viewer.class.js +110 -3
- package/dist/components/email-viewer/email-viewer.class.js.map +1 -1
- package/dist/components/email-viewer/email-viewer.js +1 -0
- package/dist/components/email-viewer/email-viewer.js.map +1 -1
- package/dist/components/email-viewer/email-viewer.styles.d.ts.map +1 -1
- package/dist/components/email-viewer/email-viewer.styles.js +31 -1
- package/dist/components/email-viewer/email-viewer.styles.js.map +1 -1
- package/dist/components/emoji-picker/emoji-data-loader.d.ts +14 -0
- package/dist/components/emoji-picker/emoji-data-loader.d.ts.map +1 -0
- package/dist/components/emoji-picker/emoji-data-loader.js +78 -0
- package/dist/components/emoji-picker/emoji-data-loader.js.map +1 -0
- package/dist/components/emoji-picker/emoji-picker.class.d.ts +98 -0
- package/dist/components/emoji-picker/emoji-picker.class.d.ts.map +1 -0
- package/dist/components/emoji-picker/emoji-picker.class.js +285 -0
- package/dist/components/emoji-picker/emoji-picker.class.js.map +1 -0
- package/dist/components/emoji-picker/emoji-picker.d.ts +2 -0
- package/dist/components/emoji-picker/emoji-picker.d.ts.map +1 -0
- package/dist/components/emoji-picker/emoji-picker.js +5 -0
- package/dist/components/emoji-picker/emoji-picker.js.map +1 -0
- package/dist/components/emoji-picker/emoji-picker.styles.d.ts +2 -0
- package/dist/components/emoji-picker/emoji-picker.styles.d.ts.map +1 -0
- package/dist/components/emoji-picker/emoji-picker.styles.js +70 -0
- package/dist/components/emoji-picker/emoji-picker.styles.js.map +1 -0
- package/dist/components/entity-card/entity-card.class.d.ts +81 -0
- package/dist/components/entity-card/entity-card.class.d.ts.map +1 -0
- package/dist/components/entity-card/entity-card.class.js +148 -0
- package/dist/components/entity-card/entity-card.class.js.map +1 -0
- package/dist/components/entity-card/entity-card.d.ts +7 -0
- package/dist/components/entity-card/entity-card.d.ts.map +1 -0
- package/dist/components/entity-card/entity-card.js +10 -0
- package/dist/components/entity-card/entity-card.js.map +1 -0
- package/dist/components/entity-card/entity-card.styles.d.ts +2 -0
- package/dist/components/entity-card/entity-card.styles.d.ts.map +1 -0
- package/dist/components/entity-card/entity-card.styles.js +48 -0
- package/dist/components/entity-card/entity-card.styles.js.map +1 -0
- package/dist/components/entity-chip/entity-chip.class.d.ts +72 -0
- package/dist/components/entity-chip/entity-chip.class.d.ts.map +1 -0
- package/dist/components/entity-chip/entity-chip.class.js +200 -0
- package/dist/components/entity-chip/entity-chip.class.js.map +1 -0
- package/dist/components/entity-chip/entity-chip.d.ts +2 -0
- package/dist/components/entity-chip/entity-chip.d.ts.map +1 -0
- package/dist/components/entity-chip/entity-chip.js +5 -0
- package/dist/components/entity-chip/entity-chip.js.map +1 -0
- package/dist/components/entity-chip/entity-chip.styles.d.ts +2 -0
- package/dist/components/entity-chip/entity-chip.styles.d.ts.map +1 -0
- package/dist/components/entity-chip/entity-chip.styles.js +46 -0
- package/dist/components/entity-chip/entity-chip.styles.js.map +1 -0
- package/dist/components/env-list/env-list.class.d.ts +55 -0
- package/dist/components/env-list/env-list.class.d.ts.map +1 -0
- package/dist/components/env-list/env-list.class.js +143 -0
- package/dist/components/env-list/env-list.class.js.map +1 -0
- package/dist/components/env-list/env-list.d.ts +2 -0
- package/dist/components/env-list/env-list.d.ts.map +1 -0
- package/dist/components/env-list/env-list.js +5 -0
- package/dist/components/env-list/env-list.js.map +1 -0
- package/dist/components/env-list/env-list.styles.d.ts +2 -0
- package/dist/components/env-list/env-list.styles.d.ts.map +1 -0
- package/dist/components/env-list/env-list.styles.js +44 -0
- package/dist/components/env-list/env-list.styles.js.map +1 -0
- package/dist/components/file-icon/file-icon.class.d.ts.map +1 -1
- package/dist/components/file-icon/file-icon.class.js +6 -1
- package/dist/components/file-icon/file-icon.class.js.map +1 -1
- package/dist/components/file-input/file-input.class.d.ts +19 -0
- package/dist/components/file-input/file-input.class.d.ts.map +1 -1
- package/dist/components/file-input/file-input.class.js +27 -1
- package/dist/components/file-input/file-input.class.js.map +1 -1
- package/dist/components/file-tree/file-tree.class.d.ts +68 -0
- package/dist/components/file-tree/file-tree.class.d.ts.map +1 -0
- package/dist/components/file-tree/file-tree.class.js +235 -0
- package/dist/components/file-tree/file-tree.class.js.map +1 -0
- package/dist/components/file-tree/file-tree.d.ts +2 -0
- package/dist/components/file-tree/file-tree.d.ts.map +1 -0
- package/dist/components/file-tree/file-tree.js +5 -0
- package/dist/components/file-tree/file-tree.js.map +1 -0
- package/dist/components/file-tree/file-tree.styles.d.ts +2 -0
- package/dist/components/file-tree/file-tree.styles.d.ts.map +1 -0
- package/dist/components/file-tree/file-tree.styles.js +10 -0
- package/dist/components/file-tree/file-tree.styles.js.map +1 -0
- package/dist/components/flag/flag.class.d.ts.map +1 -1
- package/dist/components/flag/flag.class.js +7 -15
- package/dist/components/flag/flag.class.js.map +1 -1
- package/dist/components/flow-canvas/flow-canvas.class.d.ts +411 -0
- package/dist/components/flow-canvas/flow-canvas.class.d.ts.map +1 -0
- package/dist/components/flow-canvas/flow-canvas.class.js +1570 -0
- package/dist/components/flow-canvas/flow-canvas.class.js.map +1 -0
- package/dist/components/flow-canvas/flow-canvas.d.ts +4 -0
- package/dist/components/flow-canvas/flow-canvas.d.ts.map +1 -0
- package/dist/components/flow-canvas/flow-canvas.js +7 -0
- package/dist/components/flow-canvas/flow-canvas.js.map +1 -0
- package/dist/components/flow-canvas/flow-canvas.styles.d.ts +2 -0
- package/dist/components/flow-canvas/flow-canvas.styles.d.ts.map +1 -0
- package/dist/components/flow-canvas/flow-canvas.styles.js +186 -0
- package/dist/components/flow-canvas/flow-canvas.styles.js.map +1 -0
- package/dist/components/flow-controls/flow-controls.class.d.ts +44 -0
- package/dist/components/flow-controls/flow-controls.class.d.ts.map +1 -0
- package/dist/components/flow-controls/flow-controls.class.js +203 -0
- package/dist/components/flow-controls/flow-controls.class.js.map +1 -0
- package/dist/components/flow-controls/flow-controls.d.ts +2 -0
- package/dist/components/flow-controls/flow-controls.d.ts.map +1 -0
- package/dist/components/flow-controls/flow-controls.js +5 -0
- package/dist/components/flow-controls/flow-controls.js.map +1 -0
- package/dist/components/flow-controls/flow-controls.styles.d.ts +2 -0
- package/dist/components/flow-controls/flow-controls.styles.d.ts.map +1 -0
- package/dist/components/flow-controls/flow-controls.styles.js +55 -0
- package/dist/components/flow-controls/flow-controls.styles.js.map +1 -0
- package/dist/components/flow-minimap/flow-minimap.class.d.ts +62 -0
- package/dist/components/flow-minimap/flow-minimap.class.d.ts.map +1 -0
- package/dist/components/flow-minimap/flow-minimap.class.js +291 -0
- package/dist/components/flow-minimap/flow-minimap.class.js.map +1 -0
- package/dist/components/flow-minimap/flow-minimap.d.ts +2 -0
- package/dist/components/flow-minimap/flow-minimap.d.ts.map +1 -0
- package/dist/components/flow-minimap/flow-minimap.js +5 -0
- package/dist/components/flow-minimap/flow-minimap.js.map +1 -0
- package/dist/components/flow-minimap/flow-minimap.styles.d.ts +2 -0
- package/dist/components/flow-minimap/flow-minimap.styles.d.ts.map +1 -0
- package/dist/components/flow-minimap/flow-minimap.styles.js +48 -0
- package/dist/components/flow-minimap/flow-minimap.styles.js.map +1 -0
- package/dist/components/flow-node/flow-node.class.d.ts +70 -0
- package/dist/components/flow-node/flow-node.class.d.ts.map +1 -0
- package/dist/components/flow-node/flow-node.class.js +187 -0
- package/dist/components/flow-node/flow-node.class.js.map +1 -0
- package/dist/components/flow-node/flow-node.d.ts +2 -0
- package/dist/components/flow-node/flow-node.d.ts.map +1 -0
- package/dist/components/flow-node/flow-node.js +5 -0
- package/dist/components/flow-node/flow-node.js.map +1 -0
- package/dist/components/flow-node/flow-node.styles.d.ts +2 -0
- package/dist/components/flow-node/flow-node.styles.d.ts.map +1 -0
- package/dist/components/flow-node/flow-node.styles.js +127 -0
- package/dist/components/flow-node/flow-node.styles.js.map +1 -0
- package/dist/components/flow-run-overlay/flow-run-overlay.class.d.ts +46 -0
- package/dist/components/flow-run-overlay/flow-run-overlay.class.d.ts.map +1 -0
- package/dist/components/flow-run-overlay/flow-run-overlay.class.js +182 -0
- package/dist/components/flow-run-overlay/flow-run-overlay.class.js.map +1 -0
- package/dist/components/flow-run-overlay/flow-run-overlay.d.ts +2 -0
- package/dist/components/flow-run-overlay/flow-run-overlay.d.ts.map +1 -0
- package/dist/components/flow-run-overlay/flow-run-overlay.js +5 -0
- package/dist/components/flow-run-overlay/flow-run-overlay.js.map +1 -0
- package/dist/components/flow-run-overlay/flow-run-overlay.styles.d.ts +2 -0
- package/dist/components/flow-run-overlay/flow-run-overlay.styles.d.ts.map +1 -0
- package/dist/components/flow-run-overlay/flow-run-overlay.styles.js +38 -0
- package/dist/components/flow-run-overlay/flow-run-overlay.styles.js.map +1 -0
- package/dist/components/format/format-bytes.class.d.ts +8 -0
- package/dist/components/format/format-bytes.class.d.ts.map +1 -1
- package/dist/components/format/format-bytes.class.js +36 -7
- package/dist/components/format/format-bytes.class.js.map +1 -1
- package/dist/components/format/format-date.class.d.ts.map +1 -1
- package/dist/components/format/format-date.class.js +2 -1
- package/dist/components/format/format-date.class.js.map +1 -1
- package/dist/components/format/format-number.class.d.ts +6 -0
- package/dist/components/format/format-number.class.d.ts.map +1 -1
- package/dist/components/format/format-number.class.js +34 -5
- package/dist/components/format/format-number.class.js.map +1 -1
- package/dist/components/format/relative-time.class.d.ts.map +1 -1
- package/dist/components/format/relative-time.class.js +2 -1
- package/dist/components/format/relative-time.class.js.map +1 -1
- package/dist/components/generation-status/generation-status.class.d.ts +3 -0
- package/dist/components/generation-status/generation-status.class.d.ts.map +1 -1
- package/dist/components/generation-status/generation-status.class.js +28 -11
- package/dist/components/generation-status/generation-status.class.js.map +1 -1
- package/dist/components/generation-status/generation-status.styles.d.ts.map +1 -1
- package/dist/components/generation-status/generation-status.styles.js +7 -4
- package/dist/components/generation-status/generation-status.styles.js.map +1 -1
- package/dist/components/geojson-view/geojson-view.class.d.ts +40 -0
- package/dist/components/geojson-view/geojson-view.class.d.ts.map +1 -0
- package/dist/components/geojson-view/geojson-view.class.js +185 -0
- package/dist/components/geojson-view/geojson-view.class.js.map +1 -0
- package/dist/components/geojson-view/geojson-view.d.ts +5 -0
- package/dist/components/geojson-view/geojson-view.d.ts.map +1 -0
- package/dist/components/geojson-view/geojson-view.js +18 -0
- package/dist/components/geojson-view/geojson-view.js.map +1 -0
- package/dist/components/graph/graph-canvas.d.ts +113 -0
- package/dist/components/graph/graph-canvas.d.ts.map +1 -0
- package/dist/components/graph/graph-canvas.js +180 -0
- package/dist/components/graph/graph-canvas.js.map +1 -0
- package/dist/components/graph/graph-hull.d.ts +28 -0
- package/dist/components/graph/graph-hull.d.ts.map +1 -0
- package/dist/components/graph/graph-hull.js +70 -0
- package/dist/components/graph/graph-hull.js.map +1 -0
- package/dist/components/graph/graph-loader.d.ts +6 -0
- package/dist/components/graph/graph-loader.d.ts.map +1 -1
- package/dist/components/graph/graph-loader.js +2 -0
- package/dist/components/graph/graph-loader.js.map +1 -1
- package/dist/components/graph/graph.class.d.ts +461 -2
- package/dist/components/graph/graph.class.d.ts.map +1 -1
- package/dist/components/graph/graph.class.js +1728 -121
- package/dist/components/graph/graph.class.js.map +1 -1
- package/dist/components/graph/graph.styles.d.ts.map +1 -1
- package/dist/components/graph/graph.styles.js +106 -0
- package/dist/components/graph/graph.styles.js.map +1 -1
- package/dist/components/graph-legend/graph-legend.class.d.ts +62 -0
- package/dist/components/graph-legend/graph-legend.class.d.ts.map +1 -0
- package/dist/components/graph-legend/graph-legend.class.js +132 -0
- package/dist/components/graph-legend/graph-legend.class.js.map +1 -0
- package/dist/components/graph-legend/graph-legend.d.ts +2 -0
- package/dist/components/graph-legend/graph-legend.d.ts.map +1 -0
- package/dist/components/graph-legend/graph-legend.js +5 -0
- package/dist/components/graph-legend/graph-legend.js.map +1 -0
- package/dist/components/graph-legend/graph-legend.styles.d.ts +2 -0
- package/dist/components/graph-legend/graph-legend.styles.d.ts.map +1 -0
- package/dist/components/graph-legend/graph-legend.styles.js +59 -0
- package/dist/components/graph-legend/graph-legend.styles.js.map +1 -0
- package/dist/components/handoff-divider/handoff-divider.class.d.ts +46 -0
- package/dist/components/handoff-divider/handoff-divider.class.d.ts.map +1 -0
- package/dist/components/handoff-divider/handoff-divider.class.js +99 -0
- package/dist/components/handoff-divider/handoff-divider.class.js.map +1 -0
- package/dist/components/handoff-divider/handoff-divider.d.ts +2 -0
- package/dist/components/handoff-divider/handoff-divider.d.ts.map +1 -0
- package/dist/components/handoff-divider/handoff-divider.js +5 -0
- package/dist/components/handoff-divider/handoff-divider.js.map +1 -0
- package/dist/components/handoff-divider/handoff-divider.styles.d.ts +2 -0
- package/dist/components/handoff-divider/handoff-divider.styles.d.ts.map +1 -0
- package/dist/components/handoff-divider/handoff-divider.styles.js +48 -0
- package/dist/components/handoff-divider/handoff-divider.styles.js.map +1 -0
- package/dist/components/heatmap/heatmap.class.d.ts +12 -3
- package/dist/components/heatmap/heatmap.class.d.ts.map +1 -1
- package/dist/components/heatmap/heatmap.class.js +88 -50
- package/dist/components/heatmap/heatmap.class.js.map +1 -1
- package/dist/components/highlight-layer/highlight-layer.class.d.ts +60 -0
- package/dist/components/highlight-layer/highlight-layer.class.d.ts.map +1 -0
- package/dist/components/highlight-layer/highlight-layer.class.js +151 -0
- package/dist/components/highlight-layer/highlight-layer.class.js.map +1 -0
- package/dist/components/highlight-layer/highlight-layer.d.ts +2 -0
- package/dist/components/highlight-layer/highlight-layer.d.ts.map +1 -0
- package/dist/components/highlight-layer/highlight-layer.js +5 -0
- package/dist/components/highlight-layer/highlight-layer.js.map +1 -0
- package/dist/components/highlight-layer/highlight-layer.styles.d.ts +2 -0
- package/dist/components/highlight-layer/highlight-layer.styles.d.ts.map +1 -0
- package/dist/components/highlight-layer/highlight-layer.styles.js +68 -0
- package/dist/components/highlight-layer/highlight-layer.styles.js.map +1 -0
- package/dist/components/image-comparer/image-comparer.class.d.ts.map +1 -1
- package/dist/components/image-comparer/image-comparer.class.js +2 -1
- package/dist/components/image-comparer/image-comparer.class.js.map +1 -1
- package/dist/components/image-viewer/image-viewer.class.d.ts +143 -0
- package/dist/components/image-viewer/image-viewer.class.d.ts.map +1 -0
- package/dist/components/image-viewer/image-viewer.class.js +389 -0
- package/dist/components/image-viewer/image-viewer.class.js.map +1 -0
- package/dist/components/image-viewer/image-viewer.d.ts +4 -0
- package/dist/components/image-viewer/image-viewer.d.ts.map +1 -0
- package/dist/components/image-viewer/image-viewer.js +25 -0
- package/dist/components/image-viewer/image-viewer.js.map +1 -0
- package/dist/components/image-viewer/image-viewer.styles.d.ts +2 -0
- package/dist/components/image-viewer/image-viewer.styles.d.ts.map +1 -0
- package/dist/components/image-viewer/image-viewer.styles.js +126 -0
- package/dist/components/image-viewer/image-viewer.styles.js.map +1 -0
- package/dist/components/input/input.class.d.ts +6 -3
- package/dist/components/input/input.class.d.ts.map +1 -1
- package/dist/components/input/input.class.js +4 -1
- package/dist/components/input/input.class.js.map +1 -1
- package/dist/components/input/input.styles.d.ts.map +1 -1
- package/dist/components/input/input.styles.js +5 -0
- package/dist/components/input/input.styles.js.map +1 -1
- package/dist/components/intersection-observer/intersection-observer.class.d.ts +1 -0
- package/dist/components/intersection-observer/intersection-observer.class.d.ts.map +1 -1
- package/dist/components/intersection-observer/intersection-observer.class.js +15 -0
- package/dist/components/intersection-observer/intersection-observer.class.js.map +1 -1
- package/dist/components/json-viewer/json-viewer.class.d.ts +39 -2
- package/dist/components/json-viewer/json-viewer.class.d.ts.map +1 -1
- package/dist/components/json-viewer/json-viewer.class.js +95 -6
- package/dist/components/json-viewer/json-viewer.class.js.map +1 -1
- package/dist/components/known-date/known-date.class.d.ts.map +1 -1
- package/dist/components/known-date/known-date.class.js +2 -1
- package/dist/components/known-date/known-date.class.js.map +1 -1
- package/dist/components/lightbox/lightbox.class.d.ts +2 -2
- package/dist/components/lightbox/lightbox.class.d.ts.map +1 -1
- package/dist/components/lightbox/lightbox.class.js +16 -7
- package/dist/components/lightbox/lightbox.class.js.map +1 -1
- package/dist/components/live-region/live-region.class.d.ts +5 -0
- package/dist/components/live-region/live-region.class.d.ts.map +1 -1
- package/dist/components/live-region/live-region.class.js +10 -2
- package/dist/components/live-region/live-region.class.js.map +1 -1
- package/dist/components/map/map.class.d.ts +33 -3
- package/dist/components/map/map.class.d.ts.map +1 -1
- package/dist/components/map/map.class.js +130 -5
- package/dist/components/map/map.class.js.map +1 -1
- package/dist/components/markdown/katex-loader.d.ts +23 -0
- package/dist/components/markdown/katex-loader.d.ts.map +1 -0
- package/dist/components/markdown/katex-loader.js +33 -0
- package/dist/components/markdown/katex-loader.js.map +1 -0
- package/dist/components/markdown/markdown-core.class.d.ts +334 -0
- package/dist/components/markdown/markdown-core.class.d.ts.map +1 -0
- package/dist/components/markdown/markdown-core.class.js +999 -0
- package/dist/components/markdown/markdown-core.class.js.map +1 -0
- package/dist/components/markdown/markdown-core.d.ts +2 -0
- package/dist/components/markdown/markdown-core.d.ts.map +1 -0
- package/dist/components/markdown/markdown-core.js +5 -0
- package/dist/components/markdown/markdown-core.js.map +1 -0
- package/dist/components/markdown/markdown.class.d.ts +191 -4
- package/dist/components/markdown/markdown.class.d.ts.map +1 -1
- package/dist/components/markdown/markdown.class.js +584 -11
- package/dist/components/markdown/markdown.class.js.map +1 -1
- package/dist/components/markdown/markdown.styles.d.ts.map +1 -1
- package/dist/components/markdown/markdown.styles.js +53 -0
- package/dist/components/markdown/markdown.styles.js.map +1 -1
- package/dist/components/media-card/media-card.styles.d.ts.map +1 -1
- package/dist/components/media-card/media-card.styles.js +6 -2
- package/dist/components/media-card/media-card.styles.js.map +1 -1
- package/dist/components/mention-popover/mention-popover.styles.d.ts.map +1 -1
- package/dist/components/mention-popover/mention-popover.styles.js +6 -3
- package/dist/components/mention-popover/mention-popover.styles.js.map +1 -1
- package/dist/components/message-actions/message-actions.class.d.ts +112 -0
- package/dist/components/message-actions/message-actions.class.d.ts.map +1 -0
- package/dist/components/message-actions/message-actions.class.js +277 -0
- package/dist/components/message-actions/message-actions.class.js.map +1 -0
- package/dist/components/message-actions/message-actions.d.ts +4 -0
- package/dist/components/message-actions/message-actions.d.ts.map +1 -0
- package/dist/components/message-actions/message-actions.js +7 -0
- package/dist/components/message-actions/message-actions.js.map +1 -0
- package/dist/components/message-actions/message-actions.styles.d.ts +2 -0
- package/dist/components/message-actions/message-actions.styles.d.ts.map +1 -0
- package/dist/components/message-actions/message-actions.styles.js +66 -0
- package/dist/components/message-actions/message-actions.styles.js.map +1 -0
- package/dist/components/message-feedback/message-feedback.class.d.ts +91 -0
- package/dist/components/message-feedback/message-feedback.class.d.ts.map +1 -0
- package/dist/components/message-feedback/message-feedback.class.js +266 -0
- package/dist/components/message-feedback/message-feedback.class.js.map +1 -0
- package/dist/components/message-feedback/message-feedback.d.ts +2 -0
- package/dist/components/message-feedback/message-feedback.d.ts.map +1 -0
- package/dist/components/message-feedback/message-feedback.js +5 -0
- package/dist/components/message-feedback/message-feedback.js.map +1 -0
- package/dist/components/message-feedback/message-feedback.styles.d.ts +2 -0
- package/dist/components/message-feedback/message-feedback.styles.d.ts.map +1 -0
- package/dist/components/message-feedback/message-feedback.styles.js +133 -0
- package/dist/components/message-feedback/message-feedback.styles.js.map +1 -0
- package/dist/components/mind-map/mind-map-layout.d.ts +52 -0
- package/dist/components/mind-map/mind-map-layout.d.ts.map +1 -0
- package/dist/components/mind-map/mind-map-layout.js +69 -0
- package/dist/components/mind-map/mind-map-layout.js.map +1 -0
- package/dist/components/mind-map/mind-map.class.d.ts +83 -0
- package/dist/components/mind-map/mind-map.class.d.ts.map +1 -0
- package/dist/components/mind-map/mind-map.class.js +252 -0
- package/dist/components/mind-map/mind-map.class.js.map +1 -0
- package/dist/components/mind-map/mind-map.d.ts +2 -0
- package/dist/components/mind-map/mind-map.d.ts.map +1 -0
- package/dist/components/mind-map/mind-map.js +5 -0
- package/dist/components/mind-map/mind-map.js.map +1 -0
- package/dist/components/mind-map/mind-map.styles.d.ts +2 -0
- package/dist/components/mind-map/mind-map.styles.d.ts.map +1 -0
- package/dist/components/mind-map/mind-map.styles.js +43 -0
- package/dist/components/mind-map/mind-map.styles.js.map +1 -0
- package/dist/components/model-select/model-select.class.d.ts +1 -0
- package/dist/components/model-select/model-select.class.d.ts.map +1 -1
- package/dist/components/model-select/model-select.class.js +13 -0
- package/dist/components/model-select/model-select.class.js.map +1 -1
- package/dist/components/mutation-observer/mutation-observer.class.d.ts +1 -0
- package/dist/components/mutation-observer/mutation-observer.class.d.ts.map +1 -1
- package/dist/components/mutation-observer/mutation-observer.class.js +15 -0
- package/dist/components/mutation-observer/mutation-observer.class.js.map +1 -1
- package/dist/components/neighbor-list/neighbor-list.class.d.ts +70 -0
- package/dist/components/neighbor-list/neighbor-list.class.d.ts.map +1 -0
- package/dist/components/neighbor-list/neighbor-list.class.js +177 -0
- package/dist/components/neighbor-list/neighbor-list.class.js.map +1 -0
- package/dist/components/neighbor-list/neighbor-list.d.ts +4 -0
- package/dist/components/neighbor-list/neighbor-list.d.ts.map +1 -0
- package/dist/components/neighbor-list/neighbor-list.js +7 -0
- package/dist/components/neighbor-list/neighbor-list.js.map +1 -0
- package/dist/components/neighbor-list/neighbor-list.styles.d.ts +2 -0
- package/dist/components/neighbor-list/neighbor-list.styles.d.ts.map +1 -0
- package/dist/components/neighbor-list/neighbor-list.styles.js +79 -0
- package/dist/components/neighbor-list/neighbor-list.styles.js.map +1 -0
- package/dist/components/node-palette/node-palette.class.d.ts +82 -0
- package/dist/components/node-palette/node-palette.class.d.ts.map +1 -0
- package/dist/components/node-palette/node-palette.class.js +213 -0
- package/dist/components/node-palette/node-palette.class.js.map +1 -0
- package/dist/components/node-palette/node-palette.d.ts +2 -0
- package/dist/components/node-palette/node-palette.d.ts.map +1 -0
- package/dist/components/node-palette/node-palette.js +5 -0
- package/dist/components/node-palette/node-palette.js.map +1 -0
- package/dist/components/node-palette/node-palette.styles.d.ts +2 -0
- package/dist/components/node-palette/node-palette.styles.d.ts.map +1 -0
- package/dist/components/node-palette/node-palette.styles.js +74 -0
- package/dist/components/node-palette/node-palette.styles.js.map +1 -0
- package/dist/components/notebook-viewer/dompurify-loader.d.ts +7 -0
- package/dist/components/notebook-viewer/dompurify-loader.d.ts.map +1 -0
- package/dist/components/notebook-viewer/dompurify-loader.js +23 -0
- package/dist/components/notebook-viewer/dompurify-loader.js.map +1 -0
- package/dist/components/notebook-viewer/notebook-viewer.class.d.ts +164 -0
- package/dist/components/notebook-viewer/notebook-viewer.class.d.ts.map +1 -0
- package/dist/components/notebook-viewer/notebook-viewer.class.js +442 -0
- package/dist/components/notebook-viewer/notebook-viewer.class.js.map +1 -0
- package/dist/components/notebook-viewer/notebook-viewer.d.ts +6 -0
- package/dist/components/notebook-viewer/notebook-viewer.d.ts.map +1 -0
- package/dist/components/notebook-viewer/notebook-viewer.js +21 -0
- package/dist/components/notebook-viewer/notebook-viewer.js.map +1 -0
- package/dist/components/notebook-viewer/notebook-viewer.styles.d.ts +2 -0
- package/dist/components/notebook-viewer/notebook-viewer.styles.d.ts.map +1 -0
- package/dist/components/notebook-viewer/notebook-viewer.styles.js +79 -0
- package/dist/components/notebook-viewer/notebook-viewer.styles.js.map +1 -0
- package/dist/components/overlay/overlay.styles.d.ts.map +1 -1
- package/dist/components/overlay/overlay.styles.js +17 -5
- package/dist/components/overlay/overlay.styles.js.map +1 -1
- package/dist/components/overlay/popover.class.d.ts +2 -0
- package/dist/components/overlay/popover.class.d.ts.map +1 -1
- package/dist/components/overlay/popover.class.js +10 -2
- package/dist/components/overlay/popover.class.js.map +1 -1
- package/dist/components/overlay/tooltip.class.d.ts +4 -0
- package/dist/components/overlay/tooltip.class.d.ts.map +1 -1
- package/dist/components/overlay/tooltip.class.js +21 -6
- package/dist/components/overlay/tooltip.class.js.map +1 -1
- package/dist/components/page-rail/page-rail.class.d.ts +99 -0
- package/dist/components/page-rail/page-rail.class.d.ts.map +1 -0
- package/dist/components/page-rail/page-rail.class.js +279 -0
- package/dist/components/page-rail/page-rail.class.js.map +1 -0
- package/dist/components/page-rail/page-rail.d.ts +2 -0
- package/dist/components/page-rail/page-rail.d.ts.map +1 -0
- package/dist/components/page-rail/page-rail.js +5 -0
- package/dist/components/page-rail/page-rail.js.map +1 -0
- package/dist/components/page-rail/page-rail.styles.d.ts +2 -0
- package/dist/components/page-rail/page-rail.styles.d.ts.map +1 -0
- package/dist/components/page-rail/page-rail.styles.js +85 -0
- package/dist/components/page-rail/page-rail.styles.js.map +1 -0
- package/dist/components/pagination/pagination.class.d.ts +5 -0
- package/dist/components/pagination/pagination.class.d.ts.map +1 -1
- package/dist/components/pagination/pagination.class.js +11 -9
- package/dist/components/pagination/pagination.class.js.map +1 -1
- package/dist/components/path-strip/path-strip.class.d.ts +61 -0
- package/dist/components/path-strip/path-strip.class.d.ts.map +1 -0
- package/dist/components/path-strip/path-strip.class.js +164 -0
- package/dist/components/path-strip/path-strip.class.js.map +1 -0
- package/dist/components/path-strip/path-strip.d.ts +3 -0
- package/dist/components/path-strip/path-strip.d.ts.map +1 -0
- package/dist/components/path-strip/path-strip.js +6 -0
- package/dist/components/path-strip/path-strip.js.map +1 -0
- package/dist/components/path-strip/path-strip.styles.d.ts +2 -0
- package/dist/components/path-strip/path-strip.styles.d.ts.map +1 -0
- package/dist/components/path-strip/path-strip.styles.js +62 -0
- package/dist/components/path-strip/path-strip.styles.js.map +1 -0
- package/dist/components/pdf-viewer/pdf-viewer.class.d.ts +145 -6
- package/dist/components/pdf-viewer/pdf-viewer.class.d.ts.map +1 -1
- package/dist/components/pdf-viewer/pdf-viewer.class.js +785 -21
- package/dist/components/pdf-viewer/pdf-viewer.class.js.map +1 -1
- package/dist/components/pdf-viewer/pdf-viewer.js +7 -1
- package/dist/components/pdf-viewer/pdf-viewer.js.map +1 -1
- package/dist/components/pdf-viewer/pdf-viewer.styles.d.ts.map +1 -1
- package/dist/components/pdf-viewer/pdf-viewer.styles.js +4 -0
- package/dist/components/pdf-viewer/pdf-viewer.styles.js.map +1 -1
- package/dist/components/phone-input/phone-input.class.d.ts.map +1 -1
- package/dist/components/phone-input/phone-input.class.js +5 -1
- package/dist/components/phone-input/phone-input.class.js.map +1 -1
- package/dist/components/playback/playback.styles.d.ts.map +1 -1
- package/dist/components/playback/playback.styles.js +7 -0
- package/dist/components/playback/playback.styles.js.map +1 -1
- package/dist/components/poll-status/poll-status.class.d.ts +1 -0
- package/dist/components/poll-status/poll-status.class.d.ts.map +1 -1
- package/dist/components/poll-status/poll-status.class.js +25 -7
- package/dist/components/poll-status/poll-status.class.js.map +1 -1
- package/dist/components/pptx-viewer/pptx-viewer.styles.d.ts.map +1 -1
- package/dist/components/pptx-viewer/pptx-viewer.styles.js +5 -0
- package/dist/components/pptx-viewer/pptx-viewer.styles.js.map +1 -1
- package/dist/components/progress/progress-bar.class.d.ts +5 -0
- package/dist/components/progress/progress-bar.class.d.ts.map +1 -1
- package/dist/components/progress/progress-bar.class.js +16 -2
- package/dist/components/progress/progress-bar.class.js.map +1 -1
- package/dist/components/progress/progress-ring.class.d.ts +5 -0
- package/dist/components/progress/progress-ring.class.d.ts.map +1 -1
- package/dist/components/progress/progress-ring.class.js +16 -2
- package/dist/components/progress/progress-ring.class.js.map +1 -1
- package/dist/components/progress/progress.styles.d.ts.map +1 -1
- package/dist/components/progress/progress.styles.js +6 -0
- package/dist/components/progress/progress.styles.js.map +1 -1
- package/dist/components/provenance-panel/provenance-panel.class.d.ts +71 -0
- package/dist/components/provenance-panel/provenance-panel.class.d.ts.map +1 -0
- package/dist/components/provenance-panel/provenance-panel.class.js +110 -0
- package/dist/components/provenance-panel/provenance-panel.class.js.map +1 -0
- package/dist/components/provenance-panel/provenance-panel.d.ts +7 -0
- package/dist/components/provenance-panel/provenance-panel.d.ts.map +1 -0
- package/dist/components/provenance-panel/provenance-panel.js +10 -0
- package/dist/components/provenance-panel/provenance-panel.js.map +1 -0
- package/dist/components/provenance-panel/provenance-panel.styles.d.ts +2 -0
- package/dist/components/provenance-panel/provenance-panel.styles.d.ts.map +1 -0
- package/dist/components/provenance-panel/provenance-panel.styles.js +45 -0
- package/dist/components/provenance-panel/provenance-panel.styles.js.map +1 -0
- package/dist/components/push-to-talk/push-to-talk.class.d.ts +145 -0
- package/dist/components/push-to-talk/push-to-talk.class.d.ts.map +1 -0
- package/dist/components/push-to-talk/push-to-talk.class.js +478 -0
- package/dist/components/push-to-talk/push-to-talk.class.js.map +1 -0
- package/dist/components/push-to-talk/push-to-talk.d.ts +3 -0
- package/dist/components/push-to-talk/push-to-talk.d.ts.map +1 -0
- package/dist/components/push-to-talk/push-to-talk.js +6 -0
- package/dist/components/push-to-talk/push-to-talk.js.map +1 -0
- package/dist/components/push-to-talk/push-to-talk.styles.d.ts +2 -0
- package/dist/components/push-to-talk/push-to-talk.styles.d.ts.map +1 -0
- package/dist/components/push-to-talk/push-to-talk.styles.js +79 -0
- package/dist/components/push-to-talk/push-to-talk.styles.js.map +1 -0
- package/dist/components/radio/radio.class.d.ts +1 -0
- package/dist/components/radio/radio.class.d.ts.map +1 -1
- package/dist/components/radio/radio.class.js +4 -0
- package/dist/components/radio/radio.class.js.map +1 -1
- package/dist/components/random-content/random-content.class.d.ts +3 -1
- package/dist/components/random-content/random-content.class.d.ts.map +1 -1
- package/dist/components/random-content/random-content.class.js +7 -4
- package/dist/components/random-content/random-content.class.js.map +1 -1
- package/dist/components/rating/rating.class.d.ts +8 -0
- package/dist/components/rating/rating.class.d.ts.map +1 -1
- package/dist/components/rating/rating.class.js +34 -8
- package/dist/components/rating/rating.class.js.map +1 -1
- package/dist/components/rubric-form/rubric-form.class.d.ts +195 -0
- package/dist/components/rubric-form/rubric-form.class.d.ts.map +1 -0
- package/dist/components/rubric-form/rubric-form.class.js +495 -0
- package/dist/components/rubric-form/rubric-form.class.js.map +1 -0
- package/dist/components/rubric-form/rubric-form.d.ts +9 -0
- package/dist/components/rubric-form/rubric-form.d.ts.map +1 -0
- package/dist/components/rubric-form/rubric-form.js +12 -0
- package/dist/components/rubric-form/rubric-form.js.map +1 -0
- package/dist/components/rubric-form/rubric-form.styles.d.ts +2 -0
- package/dist/components/rubric-form/rubric-form.styles.d.ts.map +1 -0
- package/dist/components/rubric-form/rubric-form.styles.js +90 -0
- package/dist/components/rubric-form/rubric-form.styles.js.map +1 -0
- package/dist/components/scroller/scroller.class.d.ts +6 -0
- package/dist/components/scroller/scroller.class.d.ts.map +1 -1
- package/dist/components/scroller/scroller.class.js +14 -4
- package/dist/components/scroller/scroller.class.js.map +1 -1
- package/dist/components/scroller/scroller.styles.d.ts.map +1 -1
- package/dist/components/scroller/scroller.styles.js +18 -0
- package/dist/components/scroller/scroller.styles.js.map +1 -1
- package/dist/components/segmented/segmented.class.d.ts +1 -0
- package/dist/components/segmented/segmented.class.d.ts.map +1 -1
- package/dist/components/segmented/segmented.class.js +1 -0
- package/dist/components/segmented/segmented.class.js.map +1 -1
- package/dist/components/segmented/segmented.styles.d.ts.map +1 -1
- package/dist/components/segmented/segmented.styles.js +21 -3
- package/dist/components/segmented/segmented.styles.js.map +1 -1
- package/dist/components/sequence-strip/sequence-strip.class.d.ts +62 -0
- package/dist/components/sequence-strip/sequence-strip.class.d.ts.map +1 -0
- package/dist/components/sequence-strip/sequence-strip.class.js +102 -0
- package/dist/components/sequence-strip/sequence-strip.class.js.map +1 -0
- package/dist/components/sequence-strip/sequence-strip.d.ts +2 -0
- package/dist/components/sequence-strip/sequence-strip.d.ts.map +1 -0
- package/dist/components/sequence-strip/sequence-strip.js +5 -0
- package/dist/components/sequence-strip/sequence-strip.js.map +1 -0
- package/dist/components/sequence-strip/sequence-strip.styles.d.ts +2 -0
- package/dist/components/sequence-strip/sequence-strip.styles.d.ts.map +1 -0
- package/dist/components/sequence-strip/sequence-strip.styles.js +62 -0
- package/dist/components/sequence-strip/sequence-strip.styles.js.map +1 -0
- package/dist/components/skeleton/skeleton.styles.d.ts.map +1 -1
- package/dist/components/skeleton/skeleton.styles.js +7 -0
- package/dist/components/skeleton/skeleton.styles.js.map +1 -1
- package/dist/components/slider/slider.class.d.ts +6 -1
- package/dist/components/slider/slider.class.d.ts.map +1 -1
- package/dist/components/slider/slider.class.js +23 -6
- package/dist/components/slider/slider.class.js.map +1 -1
- package/dist/components/slider/slider.styles.d.ts.map +1 -1
- package/dist/components/slider/slider.styles.js +15 -0
- package/dist/components/slider/slider.styles.js.map +1 -1
- package/dist/components/source-picker/source-picker.class.d.ts +78 -0
- package/dist/components/source-picker/source-picker.class.d.ts.map +1 -0
- package/dist/components/source-picker/source-picker.class.js +305 -0
- package/dist/components/source-picker/source-picker.class.js.map +1 -0
- package/dist/components/source-picker/source-picker.d.ts +5 -0
- package/dist/components/source-picker/source-picker.d.ts.map +1 -0
- package/dist/components/source-picker/source-picker.js +8 -0
- package/dist/components/source-picker/source-picker.js.map +1 -0
- package/dist/components/source-picker/source-picker.styles.d.ts +2 -0
- package/dist/components/source-picker/source-picker.styles.d.ts.map +1 -0
- package/dist/components/source-picker/source-picker.styles.js +80 -0
- package/dist/components/source-picker/source-picker.styles.js.map +1 -0
- package/dist/components/span-waterfall/span-waterfall.class.d.ts +70 -0
- package/dist/components/span-waterfall/span-waterfall.class.d.ts.map +1 -0
- package/dist/components/span-waterfall/span-waterfall.class.js +307 -0
- package/dist/components/span-waterfall/span-waterfall.class.js.map +1 -0
- package/dist/components/span-waterfall/span-waterfall.d.ts +4 -0
- package/dist/components/span-waterfall/span-waterfall.d.ts.map +1 -0
- package/dist/components/span-waterfall/span-waterfall.js +7 -0
- package/dist/components/span-waterfall/span-waterfall.js.map +1 -0
- package/dist/components/span-waterfall/span-waterfall.styles.d.ts +2 -0
- package/dist/components/span-waterfall/span-waterfall.styles.d.ts.map +1 -0
- package/dist/components/span-waterfall/span-waterfall.styles.js +130 -0
- package/dist/components/span-waterfall/span-waterfall.styles.js.map +1 -0
- package/dist/components/sparkline/sparkline.class.d.ts.map +1 -1
- package/dist/components/sparkline/sparkline.class.js +17 -7
- package/dist/components/sparkline/sparkline.class.js.map +1 -1
- package/dist/components/split/split.class.d.ts +13 -0
- package/dist/components/split/split.class.d.ts.map +1 -1
- package/dist/components/split/split.class.js +24 -4
- package/dist/components/split/split.class.js.map +1 -1
- package/dist/components/spreadsheet-viewer/spreadsheet-loader.js +1 -1
- package/dist/components/spreadsheet-viewer/spreadsheet-loader.js.map +1 -1
- package/dist/components/spreadsheet-viewer/spreadsheet-viewer.class.d.ts +93 -3
- package/dist/components/spreadsheet-viewer/spreadsheet-viewer.class.d.ts.map +1 -1
- package/dist/components/spreadsheet-viewer/spreadsheet-viewer.class.js +241 -9
- package/dist/components/spreadsheet-viewer/spreadsheet-viewer.class.js.map +1 -1
- package/dist/components/spreadsheet-viewer/spreadsheet-viewer.js +10 -1
- package/dist/components/spreadsheet-viewer/spreadsheet-viewer.js.map +1 -1
- package/dist/components/stack-trace/stack-trace-parse.d.ts +22 -0
- package/dist/components/stack-trace/stack-trace-parse.d.ts.map +1 -0
- package/dist/components/stack-trace/stack-trace-parse.js +194 -0
- package/dist/components/stack-trace/stack-trace-parse.js.map +1 -0
- package/dist/components/stack-trace/stack-trace.class.d.ts +68 -0
- package/dist/components/stack-trace/stack-trace.class.d.ts.map +1 -0
- package/dist/components/stack-trace/stack-trace.class.js +193 -0
- package/dist/components/stack-trace/stack-trace.class.js.map +1 -0
- package/dist/components/stack-trace/stack-trace.d.ts +3 -0
- package/dist/components/stack-trace/stack-trace.d.ts.map +1 -0
- package/dist/components/stack-trace/stack-trace.js +6 -0
- package/dist/components/stack-trace/stack-trace.js.map +1 -0
- package/dist/components/stack-trace/stack-trace.styles.d.ts +2 -0
- package/dist/components/stack-trace/stack-trace.styles.d.ts.map +1 -0
- package/dist/components/stack-trace/stack-trace.styles.js +101 -0
- package/dist/components/stack-trace/stack-trace.styles.js.map +1 -0
- package/dist/components/stat/stat.class.d.ts +10 -1
- package/dist/components/stat/stat.class.d.ts.map +1 -1
- package/dist/components/stat/stat.class.js +22 -7
- package/dist/components/stat/stat.class.js.map +1 -1
- package/dist/components/stepper/stepper.class.d.ts +5 -0
- package/dist/components/stepper/stepper.class.d.ts.map +1 -1
- package/dist/components/stepper/stepper.class.js +9 -1
- package/dist/components/stepper/stepper.class.js.map +1 -1
- package/dist/components/stream-status/stream-status.class.d.ts.map +1 -1
- package/dist/components/stream-status/stream-status.class.js +9 -1
- package/dist/components/stream-status/stream-status.class.js.map +1 -1
- package/dist/components/streaming-text/streaming-text.class.d.ts +6 -0
- package/dist/components/streaming-text/streaming-text.class.d.ts.map +1 -1
- package/dist/components/streaming-text/streaming-text.class.js +22 -3
- package/dist/components/streaming-text/streaming-text.class.js.map +1 -1
- package/dist/components/suggestion-chips/suggestion-chips.class.d.ts +54 -0
- package/dist/components/suggestion-chips/suggestion-chips.class.d.ts.map +1 -0
- package/dist/components/suggestion-chips/suggestion-chips.class.js +120 -0
- package/dist/components/suggestion-chips/suggestion-chips.class.js.map +1 -0
- package/dist/components/suggestion-chips/suggestion-chips.d.ts +3 -0
- package/dist/components/suggestion-chips/suggestion-chips.d.ts.map +1 -0
- package/dist/components/suggestion-chips/suggestion-chips.js +6 -0
- package/dist/components/suggestion-chips/suggestion-chips.js.map +1 -0
- package/dist/components/suggestion-chips/suggestion-chips.styles.d.ts +2 -0
- package/dist/components/suggestion-chips/suggestion-chips.styles.d.ts.map +1 -0
- package/dist/components/suggestion-chips/suggestion-chips.styles.js +60 -0
- package/dist/components/suggestion-chips/suggestion-chips.styles.js.map +1 -0
- package/dist/components/svg-viewer/svg-viewer.class.d.ts +34 -0
- package/dist/components/svg-viewer/svg-viewer.class.d.ts.map +1 -1
- package/dist/components/svg-viewer/svg-viewer.class.js +88 -1
- package/dist/components/svg-viewer/svg-viewer.class.js.map +1 -1
- package/dist/components/svg-viewer/svg-viewer.js +1 -0
- package/dist/components/svg-viewer/svg-viewer.js.map +1 -1
- package/dist/components/svg-viewer/svg-viewer.styles.d.ts.map +1 -1
- package/dist/components/svg-viewer/svg-viewer.styles.js +18 -0
- package/dist/components/svg-viewer/svg-viewer.styles.js.map +1 -1
- package/dist/components/swatch-picker/swatch-picker.class.d.ts +18 -2
- package/dist/components/swatch-picker/swatch-picker.class.d.ts.map +1 -1
- package/dist/components/swatch-picker/swatch-picker.class.js +17 -3
- package/dist/components/swatch-picker/swatch-picker.class.js.map +1 -1
- package/dist/components/swatch-picker/swatch-picker.styles.d.ts.map +1 -1
- package/dist/components/swatch-picker/swatch-picker.styles.js +84 -8
- package/dist/components/swatch-picker/swatch-picker.styles.js.map +1 -1
- package/dist/components/table/table.class.d.ts +85 -5
- package/dist/components/table/table.class.d.ts.map +1 -1
- package/dist/components/table/table.class.js +254 -41
- package/dist/components/table/table.class.js.map +1 -1
- package/dist/components/table/table.styles.d.ts.map +1 -1
- package/dist/components/table/table.styles.js +35 -0
- package/dist/components/table/table.styles.js.map +1 -1
- package/dist/components/tabs/tabs.class.d.ts +6 -0
- package/dist/components/tabs/tabs.class.d.ts.map +1 -1
- package/dist/components/tabs/tabs.class.js +10 -1
- package/dist/components/tabs/tabs.class.js.map +1 -1
- package/dist/components/tabs/tabs.styles.d.ts.map +1 -1
- package/dist/components/tabs/tabs.styles.js +15 -0
- package/dist/components/tabs/tabs.styles.js.map +1 -1
- package/dist/components/task-list/task-list.class.d.ts +89 -0
- package/dist/components/task-list/task-list.class.d.ts.map +1 -0
- package/dist/components/task-list/task-list.class.js +271 -0
- package/dist/components/task-list/task-list.class.js.map +1 -0
- package/dist/components/task-list/task-list.d.ts +2 -0
- package/dist/components/task-list/task-list.d.ts.map +1 -0
- package/dist/components/task-list/task-list.js +5 -0
- package/dist/components/task-list/task-list.js.map +1 -0
- package/dist/components/task-list/task-list.styles.d.ts +2 -0
- package/dist/components/task-list/task-list.styles.d.ts.map +1 -0
- package/dist/components/task-list/task-list.styles.js +134 -0
- package/dist/components/task-list/task-list.styles.js.map +1 -0
- package/dist/components/terminal/terminal.class.d.ts +150 -0
- package/dist/components/terminal/terminal.class.d.ts.map +1 -0
- package/dist/components/terminal/terminal.class.js +565 -0
- package/dist/components/terminal/terminal.class.js.map +1 -0
- package/dist/components/terminal/terminal.d.ts +2 -0
- package/dist/components/terminal/terminal.d.ts.map +1 -0
- package/dist/components/terminal/terminal.js +5 -0
- package/dist/components/terminal/terminal.js.map +1 -0
- package/dist/components/terminal/terminal.styles.d.ts +2 -0
- package/dist/components/terminal/terminal.styles.d.ts.map +1 -0
- package/dist/components/terminal/terminal.styles.js +77 -0
- package/dist/components/terminal/terminal.styles.js.map +1 -0
- package/dist/components/test-results/test-results.class.d.ts +99 -0
- package/dist/components/test-results/test-results.class.d.ts.map +1 -0
- package/dist/components/test-results/test-results.class.js +276 -0
- package/dist/components/test-results/test-results.class.js.map +1 -0
- package/dist/components/test-results/test-results.d.ts +2 -0
- package/dist/components/test-results/test-results.d.ts.map +1 -0
- package/dist/components/test-results/test-results.js +5 -0
- package/dist/components/test-results/test-results.js.map +1 -0
- package/dist/components/test-results/test-results.styles.d.ts +2 -0
- package/dist/components/test-results/test-results.styles.d.ts.map +1 -0
- package/dist/components/test-results/test-results.styles.js +118 -0
- package/dist/components/test-results/test-results.styles.js.map +1 -0
- package/dist/components/textarea/textarea.class.d.ts.map +1 -1
- package/dist/components/textarea/textarea.class.js +4 -0
- package/dist/components/textarea/textarea.class.js.map +1 -1
- package/dist/components/thinking-panel/thinking-panel.class.d.ts +6 -0
- package/dist/components/thinking-panel/thinking-panel.class.d.ts.map +1 -1
- package/dist/components/thinking-panel/thinking-panel.class.js +12 -2
- package/dist/components/thinking-panel/thinking-panel.class.js.map +1 -1
- package/dist/components/thread-list/thread-list.class.d.ts +140 -0
- package/dist/components/thread-list/thread-list.class.d.ts.map +1 -0
- package/dist/components/thread-list/thread-list.class.js +488 -0
- package/dist/components/thread-list/thread-list.class.js.map +1 -0
- package/dist/components/thread-list/thread-list.d.ts +5 -0
- package/dist/components/thread-list/thread-list.d.ts.map +1 -0
- package/dist/components/thread-list/thread-list.js +8 -0
- package/dist/components/thread-list/thread-list.js.map +1 -0
- package/dist/components/thread-list/thread-list.styles.d.ts +2 -0
- package/dist/components/thread-list/thread-list.styles.d.ts.map +1 -0
- package/dist/components/thread-list/thread-list.styles.js +81 -0
- package/dist/components/thread-list/thread-list.styles.js.map +1 -0
- package/dist/components/time-range/time-range.class.d.ts.map +1 -1
- package/dist/components/time-range/time-range.class.js +3 -3
- package/dist/components/time-range/time-range.class.js.map +1 -1
- package/dist/components/timeline/timeline-item.class.d.ts.map +1 -1
- package/dist/components/timeline/timeline-item.class.js +2 -1
- package/dist/components/timeline/timeline-item.class.js.map +1 -1
- package/dist/components/toast/toast-item.class.d.ts +8 -0
- package/dist/components/toast/toast-item.class.d.ts.map +1 -1
- package/dist/components/toast/toast-item.class.js +14 -2
- package/dist/components/toast/toast-item.class.js.map +1 -1
- package/dist/components/toast/toast-item.styles.d.ts.map +1 -1
- package/dist/components/toast/toast-item.styles.js +2 -0
- package/dist/components/toast/toast-item.styles.js.map +1 -1
- package/dist/components/token-input/token-input.class.d.ts +29 -3
- package/dist/components/token-input/token-input.class.d.ts.map +1 -1
- package/dist/components/token-input/token-input.class.js +41 -13
- package/dist/components/token-input/token-input.class.js.map +1 -1
- package/dist/components/token-input/token-input.styles.d.ts.map +1 -1
- package/dist/components/token-input/token-input.styles.js +6 -1
- package/dist/components/token-input/token-input.styles.js.map +1 -1
- package/dist/components/tool-call-chip/tool-call-chip.class.d.ts +6 -0
- package/dist/components/tool-call-chip/tool-call-chip.class.d.ts.map +1 -1
- package/dist/components/tool-call-chip/tool-call-chip.class.js +15 -4
- package/dist/components/tool-call-chip/tool-call-chip.class.js.map +1 -1
- package/dist/components/tool-result-dialog/tool-result-dialog.class.d.ts +6 -0
- package/dist/components/tool-result-dialog/tool-result-dialog.class.d.ts.map +1 -1
- package/dist/components/tool-result-dialog/tool-result-dialog.class.js +12 -3
- package/dist/components/tool-result-dialog/tool-result-dialog.class.js.map +1 -1
- package/dist/components/tour/tour.class.d.ts +6 -3
- package/dist/components/tour/tour.class.d.ts.map +1 -1
- package/dist/components/tour/tour.class.js +56 -20
- package/dist/components/tour/tour.class.js.map +1 -1
- package/dist/components/trace-tree/span.d.ts +26 -0
- package/dist/components/trace-tree/span.d.ts.map +1 -0
- package/dist/components/trace-tree/span.js +2 -0
- package/dist/components/trace-tree/span.js.map +1 -0
- package/dist/components/trace-tree/trace-tree.class.d.ts +85 -0
- package/dist/components/trace-tree/trace-tree.class.d.ts.map +1 -0
- package/dist/components/trace-tree/trace-tree.class.js +443 -0
- package/dist/components/trace-tree/trace-tree.class.js.map +1 -0
- package/dist/components/trace-tree/trace-tree.d.ts +5 -0
- package/dist/components/trace-tree/trace-tree.d.ts.map +1 -0
- package/dist/components/trace-tree/trace-tree.js +8 -0
- package/dist/components/trace-tree/trace-tree.js.map +1 -0
- package/dist/components/trace-tree/trace-tree.styles.d.ts +2 -0
- package/dist/components/trace-tree/trace-tree.styles.d.ts.map +1 -0
- package/dist/components/trace-tree/trace-tree.styles.js +186 -0
- package/dist/components/trace-tree/trace-tree.styles.js.map +1 -0
- package/dist/components/transcript-feed/transcript-feed.class.d.ts +89 -0
- package/dist/components/transcript-feed/transcript-feed.class.d.ts.map +1 -0
- package/dist/components/transcript-feed/transcript-feed.class.js +188 -0
- package/dist/components/transcript-feed/transcript-feed.class.js.map +1 -0
- package/dist/components/transcript-feed/transcript-feed.d.ts +2 -0
- package/dist/components/transcript-feed/transcript-feed.d.ts.map +1 -0
- package/dist/components/transcript-feed/transcript-feed.js +5 -0
- package/dist/components/transcript-feed/transcript-feed.js.map +1 -0
- package/dist/components/transcript-feed/transcript-feed.styles.d.ts +2 -0
- package/dist/components/transcript-feed/transcript-feed.styles.d.ts.map +1 -0
- package/dist/components/transcript-feed/transcript-feed.styles.js +94 -0
- package/dist/components/transcript-feed/transcript-feed.styles.js.map +1 -0
- package/dist/components/tree/tree-node.class.d.ts +25 -4
- package/dist/components/tree/tree-node.class.d.ts.map +1 -1
- package/dist/components/tree/tree-node.class.js +61 -11
- package/dist/components/tree/tree-node.class.js.map +1 -1
- package/dist/components/tree/tree-node.styles.d.ts.map +1 -1
- package/dist/components/tree/tree-node.styles.js +34 -5
- package/dist/components/tree/tree-node.styles.js.map +1 -1
- package/dist/components/tree/tree.class.d.ts +9 -0
- package/dist/components/tree/tree.class.d.ts.map +1 -1
- package/dist/components/tree/tree.class.js.map +1 -1
- package/dist/components/usage-badge/usage-badge.class.d.ts +87 -0
- package/dist/components/usage-badge/usage-badge.class.d.ts.map +1 -0
- package/dist/components/usage-badge/usage-badge.class.js +246 -0
- package/dist/components/usage-badge/usage-badge.class.js.map +1 -0
- package/dist/components/usage-badge/usage-badge.d.ts +2 -0
- package/dist/components/usage-badge/usage-badge.d.ts.map +1 -0
- package/dist/components/usage-badge/usage-badge.js +5 -0
- package/dist/components/usage-badge/usage-badge.js.map +1 -0
- package/dist/components/usage-badge/usage-badge.styles.d.ts +2 -0
- package/dist/components/usage-badge/usage-badge.styles.d.ts.map +1 -0
- package/dist/components/usage-badge/usage-badge.styles.js +62 -0
- package/dist/components/usage-badge/usage-badge.styles.js.map +1 -0
- package/dist/components/virtual-list/virtual-list.class.d.ts +62 -0
- package/dist/components/virtual-list/virtual-list.class.d.ts.map +1 -1
- package/dist/components/virtual-list/virtual-list.class.js +123 -8
- package/dist/components/virtual-list/virtual-list.class.js.map +1 -1
- package/dist/components/voice-picker/voice-picker.class.d.ts +241 -0
- package/dist/components/voice-picker/voice-picker.class.d.ts.map +1 -0
- package/dist/components/voice-picker/voice-picker.class.js +808 -0
- package/dist/components/voice-picker/voice-picker.class.js.map +1 -0
- package/dist/components/voice-picker/voice-picker.d.ts +2 -0
- package/dist/components/voice-picker/voice-picker.d.ts.map +1 -0
- package/dist/components/voice-picker/voice-picker.js +5 -0
- package/dist/components/voice-picker/voice-picker.js.map +1 -0
- package/dist/components/voice-picker/voice-picker.styles.d.ts +2 -0
- package/dist/components/voice-picker/voice-picker.styles.d.ts.map +1 -0
- package/dist/components/voice-picker/voice-picker.styles.js +272 -0
- package/dist/components/voice-picker/voice-picker.styles.js.map +1 -0
- package/dist/components/widget-renderer/default-registry.d.ts +14 -0
- package/dist/components/widget-renderer/default-registry.d.ts.map +1 -0
- package/dist/components/widget-renderer/default-registry.js +43 -0
- package/dist/components/widget-renderer/default-registry.js.map +1 -0
- package/dist/components/widget-renderer/registry.d.ts +31 -0
- package/dist/components/widget-renderer/registry.d.ts.map +1 -0
- package/dist/components/widget-renderer/registry.js +23 -0
- package/dist/components/widget-renderer/registry.js.map +1 -0
- package/dist/components/widget-renderer/resolve.d.ts +48 -0
- package/dist/components/widget-renderer/resolve.d.ts.map +1 -0
- package/dist/components/widget-renderer/resolve.js +122 -0
- package/dist/components/widget-renderer/resolve.js.map +1 -0
- package/dist/components/widget-renderer/widget-renderer.class.d.ts +67 -0
- package/dist/components/widget-renderer/widget-renderer.class.d.ts.map +1 -0
- package/dist/components/widget-renderer/widget-renderer.class.js +175 -0
- package/dist/components/widget-renderer/widget-renderer.class.js.map +1 -0
- package/dist/components/widget-renderer/widget-renderer.d.ts +5 -0
- package/dist/components/widget-renderer/widget-renderer.d.ts.map +1 -0
- package/dist/components/widget-renderer/widget-renderer.js +10 -0
- package/dist/components/widget-renderer/widget-renderer.js.map +1 -0
- package/dist/components/widget-renderer/widget-renderer.styles.d.ts +2 -0
- package/dist/components/widget-renderer/widget-renderer.styles.d.ts.map +1 -0
- package/dist/components/widget-renderer/widget-renderer.styles.js +14 -0
- package/dist/components/widget-renderer/widget-renderer.styles.js.map +1 -0
- package/dist/components/word-cloud/word-cloud-layout.d.ts +4 -0
- package/dist/components/word-cloud/word-cloud-layout.d.ts.map +1 -1
- package/dist/components/word-cloud/word-cloud-layout.js +3 -2
- package/dist/components/word-cloud/word-cloud-layout.js.map +1 -1
- package/dist/components/word-cloud/word-cloud.class.d.ts.map +1 -1
- package/dist/components/word-cloud/word-cloud.class.js +11 -3
- package/dist/components/word-cloud/word-cloud.class.js.map +1 -1
- package/dist/components/xml-viewer/xml-viewer.class.d.ts +135 -0
- package/dist/components/xml-viewer/xml-viewer.class.d.ts.map +1 -0
- package/dist/components/xml-viewer/xml-viewer.class.js +0 -0
- package/dist/components/xml-viewer/xml-viewer.class.js.map +1 -0
- package/dist/components/xml-viewer/xml-viewer.d.ts +2 -0
- package/dist/components/xml-viewer/xml-viewer.d.ts.map +1 -0
- package/dist/components/xml-viewer/xml-viewer.js +20 -0
- package/dist/components/xml-viewer/xml-viewer.js.map +1 -0
- package/dist/components/xml-viewer/xml-viewer.styles.d.ts +2 -0
- package/dist/components/xml-viewer/xml-viewer.styles.d.ts.map +1 -0
- package/dist/components/xml-viewer/xml-viewer.styles.js +156 -0
- package/dist/components/xml-viewer/xml-viewer.styles.js.map +1 -0
- package/dist/components/zoomable-frame/zoomable-frame.class.d.ts +14 -2
- package/dist/components/zoomable-frame/zoomable-frame.class.d.ts.map +1 -1
- package/dist/components/zoomable-frame/zoomable-frame.class.js +30 -14
- package/dist/components/zoomable-frame/zoomable-frame.class.js.map +1 -1
- package/dist/internal/anchor-target.d.ts +49 -0
- package/dist/internal/anchor-target.d.ts.map +1 -0
- package/dist/internal/anchor-target.js +255 -0
- package/dist/internal/anchor-target.js.map +1 -0
- package/dist/internal/ansi.d.ts +35 -0
- package/dist/internal/ansi.d.ts.map +1 -0
- package/dist/internal/ansi.js +210 -0
- package/dist/internal/ansi.js.map +1 -0
- package/dist/internal/cell-range.d.ts +19 -0
- package/dist/internal/cell-range.d.ts.map +1 -0
- package/dist/internal/cell-range.js +69 -0
- package/dist/internal/cell-range.js.map +1 -0
- package/dist/internal/intl-cache.d.ts +33 -0
- package/dist/internal/intl-cache.d.ts.map +1 -0
- package/dist/internal/intl-cache.js +0 -0
- package/dist/internal/intl-cache.js.map +1 -0
- package/dist/internal/layered-layout.d.ts +44 -0
- package/dist/internal/layered-layout.d.ts.map +1 -0
- package/dist/internal/layered-layout.js +172 -0
- package/dist/internal/layered-layout.js.map +1 -0
- package/dist/internal/localization.d.ts +12 -1
- package/dist/internal/localization.d.ts.map +1 -1
- package/dist/internal/localization.js +366 -4
- package/dist/internal/localization.js.map +1 -1
- package/dist/internal/lyra-element.d.ts +10 -1
- package/dist/internal/lyra-element.d.ts.map +1 -1
- package/dist/internal/lyra-element.js +19 -1
- package/dist/internal/lyra-element.js.map +1 -1
- package/dist/internal/root-registration-allowlist.d.ts +2 -2
- package/dist/internal/root-registration-allowlist.d.ts.map +1 -1
- package/dist/internal/root-registration-allowlist.js +55 -0
- package/dist/internal/root-registration-allowlist.js.map +1 -1
- package/dist/internal/slugger.d.ts +11 -0
- package/dist/internal/slugger.d.ts.map +1 -0
- package/dist/internal/slugger.js +45 -0
- package/dist/internal/slugger.js.map +1 -0
- package/dist/internal/text-highlights.d.ts +21 -0
- package/dist/internal/text-highlights.d.ts.map +1 -0
- package/dist/internal/text-highlights.js +172 -0
- package/dist/internal/text-highlights.js.map +1 -0
- package/dist/internal/text-quote.d.ts +53 -0
- package/dist/internal/text-quote.d.ts.map +1 -0
- package/dist/internal/text-quote.js +326 -0
- package/dist/internal/text-quote.js.map +1 -0
- package/dist/internal/tokens.styles.d.ts.map +1 -1
- package/dist/internal/tokens.styles.js +49 -0
- package/dist/internal/tokens.styles.js.map +1 -1
- package/dist/internal/viewer-search.d.ts +18 -0
- package/dist/internal/viewer-search.d.ts.map +1 -0
- package/dist/internal/viewer-search.js +21 -0
- package/dist/internal/viewer-search.js.map +1 -0
- package/dist/lyra.d.ts +136 -2
- package/dist/lyra.d.ts.map +1 -1
- package/dist/lyra.js +109 -0
- package/dist/lyra.js.map +1 -1
- package/llms-full.txt +2713 -101
- package/llms.txt +28 -1
- package/package.json +135 -9
- package/vscode-css-data.json +224 -0
- package/vscode-html-data.json +5309 -2225
- package/web-types.json +5803 -2513
|
@@ -5,16 +5,30 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { html, nothing, svg } from 'lit';
|
|
8
|
-
import { property, state } from 'lit/decorators.js';
|
|
8
|
+
import { property, state, query } from 'lit/decorators.js';
|
|
9
9
|
import { styleMap } from 'lit/directives/style-map.js';
|
|
10
10
|
import { LyraElement } from '../../internal/lyra-element.js';
|
|
11
11
|
import { nextId, srOnly } from '../../internal/a11y.js';
|
|
12
12
|
import { prefersReducedMotion } from '../../internal/motion.js';
|
|
13
13
|
import { isRtl } from '../../internal/rtl.js';
|
|
14
|
+
import { getScratchCtx } from '../../internal/canvas.js';
|
|
14
15
|
import { styles } from './graph.styles.js';
|
|
15
16
|
import { loadD3 } from './graph-loader.js';
|
|
17
|
+
import { convexHull, hullPathD, hullCentroidX, hullTopY } from './graph-hull.js';
|
|
18
|
+
import { drawGraphScene, drawPickingScene, pickColorToIndex } from './graph-canvas.js';
|
|
19
|
+
import { layeredLayout } from '../../internal/layered-layout.js';
|
|
20
|
+
import { finiteNumber, finiteRange, finiteInteger } from '../../internal/numbers.js';
|
|
16
21
|
import '../skeleton/skeleton.class.js';
|
|
17
22
|
const STUB_OFFSET_PX = 14; // matches the length of a typical broken-link stub in comparable UIs
|
|
23
|
+
const EDGE_LABEL_OFFSET_PX = 4; // perpendicular offset from the segment midpoint, in world px
|
|
24
|
+
const EDGE_LABEL_LENGTH_GATE_RATIO = 0.85; // label hides when its measured width exceeds this * edge length
|
|
25
|
+
const EDGE_LABEL_WIDTH_CACHE_MAX = 512; // distinct measured label texts kept before the oldest entry is evicted
|
|
26
|
+
const EXPAND_KEY_INTERVAL_MS = 500; // window for a double-Enter/Space to count as a double-activate
|
|
27
|
+
const EXPAND_BADGE_R = 5; // world px, the "+" badge circle radius
|
|
28
|
+
const EXPAND_BADGE_OFFSET = Math.SQRT1_2; // places the badge at the node's edge, diagonally upper-right
|
|
29
|
+
const FOCUS_HALO_PADDING = 6; // world px added to the node's own radius for the halo ring
|
|
30
|
+
const HULL_PADDING = 24; // world px; CSS mirrors this via stroke-width: 2 * --lyra-size-24px
|
|
31
|
+
const CANVAS_NODE_LABEL_MIN_ZOOM = 0.5; // canvas-only declutter -- node labels draw only at/above this scale
|
|
18
32
|
/**
|
|
19
33
|
* Tiny deterministic PRNG (mulberry32, public-domain) used only when `seed`
|
|
20
34
|
* is set, so a node's initial x/y is reproducible instead of whatever
|
|
@@ -65,6 +79,29 @@ function normalizeLinkDash(dash) {
|
|
|
65
79
|
return undefined;
|
|
66
80
|
return dash.join(' ');
|
|
67
81
|
}
|
|
82
|
+
/** Assigns a typed node with no explicit color a slot from the ordered categorical fallback
|
|
83
|
+
* palette, cycling every 8 entries (`--lyra-graph-cat-1`…`--lyra-graph-cat-8`). `index` is the
|
|
84
|
+
* node's `GraphNodeType`'s position in `nodeTypes`, not the node's own index in `nodes`. */
|
|
85
|
+
function categoricalPaletteColor(index) {
|
|
86
|
+
return `var(--lyra-graph-cat-${(index % 8) + 1})`;
|
|
87
|
+
}
|
|
88
|
+
/** side = r * sqrt(pi), area-matched to a circle of radius r (side^2 = pi*r^2). Half-side is what
|
|
89
|
+
* the path data actually needs, since both shapes are drawn centered on the origin and
|
|
90
|
+
* positioned via a `transform="translate(x,y)"` per tick, never via absolute cx/cy. */
|
|
91
|
+
function shapeHalfSide(r) {
|
|
92
|
+
return (r * Math.sqrt(Math.PI)) / 2;
|
|
93
|
+
}
|
|
94
|
+
/** A square, centered on the origin, side ~= 1.772 * r (area-matched to the circle of radius r). */
|
|
95
|
+
function squarePath(r) {
|
|
96
|
+
const s = shapeHalfSide(r);
|
|
97
|
+
return `M ${-s} ${-s} L ${s} ${-s} L ${s} ${s} L ${-s} ${s} Z`;
|
|
98
|
+
}
|
|
99
|
+
/** The same square as `squarePath()`, rotated 45 degrees: same side length, vertices at the
|
|
100
|
+
* half-diagonal distance (s * sqrt(2)) along each axis instead of the square's own corners. */
|
|
101
|
+
function diamondPath(r) {
|
|
102
|
+
const d = shapeHalfSide(r) * Math.SQRT2;
|
|
103
|
+
return `M 0 ${-d} L ${d} 0 L 0 ${d} L ${-d} 0 Z`;
|
|
104
|
+
}
|
|
68
105
|
/**
|
|
69
106
|
* `<lyra-graph>` — a force-directed node-link diagram with pan/zoom/drag.
|
|
70
107
|
* Requires the optional peer deps `d3-force`/`d3-drag`/`d3-zoom`/`d3-selection`
|
|
@@ -80,26 +117,117 @@ function normalizeLinkDash(dash) {
|
|
|
80
117
|
* already-rendered graph is a no-op; nothing re-derives already-positioned
|
|
81
118
|
* nodes' x/y from the new value.
|
|
82
119
|
*
|
|
120
|
+
* `hiddenTypes` filters nodes/links by `GraphNode.type` without discarding position state --
|
|
121
|
+
* `lastPositionById` remembers every node's last settled x/y across a hide/show round-trip, so
|
|
122
|
+
* toggling a type off and back on restores each node where it was instead of re-randomizing it.
|
|
123
|
+
*
|
|
124
|
+
* `communities` draws one translucent convex-hull blob per entry, behind links/nodes -- a hull's
|
|
125
|
+
* membership is the union of its own `memberIds` and every node whose `communityId` matches its
|
|
126
|
+
* `id`. A community with no currently-visible members (all its nodes hidden by `hiddenTypes`, or
|
|
127
|
+
* simply empty) renders no hull.
|
|
128
|
+
*
|
|
129
|
+
* `layout="layered"` swaps the d3-force simulation for a deterministic layered layout (see
|
|
130
|
+
* `src/internal/layered-layout.ts`) -- node drag is disabled in that mode, and `chargeStrength` is
|
|
131
|
+
* a documented no-op.
|
|
132
|
+
*
|
|
133
|
+
* `renderer="canvas"` swaps the per-node/per-link SVG DOM for a single DPR-aware `<canvas>` --
|
|
134
|
+
* every event/method/property behaves identically to `renderer="svg"` (the default), with hit-
|
|
135
|
+
* testing resolved via an offscreen color-picking canvas instead of DOM event targets. The
|
|
136
|
+
* documented trade-offs: no `::part(node)`/`::part(link)` styling (pixels, not elements -- theme
|
|
137
|
+
* via cssprops instead), no native SVG `<title>` tooltip (replaced by `part="tooltip"`), and a
|
|
138
|
+
* drawn focus ring instead of a CSS one. Keyboard roving/announcements are preserved through an
|
|
139
|
+
* offscreen `part="cursor-item"` button per node/link/hull, driving the identical roving-tabindex
|
|
140
|
+
* logic as `renderer="svg"`.
|
|
141
|
+
*
|
|
83
142
|
* @customElement lyra-graph
|
|
84
|
-
* @event lyra-node-click - `detail: { id }
|
|
143
|
+
* @event lyra-node-click - `detail: { id, x, y }`, where `x` and `y` are the
|
|
144
|
+
* node's current coordinates in the graph's local drawing space.
|
|
85
145
|
* @event lyra-link-click - `detail: { source, target, id? }`.
|
|
146
|
+
* @event lyra-node-enter - A node was hovered. `detail: { id }`. Suppressed while dragging or
|
|
147
|
+
* panning. Also toggles a `data-hovered` attribute on that node's `[part="node"]` element for
|
|
148
|
+
* pure-CSS theming (not a substitute for this event — a consumer computing its own
|
|
149
|
+
* adjacency-based highlight needs the id, which only the event carries).
|
|
150
|
+
* @event lyra-node-leave - The hover from `lyra-node-enter` ended. `detail: { id }`.
|
|
151
|
+
* @event lyra-link-enter - A link was hovered. `detail: { source, target, id? }`. Same
|
|
152
|
+
* suppression/`data-hovered` behavior as `lyra-node-enter`.
|
|
153
|
+
* @event lyra-link-leave - The hover from `lyra-link-enter` ended. `detail: { source, target, id?
|
|
154
|
+
* }`.
|
|
155
|
+
* @event lyra-node-expand - A node was double-activated (native `dblclick`, or two Enter/Space
|
|
156
|
+
* activations of the same focused node within 500ms). `detail: { id }`. Fires for any node
|
|
157
|
+
* regardless of `GraphNode.expandable` -- that flag only controls the visual "+" affordance and
|
|
158
|
+
* spoken "expandable" suffix.
|
|
159
|
+
* @event lyra-selection-change - `detail: { nodeIds, linkIds }`. Fires when `selectionMode` is not
|
|
160
|
+
* `'none'` and the user activates/clears a node or link. The component never assigns
|
|
161
|
+
* `selectedNodeIds`/`selectedLinkIds` itself -- controlled, mirroring `lyra-heatmap.selectedCell`.
|
|
162
|
+
* @event lyra-community-click - A hull was activated. `detail: { id }`.
|
|
86
163
|
* @csspart base - The graph wrapper.
|
|
87
164
|
* @csspart svg - The graph SVG.
|
|
88
165
|
* @csspart node - A graph node.
|
|
89
166
|
* @csspart link - A graph link.
|
|
90
167
|
* @csspart arrowhead - The marker used by directed graph links.
|
|
91
168
|
* @csspart label - A node label.
|
|
169
|
+
* @csspart link-label - A drawn edge label (only rendered when `showEdgeLabels` is set).
|
|
170
|
+
* @csspart expand-indicator - The "+" badge rendered on a node with `expandable: true`.
|
|
171
|
+
* @csspart focus-halo - The persistent ring tracking `focusId`'s node.
|
|
172
|
+
* @csspart hull - A community hull (behind links/nodes; role="button").
|
|
173
|
+
* @csspart community-label - A hull's label text.
|
|
92
174
|
* @csspart live-region - The current graph item announcement.
|
|
93
175
|
* @csspart data-list - A visually hidden list alternative for graph data.
|
|
94
176
|
* @csspart empty - The empty-state message, shown when `nodes` is empty.
|
|
177
|
+
* @csspart canvas - The single canvas surface (`renderer="canvas"` only).
|
|
178
|
+
* @csspart tooltip - The hover tooltip (`renderer="canvas"` only; the SVG `<title>` replacement).
|
|
179
|
+
* @csspart cursor-items - The container of offscreen keyboard-roving items (`renderer="canvas"` only).
|
|
180
|
+
* @csspart cursor-item - An offscreen keyboard-roving item (`renderer="canvas"`'s a11y virtual cursor).
|
|
95
181
|
* @cssprop [--lyra-node-fill=var(--lyra-color-brand)] - Default node fill, overridden per-node by `GraphNode.color`.
|
|
96
182
|
* @cssprop [--lyra-link-color=var(--lyra-color-border)] - Default link stroke, overridden per-link by a link's own `color`.
|
|
183
|
+
* @cssprop [--lyra-graph-cat-1..8] - Ordered categorical fallback palette for a typed node with no
|
|
184
|
+
* `GraphNodeType.color`, assigned by the type's index in `nodeTypes` (wraps every 8 entries).
|
|
185
|
+
* Declared centrally in `tokens.styles.ts` so `<lyra-graph>` and any future `<lyra-graph-legend>`-
|
|
186
|
+
* style component resolve the identical default.
|
|
187
|
+
* @cssprop [--lyra-graph-edge-label-halo=var(--lyra-color-surface)] - Legibility halo (`stroke`)
|
|
188
|
+
* behind a drawn edge label, painted under the fill via `paint-order: stroke`.
|
|
189
|
+
* @cssprop [--lyra-graph-focus-halo-color=var(--lyra-color-brand)] - `focus-halo` stroke color.
|
|
190
|
+
* @cssprop [--lyra-graph-selected-color=var(--lyra-color-success)] - Selected node/link stroke.
|
|
191
|
+
* @cssprop [--lyra-graph-dimmed-opacity=1] - Opacity applied to a node/link when
|
|
192
|
+
* `dimmedNodeIds`/`dimmedLinkIds` includes its id (both SVG and canvas renderers). `1` (the
|
|
193
|
+
* default) is a no-op -- an unset host sees no visual change.
|
|
194
|
+
* @cssprop [--lyra-graph-hull-fill=var(--lyra-color-brand)] - Hull fill/stroke color.
|
|
195
|
+
* @cssprop [--lyra-graph-hull-opacity=0.12] - Hull element opacity (composites fill+stroke as one
|
|
196
|
+
* group, avoiding a double-opacity seam at the fill/stroke boundary).
|
|
97
197
|
*/
|
|
98
198
|
export class LyraGraph extends LyraElement {
|
|
99
199
|
constructor() {
|
|
100
200
|
super(...arguments);
|
|
101
201
|
this.nodes = [];
|
|
102
202
|
this.links = [];
|
|
203
|
+
/** Declares each `GraphNode.type` value's legend label, fill color, and shape. A typed node with
|
|
204
|
+
* no matching entry here renders as untyped (default circle, token fill) but still participates
|
|
205
|
+
* in `hiddenTypes` filtering by its raw `type` string. */
|
|
206
|
+
this.nodeTypes = [];
|
|
207
|
+
/** Hides every node whose raw `type` value is listed here (no matching `nodeTypes` entry
|
|
208
|
+
* required), plus every link incident to a hidden node -- removed from the render, the
|
|
209
|
+
* simulation input, the keyboard roving ring, the sr-only data list, and the accessible
|
|
210
|
+
* diagram counts, as if absent. Positions round-trip via `lastPositionById`: toggling a type
|
|
211
|
+
* off and back on restores each node where it was. */
|
|
212
|
+
this.hiddenTypes = [];
|
|
213
|
+
/** Renders one translucent hull per entry, behind links/nodes. Membership is the union of
|
|
214
|
+
* `memberIds` and every node whose `communityId` matches this entry's `id`. */
|
|
215
|
+
this.communities = [];
|
|
216
|
+
/** `'force'` (default) runs the existing d3-force simulation, untouched. `'layered'` computes a
|
|
217
|
+
* deterministic Sugiyama-lite layout (`src/internal/layered-layout.ts`, a shared,
|
|
218
|
+
* dependency-free util suitable for any future layered-diagram consumer) instead -- no settle
|
|
219
|
+
* animation, node drag disabled (dragging would fight a computed layout), `chargeStrength` a
|
|
220
|
+
* documented no-op, `linkDistance` retunes the layer gap. Switching at runtime repositions
|
|
221
|
+
* without a tween. */
|
|
222
|
+
this.layout = 'force';
|
|
223
|
+
/** `'svg'` (default, unchanged) renders the existing per-node/per-link DOM. `'canvas'` swaps to
|
|
224
|
+
* a single `<canvas part="canvas">` -- the scale path (an honest ceiling for `'svg'`: dozens to
|
|
225
|
+
* low hundreds of nodes; `'canvas'` targets roughly 5,000 nodes / 10,000 links). Feature-reduced
|
|
226
|
+
* by design: no `::part(node)`/`::part(link)` styling (pixels, not elements -- theme via
|
|
227
|
+
* cssprops), no SVG `<title>`, a drawn focus ring instead of a CSS one. All events/methods/
|
|
228
|
+
* props otherwise behave identically across renderers. Runtime changes tear down and rebuild
|
|
229
|
+
* the surface; positions survive via `prevById`/`lastPositionById`. */
|
|
230
|
+
this.renderer = 'svg';
|
|
103
231
|
this.width = 800;
|
|
104
232
|
this.height = 600;
|
|
105
233
|
this.chargeStrength = -300;
|
|
@@ -108,12 +236,52 @@ export class LyraGraph extends LyraElement {
|
|
|
108
236
|
this.maxZoom = 8;
|
|
109
237
|
/** Accessible name forwarded from the host to the semantic graph SVG. */
|
|
110
238
|
this.accessibleLabel = null;
|
|
239
|
+
/** Draws each resolved (non-dangling) link's `label` as visible SVG text at the segment
|
|
240
|
+
* midpoint. Off by default — `GraphLink.label` stays spoken/tooltip-only, matching today's
|
|
241
|
+
* behavior, unless this is set. */
|
|
242
|
+
this.showEdgeLabels = false;
|
|
243
|
+
/** Below this zoom scale, every drawn edge label is hidden (a `data-edge-labels-hidden`
|
|
244
|
+
* attribute toggled on the zoomed `<g>`, no Lit re-render). Ignored when `showEdgeLabels` is
|
|
245
|
+
* false. */
|
|
246
|
+
this.edgeLabelMinZoom = 0.6;
|
|
247
|
+
/** Declaratively centers the camera on this node id once, the first time it resolves (on mount
|
|
248
|
+
* or when the id first appears in `nodes`) -- does not re-center on later mutations, so it
|
|
249
|
+
* can't fight a user's panning on a streaming graph. Renders a persistent halo
|
|
250
|
+
* (`part="focus-halo"`) around the node while set. See `focusNode()` for the imperative twin. */
|
|
251
|
+
this.focusId = null;
|
|
252
|
+
/** `'none'` (default) preserves today's behavior exactly -- no `aria-pressed`/`data-selected`,
|
|
253
|
+
* no `lyra-selection-change`. Controlled, mirroring `lyra-heatmap.selectedCell`: the component
|
|
254
|
+
* never mutates `selectedNodeIds`/`selectedLinkIds` itself, only emits intent; the host assigns
|
|
255
|
+
* them back. */
|
|
256
|
+
this.selectionMode = 'none';
|
|
257
|
+
this.selectedNodeIds = [];
|
|
258
|
+
this.selectedLinkIds = [];
|
|
259
|
+
/** Node ids to render dimmed (`data-dimmed` on the matching `[part="node"]`, themeable via
|
|
260
|
+
* `--lyra-graph-dimmed-opacity`). Controlled, mirroring `selectedNodeIds`/`selectedLinkIds`: the
|
|
261
|
+
* component never assigns this itself, only renders it -- a host typically computes it from a
|
|
262
|
+
* `lyra-node-enter`/`lyra-link-enter` hover (the complement of the hovered id's neighbor set,
|
|
263
|
+
* computed from the host's own `links` array) and assigns the result back. Empty (the default)
|
|
264
|
+
* renders every node at full opacity, unchanged from today. */
|
|
265
|
+
this.dimmedNodeIds = [];
|
|
266
|
+
/** Same contract as `dimmedNodeIds`, for links. A link's dimming key is the same `linkKey()`
|
|
267
|
+
* value (`GraphLink.id`, else `` `${source}->${target}` ``) `selectedLinkIds` already uses. */
|
|
268
|
+
this.dimmedLinkIds = [];
|
|
111
269
|
this.arrowMarkerId = nextId('graph-arrow');
|
|
112
270
|
/** True until the lazy-loaded d3 peer dependencies have settled (success or failure). */
|
|
113
271
|
this.loading = true;
|
|
114
272
|
this.simNodes = [];
|
|
115
273
|
this.simLinks = [];
|
|
116
274
|
this.danglingLinks = [];
|
|
275
|
+
/** Every node's last-known settled position, keyed by id, independent of current visibility --
|
|
276
|
+
* consulted by `rebuildSimulation()` (after the existing carried-over-position map) so a
|
|
277
|
+
* `hiddenTypes` toggle restores a node where it was instead of re-randomizing it. Pruned to ids
|
|
278
|
+
* present in `this.nodes` (not just currently-visible ones) on every rebuild. */
|
|
279
|
+
this.lastPositionById = new Map();
|
|
280
|
+
/** The `hiddenNodeCount` computed by the most recent `rebuildSimulation()` -- lets that method
|
|
281
|
+
* tell "nothing has ever been hidden" (never touch `graphLiveText`, so a consumer that never
|
|
282
|
+
* sets `hiddenTypes` keeps today's exact live-region output) apart from "a hide was just
|
|
283
|
+
* cleared" (still announce the resulting "0 of N" count). */
|
|
284
|
+
this.lastHiddenNodeCount = 0;
|
|
117
285
|
/** One roving tab stop across all nodes and links; nodes are the initial entry order. */
|
|
118
286
|
this.activeGraphItem = 0;
|
|
119
287
|
this.graphLiveText = '';
|
|
@@ -126,11 +294,165 @@ export class LyraGraph extends LyraElement {
|
|
|
126
294
|
* simNodes/simLinks properties (see rebuildSimulation()'s doc comment). */
|
|
127
295
|
this.nodeEls = [];
|
|
128
296
|
this.nodeLabelEls = [];
|
|
297
|
+
this.expandIndicatorEls = [];
|
|
298
|
+
/** Tracks the index/time of the last Enter/Space activation, for double-Enter expand detection
|
|
299
|
+
* (mirroring native dblclick semantics for keyboard users). */
|
|
300
|
+
this.lastKeyActivateIndex = null;
|
|
301
|
+
this.lastKeyActivateTime = 0;
|
|
302
|
+
/** The last `focusId` value `focusNode()` was auto-invoked for by `updated()`'s declarative
|
|
303
|
+
* centering branch -- guards against re-centering on every update while `focusId` stays set
|
|
304
|
+
* (see the `focusId` property doc for why it only ever centers once per value). Reset to `null`
|
|
305
|
+
* whenever `focusId` itself is cleared, so the same id can center again later. */
|
|
306
|
+
this.lastAppliedFocusId = null;
|
|
307
|
+
this.communityHullEls = [];
|
|
308
|
+
this.communityLabelEls = [];
|
|
309
|
+
this.pickDirty = true;
|
|
310
|
+
this.canvasCamera = { k: 1, x: 0, y: 0 };
|
|
311
|
+
/** Flat, index-aligned list matching `drawPickingScene()`'s own hulls-then-links-then-nodes pick
|
|
312
|
+
* order -- rebuilt by `redrawPickCanvas()` alongside the pick canvas itself, so a pick color's
|
|
313
|
+
* decoded index always maps back to the exact item it was drawn for. */
|
|
314
|
+
this.pickItems = [];
|
|
315
|
+
/** Whether `canvasScene` was built with edge labels included -- the zoom gate makes the scene
|
|
316
|
+
* camera-dependent at exactly two thresholds (`edgeLabelMinZoom`, `CANVAS_NODE_LABEL_MIN_ZOOM`),
|
|
317
|
+
* so a camera-only draw that crosses either must rebuild instead of reusing the cache. */
|
|
318
|
+
this.canvasSceneHasEdgeLabels = false;
|
|
319
|
+
/** True for a camera tween's whole duration (set before its first frame, cleared on
|
|
320
|
+
* resolution) -- `isPanning` alone doesn't cover this: `applyZoomTransform()`'s per-frame
|
|
321
|
+
* `zoomBehavior.transform()` call on a non-transition selection fires d3-zoom's
|
|
322
|
+
* start/zoom/end synchronously within that single call, so `isPanning` flips true-then-false
|
|
323
|
+
* within one frame rather than staying true for the tween's real duration the way an actual
|
|
324
|
+
* user gesture does. */
|
|
325
|
+
this.isCameraTweening = false;
|
|
129
326
|
this.linkEls = [];
|
|
327
|
+
this.linkLabelEls = [];
|
|
328
|
+
/** Per-simLink-index flip cache for the length declutter gate -- `onTick()` only writes
|
|
329
|
+
* `visibility` when the boolean actually changes, not every tick. */
|
|
330
|
+
this.linkLabelHiddenByLength = [];
|
|
331
|
+
this.edgeLabelWidthCache = new Map();
|
|
130
332
|
/** Dangling-stub `<line>`s, index-aligned with `danglingLinks` -- cached separately from
|
|
131
333
|
* `linkEls` (real, simulated links only) so onTick() can write their positions too; see
|
|
132
334
|
* onTick()'s own comment for why a stub needs this at all. */
|
|
133
335
|
this.danglingLinkEls = [];
|
|
336
|
+
/** Writing a transform on a plain (non-transition) selection makes d3-zoom fire its own
|
|
337
|
+
* start/zoom/end sequence synchronously, in this same call -- `isApplyingZoomTransform` lets
|
|
338
|
+
* the zoom `'start'` handler tell that self-triggered echo apart from a genuine external
|
|
339
|
+
* gesture, so a camera tween's own per-frame write doesn't cancel itself. */
|
|
340
|
+
this.isApplyingZoomTransform = false;
|
|
341
|
+
this.onCanvasDprChange = () => {
|
|
342
|
+
this.watchCanvasDpr();
|
|
343
|
+
this.markCanvasDirty();
|
|
344
|
+
};
|
|
345
|
+
this.onCanvasPointerDown = (e) => {
|
|
346
|
+
if (e.button !== 0)
|
|
347
|
+
return; // primary button only, matching native `click`'s own semantics
|
|
348
|
+
this.canvasPointerDownAt = { x: e.clientX, y: e.clientY };
|
|
349
|
+
if (this.layout === 'layered')
|
|
350
|
+
return; // drag disabled in layered mode, same as svg mode
|
|
351
|
+
const hit = this.hitTest(e.clientX, e.clientY);
|
|
352
|
+
if (hit?.kind === 'node') {
|
|
353
|
+
this.canvasDragNode = hit.node;
|
|
354
|
+
this.canvasPointerId = e.pointerId;
|
|
355
|
+
this.canvasEl.setPointerCapture(e.pointerId);
|
|
356
|
+
hit.node.fx = hit.node.x;
|
|
357
|
+
hit.node.fy = hit.node.y;
|
|
358
|
+
this.simulation?.alphaTarget(0.3).restart();
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
this.onCanvasPointerMove = (e) => {
|
|
362
|
+
if (this.canvasDragNode && this.canvasPointerId === e.pointerId) {
|
|
363
|
+
const rect = this.canvasEl.getBoundingClientRect();
|
|
364
|
+
this.canvasDragNode.fx = (e.clientX - rect.left - this.canvasCamera.x) / this.canvasCamera.k;
|
|
365
|
+
this.canvasDragNode.fy = (e.clientY - rect.top - this.canvasCamera.y) / this.canvasCamera.k;
|
|
366
|
+
this.markCanvasDirty();
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
// Coalesce hover hit-testing to one per animation frame (see pendingHover's doc) -- only the
|
|
370
|
+
// latest position matters, and running the readback-per-pointermove would multiply the cost
|
|
371
|
+
// by however many moves the browser delivers between paints.
|
|
372
|
+
this.pendingHover = { x: e.clientX, y: e.clientY };
|
|
373
|
+
if (this.hoverRafId != null)
|
|
374
|
+
return;
|
|
375
|
+
this.hoverRafId = requestAnimationFrame(() => {
|
|
376
|
+
this.hoverRafId = undefined;
|
|
377
|
+
const pending = this.pendingHover;
|
|
378
|
+
this.pendingHover = undefined;
|
|
379
|
+
if (!pending)
|
|
380
|
+
return;
|
|
381
|
+
// While the force simulation is still ticking, every tick invalidates the pick canvas, so
|
|
382
|
+
// resolving hover here would re-render the full offscreen picking scene once per frame on
|
|
383
|
+
// top of the per-tick visible redraw -- and the result would be stale a frame later anyway,
|
|
384
|
+
// since positions are still moving. Defer hover resolution until the layout settles; the
|
|
385
|
+
// next pointermove after that picks it up.
|
|
386
|
+
if (this.pickDirty && this.simulationIsTicking())
|
|
387
|
+
return;
|
|
388
|
+
const hit = this.hitTest(pending.x, pending.y);
|
|
389
|
+
this.updateCanvasTooltip(hit, pending.x, pending.y);
|
|
390
|
+
});
|
|
391
|
+
};
|
|
392
|
+
this.onCanvasPointerUp = (e) => {
|
|
393
|
+
// Starting a drag on a node (onCanvasPointerDown) and ending it here without ever crossing the
|
|
394
|
+
// move-distance threshold below is exactly a plain click -- release the drag state first, but
|
|
395
|
+
// keep going into the same click-vs-drag distance check every pointerup goes through, instead
|
|
396
|
+
// of returning early and silently swallowing the click. This mirrors svg mode, where a plain
|
|
397
|
+
// click on a node fires both d3-drag's own start/end (a no-op, since fx/fy never actually
|
|
398
|
+
// moved) and the browser's native `click` event -- the two aren't mutually exclusive there
|
|
399
|
+
// either.
|
|
400
|
+
if (this.canvasDragNode && this.canvasPointerId === e.pointerId) {
|
|
401
|
+
this.simulation?.alphaTarget(0);
|
|
402
|
+
this.canvasDragNode.fx = null;
|
|
403
|
+
this.canvasDragNode.fy = null;
|
|
404
|
+
this.canvasDragNode = undefined;
|
|
405
|
+
this.canvasPointerId = undefined;
|
|
406
|
+
this.markCanvasDirty();
|
|
407
|
+
}
|
|
408
|
+
const down = this.canvasPointerDownAt;
|
|
409
|
+
this.canvasPointerDownAt = undefined;
|
|
410
|
+
if (!down)
|
|
411
|
+
return;
|
|
412
|
+
if (Math.hypot(e.clientX - down.x, e.clientY - down.y) > 5)
|
|
413
|
+
return; // a pan/drag gesture, not a click
|
|
414
|
+
const hit = this.hitTest(e.clientX, e.clientY);
|
|
415
|
+
if (!hit) {
|
|
416
|
+
this.clearSelection();
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
if (hit.kind === 'node')
|
|
420
|
+
this.onNodeClick(hit.node, e);
|
|
421
|
+
else if (hit.kind === 'link')
|
|
422
|
+
this.onLinkClick(hit.link, e);
|
|
423
|
+
else
|
|
424
|
+
this.onCommunityClick(hit.entry.community);
|
|
425
|
+
};
|
|
426
|
+
this.onCanvasPointerLeave = () => {
|
|
427
|
+
// Drop any coalesced hover still waiting on its frame -- letting it run after the pointer
|
|
428
|
+
// already left would re-show the tooltip this handler is about to hide.
|
|
429
|
+
this.pendingHover = undefined;
|
|
430
|
+
if (this.hoverRafId != null) {
|
|
431
|
+
cancelAnimationFrame(this.hoverRafId);
|
|
432
|
+
this.hoverRafId = undefined;
|
|
433
|
+
}
|
|
434
|
+
this.updateCanvasTooltip(undefined, 0, 0);
|
|
435
|
+
};
|
|
436
|
+
this.onCanvasDblClick = (e) => {
|
|
437
|
+
const hit = this.hitTest(e.clientX, e.clientY);
|
|
438
|
+
const node = hit?.kind === 'node' ? hit.node : this.nodeAtCanvasPoint(e.clientX, e.clientY);
|
|
439
|
+
if (!node)
|
|
440
|
+
return; // background dblclick still reaches d3-zoom's own zoom-in, same as svg mode
|
|
441
|
+
// d3-zoom's own default double-click-to-zoom-in handler is bound to this identical <canvas>
|
|
442
|
+
// element (not an ancestor, so plain stopPropagation() -- which only blocks *bubbling*, not a
|
|
443
|
+
// sibling listener on the very same target -- would not suppress it). Matches svg mode's own
|
|
444
|
+
// onNodeDblClick(), which stops the equivalent bubble-phase echo on the svg one level up.
|
|
445
|
+
e.stopImmediatePropagation();
|
|
446
|
+
this.emit('lyra-node-expand', { id: node.id });
|
|
447
|
+
};
|
|
448
|
+
/** Suppresses hover events/`data-hovered` while a node drag is in progress (tracked from the
|
|
449
|
+
* existing d3-drag `.on('start')`/`.on('end')` handlers in `applyInteractions()`) — a drag
|
|
450
|
+
* crossing over other nodes/links would otherwise spam enter/leave pairs unrelated to genuine
|
|
451
|
+
* pointer hovering. */
|
|
452
|
+
this.isDragging = false;
|
|
453
|
+
/** Same purpose as `isDragging`, for d3-zoom pan/zoom gestures (tracked from `applyInteractions()`'s
|
|
454
|
+
* zoom `.on('start')`/`.on('end')` handlers, added by this same change). */
|
|
455
|
+
this.isPanning = false;
|
|
134
456
|
}
|
|
135
457
|
static { this.styles = [LyraElement.styles, styles, srOnly]; }
|
|
136
458
|
connectedCallback() {
|
|
@@ -146,6 +468,16 @@ export class LyraGraph extends LyraElement {
|
|
|
146
468
|
// the existing simulation in place instead.
|
|
147
469
|
if (this.d3) {
|
|
148
470
|
this.simulation?.restart();
|
|
471
|
+
// renderer="canvas" mode's own resize/DPR watchers are torn down by disconnectedCallback()
|
|
472
|
+
// below on every disconnect (including this reconnect) -- the <canvas> element itself
|
|
473
|
+
// survived the reparent along with the rest of this shadow tree (canvasEl === zoomedEl still
|
|
474
|
+
// holds), so re-arm them in place instead of waiting for a property-driven update that a bare
|
|
475
|
+
// reparent never triggers.
|
|
476
|
+
if (this.renderer === 'canvas' && this.canvasEl && this.canvasEl === this.zoomedEl) {
|
|
477
|
+
this.watchCanvasResize();
|
|
478
|
+
this.watchCanvasDpr();
|
|
479
|
+
this.markCanvasDirty();
|
|
480
|
+
}
|
|
149
481
|
return;
|
|
150
482
|
}
|
|
151
483
|
void loadD3().then((mods) => {
|
|
@@ -162,6 +494,21 @@ export class LyraGraph extends LyraElement {
|
|
|
162
494
|
disconnectedCallback() {
|
|
163
495
|
super.disconnectedCallback();
|
|
164
496
|
this.simulation?.stop();
|
|
497
|
+
// An in-flight focusNode()/fit() tween would otherwise keep scheduling frames and writing
|
|
498
|
+
// zoom transforms against the detached tree -- cancel it (which also settles the caller's
|
|
499
|
+
// pending Promise with `false` instead of leaving it hanging forever).
|
|
500
|
+
this.cancelCameraTween();
|
|
501
|
+
this.canvasResizeObserver?.disconnect();
|
|
502
|
+
this.canvasDprQuery?.removeEventListener('change', this.onCanvasDprChange);
|
|
503
|
+
if (this.canvasDrawRafId != null) {
|
|
504
|
+
cancelAnimationFrame(this.canvasDrawRafId);
|
|
505
|
+
this.canvasDrawRafId = undefined;
|
|
506
|
+
}
|
|
507
|
+
if (this.hoverRafId != null) {
|
|
508
|
+
cancelAnimationFrame(this.hoverRafId);
|
|
509
|
+
this.hoverRafId = undefined;
|
|
510
|
+
}
|
|
511
|
+
this.pendingHover = undefined;
|
|
165
512
|
}
|
|
166
513
|
/**
|
|
167
514
|
* A caller-supplied `radius` is clamped to [MIN_RADIUS, MAX_RADIUS] (and a
|
|
@@ -174,6 +521,636 @@ export class LyraGraph extends LyraElement {
|
|
|
174
521
|
const r = n.radius ?? (MIN_RADIUS + MAX_RADIUS) / 2;
|
|
175
522
|
return Number.isFinite(r) ? Math.min(MAX_RADIUS, Math.max(MIN_RADIUS, r)) : (MIN_RADIUS + MAX_RADIUS) / 2;
|
|
176
523
|
}
|
|
524
|
+
/** `width`/`height` normalized to a finite, positive viewport size — an invalid attribute value
|
|
525
|
+
* would otherwise flow straight into `forceCenter`, the SVG `viewBox`, and the canvas backing
|
|
526
|
+
* store's `width`/`height`, producing `NaN` geometry/transforms that silently render nothing
|
|
527
|
+
* instead of erroring. */
|
|
528
|
+
get safeWidth() {
|
|
529
|
+
return finiteRange(this.width, 800, 1);
|
|
530
|
+
}
|
|
531
|
+
get safeHeight() {
|
|
532
|
+
return finiteRange(this.height, 600, 1);
|
|
533
|
+
}
|
|
534
|
+
/** `minZoom`/`maxZoom` normalized to finite, positive scale bounds before ever reaching
|
|
535
|
+
* d3-zoom's `scaleExtent()` or a camera-clamp `Math.min`/`Math.max` — a non-finite bound would
|
|
536
|
+
* otherwise poison every subsequent zoom/pan computation with `NaN`. */
|
|
537
|
+
get safeMinZoom() {
|
|
538
|
+
return finiteRange(this.minZoom, 0.1, 0.001, 1000);
|
|
539
|
+
}
|
|
540
|
+
get safeMaxZoom() {
|
|
541
|
+
return finiteRange(this.maxZoom, 8, 0.001, 1000);
|
|
542
|
+
}
|
|
543
|
+
/** `edgeLabelMinZoom` is compared directly against the live camera scale (same domain as
|
|
544
|
+
* `minZoom`/`maxZoom`), so it's normalized with the same bounds -- a non-finite value would
|
|
545
|
+
* otherwise make every `>=`/`<` comparison against it silently `false`/`true` forever. */
|
|
546
|
+
get safeEdgeLabelMinZoom() {
|
|
547
|
+
return finiteRange(this.edgeLabelMinZoom, 0.6, 0.001, 1000);
|
|
548
|
+
}
|
|
549
|
+
/** `seed`, normalized to a finite integer when set -- `undefined` (unseeded/random) is left
|
|
550
|
+
* untouched, since it's a meaningful third state, not a missing number. Without this,
|
|
551
|
+
* `hashNodeSeed`/`mulberry32`'s `>>> 0` coercion would silently fold `NaN`/`Infinity` to `0`
|
|
552
|
+
* instead of normalizing an out-of-range attribute value the way every other numeric prop here
|
|
553
|
+
* does. */
|
|
554
|
+
get safeSeed() {
|
|
555
|
+
return this.seed == null ? undefined : finiteInteger(this.seed, 0);
|
|
556
|
+
}
|
|
557
|
+
/** `chargeStrength` is a signed d3-force strength (negative = repulsion, positive = attraction)
|
|
558
|
+
* — only guarded for finiteness, not clamped to a range, since either sign is a legitimate
|
|
559
|
+
* value. */
|
|
560
|
+
get safeChargeStrength() {
|
|
561
|
+
return finiteNumber(this.chargeStrength, -300);
|
|
562
|
+
}
|
|
563
|
+
/** `linkDistance` normalized to a finite, non-negative pixel distance — feeds `forceLink()`'s
|
|
564
|
+
* `distance()`, the layered layout's `gapY`, and the neighbor-jitter spawn radius, none of
|
|
565
|
+
* which have a sane meaning for a negative/non-finite value. */
|
|
566
|
+
get safeLinkDistance() {
|
|
567
|
+
return finiteRange(this.linkDistance, 100, 0);
|
|
568
|
+
}
|
|
569
|
+
resolveNodeType(node) {
|
|
570
|
+
return node.type != null ? this.nodeTypes.find((t) => t.id === node.type) : undefined;
|
|
571
|
+
}
|
|
572
|
+
nodeShape(node) {
|
|
573
|
+
return this.resolveNodeType(node)?.shape ?? 'circle';
|
|
574
|
+
}
|
|
575
|
+
/** Resolution precedence: `node.color` (existing, most specific) > matched `GraphNodeType.color`
|
|
576
|
+
* > the ordered categorical fallback palette by the type's index in `nodeTypes` > (returns
|
|
577
|
+
* `undefined`, letting the untyped `--lyra-node-fill` token default apply). Both data-driven
|
|
578
|
+
* color sources pass the existing `sanitizeNodeColor()`. */
|
|
579
|
+
nodeFill(node) {
|
|
580
|
+
const ownColor = sanitizeNodeColor(node.color);
|
|
581
|
+
if (ownColor)
|
|
582
|
+
return ownColor;
|
|
583
|
+
const type = this.resolveNodeType(node);
|
|
584
|
+
if (!type)
|
|
585
|
+
return undefined;
|
|
586
|
+
const typeColor = sanitizeNodeColor(type.color);
|
|
587
|
+
if (typeColor)
|
|
588
|
+
return typeColor;
|
|
589
|
+
return categoricalPaletteColor(this.nodeTypes.indexOf(type));
|
|
590
|
+
}
|
|
591
|
+
/** `this.nodes` filtered down to the ids `hiddenTypes` doesn't hide -- an untyped node (`type ==
|
|
592
|
+
* null`) is never hidden, regardless of `hiddenTypes`' contents. */
|
|
593
|
+
visibleNodes() {
|
|
594
|
+
if (!this.hiddenTypes.length)
|
|
595
|
+
return this.nodes;
|
|
596
|
+
const hidden = new Set(this.hiddenTypes);
|
|
597
|
+
return this.nodes.filter((n) => n.type == null || !hidden.has(n.type));
|
|
598
|
+
}
|
|
599
|
+
/** Resolves `this.links` against an already-built `byId` node map: a link whose source isn't in
|
|
600
|
+
* `byId` is dropped (hidden source, or a genuinely missing one); a link whose target isn't in
|
|
601
|
+
* `byId` either stubs as a dangling link (target id doesn't exist in `this.nodes` at all) or is
|
|
602
|
+
* dropped (target exists but is hidden by `hiddenTypes`). Shared by both the force and layered
|
|
603
|
+
* layout paths in `rebuildSimulation()`. */
|
|
604
|
+
resolveLinksAgainst(byId) {
|
|
605
|
+
const nodeExists = new Set(this.nodes.map((n) => n.id));
|
|
606
|
+
const resolved = [];
|
|
607
|
+
const dangling = [];
|
|
608
|
+
for (const l of this.links) {
|
|
609
|
+
const source = byId.get(l.source);
|
|
610
|
+
if (!source)
|
|
611
|
+
continue;
|
|
612
|
+
const target = byId.get(l.target);
|
|
613
|
+
if (target) {
|
|
614
|
+
resolved.push({ ...l, source, target });
|
|
615
|
+
}
|
|
616
|
+
else if (!nodeExists.has(l.target)) {
|
|
617
|
+
dangling.push({ ...l, source, target: { id: l.target, x: source.x, y: source.y }, dangling: true });
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return { resolved, dangling };
|
|
621
|
+
}
|
|
622
|
+
/** A community's currently-visible members -- the union of `memberIds` and every currently
|
|
623
|
+
* simulated node (already filtered by `hiddenTypes`) whose `communityId` matches. */
|
|
624
|
+
communityMembers(community) {
|
|
625
|
+
const idSet = new Set(community.memberIds);
|
|
626
|
+
return this.simNodes.filter((n) => idSet.has(n.id) || n.communityId === community.id);
|
|
627
|
+
}
|
|
628
|
+
/** `communities` narrowed to entries with at least one currently-visible member -- a community
|
|
629
|
+
* whose members are all hidden by `hiddenTypes` (or that starts out empty) draws no hull and
|
|
630
|
+
* doesn't occupy a roving-ring slot. */
|
|
631
|
+
visibleCommunities() {
|
|
632
|
+
if (!this.visibleCommunitiesCache) {
|
|
633
|
+
this.visibleCommunitiesCache = this.communities
|
|
634
|
+
.map((community) => ({ community, members: this.communityMembers(community) }))
|
|
635
|
+
.filter((entry) => entry.members.length > 0);
|
|
636
|
+
}
|
|
637
|
+
return this.visibleCommunitiesCache;
|
|
638
|
+
}
|
|
639
|
+
communityHull(members) {
|
|
640
|
+
return convexHull(members.map((n) => ({ x: n.x ?? 0, y: n.y ?? 0 })));
|
|
641
|
+
}
|
|
642
|
+
onCommunityClick(community) {
|
|
643
|
+
this.emit('lyra-community-click', { id: community.id });
|
|
644
|
+
}
|
|
645
|
+
cameraTransitionMs() {
|
|
646
|
+
const parsed = parseFloat(getComputedStyle(this).getPropertyValue('--lyra-transition-base'));
|
|
647
|
+
return Number.isFinite(parsed) ? parsed : 180;
|
|
648
|
+
}
|
|
649
|
+
cancelCameraTween() {
|
|
650
|
+
if (this.cameraTweenId != null) {
|
|
651
|
+
cancelAnimationFrame(this.cameraTweenId);
|
|
652
|
+
this.cameraTweenId = undefined;
|
|
653
|
+
}
|
|
654
|
+
this.isCameraTweening = false;
|
|
655
|
+
const resolve = this.cameraTweenResolve;
|
|
656
|
+
if (resolve) {
|
|
657
|
+
this.cameraTweenResolve = undefined;
|
|
658
|
+
resolve(false);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
applyZoomTransform(transform) {
|
|
662
|
+
if (!this.d3 || !this.zoomedEl || !this.zoomBehavior)
|
|
663
|
+
return;
|
|
664
|
+
this.isApplyingZoomTransform = true;
|
|
665
|
+
try {
|
|
666
|
+
this.zoomBehavior.transform(this.d3.select(this.zoomedEl), transform);
|
|
667
|
+
}
|
|
668
|
+
finally {
|
|
669
|
+
this.isApplyingZoomTransform = false;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
/** Animates from the zoom behavior's current transform toward `computeTarget()`'s result via a
|
|
673
|
+
* rAF tween that calls `zoomBehavior.transform()` every frame -- keeps d3-zoom's own internal
|
|
674
|
+
* state consistent (so the next user pan doesn't jump), unlike writing the `<g>` transform
|
|
675
|
+
* attribute directly. `computeTarget` is re-invoked on every single frame (not read once
|
|
676
|
+
* up-front) so the tween keeps tracking a still-settling force simulation's live node positions
|
|
677
|
+
* instead of tweening toward a stale snapshot from the moment the call was made --
|
|
678
|
+
* `focusNode()`/`fit()` are just as likely to run while the graph is still animating its initial
|
|
679
|
+
* layout as after it's settled. `prefers-reduced-motion` jumps straight to one write of the
|
|
680
|
+
* then-current target. A concurrent call cancels the previous tween -- resolves `true` on
|
|
681
|
+
* genuine arrival, `false` if superseded or interrupted by a user gesture before completing. */
|
|
682
|
+
tweenCamera(computeTarget) {
|
|
683
|
+
return new Promise((resolve) => {
|
|
684
|
+
if (!this.d3 || !this.zoomedEl || !this.zoomBehavior) {
|
|
685
|
+
resolve(false);
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
this.cancelCameraTween();
|
|
689
|
+
this.cameraTweenResolve = resolve;
|
|
690
|
+
this.isCameraTweening = true;
|
|
691
|
+
if (prefersReducedMotion()) {
|
|
692
|
+
this.applyZoomTransform(computeTarget());
|
|
693
|
+
this.isCameraTweening = false;
|
|
694
|
+
this.cameraTweenResolve = undefined;
|
|
695
|
+
resolve(true);
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
const current = this.d3.zoomTransform(this.zoomedEl);
|
|
699
|
+
const duration = this.cameraTransitionMs();
|
|
700
|
+
const start = performance.now();
|
|
701
|
+
const startK = current.k;
|
|
702
|
+
const startX = current.x;
|
|
703
|
+
const startY = current.y;
|
|
704
|
+
const step = (now) => {
|
|
705
|
+
const t = duration > 0 ? Math.min(1, (now - start) / duration) : 1;
|
|
706
|
+
const target = computeTarget();
|
|
707
|
+
const targetK = target.k;
|
|
708
|
+
const targetX = target.x;
|
|
709
|
+
const targetY = target.y;
|
|
710
|
+
this.applyZoomTransform(this.d3.zoomIdentity
|
|
711
|
+
.translate(startX + (targetX - startX) * t, startY + (targetY - startY) * t)
|
|
712
|
+
.scale(startK + (targetK - startK) * t));
|
|
713
|
+
if (t < 1) {
|
|
714
|
+
this.cameraTweenId = requestAnimationFrame(step);
|
|
715
|
+
}
|
|
716
|
+
else {
|
|
717
|
+
this.cameraTweenId = undefined;
|
|
718
|
+
this.isCameraTweening = false;
|
|
719
|
+
this.cameraTweenResolve = undefined;
|
|
720
|
+
resolve(true);
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
this.cameraTweenId = requestAnimationFrame(step);
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
/** Animates the camera so `id` centers in the viewport (the `width` x `height` viewBox), at
|
|
727
|
+
* `options.zoom` (clamped to `[minZoom, maxZoom]`) or the current scale when omitted. Resolves
|
|
728
|
+
* `true` on arrival; `false` for an id with no matching entry in `simNodes` -- there's nothing
|
|
729
|
+
* to center on. Announces `graphNodeFocused` through the existing live region. Does not move DOM
|
|
730
|
+
* focus -- this is a camera operation, not a roving-focus one. */
|
|
731
|
+
async focusNode(id, options) {
|
|
732
|
+
const node = this.simNodes.find((n) => n.id === id);
|
|
733
|
+
if (!node || !this.d3 || !this.zoomedEl || !this.zoomBehavior)
|
|
734
|
+
return false;
|
|
735
|
+
const current = this.d3.zoomTransform(this.zoomedEl);
|
|
736
|
+
const k = Math.min(this.safeMaxZoom, Math.max(this.safeMinZoom, options?.zoom ?? current.k));
|
|
737
|
+
const arrived = await this.tweenCamera(() => this.d3.zoomIdentity
|
|
738
|
+
.translate(this.safeWidth / 2 - k * (node.x ?? 0), this.safeHeight / 2 - k * (node.y ?? 0))
|
|
739
|
+
.scale(k));
|
|
740
|
+
if (arrived) {
|
|
741
|
+
this.graphLiveText = this.localize('graphNodeFocused', undefined, { label: this.nodeAccessibleText(node) });
|
|
742
|
+
}
|
|
743
|
+
return arrived;
|
|
744
|
+
}
|
|
745
|
+
/** Animates the camera to frame the bounding box of every currently visible node position (plus
|
|
746
|
+
* each node's own radius) at the largest scale that fits within `width` x `height` minus
|
|
747
|
+
* `padding` viewport-px on each side (clamped to `[minZoom, maxZoom]`). Silent -- no data
|
|
748
|
+
* changed, so no announcement. A no-op with no visible nodes. */
|
|
749
|
+
fit(options) {
|
|
750
|
+
if (!this.d3 || !this.zoomedEl || !this.zoomBehavior || !this.simNodes.length)
|
|
751
|
+
return;
|
|
752
|
+
const padding = options?.padding ?? 24;
|
|
753
|
+
void this.tweenCamera(() => {
|
|
754
|
+
let minX = Infinity;
|
|
755
|
+
let minY = Infinity;
|
|
756
|
+
let maxX = -Infinity;
|
|
757
|
+
let maxY = -Infinity;
|
|
758
|
+
for (const n of this.simNodes) {
|
|
759
|
+
const r = this.nodeRadius(n);
|
|
760
|
+
minX = Math.min(minX, (n.x ?? 0) - r);
|
|
761
|
+
maxX = Math.max(maxX, (n.x ?? 0) + r);
|
|
762
|
+
minY = Math.min(minY, (n.y ?? 0) - r);
|
|
763
|
+
maxY = Math.max(maxY, (n.y ?? 0) + r);
|
|
764
|
+
}
|
|
765
|
+
for (const entry of this.visibleCommunities()) {
|
|
766
|
+
for (const p of this.communityHull(entry.members)) {
|
|
767
|
+
minX = Math.min(minX, p.x - HULL_PADDING);
|
|
768
|
+
maxX = Math.max(maxX, p.x + HULL_PADDING);
|
|
769
|
+
minY = Math.min(minY, p.y - HULL_PADDING);
|
|
770
|
+
maxY = Math.max(maxY, p.y + HULL_PADDING);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
const boxW = Math.max(1, maxX - minX);
|
|
774
|
+
const boxH = Math.max(1, maxY - minY);
|
|
775
|
+
const availW = Math.max(1, this.safeWidth - padding * 2);
|
|
776
|
+
const availH = Math.max(1, this.safeHeight - padding * 2);
|
|
777
|
+
const k = Math.min(this.safeMaxZoom, Math.max(this.safeMinZoom, Math.min(availW / boxW, availH / boxH)));
|
|
778
|
+
const cx = (minX + maxX) / 2;
|
|
779
|
+
const cy = (minY + maxY) / 2;
|
|
780
|
+
return this.d3.zoomIdentity.translate(this.safeWidth / 2 - k * cx, this.safeHeight / 2 - k * cy).scale(k);
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
updateFocusHalo() {
|
|
784
|
+
if (!this.focusHaloEl)
|
|
785
|
+
return;
|
|
786
|
+
const node = this.focusId != null ? this.simNodes.find((n) => n.id === this.focusId) : undefined;
|
|
787
|
+
if (node) {
|
|
788
|
+
this.focusHaloEl.setAttribute('cx', String(node.x ?? 0));
|
|
789
|
+
this.focusHaloEl.setAttribute('cy', String(node.y ?? 0));
|
|
790
|
+
this.focusHaloEl.setAttribute('r', String(this.nodeRadius(node) + FOCUS_HALO_PADDING));
|
|
791
|
+
this.focusHaloEl.removeAttribute('hidden');
|
|
792
|
+
}
|
|
793
|
+
else {
|
|
794
|
+
this.focusHaloEl.setAttribute('hidden', '');
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
// ---------------------------------------------------------------------------------------------
|
|
798
|
+
// renderer="canvas": surface setup, DPR/resize watching, scene building, and the static draw.
|
|
799
|
+
// ---------------------------------------------------------------------------------------------
|
|
800
|
+
setUpCanvasSurface() {
|
|
801
|
+
this.canvasCtx = this.canvasEl.getContext('2d') ?? undefined;
|
|
802
|
+
this.pickCanvas = document.createElement('canvas');
|
|
803
|
+
this.pickCtx = this.pickCanvas.getContext('2d', { willReadFrequently: true });
|
|
804
|
+
this.watchCanvasResize();
|
|
805
|
+
this.watchCanvasDpr();
|
|
806
|
+
this.canvasTooltipEl = this.renderRoot.querySelector('[part="tooltip"]') ?? undefined;
|
|
807
|
+
// bindCanvasPointer() (which owns onCanvasDblClick) is bound BEFORE bindCanvasZoom() -- both
|
|
808
|
+
// end up with a 'dblclick' listener on this same <canvas>, and d3-zoom's own default
|
|
809
|
+
// double-click-to-zoom-in handler calls stopImmediatePropagation() unconditionally (see
|
|
810
|
+
// onCanvasDblClick()'s own comment). Registering first means onCanvasDblClick() runs first and
|
|
811
|
+
// gets the chance to itself stop the event (only when it actually hit a node) before d3-zoom's
|
|
812
|
+
// handler would otherwise suppress it from ever being observed at all.
|
|
813
|
+
this.bindCanvasPointer();
|
|
814
|
+
this.bindCanvasZoom();
|
|
815
|
+
}
|
|
816
|
+
watchCanvasResize() {
|
|
817
|
+
// Re-arming replaces the observer instance -- disconnect the previous one first, or a
|
|
818
|
+
// canvas -> svg -> canvas renderer round trip leaves an orphaned observer still watching the
|
|
819
|
+
// host (disconnectedCallback only ever cleans up whichever instance is current).
|
|
820
|
+
this.canvasResizeObserver?.disconnect();
|
|
821
|
+
this.canvasResizeObserver = new ResizeObserver(() => this.markCanvasDirty());
|
|
822
|
+
this.canvasResizeObserver.observe(this);
|
|
823
|
+
}
|
|
824
|
+
watchCanvasDpr() {
|
|
825
|
+
// A MediaQueryList's `matches` is fixed at creation time, so crossing the DPR threshold it was
|
|
826
|
+
// built for means building a fresh one for the new ratio -- remove the previous instance's
|
|
827
|
+
// listener first, or it leaks (disconnectedCallback only ever cleans up whichever is current).
|
|
828
|
+
this.canvasDprQuery?.removeEventListener('change', this.onCanvasDprChange);
|
|
829
|
+
this.canvasDprQuery = matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
|
|
830
|
+
this.canvasDprQuery.addEventListener('change', this.onCanvasDprChange);
|
|
831
|
+
}
|
|
832
|
+
markCanvasDirty() {
|
|
833
|
+
this.canvasScene = undefined;
|
|
834
|
+
this.pickDirty = true;
|
|
835
|
+
this.scheduleCanvasDraw();
|
|
836
|
+
}
|
|
837
|
+
/** The camera-only sibling of `markCanvasDirty()`: a pan/zoom moves the camera but leaves every
|
|
838
|
+
* world-space scene value (positions, colors, labels) untouched, so the cached `canvasScene`
|
|
839
|
+
* stays valid and only needs redrawing under the new transform. The pick canvas bakes the
|
|
840
|
+
* camera transform into its pixels, though, so it still needs a redraw before the next hit
|
|
841
|
+
* test. */
|
|
842
|
+
markCanvasCameraDirty() {
|
|
843
|
+
this.pickDirty = true;
|
|
844
|
+
this.scheduleCanvasDraw();
|
|
845
|
+
}
|
|
846
|
+
scheduleCanvasDraw() {
|
|
847
|
+
if (this.canvasDrawRafId != null)
|
|
848
|
+
return;
|
|
849
|
+
this.canvasDrawRafId = requestAnimationFrame(() => {
|
|
850
|
+
this.canvasDrawRafId = undefined;
|
|
851
|
+
this.drawCanvas();
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
/** Canvas 2D's `fillStyle`/`strokeStyle` don't accept a raw `var(--x)` string the way an inline
|
|
855
|
+
* SVG `style` attribute does -- resolves it to the actual cascaded color via `getComputedStyle`
|
|
856
|
+
* first (the same "canvas can't consume var() directly" resolution `<lyra-heatmap>` already
|
|
857
|
+
* uses for its own canvas-drawn tokens). `value` untouched when it isn't a bare `var(...)` ref
|
|
858
|
+
* (a literal `GraphNode.color`/`GraphLink.color` hex/rgb string already resolves fine as-is). */
|
|
859
|
+
resolveCssColorValue(value, cs) {
|
|
860
|
+
const match = value.match(/^var\((--[\w-]+)/);
|
|
861
|
+
if (!match)
|
|
862
|
+
return value;
|
|
863
|
+
return cs.getPropertyValue(match[1]).trim() || value;
|
|
864
|
+
}
|
|
865
|
+
buildCanvasScene(cs) {
|
|
866
|
+
const hullFillDefault = cs.getPropertyValue('--lyra-graph-hull-fill').trim() || cs.getPropertyValue('--lyra-color-brand').trim();
|
|
867
|
+
const hulls = this.visibleCommunities().map((entry) => ({
|
|
868
|
+
d: hullPathD(this.communityHull(entry.members)),
|
|
869
|
+
fill: sanitizeNodeColor(entry.community.color) ?? hullFillDefault,
|
|
870
|
+
}));
|
|
871
|
+
const linkColorDefault = cs.getPropertyValue('--lyra-link-color').trim() || cs.getPropertyValue('--lyra-color-border').trim();
|
|
872
|
+
const links = this.simLinks.map((l) => {
|
|
873
|
+
const coords = this.linkCoordinates(l);
|
|
874
|
+
const own = sanitizeNodeColor(l.color);
|
|
875
|
+
return {
|
|
876
|
+
x1: coords.x1,
|
|
877
|
+
y1: coords.y1,
|
|
878
|
+
x2: coords.x2,
|
|
879
|
+
y2: coords.y2,
|
|
880
|
+
color: own ? this.resolveCssColorValue(own, cs) : linkColorDefault,
|
|
881
|
+
width: l.width ?? 1.5,
|
|
882
|
+
dash: l.dash,
|
|
883
|
+
directed: l.directed,
|
|
884
|
+
selected: this.isSelected('link', this.linkKey(l)),
|
|
885
|
+
dimmed: this.isDimmed('link', this.linkKey(l)),
|
|
886
|
+
};
|
|
887
|
+
});
|
|
888
|
+
const edgeLabels = this.showEdgeLabels && this.canvasCamera.k >= this.safeEdgeLabelMinZoom
|
|
889
|
+
? this.simLinks
|
|
890
|
+
.filter((l) => l.label)
|
|
891
|
+
.map((l) => {
|
|
892
|
+
const pos = this.edgeLabelPosition(l);
|
|
893
|
+
const coords = this.linkCoordinates(l);
|
|
894
|
+
const edgeLength = Math.hypot(coords.x2 - coords.x1, coords.y2 - coords.y1);
|
|
895
|
+
const tooLong = this.edgeLabelWidth(l.label) > edgeLength * EDGE_LABEL_LENGTH_GATE_RATIO;
|
|
896
|
+
return { x: pos.x, y: pos.y, text: l.label, tooLong };
|
|
897
|
+
})
|
|
898
|
+
.filter((l) => !l.tooLong)
|
|
899
|
+
.map(({ x, y, text }) => ({ x, y, text }))
|
|
900
|
+
: [];
|
|
901
|
+
const nodeFillDefault = cs.getPropertyValue('--lyra-node-fill').trim() || cs.getPropertyValue('--lyra-color-brand').trim();
|
|
902
|
+
const nodes = this.simNodes.map((n) => {
|
|
903
|
+
const fill = this.nodeFill(n);
|
|
904
|
+
return {
|
|
905
|
+
x: n.x ?? 0,
|
|
906
|
+
y: n.y ?? 0,
|
|
907
|
+
r: this.nodeRadius(n),
|
|
908
|
+
shape: this.nodeShape(n),
|
|
909
|
+
fill: fill ? this.resolveCssColorValue(fill, cs) : nodeFillDefault,
|
|
910
|
+
selected: this.isSelected('node', n.id),
|
|
911
|
+
dimmed: this.isDimmed('node', n.id),
|
|
912
|
+
};
|
|
913
|
+
});
|
|
914
|
+
const nodeLabels = this.simNodes
|
|
915
|
+
.filter((n) => n.label)
|
|
916
|
+
.map((n) => ({ x: (n.x ?? 0) + this.nodeRadius(n) + 2, y: n.y ?? 0, text: n.label }));
|
|
917
|
+
const focusNode = this.focusId != null ? this.simNodes.find((n) => n.id === this.focusId) : undefined;
|
|
918
|
+
const activeNode = this.activeGraphItem >= 0 && this.activeGraphItem < this.simNodes.length
|
|
919
|
+
? this.simNodes[this.activeGraphItem]
|
|
920
|
+
: undefined;
|
|
921
|
+
return {
|
|
922
|
+
hulls,
|
|
923
|
+
links,
|
|
924
|
+
edgeLabels,
|
|
925
|
+
nodes,
|
|
926
|
+
nodeLabels,
|
|
927
|
+
focusHalo: focusNode
|
|
928
|
+
? { x: focusNode.x ?? 0, y: focusNode.y ?? 0, r: this.nodeRadius(focusNode) + FOCUS_HALO_PADDING }
|
|
929
|
+
: undefined,
|
|
930
|
+
keyboardFocusRing: activeNode
|
|
931
|
+
? { x: activeNode.x ?? 0, y: activeNode.y ?? 0, r: this.nodeRadius(activeNode) + 4 }
|
|
932
|
+
: undefined,
|
|
933
|
+
showNodeLabels: this.canvasCamera.k >= CANVAS_NODE_LABEL_MIN_ZOOM,
|
|
934
|
+
haloColor: cs.getPropertyValue('--lyra-graph-focus-halo-color').trim() || cs.getPropertyValue('--lyra-color-brand').trim(),
|
|
935
|
+
selectedColor: cs.getPropertyValue('--lyra-graph-selected-color').trim() || cs.getPropertyValue('--lyra-color-success').trim(),
|
|
936
|
+
dimmedOpacity: Number(cs.getPropertyValue('--lyra-graph-dimmed-opacity').trim()) || 1,
|
|
937
|
+
labelColor: cs.getPropertyValue('--lyra-color-text').trim(),
|
|
938
|
+
labelHaloColor: cs.getPropertyValue('--lyra-graph-edge-label-halo').trim() || cs.getPropertyValue('--lyra-color-surface').trim(),
|
|
939
|
+
font: `${this.edgeLabelFontPx()}px ${cs.getPropertyValue('--lyra-font').trim() || 'sans-serif'}`,
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
/** Sizes the backing store to the canvas's own rendered CSS box (`clientWidth`/`clientHeight`,
|
|
943
|
+
* themselves stretched to fill the host via `[part="base"]`/`[part="canvas"]`'s `100%` sizing)
|
|
944
|
+
* times `devicePixelRatio`, only touching `width`/`height` when the target actually changed --
|
|
945
|
+
* reassigning either unconditionally would implicitly clear the canvas and reset its transform
|
|
946
|
+
* on every single draw, even a pure pan/zoom repaint. Mirrors `<lyra-heatmap>`'s own DPR-scaled
|
|
947
|
+
* backing-store convention (`watchDpr()`/`onDprChange()`), adapted to `setTransform()` (an
|
|
948
|
+
* absolute reset) rather than a relative `scale()`, since this canvas -- unlike heatmap's, which
|
|
949
|
+
* always resizes its backing store on every draw -- only resizes conditionally. */
|
|
950
|
+
drawCanvas() {
|
|
951
|
+
if (!this.canvasEl || !this.canvasCtx)
|
|
952
|
+
return;
|
|
953
|
+
const dpr = window.devicePixelRatio || 1;
|
|
954
|
+
const w = this.canvasEl.clientWidth || this.safeWidth;
|
|
955
|
+
const h = this.canvasEl.clientHeight || this.safeHeight;
|
|
956
|
+
const backingW = Math.round(w * dpr);
|
|
957
|
+
const backingH = Math.round(h * dpr);
|
|
958
|
+
if (this.canvasEl.width !== backingW || this.canvasEl.height !== backingH) {
|
|
959
|
+
this.canvasEl.width = backingW;
|
|
960
|
+
this.canvasEl.height = backingH;
|
|
961
|
+
}
|
|
962
|
+
const ctx = this.canvasCtx;
|
|
963
|
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
964
|
+
ctx.clearRect(0, 0, w, h);
|
|
965
|
+
// Reuse the cached scene for a camera-only repaint; rebuild when it was invalidated
|
|
966
|
+
// (markCanvasDirty()) or when the camera crossed one of the two label-visibility zoom gates
|
|
967
|
+
// the scene bakes in (see canvasSceneHasEdgeLabels' doc).
|
|
968
|
+
const edgeLabelsVisible = this.showEdgeLabels && this.canvasCamera.k >= this.safeEdgeLabelMinZoom;
|
|
969
|
+
const nodeLabelsVisible = this.canvasCamera.k >= CANVAS_NODE_LABEL_MIN_ZOOM;
|
|
970
|
+
if (!this.canvasScene ||
|
|
971
|
+
this.canvasScene.showNodeLabels !== nodeLabelsVisible ||
|
|
972
|
+
this.canvasSceneHasEdgeLabels !== edgeLabelsVisible) {
|
|
973
|
+
this.canvasScene = this.buildCanvasScene(getComputedStyle(this));
|
|
974
|
+
this.canvasSceneHasEdgeLabels = edgeLabelsVisible;
|
|
975
|
+
}
|
|
976
|
+
drawGraphScene(ctx, this.canvasCamera, this.canvasScene);
|
|
977
|
+
}
|
|
978
|
+
// ---------------------------------------------------------------------------------------------
|
|
979
|
+
// renderer="canvas": color-picking hit-testing, pointer interaction, and the hover tooltip.
|
|
980
|
+
// ---------------------------------------------------------------------------------------------
|
|
981
|
+
rebuildPickItems() {
|
|
982
|
+
this.pickItems = [
|
|
983
|
+
...this.visibleCommunities().map((entry) => ({ kind: 'hull', entry })),
|
|
984
|
+
...this.simLinks.map((link) => ({ kind: 'link', link })),
|
|
985
|
+
...this.simNodes.map((node) => ({ kind: 'node', node })),
|
|
986
|
+
];
|
|
987
|
+
}
|
|
988
|
+
redrawPickCanvas() {
|
|
989
|
+
if (!this.pickCtx || !this.canvasEl || !this.pickCanvas)
|
|
990
|
+
return;
|
|
991
|
+
if (this.pickCanvas.width !== this.canvasEl.width || this.pickCanvas.height !== this.canvasEl.height) {
|
|
992
|
+
this.pickCanvas.width = this.canvasEl.width;
|
|
993
|
+
this.pickCanvas.height = this.canvasEl.height;
|
|
994
|
+
}
|
|
995
|
+
this.rebuildPickItems();
|
|
996
|
+
const dpr = window.devicePixelRatio || 1;
|
|
997
|
+
this.pickCtx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
998
|
+
drawPickingScene(this.pickCtx, this.canvasCamera, {
|
|
999
|
+
hulls: this.pickItems
|
|
1000
|
+
.filter((i) => i.kind === 'hull')
|
|
1001
|
+
.map((i) => ({ d: hullPathD(this.communityHull(i.entry.members)) })),
|
|
1002
|
+
links: this.pickItems
|
|
1003
|
+
.filter((i) => i.kind === 'link')
|
|
1004
|
+
.map((i) => {
|
|
1005
|
+
const c = this.linkCoordinates(i.link);
|
|
1006
|
+
return { x1: c.x1, y1: c.y1, x2: c.x2, y2: c.y2, width: i.link.width ?? 1.5 };
|
|
1007
|
+
}),
|
|
1008
|
+
nodes: this.pickItems
|
|
1009
|
+
.filter((i) => i.kind === 'node')
|
|
1010
|
+
.map((i) => ({
|
|
1011
|
+
x: i.node.x ?? 0,
|
|
1012
|
+
y: i.node.y ?? 0,
|
|
1013
|
+
r: this.nodeRadius(i.node) + 2,
|
|
1014
|
+
shape: this.nodeShape(i.node),
|
|
1015
|
+
})),
|
|
1016
|
+
});
|
|
1017
|
+
this.pickDirty = false;
|
|
1018
|
+
}
|
|
1019
|
+
hitTest(clientX, clientY) {
|
|
1020
|
+
if (!this.canvasEl || !this.pickCtx)
|
|
1021
|
+
return undefined;
|
|
1022
|
+
if (this.pickDirty)
|
|
1023
|
+
this.redrawPickCanvas();
|
|
1024
|
+
const rect = this.canvasEl.getBoundingClientRect();
|
|
1025
|
+
const dpr = window.devicePixelRatio || 1;
|
|
1026
|
+
const px = Math.round((clientX - rect.left) * dpr);
|
|
1027
|
+
const py = Math.round((clientY - rect.top) * dpr);
|
|
1028
|
+
if (px < 0 || py < 0 || px >= this.pickCtx.canvas.width || py >= this.pickCtx.canvas.height)
|
|
1029
|
+
return undefined;
|
|
1030
|
+
const data = this.pickCtx.getImageData(px, py, 1, 1).data;
|
|
1031
|
+
const index = pickColorToIndex(data[0], data[1], data[2]);
|
|
1032
|
+
return index >= 0 ? this.pickItems[index] : undefined;
|
|
1033
|
+
}
|
|
1034
|
+
bindCanvasZoom() {
|
|
1035
|
+
if (!this.d3 || !this.canvasEl)
|
|
1036
|
+
return;
|
|
1037
|
+
this.zoomBehavior = this.d3
|
|
1038
|
+
.zoom()
|
|
1039
|
+
.scaleExtent([this.safeMinZoom, this.safeMaxZoom])
|
|
1040
|
+
.on('start', () => {
|
|
1041
|
+
// Same self-triggered-echo guard as the svg zoom bind's own 'start' handler above (see its
|
|
1042
|
+
// comment) -- a camera tween's per-frame applyZoomTransform() call fires this synchronously,
|
|
1043
|
+
// and without the guard cancelCameraTween() here would cancel that very tween on its own
|
|
1044
|
+
// first frame.
|
|
1045
|
+
if (this.isApplyingZoomTransform)
|
|
1046
|
+
return;
|
|
1047
|
+
this.isPanning = true;
|
|
1048
|
+
this.cancelCameraTween();
|
|
1049
|
+
})
|
|
1050
|
+
.on('zoom', (event) => {
|
|
1051
|
+
this.canvasCamera = { k: event.transform.k, x: event.transform.x, y: event.transform.y };
|
|
1052
|
+
this.markCanvasCameraDirty();
|
|
1053
|
+
})
|
|
1054
|
+
.on('end', () => {
|
|
1055
|
+
this.isPanning = false;
|
|
1056
|
+
});
|
|
1057
|
+
this.d3.select(this.canvasEl).call(this.zoomBehavior);
|
|
1058
|
+
}
|
|
1059
|
+
bindCanvasPointer() {
|
|
1060
|
+
const canvas = this.canvasEl;
|
|
1061
|
+
canvas.addEventListener('pointerdown', this.onCanvasPointerDown);
|
|
1062
|
+
canvas.addEventListener('pointermove', this.onCanvasPointerMove);
|
|
1063
|
+
canvas.addEventListener('pointerup', this.onCanvasPointerUp);
|
|
1064
|
+
canvas.addEventListener('pointerleave', this.onCanvasPointerLeave);
|
|
1065
|
+
canvas.addEventListener('dblclick', this.onCanvasDblClick);
|
|
1066
|
+
}
|
|
1067
|
+
/** `alpha` decays toward `alphaMin` and d3-force stops its internal timer once it crosses below
|
|
1068
|
+
* it, so `alpha > alphaMin` mirrors the simulation's own running condition -- including a drag's
|
|
1069
|
+
* `alphaTarget(0.3)` reheat, and correctly excluding a seeded/reduced-motion graph whose settle
|
|
1070
|
+
* loop already converged synchronously. */
|
|
1071
|
+
simulationIsTicking() {
|
|
1072
|
+
return this.simulation != null && this.simulation.alpha() > this.simulation.alphaMin();
|
|
1073
|
+
}
|
|
1074
|
+
/** Geometric fallback for dblclick: browsers can deliver the event before the offscreen pick
|
|
1075
|
+
* canvas has painted the latest frame, while the simulation coordinates are already current. */
|
|
1076
|
+
nodeAtCanvasPoint(clientX, clientY) {
|
|
1077
|
+
if (!this.canvasEl)
|
|
1078
|
+
return undefined;
|
|
1079
|
+
const rect = this.canvasEl.getBoundingClientRect();
|
|
1080
|
+
const worldX = (clientX - rect.left - this.canvasCamera.x) / this.canvasCamera.k;
|
|
1081
|
+
const worldY = (clientY - rect.top - this.canvasCamera.y) / this.canvasCamera.k;
|
|
1082
|
+
let closest;
|
|
1083
|
+
let closestDistance = Infinity;
|
|
1084
|
+
for (const node of this.simNodes) {
|
|
1085
|
+
const distance = Math.hypot((node.x ?? 0) - worldX, (node.y ?? 0) - worldY);
|
|
1086
|
+
if (distance <= this.nodeRadius(node) + 2 / this.canvasCamera.k && distance < closestDistance) {
|
|
1087
|
+
closest = node;
|
|
1088
|
+
closestDistance = distance;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
return closest;
|
|
1092
|
+
}
|
|
1093
|
+
updateCanvasTooltip(hit, clientX, clientY) {
|
|
1094
|
+
if (!this.canvasTooltipEl)
|
|
1095
|
+
return;
|
|
1096
|
+
if (!hit || hit.kind === 'hull') {
|
|
1097
|
+
this.canvasTooltipEl.setAttribute('hidden', '');
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
const rect = this.canvasEl.getBoundingClientRect();
|
|
1101
|
+
this.canvasTooltipEl.textContent =
|
|
1102
|
+
hit.kind === 'node' ? this.nodeAccessibleText(hit.node) : this.linkAccessibleText(hit.link);
|
|
1103
|
+
// `clientX - rect.left`/`clientY - rect.top` are physical viewport offsets, so they must be
|
|
1104
|
+
// written to the physical `left`/`top` -- a logical `inset-inline-start` maps to `right` under
|
|
1105
|
+
// RTL and would mirror the tooltip across the canvas instead of tracking the cursor.
|
|
1106
|
+
this.canvasTooltipEl.style.left = `${clientX - rect.left}px`;
|
|
1107
|
+
this.canvasTooltipEl.style.top = `${clientY - rect.top}px`;
|
|
1108
|
+
this.canvasTooltipEl.removeAttribute('hidden');
|
|
1109
|
+
}
|
|
1110
|
+
isSelected(kind, id) {
|
|
1111
|
+
return kind === 'node' ? this.selectedNodeIds.includes(id) : this.selectedLinkIds.includes(id);
|
|
1112
|
+
}
|
|
1113
|
+
isDimmed(kind, id) {
|
|
1114
|
+
return kind === 'node' ? this.dimmedNodeIds.includes(id) : this.dimmedLinkIds.includes(id);
|
|
1115
|
+
}
|
|
1116
|
+
linkKey(link) {
|
|
1117
|
+
const source = typeof link.source === 'object' ? link.source.id : String(link.source);
|
|
1118
|
+
const target = typeof link.target === 'object' ? link.target.id : String(link.target);
|
|
1119
|
+
return link.id ?? `${source}->${target}`;
|
|
1120
|
+
}
|
|
1121
|
+
/** Computes and emits the selection intent for activating `id`; never assigns
|
|
1122
|
+
* `selectedNodeIds`/`selectedLinkIds` itself -- see the class doc's controlled-selection note. */
|
|
1123
|
+
emitSelectionIntent(kind, id, toggle) {
|
|
1124
|
+
if (this.selectionMode === 'none')
|
|
1125
|
+
return;
|
|
1126
|
+
const selected = this.isSelected(kind, id);
|
|
1127
|
+
if (this.selectionMode === 'single' || !toggle) {
|
|
1128
|
+
if (this.selectionMode === 'single' && selected) {
|
|
1129
|
+
this.emit('lyra-selection-change', { nodeIds: [], linkIds: [] });
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
this.emit('lyra-selection-change', kind === 'node' ? { nodeIds: [id], linkIds: [] } : { nodeIds: [], linkIds: [id] });
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1135
|
+
const nodeIds = kind === 'node'
|
|
1136
|
+
? selected
|
|
1137
|
+
? this.selectedNodeIds.filter((x) => x !== id)
|
|
1138
|
+
: [...this.selectedNodeIds, id]
|
|
1139
|
+
: this.selectedNodeIds;
|
|
1140
|
+
const linkIds = kind === 'link'
|
|
1141
|
+
? selected
|
|
1142
|
+
? this.selectedLinkIds.filter((x) => x !== id)
|
|
1143
|
+
: [...this.selectedLinkIds, id]
|
|
1144
|
+
: this.selectedLinkIds;
|
|
1145
|
+
this.emit('lyra-selection-change', { nodeIds, linkIds });
|
|
1146
|
+
}
|
|
1147
|
+
clearSelection() {
|
|
1148
|
+
if (this.selectionMode === 'none')
|
|
1149
|
+
return;
|
|
1150
|
+
if (!this.selectedNodeIds.length && !this.selectedLinkIds.length)
|
|
1151
|
+
return;
|
|
1152
|
+
this.emit('lyra-selection-change', { nodeIds: [], linkIds: [] });
|
|
1153
|
+
}
|
|
177
1154
|
willUpdate(changed) {
|
|
178
1155
|
// rebuildSimulation() (re)assigns the simNodes/simLinks reactive
|
|
179
1156
|
// properties — doing that from willUpdate() folds them into the render
|
|
@@ -181,9 +1158,27 @@ export class LyraGraph extends LyraElement {
|
|
|
181
1158
|
// instead would set a reactive property *after* the update completed,
|
|
182
1159
|
// which Lit schedules as a whole extra update pass (a dev-mode warning,
|
|
183
1160
|
// and pointless work).
|
|
184
|
-
if (this.d3 &&
|
|
1161
|
+
if (this.d3 &&
|
|
1162
|
+
(changed.has('nodes') ||
|
|
1163
|
+
changed.has('links') ||
|
|
1164
|
+
changed.has('hiddenTypes') ||
|
|
1165
|
+
changed.has('layout') ||
|
|
1166
|
+
(this.layout === 'layered' && changed.has('linkDistance')))) {
|
|
185
1167
|
this.rebuildSimulation();
|
|
186
1168
|
}
|
|
1169
|
+
// rebuildSimulation() above always reassigns simNodes, so checking it here (after that call)
|
|
1170
|
+
// also catches a nodes/links/hiddenTypes-driven rebuild, not just a direct communities set.
|
|
1171
|
+
if (changed.has('simNodes') || changed.has('communities')) {
|
|
1172
|
+
this.visibleCommunitiesCache = undefined;
|
|
1173
|
+
}
|
|
1174
|
+
// Same reasoning as rebuildSimulation() above -- assigning graphLiveText from updated() would
|
|
1175
|
+
// schedule a whole extra update pass instead of landing in the render this update is already
|
|
1176
|
+
// about to perform.
|
|
1177
|
+
if (changed.has('selectedNodeIds') || changed.has('selectedLinkIds')) {
|
|
1178
|
+
this.graphLiveText = this.localize('graphSelectionCount', undefined, {
|
|
1179
|
+
count: this.selectedNodeIds.length + this.selectedLinkIds.length,
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
187
1182
|
}
|
|
188
1183
|
updated(changed) {
|
|
189
1184
|
if (this.loading)
|
|
@@ -192,13 +1187,13 @@ export class LyraGraph extends LyraElement {
|
|
|
192
1187
|
this.removeAttribute('aria-busy');
|
|
193
1188
|
if (!this.d3)
|
|
194
1189
|
return;
|
|
195
|
-
if (!changed.has('nodes') && !changed.has('links')) {
|
|
1190
|
+
if (!changed.has('nodes') && !changed.has('links') && !changed.has('hiddenTypes')) {
|
|
196
1191
|
// These two branches are independent (not else-if): a consumer can set
|
|
197
1192
|
// width/height and chargeStrength/linkDistance in the same reactive
|
|
198
1193
|
// update batch, and both retunes must apply — not just whichever branch
|
|
199
1194
|
// happens to come first.
|
|
200
1195
|
if (changed.has('width') || changed.has('height')) {
|
|
201
|
-
this.simulation?.force('center', this.d3.forceCenter(this.
|
|
1196
|
+
this.simulation?.force('center', this.d3.forceCenter(this.safeWidth / 2, this.safeHeight / 2));
|
|
202
1197
|
this.simulation?.alpha(0.1).restart();
|
|
203
1198
|
}
|
|
204
1199
|
if (changed.has('chargeStrength') || changed.has('linkDistance')) {
|
|
@@ -207,9 +1202,9 @@ export class LyraGraph extends LyraElement {
|
|
|
207
1202
|
// them fresh) — retune the already-created force objects in place
|
|
208
1203
|
// instead of rebuilding the whole simulation.
|
|
209
1204
|
if (changed.has('chargeStrength'))
|
|
210
|
-
this.chargeForce?.strength(this.
|
|
1205
|
+
this.chargeForce?.strength(this.safeChargeStrength);
|
|
211
1206
|
if (changed.has('linkDistance'))
|
|
212
|
-
this.linkForce?.distance(this.
|
|
1207
|
+
this.linkForce?.distance(this.safeLinkDistance);
|
|
213
1208
|
this.simulation?.alpha(0.3).restart();
|
|
214
1209
|
}
|
|
215
1210
|
}
|
|
@@ -218,6 +1213,15 @@ export class LyraGraph extends LyraElement {
|
|
|
218
1213
|
// node/link querySelectorAll scan on that is equivalent to "structurally
|
|
219
1214
|
// changed" without needing a separate flag.
|
|
220
1215
|
this.applyInteractions(changed);
|
|
1216
|
+
this.applyCanvasInteractions();
|
|
1217
|
+
if (this.focusId == null) {
|
|
1218
|
+
this.lastAppliedFocusId = null;
|
|
1219
|
+
}
|
|
1220
|
+
else if (this.focusId !== this.lastAppliedFocusId && this.simNodes.some((n) => n.id === this.focusId)) {
|
|
1221
|
+
this.lastAppliedFocusId = this.focusId;
|
|
1222
|
+
void this.focusNode(this.focusId);
|
|
1223
|
+
}
|
|
1224
|
+
this.updateFocusHalo();
|
|
221
1225
|
}
|
|
222
1226
|
/**
|
|
223
1227
|
* Imperatively wires up d3-zoom (pan/zoom on the `<svg>`) and d3-drag
|
|
@@ -243,58 +1247,115 @@ export class LyraGraph extends LyraElement {
|
|
|
243
1247
|
applyInteractions(changed) {
|
|
244
1248
|
if (!this.d3)
|
|
245
1249
|
return;
|
|
1250
|
+
if (this.renderer !== 'svg')
|
|
1251
|
+
return;
|
|
246
1252
|
const svgEl = this.renderRoot.querySelector('svg');
|
|
247
1253
|
if (svgEl && svgEl !== this.zoomedEl) {
|
|
1254
|
+
// Binding a fresh svg means any previous renderer="canvas" surface is gone -- stop its
|
|
1255
|
+
// resize watcher now (it observes the host, not the removed <canvas>, so it would keep
|
|
1256
|
+
// firing markCanvasDirty() for as long as the element lives in svg mode).
|
|
1257
|
+
this.canvasResizeObserver?.disconnect();
|
|
1258
|
+
this.canvasResizeObserver = undefined;
|
|
248
1259
|
this.zoomedEl = svgEl;
|
|
249
1260
|
this.gEl = this.renderRoot.querySelector('g') ?? undefined;
|
|
1261
|
+
this.focusHaloEl = this.renderRoot.querySelector('[part="focus-halo"]') ?? undefined;
|
|
250
1262
|
this.zoomBehavior = this.d3
|
|
251
1263
|
.zoom()
|
|
252
|
-
.scaleExtent([this.
|
|
1264
|
+
.scaleExtent([this.safeMinZoom, this.safeMaxZoom])
|
|
1265
|
+
.on('start', () => {
|
|
1266
|
+
// A camera tween writes a transform on every frame via applyZoomTransform(), which
|
|
1267
|
+
// itself synchronously replays this same 'start' handler -- ignore that self-triggered
|
|
1268
|
+
// echo so a tween doesn't cancel itself on its own first frame.
|
|
1269
|
+
if (this.isApplyingZoomTransform)
|
|
1270
|
+
return;
|
|
1271
|
+
this.isPanning = true;
|
|
1272
|
+
this.cancelCameraTween();
|
|
1273
|
+
})
|
|
253
1274
|
.on('zoom', (event) => {
|
|
254
1275
|
this.gEl?.setAttribute('transform', event.transform.toString());
|
|
1276
|
+
this.updateEdgeLabelZoomGate(event.transform.k);
|
|
1277
|
+
})
|
|
1278
|
+
.on('end', () => {
|
|
1279
|
+
this.isPanning = false;
|
|
255
1280
|
});
|
|
256
1281
|
this.d3.select(svgEl).call(this.zoomBehavior);
|
|
1282
|
+
// `.call(zoomBehavior)` does not synchronously fire the 'zoom' handler above (only a real
|
|
1283
|
+
// user gesture or an explicit `.transform()` call does, and nothing in this component ever
|
|
1284
|
+
// calls `.transform()`) -- so the initial transform right here is always d3-zoom's own
|
|
1285
|
+
// identity transform, k=1. Apply the edge-label zoom gate against that known value now, or
|
|
1286
|
+
// it stays unset (edge labels wrongly visible) until the user's first pan/zoom, regardless
|
|
1287
|
+
// of what edgeLabelMinZoom actually is.
|
|
1288
|
+
this.updateEdgeLabelZoomGate(1);
|
|
257
1289
|
}
|
|
258
1290
|
else if (this.zoomBehavior && (changed.has('minZoom') || changed.has('maxZoom'))) {
|
|
259
|
-
this.zoomBehavior.scaleExtent([this.
|
|
1291
|
+
this.zoomBehavior.scaleExtent([this.safeMinZoom, this.safeMaxZoom]);
|
|
260
1292
|
}
|
|
261
|
-
if (!(changed.has('simNodes') ||
|
|
1293
|
+
if (!(changed.has('simNodes') ||
|
|
1294
|
+
changed.has('simLinks') ||
|
|
1295
|
+
changed.has('nodeTypes') ||
|
|
1296
|
+
changed.has('showEdgeLabels') ||
|
|
1297
|
+
changed.has('communities')))
|
|
262
1298
|
return;
|
|
263
1299
|
const nodeEls = Array.from(this.renderRoot.querySelectorAll('[part="node"]'));
|
|
264
1300
|
this.nodeEls = nodeEls;
|
|
265
1301
|
this.nodeLabelEls = nodeEls.map((el) => el.parentElement?.querySelector('[part="label"]') ?? null);
|
|
1302
|
+
this.expandIndicatorEls = nodeEls.map((el) => el.parentElement?.querySelector('[part="expand-indicator"]') ?? null);
|
|
266
1303
|
// Dangling stubs also carry part="link" (so they inherit the same themeable styling as a
|
|
267
1304
|
// real edge) -- excluded here explicitly so `linkEls` stays index-aligned with `simLinks`
|
|
268
1305
|
// rather than relying on stubs always sorting after real links in template/DOM order.
|
|
269
1306
|
this.linkEls = Array.from(this.renderRoot.querySelectorAll('[part="link"]:not([data-dangling])'));
|
|
1307
|
+
this.linkLabelEls = this.linkEls.map((el) => el.parentElement?.querySelector('[part="link-label"]') ?? null);
|
|
1308
|
+
this.linkLabelHiddenByLength = [];
|
|
270
1309
|
this.danglingLinkEls = Array.from(this.renderRoot.querySelectorAll('[part="link"][data-dangling]'));
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
this.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
1310
|
+
this.communityHullEls = Array.from(this.renderRoot.querySelectorAll('[part="hull"]'));
|
|
1311
|
+
this.communityLabelEls = Array.from(this.renderRoot.querySelectorAll('[part="community-label"]'));
|
|
1312
|
+
if (this.layout !== 'layered') {
|
|
1313
|
+
nodeEls.forEach((el, i) => {
|
|
1314
|
+
if (this.boundNodeEls.has(el))
|
|
1315
|
+
return;
|
|
1316
|
+
const n = this.simNodes[i];
|
|
1317
|
+
if (!n)
|
|
1318
|
+
return;
|
|
1319
|
+
this.boundNodeEls.add(el);
|
|
1320
|
+
this.d3.select(el).call(this.d3.drag()
|
|
1321
|
+
.on('start', (event) => {
|
|
1322
|
+
this.isDragging = true;
|
|
1323
|
+
// Keep a node drag from also triggering the svg's own pan gesture.
|
|
1324
|
+
event.sourceEvent?.stopPropagation();
|
|
1325
|
+
if (!event.active)
|
|
1326
|
+
this.simulation?.alphaTarget(0.3).restart();
|
|
1327
|
+
n.fx = n.x;
|
|
1328
|
+
n.fy = n.y;
|
|
1329
|
+
})
|
|
1330
|
+
.on('drag', (event) => {
|
|
1331
|
+
n.fx = event.x;
|
|
1332
|
+
n.fy = event.y;
|
|
1333
|
+
})
|
|
1334
|
+
.on('end', (event) => {
|
|
1335
|
+
this.isDragging = false;
|
|
1336
|
+
if (!event.active)
|
|
1337
|
+
this.simulation?.alphaTarget(0);
|
|
1338
|
+
n.fx = null;
|
|
1339
|
+
n.fy = null;
|
|
1340
|
+
}));
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
/** The `renderer="canvas"` twin of `applyInteractions()`'s svg zoom-bind branch -- binds d3-zoom
|
|
1345
|
+
* and the pointer/hit-testing handlers to the just-rendered `<canvas>` once (guarded by the same
|
|
1346
|
+
* `zoomedEl` field `applyInteractions()` uses, so `focusNode()`/`fit()`/`tweenCamera()` keep
|
|
1347
|
+
* working unmodified against whichever element -- svg or canvas -- is currently bound), then
|
|
1348
|
+
* marks the canvas dirty on every call so any structural/style-affecting change (new nodes/
|
|
1349
|
+
* links, a selection change, a hiddenTypes toggle, ...) schedules a fresh draw the same way a
|
|
1350
|
+
* Lit re-render already does for svg mode. */
|
|
1351
|
+
applyCanvasInteractions() {
|
|
1352
|
+
if (this.renderer !== 'canvas' || !this.canvasEl)
|
|
1353
|
+
return;
|
|
1354
|
+
if (this.canvasEl !== this.zoomedEl) {
|
|
1355
|
+
this.zoomedEl = this.canvasEl;
|
|
1356
|
+
this.setUpCanvasSurface();
|
|
1357
|
+
}
|
|
1358
|
+
this.markCanvasDirty();
|
|
298
1359
|
}
|
|
299
1360
|
/**
|
|
300
1361
|
* Runs on every d3-force simulation tick (up to ~300 while a graph settles
|
|
@@ -315,11 +1376,26 @@ export class LyraGraph extends LyraElement {
|
|
|
315
1376
|
target.x = (source.x ?? 0) + STUB_OFFSET_PX;
|
|
316
1377
|
target.y = (source.y ?? 0) + STUB_OFFSET_PX;
|
|
317
1378
|
}
|
|
1379
|
+
// Keep the remembered-position cache current with a position captured mid-settle or mid-drag
|
|
1380
|
+
// (not just the one snapshotted at the end of rebuildSimulation()) -- a hiddenTypes toggle
|
|
1381
|
+
// that lands before the next structural rebuild should still restore a node to where it
|
|
1382
|
+
// actually was, not an earlier, since-superseded snapshot. Plain Map writes, no DOM/no
|
|
1383
|
+
// reactive-property touch, so this stays on the same cheap per-tick path as the rest of this
|
|
1384
|
+
// method.
|
|
1385
|
+
for (const n of this.simNodes) {
|
|
1386
|
+
if (n.x != null && n.y != null)
|
|
1387
|
+
this.lastPositionById.set(n.id, { x: n.x, y: n.y });
|
|
1388
|
+
}
|
|
318
1389
|
this.simNodes.forEach((n, i) => {
|
|
319
|
-
const
|
|
320
|
-
if (
|
|
321
|
-
|
|
322
|
-
|
|
1390
|
+
const el = this.nodeEls[i];
|
|
1391
|
+
if (el) {
|
|
1392
|
+
if (el.tagName === 'circle') {
|
|
1393
|
+
el.setAttribute('cx', String(n.x ?? 0));
|
|
1394
|
+
el.setAttribute('cy', String(n.y ?? 0));
|
|
1395
|
+
}
|
|
1396
|
+
else {
|
|
1397
|
+
el.setAttribute('transform', `translate(${n.x ?? 0},${n.y ?? 0})`);
|
|
1398
|
+
}
|
|
323
1399
|
}
|
|
324
1400
|
const label = this.nodeLabelEls[i];
|
|
325
1401
|
if (label) {
|
|
@@ -337,6 +1413,28 @@ export class LyraGraph extends LyraElement {
|
|
|
337
1413
|
line.setAttribute('x2', String(coordinates.x2));
|
|
338
1414
|
line.setAttribute('y2', String(coordinates.y2));
|
|
339
1415
|
});
|
|
1416
|
+
if (this.showEdgeLabels) {
|
|
1417
|
+
this.simLinks.forEach((l, i) => {
|
|
1418
|
+
const labelEl = this.linkLabelEls[i];
|
|
1419
|
+
if (!labelEl)
|
|
1420
|
+
return;
|
|
1421
|
+
const pos = this.edgeLabelPosition(l);
|
|
1422
|
+
labelEl.setAttribute('x', String(pos.x));
|
|
1423
|
+
labelEl.setAttribute('y', String(pos.y));
|
|
1424
|
+
const { x1, y1, x2, y2 } = this.linkCoordinates(l);
|
|
1425
|
+
const edgeLength = Math.hypot(x2 - x1, y2 - y1);
|
|
1426
|
+
const tooLong = this.edgeLabelWidth(l.label ?? '') > edgeLength * EDGE_LABEL_LENGTH_GATE_RATIO;
|
|
1427
|
+
if (this.linkLabelHiddenByLength[i] !== tooLong) {
|
|
1428
|
+
this.linkLabelHiddenByLength[i] = tooLong;
|
|
1429
|
+
labelEl.setAttribute('visibility', tooLong ? 'hidden' : 'visible');
|
|
1430
|
+
}
|
|
1431
|
+
});
|
|
1432
|
+
}
|
|
1433
|
+
this.simNodes.forEach((n, i) => {
|
|
1434
|
+
const indicator = this.expandIndicatorEls[i];
|
|
1435
|
+
if (indicator)
|
|
1436
|
+
indicator.setAttribute('transform', `translate(${n.x ?? 0},${n.y ?? 0})`);
|
|
1437
|
+
});
|
|
340
1438
|
// Dangling stubs are excluded from d3-force's own simulation input (see
|
|
341
1439
|
// rebuildSimulation()'s "stubs never enter d3-force's own simulation input"), so the
|
|
342
1440
|
// synthetic target position the danglingLinks loop at the top of this method just
|
|
@@ -353,12 +1451,41 @@ export class LyraGraph extends LyraElement {
|
|
|
353
1451
|
line.setAttribute('x2', String(coordinates.x2));
|
|
354
1452
|
line.setAttribute('y2', String(coordinates.y2));
|
|
355
1453
|
});
|
|
1454
|
+
this.updateFocusHalo();
|
|
1455
|
+
this.visibleCommunities().forEach((entry, i) => {
|
|
1456
|
+
const hullEl = this.communityHullEls[i];
|
|
1457
|
+
const labelEl = this.communityLabelEls[i];
|
|
1458
|
+
if (!hullEl && !labelEl)
|
|
1459
|
+
return;
|
|
1460
|
+
const hull = this.communityHull(entry.members);
|
|
1461
|
+
if (hullEl)
|
|
1462
|
+
hullEl.setAttribute('d', hullPathD(hull));
|
|
1463
|
+
if (labelEl) {
|
|
1464
|
+
labelEl.setAttribute('x', String(hullCentroidX(hull)));
|
|
1465
|
+
labelEl.setAttribute('y', String(hullTopY(hull) - HULL_PADDING));
|
|
1466
|
+
}
|
|
1467
|
+
});
|
|
1468
|
+
// renderer="canvas" mode has no DOM to write positions straight to (everything above this line
|
|
1469
|
+
// no-ops there: nodeEls/linkEls/etc. are only ever populated by applyInteractions()'s svg-only
|
|
1470
|
+
// branch) -- schedule a fresh draw off the same simulation tick instead, so the settle
|
|
1471
|
+
// animation and a live node drag actually repaint the canvas rather than freezing at whatever
|
|
1472
|
+
// was last drawn on mount.
|
|
1473
|
+
if (this.renderer === 'canvas')
|
|
1474
|
+
this.markCanvasDirty();
|
|
356
1475
|
}
|
|
357
1476
|
rebuildSimulation() {
|
|
358
1477
|
if (!this.d3)
|
|
359
1478
|
return;
|
|
360
1479
|
this.simulation?.stop();
|
|
361
1480
|
this.boundNodeEls = new WeakSet();
|
|
1481
|
+
// Prune remembered positions for ids no longer present in `this.nodes` at all (not merely
|
|
1482
|
+
// hidden by hiddenTypes) -- otherwise this cache would grow forever across a long-lived,
|
|
1483
|
+
// mutating graph instead of tracking only ids that could plausibly reappear.
|
|
1484
|
+
const liveIds = new Set(this.nodes.map((n) => n.id));
|
|
1485
|
+
for (const id of this.lastPositionById.keys()) {
|
|
1486
|
+
if (!liveIds.has(id))
|
|
1487
|
+
this.lastPositionById.delete(id);
|
|
1488
|
+
}
|
|
362
1489
|
// Carry over each existing SimNode's settled position/velocity (and any
|
|
363
1490
|
// in-progress drag fx/fy) by id instead of starting every node fresh —
|
|
364
1491
|
// otherwise any structural nodes/links change (e.g. appending one new
|
|
@@ -367,60 +1494,98 @@ export class LyraGraph extends LyraElement {
|
|
|
367
1494
|
// start settle animation from scratch. Only nodes with no previous
|
|
368
1495
|
// counterpart (genuinely new ids) get forceSimulation()'s default
|
|
369
1496
|
// fresh random start below.
|
|
1497
|
+
const visible = this.visibleNodes();
|
|
1498
|
+
if (this.layout === 'layered') {
|
|
1499
|
+
this.rebuildLayeredLayout(visible);
|
|
1500
|
+
return;
|
|
1501
|
+
}
|
|
370
1502
|
const prevById = new Map(this.simNodes.map((n) => [n.id, n]));
|
|
371
|
-
const nodes =
|
|
1503
|
+
const nodes = visible.map((n) => {
|
|
372
1504
|
const prev = prevById.get(n.id);
|
|
373
|
-
|
|
1505
|
+
if (prev)
|
|
1506
|
+
return { ...prev, ...n };
|
|
1507
|
+
// A node hidden by hiddenTypes and now visible again has no prevById entry (it fell out of
|
|
1508
|
+
// simNodes while hidden) but may still have a remembered settled position from before it was
|
|
1509
|
+
// hidden -- restore that instead of leaving it for the neighbor-jitter/seed spawn logic below,
|
|
1510
|
+
// or forceSimulation()'s own random start, to place it as if it were a brand-new node.
|
|
1511
|
+
const remembered = this.lastPositionById.get(n.id);
|
|
1512
|
+
return remembered ? { ...n, x: remembered.x, y: remembered.y } : { ...n };
|
|
374
1513
|
});
|
|
375
1514
|
const byId = new Map(nodes.map((n) => [n.id, n]));
|
|
376
|
-
const resolvedLinks =
|
|
377
|
-
const danglingLinks = [];
|
|
378
|
-
for (const l of this.links) {
|
|
379
|
-
const source = byId.get(l.source);
|
|
380
|
-
if (!source)
|
|
381
|
-
continue; // no real position to draw a stub from -- stays dropped, unchanged
|
|
382
|
-
const target = byId.get(l.target);
|
|
383
|
-
if (target) {
|
|
384
|
-
resolvedLinks.push({ ...l, source, target });
|
|
385
|
-
}
|
|
386
|
-
else {
|
|
387
|
-
danglingLinks.push({
|
|
388
|
-
...l,
|
|
389
|
-
source,
|
|
390
|
-
target: { id: l.target, x: source.x, y: source.y },
|
|
391
|
-
dangling: true,
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
}
|
|
1515
|
+
const { resolved: resolvedLinks, dangling: danglingLinks } = this.resolveLinksAgainst(byId);
|
|
395
1516
|
const links = resolvedLinks; // stubs never enter d3-force's own simulation input
|
|
396
1517
|
this.danglingLinks = danglingLinks;
|
|
397
|
-
|
|
398
|
-
//
|
|
399
|
-
//
|
|
400
|
-
//
|
|
401
|
-
//
|
|
1518
|
+
const seedForSpawn = this.safeSeed;
|
|
1519
|
+
// Give a brand-new node with no carried-over position (from prevById above) a spawn point
|
|
1520
|
+
// near an already-positioned neighbor instead of forceSimulation()'s eventual random start --
|
|
1521
|
+
// expanded neighborhoods bloom around their origin instead of flying in from nowhere. Only
|
|
1522
|
+
// touches nodes with no position yet, so it can't move anything already settled.
|
|
1523
|
+
for (const n of nodes) {
|
|
1524
|
+
if (n.x != null && n.y != null)
|
|
1525
|
+
continue;
|
|
1526
|
+
const neighborLink = resolvedLinks.find((l) => {
|
|
1527
|
+
const source = l.source;
|
|
1528
|
+
const target = l.target;
|
|
1529
|
+
return (source.id === n.id && target.x != null) || (target.id === n.id && source.x != null);
|
|
1530
|
+
});
|
|
1531
|
+
if (!neighborLink)
|
|
1532
|
+
continue;
|
|
1533
|
+
const source = neighborLink.source;
|
|
1534
|
+
const target = neighborLink.target;
|
|
1535
|
+
const neighbor = source.id === n.id ? target : source;
|
|
1536
|
+
const jitterRadius = this.safeLinkDistance / 2;
|
|
1537
|
+
const angle = seedForSpawn != null
|
|
1538
|
+
? (hashNodeSeed(seedForSpawn, n.id) / 4294967296) * Math.PI * 2
|
|
1539
|
+
: Math.random() * Math.PI * 2;
|
|
1540
|
+
n.x = (neighbor.x ?? 0) + Math.cos(angle) * jitterRadius;
|
|
1541
|
+
n.y = (neighbor.y ?? 0) + Math.sin(angle) * jitterRadius;
|
|
1542
|
+
}
|
|
1543
|
+
// Give any remaining brand-new nodes (no carried-over position from prevById above, and no
|
|
1544
|
+
// already-positioned neighbor for the jitter spawn above to anchor to) a deterministic
|
|
1545
|
+
// starting x/y, keyed by node id, instead of leaving them for forceSimulation() below to
|
|
1546
|
+
// randomize. Nodes that already have a position are left untouched — same "only randomize
|
|
1547
|
+
// nodes without x/y" rule forceSimulation() itself follows — so an incremental update to a
|
|
402
1548
|
// seeded, already-settled graph doesn't reshuffle existing nodes.
|
|
403
|
-
|
|
404
|
-
if (seed != null) {
|
|
1549
|
+
if (seedForSpawn != null) {
|
|
405
1550
|
for (const n of nodes) {
|
|
406
1551
|
if (n.x != null && n.y != null)
|
|
407
1552
|
continue;
|
|
408
|
-
const rng = mulberry32(hashNodeSeed(
|
|
409
|
-
n.x = rng() * this.
|
|
410
|
-
n.y = rng() * this.
|
|
1553
|
+
const rng = mulberry32(hashNodeSeed(seedForSpawn, n.id));
|
|
1554
|
+
n.x = rng() * this.safeWidth;
|
|
1555
|
+
n.y = rng() * this.safeHeight;
|
|
411
1556
|
}
|
|
412
1557
|
}
|
|
413
|
-
this.linkForce = this.d3.forceLink(links).distance(this.
|
|
414
|
-
this.chargeForce = this.d3.forceManyBody().strength(this.
|
|
1558
|
+
this.linkForce = this.d3.forceLink(links).distance(this.safeLinkDistance);
|
|
1559
|
+
this.chargeForce = this.d3.forceManyBody().strength(this.safeChargeStrength);
|
|
415
1560
|
const simulation = this.d3
|
|
416
1561
|
.forceSimulation(nodes)
|
|
417
1562
|
.force('link', this.linkForce)
|
|
418
1563
|
.force('charge', this.chargeForce)
|
|
419
|
-
.force('center', this.d3.forceCenter(this.
|
|
1564
|
+
.force('center', this.d3.forceCenter(this.safeWidth / 2, this.safeHeight / 2))
|
|
420
1565
|
.force('collide', this.d3.forceCollide().radius((n) => this.nodeRadius(n) + 10))
|
|
421
1566
|
.on('tick', () => this.onTick());
|
|
422
1567
|
this.simulation = simulation;
|
|
423
|
-
if (prefersReducedMotion() || this.
|
|
1568
|
+
if (prefersReducedMotion() || this.safeSeed != null) {
|
|
1569
|
+
// Pin every node that already had a known position before this rebuild -- either carried
|
|
1570
|
+
// over directly (fx/fy, the same mechanism a user drag uses) or restored from
|
|
1571
|
+
// lastPositionById after being hidden by hiddenTypes -- so introducing a new node/link can't
|
|
1572
|
+
// visibly reposition it during this synchronous settle. Only a genuinely new node (no prior
|
|
1573
|
+
// counterpart in either source) is free to move while the simulation converges. A node whose
|
|
1574
|
+
// fx/fy was already set (an active user drag concurrent with this rebuild) is left alone
|
|
1575
|
+
// entirely -- both the pin and the later release below only apply to a node this loop itself
|
|
1576
|
+
// pinned, so a real in-progress drag's own fx/fy is never clobbered. Everything this loop
|
|
1577
|
+
// does pin gets released again immediately below, so this has no lasting effect on a later
|
|
1578
|
+
// user-initiated drag, nor on the live, async settle a non-seeded/non-reduced-motion graph
|
|
1579
|
+
// still animates over ~300 frames.
|
|
1580
|
+
const pinnedForSettle = new Set();
|
|
1581
|
+
for (const n of nodes) {
|
|
1582
|
+
const hadKnownPosition = prevById.has(n.id) || this.lastPositionById.has(n.id);
|
|
1583
|
+
if (hadKnownPosition && n.x != null && n.y != null && n.fx == null && n.fy == null) {
|
|
1584
|
+
n.fx = n.x;
|
|
1585
|
+
n.fy = n.y;
|
|
1586
|
+
pinnedForSettle.add(n.id);
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
424
1589
|
// Converge synchronously instead of animating the settle over ~300
|
|
425
1590
|
// rendered frames — the simulation is already stopped (alpha at
|
|
426
1591
|
// alphaMin) by the time the DOM for this rebuild is first painted.
|
|
@@ -431,6 +1596,12 @@ export class LyraGraph extends LyraElement {
|
|
|
431
1596
|
simulation.stop();
|
|
432
1597
|
while (simulation.alpha() > simulation.alphaMin())
|
|
433
1598
|
simulation.tick();
|
|
1599
|
+
for (const n of nodes) {
|
|
1600
|
+
if (pinnedForSettle.has(n.id)) {
|
|
1601
|
+
n.fx = null;
|
|
1602
|
+
n.fy = null;
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
434
1605
|
}
|
|
435
1606
|
// Assign these SAME array/object references (not copies) exactly once
|
|
436
1607
|
// for this structural rebuild: forceSimulation(nodes) above already
|
|
@@ -442,17 +1613,137 @@ export class LyraGraph extends LyraElement {
|
|
|
442
1613
|
// re-render up to ~300 times on load and continuously while dragging.
|
|
443
1614
|
this.simNodes = nodes;
|
|
444
1615
|
this.simLinks = links;
|
|
1616
|
+
for (const n of nodes) {
|
|
1617
|
+
if (n.x != null && n.y != null)
|
|
1618
|
+
this.lastPositionById.set(n.id, { x: n.x, y: n.y });
|
|
1619
|
+
}
|
|
1620
|
+
this.announceHiddenNodeCount(nodes.length);
|
|
1621
|
+
}
|
|
1622
|
+
/** Announces the current hidden-node count via the live region -- shared by both the force and
|
|
1623
|
+
* layered rebuild paths (each calls this with its own final visible-node count) so `hiddenTypes`
|
|
1624
|
+
* filtering announces identically regardless of `layout`. Called from right here (not from
|
|
1625
|
+
* willUpdate()/updated() gated on a 'hiddenTypes'/'nodes' PropertyValues diff) because
|
|
1626
|
+
* rebuildSimulation() itself is also invoked directly from connectedCallback() once the lazy d3
|
|
1627
|
+
* peer deps resolve -- a call that never goes through Lit's changed-property diffing at all.
|
|
1628
|
+
* Computing it there instead would miss that path entirely: a graph mounted with hiddenTypes
|
|
1629
|
+
* already set would compute this from a still-empty simNodes (0 settled nodes yet) on the
|
|
1630
|
+
* property-driven pass, then never get a chance to correct it once the real simNodes became
|
|
1631
|
+
* available. Only ever touches graphLiveText when there's something to say -- a node is
|
|
1632
|
+
* currently hidden, or one just stopped being hidden -- so a consumer that never sets
|
|
1633
|
+
* hiddenTypes keeps today's exact live-region output. */
|
|
1634
|
+
announceHiddenNodeCount(visibleNodeCount) {
|
|
1635
|
+
const totalNodeCount = this.nodes.length;
|
|
1636
|
+
const hiddenNodeCount = totalNodeCount - visibleNodeCount;
|
|
1637
|
+
if (totalNodeCount > 0 && (hiddenNodeCount > 0 || this.lastHiddenNodeCount > 0)) {
|
|
1638
|
+
this.graphLiveText = this.localize('graphNodesHidden', undefined, {
|
|
1639
|
+
hidden: hiddenNodeCount,
|
|
1640
|
+
total: totalNodeCount,
|
|
1641
|
+
});
|
|
1642
|
+
}
|
|
1643
|
+
this.lastHiddenNodeCount = hiddenNodeCount;
|
|
1644
|
+
}
|
|
1645
|
+
/** The `layout="layered"` path: computes final positions synchronously via the shared
|
|
1646
|
+
* `layeredLayout()` util (2r x 2r boxes, `gapY = linkDistance`, `gapX = 12`), centers the
|
|
1647
|
+
* drawing in `width` x `height`, and skips forceSimulation() entirely -- no `this.simulation`,
|
|
1648
|
+
* no ticking, no `prevById` carry-over (deterministic input -> output makes it unnecessary; a
|
|
1649
|
+
* structural change simply recomputes wholesale). `lyra-graph` never passes `fixedPositions`. */
|
|
1650
|
+
rebuildLayeredLayout(visible) {
|
|
1651
|
+
const boxes = visible.map((n) => {
|
|
1652
|
+
const r = this.nodeRadius(n);
|
|
1653
|
+
return { id: n.id, width: r * 2, height: r * 2 };
|
|
1654
|
+
});
|
|
1655
|
+
const visibleIds = new Set(visible.map((n) => n.id));
|
|
1656
|
+
const edges = this.links
|
|
1657
|
+
.filter((l) => visibleIds.has(l.source) && visibleIds.has(l.target))
|
|
1658
|
+
.map((l) => ({ source: l.source, target: l.target }));
|
|
1659
|
+
const raw = layeredLayout({ nodes: boxes, edges, options: { gapX: 12, gapY: this.safeLinkDistance } });
|
|
1660
|
+
let minX = Infinity;
|
|
1661
|
+
let minY = Infinity;
|
|
1662
|
+
let maxX = -Infinity;
|
|
1663
|
+
let maxY = -Infinity;
|
|
1664
|
+
for (const p of raw.values()) {
|
|
1665
|
+
minX = Math.min(minX, p.x);
|
|
1666
|
+
maxX = Math.max(maxX, p.x);
|
|
1667
|
+
minY = Math.min(minY, p.y);
|
|
1668
|
+
maxY = Math.max(maxY, p.y);
|
|
1669
|
+
}
|
|
1670
|
+
const offsetX = raw.size ? this.safeWidth / 2 - (minX + (maxX - minX) / 2) : this.safeWidth / 2;
|
|
1671
|
+
const offsetY = raw.size ? this.safeHeight / 2 - (minY + (maxY - minY) / 2) : this.safeHeight / 2;
|
|
1672
|
+
const nodes = visible.map((n) => {
|
|
1673
|
+
const p = raw.get(n.id);
|
|
1674
|
+
return { ...n, x: (p?.x ?? this.safeWidth / 2) + offsetX, y: (p?.y ?? this.safeHeight / 2) + offsetY };
|
|
1675
|
+
});
|
|
1676
|
+
const byId = new Map(nodes.map((n) => [n.id, n]));
|
|
1677
|
+
const { resolved, dangling } = this.resolveLinksAgainst(byId);
|
|
1678
|
+
this.danglingLinks = dangling;
|
|
1679
|
+
this.simulation = undefined;
|
|
1680
|
+
this.simNodes = nodes;
|
|
1681
|
+
this.simLinks = resolved;
|
|
1682
|
+
for (const n of nodes) {
|
|
1683
|
+
if (n.x != null && n.y != null)
|
|
1684
|
+
this.lastPositionById.set(n.id, { x: n.x, y: n.y });
|
|
1685
|
+
}
|
|
1686
|
+
this.announceHiddenNodeCount(nodes.length);
|
|
445
1687
|
}
|
|
446
|
-
onNodeClick(node) {
|
|
447
|
-
this.emit('lyra-node-click', { id: node.id });
|
|
1688
|
+
onNodeClick(node, e) {
|
|
1689
|
+
this.emit('lyra-node-click', { id: node.id, x: node.x ?? 0, y: node.y ?? 0 });
|
|
1690
|
+
this.emitSelectionIntent('node', node.id, !!(e?.ctrlKey || e?.metaKey));
|
|
448
1691
|
}
|
|
449
|
-
|
|
1692
|
+
/** Returns a node's current position in the graph's local drawing space. */
|
|
1693
|
+
getNodePosition(id) {
|
|
1694
|
+
const node = this.simNodes.find((candidate) => candidate.id === id);
|
|
1695
|
+
if (!node || !Number.isFinite(node.x) || !Number.isFinite(node.y))
|
|
1696
|
+
return undefined;
|
|
1697
|
+
return { x: node.x, y: node.y };
|
|
1698
|
+
}
|
|
1699
|
+
onLinkClick(link, e) {
|
|
450
1700
|
const source = typeof link.source === 'object' ? link.source.id : String(link.source);
|
|
451
1701
|
const target = typeof link.target === 'object' ? link.target.id : String(link.target);
|
|
452
1702
|
this.emit('lyra-link-click', { source, target, ...(link.id ? { id: link.id } : {}) });
|
|
1703
|
+
this.emitSelectionIntent('link', this.linkKey(link), !!(e?.ctrlKey || e?.metaKey));
|
|
1704
|
+
}
|
|
1705
|
+
onNodeEnter(node, e) {
|
|
1706
|
+
if (this.isDragging || this.isPanning || this.isCameraTweening)
|
|
1707
|
+
return;
|
|
1708
|
+
e.currentTarget.setAttribute('data-hovered', '');
|
|
1709
|
+
this.emit('lyra-node-enter', { id: node.id });
|
|
1710
|
+
}
|
|
1711
|
+
onNodeLeave(node, e) {
|
|
1712
|
+
if (this.isDragging || this.isPanning || this.isCameraTweening)
|
|
1713
|
+
return;
|
|
1714
|
+
e.currentTarget.removeAttribute('data-hovered');
|
|
1715
|
+
this.emit('lyra-node-leave', { id: node.id });
|
|
1716
|
+
}
|
|
1717
|
+
onNodeDblClick(node, e) {
|
|
1718
|
+
// Stops the dblclick from also reaching the svg's own d3-zoom double-click-to-zoom-in
|
|
1719
|
+
// listener -- background double-click (not on a node) keeps that default behavior.
|
|
1720
|
+
e.stopPropagation();
|
|
1721
|
+
this.emit('lyra-node-expand', { id: node.id });
|
|
1722
|
+
}
|
|
1723
|
+
onLinkEnter(link, e) {
|
|
1724
|
+
if (this.isDragging || this.isPanning || this.isCameraTweening)
|
|
1725
|
+
return;
|
|
1726
|
+
e.currentTarget.setAttribute('data-hovered', '');
|
|
1727
|
+
const source = typeof link.source === 'object' ? link.source.id : String(link.source);
|
|
1728
|
+
const target = typeof link.target === 'object' ? link.target.id : String(link.target);
|
|
1729
|
+
this.emit('lyra-link-enter', { source, target, ...(link.id ? { id: link.id } : {}) });
|
|
1730
|
+
}
|
|
1731
|
+
onLinkLeave(link, e) {
|
|
1732
|
+
if (this.isDragging || this.isPanning || this.isCameraTweening)
|
|
1733
|
+
return;
|
|
1734
|
+
e.currentTarget.removeAttribute('data-hovered');
|
|
1735
|
+
const source = typeof link.source === 'object' ? link.source.id : String(link.source);
|
|
1736
|
+
const target = typeof link.target === 'object' ? link.target.id : String(link.target);
|
|
1737
|
+
this.emit('lyra-link-leave', { source, target, ...(link.id ? { id: link.id } : {}) });
|
|
453
1738
|
}
|
|
454
1739
|
nodeAccessibleText(node) {
|
|
455
|
-
|
|
1740
|
+
let text = node.accessibleLabel || node.label || node.id;
|
|
1741
|
+
const type = this.resolveNodeType(node);
|
|
1742
|
+
if (type)
|
|
1743
|
+
text = this.localize('graphTypedNode', undefined, { label: text, type: type.label });
|
|
1744
|
+
if (node.expandable)
|
|
1745
|
+
text = this.localize('graphExpandableItem', undefined, { item: text });
|
|
1746
|
+
return text;
|
|
456
1747
|
}
|
|
457
1748
|
linkAccessibleText(link) {
|
|
458
1749
|
if (link.accessibleLabel)
|
|
@@ -487,8 +1778,69 @@ export class LyraGraph extends LyraElement {
|
|
|
487
1778
|
y2: targetY - (dy / distance) * inset,
|
|
488
1779
|
};
|
|
489
1780
|
}
|
|
1781
|
+
/** World-space midpoint of a link, offset EDGE_LABEL_OFFSET_PX perpendicular to the segment
|
|
1782
|
+
* (horizontal, unrotated text — rotated edge-label text is a readability and RTL hazard). */
|
|
1783
|
+
edgeLabelPosition(link) {
|
|
1784
|
+
const { x1, y1, x2, y2 } = this.linkCoordinates(link);
|
|
1785
|
+
const dx = x2 - x1;
|
|
1786
|
+
const dy = y2 - y1;
|
|
1787
|
+
const len = Math.hypot(dx, dy);
|
|
1788
|
+
const mx = (x1 + x2) / 2;
|
|
1789
|
+
const my = (y1 + y2) / 2;
|
|
1790
|
+
if (len === 0)
|
|
1791
|
+
return { x: mx, y: my };
|
|
1792
|
+
return {
|
|
1793
|
+
x: mx + (-dy / len) * EDGE_LABEL_OFFSET_PX,
|
|
1794
|
+
y: my + (dx / len) * EDGE_LABEL_OFFSET_PX,
|
|
1795
|
+
};
|
|
1796
|
+
}
|
|
1797
|
+
edgeLabelFontPx() {
|
|
1798
|
+
const raw = getComputedStyle(this).getPropertyValue('--lyra-font-size-2xs').trim();
|
|
1799
|
+
const parsed = parseFloat(raw);
|
|
1800
|
+
if (!Number.isFinite(parsed))
|
|
1801
|
+
return 10;
|
|
1802
|
+
// rem tokens are resolved relative to the root font-size; this is a decluttering heuristic,
|
|
1803
|
+
// not a pixel-perfect layout, so the standard 16px/rem approximation is sufficient.
|
|
1804
|
+
return raw.endsWith('rem') ? parsed * 16 : parsed;
|
|
1805
|
+
}
|
|
1806
|
+
edgeLabelWidth(text) {
|
|
1807
|
+
const cached = this.edgeLabelWidthCache.get(text);
|
|
1808
|
+
if (cached != null)
|
|
1809
|
+
return cached;
|
|
1810
|
+
const ctx = getScratchCtx();
|
|
1811
|
+
let width;
|
|
1812
|
+
if (ctx) {
|
|
1813
|
+
const fontFamily = getComputedStyle(this).getPropertyValue('--lyra-font').trim() || 'sans-serif';
|
|
1814
|
+
ctx.font = `${this.edgeLabelFontPx()}px ${fontFamily}`;
|
|
1815
|
+
width = ctx.measureText(text).width;
|
|
1816
|
+
}
|
|
1817
|
+
else {
|
|
1818
|
+
width = text.length * this.edgeLabelFontPx() * 0.6;
|
|
1819
|
+
}
|
|
1820
|
+
// Bound the cache under label churn (a streaming graph can cycle through unbounded distinct
|
|
1821
|
+
// label texts) -- Map iteration yields insertion order, so evicting the first key drops the
|
|
1822
|
+
// oldest-measured entry.
|
|
1823
|
+
if (this.edgeLabelWidthCache.size >= EDGE_LABEL_WIDTH_CACHE_MAX) {
|
|
1824
|
+
const oldest = this.edgeLabelWidthCache.keys().next().value;
|
|
1825
|
+
if (oldest !== undefined)
|
|
1826
|
+
this.edgeLabelWidthCache.delete(oldest);
|
|
1827
|
+
}
|
|
1828
|
+
this.edgeLabelWidthCache.set(text, width);
|
|
1829
|
+
return width;
|
|
1830
|
+
}
|
|
1831
|
+
/** Toggles `data-edge-labels-hidden` on the cached zoomed `<g>` when crossing `edgeLabelMinZoom`
|
|
1832
|
+
* -- called from the d3-zoom `'zoom'` handler (render-free, CSS hides `[part="link-label"]`
|
|
1833
|
+
* beneath the attribute) so this scales with every pan/zoom event without a Lit re-render. */
|
|
1834
|
+
updateEdgeLabelZoomGate(k) {
|
|
1835
|
+
if (!this.gEl)
|
|
1836
|
+
return;
|
|
1837
|
+
if (k < this.safeEdgeLabelMinZoom)
|
|
1838
|
+
this.gEl.setAttribute('data-edge-labels-hidden', '');
|
|
1839
|
+
else
|
|
1840
|
+
this.gEl.removeAttribute('data-edge-labels-hidden');
|
|
1841
|
+
}
|
|
490
1842
|
graphItemCount() {
|
|
491
|
-
return this.simNodes.length + this.simLinks.length;
|
|
1843
|
+
return this.simNodes.length + this.simLinks.length + this.visibleCommunities().length;
|
|
492
1844
|
}
|
|
493
1845
|
normalizedGraphItem(index = this.activeGraphItem) {
|
|
494
1846
|
const count = this.graphItemCount();
|
|
@@ -499,8 +1851,19 @@ export class LyraGraph extends LyraElement {
|
|
|
499
1851
|
const node = this.simNodes[index];
|
|
500
1852
|
return node ? this.localize('graphNode', undefined, { label: this.nodeAccessibleText(node) }) : '';
|
|
501
1853
|
}
|
|
502
|
-
const
|
|
503
|
-
|
|
1854
|
+
const linkIndex = index - this.simNodes.length;
|
|
1855
|
+
if (linkIndex < this.simLinks.length) {
|
|
1856
|
+
const link = this.simLinks[linkIndex];
|
|
1857
|
+
return link ? this.linkAccessibleText(link) : '';
|
|
1858
|
+
}
|
|
1859
|
+
const hullIndex = linkIndex - this.simLinks.length;
|
|
1860
|
+
const entry = this.visibleCommunities()[hullIndex];
|
|
1861
|
+
return entry
|
|
1862
|
+
? this.localize('graphCommunity', undefined, {
|
|
1863
|
+
label: entry.community.label ?? entry.community.id,
|
|
1864
|
+
count: entry.members.length,
|
|
1865
|
+
})
|
|
1866
|
+
: '';
|
|
504
1867
|
}
|
|
505
1868
|
graphItemAnnouncement(index) {
|
|
506
1869
|
return this.localize('graphItemAnnouncement', undefined, {
|
|
@@ -522,10 +1885,16 @@ export class LyraGraph extends LyraElement {
|
|
|
522
1885
|
this.activeGraphItem = normalized;
|
|
523
1886
|
this.graphLiveText = this.graphItemAnnouncement(normalized);
|
|
524
1887
|
void this.updateComplete.then(() => {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
1888
|
+
// renderer="canvas" has no [part="node"]/[part="link"]/[part="hull"] elements at all -- the
|
|
1889
|
+
// roving tab stop lives on the offscreen [part="cursor-item"] buttons instead (see render()),
|
|
1890
|
+
// in the same flat nodes-then-links-then-hulls order.
|
|
1891
|
+
const items = (this.renderer === 'canvas'
|
|
1892
|
+
? Array.from(this.renderRoot.querySelectorAll('[part="cursor-item"]'))
|
|
1893
|
+
: [
|
|
1894
|
+
...Array.from(this.renderRoot.querySelectorAll('[part="node"]')),
|
|
1895
|
+
...Array.from(this.renderRoot.querySelectorAll('[part="link"]')),
|
|
1896
|
+
...Array.from(this.renderRoot.querySelectorAll('[part="hull"]')),
|
|
1897
|
+
]);
|
|
529
1898
|
items[normalized]?.focus();
|
|
530
1899
|
});
|
|
531
1900
|
}
|
|
@@ -542,7 +1911,20 @@ export class LyraGraph extends LyraElement {
|
|
|
542
1911
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
543
1912
|
e.preventDefault();
|
|
544
1913
|
this.onGraphItemFocus(index);
|
|
545
|
-
activate();
|
|
1914
|
+
activate(e);
|
|
1915
|
+
if (index < this.simNodes.length) {
|
|
1916
|
+
const now = performance.now();
|
|
1917
|
+
if (this.lastKeyActivateIndex === index && now - this.lastKeyActivateTime <= EXPAND_KEY_INTERVAL_MS) {
|
|
1918
|
+
const node = this.simNodes[index];
|
|
1919
|
+
if (node)
|
|
1920
|
+
this.emit('lyra-node-expand', { id: node.id });
|
|
1921
|
+
this.lastKeyActivateIndex = null;
|
|
1922
|
+
}
|
|
1923
|
+
else {
|
|
1924
|
+
this.lastKeyActivateIndex = index;
|
|
1925
|
+
this.lastKeyActivateTime = now;
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
546
1928
|
return;
|
|
547
1929
|
}
|
|
548
1930
|
const count = this.graphItemCount();
|
|
@@ -571,7 +1953,7 @@ export class LyraGraph extends LyraElement {
|
|
|
571
1953
|
<div part="base">
|
|
572
1954
|
<lyra-skeleton
|
|
573
1955
|
variant="rect"
|
|
574
|
-
style=${`--lyra-skeleton-w:${this.
|
|
1956
|
+
style=${`--lyra-skeleton-w:${this.safeWidth}px;--lyra-skeleton-h:${this.safeHeight}px`}
|
|
575
1957
|
></lyra-skeleton>
|
|
576
1958
|
</div>
|
|
577
1959
|
`;
|
|
@@ -579,6 +1961,99 @@ export class LyraGraph extends LyraElement {
|
|
|
579
1961
|
if (!this.nodes.length) {
|
|
580
1962
|
return html `<div part="base"><div part="empty">${this.localize('noData')}</div></div>`;
|
|
581
1963
|
}
|
|
1964
|
+
if (this.renderer === 'canvas') {
|
|
1965
|
+
return html `
|
|
1966
|
+
<div part="base">
|
|
1967
|
+
<canvas
|
|
1968
|
+
part="canvas"
|
|
1969
|
+
role="group"
|
|
1970
|
+
aria-label=${this.accessibleLabel ||
|
|
1971
|
+
this.localize('graphDiagram', undefined, {
|
|
1972
|
+
nodeCount: this.simNodes.length,
|
|
1973
|
+
linkCount: this.simLinks.length,
|
|
1974
|
+
})}
|
|
1975
|
+
tabindex=${this.graphItemCount() ? '-1' : '0'}
|
|
1976
|
+
></canvas>
|
|
1977
|
+
<div part="tooltip" hidden></div>
|
|
1978
|
+
<div part="live-region" class="sr-only" role="status" aria-live="polite" aria-atomic="true">
|
|
1979
|
+
${this.graphLiveText ||
|
|
1980
|
+
(this.normalizedGraphItem() >= 0 ? this.graphItemAnnouncement(this.normalizedGraphItem()) : '')}
|
|
1981
|
+
</div>
|
|
1982
|
+
<ul part="data-list" class="sr-only" aria-label=${this.localize('graphDataList')}>
|
|
1983
|
+
${this.simNodes.map((node) => html `<li>${this.localize('graphNode', undefined, { label: this.nodeAccessibleText(node) })}</li>`)}
|
|
1984
|
+
${this.simLinks.map((link) => html `<li>${this.linkAccessibleText(link)}</li>`)}
|
|
1985
|
+
${this.visibleCommunities().map((entry) => html `<li>${this.localize('graphCommunity', undefined, {
|
|
1986
|
+
label: entry.community.label ?? entry.community.id,
|
|
1987
|
+
count: entry.members.length,
|
|
1988
|
+
})}</li>`)}
|
|
1989
|
+
</ul>
|
|
1990
|
+
<div
|
|
1991
|
+
part="cursor-items"
|
|
1992
|
+
class="sr-only"
|
|
1993
|
+
@keydown=${(e) => {
|
|
1994
|
+
// Escape-clears-selection lives here (not on the canvas itself) because keydown from
|
|
1995
|
+
// a focused cursor-item bubbles up through this container, never through the canvas
|
|
1996
|
+
// -- the cursor-items list is canvas's sibling, not its descendant. Mirrors the svg
|
|
1997
|
+
// template's own root-level Escape handler; each cursor-item's own onGraphKeyDown()
|
|
1998
|
+
// (Enter/Space/arrows/Home/End) leaves Escape unhandled the same way a node/link
|
|
1999
|
+
// element does, so it bubbles here.
|
|
2000
|
+
if (e.key === 'Escape')
|
|
2001
|
+
this.clearSelection();
|
|
2002
|
+
}}
|
|
2003
|
+
>
|
|
2004
|
+
${this.simNodes.map((n, i) => html `
|
|
2005
|
+
<!-- hit-area-exempt: this button lives inside [part="cursor-items"]'s
|
|
2006
|
+
class="sr-only" (internal/a11y.ts's clip: rect(0 0 0 0) box) -- it's
|
|
2007
|
+
the offscreen keyboard-roving a11y virtual cursor described in this
|
|
2008
|
+
class's own doc comment, never a visible/pointer-clickable box, so
|
|
2009
|
+
the 40px hit-area floor (meant for on-screen tap targets) doesn't apply. -->
|
|
2010
|
+
<button
|
|
2011
|
+
part="cursor-item"
|
|
2012
|
+
tabindex=${this.normalizedGraphItem() === i ? '0' : '-1'}
|
|
2013
|
+
aria-label=${this.nodeAccessibleText(n)}
|
|
2014
|
+
@focus=${() => this.onGraphItemFocus(i)}
|
|
2015
|
+
@keydown=${(e) => this.onGraphKeyDown(e, i, (ev) => this.onNodeClick(n, ev))}
|
|
2016
|
+
@click=${(e) => this.onNodeClick(n, e)}
|
|
2017
|
+
></button>
|
|
2018
|
+
`)}
|
|
2019
|
+
${this.simLinks.map((l, li) => {
|
|
2020
|
+
const i = this.simNodes.length + li;
|
|
2021
|
+
return html `
|
|
2022
|
+
<!-- hit-area-exempt: see the node cursor-item above -- same offscreen
|
|
2023
|
+
sr-only virtual-cursor button, no visible/pointer-clickable box. -->
|
|
2024
|
+
<button
|
|
2025
|
+
part="cursor-item"
|
|
2026
|
+
tabindex=${this.normalizedGraphItem() === i ? '0' : '-1'}
|
|
2027
|
+
aria-label=${this.linkAccessibleText(l)}
|
|
2028
|
+
@focus=${() => this.onGraphItemFocus(i)}
|
|
2029
|
+
@keydown=${(e) => this.onGraphKeyDown(e, i, (ev) => this.onLinkClick(l, ev))}
|
|
2030
|
+
@click=${(e) => this.onLinkClick(l, e)}
|
|
2031
|
+
></button>
|
|
2032
|
+
`;
|
|
2033
|
+
})}
|
|
2034
|
+
${this.visibleCommunities().map((entry, hi) => {
|
|
2035
|
+
const i = this.simNodes.length + this.simLinks.length + hi;
|
|
2036
|
+
const label = this.localize('graphCommunity', undefined, {
|
|
2037
|
+
label: entry.community.label ?? entry.community.id,
|
|
2038
|
+
count: entry.members.length,
|
|
2039
|
+
});
|
|
2040
|
+
return html `
|
|
2041
|
+
<!-- hit-area-exempt: see the node cursor-item above -- same offscreen
|
|
2042
|
+
sr-only virtual-cursor button, no visible/pointer-clickable box. -->
|
|
2043
|
+
<button
|
|
2044
|
+
part="cursor-item"
|
|
2045
|
+
tabindex=${this.normalizedGraphItem() === i ? '0' : '-1'}
|
|
2046
|
+
aria-label=${label}
|
|
2047
|
+
@focus=${() => this.onGraphItemFocus(i)}
|
|
2048
|
+
@keydown=${(e) => this.onGraphKeyDown(e, i, () => this.onCommunityClick(entry.community))}
|
|
2049
|
+
@click=${() => this.onCommunityClick(entry.community)}
|
|
2050
|
+
></button>
|
|
2051
|
+
`;
|
|
2052
|
+
})}
|
|
2053
|
+
</div>
|
|
2054
|
+
</div>
|
|
2055
|
+
`;
|
|
2056
|
+
}
|
|
582
2057
|
return html `
|
|
583
2058
|
<div part="base">
|
|
584
2059
|
<svg
|
|
@@ -589,8 +2064,16 @@ export class LyraGraph extends LyraElement {
|
|
|
589
2064
|
nodeCount: this.simNodes.length,
|
|
590
2065
|
linkCount: this.simLinks.length,
|
|
591
2066
|
})}
|
|
592
|
-
viewBox="0 0 ${this.
|
|
2067
|
+
viewBox="0 0 ${this.safeWidth} ${this.safeHeight}"
|
|
593
2068
|
tabindex=${this.graphItemCount() ? '-1' : '0'}
|
|
2069
|
+
@click=${(e) => {
|
|
2070
|
+
if (e.target === e.currentTarget)
|
|
2071
|
+
this.clearSelection();
|
|
2072
|
+
}}
|
|
2073
|
+
@keydown=${(e) => {
|
|
2074
|
+
if (e.key === 'Escape')
|
|
2075
|
+
this.clearSelection();
|
|
2076
|
+
}}
|
|
594
2077
|
>
|
|
595
2078
|
<defs>
|
|
596
2079
|
<marker
|
|
@@ -607,28 +2090,64 @@ export class LyraGraph extends LyraElement {
|
|
|
607
2090
|
</marker>
|
|
608
2091
|
</defs>
|
|
609
2092
|
<g transform="">
|
|
2093
|
+
${this.visibleCommunities().map((entry, hullIndex) => {
|
|
2094
|
+
const itemIndex = this.simNodes.length + this.simLinks.length + hullIndex;
|
|
2095
|
+
const hull = this.communityHull(entry.members);
|
|
2096
|
+
const fill = sanitizeNodeColor(entry.community.color);
|
|
2097
|
+
const label = this.localize('graphCommunity', undefined, {
|
|
2098
|
+
label: entry.community.label ?? entry.community.id,
|
|
2099
|
+
count: entry.members.length,
|
|
2100
|
+
});
|
|
2101
|
+
return svg `<g>
|
|
2102
|
+
<path
|
|
2103
|
+
part="hull"
|
|
2104
|
+
role="button"
|
|
2105
|
+
tabindex=${this.normalizedGraphItem() === itemIndex ? '0' : '-1'}
|
|
2106
|
+
aria-label=${label}
|
|
2107
|
+
d=${hullPathD(hull)}
|
|
2108
|
+
style=${styleMap(fill ? { '--lyra-graph-hull-fill': fill } : {})}
|
|
2109
|
+
@click=${() => this.onCommunityClick(entry.community)}
|
|
2110
|
+
@focus=${() => this.onGraphItemFocus(itemIndex)}
|
|
2111
|
+
@keydown=${(e) => this.onGraphKeyDown(e, itemIndex, () => this.onCommunityClick(entry.community))}
|
|
2112
|
+
></path>
|
|
2113
|
+
<text part="community-label" aria-hidden="true" x=${hullCentroidX(hull)} y=${hullTopY(hull) - HULL_PADDING}>${entry.community.label ?? entry.community.id}</text>
|
|
2114
|
+
</g>`;
|
|
2115
|
+
})}
|
|
610
2116
|
${this.simLinks.map((l, linkIndex) => {
|
|
611
2117
|
const itemIndex = this.simNodes.length + linkIndex;
|
|
612
2118
|
const coordinates = this.linkCoordinates(l);
|
|
613
2119
|
const color = sanitizeNodeColor(l.color);
|
|
614
2120
|
const dash = normalizeLinkDash(l.dash);
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
2121
|
+
const labelPos = this.showEdgeLabels && l.label ? this.edgeLabelPosition(l) : undefined;
|
|
2122
|
+
const lineEl = svg `<line
|
|
2123
|
+
part="link"
|
|
2124
|
+
role="button"
|
|
2125
|
+
tabindex=${this.normalizedGraphItem() === itemIndex ? '0' : '-1'}
|
|
2126
|
+
aria-label=${this.linkAccessibleText(l)}
|
|
2127
|
+
aria-pressed=${this.selectionMode !== 'none' ? String(this.isSelected('link', this.linkKey(l))) : nothing}
|
|
2128
|
+
?data-selected=${this.isSelected('link', this.linkKey(l))}
|
|
2129
|
+
?data-dimmed=${this.isDimmed('link', this.linkKey(l))}
|
|
2130
|
+
stroke-width=${l.width ?? 1.5}
|
|
2131
|
+
stroke-dasharray=${dash ?? nothing}
|
|
2132
|
+
marker-end=${l.directed ? `url(#${this.arrowMarkerId})` : nothing}
|
|
2133
|
+
style=${styleMap(color ? { '--lyra-link-color': color } : {})}
|
|
2134
|
+
x1=${coordinates.x1}
|
|
2135
|
+
y1=${coordinates.y1}
|
|
2136
|
+
x2=${coordinates.x2}
|
|
2137
|
+
y2=${coordinates.y2}
|
|
2138
|
+
@click=${(e) => this.onLinkClick(l, e)}
|
|
2139
|
+
@focus=${() => this.onGraphItemFocus(itemIndex)}
|
|
2140
|
+
@keydown=${(e) => this.onGraphKeyDown(e, itemIndex, (ev) => this.onLinkClick(l, ev))}
|
|
2141
|
+
@mouseenter=${(e) => this.onLinkEnter(l, e)}
|
|
2142
|
+
@mouseleave=${(e) => this.onLinkLeave(l, e)}
|
|
2143
|
+
>${l.description || l.label ? svg `<title>${l.description || l.label}</title>` : nothing}</line>`;
|
|
2144
|
+
// Only wrap in a <g> when a label will actually be drawn -- an unconditional wrapper
|
|
2145
|
+
// would change existing consumers' rendered link DOM (bare <line part="link">) even
|
|
2146
|
+
// when showEdgeLabels is never set, breaking the "existing usage renders byte-for-byte
|
|
2147
|
+
// identical output" contract this drawn-edge-label feature must preserve.
|
|
2148
|
+
return labelPos
|
|
2149
|
+
? svg `<g>${lineEl}<text part="link-label" aria-hidden="true" text-anchor="middle" x=${labelPos.x} y=${labelPos.y}>${l.label}</text></g>`
|
|
2150
|
+
: lineEl;
|
|
632
2151
|
})}
|
|
633
2152
|
${this.danglingLinks.map((l) => {
|
|
634
2153
|
const source = l.source;
|
|
@@ -644,27 +2163,69 @@ export class LyraGraph extends LyraElement {
|
|
|
644
2163
|
></line>`;
|
|
645
2164
|
})}
|
|
646
2165
|
${this.simNodes.map((n, nodeIndex) => {
|
|
647
|
-
const
|
|
2166
|
+
const shape = this.nodeShape(n);
|
|
2167
|
+
const fill = this.nodeFill(n);
|
|
648
2168
|
const itemIndex = nodeIndex;
|
|
2169
|
+
const tabindex = this.normalizedGraphItem() === itemIndex ? '0' : '-1';
|
|
2170
|
+
const label = this.nodeAccessibleText(n);
|
|
2171
|
+
// Unlike link styling below (which always renders style=${styleMap(...)}, even as
|
|
2172
|
+
// an empty string), an untyped/unknown-type node must render with NO style
|
|
2173
|
+
// attribute at all -- not just an empty one -- so hasAttribute('style') distinguishes
|
|
2174
|
+
// "no fill override" from "fill override present" for consumers/tests probing the DOM.
|
|
2175
|
+
const style = fill ? styleMap({ '--lyra-node-fill': fill }) : nothing;
|
|
2176
|
+
const title = n.description ? svg `<title>${n.description}</title>` : nothing;
|
|
2177
|
+
const shapeEl = shape === 'circle'
|
|
2178
|
+
? svg `<circle
|
|
2179
|
+
part="node"
|
|
2180
|
+
role="button"
|
|
2181
|
+
tabindex=${tabindex}
|
|
2182
|
+
aria-label=${label}
|
|
2183
|
+
aria-pressed=${this.selectionMode !== 'none' ? String(this.isSelected('node', n.id)) : nothing}
|
|
2184
|
+
?data-selected=${this.isSelected('node', n.id)}
|
|
2185
|
+
?data-dimmed=${this.isDimmed('node', n.id)}
|
|
2186
|
+
r=${this.nodeRadius(n)}
|
|
2187
|
+
cx=${n.x ?? 0}
|
|
2188
|
+
cy=${n.y ?? 0}
|
|
2189
|
+
style=${style}
|
|
2190
|
+
@click=${(e) => this.onNodeClick(n, e)}
|
|
2191
|
+
@dblclick=${(e) => this.onNodeDblClick(n, e)}
|
|
2192
|
+
@focus=${() => this.onGraphItemFocus(itemIndex)}
|
|
2193
|
+
@keydown=${(e) => this.onGraphKeyDown(e, itemIndex, (ev) => this.onNodeClick(n, ev))}
|
|
2194
|
+
@mouseenter=${(e) => this.onNodeEnter(n, e)}
|
|
2195
|
+
@mouseleave=${(e) => this.onNodeLeave(n, e)}
|
|
2196
|
+
>${title}</circle>`
|
|
2197
|
+
: svg `<path
|
|
2198
|
+
part="node"
|
|
2199
|
+
role="button"
|
|
2200
|
+
tabindex=${tabindex}
|
|
2201
|
+
aria-label=${label}
|
|
2202
|
+
aria-pressed=${this.selectionMode !== 'none' ? String(this.isSelected('node', n.id)) : nothing}
|
|
2203
|
+
?data-selected=${this.isSelected('node', n.id)}
|
|
2204
|
+
?data-dimmed=${this.isDimmed('node', n.id)}
|
|
2205
|
+
d=${shape === 'square' ? squarePath(this.nodeRadius(n)) : diamondPath(this.nodeRadius(n))}
|
|
2206
|
+
transform="translate(${n.x ?? 0},${n.y ?? 0})"
|
|
2207
|
+
style=${style}
|
|
2208
|
+
@click=${(e) => this.onNodeClick(n, e)}
|
|
2209
|
+
@dblclick=${(e) => this.onNodeDblClick(n, e)}
|
|
2210
|
+
@focus=${() => this.onGraphItemFocus(itemIndex)}
|
|
2211
|
+
@keydown=${(e) => this.onGraphKeyDown(e, itemIndex, (ev) => this.onNodeClick(n, ev))}
|
|
2212
|
+
@mouseenter=${(e) => this.onNodeEnter(n, e)}
|
|
2213
|
+
@mouseleave=${(e) => this.onNodeLeave(n, e)}
|
|
2214
|
+
>${title}</path>`;
|
|
649
2215
|
return svg `<g>
|
|
650
|
-
|
|
651
|
-
part="node"
|
|
652
|
-
role="button"
|
|
653
|
-
tabindex=${this.normalizedGraphItem() === itemIndex ? '0' : '-1'}
|
|
654
|
-
aria-label=${this.nodeAccessibleText(n)}
|
|
655
|
-
r=${this.nodeRadius(n)}
|
|
656
|
-
cx=${n.x ?? 0}
|
|
657
|
-
cy=${n.y ?? 0}
|
|
658
|
-
style=${styleMap(fill ? { '--lyra-node-fill': fill } : {})}
|
|
659
|
-
@click=${() => this.onNodeClick(n)}
|
|
660
|
-
@focus=${() => this.onGraphItemFocus(itemIndex)}
|
|
661
|
-
@keydown=${(e) => this.onGraphKeyDown(e, itemIndex, () => this.onNodeClick(n))}
|
|
662
|
-
>${n.description ? svg `<title>${n.description}</title>` : nothing}</circle>
|
|
2216
|
+
${shapeEl}
|
|
663
2217
|
${n.label
|
|
664
2218
|
? svg `<text part="label" aria-hidden="true" x=${(n.x ?? 0) + this.nodeRadius(n) + 2} y=${n.y ?? 0}>${n.label}</text>`
|
|
665
2219
|
: ''}
|
|
2220
|
+
${n.expandable
|
|
2221
|
+
? svg `<g part="expand-indicator" aria-hidden="true" transform="translate(${n.x ?? 0},${n.y ?? 0})">
|
|
2222
|
+
<circle r=${EXPAND_BADGE_R} cx=${this.nodeRadius(n) * EXPAND_BADGE_OFFSET} cy=${-this.nodeRadius(n) * EXPAND_BADGE_OFFSET}></circle>
|
|
2223
|
+
<path d="M ${this.nodeRadius(n) * EXPAND_BADGE_OFFSET - EXPAND_BADGE_R / 2} ${-this.nodeRadius(n) * EXPAND_BADGE_OFFSET} L ${this.nodeRadius(n) * EXPAND_BADGE_OFFSET + EXPAND_BADGE_R / 2} ${-this.nodeRadius(n) * EXPAND_BADGE_OFFSET} M ${this.nodeRadius(n) * EXPAND_BADGE_OFFSET} ${-this.nodeRadius(n) * EXPAND_BADGE_OFFSET - EXPAND_BADGE_R / 2} L ${this.nodeRadius(n) * EXPAND_BADGE_OFFSET} ${-this.nodeRadius(n) * EXPAND_BADGE_OFFSET + EXPAND_BADGE_R / 2}"></path>
|
|
2224
|
+
</g>`
|
|
2225
|
+
: ''}
|
|
666
2226
|
</g>`;
|
|
667
2227
|
})}
|
|
2228
|
+
<circle part="focus-halo" aria-hidden="true" hidden r="0" cx="0" cy="0"></circle>
|
|
668
2229
|
</g>
|
|
669
2230
|
</svg>
|
|
670
2231
|
<div part="live-region" class="sr-only" role="status" aria-live="polite" aria-atomic="true">
|
|
@@ -674,6 +2235,10 @@ export class LyraGraph extends LyraElement {
|
|
|
674
2235
|
<ul part="data-list" class="sr-only" aria-label=${this.localize('graphDataList')}>
|
|
675
2236
|
${this.simNodes.map((node) => html `<li>${this.localize('graphNode', undefined, { label: this.nodeAccessibleText(node) })}</li>`)}
|
|
676
2237
|
${this.simLinks.map((link) => html `<li>${this.linkAccessibleText(link)}</li>`)}
|
|
2238
|
+
${this.visibleCommunities().map((entry) => html `<li>${this.localize('graphCommunity', undefined, {
|
|
2239
|
+
label: entry.community.label ?? entry.community.id,
|
|
2240
|
+
count: entry.members.length,
|
|
2241
|
+
})}</li>`)}
|
|
677
2242
|
</ul>
|
|
678
2243
|
</div>
|
|
679
2244
|
`;
|
|
@@ -685,6 +2250,21 @@ __decorate([
|
|
|
685
2250
|
__decorate([
|
|
686
2251
|
property({ attribute: false })
|
|
687
2252
|
], LyraGraph.prototype, "links", void 0);
|
|
2253
|
+
__decorate([
|
|
2254
|
+
property({ attribute: false })
|
|
2255
|
+
], LyraGraph.prototype, "nodeTypes", void 0);
|
|
2256
|
+
__decorate([
|
|
2257
|
+
property({ attribute: false })
|
|
2258
|
+
], LyraGraph.prototype, "hiddenTypes", void 0);
|
|
2259
|
+
__decorate([
|
|
2260
|
+
property({ attribute: false })
|
|
2261
|
+
], LyraGraph.prototype, "communities", void 0);
|
|
2262
|
+
__decorate([
|
|
2263
|
+
property()
|
|
2264
|
+
], LyraGraph.prototype, "layout", void 0);
|
|
2265
|
+
__decorate([
|
|
2266
|
+
property()
|
|
2267
|
+
], LyraGraph.prototype, "renderer", void 0);
|
|
688
2268
|
__decorate([
|
|
689
2269
|
property({ type: Number })
|
|
690
2270
|
], LyraGraph.prototype, "width", void 0);
|
|
@@ -709,6 +2289,30 @@ __decorate([
|
|
|
709
2289
|
__decorate([
|
|
710
2290
|
property({ type: Number })
|
|
711
2291
|
], LyraGraph.prototype, "seed", void 0);
|
|
2292
|
+
__decorate([
|
|
2293
|
+
property({ type: Boolean, attribute: 'show-edge-labels' })
|
|
2294
|
+
], LyraGraph.prototype, "showEdgeLabels", void 0);
|
|
2295
|
+
__decorate([
|
|
2296
|
+
property({ type: Number, attribute: 'edge-label-min-zoom' })
|
|
2297
|
+
], LyraGraph.prototype, "edgeLabelMinZoom", void 0);
|
|
2298
|
+
__decorate([
|
|
2299
|
+
property({ attribute: 'focus-id' })
|
|
2300
|
+
], LyraGraph.prototype, "focusId", void 0);
|
|
2301
|
+
__decorate([
|
|
2302
|
+
property({ attribute: 'selection-mode' })
|
|
2303
|
+
], LyraGraph.prototype, "selectionMode", void 0);
|
|
2304
|
+
__decorate([
|
|
2305
|
+
property({ attribute: false })
|
|
2306
|
+
], LyraGraph.prototype, "selectedNodeIds", void 0);
|
|
2307
|
+
__decorate([
|
|
2308
|
+
property({ attribute: false })
|
|
2309
|
+
], LyraGraph.prototype, "selectedLinkIds", void 0);
|
|
2310
|
+
__decorate([
|
|
2311
|
+
property({ attribute: false })
|
|
2312
|
+
], LyraGraph.prototype, "dimmedNodeIds", void 0);
|
|
2313
|
+
__decorate([
|
|
2314
|
+
property({ attribute: false })
|
|
2315
|
+
], LyraGraph.prototype, "dimmedLinkIds", void 0);
|
|
712
2316
|
__decorate([
|
|
713
2317
|
state()
|
|
714
2318
|
], LyraGraph.prototype, "loading", void 0);
|
|
@@ -724,4 +2328,7 @@ __decorate([
|
|
|
724
2328
|
__decorate([
|
|
725
2329
|
state()
|
|
726
2330
|
], LyraGraph.prototype, "graphLiveText", void 0);
|
|
2331
|
+
__decorate([
|
|
2332
|
+
query('canvas')
|
|
2333
|
+
], LyraGraph.prototype, "canvasEl", void 0);
|
|
727
2334
|
//# sourceMappingURL=graph.class.js.map
|