@kubex/zinc 1.1.185 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.browserslistrc +2 -0
- package/.github/workflows/js_build_and_deploy.yaml +54 -1
- package/.github/workflows/test.yaml +27 -0
- package/dist/chunks/zn.UWJLIXDT.js +1 -0
- package/dist/custom-elements.json +9998 -2345
- package/dist/vscode.html-custom-data.json +1022 -67
- package/dist/web-types.json +2129 -177
- package/dist/zn.d.ts +2293 -416
- package/dist/zn.min.css +1 -1
- package/dist/zn.min.js +2310 -1637
- package/docs/_includes/default.njk +4 -1
- package/docs/assets/scripts/docs.js +22 -6
- package/docs/assets/styles/docs.css +9 -2
- package/docs/data/report-table-day-compare.json +380 -0
- package/docs/data/report-table.json +314 -0
- package/docs/pages/components/avatar-group.md +57 -0
- package/docs/pages/components/badge.md +67 -0
- package/docs/pages/components/button.md +41 -1
- package/docs/pages/components/chat-message.md +16 -0
- package/docs/pages/components/checkbox.md +1 -1
- package/docs/pages/components/chip.md +25 -13
- package/docs/pages/components/color-picker.md +37 -0
- package/docs/pages/components/copy-button.md +2 -2
- package/docs/pages/components/data-table-filter.md +33 -50
- package/docs/pages/components/data-table-search.md +4 -4
- package/docs/pages/components/data-table.md +27 -3
- package/docs/pages/components/date-range.md +116 -0
- package/docs/pages/components/dialog.md +29 -37
- package/docs/pages/components/diff-row.md +28 -0
- package/docs/pages/components/diff.md +46 -0
- package/docs/pages/components/editor.md +55 -0
- package/docs/pages/components/icon.md +46 -1
- package/docs/pages/components/input.md +30 -11
- package/docs/pages/components/item.md +35 -0
- package/docs/pages/components/key-value.md +25 -0
- package/docs/pages/components/menu.md +74 -7
- package/docs/pages/components/nav-item.md +15 -0
- package/docs/pages/components/nav-list.md +132 -0
- package/docs/pages/components/navbar.md +100 -1
- package/docs/pages/components/page.md +242 -74
- package/docs/pages/components/priority-list.md +43 -5
- package/docs/pages/components/query-builder.md +23 -0
- package/docs/pages/components/radio-group.md +33 -1
- package/docs/pages/components/radio.md +1 -1
- package/docs/pages/components/report-table.md +202 -0
- package/docs/pages/components/stat.md +30 -0
- package/docs/pages/components/tile.md +11 -0
- package/docs/pages/components/tooltip.md +1 -1
- package/docs/pages/components/translation-grid.md +86 -0
- package/docs/pages/components/vertical-stepper.md +108 -64
- package/package.json +2 -1
- package/scss/_global-spacing.scss +2 -2
- package/scss/_root.scss +11 -171
- package/scss/boot.scss +14 -0
- package/scss/mixins/_helper-mixins.scss +24 -2
- package/scss/mixins/_motion-mixins.scss +126 -0
- package/scss/mixins/_spacing-mixins.scss +4 -3
- package/scss/mixins/_tab-indicator-mixins.scss +12 -0
- package/scss/mixins/_typography-mixins.scss +1 -1
- package/scss/mixins/index.scss +14 -0
- package/scss/shared/_base.scss +32 -1
- package/scss/shared/_button-mixin.scss +7 -5
- package/scss/shared/_table.scss +35 -4
- package/scss/shared/nav.scss +4 -0
- package/scss/shared/shimmer.scss +1 -1
- package/scss/table-controls.scss +206 -0
- package/scss/themes/_dark.scss +1 -3
- package/scss/themes/_index.scss +1 -1
- package/scss/themes/_light.scss +46 -6
- package/scss/themes/_modes.scss +11 -11
- package/scss/themes/_openbyte.scss +944 -0
- package/scss/themes/_typography.scss +4 -2
- package/scss/variables/index.scss +0 -9
- package/src/components/alert/alert.component.ts +14 -4
- package/src/components/alert/alert.scss +55 -69
- package/src/components/alert/alert.test.ts +8 -0
- package/src/components/animated-button/animated-button.component.ts +3 -2
- package/src/components/animated-button/animated-button.scss +6 -23
- package/src/components/animated-button/animated-button.test.ts +4 -3
- package/src/components/avatar-group/avatar-group.component.ts +84 -0
- package/src/components/avatar-group/avatar-group.scss +54 -0
- package/src/components/avatar-group/avatar-group.test.ts +59 -0
- package/src/components/avatar-group/index.ts +12 -0
- package/src/components/badge/badge.component.ts +49 -0
- package/src/components/badge/badge.scss +80 -0
- package/src/components/badge/badge.test.ts +34 -0
- package/src/components/badge/index.ts +12 -0
- package/src/components/bulk-actions/bulk-actions.component.ts +14 -2
- package/src/components/button/button.component.ts +228 -8
- package/src/components/button/button.scss +115 -32
- package/src/components/button/button.test.ts +122 -0
- package/src/components/button-menu/button-menu.component.ts +32 -11
- package/src/components/button-menu/button-menu.scss +5 -1
- package/src/components/channel-tile/channel-tile.component.ts +34 -27
- package/src/components/channel-tile/channel-tile.scss +76 -43
- package/src/components/chart/builders.test.ts +46 -0
- package/src/components/chart/builders.ts +27 -3
- package/src/components/chart/chart-live.test.ts +4 -6
- package/src/components/chart/chart.component.ts +125 -5
- package/src/components/chart/chart.scss +121 -0
- package/src/components/chart/chart.test.ts +81 -0
- package/src/components/chat-message/chat-message.component.ts +21 -1
- package/src/components/chat-message/chat-message.scss +13 -2
- package/src/components/chat-message/chat-message.test.ts +9 -0
- package/src/components/checkbox/checkbox.component.ts +61 -27
- package/src/components/checkbox/checkbox.scss +58 -25
- package/src/components/checkbox-group/checkbox-group.component.ts +7 -1
- package/src/components/chip/chip.component.ts +11 -1
- package/src/components/chip/chip.scss +91 -26
- package/src/components/chip/chip.test.ts +17 -0
- package/src/components/collapsible/collapsible.component.ts +17 -3
- package/src/components/collapsible/collapsible.scss +19 -10
- package/src/components/color-picker/color-picker.component.ts +277 -0
- package/src/components/color-picker/color-picker.scss +141 -0
- package/src/components/color-picker/color-picker.test.ts +57 -0
- package/src/components/color-picker/index.ts +12 -0
- package/src/components/cols/cols.component.ts +10 -0
- package/src/components/cols/cols.test.ts +17 -0
- package/src/components/confirm/confirm.component.ts +20 -6
- package/src/components/confirm/confirm.test.ts +52 -0
- package/src/components/content-block/content-block.component.ts +38 -9
- package/src/components/content-block/content-block.scss +11 -5
- package/src/components/content-block/content-block.test.ts +26 -0
- package/src/components/copy-button/copy-button.component.ts +2 -2
- package/src/components/copy-button/copy-button.scss +17 -4
- package/src/components/data-select/data-select.component.ts +3 -1
- package/src/components/data-table/data-table.component.ts +362 -140
- package/src/components/data-table/data-table.scss +133 -60
- package/src/components/data-table/data-table.test.ts +356 -4
- package/src/components/data-table-filter/data-table-filter.component.ts +426 -406
- package/src/components/data-table-filter/data-table-filter.scss +176 -148
- package/src/components/data-table-filter/data-table-filter.test.ts +271 -273
- package/src/components/data-table-search/data-table-search.component.ts +4 -2
- package/src/components/data-table-search/data-table-search.scss +8 -1
- package/src/components/data-table-search/data-table-search.test.ts +29 -0
- package/src/components/date-range/date-range-math.test.ts +78 -0
- package/src/components/date-range/date-range-math.ts +105 -0
- package/src/components/date-range/date-range.component.ts +375 -0
- package/src/components/date-range/date-range.scss +272 -0
- package/src/components/date-range/date-range.test.ts +247 -0
- package/src/components/date-range/index.ts +12 -0
- package/src/components/datepicker/datepicker.component.ts +44 -7
- package/src/components/datepicker/datepicker.scss +9 -0
- package/src/components/datepicker/datepicker.test.ts +2 -2
- package/src/components/dialog/dialog.component.ts +38 -19
- package/src/components/dialog/dialog.scss +65 -36
- package/src/components/dialog/dialog.test.ts +14 -0
- package/src/components/diff/diff.component.ts +55 -0
- package/src/components/diff/diff.scss +46 -0
- package/src/components/diff/diff.test.ts +15 -0
- package/src/components/diff/index.ts +12 -0
- package/src/components/diff-row/diff-row.component.ts +75 -0
- package/src/components/diff-row/diff-row.scss +70 -0
- package/src/components/diff-row/diff-row.test.ts +37 -0
- package/src/components/diff-row/index.ts +12 -0
- package/src/components/dropdown/dropdown.component.ts +12 -10
- package/src/components/dropdown/dropdown.scss +2 -0
- package/src/components/editor/editor.component.ts +159 -11
- package/src/components/editor/editor.scss +250 -1
- package/src/components/editor/editor.test.ts +31 -3
- package/src/components/editor/modules/ai/panel/ai-panel.scss +0 -1
- package/src/components/editor/modules/attachment/attachment.ts +53 -31
- package/src/components/editor/modules/context-menu/context-menu.ts +17 -0
- package/src/components/editor/modules/dialog/dialog.component.ts +23 -1
- package/src/components/editor/modules/dialog/dialog.test.ts +28 -0
- package/src/components/editor/modules/emoji/emoji.ts +4 -5
- package/src/components/editor/modules/merge-field/merge-field.ts +83 -0
- package/src/components/editor/modules/toolbar/toolbar.component.ts +121 -68
- package/src/components/editor/modules/toolbar/toolbar.scss +38 -0
- package/src/components/editor/modules/toolbar/toolbar.ts +25 -1
- package/src/components/empty-state/empty-state.component.ts +6 -1
- package/src/components/empty-state/empty-state.scss +21 -4
- package/src/components/expanding-action/expanding-action.component.ts +22 -34
- package/src/components/expanding-action/expanding-action.scss +3 -45
- package/src/components/expanding-action/expanding-action.test.ts +2 -1
- package/src/components/file/file.component.ts +30 -2
- package/src/components/file/file.scss +6 -0
- package/src/components/flow-builder/flow-builder.component.ts +36 -3
- package/src/components/flow-builder/flow-builder.scss +0 -6
- package/src/components/flow-builder/modules/flow-canvas/flow-canvas.component.ts +8 -0
- package/src/components/flow-builder/modules/flow-canvas/flow-canvas.scss +10 -5
- package/src/components/flow-builder/modules/flow-node/flow-node.component.ts +17 -0
- package/src/components/flow-builder/modules/flow-node/flow-node.scss +10 -0
- package/src/components/form-actions/form-actions.component.ts +48 -2
- package/src/components/form-actions/form-actions.scss +1 -1
- package/src/components/form-group/form-group.component.ts +10 -3
- package/src/components/form-group/form-group.scss +37 -4
- package/src/components/form-group/form-group.test.ts +10 -0
- package/src/components/header/header.component.ts +11 -4
- package/src/components/header/header.scss +47 -5
- package/src/components/hover-container/hover-container.component.ts +4 -5
- package/src/components/icon/icon.component.ts +95 -9
- package/src/components/icon/icon.scss +70 -6
- package/src/components/icon/icon.test.ts +55 -0
- package/src/components/icon-picker/icon-picker.component.ts +35 -1
- package/src/components/inline-edit/inline-edit.component.ts +38 -8
- package/src/components/inline-edit/inline-edit.scss +128 -19
- package/src/components/input/input.component.ts +173 -297
- package/src/components/input/input.scss +65 -43
- package/src/components/input/input.test.ts +86 -4
- package/src/components/item/item.component.ts +12 -0
- package/src/components/item/item.scss +102 -3
- package/src/components/item/item.test.ts +23 -0
- package/src/components/key/key.component.ts +2 -2
- package/src/components/key/key.scss +11 -0
- package/src/components/key-value/index.ts +12 -0
- package/src/components/key-value/key-value.component.ts +160 -0
- package/src/components/key-value/key-value.scss +20 -0
- package/src/components/key-value/key-value.test.ts +22 -0
- package/src/components/markdown-editor/markdown-editor.component.ts +8 -1
- package/src/components/menu/menu.component.ts +21 -2
- package/src/components/menu/menu.scss +43 -23
- package/src/components/menu/menu.test.ts +33 -0
- package/src/components/menu-item/menu-item.component.ts +13 -2
- package/src/components/menu-item/menu-item.scss +56 -23
- package/src/components/menu-item/menu-item.test.ts +31 -0
- package/src/components/menu-item/submenu-controller.ts +25 -15
- package/src/components/menu-label/index.ts +12 -0
- package/src/components/menu-label/menu-label.component.ts +30 -0
- package/src/components/menu-label/menu-label.scss +18 -0
- package/src/components/nav-item/index.ts +12 -0
- package/src/components/nav-item/nav-item.component.ts +83 -0
- package/src/components/nav-item/nav-item.scss +128 -0
- package/src/components/nav-list/index.ts +12 -0
- package/src/components/nav-list/nav-list.component.ts +313 -0
- package/src/components/nav-list/nav-list.scss +87 -0
- package/src/components/nav-list/nav-list.test.ts +250 -0
- package/src/components/navbar/navbar.component.ts +235 -171
- package/src/components/navbar/navbar.scss +333 -169
- package/src/components/navbar/navbar.test.ts +63 -143
- package/src/components/page/page.component.ts +114 -29
- package/src/components/page/page.scss +223 -95
- package/src/components/page/page.test.ts +214 -3
- package/src/components/page-builder/page-builder.component.ts +51 -5
- package/src/components/page-builder/page-builder.scss +6 -1
- package/src/components/page-nav/page-nav.component.ts +25 -3
- package/src/components/page-nav/page-nav.scss +10 -2
- package/src/components/pagination/pagination.scss +1 -1
- package/src/components/panel/panel.component.ts +14 -13
- package/src/components/panel/panel.scss +14 -10
- package/src/components/panel/panel.test.ts +42 -0
- package/src/components/popup/popup.component.ts +20 -13
- package/src/components/popup/popup.test.ts +21 -1
- package/src/components/priority-list/priority-list.component.ts +157 -172
- package/src/components/priority-list/priority-list.scss +113 -17
- package/src/components/priority-list/priority-list.test.ts +301 -3
- package/src/components/progress-bar/progress-bar.component.ts +1 -1
- package/src/components/progress-bar/progress-bar.scss +16 -4
- package/src/components/progress-tile/progress-tile.scss +1 -1
- package/src/components/query-builder/query-builder.component.ts +85 -10
- package/src/components/query-builder/query-builder.scss +7 -1
- package/src/components/query-builder/query-builder.test.ts +40 -0
- package/src/components/radio/radio.component.ts +57 -18
- package/src/components/radio/radio.scss +101 -26
- package/src/components/radio-group/radio-group.component.ts +45 -7
- package/src/components/radio-group/radio-group.scss +17 -0
- package/src/components/radio-group/radio-group.test.ts +63 -2
- package/src/components/rating/rating.component.ts +23 -0
- package/src/components/rating/rating.scss +1 -1
- package/src/components/remarkd-editor/remarkd-editor.component.ts +60 -5
- package/src/components/remarkd-editor/remarkd-editor.scss +12 -4
- package/src/components/report-table/index.ts +12 -0
- package/src/components/report-table/report-format.test.ts +86 -0
- package/src/components/report-table/report-format.ts +72 -0
- package/src/components/report-table/report-math.test.ts +74 -0
- package/src/components/report-table/report-math.ts +252 -0
- package/src/components/report-table/report-table.component.ts +681 -0
- package/src/components/report-table/report-table.scss +328 -0
- package/src/components/report-table/report-table.test.ts +702 -0
- package/src/components/reveal/reveal.component.ts +15 -1
- package/src/components/reveal/reveal.scss +5 -0
- package/src/components/schedule-builder/schedule-builder.component.ts +23 -8
- package/src/components/scroll-container/scroll-container.component.ts +19 -1
- package/src/components/scroll-container/scroll-container.scss +6 -1
- package/src/components/select/select.component.ts +52 -36
- package/src/components/select/select.scss +42 -25
- package/src/components/select/select.test.ts +14 -2
- package/src/components/settings-container/settings-container.scss +18 -5
- package/src/components/sidebar/sidebar.component.ts +8 -1
- package/src/components/sidebar/sidebar.scss +6 -1
- package/src/components/skeleton/skeleton.component.ts +3 -3
- package/src/components/skeleton/skeleton.scss +6 -6
- package/src/components/skeleton/skeleton.test.ts +9 -0
- package/src/components/slash-menu/slash-menu.scss +1 -1
- package/src/components/slideout/slideout.component.ts +20 -3
- package/src/components/slideout/slideout.scss +13 -6
- package/src/components/slideout/slideout.test.ts +19 -0
- package/src/components/split-button/split-button.component.ts +1 -1
- package/src/components/split-pane/split-pane.component.ts +71 -8
- package/src/components/split-pane/split-pane.scss +145 -41
- package/src/components/split-pane/split-pane.test.ts +23 -3
- package/src/components/stat/stat.component.ts +209 -14
- package/src/components/stat/stat.scss +305 -5
- package/src/components/stat/stat.test.ts +143 -2
- package/src/components/status-indicator/status-indicator.scss +22 -21
- package/src/components/stepper/stepper.scss +3 -3
- package/src/components/tab/tab.component.ts +1 -0
- package/src/components/table/table.component.ts +12 -1
- package/src/components/table/table.scss +21 -13
- package/src/components/table/table.test.ts +17 -0
- package/src/components/tabs/tabs.component.ts +150 -37
- package/src/components/tabs/tabs.scss +48 -7
- package/src/components/tabs/tabs.test.ts +169 -0
- package/src/components/textarea/textarea.component.ts +25 -3
- package/src/components/textarea/textarea.scss +10 -0
- package/src/components/textarea/textarea.test.ts +8 -4
- package/src/components/theme-editor/theme-editor.scss +0 -6
- package/src/components/tile/tile.component.ts +32 -2
- package/src/components/tile/tile.scss +40 -7
- package/src/components/tile/tile.test.ts +10 -0
- package/src/components/toggle/toggle.component.ts +23 -7
- package/src/components/toggle/toggle.scss +36 -29
- package/src/components/toggle/toggle.test.ts +17 -0
- package/src/components/tooltip/tooltip.component.ts +3 -0
- package/src/components/tooltip/tooltip.scss +11 -6
- package/src/components/tooltip/tooltip.test.ts +12 -0
- package/src/components/translation-field/index.ts +12 -0
- package/src/components/translation-field/translation-field.component.ts +55 -0
- package/src/components/translation-field/translation-field.scss +101 -0
- package/src/components/translation-fields/index.ts +12 -0
- package/src/components/translation-fields/translation-fields.component.ts +80 -0
- package/src/components/translation-fields/translation-fields.scss +60 -0
- package/src/components/translation-grid/index.ts +12 -0
- package/src/components/translation-grid/translation-grid.component.ts +157 -0
- package/src/components/translation-grid/translation-grid.scss +138 -0
- package/src/components/translation-grid/translation-grid.test.ts +28 -0
- package/src/components/vertical-stepper/vertical-stepper.component.ts +35 -9
- package/src/components/vertical-stepper/vertical-stepper.scss +110 -39
- package/src/components/vertical-stepper/vertical-stepper.test.ts +35 -0
- package/src/components/well/well.scss +2 -2
- package/src/events/events.ts +2 -0
- package/src/events/zn-chart-click.ts +13 -0
- package/src/events/zn-report-change.ts +7 -0
- package/src/form-control.scss +36 -3
- package/src/internal/anchored-popover.ts +175 -0
- package/src/internal/animate.ts +19 -5
- package/src/internal/cosmic-border.ts +15 -0
- package/src/internal/form.ts +1 -1
- package/src/internal/hover-intent.ts +15 -0
- package/src/internal/input-modality.ts +15 -0
- package/src/internal/pointer-intent.ts +37 -0
- package/src/internal/reorder.ts +625 -0
- package/src/internal/scroll.ts +51 -3
- package/src/internal/selection-card.ts +1 -1
- package/src/internal/tab-indicator.ts +92 -0
- package/src/internal/table-sort.ts +25 -0
- package/src/internal/table-tabs.ts +108 -0
- package/src/internal/test-drag.ts +35 -0
- package/src/internal/theme-openbyte.test.ts +126 -0
- package/src/internal/theme.ts +4 -4
- package/src/internal/zinc-element.ts +2 -2
- package/src/selection-card.scss +25 -0
- package/src/types/web-test-runner-commands.d.ts +1 -0
- package/src/utilities/color.test.ts +43 -0
- package/src/utilities/color.ts +189 -0
- package/src/zinc.ts +14 -0
- package/.github/workflows/eleventy_build.yml +0 -42
- package/scss/themes/_aura.scss +0 -114
|
@@ -16,23 +16,24 @@
|
|
|
16
16
|
overflow: hidden;
|
|
17
17
|
cursor: pointer;
|
|
18
18
|
border-right: 1px solid rgb(var(--zn-border-color));
|
|
19
|
-
background-color: rgb(var(--zn-
|
|
19
|
+
background-color: rgb(var(--zn-color-tab));
|
|
20
20
|
transition: background-color 0.15s ease;
|
|
21
21
|
user-select: none;
|
|
22
22
|
|
|
23
23
|
&:focus-visible {
|
|
24
|
-
outline:
|
|
25
|
-
|
|
24
|
+
outline: none;
|
|
25
|
+
box-shadow: inset 0 0 0 2px var(--zn-input-focus-ring-color, rgba(var(--zn-primary), 0.35));
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
:host(.active) .channel-tile {
|
|
30
30
|
background-color: rgb(var(--zn-panel));
|
|
31
|
+
box-shadow: inset 0 -2px 0 rgb(var(--zn-primary));
|
|
31
32
|
cursor: default;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
:host(:not(.active)) .channel-tile--
|
|
35
|
-
background-color: rgb(var(--zn-
|
|
35
|
+
:host(:not(.active)) .channel-tile:not(.channel-tile--incoming):hover {
|
|
36
|
+
background-color: rgb(var(--zn-body));
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
.channel-tile--incoming {
|
|
@@ -52,15 +53,17 @@
|
|
|
52
53
|
align-items: center;
|
|
53
54
|
flex-shrink: 0;
|
|
54
55
|
height: 24px;
|
|
55
|
-
padding: 0
|
|
56
|
-
background-color:
|
|
56
|
+
padding: 0 12px;
|
|
57
|
+
background-color: var(--zn-color-neutral-100);
|
|
57
58
|
|
|
58
59
|
h3 {
|
|
59
60
|
margin: 0;
|
|
60
|
-
font-size:
|
|
61
|
-
line-height:
|
|
62
|
-
font-weight:
|
|
63
|
-
|
|
61
|
+
font-size: 10px;
|
|
62
|
+
line-height: 24px;
|
|
63
|
+
font-weight: 600;
|
|
64
|
+
letter-spacing: 0.04em;
|
|
65
|
+
text-transform: uppercase;
|
|
66
|
+
color: rgb(var(--zn-color-muted-text));
|
|
64
67
|
text-overflow: ellipsis;
|
|
65
68
|
white-space: nowrap;
|
|
66
69
|
overflow: hidden;
|
|
@@ -84,18 +87,62 @@
|
|
|
84
87
|
flex: 1;
|
|
85
88
|
display: flex;
|
|
86
89
|
align-items: center;
|
|
87
|
-
gap:
|
|
88
|
-
padding:
|
|
90
|
+
gap: 10px;
|
|
91
|
+
padding: 0 12px;
|
|
89
92
|
width: 100%;
|
|
93
|
+
min-height: 52px;
|
|
94
|
+
box-sizing: border-box;
|
|
90
95
|
overflow: hidden;
|
|
91
96
|
z-index: 1;
|
|
92
97
|
}
|
|
93
98
|
|
|
99
|
+
// The 32px leading circle, shared by the active icon, the accept button and the reject control
|
|
100
|
+
.channel-tile__lead {
|
|
101
|
+
--zn-button-height: 30px; // inside the 1px border
|
|
102
|
+
--zn-button-plain-hover-background: transparent;
|
|
103
|
+
|
|
104
|
+
position: relative;
|
|
105
|
+
flex: none;
|
|
106
|
+
display: grid;
|
|
107
|
+
place-content: center;
|
|
108
|
+
width: 32px;
|
|
109
|
+
height: 32px;
|
|
110
|
+
box-sizing: border-box;
|
|
111
|
+
border-radius: 50%;
|
|
112
|
+
border: 1px solid rgb(var(--zn-border-color));
|
|
113
|
+
background-color: rgb(var(--zn-panel));
|
|
114
|
+
color: rgb(var(--zn-color-muted-text));
|
|
115
|
+
transition: color 0.15s ease, border-color 0.15s ease;
|
|
116
|
+
|
|
117
|
+
zn-icon {
|
|
118
|
+
--icon-color: currentColor;
|
|
119
|
+
|
|
120
|
+
color: inherit;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.channel-tile--available .channel-tile__lead {
|
|
125
|
+
border-style: dashed;
|
|
126
|
+
background-color: transparent;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.channel-tile:not(.channel-tile--default) .channel-tile__lead {
|
|
130
|
+
color: rgb(var(--channel-tile-color));
|
|
131
|
+
border-color: rgb(var(--channel-tile-color));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
:host(.active) .channel-tile--default .channel-tile__lead {
|
|
135
|
+
color: rgb(var(--zn-primary));
|
|
136
|
+
border-color: rgb(var(--zn-primary));
|
|
137
|
+
}
|
|
138
|
+
|
|
94
139
|
.channel-tile__content {
|
|
95
140
|
display: flex;
|
|
96
141
|
flex-direction: column;
|
|
142
|
+
justify-content: center;
|
|
97
143
|
flex-grow: 1;
|
|
98
|
-
gap:
|
|
144
|
+
gap: 2px;
|
|
145
|
+
min-height: 32px;
|
|
99
146
|
overflow: hidden;
|
|
100
147
|
|
|
101
148
|
@container (max-width: 200px) {
|
|
@@ -105,11 +152,10 @@
|
|
|
105
152
|
|
|
106
153
|
.channel-tile__title {
|
|
107
154
|
margin: 0;
|
|
108
|
-
font-size:
|
|
109
|
-
line-height:
|
|
110
|
-
font-weight:
|
|
111
|
-
color: var(--zn-text-heading
|
|
112
|
-
text-transform: var(--zn-text-heading-section-transform);
|
|
155
|
+
font-size: 13px;
|
|
156
|
+
line-height: 15px;
|
|
157
|
+
font-weight: 600;
|
|
158
|
+
color: rgb(var(--zn-text-heading));
|
|
113
159
|
text-overflow: ellipsis;
|
|
114
160
|
white-space: nowrap;
|
|
115
161
|
overflow: hidden;
|
|
@@ -117,11 +163,10 @@
|
|
|
117
163
|
|
|
118
164
|
.channel-tile__subtitle {
|
|
119
165
|
margin: 0;
|
|
120
|
-
font-size:
|
|
121
|
-
line-height:
|
|
122
|
-
font-weight:
|
|
123
|
-
color: var(--zn-
|
|
124
|
-
text-transform: var(--zn-text-subheading-small-transform);
|
|
166
|
+
font-size: 12px;
|
|
167
|
+
line-height: 15px;
|
|
168
|
+
font-weight: 400;
|
|
169
|
+
color: rgb(var(--zn-color-muted-text));
|
|
125
170
|
text-overflow: ellipsis;
|
|
126
171
|
white-space: nowrap;
|
|
127
172
|
overflow: hidden;
|
|
@@ -134,25 +179,18 @@
|
|
|
134
179
|
gap: var(--zn-spacing-small);
|
|
135
180
|
}
|
|
136
181
|
|
|
137
|
-
.channel-tile__reject {
|
|
138
|
-
flex-shrink: 0;
|
|
139
|
-
display: flex;
|
|
140
|
-
align-items: center;
|
|
141
|
-
justify-content: center;
|
|
142
|
-
width: 36px;
|
|
143
|
-
height: 36px;
|
|
144
|
-
border-radius: 50%;
|
|
145
|
-
border: none;
|
|
182
|
+
.channel-tile--available .channel-tile__reject {
|
|
146
183
|
padding: 0;
|
|
147
184
|
margin: 0;
|
|
148
|
-
|
|
185
|
+
border-style: solid;
|
|
186
|
+
background-color: rgb(var(--zn-panel));
|
|
149
187
|
color: rgb(var(--zn-color-error));
|
|
150
188
|
cursor: pointer;
|
|
151
|
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
|
|
152
189
|
|
|
153
190
|
&:hover {
|
|
154
|
-
background-color:
|
|
155
|
-
color: rgb(var(--zn-color-
|
|
191
|
+
background-color: rgb(var(--zn-color-error));
|
|
192
|
+
border-color: rgb(var(--zn-color-error));
|
|
193
|
+
color: rgb(var(--zn-panel));
|
|
156
194
|
}
|
|
157
195
|
}
|
|
158
196
|
|
|
@@ -161,8 +199,7 @@
|
|
|
161
199
|
bottom: 0;
|
|
162
200
|
left: 0;
|
|
163
201
|
right: 0;
|
|
164
|
-
height:
|
|
165
|
-
background-color: rgba(var(--zn-shadow), 0.2);
|
|
202
|
+
height: 2px;
|
|
166
203
|
overflow: hidden;
|
|
167
204
|
z-index: 1;
|
|
168
205
|
|
|
@@ -196,7 +233,3 @@
|
|
|
196
233
|
.channel-tile--disabled {
|
|
197
234
|
--channel-tile-color: var(--zn-color-disabled, 204, 204, 204);
|
|
198
235
|
}
|
|
199
|
-
|
|
200
|
-
.channel-tile--incoming .channel-tile__body zn-button {
|
|
201
|
-
--zn-color-tab: var(--zn-color-panel);
|
|
202
|
-
}
|
|
@@ -430,3 +430,49 @@ describe('buildSankeyOption', () => {
|
|
|
430
430
|
expect((opt.tooltip as any).trigger).to.equal('item');
|
|
431
431
|
});
|
|
432
432
|
});
|
|
433
|
+
|
|
434
|
+
describe('cartesian legends', () => {
|
|
435
|
+
it('hides the legend for a single series', () => {
|
|
436
|
+
const opt = buildLineOption({ ...baseProps, type: 'line' });
|
|
437
|
+
expect((opt.legend as any).show).to.equal(false);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it('shows the legend for several series, ignoring hidden ones', () => {
|
|
441
|
+
const two = buildLineOption({ ...baseProps, data: [{ name: 'A', data: [1] }, { name: 'B', data: [2] }] });
|
|
442
|
+
const oneVisible = buildLineOption({ ...baseProps, data: [{ name: 'A', data: [1] }, { name: '_base', data: [2] }] });
|
|
443
|
+
expect((two.legend as any).show).to.equal(true);
|
|
444
|
+
expect((oneVisible.legend as any).show).to.equal(false);
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it('scrolls the legend on one line so it never wraps into the grid', () => {
|
|
448
|
+
const opt = buildLineOption({ ...baseProps, data: [{ name: 'A', data: [1] }, { name: 'B', data: [2] }] });
|
|
449
|
+
expect((opt.legend as any).type).to.equal('scroll');
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
describe('markLatest', () => {
|
|
454
|
+
it('hides every point but the last, which gets a hollow dot', () => {
|
|
455
|
+
const series = (buildAreaOption({ ...baseProps, type: 'area', markLatest: true }).series as any[])[0];
|
|
456
|
+
expect(series.symbol).to.equal('none');
|
|
457
|
+
expect(series.data.slice(0, 2)).to.deep.equal([10, 20]);
|
|
458
|
+
expect(series.data[2]).to.deep.equal({ value: 30, symbol: 'emptyCircle', symbolSize: 8 });
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
it('marks the last point with a value, skipping trailing gaps', () => {
|
|
462
|
+
const data = [{ name: 'A', data: [10, 20, null] }];
|
|
463
|
+
const series = (buildAreaOption({ ...baseProps, type: 'area', markLatest: true, data }).series as any[])[0];
|
|
464
|
+
expect(series.data).to.deep.equal([10, { value: 20, symbol: 'emptyCircle', symbolSize: 8 }, null]);
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
it('leaves a silent reference series unmarked', () => {
|
|
468
|
+
const data = [{ name: 'Pass mark', data: [70, 70], silent: true, symbol: 'none' }];
|
|
469
|
+
const series = (buildAreaOption({ ...baseProps, type: 'area', markLatest: true, data }).series as any[])[0];
|
|
470
|
+
expect(series.data).to.deep.equal([70, 70]);
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
it('leaves the points alone by default', () => {
|
|
474
|
+
const series = (buildLineOption({ ...baseProps, type: 'line' }).series as any[])[0];
|
|
475
|
+
expect(series.symbol).to.equal(undefined);
|
|
476
|
+
expect(series.data).to.deep.equal([10, 20, 30]);
|
|
477
|
+
});
|
|
478
|
+
});
|
|
@@ -81,6 +81,8 @@ export interface BuilderProps {
|
|
|
81
81
|
indicators?: RadarIndicator[];
|
|
82
82
|
minValue?: number;
|
|
83
83
|
maxValue?: number;
|
|
84
|
+
/** Marks each line's last point with a hollow dot and hides the others. */
|
|
85
|
+
markLatest?: boolean;
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
function baseOption(props: BuilderProps, tooltipTrigger: 'axis' | 'item'): EChartsOption {
|
|
@@ -102,17 +104,24 @@ function baseOption(props: BuilderProps, tooltipTrigger: 'axis' | 'item'): EChar
|
|
|
102
104
|
: undefined,
|
|
103
105
|
},
|
|
104
106
|
legend: {
|
|
107
|
+
type: 'scroll',
|
|
105
108
|
top: 0,
|
|
106
109
|
right: 0,
|
|
107
110
|
icon: 'circle',
|
|
108
111
|
textStyle: { color: textColor },
|
|
112
|
+
pageIconSize: 10,
|
|
113
|
+
pageTextStyle: { color: textColor },
|
|
109
114
|
},
|
|
110
115
|
};
|
|
111
116
|
}
|
|
112
117
|
|
|
113
118
|
function commonOption(props: BuilderProps): EChartsOption {
|
|
119
|
+
const base = baseOption(props, 'axis');
|
|
120
|
+
// A lone series is named by the chart's own caption, so its legend only repeats it.
|
|
121
|
+
const named = props.data.filter((s) => !s.name.startsWith('_')).length;
|
|
114
122
|
return {
|
|
115
|
-
...
|
|
123
|
+
...base,
|
|
124
|
+
legend: { ...(base.legend as Record<string, unknown>), show: named > 1 },
|
|
116
125
|
grid: {
|
|
117
126
|
left: 40,
|
|
118
127
|
right: 20,
|
|
@@ -223,14 +232,28 @@ export function buildBarOption(props: BuilderProps): EChartsOption {
|
|
|
223
232
|
};
|
|
224
233
|
}
|
|
225
234
|
|
|
235
|
+
// latestMarker hides a line's points except the last, which gets a hollow dot.
|
|
236
|
+
function latestMarker(props: BuilderProps, s: SeriesItem): Record<string, unknown> {
|
|
237
|
+
if (!props.markLatest || s.silent || !s.data?.length) return {};
|
|
238
|
+
const data = normalizeData(s.data);
|
|
239
|
+
// A null is a gap, so the marker goes on the last point that has a value.
|
|
240
|
+
const last = data.findLastIndex(d => d !== null && d !== undefined && !(Array.isArray(d) && d[d.length - 1] === null));
|
|
241
|
+
if (last < 0) return { symbol: 'none' };
|
|
242
|
+
return {
|
|
243
|
+
symbol: 'none',
|
|
244
|
+
data: data.map((d, i) => (i === last ? { value: d, symbol: 'emptyCircle', symbolSize: 8 } : d)),
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
226
248
|
export function buildLineOption(props: BuilderProps): EChartsOption {
|
|
227
249
|
return {
|
|
228
250
|
...commonOption(props),
|
|
229
251
|
xAxis: buildXAxis(props, true),
|
|
230
252
|
yAxis: buildYAxis(props),
|
|
231
|
-
series: seriesFromProps(props, 'line', () => ({
|
|
253
|
+
series: seriesFromProps(props, 'line', (s) => ({
|
|
232
254
|
symbolSize: props.datapointSize,
|
|
233
255
|
smooth: props.smooth,
|
|
256
|
+
...latestMarker(props, s),
|
|
234
257
|
})),
|
|
235
258
|
};
|
|
236
259
|
}
|
|
@@ -240,10 +263,11 @@ export function buildAreaOption(props: BuilderProps): EChartsOption {
|
|
|
240
263
|
...commonOption(props),
|
|
241
264
|
xAxis: buildXAxis(props, true),
|
|
242
265
|
yAxis: buildYAxis(props),
|
|
243
|
-
series: seriesFromProps(props, 'line', () => ({
|
|
266
|
+
series: seriesFromProps(props, 'line', (s) => ({
|
|
244
267
|
symbolSize: props.datapointSize,
|
|
245
268
|
smooth: props.smooth,
|
|
246
269
|
areaStyle: { opacity: 0.1 },
|
|
270
|
+
...latestMarker(props, s),
|
|
247
271
|
})),
|
|
248
272
|
};
|
|
249
273
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return */
|
|
2
|
+
import '../../../dist/zn.min.js';
|
|
2
3
|
import { expect, fixture, html } from '@open-wc/testing';
|
|
3
|
-
import ZnChart from './chart.component';
|
|
4
|
-
|
|
5
|
-
ZnChart.define('zn-chart-live-test');
|
|
6
4
|
class Source extends EventTarget {
|
|
7
5
|
static instances: Source[]=[]; closed=false; onopen?:()=>void; onerror?:()=>void;
|
|
8
6
|
url: string;
|
|
@@ -17,7 +15,7 @@ describe('chart SSE component',()=>{
|
|
|
17
15
|
beforeEach(()=>{Source.instances=[];window.EventSource=Source as unknown as typeof EventSource;});
|
|
18
16
|
afterEach(()=>{window.EventSource=original;});
|
|
19
17
|
it('renders SSE buckets and expected bands, reacts to display changes, and stops when removed',async()=>{
|
|
20
|
-
const el:any=await fixture(html`<zn-chart
|
|
18
|
+
const el:any=await fixture(html`<zn-chart type="line" xaxis="datetime" enable-animations="350" live stream-url="https://relay.example/events"></zn-chart>`);
|
|
21
19
|
await el.updateComplete;await pause();
|
|
22
20
|
const source=Source.instances.at(-1)!;
|
|
23
21
|
expect(source).to.exist;
|
|
@@ -57,7 +55,7 @@ describe('chart SSE component',()=>{
|
|
|
57
55
|
el.remove();expect(source.closed).to.equal(true);
|
|
58
56
|
});
|
|
59
57
|
it('keeps transitions enabled for a high-volume hour', async()=>{
|
|
60
|
-
const el:any=await fixture(html`<zn-chart
|
|
58
|
+
const el:any=await fixture(html`<zn-chart type="line" xaxis="datetime" enable-animations="350" live stream-url="https://relay.example/hour"></zn-chart>`);
|
|
61
59
|
await el.updateComplete;await pause();
|
|
62
60
|
Source.instances.at(-1)!.send('snapshot',{
|
|
63
61
|
from:0,until:3600000,server_time:Date.now(),expires_at:Date.now()+60000,resolution_seconds:1,metric:'average',
|
|
@@ -71,7 +69,7 @@ describe('chart SSE component',()=>{
|
|
|
71
69
|
el.remove();
|
|
72
70
|
});
|
|
73
71
|
it('restarts transport when its URL changes and when reattached',async()=>{
|
|
74
|
-
const el:any=await fixture(html`<zn-chart
|
|
72
|
+
const el:any=await fixture(html`<zn-chart type="line" live stream-url="https://relay.example/a"></zn-chart>`);
|
|
75
73
|
await el.updateComplete;await pause();
|
|
76
74
|
const old=Source.instances.at(-1)!;
|
|
77
75
|
el.streamUrl='https://relay.example/b';await el.updateComplete;
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
type SeriesItem,
|
|
18
18
|
} from './builders';
|
|
19
19
|
import { type CSSResultGroup, html, type PropertyValues, unsafeCSS } from 'lit';
|
|
20
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
20
21
|
import { type EChartsModule, loadECharts } from './echarts-loader';
|
|
21
22
|
import { LiveTransport, LiveWindow } from './live';
|
|
22
23
|
import { property, state } from 'lit/decorators.js';
|
|
@@ -32,6 +33,8 @@ import type { ECharts } from 'echarts/core';
|
|
|
32
33
|
* @since 1.0
|
|
33
34
|
*
|
|
34
35
|
* @csspart base - The component's base wrapper.
|
|
36
|
+
*
|
|
37
|
+
* @event zn-chart-click - Emitted when a data point, bar or slice is clicked.
|
|
35
38
|
*/
|
|
36
39
|
export default class ZnChart extends ZincElement {
|
|
37
40
|
static styles: CSSResultGroup = unsafeCSS(styles);
|
|
@@ -47,6 +50,7 @@ export default class ZnChart extends ZincElement {
|
|
|
47
50
|
@property({ type: Boolean }) stacked = false;
|
|
48
51
|
|
|
49
52
|
@property({ type: Boolean }) live = false;
|
|
53
|
+
/** JSON series polled with `live`; otherwise fetched once, as a series array or `{categories, data}`. */
|
|
50
54
|
@property({ attribute: 'data-url' }) dataUrl = '';
|
|
51
55
|
@property({ attribute: 'stream-url' }) streamUrl = '';
|
|
52
56
|
@property({ attribute: 'live-renew-url' }) liveRenewUrl = '';
|
|
@@ -75,6 +79,8 @@ export default class ZnChart extends ZincElement {
|
|
|
75
79
|
@property({ attribute: 'show-labels', type: Boolean }) showLabels?: boolean;
|
|
76
80
|
@property({ attribute: 'min-value', type: Number }) minValue?: number;
|
|
77
81
|
@property({ attribute: 'max-value', type: Number }) maxValue?: number;
|
|
82
|
+
/** On line and area charts, marks each series' latest point and hides the rest. */
|
|
83
|
+
@property({ attribute: 'mark-latest', type: Boolean }) markLatest = false;
|
|
78
84
|
@property({
|
|
79
85
|
converter: {
|
|
80
86
|
fromAttribute: (value: string | null) => {
|
|
@@ -91,6 +97,11 @@ export default class ZnChart extends ZincElement {
|
|
|
91
97
|
private initPromise?: Promise<void>;
|
|
92
98
|
private liveTimer?: number;
|
|
93
99
|
private pollAbort?: AbortController;
|
|
100
|
+
private loadedUrl = '';
|
|
101
|
+
/** Set while `data-url` loads; cartesian charts show a placeholder until the data arrives. */
|
|
102
|
+
@state() private loading = false;
|
|
103
|
+
@state() private loadingOut = false;
|
|
104
|
+
private riseIn = false;
|
|
94
105
|
@state() private liveStatus = 'connecting';
|
|
95
106
|
private liveWindow = new LiveWindow();
|
|
96
107
|
private replaceLiveSeries = true;
|
|
@@ -133,6 +144,7 @@ export default class ZnChart extends ZincElement {
|
|
|
133
144
|
option.animationThreshold = 10000;
|
|
134
145
|
option.animationEasingUpdate = 'linear';
|
|
135
146
|
}
|
|
147
|
+
if (this.riseIn) this.prepareRise(option);
|
|
136
148
|
if (this.liveWindow.frame && this.live && !this.replaceLiveSeries) {
|
|
137
149
|
// Keep the prediction's models and data in ECharts between snapshots.
|
|
138
150
|
// Only measurements and the moving viewport change on deltas/heartbeats.
|
|
@@ -148,16 +160,50 @@ export default class ZnChart extends ZincElement {
|
|
|
148
160
|
animationThreshold: 10000,
|
|
149
161
|
});
|
|
150
162
|
} else {
|
|
151
|
-
this.chart?.setOption(option, { replaceMerge: ['series', 'legend', 'xAxis'] });
|
|
163
|
+
this.chart?.setOption(option, { replaceMerge: ['series', 'legend', 'xAxis', 'yAxis'] });
|
|
152
164
|
}
|
|
153
165
|
this.replaceLiveSeries = false;
|
|
154
166
|
}
|
|
155
167
|
|
|
168
|
+
// Draws the loaded series flat on the baseline first, so ECharts animates them up to their values
|
|
169
|
+
private prepareRise(option: ReturnType<ZnChart['buildOption']>) {
|
|
170
|
+
this.riseIn = false;
|
|
171
|
+
if (!ZnChart.riseTypes.includes(this.type) || window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
|
|
172
|
+
const series = (Array.isArray(option.series) ? option.series : option.series ? [option.series] : []) as Record<string, unknown>[];
|
|
173
|
+
const flat = (v: unknown): unknown => typeof v === 'number' ? 0
|
|
174
|
+
: Array.isArray(v) ? [v[0], 0, ...v.slice(2)]
|
|
175
|
+
: v && typeof v === 'object' && 'value' in v ? { ...v, value: flat((v as { value: unknown }).value) } : v;
|
|
176
|
+
this.chart?.setOption({
|
|
177
|
+
...option,
|
|
178
|
+
animation: false,
|
|
179
|
+
series: series.map((item, idx) => ({
|
|
180
|
+
...item, id: `rise-${idx}`, data: Array.isArray(item.data) ? item.data.map(flat) : item.data,
|
|
181
|
+
})),
|
|
182
|
+
}, { replaceMerge: ['series', 'legend', 'xAxis', 'yAxis'] });
|
|
183
|
+
option.animation = true;
|
|
184
|
+
option.animationDurationUpdate = 450;
|
|
185
|
+
option.animationEasingUpdate = 'cubicOut';
|
|
186
|
+
// Same ids as the flat pass, so ECharts updates those series rather than drawing new ones in
|
|
187
|
+
option.series = series.map((item, idx) => ({
|
|
188
|
+
...item, id: `rise-${idx}`, animationDelayUpdate: idx * 40,
|
|
189
|
+
})) as typeof option.series;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private static readonly riseTypes: ChartType[] = ['line', 'area', 'bar'];
|
|
193
|
+
private static readonly viewOnly = ['liveStatus', 'loading', 'loadingOut'];
|
|
194
|
+
|
|
195
|
+
protected willUpdate(changed: PropertyValues) {
|
|
196
|
+
super.willUpdate(changed);
|
|
197
|
+
if ((changed.has('dataUrl') || changed.has('live')) && this.dataUrl && !this.live && this.dataUrl !== this.loadedUrl) {
|
|
198
|
+
this.loading = true;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
156
202
|
protected updated(changed: PropertyValues) {
|
|
157
203
|
super.updated(changed);
|
|
158
204
|
if (!this.chart) return;
|
|
159
205
|
if (['live', 'dataUrl', 'streamUrl', 'liveRenewUrl', 'liveInterval'].some(key => changed.has(key))) this.startLive();
|
|
160
|
-
if (changed.
|
|
206
|
+
if ([...changed.keys()].some(key => !ZnChart.viewOnly.includes(key as string))) this.updateChart();
|
|
161
207
|
}
|
|
162
208
|
|
|
163
209
|
connectedCallback() {
|
|
@@ -193,12 +239,24 @@ export default class ZnChart extends ZincElement {
|
|
|
193
239
|
|
|
194
240
|
private getTextColor(): string | undefined {
|
|
195
241
|
const cs = getComputedStyle(this);
|
|
242
|
+
const themed = cs.getPropertyValue('--zn-chart-text-color').trim();
|
|
243
|
+
if (themed) return themed;
|
|
196
244
|
const rgb = cs.getPropertyValue('--zn-text').trim();
|
|
197
245
|
if (!rgb) return undefined;
|
|
198
246
|
const opacity = cs.getPropertyValue('--zn-text-opacity').trim() || '1';
|
|
199
247
|
return `rgba(${rgb}, ${opacity})`;
|
|
200
248
|
}
|
|
201
249
|
|
|
250
|
+
// A theme supplies a categorical palette as --zn-chart-color-1..6; without
|
|
251
|
+
// one, ECharts keeps its own default palette.
|
|
252
|
+
private getPalette(): string[] | undefined {
|
|
253
|
+
const cs = getComputedStyle(this);
|
|
254
|
+
const colors = [1, 2, 3, 4, 5, 6]
|
|
255
|
+
.map(i => cs.getPropertyValue(`--zn-chart-color-${i}`).trim())
|
|
256
|
+
.filter(Boolean);
|
|
257
|
+
return colors.length ? colors : undefined;
|
|
258
|
+
}
|
|
259
|
+
|
|
202
260
|
private getBorderColor(): string | undefined {
|
|
203
261
|
const rgb = getComputedStyle(this).getPropertyValue('--zn-border-color').trim();
|
|
204
262
|
return rgb ? `rgb(${rgb})` : undefined;
|
|
@@ -214,7 +272,7 @@ export default class ZnChart extends ZincElement {
|
|
|
214
272
|
stacked: this.stacked,
|
|
215
273
|
enableAnimations: this.enableAnimations,
|
|
216
274
|
datapointSize: this.datapointSize,
|
|
217
|
-
colors: this.colors,
|
|
275
|
+
colors: this.colors ?? this.getPalette(),
|
|
218
276
|
theme: this.getTheme(),
|
|
219
277
|
smooth: this.smooth,
|
|
220
278
|
scale: this.scale,
|
|
@@ -227,6 +285,7 @@ export default class ZnChart extends ZincElement {
|
|
|
227
285
|
indicators: Array.isArray(this.indicators) ? this.indicators : [],
|
|
228
286
|
minValue: this.minValue,
|
|
229
287
|
maxValue: this.maxValue,
|
|
288
|
+
markLatest: this.markLatest,
|
|
230
289
|
};
|
|
231
290
|
switch (this.type) {
|
|
232
291
|
case 'bar': return buildBarOption(props);
|
|
@@ -257,6 +316,16 @@ export default class ZnChart extends ZincElement {
|
|
|
257
316
|
|
|
258
317
|
this.chart = echarts.init(host);
|
|
259
318
|
this.chart.setOption(this.buildOption());
|
|
319
|
+
this.chart.on('click', params => {
|
|
320
|
+
this.emit('zn-chart-click', {
|
|
321
|
+
detail: {
|
|
322
|
+
seriesName: params.seriesName ?? '',
|
|
323
|
+
name: params.name,
|
|
324
|
+
dataIndex: params.dataIndex,
|
|
325
|
+
value: params.value,
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
});
|
|
260
329
|
|
|
261
330
|
if (this.syncGroup) {
|
|
262
331
|
this.chart.group = this.syncGroup;
|
|
@@ -277,7 +346,8 @@ export default class ZnChart extends ZincElement {
|
|
|
277
346
|
|
|
278
347
|
private startLive() {
|
|
279
348
|
this.stopLive(); this.liveWindow = new LiveWindow(); this.replaceLiveSeries = true;
|
|
280
|
-
if (!this.
|
|
349
|
+
if (!this.isConnected) return;
|
|
350
|
+
if (!this.live) { void this.loadData(); return; }
|
|
281
351
|
if (this.streamUrl || this.liveRenewUrl) {
|
|
282
352
|
try { this.transport.start(this.streamUrl, this.liveRenewUrl); } catch { this.stopLive(); }
|
|
283
353
|
return;
|
|
@@ -297,6 +367,34 @@ export default class ZnChart extends ZincElement {
|
|
|
297
367
|
this.liveTimer = window.setTimeout(() => void poll(), Math.max(250, this.liveInterval));
|
|
298
368
|
}
|
|
299
369
|
|
|
370
|
+
private async loadData() {
|
|
371
|
+
if (!this.dataUrl || this.dataUrl === this.loadedUrl) return;
|
|
372
|
+
const controller = new AbortController(); this.pollAbort = controller;
|
|
373
|
+
try {
|
|
374
|
+
const res = await fetch(this.dataUrl, {
|
|
375
|
+
signal: controller.signal,
|
|
376
|
+
credentials: 'same-origin',
|
|
377
|
+
headers: { Accept: 'application/json', 'x-kx-fetch-style': 'raw-json' },
|
|
378
|
+
});
|
|
379
|
+
if (res.ok) {
|
|
380
|
+
const body = await res.json() as SeriesItem[] | { data?: SeriesItem[]; categories?: string[] };
|
|
381
|
+
if (controller.signal.aborted) return;
|
|
382
|
+
this.loadedUrl = this.dataUrl;
|
|
383
|
+
this.riseIn = true;
|
|
384
|
+
if (Array.isArray(body)) {
|
|
385
|
+
this.data = body;
|
|
386
|
+
} else {
|
|
387
|
+
this.categories = body.categories ?? this.categories;
|
|
388
|
+
this.data = body.data ?? [];
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
} catch { /* keep what the chart already shows */ }
|
|
392
|
+
if (controller.signal.aborted) return;
|
|
393
|
+
this.loading = false;
|
|
394
|
+
this.loadingOut = true;
|
|
395
|
+
window.setTimeout(() => { this.loadingOut = false; }, 400);
|
|
396
|
+
}
|
|
397
|
+
|
|
300
398
|
private reinit() {
|
|
301
399
|
this.stopLive();
|
|
302
400
|
this.chart?.dispose();
|
|
@@ -335,8 +433,30 @@ export default class ZnChart extends ZincElement {
|
|
|
335
433
|
this.chart = undefined;
|
|
336
434
|
}
|
|
337
435
|
|
|
436
|
+
private renderLoading() {
|
|
437
|
+
if (!(this.loading || this.loadingOut) || !ZnChart.riseTypes.includes(this.type)) return null;
|
|
438
|
+
return html`
|
|
439
|
+
<div class="${classMap({ loading: true, 'loading--out': !this.loading })}" style="height: ${this.height}px"
|
|
440
|
+
role="status" aria-label="Loading chart">
|
|
441
|
+
<div class="loading__legend">
|
|
442
|
+
${[48, 40, 52, 36].map(w => html`<span class="loading__pill" style="width: ${w}px"></span>`)}
|
|
443
|
+
</div>
|
|
444
|
+
<div class="loading__plot">
|
|
445
|
+
${[0, 1, 2, 3, 4].map(i => html`
|
|
446
|
+
<span class="loading__row" style="animation-delay: ${i * 120}ms">
|
|
447
|
+
<span class="loading__pill loading__label"></span>
|
|
448
|
+
</span>`)}
|
|
449
|
+
<span class="loading__track"><span class="loading__pill loading__label"></span></span>
|
|
450
|
+
<span class="loading__x">
|
|
451
|
+
${[0, 1, 2, 3, 4, 5].map(() => html`<span class="loading__pill"></span>`)}
|
|
452
|
+
</span>
|
|
453
|
+
</div>
|
|
454
|
+
</div>`;
|
|
455
|
+
}
|
|
456
|
+
|
|
338
457
|
protected render(): unknown {
|
|
339
|
-
return html`<div class="chart"><div id="chart"></div>
|
|
458
|
+
return html`<div class="${classMap({ chart: true, 'chart--loading': this.loading })}"><div id="chart"></div>
|
|
459
|
+
${this.renderLoading()}
|
|
340
460
|
${this.live && (this.streamUrl || this.liveRenewUrl) ? html`<div role="status" aria-live="polite">Live: ${this.liveStatus}${this.liveWindow.frame ? ` · ${this.liveWindow.frame.resolution_seconds}s intervals · Expected range: ${this.liveWindow.predictionStatus}` : ''}</div>` : ''}
|
|
341
461
|
</div>`;
|
|
342
462
|
}
|