From 21e50db5ecdc6a0b2f8250f115562ab4fd6e3f4d Mon Sep 17 00:00:00 2001 From: Ghislain B Date: Thu, 9 May 2024 09:28:29 -0400 Subject: [PATCH] feat!: pure SVG icons, Moment to Tempo, Flatpickr to Vanilla-Calendar (#1518) * feat!: pure SVG icons, Moment to Tempo, Flatpickr to Vanilla-Calendar --- .vscode/settings.json | 3 +- CHANGELOG.md | 569 +++++ README.md | 38 +- docs/TOC.md | 3 + docs/column-functionalities/Cell-Menu.md | 46 +- docs/column-functionalities/Editors.md | 12 +- docs/column-functionalities/Formatters.md | 56 +- .../Autocomplete-Editor-(Kraaden-lib).md | 5 - .../editors/Date-Editor-(flatpickr).md | 4 +- ...elect-Dropdown-Editor-(single,multiple).md | 26 +- .../editors/date-editor-(vanilla-calendar).md | 72 + .../filters/Compound-Filters.md | 25 +- .../filters/Range-Filters.md | 31 +- .../filters/Select-Filter.md | 115 +- .../filters/Styling-Filled-Filters.md | 78 +- docs/developer-guides/csp-compliance.md | 19 +- docs/getting-started/installation-vanilla.md | 112 + docs/getting-started/quick-start.md | 3 +- .../Composite-Editor-Modal.md | 12 +- docs/grid-functionalities/Context-Menu.md | 42 +- docs/grid-functionalities/Export-to-Excel.md | 22 +- .../Export-to-Text-File.md | 4 +- docs/grid-functionalities/Grid-Menu.md | 18 +- docs/grid-functionalities/Tree-Data-Grid.md | 4 +- .../frozen-columns-rows.md | 2 +- .../grouping-aggregators.md | 22 +- .../header-menu-header-buttons.md | 6 +- docs/migrations/migration-to-5.x.md | 255 +++ docs/styling/dark-mode.md | 4 +- docs/styling/styling.md | 250 +- eslint.config.mjs | 2 - .../vite-demo-vanilla-bundle/CHANGELOG.md | 77 + .../vite-demo-vanilla-bundle/package.json | 7 +- .../vite-demo-vanilla-bundle/src/app.html | 4 +- .../vite-demo-vanilla-bundle/src/bulma.scss | 17 + .../src/examples/example-grid-options.ts | 4 +- .../src/examples/example01.html | 8 +- .../src/examples/example02.html | 10 +- .../src/examples/example03.html | 16 +- .../src/examples/example03.ts | 40 +- .../src/examples/example04.html | 14 +- .../src/examples/example04.ts | 10 +- .../src/examples/example05.html | 16 +- .../src/examples/example05.scss | 7 + .../src/examples/example05.ts | 4 +- .../src/examples/example06.html | 14 +- .../src/examples/example06.scss | 28 +- .../src/examples/example06.ts | 10 +- .../src/examples/example07.html | 25 +- .../src/examples/example07.scss | 26 +- .../src/examples/example07.ts | 25 +- .../src/examples/example08.html | 8 +- .../src/examples/example09.html | 4 +- .../src/examples/example10.html | 14 +- .../src/examples/example10.ts | 37 +- .../src/examples/example11.html | 12 +- .../src/examples/example11.ts | 10 +- .../src/examples/example12.html | 22 +- .../src/examples/example12.ts | 34 +- .../src/examples/example13.html | 2 +- .../src/examples/example13.ts | 8 +- .../src/examples/example14.html | 12 +- .../src/examples/example14.ts | 21 +- .../src/examples/example15.html | 4 +- .../src/examples/example15.ts | 6 +- .../src/examples/example16.html | 4 +- .../src/examples/example16.scss | 78 +- .../src/examples/example16.ts | 13 +- .../src/examples/example17.html | 2 +- .../src/examples/example17.ts | 2 +- .../src/examples/example18.html | 12 +- .../src/examples/example18.scss | 13 + .../src/examples/example18.ts | 38 +- .../src/examples/example19.html | 6 +- .../src/examples/example20.html | 2 +- .../src/examples/example21.html | 20 +- .../src/examples/example21.scss | 176 +- .../src/examples/example21.ts | 57 +- .../src/examples/example22.html | 5 +- .../src/examples/example22.ts | 8 +- .../src/examples/icons.html | 401 ++-- .../src/examples/icons.scss | 12 + .../src/examples/icons.ts | 32 +- examples/vite-demo-vanilla-bundle/src/main.ts | 8 +- .../src/material-styles.scss | 88 +- .../vite-demo-vanilla-bundle/src/styles.scss | 40 +- .../vite-demo-vanilla-bundle/vite.config.mts | 5 - lerna.json | 3 +- package.json | 5 +- packages/binding/CHANGELOG.md | 15 + packages/binding/README.md | 1 + packages/binding/package.json | 2 +- packages/binding/src/bindingEvent.service.ts | 2 +- packages/common/CHANGELOG.md | 621 +++++ packages/common/README.md | 1 + packages/common/package.json | 13 +- .../commonEditorFilterUtils.ts | 34 +- .../src/core/__tests__/slickDataView.spec.ts | 1 - .../src/core/__tests__/slickGrid.spec.ts | 10 - packages/common/src/core/slickGrid.ts | 79 +- .../__tests__/autocompleterEditor.spec.ts | 5 +- .../src/editors/__tests__/dateEditor.spec.ts | 269 ++- .../src/editors/__tests__/floatEditor.spec.ts | 2 +- .../src/editors/__tests__/inputEditor.spec.ts | 18 + .../editors/__tests__/integerEditor.spec.ts | 2 +- .../__tests__/multipleSelectEditor.spec.ts | 4 +- .../editors/__tests__/selectEditor.spec.ts | 72 +- .../__tests__/singleSelectEditor.spec.ts | 13 +- .../common/src/editors/autocompleterEditor.ts | 14 +- packages/common/src/editors/dateEditor.ts | 286 +-- packages/common/src/editors/editors.index.ts | 2 +- packages/common/src/editors/floatEditor.ts | 83 - packages/common/src/editors/inputEditor.ts | 56 +- packages/common/src/editors/integerEditor.ts | 45 - packages/common/src/editors/longTextEditor.ts | 22 +- packages/common/src/editors/selectEditor.ts | 21 +- .../slickCellExcelCopyManager.spec.ts | 4 +- .../slickCellExternalCopyManager.spec.ts | 2 - .../__tests__/slickCellMenu.plugin.spec.ts | 6 +- .../__tests__/slickCellRangeDecorator.spec.ts | 2 - .../__tests__/slickCellRangeSelector.spec.ts | 1 - .../__tests__/slickCellSelectionModel.spec.ts | 1 - .../slickCheckboxSelectColumn.spec.ts | 16 +- .../__tests__/slickColumnPicker.spec.ts | 28 +- .../__tests__/slickContextMenu.spec.ts | 15 +- .../__tests__/slickDraggableGrouping.spec.ts | 10 +- .../__tests__/slickGridMenu.spec.ts | 70 +- .../__tests__/slickHeaderButtons.spec.ts | 2 +- .../__tests__/slickHeaderMenu.spec.ts | 75 +- .../__tests__/slickRowMoveManager.spec.ts | 5 +- .../__tests__/slickRowSelectionModel.spec.ts | 1 - .../src/extensions/extensionCommonUtils.ts | 95 +- .../extensions/slickCheckboxSelectColumn.ts | 43 +- .../src/extensions/slickColumnPicker.ts | 1 + .../common/src/extensions/slickContextMenu.ts | 15 +- .../src/extensions/slickDraggableGrouping.ts | 4 +- .../common/src/extensions/slickGridMenu.ts | 23 +- .../common/src/extensions/slickHeaderMenu.ts | 15 +- .../src/extensions/slickRowBasedEdit.ts | 8 +- .../src/extensions/slickRowMoveManager.ts | 2 +- .../dateEuroShortFilterCondition.spec.ts | 95 +- .../dateUsShortFilterCondition.spec.ts | 20 +- .../filterConditionProcesses.spec.ts | 11 - .../filter-conditions/dateFilterCondition.ts | 36 +- .../filterConditionProcesses.ts | 2 +- .../__tests__/autocompleterFilter.spec.ts | 3 +- .../__tests__/compoundDateFilter.spec.ts | 307 ++- .../filters/__tests__/dateRangeFilter.spec.ts | 248 +- .../__tests__/nativeSelectFilter.spec.ts | 420 ---- .../filters/__tests__/selectFilter.spec.ts | 27 +- .../common/src/filters/autocompleterFilter.ts | 3 +- packages/common/src/filters/dateFilter.ts | 318 +-- packages/common/src/filters/filters.index.ts | 4 - packages/common/src/filters/index.ts | 1 - .../common/src/filters/nativeSelectFilter.ts | 230 -- packages/common/src/filters/selectFilter.ts | 4 +- .../__tests__/checkmarkFormatter.spec.ts | 98 - .../checkmarkMaterialFormatter.spec.ts | 12 +- .../collectionEditorFormatter.spec.ts | 2 - .../__tests__/collectionFormatter.spec.ts | 2 - .../__tests__/dateEuroShortFormatter.spec.ts | 6 +- .../dateTimeEuroShortAM_PMFormatter.spec.ts | 6 +- .../dateTimeEuroShortAmPmFormatter.spec.ts | 6 +- .../dateTimeEuroShortFormatter.spec.ts | 6 +- .../dateTimeUsShortAM_PMFormatter.spec.ts | 6 +- .../dateTimeUsShortAmPmFormatter.spec.ts | 6 +- .../dateTimeUsShortFormatter.spec.ts | 6 +- .../__tests__/dateUsShortFormatter.spec.ts | 6 +- .../__tests__/dateUtcFormatter.spec.ts | 6 +- .../__tests__/hyperlinkFormatter.spec.ts | 8 +- .../__tests__/iconBooleanFormatter.spec.ts | 54 +- .../__tests__/iconFormatter.spec.ts | 14 +- .../src/formatters/checkmarkFormatter.ts | 24 - .../src/formatters/formatterUtilities.ts | 18 +- .../common/src/formatters/formatters.index.ts | 13 +- .../src/formatters/hyperlinkFormatter.ts | 7 +- .../src/formatters/iconBooleanFormatter.ts | 4 +- .../common/src/formatters/iconFormatter.ts | 10 +- packages/common/src/formatters/index.ts | 1 - packages/common/src/global-grid-options.ts | 51 +- packages/common/src/index.ts | 5 +- .../common/src/interfaces/column.interface.ts | 7 - .../src/interfaces/columnEditor.interface.ts | 3 +- .../src/interfaces/columnFilter.interface.ts | 3 +- .../interfaces/flatpickrOption.interface.ts | 178 -- .../src/interfaces/gridOption.interface.ts | 20 +- packages/common/src/interfaces/index.ts | 2 +- .../vanillaCalendarOption.interface.ts | 8 + .../__tests__/backend-utilities.spec.ts | 2 - .../src/services/__tests__/dateUtils.spec.ts | 170 ++ .../services/__tests__/domUtilities.spec.ts | 71 - .../__tests__/extension.service.spec.ts | 1 - .../services/__tests__/filter.service.spec.ts | 28 +- .../services/__tests__/grid.service.spec.ts | 3 - .../groupingAndColspan.service.spec.ts | 2 +- .../services/__tests__/shared.service.spec.ts | 2 - .../services/__tests__/sort.service.spec.ts | 14 +- .../src/services/__tests__/utilities.spec.ts | 249 -- packages/common/src/services/dateUtils.ts | 189 ++ packages/common/src/services/domUtilities.ts | 25 +- .../common/src/services/filter.service.ts | 10 +- .../services/groupingAndColspan.service.ts | 2 +- packages/common/src/services/index.ts | 1 + packages/common/src/services/utilities.ts | 214 -- .../dateEuroShortSortComparer.spec.ts | 16 +- .../__tests__/dateUsShortSortComparer.spec.ts | 16 +- .../common/src/sortComparers/dateUtilities.ts | 25 +- .../src/sortComparers/sortComparers.index.ts | 2 +- packages/common/src/styles/_private.scss | 27 - .../src/styles/_variables-theme-material.scss | 98 +- .../styles/_variables-theme-salesforce.scss | 120 +- packages/common/src/styles/_variables.scss | 340 ++- .../src/styles/colors-from-filters.scss | 87 - packages/common/src/styles/colors.scss | 165 +- packages/common/src/styles/extra-styling.scss | 29 +- .../common/src/styles/flatpickr-dark.scss | 107 - packages/common/src/styles/flatpickr.min.scss | 13 - .../src/styles/material-svg-utilities.scss | 82 - .../common/src/styles/sass-utilities.scss | 48 - .../common/src/styles/slick-autocomplete.scss | 1 - .../common/src/styles/slick-bootstrap.scss | 462 ---- .../common/src/styles/slick-component.scss | 102 +- packages/common/src/styles/slick-editors.scss | 67 +- packages/common/src/styles/slick-filters.scss | 4 +- packages/common/src/styles/slick-grid.scss | 722 ++++-- packages/common/src/styles/slick-plugins.scss | 349 +-- .../slick-without-bootstrap-min-styling.scss | 2 +- packages/common/src/styles/slick.layout.scss | 8 +- .../common/src/styles/slickgrid-examples.scss | 11 +- .../src/styles/slickgrid-icons-svg-utils.scss | 58 + ...al-svg-icons.scss => slickgrid-icons.scss} | 2001 +++++++++-------- .../slickgrid-theme-bootstrap.lite.scss | 18 + .../src/styles/slickgrid-theme-bootstrap.scss | 6 +- .../styles/slickgrid-theme-material.bare.scss | 21 - .../styles/slickgrid-theme-material.lite.scss | 18 +- .../src/styles/slickgrid-theme-material.scss | 34 +- .../slickgrid-theme-salesforce.bare.scss | 21 - .../slickgrid-theme-salesforce.lite.scss | 17 +- .../styles/slickgrid-theme-salesforce.scss | 14 +- packages/common/src/styles/svg-utilities.scss | 19 + .../composite-editor-component/CHANGELOG.md | 29 + packages/composite-editor-component/README.md | 1 + .../composite-editor-component/package.json | 2 +- .../src/compositeEditor.factory.spec.ts | 2 +- .../src/slick-composite-editor.component.ts | 8 +- packages/custom-footer-component/CHANGELOG.md | 17 + packages/custom-footer-component/README.md | 1 + packages/custom-footer-component/package.json | 6 +- .../src/slick-footer.component.ts | 6 +- packages/custom-tooltip-plugin/CHANGELOG.md | 24 + packages/custom-tooltip-plugin/README.md | 4 +- packages/custom-tooltip-plugin/package.json | 8 +- .../src/__tests__/slickCustomTooltip.spec.ts | 3 +- .../src/slickCustomTooltip.ts | 28 +- packages/empty-warning-component/CHANGELOG.md | 23 + packages/empty-warning-component/README.md | 1 + packages/empty-warning-component/package.json | 2 +- .../src/slick-empty-warning.component.ts | 8 +- .../src/slick-empty-warning.spec.ts | 52 +- packages/event-pub-sub/CHANGELOG.md | 13 + packages/event-pub-sub/README.md | 1 + packages/event-pub-sub/package.json | 2 +- packages/excel-export/CHANGELOG.md | 40 + packages/excel-export/README.md | 1 + packages/excel-export/package.json | 5 +- .../excel-export/src/excelExport.service.ts | 4 +- packages/graphql/CHANGELOG.md | 24 + packages/graphql/README.md | 1 + packages/graphql/package.json | 5 +- .../__tests__/graphqlQueryBuilder.spec.ts | 5 +- packages/odata/CHANGELOG.md | 20 + packages/odata/README.md | 1 + packages/odata/package.json | 2 +- .../odata/src/services/grid-odata.service.ts | 4 +- packages/pagination-component/CHANGELOG.md | 19 + packages/pagination-component/README.md | 1 + packages/pagination-component/package.json | 2 +- .../src/slick-pagination.component.ts | 97 +- packages/row-detail-view-plugin/CHANGELOG.md | 17 + packages/row-detail-view-plugin/README.md | 1 + packages/row-detail-view-plugin/package.json | 2 +- packages/rxjs-observable/CHANGELOG.md | 8 + packages/rxjs-observable/README.md | 1 + packages/rxjs-observable/package.json | 2 +- packages/text-export/CHANGELOG.md | 19 + packages/text-export/README.md | 1 + packages/text-export/package.json | 2 +- .../text-export/src/textExport.service.ts | 4 +- packages/utils/CHANGELOG.md | 16 + packages/utils/README.md | 1 + packages/utils/package.json | 2 +- packages/utils/src/__tests__/domUtils.spec.ts | 6 +- packages/utils/src/domUtils.ts | 12 +- packages/utils/src/nodeExtend.ts | 1 + packages/utils/src/utils.ts | 53 +- packages/vanilla-bundle/CHANGELOG.md | 230 ++ packages/vanilla-bundle/README.md | 1 + packages/vanilla-bundle/package.json | 3 +- .../__tests__/slick-vanilla-grid.spec.ts | 46 +- .../components/slick-vanilla-grid-bundle.ts | 45 +- packages/vanilla-bundle/src/index.ts | 2 +- packages/vanilla-force-bundle/CHANGELOG.md | 34 + packages/vanilla-force-bundle/README.md | 1 + .../slickgrid-vanilla-bundle.zip | Bin 596961 -> 547441 bytes packages/vanilla-force-bundle/package.json | 2 +- packages/vanilla-force-bundle/src/index.ts | 2 +- .../src/salesforce-global-grid-options.ts | 12 +- pnpm-lock.yaml | 139 +- test/cypress/e2e/example01.cy.ts | 28 +- test/cypress/e2e/example02.cy.ts | 15 +- test/cypress/e2e/example03.cy.ts | 2 +- test/cypress/e2e/example04.cy.ts | 4 +- test/cypress/e2e/example05.cy.ts | 4 +- test/cypress/e2e/example06.cy.ts | 8 +- test/cypress/e2e/example07.cy.ts | 22 +- test/cypress/e2e/example08.cy.ts | 6 +- test/cypress/e2e/example10.cy.ts | 18 +- test/cypress/e2e/example11.cy.ts | 30 +- test/cypress/e2e/example12.cy.ts | 41 +- test/cypress/e2e/example13.cy.ts | 32 +- test/cypress/e2e/example16.cy.ts | 4 +- test/cypress/e2e/example18.cy.ts | 10 +- test/cypress/e2e/example19.cy.ts | 2 +- test/cypress/e2e/example21.cy.ts | 69 +- test/jest-global-mocks.ts | 18 +- 325 files changed, 8226 insertions(+), 7247 deletions(-) create mode 100644 docs/column-functionalities/editors/date-editor-(vanilla-calendar).md create mode 100644 docs/getting-started/installation-vanilla.md create mode 100644 docs/migrations/migration-to-5.x.md delete mode 100644 packages/common/src/filters/__tests__/nativeSelectFilter.spec.ts delete mode 100644 packages/common/src/filters/nativeSelectFilter.ts delete mode 100644 packages/common/src/formatters/__tests__/checkmarkFormatter.spec.ts delete mode 100644 packages/common/src/formatters/checkmarkFormatter.ts delete mode 100644 packages/common/src/interfaces/flatpickrOption.interface.ts create mode 100644 packages/common/src/interfaces/vanillaCalendarOption.interface.ts create mode 100644 packages/common/src/services/__tests__/dateUtils.spec.ts delete mode 100644 packages/common/src/services/__tests__/domUtilities.spec.ts create mode 100644 packages/common/src/services/dateUtils.ts delete mode 100644 packages/common/src/styles/_private.scss delete mode 100644 packages/common/src/styles/colors-from-filters.scss delete mode 100644 packages/common/src/styles/flatpickr-dark.scss delete mode 100644 packages/common/src/styles/flatpickr.min.scss delete mode 100644 packages/common/src/styles/material-svg-utilities.scss delete mode 100644 packages/common/src/styles/sass-utilities.scss delete mode 100644 packages/common/src/styles/slick-bootstrap.scss create mode 100644 packages/common/src/styles/slickgrid-icons-svg-utils.scss rename packages/common/src/styles/{material-svg-icons.scss => slickgrid-icons.scss} (55%) create mode 100644 packages/common/src/styles/slickgrid-theme-bootstrap.lite.scss delete mode 100644 packages/common/src/styles/slickgrid-theme-material.bare.scss delete mode 100644 packages/common/src/styles/slickgrid-theme-salesforce.bare.scss create mode 100644 packages/common/src/styles/svg-utilities.scss diff --git a/.vscode/settings.json b/.vscode/settings.json index 2568ea7b3..bd6e1b612 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,6 @@ "javascript", "typescript" ], - "typescript.format.semicolons": "insert" + "typescript.format.semicolons": "insert", + "typescript.tsdk": "node_modules\\typescript\\lib" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ddfc46584..13c5aa42f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,21 +4,80 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.0-beta.3](https://github.com/ghiscoding/slickgrid-universal/compare/v5.0.0-beta.2...v5.0.0-beta.3) (2024-05-09) + +### Bug Fixes + +* **common:** consider target size when auto-position picker/modal ([#1517](https://github.com/ghiscoding/slickgrid-universal/issues/1517)) ([e3a70b8](https://github.com/ghiscoding/slickgrid-universal/commit/e3a70b810d04c963f48454b78053c1bd45f96ebf)) - by @ghiscoding +* **common:** Select Editor should always close with Escape key ([#1512](https://github.com/ghiscoding/slickgrid-universal/issues/1512)) ([e37bb28](https://github.com/ghiscoding/slickgrid-universal/commit/e37bb281ee83c25e9c4e15930e06bf9a044c65e9)) - by @ghiscoding +* **core:** tweak setupColumnSort() to fix exception with hidden col ([#1509](https://github.com/ghiscoding/slickgrid-universal/issues/1509)) ([94b836a](https://github.com/ghiscoding/slickgrid-universal/commit/94b836a025ecb19b72f439079382280740b51027)) - by @ghiscoding +* **editors:** body click or Escape key should cancel Select Editor ([#1513](https://github.com/ghiscoding/slickgrid-universal/issues/1513)) ([3d765a9](https://github.com/ghiscoding/slickgrid-universal/commit/3d765a9d282b684c38c550a1e5736cb1b2132f8e)) - by @ghiscoding +* make some more cleanup with now optional DOMPurify ([#1508](https://github.com/ghiscoding/slickgrid-universal/issues/1508)) ([7fafbcc](https://github.com/ghiscoding/slickgrid-universal/commit/7fafbcc21fccfcd83d3ab103f313398c9d4b82e2)) - by @ghiscoding +* **plugins:** clicking a grid cell should close any open menu ([#1515](https://github.com/ghiscoding/slickgrid-universal/issues/1515)) ([383792d](https://github.com/ghiscoding/slickgrid-universal/commit/383792d389e56239d62874842a50ec838f0bd3e9)) - by @ghiscoding +* **styling:** improve UI & fix small issues found after testing upstream ([#1510](https://github.com/ghiscoding/slickgrid-universal/issues/1510)) ([a4ef70f](https://github.com/ghiscoding/slickgrid-universal/commit/a4ef70f70953c13f7abb0075586439931f18af74)) - by @ghiscoding +* **tooltip:** only show tooltip that has value ([#1511](https://github.com/ghiscoding/slickgrid-universal/issues/1511)) ([2ff15da](https://github.com/ghiscoding/slickgrid-universal/commit/2ff15da4a21cd98b63f251b9b248454658dac698)) - by @ghiscoding + +## [5.0.0-beta.2](https://github.com/ghiscoding/slickgrid-universal/compare/v4.7.0...v5.0.0-beta.2) (2024-05-07) + +### ⚠ BREAKING CHANGES + +* migrate from Moment to Tempo (#1507) +* **common:** make DOMPurify as optional sanitizer grid option (#1503) +* **styling:** delete "bare" Themes but keep "lite" & add to Bootstrap (#1493) +* **common:** migrate from `moment` to `moment-tiny` (#1456) +* **filters:** remove native `Filters.select` (#1485) +* **styling:** delete `checkmarkFormatter` and any Font-Awesome related (#1484) +* **common:** migrate from Flatpickr to Vanilla-Calendar (#1466) +* **styling:** remove SASS `math.div` polyfill (#1483) +* **styling:** convert SVG icons to pure CSS (#1474) + +### Features + +* **common:** make DOMPurify as optional sanitizer grid option ([#1503](https://github.com/ghiscoding/slickgrid-universal/issues/1503)) ([0aa0859](https://github.com/ghiscoding/slickgrid-universal/commit/0aa085955f81303c0193fbdcd36ff220263814e3)) - by @ghiscoding +* **common:** migrate from `moment` to `moment-tiny` ([#1456](https://github.com/ghiscoding/slickgrid-universal/issues/1456)) ([90690f4](https://github.com/ghiscoding/slickgrid-universal/commit/90690f4b6a4c8f8a7a221ddc1df69077384f48a9)) - by @ghiscoding +* **common:** migrate from Flatpickr to Vanilla-Calendar ([#1466](https://github.com/ghiscoding/slickgrid-universal/issues/1466)) ([fb6e950](https://github.com/ghiscoding/slickgrid-universal/commit/fb6e950f429b4abd868fca86d9c304580a745b1c)) - by @ghiscoding +* **filters:** remove native `Filters.select` ([#1485](https://github.com/ghiscoding/slickgrid-universal/issues/1485)) ([fae4c4a](https://github.com/ghiscoding/slickgrid-universal/commit/fae4c4a199409cec40ebb2703b6ae6d0d14e4af7)) - by @ghiscoding +* migrate from Moment to Tempo ([#1507](https://github.com/ghiscoding/slickgrid-universal/issues/1507)) ([adef47f](https://github.com/ghiscoding/slickgrid-universal/commit/adef47f21a0e32bd32ec4efce931770dc252d3b5)) - by @ghiscoding +* **styling:** convert SVG icons to pure CSS ([#1474](https://github.com/ghiscoding/slickgrid-universal/issues/1474)) ([70cda8a](https://github.com/ghiscoding/slickgrid-universal/commit/70cda8aa9304ac8ea4bab06390dc1b4c4423df2e)) - by @ghiscoding +* **styling:** delete "bare" Themes but keep "lite" & add to Bootstrap ([#1493](https://github.com/ghiscoding/slickgrid-universal/issues/1493)) ([ca5ac06](https://github.com/ghiscoding/slickgrid-universal/commit/ca5ac0663c1670f9e9af1f88d6f6c85e9e064359)) - by @ghiscoding +* **styling:** delete `checkmarkFormatter` and any Font-Awesome related ([#1484](https://github.com/ghiscoding/slickgrid-universal/issues/1484)) ([2de3fe2](https://github.com/ghiscoding/slickgrid-universal/commit/2de3fe2d07a14225a31fbc77e72c47895de664d6)) - by @ghiscoding +* **styling:** remove SASS `math.div` polyfill ([#1483](https://github.com/ghiscoding/slickgrid-universal/issues/1483)) ([12661a3](https://github.com/ghiscoding/slickgrid-universal/commit/12661a3ff13ea844f6e16028216e1ed8808ee4d9)) - by @ghiscoding + +### Bug Fixes + +* **core:** col name from HTML shouldn't disappear in picker, fixes [#1475](https://github.com/ghiscoding/slickgrid-universal/issues/1475) ([#1476](https://github.com/ghiscoding/slickgrid-universal/issues/1476)) ([15a590b](https://github.com/ghiscoding/slickgrid-universal/commit/15a590b2e52f8864aeccc38f9a708c0453b6e4a6)) - by @ghiscoding +* **editor:** autocomplete should only save empty when val is null ([#1500](https://github.com/ghiscoding/slickgrid-universal/issues/1500)) ([8de1340](https://github.com/ghiscoding/slickgrid-universal/commit/8de13402d244cb3aa2fcdb4af62e05b06f6cb27c)) - by @ghiscoding +* **editor:** input editor should call save on focusout or blur of input ([#1497](https://github.com/ghiscoding/slickgrid-universal/issues/1497)) ([ccd344e](https://github.com/ghiscoding/slickgrid-universal/commit/ccd344ecd2e6abcff1d7b9f5e7d7fe85a4c20fdd)) - by @ghiscoding +* **editor:** new Date Editor input clear button wasn't working ([#1487](https://github.com/ghiscoding/slickgrid-universal/issues/1487)) ([4ac34ee](https://github.com/ghiscoding/slickgrid-universal/commit/4ac34ee6d95398c77f10f89b0ad4c3168765b6a0)) - by @ghiscoding +* **styling:** couple of small alignment issues when using flex ([#1496](https://github.com/ghiscoding/slickgrid-universal/issues/1496)) ([2188242](https://github.com/ghiscoding/slickgrid-universal/commit/21882420eb9c31b7922038fa45f373d42e2fb35f)) - by @ghiscoding +* **styling:** empty warning should separate icon & text ([#1491](https://github.com/ghiscoding/slickgrid-universal/issues/1491)) ([240cbd3](https://github.com/ghiscoding/slickgrid-universal/commit/240cbd3b5a8cfb6a6cab563bc43d705332d59beb)) - by @ghiscoding +* **styling:** properly import Vanilla-Calendar CSS and only once ([#1492](https://github.com/ghiscoding/slickgrid-universal/issues/1492)) ([75dce74](https://github.com/ghiscoding/slickgrid-universal/commit/75dce746659796f7d1c21e5ebcfd0418588df4c0)) - by @ghiscoding +* **styling:** Row Move icon shouldn't show extra dot ([69f7bfc](https://github.com/ghiscoding/slickgrid-universal/commit/69f7bfcb7eb078815f5edb6d84d53c0905df27a1)) - by @ghiscoding-SE +* **tooltip:** don't sanitize empty text, fixes empty tooltip being shown ([#1495](https://github.com/ghiscoding/slickgrid-universal/issues/1495)) ([dcc693b](https://github.com/ghiscoding/slickgrid-universal/commit/dcc693b26677873b93ccb770ff8ef9a514085341)) - by @ghiscoding +* tweak setupColumnSort() to fix exception when col no longer exists ([#1477](https://github.com/ghiscoding/slickgrid-universal/issues/1477)) ([094d760](https://github.com/ghiscoding/slickgrid-universal/commit/094d7602d7170b2f395985ce5635041bb2b803d2)) - by @ghiscoding + # [4.7.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.6.3...v4.7.0) (2024-04-20) ### Bug Fixes * **common:** don't try to strip tags on object input to calc cell width ([#1453](https://github.com/ghiscoding/slickgrid-universal/issues/1453)) ([5ab671b](https://github.com/ghiscoding/slickgrid-universal/commit/5ab671bee805f7b7d9b139e9bf7a14b31b5aea56)) - by @ghiscoding + * **common:** switch back to `autocompleter` with ESM build ([#1450](https://github.com/ghiscoding/slickgrid-universal/issues/1450)) ([ad66a12](https://github.com/ghiscoding/slickgrid-universal/commit/ad66a121b4a6b7718009948d873ceb8f5c66a32c)) - by @ghiscoding + * **core:** Editor.keyCaptureList is an array of numbers ([#1458](https://github.com/ghiscoding/slickgrid-universal/issues/1458)) ([62a686e](https://github.com/ghiscoding/slickgrid-universal/commit/62a686e7db4dc4ef65d0c426c8623dc8f1e3f9d9)) - by @ghiscoding + * **OData:** sorting columns via `id` instead of field property name, fixes [#1467](https://github.com/ghiscoding/slickgrid-universal/issues/1467) ([#1469](https://github.com/ghiscoding/slickgrid-universal/issues/1469)) ([0a4d402](https://github.com/ghiscoding/slickgrid-universal/commit/0a4d40255e240bddf752a2e7bf39a99ae234cc6e)) - by @zewa666 + * **styling:** improve button & text colors for Dark Mode ([9414ab4](https://github.com/ghiscoding/slickgrid-universal/commit/9414ab4e24482d080f3113d32d96fe635856a871)) - by @ghiscoding-SE + * wrong operator comparison ([#1461](https://github.com/ghiscoding/slickgrid-universal/issues/1461)) ([abe772b](https://github.com/ghiscoding/slickgrid-universal/commit/abe772b9ad9480688ef000dddfa86d2cdc6b7e52)) - by @zewa666 ### Features * **common:** add global `defaultEditorOptions` & `defaultFilterOptions` ([#1470](https://github.com/ghiscoding/slickgrid-universal/issues/1470)) ([0462f17](https://github.com/ghiscoding/slickgrid-universal/commit/0462f17b215d5c1b88e1a9fe482877ed733486b3)) - by @ghiscoding + * **core:** add `getFilterArgs()` to `SlickDataView` ([#1457](https://github.com/ghiscoding/slickgrid-universal/issues/1457)) ([7563126](https://github.com/ghiscoding/slickgrid-universal/commit/7563126cfbf792fc86a494850e5a3bad7d8991f7)) - by @ghiscoding + * notify onValidationError on paste if validation failed ([#1462](https://github.com/ghiscoding/slickgrid-universal/issues/1462)) ([38b465c](https://github.com/ghiscoding/slickgrid-universal/commit/38b465cb8ebcdd6012b939677a4367c2dce010e9)) - by @zewa666 ## [4.6.3](https://github.com/ghiscoding/slickgrid-universal/compare/v4.6.1...v4.6.3) (2024-03-31) @@ -30,11 +89,17 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **common:** move DOMPurify/SortableJS [@types](https://github.com/types) as dependencies ([51eaec7](https://github.com/ghiscoding/slickgrid-universal/commit/51eaec756120c93f0fbb9ed58b5784025b808e59)) - by @ghiscoding + * **common:** switch to `autocompleter-es` to get ESM build ([#1449](https://github.com/ghiscoding/slickgrid-universal/issues/1449)) ([aa59334](https://github.com/ghiscoding/slickgrid-universal/commit/aa59334d280d76078bc9cf36e66daa0bd4c6fac1)) - by @ghiscoding + * improve Dark Mode styling for icons barely visible in dark ([16b1a6e](https://github.com/ghiscoding/slickgrid-universal/commit/16b1a6e52bec83ed25bca077fe2ea30b5966f3ab)) - by @ghiscoding + * **pubsub:** externalize PubSub event to SlickEventData to stop bubbling ([#1444](https://github.com/ghiscoding/slickgrid-universal/issues/1444)) ([973d0ab](https://github.com/ghiscoding/slickgrid-universal/commit/973d0abb0a4df050ad68a6c7e6493bf7ae4abd52)) - by @ghiscoding + * revisit package `exports` to pass "are the types wrong" ([#1440](https://github.com/ghiscoding/slickgrid-universal/issues/1440)) ([20229f7](https://github.com/ghiscoding/slickgrid-universal/commit/20229f78adef51078f99fce3f5a46ac88280a048)) - by @ghiscoding + * **styling:** missing/too many borders compound filters w/group addon ([#1446](https://github.com/ghiscoding/slickgrid-universal/issues/1446)) ([863933f](https://github.com/ghiscoding/slickgrid-universal/commit/863933f8cd1988f5ae1b387839a99532cd58d92d)) - by @ghiscoding + * **tooltip:** allow multiple tooltips per grid cell ([#1448](https://github.com/ghiscoding/slickgrid-universal/issues/1448)) ([061c4a0](https://github.com/ghiscoding/slickgrid-universal/commit/061c4a087484238f7285eb27a1c238ac75972f19)) - by @ghiscoding # [4.6.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.5.0...v4.6.0) (2024-03-23) @@ -42,22 +107,35 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * `column.editor` and `gridOptions.editorFactory` type changed ([#1428](https://github.com/ghiscoding/slickgrid-universal/issues/1428)) ([bf8c5b9](https://github.com/ghiscoding/slickgrid-universal/commit/bf8c5b95aca22bced0d926d6ac118c9fa0e61411)) - by @ghiscoding + * **build:** add ESLint-TS rules to enforce `type` imports and exports ([#1432](https://github.com/ghiscoding/slickgrid-universal/issues/1432)) ([cce4693](https://github.com/ghiscoding/slickgrid-universal/commit/cce4693556e01d7f664fbe832ae4e7fd5776dc6b)) - by @ghiscoding + * **build:** add ESLint-TS rules to enforce `type` imports and exports ([#1437](https://github.com/ghiscoding/slickgrid-universal/issues/1437)) ([324c4fe](https://github.com/ghiscoding/slickgrid-universal/commit/324c4fee22f83655a3b25b08ae73dbcca2e1e6e7)) - by @ghiscoding + * **common:** add missing Filter `model` Type of `FilterConstructor` ([#1430](https://github.com/ghiscoding/slickgrid-universal/issues/1430)) ([3f3e952](https://github.com/ghiscoding/slickgrid-universal/commit/3f3e952b20b41dda5bf2cd1648c6d6f02e7c7943)) - by @ghiscoding + * **common:** bump ms-select to fix compatibility problem in Salesforce ([#1425](https://github.com/ghiscoding/slickgrid-universal/issues/1425)) ([d3d2d39](https://github.com/ghiscoding/slickgrid-universal/commit/d3d2d390a8a1b17d0cd3699ddebfea855fdc5f77)) - by @ghiscoding + * **common:** Select All checkbox shouldn't disappear w/Dark Mode toggle ([#1421](https://github.com/ghiscoding/slickgrid-universal/issues/1421)) ([5fab179](https://github.com/ghiscoding/slickgrid-universal/commit/5fab1792cfdf24172bd46556b6fe5513c93d19d1)) - by @ghiscoding + * Join type ([#1427](https://github.com/ghiscoding/slickgrid-universal/issues/1427)) ([21c76cc](https://github.com/ghiscoding/slickgrid-universal/commit/21c76cc9d921ad34516bd38070afd791ff55de56)) - by @zewa666 + * **styling:** add border & box-shadow to Flatpickr in Dark Mode ([fdbb6ae](https://github.com/ghiscoding/slickgrid-universal/commit/fdbb6ae9de7069968af747240a9b2ad74b0c8184)) - by @ghiscoding + * **styling:** add missing orange border for Salesforce modified inputs ([e830dd3](https://github.com/ghiscoding/slickgrid-universal/commit/e830dd3df4c6c0176ac88304247571f5ef05d4ef)) - by @ghiscoding + * **styling:** add more visual cue for column picker uncheck row select ([b4712e9](https://github.com/ghiscoding/slickgrid-universal/commit/b4712e9a8c03b60457d9033f11affb7364231de2)) - by @ghiscoding + * **styling:** don't add filled border all side for group-addon btn ([30be835](https://github.com/ghiscoding/slickgrid-universal/commit/30be8353101157a00440dba0357f88879bd3acda)) - by @ghiscoding-SE + * **styling:** small Composite Editor fixes for Dark Mode ([#1417](https://github.com/ghiscoding/slickgrid-universal/issues/1417)) ([7e00087](https://github.com/ghiscoding/slickgrid-universal/commit/7e000877a85059e23d3aa4c00c04d0e4e1e0abc1)) - by @ghiscoding ### Features * **common:** add optional "Toggle Dark Mode" in Grid Menu ([#1418](https://github.com/ghiscoding/slickgrid-universal/issues/1418)) ([990c1df](https://github.com/ghiscoding/slickgrid-universal/commit/990c1df2a39a6b5098c991b16f43c5679daf4bb5)) - by @ghiscoding + * **core:** rename SG `editorClass` & deprecate `internalColumnEditor` ([#1429](https://github.com/ghiscoding/slickgrid-universal/issues/1429)) ([409115c](https://github.com/ghiscoding/slickgrid-universal/commit/409115cecb132556e88abf6e281f4fcb52414d71)) - by @ghiscoding + * upgrade to ms-select-vanilla v3.x ([#1439](https://github.com/ghiscoding/slickgrid-universal/issues/1439)) ([8f2378e](https://github.com/ghiscoding/slickgrid-universal/commit/8f2378e6cfed3489ce487fe84947bdabd04e31d2)) - by @ghiscoding # [4.5.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.4.1...v4.5.0) (2024-03-05) @@ -65,22 +143,35 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * auto-resize not just grid but also headers for Salesforce tabs ([#1395](https://github.com/ghiscoding/slickgrid-universal/issues/1395)) ([6180461](https://github.com/ghiscoding/slickgrid-universal/commit/6180461b543cb7d4cc14d1504cb0db7d35990164)) - by @ghiscoding + * **common:** switch to `isomorphic-dompurify` for SSR support ([#1413](https://github.com/ghiscoding/slickgrid-universal/issues/1413)) ([b619453](https://github.com/ghiscoding/slickgrid-universal/commit/b619453fd9825500f2d9589e31bdcf5e17ac412d)), closes [/github.com/ghiscoding/Angular-Slickgrid/discussions/838#discussioncomment-8574215](https://github.com//github.com/ghiscoding/Angular-Slickgrid/discussions/838/issues/discussioncomment-8574215) - by @ghiscoding + * **core:** add extra checks for some objects to be a bit more strict ([#1404](https://github.com/ghiscoding/slickgrid-universal/issues/1404)) ([8b95c50](https://github.com/ghiscoding/slickgrid-universal/commit/8b95c505ed2409cde7b790f97b4fbc0d666ca459)) - by @ghiscoding + * **plugin:** the RowMove plugin cell should be selectable ([#1408](https://github.com/ghiscoding/slickgrid-universal/issues/1408)) ([8c01a13](https://github.com/ghiscoding/slickgrid-universal/commit/8c01a1361898fe3f3b6cfdba3239f93f2e8acec9)) - by @ghiscoding + * **styling:** add full width to grid container ([#1409](https://github.com/ghiscoding/slickgrid-universal/issues/1409)) ([eedc162](https://github.com/ghiscoding/slickgrid-universal/commit/eedc162e243b3c0bbf450bd404b199f5ee511926)) - by @ghiscoding + * **styling:** add menu shadow & increase contrast for Dark Mode ([bff2da0](https://github.com/ghiscoding/slickgrid-universal/commit/bff2da0dd027103c30fa86635b9e45460b10e700)) - by @ghiscoding + * **styling:** ms-select filter should use same color as other filters ([#1396](https://github.com/ghiscoding/slickgrid-universal/issues/1396)) ([a30d590](https://github.com/ghiscoding/slickgrid-universal/commit/a30d59066419d2c3324718f1d5497e8e89ebf749)) - by @ghiscoding + * **styling:** ms-select highlight bg-color same as nav highlight ([fe77341](https://github.com/ghiscoding/slickgrid-universal/commit/fe77341645f72be6c03a8e210dc08e6d0ef131d4)) - by @ghiscoding-SE + * **styling:** properly align flexbox ms-select icon+text vertically ([#1397](https://github.com/ghiscoding/slickgrid-universal/issues/1397)) ([e744d02](https://github.com/ghiscoding/slickgrid-universal/commit/e744d0256d25ba6ad5d538b827460828b6e0666f)) - by @ghiscoding + * **styling:** remove header menu open class for Dark Mode ([6a2e7e1](https://github.com/ghiscoding/slickgrid-universal/commit/6a2e7e13a18921c2b70caeb2690298173310aece)) - by @ghiscoding + * **styling:** tweak Composite Editor form disabled buttons style ([5052ba1](https://github.com/ghiscoding/slickgrid-universal/commit/5052ba19858ff2bced69f0846e00bbb36c9d0fde)) - by @ghiscoding ### Features * **common:** upgrade `multiple-select-vanilla` to v2 ([#1401](https://github.com/ghiscoding/slickgrid-universal/issues/1401)) ([d6bb1d7](https://github.com/ghiscoding/slickgrid-universal/commit/d6bb1d7ef76100268456b2ab499c496a78debdd8)) - by @ghiscoding + * **deps:** simplify package TS Types exports ([#1402](https://github.com/ghiscoding/slickgrid-universal/issues/1402)) ([19bac52](https://github.com/ghiscoding/slickgrid-universal/commit/19bac52e5fcb8e523a26ab1f6564f0b6a2b93ef4)) - by @ghiscoding + * **editor:** add `onRendered` lifecycle callback option ([#1410](https://github.com/ghiscoding/slickgrid-universal/issues/1410)) ([9d348d6](https://github.com/ghiscoding/slickgrid-universal/commit/9d348d6e4b693e23a2959917e02a7bcfa55a0c90)) - by @ghiscoding + * **styling:** add Dark Mode grid option ([#1407](https://github.com/ghiscoding/slickgrid-universal/issues/1407)) ([855151b](https://github.com/ghiscoding/slickgrid-universal/commit/855151b9f47a5238e3069f8c85ba4ed8a5bf9bb6)) - by @ghiscoding ## [4.4.1](https://github.com/ghiscoding/slickgrid-universal/compare/v4.3.1...v4.4.1) (2024-02-13) @@ -88,10 +179,15 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **ci:** disable Husky when pushing new release ([#1390](https://github.com/ghiscoding/slickgrid-universal/issues/1390)) ([6f9372e](https://github.com/ghiscoding/slickgrid-universal/commit/6f9372ebfb07a294935f81a09eff07549fab5185)) - by @ghiscoding + * **core:** replace `any` types by valid types ([#1378](https://github.com/ghiscoding/slickgrid-universal/issues/1378)) ([02c4bc1](https://github.com/ghiscoding/slickgrid-universal/commit/02c4bc15e0da31c055c0fac9eecb7c4a17df3eb7)) - by @ghiscoding + * **demo:** change trading demo full screen z-index lower than ms-select ([1f4a9ac](https://github.com/ghiscoding/slickgrid-universal/commit/1f4a9acd68bc9559420d48597f9214c16f48556e)) - by @ghiscoding + * **deps:** update all non-major dependencies ([#1381](https://github.com/ghiscoding/slickgrid-universal/issues/1381)) ([2562352](https://github.com/ghiscoding/slickgrid-universal/commit/25623527d05dd713123e1031b682f0a80cca37de)) - by @renovate-bot + * mouse cell selection with active editor ([#1382](https://github.com/ghiscoding/slickgrid-universal/issues/1382)) ([17549b8](https://github.com/ghiscoding/slickgrid-universal/commit/17549b89933b10688fe8d186ab18ab4c8b7e9f87)) - by @zewa666 + * **publish:** do not npm publish `tsconfig.tsbuildinfo` ([#1373](https://github.com/ghiscoding/slickgrid-universal/issues/1373)) ([9223338](https://github.com/ghiscoding/slickgrid-universal/commit/922333843852ae861015e4bbec053d4937222aa2)) - by @ghiscoding ### Features @@ -103,10 +199,15 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** replace `any` types by valid types ([#1378](https://github.com/ghiscoding/slickgrid-universal/issues/1378)) ([02c4bc1](https://github.com/ghiscoding/slickgrid-universal/commit/02c4bc15e0da31c055c0fac9eecb7c4a17df3eb7)) - by @ghiscoding + * **demo:** change trading demo full screen z-index lower than ms-select ([1f4a9ac](https://github.com/ghiscoding/slickgrid-universal/commit/1f4a9acd68bc9559420d48597f9214c16f48556e)) - by @ghiscoding + * **deps:** update all non-major dependencies ([#1381](https://github.com/ghiscoding/slickgrid-universal/issues/1381)) ([2562352](https://github.com/ghiscoding/slickgrid-universal/commit/25623527d05dd713123e1031b682f0a80cca37de)) - by @renovate-bot + * mouse cell selection with active editor ([#1382](https://github.com/ghiscoding/slickgrid-universal/issues/1382)) ([17549b8](https://github.com/ghiscoding/slickgrid-universal/commit/17549b89933b10688fe8d186ab18ab4c8b7e9f87)) - by @zewa666 + * **publish:** do not npm publish `tsconfig.tsbuildinfo` ([#1373](https://github.com/ghiscoding/slickgrid-universal/issues/1373)) ([9223338](https://github.com/ghiscoding/slickgrid-universal/commit/922333843852ae861015e4bbec053d4937222aa2)) - by @ghiscoding + * **common:** make "ctrl + c" great again ([#1379](https://github.com/ghiscoding/slickgrid-universal/pull/1379)) ([3bf59e](3bf59e04f2fd9e234ca063b5827e6403a6fcd044)) - by @zewa666 ### Features @@ -118,15 +219,21 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** frozen grid w/hidden column should remove from DOM ([#1372](https://github.com/ghiscoding/slickgrid-universal/issues/1372)) ([2c1346e](https://github.com/ghiscoding/slickgrid-universal/commit/2c1346e53e0e5cba57c949f7b70d2b20d3dc1d22)) - by @ghiscoding + * **deps:** update all non-major dependencies ([#1368](https://github.com/ghiscoding/slickgrid-universal/issues/1368)) ([b49e895](https://github.com/ghiscoding/slickgrid-universal/commit/b49e89524815006c348917039342e53f00871110)) - by @renovate-bot + * Salesforce doesn't support Document Fragment ([#1365](https://github.com/ghiscoding/slickgrid-universal/issues/1365)) ([9e3fb5f](https://github.com/ghiscoding/slickgrid-universal/commit/9e3fb5f2f3220d6e57d2efc20fd85105a8a39454)) - by @ghiscoding + * **styling:** remove different bg-color on unorderable column ([#1358](https://github.com/ghiscoding/slickgrid-universal/issues/1358)) ([91426d1](https://github.com/ghiscoding/slickgrid-universal/commit/91426d1f6801680a5c40b3b900ab1a64cd771277)) - by @ghiscoding ### Performance Improvements * **core:** convert `for..in` to `Object.keys().forEach` for better perf ([#1370](https://github.com/ghiscoding/slickgrid-universal/issues/1370)) ([29111a9](https://github.com/ghiscoding/slickgrid-universal/commit/29111a94756c34a2e01f2431c14b7ed806349a94)) - by @ghiscoding + * decrease calls to setItems & grid invalidate ([#1363](https://github.com/ghiscoding/slickgrid-universal/issues/1363)) ([cab6898](https://github.com/ghiscoding/slickgrid-universal/commit/cab68989ebd53178dfcee5ed293379dc8932a72f)) - by @ghiscoding + * **plugins:** decrease number of calls to translate all extensions only once ([#1359](https://github.com/ghiscoding/slickgrid-universal/issues/1359)) ([3e002f1](https://github.com/ghiscoding/slickgrid-universal/commit/3e002f15a06abd06893783e0667798f5ff8893cf)) - by @ghiscoding + * **plugins:** Row Base Editing tooltip title should be translated only once ([#1360](https://github.com/ghiscoding/slickgrid-universal/issues/1360)) ([ef4e8f9](https://github.com/ghiscoding/slickgrid-universal/commit/ef4e8f9f4bf491d670986c6dac8531274aaaa46b)) - by @ghiscoding # [4.3.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.2.0...v4.3.0) (2024-01-20) @@ -134,31 +241,53 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * `getCellFromPoint()` should return row/cell -1 outside grid canvas ([#1325](https://github.com/ghiscoding/slickgrid-universal/issues/1325)) ([b483e62](https://github.com/ghiscoding/slickgrid-universal/commit/b483e62fc3931f836c77677db67557adb2ca4edd)) - by @ghiscoding + * add grid & cell `role` for screen ready accessibility ([#1337](https://github.com/ghiscoding/slickgrid-universal/issues/1337)) ([7309fa8](https://github.com/ghiscoding/slickgrid-universal/commit/7309fa8de4fc00f930e68af090010d91080b6213)) - by @ghiscoding + * **core:** allow extra spaces in `headerCssClass` & other `cssClass` ([#1303](https://github.com/ghiscoding/slickgrid-universal/issues/1303)) ([59ebaa6](https://github.com/ghiscoding/slickgrid-universal/commit/59ebaa65b6882ed3274a3185f457ecef4b2c5b51)) - by @ghiscoding + * **core:** allow extra spaces to be striped to any css classes ([#1352](https://github.com/ghiscoding/slickgrid-universal/issues/1352)) ([e5e29c0](https://github.com/ghiscoding/slickgrid-universal/commit/e5e29c063a9e018c2148685cfea5fc43c89426b9)) - by @ghiscoding + * **core:** column resize handle could throw when invalid elm ([#1344](https://github.com/ghiscoding/slickgrid-universal/issues/1344)) ([41f6058](https://github.com/ghiscoding/slickgrid-universal/commit/41f60583831b7284cba56f2af9cfe45b4a09d617)) - by @ghiscoding + * **core:** DataView `inlineFilters` should allow ES6 arrow functions ([#1304](https://github.com/ghiscoding/slickgrid-universal/issues/1304)) ([25b9a10](https://github.com/ghiscoding/slickgrid-universal/commit/25b9a10fdd14585f1b303361b2814e860c6e7031)) - by @ghiscoding + * **core:** don't show column header empty title tooltip ([#1317](https://github.com/ghiscoding/slickgrid-universal/issues/1317)) ([8b20407](https://github.com/ghiscoding/slickgrid-universal/commit/8b2040754f1810191fb26f0a5a91a19eae13ebfd)) - by @ghiscoding + * **core:** EventHandler subscribed event should be SlickEventData type ([#1327](https://github.com/ghiscoding/slickgrid-universal/issues/1327)) ([2573310](https://github.com/ghiscoding/slickgrid-universal/commit/25733102dbcefcbacc2ce5d6f4c07bd9d1cce6a1)) - by @ghiscoding + * **core:** remove editor keydown keyCaptureList duplicate code ([#1322](https://github.com/ghiscoding/slickgrid-universal/issues/1322)) ([c5f6b85](https://github.com/ghiscoding/slickgrid-universal/commit/c5f6b8575513aa6eb0215a47a0365fdab0059c3e)) - by @ghiscoding + * **core:** SlickEvent handler event should be type of ArgType ([#1328](https://github.com/ghiscoding/slickgrid-universal/issues/1328)) ([a9cb8ee](https://github.com/ghiscoding/slickgrid-universal/commit/a9cb8ee3f1a5da4249851e5b701b027b3f72ad26)), closes [#1327](https://github.com/ghiscoding/slickgrid-universal/issues/1327) - by @ghiscoding + * **demo:** Unsaved Cell CSS Styling follow sort/filter/pagination ([#1313](https://github.com/ghiscoding/slickgrid-universal/issues/1313)) ([7619579](https://github.com/ghiscoding/slickgrid-universal/commit/761957987e85ed9829900739e659d8d02230ea12)) - by @ghiscoding + * Editors/Filters should create SlickEventData with event arg ([#1326](https://github.com/ghiscoding/slickgrid-universal/issues/1326)) ([e008902](https://github.com/ghiscoding/slickgrid-universal/commit/e008902e6d85a7a424ed8c9e32786490daac66ce)) - by @ghiscoding + * **plugin:** CustomDataView for CellSelectionModel & SlickCustomTooltip ([#1306](https://github.com/ghiscoding/slickgrid-universal/issues/1306)) ([3bdd300](https://github.com/ghiscoding/slickgrid-universal/commit/3bdd30038b93af2db1f2f4a8b7df72ca6a06a06e)) - by @ghiscoding + * regression with `onSelectedRowsChanged` not receiving correct `caller` prop ([#1341](https://github.com/ghiscoding/slickgrid-universal/issues/1341)) ([03cad4a](https://github.com/ghiscoding/slickgrid-universal/commit/03cad4a34bf13a8e1342306f9210525f5025321f)) - by @ghiscoding + * SlickEmptyWarningComponent should accept native HTML for CSP safe ([#1333](https://github.com/ghiscoding/slickgrid-universal/issues/1333)) ([4740f96](https://github.com/ghiscoding/slickgrid-universal/commit/4740f961813666cbae918cb4940e7c2ec57bec2d)) - by @ghiscoding + * when `onDragInit` return false it should stop ([#1340](https://github.com/ghiscoding/slickgrid-universal/issues/1340)) ([d9c714c](https://github.com/ghiscoding/slickgrid-universal/commit/d9c714c042739d5cbdbe51b876f16a3152d200e6)), closes [#1339](https://github.com/ghiscoding/slickgrid-universal/issues/1339) - by @ghiscoding + * when `onResizeStart` return false it should stop ([#1339](https://github.com/ghiscoding/slickgrid-universal/issues/1339)) ([5a3bd1c](https://github.com/ghiscoding/slickgrid-universal/commit/5a3bd1c0c6a19294fe6578766d6b2d56ac8e2cac)) - by @ghiscoding ### Features * add `name` option to CheckboxSelectColumn plugin on columDef ([#1331](https://github.com/ghiscoding/slickgrid-universal/issues/1331)) ([abe344b](https://github.com/ghiscoding/slickgrid-universal/commit/abe344b025b385630077bfb63d5534a88b3b7d71)) - by @ghiscoding + * add `onBeforePasteCell` event to excel copy buffer ([#1298](https://github.com/ghiscoding/slickgrid-universal/issues/1298)) ([22037ca](https://github.com/ghiscoding/slickgrid-universal/commit/22037ca7918fc4bfb55bb4bf619cd280b564a351)) - by @zewa666 + * add column `reorderable` option to optionally lock a column ([#1357](https://github.com/ghiscoding/slickgrid-universal/issues/1357)) ([44f6c08](https://github.com/ghiscoding/slickgrid-universal/commit/44f6c085f009ec41bec711aa14ae7fbb3fcbc156)) - by @ghiscoding + * convert CheckSelectColumn plugin to native HTML for CSP safe code ([#1332](https://github.com/ghiscoding/slickgrid-universal/issues/1332)) ([2b9216d](https://github.com/ghiscoding/slickgrid-universal/commit/2b9216df3e1796ffb4081127cdaa9011e4d48b23)) - by @ghiscoding + * **core:** expose all SlickEvent via internal PubSub Service ([#1311](https://github.com/ghiscoding/slickgrid-universal/issues/1311)) ([f56edef](https://github.com/ghiscoding/slickgrid-universal/commit/f56edef91b76ab044134ddf36d67599e6d80f39c)) - by @ghiscoding + * **editor:** auto commit before save; add `onBeforeEditMode` callback ([#1353](https://github.com/ghiscoding/slickgrid-universal/issues/1353)) ([f33bf52](https://github.com/ghiscoding/slickgrid-universal/commit/f33bf5202e0db30121bf52ce184555f6524dde85)) - by @zewa666 + * **plugin:** new Row Based Editor ([#1323](https://github.com/ghiscoding/slickgrid-universal/issues/1323)) ([64d464c](https://github.com/ghiscoding/slickgrid-universal/commit/64d464c2094c014024ddeaf49bd4f6ec898b1c25)) - by @zewa666 ### Performance Improvements @@ -170,17 +299,25 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * `updateColumns()` should be public use with column hidden ([#1288](https://github.com/ghiscoding/slickgrid-universal/issues/1288)) ([211180b](https://github.com/ghiscoding/slickgrid-universal/commit/211180b8c1f32250e6fc7a559baaa203154473e0)) - by @ghiscoding + * applyDefaults use provided grid options before applying defaults ([#1283](https://github.com/ghiscoding/slickgrid-universal/issues/1283)) ([7fc772f](https://github.com/ghiscoding/slickgrid-universal/commit/7fc772fb80a80e0eafa900fc688667d12e1f9429)) - by @ghiscoding + * **core:** `SlickGroupItemMetadataProvider` should implements `SlickPlugin` ([#1294](https://github.com/ghiscoding/slickgrid-universal/issues/1294)) ([5aac2b6](https://github.com/ghiscoding/slickgrid-universal/commit/5aac2b6a37cdd21938fa54769b72ce317562e45d)) - by @ghiscoding + * **core:** add missing option to control row highlight duration after CRUD ([#1278](https://github.com/ghiscoding/slickgrid-universal/issues/1278)) ([8240c8c](https://github.com/ghiscoding/slickgrid-universal/commit/8240c8c9710f4e5d902ec9961f6a721ae0f84f7f)) - by @ghiscoding + * GroupingGetterFunction should be allowed to return arbitrary value ([#1296](https://github.com/ghiscoding/slickgrid-universal/issues/1296)) ([3807116](https://github.com/ghiscoding/slickgrid-universal/commit/38071168e0fe5eea7d5e1ee117fae98c09057a4c)) - by @ghiscoding + * **RowDetail:** sort change should collapse all Row Detail ([#1284](https://github.com/ghiscoding/slickgrid-universal/issues/1284)) ([21f6031](https://github.com/ghiscoding/slickgrid-universal/commit/21f60310a402dd12c80bf4553588c6cd777a131a)) - by @ghiscoding + * use correct argument type on `setData()` ([#1287](https://github.com/ghiscoding/slickgrid-universal/issues/1287)) ([0b0b86c](https://github.com/ghiscoding/slickgrid-universal/commit/0b0b86c2325ea2a11b74d8fe8debeb02e23bb014)) - by @ghiscoding ### Features * (re)add option to cancel Row Detail opening ([#1286](https://github.com/ghiscoding/slickgrid-universal/issues/1286)) ([f08925c](https://github.com/ghiscoding/slickgrid-universal/commit/f08925c50c1dd18448a04a55c8303736e3cc2289)) - by @ghiscoding + * datasetIdPropertyName respected in newRowCreator ([#1279](https://github.com/ghiscoding/slickgrid-universal/issues/1279)) ([9d60a9d](https://github.com/ghiscoding/slickgrid-universal/commit/9d60a9d82e605ae2351822c66ff8757349b906cf)) - by @zewa666 + * make DataView Grouping `compileAccumulatorLoop` CSP safe ([#1295](https://github.com/ghiscoding/slickgrid-universal/issues/1295)) ([af82208](https://github.com/ghiscoding/slickgrid-universal/commit/af8220881b2791be2cc3f6605eda3955428094c7)) - by @ghiscoding ### Performance Improvements @@ -192,11 +329,13 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **composite:** `onSave` always include last dataContext on few inserts ([#1271](https://github.com/ghiscoding/slickgrid-universal/issues/1271)) ([14791e7](https://github.com/ghiscoding/slickgrid-universal/commit/14791e7edd99b84c8bfefff3d287399cbba9ffad)) - by @ghiscoding + * **npm:** publish src folder for source maps, fixes downstream builds ([#1269](https://github.com/ghiscoding/slickgrid-universal/issues/1269)) ([701da75](https://github.com/ghiscoding/slickgrid-universal/commit/701da752565384408e22857a201828379bfc26ff)) - by @ghiscoding ### Features * **core:** add `rowHighlightCssClass` & `highlightRow()` to SlickGrid ([#1272](https://github.com/ghiscoding/slickgrid-universal/issues/1272)) ([31c38ad](https://github.com/ghiscoding/slickgrid-universal/commit/31c38ad4d0a2e5c07ad92964fee303b31a192b59)) - by @ghiscoding + * **utils:** replace slick-core extend utils with `node-extend` ([#1277](https://github.com/ghiscoding/slickgrid-universal/issues/1277)) ([3439118](https://github.com/ghiscoding/slickgrid-universal/commit/3439118da344cd852a1b1af5bd83c4b894213464)) - by @ghiscoding ## [4.0.3](https://github.com/ghiscoding/slickgrid-universal/compare/v4.0.2...v4.0.3) (2023-12-16) @@ -206,6 +345,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline * add back moment rollup patch with default import ([2e81421](https://github.com/ghiscoding/slickgrid-universal/commit/2e814214fe7246c76fe8e1398c87cd20cc41c862)) - by @ghiscoding ## [4.0.2](https://github.com/ghiscoding/slickgrid-universal/compare/v3.7.2...v4.0.2) (2023-12-15) + ### Follow the [Migration 4.x Guide](https://ghiscoding.gitbook.io/slickgrid-universal/migrations/migration-to-4.x) ### Bug Fixes @@ -229,8 +369,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * `stripTags` shouldn't throw with null/undefined ([8f706fc](https://github.com/ghiscoding/slickgrid-universal/commit/8f706fc95f837c6352fb3217952c86b4326f8aaf)) - by @ghiscoding + * **core:** SlickEventHandler handler args should have Types ([#1261](https://github.com/ghiscoding/slickgrid-universal/issues/1261)) ([a33129b](https://github.com/ghiscoding/slickgrid-universal/commit/a33129b0ce1443443e7dcebb3562ffd538b6a731)) - by @ghiscoding + * regression, Row Detail no longer displayed after CSP safe code ([#1259](https://github.com/ghiscoding/slickgrid-universal/issues/1259)) ([a35f0a4](https://github.com/ghiscoding/slickgrid-universal/commit/a35f0a488775e8ccb68ec8fe0ece9abc47c358f4)) - by @ghiscoding + * **utils:** undefined html shouldn't throw on stripTags ([05361e7](https://github.com/ghiscoding/slickgrid-universal/commit/05361e7430694d9a41075f744460eaf187a50b11)) - by @ghiscoding # [4.0.0-alpha.0](https://github.com/ghiscoding/slickgrid-universal/compare/v3.7.1...v4.0.0-alpha.0) (2023-12-09) @@ -238,21 +381,33 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * `setActiveCellInternal()` should not throw when cell/row undefined ([dbe6413](https://github.com/ghiscoding/slickgrid-universal/commit/dbe64132294bc88f5dc13ac23a6f6f84ac5e1ffd)) - by @ghiscoding + * change dynamic html string w/CSP safe code to fix scroll ([#1210](https://github.com/ghiscoding/slickgrid-universal/issues/1210)) ([cd03907](https://github.com/ghiscoding/slickgrid-universal/commit/cd03907b20468190db7f84f3ae24fbd531e4f6e4)) - by @ghiscoding + * Draggable shouldn't trigger dragEnd without first dragging ([#1211](https://github.com/ghiscoding/slickgrid-universal/issues/1211)) ([47cb36e](https://github.com/ghiscoding/slickgrid-universal/commit/47cb36e78995f70933807aa33ba3afa0fecf491e)) - by @ghiscoding + * escape glob pattern for SASS copy to work in CI ([0590b24](https://github.com/ghiscoding/slickgrid-universal/commit/0590b24bf2ac140ba69149bd55cbff95b3493112)) - by @ghiscoding-SE + * only allow row drag on cell w/`dnd` or `cell-reorder`, fix [#937](https://github.com/ghiscoding/slickgrid-universal/issues/937) ([6a2ab55](https://github.com/ghiscoding/slickgrid-universal/commit/6a2ab550a253a4a1f35e4e81a120fa9247ce753b)), closes [#897](https://github.com/ghiscoding/slickgrid-universal/issues/897) - by @ghiscoding-SE + * remove CellRange, SlickRange, SlickGroup, ... unused interfaces ([#1219](https://github.com/ghiscoding/slickgrid-universal/issues/1219)) ([a4cc469](https://github.com/ghiscoding/slickgrid-universal/commit/a4cc469e9c21c5ed851bfbaafdc6b580e7389272)) - by @ghiscoding + * the `devMode` should be `false` or an object with other options ([ac57992](https://github.com/ghiscoding/slickgrid-universal/commit/ac57992abd821cdd6fec823464944dadfa1e7b2c)) - by @ghiscoding-SE + * the `devMode` should be `false` or an object with other options ([ad2285a](https://github.com/ghiscoding/slickgrid-universal/commit/ad2285a3890442b28dfc7c668ab1b1376e17d3df)) - by @ghiscoding-SE + * try adding sort icon on non `sortable` column shouldn't throw ([4791fc8](https://github.com/ghiscoding/slickgrid-universal/commit/4791fc89078d9f3212d034fb1d5e43b8bbfffc5d)) - by @ghiscoding-SE ### Features * convert GroupItemMetadataProvider Formatter to native HTML for CSP ([#1215](https://github.com/ghiscoding/slickgrid-universal/issues/1215)) ([d723856](https://github.com/ghiscoding/slickgrid-universal/commit/d723856777329f2e40fe3a12d3c59e33afd0e3a8)) - by @ghiscoding + * introduce devMode to support nodejs based unit testing ([#1251](https://github.com/ghiscoding/slickgrid-universal/issues/1251)) ([596737d](https://github.com/ghiscoding/slickgrid-universal/commit/596737d52a2ec8c42320152342144ff32191ebfd)) - by @ghiscoding + * remove unnecessary Formatters, replace by `cssClass` ([#1225](https://github.com/ghiscoding/slickgrid-universal/issues/1225)) ([de26496](https://github.com/ghiscoding/slickgrid-universal/commit/de26496aa5dc462869a4a1ff966b32baf86e188b)) - by @ghiscoding + * rewrite all Formatters as native HTML elements ([#1229](https://github.com/ghiscoding/slickgrid-universal/issues/1229)) ([5cb4dd5](https://github.com/ghiscoding/slickgrid-universal/commit/5cb4dd5757adc401ed4e6deab0e41bcd08a827a3)) - by @ghiscoding + * use PubSub Service singleton to subscribe to any SlickEvent ([#1248](https://github.com/ghiscoding/slickgrid-universal/issues/1248)) ([388bd11](https://github.com/ghiscoding/slickgrid-universal/commit/388bd115c1a15f853da8ac943a6e5e3574630438)) - by @ghiscoding ### Performance Improvements @@ -264,6 +419,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * the `devMode` should be `false` or an object with other options ([ad2285a](https://github.com/ghiscoding/slickgrid-universal/commit/ad2285a3890442b28dfc7c668ab1b1376e17d3df)) - by @ghiscoding-SE + * use !important on CSS text utils ([7fdbeb6](https://github.com/ghiscoding/slickgrid-universal/commit/7fdbeb6c46201ae80d6e71e2df7016735b771bf2)) - by @ghiscoding ## [3.7.1](https://github.com/ghiscoding/slickgrid-universal/compare/v3.7.0...v3.7.1) (2023-12-08) @@ -277,13 +433,17 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * cell selection range with key combos were incorrect ([#1244](https://github.com/ghiscoding/slickgrid-universal/issues/1244)) ([79d86fe](https://github.com/ghiscoding/slickgrid-universal/commit/79d86fea99258ccf82a5d3d8c684410623e6753b)) - by @ghiscoding + * DraggableGrouping & Select Filter `collectionAsync` mem leaks ([#1247](https://github.com/ghiscoding/slickgrid-universal/issues/1247)) ([7dcf53a](https://github.com/ghiscoding/slickgrid-universal/commit/7dcf53ac4d7873c75e82e01c2b4a806f88d8ff39)) - by @ghiscoding + * **formatters:** show console error on invalid multiple formatters ([#1227](https://github.com/ghiscoding/slickgrid-universal/issues/1227)) ([fd69ac0](https://github.com/ghiscoding/slickgrid-universal/commit/fd69ac01c68496d4e7d5dd2f06186fba961016d9)) - by @ghiscoding + * registered external resouces should keep singleton ref ([#1242](https://github.com/ghiscoding/slickgrid-universal/issues/1242)) ([adf2054](https://github.com/ghiscoding/slickgrid-universal/commit/adf2054bdc8ef7701e6fab78e685d49b8424da29)) - by @ghiscoding ### Features * **Formatters:** add new `Formatters.iconBoolean` for icon w/truthy val ([#1228](https://github.com/ghiscoding/slickgrid-universal/issues/1228)) ([17ab965](https://github.com/ghiscoding/slickgrid-universal/commit/17ab965102c1f71270ea2423f9d6e0fd4ad73c14)) - by @ghiscoding + * **GraphQL:** Provide ability to specify operationName ([#1224](https://github.com/ghiscoding/slickgrid-universal/issues/1224)) ([4db6c34](https://github.com/ghiscoding/slickgrid-universal/commit/4db6c343fd7ce5f4c81ee0d1df0f964d0aac9d48)) - by @Harsgalt86 # 3.6.0 (2023-11-26) @@ -297,6 +457,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **common:** ms-select-vanilla requires `@types/trusted-types` dep ([#1190](https://github.com/ghiscoding/slickgrid-universal/issues/1190)) ([284a379](https://github.com/ghiscoding/slickgrid-universal/commit/284a3791027423d0d7f45a950e0a3b8a8a684612)) - by @ghiscoding + * improve build & types exports for all targets, Node, CJS/ESM ([#1188](https://github.com/ghiscoding/slickgrid-universal/issues/1188)) ([980fd68](https://github.com/ghiscoding/slickgrid-universal/commit/980fd68f6ce9564bb1fcac5f6ee68fd35f839e8f)) - by @ghiscoding # [3.5.0](https://github.com/ghiscoding/slickgrid-universal/compare/v3.4.2...v3.5.0) (2023-11-10) @@ -304,13 +465,17 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **common:** SlickCellRangeSelector shouldn't stop editor event bubbling ([#1183](https://github.com/ghiscoding/slickgrid-universal/issues/1183)) ([7bb9d25](https://github.com/ghiscoding/slickgrid-universal/commit/7bb9d25c40c3f7f53be57c45917802e5f426c599)) - by @ghiscoding + * **graphql:** deprecate `isWithCursor` in favor of simpler `useCursor` ([#1187](https://github.com/ghiscoding/slickgrid-universal/issues/1187)) ([7b3590f](https://github.com/ghiscoding/slickgrid-universal/commit/7b3590f323ea2fe3d3f312674205fc94485213fa)) - by @ghiscoding + * **pagination:** should recreate pagination on cursor based changed ([#1175](https://github.com/ghiscoding/slickgrid-universal/issues/1175)) ([c7836aa](https://github.com/ghiscoding/slickgrid-universal/commit/c7836aae4a4ea0892791acc79a7bcb338ddb2038)) - by @ghiscoding + * **styles:** menu command with & without icons aren't aligned ([#1180](https://github.com/ghiscoding/slickgrid-universal/issues/1180)) ([35f040d](https://github.com/ghiscoding/slickgrid-universal/commit/35f040dbd1f2d384aadbfbe351dd0e55f8d34c68)) - by @ghiscoding ### Features * **common:** add `compoundOperatorAltTexts` grid option ([#1181](https://github.com/ghiscoding/slickgrid-universal/issues/1181)) ([dc0aa5e](https://github.com/ghiscoding/slickgrid-universal/commit/dc0aa5e28351af989e9dd691916af909e3a5fdf5)) - by @ghiscoding + * **GraphQL:** add verbatim search terms to backend services ([#1174](https://github.com/ghiscoding/slickgrid-universal/issues/1174)) ([eadc5ef](https://github.com/ghiscoding/slickgrid-universal/commit/eadc5ef636e8bf331d89f37be4596e7cc534b974)) - by @Harsgalt86 ## [3.4.2](https://github.com/ghiscoding/slickgrid-universal/compare/v3.4.1...v3.4.2) (2023-11-02) @@ -328,30 +493,51 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **common:** `unbindAll` with a group name should remove all tagged ones ([#1152](https://github.com/ghiscoding/slickgrid-universal/issues/1152)) ([5014354](https://github.com/ghiscoding/slickgrid-universal/commit/5014354803d4561409c0f9622ad8bc5093d494cf)), closes [#1150](https://github.com/ghiscoding/slickgrid-universal/issues/1150) - by @ghiscoding + * **common:** calling `bind` with multiple events should add group name ([#1157](https://github.com/ghiscoding/slickgrid-universal/issues/1157)) ([9023b54](https://github.com/ghiscoding/slickgrid-universal/commit/9023b54146b72c0305128484f9fd6f9d1ac47b48)), closes [#1150](https://github.com/ghiscoding/slickgrid-universal/issues/1150) - by @ghiscoding + * **common:** clicking Menu close button should only close current menu ([#1160](https://github.com/ghiscoding/slickgrid-universal/issues/1160)) ([b524ef1](https://github.com/ghiscoding/slickgrid-universal/commit/b524ef1af6c662bc4ebcd87ad95aa99dd077a119)) - by @ghiscoding + * **common:** context menu should close when clicking another cell ([#1163](https://github.com/ghiscoding/slickgrid-universal/issues/1163)) ([bd132c5](https://github.com/ghiscoding/slickgrid-universal/commit/bd132c52a082147c2366b2fade124e145834902f)) - by @ghiscoding + * **common:** disable throwWhenFrozenNotAllViewable w/frozen grids ([#1149](https://github.com/ghiscoding/slickgrid-universal/issues/1149)) ([9a06875](https://github.com/ghiscoding/slickgrid-universal/commit/9a06875d8654c47d97aaaa0fd5191c1bfeae7288)) - by @ghiscoding + * **common:** make sure destroy is a function before calling it ([#1148](https://github.com/ghiscoding/slickgrid-universal/issues/1148)) ([dba9606](https://github.com/ghiscoding/slickgrid-universal/commit/dba96060666a929eb616bcacb492f6f5f3f56106)) - by @ghiscoding + * **common:** mouseover disabled sub-menu shouldn't open it ([#1167](https://github.com/ghiscoding/slickgrid-universal/issues/1167)) ([550f103](https://github.com/ghiscoding/slickgrid-universal/commit/550f1031ca2c56649ed630ab753d757a3fb799fa)) - by @ghiscoding + * **common:** replace `innerHTML: '×'` with `textContent: '×'` ([#1156](https://github.com/ghiscoding/slickgrid-universal/issues/1156)) ([e8b2cfb](https://github.com/ghiscoding/slickgrid-universal/commit/e8b2cfb4b3d182de429ba367d1c83b873670fabc)) - by @ghiscoding + * **common:** rollback event capture causing multiple calls ([#1168](https://github.com/ghiscoding/slickgrid-universal/issues/1168)) ([90876c9](https://github.com/ghiscoding/slickgrid-universal/commit/90876c9a57f291271a3510541e4a24a4ef86413c)) - by @ghiscoding + * deprecate HeaderMenu `items` in favor of `commandItems` ([634441c](https://github.com/ghiscoding/slickgrid-universal/commit/634441c34e17a0a11c672df32c71014309efc13e)) - by @ghiscoding + * deprecate HeaderMenu `items` in favor of `commandItems` ([#1159](https://github.com/ghiscoding/slickgrid-universal/issues/1159)) ([2b26d6d](https://github.com/ghiscoding/slickgrid-universal/commit/2b26d6da1232f4ad4a7d0db8ad077b3b2e3c6bd7)) - by @ghiscoding + * **deps:** update all non-major dependencies ([#1136](https://github.com/ghiscoding/slickgrid-universal/issues/1136)) ([a755b0f](https://github.com/ghiscoding/slickgrid-universal/commit/a755b0f0ff8af47c6d1d534930b1354fd28a781f)) - by @renovate-bot + * **deps:** update all non-major dependencies ([#1138](https://github.com/ghiscoding/slickgrid-universal/issues/1138)) ([82a602e](https://github.com/ghiscoding/slickgrid-universal/commit/82a602e8c3c25a45979d3e3bbf4766d1bae33f80)) - by @renovate-bot + * **gridMenu:** remove GridMenu from DOM after closing it ([#1169](https://github.com/ghiscoding/slickgrid-universal/issues/1169)) ([87b242f](https://github.com/ghiscoding/slickgrid-universal/commit/87b242fdebd6d8ce838842458e192a6e90de3d80)) - by @ghiscoding + * move `innerHTML` as separate assignment to improve CSP trusted types ([#1162](https://github.com/ghiscoding/slickgrid-universal/issues/1162)) ([9c6a002](https://github.com/ghiscoding/slickgrid-universal/commit/9c6a002666f16b1096d3f928900ad412a4124233)) - by @ghiscoding ### Features * add `subMenuOpenByEvent` option to open sub-menus via mouseover ([#1161](https://github.com/ghiscoding/slickgrid-universal/issues/1161)) ([609f88b](https://github.com/ghiscoding/slickgrid-universal/commit/609f88b2b80515a540bd7ae1c8366b57bd288dbc)) - by @ghiscoding + * add sub-menu(s) to CellMenu & ContextMenu plugins ([#1141](https://github.com/ghiscoding/slickgrid-universal/issues/1141)) ([bd18af1](https://github.com/ghiscoding/slickgrid-universal/commit/bd18af1ee960f9417cb7625ff8c3fb5d9567d16e)) - by @ghiscoding + * add sub-menu(s) to GridMenu plugin ([#1151](https://github.com/ghiscoding/slickgrid-universal/issues/1151)) ([5178310](https://github.com/ghiscoding/slickgrid-universal/commit/5178310c0247d5524300841aac7aea7c4f3df733)) - by @ghiscoding + * add sub-menu(s) to HeaderMenu plugin ([#1158](https://github.com/ghiscoding/slickgrid-universal/issues/1158)) ([eeab42e](https://github.com/ghiscoding/slickgrid-universal/commit/eeab42e270e53341a8572ab55ed758276a4d30d6)) - by @ghiscoding + * add support for grid inside Shadow DOM ([#1166](https://github.com/ghiscoding/slickgrid-universal/issues/1166)) ([f7b8c46](https://github.com/ghiscoding/slickgrid-universal/commit/f7b8c46593c71b7114ac85610c12ad6187e3f6de)) - by @ghiscoding + * **common:** add group name to `bind` and `unbindAll` methods ([#1150](https://github.com/ghiscoding/slickgrid-universal/issues/1150)) ([6c3b90e](https://github.com/ghiscoding/slickgrid-universal/commit/6c3b90e774906621d5b1584a2372ba633d2366ff)) - by @ghiscoding + * **common:** create ColumnPicker dynamically every time ([#1165](https://github.com/ghiscoding/slickgrid-universal/issues/1165)) ([7e8d80e](https://github.com/ghiscoding/slickgrid-universal/commit/7e8d80e807176ba2064cbb71d06fb53995aae06c)) - by @ghiscoding + * **graphql:** add optional cursor pagination to GraphQL backend service ([#1153](https://github.com/ghiscoding/slickgrid-universal/issues/1153)) ([29579b2](https://github.com/ghiscoding/slickgrid-universal/commit/29579b23ab1e531b3323cbf10eb9e9882e244b8f)) - by @Harsgalt86 ## [3.3.2](https://github.com/ghiscoding/slickgrid-universal/compare/v3.3.1...v3.3.2) (2023-10-06) @@ -375,6 +561,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * add option to cancel Row Detail opening ([#1125](https://github.com/ghiscoding/slickgrid-universal/issues/1125)) ([82ba377](https://github.com/ghiscoding/slickgrid-universal/commit/82ba377132d90335ea2bca5bf628ab47841fc913)) - by @ghiscoding + * add pageUp/pageDown/home/end to SlickCellSelection ([#1126](https://github.com/ghiscoding/slickgrid-universal/issues/1126)) ([b7e9e0d](https://github.com/ghiscoding/slickgrid-universal/commit/b7e9e0db9fde184c76cb835858d195ad28657b05)) - by @ghiscoding ## [3.2.2](https://github.com/ghiscoding/slickgrid-universal/compare/v3.2.1...v3.2.2) (2023-09-24) @@ -382,8 +569,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **deps:** update all non-major dependencies ([#1113](https://github.com/ghiscoding/slickgrid-universal/issues/1113)) ([37741fe](https://github.com/ghiscoding/slickgrid-universal/commit/37741fe572e866ca5e1c7c53280eb9a1a2da6518)) - by @renovate-bot + * **deps:** update dependency multiple-select-vanilla to ^0.4.10 ([#1098](https://github.com/ghiscoding/slickgrid-universal/issues/1098)) ([ab97b9d](https://github.com/ghiscoding/slickgrid-universal/commit/ab97b9df3205f1a55f69f3722d276c8c71d8fd29)) - by @renovate-bot + * **GridService:** clear any opened highlight timers before disposing ([#1116](https://github.com/ghiscoding/slickgrid-universal/issues/1116)) ([c6a0957](https://github.com/ghiscoding/slickgrid-universal/commit/c6a095702a672e14b442e71be492942c07d6f1e6)) - by @ghiscoding + * **resizer:** resize without container ([#1117](https://github.com/ghiscoding/slickgrid-universal/issues/1117)) ([9013522](https://github.com/ghiscoding/slickgrid-universal/commit/90135223130dacfdd376b56d4cf49437328b08ae)) - by @zewa666 ### Reverts @@ -395,6 +585,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **common:** Select Filter/Editor enableRenderHtml was wrong ([#1096](https://github.com/ghiscoding/slickgrid-universal/issues/1096)) ([1f09eef](https://github.com/ghiscoding/slickgrid-universal/commit/1f09eefaf2dbb13434fd90b54b5361ef9f08116c)) - by @ghiscoding + * **deps:** update dependency conventional-changelog-conventionalcommits to v7 ([#1091](https://github.com/ghiscoding/slickgrid-universal/issues/1091)) ([6c23aef](https://github.com/ghiscoding/slickgrid-universal/commit/6c23aef29ac19735b18bdbfd1d8f51423f249989)) - by @renovate-bot ## [3.2.0](https://github.com/ghiscoding/slickgrid-universal/compare/v3.1.0...v3.2.0) (2023-08-21) @@ -402,15 +593,21 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **export:** add `autoDetectCellFormat` flag to Excel Export Options ([#1083](https://github.com/ghiscoding/slickgrid-universal/issues/1083)) ([839b09a](https://github.com/ghiscoding/slickgrid-universal/commit/839b09a10ceba889bc96a7f229f58412a6d5649c)) - by @ghiscoding + * **TreeData:** add auto-recalc feature for Tree Totals w/Aggregators ([#1084](https://github.com/ghiscoding/slickgrid-universal/issues/1084)) ([e884c03](https://github.com/ghiscoding/slickgrid-universal/commit/e884c0356595c161b746ca370efa4bd74088c458)) - by @ghiscoding + * **TreeData:** add optional Aggregators to Tree Data grids ([#1074](https://github.com/ghiscoding/slickgrid-universal/issues/1074)) ([6af5fd1](https://github.com/ghiscoding/slickgrid-universal/commit/6af5fd17b582834b24655b06c34c634a99c93c6e)) - by @ghiscoding ### Bug Fixes * adding dataset hierarchical item shouldn't cause scroll flickering ([#1076](https://github.com/ghiscoding/slickgrid-universal/issues/1076)) ([8536e0e](https://github.com/ghiscoding/slickgrid-universal/commit/8536e0e04f1168648251f517cb47ea2e7129e231)) - by @ghiscoding + * **common:** Sort Service could throw on 3rd with undefined columnId ([#1059](https://github.com/ghiscoding/slickgrid-universal/issues/1059)) ([1141230](https://github.com/ghiscoding/slickgrid-universal/commit/114123040a6b69d40f928955627121189a6feb75)) - by @ghiscoding + * copying multiple times only kept last undo CellExternalCopyManager ([#1075](https://github.com/ghiscoding/slickgrid-universal/issues/1075)) ([e3beee2](https://github.com/ghiscoding/slickgrid-universal/commit/e3beee208fcd223e911d2d88a15b9d2950267eda)) - by @ghiscoding + * **deps:** update dependency autocompleter to v9 ([#1051](https://github.com/ghiscoding/slickgrid-universal/issues/1051)) ([0e05f2a](https://github.com/ghiscoding/slickgrid-universal/commit/0e05f2a4c9f3c9640a3982b7cfa04ea71cfaab96)) - by @renovate-bot + * **TreeData:** auto-recalc should update totals for collapsed items too ([#1086](https://github.com/ghiscoding/slickgrid-universal/issues/1086)) ([25d39f2](https://github.com/ghiscoding/slickgrid-universal/commit/25d39f277093990f150ec4aa471c079eab73e4b1)) - by @ghiscoding ## [3.1.0](https://github.com/ghiscoding/slickgrid-universal/compare/v3.0.1...v3.1.0) (2023-07-20) @@ -422,6 +619,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **deps:** update dependency dompurify to ^3.0.5 ([#1030](https://github.com/ghiscoding/slickgrid-universal/issues/1030)) ([728bc58](https://github.com/ghiscoding/slickgrid-universal/commit/728bc58b6844544479695f29984221c9ea099936)) - by @renovate-bot + * **plugins:** RowMoveManager shouldn't add cssClass when not usable ([#1044](https://github.com/ghiscoding/slickgrid-universal/issues/1044)) ([f25eeec](https://github.com/ghiscoding/slickgrid-universal/commit/f25eeec7a277d4b915d1423f12e688ad8ac98e7c)) - by @ghiscoding ## [3.0.1](https://github.com/ghiscoding/slickgrid-universal/compare/v3.0.0...v3.0.1) (2023-07-01) @@ -429,12 +627,19 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **common:** Select Filter/Editor regular text shouldn't be html encoded ([#1011](https://github.com/ghiscoding/slickgrid-universal/issues/1011)) ([c203a2c](https://github.com/ghiscoding/slickgrid-universal/commit/c203a2ce4d4e5cf6dfb0e05a25f5fd6b0c4cbe4d)), closes [#976](https://github.com/ghiscoding/slickgrid-universal/issues/976) - by @ghiscoding + * **deps:** update all non-major dependencies ([#1016](https://github.com/ghiscoding/slickgrid-universal/issues/1016)) ([c34ed84](https://github.com/ghiscoding/slickgrid-universal/commit/c34ed84c8c5aa20876c70b6350f711e16fe6b965)) - by @renovate-bot + * **deps:** update dependency autocompleter to ^8.0.4 ([#996](https://github.com/ghiscoding/slickgrid-universal/issues/996)) ([3adf3a1](https://github.com/ghiscoding/slickgrid-universal/commit/3adf3a1a4cf960963ce1447617b3f34b68b6ff4d)) - by @renovate-bot + * **deps:** update dependency conventional-changelog-conventionalcommits to v6 ([#990](https://github.com/ghiscoding/slickgrid-universal/issues/990)) ([b3fbcf5](https://github.com/ghiscoding/slickgrid-universal/commit/b3fbcf57556a7eb964782eb967c187f4307323f8)) - by @renovate-bot + * **deps:** update dependency slickgrid to ^4.0.1 ([#1017](https://github.com/ghiscoding/slickgrid-universal/issues/1017)) ([2750816](https://github.com/ghiscoding/slickgrid-universal/commit/2750816b7b669a820362934daa9bbfd5d60f3ac5)) - by @renovate-bot + * **GridState:** calling `getAssociatedGridColumns` should extend column ([#1014](https://github.com/ghiscoding/slickgrid-universal/issues/1014)) ([77cec0c](https://github.com/ghiscoding/slickgrid-universal/commit/77cec0cd052ec3145d73a7a16d0c7f5c663e3901)) - by @ghiscoding + * **GridState:** calling getAssociatedGridColumns should extend column (part2) ([#1015](https://github.com/ghiscoding/slickgrid-universal/issues/1015)) ([3ea1d02](https://github.com/ghiscoding/slickgrid-universal/commit/3ea1d0289ba260325a2592fda42fecce10499525)) - by @ghiscoding + * **grouping:** DraggableGrouping could throw when leaving page ([#1019](https://github.com/ghiscoding/slickgrid-universal/issues/1019)) ([c233a9c](https://github.com/ghiscoding/slickgrid-universal/commit/c233a9c5db1fc06395e75f1bc5bb34ea3431ba1f)) - by @ghiscoding ## [3.0.0](https://github.com/ghiscoding/slickgrid-universal/compare/v2.6.4...v3.0.0) (2023-05-29) @@ -458,11 +663,13 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### ⚠ BREAKING CHANGES * drop jQuery requirement (#962) + * **common:** migrate to multiple-select-vanilla (#919) ### Features * **common:** migrate to multiple-select-vanilla ([#919](https://github.com/ghiscoding/slickgrid-universal/issues/919)) ([bc74207](https://github.com/ghiscoding/slickgrid-universal/commit/bc74207e9b2ec46209e87b126e1fcff596c162af)) - by @ghiscoding + * drop jQuery requirement ([#962](https://github.com/ghiscoding/slickgrid-universal/issues/962)) ([3da21da](https://github.com/ghiscoding/slickgrid-universal/commit/3da21daacc391a0fb309fcddd78442642c5269f6)) - by @ghiscoding ## [2.6.4](https://github.com/ghiscoding/slickgrid-universal/compare/v2.6.3...v2.6.4) (2023-05-20) @@ -470,11 +677,17 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **binding:** remove unnecessary sanitizer in BindingService ([#947](https://github.com/ghiscoding/slickgrid-universal/issues/947)) ([32a9a35](https://github.com/ghiscoding/slickgrid-universal/commit/32a9a35861647510ccb0d3dd14340cd3a1689fc1)) - by @ghiscoding + * **core:** add better aria accessibility missing on menus and checkboxes ([#968](https://github.com/ghiscoding/slickgrid-universal/issues/968)) ([8041c11](https://github.com/ghiscoding/slickgrid-universal/commit/8041c1189afd7460bbcc0226c49086878c3b5f90)) - by @ghiscoding + * **core:** set `wheel` event listener to passive for better perf ([#971](https://github.com/ghiscoding/slickgrid-universal/issues/971)) ([e4417e8](https://github.com/ghiscoding/slickgrid-universal/commit/e4417e865f6fdf4bcb27eebfc476d959a16d47ea)) - by @ghiscoding + * **deps:** update all non-major dependencies ([#975](https://github.com/ghiscoding/slickgrid-universal/issues/975)) ([c4313b0](https://github.com/ghiscoding/slickgrid-universal/commit/c4313b014da67826b46324c2933f923ea90e7088)) - by @renovate-bot + * **deps:** update dependency @faker-js/faker to v8 ([#973](https://github.com/ghiscoding/slickgrid-universal/issues/973)) ([0f2837e](https://github.com/ghiscoding/slickgrid-universal/commit/0f2837e61862016cbbdeef8e4e2517ccfaea2202)) - by @renovate-bot + * **export:** fix negative number exports to Excel ([#977](https://github.com/ghiscoding/slickgrid-universal/issues/977)) ([edf5721](https://github.com/ghiscoding/slickgrid-universal/commit/edf5721007ce0745fc81f3f0261fb7e25340cbc1)) - by @ghiscoding + * SlickDraggableGrouping should hide group elms when dragging ([#965](https://github.com/ghiscoding/slickgrid-universal/issues/965)) ([6601998](https://github.com/ghiscoding/slickgrid-universal/commit/660199896df040a34f8947acf81a5d720d11a8c4)) - by @ghiscoding ## [2.6.3](https://github.com/ghiscoding/slickgrid-universal/compare/v2.6.2...v2.6.3) (2023-03-23) @@ -500,6 +713,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * Edt cell mouseout should save & excel copy buffer should still work ([#917](https://github.com/ghiscoding/slickgrid-universal/issues/917)) ([18ba0fc](https://github.com/ghiscoding/slickgrid-universal/commit/18ba0fc4ed2cb2f678dc4a5486439d59e051a94a)), closes [#901](https://github.com/ghiscoding/slickgrid-universal/issues/901) [#901](https://github.com/ghiscoding/slickgrid-universal/issues/901) - by @ghiscoding + * **tooltip:** only create tooltip on header row/column from title attr ([#915](https://github.com/ghiscoding/slickgrid-universal/issues/915)) ([1d9c185](https://github.com/ghiscoding/slickgrid-universal/commit/1d9c185621ecdaa3a4f7c36f521579cbe5d79989)) - by @ghiscoding ### Features @@ -511,12 +725,19 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **autocomplete:** Autocomplete drop container should take content width ([#897](https://github.com/ghiscoding/slickgrid-universal/issues/897)) ([9690a38](https://github.com/ghiscoding/slickgrid-universal/commit/9690a38f678ca6f0632b847aebfe93e5b7f0bc12)) - by @ghiscoding + * **build:** package exports prop had invalid ESM import link ([#892](https://github.com/ghiscoding/slickgrid-universal/issues/892)) ([7f95f69](https://github.com/ghiscoding/slickgrid-universal/commit/7f95f698447f8178cb7ceec416c35f4957fddbe9)) - by @ghiscoding + * **common:** Excel copy cell ranges shouldn't lose its cell focus ([#901](https://github.com/ghiscoding/slickgrid-universal/issues/901)) ([1dc8b76](https://github.com/ghiscoding/slickgrid-universal/commit/1dc8b762b4fc8070eec003161fdc9c4ebf60afd2)) - by @ghiscoding + * **deps:** update dependency autocompleter to v8 ([#895](https://github.com/ghiscoding/slickgrid-universal/issues/895)) ([7df225d](https://github.com/ghiscoding/slickgrid-universal/commit/7df225d844ec5629800373da59aeed44eee04e1b)) - by @renovate-bot + * **deps:** update dependency dompurify to v3 ([#907](https://github.com/ghiscoding/slickgrid-universal/issues/907)) ([66c8b4d](https://github.com/ghiscoding/slickgrid-universal/commit/66c8b4d602d88d733070b2189468bf1b6508d7eb)) - by @renovate-bot + * **editor:** comparing select editor value against `['']` isn't valid ([#909](https://github.com/ghiscoding/slickgrid-universal/issues/909)) ([d93fd5f](https://github.com/ghiscoding/slickgrid-universal/commit/d93fd5f163e393c47fad8c8d285a5788b3834adf)) - by @ghiscoding + * **export:** Excel export auto-detect number with Formatters.multiple ([#902](https://github.com/ghiscoding/slickgrid-universal/issues/902)) ([be33a68](https://github.com/ghiscoding/slickgrid-universal/commit/be33a68cadbdaed0c60b00bdcd123f3a4797fb8a)) - by @ghiscoding + * **RowDetail:** Row Detail extension should work with editable grid ([#896](https://github.com/ghiscoding/slickgrid-universal/issues/896)) ([99677f0](https://github.com/ghiscoding/slickgrid-universal/commit/99677f08b9cb383a2b64540700e501c7bdfe9f72)) - by @ghiscoding ### Features @@ -544,6 +765,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **filters:** provide flag to disable special chars input filter parsing ([#873](https://github.com/ghiscoding/slickgrid-universal/issues/873)) ([7e35dae](https://github.com/ghiscoding/slickgrid-universal/commit/7e35dae2258c191e76dbdf01ac654f4a54b5b547)), closes [/stackoverflow.com/questions/75155658/in-angular-slickgrid-the-records-with-special-characters-are-not-gett/75160978#75160978](https://github.com//stackoverflow.com/questions/75155658/in-angular-slickgrid-the-records-with-special-characters-are-not-gett/75160978/issues/75160978) - by @ghiscoding + * **styling:** do not remove ul>li bullet on html root, fixes [#868](https://github.com/ghiscoding/slickgrid-universal/issues/868) ([#872](https://github.com/ghiscoding/slickgrid-universal/issues/872)) ([59fa0ba](https://github.com/ghiscoding/slickgrid-universal/commit/59fa0badad181172bf37a31ecf4ef0f44ee47e8d)) - by @ghiscoding ### Features @@ -567,19 +789,29 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **editors:** Autocomplete list should be using same width as cell width ([#846](https://github.com/ghiscoding/slickgrid-universal/issues/846)) ([0055f8a](https://github.com/ghiscoding/slickgrid-universal/commit/0055f8a925f7ec6e381c9b9b05dccdb405b7a420)) - by @ghiscoding + * **export:** create custom Excel cell format with Formatters.decimal ([#844](https://github.com/ghiscoding/slickgrid-universal/issues/844)) ([a7a626c](https://github.com/ghiscoding/slickgrid-universal/commit/a7a626ccaaa510d084979d38d9a6b5a439f24e6d)) - by @ghiscoding + * **exports:** Date should always export w/Formatter unless false ([#856](https://github.com/ghiscoding/slickgrid-universal/issues/856)) ([1b249e8](https://github.com/ghiscoding/slickgrid-universal/commit/1b249e88e3033ff4c432346ae32ce3183537237b)) - by @ghiscoding + * **formatters:** add all missing Date Formatters ([#855](https://github.com/ghiscoding/slickgrid-universal/issues/855)) ([9d29e59](https://github.com/ghiscoding/slickgrid-universal/commit/9d29e59818ae4e7d3cac692f0479e0147cc2ba8d)) - by @ghiscoding + * **formatters:** Date Formatter should work with Date object ([#854](https://github.com/ghiscoding/slickgrid-universal/issues/854)) ([30b80e2](https://github.com/ghiscoding/slickgrid-universal/commit/30b80e27b209dbafda25963864116d980650a648)) - by @ghiscoding + * **styling:** Grid Menu & Col Picker overflow in Firefox ([#845](https://github.com/ghiscoding/slickgrid-universal/issues/845)) ([9b0aef7](https://github.com/ghiscoding/slickgrid-universal/commit/9b0aef74d569c73e18d64e29034d777315c19cf8)) - by @ghiscoding ### Features * Excel exporter will now observe if numeric type has dollar formatter. If it does, it will use the dollarFormatter stylesheet. ([#843](https://github.com/ghiscoding/slickgrid-universal/issues/843)) ([ebabbaf](https://github.com/ghiscoding/slickgrid-universal/commit/ebabbafa240f114c7bdbd11d5d29fe1864d5bcba)) - by @austinsimpson + * **exports:** add Excel auto-detect format by field types & formatters ([#848](https://github.com/ghiscoding/slickgrid-universal/issues/848)) ([27a18c4](https://github.com/ghiscoding/slickgrid-universal/commit/27a18c416e71a2a1f418d5c2c850fd331262bf7f)) - by @ghiscoding + * **exports:** add Excel custom cell (column) styling ([#851](https://github.com/ghiscoding/slickgrid-universal/issues/851)) ([dd92d44](https://github.com/ghiscoding/slickgrid-universal/commit/dd92d44e0ac27c94a72c98af314cfa23f525f94c)) - by @ghiscoding + * **exports:** add optional Excel export parser callback functions ([#852](https://github.com/ghiscoding/slickgrid-universal/issues/852)) ([975da5b](https://github.com/ghiscoding/slickgrid-universal/commit/975da5b1d87ac287c1240e7ec88be4760e22ca74)) - by @ghiscoding + * **exports:** add optional file MIME type to Excel export service ([#849](https://github.com/ghiscoding/slickgrid-universal/issues/849)) ([05402e5](https://github.com/ghiscoding/slickgrid-universal/commit/05402e5b3a4cec9306ed21a495cc89c31b3816d8)) - by @ghiscoding + * **formatters:** add Currency Formatter and GroupTotalFormatter ([#850](https://github.com/ghiscoding/slickgrid-universal/issues/850)) ([ad373ab](https://github.com/ghiscoding/slickgrid-universal/commit/ad373abd84468367d43bf4fa0feccb99ae22821c)) - by @ghiscoding ## [2.1.3](https://github.com/ghiscoding/slickgrid-universal/compare/v2.1.2...v2.1.3) (2022-12-08) @@ -587,9 +819,13 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **common:** Date Sorting was shuffling other lines with same dates ([#831](https://github.com/ghiscoding/slickgrid-universal/issues/831)) ([db34213](https://github.com/ghiscoding/slickgrid-universal/commit/db34213bc8594ae12a6fd241f9fb6d6bfd1b8334)) - by @ghiscoding + * **common:** Resizer Service regression still resize container width ([#834](https://github.com/ghiscoding/slickgrid-universal/issues/834)) ([0db8b7e](https://github.com/ghiscoding/slickgrid-universal/commit/0db8b7ec9ecb3c7e88ee6905037da7e13064c60f)) - by @ghiscoding + * **common:** Resizer Service should only resize grid not its container ([#833](https://github.com/ghiscoding/slickgrid-universal/issues/833)) ([7d21233](https://github.com/ghiscoding/slickgrid-universal/commit/7d21233deb16a1bda99799fe54401a8b9410197a)) - by @ghiscoding + * Grid Menu filtering options should be removed when option disabled ([#837](https://github.com/ghiscoding/slickgrid-universal/issues/837)) ([9bc29d2](https://github.com/ghiscoding/slickgrid-universal/commit/9bc29d2682256605dd80475015b85879e1298381)) - by @ghiscoding + * Fix for page being cleared when using copy and paste with selectEditor ([#836](https://github.com/ghiscoding/slickgrid-universal/pull/836)) ([f1cadb33](https://github.com/ghiscoding/slickgrid-universal/commit/f1cadb33d99bcd98bc3c79221fbe55a5b1d72cfd)) - by @austinsimpson ## [2.1.2](https://github.com/ghiscoding/slickgrid-universal/compare/v2.1.1...v2.1.2) (2022-12-02) @@ -597,12 +833,19 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **addons:** do not add special columns twice (like Row Selection) ([#822](https://github.com/ghiscoding/slickgrid-universal/issues/822)) ([a80d6f8](https://github.com/ghiscoding/slickgrid-universal/commit/a80d6f8f2cae674e0a870eb9c450de991cd84837)) - by @ghiscoding + * **addons:** onGroupChanged callback should be executed with Draggable ([#826](https://github.com/ghiscoding/slickgrid-universal/issues/826)) ([35c2631](https://github.com/ghiscoding/slickgrid-universal/commit/35c2631feb00a5b2efe6903e9bfdfe5c95df318e)) - by @ghiscoding + * all querySelector should be specific to a grid UID ([#823](https://github.com/ghiscoding/slickgrid-universal/issues/823)) ([bc2b65c](https://github.com/ghiscoding/slickgrid-universal/commit/bc2b65c676762d21ef45e7b76caf900708c1422f)) - by @ghiscoding + * **common:** remove unused console log ([593928a](https://github.com/ghiscoding/slickgrid-universal/commit/593928af8a7e92ecf2a8c67e4cff4c8e5da58468)) - by @ghiscoding + * **core:** grid service `resetGrid` method wasn't always resetting ([57de9c8](https://github.com/ghiscoding/slickgrid-universal/commit/57de9c85b33d78fcdfbe843ae2067ddcbe430f54)) - by @ghiscoding + * **core:** grid service `resetGrid` method wasn't always resetting ([#829](https://github.com/ghiscoding/slickgrid-universal/issues/829)) ([1ffc382](https://github.com/ghiscoding/slickgrid-universal/commit/1ffc38265006e8b6e584e6de8f6c4fe53c2e2bf8)) - by @ghiscoding + * **styling:** editor clear button should always be centered ([3e9f330](https://github.com/ghiscoding/slickgrid-universal/commit/3e9f3304dc2b02450e859af27af254fee1fbd650)) - by @ghiscoding + * **styling:** focused compound input box-shadow css ([2c50c47](https://github.com/ghiscoding/slickgrid-universal/commit/2c50c47a76556ae4a6f842c483800d5af90637fc)) - by @ghiscoding ## [2.1.1](https://github.com/ghiscoding/slickgrid-universal/compare/v2.1.0...v2.1.1) (2022-11-19) @@ -610,6 +853,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **plugin:** do not show drag group sort when column is not sortable ([#819](https://github.com/ghiscoding/slickgrid-universal/issues/819)) ([049303b](https://github.com/ghiscoding/slickgrid-universal/commit/049303b0f6d085e7d022a2c87572c9ac90082b3e)) - by @ghiscoding + * **plugins:** rollback PR [#781](https://github.com/ghiscoding/slickgrid-universal/issues/781) to fix regression with Grid Presets ([#820](https://github.com/ghiscoding/slickgrid-universal/issues/820)) ([60e4a29](https://github.com/ghiscoding/slickgrid-universal/commit/60e4a299a2cbdee947b36dbfbb690f22156f8693)) - by @ghiscoding # [2.1.0](https://github.com/ghiscoding/slickgrid-universal/compare/v2.0.0...v2.1.0) (2022-11-17) @@ -617,42 +861,65 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **build:** upgrading to TypeScript 4.9 brought new build issue ([#816](https://github.com/ghiscoding/slickgrid-universal/issues/816)) ([4d46d8a](https://github.com/ghiscoding/slickgrid-universal/commit/4d46d8ab251bd78671140f82cb143b973e5422b3)) - by @ghiscoding + * **common:** changing Slider value(s) should update Tooltip instantly ([#800](https://github.com/ghiscoding/slickgrid-universal/issues/800)) ([9c6be27](https://github.com/ghiscoding/slickgrid-universal/commit/9c6be271a956876edaa03be7bf4bda9821840910)) - by @ghiscoding + * **common:** Slider Range should update both number addons ([#803](https://github.com/ghiscoding/slickgrid-universal/issues/803)) ([3cfd84e](https://github.com/ghiscoding/slickgrid-universal/commit/3cfd84e7ec4e45cf6a4896dc6143da1fecb0402c)) - by @ghiscoding + * **deps:** update dependency autocompleter to v7 ([#804](https://github.com/ghiscoding/slickgrid-universal/issues/804)) ([c298646](https://github.com/ghiscoding/slickgrid-universal/commit/c298646fca64059ca3a59a370f870ad4b3a573da)) - by @renovate-bot + * **deps:** update dependency dompurify to ^2.4.1 ([#806](https://github.com/ghiscoding/slickgrid-universal/issues/806)) ([a33d8fb](https://github.com/ghiscoding/slickgrid-universal/commit/a33d8fbf3e48bfa29b9173f9263620e61608fffb)) - by @renovate-bot + * **editors:** disable browser autofill on the Editors.autocompleter ([#776](https://github.com/ghiscoding/slickgrid-universal/issues/776)) ([fd2cf53](https://github.com/ghiscoding/slickgrid-universal/commit/fd2cf535c0bd941203951c665bb3da00f4a4677e)) - by @ghiscoding + * **editors:** Slider editor track not showing after Slider filter change ([#792](https://github.com/ghiscoding/slickgrid-universal/issues/792)) ([2ad02d2](https://github.com/ghiscoding/slickgrid-universal/commit/2ad02d22cfbb2187df62f0ec19b26f828fec57a6)) - by @ghiscoding + * **filters:** changing Slider value should update tooltip value ([#788](https://github.com/ghiscoding/slickgrid-universal/issues/788)) ([509a31d](https://github.com/ghiscoding/slickgrid-universal/commit/509a31d5630689c6c91cc2cef4e87b8dea72a243)) - by @ghiscoding + * **filters:** Slider default operator should be greater or equal (>=) ([#793](https://github.com/ghiscoding/slickgrid-universal/issues/793)) ([b895864](https://github.com/ghiscoding/slickgrid-universal/commit/b895864bc39a415622ac9f2a4b79565aa3d89179)) - by @ghiscoding + * **styling:** new Slider not flexed correctly ([#799](https://github.com/ghiscoding/slickgrid-universal/issues/799)) ([83a86d0](https://github.com/ghiscoding/slickgrid-universal/commit/83a86d0575a47ed3a11ede31af2a8a3a8186fb9d)) - by @ghiscoding + * **toolip:** left & right align were inverted ([#797](https://github.com/ghiscoding/slickgrid-universal/issues/797)) ([91c4a5c](https://github.com/ghiscoding/slickgrid-universal/commit/91c4a5c61a4f78478929f2be41a17e3e2d210a30)) - by @ghiscoding ### Features * **addon:** add group by sorting to SlickDraggableGrouping ([#814](https://github.com/ghiscoding/slickgrid-universal/issues/814)) ([962a756](https://github.com/ghiscoding/slickgrid-universal/commit/962a756fb17476221867c977752e28bd1d74f6db)) - by @ghiscoding + * **common:** add "targetSelector" to onFilterChanged & Grid State ([#813](https://github.com/ghiscoding/slickgrid-universal/issues/813)) ([a25791a](https://github.com/ghiscoding/slickgrid-universal/commit/a25791a5d11b73fd88d80ef8a6f788b27d7390ec)) - by @ghiscoding + * **common:** use editorOptions/filterOptions instead of params ([#798](https://github.com/ghiscoding/slickgrid-universal/issues/798)) ([a3c8b6e](https://github.com/ghiscoding/slickgrid-universal/commit/a3c8b6e48dbe3db7eb154837f15ce10780923b32)) - by @ghiscoding + * **core:** expose EventPubSub Service on SlickerGridInstance ([#780](https://github.com/ghiscoding/slickgrid-universal/issues/780)) ([8ad54b5](https://github.com/ghiscoding/slickgrid-universal/commit/8ad54b5739772eb8d96d23e1be04ebb426dfa596)) - by @ghiscoding + * **filters:** add "target" prop to `onBeforeSearchChange` ([#796](https://github.com/ghiscoding/slickgrid-universal/issues/796)) ([c4606fd](https://github.com/ghiscoding/slickgrid-universal/commit/c4606fde3cf206f81ab5f83d150cf3ce29cbfe75)) - by @ghiscoding + * **filters:** add back Slider Range filter in pure JS ([#784](https://github.com/ghiscoding/slickgrid-universal/issues/784)) ([b84525c](https://github.com/ghiscoding/slickgrid-universal/commit/b84525c3c087582854e30b386a1015f6ce3156b4)) - by @ghiscoding + * **filters:** add grid option `skipCompoundOperatorFilterWithNullInput` ([#794](https://github.com/ghiscoding/slickgrid-universal/issues/794)) ([617c88d](https://github.com/ghiscoding/slickgrid-universal/commit/617c88d7432c35b8ac0c0f40066a2f55a58b6d35)) - by @ghiscoding + * **filters:** add Slider filter track filled track color ([#795](https://github.com/ghiscoding/slickgrid-universal/issues/795)) ([5fbd9c9](https://github.com/ghiscoding/slickgrid-universal/commit/5fbd9c9036844e7e88a99fea6a4d1e1f0fd2377a)) - by @ghiscoding + * **plugins:** sync column definitions to user after plugin adds column ([#781](https://github.com/ghiscoding/slickgrid-universal/issues/781)) ([0755b65](https://github.com/ghiscoding/slickgrid-universal/commit/0755b655b7be5911345334e094544a14c3698b51)) - by @ghiscoding + * **tooltip:** add a new "center" position option to SlickCustomTooltip ([#787](https://github.com/ghiscoding/slickgrid-universal/issues/787)) ([b019de5](https://github.com/ghiscoding/slickgrid-universal/commit/b019de50244836a984314ea6e6f5cee639551438)) - by @ghiscoding ### Performance Improvements * **filters:** merge all date range & compound filters into one class ([#812](https://github.com/ghiscoding/slickgrid-universal/issues/812)) ([ca9adfa](https://github.com/ghiscoding/slickgrid-universal/commit/ca9adfae84ca8fd57b61548b1222ade5a8b9c498)) - by @ghiscoding + * **filters:** merge all input & compound filters into one class ([#809](https://github.com/ghiscoding/slickgrid-universal/issues/809)) ([6d08f4d](https://github.com/ghiscoding/slickgrid-universal/commit/6d08f4dc9fc471b316f375d77fa8ae1805dc9b83)) - by @ghiscoding + * **filters:** merge all Slider filters into one class ([#791](https://github.com/ghiscoding/slickgrid-universal/issues/791)) ([fc4304b](https://github.com/ghiscoding/slickgrid-universal/commit/fc4304b3dd47ac10df65f5b8dda9d8ce5aad8ed9)) - by @ghiscoding # [2.0.0](https://github.com/ghiscoding/slickgrid-universal/compare/v1.4.0...v2.0.0) (2022-10-17) ⚠️ Breaking Change - Follow the [Migration 2.x Guide](https://github.com/ghiscoding/slickgrid-universal/wiki/Migration-to-2.x) + ### Bug Fixes * **deps:** update all non-major dependencies ([#769](https://github.com/ghiscoding/slickgrid-universal/issues/769)) ([4e05a4b](https://github.com/ghiscoding/slickgrid-universal/commit/4e05a4b977c760511fc90903c0f62673859bd65f)) - by @renovate-bot + * **styling:** fix some styling issues with input groups and Firefox ([#750](https://github.com/ghiscoding/slickgrid-universal/issues/750)) ([1aa849e](https://github.com/ghiscoding/slickgrid-universal/commit/1aa849ea81461dc9bbd7b3bc05a092bb14c88be2)) - by @ghiscoding ### Features @@ -664,12 +931,15 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **deps:** update all non-major dependencies ([#769](https://github.com/ghiscoding/slickgrid-universal/issues/769)) ([4e05a4b](https://github.com/ghiscoding/slickgrid-universal/commit/4e05a4b977c760511fc90903c0f62673859bd65f)) - by @renovate-bot + * **styling:** fix some styling issues with input groups and Firefox ([#750](https://github.com/ghiscoding/slickgrid-universal/issues/750)) ([1aa849e](https://github.com/ghiscoding/slickgrid-universal/commit/1aa849ea81461dc9bbd7b3bc05a092bb14c88be2)) - by @ghiscoding ## ⚠️ Breaking Change + ### - Features * **common:** replace jQueryUI Autocomplete with Kradeen Autocomplete ([#752](https://github.com/ghiscoding/slickgrid-universal/issues/752)) ([991d29c](https://github.com/ghiscoding/slickgrid-universal/commit/991d29c4c8c85d800d69c4ba16d608d7a20d2a90)) - by @ghiscoding + * **common:** remove & replace jQueryUI with SortableJS in common & SlickDraggableGrouping ([#756](https://github.com/ghiscoding/slickgrid-universal/issues/756)) ([b1c5a84](https://github.com/ghiscoding/slickgrid-universal/commit/b1c5a84bb9a10ff805dfd13996ecf60dae3ab609)) - by @ghiscoding # [1.4.0](https://github.com/ghiscoding/slickgrid-universal/compare/v1.3.7...v1.4.0) (2022-08-15) @@ -677,16 +947,23 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **bundle:** fetch API isn't always an instance of Response ([#744](https://github.com/ghiscoding/slickgrid-universal/issues/744)) ([72a6f24](https://github.com/ghiscoding/slickgrid-universal/commit/72a6f2489a88974c8f5faf0041184ac78d6c7caa)) - by @ghiscoding + * **collectionAsync:** hidden column does not load edit field selection ([#742](https://github.com/ghiscoding/slickgrid-universal/issues/742)) ([763c61c](https://github.com/ghiscoding/slickgrid-universal/commit/763c61cfa7e82dd82b88f22db3eb47dc274a5eb3)) - by @mcallegario + * **common:** duplicate translation namespace prefix, fixes [#738](https://github.com/ghiscoding/slickgrid-universal/issues/738) ([#739](https://github.com/ghiscoding/slickgrid-universal/issues/739)) ([ed6b0cc](https://github.com/ghiscoding/slickgrid-universal/commit/ed6b0cc4f664e27830357ac45d523d0571c94bce)) - by @someusersomeuser + * **demo:** edit outline should follow on filter/pagination changed ([3e9a6c7](https://github.com/ghiscoding/slickgrid-universal/commit/3e9a6c7538af5e714cc20ec5926f343912e63b20)) - by @ghiscoding + * **deps:** update all non-major dependencies ([#740](https://github.com/ghiscoding/slickgrid-universal/issues/740)) ([c8acb65](https://github.com/ghiscoding/slickgrid-universal/commit/c8acb6542a768b2a2b4e0ea0e1f71533d7077927)) - by @renovate-bot + * **filters:** fetch API isn't always an instance of Response ([#746](https://github.com/ghiscoding/slickgrid-universal/issues/746)) ([11be5c2](https://github.com/ghiscoding/slickgrid-universal/commit/11be5c2f9554c8fad2b984864ec7180698d02d19)), closes [#744](https://github.com/ghiscoding/slickgrid-universal/issues/744) - by @ghiscoding + * **utils:** the `isObject` method was not always correct ([#745](https://github.com/ghiscoding/slickgrid-universal/issues/745)) ([9b09e4a](https://github.com/ghiscoding/slickgrid-universal/commit/9b09e4aa2ca102100a113d4e2996f80c75aa6c2f)) - by @ghiscoding ### Features * **common:** remove jquery-ui-dist from deps, use jquery-ui only ([#733](https://github.com/ghiscoding/slickgrid-universal/issues/733)) ([b89d1f1](https://github.com/ghiscoding/slickgrid-universal/commit/b89d1f169bfde21d8a46520aed580c12db5f668f)) - by @ghiscoding + * **common:** update title prop on change event for Slider Filter/Editor ([#743](https://github.com/ghiscoding/slickgrid-universal/issues/743)) ([0ca6f3f](https://github.com/ghiscoding/slickgrid-universal/commit/0ca6f3f4d8894d4bb9459cabca9a3492e7cca0ad)) - by @ghiscoding ## [1.3.7](https://github.com/ghiscoding/slickgrid-universal/compare/v1.3.6...v1.3.7) (2022-08-02) @@ -694,6 +971,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **service:** should be able to update dataview item not shown in grid ([#730](https://github.com/ghiscoding/slickgrid-universal/issues/730)) ([dc88c87](https://github.com/ghiscoding/slickgrid-universal/commit/dc88c870e046e904b160546239ab2d403237d98a)) - by @ghiscoding + * **uilts:** able to use setDeepValue on undefined/empty object ([#732](https://github.com/ghiscoding/slickgrid-universal/issues/732)) ([e370eef](https://github.com/ghiscoding/slickgrid-universal/commit/e370eef758a7e5fe20e87729bc407ca2bdd55504)) - by @ghiscoding ## [1.3.6](https://github.com/ghiscoding/slickgrid-universal/compare/v1.3.5...v1.3.6) (2022-07-28) @@ -713,6 +991,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **deps:** update dependency jquery-ui to ^1.13.2 ([#720](https://github.com/ghiscoding/slickgrid-universal/issues/720)) ([8351f14](https://github.com/ghiscoding/slickgrid-universal/commit/8351f144192ec5e91ad52678787a448cf42f975f)) - by @renovate-bot + * **utils:** setDeepValue should accept array properties ([#728](https://github.com/ghiscoding/slickgrid-universal/issues/728)) ([0dedeba](https://github.com/ghiscoding/slickgrid-universal/commit/0dedeba76ac817f73320778e63c1987a1708360e)), closes [SO](https://github.com//stackoverflow.com/questions/62423893/in-slick-grid-inline-edit-i-cant-able-to-get-the-entire-object/73153946/issues/73153946) - by @ghiscoding ## [1.3.3](https://github.com/ghiscoding/slickgrid-universal/compare/v1.3.2...v1.3.3) (2022-07-07) @@ -726,6 +1005,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **composite:** selected row count always 0 on mass-selected ([#712](https://github.com/ghiscoding/slickgrid-universal/issues/712)) ([ec42dc7](https://github.com/ghiscoding/slickgrid-universal/commit/ec42dc753fbf8c84040e252f328e51ea4a98cedf)) + * **deps:** update all non-major dependencies ([230291c](https://github.com/ghiscoding/slickgrid-universal/commit/230291c94506fdd12e7f843a3d7f324922ef97f6)) # [1.3.0](https://github.com/ghiscoding/slickgrid-universal/compare/v1.2.6...v1.3.0) (2022-06-18) @@ -733,9 +1013,13 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **deps:** add missing depency in vanilla bundle package ([fa08fe6](https://github.com/ghiscoding/slickgrid-universal/commit/fa08fe6f097461c2bf8029307e59631738b1654b)) + * **deps:** add missing dependencies in child package ([97d0230](https://github.com/ghiscoding/slickgrid-universal/commit/97d02306899e583779c3b6d5b219b2798a5f9cfd)) + * **deps:** update all non-major dependencies ([5097cea](https://github.com/ghiscoding/slickgrid-universal/commit/5097ceae88c0ea212e0aa6ea2a5b1020368f3216)) + * **deps:** update yarn lock file ([0bd337f](https://github.com/ghiscoding/slickgrid-universal/commit/0bd337ffcae800ae91670b886ebfd1ef155c80c1)) + * **deps:** use chore dependency package name ([2fce29c](https://github.com/ghiscoding/slickgrid-universal/commit/2fce29c5e64f160203529b5bf9435562cf5f5941)) ### Features @@ -765,9 +1049,13 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** deleting Slicker object caused issue with cache ([3f3e261](https://github.com/ghiscoding/slickgrid-universal/commit/3f3e261c1855e7eb695e00a105b7c797462ed298)), closes [#606](https://github.com/ghiscoding/slickgrid-universal/issues/606) + * **editors:** select editor should call save only once ([d111c2f](https://github.com/ghiscoding/slickgrid-universal/commit/d111c2f7799151236c6053d7a5288d1fdd530550)) + * **resizer:** use default resize when resizeByContent has no data ([8499b61](https://github.com/ghiscoding/slickgrid-universal/commit/8499b61b5cc6365af0035d254a9487c79b74bd7f)) + * **selections:** selected rows doesn't update when hidden column shown ([0d1cf29](https://github.com/ghiscoding/slickgrid-universal/commit/0d1cf294e8ae944672a9c9a2cece1de553c2f973)), closes [#661](https://github.com/ghiscoding/slickgrid-universal/issues/661) + * **styling:** add pointer cursor on ms-filter, avoid Bootstrap override ([11e1e12](https://github.com/ghiscoding/slickgrid-universal/commit/11e1e12115896e73096e10b34575e4e8ebe5b819)) ## [1.2.1](https://github.com/ghiscoding/slickgrid-universal/compare/v1.2.0...v1.2.1) (2022-01-18) @@ -775,7 +1063,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **memory:** clear & dispose of grid to avoid mem leaks & detached elm ([7035db5](https://github.com/ghiscoding/slickgrid-universal/commit/7035db5f878187f6fb8b9d2effacb7443f25e2c9)) + * **odata:** fix range filtering with ".." ([b07af88](https://github.com/ghiscoding/slickgrid-universal/commit/b07af88c6d2912f58e976a428927e63c9fdffbad)) + * **odata:** fix range filtering with ".." ([d14d3e9](https://github.com/ghiscoding/slickgrid-universal/commit/d14d3e9f92fad2c14a7227b8f822dffc79c8934c)) # [1.2.0](https://github.com/ghiscoding/slickgrid-universal/compare/v1.1.1...v1.2.0) (2022-01-06) @@ -783,35 +1073,61 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **build:** optimize dev watch ([ab7d405](https://github.com/ghiscoding/slickgrid-universal/commit/ab7d405ecffc047e9bd4289dd796899c94c0db62)) + * **demo:** latest change with Filter container breaks other demos ([129cc78](https://github.com/ghiscoding/slickgrid-universal/commit/129cc78ac34ad632f2a265d49a631e04b119250b)) + * **dev:** optimize webpack dev watch ([1340c51](https://github.com/ghiscoding/slickgrid-universal/commit/1340c51b7e2554e9c29ebb9b8ab9b27a3f20cfe9)) + * **filter:** add the "filled" class for styling purposes ([ea7974a](https://github.com/ghiscoding/slickgrid-universal/commit/ea7974a9a7d54150c16d22ccb8008c692faf6132)) + * **filter:** add the "filled" class for styling purposes - better code ([4a650cd](https://github.com/ghiscoding/slickgrid-universal/commit/4a650cd269852ab20088b274939e89b2cfc96ec8)) + * **filter:** add the "filled" class for styling purposes - ajust code format ([abe481e](https://github.com/ghiscoding/slickgrid-universal/commit/abe481e0cd11bfe204399814c1be0eeb66d3f91a)) + * **filter:** add the "filled" class for styling purposes - ajust format ([fc8c899](https://github.com/ghiscoding/slickgrid-universal/commit/fc8c8992381b001d6ada449352d7b66c6ca08e00)) + * **filter:** update multiple-select to fix select filtering ([63dcd08](https://github.com/ghiscoding/slickgrid-universal/commit/63dcd0873026fb8ba036ca52ba31f583d6ad136f)), closes [#865](https://github.com/ghiscoding/slickgrid-universal/issues/865) + * **plugins:** Draggable Grouping Toggle All should follow `collapsed` ([7fedfa1](https://github.com/ghiscoding/slickgrid-universal/commit/7fedfa1129e12a3bf665efe0bd9160b6a7a1b6a9)) + * **services:** unsubscribe shouldn't remove when poping out of array ([e841da9](https://github.com/ghiscoding/slickgrid-universal/commit/e841da9df7a23bf7b789e4a13803488ab479ff15)) ### Features * **binding:** make Binding Service a little smarter ([98a7661](https://github.com/ghiscoding/slickgrid-universal/commit/98a766173638246b6a17e31812929a9bba1eb52b)) + * **composite:** add new `validateMassUpdateChange` callback & bug fixes ([#603](https://github.com/ghiscoding/slickgrid-universal/issues/603)) ([2c1559b](https://github.com/ghiscoding/slickgrid-universal/commit/2c1559b7a3b0b1a642a664e59a025ce78a747946)) + * **demo:** add new Example to demo Real-time Market Trading ([e50434a](https://github.com/ghiscoding/slickgrid-universal/commit/e50434ac3dab98644e23266c81d09b3789ea7de4)) + * **filters:** change-filter-element-Container ([31c6e54](https://github.com/ghiscoding/slickgrid-universal/commit/31c6e54a3b2e0d135d8407c74b7bfa329a85e0c5)) + * **filters:** change-filter-element-Container ([d455d27](https://github.com/ghiscoding/slickgrid-universal/commit/d455d2781f19fc9865600b6123f679ab3526cf04)) + * **filters:** change-filter-element-Container ([704c52a](https://github.com/ghiscoding/slickgrid-universal/commit/704c52a1d5dec9fedbe837ceca41b96a0d673061)) + * **filters:** change-filter-element-Container-ajust-code-format ([efb0189](https://github.com/ghiscoding/slickgrid-universal/commit/efb0189b0ce357b07025e2f9f29717a41128ab6b)) + * **filters:** change-filter-element-Container-ajust-test ([268ccb4](https://github.com/ghiscoding/slickgrid-universal/commit/268ccb4d6be916959f2eadd87d7c506dff1df472)) + * **filters:** change-filter-element-Container-data-test ([78c3ec7](https://github.com/ghiscoding/slickgrid-universal/commit/78c3ec757a71388eafd0b90e6c48d86f85b0e9db)) + * **filters:** change-filter-element-Container-Example ([369c6ef](https://github.com/ghiscoding/slickgrid-universal/commit/369c6ef27e639147a755fb1289abcb2eed307153)) + * **filters:** change-filter-element-Container-test ([61e29c5](https://github.com/ghiscoding/slickgrid-universal/commit/61e29c5851487f7470e6f631c890c346f07ed242)) + * **filters:** filter-element-Container- DOMPurify ([3749fc4](https://github.com/ghiscoding/slickgrid-universal/commit/3749fc48387412abefe69414db6060d947a704b5)) + * **filters:** inclusion of the modal filter in example 7 ([1ac2da9](https://github.com/ghiscoding/slickgrid-universal/commit/1ac2da9da5540a5653ac72b825ad6624b331aa8f)) + * **filters:** modal-filter-example ([ab46202](https://github.com/ghiscoding/slickgrid-universal/commit/ab46202bfbd99497af39830cf59068682f5f8bd1)) + * **plugins:** Apply auto scroll when dragging on RowMoveManager plugin ([1c14a4f](https://github.com/ghiscoding/slickgrid-universal/commit/1c14a4fd06693425be52e91f405d1c8739699627)), closes [#662](https://github.com/ghiscoding/slickgrid-universal/issues/662) + * **selection:** auto-scroll the viewport when dragging with selection ([ecd9c57](https://github.com/ghiscoding/slickgrid-universal/commit/ecd9c57bd6c1315e2358722785a87582ec939f85)), closes [#656](https://github.com/ghiscoding/slickgrid-universal/issues/656) + * **services:** add `skipError` to CRUD methods in Grid Service ([869ed87](https://github.com/ghiscoding/slickgrid-universal/commit/869ed87bfa4e60d089138bcba1da5f4bb120e73b)) + * **services:** add extra features to EventPubSub Service ([9bd02b5](https://github.com/ghiscoding/slickgrid-universal/commit/9bd02b5d92bcf6aaf89a828c4e6496a24e795c53)) ## [1.1.1](https://github.com/ghiscoding/slickgrid-universal/compare/v1.1.0...v1.1.1) (2021-12-11) @@ -825,53 +1141,97 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **build:** add DOM purify optional default import to fix rollup builds ([73bc3c0](https://github.com/ghiscoding/slickgrid-universal/commit/73bc3c0756cf6d28b292f0162afffc06412a126e)) + * **build:** DOMPurify import fix for all framework ([c551d0c](https://github.com/ghiscoding/slickgrid-universal/commit/c551d0c64d4c7325578acf4feb5d22132c7d7f91)) + * **comp:** replace `prepend` not supported in IE/Salesforce ([b210f9d](https://github.com/ghiscoding/slickgrid-universal/commit/b210f9d6a7e13f7ca69330955b674b9786dd29bb)) + * **comp:** replace `prepend` not supported in IE/Salesforce ([13bd9a4](https://github.com/ghiscoding/slickgrid-universal/commit/13bd9a4f8c4fdaedccc65db7100527be0e84eb00)) + * **context:** remove fixed width on ContextMenu use auto instead ([403679b](https://github.com/ghiscoding/slickgrid-universal/commit/403679be5ca8547b53ed2525a4017923302afae7)) + * **context:** strip hidden special chars on context menu Copy command ([5d81644](https://github.com/ghiscoding/slickgrid-universal/commit/5d81644a194b66e7fb5efc550a08962d8087f0e3)) + * **context:** strip hidden special chars on context menu Copy command ([f94ca83](https://github.com/ghiscoding/slickgrid-universal/commit/f94ca834b1fdee94e4e44bdc3d245956a4437de6)) + * **docs:** fix a typo in readme to force push a release ([00eba2e](https://github.com/ghiscoding/slickgrid-universal/commit/00eba2ec3f14492b822082ccfc1724450a25b9c7)) + * **filters:** remove Filters from DOM after header row gets destroyed ([3f08162](https://github.com/ghiscoding/slickgrid-universal/commit/3f08162cd8b5fbb407c77b6dc441e60239ba5788)) + * **locales:** add missing text & remove global config texts fix Locales ([655a872](https://github.com/ghiscoding/slickgrid-universal/commit/655a872d7160ab53530f8e2fdc575817af782b5d)) + * **plugin:** Copy command from Context Menu should work with numbers ([9d36491](https://github.com/ghiscoding/slickgrid-universal/commit/9d36491c407beb0fdc53588ffc6264306fab607a)) + * **plugin:** providing usability override via grid option should work ([6446a10](https://github.com/ghiscoding/slickgrid-universal/commit/6446a1061d7d0126cfe655518b7179d93356aa83)), closes [#555](https://github.com/ghiscoding/slickgrid-universal/issues/555) + * **plugins:** remove invalid export for build to work ([9353022](https://github.com/ghiscoding/slickgrid-universal/commit/9353022593ba9b16e34a8b3dd3ad62bc5b5e7569)) + * **styling:** better support of auto width on drop menu ([8a48dd2](https://github.com/ghiscoding/slickgrid-universal/commit/8a48dd2a224c757534a631e88a4864e151496438)) + * **styling:** Grid Menu Title not aligned correctly with Bootstrap ([e2b991f](https://github.com/ghiscoding/slickgrid-universal/commit/e2b991fb05b8ca94e5a0e3986aabaefc7bc245fb)) + * **styling:** slightly off Autocomplete position ([cd03f67](https://github.com/ghiscoding/slickgrid-universal/commit/cd03f67f50db301cfe74a1e20efd998102bcf3bf)) + * **styling:** tweak & fix all styling with Salesforce & other frameworks ([86dbb76](https://github.com/ghiscoding/slickgrid-universal/commit/86dbb76b439a99773a3fe6fd154440eacb20d510)) + * **tree:** reset to initial tree sort when calling "Clear all Sorting" ([8bd3f4f](https://github.com/ghiscoding/slickgrid-universal/commit/8bd3f4f68247681f8eb57e7aabd59b636face7e7)) + * **treeGrid:** Bug in onCellClick event ([42155af](https://github.com/ghiscoding/slickgrid-universal/commit/42155af12b0808fc95d5f1c00fcec9bfaef64c44)) + * apply fixes & refactoring after testing in Aurelia-Slickgrid ([038fa3f](https://github.com/ghiscoding/slickgrid-universal/commit/038fa3f56f202465f2b40af57e8acf752fe31f60)) + * switch normal/frozen should always show Grid Menu on far right ([6bef090](https://github.com/ghiscoding/slickgrid-universal/commit/6bef0901652a2bdbf661cf5a0fc0d9a7c325a44a)) + * translation wasn't working with context menu ([889e443](https://github.com/ghiscoding/slickgrid-universal/commit/889e44387279c7834944600417c0c2da11b7991f)) ### Features * **build:** create `salesforce-vanilla-bundle` standalone package ([214d8e7](https://github.com/ghiscoding/slickgrid-universal/commit/214d8e77646d3fdac278cf18227c96f346c94522)) + * **controls:** add `minHeight` option to ColumnPicker/GridMenu ([cfcfc85](https://github.com/ghiscoding/slickgrid-universal/commit/cfcfc8588b854530425f2bea19e8aa7c5256d059)) + * **controls:** convert and add ColumnPicker into Slickgrid-Universal ([1f937b9](https://github.com/ghiscoding/slickgrid-universal/commit/1f937b9a3abe43cf1a2bb1f52ba625c34431e328)) + * **controls:** move external Grid Menu into Slickgrid-Universal ([40adff4](https://github.com/ghiscoding/slickgrid-universal/commit/40adff49c2a74769823dfbed3d32b239608e2a59)) + * **core:** add TS utility to infer extension instance by name ([3f4f65f](https://github.com/ghiscoding/slickgrid-universal/commit/3f4f65fb1c4f01cddca0e356a0a770b575a7384a)) + * **plugins:** add all Cell Range/Selection plugins into Universal ([3b4ddca](https://github.com/ghiscoding/slickgrid-universal/commit/3b4ddcaff6e2e8db5804b995ff2282f306cc1a7a)) + * **plugins:** add extra callback methods to checkbox selector ([#570](https://github.com/ghiscoding/slickgrid-universal/issues/570)) ([a9245f9](https://github.com/ghiscoding/slickgrid-universal/commit/a9245f920397bab0ef5105404babe8443654785c)) + * **plugins:** add Row Detail plugin final code & tests ([045ea6d](https://github.com/ghiscoding/slickgrid-universal/commit/045ea6d0e49e55163edcbe1ec6e796f51349667b)) + * **plugins:** make it possible to use both Header Button/Menu together ([965bd58](https://github.com/ghiscoding/slickgrid-universal/commit/965bd588aeba7528031f309020bdfd3c611ebeab)) + * **plugins:** move Checkbox and Row Selection plugins to universal ([06f0ab1](https://github.com/ghiscoding/slickgrid-universal/commit/06f0ab155a2f0ee06681d3e94780397c5e4f9f67)) + * **plugins:** move external Cell Menu into Slickgrid-Universal ([6f34c10](https://github.com/ghiscoding/slickgrid-universal/commit/6f34c10b9a8522ae430e13c9519083451bf71ebf)) + * **plugins:** move external cell related plugins to universal ([11e15d8](https://github.com/ghiscoding/slickgrid-universal/commit/11e15d88360b7b30ca7ab94624a7928201f15945)) + * **plugins:** move external Context Menu into Slickgrid-Universal ([2170bb4](https://github.com/ghiscoding/slickgrid-universal/commit/2170bb4e3f02ef6f45ad13a1c59730047942651e)) + * **plugins:** move external Draggable Grouping into Slickgrid-Universal ([8e6eb48](https://github.com/ghiscoding/slickgrid-universal/commit/8e6eb4881741313b7d582d2e3d17ffef582ecb35)) + * **plugins:** move external GroupItemMetataProvider into Universal ([8f18c7d](https://github.com/ghiscoding/slickgrid-universal/commit/8f18c7d3d616e4cd72eb5478d544ec241c53154f)) + * **plugins:** move external Header Button into Slickgrid-Universal ([69711ad](https://github.com/ghiscoding/slickgrid-universal/commit/69711aded5aa835091789800214f82cd7c72753e)) + * **plugins:** move external Header Menu into Slickgrid-Universal ([aeba480](https://github.com/ghiscoding/slickgrid-universal/commit/aeba4801fdb5cba3976984f5c591be8c1ad97e4b)) + * **plugins:** move Row Detail View plugin to universal ([9700ff4](https://github.com/ghiscoding/slickgrid-universal/commit/9700ff49132e9408b808f916f634976d80e12579)) + * **plugins:** move Row Detail View plugin to universal ([fb327a6](https://github.com/ghiscoding/slickgrid-universal/commit/fb327a6abe85b86683572cde2a550de43a01f9e1)) + * **plugins:** move Row Move Manager plugin to universal ([b19b2ed](https://github.com/ghiscoding/slickgrid-universal/commit/b19b2ed2da669662fbbdcf9fdefac243132909b2)) + * **plugins:** replace AutoTooltips Extension by plugin ([80df14d](https://github.com/ghiscoding/slickgrid-universal/commit/80df14da9b66e9e1b8314e5adb1b96890cc7baa1)) + * **plugins:** show bullet when command menu icon missing ([cbe580a](https://github.com/ghiscoding/slickgrid-universal/commit/cbe580a97313b7b90e287586b4a6420f0a983f20)) + * **selection:** add `caller` property to `onSelectedRowsChanged` event ([cc5f4ae](https://github.com/ghiscoding/slickgrid-universal/commit/cc5f4aec7334b6d001bde55dacf83722c3b2763b)) + * **utils:** replace ext lib `assign-deep` by local `deepMerge` util ([2f56bd3](https://github.com/ghiscoding/slickgrid-universal/commit/2f56bd3571d9c5fb689a09d21cfb3813f5b70e89)) ## [0.19.2](https://github.com/ghiscoding/slickgrid-universal/compare/v0.19.1...v0.19.2) (2021-11-19) @@ -879,8 +1239,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **build:** add DOM purify optional default import to fix rollup builds ([3bd335d](https://github.com/ghiscoding/slickgrid-universal/commit/3bd335dd62d0829c1581ca0fde560c93dcd84458)) + * **resizer:** use autosize width when total width smaller than viewport ([555fb0c](https://github.com/ghiscoding/slickgrid-universal/commit/555fb0cb793c111de837ffe6e9f212fcbf5ed701)) + * **translation:** add new UNFREEZE_COLUMNS to fix translation ([0010861](https://github.com/ghiscoding/slickgrid-universal/commit/001086165434f619f1e90f664e2185b77fb6a92e)) + * **translation:** add new UNFREEZE_COLUMNS to fix translation ([22ed231](https://github.com/ghiscoding/slickgrid-universal/commit/22ed2313c45587f2ebdb279c9e47df881c6f83d6)) ## [0.19.1](https://github.com/ghiscoding/slickgrid-universal/compare/v0.19.0...v0.19.1) (2021-11-15) @@ -888,10 +1251,15 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **build:** typo on script package name to rename ([76cee09](https://github.com/ghiscoding/slickgrid-universal/commit/76cee094f4ef771ebfdb79386c3e8577f89d397e)) + * **context:** strin hidden special chars on context menu Copy command ([221c05d](https://github.com/ghiscoding/slickgrid-universal/commit/221c05d8d6345d090074c92e423071888e4a2686)) + * **context:** when copying use opacity 0 on temp element ([3f0896f](https://github.com/ghiscoding/slickgrid-universal/commit/3f0896fab30aa5a3da278912f00272ce434b8c15)) + * **export:** sanitize any html that could exist in header titles ([abdae52](https://github.com/ghiscoding/slickgrid-universal/commit/abdae52822c4496286a653ed84be964213e1d32f)) + * **subscriptions:** unsubscribe every subcriptions while disposing comp ([bf0dcd4](https://github.com/ghiscoding/slickgrid-universal/commit/bf0dcd4963171b703f07e705aac7230402c84dbf)) + * **tree:** reset to initial tree sort when calling "Clear all Sorting" ([984e3a7](https://github.com/ghiscoding/slickgrid-universal/commit/984e3a7bf0bf734f035514d32d44c6164c6fdab1)) # [0.19.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.18.0...v0.19.0) (2021-10-28) @@ -899,14 +1267,19 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **frozen:** calling `setPinning` with empty object/null should clear it ([48b11f7](https://github.com/ghiscoding/slickgrid-universal/commit/48b11f74f2ce6541b6e6e03bf7fe194e5be96d0e)) + * **style:** remove unnecessary css source map ([4e6fc08](https://github.com/ghiscoding/slickgrid-universal/commit/4e6fc085abe19389d28bf7a8cea3f83859582bdc)) + * **styling:** cleanup CSS files to ship smaller bundle ([69b18bf](https://github.com/ghiscoding/slickgrid-universal/commit/69b18bf3505fc5538de878b7dbf33104faa8b11a)) + * **tree:** Grid State should have Tree Data initial sort ([b24ce40](https://github.com/ghiscoding/slickgrid-universal/commit/b24ce4032ea671aa6de6d8e2bb8b045359fd897b)) + * **tree:** use previous state when refreshing dataset afterward ([0982474](https://github.com/ghiscoding/slickgrid-universal/commit/09824741be404d3d05ccff4417f243c4b1c5c113)) ### Features * **plugin:** add row move shadown item while moving/dragging row ([c665ec8](https://github.com/ghiscoding/slickgrid-universal/commit/c665ec88be859feeea89e5ab8826f2b0a57c5cfb)) + * **plugin:** create new Custom Tooltip plugin ([4c8c4f6](https://github.com/ghiscoding/slickgrid-universal/commit/4c8c4f62423665bc2e1dcf0675b1300607397b6a)) # [0.18.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.17.0...v0.18.0) (2021-09-29) @@ -914,20 +1287,31 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **comp:** replace `prepend` not supported in IE/Salesforce ([f183115](https://github.com/ghiscoding/slickgrid-universal/commit/f183115e19b3a72d2496db778fab47be35e1aa40)) + * **context:** Copy Cell via Context Menu shouldn't include Tree symbols ([f710084](https://github.com/ghiscoding/slickgrid-universal/commit/f710084c06cd47d900daccd389de131209e19163)) + * **filters:** css "filled" class on filters should also work w/Grid View ([e8edae7](https://github.com/ghiscoding/slickgrid-universal/commit/e8edae79bcd5c28438203e269d26f107e26c4ae5)) + * **resizer:** clear pending resizeGrid on dispose ([07ed6a0](https://github.com/ghiscoding/slickgrid-universal/commit/07ed6a0390f235341b116d981aa4ee84719b029b)) + * **resizer:** only bind autoresize when enabled ([ca894c0](https://github.com/ghiscoding/slickgrid-universal/commit/ca894c0a83b5762a42b703f28fc59bdb38e01944)) + * **styling:** List bullets shouldn't show in any frameworks, fixes [#487](https://github.com/ghiscoding/slickgrid-universal/issues/487) ([53ea537](https://github.com/ghiscoding/slickgrid-universal/commit/53ea5379c6109383630362717b980a1dbe099681)) + * **tree:** when Tree Data is filtered then Sort, footer count is invalid ([4f5fc44](https://github.com/ghiscoding/slickgrid-universal/commit/4f5fc443fbc7a0ab3cbe46722fc6bd85fd4b1594)) ### Features * **context:** expose 3 events for Tree/Grouping clear/collapse/expand ([317f3ad](https://github.com/ghiscoding/slickgrid-universal/commit/317f3ad443f8ac81c7cacacaec6d38553bec147b)) + * **pagination:** rewrite in vanilla JS make it usable in any framework ([0211181](https://github.com/ghiscoding/slickgrid-universal/commit/0211181d0353f1f8d2baa0eaba3c2e85073285e7)) + * **Resizer:** add useResizeObserver option ([bb33cdd](https://github.com/ghiscoding/slickgrid-universal/commit/bb33cdd716834913846ab2fcf74a84f8424acf92)) + * **sorts:** option to ignore accent while sorting text ([1b4fe81](https://github.com/ghiscoding/slickgrid-universal/commit/1b4fe81d613b780aefcc0ba3e7b16c20eaebd0aa)) + * **styling:** increase highlight of filters that are filled w/values ([8f93534](https://github.com/ghiscoding/slickgrid-universal/commit/8f9353418190ee3e11aca65d1a57fa4204331011)) + * **tree:** new `excludeChildrenWhenFilteringTree` set as new default ([47df943](https://github.com/ghiscoding/slickgrid-universal/commit/47df943414f383a47062a7ad9245700a1bd8a24e)) # [0.17.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.16.2...v0.17.0) (2021-09-09) @@ -935,29 +1319,49 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **bundle:** don't assume slickgrid/dataview are always defined ([0505713](https://github.com/ghiscoding/slickgrid-universal/commit/050571315f0d11f1eff853b3961f3be941a99e51)) + * **composite:** calling Edit change shouldn't affect Mass-Update ([0ae2a90](https://github.com/ghiscoding/slickgrid-universal/commit/0ae2a90e2aad095f122c308e9d1343f475ad7190)) + * **core:** potential event binding leaks not all removed when disposing ([3e61712](https://github.com/ghiscoding/slickgrid-universal/commit/3e61712156f3b76b48b04d66bb05f2533f041831)) + * **filters:** IN_CONTAINS should be sanitized when used with html ([961d8fd](https://github.com/ghiscoding/slickgrid-universal/commit/961d8fd7ea6f915dd8f0749d0329219b82923fea)) + * **filters:** remove Filters from DOM after header row gets destroyed ([b08d4ba](https://github.com/ghiscoding/slickgrid-universal/commit/b08d4ba070ec9d9d131d6830e4625e6ef950ac09)) + * **footer:** use `getFilteredItemCount` to show correct count, fix [#469](https://github.com/ghiscoding/slickgrid-universal/issues/469) ([963235c](https://github.com/ghiscoding/slickgrid-universal/commit/963235c017c28309460d2cb88de88c880ac0cb4f)) + * **grouping:** Draggable Grouping should clear preheader when called ([37811a5](https://github.com/ghiscoding/slickgrid-universal/commit/37811a51d2af04e78aedc88ff5d8eae8a622ac40)) + * **resizer:** regression introduced by [#462](https://github.com/ghiscoding/slickgrid-universal/issues/462) for the grid resize in SF ([f34d8b9](https://github.com/ghiscoding/slickgrid-universal/commit/f34d8b9678c7ee9e76534a7f7ffdf2c4d7f9f772)) + * **resizer:** resizer not always triggered in SF and show broken UI ([89fc62e](https://github.com/ghiscoding/slickgrid-universal/commit/89fc62eff7fac8b5cf43b3b6acd7590ed84288f6)) + * **state:** don't use previous columns ref when getting current cols ([f312c60](https://github.com/ghiscoding/slickgrid-universal/commit/f312c60349d5bc95527ec93cb752f449d1c761f7)) + * **styling:** add ms-select placeholder bg-color to fix Bootstrap 5 ([2c34d12](https://github.com/ghiscoding/slickgrid-universal/commit/2c34d1229c14bd36bd034062cc7eb7a7cbe1bf5c)) + * **styling:** add ms-select placeholder bg-color to fix Bootstrap 5 ([5d6454e](https://github.com/ghiscoding/slickgrid-universal/commit/5d6454e9f175b8694f372a7e26492ae573eb918f)) ### Features * **aggregators:** add better TS typing for all Aggregators ([1518d6a](https://github.com/ghiscoding/slickgrid-universal/commit/1518d6aef194f184390316f8421f51d23a1d470a)) + * **backend:** add cancellable onBeforeSearchChange & revert on error ([b26a53d](https://github.com/ghiscoding/slickgrid-universal/commit/b26a53d2e1fc7172c8c054b9c27ab1b3a2d3dff6)) + * **backend:** add cancellable onBeforeSort & revert sort on error ([958f823](https://github.com/ghiscoding/slickgrid-universal/commit/958f823a6bffedc2c146c7c68d49a29419812995)) + * **backend:** add cancellable Pagination change & revert on error ([7a8d903](https://github.com/ghiscoding/slickgrid-universal/commit/7a8d9038f230ba433f2773c02992a211a322ebd4)) + * **composite:** move SlickGrid Composite Editor factory into universal ([c813cea](https://github.com/ghiscoding/slickgrid-universal/commit/c813ceac1ed6535963df15e7933a444de3a8790a)) + * **editors:** add Ctrl+S combo to enhance LongText (textarea) Editor ([5116bbd](https://github.com/ghiscoding/slickgrid-universal/commit/5116bbd9e837a3bbd9835b10b2167edf3561cd3d)) + * **filters:** option to ignore accent while filtering text, closes [#470](https://github.com/ghiscoding/slickgrid-universal/issues/470) ([cba9a4e](https://github.com/ghiscoding/slickgrid-universal/commit/cba9a4e4d12b6dfaaec06af5edf4c629b2943feb)) + * **sanitize:** make sure any string sent to innerHtml are sanitized ([fe55046](https://github.com/ghiscoding/slickgrid-universal/commit/fe550461d27d01cb5c54d93812db82fa7213f96b)) + * **styling:** only show header menu caret when hovering ([41e7856](https://github.com/ghiscoding/slickgrid-universal/commit/41e7856f9483f7228d1455f2e3810ae58a5f5c8d)) + * **tree:** add `dynamicallyToggledItemState` method to toggle parent(s) ([26369f9](https://github.com/ghiscoding/slickgrid-universal/commit/26369f9b6c9e81ad5705f580896ab28cf362d090)) ## [0.16.2](https://github.com/ghiscoding/slickgrid-universal/compare/v0.16.1...v0.16.2) (2021-07-23) @@ -965,6 +1369,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **formatters:** Complex Object Formatter shouldn't throw with null data ([3421465](https://github.com/ghiscoding/slickgrid-universal/commit/342146557c16b560b5b8ef0f0e47f971179bc765)) + * **tree:** exclude the correct type from interface argument ([af51784](https://github.com/ghiscoding/slickgrid-universal/commit/af51784aa3471dcc88c567f4c3762ab7590184f6)) ## [0.16.1](https://github.com/ghiscoding/slickgrid-universal/compare/v0.16.0...v0.16.1) (2021-07-16) @@ -978,10 +1383,15 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **events:** use nullish coalescing in slickgrid event prefix ([6ff551b](https://github.com/ghiscoding/slickgrid-universal/commit/6ff551b6dab1ba1d8b471273f3419bdb29a60a35)) + * **examples:** onBeforeEditCell should return bool true/false ([382bfc8](https://github.com/ghiscoding/slickgrid-universal/commit/382bfc8d9f8bc2c176d617bd49e9b9b230c47be9)) + * **filter:** refreshTreeDataFilters only when Tree is enabled ([07c70d5](https://github.com/ghiscoding/slickgrid-universal/commit/07c70d5d17dab464cefb1046c72abbd41da4c834)) + * **filters:** always find locale even without TranslaterService ([c4b17c4](https://github.com/ghiscoding/slickgrid-universal/commit/c4b17c4f51ba6f80b907dab0fd0493a8b0944908)) + * **styling:** remove css variable on width causing UX problem ([df69f9c](https://github.com/ghiscoding/slickgrid-universal/commit/df69f9c33604187f91adaf5bb8b43b6abd624d32)) + * **tree:** same dataset length but w/different prop should refresh Tree ([549008a](https://github.com/ghiscoding/slickgrid-universal/commit/549008a40ef34a95200c275fbf84bbf7b10aa4bb)) ### Features @@ -989,7 +1399,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline * **aria:** add aria-label to all Editors/Filters & other html templates ([1a4f8f7](https://github.com/ghiscoding/slickgrid-universal/commit/1a4f8f7873d76b7da5a7d38debed598d3d395c10)) * make constructor arguments as readonly ([a4588ea](https://github.com/ghiscoding/slickgrid-universal/commit/a4588ea5722ae44b647b8c0d02cf8e2a60ff5963)) + * **services:** make everything extendable by using `protected` ([ecbb93a](https://github.com/ghiscoding/slickgrid-universal/commit/ecbb93a56abba39dd050bbd6019b86694495edd1)) + * **styling:** add support for CSS Variables ([674dd1a](https://github.com/ghiscoding/slickgrid-universal/commit/674dd1a064d4d42af1d5841ac87ba8ea35a26b2f)) # [0.15.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.14.1...v0.15.0) (2021-07-06) @@ -997,56 +1409,103 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **addon:** providing columnIndexPosition should always work ([42c8cff](https://github.com/ghiscoding/slickgrid-universal/commit/42c8cff7dd6cf9103149445969be289710549590)) + * **build:** the "files" property should be included in pkg.json ([3d8f12e](https://github.com/ghiscoding/slickgrid-universal/commit/3d8f12e5f55079445c6fb5cde767f8e0b4511ebb)) + * **demo:** we should be able to move row(s) and keep selections ([d5669a1](https://github.com/ghiscoding/slickgrid-universal/commit/d5669a1d9c07680540d084dad6e1ef06faca0357)) + * **editors:** longText Editor (textarea) was scrolling to page bottom ([a4e37a0](https://github.com/ghiscoding/slickgrid-universal/commit/a4e37a0baf329a100f72fe12c35af67fa072829a)) + * **editors:** select dropdown value is undefined it shouldn't call save ([015294b](https://github.com/ghiscoding/slickgrid-universal/commit/015294b86e431e8109ce540dda7856b7e9e27575)) + * **export:** expanded Row Detail shouldn't be exported, fixes [#390](https://github.com/ghiscoding/slickgrid-universal/issues/390) ([cef826c](https://github.com/ghiscoding/slickgrid-universal/commit/cef826c1deb458c316bdeaa4fdeba27e748595f3)) + * **filters:** filtering with IN_CONTAINS should also work with spaces ([ab54724](https://github.com/ghiscoding/slickgrid-universal/commit/ab5472437b94fe81270f809ab6fd00f204c688b8)) + * **formatters:** shouldn't auto-add editor formatter multiple times ([177b8d4](https://github.com/ghiscoding/slickgrid-universal/commit/177b8d44cddbbcdece48360071fbed25ceab10eb)) + * **frozen:** in some occasion column pinning changes column positions ([70cb74e](https://github.com/ghiscoding/slickgrid-universal/commit/70cb74ef1119a60b37d438130d4a463a87a8939a)) + * **menu:** toggle filter bar could be out of sync w/horizontal scroll ([ab7f589](https://github.com/ghiscoding/slickgrid-universal/commit/ab7f58929b10d1b250765b707363aedd9f9d7866)) + * **pagination:** able to change translate pubsub event name in component ([4745063](https://github.com/ghiscoding/slickgrid-universal/commit/4745063930374a21986fc11d736d3bd05c9d6e41)) + * **pagination:** should be able to toggle Pagination ([c0367c2](https://github.com/ghiscoding/slickgrid-universal/commit/c0367c24da2ccb3558e1b27f8e70a81d84201479)) + * **Pagination:** the Pagination wasn't showing when using dataset setter ([ac3f933](https://github.com/ghiscoding/slickgrid-universal/commit/ac3f933d9829edcf89e5ea15571da9a7e4b7c4ba)) + * **plugin:** row move shouldn't go further when onBefore returns false ([e9bfb5c](https://github.com/ghiscoding/slickgrid-universal/commit/e9bfb5ceba6a18a020b8b34f72abba6e3d13d8b8)) + * **resizer:** few fixes & adjustments after trying in SF ([32e80ec](https://github.com/ghiscoding/slickgrid-universal/commit/32e80ecdbc5072c1619593d101289a3c1ea92b3a)) + * **resizer:** tweak resize check to stop much earlier ([ea35b08](https://github.com/ghiscoding/slickgrid-universal/commit/ea35b08973e7b58b49969337875816bcad78e0ba)) + * **services:** toggle pagination was not displaying all row selection ([e51ccb4](https://github.com/ghiscoding/slickgrid-universal/commit/e51ccb4352bf3a578159b8b63f0a6caf891c382a)) + * **state:** changeColumnsArrangement should work w/columnIndexPosition ([7c1e9d3](https://github.com/ghiscoding/slickgrid-universal/commit/7c1e9d3d243988d6d99a9696b0afbe8f62ac45b4)) + * **state:** Grid View/Columns dynamically should work w/row move ([a7cf1df](https://github.com/ghiscoding/slickgrid-universal/commit/a7cf1dfb73c770908aadf01fd67680c985449f9d)) + * **state:** Grid View/Columns dynamically should work w/row selection ([865944f](https://github.com/ghiscoding/slickgrid-universal/commit/865944f5d6aadc0c05c7f83db7c11a569a33118f)) + * **styling:** address latest dart-sass math division deprecation warning ([b7317d8](https://github.com/ghiscoding/slickgrid-universal/commit/b7317d8fa619b35fb65789e12b268d65ff65968c)) + * **styling:** header title should show ellipsis if too long ([607e14d](https://github.com/ghiscoding/slickgrid-universal/commit/607e14d7fffa4f9854eff5103e1a1a0881664286)) + * **tree:** calling updateItems should not lose the Tree collapsing icon ([45b9622](https://github.com/ghiscoding/slickgrid-universal/commit/45b96225dd5a676b6a85bbb2c8146137eb95b33f)) + * **tree:** using `initiallyCollapsed` change internal toggled state ([380f2f9](https://github.com/ghiscoding/slickgrid-universal/commit/380f2f903d9908e2bed5b3f44d04e28e5d5b9c63)) + * initial grid state should also include toggled presets ([f1fe39f](https://github.com/ghiscoding/slickgrid-universal/commit/f1fe39f5d68487e815be7fd3d7ca5a6fd4cba7c6)) + * make sure dataset is array before getting his length ([702d9fd](https://github.com/ghiscoding/slickgrid-universal/commit/702d9fddb5e753bfa5323bd2f25fd0bb33cb749a)) + * option labels weren't showing correctly after running Cypress tests ([10d4339](https://github.com/ghiscoding/slickgrid-universal/commit/10d4339da70cce4977707a6a19a79cceb4bf87df)) + * provide input type directly in constructor before init() is called ([e89c3bd](https://github.com/ghiscoding/slickgrid-universal/commit/e89c3bd3da66e4b16342cefe1eedd5df96363e45)) ### Features * **components:** extract Custom Footer to be an external component ([1794c27](https://github.com/ghiscoding/slickgrid-universal/commit/1794c27d7669c172f606d709d3360bc5d2f77798)) + * **editors:** convert jQuery to native element on slider editor ([3181cf0](https://github.com/ghiscoding/slickgrid-universal/commit/3181cf069d9f3bc85dc0d13ceeb9623d21ae8eff)) + * **editors:** replace jQuery with native element on date editor ([062f1f9](https://github.com/ghiscoding/slickgrid-universal/commit/062f1f9713c8f236c30b4d631b601b24b56a530d)) + * **editors:** use class inheritance to extend main input editor ([ad3e696](https://github.com/ghiscoding/slickgrid-universal/commit/ad3e6965d4cd4295086401de26b5d3aad13a7650)) + * **filters:** build multiple-select options from native dom elements ([aa548a9](https://github.com/ghiscoding/slickgrid-universal/commit/aa548a9bc05da0d4d5233a2633ae3055fd9f7178)) + * **filters:** convert jQuery to native element on more filters ([b46eb5e](https://github.com/ghiscoding/slickgrid-universal/commit/b46eb5ebdb177e7d0d6c93cb6df541cedc7eb5d1)) + * **filters:** convert jQuery to native elements on multiple filters ([3a80996](https://github.com/ghiscoding/slickgrid-universal/commit/3a80996bec96e465d23a30387af707289f4089e3)) + * **footer:** add option to customize right footer text ([2ea41cc](https://github.com/ghiscoding/slickgrid-universal/commit/2ea41cc8ab38ebc5d5276c90de33b57247c4476f)) + * **formatters:** add Bootstrap Dropdown Formatter ([5ba9423](https://github.com/ghiscoding/slickgrid-universal/commit/5ba9423200e60460c22f05253901707ef7055782)) + * **Pagination:** decouple the Pagination Component to separate package ([606795b](https://github.com/ghiscoding/slickgrid-universal/commit/606795b677956a88c2e4b5e943fddcaba3113b51)) + * **services:** convert jQuery to native elements ([4da0a20](https://github.com/ghiscoding/slickgrid-universal/commit/4da0a201aaa866447a0c76e3b9c16503e2ed6af9)) + * **services:** decouple the EventPubSubService to separate package ([9f51665](https://github.com/ghiscoding/slickgrid-universal/commit/9f516655e9ce5f06e0cfeabc43536834dc38c70b)) + * **services:** move Resizer Service w/common services folder for reuse ([d127ac7](https://github.com/ghiscoding/slickgrid-universal/commit/d127ac797ee787ea7785e8ae9f4c0bcaed786afd)) + * **styling:** add a new `color-disabled-dark` ([55c3062](https://github.com/ghiscoding/slickgrid-universal/commit/55c30621241ec5da7a2e19879265c4e15a6ad907)) + * **styling:** add a new `color-disabled` ([7151198](https://github.com/ghiscoding/slickgrid-universal/commit/7151198dd393c0bc93151cc4dc9c3295917b6b3e)) + * **styling:** add extra material icons & new color ([4205b66](https://github.com/ghiscoding/slickgrid-universal/commit/4205b664e80af691c72d5520e4778ad4cd7d94b3)) + * **tree:** add `getItemCount` method with optional tree level ([b3f8f94](https://github.com/ghiscoding/slickgrid-universal/commit/b3f8f9484e7ea352b2ed264c6a27e1e091eaf918)) + * **tree:** add Tree Collapse Grid State/Preset ([998b01a](https://github.com/ghiscoding/slickgrid-universal/commit/998b01a2f10ccee5636f616921dd86b35a4feaec)) + * **tree:** add ways to reapply Tree Collapse previous state ([3702ed3](https://github.com/ghiscoding/slickgrid-universal/commit/3702ed32629f84397349147c978ca650043c45eb)) + * add new Input Password Editor which uses common inputEditor ([87e547c](https://github.com/ghiscoding/slickgrid-universal/commit/87e547c0dbccc106a1109c3902ac2027fbd52138)) + * convert jQuery to native element on few more filters ([7d5e1e8](https://github.com/ghiscoding/slickgrid-universal/commit/7d5e1e859a0331699d6fb07d2d35797d7274d1df)) ## [0.14.1](https://github.com/ghiscoding/slickgrid-universal/compare/v0.14.0...v0.14.1) (2021-05-22) @@ -1060,31 +1519,53 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **backend:** able to preset filters on hidden columns & all queried ([f1d92cd](https://github.com/ghiscoding/slickgrid-universal/commit/f1d92cda4cb3fabee00bb10dae36d68cd1d861e5)) + * **backend:** able to preset filters on hidden columns & all queried ([c610979](https://github.com/ghiscoding/slickgrid-universal/commit/c610979c54170c069b97a71864d95d0363d75e80)) + * **editors:** select editor inline blur save before destroy ([0e591b1](https://github.com/ghiscoding/slickgrid-universal/commit/0e591b1812fc1c733c03f7afcf81dee7a3e4b107)) + * **formatters:** Tree Data use nullish coallescing w/optional chaining ([f6cf14c](https://github.com/ghiscoding/slickgrid-universal/commit/f6cf14c06518d47742ee17d82a22a39af490c9e7)) + * **frozen:** rollback previous commit since the issue was found in SlickGrid (core) ([780bcd7](https://github.com/ghiscoding/slickgrid-universal/commit/780bcd7bfae35e26cd84c9a6d220e2dab9eca3b4)) + * **presets:** loading columns presets should only be done once ([4273aa9](https://github.com/ghiscoding/slickgrid-universal/commit/4273aa9f123d429d5fe4d2163b19407cece86ba9)), closes [#341](https://github.com/ghiscoding/slickgrid-universal/issues/341) + * **resizer:** fix a regression bug caused by previous PR [#341](https://github.com/ghiscoding/slickgrid-universal/issues/341) ([462e330](https://github.com/ghiscoding/slickgrid-universal/commit/462e330d9457300fa3ef4e67bf8e012d8167ca2c)) + * **resizer:** remove delay to call resize by content to avoid flickering ([961efe6](https://github.com/ghiscoding/slickgrid-universal/commit/961efe6fe7ad721e8196c76ed4c35205830b6b83)) + * **services:** fix couple of issues found with custom grid views ([db06736](https://github.com/ghiscoding/slickgrid-universal/commit/db0673688b2b6e6dde8f25af9551bf6c27174a44)) + * **sorting:** multi-column sort shouldn't work when option is disabled ([bfc8651](https://github.com/ghiscoding/slickgrid-universal/commit/bfc865128de0a9e4c21ff0dc8b564c15c88dea93)) + * **styling:** add a better search filter magnify glass icon as placeholder ([5464824](https://github.com/ghiscoding/slickgrid-universal/commit/5464824f3719ebddb303ee1b82161638d870a288)) + * **styling:** center horizontally checkbox selector in column header ([bb5aebc](https://github.com/ghiscoding/slickgrid-universal/commit/bb5aebc355a22e19b0071bfe993bbeb0e1090265)) + * **styling:** dart-sass deprecation warnings use math utils instead ([b5d8103](https://github.com/ghiscoding/slickgrid-universal/commit/b5d81030eb859524e09547ef13642dbed2902ea5)) + * **tree:** Tree Data export should also include correct indentation ([f1e06c1](https://github.com/ghiscoding/slickgrid-universal/commit/f1e06c11f9eaa9ee778d319bfbaba20bb9abfcc9)) + * **tree:** couple of issues found in Tree Data, fixes [#307](https://github.com/ghiscoding/slickgrid-universal/issues/307) ([e684d1a](https://github.com/ghiscoding/slickgrid-universal/commit/e684d1af1c078a8861c3c94fe5486cbe68d57b85)) ### Features * **addon:** provide grid menu labels for all built-in commands ([44c72d3](https://github.com/ghiscoding/slickgrid-universal/commit/44c72d3ca0b8a88e6ae5022a25b11c4d41fd2897)) + * **editors:** add `compositeEditorFormOrder` option ([03f2d66](https://github.com/ghiscoding/slickgrid-universal/commit/03f2d662a69d71edf4b61cdda862fb4eef0f9b47)) + * **editors:** add ways to preload date without closing date picker ([3088038](https://github.com/ghiscoding/slickgrid-universal/commit/30880380584b281c756e0ad437031631e6f607e0)) + * **resizer:** add `resizeByContentOnlyOnFirstLoad` grid option ([ffe7dc4](https://github.com/ghiscoding/slickgrid-universal/commit/ffe7dc4c2a7ae778c8e731fd7637b154c10035f0)) + * **resizer:** add single Column Resize by Content dblClick & headerMenu ([683389f](https://github.com/ghiscoding/slickgrid-universal/commit/683389fcc343ac5c0378a9e34b7f11dda97fc719)) + * **services:** add onBeforeResizeByContent (onAfter) ([3e99fab](https://github.com/ghiscoding/slickgrid-universal/commit/3e99fabb8554161e4301c0596eaebd9e0d246de7)) + * **styling:** add new marker material icons for project ([9b386fa](https://github.com/ghiscoding/slickgrid-universal/commit/9b386fa3e6af8e76cf4beb5aa0b5322db2f270af)) + * **tree:** improve Tree Data speed considerably ([5487798](https://github.com/ghiscoding/slickgrid-universal/commit/548779801d06cc9ae7e319e72d351c8a868ed79f)) + * **editors:** replace jQuery with native elements ([d6e8f4e](https://github.com/ghiscoding/slickgrid-universal/commit/d6e8f4e59823673df290b179d7ee277e3d7bb1af)) # [0.13.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.12.0...v0.13.0) (2021-04-27) @@ -1092,24 +1573,39 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **demo:** call `scrollColumnIntoView` after changing view ([b751151](https://github.com/ghiscoding/slickgrid-universal/commit/b751151fb11dfaeb48ff1f4daf5ed32ad56122a0)) + * **editors:** Composite Editor modal compo should work w/complex objects ([#298](https://github.com/ghiscoding/slickgrid-universal/issues/298)) ([721a6c5](https://github.com/ghiscoding/slickgrid-universal/commit/721a6c5627369cfc89710705384995f8aba3a178)) + * **exports:** grid with colspan should be export accordingly ([#311](https://github.com/ghiscoding/slickgrid-universal/issues/311)) ([e899fbb](https://github.com/ghiscoding/slickgrid-universal/commit/e899fbba3daa41261dcaa57b0555e37e9bdfafb4)) + * **footer:** add correct implemtation of locale usage in custom footer ([6e18bf9](https://github.com/ghiscoding/slickgrid-universal/commit/6e18bf9a8af070428bbb3cb429392df1eb19be54)) + * **observables:** http cancellable Subject should be unsubscribed ([cbc951b](https://github.com/ghiscoding/slickgrid-universal/commit/cbc951bcf5891658f55981e88887f41b4fb5d5c4)) + * **resize:** columns reposition not coming back after grid setOptions ([f2027e6](https://github.com/ghiscoding/slickgrid-universal/commit/f2027e60f418bb94f9d32c779d0474de4d87a5c9)) + * **selection:** full row selection should be selected w/show hidden row ([f76e30c](https://github.com/ghiscoding/slickgrid-universal/commit/f76e30cdca476c947089d88069bd21e42639ba7e)) + * **tests:** try setting fixed TZ while running Jest ([d316db9](https://github.com/ghiscoding/slickgrid-universal/commit/d316db98acada214b082c2ff9925449822df96e8)) ### Features * **editors:** add `onBeforeOpen` optional callback to Composite Editor ([#306](https://github.com/ghiscoding/slickgrid-universal/issues/306)) ([a642482](https://github.com/ghiscoding/slickgrid-universal/commit/a642482254009115366ca4992e2e60647f8ae9b0)) + * **editors:** add `target` to `onBeforeEditCell` w/called by composite ([#301](https://github.com/ghiscoding/slickgrid-universal/issues/301)) ([7440ff5](https://github.com/ghiscoding/slickgrid-universal/commit/7440ff58988acd7abd1ce249b1ceb72556cceb1d)) + * **filters:** add option to filter empty values for select filter ([#310](https://github.com/ghiscoding/slickgrid-universal/issues/310)) ([c58a92a](https://github.com/ghiscoding/slickgrid-universal/commit/c58a92a8e2b29ea216211e3561d5567c43f0376a)) + * **filters:** option to add custom compound operator list ([3e8d2cb](https://github.com/ghiscoding/slickgrid-universal/commit/3e8d2cbcea6181e3ce3157798f003a8479d11011)) + * **footer:** add row selection count to the footer component ([8ba146c](https://github.com/ghiscoding/slickgrid-universal/commit/8ba146cd4cbdccdb61f3441918065fad4561ff84)) + * **resize:** add column resize by cell content ([#309](https://github.com/ghiscoding/slickgrid-universal/issues/309)) ([515a072](https://github.com/ghiscoding/slickgrid-universal/commit/515a072b3a16d3aca0f48e62c968ae89a1510669)) + * **services:** remove deprecated hideColumnByIndex form Grid Service ([#312](https://github.com/ghiscoding/slickgrid-universal/issues/312)) ([b00c64d](https://github.com/ghiscoding/slickgrid-universal/commit/b00c64d8f88d4560c677f667a84d95ba30e96399)) + * **styling:** switch from node-sass to dart-sass (sass) ([81f8d9f](https://github.com/ghiscoding/slickgrid-universal/commit/81f8d9fbd1381b4c877eeeb4992bdcc90c1cd677)) + * **typing:** add missing item metadata interface ([#299](https://github.com/ghiscoding/slickgrid-universal/issues/299)) ([7cf0a21](https://github.com/ghiscoding/slickgrid-universal/commit/7cf0a2185c73dcb7748a193ba2272bb7af699266)) # [0.12.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.11.2...v0.12.0) (2021-03-24) @@ -1117,27 +1613,45 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **editors:** show all editors as 100% height in their cell container ([#277](https://github.com/ghiscoding/slickgrid-universal/issues/277)) ([3f49aea](https://github.com/ghiscoding/slickgrid-universal/commit/3f49aeabd6016c705d4d6b809345fe1ac948cfc5)) + * **filters:** rollback a change made in PR [#288](https://github.com/ghiscoding/slickgrid-universal/issues/288) causing preset issues ([18ffc0c](https://github.com/ghiscoding/slickgrid-universal/commit/18ffc0c8285e4e2306bc60817fba357734a65b61)) + * **filters:** SearchTerms shouldn't come back after calling clearFilters ([04f3d12](https://github.com/ghiscoding/slickgrid-universal/commit/04f3d1267de493b9dc1e922dca3b433b9cb34fde)) + * **filters:** string <> should be Not Contains instead of Not Equal ([#276](https://github.com/ghiscoding/slickgrid-universal/issues/276)) ([960884d](https://github.com/ghiscoding/slickgrid-universal/commit/960884ddf58b1e87ad5ef71e3713f8836e6190c0)) + * **firefox:** add all missing SVG color filter classes for Firefox/SF ([#296](https://github.com/ghiscoding/slickgrid-universal/issues/296)) ([a07ebdf](https://github.com/ghiscoding/slickgrid-universal/commit/a07ebdfbd2c2197c28102efe1f4a685ea61185e1)) + * **lerna:** downgrade Lerna to previous version to fix thread leaking ([#281](https://github.com/ghiscoding/slickgrid-universal/issues/281)) ([ffde71c](https://github.com/ghiscoding/slickgrid-universal/commit/ffde71c84fd12e9a9fed878b818521fea96c99a5)) + * **pinning:** reordering cols position freezing cols shouldn't affect ([#275](https://github.com/ghiscoding/slickgrid-universal/issues/275)) ([a30665d](https://github.com/ghiscoding/slickgrid-universal/commit/a30665d54da583c47b1f533002173af99e9ab20d)) + * **plugin:** Grid Menu Clear Frozen Cols shouldn't change cols positions ([#291](https://github.com/ghiscoding/slickgrid-universal/issues/291)) ([4fdab08](https://github.com/ghiscoding/slickgrid-universal/commit/4fdab08357d12349b6402e3007f4ab399d9a2140)) + * **presets:** Filter & Sorting presets & Footer metrics issues ([#285](https://github.com/ghiscoding/slickgrid-universal/issues/285)) ([3174c86](https://github.com/ghiscoding/slickgrid-universal/commit/3174c86e011b4927510b99a348e8019adb4baa00)) + * **presets:** Multiple Select Filter Grid Presets values should be shown ([dd1f231](https://github.com/ghiscoding/slickgrid-universal/commit/dd1f231850819bde455e24d743b9e1637767ecb3)) + * **resizer:** allow gridHeight/gridWidth to be passed as string ([#284](https://github.com/ghiscoding/slickgrid-universal/issues/284)) ([20bda50](https://github.com/ghiscoding/slickgrid-universal/commit/20bda50bf3ab647ae4ee3d7ffe0c9c8b58e8f187)), closes [#534](https://github.com/ghiscoding/slickgrid-universal/issues/534) + * **sorting:** add some unit tests that were previously commented out ([#290](https://github.com/ghiscoding/slickgrid-universal/issues/290)) ([2a91fa6](https://github.com/ghiscoding/slickgrid-universal/commit/2a91fa6f672650bb525a4ba1774d02c5ac435c5b)) ### Features * **editors:** add `onSelect` callback to Autocomplete Editor ([#286](https://github.com/ghiscoding/slickgrid-universal/issues/286)) ([2d106d4](https://github.com/ghiscoding/slickgrid-universal/commit/2d106d4df0a259d36bee3d910320706ddb7e8580)) + * **filters:** add new IN_COLLECTION operator to allow searching cell value as Array ([#282](https://github.com/ghiscoding/slickgrid-universal/issues/282)) ([ecce93c](https://github.com/ghiscoding/slickgrid-universal/commit/ecce93c92b7424522ad2af0d7d82963a3a56ca97)) + * **filters:** add optional `filterTypingDebounce` for filters w/keyup ([#289](https://github.com/ghiscoding/slickgrid-universal/issues/289)) ([3aecc89](https://github.com/ghiscoding/slickgrid-universal/commit/3aecc899ebd78d9597cc4ed4919c0a8dd26673a8)) + * **filters:** add optional `filterTypingDebounce` for keyboard filters ([#283](https://github.com/ghiscoding/slickgrid-universal/issues/283)) ([bb7dcd3](https://github.com/ghiscoding/slickgrid-universal/commit/bb7dcd3a9e28f45c7339e2f30685220b7a152507)) + * **filters:** add possibility to filter by text range like "a..e" ([#279](https://github.com/ghiscoding/slickgrid-universal/issues/279)) ([e44145d](https://github.com/ghiscoding/slickgrid-universal/commit/e44145d897da570bf6ea15b156c7961ce96ce6f0)) + * **filters:** display operator into input text filter from Grid Presets ([#288](https://github.com/ghiscoding/slickgrid-universal/issues/288)) ([3fad4fe](https://github.com/ghiscoding/slickgrid-universal/commit/3fad4fe9ef3bec290dabb860d7ea4baf8f182a4a)) + * **resources:** add RxJS support into Slickgrid-Universal via external package ([#280](https://github.com/ghiscoding/slickgrid-universal/issues/280)) ([c10fc33](https://github.com/ghiscoding/slickgrid-universal/commit/c10fc339019c04ec0f7c4357ccdb3949a2358460)) + * **state:** add Pinning (frozen) to Grid State & Presets ([#292](https://github.com/ghiscoding/slickgrid-universal/issues/292)) ([ba703d8](https://github.com/ghiscoding/slickgrid-universal/commit/ba703d8353a243ffed4d40804c0f977119424f6c)) ## [0.11.2](https://github.com/ghiscoding/slickgrid-universal/compare/v0.11.1...v0.11.2) (2021-02-27) @@ -1157,20 +1671,31 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **backend:** incorrect item count with GraphQL and useLocalFiltering ([3996cf4](https://github.com/ghiscoding/slickgrid-universal/commit/3996cf45b59c721b777e04dba3c10bbf03667bdb)) + * **build:** enable tsconfig strict mode tsconfig ([#269](https://github.com/ghiscoding/slickgrid-universal/issues/269)) ([095fc71](https://github.com/ghiscoding/slickgrid-universal/commit/095fc71052c1f4e776544781da5fe762cfa16238)) + * **filters:** don't use indexOf NOT_IN_CONTAINS ([#262](https://github.com/ghiscoding/slickgrid-universal/issues/262)) ([310be30](https://github.com/ghiscoding/slickgrid-universal/commit/310be30efb653151a75dde0a14b1ed3f9946b333)) + * **filters:** use defaultFilterOperator in range when none provided ([#271](https://github.com/ghiscoding/slickgrid-universal/issues/271)) ([993675f](https://github.com/ghiscoding/slickgrid-universal/commit/993675f6b0d76e76010d5cadc6696134a73dad66)) + * **helpers:** should be able to highlight first row (0) ([#268](https://github.com/ghiscoding/slickgrid-universal/issues/268)) ([a58be17](https://github.com/ghiscoding/slickgrid-universal/commit/a58be17959e28ab9a1280c3d7d7c8df9db02587e)), closes [#527](https://github.com/ghiscoding/slickgrid-universal/issues/527) + * **plugin:** recreate header menu when adding column dynamically ([#257](https://github.com/ghiscoding/slickgrid-universal/issues/257)) ([16c4984](https://github.com/ghiscoding/slickgrid-universal/commit/16c49845c5d3388502811c15f0a23daa1a01f850)) ### Features * **demo:** add Example 13 Header Button Plugin ([f345cd1](https://github.com/ghiscoding/slickgrid-universal/commit/f345cd18b89f849f3f873538c214d3ac24ff12f8)) + * **editors:** add a Clear (X) button to the Autocomplete Editor ([#270](https://github.com/ghiscoding/slickgrid-universal/issues/270)) ([ffbd188](https://github.com/ghiscoding/slickgrid-universal/commit/ffbd188534992c31848691154517deb64694f3b2)) + * **filters:** add updateSingleFilter for a single external filter ([#265](https://github.com/ghiscoding/slickgrid-universal/issues/265)) ([20564a3](https://github.com/ghiscoding/slickgrid-universal/commit/20564a3096948626beada698460b72374a18ca7c)) + * **perf:** huge filtering speed improvements ([a101ed1](https://github.com/ghiscoding/slickgrid-universal/commit/a101ed1b62c2fbfec2712f64e08192a4852bce9d)) + * **perf:** improve date sorting speed ([258da22](https://github.com/ghiscoding/slickgrid-universal/commit/258da2238bba3693eada058f9405012f68af150b)) + * **perf:** improve date sorting speed ([#259](https://github.com/ghiscoding/slickgrid-universal/issues/259)) ([a52f4fc](https://github.com/ghiscoding/slickgrid-universal/commit/a52f4fcee1627ac5906388f8dcf4b7fe3f5c4aa7)) + * **services:** add bulk transactions in Grid Service CRUD methods ([#256](https://github.com/ghiscoding/slickgrid-universal/issues/256)) ([03385d9](https://github.com/ghiscoding/slickgrid-universal/commit/03385d9ac58cb3ce7501a409394706c0cb4f4d29)) ## [0.10.2](https://github.com/ghiscoding/slickgrid-universal/compare/v0.10.1...v0.10.2) (2021-01-28) @@ -1190,28 +1715,47 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **comp:** empty data warning should work with autoheight grid ([#240](https://github.com/ghiscoding/slickgrid-universal/issues/240)) ([8c9cb84](https://github.com/ghiscoding/slickgrid-universal/commit/8c9cb84847bfd08a678d333a8555ae6fc9295670)) + * **component:** Composite Editor sometime shows empty mass update form ([#244](https://github.com/ghiscoding/slickgrid-universal/issues/244)) ([d3ad4db](https://github.com/ghiscoding/slickgrid-universal/commit/d3ad4db45d259fa8ab977cd45c830a7d3bd342d8)) + * **components:** empty data warning should work with autoheight grid ([#234](https://github.com/ghiscoding/slickgrid-universal/issues/234)) ([16daa36](https://github.com/ghiscoding/slickgrid-universal/commit/16daa368f0e46112fc1d1dd0b1a944ec2b60ced0)) + * **core:** fix types index.d.ts url ([a76b3a3](https://github.com/ghiscoding/slickgrid-universal/commit/a76b3a3d97a6d211ec2e7e8d9060fd8dd0719f58)) + * **editors:** add blank disabled fields in Composite Editor form values ([#233](https://github.com/ghiscoding/slickgrid-universal/issues/233)) ([b634902](https://github.com/ghiscoding/slickgrid-universal/commit/b6349029b705991b7ac2d1df99f5b330fe69ef36)) + * **editors:** add option to skip missing composite editor ([#232](https://github.com/ghiscoding/slickgrid-universal/issues/232)) ([925dba8](https://github.com/ghiscoding/slickgrid-universal/commit/925dba86aca57825ab04d0cdc01484d52bf99265)) + * **editors:** fix clear date & blank disabled field w/Composite Editor ([#235](https://github.com/ghiscoding/slickgrid-universal/issues/235)) ([9aac97d](https://github.com/ghiscoding/slickgrid-universal/commit/9aac97d2d433c809facc8d7092467780d55ca01a)) + * **exports:** Excel Export custom width applies the width to next column ([#242](https://github.com/ghiscoding/slickgrid-universal/issues/242)) ([146f64f](https://github.com/ghiscoding/slickgrid-universal/commit/146f64f1b89005e6bb5e982721b5c7e43ecf5ac4)) + * **filters:** Grid State filters should always include an operator ([#238](https://github.com/ghiscoding/slickgrid-universal/issues/238)) ([f64ed37](https://github.com/ghiscoding/slickgrid-universal/commit/f64ed37f7ffe01346c8f68d4bd170ffdce54839d)) + * **frozen:** hiding multiple columns when using pinning gets out of sync ([#243](https://github.com/ghiscoding/slickgrid-universal/issues/243)) ([b255220](https://github.com/ghiscoding/slickgrid-universal/commit/b255220ec37dbdc9df4f3ecccb4397656cf9f2a6)) + * **lint:** add eslint as a pre task when bundling & fix linting errors ([#246](https://github.com/ghiscoding/slickgrid-universal/issues/246)) ([6f7ccd8](https://github.com/ghiscoding/slickgrid-universal/commit/6f7ccd8ee4cc5e005034965a2c2dcc0499f06a73)) + * **pinning:** recalculate frozen idx properly when column shown changes ([#241](https://github.com/ghiscoding/slickgrid-universal/issues/241)) ([3b55972](https://github.com/ghiscoding/slickgrid-universal/commit/3b559726acdff96970c68c10c8d256d0403d6c4f)) + * **plugins:** add missing Row Detail filtering code ([#239](https://github.com/ghiscoding/slickgrid-universal/issues/239)) ([d9cad63](https://github.com/ghiscoding/slickgrid-universal/commit/d9cad635840650d2b2dd91444ffa0121147f4140)) + * **plugins:** throw error when Tree Data used with Pagination ([#229](https://github.com/ghiscoding/slickgrid-universal/issues/229)) ([85718e1](https://github.com/ghiscoding/slickgrid-universal/commit/85718e18cd181734df3ba1a2440ead4368741c53)) + * **tsc:** running dev watch was overriding commonjs folder ([#249](https://github.com/ghiscoding/slickgrid-universal/issues/249)) ([e466f62](https://github.com/ghiscoding/slickgrid-universal/commit/e466f6214d9450b593daecfdee6682f1f7c9ed19)) ### Features * **editors:** add Clone functionality to Composite Editor ([#236](https://github.com/ghiscoding/slickgrid-universal/issues/236)) ([df545e4](https://github.com/ghiscoding/slickgrid-universal/commit/df545e4ec64271307b1979feb5e786f449433639)) + * **editors:** add Column Editor collectionOverride option ([0efb18f](https://github.com/ghiscoding/slickgrid-universal/commit/0efb18f916ecd407ec1589bc18f076907fa356c7)) + * **editors:** change all private keyword to protected for extensability ([#247](https://github.com/ghiscoding/slickgrid-universal/issues/247)) ([089b6cb](https://github.com/ghiscoding/slickgrid-universal/commit/089b6cbbdd6284d94f765fdad08642e0d0d81ff0)) + * **filters:** change all private keyword to protected for extensability ([#245](https://github.com/ghiscoding/slickgrid-universal/issues/245)) ([52cc702](https://github.com/ghiscoding/slickgrid-universal/commit/52cc7022c4b847566d89e91a80c423373538a15a)) + * **formatters:** add grid option to auto add custom editor formatter ([#248](https://github.com/ghiscoding/slickgrid-universal/issues/248)) ([db77d46](https://github.com/ghiscoding/slickgrid-universal/commit/db77d464ee37eda573351e89d4c5acc9b5648649)) + * add nameCompositeEditor override to be used by Composite Editor ([fcdb2e9](https://github.com/ghiscoding/slickgrid-universal/commit/fcdb2e92ed736b09e947cdbcf39ee157afc4acab)) # [0.9.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.8.0...v0.9.0) (2021-01-06) @@ -1219,15 +1763,21 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **backend:** GraphQL queries with input filter ([#217](https://github.com/ghiscoding/slickgrid-universal/issues/217)) ([ff7f1e5](https://github.com/ghiscoding/slickgrid-universal/commit/ff7f1e5e8733d25a1fd7869e4de2b1bc700b8a7b)) + * **backend:** OData queries with input filter ([#224](https://github.com/ghiscoding/slickgrid-universal/issues/224)) ([fec1ce8](https://github.com/ghiscoding/slickgrid-universal/commit/fec1ce879507998a04088bf494cfd5a595e90160)) + * **build:** import Flatpickr Locale on demand via regular imports ([#227](https://github.com/ghiscoding/slickgrid-universal/issues/227)) ([6644822](https://github.com/ghiscoding/slickgrid-universal/commit/664482210557fc1a7a178856e2641f71b9580c44)) + * **core:** adjust vscode debugger path overrides for WebPack 5 debugging ([a45b3d2](https://github.com/ghiscoding/slickgrid-universal/commit/a45b3d2aa318012366c98fa5b4b3c95cc647120d)) ### Features * **build:** upgrade to WebPack 5 ([#225](https://github.com/ghiscoding/slickgrid-universal/issues/225)) ([c6b3ad3](https://github.com/ghiscoding/slickgrid-universal/commit/c6b3ad3eb6fb64306bfd8bd300fcc1e86b27e5a6)) + * **ci:** replace CircleCI with GitHub Actions ([#211](https://github.com/ghiscoding/slickgrid-universal/issues/211)) ([4f91140](https://github.com/ghiscoding/slickgrid-universal/commit/4f9114031ca6236ef45f04b67dcba1a9981035c4)) + * **editors:** add Column Editor collectionOverride option ([#228](https://github.com/ghiscoding/slickgrid-universal/issues/228)) ([91421fc](https://github.com/ghiscoding/slickgrid-universal/commit/91421fc0154e432874fb2211e430a79032b996b8)) + * **styling:** add support for Bootstrap 5 ([#226](https://github.com/ghiscoding/slickgrid-universal/issues/226)) ([e35f116](https://github.com/ghiscoding/slickgrid-universal/commit/e35f116efc1989f675ef6e030d80a8a31a444373)) # [0.8.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.7.7...v0.8.0) (2020-12-22) @@ -1235,6 +1785,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** change moment/lodash imports so it works with ES6 module ([#210](https://github.com/ghiscoding/slickgrid-universal/issues/210)) ([2d25d3b](https://github.com/ghiscoding/slickgrid-universal/commit/2d25d3b99f7be93f2bc69f006fb67a39cf39ce7c)) + * **core:** use regular imports instead of require to load plugins ([#209](https://github.com/ghiscoding/slickgrid-universal/issues/209)) ([6816696](https://github.com/ghiscoding/slickgrid-universal/commit/6816696c98be0d2dd80c1ff49358bd49ee7caacb)) ### Features @@ -1262,7 +1813,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **components:** don't instantiate composite editor twice ([#207](https://github.com/ghiscoding/slickgrid-universal/issues/207)) ([8548393](https://github.com/ghiscoding/slickgrid-universal/commit/854839358bf276432169447bebefe736de02f57d)) + * **editors:** fix BS3,BS4 styles & slider value not shown with undefined ([#204](https://github.com/ghiscoding/slickgrid-universal/issues/204)) ([3aca8f9](https://github.com/ghiscoding/slickgrid-universal/commit/3aca8f9053365c1987f6c5abc43f8ce5eca015fb)) + * **exports:** should be able to change export file name ([#205](https://github.com/ghiscoding/slickgrid-universal/issues/205)) ([9d26213](https://github.com/ghiscoding/slickgrid-universal/commit/9d262134b12da46ef1fea970f092d96ce875ed78)) ## [0.7.2](https://github.com/ghiscoding/slickgrid-universal/compare/v0.7.1...v0.7.2) (2020-12-17) @@ -1270,7 +1823,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** range default should be inclusive instead of exclusive ([#203](https://github.com/ghiscoding/slickgrid-universal/issues/203)) ([b7f74ad](https://github.com/ghiscoding/slickgrid-universal/commit/b7f74ad8a1539aed32ac643b4fe395fbdecf4459)) + * **sorting:** add cellValueCouldBeUndefined in grid option for sorting ([#202](https://github.com/ghiscoding/slickgrid-universal/issues/202)) ([865256e](https://github.com/ghiscoding/slickgrid-universal/commit/865256efe927a5715840963cb2945f16a402789b)) + * **stylings:** small alignment issue with the slider value elm height ([5a453b8](https://github.com/ghiscoding/slickgrid-universal/commit/5a453b8739c07e07f835e111d7d3ca5d627a0c2f)) ## [0.7.1](https://github.com/ghiscoding/slickgrid-universal/compare/v0.7.0...v0.7.1) (2020-12-17) @@ -1292,14 +1847,19 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** add console error if any of column def id includes dot ([#198](https://github.com/ghiscoding/slickgrid-universal/issues/198)) ([6ee40af](https://github.com/ghiscoding/slickgrid-universal/commit/6ee40af507b066602c39e057349b5ead6e7952f3)) + * **demo:** changing page should remove unsaved cell styling ([17fa349](https://github.com/ghiscoding/slickgrid-universal/commit/17fa3499e298798fdeccf908feb0f0e5ee40436e)) + * **stylings:** composite editor styling fixes for BS4 ([#195](https://github.com/ghiscoding/slickgrid-universal/issues/195)) ([305eb90](https://github.com/ghiscoding/slickgrid-universal/commit/305eb90c75e6a4aa076c62b5364b904dc5c6518e)) + * **stylings:** re-align the svg icons & single/multiple-select icon+text ([#194](https://github.com/ghiscoding/slickgrid-universal/issues/194)) ([b730be7](https://github.com/ghiscoding/slickgrid-universal/commit/b730be7a75b3035c01aa7ca8f48a88df447ad461)) ### Features * **core:** add registerExternalResources for Components/Services ([#196](https://github.com/ghiscoding/slickgrid-universal/issues/196)) ([ee02f1d](https://github.com/ghiscoding/slickgrid-universal/commit/ee02f1d62d1a0601421352e43d17bd8c89e4348c)) + * **core:** refactor code using the container service everywhere ([#197](https://github.com/ghiscoding/slickgrid-universal/issues/197)) ([96ce9bd](https://github.com/ghiscoding/slickgrid-universal/commit/96ce9bdbf18330e522dad0cbb0eda09c41f6a3df)) + * **formatters:** add numberPrefix & Suffix to Decimal Formatter ([#193](https://github.com/ghiscoding/slickgrid-universal/issues/193)) ([0e4d30c](https://github.com/ghiscoding/slickgrid-universal/commit/0e4d30c0ee23bc598206fbba4e5ed406e4aeecfe)) ## [0.5.1](https://github.com/ghiscoding/slickgrid-universal/compare/v0.5.0...v0.5.1) (2020-12-10) @@ -1311,8 +1871,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **editors:** make sure select editor is defined before reading a prop ([763f981](https://github.com/ghiscoding/slickgrid-universal/commit/763f98111d03652b0ad903ba487a3b8c83a5ef5d)) + * **editors:** only translate button texts when enableTranslate is true ([b698c6b](https://github.com/ghiscoding/slickgrid-universal/commit/b698c6bd3f13af017c7f3c0113b8407269ba1e0d)) + * **editors:** Select Editor option to return flat data w/complex object ([#189](https://github.com/ghiscoding/slickgrid-universal/issues/189)) ([4695cd3](https://github.com/ghiscoding/slickgrid-universal/commit/4695cd3b6871dc1ceca4036fd30935eca8011b7e)) + * **exports:** when cell value is empty object return empty string ([#190](https://github.com/ghiscoding/slickgrid-universal/issues/190)) ([cd34901](https://github.com/ghiscoding/slickgrid-universal/commit/cd349012c82a8bdff113fb9f8ef23ea18c6e3035)) ### Features @@ -1346,6 +1909,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** properly export Enums, Interfaces, Services & Utilities ([#184](https://github.com/ghiscoding/slickgrid-universal/issues/184)) ([0c23398](https://github.com/ghiscoding/slickgrid-universal/commit/0c233984a6e9d718659c119b65a95d6c38d36b0c)) + * **core:** showing/hiding column shouldn't affect its freezing position ([#185](https://github.com/ghiscoding/slickgrid-universal/issues/185)) ([2a812ed](https://github.com/ghiscoding/slickgrid-universal/commit/2a812edb82c8004ab43df224c67ede228ab72c00)) ### Features @@ -1357,8 +1921,13 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** don't expose src folder on npm & update few npm package ([#168](https://github.com/ghiscoding/slickgrid-universal/issues/168)) ([3c05938](https://github.com/ghiscoding/slickgrid-universal/commit/3c059381b35bba88ea98d0206692c912c625f227)) + * **core:** rename i18n to translater & fix few other issues ([#174](https://github.com/ghiscoding/slickgrid-universal/issues/174)) ([34c963a](https://github.com/ghiscoding/slickgrid-universal/commit/34c963a2bcef1b841d3c62ea405a4bc49be98a5c)) + * **editors:** make sure editor element exist before focusing ([e57235b](https://github.com/ghiscoding/slickgrid-universal/commit/e57235b4339ffa1bee522c245665bb598d963fd1)) + * **examples:** queued edit cells style should follow page it was edited ([#167](https://github.com/ghiscoding/slickgrid-universal/issues/167)) ([bf72139](https://github.com/ghiscoding/slickgrid-universal/commit/bf7213994151c148e878d703ea21d8f8ffb43ca8)) + * **extensions:** draggable grouping style change to look better ([#171](https://github.com/ghiscoding/slickgrid-universal/issues/171)) ([d00be88](https://github.com/ghiscoding/slickgrid-universal/commit/d00be8868370f3679555b8f52ef4ad85916c93ac)) + * **formatters:** date formatters should accept ISO input & output to US ([#172](https://github.com/ghiscoding/slickgrid-universal/issues/172)) ([85ce7cf](https://github.com/ghiscoding/slickgrid-universal/commit/85ce7cf3636d5bb43d3ef18ec6998bb0c423d218)) diff --git a/README.md b/README.md index acd0493cb..f4caa772a 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ [![codecov](https://codecov.io/gh/ghiscoding/slickgrid-universal/branch/master/graph/badge.svg)](https://codecov.io/gh/ghiscoding/slickgrid-universal) ### Documentation -📘 [Documentation](https://ghiscoding.gitbook.io/slickgrid-universal/) website powered by GitBook (_for version >=4.x or use the [Wikis](https://github.com/ghiscoding/slickgrid-universal/wiki) for older versions_) +📘 [Documentation](https://ghiscoding.gitbook.io/slickgrid-universal/) website powered by GitBook for version 4+ (__or use [Wikis](https://github.com/ghiscoding/slickgrid-universal/wiki) for older versions__) ### Live Demo [Live Demo](https://ghiscoding.github.io/slickgrid-universal/) website @@ -59,25 +59,25 @@ Slickgrid-Universal has close to **100%** Unit Test Coverage, almost 5,000 Jest ### Available Public Packages -| Package Name | Version | Description | Changes | +| Package Name | Version | Size (gzip) | Changes | | -------------| ------- | ----------- | ------- | -| [@slickgrid-universal/common](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/common) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/common.svg)](https://www.npmjs.com/package/@slickgrid-universal/common) | commonly used Formatters/Editors/Filters/Services/... | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/CHANGELOG.md) | -| [@slickgrid-universal/binding](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/binding) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/binding.svg)](https://www.npmjs.com/package/@slickgrid-universal/binding) | basic Binding Engine & Helper | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/binding/CHANGELOG.md) | -| [@slickgrid-universal/event-pub-sub](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/event-pub-sub) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/event-pub-sub.svg)](https://www.npmjs.com/package/@slickgrid-universal/event-pub-sub) | basic PubSub Service using JS Events | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/event-pub-sub/CHANGELOG.md) | -| [@slickgrid-universal/composite-editor-component](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/composite-editor-component) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/composite-editor-component.svg)](https://www.npmjs.com/package/@slickgrid-universal/composite-editor-component) | Composite Editor Modal Component | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/composite-editor-component/CHANGELOG.md) | -| [@slickgrid-universal/custom-footer-component](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/custom-footer-component) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/custom-footer-component.svg)](https://www.npmjs.com/package/@slickgrid-universal/custom-footer-component) | Custom Footer Component for the grid | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/custom-footer-component/CHANGELOG.md) | -| [@slickgrid-universal/custom-tooltip-plugin](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/custom-tooltip-plugin) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/custom-tooltip-plugin.svg)](https://www.npmjs.com/package/@slickgrid-universal/custom-tooltip-plugin) | Custom Tooltip (plugin) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/custom-tooltip-plugin/CHANGELOG.md) | -| [@slickgrid-universal/empty-warning-component](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/empty-warning-component) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/empty-warning-component.svg)](https://www.npmjs.com/package/@slickgrid-universal/empty-warning-component) | simple Empty Data Warning Component | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/empty-warning-component/CHANGELOG.md) | -| [@slickgrid-universal/pagination-component](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/pagination-component) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/pagination-component.svg)](https://www.npmjs.com/package/@slickgrid-universal/pagination-component) | simple Pagination Component | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/pagination-component/CHANGELOG.md) | -| [@slickgrid-universal/excel-export](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/excel-export) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/excel-export.svg)](https://www.npmjs.com/package/@slickgrid-universal/excel-export) | Export to Excel Service (`xls`/`xlsx`) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/excel-export/CHANGELOG.md) | -| [@slickgrid-universal/text-export](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/text-export) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/text-export.svg)](https://www.npmjs.com/package/@slickgrid-universal/text-export) | Export to Text File Service (`csv`/`txt`) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/text-export/CHANGELOG.md) | -| [@slickgrid-universal/graphql](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/graphql) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/graphql.svg)](https://www.npmjs.com/package/@slickgrid-universal/graphql) | GraphQL Query Service (Filter/Sort/Paging) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/graphql/CHANGELOG.md) | -| [@slickgrid-universal/odata](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/odata) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/odata.svg)](https://www.npmjs.com/package/@slickgrid-universal/odata) | OData Query Service (Filter/Sort/Paging) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/odata/CHANGELOG.md) | -| [@slickgrid-universal/row-detail-view-plugin](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/row-detail-view-plugin) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/row-detail-view-plugin.svg)](https://www.npmjs.com/package/@slickgrid-universal/row-detail-view-plugin) | Row Detail View (plugin) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/row-detail-view-plugin/CHANGELOG.md) | -| [@slickgrid-universal/rxjs-observable](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/rxjs-observable) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/rxjs-observable.svg)](https://www.npmjs.com/package/@slickgrid-universal/rxjs-observable) | RxJS Observable Service Wrapper | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/rxjs-observable/CHANGELOG.md) | -| [@slickgrid-universal/utils](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/utils) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/utils.svg)](https://www.npmjs.com/package/@slickgrid-universal/utils) | Common JS Utils | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/utils/CHANGELOG.md) -| [@slickgrid-universal/vanilla-bundle](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/vanilla-bundle) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/vanilla-bundle.svg)](https://www.npmjs.com/package/@slickgrid-universal/vanilla-bundle) | Vanilla TypeScript/ES6 implementation | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/vanilla-bundle/CHANGELOG.md) -| [@slickgrid-universal/vanilla-force-bundle](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/vanilla-force-bundle) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/vanilla-force-bundle.svg)](https://www.npmjs.com/package/@slickgrid-universal/vanilla-force-bundle) | Vanilla TypeScript/ES6 for Salesforce implementation | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/vanilla-force-bundle/CHANGELOG.md) +| [@slickgrid-universal/common](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/common) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/common.svg)](https://www.npmjs.com/package/@slickgrid-universal/common) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/common?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/common) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/CHANGELOG.md) | +| [@slickgrid-universal/binding](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/binding) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/binding.svg)](https://www.npmjs.com/package/@slickgrid-universal/binding) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/binding?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/binding) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/binding/CHANGELOG.md) | +| [@slickgrid-universal/event-pub-sub](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/event-pub-sub) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/event-pub-sub.svg)](https://www.npmjs.com/package/@slickgrid-universal/event-pub-sub) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/event-pub-sub?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/event-pub-sub) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/event-pub-sub/CHANGELOG.md) | +| [@slickgrid-universal/composite-editor-component](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/composite-editor-component) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/composite-editor-component.svg)](https://www.npmjs.com/package/@slickgrid-universal/composite-editor-component) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/composite-editor-component?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/composite-editor-component) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/composite-editor-component/CHANGELOG.md) | +| [@slickgrid-universal/custom-footer-component](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/custom-footer-component) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/custom-footer-component.svg)](https://www.npmjs.com/package/@slickgrid-universal/custom-footer-component) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/custom-footer-component?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/custom-footer-component) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/custom-footer-component/CHANGELOG.md) | +| [@slickgrid-universal/custom-tooltip-plugin](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/custom-tooltip-plugin) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/custom-tooltip-plugin.svg)](https://www.npmjs.com/package/@slickgrid-universal/custom-tooltip-plugin) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/custom-tooltip-plugin?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/custom-tooltip-plugin) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/custom-tooltip-plugin/CHANGELOG.md) | +| [@slickgrid-universal/empty-warning-component](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/empty-warning-component) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/empty-warning-component.svg)](https://www.npmjs.com/package/@slickgrid-universal/empty-warning-component) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/empty-warning-component?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/empty-warning-component) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/empty-warning-component/CHANGELOG.md) | +| [@slickgrid-universal/pagination-component](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/pagination-component) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/pagination-component.svg)](https://www.npmjs.com/package/@slickgrid-universal/pagination-component) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/pagination-component?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/pagination-component) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/pagination-component/CHANGELOG.md) | +| [@slickgrid-universal/excel-export](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/excel-export) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/excel-export.svg)](https://www.npmjs.com/package/@slickgrid-universal/excel-export) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/excel-export?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/excel-export) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/excel-export/CHANGELOG.md) | +| [@slickgrid-universal/text-export](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/text-export) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/text-export.svg)](https://www.npmjs.com/package/@slickgrid-universal/text-export) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/text-export?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/text-export) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/text-export/CHANGELOG.md) | +| [@slickgrid-universal/graphql](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/graphql) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/graphql.svg)](https://www.npmjs.com/package/@slickgrid-universal/graphql) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/graphql?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/graphql) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/graphql/CHANGELOG.md) | +| [@slickgrid-universal/odata](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/odata) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/odata.svg)](https://www.npmjs.com/package/@slickgrid-universal/odata) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/odata?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/odata) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/odata/CHANGELOG.md) | +| [@slickgrid-universal/row-detail-view-plugin](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/row-detail-view-plugin) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/row-detail-view-plugin.svg)](https://www.npmjs.com/package/@slickgrid-universal/row-detail-view-plugin) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/row-detail-view-plugin?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/row-detail-view-plugin) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/row-detail-view-plugin/CHANGELOG.md) | +| [@slickgrid-universal/rxjs-observable](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/rxjs-observable) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/rxjs-observable.svg)](https://www.npmjs.com/package/@slickgrid-universal/rxjs-observable) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/rxjs-observable?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/rxjs-observable) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/rxjs-observable/CHANGELOG.md) | +| [@slickgrid-universal/utils](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/utils) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/utils.svg)](https://www.npmjs.com/package/@slickgrid-universal/utils) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/utils?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/utils) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/utils/CHANGELOG.md) +| [@slickgrid-universal/vanilla-bundle](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/vanilla-bundle) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/vanilla-bundle.svg)](https://www.npmjs.com/package/@slickgrid-universal/vanilla-bundle) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/vanilla-bundle?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/vanilla-bundle) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/vanilla-bundle/CHANGELOG.md) +| [@slickgrid-universal/vanilla-force-bundle](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/vanilla-force-bundle) | [![npm](https://img.shields.io/npm/v/@slickgrid-universal/vanilla-force-bundle.svg)](https://www.npmjs.com/package/@slickgrid-universal/vanilla-force-bundle) | [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/vanilla-force-bundle?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/vanilla-force-bundle) | [changelog](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/vanilla-force-bundle/CHANGELOG.md) ## Installation **NOTE:** the installation instructions below are **only** required if you want to contribute to this project, however if you just want to download a quick Slickgrid-Universal demo, then I would suggest to take a look at either [Slickgrid-Universal Vite Demo](https://github.com/ghiscoding/slickgrid-universal-vite-demo) or [Slickgrid-Universal WebPack Demo](https://github.com/ghiscoding/slickgrid-universal-webpack-demo). diff --git a/docs/TOC.md b/docs/TOC.md index ffbb77874..f1f8d055d 100644 --- a/docs/TOC.md +++ b/docs/TOC.md @@ -6,6 +6,7 @@ * [Quick start](getting-started/quick-start.md) * [Salesforce (LWC)](getting-started/installation-salesforce.md) +* [Vanilla Installation](getting-started/installation-vanilla.md) ## Styling @@ -18,6 +19,7 @@ * [Editors](column-functionalities/Editors.md) * [new Autocomplete (Kraaden-lib)](column-functionalities/editors/Autocomplete-Editor-(Kraaden-lib).md) * [Date Picker (flatpickr)](column-functionalities/editors/Date-Editor-(flatpickr).md) + * [Date Picker (vanilla-calendar)](column-functionalities/editors/date-editor-(vanilla-calendar).md) * [LongText (textarea)](column-functionalities/editors/LongText-Editor-(textarea).md) * [Select Dropdown Editor (single/multiple)](column-functionalities/editors/Select-Dropdown-Editor-(single,multiple).md) * [Filters](column-functionalities/filters/README.md) @@ -76,3 +78,4 @@ * [Migration Guide to 2.x](migrations/migration-to-2.x.md) * [Migration Guide to 3.x](migrations/migration-to-3.x.md) * [Migration Guide to 4.x](migrations/migration-to-4.x.md) +* [Migration Guide to 5.x](migrations/migration-to-5.x.md) diff --git a/docs/column-functionalities/Cell-Menu.md b/docs/column-functionalities/Cell-Menu.md index 48983d58f..4afffbfd1 100644 --- a/docs/column-functionalities/Cell-Menu.md +++ b/docs/column-functionalities/Cell-Menu.md @@ -38,7 +38,7 @@ this.columnDefinitions = [ console.log(args.dataContext, args.column); // action callback.. do something } }, - { command: 'help', title: 'HELP', iconCssClass: 'fa fa-question-circle', positionOrder: 62 }, + { command: 'help', title: 'HELP', iconCssClass: 'mdi mdi-help-circle', positionOrder: 62 }, // you can add sub-menus by adding nested `commandItems` { // we can also have multiple nested sub-menus @@ -74,8 +74,8 @@ this.columnDefinitions = [ cellMenu: { optionTitle: 'Change Effort Driven Flag', // optional, add title optionItems: [ - { option: true, title: 'True', iconCssClass: 'fa fa-check-square-o' }, - { option: false, title: 'False', iconCssClass: 'fa fa-square-o' }, + { option: true, title: 'True', iconCssClass: 'mdi mdi-check-box-outline' }, + { option: false, title: 'False', iconCssClass: 'mdi mdi-checkbox-blank-outline' }, { divider: true, command: '', positionOrder: 60 }, ], // subscribe to Context Menu onOptionSelected event (or use the "action" callback on each option) @@ -153,7 +153,7 @@ this.columnDefinitions = [ { id: 'action', field: 'action', name: 'Action', cellMenu: { menuUsabilityOverride: (args) => { - const dataContext = args && args.dataContext; + const dataContext = args?.dataContext; return (dataContext.id < 21); // say we want to display the menu only from Task 0 to 20 }, } @@ -163,24 +163,22 @@ this.columnDefinitions = [ To give another example, with Options this time, we could say that we enable the `n/a` option only when the row is Completed. So we could do it this way ```ts -this.columnDefinitions = [ - { id: 'action', field: 'action', name: 'Action', - cellMenu: { - optionItems: [ - { - option: 0, title: 'n/a', textCssClass: 'italic', - // only enable this option when the task is Not Completed - itemUsabilityOverride: (args) => { - const dataContext = args && args.dataContext; - return !dataContext.completed; - }, - { option: 1, iconCssClass: 'fa fa-star-o yellow', title: 'Low' }, - { option: 2, iconCssClass: 'fa fa-star-half-o orange', title: 'Medium' }, - { option: 3, iconCssClass: 'fa fa-star red', title: 'High' }, - ] - } +this.columnDefinitions = [{ + id: 'action', field: 'action', name: 'Action', + cellMenu: { + optionItems: [{ + option: 0, title: 'n/a', textCssClass: 'italic', + // only enable this option when the task is Not Completed + itemUsabilityOverride: (args) => { + const dataContext = args?.dataContext; + return !dataContext.completed; + }, + { option: 1, iconCssClass: 'mdi mdi-star-outline yellow', title: 'Low' }, + { option: 2, iconCssClass: 'mdi mdi-star orange', title: 'Medium' }, + { option: 3, iconCssClass: 'mdi mdi-star red', title: 'High' }, + }] } -]; +}]; ``` ### How to add Translations? @@ -191,9 +189,9 @@ this.columnDefinitions = [ cellMenu: { optionTitleKey: 'COMMANDS', // optionally pass a title to show over the Options optionItems: [ - { option: 1, titleKey: 'LOW', iconCssClass: 'fa fa-star-o yellow' }, - { option: 2, titleKey: 'MEDIUM', iconCssClass: 'fa fa-star-half-o orange' }, - { option: 3, titleKey: 'HIGH', iconCssClass: 'fa fa-star red' }, + { option: 1, titleKey: 'LOW', iconCssClass: 'mdi mdi-star-outline yellow' }, + { option: 2, titleKey: 'MEDIUM', iconCssClass: 'mdi mdi-star orange' }, + { option: 3, titleKey: 'HIGH', iconCssClass: 'mdi mdi-star red' }, ] } } diff --git a/docs/column-functionalities/Editors.md b/docs/column-functionalities/Editors.md index 935b4cf96..eec15e57f 100644 --- a/docs/column-functionalities/Editors.md +++ b/docs/column-functionalities/Editors.md @@ -108,7 +108,7 @@ this.columnDefinitions = [ ]; ``` -So to make it more clear, the `saveOutputType` is the format that will be sent to the `onCellChange` event, then the `outputType` is how the date will show up in the date picker (Flatpickr) and finally the `type` is basically the input format (coming from your dataset). Note however that each property are cascading, if 1 property is missing it will go to the next one until 1 is found... for example, on the `onCellChange` if you aren't defining `saveOutputType`, it will try to use `outputType`, if again none is provided it will try to use `type` and finally if none is provided it will use `FieldType.dateIso` as the default. +So to make it more clear, the `saveOutputType` is the format that will be sent to the `onCellChange` event, then the `outputType` is how the date will show up in the date picker (Vanilla-Calendar) and finally the `type` is basically the input format (coming from your dataset). Note however that each property are cascading, if 1 property is missing it will go to the next one until 1 is found... for example, on the `onCellChange` if you aren't defining `saveOutputType`, it will try to use `outputType`, if again none is provided it will try to use `type` and finally if none is provided it will use `FieldType.dateIso` as the default. ## Perform an action After Inline Edit #### Recommended way @@ -201,9 +201,9 @@ Some of the Editors could receive extra options, which is mostly the case for Ed ```ts this.columnDefinitions = [{ id: 'start', name: 'Start Date', field: 'start', - editor: { + editor: { model: Editors.date, - editorOptions: { minDate: 'today' } + editorOptions: { range: { min: 'today' } } as VanillaCalendarOption } }]; ``` @@ -213,10 +213,10 @@ You could also define certain options as a global level (for the entire grid or ```ts this.gridOptions = { - defaultEditorOptions: { + defaultEditorOptions: { autocompleter: { debounceWaitMs: 150 }, // typed as AutocompleterOption - date: { minDate: 'today' }, - longText: { cols: 50, rows: 5 } + date: { range: { min: 'today' } }, + longText: { cols: 50, rows: 5 } } } ``` diff --git a/docs/column-functionalities/Formatters.md b/docs/column-functionalities/Formatters.md index 752267fb3..d6e0ea991 100644 --- a/docs/column-functionalities/Formatters.md +++ b/docs/column-functionalities/Formatters.md @@ -13,19 +13,18 @@ ### Definition `Formatters` are functions that can be used to change and format certain column(s) in the grid. Please note that it does not alter the input data, it simply changes the styling by formatting the data differently to the screen (what the user visually see). -A good example of a `Formatter` could be a column name `isActive` which is a `boolean` field with input data as `True` or `False`. User would prefer to simply see a checkbox as a visual indication representing the `True` flag, for this behavior you can use `Formatters.checkmark` which will use [Font-Awesome](http://fontawesome.io/icons/) icon of `fa-check` when `True` or an empty string when `False`. +A good example of a `Formatter` could be a column name `isActive` which is a `boolean` field with input data as `True` or `False`. User would prefer to simply see a checkbox as a visual indication representing the `True` flag, for this behavior you can use `Formatters.checkmarkMaterial` which will use optional SVG icons of `mdi-check` when `True` or an empty string when `False`. For a [UI sample](#ui-sample), scroll down below. ### Provided Formatters `Slickgrid-Universal` ships with a few `Formatters` by default which helps with common fields, you can see the [entire list here](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/formatters/index.ts#L37). -> **Note** you might not need a Formatter when a simple CSS style is needed, think about using `cssClass` column property instead. +> **Note** you might not need a Formatter when a simple CSS style and class might be enough, think about using `cssClass` column property as much as possible since it has much better perf. #### List of provided `Formatters` - `arrayObjectToCsv`: Takes an array of complex objects converts it to a comma delimited string. - `arrayToCsv` : takes an array of text and returns it as CSV string -- `checkmark` : uses Font-Awesome [(fa-check)](http://fontawesome.io/icon/check/) - `checkmarkMaterial` use Material Design to display a checkmark icon - `collection`: Looks up values from the columnDefinition.params.collection property and displays the label in CSV or string format - `complexObject`: takes a complex object (with a `field` that has a `.` notation) and pull correct value, there are multiple ways to use it @@ -47,6 +46,7 @@ For a [UI sample](#ui-sample), scroll down below. - `dateTimeUs` : Takes a Date object and displays it as an US Date+Time format (MM/DD/YYYY HH:mm:ss) - `dateTimeShortUs`: Takes a Date object and displays it as an US Date+Time (without seconds) format (MM/DD/YYYY HH:mm:ss) - `dateTimeUsAmPm` : Takes a Date object and displays it as an US Date+Time+(am/pm) format (MM/DD/YYYY hh:mm:ss a) +- `dateUtc` : Takes a Date object and displays it as a TZ format (YYYY-MM-DDThh:mm:ssZ) - `decimal`: Display the value as x decimals formatted, defaults to 2 decimals. You can pass "minDecimal" and/or "maxDecimal" to the "params" property. - `dollar`: Display the value as 2 decimals formatted with dollar sign '$' at the end of of the value. - `dollarColored`: Display the value as 2 decimals formatted with dollar sign '$' at the end of of the value, change color of text to red/green on negative/positive value @@ -71,10 +71,12 @@ For a [UI sample](#ui-sample), scroll down below. - `translateBoolean`: Takes a boolean value, cast it to upperCase string and finally translates it (i18n). - `tree`: Formatter that must be used when the column is a Tree Data column -**Note:** The list might not always be up to date, you can refer to the [Formatters export](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/formatters/index.ts#L37) to know exactly which ones are available. +> **Note:** The list is certainly not up to date (especially for Dates), please refer to the [Formatters export](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/formatters/index.ts#L37) to know exactly which formatters are available. + +> **Note** all Date formatters are formatted using [Tempo](https://tempo.formkit.com/#format-tokens). There are also many more Date formats not shown above, simply visit the [formatters.index](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/formatters/formatters.index.ts#L101) to see all available Date/Time formats. ### Usage -To use any of them, you need to import `Formatters` from `Slickgrid-Universal` and add a `formatter: ...` in your column definitions as shown below: +To use any of them, you simply need to import `Formatters` from `Slickgrid-Universal` and add a `formatter: Formatters.xyz` (where `xyx` is the name of the built-in formatter) in your column definitions as shown below: #### TypeSript ```ts @@ -97,39 +99,7 @@ export class Example { { id: '%', name: '% Complete', field: 'percentComplete', formatter: Formatters.percentComplete }, { id: 'start', name: 'Start', field: 'start', formatter: Formatters.dateIso }, { id: 'finish', name: 'Finish', field: 'finish', formatter: Formatters.dateIso }, - { id: 'effort-driven', name: 'Effort Driven', field: 'effortDriven', formatter: Formatters.checkmark } - ]; - } -} -``` - -#### SalesForce (ES6) -For SalesForce the code is nearly the same, the only difference is to add the `Slicker` prefix, so instead of `Formatters.abc` we need to use `Slicker.Formatters.abc` - -```ts -// ... SF_Slickgrid import - - -export class Example { - const Slicker = window.Slicker; - - columnDefinitions: Column[]; - gridOptions: GridOption; - dataset: any[]; - - constructor() { - // define the grid options & columns and then create the grid itself - this.defineGrid(); - } - - defineGrid() { - this.columnDefinitions = [ - { id: 'title', name: 'Title', field: 'title' }, - { id: 'duration', name: 'Duration (days)', field: 'duration' }, - { id: '%', name: '% Complete', field: 'percentComplete', formatter: Slicker.Formatters.percentComplete }, - { id: 'start', name: 'Start', field: 'start', formatter: Slicker.Formatters.dateIso }, - { id: 'finish', name: 'Finish', field: 'finish', formatter: Slicker.Formatters.dateIso }, - { id: 'effort-driven', name: 'Effort Driven', field: 'effortDriven', formatter: Slicker.Formatters.checkmark } + { id: 'effort-driven', name: 'Effort Driven', field: 'effortDriven', formatter: Formatters.checkmarkMaterial } ]; } } @@ -191,11 +161,13 @@ export interface FormatterResultObject { ``` ### Example of a Custom Formatter with HTML string -For example, we will use `Font-Awesome` with a `boolean` as input data, and display a (fire) icon when `True` or a (snowflake) when `False`. This custom formatter is actually display in the [UI sample](#ui-sample) shown below. + +For example, we will use our optional SVG icons `.mdi` with a `boolean` as input data, and display a (fire) icon when `True` or a (snowflake) when `False`. This custom formatter is actually display in the [UI sample](#ui-sample) shown below. + ```ts // create a custom Formatter with the Formatter type const myCustomCheckboxFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column, dataContext: any) => - value ? `` : ''; + value ? `` : ''; ``` #### Example with `FormatterResultObject` instead of a string @@ -203,7 +175,7 @@ Using this object return type will provide the user the same look and feel, it w ```ts // create a custom Formatter and returning a string and/or an object of type FormatterResultObject const myCustomCheckboxFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column, dataContext: any, grid?: any) => - value ? { addClasses: 'fa fa-fire', text: '', tooltip: 'burning fire' } : ''; + value ? { addClasses: 'mdi mdi-fire', text: '', tooltip: 'burning fire' } : ''; ``` ### Example of Custom Formatter with Native DOM Element @@ -212,7 +184,7 @@ Since version 4.x, you can now also return native DOM element instead of an HTML 2. Performance (the reasons are similar to point 1.) - since it's native it can be appended directly to the grid cell - when it's an HTML string, it has to do 2 extra steps (which is an overhead process) - i. sanitize the string (we use [DOMPurify](https://github.com/cure53/DOMPurify) by default) + i. sanitize the string (when a sanitizer, for example [DOMPurify](https://github.com/cure53/DOMPurify)) ii. SlickGrid then has to convert it to native element by using `innerHTML` on the grid cell Demo diff --git a/docs/column-functionalities/editors/Autocomplete-Editor-(Kraaden-lib).md b/docs/column-functionalities/editors/Autocomplete-Editor-(Kraaden-lib).md index f669b165a..7af780e4a 100644 --- a/docs/column-functionalities/editors/Autocomplete-Editor-(Kraaden-lib).md +++ b/docs/column-functionalities/editors/Autocomplete-Editor-(Kraaden-lib).md @@ -276,11 +276,6 @@ export class GridBasicComponent { editorOptions: { showOnFocus: true, minLength: 1, - classes: { - // choose a custom style layout - // 'ui-autocomplete': 'autocomplete-custom-two-rows', - 'ui-autocomplete': 'autocomplete-custom-four-corners', - }, fetch: (searchText, updateCallback) => { yourAsyncApiCall(searchText) // typically you'll want to return no more than 10 results .then(result => updateCallback((results.length > 0) ? results : [{ label: 'No match found.', value: '' }]); }) diff --git a/docs/column-functionalities/editors/Date-Editor-(flatpickr).md b/docs/column-functionalities/editors/Date-Editor-(flatpickr).md index e3b430a1a..743c6e35d 100644 --- a/docs/column-functionalities/editors/Date-Editor-(flatpickr).md +++ b/docs/column-functionalities/editors/Date-Editor-(flatpickr).md @@ -41,8 +41,8 @@ You could also define certain options as a global level (for the entire grid or ```ts this.gridOptions = { - defaultEditorOptions: { - date: { minDate: 'today' }, // typed as FlatpickrOption + defaultEditorOptions: { + date: { range: { min: 'today' } }, // typed as FlatpickrOption } } ``` diff --git a/docs/column-functionalities/editors/Select-Dropdown-Editor-(single,multiple).md b/docs/column-functionalities/editors/Select-Dropdown-Editor-(single,multiple).md index bd7fdd9a0..7e1026e56 100644 --- a/docs/column-functionalities/editors/Select-Dropdown-Editor-(single,multiple).md +++ b/docs/column-functionalities/editors/Select-Dropdown-Editor-(single,multiple).md @@ -36,14 +36,21 @@ this.columnDefinitions = [ ``` ### Editor Options (`MultipleSelectOption` interface) -All the available options that can be provided as `editorOptions` to your column definitions can be found under this [multipleSelectOption interface](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/interfaces/multipleSelectOption.interface.ts) and you should cast your `editorOptions` to that interface to make sure that you use only valid options of the `multiple-select.js` library. +All the available options that can be provided as `editorOptions` to your column definitions via the `MultipleSelectOption` interface of the external library and so you should cast your `editorOptions` to that interface to make sure that you use only valid options of the `Multiple-Select-Vanilla` library. ```ts -editor: { - model: Editors.SingleSelect, - editorOptions: { - maxHeight: 400 - } as MultipleSelectOption +import { MultipleSelectOption } from 'multiple-select-vanilla'; + +prepareGrid() { + this.columnDefinitions = [{ + id: 'isActive', name: 'Active', field: 'isActive', + editor: { + model: Editors.singleSelect, + editorOptions: { + maxHeight: 400 + } as MultipleSelectOption + } + }]; } ``` @@ -52,7 +59,7 @@ You could also define certain options as a global level (for the entire grid or ```ts this.gridOptions = { - defaultEditorOptions: { + defaultEditorOptions: { // Note: that `select` combines both multipleSelect & singleSelect select: { minHeight: 350 }, // typed as MultipleSelectOption } @@ -163,7 +170,7 @@ this.columnDefinitions = [ editor: { // display checkmark icon when True enableRenderHtml: true, - collection: [{ value: '', label: '' }, { value: true, label: 'True', labelPrefix: ` ` }, { value: false, label: 'False' }], + collection: [{ value: '', label: '' }, { value: true, label: 'True', labelPrefix: ` ` }, { value: false, label: 'False' }], model: Editors.singleSelect } } @@ -224,6 +231,3 @@ this.columnDefinitions = [ } ]; ``` - -### Change Default DOMPurify Options (sanitize html) -If you find that the HTML that you passed is being sanitized and you wish to change it, then you can change the default `sanitizeHtmlOptions` property defined in the Global Grid Options, for more info on how to change these global options, see the `Global Grid Options` and also take a look at the [GitHub - DOMPurify](https://github.com/cure53/DOMPurify#can-i-configure-it) configurations. diff --git a/docs/column-functionalities/editors/date-editor-(vanilla-calendar).md b/docs/column-functionalities/editors/date-editor-(vanilla-calendar).md new file mode 100644 index 000000000..9b0e29d1d --- /dev/null +++ b/docs/column-functionalities/editors/date-editor-(vanilla-calendar).md @@ -0,0 +1,72 @@ +##### index +- [Editor Options](#editor-options) +- [Custom Validator](#custom-validator) +- See the [Editors - Wiki](../Editors.md) for more general info about Editors (validators, event handlers, ...) + +### Information +The Date Editor is provided through an external library named [Vanilla-Calendar-Picker](https://github.com/ghiscoding/vanilla-calendar-picker) (a fork of [Vanilla-Calendar-Pro](https://vanilla-calendar.pro)) and all options from that library can be added to your `editorOptions` (see below), so in order to add things like minimum date, disabling dates, ... just review all the [Vanilla-Calendar-Pro](https://vanilla-calendar.pro/docs/reference/additionally/settings) and then add them into `editorOptions`. We use [Tempo](https://tempo.formkit.com/) to parse and format Dates to the chosen format (when `type`, `outputType` and/or `saveType` are provided in your column definition) + +> **Note** Also just so you know, `editorOptions` is used by all other editors as well to expose external library like Autocompleter, Multiple-Select, etc... + +### Demo +[Demo Page](https://ghiscoding.github.io/slickgrid-universal/#/example12) | [Demo Component](https://github.com/ghiscoding/slickgrid-universal/blob/master/examples/webpack-demo-vanilla-bundle/src/examples/example12.ts) + +### Editor Options +You can use any of the Vanilla-Calendar [settings](https://vanilla-calendar.pro/docs/reference/additionally/settings) by adding them to `editorOptions` as shown below. + +> **Note** for easier implementation, you should import `VanillaCalendarOption` from Slickgrid-Universal common package. + +```ts +import { type VanillaCalendarOption } from '@slickgrid-universal/common'; + +prepareGrid() { + this.columnDefinitions = [ + { + id: 'title', name: 'Title', field: 'title', + editor: { + model: Editors.date, + editorOptions: { + range: { + max: 'today', + disabled: ['2022-08-15', '2022-08-20'], + } + } as VanillaCalendarOption, + }, + }, + ]; +} +``` + +#### Grid Option `defaultEditorOptions +You could also define certain options as a global level (for the entire grid or even all grids) by taking advantage of the `defaultEditorOptions` Grid Option. Note that they are set via the editor type as a key name (`autocompleter`, `date`, ...) and then the content is the same as `editorOptions` (also note that each key is already typed with the correct editor option interface), for example + +```ts +this.gridOptions = { + defaultEditorOptions: { + date: { range: { min: 'today' } }, // typed as VanillaCalendarOption + } +} +``` + +### Custom Validator +You can add a Custom Validator from an external function or inline (inline is shown below and comes from [Example 12](https://ghiscoding.github.io/slickgrid-universal/#/example12)) +```ts +initializeGrid() { + this.columnDefinitions = [ + { + id: 'title', name: 'Title', field: 'title', + editor: { + model: Editors.date, + required: true, + validator: (value, args) => { + const dataContext = args && args.item; + if (dataContext && (dataContext.completed && !value)) { + return { valid: false, msg: 'You must provide a "Finish" date when "Completed" is checked.' }; + } + return { valid: true, msg: '' }; + } + }, + }, + ]; +} +``` \ No newline at end of file diff --git a/docs/column-functionalities/filters/Compound-Filters.md b/docs/column-functionalities/filters/Compound-Filters.md index 8c5caebd8..bd268a26c 100644 --- a/docs/column-functionalities/filters/Compound-Filters.md +++ b/docs/column-functionalities/filters/Compound-Filters.md @@ -3,7 +3,6 @@ - [SASS Styling](#sass-styling) - [Compound Input Filter](#how-to-use-compoundinput-filter) - [Compound Date Filter](#how-to-use-compounddate-filter) - - [Filter Options (`FlatpickrOption` interface)](#filter-options-flatpickroption-interface) - [Compound Operator List (custom list)](#compound-operator-list-custom-list) - [Compound Operator Alternate Texts](#compound-operator-alternate-texts) - [Filter Complex Object](../Input-Filter.md#how-to-filter-complex-objects) @@ -11,7 +10,7 @@ - [How to avoid filtering when only Operator dropdown is changed?](#how-to-avoid-filtering-when-only-operator-dropdown-is-changed) ### Description -Compound filters are a combination of 2 elements (Operator Select + Input Filter) used as a filter on a column. This is very useful to make it obvious to the user that there are Operator available and even more useful with a date picker (`Flatpickr`). +Compound filters are a combination of 2 elements (Operator Select + Input Filter) used as a filter on a column. This is very useful to make it obvious to the user that there are Operator available and even more useful with a date picker (`Vanilla-Calendar`). ### Demo [Demo Page](https://ghiscoding.github.io/slickgrid-universal/#/example02) / [Demo Component](https://github.com/ghiscoding/slickgrid-universal/blob/master/examples/webpack-demo-vanilla-bundle/src/examples/example02.ts) @@ -21,11 +20,11 @@ There are multiple types of compound filters available 1. `Filters.compoundInputText` adds an Operator combine to an Input of type `text` (alias to `Filters.compoundInput`). 2. `Filters.compoundInputNumber` adds an Operator combine to an Input of type `number`. 3. `Filters.compoundInputPassword` adds an Operator combine to an Input of type `password. -4. `Filters.compoundDate` adds an Operator combine to a Date Picker (flatpickr). +4. `Filters.compoundDate` adds an Operator combine to a Date Picker (Vanilla-Calendar). 5. `Filters.compoundSlider` adds an Operator combine to a Slider Filter. ### SASS Styling -You can change the `$flatpickr-bgcolor` and any of the `$compound-filter-X` SASS [variables](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/styles/_variables.scss#L660) for styling. For more info on how to use SASS in your project, read the [Wiki - Styling](../../styling/styling.md) +You can change some of the SASS [variables](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/styles/_variables.scss#L648) for styling. For more info on how to use SASS in your project, read the [Wiki - Styling](../../styling/styling.md) ### How to use CompoundInput Filter Simply set the flag `filterable` to True and use the filter type `Filters.compoundInput`. Here is an example with a full column definition: @@ -52,7 +51,7 @@ The column definition `type` will affect the list of Operators shown, for exampl ### How to use CompoundDate Filter -Again set the column definition flag `filterable: true` and use the filter type `Filters.compoundDate`. Here is an example with a full column definition: +As any other columns, set the column definition flag `filterable: true` and use the filter type `Filters.compoundDate`. Here is an example with a full column definition: ```ts // define you columns, in this demo Effort Driven will use a Select Filter this.columnDefinitions = [ @@ -76,6 +75,8 @@ this.gridOptions = { }; ``` +> **Note** we use [Tempo](https://tempo.formkit.com/) to parse and format Dates to the chosen format via the `type` option when provided in your column definition. + #### Dealing with different input/ouput dates (example: UTC) What if your date input (from your dataset) has a different output on the screen (UI)? In that case, you will most probably have a Formatter and type representing the input type, we also provided an `outputType` that can be used to deal with that case. @@ -125,15 +126,15 @@ this.gridOptions = { }; ``` -#### Filter Options (`FlatpickrOption` interface) -All the available options that can be provided as `filterOptions` to your column definitions can be found under this [FlatpickrOption interface](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/interfaces/flatpickrOption.interface.ts) and you should cast your `filterOptions` to that interface to make sure that you use only valid options of the [Flatpickr](https://flatpickr.js.org/) library. +#### Filter Options (`VanillaCalendarOption` interface) +All the available options that can be provided as `filterOptions` to your column definitions can be found under this [VanillaCalendarOption interface](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/interfaces/vanillaCalendarOption.interface.ts) and you should cast your `filterOptions` with the expected interface to make sure that you use only valid settings of the [Vanilla-Calendar](https://vanilla-calendar.pro/docs/reference/additionally/settings) library. ```ts filter: { model: Filters.compoundDate, filterOptions: { - minDate: 'today' - } as FlatpickrOption + range: { min: 'today' } + } as VanillaCalendarOption } ``` @@ -142,10 +143,10 @@ You could also define certain options as a global level (for the entire grid or ```ts this.gridOptions = { - defaultFilterOptions: { + defaultFilterOptions: { // Note: that `date`, `select` and `slider` are combining both compound & range filters together - date: { minDate: 'today' }, - select: { minHeight: 350 }, // typed as MultipleSelectOption + date: { range: { min: 'today' } }, // typed as VanillaCalendarOption + select: { minHeight: 350 }, // typed as MultipleSelectOption slider: { sliderStartValue: 10 } } } diff --git a/docs/column-functionalities/filters/Range-Filters.md b/docs/column-functionalities/filters/Range-Filters.md index 0c1a26d19..0a204da01 100644 --- a/docs/column-functionalities/filters/Range-Filters.md +++ b/docs/column-functionalities/filters/Range-Filters.md @@ -4,11 +4,10 @@ - [Using a Slider Range](#using-a-slider-range-filter) - [Filter Options](#filter-options) - [Using a Date Range](#using-a-date-range-filter) - - [Filter Options (`FlatpickrOption` interface)](#filter-options-flatpickroption-interface) - [Update Filters Dynamically](Input-Filter.md#update-filters-dynamically) ### Introduction -Range filters allows you to search for a value between 2 min/max values, the 2 most common use case would be to filter between 2 numbers or dates, you can do that with the new Slider & Date Range Filters. The range can also be defined as inclusive (`>= 0 and <= 10`) or exclusive (`> 0 and < 10`), the default is exclusive but you can change that, see below for more info. +Range filters allows you to search for a value between 2 min/max values, the 2 most common use case would be to filter between 2 numbers or dates, you can do that with the Slider & Date Range Filters. The range can also be defined as inclusive (`>= 0 and <= 10`) or exclusive (`> 0 and < 10`), the default is exclusive but you can change that, see below for more info. ### Using an Inclusive Range (default is Exclusive) By default all the range filters are with exclusive range, which mean between value `x` and `y` but without including them. If you wish to include the `x` and `y` values, you can change that through the `operator` property. @@ -123,9 +122,9 @@ You could also define certain options as a global level (for the entire grid or ```ts this.gridOptions = { - defaultFilterOptions: { + defaultFilterOptions: { // Note: that `date`, `select` and `slider` are combining both compound & range filters together - date: { minDate: 'today' }, + date: { range: { min: 'today' } }, select: { minHeight: 350 }, // typed as MultipleSelectOption slider: { sliderStartValue: 10 } } @@ -133,10 +132,12 @@ this.gridOptions = { ``` ### Using a Date Range Filter -The date range filter allows you to search data between 2 dates (it uses [Flatpickr Range](https://flatpickr.js.org/examples/#range-calendar) feature). +The date range filter allows you to search data between 2 dates (it uses [Vanilla-Calendar Range](https://vanilla-calendar.pro/) feature). + +> **Note** we use [Tempo](https://tempo.formkit.com/) to parse and format Dates to the chosen format via the `type` option when provided in your column definition. ##### Component -import { Filters, FlatpickrOption, Formatters, GridOption, OperatorType } from '@slickgrid-universal/common'; +import { Filters, Formatters, GridOption, OperatorType, VanillaCalendarOption } from '@slickgrid-universal/common'; ```typescript export class GridBasicComponent { @@ -148,14 +149,16 @@ export class GridBasicComponent { // your columns definition this.columnDefinitions = [ { - id: 'finish', name: 'Finish', field: 'finish', headerKey: 'FINISH', formatter: Formatters.dateIso, sortable: true, minWidth: 75, width: 120, exportWithFormatter: true, + id: 'finish', name: 'Finish', field: 'finish', headerKey: 'FINISH', + minWidth: 75, width: 120, exportWithFormatter: true, + formatter: Formatters.dateIso, sortable: true, type: FieldType.date, filterable: true, filter: { model: Filters.dateRange, - // override any of the Flatpickr options through "filterOptions" - editorOptions: { minDate: 'today' } as FlatpickrOption + // override any of the Vanilla-Calendar options through "filterOptions" + editorOptions: { range: { min: 'today' } } as VanillaCalendarOption } }, ]; @@ -167,14 +170,14 @@ export class GridBasicComponent { } ``` -##### Filter Options (`FlatpickrOption` interface) -All the available options that can be provided as `filterOptions` to your column definitions can be found under this [FlatpickrOption interface](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/interfaces/flatpickrOption.interface.ts) and you should cast your `filterOptions` to that interface to make sure that you use only valid options of the [Flatpickr](https://flatpickr.js.org/) library. +#### Filter Options (`VanillaCalendarOption` interface) +All the available options that can be provided as `filterOptions` to your column definitions can be found under this [VanillaCalendarOption interface](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/interfaces/vanillaCalendarOption.interface.ts) and you should cast your `filterOptions` with the expected interface to make sure that you use only valid settings of the [Vanilla-Calendar](https://vanilla-calendar.pro/docs/reference/additionally/settings) library. ```ts filter: { - model: Filters.dateRange, + model: Filters.compoundDate, filterOptions: { - minDate: 'today' - } as FlatpickrOption + range: { min: 'today' } + } as VanillaCalendarOption } ``` diff --git a/docs/column-functionalities/filters/Select-Filter.md b/docs/column-functionalities/filters/Select-Filter.md index 40872a9a5..aaaa86498 100644 --- a/docs/column-functionalities/filters/Select-Filter.md +++ b/docs/column-functionalities/filters/Select-Filter.md @@ -416,17 +416,13 @@ this.columnDefinitions = [ filter: { // display checkmark icon when True enableRenderHtml: true, - collection: [{ value: '', label: '' }, { value: true, label: 'True', labelPrefix: ` ` }, { value: false, label: 'False' }], + collection: [{ value: '', label: '' }, { value: true, label: 'True', labelPrefix: ` ` }, { value: false, label: 'False' }], model: Filters.singleSelect } } ]; ``` -#### Change Default DOMPurify Options (sanitize html) -If you find that the HTML that you passed is being sanitized and you wish to change it, then you can change the default `sanitizeHtmlOptions` property defined in the Global Grid Options, for more info on how to change these [global options](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/global-grid-options.ts). - - ### Collection Add Blank Entry In some cases a blank entry at the beginning of the collection could be useful, the most common example for this is to use the first option as a blank entry to tell our Filter to show everything. So for that we can use the `addBlankEntry` flag in `collectionOptions @@ -554,14 +550,21 @@ this.columnDefinitions = [ ``` ### Filter Options (`MultipleSelectOption` interface) -All the available options that can be provided as `filterOptions` to your column definitions can be found under this [multipleSelectOption interface](/ghiscoding/slickgrid-universal/tree/master/packages/common/src/interfaces/multipleSelectOption.interface.ts) and you should cast your `filterOptions` to that interface to make sure that you use only valid options of the `multiple-select.js` library. +All the available options that can be provided as `filterOptions` to your column definitions via the `MultipleSelectOption` interface of the external library and so you should cast your `filterOptions` to that interface to make sure that you use only valid options of the `Multiple-Select-Vanilla` library. ```ts -filter: { - model: Filters.singleSelect, - filterOptions: { - maxHeight: 400 - } as MultipleSelectOption +import { MultipleSelectOption } from 'multiple-select-vanilla'; + +prepareGrid() { + this.columnDefinitions = [{ + id: 'isActive', name: 'Active', field: 'isActive', + filter: { + model: Filters.singleSelect, + filterOptions: { + maxHeight: 400 + } as MultipleSelectOption + } + }]; } ``` @@ -570,7 +573,7 @@ You could also define certain options as a global level (for the entire grid or ```ts this.gridOptions = { - defaultFilterOptions: { + defaultFilterOptions: { // Note: that `select` combines both multipleSelect & singleSelect select: { minHeight: 350 }, // typed as MultipleSelectOption } @@ -598,53 +601,61 @@ Couple of small options were added to suit SlickGrid-Universal needs, which is w ##### Code ```typescript -this.columnDefinitions = [ - { - id: 'isActive', name: 'Is Active', field: 'isActive', - filterable: true, - filter: { - collection: [{ value: '', label: '' }, { value: true, label: 'true' }, { value: false, label: 'false' }], - model: Filters.singleSelect, - filterOptions: { - // add any multiple-select.js options (from original or custom version) - autoAdjustDropPosition: false, // by default set to True, but you can disable it - position: 'top' - } as MultipleSelectOption +import { MultipleSelectOption } from 'multiple-select-vanilla'; + +prepareGrid() { + this.columnDefinitions = [ + { + id: 'isActive', name: 'Is Active', field: 'isActive', + filterable: true, + filter: { + collection: [{ value: '', label: '' }, { value: true, label: 'true' }, { value: false, label: 'false' }], + model: Filters.singleSelect, + filterOptions: { + // add any multiple-select.js options (from original or custom version) + autoAdjustDropPosition: false, // by default set to True, but you can disable it + position: 'top' + } as MultipleSelectOption + } } - } -]; + ]; +} ``` #### Display shorter selected label text If we find that our text shown as selected text is too wide, we can choose change that by using `optionLabel` in Custom Structure. ```typescript -this.columnDefinitions = [ - { - id: 'isActive', name: 'Is Active', field: 'isActive', - filterable: true, - filter: { - collection: [ - { value: 1, label: '1', suffix: 'day' }, - { value: 2, label: '2', suffix: 'days' }, - { value: 3, label: '3', suffix: 'days' }, - // ... - ], - model: Filters.multipleSelect, - customStructure: { - label: 'label', - labelSuffix: 'suffix', - value: 'value', - optionLabel: 'value', // use value instead to show "1, 2" instead of "1 day, 2 days" - }, - filterOptions: { - // use different label to show as selected text - // please note the Custom Structure with optionLabel defined - // or use "useSelectOptionLabelToHtml" to render HTML - useSelectOptionLabel: true - } as MultipleSelectOption +import { MultipleSelectOption } from 'multiple-select-vanilla'; + +prepareGrid() { + this.columnDefinitions = [ + { + id: 'isActive', name: 'Is Active', field: 'isActive', + filterable: true, + filter: { + collection: [ + { value: 1, label: '1', suffix: 'day' }, + { value: 2, label: '2', suffix: 'days' }, + { value: 3, label: '3', suffix: 'days' }, + // ... + ], + model: Filters.multipleSelect, + customStructure: { + label: 'label', + labelSuffix: 'suffix', + value: 'value', + optionLabel: 'value', // use value instead to show "1, 2" instead of "1 day, 2 days" + }, + filterOptions: { + // use different label to show as selected text + // please note the Custom Structure with optionLabel defined + // or use "useSelectOptionLabelToHtml" to render HTML + useSelectOptionLabel: true + } as MultipleSelectOption + } } - } -]; + ]; +} ``` ### Query against another field property diff --git a/docs/column-functionalities/filters/Styling-Filled-Filters.md b/docs/column-functionalities/filters/Styling-Filled-Filters.md index 8ac7c970b..895d103f0 100644 --- a/docs/column-functionalities/filters/Styling-Filled-Filters.md +++ b/docs/column-functionalities/filters/Styling-Filled-Filters.md @@ -1,55 +1,45 @@ -You can style any (or all) of the Filter(s) when they have value, the lib will automatically add a `filled` CSS class which you can style as your wish. There is no style by default, if you wish to add styling, you will be required to add your own. +You can style any (or all) of the Filter(s) when they have value, the lib will automatically add a `filled` CSS class which you can style as your wish. There is no style by default, if you wish to add styling, you will be required to add your own. -## Styled Example +## Styled Example ![grid_filled_styling](https://user-images.githubusercontent.com/643976/51334569-14306d00-1a4e-11e9-816c-439796eb8a59.png) ## Code example -For example, the print screen shown earlier was styled using this piece of SASS (`.scss`) code. Also note that the demo adds a Font-Awesome icon which can be used with `font-family: "FontAwesome"` and the relevent unicode character, for example the filter icon is `content: " \f0b0"`. You can basically add a lot of different styling to your populated filters. +For example, the print screen shown earlier was styled using this piece of SASS (`.scss`) code. You can customize the styling to your liking. ```scss -$filter-filled-bg-color: darkorange; - -.search-filter.filled { - // color: rgb(189, 104, 1); - // font-weight: bold; - background-color: $filter-filled-bg-color; - .ms-choice { - // color: rgb(189, 104, 1); - // font-weight: bold; - background-color: $filter-filled-bg-color; - } - - - input, input.flatpickr-input { - // border: 1px solid darken(rgb(204, 204, 204), 15%) !important; - // color: rgb(189, 104, 1); - // font-weight: bold; - background-color: $filter-filled-bg-color !important; +$slick-filled-filter-color: $slick-form-control-focus-border-color; +$slick-filled-filter-border: $slick-form-control-border; +$slick-filled-filter-box-shadow: $slick-form-control-focus-border-color; +$slick-filled-filter-font-weight: 400; + +.slick-headerrow { + input.search-filter.filled, + .search-filter.filled input, + .search-filter.filled .date-picker input, + .search-filter.filled .input-group-addon.slider-value, + .search-filter.filled .input-group-addon.slider-range-value, + .search-filter.filled .input-group-addon select { + color: $slick-filled-filter-color; + font-weight: $slick-filled-filter-font-weight; + border: $slick-filled-filter-border; + box-shadow: $slick-filled-filter-box-shadow; + &.input-group-prepend { + border-right: 0; + } + &.input-group-append { + border-left: 0; + } } - /* - &.ms-parent, .flatpickr > input, .input-group > input { - border: 1px solid darken(rgb(204, 204, 204), 15%) !important; - } - */ - - div.flatpickr:after, button > div:after, & + span:after, .input-group > span:after { - font-family: "FontAwesome"; - font-size: 75%; - content: " \f0b0"; - position: absolute; - top: 2px; - right: 5px; - z-index: 1000; - color: #ca880f; - } - - .ms-choice > div:after { - top: -4px; - right: 16px; + .search-filter.filled .input-group-prepend select { + border-right: 0; } - & + span:after { - top: 6px; - right: 10px; + .search-filter.filled .ms-choice { + box-shadow: $slick-filled-filter-box-shadow; + border:$slick-filled-filter-border; + span { + font-weight: $slick-filled-filter-font-weight; + color: $slick-filled-filter-color; + } } } ``` diff --git a/docs/developer-guides/csp-compliance.md b/docs/developer-guides/csp-compliance.md index adfb74c39..4c58f2bba 100644 --- a/docs/developer-guides/csp-compliance.md +++ b/docs/developer-guides/csp-compliance.md @@ -1,7 +1,20 @@ ## CSP Compliance -The library is now, at least mostly, CSP (Content Security Policy) compliant since `v4.0`, however there are some exceptions to be aware of. When using any html string as template (for example with Custom Formatter returning an html string), you will not be fully compliant unless you return `TrustedHTML`. You can achieve this by using the `sanitizer` method in combo with [DOMPurify](https://github.com/cure53/DOMPurify) to return `TrustedHTML` as shown below and with that in place you should be CSP compliant. +The library is for the most part CSP (Content Security Policy) compliant since `v4.0` **but** only if you configure the `sanitizer` grid option. We were previously using `DOMPurify` internally in the project (in version <=4.x) but it was made optional in version 5 and higher. The main reason to make it optional was because most users would use `dompurify` but some users who require SSR support would want to use `isomorphic-dompurify`. You could also skip the `sanitizer` configuration, but that is not recommended. -> **Note** the default sanitizer in Slickgrid-Universal is actually already configured to return `TrustedHTML` but the CSP safe in the DataView is opt-in via `useCSPSafeFilter` +> **Note** even if the `sanitizer` is optional, we **strongly suggest** that you configure it as a global grid option to avoid possible XSS attacks from your data and also to be CSP compliant. Note that for Salesforce users, you do not have to configure it since Salesforce already use DOMPurify internally. + +As mentioned above, the project is mostly CSP compliant, however there are some exceptions to be aware of. When using any html string as template (for example with Custom Formatter returning an html string), you will not be fully compliant unless you return `TrustedHTML`. You can achieve this by using the `sanitizer` method in combo with [DOMPurify](https://github.com/cure53/DOMPurify) to return `TrustedHTML` as shown below and with that in place you should be CSP compliant. + +```diff +// prefer the global grid options if possible +this.gridOptions = { + sanitizer: (dirtyHtml) => DOMPurify.sanitize(dirtyHtml, { ADD_ATTR: ['level'], RETURN_TRUSTED_TYPE: true }) +}; +``` + +> **Note** If you're wondering about the `ADD_ATTR: ['level']`, well the "level" is a custom attribute used by SlickGrid Grouping/Draggable Grouping to track the grouping level depth and it must be kept. + +> **Note** the DataView is not CSP safe by default, it is opt-in via the `useCSPSafeFilter` option. ```typescript import DOMPurify from 'dompurify'; @@ -15,7 +28,9 @@ this.gridOptions = { } this.sgb = new Slicker.GridBundle(gridContainerElm, this.columnDefinitions, this.gridOptions, this.dataset); ``` + with this code in place, we can use the following CSP meta tag (which is what we use in the lib demo, ref: [index.html](https://github.com/ghiscoding/slickgrid-universal/blob/master/examples/vite-demo-vanilla-bundle/index.html#L8-L14)) + ```html ``` diff --git a/docs/getting-started/installation-vanilla.md b/docs/getting-started/installation-vanilla.md new file mode 100644 index 000000000..155ce5985 --- /dev/null +++ b/docs/getting-started/installation-vanilla.md @@ -0,0 +1,112 @@ +# Quick start + +> **NOTE** these instructions are for the latest v5.x and might differ from earlier versions of the lib. + +### 1. Install NPM Package +Install the `Angular-Slickgrid`, and other external packages like `Bootstrap` and `Font-Awesome` +(Bootstrap, Font-Awesome are optional, you can choose other lib if you wish) +```bash +npm install --save @slickgrid-universal/common + +# install whichever UI framework you want to use like Bootstrap, Bulma, ... +npm install bootstrap +``` + +### 2. Create a basic grid +And finally, you are now ready to use it in your project, for example let's create both html/ts files for a basic example. + +##### 1. define a grid container in your View +```html +

My First Grid

+ +
+
+``` + +##### 2. configure the Column Definitions, Grid Options and pass a Dataset to the grid +below we use `mounted`, but it could be totally different dependending on what framework you use (it could be `mounted`, `attached`, `onRender`, ...) + +```ts +import { Column, GridOption, Slicker } from '@slickgrid-universal/common'; + +export class GridBasicComponent { + columnDefinitions: Column[] = []; + gridOptions: GridOption = {}; + + constructor() { + this.prepareGrid(); + } + + mounted() { + const container = document.querySelector(`.grid1`) as HTMLDivElement; + this.sgb = new Slicker.GridBundle(container, this.columnDefinitions, this.getData()); + } + + getData() { + // ... + } + + prepareGrid() { + this.columnDefinitions = [ + { id: 'title', name: 'Title', field: 'title', sortable: true }, + { id: 'duration', name: 'Duration (days)', field: 'duration', sortable: true }, + { id: '%', name: '% Complete', field: 'percentComplete', sortable: true }, + { id: 'start', name: 'Start', field: 'start' }, + { id: 'finish', name: 'Finish', field: 'finish' }, + ]; + + this.gridOptions = { + enableAutoResize: true, + enableSorting: true + }; + + // fill the dataset with your data (or read it from the DB) + this.dataset = [ + { id: 0, title: 'Task 1', duration: 45, percentComplete: 5, start: '2001-01-01', finish: '2001-01-31' }, + { id: 1, title: 'Task 2', duration: 33, percentComplete: 34, start: '2001-01-11', finish: '2001-02-04' }, + ]; + } +} +``` + +### 3. CSS / SASS Styles +Load your prefered theme, choose between Bootstrap (default), Material or Salesforce themes. You can also customize them to your taste (either by using SASS or CSS variables). + +#### CSS +Default compiled `css`, you can load it through HTML or import it in your JS code depending on your project. + +```html +# Bootstrap Theme + +``` + +> **Note** to use a different theme, simply replace the theme suffix, for example `"slickgrid-theme-material.css"` for the Material Theme. + +#### SASS (scss) +You could also compile the SASS files with your own customization, for that simply take any of the [_variables.scss](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/styles/_variables.scss) (without the `!default` flag) variable file and make sure to import the Bootstrap Theme afterward. For example, you could modify your `style.scss` with the following changes: + +```scss +/* for example, let's change the mouse hover color */ +$cell-odd-background-color: lightyellow; +$row-mouse-hover-color: lightgreen; + +/* make sure to add the @import the SlickGrid Theme AFTER the variables changes */ +@import '@slickgrid-universal/common/dist/styles/sass/slickgrid-theme-bootstrap.scss'; +``` + +### 4. Explore the Documentation +The last step is really to explore all the pages that are available on the documentation website which are often updated. For example a good starter is to look at the following +- all the `Grid Options` you can take a look at, [Slickgrid-Universal - Grid Options](https://github.com/ghiscoding/angular-slickgrid/blob/master/src/app/modules/angular-slickgrid/models/gridOption.interface.ts) interface +- [Formatters](../column-functionalities/Formatters.md) +- [Editors](../column-functionalities/Editors.md) +- [Filters](../column-functionalities/filters/Select-Filter.md) +- [Grid Menu](../grid-functionalities/Grid-Menu.md) +... and much more, just explorer the Documentation through the table of content (on your left) + +### 5. Get Started +The best way to get started is to clone either the [Slickgrid-Universal Vite Demo](https://github.com/ghiscoding/slickgrid-universal-vite-demo) or [Slickgrid-Universal WebPack Demo](https://github.com/ghiscoding/slickgrid-universal-webpack-demo). + +##### All Live Demo Examples have links to the actual code +If you would like to see the code to a particular Example. Just click on the "see code" that is available in every live examples. + +... and that should cover it, now let's code! \ No newline at end of file diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index e5fbfad0f..1175f79b7 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -9,8 +9,9 @@ To get started follow any of these instruction Wikis depending on your choice of | Angular | [Wiki - HOWTO (Step by Step)](https://ghiscoding.gitbook.io/angular-slickgrid/getting-started/quick-start) | [Live Demo](https://ghiscoding.github.io/Angular-Slickgrid/) | | Aurelia | [Wiki - HOWTO (Step by Step)](https://ghiscoding.gitbook.io/aurelia-slickgrid/getting-started/quick-start) | [Live Demo](https://ghiscoding.github.io/aurelia-slickgrid/) | | React | [Wiki - HOWTO (Step by Step)](https://ghiscoding.gitbook.io/slickgrid-react/getting-started/quick-start) | [Live Demo](https://ghiscoding.github.io/slickgrid-react/) | -| Salesforce | Installation | [Print Screen](https://github.com/ghiscoding/slickgrid-universal/wiki#salesforce-demo---print-screen) | +| Salesforce | [Salesforce Installation](./installation-salesforce.md) | [Print Screen](https://github.com/ghiscoding/slickgrid-universal/wiki#salesforce-demo---print-screen) | | ---- | | | +| Vanilla | [Installation (Step by Step)](./installation-vanilla.md) | | | ---- | | | **General Subjects** diff --git a/docs/grid-functionalities/Composite-Editor-Modal.md b/docs/grid-functionalities/Composite-Editor-Modal.md index 19aa2f983..e8b9ec0d7 100644 --- a/docs/grid-functionalities/Composite-Editor-Modal.md +++ b/docs/grid-functionalities/Composite-Editor-Modal.md @@ -467,6 +467,7 @@ export class GridExample { if (columnDef.id === 'completed') { this.compositeEditorInstance.changeFormEditorOption('percentComplete', 'filter', formValues.completed); this.compositeEditorInstance.changeFormEditorOption('product', 'minLength', 3); + this.compositeEditorInstance.changeFormEditorOption('finish', 'range', { min: 'today' }); } } } @@ -496,9 +497,9 @@ export class GridExample { // you can also change some editor options // not all Editors supports this functionality, so far only these Editors are supported: AutoComplete, Date, Single/Multiple Select if (columnDef.id === 'completed') { - this.compositeEditorInstance.changeFormEditorOption('percentComplete', 'filter', true); // multiple-select.js, show filter in dropdown - this.compositeEditorInstance.changeFormEditorOption('product', 'minLength', 3); // autocomplete, change minLength char to type - this.compositeEditorInstance.changeFormEditorOption('finish', 'minDate', 'today'); // flatpickr date picker, change minDate to today + this.compositeEditorInstance.changeFormEditorOption('percentComplete', 'filter', true); // multiple-select.js, show filter in dropdown + this.compositeEditorInstance.changeFormEditorOption('product', 'minLength', 3); // autocomplete, change minLength char to type + this.compositeEditorInstance.changeFormEditorOption('finish', 'range', { min: 'today' }); // vanilla calendar date picker, change minDate to today } } } @@ -619,7 +620,7 @@ Disabling field(s) is done through the exact same way that you would do it in th ```ts handleOnBeforeEditCell(event) { const eventData = event.detail.eventData; - const args = event && event.detail && event.detail.args; + const args = event?.detail?.args; const { column, item, grid } = args; if (column && item) { @@ -649,13 +650,14 @@ checkItemIsEditable(dataContext: any, columnDef: Column, grid: SlickGrid) { return isEditable; } ``` + #### Disabling Form Inputs but only in Composite Editor What if you want to disable certain form inputs but only in the Composite Editor, or use different logic in the grid. For that we added an extra `target` (`target` will return either "grid" or "composite") in the returned `args`, so you could apply different logic based on the target being the grid or the composite editor. For example: ```ts handleOnBeforeEditCell(event) { const eventData = event.detail.eventData; - const args = event && event.detail && event.detail.args; + const args = event?.detail?.args; const { column, item, grid, target } = args; if (column && item) { diff --git a/docs/grid-functionalities/Context-Menu.md b/docs/grid-functionalities/Context-Menu.md index 64ca9c170..5e94673e9 100644 --- a/docs/grid-functionalities/Context-Menu.md +++ b/docs/grid-functionalities/Context-Menu.md @@ -39,7 +39,7 @@ this.gridOptions = { console.log(args.dataContext, args.column); // action callback.. do something } }, - { command: 'help', title: 'HELP', iconCssClass: 'fa fa-question-circle', positionOrder: 62 }, + { command: 'help', title: 'HELP', iconCssClass: 'mdi mdi-help-circle', positionOrder: 62 }, // you can add sub-menus by adding nested `commandItems` { // we can also have multiple nested sub-menus @@ -68,14 +68,14 @@ this.gridOptions = { hideCloseButton: false, optionTitle: 'Change Effort Driven Flag', // optional, add title optionItems: [ - { option: true, title: 'True', iconCssClass: 'fa fa-check-square-o' }, - { option: false, title: 'False', iconCssClass: 'fa fa-square-o' }, + { option: true, title: 'True', iconCssClass: 'mdi mdi-check-box-outline' }, + { option: false, title: 'False', iconCssClass: 'mdi mdi-checkbox-blank-outline' }, { divider: true, command: '', positionOrder: 60 }, ], // subscribe to Context Menu onOptionSelected event (or use the "action" callback on each option) onOptionSelected: (e, args) => { // change Priority - const dataContext = args && args.dataContext; + const dataContext = args?.dataContext; if (dataContext && dataContext.hasOwnProperty('priority')) { dataContext.priority = args.item.option; this.sgb.gridService.updateItem(dataContext); @@ -133,7 +133,7 @@ For example, say we want the Context Menu to only be available on the first 20 r ```ts contextMenu: { menuUsabilityOverride: (args) => { - const dataContext = args && args.dataContext; + const dataContext = args?.dataContext; return (dataContext.id < 21); // say we want to display the menu only from Task 0 to 20 }, ``` @@ -141,18 +141,17 @@ contextMenu: { To give another example, with Options this time, we could say that we enable the `n/a` option only when the row is Completed. So we could do it this way ```ts contextMenu: { - optionItems: [ - { + optionItems: [{ option: 0, title: 'n/a', textCssClass: 'italic', // only enable this option when the task is Not Completed itemUsabilityOverride: (args) => { - const dataContext = args && args.dataContext; + const dataContext = args?.dataContext; return !dataContext.completed; }, - { option: 1, iconCssClass: 'fa fa-star-o yellow', title: 'Low' }, - { option: 2, iconCssClass: 'fa fa-star-half-o orange', title: 'Medium' }, - { option: 3, iconCssClass: 'fa fa-star red', title: 'High' }, - ] + { option: 1, iconCssClass: 'mdi mdi-star-outline yellow', title: 'Low' }, + { option: 2, iconCssClass: 'mdi mdi-star orange', title: 'Medium' }, + { option: 3, iconCssClass: 'mdi mdi-star red', title: 'High' }, + }] } ``` @@ -161,12 +160,11 @@ It works exactly like the rest of the library when `enableTranslate` is set, all ```ts contextMenu: { optionTitleKey: 'COMMANDS', // optionally pass a title to show over the Options - optionItems: [ - { - { option: 1, titleKey: 'LOW', iconCssClass: 'fa fa-star-o yellow' }, - { option: 2, titleKey: 'MEDIUM', iconCssClass: 'fa fa-star-half-o orange' }, - { option: 3, titleKey: 'HIGH', iconCssClass: 'fa fa-star red' }, - ] + optionItems: [{ + { option: 1, titleKey: 'LOW', iconCssClass: 'mdi mdi-star-outline yellow' }, + { option: 2, titleKey: 'MEDIUM', iconCssClass: 'mdi mdi-star orange' }, + { option: 3, titleKey: 'HIGH', iconCssClass: 'mdi mdi-star red' }, + }] } ``` @@ -199,10 +197,10 @@ contextMenu: { hideExportTextDelimitedCommand: true, hideMenuOnScroll: true, hideOptionSection: false, - iconCopyCellValueCommand: 'fa fa-clone', - iconExportCsvCommand: 'fa fa-download', - iconExportExcelCommand: 'fa fa-file-excel-o text-success', - iconExportTextDelimitedCommand: 'fa fa-download', + iconCopyCellValueCommand: 'mdi mdi-content-copy', + iconExportCsvCommand: 'mdi mdi-download', + iconExportExcelCommand: 'mdi mdi-file-excel-outline text-success', + iconExportTextDelimitedCommand: 'mdi mdi-download', width: 200, }, ``` diff --git a/docs/grid-functionalities/Export-to-Excel.md b/docs/grid-functionalities/Export-to-Excel.md index eb8e09ae7..e6bbc0bdb 100644 --- a/docs/grid-functionalities/Export-to-Excel.md +++ b/docs/grid-functionalities/Export-to-Excel.md @@ -1,7 +1,6 @@ #### index - [Grid Options](#grid-options) - [Column Definition & Options](#column-definition-and-options) -- [Custom Column Width](#custom-column-width) - [Custom Cell Styling](#custom-cell-styling) - [Cell Value Parser](#cell-value-parser) - [Cell Format Auto-Detect Disable](#cell-format-auto-detect-disable) @@ -59,7 +58,7 @@ initializeGrid() { - So basically, if `exportWithFormatter` is set to True in the `excelExportOptions` of the Grid Options, but is set to False in the Column Definition, then the result will be False and will not evaluate it's Formatter. - `exportCustomFormatter` will let you choose a different Formatter when exporting - For example, you might have `formatter: Formatters.checkmark` but you want to see a boolean translated value, in this case you would define an extra property of `customFormatter: Formatters.translateBoolean`. -- set `sanitizeDataExport` to remove any HTML/Script code from being export. For example if your value is `True` will export `True` without any HTML (data is sanitized). +- set `sanitizeDataExport` to remove any HTML/Script code from being export. For example if your value is `True` will export `True` without any HTML (data is sanitized). - this flag can be used in the Grid Options (all columns) or in a Column Definition (per column). #### Grid Options @@ -74,7 +73,7 @@ Inside the column definition there are couple of flags you can set in `excelExpo - `sheetName` allows you to change the Excel Sheet Name (defaults to "Sheet1") - `groupingColumnHeaderTitle` The column header title (at A0 in Excel) of the Group by. If nothing is provided it will use "Group By" - `groupingAggregatorRowText` The default text to display in 1st column of the File Export, which will identify that the current row is a Grouping Aggregator -- set `sanitizeDataExport` to remove any HTML/Script code from being export. For example if your value is `True` will export `True` without any HTML (data is sanitized). +- set `sanitizeDataExport` to remove any HTML/Script code from being export. For example if your value is `True` will export `True` without any HTML (data is sanitized). - this flag can be used in the Grid Options (all columns) or in a Column Definition (per column). - `customExcelHeader` is a callback method that can be used to provide a custom Header Title to your Excel File @@ -118,21 +117,6 @@ initializeGrid() { What we can see from the example, is that it will use all Formatters (when exist) on this grid, except for the last column "Completed" since that column has explicitly defined `exportWithFormatter: false` -### Custom Column Width - -**NOTE** now deprecated, please use [Custom Cell Styling](#custom-cell-styling) instead - -You can define a custom Excel column width (the width Excel's own width which is not in pixel). You can define a custom width per column (in your column definitions) and/or for the entire grid (in your grid options). - -#### Per Column -You could set a custom width per column -```ts -this.columnDefinitions = [ - { id: 'firstName', name: 'FirstName', exportColumnWidth: 10, }, - // ... -]; -``` - #### For the entire Grid You could also set a custom width for the entire grid export via the `excelExportOptions` ```ts @@ -238,7 +222,7 @@ If you have lots of data, you might want to show a spinner telling the user that ##### View ```html - +
diff --git a/docs/grid-functionalities/Export-to-Text-File.md b/docs/grid-functionalities/Export-to-Text-File.md index 53c32373c..b32b4e651 100644 --- a/docs/grid-functionalities/Export-to-Text-File.md +++ b/docs/grid-functionalities/Export-to-Text-File.md @@ -52,7 +52,7 @@ Inside the column definition there are couple of flags you can set and also some - `exportCustomFormatter` will let you choose a different Formatter when exporting - For example, you might have `formatter: Formatters.checkmark` but you want to see a boolean translated value, in this case you would define an extra property of `exportCustomFormatter: Formatters.translateBoolean`. - you can set `exportCsvForceToKeepAsString` flag, this one will wrap the cell value into double quotes and add an equal sign in the front, this is especially useful on a column that could be turned into an exponential number by Excel. For example, we could have "1E06" and without this flag will become (1.0E06) in Excel, unless we enable the flag which will become `="1E06"` which will keep it as a string, also note that it will be shown as "1E06" but if you click on the cell value, you will see `="1E06"` -- set `sanitizeDataExport` to remove any HTML/Script code from being export. For example if your value is `True` will export `True` without any HTML (data is sanitized). +- set `sanitizeDataExport` to remove any HTML/Script code from being export. For example if your value is `True` will export `True` without any HTML (data is sanitized). - this flag can be used in the Grid Options (all columns) or in a Column Definition (per column). #### Behaviors @@ -140,7 +140,7 @@ If you have lots of data, you might want to show a spinner telling the user that ##### View ```html - +
diff --git a/docs/grid-functionalities/Grid-Menu.md b/docs/grid-functionalities/Grid-Menu.md index 4c8b2d30e..fce112f7e 100644 --- a/docs/grid-functionalities/Grid-Menu.md +++ b/docs/grid-functionalities/Grid-Menu.md @@ -29,18 +29,18 @@ this.gridOptions = { gridMenu: { commandTitle: 'Custom Commands', columnTitle: 'Columns', - iconCssClass: 'fa fa-ellipsis-v', + iconCssClass: 'mdi mdi-dots-vertical', menuWidth: 17, resizeOnShowHeaderRow: true, commandItems: [ { - iconCssClass: 'fa fa-filter text-danger', + iconCssClass: 'mdi mdi-filter-remove-outline', title: 'Clear All Filters', disabled: false, command: 'clear-filter' }, { - iconCssClass: 'fa fa-random', + iconCssClass: 'mdi-flip-vertical', title: 'Toggle Filter Row', disabled: false, command: 'toggle-filter' @@ -110,12 +110,12 @@ You can change any of the default command icon(s) by changing the `icon[X-comman this.gridOptions = { enableGridMenu: true, gridMenu: { - iconClearAllFiltersCommand: 'fa fa-filter text-danger' - iconClearAllSortingCommand: 'fa fa-unsorted text-danger', - iconExportCsvCommand: 'fa fa-download', - iconExportTextDelimitedCommand: 'fa fa-download', - iconRefreshDatasetCommand: 'fa fa-refresh', - iconToggleFilterCommand: 'fa fa-random', + iconClearAllFiltersCommand: 'mdi mdi-filter-remove-outline' + iconClearAllSortingCommand: 'mdi mdi-sort-variant-off', + iconExportCsvCommand: 'mdi mdi-download', + iconExportTextDelimitedCommand: 'mdi mdi-download', + iconRefreshDatasetCommand: 'mdi mdi-sync', + iconToggleFilterCommand: 'mdi-flip-vertical', }, }; ``` diff --git a/docs/grid-functionalities/Tree-Data-Grid.md b/docs/grid-functionalities/Tree-Data-Grid.md index 4065e6489..34afee089 100644 --- a/docs/grid-functionalities/Tree-Data-Grid.md +++ b/docs/grid-functionalities/Tree-Data-Grid.md @@ -349,10 +349,10 @@ this.columnDefinitions = [ if (avgVal !== undefined && sumVal !== undefined) { // when found Avg & Sum, we'll display both - return isNaN(sumVal) ? '' : `sum: ${decimalFormatted(sumVal, 0, 2)} MB / avg: ${decimalFormatted(avgVal, 0, 2)} MB (${treeLevel === 0 ? 'total' : 'sub-total'})`; + return isNaN(sumVal) ? '' : `sum: ${decimalFormatted(sumVal, 0, 2)} MB / avg: ${decimalFormatted(avgVal, 0, 2)} MB (${treeLevel === 0 ? 'total' : 'sub-total'})`; } else if (sumVal !== undefined) { // or when only Sum is aggregated, then just show Sum - return isNaN(sumVal) ? '' : `sum: ${decimalFormatted(sumVal, 0, 2)} MB (${treeLevel === 0 ? 'total' : 'sub-total'})`; + return isNaN(sumVal) ? '' : `sum: ${decimalFormatted(sumVal, 0, 2)} MB (${treeLevel === 0 ? 'total' : 'sub-total'})`; } } // reaching this line means it's a regular dataContext without totals, so regular formatter output will be used diff --git a/docs/grid-functionalities/frozen-columns-rows.md b/docs/grid-functionalities/frozen-columns-rows.md index 77e1f2825..f3aba1c33 100644 --- a/docs/grid-functionalities/frozen-columns-rows.md +++ b/docs/grid-functionalities/frozen-columns-rows.md @@ -81,7 +81,7 @@ You can change the number of pinned columns/rows and even the pinning of columns : ${ isFrozenBottom ? 'Bottom' : 'Top' } diff --git a/docs/grid-functionalities/grouping-aggregators.md b/docs/grid-functionalities/grouping-aggregators.md index d28fd8c7d..60179aff6 100644 --- a/docs/grid-functionalities/grouping-aggregators.md +++ b/docs/grid-functionalities/grouping-aggregators.md @@ -179,21 +179,19 @@ To "Clear all Grouping", "Collapse all Groups" and "Expand all Groups", we can s ``` ### Styling (change icons) -The current icons are Font Awesome chevron (right/down), however if you wish to use +/- icons. You can simply update the SASS variables to use whichever icons (or even Font Family icon) you desire. The SASS variables you can change are +The current icons are chevron (right/down), however if you wish to use +/- icons. You can simply update the SASS variables to use whichever SVG icon paths. The SASS variables you can change are ```css -$icon-group-color: $primary-color; -$icon-group-expanded: "\f107"; -$icon-group-collapsed: "\f105"; -$icon-group-font-size: ($icon-font-size + 2px); -$icon-group-font-weight: bold; -$icon-group-margin-right: 2px; -$icon-group-height: 20px; -$icon-group-width: 14px; +$slick-icon-group-color: $primary-color; +$slick-icon-group-expanded-svg-path: "M19,19V5H5V19H19M19,3A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5C3,3.89 3.9,3 5,3H19M11,7H13V11H17V13H13V17H11V13H7V11H11V7Z"; +$slick-icon-group-collapsed-svg-path: "M19,19V5H5V19H19M19,3A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5C3,3.89 3.9,3 5,3H19M17,11V13H7V11H17Z"; +$slick-icon-group-font-size: 20px; +$slick-icon-group-font-weight: bold; +$slick-icon-group-margin-right: 2px; /* Grouping Totals Formatter */ -$group-totals-formatter-color: gray; -$group-totals-formatter-bgcolor: white; -$group-totals-formatter-font-size: 14px; +$slick-group-totals-formatter-color: gray; +$slick-group-totals-formatter-bgcolor: white; +$slick-group-totals-formatter-font-size: 14px; ``` For more info on SASS styling and variables, please read the [Wiki - SASS Styling](../styling/styling.md), \ No newline at end of file diff --git a/docs/grid-functionalities/header-menu-header-buttons.md b/docs/grid-functionalities/header-menu-header-buttons.md index 42b15c577..97d6dfe64 100644 --- a/docs/grid-functionalities/header-menu-header-buttons.md +++ b/docs/grid-functionalities/header-menu-header-buttons.md @@ -64,9 +64,9 @@ You can change any of the default command icon(s) by changing the `icon[X-comman this.gridOptions = { enableHeaderMenu: true, headerMenu: { - iconColumnHideCommand: 'fa fa-times' - iconSortAscCommand: 'fa fa-sort-asc' - iconSortDescCommand: 'fa fa-sort-desc', + iconColumnHideCommand: 'mdi mdi-close' + iconSortAscCommand: 'mdi mdi-sort-ascending' + iconSortDescCommand: 'mdi mdi-sort-descending', }, }; ``` diff --git a/docs/migrations/migration-to-5.x.md b/docs/migrations/migration-to-5.x.md new file mode 100644 index 000000000..1e9f56f80 --- /dev/null +++ b/docs/migrations/migration-to-5.x.md @@ -0,0 +1,255 @@ +## Version 5 - Better UI and Dark Mode with Pure CSS SVG icons ✨ +This new release brings a lot of changes oriented towards better UI/UX, our SVG icons are now pure CSS and can be colorized like any other text via the native CSS `color` property (which helps a lot to improve the Dark Mode Theme). + +Another noticeable UI change is the migration from [Flatpickr](https://flatpickr.js.org/) to [Vanilla-Calendar-Picker](https://github.com/ghiscoding/vanilla-calendar-picker) (which is a fork of [Vanilla-Calendar-Pro](https://vanilla-calendar.pro/) and we'll hopefully drop the fork in the near future if possible), there are multiple reasons to migrate our date picker to another library as shown below. Another change that is mostly internal but is also indirectly connected to the date picker is the migration from MomentJS to [Tempo](https://tempo.formkit.com/) which is modern and is packaged as ESM which is great for Tree Shaking. + +##### Flatpickr cons: + - barely supported (lots of opened PR but nothing merged for the past 2 years) + - not fully ESM ready (it's only partially ESM, for example it is detected as CJS in Angular-Slickgrid and requires an exception in `allowedCommonJsDependencies`) + - styling could be a bit more modern (the use of native select/input to change year/month/time is a bit outdated and rudimentary) + - date range selection is not very user friendly (UX) + +##### Vanilla-Calendar (VC) + - pros: + - ESM ready + - modern styling and also includes Dark Mode theme + - date range becomes a lot more easy by displaying a picker with 2 months + - cons: + - build size is slightly larger but its UI/UX is awesome (especially when chaning month/year) + - settings are named differently and are not using flat config (complex object settings) and requires code change + - for example Flatpickr `minDate: 'today'` is instead `range: { min: 'today' }` in VC + - some settings were missing, like the `'today'` shortcut which is why I forked the VC project + - I did open a few PRs on the main project, so the hope is to drop the fork in the future while being a totally transparent change to you when it happens. + +With this release, and after 7 years of development as a 1 man show (myself @ghiscoding), I believe that I have achieved all goals and even more than I originally planned to accomplish and with that being said, I am not foreseeing any new major releases on the short term. As a recap, I think that the biggest challenge was the removal of jQuery/jQueryUI and transition to native code, that took 2-3 years to accomplish, and I am of course very proud to have achieved. All dependencies are now also all ESM and the project is CSP compliant. + +To summarize, the goal of this new release was mainly to improve UI/UX (mostly for Dark Mode) and also to make it fully ESM ready. Also noteworthy, the project is smaller in size (~100Kb smaller) compared to what it was in v2.x (that was when the user had to install jQuery/jQueryUI separately). So, considering that we're no longer requiring the install of jQuery/jQueryUI, and also considering that these 2 dependencies had a total of well over 200kb. We can safely assume that our project build size is in fact a lot smaller than it was just 2 years ago, that is really nice to know considering that we kept adding features (like Dark Mode and other features) while still decreasing its size over the years :) + +#### Major Changes - Quick Summary +- minimum requirements bump + - Node >=v18.x + - Bootstrap >=v5.x (or any other UI framework) + - SASS >=v1.35 (`dart-sass`) + - migrated from Flatpickr to Vanilla-Calendar (visit [Vanilla-Calendar-Pro](https://vanilla-calendar.pro/) for demos and docs) + - migrated from MomentJS to [Tempo](https://tempo.formkit.com/) (by the FormKit +team) + +> **Note** for the entire list of tasks & code changes applied in this release, you may want to take a look at the [Roadmap to 5.0](https://github.com/ghiscoding/slickgrid-universal/discussions/1482) Discussion. + +For most breaking changes, a quick Search & Replace in your code editor should suffice. + +> **Note:** if you come from an earlier version, please make sure to follow each migrations in their respected order (review previous migration guides) + +## Changes + +### Styling + +#### CSS classes `.color-xx` are all removed (use `.text-color-xx` or native `color` instead) +> **Note** these extra colors are only available in the Material & Salesforce Themes (it is not included in the Bootstrap Theme since Bootstrap have their own coloring utils). + +Since the SVG icons are now pure CSS, we can now colorize any of them the same way that we would do for any other text via the `color` CSS property 🌈. For that reason, we no longer need any of the `.color-xx` CSS classes (which were created via CSS [filter](https://developer.mozilla.org/en-US/docs/Web/CSS/filter)). They were useful to override the SVG icon colors (by using CSS `filter`), but since we can now use the regular CSS `color` property, the `color-xx` are no longer necessary and were all removed (just use `text-color-xx` instead or plain CSS `color`s). + +```diff + +``` +or move the class to the parent container and have both the icon & the text `inherit` the color :) +```diff ++ +``` + +#### SASS variables +A lot of SASS variables were changed, we recommend that you take a look at the [_variables.scss](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/styles/_variables.scss) file to compare them with your SASS overrides and fix any SASS build issues. For example a lot of the ms-select variables and all Flatpickr related variables were deleted (note that Vanilla-Calendar doesn't actually have any variables). Also a lot of the icon related variables were renamed and updated (icons now all have the suffix `-icon-svg-path` for the SVG vector path, you can easily change them with SASS). + +> **Note** if you want create your own SVGs icons in pure CSS, you could use the `generateSvgStyle()` SASS function from Slickgrid-Universal [`svg-utilities.scss`](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/styles/svg-utilities.scss) (take a look at the [`slickgrid-icons.scss`](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/styles/slickgrid-icons.scss) for some usage) + +#### SASS (dart-sass) `math` polyfills are removed +When SASS (dart-sass) released their version 1.33 (~3 years ago), it caused a ton of console warnings (and a lot of unhappy users) in projects that were using `/` in their SASS files (for math division) instead of their new `math.div()` function. To avoid seeing all these warnings, I added a temporary polyfill at the time (that piece of code was actually copied from the Bootstrap project). That polyfill patch was put in place about 3 years ago, so I'm assuming that most users have already upgraded their SASS version and already fixed all of these warnings... So, I think it's now safe to remove this polyfill, because like I said earlier, it was really meant to be a temp patch. If you see any warnings coming back, then a suggestion would be to use the SASS CLI `--quiet-upstream` option. + +For reference, below is an example of these old Math warnings which were coming up when using the SASS CLI + +```sh +Recommendation: math.div($m, $columns) +More info and automated migrator: https://sass-lang.com/d/slash-div +╷ +94 │ margin-right: $m / $columns * 100% +│ ^^^^^^^^^^^^^^^^^^ +``` + +#### Font-Awesome references are all removed +Since this release introduces pure CSS SVG icons, I went ahead and deleted all Font-Awesome references (which were mostly in the Bootstrap Theme). The reason is simple, the built-in icons are now all pure CSS SVG icons (sort, grouping, row detail, row move, row selection). You can also change these icons via SASS (or CSS variables with a bit more work). However, please note that there are a few plugins which use external icons via CSS classes (mostly all menu plugins like Header Menu, Grid Menu, Content Menu, ...) and for that reason **all Styling Themes** now include the Slickgrid-Universal Material icons subset (~200 icons) by default (not just Material & Salesforce but now also the Bootstrap Theme as well). In short, the grid is now using SVG icons by default and Font-Awesome icons will no longer be used internally (you can still use it in your project but it won't be used by the grid itself unless you set them in your grid options). + +If you no longer need Font-Awesome, then consider removing it completely + +```diff +# package.json +{ + dependencies: { +- "font-awesome": "^4.7.0" + } +} +``` + +What if you don't want to use the [Slickgrid-Universal icons](https://ghiscoding.github.io/slickgrid-universal/#/icons) (`.mdi`) subset and would rather use a different font/SVG library? In that case, I would suggest that you use the "lite" Themes (which do not include the colors & icons subset) and then make sure to update all the menu plugins with the correct CSS classes. For example the global grid options of the Grid Menu is now configured with the following icon classes (notice that we no longer provide any Font-Awesome "fa" icon references in our global grid options). Also note that what is shown below is just 1 of the multiple menu plugins to configure, make sure to review them all (you can review the [global-grid-options.ts](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/global-grid-options.ts) file). + +```ts +// default global grid options +export const GlobalGridOptions = { + gridMenu: { + iconCssClass: 'mdi mdi-menu', + iconClearAllFiltersCommand: 'mdi mdi-filter-remove-outline', + iconClearAllSortingCommand: 'mdi mdi-sort-variant-off', + iconClearFrozenColumnsCommand: 'mdi mdi-pin-off-outline', + iconExportCsvCommand: 'mdi mdi-download', + iconExportExcelCommand: 'mdi mdi-file-excel-outline', + iconExportTextDelimitedCommand: 'mdi mdi-download', + iconRefreshDatasetCommand: 'mdi mdi-sync', + iconToggleDarkModeCommand: 'mdi mdi-brightness-4', + iconToggleFilterCommand: 'mdi mdi-flip-vertical', + iconTogglePreHeaderCommand: 'mdi mdi-flip-vertical', + }, + headerMenu: { + // icon... + } +} +``` + +and below is a quick snapshot of the file size diff with the "lite" themes (without icons) vs the default themes (with colors & icons subset). However note that the built-in icons are of course always included even in the "lite" themes. + +![image](https://github.com/ghiscoding/Angular-Slickgrid/assets/643976/ea7542b9-3c7e-4a6f-ae4d-355138f74188) + +### Deprecated code removed/renamed +##### `getHTMLFromFragment()` removed +The util `getHTMLFromFragment()` function was removed in favor of `getHtmlStringOutput()`, the new function will auto-detect if it's a DocumentFragment, an HTMLElement or an HTML string and will execute the appropriate action. + +##### jQueryUI CSS classes leftovers +There were a few remaining traces of jQueryUI CSS classes like `.ui-state-default` and other similar classes in the core lib, they were all removed in this release. If you were querying any of them in CSS for styling purposes, you can simply rename them to `.slick-state-*` + +```diff +- .ui-state-default, .ui-state-hover { ++ .slick-state-default, .slick-state-hover { +} +``` + +#### Formatters Cleanup & Removals + +Since we now use SVGs everywhere and we got rid of any Font usage (no more Font-Awesome code anywhere), the `checkmark` Formatter no longer has any reason to exist and was removed. If you were using it and still plan to use Font-Awesome in your project, then you'll have to either recreate the Formatter yourself or use alternatives. You could use the `Formatters.icon` or `Formatters.iconBoolean` which require the CSS classes to be provided via `params`. Or as a last alternative, and if you are importing the optional SVG icons `.mdi` subset, then we recommend you simply switch to the `checkmarkMaterial` Formatter. + +```diff +this.columnDefinitions = [ + { + id: 'isActive', name: 'Active', field: 'isActive', +- formatter: Formatters.checkmark ++ formatter: Formatters.checkmarkMaterial + }, +]; +``` + +or create a Custom Formatter + +```ts +// create a custom Formatter and returning a string and/or an object of type FormatterResultObject +const myCheckmarkFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column, dataContext: any) => { + // via native HTML (for CSP safe), you could also use our `createDomElement()` util for 1 liner + const iconElm = document.createElement('i'); + iconElm.className = value ? 'mdi mdi-check' : ''; + return iconElm; + + // or via simple HTML string + return value ? '' : ''; +} +``` + +## Column Functionalities + +### Native Select Filter (removed) +I would be very surprised if anyone had ever used the `Filters.select`, which was a native ` - - diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example04.ts b/examples/vite-demo-vanilla-bundle/src/examples/example04.ts index dd2552b6d..12ac82a91 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example04.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example04.ts @@ -106,7 +106,7 @@ export default class Example04 { // We can also add HTML text to be rendered (any bad script will be sanitized) but we have to opt-in, else it will be sanitized enableRenderHtml: true, // collection: [{ value: '1', label: '1' }, { value: '2', label: '2' }, { value: '3', label: '3' }, { value: '4', label: '4' }, { value: '5', label: '5' }], - collection: Array.from(Array(101).keys()).map(k => ({ value: k, label: k, symbol: '' })), + collection: Array.from(Array(101).keys()).map(k => ({ value: k, label: k, symbol: '' })), customStructure: { value: 'value', label: 'label', @@ -424,16 +424,16 @@ export default class Example04 { } }, optionItems: [ - { option: 0, iconCssClass: 'mdi mdi-checkbox-blank-outline color-secondary', title: 'Not Started (0%)' }, + { option: 0, iconCssClass: 'mdi mdi-checkbox-blank-outline text-color-secondary', title: 'Not Started (0%)' }, { option: 50, iconCssClass: 'mdi mdi-flip-vertical', title: 'Half Completed (50%)' }, - { option: 100, iconCssClass: 'mdi mdi-checkbox-marked color-success', title: 'Completed (100%)' }, + { option: 100, iconCssClass: 'mdi mdi-checkbox-marked text-color-success', title: 'Completed (100%)' }, 'divider', { // we can also have multiple nested sub-menus option: null, title: 'Sub-Options (demo)', subMenuTitle: 'Set Percent Complete', optionItems: [ - { option: 0, iconCssClass: 'mdi mdi-checkbox-blank-outline color-secondary', title: 'Not Started (0%)' }, + { option: 0, iconCssClass: 'mdi mdi-checkbox-blank-outline text-color-secondary', title: 'Not Started (0%)' }, { option: 50, iconCssClass: 'mdi mdi-flip-vertical', title: 'Half Completed (50%)' }, - { option: 100, iconCssClass: 'mdi mdi-checkbox-marked color-success', title: 'Completed (100%)' }, + { option: 100, iconCssClass: 'mdi mdi-checkbox-marked text-color-success', title: 'Completed (100%)' }, ] } ], diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example05.html b/examples/vite-demo-vanilla-bundle/src/examples/example05.html index 95acc78c9..a55cf44b3 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example05.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/example05.html @@ -7,7 +7,7 @@

- code + code

@@ -26,11 +26,11 @@
@@ -19,23 +19,23 @@
diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example06.scss b/examples/vite-demo-vanilla-bundle/src/examples/example06.scss index 9f2aba6f9..d44315602 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example06.scss +++ b/examples/vite-demo-vanilla-bundle/src/examples/example06.scss @@ -1,7 +1,12 @@ // @import '@slickgrid-universal/common/dist/styles/sass/slickgrid-theme-salesforce.scss'; -@import '@slickgrid-universal/common/dist/styles/sass/sass-utilities.scss'; .grid6 { + .slick-cell { + display: inline-flex; + align-items: center; + column-gap: 4px; + } + .avg-total { color: #ac76ff; } @@ -16,32 +21,33 @@ } .mdi-file-pdf-outline { - /** 1. use `filter` color */ - // filter: invert(62%) sepia(93%) saturate(5654%) hue-rotate(325deg) brightness(100%) contrast(90%); - - /** 2. or use the SASS @mixin that will produce the `filter` color */ - @include recolor(#f14668, 0.9); + color: #f14668; + opacity: 0.9; } .mdi-folder, .mdi-folder-open { - @include recolor(#ffa500, 0.9); + color: #ffa500; + opacity: 0.9; } .mdi-file-music-outline { - @include recolor(#3298dc, 0.9); + color: #3298dc; + opacity: 0.9; } .mdi-file-excel-outline { - @include recolor(#1E9F75, 0.9); + color: #1E9F75; + opacity: 0.9; } .mdi-file-document-outline, .mdi-file-question-outline { - @include recolor(#686868, 0.9); + color: #686868; + opacity: 0.9; } } .display-inline-block { display: inline-block; } -// font-5px up to font-50px +// create a few 15px indentation multiplied by level number @for $i from 1 through 6 { .width-#{$i*15}px { width: #{$i * 15}px; } } \ No newline at end of file diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example06.ts b/examples/vite-demo-vanilla-bundle/src/examples/example06.ts index b77ef9cf6..a346a680a 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example06.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example06.ts @@ -41,12 +41,12 @@ export default class Example06 { this.datasetHierarchical = this.mockDataset(); const gridContainerElm = document.querySelector('.grid6') as HTMLDivElement; this.sgb = new Slicker.GridBundle(gridContainerElm, this.columnDefinitions, { ...ExampleGridOptions, ...this.gridOptions }, undefined, this.datasetHierarchical); - document.body.classList.add('material-theme'); + document.body.classList.add('salesforce-theme'); } dispose() { this.sgb?.dispose(); - document.body.classList.remove('material-theme'); + document.body.classList.remove('salesforce-theme'); } initializeGrid() { @@ -97,10 +97,10 @@ export default class Example06 { if (avgVal !== undefined && sumVal !== undefined) { // when found Avg & Sum, we'll display both - return isNaN(sumVal) ? '' : `sum: ${decimalFormatted(sumVal, 0, 2)} MB / avg: ${decimalFormatted(avgVal, 0, 2)} MB (${treeLevel === 0 ? 'total' : 'sub-total'})`; + return isNaN(sumVal) ? '' : `sum: ${decimalFormatted(sumVal, 0, 2)} MB / avg: ${decimalFormatted(avgVal, 0, 2)} MB (${treeLevel === 0 ? 'total' : 'sub-total'})`; } else if (sumVal !== undefined) { // or when only Sum is aggregated, then just show Sum - return isNaN(sumVal) ? '' : `sum: ${decimalFormatted(sumVal, 0, 2)} MB (${treeLevel === 0 ? 'total' : 'sub-total'})`; + return isNaN(sumVal) ? '' : `sum: ${decimalFormatted(sumVal, 0, 2)} MB (${treeLevel === 0 ? 'total' : 'sub-total'})`; } } // reaching this line means it's a regular dataContext without totals, so regular formatter output will be used @@ -132,7 +132,7 @@ export default class Example06 { enableFiltering: true, enableTreeData: true, // you must enable this flag for the filtering & sorting to work as expected multiColumnSort: false, // multi-column sorting is not supported with Tree Data, so you need to disable it - rowHeight: 40, + rowHeight: 35, treeDataOptions: { columnId: 'file', childrenPropName: 'files', diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example07.html b/examples/vite-demo-vanilla-bundle/src/examples/example07.html index bb0f27338..e4d8196d1 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example07.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/example07.html @@ -2,7 +2,7 @@

Example 07 - Row Move & Row Selections @@ -10,42 +10,42 @@

see - code + code

Locale: diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example07.scss b/examples/vite-demo-vanilla-bundle/src/examples/example07.scss index 169574547..60f69adac 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example07.scss +++ b/examples/vite-demo-vanilla-bundle/src/examples/example07.scss @@ -1,11 +1,17 @@ -#modal-allFilter-table { - display: table; -} -#modal-allFilter-table .row { - display: table-row; -} -#modal-allFilter-table .column { - display: table-cell; - vertical-align: top; - width: 40%; +:root { + .grid7 { + --slick-cell-display: flex; + } + + #modal-allFilter-table { + display: table; + } + #modal-allFilter-table .row { + display: table-row; + } + #modal-allFilter-table .column { + display: table-cell; + vertical-align: top; + width: 40%; + } } \ No newline at end of file diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example07.ts b/examples/vite-demo-vanilla-bundle/src/examples/example07.ts index 31370f755..380cde5f0 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example07.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example07.ts @@ -10,7 +10,7 @@ import { import { BindingEventService } from '@slickgrid-universal/binding'; import { ExcelExportService } from '@slickgrid-universal/excel-export'; import { Slicker, type SlickVanillaGridBundle } from '@slickgrid-universal/vanilla-bundle'; -import DOMPurify from 'isomorphic-dompurify'; +import DOMPurify from 'dompurify'; import { ExampleGridOptions } from './example-grid-options'; import type { TranslateService } from '../translate.service'; @@ -32,10 +32,10 @@ export default class Example07 { translateService: TranslateService; set isFilteringEnabled(enabled: boolean) { - this.filteringEnabledClass = enabled ? 'icon mdi mdi-toggle-switch' : 'icon mdi mdi-toggle-switch-off-outline'; + this.filteringEnabledClass = enabled ? 'mdi mdi-toggle-switch' : 'mdi mdi-toggle-switch-off-outline'; } set isSortingEnabled(enabled: boolean) { - this.sortingEnabledClass = enabled ? 'icon mdi mdi-toggle-switch' : 'icon mdi mdi-toggle-switch-off-outline'; + this.sortingEnabledClass = enabled ? 'mdi mdi-toggle-switch' : 'mdi mdi-toggle-switch-off-outline'; } constructor() { @@ -76,9 +76,10 @@ export default class Example07 { // params: { useFormatterOuputToFilter: true } }, { - id: 'action', name: 'Action', field: 'action', minWidth: 60, maxWidth: 60, + id: 'action', name: 'Action', field: 'action', minWidth: 55, maxWidth: 55, excludeFromExport: true, excludeFromHeaderMenu: true, - formatter: () => `
`, + cssClass: 'justify-center', + formatter: () => `
`, cellMenu: { hideCloseButton: false, subItemChevronClass: 'mdi mdi-chevron-down mdi-rotate-270', @@ -86,7 +87,7 @@ export default class Example07 { commandItems: [ { command: 'command1', titleKey: 'DELETE_ROW', - iconCssClass: 'mdi mdi-close color-danger', cssClass: 'has-text-danger', textCssClass: 'bold', + iconCssClass: 'mdi mdi-close', cssClass: 'has-text-danger', textCssClass: 'bold', action: (_e, args) => { if (confirm(`Do you really want to delete row (${args.row! + 1}) with "${args.dataContext.title}"?`)) { this.sgb?.gridService.deleteItemById(args.dataContext.id); @@ -193,8 +194,8 @@ export default class Example07 { enableRenderHtml: true, collection: [ { value: '', label: '' }, - { value: true, label: 'True', labelSuffix: ` ` }, - { value: false, label: 'False', labelSuffix: ` ` } + { value: true, label: 'True', labelSuffix: ` ` }, + { value: false, label: 'False', labelSuffix: ` ` } ], model: Filters.singleSelect }, @@ -208,8 +209,8 @@ export default class Example07 { enableRenderHtml: true, collectionAsync: new Promise(resolve => setTimeout(() => { resolve([ - { value: true, label: 'True', labelSuffix: ` ` }, - { value: false, label: 'False', labelSuffix: ` ` } + { value: true, label: 'True', labelSuffix: ` ` }, + { value: false, label: 'False', labelSuffix: ` ` } ]); }, 250)), }, @@ -403,7 +404,7 @@ export default class Example07 {
@@ -50,11 +50,11 @@

Grid 1 (with Header Grouping & Colspan) diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example09.html b/examples/vite-demo-vanilla-bundle/src/examples/example09.html index 783e87ef6..f2ba40434 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example09.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/example09.html @@ -5,7 +5,7 @@

- code + code

@@ -21,7 +21,7 @@
+ +
@@ -16,7 +23,7 @@
Locale: diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example10.ts b/examples/vite-demo-vanilla-bundle/src/examples/example10.ts index 46f52dcf7..9fcf8b337 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example10.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example10.ts @@ -7,14 +7,15 @@ import { type GridOption, type GridStateChange, type Metrics, - type MultipleSelectOption, OperatorType, SortDirection, } from '@slickgrid-universal/common'; import { BindingEventService } from '@slickgrid-universal/binding'; import { GraphqlService, type GraphqlPaginatedResult, type GraphqlServiceApi, type GraphqlServiceOption, } from '@slickgrid-universal/graphql'; import { Slicker, type SlickVanillaGridBundle } from '@slickgrid-universal/vanilla-bundle'; -import moment from 'moment-mini'; +import { addDay, format } from '@formkit/tempo'; +import { type MultipleSelectOption } from 'multiple-select-vanilla'; + import { ExampleGridOptions } from './example-grid-options'; import type { TranslateService } from '../translate.service'; import './example10.scss'; @@ -26,6 +27,7 @@ const FAKE_SERVER_DELAY = 250; export default class Example10 { private _bindingEventService: BindingEventService; + private _darkMode = false; columnDefinitions: Column[]; gridOptions: GridOption; dataset = []; @@ -68,6 +70,8 @@ export default class Example10 { this._bindingEventService.unbindAll(); // this.saveCurrentGridState(); document.body.classList.remove('material-theme'); + document.body.setAttribute('data-theme', 'light'); + document.querySelector('.demo-container')?.classList.remove('dark-mode'); } initializeGrid() { @@ -126,8 +130,8 @@ export default class Example10 { }, ]; - const presetLowestDay = moment().add(-2, 'days').format('YYYY-MM-DD'); - const presetHighestDay = moment().add(20, 'days').format('YYYY-MM-DD'); + const presetLowestDay = format(addDay(new Date(), -2), 'YYYY-MM-DD'); + const presetHighestDay = format(addDay(new Date(), 20), 'YYYY-MM-DD'); this.gridOptions = { enableAutoTooltip: true, @@ -299,8 +303,8 @@ export default class Example10 { } setFiltersDynamically() { - const presetLowestDay = moment().add(-2, 'days').format('YYYY-MM-DD'); - const presetHighestDay = moment().add(20, 'days').format('YYYY-MM-DD'); + const presetLowestDay = format(addDay(new Date(), -2), 'YYYY-MM-DD'); + const presetHighestDay = format(addDay(new Date(), 20), 'YYYY-MM-DD'); // we can Set Filters Dynamically (or different filters) afterward through the FilterService this.sgb.filterService.updateFilters([ @@ -321,8 +325,8 @@ export default class Example10 { } resetToOriginalPresets() { - const presetLowestDay = moment().add(-2, 'days').format('YYYY-MM-DD'); - const presetHighestDay = moment().add(20, 'days').format('YYYY-MM-DD'); + const presetLowestDay = format(addDay(new Date(), -2), 'YYYY-MM-DD'); + const presetHighestDay = format(addDay(new Date(), 20), 'YYYY-MM-DD'); this.sgb?.filterService.updateFilters([ // you can use OperatorType or type them as string, e.g.: operator: 'EQ' @@ -356,6 +360,23 @@ export default class Example10 { this.selectedLanguageFile = `${this.selectedLanguage}.json`; } + toggleDarkMode() { + this._darkMode = !this._darkMode; + this.toggleBodyBackground(); + this.sgb.gridOptions = { ...this.sgb.gridOptions, darkMode: this._darkMode }; + this.sgb.slickGrid?.setOptions({ darkMode: this._darkMode }); + } + + toggleBodyBackground() { + if (this._darkMode) { + document.body.setAttribute('data-theme', 'dark'); + document.querySelector('.demo-container')?.classList.add('dark-mode'); + } else { + document.body.setAttribute('data-theme', 'light'); + document.querySelector('.demo-container')?.classList.remove('dark-mode'); + } + } + private resetOptions(options: Partial) { const graphqlService = this.gridOptions.backendServiceApi!.service as GraphqlService; this.sgb?.paginationService!.setCursorBased(options.useCursor!); diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example11.html b/examples/vite-demo-vanilla-bundle/src/examples/example11.html index 386cd1ccc..bfb4a2475 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example11.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/example11.html @@ -6,7 +6,7 @@

- code + code

@@ -15,19 +15,19 @@

diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example11.ts b/examples/vite-demo-vanilla-bundle/src/examples/example11.ts index 0545cbc14..38d521ea9 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example11.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example11.ts @@ -13,11 +13,11 @@ import { type Formatter, Formatters, type GridOption, - type MultipleSelectOption, OperatorType, SlickGlobalEditorLock, type SliderOption, SortComparers, + type VanillaCalendarOption, // utilities deepCopy, @@ -27,7 +27,7 @@ import { BindingEventService } from '@slickgrid-universal/binding'; import { SlickCustomTooltip } from '@slickgrid-universal/custom-tooltip-plugin'; import { ExcelExportService } from '@slickgrid-universal/excel-export'; import { Slicker, type SlickVanillaGridBundle } from '@slickgrid-universal/vanilla-bundle'; -import moment from 'moment-mini'; +import { type MultipleSelectOption } from 'multiple-select-vanilla'; import exampleModal from './example11-modal.html?raw'; import Example11Modal from './example11-modal'; @@ -81,7 +81,7 @@ export default class Example11 { sgb: SlickVanillaGridBundle; gridContainerElm: HTMLDivElement; viewSelectElm: HTMLSelectElement; - currentYear = moment().year(); + currentYear = new Date().getFullYear(); defaultPredefinedPresets = [ { label: 'Tasks Finished in Previous Years (wo/Product,Country)', @@ -177,7 +177,7 @@ export default class Example11 { }, { id: 'finish', name: 'Finish', field: 'finish', sortable: true, minWidth: 80, - editor: { model: Editors.date, massUpdate: true, editorOptions: { minDate: 'today' }, }, + editor: { model: Editors.date, massUpdate: true, editorOptions: { range: { min: 'today' } } as VanillaCalendarOption }, formatter: Formatters.dateIso, type: FieldType.date, outputType: FieldType.dateIso, filterable: true, filter: { model: Filters.compoundDate }, @@ -270,7 +270,7 @@ export default class Example11 { { id: 'action', name: 'Action', field: 'action', minWidth: 70, width: 75, maxWidth: 75, excludeFromExport: true, - formatter: () => ` + formatter: () => `  `, onCellClick: (event: Event, args) => { const dataContext = args.dataContext; diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example12.html b/examples/vite-demo-vanilla-bundle/src/examples/example12.html index 3d20a7525..2c2c74b81 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example12.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/example12.html @@ -3,7 +3,7 @@

(with Salesforce Theme) @@ -12,7 +12,7 @@

- code + code

@@ -21,25 +21,25 @@

@@ -55,35 +55,35 @@

diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example12.ts b/examples/vite-demo-vanilla-bundle/src/examples/example12.ts index 76de21bce..ad44b1a59 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example12.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example12.ts @@ -1,4 +1,3 @@ -// import { Instance as FlatpickrInstance } from 'flatpickr/dist/types/instance'; import { type AutocompleterOption, type Column, @@ -8,16 +7,15 @@ import { EventNamingStyle, FieldType, Filters, - type FlatpickrOption, type Formatter, Formatters, type GridOption, type LongTextEditorOption, - type MultipleSelectOption, type OnCompositeEditorChangeEventArgs, SlickGlobalEditorLock, type SliderOption, SortComparers, + type VanillaCalendarOption, // utilities formatNumber, @@ -27,6 +25,8 @@ import { ExcelExportService } from '@slickgrid-universal/excel-export'; import { type SlickerGridInstance } from '@slickgrid-universal/vanilla-bundle'; import { Slicker, type VanillaForceGridBundle } from '@slickgrid-universal/vanilla-force-bundle'; import { SlickCompositeEditor, SlickCompositeEditorComponent } from '@slickgrid-universal/composite-editor-component'; +import { type MultipleSelectOption } from 'multiple-select-vanilla'; + import { ExampleGridOptions } from './example-grid-options'; import countriesJson from './data/countries.json?raw'; import './example12.scss'; @@ -153,7 +153,7 @@ export default class Example12 { initializeGrid() { this.columnDefinitions = [ { - id: 'title', name: ' Title ', field: 'title', sortable: true, type: FieldType.string, minWidth: 75, + id: 'title', name: ' Title ', field: 'title', sortable: true, type: FieldType.string, minWidth: 75, cssClass: 'text-bold text-uppercase', filterable: true, columnGroup: 'Common Factor', filter: { model: Filters.compoundInputText }, @@ -271,16 +271,17 @@ export default class Example12 { editor: { model: Editors.date, editorOptions: { - minDate: 'today', + range: { min: 'today' }, // set minimum date as today // if we want to preload the date picker with a different date, - // we could toggle the `closeOnSelect: false`, set the date in the picker and re-toggle `closeOnSelect: true` - // closeOnSelect: false, - // onOpen: (selectedDates: Date[] | Date, dateStr: string, instance: FlatpickrInstance) => { - // instance.setDate('2021-06-04', true); - // instance.set('closeOnSelect', true); - // }, - } as FlatpickrOption, + // we could do it by assigning settings.seleted.dates + // NOTE: vanilla-calendar doesn't automatically focus the picker to the year/month and you need to do it yourself + // selected: { + // dates: ['2021-06-04'], + // month: 6 - 1, // Note: JS Date month (only) is zero index based, so June is 6-1 => 5 + // year: 2021 + // } + } as VanillaCalendarOption, massUpdate: true, validator: (value, args) => { const dataContext = args && args.item; @@ -364,7 +365,8 @@ export default class Example12 { { id: 'action', name: 'Action', field: 'action', width: 70, minWidth: 70, maxWidth: 70, excludeFromExport: true, - formatter: () => `
`, + cssClass: 'justify-center flex', + formatter: () => `
`, cellMenu: { hideCloseButton: false, commandTitle: 'Commands', @@ -386,7 +388,7 @@ export default class Example12 { 'divider', { command: 'delete-row', title: 'Delete Row', positionOrder: 64, - iconCssClass: 'mdi mdi-close color-danger', cssClass: 'red', textCssClass: 'text-italic color-danger-light', + iconCssClass: 'mdi mdi-close', cssClass: 'has-text-danger', textCssClass: 'text-italic', // only show command to 'Delete Row' when the task is not completed itemVisibilityOverride: (args) => { return !args.dataContext?.completed; @@ -626,7 +628,7 @@ export default class Example12 { /* if (columnDef.id === 'completed') { this.compositeEditorInstance.changeFormEditorOption('percentComplete', 'filter', true); // multiple-select.js, show filter in dropdown - this.compositeEditorInstance.changeFormEditorOption('finish', 'minDate', 'today'); // flatpickr, change minDate to today + this.compositeEditorInstance.changeFormEditorOption('finish', 'range', { min: 'today' }); // calendar picker, change minDate to today } */ } @@ -972,7 +974,7 @@ export default class Example12 { modalTitle = 'Clone - {{title}}'; break; case 'edit': - modalTitle = 'Editing - {{title}} (id: {{id}})'; // 'Editing - {{title}} ({{product.itemName}})' + modalTitle = 'Editing - {{title}} (id: {{id}})'; // 'Editing - {{title}} ({{product.itemName}})' break; case 'mass-update': modalTitle = 'Mass Update All Records'; diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example13.html b/examples/vite-demo-vanilla-bundle/src/examples/example13.html index 37807dd8b..1dfc16936 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example13.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/example13.html @@ -5,7 +5,7 @@

- code + code

diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example13.ts b/examples/vite-demo-vanilla-bundle/src/examples/example13.ts index 649bd2e42..8d07b5fd3 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example13.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example13.ts @@ -98,13 +98,13 @@ export default class Example13 { const command = args.command; if (command === 'toggle-highlight') { - if (button.cssClass === 'mdi mdi-lightbulb-on color-danger') { + if (button.cssClass === 'mdi mdi-lightbulb-on text-color-danger') { if (gridNo === 1) { delete columns1WithHighlightingById[column.id]; } else { delete columns2WithHighlightingById[column.id]; } - button.cssClass = 'mdi mdi-lightbulb-outline color-warning faded'; + button.cssClass = 'mdi mdi-lightbulb-outline text-color-warning faded'; button.tooltip = 'Highlight negative numbers.'; } else { if (gridNo === 1) { @@ -112,7 +112,7 @@ export default class Example13 { } else { columns2WithHighlightingById[column.id] = true; } - button.cssClass = 'mdi mdi-lightbulb-on color-danger'; + button.cssClass = 'mdi mdi-lightbulb-on text-color-danger'; button.tooltip = 'Remove highlight.'; } this[`sgb${gridNo}`].slickGrid?.invalidate(); @@ -143,7 +143,7 @@ export default class Example13 { header: { buttons: [ { - cssClass: 'mdi mdi-lightbulb-outline color-warning faded', + cssClass: 'mdi mdi-lightbulb-outline text-color-warning faded', command: 'toggle-highlight', tooltip: 'Highlight negative numbers.', itemVisibilityOverride: (args) => { diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example14.html b/examples/vite-demo-vanilla-bundle/src/examples/example14.html index b2a2ffcba..dee8edac6 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example14.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/example14.html @@ -6,7 +6,7 @@

- code + code

@@ -30,14 +30,14 @@

Container Width (1000px)

@@ -46,20 +46,20 @@

Container Width (1000px)

diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example14.ts b/examples/vite-demo-vanilla-bundle/src/examples/example14.ts index 7c5291cb6..70a3fa8cd 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example14.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example14.ts @@ -6,7 +6,6 @@ import { EventNamingStyle, FieldType, Filters, - type FlatpickrOption, type Formatter, Formatters, type GridOption, @@ -15,6 +14,7 @@ import { SlickGlobalEditorLock, type SliderRangeOption, SortComparers, + type VanillaCalendarOption, // utilities formatNumber, @@ -93,7 +93,7 @@ export default class Example14 { isGridEditable = true; classDefaultResizeButton = 'button is-small'; classNewResizeButton = 'button is-small is-selected is-primary'; - editQueue: Array<{ item: any; columns: Column[]; editCommand: EditCommand }> = []; + editQueue: Array<{ item: any; columns: Column[]; editCommand: EditCommand; }> = []; editedItems = {}; sgb: SlickVanillaGridBundle; gridContainerElm: HTMLDivElement; @@ -220,7 +220,7 @@ export default class Example14 { exportCustomFormatter: Formatters.dateUs, type: FieldType.date, outputType: FieldType.dateUs, saveOutputType: FieldType.dateUtc, filterable: true, filter: { model: Filters.compoundDate }, - editor: { model: Editors.date, editorOptions: { hideClearButton: false } as FlatpickrOption }, + editor: { model: Editors.date, editorOptions: { hideClearButton: false } as VanillaCalendarOption }, }, { id: 'completed', name: 'Completed', field: 'completed', width: 80, minWidth: 75, maxWidth: 100, @@ -242,7 +242,7 @@ export default class Example14 { exportCustomFormatter: Formatters.dateUs, editor: { model: Editors.date, - editorOptions: { minDate: 'today' }, + editorOptions: { range: { min: 'today' } } as VanillaCalendarOption, validator: (value, args) => { const dataContext = args && args.item; if (dataContext && (dataContext.completed && !value)) { @@ -326,7 +326,8 @@ export default class Example14 { { id: 'action', name: 'Action', field: 'action', width: 70, minWidth: 70, maxWidth: 70, excludeFromExport: true, - formatter: () => `
`, + cssClass: 'justify-center flex', + formatter: () => `
`, cellMenu: { hideCloseButton: false, commandTitle: 'Commands', @@ -334,14 +335,14 @@ export default class Example14 { { command: 'help', title: 'Help!', - iconCssClass: 'mdi mdi-circle-question', + iconCssClass: 'mdi mdi-help-circle', positionOrder: 66, action: () => alert('Please Help!'), }, 'divider', { command: 'delete-row', title: 'Delete Row', positionOrder: 64, - iconCssClass: 'mdi mdi-close color-danger', cssClass: 'red', textCssClass: 'text-italic color-danger-light', + iconCssClass: 'mdi mdi-close text-color-danger', cssClass: 'red', textCssClass: 'text-italic text-color-danger-light', // only show command to 'Delete Row' when the task is not completed itemVisibilityOverride: (args) => { return !args.dataContext?.completed; @@ -507,7 +508,7 @@ export default class Example14 { } showSpinner() { - this.loadingClass = 'mdi mdi-load mdi-spin-1s mdi-24px color-alt-success'; + this.loadingClass = 'mdi mdi-load mdi-spin-1s mdi-24px text-color-alt-success'; } loadData(count: number) { @@ -578,7 +579,7 @@ export default class Example14 { } handleOnBeforeEditCell(event) { - const args = event && event.detail && event.detail.args; + const args = event?.detail?.args; const { column, item, grid } = args; if (column && item) { @@ -591,7 +592,7 @@ export default class Example14 { } handleOnCellChange(event) { - const args = event && event.detail && event.detail.args; + const args = event?.detail?.args; const dataContext = args && args.item; // when the field "completed" changes to false, we also need to blank out the "finish" date diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example15.html b/examples/vite-demo-vanilla-bundle/src/examples/example15.html index 0cb16b155..2366235bc 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example15.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/example15.html @@ -5,7 +5,7 @@

- code + code

@@ -20,7 +20,7 @@
@@ -12,7 +12,7 @@

- code + code

diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example16.scss b/examples/vite-demo-vanilla-bundle/src/examples/example16.scss index 5a9cdcdff..f6c88923d 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example16.scss +++ b/examples/vite-demo-vanilla-bundle/src/examples/example16.scss @@ -27,35 +27,53 @@ // it's preferable to use CSS Variables (or SASS) but if you want to change colors of your tooltip for 1 column in particular you can do it this way // e.g. change css of 5th column 4 (zero index: l4) -.l4 { - --slick-tooltip-color: #fff; +.grid16-tooltip { + &.l4 { + --slick-tooltip-color: #fff; + } + &.l4 .header-tooltip-title, + &.l4 .headerrow-tooltip-title { + color: #ffffff; + } + &.l4 { + color: #ffffff; + background-color: #696969; + border: 2px solid #545454; + } + &.l4.arrow-down::after, + &.l4.arrow-up::after { + border-width: 10px; // arrow size + } + &.l4.arrow-down::after { + border-top-color: #464646; // arrow down color + } + &.l4.arrow-up::after { + top: -20px; // arrow size * 2 + border-bottom-color: #464646; // arrow up color + } + &.l4.arrow-left-align::after { + margin-left: 15px; + } + &.l4.arrow-right-align::after { + margin-left: calc(100% - 20px - 15px); // 20px is (arrow size * 2), 15px is your extra side margin + } + &.l6.arrow-left-align::after { + margin-left: 4px; + } } -.l4 .header-tooltip-title, -.l4 .headerrow-tooltip-title { - color: #ffffff; -} -.l4.slick-custom-tooltip { - color: #ffffff; - background-color: #696969; - border: 2px solid #545454; -} -.l4.slick-custom-tooltip.arrow-down::after, -.l4.slick-custom-tooltip.arrow-up::after { - border-width: 10px; // arrow size -} -.l4.slick-custom-tooltip.arrow-down::after { - border-top-color: #464646; // arrow down color -} -.l4.slick-custom-tooltip.arrow-up::after { - top: -20px; // arrow size * 2 - border-bottom-color: #464646; // arrow up color -} -.l4.slick-custom-tooltip.arrow-left-align::after { - margin-left: 15px; -} -.l4.slick-custom-tooltip.arrow-right-align::after { - margin-left: calc(100% - 20px - 15px); // 20px is (arrow size * 2), 15px is your extra side margin -} -.l6.slick-custom-tooltip.arrow-left-align::after { - margin-left: 4px; + +[data-theme=dark] .grid16-tooltip { + --slick-tooltip-color: #dadada; + --slick-tooltip-border: 1px solid #5a5a5a; + --slick-tooltip-background-color: #414141; + --slick-tooltip-arrow-color: #707070; + + &.l4 { + --slick-tooltip-color: #dadada; + --slick-tooltip-background-color: #a7a7a7; + --slick-tooltip-border: 2px solid #999999; + } + .text-color-primary { + color: #83c5ff; + } } \ No newline at end of file diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example16.ts b/examples/vite-demo-vanilla-bundle/src/examples/example16.ts index 5ac4fa6cc..62a3066c3 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example16.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example16.ts @@ -10,6 +10,7 @@ import { OperatorType, type SliderOption, type SliderRangeOption, + type VanillaCalendarOption, } from '@slickgrid-universal/common'; import { BindingEventService } from '@slickgrid-universal/binding'; import { SlickCustomTooltip } from '@slickgrid-universal/custom-tooltip-plugin'; @@ -197,7 +198,7 @@ export default class Example16 { }, { id: 'finish', name: 'Finish', field: 'finish', sortable: true, - editor: { model: Editors.date, editorOptions: { minDate: 'today' }, }, + editor: { model: Editors.date, editorOptions: { range: { min: 'today' } } as VanillaCalendarOption }, // formatter: Formatters.dateIso, type: FieldType.date, outputType: FieldType.dateIso, formatter: Formatters.dateIso, @@ -279,8 +280,9 @@ export default class Example16 { }, }, { - id: 'action', name: 'Action', field: 'action', width: 70, minWidth: 70, maxWidth: 70, - formatter: () => `
`, + id: 'action', name: 'Action', field: 'action', width: 55, minWidth: 55, maxWidth: 55, + cssClass: 'justify-center flex', + formatter: () => `
`, excludeFromExport: true, // customTooltip: { // formatter: () => `Click to open Cell Menu`, // return empty so it won't show any pre-tooltip @@ -354,6 +356,7 @@ export default class Example16 { // Custom Tooltip options can be defined in a Column or Grid Options or a mixed of both (first options found wins) externalResources: [new SlickCustomTooltip(), new ExcelExportService(), new TextExportService()], customTooltip: { + className: 'grid16-tooltip', formatter: this.tooltipFormatter.bind(this), headerFormatter: this.headerFormatter, headerRowFormatter: this.headerRowFormatter, @@ -481,7 +484,7 @@ export default class Example16 { // use a 2nd Formatter to get the percent completion // any properties provided from the `asyncPost` will end up in the `__params` property (unless a different prop name is provided via `asyncParamsPropName`) const completionBar = Formatters.percentCompleteBarWithText(row, cell, dataContext.percentComplete, column, dataContext, grid) as HTMLElement; - const out = `
${tooltipTitle}
+ const out = `
${tooltipTitle}
Completion:
${completionBar.outerHTML || ''}
Lifespan:
${dataContext.__params.lifespan.toFixed(2)}
Ratio:
${dataContext.__params.ratio.toFixed(2)}
@@ -504,7 +507,7 @@ export default class Example16 { iconCount = 5; } for (let i = 0; i < iconCount; i++) { - const iconColor = iconCount === 5 ? 'color-success' : iconCount >= 3 ? 'color-alt-warning' : 'color-se-secondary-light'; + const iconColor = iconCount === 5 ? 'text-color-success' : iconCount >= 3 ? 'text-color-alt-warning' : 'text-color-se-secondary-light'; output += ``; } return output; diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example17.html b/examples/vite-demo-vanilla-bundle/src/examples/example17.html index 620ea47e5..8abcbf8c2 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example17.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/example17.html @@ -4,7 +4,7 @@

Example 17 - Auto-Scroll with Range Selector see - code + code

diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example17.ts b/examples/vite-demo-vanilla-bundle/src/examples/example17.ts index 289178712..e8d3b7060 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example17.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example17.ts @@ -46,7 +46,7 @@ export default class Example17 { /* Define grid Options and Columns */ defineGrids() { this.columnDefinitions1 = [ - { id: 'sel', name: '#', field: 'id', cssClass: 'cell-unselectable', resizable: false, selectable: false, focusable: false, width: 40 }, + { id: 'sel', name: '#', field: 'id', cssClass: 'cell-unselectable', resizable: false, selectable: false, focusable: false, width: 40, excludeFromHeaderMenu: true }, { id: 'title', name: 'Title', field: 'title', cssClass: 'cell-title', sortable: true, width: 90, filterable: true }, { id: 'duration', name: 'Duration', field: 'duration', width: 90, sortable: true, filterable: true, groupTotalsFormatter: GroupTotalFormatters.sumTotals }, { id: '%', name: '% Complete', field: 'percentComplete', width: 90, sortable: true, filterable: true, formatter: Formatters.percentCompleteBar }, diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example18.html b/examples/vite-demo-vanilla-bundle/src/examples/example18.html index 57a1cb1c4..9a96bf863 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example18.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/example18.html @@ -1,11 +1,17 @@

Example 18 - Real-Time Trading Platform (with Material Theme) + + +

@@ -26,13 +32,13 @@
diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example18.scss b/examples/vite-demo-vanilla-bundle/src/examples/example18.scss index 5e74f4181..122cd4376 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example18.scss +++ b/examples/vite-demo-vanilla-bundle/src/examples/example18.scss @@ -49,3 +49,16 @@ $sparkline-color: #00b78d; // fill: none; fill: rgba($sparkline-color, 0.03); } + +.slick-dark-mode, +.dark-mode { + .changed-gain { + background-color: #00ff001d !important; + } + .changed-loss { + background-color: #ff00001b !important; + } + .trading-platform.full-screen { + background-color: #33393e; + } +} \ No newline at end of file diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example18.ts b/examples/vite-demo-vanilla-bundle/src/examples/example18.ts index 977d54303..3ab368baf 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example18.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example18.ts @@ -24,17 +24,20 @@ const currencyFormatter: Formatter = (_cell, _row, value: string) => const priceFormatter: Formatter = (_cell, _row, value, _col, dataContext) => { const direction = dataContext.priceChange >= 0 ? 'up' : 'down'; const fragment = new DocumentFragment(); + const divElm = document.createElement('div'); + divElm.className = 'd-inline-flex align-items-center'; const spanElm = document.createElement('span'); - spanElm.className = `mdi mdi-arrow-${direction} color-${direction === 'up' ? 'success' : 'danger'}`; - fragment.appendChild(spanElm); + spanElm.className = `mdi mdi-arrow-${direction} text-color-${direction === 'up' ? 'success' : 'danger'}`; + divElm.appendChild(spanElm); + fragment.appendChild(divElm); if (value instanceof HTMLElement) { - fragment.appendChild(value); + divElm.appendChild(value); } return fragment; }; const transactionTypeFormatter: Formatter = (_row, _cell, value: string) => - ` ${value}`; + `
${value}
`; const historicSparklineFormatter: Formatter = (_row, _cell, _value: string, _col, dataContext) => { const svgElem = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); @@ -47,6 +50,7 @@ const historicSparklineFormatter: Formatter = (_row, _cell, _value: string, _col }; export default class Example18 { + private _darkMode = false; columnDefinitions: Column[] = []; dataset: any[] = []; gridOptions!: GridOption; @@ -57,7 +61,7 @@ export default class Example18 { maxChangePerCycle = 10; refreshRate = 75; timer: any; - toggleClassName = this.isFullScreen ? 'icon mdi mdi-arrow-collapse' : 'icon mdi mdi-arrow-expand'; + toggleClassName = this.isFullScreen ? 'mdi mdi-arrow-collapse' : 'mdi mdi-arrow-expand'; sgb: SlickVanillaGridBundle; attached() { @@ -77,6 +81,8 @@ export default class Example18 { dispose() { this.stopSimulation(); this.sgb?.dispose(); + document.querySelector('.demo-container')?.classList.remove('dark-mode'); + document.body.setAttribute('data-theme', 'light'); document.body.classList.remove('material-theme'); } @@ -176,18 +182,19 @@ export default class Example18 { }, draggableGrouping: { dropPlaceHolderText: 'Drop a column header here to group by any of these available columns: Currency, Market or Type', - deleteIconCssClass: 'mdi mdi-close color-danger', + deleteIconCssClass: 'mdi mdi-close text-color-danger', sortAscIconCssClass: 'mdi mdi-arrow-up', sortDescIconCssClass: 'mdi mdi-arrow-down', }, enableDraggableGrouping: true, createPreHeaderPanel: true, + darkMode: this._darkMode, showPreHeaderPanel: true, preHeaderPanelHeight: 40, enableCellNavigation: true, enableFiltering: true, cellHighlightCssClass: 'changed', - rowHeight: 40 + rowHeight: 40, }; } @@ -310,6 +317,23 @@ export default class Example18 { this.sgb.resizerService.resizeGrid(); } + toggleDarkMode() { + this._darkMode = !this._darkMode; + this.toggleBodyBackground(); + this.sgb.gridOptions = { ...this.sgb.gridOptions, darkMode: this._darkMode }; + this.sgb.slickGrid?.setOptions({ darkMode: this._darkMode }); + } + + toggleBodyBackground() { + if (this._darkMode) { + document.body.setAttribute('data-theme', 'dark'); + document.querySelector('.demo-container')?.classList.add('dark-mode'); + } else { + document.body.setAttribute('data-theme', 'light'); + document.querySelector('.demo-container')?.classList.remove('dark-mode'); + } + } + private randomNumber(min: number, max: number, floor = true) { const number = Math.random() * (max - min + 1) + min; return floor ? Math.floor(number) : number; diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example19.html b/examples/vite-demo-vanilla-bundle/src/examples/example19.html index 759f9ac72..2e9babcf4 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example19.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/example19.html @@ -12,7 +12,7 @@

see - code + code

@@ -26,11 +26,11 @@
diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example20.html b/examples/vite-demo-vanilla-bundle/src/examples/example20.html index da0149a3c..eda0c3e8c 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example20.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/example20.html @@ -5,7 +5,7 @@

see - code + code

diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example21.html b/examples/vite-demo-vanilla-bundle/src/examples/example21.html index c0f5b5ce0..8984dc1f3 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example21.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/example21.html @@ -1,29 +1,41 @@

Example 21 - Row Detail View (with Salesforce Theme) + + + +

-    - + + + + + +
diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example21.scss b/examples/vite-demo-vanilla-bundle/src/examples/example21.scss index 04ca7d0ae..d5f1f8fe5 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example21.scss +++ b/examples/vite-demo-vanilla-bundle/src/examples/example21.scss @@ -1,94 +1,104 @@ -.detail { - padding: 5px -} -.preload { - font-size: 18px; -} -.detail { - display: flex; - align-items: center; - max-width: 450px; - // border-bottom: 1px solid #e8e8e8; +.grid21 { + .slick-cell { + display: inline-flex; + align-items: center; + column-gap: 4px; + } + .preload { + font-size: 18px; + } + .detail { + display: flex; + align-items: center; + max-width: 450px; + padding: 5px; + border-bottom: 1px solid #e8e8e8; - label { - font-weight: 600; - font-size: 16px; - margin-right: 10px; - flex-grow: 1; + label { + font-weight: 600; + font-size: 16px; + margin-right: 10px; + flex-grow: 1; + } + span { + font-size: 15px; + } } - span { - font-size: 15px; + + input.filter { + border: 1px solid #dadada; + border-radius: 2px; + } + input.filter::placeholder { + opacity: 0.4; + } + .dynamic-cell-detail { + // background-color: #f8f8f8; + } + .dynamic-cell-detail > :first-child { + vertical-align: middle; + line-height: 13px; + padding: 10px; + margin-left: 20px; + } + .slick-headerrow-column { + background: #f1f1f1; + text-overflow: clip; + box-sizing: border-box; } -} -input.filter { - border: 1px solid #dadada; - border-radius: 2px; -} -input.filter::placeholder { - opacity: 0.4; -} -.dynamic-cell-detail { - box-shadow: inset 0 0 0 1px #b0c1d0; - background-color: #f8f8f8; -} -.dynamic-cell-detail > :first-child { - vertical-align: middle; - line-height: 13px; - padding: 10px; - margin-left: 20px; -} -.slick-headerrow-column { - background: #f1f1f1; - text-overflow: clip; - box-sizing: border-box; -} + .slick-headerrow-column input { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + -moz-box-sizing: border-box; + box-sizing: border-box; + } -.slick-headerrow-column input { - margin: 0; - padding: 0; - width: 100%; - height: 100%; - -moz-box-sizing: border-box; - box-sizing: border-box; -} + /* Style the tab */ + .tab { + overflow: hidden; + border: 1px solid #ccc; + background-color: #f1f1f1; + } -/* Style the tab */ -.tab { - overflow: hidden; - border: 1px solid #ccc; - background-color: #f1f1f1; -} + /* Style the buttons inside the tab */ + .tab button { + background-color: inherit; + float: left; + border: none; + outline: none; + cursor: pointer; + padding: 14px 16px; + transition: 0.3s; + font-size: 17px; + } -/* Style the buttons inside the tab */ -.tab button { - background-color: inherit; - float: left; - border: none; - outline: none; - cursor: pointer; - padding: 14px 16px; - transition: 0.3s; - font-size: 17px; -} + /* Change background color of buttons on hover */ + .tab button:hover { + background-color: #ddd; + } -/* Change background color of buttons on hover */ -.tab button:hover { - background-color: #ddd; -} + /* Create an active/current tablink class */ + .tab button.active { + background-color: #ccc; + } -/* Create an active/current tablink class */ -.tab button.active { - background-color: #ccc; + /* Style the tab content */ + .tabcontent { + display: none; + padding: 6px 12px; + border: 1px solid #ccc; + border-top: none; + } + .options-panel { + width: 375px; + } } -/* Style the tab content */ -.tabcontent { - display: none; - padding: 6px 12px; - border: 1px solid #ccc; - border-top: none; -} -.options-panel { - width: 375px; -} \ No newline at end of file +// .slick-dark-mode { +// .dynamic-cell-detail { +// background-color: #3c4349; +// } +// } \ No newline at end of file diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example21.ts b/examples/vite-demo-vanilla-bundle/src/examples/example21.ts index c50772d17..4a78a3b4f 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example21.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example21.ts @@ -24,12 +24,15 @@ interface ItemDetail extends Item { export default class Example21 { private _bindingEventService: BindingEventService; + private _darkMode = false; private _eventHandler: SlickEventHandler; + isGridEditable = false; detailViewRowCount = 7; gridOptions!: GridOption; columnDefinitions!: Column[]; dataset!: Item[]; sgb!: SlickVanillaGridBundle; + serverApiDelay = 400; status = ''; statusClass = ''; gridContainerElm: HTMLDivElement; @@ -61,9 +64,12 @@ export default class Example21 { } dispose() { + console.log('dispose'); this._eventHandler.unsubscribeAll(); this._bindingEventService.unbindAll(); this.sgb?.dispose(); + document.querySelector('.demo-container')?.classList.remove('dark-mode'); + document.body.setAttribute('data-theme', 'light'); } /* Define grid Options and Columns */ @@ -120,6 +126,25 @@ export default class Example21 { return true; } + toggleGridEditReadonly() { + // then change a single grid options to make the grid non-editable (readonly) + this.isGridEditable = !this.isGridEditable; + if (this.isGridEditable) { + this.rowDetail.collapseAll(); + this.rowDetail.addonOptions.useRowClick = false; + this.gridOptions.autoCommitEdit = !this.gridOptions.autoCommitEdit; + this.sgb.slickGrid?.setOptions({ + editable: true, + autoEdit: true, + enableCellNavigation: true, + }); + } else { + this.rowDetail.addonOptions.useRowClick = true; + this.sgb.gridOptions = { ...this.sgb.gridOptions, editable: this.isGridEditable }; + this.gridOptions = this.sgb.gridOptions; + } + } + closeAllRowDetail() { this.rowDetail.collapseAll(); } @@ -151,8 +176,8 @@ export default class Example21 { this._eventHandler.subscribe(this.rowDetail.onAsyncEndUpdate, (_e, args) => { console.log('finished updating the post async template', args); - this.handleDeleteRowOnClick(args.item.id); - this.handleAssigneeOnClick(args.item.id); + this.addDeleteRowOnClickListener(args.item.id); + this.addAssigneeOnClickListener(args.item.id); }); // the following subscribers can be useful to Save/Re-Render a View @@ -162,21 +187,21 @@ export default class Example21 { }); this._eventHandler.subscribe(this.rowDetail.onRowBackToViewportRange, (_e, args) => { - this.handleDeleteRowOnClick(args.item.id); - this.handleAssigneeOnClick(args.item.id); + this.addDeleteRowOnClickListener(args.item.id); + this.addAssigneeOnClickListener(args.item.id); }); } /** Loading template, can be an HTML string or an HTML Element */ loadingTemplate() { const headerElm = createDomElement('h5', { className: 'title is-5' }); - headerElm.appendChild(createDomElement('i', { className: 'mdi mdi-load mdi-spin-1s mdi-v-align-middle mdi-40px' })); + headerElm.appendChild(createDomElement('i', { className: 'mdi mdi-load mdi-spin-1s mdi-40px' })); headerElm.appendChild(document.createTextNode('Loading...')); return headerElm; } - /** Row Detail View, can be an HTML string or an HTML Element */ + /** Row Detail View, can be an HTML string or an HTML Element (we'll use HTML string for simplicity of the demo) */ loadView(itemDetail: ItemDetail) { return `
@@ -227,7 +252,7 @@ export default class Example21 { // resolve the data after delay specified resolve(itemDetail); - }, 1000); + }, this.serverApiDelay); }); } @@ -240,14 +265,14 @@ export default class Example21 { }, undefined, this); } - handleDeleteRowOnClick(itemId: string) { + addDeleteRowOnClickListener(itemId: string) { const deleteBtnElm = document.querySelector('#delete_row_' + itemId); if (deleteBtnElm) { this._bindingEventService.bind(deleteBtnElm, 'click', this.handleDeleteRow.bind(this, itemId), undefined, `event-detail-${itemId}`); } } - handleAssigneeOnClick(itemId: string) { + addAssigneeOnClickListener(itemId: string) { const assigneeBtnElm = document.querySelector('#who-is-assignee_' + itemId); if (assigneeBtnElm) { this._bindingEventService.bind(assigneeBtnElm, 'click', this.handleAssigneeClicked.bind(this, itemId), undefined, `event-detail-${itemId}`); @@ -309,4 +334,18 @@ export default class Example21 { randomNumber(min: number, max: number) { return Math.floor(Math.random() * (max - min + 1) + min); } + + toggleDarkMode() { + this._darkMode = !this._darkMode; + if (this._darkMode) { + document.body.setAttribute('data-theme', 'dark'); + document.querySelector('.demo-container')?.classList.add('dark-mode'); + } else { + document.body.setAttribute('data-theme', 'light'); + document.querySelector('.demo-container')?.classList.remove('dark-mode'); + } + // we must close all row details because the grid is invalidated and the events listeners will stop working because they are detached after re-rendering + this.closeAllRowDetail(); + this.sgb.slickGrid?.setOptions({ darkMode: this._darkMode }); + } } diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example22.html b/examples/vite-demo-vanilla-bundle/src/examples/example22.html index 2584aa267..c137efb56 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example22.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/example22.html @@ -8,7 +8,7 @@

target="_blank" href="https://github.com/ghiscoding/slickgrid-universal/blob/master/examples/vite-demo-vanilla-bundle/src/examples/example22.ts" > - code + code

@@ -61,7 +61,8 @@
data-test="toggle-language" onclick.delegate="switchLanguage()" > - Switch Language for Action column buttons + + Switch Language for Action column buttons Locale: diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example22.ts b/examples/vite-demo-vanilla-bundle/src/examples/example22.ts index 2e9ababcf..8cc705e12 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example22.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example22.ts @@ -88,7 +88,7 @@ export default class Example22 { minWidth: 100, filterable: true, type: FieldType.number, - editor: { model: Editors.text, validator: (val) => (val > 100 ? { msg: 'Max 100% allowed', valid: false} : { msg: '', valid: true}) }, + editor: { model: Editors.text, validator: (val) => (val > 100 ? { msg: 'Max 100% allowed', valid: false } : { msg: '', valid: true }) }, }, { id: 'start', @@ -192,18 +192,18 @@ export default class Example22 { cancelButtonClassName: 'button-style padding-3px', cancelButtonTitle: 'Cancel row', cancelButtonTitleKey: 'RBE_BTN_CANCEL', - iconCancelButtonClassName: 'mdi mdi-undo color-danger', + iconCancelButtonClassName: 'mdi mdi-undo text-color-danger', cancelButtonPrompt: 'Are you sure you want to cancel your changes?', updateButtonClassName: 'button-style padding-3px mr-2', updateButtonTitle: 'Update row', updateButtonTitleKey: 'RBE_BTN_UPDATE', - iconUpdateButtonClassName: 'mdi mdi-check color-success', + iconUpdateButtonClassName: 'mdi mdi-check text-color-success', updateButtonPrompt: 'Save changes?', deleteButtonClassName: 'button-style padding-3px', deleteButtonTitle: 'Delete row', - iconDeleteButtonClassName: 'mdi mdi-trash-can color-danger', + iconDeleteButtonClassName: 'mdi mdi-trash-can text-color-danger', deleteButtonPrompt: 'Are you sure you want to delete this row?', }, }, diff --git a/examples/vite-demo-vanilla-bundle/src/examples/icons.html b/examples/vite-demo-vanilla-bundle/src/examples/icons.html index 375a45e6d..f68415b33 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/icons.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/icons.html @@ -1,12 +1,18 @@ -

Material Design Icons +

SlickGrid Material Icons (icons & utilities that are available in Slickgrid-Universal) + + +

- Material Design Icons - Official Website (+5000 icons) + All icons came from Material Design Icons - Official Website (+5000 icons)

We only keep a small subset of the Material Design Icons, scroll to the bottom to see which ones are included in the @@ -16,35 +22,42 @@

Material Design Icons

Icon Utilities - +

-
mdi-spin
-
mdi-spin-1s
-
mdi-spin-2s
-
mdi-spin-3s
-
mdi-spin-4s
-
mdi-spin-5s
-
mdi-rotate-45
-
mdi-rotate-90
-
mdi-rotate-135
-
mdi-rotate-180
-
mdi-rotate-220
-
mdi-flip-h
-
mdi-flip-v
+
mdi-spin / mdi-spin-2s
+
mdi-spin-1s
+
mdi-spin-2s
+
mdi-spin-3s
+
mdi-spin-4s
+
mdi-spin-5s
+
mdi-rotate-45
+
mdi-rotate-90
+
mdi-rotate-135
+
mdi-rotate-180
+
mdi-rotate-225
+
mdi-rotate-270
+
mdi-rotate-315
+
mdi-flip-h
+
mdi-flip-v

Icon Sizes - (from 8px up to 50px) + (from 10px up to 50px)

+

+ Note, since icons are now pure CSS you could also use any font size CSS classes (when available) like "font-20px" + or you could also change font-size yourself or even simply inherit text font size. + +

-
mdi-8px
-
mdi-10px
-
mdi-15px
-
mdi-20px
-
mdi-25px
-
mdi-50px
+
font-10px
+
mdi-15px
+
mdi-22px
+
mdi-25px
+
mdi-38px
+
mdi-50px
@@ -54,7 +67,7 @@
text-bold
text-center
text-left
-
text-right
+
text-right
text-lowercase
text-uppercase @@ -69,10 +82,10 @@
Padding & Icons Styled as a Button - (padding from 0px up to 30px) + (padding from 0px up to 30px)

- Note, you can use the same pattern with "margin-0px", "padding-0x" and "font-5px" + Note, you can use the same pattern with "margin-0px", "padding-0x" and "font-5px"

@@ -102,250 +115,218 @@
-
- Icons Alignments - (padding from 0px up to 30px) -
-
-
- - mdi-v-align-bottom -
-
- - mdi-v-align-middle -
-
- mdi-v-align-sub -
-
- mdi-v-align-super -
-
- - mdi-v-align-text-bottom -
-
- - mdi-v-align-text-top -
-
- mdi-v-align-top -
-
-

- Icon Colors + Icon & Text Colors

-
- - color-primary +
+ + text-color-primary
-
- - color-primary-light +
+ + text-color-primary-light
-
- - color-primary-dark +
+ + text-color-primary-dark
-
- - color-secondary +
+ + text-color-secondary
-
- - color-secondary-light +
+ + text-color-secondary-light
-
- - color-secondary-dark +
+ + text-color-secondary-dark
-
- - color-success +
+ + text-color-success
-
- - color-success-light +
+ + text-color-success-light
-
- - color-success-dark +
+ + text-color-success-dark
-
- - color-danger +
+ + text-color-danger
-
- - color-danger-light +
+ + text-color-danger-light
-
- - color-danger-dark +
+ + text-color-danger-dark
-
- - color-warning +
+ + text-color-warning
-
- - color-warning-light +
+ + text-color-warning-light
-
- - color-warning-dark +
+ + text-color-warning-dark
-
- - color-info +
+ + text-color-info
-
- - color-info-light +
+ + text-color-info-light
-
- - color-info-dark +
+ + text-color-info-dark
-
- - color-muted +
+ + text-color-muted
-
- - color-muted-light +
+ + text-color-muted-light
-
- - color-muted-dark +
+ + text-color-muted-dark
-
- - color-alt-default +
+ + text-color-alt-default
-
- - color-alt-default-light +
+ + text-color-alt-default-light
-
- - color-alt-default-dark +
+ + text-color-alt-default-dark
-
- - color-alt-warning +
+ + text-color-alt-warning
-
- - color-alt-warning-light +
+ + text-color-alt-warning-light
-
- - color-alt-warning-dark +
+ + text-color-alt-warning-dark
-
- - color-alt-danger +
+ + text-color-alt-danger
-
- - color-alt-danger-light +
+ + text-color-alt-danger-light
-
- - color-alt-danger-dark +
+ + text-color-alt-danger-dark
-
- - color-alt-success +
+ + text-color-alt-success
-
- - color-alt-success-light +
+ + text-color-alt-success-light
-
- - color-alt-success-dark +
+ + text-color-alt-success-dark
-
- - color-se-primary +
+ + text-color-se-primary
-
- - color-se-link +
+ + text-color-se-link
-
- - color-se-link-dark +
+ + text-color-se-link-dark
-
- - color-se-danger +
+ + text-color-se-danger
-
- - color-se-secondary-light +
+ + text-color-se-secondary-light
-
- - color-se-secondary +
+ + text-color-se-secondary
-
- - color-se-warning +
+ + text-color-se-warning
-
- - color-se-warning-light +
+ + text-color-se-warning-light
-
- - color-sf-highlight +
+ + text-color-sf-highlight
-
- - color-sf-primary +
+ + text-color-sf-primary
-
- - color-sf-primary-dark +
+ + text-color-sf-primary-dark
-
- - color-dark +
+ + text-color-dark
-
- - color-body +
+ + text-color-body
-
- - color-disabled +
+ + text-color-disabled
-
- - color-disabled-dark +
+ + text-color-disabled-dark
-
- - color-light +
+ + text-color-light
-
- - color-white +
+ + text-color-white

Icons currently available in the lib - +

\ No newline at end of file diff --git a/examples/vite-demo-vanilla-bundle/src/examples/icons.scss b/examples/vite-demo-vanilla-bundle/src/examples/icons.scss index 5ca991db5..ee539d95e 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/icons.scss +++ b/examples/vite-demo-vanilla-bundle/src/examples/icons.scss @@ -17,4 +17,16 @@ } .bg-gray { background-color: #3F3E3E; +} +.icon-box { + display: flex; + align-items: center; +} +.button-style { + display: inline-flex; + align-items: center; + justify-content: center; +} +.mr-5px { + margin-right: 5px; } \ No newline at end of file diff --git a/examples/vite-demo-vanilla-bundle/src/examples/icons.ts b/examples/vite-demo-vanilla-bundle/src/examples/icons.ts index d4f617f75..2abded044 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/icons.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/icons.ts @@ -1,6 +1,8 @@ import './icons.scss'; export default class Icons { + private _darkMode = false; + attached() { const iconContainerElm = document.querySelector(`.icons-container`) as HTMLDivElement; const iconCounter = document.querySelector(`.icon-counter`) as HTMLDivElement; @@ -10,14 +12,18 @@ export default class Icons { icons.forEach((icon) => { const iconDivElm = document.createElement('div'); - iconDivElm.className = 'slick-col-medium-2'; - iconDivElm.style.paddingBottom = '5px'; + iconDivElm.className = 'slick-col-medium-2 icon-box'; + iconDivElm.style.marginBottom = '5px'; const iconElm = document.createElement('span'); iconElm.className = icon.replace(/\./gi, ' '); - iconElm.classList.add('mdi-24px'); + if (icon.includes('mdi-change-record-type')) { + iconElm.classList.add('mdi-20px'); + } else { + iconElm.classList.add('mdi-24px'); + } iconElm.title = icon.replace('.mdi.', ''); - iconElm.style.marginRight = '2px'; + iconElm.style.marginRight = '5px'; iconDivElm.appendChild(iconElm); const iconNameElm = document.createElement('span'); @@ -28,6 +34,22 @@ export default class Icons { }); } + dispose() { + document.querySelector('.demo-container')?.classList.remove('dark-mode'); + document.body.setAttribute('data-theme', 'light'); + } + + toggleDarkMode() { + this._darkMode = !this._darkMode; + if (this._darkMode) { + document.body.setAttribute('data-theme', 'dark'); + document.querySelector('.demo-container')?.classList.add('dark-mode'); + } else { + document.body.setAttribute('data-theme', 'light'); + document.querySelector('.demo-container')?.classList.remove('dark-mode'); + } + } + getIcons() { return [ '.mdi.mdi-account', @@ -59,6 +81,7 @@ export default class Icons { '.mdi.mdi-arrow-expand', '.mdi.mdi-arrow-expand-horizontal', '.mdi.mdi-arrow-split-vertical', + '.mdi.mdi-book-open-blank-variant-outline', '.mdi.mdi-brightness-4', '.mdi.mdi-calendar', '.mdi.mdi-calendar-check', @@ -204,6 +227,7 @@ export default class Icons { '.mdi.mdi-snowflake', '.mdi.mdi-sort-ascending', '.mdi.mdi-sort-descending', + '.mdi.mdi-sort-variant-off', '.mdi.mdi-sort-variant-remove', '.mdi.mdi-square-edit-outline', '.mdi.mdi-star', diff --git a/examples/vite-demo-vanilla-bundle/src/main.ts b/examples/vite-demo-vanilla-bundle/src/main.ts index 4ae989561..3e0a57dea 100644 --- a/examples/vite-demo-vanilla-bundle/src/main.ts +++ b/examples/vite-demo-vanilla-bundle/src/main.ts @@ -1,15 +1,9 @@ -// import all CSS required by Slickgrid-Universal -import 'flatpickr/dist/flatpickr.min.css'; -import './styles.scss'; - import { Renderer } from './renderer'; import * as SlickerModule from '@slickgrid-universal/vanilla-bundle'; import { App } from './app'; import AppView from './app.html?raw'; import { TranslateService } from './translate.service'; - -// load necessary Flatpickr Locale(s), but make sure it's imported AFTER the SlickerModule import -import 'flatpickr/dist/l10n/fr'; +import './styles.scss'; class Main { app!: App; diff --git a/examples/vite-demo-vanilla-bundle/src/material-styles.scss b/examples/vite-demo-vanilla-bundle/src/material-styles.scss index d3f5f9879..81d72ab35 100644 --- a/examples/vite-demo-vanilla-bundle/src/material-styles.scss +++ b/examples/vite-demo-vanilla-bundle/src/material-styles.scss @@ -3,8 +3,11 @@ // @import '@slickgrid-universal/common/dist/styles/sass/slickgrid-theme-material.scss'; :root { - body.material-theme { + body.material-theme, + body.material-theme .icon-checkbox-container { + $dark-primary-color: #66bb6a; $slick-primary-color: #009530; + --text-color-primary: #009530; --slick-primary-color: #009530; --slick-header-menu-display: inline-block; --slick-compound-filter-operator-select-border: 1px solid #00c840; @@ -39,24 +42,22 @@ --slick-header-font-size: 12px; --slick-filled-filter-font-weight: normal; --slick-icon-sort-color: var(--slick-primary-color); - --slick-icon-sort-asc: url('data:image/svg+xml,'); - --slick-icon-sort-desc: url('data:image/svg+xml,'); - --slick-icon-sort-font-size: 18px; - --slick-icon-sort-width: 18px; - --slick-icon-sort-position-right: 14px; - --slick-checkbox-selector-size: 22px; - --slick-checkbox-selector-icon-width: 22px; - --slick-checkbox-selector-checked-color: var(--slick-primary-color); - --slick-checkbox-selector-color: var(--slick-primary-color); - --slick-checkbox-selector-icon-border: none; - --slick-checkbox-selector-icon-bg-color: transparent; - --slick-checkbox-selector-icon-checked: url('data:image/svg+xml,'); - --slick-checkbox-selector-icon-unchecked: url('data:image/svg+xml,'); + --slick-column-picker-icon-color: #009530; + --slick-compound-filter-text-color: #009530; + --slick-checkbox-icon-color: var(--slick-primary-color); + --slick-checkbox-icon-border: none; + --slick-checkbox-icon-width: 22px; + --slick-checkbox-icon-bg-color: transparent; + --slick-checkbox-icon-container-bg-color: transparent; + --slick-checkbox-icon-unchecked-color-visibility: visible; + --slick-checkbox-icon-container-size: 1rem; + --slick-checkbox-icon-font-size: 28px; + --slick-checkbox-icon-container-size: 1.4rem; + --slick-checkbox-opacity-hover: 0.9; + --slick-checkbox-size: 22px; + --slick-checkbox-unchecked-opacity: 1; --slick-icon-group-color: var(--slick-primary-color); - --slick-icon-group-collapsed: url('data:image/svg+xml,'); - --slick-icon-group-expanded: url('data:image/svg+xml,'); - --slick-icon-group-width: 22px; - + --slick-pagination-icon-color: #009530; --slick-slider-filter-thumb-border: 2px solid rgba(0, 149, 48, .68); --slick-slider-filter-thumb-active-bg-color: #fff; --slick-slider-filter-thumb-active-color: rgba(#02bf3e, .88); @@ -74,22 +75,24 @@ --slick-multiselect-ok-button-text-color: #009530; --slick-multiselect-ok-button-text-hover-color: #00a736; --slick-multiselect-select-all-text-color: #007c28; - --slick-column-picker-checkbox-icon-checked: url('data:image/svg+xml,'); - --slick-column-picker-checkbox-icon-unchecked: var(--slick-column-picker-checkbox-icon-checked); - --slick-multiselect-icon-unchecked: url('data:image/svg+xml,'); --ms-checkbox-color: var(--slick-primary-color); --slick-multiselect-icon-color: var(--slick-primary-color); - --slick-multiselect-icon-radio-checked: url('data:image/svg+xml,'); - --slick-multiselect-icon-radio-unchecked: url('data:image/svg+xml,'); - .color-primary { - filter: url("data:image/svg+xml;utf8, #recolor"); + .icon-checkbox-container { + --slick-checkbox-icon-container-bg-color: transparent; + --slick-checkbox-unchecked-opacity: 0.9; + .mdi-icon-check { + --slick-checkbox-icon-checked-svg: url('data:image/svg+xml;utf8,%3Csvg viewBox="0 0 24 24" display="inline-block" height="1em" width="1em" vertical-align="text-bottom" xmlns="http://www.w3.org/2000/svg" %3E%3Cpath fill="currentColor" d="M10,17L5,12L6.41,10.58L10,14.17L17.59,6.58L19,8M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3Z"/%3E%3C/svg%3E') !important; + } + .mdi-icon-uncheck { + --slick-checkbox-icon-unchecked-svg: url('data:image/svg+xml;utf8,%3Csvg viewBox="0 0 24 24" display="inline-block" height="1em" width="1em" vertical-align="text-bottom" xmlns="http://www.w3.org/2000/svg" %3E%3Cpath fill="currentColor" d="M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M19,5V19H5V5H19Z"/%3E%3C/svg%3E') !important; + } } .slick-headerrow { input.search-filter.filled, .search-filter.filled input, - .search-filter.filled input.flatpickr-input, + .search-filter.filled input.date-picker, .search-filter.filled .input-group-addon.slider-value, .search-filter.filled .input-group-addon.slider-range-value, .search-filter.filled .input-group-addon select { @@ -118,12 +121,19 @@ .ms-dark-mode, .ms-drop.ms-dark-mode, .slick-dark-mode .ms-dark-mode, + .slick-dark-mode .icon-checkbox-container, + .ms-dark-mode .icon-checkbox-container, .slick-dark-mode { --slick-base-dark-menu-bg-color: #212121; --slick-primary-color: #66bb6a; - --slick-button-primary-bg-color: var(--slick-primary-color); + --slick-button-primary-bg-color:#66bb6a; + --slick-cell-active-box-shadow: inset 0 0 0 1px #aaaaaa; --slick-cell-box-shadow: none; - --slick-column-picker-checkbox-color: #49a54e; + --slick-checkbox-icon-color: #66bb6a; + --slick-checkbox-icon-height: 22px; + --slick-checkbox-icon-bg-color: transparent; + --slick-checkbox-icon-border: none; + --slick-column-picker-icon-color: #66bb6a; --slick-compound-filter-text-color: #66bb6a; --slick-compound-filter-operator-select-border: 1px solid #66bb6a; --slick-header-filter-row-border-bottom: 1px solid #505050; @@ -134,17 +144,13 @@ --slick-pane-top-border-top: 1px solid #505050; --slick-filled-filter-color: #66bb6a; --slick-highlight-color: #49a54e; - --slick-pagination-icon-color: #49a54e; - --slick-checkbox-selector-checked-color: #66bb6a; + --slick-icon-sort-color: #66bb6a; + --slick-grid-menu-icon-btn-color: #bbb; + --slick-pagination-icon-color: #66bb6a; --slick-row-mouse-hover-box-shadow: none; --slick-row-mouse-hover-color: #505050; --slick-row-selected-color: #474747; - --slick-checkbox-selector-opacity: 1; - --slick-checkbox-selector-icon-height: 22px; - --slick-checkbox-selector-icon-bg-color: transparent; - --slick-checkbox-selector-icon-border: none; - --slick-multiselect-icon-radio-color: var(--slick-primary-color); - --ms-checkbox-color: var(--slick-primary-color); + --ms-checkbox-color: #66bb6a; --ms-checkbox-hover-color: #{lighten(#49a54e, 13%)}; --ms-ok-button-text-color: #66bb6a; --ms-ok-button-text-hover-color: #{lighten(#66bb6a, 5%)}; @@ -157,10 +163,18 @@ } input.search-filter.filled, .search-filter.filled input, - .search-filter.filled input.flatpickr-input { + .search-filter.filled .date-picker input { color: var(--slick-text-color); } } } } + + body.material-theme .ms-dark-mode, + body.material-theme .ms-drop.ms-dark-mode, + body.material-theme .slick-dark-mode .ms-dark-mode, + body.material-theme .slick-dark-mode, + body.material-theme .dark-mode .text-color-primary { + --slick-primary-color: #66bb6a; + } } diff --git a/examples/vite-demo-vanilla-bundle/src/styles.scss b/examples/vite-demo-vanilla-bundle/src/styles.scss index cff379557..012ce46ac 100644 --- a/examples/vite-demo-vanilla-bundle/src/styles.scss +++ b/examples/vite-demo-vanilla-bundle/src/styles.scss @@ -9,6 +9,17 @@ $slick-link-color: #006DCC; @import './bulma.scss'; +:root { + .ms-dark-mode, + .ms-drop.ms-dark-mode, + .slick-dark-mode .ms-dark-mode, + .slick-dark-mode, + .dark-mode .text-color-primary { + --slick-primary-color: #66b8ff; + --text-color-primary: #66b8ff; + } +} + $navbar-height: 52px; body { height: calc(100vh - $navbar-height); @@ -34,9 +45,9 @@ body { } .demo-container.dark-mode { background-color: #33393e; - color: #dddddd; + color: #f0f0f0; h3 { - color: #dddddd; + color: #e4e4e4; } .subtitle { color: #cbcbcb; @@ -85,8 +96,20 @@ input.is-narrow { width: 35px; margin-top: -1px; } +.d-inline-flex { + display: inline-flex; +} +.align-items-center { + align-items: center; +} +.columns:not(:last-child) { + margin-bottom: calc(1.5rem - 0.9rem); +} +.gap-5px { + gap: 5px; +} .text-green { - color: green; + color: #009e00; } .text-violet { color: #659bff; @@ -97,9 +120,12 @@ input.is-narrow { .text-red { color: red; } -.d-inline-flex { - display: inline-flex; +.flex { + display: flex !important; } -.columns:not(:last-child) { - margin-bottom: calc(1.5rem - 0.9rem); +.align-center { + align-items: center; +} +.justify-center { + justify-content: center; } \ No newline at end of file diff --git a/examples/vite-demo-vanilla-bundle/vite.config.mts b/examples/vite-demo-vanilla-bundle/vite.config.mts index 3bfc9b9ea..e9d9d53be 100644 --- a/examples/vite-demo-vanilla-bundle/vite.config.mts +++ b/examples/vite-demo-vanilla-bundle/vite.config.mts @@ -10,11 +10,6 @@ export default defineConfig(() => { chunkSizeWarningLimit: 6000, emptyOutDir: true, outDir: '../../website', - rollupOptions: { - external: [ - './node_modules/flatpickr/dist/l10n/fr', - ], - }, }, preview: { port: 8888 diff --git a/lerna.json b/lerna.json index 713424684..78ccdda00 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/@lerna-lite/cli/schemas/lerna-schema.json", - "version": "4.7.0", + "version": "5.0.0-beta.3", "npmClient": "pnpm", "loglevel": "info", "command": { @@ -20,6 +20,7 @@ "syncWorkspaceLock": true } }, + "changelogPreset": "conventional-changelog-conventionalcommits", "packages": [ "examples/*", "packages/*" diff --git a/package.json b/package.json index 87584bc96..24d4ae41e 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "preview:publish": "lerna publish from-package --dry-run --yes", "preview:version": "lerna version --dry-run --yes", "preview:roll-new-release": "pnpm bundle && pnpm new-version --dry-run && pnpm new-publish --dry-run", + "beta-release": "lerna publish 5.0.0-beta.2 --dist-tag beta", "new-version": "lerna version", "new-publish": "lerna publish from-package", "roll-new-release": "pnpm bundle && pnpm new-version && pnpm new-publish", @@ -58,6 +59,7 @@ "@4tw/cypress-drag-drop": "^2.2.5", "@commitlint/cli": "^19.3.0", "@commitlint/config-conventional": "^19.2.2", + "@formkit/tempo": "^0.1.1", "@jest/types": "^29.6.3", "@lerna-lite/cli": "^3.3.3", "@lerna-lite/publish": "^3.3.3", @@ -65,6 +67,7 @@ "@lerna-lite/watch": "^3.3.3", "@types/jest": "^29.5.12", "@types/node": "^20.12.11", + "conventional-changelog-conventionalcommits": "^7.0.2", "cross-env": "^7.0.3", "cypress": "^13.9.0", "cypress-real-events": "^1.12.0", @@ -74,7 +77,6 @@ "eslint-plugin-import": "^2.29.1", "eslint-plugin-jest": "^28.5.0", "eslint-plugin-n": "^17.5.1", - "flatpickr": "^4.6.13", "husky": "^9.0.11", "jest": "^29.7.0", "jest-cli": "^29.7.0", @@ -82,7 +84,6 @@ "jest-extended": "^4.0.2", "jsdom": "^24.0.0", "jsdom-global": "^3.0.2", - "moment-mini": "^2.29.4", "npm-run-all2": "^6.1.2", "pnpm": "^8.15.8", "rimraf": "^5.0.5", diff --git a/packages/binding/CHANGELOG.md b/packages/binding/CHANGELOG.md index 6fe9a4079..c2bfdeb1f 100644 --- a/packages/binding/CHANGELOG.md +++ b/packages/binding/CHANGELOG.md @@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.0-beta.3](https://github.com/ghiscoding/slickgrid-universal/compare/v5.0.0-beta.2...v5.0.0-beta.3) (2024-05-09) + +**Note:** Version bump only for package @slickgrid-universal/binding + +## [5.0.0-beta.2](https://github.com/ghiscoding/slickgrid-universal/compare/v4.7.0...v5.0.0-beta.2) (2024-05-07) + +### ⚠ BREAKING CHANGES + +* **common:** migrate from Flatpickr to Vanilla-Calendar (#1466) + +### Features + +* **common:** migrate from Flatpickr to Vanilla-Calendar ([#1466](https://github.com/ghiscoding/slickgrid-universal/issues/1466)) ([fb6e950](https://github.com/ghiscoding/slickgrid-universal/commit/fb6e950f429b4abd868fca86d9c304580a745b1c)) - by @ghiscoding + # [4.7.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.6.3...v4.7.0) (2024-04-20) **Note:** Version bump only for package @slickgrid-universal/binding @@ -141,6 +155,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **build:** package exports prop had invalid ESM import link ([#892](https://github.com/ghiscoding/slickgrid-universal/issues/892)) ([7f95f69](https://github.com/ghiscoding/slickgrid-universal/commit/7f95f698447f8178cb7ceec416c35f4957fddbe9)) - by @ghiscoding + * **deps:** update dependency dompurify to v3 ([#907](https://github.com/ghiscoding/slickgrid-universal/issues/907)) ([66c8b4d](https://github.com/ghiscoding/slickgrid-universal/commit/66c8b4d602d88d733070b2189468bf1b6508d7eb)) - by @renovate-bot # [2.4.0](https://github.com/ghiscoding/slickgrid-universal/compare/v2.3.0...v2.4.0) (2023-02-04) diff --git a/packages/binding/README.md b/packages/binding/README.md index 6a26d9488..bae5f2a55 100644 --- a/packages/binding/README.md +++ b/packages/binding/README.md @@ -3,6 +3,7 @@ [![lerna--lite](https://img.shields.io/badge/maintained%20with-lerna--lite-e137ff)](https://github.com/ghiscoding/lerna-lite) [![npm](https://img.shields.io/npm/v/@slickgrid-universal/binding.svg)](https://www.npmjs.com/package/@slickgrid-universal/binding) [![npm](https://img.shields.io/npm/dy/@slickgrid-universal/binding)](https://www.npmjs.com/package/@slickgrid-universal/binding) +[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/binding?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/binding) [![Actions Status](https://github.com/ghiscoding/slickgrid-universal/workflows/CI%20Build/badge.svg)](https://github.com/ghiscoding/slickgrid-universal/actions) [![Cypress.io](https://img.shields.io/badge/tested%20with-Cypress-04C38E.svg)](https://www.cypress.io/) diff --git a/packages/binding/package.json b/packages/binding/package.json index 089e7e1af..13cf5beab 100644 --- a/packages/binding/package.json +++ b/packages/binding/package.json @@ -1,6 +1,6 @@ { "name": "@slickgrid-universal/binding", - "version": "4.7.0", + "version": "5.0.0-beta.3", "description": "Simple Vanilla Implementation of a Binding Engine & Helper to add properties/events 2 way bindings", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", diff --git a/packages/binding/src/bindingEvent.service.ts b/packages/binding/src/bindingEvent.service.ts index 3e7450d04..c85217a95 100644 --- a/packages/binding/src/bindingEvent.service.ts +++ b/packages/binding/src/bindingEvent.service.ts @@ -18,7 +18,7 @@ export class BindingEventService { } /** Bind an event listener to any element */ - bind(elementOrElements: Element | NodeListOf | Window, eventNameOrNames: string | string[], listener: EventListenerOrEventListenerObject, listenerOptions?: boolean | AddEventListenerOptions, groupName = '') { + bind(elementOrElements: Document | Element | NodeListOf | Window, eventNameOrNames: string | string[], listener: EventListenerOrEventListenerObject, listenerOptions?: boolean | AddEventListenerOptions, groupName = '') { // convert to array for looping in next task const eventNames = (Array.isArray(eventNameOrNames)) ? eventNameOrNames : [eventNameOrNames]; diff --git a/packages/common/CHANGELOG.md b/packages/common/CHANGELOG.md index 176aed85d..fcb4655f9 100644 --- a/packages/common/CHANGELOG.md +++ b/packages/common/CHANGELOG.md @@ -4,19 +4,76 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.0-beta.3](https://github.com/ghiscoding/slickgrid-universal/compare/v5.0.0-beta.2...v5.0.0-beta.3) (2024-05-09) + +### Bug Fixes + +* **common:** consider target size when auto-position picker/modal ([#1517](https://github.com/ghiscoding/slickgrid-universal/issues/1517)) ([e3a70b8](https://github.com/ghiscoding/slickgrid-universal/commit/e3a70b810d04c963f48454b78053c1bd45f96ebf)) - by @ghiscoding +* **common:** Select Editor should always close with Escape key ([#1512](https://github.com/ghiscoding/slickgrid-universal/issues/1512)) ([e37bb28](https://github.com/ghiscoding/slickgrid-universal/commit/e37bb281ee83c25e9c4e15930e06bf9a044c65e9)) - by @ghiscoding +* **core:** tweak setupColumnSort() to fix exception with hidden col ([#1509](https://github.com/ghiscoding/slickgrid-universal/issues/1509)) ([94b836a](https://github.com/ghiscoding/slickgrid-universal/commit/94b836a025ecb19b72f439079382280740b51027)) - by @ghiscoding +* **editors:** body click or Escape key should cancel Select Editor ([#1513](https://github.com/ghiscoding/slickgrid-universal/issues/1513)) ([3d765a9](https://github.com/ghiscoding/slickgrid-universal/commit/3d765a9d282b684c38c550a1e5736cb1b2132f8e)) - by @ghiscoding +* make some more cleanup with now optional DOMPurify ([#1508](https://github.com/ghiscoding/slickgrid-universal/issues/1508)) ([7fafbcc](https://github.com/ghiscoding/slickgrid-universal/commit/7fafbcc21fccfcd83d3ab103f313398c9d4b82e2)) - by @ghiscoding +* **plugins:** clicking a grid cell should close any open menu ([#1515](https://github.com/ghiscoding/slickgrid-universal/issues/1515)) ([383792d](https://github.com/ghiscoding/slickgrid-universal/commit/383792d389e56239d62874842a50ec838f0bd3e9)) - by @ghiscoding +* **styling:** improve UI & fix small issues found after testing upstream ([#1510](https://github.com/ghiscoding/slickgrid-universal/issues/1510)) ([a4ef70f](https://github.com/ghiscoding/slickgrid-universal/commit/a4ef70f70953c13f7abb0075586439931f18af74)) - by @ghiscoding +* **tooltip:** only show tooltip that has value ([#1511](https://github.com/ghiscoding/slickgrid-universal/issues/1511)) ([2ff15da](https://github.com/ghiscoding/slickgrid-universal/commit/2ff15da4a21cd98b63f251b9b248454658dac698)) - by @ghiscoding + +## [5.0.0-beta.2](https://github.com/ghiscoding/slickgrid-universal/compare/v4.7.0...v5.0.0-beta.2) (2024-05-07) + +### ⚠ BREAKING CHANGES + +* migrate from Moment to Tempo (#1507) +* **common:** make DOMPurify as optional sanitizer grid option (#1503) +* **styling:** delete "bare" Themes but keep "lite" & add to Bootstrap (#1493) +* **common:** migrate from `moment` to `moment-tiny` (#1456) +* **filters:** remove native `Filters.select` (#1485) +* **styling:** delete `checkmarkFormatter` and any Font-Awesome related (#1484) +* **common:** migrate from Flatpickr to Vanilla-Calendar (#1466) +* **styling:** remove SASS `math.div` polyfill (#1483) +* **styling:** convert SVG icons to pure CSS (#1474) + +### Features + +* **common:** make DOMPurify as optional sanitizer grid option ([#1503](https://github.com/ghiscoding/slickgrid-universal/issues/1503)) ([0aa0859](https://github.com/ghiscoding/slickgrid-universal/commit/0aa085955f81303c0193fbdcd36ff220263814e3)) - by @ghiscoding +* **common:** migrate from `moment` to `moment-tiny` ([#1456](https://github.com/ghiscoding/slickgrid-universal/issues/1456)) ([90690f4](https://github.com/ghiscoding/slickgrid-universal/commit/90690f4b6a4c8f8a7a221ddc1df69077384f48a9)) - by @ghiscoding +* **common:** migrate from Flatpickr to Vanilla-Calendar ([#1466](https://github.com/ghiscoding/slickgrid-universal/issues/1466)) ([fb6e950](https://github.com/ghiscoding/slickgrid-universal/commit/fb6e950f429b4abd868fca86d9c304580a745b1c)) - by @ghiscoding +* **filters:** remove native `Filters.select` ([#1485](https://github.com/ghiscoding/slickgrid-universal/issues/1485)) ([fae4c4a](https://github.com/ghiscoding/slickgrid-universal/commit/fae4c4a199409cec40ebb2703b6ae6d0d14e4af7)) - by @ghiscoding +* migrate from Moment to Tempo ([#1507](https://github.com/ghiscoding/slickgrid-universal/issues/1507)) ([adef47f](https://github.com/ghiscoding/slickgrid-universal/commit/adef47f21a0e32bd32ec4efce931770dc252d3b5)) - by @ghiscoding +* **styling:** convert SVG icons to pure CSS ([#1474](https://github.com/ghiscoding/slickgrid-universal/issues/1474)) ([70cda8a](https://github.com/ghiscoding/slickgrid-universal/commit/70cda8aa9304ac8ea4bab06390dc1b4c4423df2e)) - by @ghiscoding +* **styling:** delete "bare" Themes but keep "lite" & add to Bootstrap ([#1493](https://github.com/ghiscoding/slickgrid-universal/issues/1493)) ([ca5ac06](https://github.com/ghiscoding/slickgrid-universal/commit/ca5ac0663c1670f9e9af1f88d6f6c85e9e064359)) - by @ghiscoding +* **styling:** delete `checkmarkFormatter` and any Font-Awesome related ([#1484](https://github.com/ghiscoding/slickgrid-universal/issues/1484)) ([2de3fe2](https://github.com/ghiscoding/slickgrid-universal/commit/2de3fe2d07a14225a31fbc77e72c47895de664d6)) - by @ghiscoding +* **styling:** remove SASS `math.div` polyfill ([#1483](https://github.com/ghiscoding/slickgrid-universal/issues/1483)) ([12661a3](https://github.com/ghiscoding/slickgrid-universal/commit/12661a3ff13ea844f6e16028216e1ed8808ee4d9)) - by @ghiscoding + +### Bug Fixes + +* **core:** col name from HTML shouldn't disappear in picker, fixes [#1475](https://github.com/ghiscoding/slickgrid-universal/issues/1475) ([#1476](https://github.com/ghiscoding/slickgrid-universal/issues/1476)) ([15a590b](https://github.com/ghiscoding/slickgrid-universal/commit/15a590b2e52f8864aeccc38f9a708c0453b6e4a6)) - by @ghiscoding +* **editor:** autocomplete should only save empty when val is null ([#1500](https://github.com/ghiscoding/slickgrid-universal/issues/1500)) ([8de1340](https://github.com/ghiscoding/slickgrid-universal/commit/8de13402d244cb3aa2fcdb4af62e05b06f6cb27c)) - by @ghiscoding +* **editor:** input editor should call save on focusout or blur of input ([#1497](https://github.com/ghiscoding/slickgrid-universal/issues/1497)) ([ccd344e](https://github.com/ghiscoding/slickgrid-universal/commit/ccd344ecd2e6abcff1d7b9f5e7d7fe85a4c20fdd)) - by @ghiscoding +* **editor:** new Date Editor input clear button wasn't working ([#1487](https://github.com/ghiscoding/slickgrid-universal/issues/1487)) ([4ac34ee](https://github.com/ghiscoding/slickgrid-universal/commit/4ac34ee6d95398c77f10f89b0ad4c3168765b6a0)) - by @ghiscoding +* **styling:** couple of small alignment issues when using flex ([#1496](https://github.com/ghiscoding/slickgrid-universal/issues/1496)) ([2188242](https://github.com/ghiscoding/slickgrid-universal/commit/21882420eb9c31b7922038fa45f373d42e2fb35f)) - by @ghiscoding +* **styling:** empty warning should separate icon & text ([#1491](https://github.com/ghiscoding/slickgrid-universal/issues/1491)) ([240cbd3](https://github.com/ghiscoding/slickgrid-universal/commit/240cbd3b5a8cfb6a6cab563bc43d705332d59beb)) - by @ghiscoding +* **styling:** properly import Vanilla-Calendar CSS and only once ([#1492](https://github.com/ghiscoding/slickgrid-universal/issues/1492)) ([75dce74](https://github.com/ghiscoding/slickgrid-universal/commit/75dce746659796f7d1c21e5ebcfd0418588df4c0)) - by @ghiscoding +* **styling:** Row Move icon shouldn't show extra dot ([69f7bfc](https://github.com/ghiscoding/slickgrid-universal/commit/69f7bfcb7eb078815f5edb6d84d53c0905df27a1)) - by @ghiscoding-SE +* **tooltip:** don't sanitize empty text, fixes empty tooltip being shown ([#1495](https://github.com/ghiscoding/slickgrid-universal/issues/1495)) ([dcc693b](https://github.com/ghiscoding/slickgrid-universal/commit/dcc693b26677873b93ccb770ff8ef9a514085341)) - by @ghiscoding +* tweak setupColumnSort() to fix exception when col no longer exists ([#1477](https://github.com/ghiscoding/slickgrid-universal/issues/1477)) ([094d760](https://github.com/ghiscoding/slickgrid-universal/commit/094d7602d7170b2f395985ce5635041bb2b803d2)) - by @ghiscoding + # [4.7.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.6.3...v4.7.0) (2024-04-20) ### Bug Fixes * **common:** don't try to strip tags on object input to calc cell width ([#1453](https://github.com/ghiscoding/slickgrid-universal/issues/1453)) ([5ab671b](https://github.com/ghiscoding/slickgrid-universal/commit/5ab671bee805f7b7d9b139e9bf7a14b31b5aea56)) - by @ghiscoding + * **common:** switch back to `autocompleter` with ESM build ([#1450](https://github.com/ghiscoding/slickgrid-universal/issues/1450)) ([ad66a12](https://github.com/ghiscoding/slickgrid-universal/commit/ad66a121b4a6b7718009948d873ceb8f5c66a32c)) - by @ghiscoding + * **core:** Editor.keyCaptureList is an array of numbers ([#1458](https://github.com/ghiscoding/slickgrid-universal/issues/1458)) ([62a686e](https://github.com/ghiscoding/slickgrid-universal/commit/62a686e7db4dc4ef65d0c426c8623dc8f1e3f9d9)) - by @ghiscoding + * **styling:** improve button & text colors for Dark Mode ([9414ab4](https://github.com/ghiscoding/slickgrid-universal/commit/9414ab4e24482d080f3113d32d96fe635856a871)) - by @ghiscoding-SE ### Features * **common:** add global `defaultEditorOptions` & `defaultFilterOptions` ([#1470](https://github.com/ghiscoding/slickgrid-universal/issues/1470)) ([0462f17](https://github.com/ghiscoding/slickgrid-universal/commit/0462f17b215d5c1b88e1a9fe482877ed733486b3)) - by @ghiscoding + * **core:** add `getFilterArgs()` to `SlickDataView` ([#1457](https://github.com/ghiscoding/slickgrid-universal/issues/1457)) ([7563126](https://github.com/ghiscoding/slickgrid-universal/commit/7563126cfbf792fc86a494850e5a3bad7d8991f7)) - by @ghiscoding + * notify onValidationError on paste if validation failed ([#1462](https://github.com/ghiscoding/slickgrid-universal/issues/1462)) ([38b465c](https://github.com/ghiscoding/slickgrid-universal/commit/38b465cb8ebcdd6012b939677a4367c2dce010e9)) - by @zewa666 ## [4.6.1](https://github.com/ghiscoding/slickgrid-universal/compare/v4.6.0...v4.6.1) (2024-03-31) @@ -24,11 +81,17 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **common:** move DOMPurify/SortableJS [@types](https://github.com/types) as dependencies ([51eaec7](https://github.com/ghiscoding/slickgrid-universal/commit/51eaec756120c93f0fbb9ed58b5784025b808e59)) - by @ghiscoding + * **common:** switch to `autocompleter-es` to get ESM build ([#1449](https://github.com/ghiscoding/slickgrid-universal/issues/1449)) ([aa59334](https://github.com/ghiscoding/slickgrid-universal/commit/aa59334d280d76078bc9cf36e66daa0bd4c6fac1)) - by @ghiscoding + * improve Dark Mode styling for icons barely visible in dark ([16b1a6e](https://github.com/ghiscoding/slickgrid-universal/commit/16b1a6e52bec83ed25bca077fe2ea30b5966f3ab)) - by @ghiscoding + * **pubsub:** externalize PubSub event to SlickEventData to stop bubbling ([#1444](https://github.com/ghiscoding/slickgrid-universal/issues/1444)) ([973d0ab](https://github.com/ghiscoding/slickgrid-universal/commit/973d0abb0a4df050ad68a6c7e6493bf7ae4abd52)) - by @ghiscoding + * revisit package `exports` to pass "are the types wrong" ([#1440](https://github.com/ghiscoding/slickgrid-universal/issues/1440)) ([20229f7](https://github.com/ghiscoding/slickgrid-universal/commit/20229f78adef51078f99fce3f5a46ac88280a048)) - by @ghiscoding + * **styling:** missing/too many borders compound filters w/group addon ([#1446](https://github.com/ghiscoding/slickgrid-universal/issues/1446)) ([863933f](https://github.com/ghiscoding/slickgrid-universal/commit/863933f8cd1988f5ae1b387839a99532cd58d92d)) - by @ghiscoding + * **tooltip:** allow multiple tooltips per grid cell ([#1448](https://github.com/ghiscoding/slickgrid-universal/issues/1448)) ([061c4a0](https://github.com/ghiscoding/slickgrid-universal/commit/061c4a087484238f7285eb27a1c238ac75972f19)) - by @ghiscoding # [4.6.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.5.0...v4.6.0) (2024-03-23) @@ -36,21 +99,33 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * `column.editor` and `gridOptions.editorFactory` type changed ([#1428](https://github.com/ghiscoding/slickgrid-universal/issues/1428)) ([bf8c5b9](https://github.com/ghiscoding/slickgrid-universal/commit/bf8c5b95aca22bced0d926d6ac118c9fa0e61411)) - by @ghiscoding + * **build:** add ESLint-TS rules to enforce `type` imports and exports ([#1432](https://github.com/ghiscoding/slickgrid-universal/issues/1432)) ([cce4693](https://github.com/ghiscoding/slickgrid-universal/commit/cce4693556e01d7f664fbe832ae4e7fd5776dc6b)) - by @ghiscoding + * **common:** add missing Filter `model` Type of `FilterConstructor` ([#1430](https://github.com/ghiscoding/slickgrid-universal/issues/1430)) ([3f3e952](https://github.com/ghiscoding/slickgrid-universal/commit/3f3e952b20b41dda5bf2cd1648c6d6f02e7c7943)) - by @ghiscoding + * **common:** bump ms-select to fix compatibility problem in Salesforce ([#1425](https://github.com/ghiscoding/slickgrid-universal/issues/1425)) ([d3d2d39](https://github.com/ghiscoding/slickgrid-universal/commit/d3d2d390a8a1b17d0cd3699ddebfea855fdc5f77)) - by @ghiscoding + * **common:** Select All checkbox shouldn't disappear w/Dark Mode toggle ([#1421](https://github.com/ghiscoding/slickgrid-universal/issues/1421)) ([5fab179](https://github.com/ghiscoding/slickgrid-universal/commit/5fab1792cfdf24172bd46556b6fe5513c93d19d1)) - by @ghiscoding + * Join type ([#1427](https://github.com/ghiscoding/slickgrid-universal/issues/1427)) ([21c76cc](https://github.com/ghiscoding/slickgrid-universal/commit/21c76cc9d921ad34516bd38070afd791ff55de56)) - by @zewa666 + * **styling:** add border & box-shadow to Flatpickr in Dark Mode ([fdbb6ae](https://github.com/ghiscoding/slickgrid-universal/commit/fdbb6ae9de7069968af747240a9b2ad74b0c8184)) - by @ghiscoding + * **styling:** add missing orange border for Salesforce modified inputs ([e830dd3](https://github.com/ghiscoding/slickgrid-universal/commit/e830dd3df4c6c0176ac88304247571f5ef05d4ef)) - by @ghiscoding + * **styling:** add more visual cue for column picker uncheck row select ([b4712e9](https://github.com/ghiscoding/slickgrid-universal/commit/b4712e9a8c03b60457d9033f11affb7364231de2)) - by @ghiscoding + * **styling:** don't add filled border all side for group-addon btn ([30be835](https://github.com/ghiscoding/slickgrid-universal/commit/30be8353101157a00440dba0357f88879bd3acda)) - by @ghiscoding-SE + * **styling:** small Composite Editor fixes for Dark Mode ([#1417](https://github.com/ghiscoding/slickgrid-universal/issues/1417)) ([7e00087](https://github.com/ghiscoding/slickgrid-universal/commit/7e000877a85059e23d3aa4c00c04d0e4e1e0abc1)) - by @ghiscoding ### Features * **common:** add optional "Toggle Dark Mode" in Grid Menu ([#1418](https://github.com/ghiscoding/slickgrid-universal/issues/1418)) ([990c1df](https://github.com/ghiscoding/slickgrid-universal/commit/990c1df2a39a6b5098c991b16f43c5679daf4bb5)) - by @ghiscoding + * **core:** rename SG `editorClass` & deprecate `internalColumnEditor` ([#1429](https://github.com/ghiscoding/slickgrid-universal/issues/1429)) ([409115c](https://github.com/ghiscoding/slickgrid-universal/commit/409115cecb132556e88abf6e281f4fcb52414d71)) - by @ghiscoding + * upgrade to ms-select-vanilla v3.x ([#1439](https://github.com/ghiscoding/slickgrid-universal/issues/1439)) ([8f2378e](https://github.com/ghiscoding/slickgrid-universal/commit/8f2378e6cfed3489ce487fe84947bdabd04e31d2)) - by @ghiscoding # [4.5.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.4.1...v4.5.0) (2024-03-05) @@ -58,22 +133,35 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * auto-resize not just grid but also headers for Salesforce tabs ([#1395](https://github.com/ghiscoding/slickgrid-universal/issues/1395)) ([6180461](https://github.com/ghiscoding/slickgrid-universal/commit/6180461b543cb7d4cc14d1504cb0db7d35990164)) - by @ghiscoding + * **common:** switch to `isomorphic-dompurify` for SSR support ([#1413](https://github.com/ghiscoding/slickgrid-universal/issues/1413)) ([b619453](https://github.com/ghiscoding/slickgrid-universal/commit/b619453fd9825500f2d9589e31bdcf5e17ac412d)), closes [/github.com/ghiscoding/Angular-Slickgrid/discussions/838#discussioncomment-8574215](https://github.com//github.com/ghiscoding/Angular-Slickgrid/discussions/838/issues/discussioncomment-8574215) - by @ghiscoding + * **core:** add extra checks for some objects to be a bit more strict ([#1404](https://github.com/ghiscoding/slickgrid-universal/issues/1404)) ([8b95c50](https://github.com/ghiscoding/slickgrid-universal/commit/8b95c505ed2409cde7b790f97b4fbc0d666ca459)) - by @ghiscoding + * **plugin:** the RowMove plugin cell should be selectable ([#1408](https://github.com/ghiscoding/slickgrid-universal/issues/1408)) ([8c01a13](https://github.com/ghiscoding/slickgrid-universal/commit/8c01a1361898fe3f3b6cfdba3239f93f2e8acec9)) - by @ghiscoding + * **styling:** add full width to grid container ([#1409](https://github.com/ghiscoding/slickgrid-universal/issues/1409)) ([eedc162](https://github.com/ghiscoding/slickgrid-universal/commit/eedc162e243b3c0bbf450bd404b199f5ee511926)) - by @ghiscoding + * **styling:** add menu shadow & increase contrast for Dark Mode ([bff2da0](https://github.com/ghiscoding/slickgrid-universal/commit/bff2da0dd027103c30fa86635b9e45460b10e700)) - by @ghiscoding + * **styling:** ms-select filter should use same color as other filters ([#1396](https://github.com/ghiscoding/slickgrid-universal/issues/1396)) ([a30d590](https://github.com/ghiscoding/slickgrid-universal/commit/a30d59066419d2c3324718f1d5497e8e89ebf749)) - by @ghiscoding + * **styling:** ms-select highlight bg-color same as nav highlight ([fe77341](https://github.com/ghiscoding/slickgrid-universal/commit/fe77341645f72be6c03a8e210dc08e6d0ef131d4)) - by @ghiscoding-SE + * **styling:** properly align flexbox ms-select icon+text vertically ([#1397](https://github.com/ghiscoding/slickgrid-universal/issues/1397)) ([e744d02](https://github.com/ghiscoding/slickgrid-universal/commit/e744d0256d25ba6ad5d538b827460828b6e0666f)) - by @ghiscoding + * **styling:** remove header menu open class for Dark Mode ([6a2e7e1](https://github.com/ghiscoding/slickgrid-universal/commit/6a2e7e13a18921c2b70caeb2690298173310aece)) - by @ghiscoding + * **styling:** tweak Composite Editor form disabled buttons style ([5052ba1](https://github.com/ghiscoding/slickgrid-universal/commit/5052ba19858ff2bced69f0846e00bbb36c9d0fde)) - by @ghiscoding ### Features * **common:** upgrade `multiple-select-vanilla` to v2 ([#1401](https://github.com/ghiscoding/slickgrid-universal/issues/1401)) ([d6bb1d7](https://github.com/ghiscoding/slickgrid-universal/commit/d6bb1d7ef76100268456b2ab499c496a78debdd8)) - by @ghiscoding + * **deps:** simplify package TS Types exports ([#1402](https://github.com/ghiscoding/slickgrid-universal/issues/1402)) ([19bac52](https://github.com/ghiscoding/slickgrid-universal/commit/19bac52e5fcb8e523a26ab1f6564f0b6a2b93ef4)) - by @ghiscoding + * **editor:** add `onRendered` lifecycle callback option ([#1410](https://github.com/ghiscoding/slickgrid-universal/issues/1410)) ([9d348d6](https://github.com/ghiscoding/slickgrid-universal/commit/9d348d6e4b693e23a2959917e02a7bcfa55a0c90)) - by @ghiscoding + * **styling:** add Dark Mode grid option ([#1407](https://github.com/ghiscoding/slickgrid-universal/issues/1407)) ([855151b](https://github.com/ghiscoding/slickgrid-universal/commit/855151b9f47a5238e3069f8c85ba4ed8a5bf9bb6)) - by @ghiscoding ## [4.4.1](https://github.com/ghiscoding/slickgrid-universal/compare/v4.3.1...v4.4.1) (2024-02-13) @@ -81,8 +169,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** replace `any` types by valid types ([#1378](https://github.com/ghiscoding/slickgrid-universal/issues/1378)) ([02c4bc1](https://github.com/ghiscoding/slickgrid-universal/commit/02c4bc15e0da31c055c0fac9eecb7c4a17df3eb7)) - by @ghiscoding + * **deps:** update all non-major dependencies ([#1381](https://github.com/ghiscoding/slickgrid-universal/issues/1381)) ([2562352](https://github.com/ghiscoding/slickgrid-universal/commit/25623527d05dd713123e1031b682f0a80cca37de)) - by @renovate-bot + * mouse cell selection with active editor ([#1382](https://github.com/ghiscoding/slickgrid-universal/issues/1382)) ([17549b8](https://github.com/ghiscoding/slickgrid-universal/commit/17549b89933b10688fe8d186ab18ab4c8b7e9f87)) - by @zewa666 + * **publish:** do not npm publish `tsconfig.tsbuildinfo` ([#1373](https://github.com/ghiscoding/slickgrid-universal/issues/1373)) ([9223338](https://github.com/ghiscoding/slickgrid-universal/commit/922333843852ae861015e4bbec053d4937222aa2)) - by @ghiscoding ### Features @@ -94,8 +185,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** replace `any` types by valid types ([#1378](https://github.com/ghiscoding/slickgrid-universal/issues/1378)) ([02c4bc1](https://github.com/ghiscoding/slickgrid-universal/commit/02c4bc15e0da31c055c0fac9eecb7c4a17df3eb7)) - by @ghiscoding + * **deps:** update all non-major dependencies ([#1381](https://github.com/ghiscoding/slickgrid-universal/issues/1381)) ([2562352](https://github.com/ghiscoding/slickgrid-universal/commit/25623527d05dd713123e1031b682f0a80cca37de)) - by @renovate-bot + * mouse cell selection with active editor ([#1382](https://github.com/ghiscoding/slickgrid-universal/issues/1382)) ([17549b8](https://github.com/ghiscoding/slickgrid-universal/commit/17549b89933b10688fe8d186ab18ab4c8b7e9f87)) - by @zewa666 + * **publish:** do not npm publish `tsconfig.tsbuildinfo` ([#1373](https://github.com/ghiscoding/slickgrid-universal/issues/1373)) ([9223338](https://github.com/ghiscoding/slickgrid-universal/commit/922333843852ae861015e4bbec053d4937222aa2)) - by @ghiscoding ### Features @@ -107,13 +201,17 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** frozen grid w/hidden column should remove from DOM ([#1372](https://github.com/ghiscoding/slickgrid-universal/issues/1372)) ([2c1346e](https://github.com/ghiscoding/slickgrid-universal/commit/2c1346e53e0e5cba57c949f7b70d2b20d3dc1d22)) - by @ghiscoding + * **styling:** remove different bg-color on unorderable column ([#1358](https://github.com/ghiscoding/slickgrid-universal/issues/1358)) ([91426d1](https://github.com/ghiscoding/slickgrid-universal/commit/91426d1f6801680a5c40b3b900ab1a64cd771277)) - by @ghiscoding ### Performance Improvements * **core:** convert `for..in` to `Object.keys().forEach` for better perf ([#1370](https://github.com/ghiscoding/slickgrid-universal/issues/1370)) ([29111a9](https://github.com/ghiscoding/slickgrid-universal/commit/29111a94756c34a2e01f2431c14b7ed806349a94)) - by @ghiscoding + * decrease calls to setItems & grid invalidate ([#1363](https://github.com/ghiscoding/slickgrid-universal/issues/1363)) ([cab6898](https://github.com/ghiscoding/slickgrid-universal/commit/cab68989ebd53178dfcee5ed293379dc8932a72f)) - by @ghiscoding + * **plugins:** decrease number of calls to translate all extensions only once ([#1359](https://github.com/ghiscoding/slickgrid-universal/issues/1359)) ([3e002f1](https://github.com/ghiscoding/slickgrid-universal/commit/3e002f15a06abd06893783e0667798f5ff8893cf)) - by @ghiscoding + * **plugins:** Row Base Editing tooltip title should be translated only once ([#1360](https://github.com/ghiscoding/slickgrid-universal/issues/1360)) ([ef4e8f9](https://github.com/ghiscoding/slickgrid-universal/commit/ef4e8f9f4bf491d670986c6dac8531274aaaa46b)) - by @ghiscoding # [4.3.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.2.0...v4.3.0) (2024-01-20) @@ -121,30 +219,51 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * `getCellFromPoint()` should return row/cell -1 outside grid canvas ([#1325](https://github.com/ghiscoding/slickgrid-universal/issues/1325)) ([b483e62](https://github.com/ghiscoding/slickgrid-universal/commit/b483e62fc3931f836c77677db67557adb2ca4edd)) - by @ghiscoding + * add grid & cell `role` for screen ready accessibility ([#1337](https://github.com/ghiscoding/slickgrid-universal/issues/1337)) ([7309fa8](https://github.com/ghiscoding/slickgrid-universal/commit/7309fa8de4fc00f930e68af090010d91080b6213)) - by @ghiscoding + * **core:** allow extra spaces in `headerCssClass` & other `cssClass` ([#1303](https://github.com/ghiscoding/slickgrid-universal/issues/1303)) ([59ebaa6](https://github.com/ghiscoding/slickgrid-universal/commit/59ebaa65b6882ed3274a3185f457ecef4b2c5b51)) - by @ghiscoding + * **core:** allow extra spaces to be striped to any css classes ([#1352](https://github.com/ghiscoding/slickgrid-universal/issues/1352)) ([e5e29c0](https://github.com/ghiscoding/slickgrid-universal/commit/e5e29c063a9e018c2148685cfea5fc43c89426b9)) - by @ghiscoding + * **core:** column resize handle could throw when invalid elm ([#1344](https://github.com/ghiscoding/slickgrid-universal/issues/1344)) ([41f6058](https://github.com/ghiscoding/slickgrid-universal/commit/41f60583831b7284cba56f2af9cfe45b4a09d617)) - by @ghiscoding + * **core:** DataView `inlineFilters` should allow ES6 arrow functions ([#1304](https://github.com/ghiscoding/slickgrid-universal/issues/1304)) ([25b9a10](https://github.com/ghiscoding/slickgrid-universal/commit/25b9a10fdd14585f1b303361b2814e860c6e7031)) - by @ghiscoding + * **core:** don't show column header empty title tooltip ([#1317](https://github.com/ghiscoding/slickgrid-universal/issues/1317)) ([8b20407](https://github.com/ghiscoding/slickgrid-universal/commit/8b2040754f1810191fb26f0a5a91a19eae13ebfd)) - by @ghiscoding + * **core:** EventHandler subscribed event should be SlickEventData type ([#1327](https://github.com/ghiscoding/slickgrid-universal/issues/1327)) ([2573310](https://github.com/ghiscoding/slickgrid-universal/commit/25733102dbcefcbacc2ce5d6f4c07bd9d1cce6a1)) - by @ghiscoding + * **core:** remove editor keydown keyCaptureList duplicate code ([#1322](https://github.com/ghiscoding/slickgrid-universal/issues/1322)) ([c5f6b85](https://github.com/ghiscoding/slickgrid-universal/commit/c5f6b8575513aa6eb0215a47a0365fdab0059c3e)) - by @ghiscoding + * **core:** SlickEvent handler event should be type of ArgType ([#1328](https://github.com/ghiscoding/slickgrid-universal/issues/1328)) ([a9cb8ee](https://github.com/ghiscoding/slickgrid-universal/commit/a9cb8ee3f1a5da4249851e5b701b027b3f72ad26)), closes [#1327](https://github.com/ghiscoding/slickgrid-universal/issues/1327) - by @ghiscoding + * Editors/Filters should create SlickEventData with event arg ([#1326](https://github.com/ghiscoding/slickgrid-universal/issues/1326)) ([e008902](https://github.com/ghiscoding/slickgrid-universal/commit/e008902e6d85a7a424ed8c9e32786490daac66ce)) - by @ghiscoding + * **plugin:** CustomDataView for CellSelectionModel & SlickCustomTooltip ([#1306](https://github.com/ghiscoding/slickgrid-universal/issues/1306)) ([3bdd300](https://github.com/ghiscoding/slickgrid-universal/commit/3bdd30038b93af2db1f2f4a8b7df72ca6a06a06e)) - by @ghiscoding + * regression with `onSelectedRowsChanged` not receiving correct `caller` prop ([#1341](https://github.com/ghiscoding/slickgrid-universal/issues/1341)) ([03cad4a](https://github.com/ghiscoding/slickgrid-universal/commit/03cad4a34bf13a8e1342306f9210525f5025321f)) - by @ghiscoding + * SlickEmptyWarningComponent should accept native HTML for CSP safe ([#1333](https://github.com/ghiscoding/slickgrid-universal/issues/1333)) ([4740f96](https://github.com/ghiscoding/slickgrid-universal/commit/4740f961813666cbae918cb4940e7c2ec57bec2d)) - by @ghiscoding + * when `onDragInit` return false it should stop ([#1340](https://github.com/ghiscoding/slickgrid-universal/issues/1340)) ([d9c714c](https://github.com/ghiscoding/slickgrid-universal/commit/d9c714c042739d5cbdbe51b876f16a3152d200e6)), closes [#1339](https://github.com/ghiscoding/slickgrid-universal/issues/1339) - by @ghiscoding + * when `onResizeStart` return false it should stop ([#1339](https://github.com/ghiscoding/slickgrid-universal/issues/1339)) ([5a3bd1c](https://github.com/ghiscoding/slickgrid-universal/commit/5a3bd1c0c6a19294fe6578766d6b2d56ac8e2cac)) - by @ghiscoding ### Features * add `name` option to CheckboxSelectColumn plugin on columDef ([#1331](https://github.com/ghiscoding/slickgrid-universal/issues/1331)) ([abe344b](https://github.com/ghiscoding/slickgrid-universal/commit/abe344b025b385630077bfb63d5534a88b3b7d71)) - by @ghiscoding + * add `onBeforePasteCell` event to excel copy buffer ([#1298](https://github.com/ghiscoding/slickgrid-universal/issues/1298)) ([22037ca](https://github.com/ghiscoding/slickgrid-universal/commit/22037ca7918fc4bfb55bb4bf619cd280b564a351)) - by @zewa666 + * add column `reorderable` option to optionally lock a column ([#1357](https://github.com/ghiscoding/slickgrid-universal/issues/1357)) ([44f6c08](https://github.com/ghiscoding/slickgrid-universal/commit/44f6c085f009ec41bec711aa14ae7fbb3fcbc156)) - by @ghiscoding + * convert CheckSelectColumn plugin to native HTML for CSP safe code ([#1332](https://github.com/ghiscoding/slickgrid-universal/issues/1332)) ([2b9216d](https://github.com/ghiscoding/slickgrid-universal/commit/2b9216df3e1796ffb4081127cdaa9011e4d48b23)) - by @ghiscoding + * **core:** expose all SlickEvent via internal PubSub Service ([#1311](https://github.com/ghiscoding/slickgrid-universal/issues/1311)) ([f56edef](https://github.com/ghiscoding/slickgrid-universal/commit/f56edef91b76ab044134ddf36d67599e6d80f39c)) - by @ghiscoding + * **editor:** auto commit before save; add `onBeforeEditMode` callback ([#1353](https://github.com/ghiscoding/slickgrid-universal/issues/1353)) ([f33bf52](https://github.com/ghiscoding/slickgrid-universal/commit/f33bf5202e0db30121bf52ce184555f6524dde85)) - by @zewa666 + * **plugin:** new Row Based Editor ([#1323](https://github.com/ghiscoding/slickgrid-universal/issues/1323)) ([64d464c](https://github.com/ghiscoding/slickgrid-universal/commit/64d464c2094c014024ddeaf49bd4f6ec898b1c25)) - by @zewa666 ### Performance Improvements @@ -156,17 +275,25 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * `updateColumns()` should be public use with column hidden ([#1288](https://github.com/ghiscoding/slickgrid-universal/issues/1288)) ([211180b](https://github.com/ghiscoding/slickgrid-universal/commit/211180b8c1f32250e6fc7a559baaa203154473e0)) - by @ghiscoding + * applyDefaults use provided grid options before applying defaults ([#1283](https://github.com/ghiscoding/slickgrid-universal/issues/1283)) ([7fc772f](https://github.com/ghiscoding/slickgrid-universal/commit/7fc772fb80a80e0eafa900fc688667d12e1f9429)) - by @ghiscoding + * **core:** `SlickGroupItemMetadataProvider` should implements `SlickPlugin` ([#1294](https://github.com/ghiscoding/slickgrid-universal/issues/1294)) ([5aac2b6](https://github.com/ghiscoding/slickgrid-universal/commit/5aac2b6a37cdd21938fa54769b72ce317562e45d)) - by @ghiscoding + * **core:** add missing option to control row highlight duration after CRUD ([#1278](https://github.com/ghiscoding/slickgrid-universal/issues/1278)) ([8240c8c](https://github.com/ghiscoding/slickgrid-universal/commit/8240c8c9710f4e5d902ec9961f6a721ae0f84f7f)) - by @ghiscoding + * GroupingGetterFunction should be allowed to return arbitrary value ([#1296](https://github.com/ghiscoding/slickgrid-universal/issues/1296)) ([3807116](https://github.com/ghiscoding/slickgrid-universal/commit/38071168e0fe5eea7d5e1ee117fae98c09057a4c)) - by @ghiscoding + * **RowDetail:** sort change should collapse all Row Detail ([#1284](https://github.com/ghiscoding/slickgrid-universal/issues/1284)) ([21f6031](https://github.com/ghiscoding/slickgrid-universal/commit/21f60310a402dd12c80bf4553588c6cd777a131a)) - by @ghiscoding + * use correct argument type on `setData()` ([#1287](https://github.com/ghiscoding/slickgrid-universal/issues/1287)) ([0b0b86c](https://github.com/ghiscoding/slickgrid-universal/commit/0b0b86c2325ea2a11b74d8fe8debeb02e23bb014)) - by @ghiscoding ### Features * (re)add option to cancel Row Detail opening ([#1286](https://github.com/ghiscoding/slickgrid-universal/issues/1286)) ([f08925c](https://github.com/ghiscoding/slickgrid-universal/commit/f08925c50c1dd18448a04a55c8303736e3cc2289)) - by @ghiscoding + * datasetIdPropertyName respected in newRowCreator ([#1279](https://github.com/ghiscoding/slickgrid-universal/issues/1279)) ([9d60a9d](https://github.com/ghiscoding/slickgrid-universal/commit/9d60a9d82e605ae2351822c66ff8757349b906cf)) - by @zewa666 + * make DataView Grouping `compileAccumulatorLoop` CSP safe ([#1295](https://github.com/ghiscoding/slickgrid-universal/issues/1295)) ([af82208](https://github.com/ghiscoding/slickgrid-universal/commit/af8220881b2791be2cc3f6605eda3955428094c7)) - by @ghiscoding ### Performance Improvements @@ -182,6 +309,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **core:** add `rowHighlightCssClass` & `highlightRow()` to SlickGrid ([#1272](https://github.com/ghiscoding/slickgrid-universal/issues/1272)) ([31c38ad](https://github.com/ghiscoding/slickgrid-universal/commit/31c38ad4d0a2e5c07ad92964fee303b31a192b59)) - by @ghiscoding + * **utils:** replace slick-core extend utils with `node-extend` ([#1277](https://github.com/ghiscoding/slickgrid-universal/issues/1277)) ([3439118](https://github.com/ghiscoding/slickgrid-universal/commit/3439118da344cd852a1b1af5bd83c4b894213464)) - by @ghiscoding ## [4.0.3](https://github.com/ghiscoding/slickgrid-universal/compare/v4.0.2...v4.0.3) (2023-12-16) @@ -209,6 +337,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** SlickEventHandler handler args should have Types ([#1261](https://github.com/ghiscoding/slickgrid-universal/issues/1261)) ([a33129b](https://github.com/ghiscoding/slickgrid-universal/commit/a33129b0ce1443443e7dcebb3562ffd538b6a731)) - by @ghiscoding + * regression, Row Detail no longer displayed after CSP safe code ([#1259](https://github.com/ghiscoding/slickgrid-universal/issues/1259)) ([a35f0a4](https://github.com/ghiscoding/slickgrid-universal/commit/a35f0a488775e8ccb68ec8fe0ece9abc47c358f4)) - by @ghiscoding # [4.0.0-alpha.0](https://github.com/ghiscoding/slickgrid-universal/compare/v3.7.1...v4.0.0-alpha.0) (2023-12-09) @@ -216,21 +345,33 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * `setActiveCellInternal()` should not throw when cell/row undefined ([dbe6413](https://github.com/ghiscoding/slickgrid-universal/commit/dbe64132294bc88f5dc13ac23a6f6f84ac5e1ffd)) - by @ghiscoding + * change dynamic html string w/CSP safe code to fix scroll ([#1210](https://github.com/ghiscoding/slickgrid-universal/issues/1210)) ([cd03907](https://github.com/ghiscoding/slickgrid-universal/commit/cd03907b20468190db7f84f3ae24fbd531e4f6e4)) - by @ghiscoding + * Draggable shouldn't trigger dragEnd without first dragging ([#1211](https://github.com/ghiscoding/slickgrid-universal/issues/1211)) ([47cb36e](https://github.com/ghiscoding/slickgrid-universal/commit/47cb36e78995f70933807aa33ba3afa0fecf491e)) - by @ghiscoding + * escape glob pattern for SASS copy to work in CI ([0590b24](https://github.com/ghiscoding/slickgrid-universal/commit/0590b24bf2ac140ba69149bd55cbff95b3493112)) - by @ghiscoding-SE + * only allow row drag on cell w/`dnd` or `cell-reorder`, fix [#937](https://github.com/ghiscoding/slickgrid-universal/issues/937) ([6a2ab55](https://github.com/ghiscoding/slickgrid-universal/commit/6a2ab550a253a4a1f35e4e81a120fa9247ce753b)), closes [#897](https://github.com/ghiscoding/slickgrid-universal/issues/897) - by @ghiscoding-SE + * remove CellRange, SlickRange, SlickGroup, ... unused interfaces ([#1219](https://github.com/ghiscoding/slickgrid-universal/issues/1219)) ([a4cc469](https://github.com/ghiscoding/slickgrid-universal/commit/a4cc469e9c21c5ed851bfbaafdc6b580e7389272)) - by @ghiscoding + * the `devMode` should be `false` or an object with other options ([ac57992](https://github.com/ghiscoding/slickgrid-universal/commit/ac57992abd821cdd6fec823464944dadfa1e7b2c)) - by @ghiscoding-SE + * the `devMode` should be `false` or an object with other options ([ad2285a](https://github.com/ghiscoding/slickgrid-universal/commit/ad2285a3890442b28dfc7c668ab1b1376e17d3df)) - by @ghiscoding-SE + * try adding sort icon on non `sortable` column shouldn't throw ([4791fc8](https://github.com/ghiscoding/slickgrid-universal/commit/4791fc89078d9f3212d034fb1d5e43b8bbfffc5d)) - by @ghiscoding-SE ### Features * convert GroupItemMetadataProvider Formatter to native HTML for CSP ([#1215](https://github.com/ghiscoding/slickgrid-universal/issues/1215)) ([d723856](https://github.com/ghiscoding/slickgrid-universal/commit/d723856777329f2e40fe3a12d3c59e33afd0e3a8)) - by @ghiscoding + * introduce devMode to support nodejs based unit testing ([#1251](https://github.com/ghiscoding/slickgrid-universal/issues/1251)) ([596737d](https://github.com/ghiscoding/slickgrid-universal/commit/596737d52a2ec8c42320152342144ff32191ebfd)) - by @ghiscoding + * remove unnecessary Formatters, replace by `cssClass` ([#1225](https://github.com/ghiscoding/slickgrid-universal/issues/1225)) ([de26496](https://github.com/ghiscoding/slickgrid-universal/commit/de26496aa5dc462869a4a1ff966b32baf86e188b)) - by @ghiscoding + * rewrite all Formatters as native HTML elements ([#1229](https://github.com/ghiscoding/slickgrid-universal/issues/1229)) ([5cb4dd5](https://github.com/ghiscoding/slickgrid-universal/commit/5cb4dd5757adc401ed4e6deab0e41bcd08a827a3)) - by @ghiscoding + * use PubSub Service singleton to subscribe to any SlickEvent ([#1248](https://github.com/ghiscoding/slickgrid-universal/issues/1248)) ([388bd11](https://github.com/ghiscoding/slickgrid-universal/commit/388bd115c1a15f853da8ac943a6e5e3574630438)) - by @ghiscoding ### Performance Improvements @@ -242,6 +383,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * the `devMode` should be `false` or an object with other options ([ad2285a](https://github.com/ghiscoding/slickgrid-universal/commit/ad2285a3890442b28dfc7c668ab1b1376e17d3df)) - by @ghiscoding-SE + * use !important on CSS text utils ([7fdbeb6](https://github.com/ghiscoding/slickgrid-universal/commit/7fdbeb6c46201ae80d6e71e2df7016735b771bf2)) - by @ghiscoding ## [3.7.1](https://github.com/ghiscoding/slickgrid-universal/compare/v3.7.0...v3.7.1) (2023-12-08) @@ -255,8 +397,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * cell selection range with key combos were incorrect ([#1244](https://github.com/ghiscoding/slickgrid-universal/issues/1244)) ([79d86fe](https://github.com/ghiscoding/slickgrid-universal/commit/79d86fea99258ccf82a5d3d8c684410623e6753b)) - by @ghiscoding + * DraggableGrouping & Select Filter `collectionAsync` mem leaks ([#1247](https://github.com/ghiscoding/slickgrid-universal/issues/1247)) ([7dcf53a](https://github.com/ghiscoding/slickgrid-universal/commit/7dcf53ac4d7873c75e82e01c2b4a806f88d8ff39)) - by @ghiscoding + * **formatters:** show console error on invalid multiple formatters ([#1227](https://github.com/ghiscoding/slickgrid-universal/issues/1227)) ([fd69ac0](https://github.com/ghiscoding/slickgrid-universal/commit/fd69ac01c68496d4e7d5dd2f06186fba961016d9)) - by @ghiscoding + * registered external resouces should keep singleton ref ([#1242](https://github.com/ghiscoding/slickgrid-universal/issues/1242)) ([adf2054](https://github.com/ghiscoding/slickgrid-universal/commit/adf2054bdc8ef7701e6fab78e685d49b8424da29)) - by @ghiscoding ### Features @@ -274,6 +419,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **common:** ms-select-vanilla requires `@types/trusted-types` dep ([#1190](https://github.com/ghiscoding/slickgrid-universal/issues/1190)) ([284a379](https://github.com/ghiscoding/slickgrid-universal/commit/284a3791027423d0d7f45a950e0a3b8a8a684612)) - by @ghiscoding + * improve build & types exports for all targets, Node, CJS/ESM ([#1188](https://github.com/ghiscoding/slickgrid-universal/issues/1188)) ([980fd68](https://github.com/ghiscoding/slickgrid-universal/commit/980fd68f6ce9564bb1fcac5f6ee68fd35f839e8f)) - by @ghiscoding # [3.5.0](https://github.com/ghiscoding/slickgrid-universal/compare/v3.4.2...v3.5.0) (2023-11-10) @@ -281,13 +427,17 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **common:** SlickCellRangeSelector shouldn't stop editor event bubbling ([#1183](https://github.com/ghiscoding/slickgrid-universal/issues/1183)) ([7bb9d25](https://github.com/ghiscoding/slickgrid-universal/commit/7bb9d25c40c3f7f53be57c45917802e5f426c599)) - by @ghiscoding + * **graphql:** deprecate `isWithCursor` in favor of simpler `useCursor` ([#1187](https://github.com/ghiscoding/slickgrid-universal/issues/1187)) ([7b3590f](https://github.com/ghiscoding/slickgrid-universal/commit/7b3590f323ea2fe3d3f312674205fc94485213fa)) - by @ghiscoding + * **pagination:** should recreate pagination on cursor based changed ([#1175](https://github.com/ghiscoding/slickgrid-universal/issues/1175)) ([c7836aa](https://github.com/ghiscoding/slickgrid-universal/commit/c7836aae4a4ea0892791acc79a7bcb338ddb2038)) - by @ghiscoding + * **styles:** menu command with & without icons aren't aligned ([#1180](https://github.com/ghiscoding/slickgrid-universal/issues/1180)) ([35f040d](https://github.com/ghiscoding/slickgrid-universal/commit/35f040dbd1f2d384aadbfbe351dd0e55f8d34c68)) - by @ghiscoding ### Features * **common:** add `compoundOperatorAltTexts` grid option ([#1181](https://github.com/ghiscoding/slickgrid-universal/issues/1181)) ([dc0aa5e](https://github.com/ghiscoding/slickgrid-universal/commit/dc0aa5e28351af989e9dd691916af909e3a5fdf5)) - by @ghiscoding + * Graphql verbatim search terms ([#1174](https://github.com/ghiscoding/slickgrid-universal/issues/1174)) ([eadc5ef](https://github.com/ghiscoding/slickgrid-universal/commit/eadc5ef636e8bf331d89f37be4596e7cc534b974)) - by @Harsgalt86 ## [3.4.2](https://github.com/ghiscoding/slickgrid-universal/compare/v3.4.1...v3.4.2) (2023-11-02) @@ -305,28 +455,47 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **common:** `unbindAll` with a group name should remove all tagged ones ([#1152](https://github.com/ghiscoding/slickgrid-universal/issues/1152)) ([5014354](https://github.com/ghiscoding/slickgrid-universal/commit/5014354803d4561409c0f9622ad8bc5093d494cf)), closes [#1150](https://github.com/ghiscoding/slickgrid-universal/issues/1150) - by @ghiscoding + * **common:** calling `bind` with multiple events should add group name ([#1157](https://github.com/ghiscoding/slickgrid-universal/issues/1157)) ([9023b54](https://github.com/ghiscoding/slickgrid-universal/commit/9023b54146b72c0305128484f9fd6f9d1ac47b48)), closes [#1150](https://github.com/ghiscoding/slickgrid-universal/issues/1150) - by @ghiscoding + * **common:** clicking Menu close button should only close current menu ([#1160](https://github.com/ghiscoding/slickgrid-universal/issues/1160)) ([b524ef1](https://github.com/ghiscoding/slickgrid-universal/commit/b524ef1af6c662bc4ebcd87ad95aa99dd077a119)) - by @ghiscoding + * **common:** context menu should close when clicking another cell ([#1163](https://github.com/ghiscoding/slickgrid-universal/issues/1163)) ([bd132c5](https://github.com/ghiscoding/slickgrid-universal/commit/bd132c52a082147c2366b2fade124e145834902f)) - by @ghiscoding + * **common:** disable throwWhenFrozenNotAllViewable w/frozen grids ([#1149](https://github.com/ghiscoding/slickgrid-universal/issues/1149)) ([9a06875](https://github.com/ghiscoding/slickgrid-universal/commit/9a06875d8654c47d97aaaa0fd5191c1bfeae7288)) - by @ghiscoding + * **common:** make sure destroy is a function before calling it ([#1148](https://github.com/ghiscoding/slickgrid-universal/issues/1148)) ([dba9606](https://github.com/ghiscoding/slickgrid-universal/commit/dba96060666a929eb616bcacb492f6f5f3f56106)) - by @ghiscoding + * **common:** mouseover disabled sub-menu shouldn't open it ([#1167](https://github.com/ghiscoding/slickgrid-universal/issues/1167)) ([550f103](https://github.com/ghiscoding/slickgrid-universal/commit/550f1031ca2c56649ed630ab753d757a3fb799fa)) - by @ghiscoding + * **common:** replace `innerHTML: '×'` with `textContent: '×'` ([#1156](https://github.com/ghiscoding/slickgrid-universal/issues/1156)) ([e8b2cfb](https://github.com/ghiscoding/slickgrid-universal/commit/e8b2cfb4b3d182de429ba367d1c83b873670fabc)) - by @ghiscoding + * **common:** rollback event capture causing multiple calls ([#1168](https://github.com/ghiscoding/slickgrid-universal/issues/1168)) ([90876c9](https://github.com/ghiscoding/slickgrid-universal/commit/90876c9a57f291271a3510541e4a24a4ef86413c)) - by @ghiscoding + * deprecate HeaderMenu `items` in favor of `commandItems` ([#1159](https://github.com/ghiscoding/slickgrid-universal/issues/1159)) ([2b26d6d](https://github.com/ghiscoding/slickgrid-universal/commit/2b26d6da1232f4ad4a7d0db8ad077b3b2e3c6bd7)) - by @ghiscoding + * **deps:** update all non-major dependencies ([#1138](https://github.com/ghiscoding/slickgrid-universal/issues/1138)) ([82a602e](https://github.com/ghiscoding/slickgrid-universal/commit/82a602e8c3c25a45979d3e3bbf4766d1bae33f80)) - by @renovate-bot + * **gridMenu:** remove GridMenu from DOM after closing it ([#1169](https://github.com/ghiscoding/slickgrid-universal/issues/1169)) ([87b242f](https://github.com/ghiscoding/slickgrid-universal/commit/87b242fdebd6d8ce838842458e192a6e90de3d80)) - by @ghiscoding + * move `innerHTML` as separate assignment to improve CSP trusted types ([#1162](https://github.com/ghiscoding/slickgrid-universal/issues/1162)) ([9c6a002](https://github.com/ghiscoding/slickgrid-universal/commit/9c6a002666f16b1096d3f928900ad412a4124233)) - by @ghiscoding ### Features * add `subMenuOpenByEvent` option to open sub-menus via mouseover ([#1161](https://github.com/ghiscoding/slickgrid-universal/issues/1161)) ([609f88b](https://github.com/ghiscoding/slickgrid-universal/commit/609f88b2b80515a540bd7ae1c8366b57bd288dbc)) - by @ghiscoding + * add sub-menu(s) to CellMenu & ContextMenu plugins ([#1141](https://github.com/ghiscoding/slickgrid-universal/issues/1141)) ([bd18af1](https://github.com/ghiscoding/slickgrid-universal/commit/bd18af1ee960f9417cb7625ff8c3fb5d9567d16e)) - by @ghiscoding + * add sub-menu(s) to GridMenu plugin ([#1151](https://github.com/ghiscoding/slickgrid-universal/issues/1151)) ([5178310](https://github.com/ghiscoding/slickgrid-universal/commit/5178310c0247d5524300841aac7aea7c4f3df733)) - by @ghiscoding + * add sub-menu(s) to HeaderMenu plugin ([#1158](https://github.com/ghiscoding/slickgrid-universal/issues/1158)) ([eeab42e](https://github.com/ghiscoding/slickgrid-universal/commit/eeab42e270e53341a8572ab55ed758276a4d30d6)) - by @ghiscoding + * add support for grid inside Shadow DOM ([#1166](https://github.com/ghiscoding/slickgrid-universal/issues/1166)) ([f7b8c46](https://github.com/ghiscoding/slickgrid-universal/commit/f7b8c46593c71b7114ac85610c12ad6187e3f6de)) - by @ghiscoding + * **common:** add group name to `bind` and `unbindAll` methods ([#1150](https://github.com/ghiscoding/slickgrid-universal/issues/1150)) ([6c3b90e](https://github.com/ghiscoding/slickgrid-universal/commit/6c3b90e774906621d5b1584a2372ba633d2366ff)) - by @ghiscoding + * **common:** create ColumnPicker dynamically every time ([#1165](https://github.com/ghiscoding/slickgrid-universal/issues/1165)) ([7e8d80e](https://github.com/ghiscoding/slickgrid-universal/commit/7e8d80e807176ba2064cbb71d06fb53995aae06c)) - by @ghiscoding + * **graphql:** add optional cursor pagination to GraphQL backend service ([#1153](https://github.com/ghiscoding/slickgrid-universal/issues/1153)) ([29579b2](https://github.com/ghiscoding/slickgrid-universal/commit/29579b23ab1e531b3323cbf10eb9e9882e244b8f)) - by @Harsgalt86 ## [3.3.2](https://github.com/ghiscoding/slickgrid-universal/compare/v3.3.1...v3.3.2) (2023-10-06) @@ -348,7 +517,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **deps:** update dependency multiple-select-vanilla to ^0.4.10 ([#1098](https://github.com/ghiscoding/slickgrid-universal/issues/1098)) ([ab97b9d](https://github.com/ghiscoding/slickgrid-universal/commit/ab97b9df3205f1a55f69f3722d276c8c71d8fd29)) - by @renovate-bot + * **GridService:** clear any opened highlight timers before disposing ([#1116](https://github.com/ghiscoding/slickgrid-universal/issues/1116)) ([c6a0957](https://github.com/ghiscoding/slickgrid-universal/commit/c6a095702a672e14b442e71be492942c07d6f1e6)) - by @ghiscoding + * **resizer:** resize without container ([#1117](https://github.com/ghiscoding/slickgrid-universal/issues/1117)) ([9013522](https://github.com/ghiscoding/slickgrid-universal/commit/90135223130dacfdd376b56d4cf49437328b08ae)) - by @zewa666 ## [3.2.1](https://github.com/ghiscoding/slickgrid-universal/compare/v3.2.0...v3.2.1) (2023-09-05) @@ -362,14 +533,19 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **export:** add `autoDetectCellFormat` flag to Excel Export Options ([#1083](https://github.com/ghiscoding/slickgrid-universal/issues/1083)) ([839b09a](https://github.com/ghiscoding/slickgrid-universal/commit/839b09a10ceba889bc96a7f229f58412a6d5649c)) - by @ghiscoding + * **TreeData:** add auto-recalc feature for Tree Totals w/Aggregators ([#1084](https://github.com/ghiscoding/slickgrid-universal/issues/1084)) ([e884c03](https://github.com/ghiscoding/slickgrid-universal/commit/e884c0356595c161b746ca370efa4bd74088c458)) - by @ghiscoding + * **TreeData:** add optional Aggregators to Tree Data grids ([#1074](https://github.com/ghiscoding/slickgrid-universal/issues/1074)) ([6af5fd1](https://github.com/ghiscoding/slickgrid-universal/commit/6af5fd17b582834b24655b06c34c634a99c93c6e)) - by @ghiscoding ### Bug Fixes * **common:** Sort Service could throw on 3rd with undefined columnId ([#1059](https://github.com/ghiscoding/slickgrid-universal/issues/1059)) ([1141230](https://github.com/ghiscoding/slickgrid-universal/commit/114123040a6b69d40f928955627121189a6feb75)) - by @ghiscoding + * copying multiple times only kept last undo CellExternalCopyManager ([#1075](https://github.com/ghiscoding/slickgrid-universal/issues/1075)) ([e3beee2](https://github.com/ghiscoding/slickgrid-universal/commit/e3beee208fcd223e911d2d88a15b9d2950267eda)) - by @ghiscoding + * **deps:** update dependency autocompleter to v9 ([#1051](https://github.com/ghiscoding/slickgrid-universal/issues/1051)) ([0e05f2a](https://github.com/ghiscoding/slickgrid-universal/commit/0e05f2a4c9f3c9640a3982b7cfa04ea71cfaab96)) - by @renovate-bot + * **TreeData:** auto-recalc should update totals for collapsed items too ([#1086](https://github.com/ghiscoding/slickgrid-universal/issues/1086)) ([25d39f2](https://github.com/ghiscoding/slickgrid-universal/commit/25d39f277093990f150ec4aa471c079eab73e4b1)) - by @ghiscoding ## [3.1.0](https://github.com/ghiscoding/slickgrid-universal/compare/v3.0.1...v3.1.0) (2023-07-20) @@ -381,6 +557,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **deps:** update dependency dompurify to ^3.0.5 ([#1030](https://github.com/ghiscoding/slickgrid-universal/issues/1030)) ([728bc58](https://github.com/ghiscoding/slickgrid-universal/commit/728bc58b6844544479695f29984221c9ea099936)) - by @renovate-bot + * **plugins:** RowMoveManager shouldn't add cssClass when not usable ([#1044](https://github.com/ghiscoding/slickgrid-universal/issues/1044)) ([f25eeec](https://github.com/ghiscoding/slickgrid-universal/commit/f25eeec7a277d4b915d1423f12e688ad8ac98e7c)) - by @ghiscoding ## [3.0.1](https://github.com/ghiscoding/slickgrid-universal/compare/v3.0.0...v3.0.1) (2023-07-01) @@ -388,11 +565,17 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **common:** Select Filter/Editor regular text shouldn't be html encoded ([#1011](https://github.com/ghiscoding/slickgrid-universal/issues/1011)) ([c203a2c](https://github.com/ghiscoding/slickgrid-universal/commit/c203a2ce4d4e5cf6dfb0e05a25f5fd6b0c4cbe4d)), closes [#976](https://github.com/ghiscoding/slickgrid-universal/issues/976) - by @ghiscoding + * **deps:** update all non-major dependencies ([#1016](https://github.com/ghiscoding/slickgrid-universal/issues/1016)) ([c34ed84](https://github.com/ghiscoding/slickgrid-universal/commit/c34ed84c8c5aa20876c70b6350f711e16fe6b965)) - by @renovate-bot + * **deps:** update dependency autocompleter to ^8.0.4 ([#996](https://github.com/ghiscoding/slickgrid-universal/issues/996)) ([3adf3a1](https://github.com/ghiscoding/slickgrid-universal/commit/3adf3a1a4cf960963ce1447617b3f34b68b6ff4d)) - by @renovate-bot + * **deps:** update dependency slickgrid to ^4.0.1 ([#1017](https://github.com/ghiscoding/slickgrid-universal/issues/1017)) ([2750816](https://github.com/ghiscoding/slickgrid-universal/commit/2750816b7b669a820362934daa9bbfd5d60f3ac5)) - by @renovate-bot + * **GridState:** calling `getAssociatedGridColumns` should extend column ([#1014](https://github.com/ghiscoding/slickgrid-universal/issues/1014)) ([77cec0c](https://github.com/ghiscoding/slickgrid-universal/commit/77cec0cd052ec3145d73a7a16d0c7f5c663e3901)) - by @ghiscoding + * **GridState:** calling getAssociatedGridColumns should extend column (part2) ([#1015](https://github.com/ghiscoding/slickgrid-universal/issues/1015)) ([3ea1d02](https://github.com/ghiscoding/slickgrid-universal/commit/3ea1d0289ba260325a2592fda42fecce10499525)) - by @ghiscoding + * **grouping:** DraggableGrouping could throw when leaving page ([#1019](https://github.com/ghiscoding/slickgrid-universal/issues/1019)) ([c233a9c](https://github.com/ghiscoding/slickgrid-universal/commit/c233a9c5db1fc06395e75f1bc5bb34ea3431ba1f)) - by @ghiscoding ## [3.0.0](https://github.com/ghiscoding/slickgrid-universal/compare/v2.6.4...v3.0.0) (2023-05-29) @@ -414,11 +597,13 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### ⚠ BREAKING CHANGES * drop jQuery requirement (#962) + * **common:** migrate to multiple-select-vanilla (#919) ### Features * **common:** migrate to multiple-select-vanilla ([#919](https://github.com/ghiscoding/slickgrid-universal/issues/919)) ([bc74207](https://github.com/ghiscoding/slickgrid-universal/commit/bc74207e9b2ec46209e87b126e1fcff596c162af)) - by @ghiscoding + * drop jQuery requirement ([#962](https://github.com/ghiscoding/slickgrid-universal/issues/962)) ([3da21da](https://github.com/ghiscoding/slickgrid-universal/commit/3da21daacc391a0fb309fcddd78442642c5269f6)) - by @ghiscoding ## [2.6.4](https://github.com/ghiscoding/slickgrid-universal/compare/v2.6.3...v2.6.4) (2023-05-20) @@ -426,8 +611,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** add better aria accessibility missing on menus and checkboxes ([#968](https://github.com/ghiscoding/slickgrid-universal/issues/968)) ([8041c11](https://github.com/ghiscoding/slickgrid-universal/commit/8041c1189afd7460bbcc0226c49086878c3b5f90)) - by @ghiscoding + * **core:** set `wheel` event listener to passive for better perf ([#971](https://github.com/ghiscoding/slickgrid-universal/issues/971)) ([e4417e8](https://github.com/ghiscoding/slickgrid-universal/commit/e4417e865f6fdf4bcb27eebfc476d959a16d47ea)) - by @ghiscoding + * **export:** fix negative number exports to Excel ([#977](https://github.com/ghiscoding/slickgrid-universal/issues/977)) ([edf5721](https://github.com/ghiscoding/slickgrid-universal/commit/edf5721007ce0745fc81f3f0261fb7e25340cbc1)) - by @ghiscoding + * SlickDraggableGrouping should hide group elms when dragging ([#965](https://github.com/ghiscoding/slickgrid-universal/issues/965)) ([6601998](https://github.com/ghiscoding/slickgrid-universal/commit/660199896df040a34f8947acf81a5d720d11a8c4)) - by @ghiscoding ## [2.6.3](https://github.com/ghiscoding/slickgrid-universal/compare/v2.6.2...v2.6.3) (2023-03-23) @@ -463,12 +651,19 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **autocomplete:** Autocomplete drop container should take content width ([#897](https://github.com/ghiscoding/slickgrid-universal/issues/897)) ([9690a38](https://github.com/ghiscoding/slickgrid-universal/commit/9690a38f678ca6f0632b847aebfe93e5b7f0bc12)) - by @ghiscoding + * **build:** package exports prop had invalid ESM import link ([#892](https://github.com/ghiscoding/slickgrid-universal/issues/892)) ([7f95f69](https://github.com/ghiscoding/slickgrid-universal/commit/7f95f698447f8178cb7ceec416c35f4957fddbe9)) - by @ghiscoding + * **common:** Excel copy cell ranges shouldn't lose its cell focus ([#901](https://github.com/ghiscoding/slickgrid-universal/issues/901)) ([1dc8b76](https://github.com/ghiscoding/slickgrid-universal/commit/1dc8b762b4fc8070eec003161fdc9c4ebf60afd2)) - by @ghiscoding + * **deps:** update dependency autocompleter to v8 ([#895](https://github.com/ghiscoding/slickgrid-universal/issues/895)) ([7df225d](https://github.com/ghiscoding/slickgrid-universal/commit/7df225d844ec5629800373da59aeed44eee04e1b)) - by @renovate-bot + * **deps:** update dependency dompurify to v3 ([#907](https://github.com/ghiscoding/slickgrid-universal/issues/907)) ([66c8b4d](https://github.com/ghiscoding/slickgrid-universal/commit/66c8b4d602d88d733070b2189468bf1b6508d7eb)) - by @renovate-bot + * **editor:** comparing select editor value against `['']` isn't valid ([#909](https://github.com/ghiscoding/slickgrid-universal/issues/909)) ([d93fd5f](https://github.com/ghiscoding/slickgrid-universal/commit/d93fd5f163e393c47fad8c8d285a5788b3834adf)) - by @ghiscoding + * **export:** Excel export auto-detect number with Formatters.multiple ([#902](https://github.com/ghiscoding/slickgrid-universal/issues/902)) ([be33a68](https://github.com/ghiscoding/slickgrid-universal/commit/be33a68cadbdaed0c60b00bdcd123f3a4797fb8a)) - by @ghiscoding + * **RowDetail:** Row Detail extension should work with editable grid ([#896](https://github.com/ghiscoding/slickgrid-universal/issues/896)) ([99677f0](https://github.com/ghiscoding/slickgrid-universal/commit/99677f08b9cb383a2b64540700e501c7bdfe9f72)) - by @ghiscoding ### Features @@ -496,6 +691,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **filters:** provide flag to disable special chars input filter parsing ([#873](https://github.com/ghiscoding/slickgrid-universal/issues/873)) ([7e35dae](https://github.com/ghiscoding/slickgrid-universal/commit/7e35dae2258c191e76dbdf01ac654f4a54b5b547)), closes [/stackoverflow.com/questions/75155658/in-angular-slickgrid-the-records-with-special-characters-are-not-gett/75160978#75160978](https://github.com//stackoverflow.com/questions/75155658/in-angular-slickgrid-the-records-with-special-characters-are-not-gett/75160978/issues/75160978) - by @ghiscoding + * **styling:** do not remove ul>li bullet on html root, fixes [#868](https://github.com/ghiscoding/slickgrid-universal/issues/868) ([#872](https://github.com/ghiscoding/slickgrid-universal/issues/872)) ([59fa0ba](https://github.com/ghiscoding/slickgrid-universal/commit/59fa0badad181172bf37a31ecf4ef0f44ee47e8d)) - by @ghiscoding ## [2.2.2](https://github.com/ghiscoding/slickgrid-universal/compare/v2.2.1...v2.2.2) (2022-12-24) @@ -515,18 +711,27 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **editors:** Autocomplete list should be using same width as cell width ([#846](https://github.com/ghiscoding/slickgrid-universal/issues/846)) ([0055f8a](https://github.com/ghiscoding/slickgrid-universal/commit/0055f8a925f7ec6e381c9b9b05dccdb405b7a420)) - by @ghiscoding + * **export:** create custom Excel cell format with Formatters.decimal ([#844](https://github.com/ghiscoding/slickgrid-universal/issues/844)) ([a7a626c](https://github.com/ghiscoding/slickgrid-universal/commit/a7a626ccaaa510d084979d38d9a6b5a439f24e6d)) - by @ghiscoding + * **exports:** Date should always export w/Formatter unless false ([#856](https://github.com/ghiscoding/slickgrid-universal/issues/856)) ([1b249e8](https://github.com/ghiscoding/slickgrid-universal/commit/1b249e88e3033ff4c432346ae32ce3183537237b)) - by @ghiscoding + * **formatters:** add all missing Date Formatters ([#855](https://github.com/ghiscoding/slickgrid-universal/issues/855)) ([9d29e59](https://github.com/ghiscoding/slickgrid-universal/commit/9d29e59818ae4e7d3cac692f0479e0147cc2ba8d)) - by @ghiscoding + * **formatters:** Date Formatter should work with Date object ([#854](https://github.com/ghiscoding/slickgrid-universal/issues/854)) ([30b80e2](https://github.com/ghiscoding/slickgrid-universal/commit/30b80e27b209dbafda25963864116d980650a648)) - by @ghiscoding + * **styling:** Grid Menu & Col Picker overflow in Firefox ([#845](https://github.com/ghiscoding/slickgrid-universal/issues/845)) ([9b0aef7](https://github.com/ghiscoding/slickgrid-universal/commit/9b0aef74d569c73e18d64e29034d777315c19cf8)) - by @ghiscoding ### Features * **exports:** add Excel auto-detect format by field types & formatters ([#848](https://github.com/ghiscoding/slickgrid-universal/issues/848)) ([27a18c4](https://github.com/ghiscoding/slickgrid-universal/commit/27a18c416e71a2a1f418d5c2c850fd331262bf7f)) - by @ghiscoding + * **exports:** add Excel custom cell (column) styling ([#851](https://github.com/ghiscoding/slickgrid-universal/issues/851)) ([dd92d44](https://github.com/ghiscoding/slickgrid-universal/commit/dd92d44e0ac27c94a72c98af314cfa23f525f94c)) - by @ghiscoding + * **exports:** add optional Excel export parser callback functions ([#852](https://github.com/ghiscoding/slickgrid-universal/issues/852)) ([975da5b](https://github.com/ghiscoding/slickgrid-universal/commit/975da5b1d87ac287c1240e7ec88be4760e22ca74)) - by @ghiscoding + * **exports:** add optional file MIME type to Excel export service ([#849](https://github.com/ghiscoding/slickgrid-universal/issues/849)) ([05402e5](https://github.com/ghiscoding/slickgrid-universal/commit/05402e5b3a4cec9306ed21a495cc89c31b3816d8)) - by @ghiscoding + * **formatters:** add Currency Formatter and GroupTotalFormatter ([#850](https://github.com/ghiscoding/slickgrid-universal/issues/850)) ([ad373ab](https://github.com/ghiscoding/slickgrid-universal/commit/ad373abd84468367d43bf4fa0feccb99ae22821c)) - by @ghiscoding ## [2.1.3](https://github.com/ghiscoding/slickgrid-universal/compare/v2.1.2...v2.1.3) (2022-12-08) @@ -534,7 +739,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **common:** Date Sorting was shuffling other lines with same dates ([#831](https://github.com/ghiscoding/slickgrid-universal/issues/831)) ([db34213](https://github.com/ghiscoding/slickgrid-universal/commit/db34213bc8594ae12a6fd241f9fb6d6bfd1b8334)) - by @ghiscoding + * **common:** Resizer Service should only resize grid not its container ([#833](https://github.com/ghiscoding/slickgrid-universal/issues/833)) ([7d21233](https://github.com/ghiscoding/slickgrid-universal/commit/7d21233deb16a1bda99799fe54401a8b9410197a)) - by @ghiscoding + * Fix for page being cleared when using copy and paste with selectEditor ([#836](https://github.com/ghiscoding/slickgrid-universal/pull/836)) ([f1cadb33](https://github.com/ghiscoding/slickgrid-universal/commit/f1cadb33d99bcd98bc3c79221fbe55a5b1d72cfd)) - by @austinsimpson ## [2.1.2](https://github.com/ghiscoding/slickgrid-universal/compare/v2.1.1...v2.1.2) (2022-12-02) @@ -542,10 +749,15 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **addons:** do not add special columns twice (like Row Selection) ([#822](https://github.com/ghiscoding/slickgrid-universal/issues/822)) ([a80d6f8](https://github.com/ghiscoding/slickgrid-universal/commit/a80d6f8f2cae674e0a870eb9c450de991cd84837)) - by @ghiscoding + * **addons:** onGroupChanged callback should be executed with Draggable ([#826](https://github.com/ghiscoding/slickgrid-universal/issues/826)) ([35c2631](https://github.com/ghiscoding/slickgrid-universal/commit/35c2631feb00a5b2efe6903e9bfdfe5c95df318e)) - by @ghiscoding + * **common:** remove unused console log ([593928a](https://github.com/ghiscoding/slickgrid-universal/commit/593928af8a7e92ecf2a8c67e4cff4c8e5da58468)) - by @ghiscoding + * **core:** grid service `resetGrid` method wasn't always resetting ([#829](https://github.com/ghiscoding/slickgrid-universal/issues/829)) ([1ffc382](https://github.com/ghiscoding/slickgrid-universal/commit/1ffc38265006e8b6e584e6de8f6c4fe53c2e2bf8)) - by @ghiscoding + * **styling:** editor clear button should always be centered ([3e9f330](https://github.com/ghiscoding/slickgrid-universal/commit/3e9f3304dc2b02450e859af27af254fee1fbd650)) - by @ghiscoding + * **styling:** focused compound input box-shadow css ([2c50c47](https://github.com/ghiscoding/slickgrid-universal/commit/2c50c47a76556ae4a6f842c483800d5af90637fc)) - by @ghiscoding ## [2.1.1](https://github.com/ghiscoding/slickgrid-universal/compare/v2.1.0...v2.1.1) (2022-11-19) @@ -559,32 +771,51 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **build:** upgrading to TypeScript 4.9 brought new build issue ([#816](https://github.com/ghiscoding/slickgrid-universal/issues/816)) ([4d46d8a](https://github.com/ghiscoding/slickgrid-universal/commit/4d46d8ab251bd78671140f82cb143b973e5422b3)) - by @ghiscoding + * **common:** changing Slider value(s) should update Tooltip instantly ([#800](https://github.com/ghiscoding/slickgrid-universal/issues/800)) ([9c6be27](https://github.com/ghiscoding/slickgrid-universal/commit/9c6be271a956876edaa03be7bf4bda9821840910)) - by @ghiscoding + * **common:** Slider Range should update both number addons ([#803](https://github.com/ghiscoding/slickgrid-universal/issues/803)) ([3cfd84e](https://github.com/ghiscoding/slickgrid-universal/commit/3cfd84e7ec4e45cf6a4896dc6143da1fecb0402c)) - by @ghiscoding + * **deps:** update dependency autocompleter to v7 ([#804](https://github.com/ghiscoding/slickgrid-universal/issues/804)) ([c298646](https://github.com/ghiscoding/slickgrid-universal/commit/c298646fca64059ca3a59a370f870ad4b3a573da)) - by @renovate-bot + * **deps:** update dependency dompurify to ^2.4.1 ([#806](https://github.com/ghiscoding/slickgrid-universal/issues/806)) ([a33d8fb](https://github.com/ghiscoding/slickgrid-universal/commit/a33d8fbf3e48bfa29b9173f9263620e61608fffb)) - by @renovate-bot + * **editors:** disable browser autofill on the Editors.autocompleter ([#776](https://github.com/ghiscoding/slickgrid-universal/issues/776)) ([fd2cf53](https://github.com/ghiscoding/slickgrid-universal/commit/fd2cf535c0bd941203951c665bb3da00f4a4677e)) - by @ghiscoding + * **editors:** Slider editor track not showing after Slider filter change ([#792](https://github.com/ghiscoding/slickgrid-universal/issues/792)) ([2ad02d2](https://github.com/ghiscoding/slickgrid-universal/commit/2ad02d22cfbb2187df62f0ec19b26f828fec57a6)) - by @ghiscoding + * **filters:** changing Slider value should update tooltip value ([#788](https://github.com/ghiscoding/slickgrid-universal/issues/788)) ([509a31d](https://github.com/ghiscoding/slickgrid-universal/commit/509a31d5630689c6c91cc2cef4e87b8dea72a243)) - by @ghiscoding + * **filters:** Slider default operator should be greater or equal (>=) ([#793](https://github.com/ghiscoding/slickgrid-universal/issues/793)) ([b895864](https://github.com/ghiscoding/slickgrid-universal/commit/b895864bc39a415622ac9f2a4b79565aa3d89179)) - by @ghiscoding + * **styling:** new Slider not flexed correctly ([#799](https://github.com/ghiscoding/slickgrid-universal/issues/799)) ([83a86d0](https://github.com/ghiscoding/slickgrid-universal/commit/83a86d0575a47ed3a11ede31af2a8a3a8186fb9d)) - by @ghiscoding ### Features * **addon:** add group by sorting to SlickDraggableGrouping ([#814](https://github.com/ghiscoding/slickgrid-universal/issues/814)) ([962a756](https://github.com/ghiscoding/slickgrid-universal/commit/962a756fb17476221867c977752e28bd1d74f6db)) - by @ghiscoding + * **common:** add "targetSelector" to onFilterChanged & Grid State ([#813](https://github.com/ghiscoding/slickgrid-universal/issues/813)) ([a25791a](https://github.com/ghiscoding/slickgrid-universal/commit/a25791a5d11b73fd88d80ef8a6f788b27d7390ec)) - by @ghiscoding + * **common:** use editorOptions/filterOptions instead of params ([#798](https://github.com/ghiscoding/slickgrid-universal/issues/798)) ([a3c8b6e](https://github.com/ghiscoding/slickgrid-universal/commit/a3c8b6e48dbe3db7eb154837f15ce10780923b32)) - by @ghiscoding + * **filters:** add "target" prop to `onBeforeSearchChange` ([#796](https://github.com/ghiscoding/slickgrid-universal/issues/796)) ([c4606fd](https://github.com/ghiscoding/slickgrid-universal/commit/c4606fde3cf206f81ab5f83d150cf3ce29cbfe75)) - by @ghiscoding + * **filters:** add back Slider Range filter in pure JS ([#784](https://github.com/ghiscoding/slickgrid-universal/issues/784)) ([b84525c](https://github.com/ghiscoding/slickgrid-universal/commit/b84525c3c087582854e30b386a1015f6ce3156b4)) - by @ghiscoding + * **filters:** add grid option `skipCompoundOperatorFilterWithNullInput` ([#794](https://github.com/ghiscoding/slickgrid-universal/issues/794)) ([617c88d](https://github.com/ghiscoding/slickgrid-universal/commit/617c88d7432c35b8ac0c0f40066a2f55a58b6d35)) - by @ghiscoding + * **filters:** add Slider filter track filled track color ([#795](https://github.com/ghiscoding/slickgrid-universal/issues/795)) ([5fbd9c9](https://github.com/ghiscoding/slickgrid-universal/commit/5fbd9c9036844e7e88a99fea6a4d1e1f0fd2377a)) - by @ghiscoding + * **plugins:** sync column definitions to user after plugin adds column ([#781](https://github.com/ghiscoding/slickgrid-universal/issues/781)) ([0755b65](https://github.com/ghiscoding/slickgrid-universal/commit/0755b655b7be5911345334e094544a14c3698b51)) - by @ghiscoding + * **tooltip:** add a new "center" position option to SlickCustomTooltip ([#787](https://github.com/ghiscoding/slickgrid-universal/issues/787)) ([b019de5](https://github.com/ghiscoding/slickgrid-universal/commit/b019de50244836a984314ea6e6f5cee639551438)) - by @ghiscoding ### Performance Improvements * **filters:** merge all date range & compound filters into one class ([#812](https://github.com/ghiscoding/slickgrid-universal/issues/812)) ([ca9adfa](https://github.com/ghiscoding/slickgrid-universal/commit/ca9adfae84ca8fd57b61548b1222ade5a8b9c498)) - by @ghiscoding + * **filters:** merge all input & compound filters into one class ([#809](https://github.com/ghiscoding/slickgrid-universal/issues/809)) ([6d08f4d](https://github.com/ghiscoding/slickgrid-universal/commit/6d08f4dc9fc471b316f375d77fa8ae1805dc9b83)) - by @ghiscoding + * **filters:** merge all Slider filters into one class ([#791](https://github.com/ghiscoding/slickgrid-universal/issues/791)) ([fc4304b](https://github.com/ghiscoding/slickgrid-universal/commit/fc4304b3dd47ac10df65f5b8dda9d8ce5aad8ed9)) - by @ghiscoding # [2.0.0](https://github.com/ghiscoding/slickgrid-universal/compare/v1.4.0...v2.0.0) (2022-10-17) @@ -592,6 +823,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **deps:** update all non-major dependencies ([#769](https://github.com/ghiscoding/slickgrid-universal/issues/769)) ([4e05a4b](https://github.com/ghiscoding/slickgrid-universal/commit/4e05a4b977c760511fc90903c0f62673859bd65f)) - by @renovate-bot + * **styling:** fix some styling issues with input groups and Firefox ([#750](https://github.com/ghiscoding/slickgrid-universal/issues/750)) ([1aa849e](https://github.com/ghiscoding/slickgrid-universal/commit/1aa849ea81461dc9bbd7b3bc05a092bb14c88be2)) - by @ghiscoding ### Features @@ -603,6 +835,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **deps:** update all non-major dependencies ([#769](https://github.com/ghiscoding/slickgrid-universal/issues/769)) ([4e05a4b](https://github.com/ghiscoding/slickgrid-universal/commit/4e05a4b977c760511fc90903c0f62673859bd65f)) - by @renovate-bot + * **styling:** fix some styling issues with input groups and Firefox ([#750](https://github.com/ghiscoding/slickgrid-universal/issues/750)) ([1aa849e](https://github.com/ghiscoding/slickgrid-universal/commit/1aa849ea81461dc9bbd7b3bc05a092bb14c88be2)) - by @ghiscoding ### Features @@ -614,12 +847,15 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **common:** duplicate translation namespace prefix, fixes [#738](https://github.com/ghiscoding/slickgrid-universal/issues/738) ([#739](https://github.com/ghiscoding/slickgrid-universal/issues/739)) ([ed6b0cc](https://github.com/ghiscoding/slickgrid-universal/commit/ed6b0cc4f664e27830357ac45d523d0571c94bce)) - by @someusersomeuser + * **deps:** update all non-major dependencies ([#740](https://github.com/ghiscoding/slickgrid-universal/issues/740)) ([c8acb65](https://github.com/ghiscoding/slickgrid-universal/commit/c8acb6542a768b2a2b4e0ea0e1f71533d7077927)) - by @renovate-bot + * **filters:** fetch API isn't always an instance of Response ([#746](https://github.com/ghiscoding/slickgrid-universal/issues/746)) ([11be5c2](https://github.com/ghiscoding/slickgrid-universal/commit/11be5c2f9554c8fad2b984864ec7180698d02d19)), closes [#744](https://github.com/ghiscoding/slickgrid-universal/issues/744) - by @ghiscoding ### Features * **common:** remove jquery-ui-dist from deps, use jquery-ui only ([#733](https://github.com/ghiscoding/slickgrid-universal/issues/733)) ([b89d1f1](https://github.com/ghiscoding/slickgrid-universal/commit/b89d1f169bfde21d8a46520aed580c12db5f668f)) - by @ghiscoding + * **common:** update title prop on change event for Slider Filter/Editor ([#743](https://github.com/ghiscoding/slickgrid-universal/issues/743)) ([0ca6f3f](https://github.com/ghiscoding/slickgrid-universal/commit/0ca6f3f4d8894d4bb9459cabca9a3492e7cca0ad)) - by @ghiscoding ## [1.3.7](https://github.com/ghiscoding/slickgrid-universal/compare/v1.3.6...v1.3.7) (2022-08-02) @@ -651,6 +887,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **composite:** selected row count always 0 on mass-selected ([#712](https://github.com/ghiscoding/slickgrid-universal/issues/712)) ([ec42dc7](https://github.com/ghiscoding/slickgrid-universal/commit/ec42dc753fbf8c84040e252f328e51ea4a98cedf)) + * **deps:** update all non-major dependencies ([230291c](https://github.com/ghiscoding/slickgrid-universal/commit/230291c94506fdd12e7f843a3d7f324922ef97f6)) # [1.3.0](https://github.com/ghiscoding/slickgrid-universal/compare/v1.2.6...v1.3.0) (2022-06-18) @@ -658,6 +895,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **deps:** add missing dependencies in child package ([97d0230](https://github.com/ghiscoding/slickgrid-universal/commit/97d02306899e583779c3b6d5b219b2798a5f9cfd)) + * **deps:** update all non-major dependencies ([5097cea](https://github.com/ghiscoding/slickgrid-universal/commit/5097ceae88c0ea212e0aa6ea2a5b1020368f3216)) ### Features @@ -687,8 +925,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **editors:** select editor should call save only once ([d111c2f](https://github.com/ghiscoding/slickgrid-universal/commit/d111c2f7799151236c6053d7a5288d1fdd530550)) + * **resizer:** use default resize when resizeByContent has no data ([8499b61](https://github.com/ghiscoding/slickgrid-universal/commit/8499b61b5cc6365af0035d254a9487c79b74bd7f)) + * **selections:** selected rows doesn't update when hidden column shown ([0d1cf29](https://github.com/ghiscoding/slickgrid-universal/commit/0d1cf294e8ae944672a9c9a2cece1de553c2f973)), closes [#661](https://github.com/ghiscoding/slickgrid-universal/issues/661) + * **styling:** add pointer cursor on ms-filter, avoid Bootstrap override ([11e1e12](https://github.com/ghiscoding/slickgrid-universal/commit/11e1e12115896e73096e10b34575e4e8ebe5b819)) ## [1.2.1](https://github.com/ghiscoding/slickgrid-universal/compare/v1.2.0...v1.2.1) (2022-01-18) @@ -702,28 +943,47 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **demo:** latest change with Filter container breaks other demos ([129cc78](https://github.com/ghiscoding/slickgrid-universal/commit/129cc78ac34ad632f2a265d49a631e04b119250b)) + * **filter:** add the "filled" class for styling purposes ([ea7974a](https://github.com/ghiscoding/slickgrid-universal/commit/ea7974a9a7d54150c16d22ccb8008c692faf6132)) + * **filter:** add the "filled" class for styling purposes - better code ([4a650cd](https://github.com/ghiscoding/slickgrid-universal/commit/4a650cd269852ab20088b274939e89b2cfc96ec8)) + * **filter:** add the "filled" class for styling purposes - ajust code format ([abe481e](https://github.com/ghiscoding/slickgrid-universal/commit/abe481e0cd11bfe204399814c1be0eeb66d3f91a)) + * **filter:** add the "filled" class for styling purposes - ajust format ([fc8c899](https://github.com/ghiscoding/slickgrid-universal/commit/fc8c8992381b001d6ada449352d7b66c6ca08e00)) + * **filter:** update multiple-select to fix select filtering ([63dcd08](https://github.com/ghiscoding/slickgrid-universal/commit/63dcd0873026fb8ba036ca52ba31f583d6ad136f)), closes [#865](https://github.com/ghiscoding/slickgrid-universal/issues/865) + * **plugins:** Draggable Grouping Toggle All should follow `collapsed` ([7fedfa1](https://github.com/ghiscoding/slickgrid-universal/commit/7fedfa1129e12a3bf665efe0bd9160b6a7a1b6a9)) + * **services:** unsubscribe shouldn't remove when poping out of array ([e841da9](https://github.com/ghiscoding/slickgrid-universal/commit/e841da9df7a23bf7b789e4a13803488ab479ff15)) ### Features * **binding:** make Binding Service a little smarter ([98a7661](https://github.com/ghiscoding/slickgrid-universal/commit/98a766173638246b6a17e31812929a9bba1eb52b)) + * **composite:** add new `validateMassUpdateChange` callback & bug fixes ([#603](https://github.com/ghiscoding/slickgrid-universal/issues/603)) ([2c1559b](https://github.com/ghiscoding/slickgrid-universal/commit/2c1559b7a3b0b1a642a664e59a025ce78a747946)) + * **demo:** add new Example to demo Real-time Market Trading ([e50434a](https://github.com/ghiscoding/slickgrid-universal/commit/e50434ac3dab98644e23266c81d09b3789ea7de4)) + * **filters:** change-filter-element-Container ([31c6e54](https://github.com/ghiscoding/slickgrid-universal/commit/31c6e54a3b2e0d135d8407c74b7bfa329a85e0c5)) + * **filters:** change-filter-element-Container ([d455d27](https://github.com/ghiscoding/slickgrid-universal/commit/d455d2781f19fc9865600b6123f679ab3526cf04)) + * **filters:** change-filter-element-Container ([704c52a](https://github.com/ghiscoding/slickgrid-universal/commit/704c52a1d5dec9fedbe837ceca41b96a0d673061)) + * **filters:** change-filter-element-Container-ajust-code-format ([efb0189](https://github.com/ghiscoding/slickgrid-universal/commit/efb0189b0ce357b07025e2f9f29717a41128ab6b)) + * **filters:** change-filter-element-Container-ajust-test ([268ccb4](https://github.com/ghiscoding/slickgrid-universal/commit/268ccb4d6be916959f2eadd87d7c506dff1df472)) + * **filters:** change-filter-element-Container-test ([61e29c5](https://github.com/ghiscoding/slickgrid-universal/commit/61e29c5851487f7470e6f631c890c346f07ed242)) + * **plugins:** Apply auto scroll when dragging on RowMoveManager plugin ([1c14a4f](https://github.com/ghiscoding/slickgrid-universal/commit/1c14a4fd06693425be52e91f405d1c8739699627)), closes [#662](https://github.com/ghiscoding/slickgrid-universal/issues/662) + * **selection:** auto-scroll the viewport when dragging with selection ([ecd9c57](https://github.com/ghiscoding/slickgrid-universal/commit/ecd9c57bd6c1315e2358722785a87582ec939f85)), closes [#656](https://github.com/ghiscoding/slickgrid-universal/issues/656) + * **services:** add `skipError` to CRUD methods in Grid Service ([869ed87](https://github.com/ghiscoding/slickgrid-universal/commit/869ed87bfa4e60d089138bcba1da5f4bb120e73b)) + * **services:** add extra features to EventPubSub Service ([9bd02b5](https://github.com/ghiscoding/slickgrid-universal/commit/9bd02b5d92bcf6aaf89a828c4e6496a24e795c53)) # [1.1.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.19.2...v1.1.0) (2021-12-11) @@ -731,50 +991,91 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **build:** add DOM purify optional default import to fix rollup builds ([73bc3c0](https://github.com/ghiscoding/slickgrid-universal/commit/73bc3c0756cf6d28b292f0162afffc06412a126e)) + * **build:** DOMPurify import fix for all framework ([c551d0c](https://github.com/ghiscoding/slickgrid-universal/commit/c551d0c64d4c7325578acf4feb5d22132c7d7f91)) + * **comp:** replace `prepend` not supported in IE/Salesforce ([13bd9a4](https://github.com/ghiscoding/slickgrid-universal/commit/13bd9a4f8c4fdaedccc65db7100527be0e84eb00)) + * **context:** remove fixed width on ContextMenu use auto instead ([403679b](https://github.com/ghiscoding/slickgrid-universal/commit/403679be5ca8547b53ed2525a4017923302afae7)) + * **context:** strip hidden special chars on context menu Copy command ([5d81644](https://github.com/ghiscoding/slickgrid-universal/commit/5d81644a194b66e7fb5efc550a08962d8087f0e3)) + * **context:** strip hidden special chars on context menu Copy command ([f94ca83](https://github.com/ghiscoding/slickgrid-universal/commit/f94ca834b1fdee94e4e44bdc3d245956a4437de6)) + * **filters:** remove Filters from DOM after header row gets destroyed ([3f08162](https://github.com/ghiscoding/slickgrid-universal/commit/3f08162cd8b5fbb407c77b6dc441e60239ba5788)) + * **locales:** add missing text & remove global config texts fix Locales ([655a872](https://github.com/ghiscoding/slickgrid-universal/commit/655a872d7160ab53530f8e2fdc575817af782b5d)) + * **plugin:** Copy command from Context Menu should work with numbers ([9d36491](https://github.com/ghiscoding/slickgrid-universal/commit/9d36491c407beb0fdc53588ffc6264306fab607a)) + * **plugin:** providing usability override via grid option should work ([6446a10](https://github.com/ghiscoding/slickgrid-universal/commit/6446a1061d7d0126cfe655518b7179d93356aa83)), closes [#555](https://github.com/ghiscoding/slickgrid-universal/issues/555) + * **plugins:** remove invalid export for build to work ([9353022](https://github.com/ghiscoding/slickgrid-universal/commit/9353022593ba9b16e34a8b3dd3ad62bc5b5e7569)) + * **styling:** better support of auto width on drop menu ([8a48dd2](https://github.com/ghiscoding/slickgrid-universal/commit/8a48dd2a224c757534a631e88a4864e151496438)) + * **styling:** Grid Menu Title not aligned correctly with Bootstrap ([e2b991f](https://github.com/ghiscoding/slickgrid-universal/commit/e2b991fb05b8ca94e5a0e3986aabaefc7bc245fb)) + * **styling:** slightly off Autocomplete position ([cd03f67](https://github.com/ghiscoding/slickgrid-universal/commit/cd03f67f50db301cfe74a1e20efd998102bcf3bf)) + * **styling:** tweak & fix all styling with Salesforce & other frameworks ([86dbb76](https://github.com/ghiscoding/slickgrid-universal/commit/86dbb76b439a99773a3fe6fd154440eacb20d510)) + * **tree:** reset to initial tree sort when calling "Clear all Sorting" ([8bd3f4f](https://github.com/ghiscoding/slickgrid-universal/commit/8bd3f4f68247681f8eb57e7aabd59b636face7e7)) + * **treeGrid:** Bug in onCellClick event ([42155af](https://github.com/ghiscoding/slickgrid-universal/commit/42155af12b0808fc95d5f1c00fcec9bfaef64c44)) + * apply fixes & refactoring after testing in Aurelia-Slickgrid ([038fa3f](https://github.com/ghiscoding/slickgrid-universal/commit/038fa3f56f202465f2b40af57e8acf752fe31f60)) + * switch normal/frozen should always show Grid Menu on far right ([6bef090](https://github.com/ghiscoding/slickgrid-universal/commit/6bef0901652a2bdbf661cf5a0fc0d9a7c325a44a)) + * translation wasn't working with context menu ([889e443](https://github.com/ghiscoding/slickgrid-universal/commit/889e44387279c7834944600417c0c2da11b7991f)) ### Features * **controls:** add `minHeight` option to ColumnPicker/GridMenu ([cfcfc85](https://github.com/ghiscoding/slickgrid-universal/commit/cfcfc8588b854530425f2bea19e8aa7c5256d059)) + * **controls:** convert and add ColumnPicker into Slickgrid-Universal ([1f937b9](https://github.com/ghiscoding/slickgrid-universal/commit/1f937b9a3abe43cf1a2bb1f52ba625c34431e328)) + * **controls:** move external Grid Menu into Slickgrid-Universal ([40adff4](https://github.com/ghiscoding/slickgrid-universal/commit/40adff49c2a74769823dfbed3d32b239608e2a59)) + * **core:** add TS utility to infer extension instance by name ([3f4f65f](https://github.com/ghiscoding/slickgrid-universal/commit/3f4f65fb1c4f01cddca0e356a0a770b575a7384a)) + * **plugins:** add all Cell Range/Selection plugins into Universal ([3b4ddca](https://github.com/ghiscoding/slickgrid-universal/commit/3b4ddcaff6e2e8db5804b995ff2282f306cc1a7a)) + * **plugins:** add extra callback methods to checkbox selector ([#570](https://github.com/ghiscoding/slickgrid-universal/issues/570)) ([a9245f9](https://github.com/ghiscoding/slickgrid-universal/commit/a9245f920397bab0ef5105404babe8443654785c)) + * **plugins:** add Row Detail plugin final code & tests ([045ea6d](https://github.com/ghiscoding/slickgrid-universal/commit/045ea6d0e49e55163edcbe1ec6e796f51349667b)) + * **plugins:** make it possible to use both Header Button/Menu together ([965bd58](https://github.com/ghiscoding/slickgrid-universal/commit/965bd588aeba7528031f309020bdfd3c611ebeab)) + * **plugins:** move Checkbox and Row Selection plugins to universal ([06f0ab1](https://github.com/ghiscoding/slickgrid-universal/commit/06f0ab155a2f0ee06681d3e94780397c5e4f9f67)) + * **plugins:** move external Cell Menu into Slickgrid-Universal ([6f34c10](https://github.com/ghiscoding/slickgrid-universal/commit/6f34c10b9a8522ae430e13c9519083451bf71ebf)) + * **plugins:** move external cell related plugins to universal ([11e15d8](https://github.com/ghiscoding/slickgrid-universal/commit/11e15d88360b7b30ca7ab94624a7928201f15945)) + * **plugins:** move external Context Menu into Slickgrid-Universal ([2170bb4](https://github.com/ghiscoding/slickgrid-universal/commit/2170bb4e3f02ef6f45ad13a1c59730047942651e)) + * **plugins:** move external Draggable Grouping into Slickgrid-Universal ([8e6eb48](https://github.com/ghiscoding/slickgrid-universal/commit/8e6eb4881741313b7d582d2e3d17ffef582ecb35)) + * **plugins:** move external GroupItemMetataProvider into Universal ([8f18c7d](https://github.com/ghiscoding/slickgrid-universal/commit/8f18c7d3d616e4cd72eb5478d544ec241c53154f)) + * **plugins:** move external Header Button into Slickgrid-Universal ([69711ad](https://github.com/ghiscoding/slickgrid-universal/commit/69711aded5aa835091789800214f82cd7c72753e)) + * **plugins:** move external Header Menu into Slickgrid-Universal ([aeba480](https://github.com/ghiscoding/slickgrid-universal/commit/aeba4801fdb5cba3976984f5c591be8c1ad97e4b)) + * **plugins:** move Row Detail View plugin to universal ([9700ff4](https://github.com/ghiscoding/slickgrid-universal/commit/9700ff49132e9408b808f916f634976d80e12579)) + * **plugins:** move Row Detail View plugin to universal ([fb327a6](https://github.com/ghiscoding/slickgrid-universal/commit/fb327a6abe85b86683572cde2a550de43a01f9e1)) + * **plugins:** move Row Move Manager plugin to universal ([b19b2ed](https://github.com/ghiscoding/slickgrid-universal/commit/b19b2ed2da669662fbbdcf9fdefac243132909b2)) + * **plugins:** replace AutoTooltips Extension by plugin ([80df14d](https://github.com/ghiscoding/slickgrid-universal/commit/80df14da9b66e9e1b8314e5adb1b96890cc7baa1)) + * **plugins:** show bullet when command menu icon missing ([cbe580a](https://github.com/ghiscoding/slickgrid-universal/commit/cbe580a97313b7b90e287586b4a6420f0a983f20)) + * **selection:** add `caller` property to `onSelectedRowsChanged` event ([cc5f4ae](https://github.com/ghiscoding/slickgrid-universal/commit/cc5f4aec7334b6d001bde55dacf83722c3b2763b)) + * **utils:** replace ext lib `assign-deep` by local `deepMerge` util ([2f56bd3](https://github.com/ghiscoding/slickgrid-universal/commit/2f56bd3571d9c5fb689a09d21cfb3813f5b70e89)) ## [0.19.2](https://github.com/ghiscoding/slickgrid-universal/compare/v0.19.1...v0.19.2) (2021-11-19) @@ -782,8 +1083,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **build:** add DOM purify optional default import to fix rollup builds ([3bd335d](https://github.com/ghiscoding/slickgrid-universal/commit/3bd335dd62d0829c1581ca0fde560c93dcd84458)) + * **resizer:** use autosize width when total width smaller than viewport ([555fb0c](https://github.com/ghiscoding/slickgrid-universal/commit/555fb0cb793c111de837ffe6e9f212fcbf5ed701)) + * **translation:** add new UNFREEZE_COLUMNS to fix translation ([0010861](https://github.com/ghiscoding/slickgrid-universal/commit/001086165434f619f1e90f664e2185b77fb6a92e)) + * **translation:** add new UNFREEZE_COLUMNS to fix translation ([22ed231](https://github.com/ghiscoding/slickgrid-universal/commit/22ed2313c45587f2ebdb279c9e47df881c6f83d6)) ## [0.19.1](https://github.com/ghiscoding/slickgrid-universal/compare/v0.19.0...v0.19.1) (2021-11-15) @@ -791,8 +1095,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **context:** strin hidden special chars on context menu Copy command ([221c05d](https://github.com/ghiscoding/slickgrid-universal/commit/221c05d8d6345d090074c92e423071888e4a2686)) + * **context:** when copying use opacity 0 on temp element ([3f0896f](https://github.com/ghiscoding/slickgrid-universal/commit/3f0896fab30aa5a3da278912f00272ce434b8c15)) + * **subscriptions:** unsubscribe every subcriptions while disposing comp ([bf0dcd4](https://github.com/ghiscoding/slickgrid-universal/commit/bf0dcd4963171b703f07e705aac7230402c84dbf)) + * **tree:** reset to initial tree sort when calling "Clear all Sorting" ([984e3a7](https://github.com/ghiscoding/slickgrid-universal/commit/984e3a7bf0bf734f035514d32d44c6164c6fdab1)) # [0.19.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.18.0...v0.19.0) (2021-10-28) @@ -800,17 +1107,25 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * make it work with AutoTooltip and extra option to skip it ([2f7e4c5](https://github.com/ghiscoding/slickgrid-universal/commit/2f7e4c502471c236a76510905ddbf07f653ea5d8)) + * **frozen:** calling `setPinning` with empty object/null should clear it ([48b11f7](https://github.com/ghiscoding/slickgrid-universal/commit/48b11f74f2ce6541b6e6e03bf7fe194e5be96d0e)) + * **style:** remove unnecessary css source map ([4e6fc08](https://github.com/ghiscoding/slickgrid-universal/commit/4e6fc085abe19389d28bf7a8cea3f83859582bdc)) + * **styling:** cleanup CSS files to ship smaller bundle ([69b18bf](https://github.com/ghiscoding/slickgrid-universal/commit/69b18bf3505fc5538de878b7dbf33104faa8b11a)) + * **tree:** Grid State should have Tree Data initial sort ([b24ce40](https://github.com/ghiscoding/slickgrid-universal/commit/b24ce4032ea671aa6de6d8e2bb8b045359fd897b)) + * **tree:** use previous state when refreshing dataset afterward ([0982474](https://github.com/ghiscoding/slickgrid-universal/commit/09824741be404d3d05ccff4417f243c4b1c5c113)) ### Features * **plugin:** add row move shadown item while moving/dragging row ([c665ec8](https://github.com/ghiscoding/slickgrid-universal/commit/c665ec88be859feeea89e5ab8826f2b0a57c5cfb)) + * add async process to use with Promise/Observable ([7350a6d](https://github.com/ghiscoding/slickgrid-universal/commit/7350a6d06ef5bb8495a05e22421f9b7b5a4270cb)) + * add auto-position depending on available space ([82d6134](https://github.com/ghiscoding/slickgrid-universal/commit/82d6134003900ca8e345bd02a35e3830476638e3)) + * **plugin:** create new Custom Tooltip plugin ([4c8c4f6](https://github.com/ghiscoding/slickgrid-universal/commit/4c8c4f62423665bc2e1dcf0675b1300607397b6a)) # [0.18.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.17.0...v0.18.0) (2021-09-29) @@ -818,18 +1133,27 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **context:** Copy Cell via Context Menu shouldn't include Tree symbols ([f710084](https://github.com/ghiscoding/slickgrid-universal/commit/f710084c06cd47d900daccd389de131209e19163)) + * **filters:** css "filled" class on filters should also work w/Grid View ([e8edae7](https://github.com/ghiscoding/slickgrid-universal/commit/e8edae79bcd5c28438203e269d26f107e26c4ae5)) + * **resizer:** clear pending resizeGrid on dispose ([07ed6a0](https://github.com/ghiscoding/slickgrid-universal/commit/07ed6a0390f235341b116d981aa4ee84719b029b)) + * **resizer:** only bind autoresize when enabled ([ca894c0](https://github.com/ghiscoding/slickgrid-universal/commit/ca894c0a83b5762a42b703f28fc59bdb38e01944)) + * **styling:** List bullets shouldn't show in any frameworks, fixes [#487](https://github.com/ghiscoding/slickgrid-universal/issues/487) ([53ea537](https://github.com/ghiscoding/slickgrid-universal/commit/53ea5379c6109383630362717b980a1dbe099681)) + * **tree:** when Tree Data is filtered then Sort, footer count is invalid ([4f5fc44](https://github.com/ghiscoding/slickgrid-universal/commit/4f5fc443fbc7a0ab3cbe46722fc6bd85fd4b1594)) ### Features * **context:** expose 3 events for Tree/Grouping clear/collapse/expand ([317f3ad](https://github.com/ghiscoding/slickgrid-universal/commit/317f3ad443f8ac81c7cacacaec6d38553bec147b)) + * **Resizer:** add useResizeObserver option ([bb33cdd](https://github.com/ghiscoding/slickgrid-universal/commit/bb33cdd716834913846ab2fcf74a84f8424acf92)) + * **sorts:** option to ignore accent while sorting text ([1b4fe81](https://github.com/ghiscoding/slickgrid-universal/commit/1b4fe81d613b780aefcc0ba3e7b16c20eaebd0aa)) + * **styling:** increase highlight of filters that are filled w/values ([8f93534](https://github.com/ghiscoding/slickgrid-universal/commit/8f9353418190ee3e11aca65d1a57fa4204331011)) + * **tree:** new `excludeChildrenWhenFilteringTree` set as new default ([47df943](https://github.com/ghiscoding/slickgrid-universal/commit/47df943414f383a47062a7ad9245700a1bd8a24e)) # [0.17.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.16.2...v0.17.0) (2021-09-09) @@ -837,25 +1161,41 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **filters:** IN_CONTAINS should be sanitized when used with html ([961d8fd](https://github.com/ghiscoding/slickgrid-universal/commit/961d8fd7ea6f915dd8f0749d0329219b82923fea)) + * **filters:** remove Filters from DOM after header row gets destroyed ([b08d4ba](https://github.com/ghiscoding/slickgrid-universal/commit/b08d4ba070ec9d9d131d6830e4625e6ef950ac09)) + * **grouping:** Draggable Grouping should clear preheader when called ([37811a5](https://github.com/ghiscoding/slickgrid-universal/commit/37811a51d2af04e78aedc88ff5d8eae8a622ac40)) + * **resizer:** regression introduced by [#462](https://github.com/ghiscoding/slickgrid-universal/issues/462) for the grid resize in SF ([f34d8b9](https://github.com/ghiscoding/slickgrid-universal/commit/f34d8b9678c7ee9e76534a7f7ffdf2c4d7f9f772)) + * **resizer:** resizer not always triggered in SF and show broken UI ([89fc62e](https://github.com/ghiscoding/slickgrid-universal/commit/89fc62eff7fac8b5cf43b3b6acd7590ed84288f6)) + * **state:** don't use previous columns ref when getting current cols ([f312c60](https://github.com/ghiscoding/slickgrid-universal/commit/f312c60349d5bc95527ec93cb752f449d1c761f7)) + * **styling:** add ms-select placeholder bg-color to fix Bootstrap 5 ([2c34d12](https://github.com/ghiscoding/slickgrid-universal/commit/2c34d1229c14bd36bd034062cc7eb7a7cbe1bf5c)) + * **styling:** add ms-select placeholder bg-color to fix Bootstrap 5 ([5d6454e](https://github.com/ghiscoding/slickgrid-universal/commit/5d6454e9f175b8694f372a7e26492ae573eb918f)) ### Features * **aggregators:** add better TS typing for all Aggregators ([1518d6a](https://github.com/ghiscoding/slickgrid-universal/commit/1518d6aef194f184390316f8421f51d23a1d470a)) + * **backend:** add cancellable onBeforeSearchChange & revert on error ([b26a53d](https://github.com/ghiscoding/slickgrid-universal/commit/b26a53d2e1fc7172c8c054b9c27ab1b3a2d3dff6)) + * **backend:** add cancellable onBeforeSort & revert sort on error ([958f823](https://github.com/ghiscoding/slickgrid-universal/commit/958f823a6bffedc2c146c7c68d49a29419812995)) + * **backend:** add cancellable Pagination change & revert on error ([7a8d903](https://github.com/ghiscoding/slickgrid-universal/commit/7a8d9038f230ba433f2773c02992a211a322ebd4)) + * **composite:** move SlickGrid Composite Editor factory into universal ([c813cea](https://github.com/ghiscoding/slickgrid-universal/commit/c813ceac1ed6535963df15e7933a444de3a8790a)) + * **editors:** add Ctrl+S combo to enhance LongText (textarea) Editor ([5116bbd](https://github.com/ghiscoding/slickgrid-universal/commit/5116bbd9e837a3bbd9835b10b2167edf3561cd3d)) + * **filters:** option to ignore accent while filtering text, closes [#470](https://github.com/ghiscoding/slickgrid-universal/issues/470) ([cba9a4e](https://github.com/ghiscoding/slickgrid-universal/commit/cba9a4e4d12b6dfaaec06af5edf4c629b2943feb)) + * **sanitize:** make sure any string sent to innerHtml are sanitized ([fe55046](https://github.com/ghiscoding/slickgrid-universal/commit/fe550461d27d01cb5c54d93812db82fa7213f96b)) + * **styling:** only show header menu caret when hovering ([41e7856](https://github.com/ghiscoding/slickgrid-universal/commit/41e7856f9483f7228d1455f2e3810ae58a5f5c8d)) + * **tree:** add `dynamicallyToggledItemState` method to toggle parent(s) ([26369f9](https://github.com/ghiscoding/slickgrid-universal/commit/26369f9b6c9e81ad5705f580896ab28cf362d090)) ## [0.16.2](https://github.com/ghiscoding/slickgrid-universal/compare/v0.16.1...v0.16.2) (2021-07-23) @@ -863,6 +1203,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **formatters:** Complex Object Formatter shouldn't throw with null data ([3421465](https://github.com/ghiscoding/slickgrid-universal/commit/342146557c16b560b5b8ef0f0e47f971179bc765)) + * **tree:** exclude the correct type from interface argument ([af51784](https://github.com/ghiscoding/slickgrid-universal/commit/af51784aa3471dcc88c567f4c3762ab7590184f6)) ## [0.16.1](https://github.com/ghiscoding/slickgrid-universal/compare/v0.16.0...v0.16.1) (2021-07-16) @@ -876,7 +1217,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **filter:** refreshTreeDataFilters only when Tree is enabled ([07c70d5](https://github.com/ghiscoding/slickgrid-universal/commit/07c70d5d17dab464cefb1046c72abbd41da4c834)) + * **filters:** always find locale even without TranslaterService ([c4b17c4](https://github.com/ghiscoding/slickgrid-universal/commit/c4b17c4f51ba6f80b907dab0fd0493a8b0944908)) + * **styling:** remove css variable on width causing UX problem ([df69f9c](https://github.com/ghiscoding/slickgrid-universal/commit/df69f9c33604187f91adaf5bb8b43b6abd624d32)) ### Features @@ -884,7 +1227,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline * **aria:** add aria-label to all Editors/Filters & other html templates ([1a4f8f7](https://github.com/ghiscoding/slickgrid-universal/commit/1a4f8f7873d76b7da5a7d38debed598d3d395c10)) * make constructor arguments as readonly ([a4588ea](https://github.com/ghiscoding/slickgrid-universal/commit/a4588ea5722ae44b647b8c0d02cf8e2a60ff5963)) + * **services:** make everything extendable by using `protected` ([ecbb93a](https://github.com/ghiscoding/slickgrid-universal/commit/ecbb93a56abba39dd050bbd6019b86694495edd1)) + * **styling:** add support for CSS Variables ([674dd1a](https://github.com/ghiscoding/slickgrid-universal/commit/674dd1a064d4d42af1d5841ac87ba8ea35a26b2f)) # [0.15.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.14.1...v0.15.0) (2021-07-06) @@ -892,48 +1237,87 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **addon:** providing columnIndexPosition should always work ([42c8cff](https://github.com/ghiscoding/slickgrid-universal/commit/42c8cff7dd6cf9103149445969be289710549590)) + * **demo:** we should be able to move row(s) and keep selections ([d5669a1](https://github.com/ghiscoding/slickgrid-universal/commit/d5669a1d9c07680540d084dad6e1ef06faca0357)) + * **editors:** longText Editor (textarea) was scrolling to page bottom ([a4e37a0](https://github.com/ghiscoding/slickgrid-universal/commit/a4e37a0baf329a100f72fe12c35af67fa072829a)) + * **editors:** select dropdown value is undefined it shouldn't call save ([015294b](https://github.com/ghiscoding/slickgrid-universal/commit/015294b86e431e8109ce540dda7856b7e9e27575)) + * **filters:** filtering with IN_CONTAINS should also work with spaces ([ab54724](https://github.com/ghiscoding/slickgrid-universal/commit/ab5472437b94fe81270f809ab6fd00f204c688b8)) + * **frozen:** in some occasion column pinning changes column positions ([70cb74e](https://github.com/ghiscoding/slickgrid-universal/commit/70cb74ef1119a60b37d438130d4a463a87a8939a)) + * **menu:** toggle filter bar could be out of sync w/horizontal scroll ([ab7f589](https://github.com/ghiscoding/slickgrid-universal/commit/ab7f58929b10d1b250765b707363aedd9f9d7866)) + * **pagination:** should be able to toggle Pagination ([c0367c2](https://github.com/ghiscoding/slickgrid-universal/commit/c0367c24da2ccb3558e1b27f8e70a81d84201479)) + * **plugin:** row move shouldn't go further when onBefore returns false ([e9bfb5c](https://github.com/ghiscoding/slickgrid-universal/commit/e9bfb5ceba6a18a020b8b34f72abba6e3d13d8b8)) + * **resizer:** few fixes & adjustments after trying in SF ([32e80ec](https://github.com/ghiscoding/slickgrid-universal/commit/32e80ecdbc5072c1619593d101289a3c1ea92b3a)) + * **services:** toggle pagination was not displaying all row selection ([e51ccb4](https://github.com/ghiscoding/slickgrid-universal/commit/e51ccb4352bf3a578159b8b63f0a6caf891c382a)) + * **state:** changeColumnsArrangement should work w/columnIndexPosition ([7c1e9d3](https://github.com/ghiscoding/slickgrid-universal/commit/7c1e9d3d243988d6d99a9696b0afbe8f62ac45b4)) + * **state:** Grid View/Columns dynamically should work w/row move ([a7cf1df](https://github.com/ghiscoding/slickgrid-universal/commit/a7cf1dfb73c770908aadf01fd67680c985449f9d)) + * **state:** Grid View/Columns dynamically should work w/row selection ([865944f](https://github.com/ghiscoding/slickgrid-universal/commit/865944f5d6aadc0c05c7f83db7c11a569a33118f)) + * **styling:** address latest dart-sass math division deprecation warning ([b7317d8](https://github.com/ghiscoding/slickgrid-universal/commit/b7317d8fa619b35fb65789e12b268d65ff65968c)) + * **styling:** header title should show ellipsis if too long ([607e14d](https://github.com/ghiscoding/slickgrid-universal/commit/607e14d7fffa4f9854eff5103e1a1a0881664286)) + * **tree:** using `initiallyCollapsed` change internal toggled state ([380f2f9](https://github.com/ghiscoding/slickgrid-universal/commit/380f2f903d9908e2bed5b3f44d04e28e5d5b9c63)) + * initial grid state should also include toggled presets ([f1fe39f](https://github.com/ghiscoding/slickgrid-universal/commit/f1fe39f5d68487e815be7fd3d7ca5a6fd4cba7c6)) + * **tree:** calling updateItems should not lose the Tree collapsing icon ([45b9622](https://github.com/ghiscoding/slickgrid-universal/commit/45b96225dd5a676b6a85bbb2c8146137eb95b33f)) + * option labels weren't showing correctly after running Cypress tests ([10d4339](https://github.com/ghiscoding/slickgrid-universal/commit/10d4339da70cce4977707a6a19a79cceb4bf87df)) + * provide input type directly in constructor before init() is called ([e89c3bd](https://github.com/ghiscoding/slickgrid-universal/commit/e89c3bd3da66e4b16342cefe1eedd5df96363e45)) ### Features * **components:** extract Custom Footer to be an external component ([1794c27](https://github.com/ghiscoding/slickgrid-universal/commit/1794c27d7669c172f606d709d3360bc5d2f77798)) + * **editors:** convert jQuery to native element on slider editor ([3181cf0](https://github.com/ghiscoding/slickgrid-universal/commit/3181cf069d9f3bc85dc0d13ceeb9623d21ae8eff)) + * **editors:** replace jQuery with native element on date editor ([062f1f9](https://github.com/ghiscoding/slickgrid-universal/commit/062f1f9713c8f236c30b4d631b601b24b56a530d)) + * **editors:** use class inheritance to extend main input editor ([ad3e696](https://github.com/ghiscoding/slickgrid-universal/commit/ad3e6965d4cd4295086401de26b5d3aad13a7650)) + * **filters:** build multiple-select options from native dom elements ([aa548a9](https://github.com/ghiscoding/slickgrid-universal/commit/aa548a9bc05da0d4d5233a2633ae3055fd9f7178)) + * **filters:** convert jQuery to native element on more filters ([b46eb5e](https://github.com/ghiscoding/slickgrid-universal/commit/b46eb5ebdb177e7d0d6c93cb6df541cedc7eb5d1)) + * **filters:** convert jQuery to native elements on multiple filters ([3a80996](https://github.com/ghiscoding/slickgrid-universal/commit/3a80996bec96e465d23a30387af707289f4089e3)) + * **footer:** add option to customize right footer text ([2ea41cc](https://github.com/ghiscoding/slickgrid-universal/commit/2ea41cc8ab38ebc5d5276c90de33b57247c4476f)) + * **formatters:** add Bootstrap Dropdown Formatter ([5ba9423](https://github.com/ghiscoding/slickgrid-universal/commit/5ba9423200e60460c22f05253901707ef7055782)) + * **services:** convert jQuery to native elements ([4da0a20](https://github.com/ghiscoding/slickgrid-universal/commit/4da0a201aaa866447a0c76e3b9c16503e2ed6af9)) + * **services:** decouple the EventPubSubService to separate package ([9f51665](https://github.com/ghiscoding/slickgrid-universal/commit/9f516655e9ce5f06e0cfeabc43536834dc38c70b)) + * **services:** move Resizer Service w/common services folder for reuse ([d127ac7](https://github.com/ghiscoding/slickgrid-universal/commit/d127ac797ee787ea7785e8ae9f4c0bcaed786afd)) + * **styling:** add a new `color-disabled-dark` ([55c3062](https://github.com/ghiscoding/slickgrid-universal/commit/55c30621241ec5da7a2e19879265c4e15a6ad907)) + * **styling:** add a new `color-disabled` ([7151198](https://github.com/ghiscoding/slickgrid-universal/commit/7151198dd393c0bc93151cc4dc9c3295917b6b3e)) + * **styling:** add extra material icons & new color ([4205b66](https://github.com/ghiscoding/slickgrid-universal/commit/4205b664e80af691c72d5520e4778ad4cd7d94b3)) + * **tree:** add `getItemCount` method with optional tree level ([b3f8f94](https://github.com/ghiscoding/slickgrid-universal/commit/b3f8f9484e7ea352b2ed264c6a27e1e091eaf918)) + * **tree:** add Tree Collapse Grid State/Preset ([998b01a](https://github.com/ghiscoding/slickgrid-universal/commit/998b01a2f10ccee5636f616921dd86b35a4feaec)) + * **tree:** add ways to reapply Tree Collapse previous state ([3702ed3](https://github.com/ghiscoding/slickgrid-universal/commit/3702ed32629f84397349147c978ca650043c45eb)) + * add new Input Password Editor which uses common inputEditor ([87e547c](https://github.com/ghiscoding/slickgrid-universal/commit/87e547c0dbccc106a1109c3902ac2027fbd52138)) + * convert jQuery to native element on few more filters ([7d5e1e8](https://github.com/ghiscoding/slickgrid-universal/commit/7d5e1e859a0331699d6fb07d2d35797d7274d1df)) ## [0.14.1](https://github.com/ghiscoding/slickgrid-universal/compare/v0.14.0...v0.14.1) (2021-05-22) @@ -947,37 +1331,65 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **backend:** able to preset filters on hidden columns & all queried ([c610979](https://github.com/ghiscoding/slickgrid-universal/commit/c610979c54170c069b97a71864d95d0363d75e80)) + * **editors:** select editor inline blur save before destroy ([0e591b1](https://github.com/ghiscoding/slickgrid-universal/commit/0e591b1812fc1c733c03f7afcf81dee7a3e4b107)) + * **frozen:** rollback previous commit since the issue was found in SlickGrid (core) ([780bcd7](https://github.com/ghiscoding/slickgrid-universal/commit/780bcd7bfae35e26cd84c9a6d220e2dab9eca3b4)) + * **resizer:** remove delay to call resize by content to avoid flickering ([961efe6](https://github.com/ghiscoding/slickgrid-universal/commit/961efe6fe7ad721e8196c76ed4c35205830b6b83)) + * **services:** fix couple of issues found with custom grid views ([db06736](https://github.com/ghiscoding/slickgrid-universal/commit/db0673688b2b6e6dde8f25af9551bf6c27174a44)) + * **sorting:** multi-column sort shouldn't work when option is disabled ([bfc8651](https://github.com/ghiscoding/slickgrid-universal/commit/bfc865128de0a9e4c21ff0dc8b564c15c88dea93)) + * **styling:** center horizontally checkbox selector in column header ([bb5aebc](https://github.com/ghiscoding/slickgrid-universal/commit/bb5aebc355a22e19b0071bfe993bbeb0e1090265)) + * **tree:** Tree Data export should also include correct indentation ([f1e06c1](https://github.com/ghiscoding/slickgrid-universal/commit/f1e06c11f9eaa9ee778d319bfbaba20bb9abfcc9)) + * add item should work in the demo even with filter preset ([d9c97eb](https://github.com/ghiscoding/slickgrid-universal/commit/d9c97ebb587184e94439f6fde1ec8c8a739e7bfa)) + * add item to flat and/or tree should both work ([1b19028](https://github.com/ghiscoding/slickgrid-universal/commit/1b19028c9d58a31597906e371f439b094bca7ff0)) + * adding optional tree level property should be used when sorting ([a3598c5](https://github.com/ghiscoding/slickgrid-universal/commit/a3598c519a875585498cc828b5a0e76e95890795)) + * addItem from grid service should work with tree data ([8b468f0](https://github.com/ghiscoding/slickgrid-universal/commit/8b468f055144b001378395546519d1801e046a0a)) + * export to file/excel should also have tree indentation ([8c4c2b8](https://github.com/ghiscoding/slickgrid-universal/commit/8c4c2b8d30bb78e927f0a28bb0f7bef81e95d789)) + * Grid Service addItem should invalidate hierarchical dataset itself ([066e894](https://github.com/ghiscoding/slickgrid-universal/commit/066e894271603562b10e014c4febfb18626e54f0)) + * previous commit caused issue with composite editor ([13c2a49](https://github.com/ghiscoding/slickgrid-universal/commit/13c2a49916282c1888ae23c1720a617755341e0f)) + * return all onBeforeX events in delayed promise to fix spinner ([bb36d1a](https://github.com/ghiscoding/slickgrid-universal/commit/bb36d1af114031eb973cf9993bdb9be1dd050de3)) + * **formatters:** Tree Data use nullish coallescing w/optional chaining ([f6cf14c](https://github.com/ghiscoding/slickgrid-universal/commit/f6cf14c06518d47742ee17d82a22a39af490c9e7)) + * **styling:** add a better search filter magnify glass icon as placeholder ([5464824](https://github.com/ghiscoding/slickgrid-universal/commit/5464824f3719ebddb303ee1b82161638d870a288)) + * **tree:** couple of issues found in Tree Data, fixes [#307](https://github.com/ghiscoding/slickgrid-universal/issues/307) ([e684d1a](https://github.com/ghiscoding/slickgrid-universal/commit/e684d1af1c078a8861c3c94fe5486cbe68d57b85)) ### Features * **addon:** provide grid menu labels for all built-in commands ([44c72d3](https://github.com/ghiscoding/slickgrid-universal/commit/44c72d3ca0b8a88e6ae5022a25b11c4d41fd2897)) + * **editors:** add `compositeEditorFormOrder` option ([03f2d66](https://github.com/ghiscoding/slickgrid-universal/commit/03f2d662a69d71edf4b61cdda862fb4eef0f9b47)) + * **editors:** add ways to preload date without closing date picker ([3088038](https://github.com/ghiscoding/slickgrid-universal/commit/30880380584b281c756e0ad437031631e6f607e0)) + * **resizer:** add `resizeByContentOnlyOnFirstLoad` grid option ([ffe7dc4](https://github.com/ghiscoding/slickgrid-universal/commit/ffe7dc4c2a7ae778c8e731fd7637b154c10035f0)) + * **resizer:** add single Column Resize by Content dblClick & headerMenu ([683389f](https://github.com/ghiscoding/slickgrid-universal/commit/683389fcc343ac5c0378a9e34b7f11dda97fc719)) + * **styling:** add new marker material icons for project ([9b386fa](https://github.com/ghiscoding/slickgrid-universal/commit/9b386fa3e6af8e76cf4beb5aa0b5322db2f270af)) + * add `titleFormatter` to Tree Data ([8bf32ca](https://github.com/ghiscoding/slickgrid-universal/commit/8bf32caa08a6c5a28c7114cb8abe33a5ed9bc4cb)) + * add few pubsub events to help with big dataset ([360c62c](https://github.com/ghiscoding/slickgrid-universal/commit/360c62cb0979792dddef8fab39383266c0d855e3)) + * add optional child value prefix to Tree Formatter ([9da9662](https://github.com/ghiscoding/slickgrid-universal/commit/9da966298120686929ab3dd2f276574d7f6c8c7e)) + * **tree:** improve Tree Data speed considerably ([5487798](https://github.com/ghiscoding/slickgrid-universal/commit/548779801d06cc9ae7e319e72d351c8a868ed79f)) + * **editors:** replace jQuery with native elements ([d6e8f4e](https://github.com/ghiscoding/slickgrid-universal/commit/d6e8f4e59823673df290b179d7ee277e3d7bb1af)) # [0.13.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.12.0...v0.13.0) (2021-04-27) @@ -985,20 +1397,31 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **editors:** Composite Editor modal compo should work w/complex objects ([#298](https://github.com/ghiscoding/slickgrid-universal/issues/298)) ([721a6c5](https://github.com/ghiscoding/slickgrid-universal/commit/721a6c5627369cfc89710705384995f8aba3a178)) + * **exports:** grid with colspan should be export accordingly ([#311](https://github.com/ghiscoding/slickgrid-universal/issues/311)) ([e899fbb](https://github.com/ghiscoding/slickgrid-universal/commit/e899fbba3daa41261dcaa57b0555e37e9bdfafb4)) + * **observables:** http cancellable Subject should be unsubscribed ([cbc951b](https://github.com/ghiscoding/slickgrid-universal/commit/cbc951bcf5891658f55981e88887f41b4fb5d5c4)) + * **selection:** full row selection should be selected w/show hidden row ([f76e30c](https://github.com/ghiscoding/slickgrid-universal/commit/f76e30cdca476c947089d88069bd21e42639ba7e)) ### Features * **editors:** add `onBeforeOpen` optional callback to Composite Editor ([#306](https://github.com/ghiscoding/slickgrid-universal/issues/306)) ([a642482](https://github.com/ghiscoding/slickgrid-universal/commit/a642482254009115366ca4992e2e60647f8ae9b0)) + * **editors:** add `target` to `onBeforeEditCell` w/called by composite ([#301](https://github.com/ghiscoding/slickgrid-universal/issues/301)) ([7440ff5](https://github.com/ghiscoding/slickgrid-universal/commit/7440ff58988acd7abd1ce249b1ceb72556cceb1d)) + * **filters:** add option to filter empty values for select filter ([#310](https://github.com/ghiscoding/slickgrid-universal/issues/310)) ([c58a92a](https://github.com/ghiscoding/slickgrid-universal/commit/c58a92a8e2b29ea216211e3561d5567c43f0376a)) + * **filters:** option to add custom compound operator list ([3e8d2cb](https://github.com/ghiscoding/slickgrid-universal/commit/3e8d2cbcea6181e3ce3157798f003a8479d11011)) + * **footer:** add row selection count to the footer component ([8ba146c](https://github.com/ghiscoding/slickgrid-universal/commit/8ba146cd4cbdccdb61f3441918065fad4561ff84)) + * **resize:** add column resize by cell content ([#309](https://github.com/ghiscoding/slickgrid-universal/issues/309)) ([515a072](https://github.com/ghiscoding/slickgrid-universal/commit/515a072b3a16d3aca0f48e62c968ae89a1510669)) + * **services:** remove deprecated hideColumnByIndex form Grid Service ([#312](https://github.com/ghiscoding/slickgrid-universal/issues/312)) ([b00c64d](https://github.com/ghiscoding/slickgrid-universal/commit/b00c64d8f88d4560c677f667a84d95ba30e96399)) + * **styling:** switch from node-sass to dart-sass (sass) ([81f8d9f](https://github.com/ghiscoding/slickgrid-universal/commit/81f8d9fbd1381b4c877eeeb4992bdcc90c1cd677)) + * **typing:** add missing item metadata interface ([#299](https://github.com/ghiscoding/slickgrid-universal/issues/299)) ([7cf0a21](https://github.com/ghiscoding/slickgrid-universal/commit/7cf0a2185c73dcb7748a193ba2272bb7af699266)) # [0.12.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.11.2...v0.12.0) (2021-03-24) @@ -1006,26 +1429,43 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **editors:** show all editors as 100% height in their cell container ([#277](https://github.com/ghiscoding/slickgrid-universal/issues/277)) ([3f49aea](https://github.com/ghiscoding/slickgrid-universal/commit/3f49aeabd6016c705d4d6b809345fe1ac948cfc5)) + * **filters:** rollback a change made in PR [#288](https://github.com/ghiscoding/slickgrid-universal/issues/288) causing preset issues ([18ffc0c](https://github.com/ghiscoding/slickgrid-universal/commit/18ffc0c8285e4e2306bc60817fba357734a65b61)) + * **filters:** SearchTerms shouldn't come back after calling clearFilters ([04f3d12](https://github.com/ghiscoding/slickgrid-universal/commit/04f3d1267de493b9dc1e922dca3b433b9cb34fde)) + * **filters:** string <> should be Not Contains instead of Not Equal ([#276](https://github.com/ghiscoding/slickgrid-universal/issues/276)) ([960884d](https://github.com/ghiscoding/slickgrid-universal/commit/960884ddf58b1e87ad5ef71e3713f8836e6190c0)) + * **firefox:** add all missing SVG color filter classes for Firefox/SF ([#296](https://github.com/ghiscoding/slickgrid-universal/issues/296)) ([a07ebdf](https://github.com/ghiscoding/slickgrid-universal/commit/a07ebdfbd2c2197c28102efe1f4a685ea61185e1)) + * **pinning:** reordering cols position freezing cols shouldn't affect ([#275](https://github.com/ghiscoding/slickgrid-universal/issues/275)) ([a30665d](https://github.com/ghiscoding/slickgrid-universal/commit/a30665d54da583c47b1f533002173af99e9ab20d)) + * **plugin:** Grid Menu Clear Frozen Cols shouldn't change cols positions ([#291](https://github.com/ghiscoding/slickgrid-universal/issues/291)) ([4fdab08](https://github.com/ghiscoding/slickgrid-universal/commit/4fdab08357d12349b6402e3007f4ab399d9a2140)) + * **presets:** Filter & Sorting presets & Footer metrics issues ([#285](https://github.com/ghiscoding/slickgrid-universal/issues/285)) ([3174c86](https://github.com/ghiscoding/slickgrid-universal/commit/3174c86e011b4927510b99a348e8019adb4baa00)) + * **presets:** Multiple Select Filter Grid Presets values should be shown ([dd1f231](https://github.com/ghiscoding/slickgrid-universal/commit/dd1f231850819bde455e24d743b9e1637767ecb3)) + * **resizer:** allow gridHeight/gridWidth to be passed as string ([#284](https://github.com/ghiscoding/slickgrid-universal/issues/284)) ([20bda50](https://github.com/ghiscoding/slickgrid-universal/commit/20bda50bf3ab647ae4ee3d7ffe0c9c8b58e8f187)), closes [#534](https://github.com/ghiscoding/slickgrid-universal/issues/534) + * **sorting:** add some unit tests that were previously commented out ([#290](https://github.com/ghiscoding/slickgrid-universal/issues/290)) ([2a91fa6](https://github.com/ghiscoding/slickgrid-universal/commit/2a91fa6f672650bb525a4ba1774d02c5ac435c5b)) ### Features * **editors:** add `onSelect` callback to Autocomplete Editor ([#286](https://github.com/ghiscoding/slickgrid-universal/issues/286)) ([2d106d4](https://github.com/ghiscoding/slickgrid-universal/commit/2d106d4df0a259d36bee3d910320706ddb7e8580)) + * **filters:** add new IN_COLLECTION operator to allow searching cell value as Array ([#282](https://github.com/ghiscoding/slickgrid-universal/issues/282)) ([ecce93c](https://github.com/ghiscoding/slickgrid-universal/commit/ecce93c92b7424522ad2af0d7d82963a3a56ca97)) + * **filters:** add optional `filterTypingDebounce` for filters w/keyup ([#289](https://github.com/ghiscoding/slickgrid-universal/issues/289)) ([3aecc89](https://github.com/ghiscoding/slickgrid-universal/commit/3aecc899ebd78d9597cc4ed4919c0a8dd26673a8)) + * **filters:** add optional `filterTypingDebounce` for keyboard filters ([#283](https://github.com/ghiscoding/slickgrid-universal/issues/283)) ([bb7dcd3](https://github.com/ghiscoding/slickgrid-universal/commit/bb7dcd3a9e28f45c7339e2f30685220b7a152507)) + * **filters:** add possibility to filter by text range like "a..e" ([#279](https://github.com/ghiscoding/slickgrid-universal/issues/279)) ([e44145d](https://github.com/ghiscoding/slickgrid-universal/commit/e44145d897da570bf6ea15b156c7961ce96ce6f0)) + * **filters:** display operator into input text filter from Grid Presets ([#288](https://github.com/ghiscoding/slickgrid-universal/issues/288)) ([3fad4fe](https://github.com/ghiscoding/slickgrid-universal/commit/3fad4fe9ef3bec290dabb860d7ea4baf8f182a4a)) + * **resources:** add RxJS support into Slickgrid-Universal via external package ([#280](https://github.com/ghiscoding/slickgrid-universal/issues/280)) ([c10fc33](https://github.com/ghiscoding/slickgrid-universal/commit/c10fc339019c04ec0f7c4357ccdb3949a2358460)) + * **state:** add Pinning (frozen) to Grid State & Presets ([#292](https://github.com/ghiscoding/slickgrid-universal/issues/292)) ([ba703d8](https://github.com/ghiscoding/slickgrid-universal/commit/ba703d8353a243ffed4d40804c0f977119424f6c)) ## [0.11.2](https://github.com/ghiscoding/slickgrid-universal/compare/v0.11.1...v0.11.2) (2021-02-27) @@ -1045,19 +1485,29 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **build:** enable tsconfig strict mode tsconfig ([#269](https://github.com/ghiscoding/slickgrid-universal/issues/269)) ([095fc71](https://github.com/ghiscoding/slickgrid-universal/commit/095fc71052c1f4e776544781da5fe762cfa16238)) + * **filters:** don't use indexOf NOT_IN_CONTAINS ([#262](https://github.com/ghiscoding/slickgrid-universal/issues/262)) ([310be30](https://github.com/ghiscoding/slickgrid-universal/commit/310be30efb653151a75dde0a14b1ed3f9946b333)) + * **filters:** use defaultFilterOperator in range when none provided ([#271](https://github.com/ghiscoding/slickgrid-universal/issues/271)) ([993675f](https://github.com/ghiscoding/slickgrid-universal/commit/993675f6b0d76e76010d5cadc6696134a73dad66)) + * **helpers:** should be able to highlight first row (0) ([#268](https://github.com/ghiscoding/slickgrid-universal/issues/268)) ([a58be17](https://github.com/ghiscoding/slickgrid-universal/commit/a58be17959e28ab9a1280c3d7d7c8df9db02587e)), closes [#527](https://github.com/ghiscoding/slickgrid-universal/issues/527) + * **plugin:** recreate header menu when adding column dynamically ([#257](https://github.com/ghiscoding/slickgrid-universal/issues/257)) ([16c4984](https://github.com/ghiscoding/slickgrid-universal/commit/16c49845c5d3388502811c15f0a23daa1a01f850)) ### Features * **demo:** add Example 13 Header Button Plugin ([f345cd1](https://github.com/ghiscoding/slickgrid-universal/commit/f345cd18b89f849f3f873538c214d3ac24ff12f8)) + * **editors:** add a Clear (X) button to the Autocomplete Editor ([#270](https://github.com/ghiscoding/slickgrid-universal/issues/270)) ([ffbd188](https://github.com/ghiscoding/slickgrid-universal/commit/ffbd188534992c31848691154517deb64694f3b2)) + * **filters:** add updateSingleFilter for a single external filter ([#265](https://github.com/ghiscoding/slickgrid-universal/issues/265)) ([20564a3](https://github.com/ghiscoding/slickgrid-universal/commit/20564a3096948626beada698460b72374a18ca7c)) + * **perf:** huge filtering speed improvements ([a101ed1](https://github.com/ghiscoding/slickgrid-universal/commit/a101ed1b62c2fbfec2712f64e08192a4852bce9d)) + * **perf:** improve date sorting speed ([258da22](https://github.com/ghiscoding/slickgrid-universal/commit/258da2238bba3693eada058f9405012f68af150b)) + * **perf:** improve date sorting speed ([#259](https://github.com/ghiscoding/slickgrid-universal/issues/259)) ([a52f4fc](https://github.com/ghiscoding/slickgrid-universal/commit/a52f4fcee1627ac5906388f8dcf4b7fe3f5c4aa7)) + * **services:** add bulk transactions in Grid Service CRUD methods ([#256](https://github.com/ghiscoding/slickgrid-universal/issues/256)) ([03385d9](https://github.com/ghiscoding/slickgrid-universal/commit/03385d9ac58cb3ce7501a409394706c0cb4f4d29)) ## [0.10.2](https://github.com/ghiscoding/slickgrid-universal/compare/v0.10.1...v0.10.2) (2021-01-28) @@ -1077,20 +1527,31 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** fix types index.d.ts url ([a76b3a3](https://github.com/ghiscoding/slickgrid-universal/commit/a76b3a3d97a6d211ec2e7e8d9060fd8dd0719f58)) + * **editors:** add blank disabled fields in Composite Editor form values ([#233](https://github.com/ghiscoding/slickgrid-universal/issues/233)) ([b634902](https://github.com/ghiscoding/slickgrid-universal/commit/b6349029b705991b7ac2d1df99f5b330fe69ef36)) + * **editors:** fix clear date & blank disabled field w/Composite Editor ([#235](https://github.com/ghiscoding/slickgrid-universal/issues/235)) ([9aac97d](https://github.com/ghiscoding/slickgrid-universal/commit/9aac97d2d433c809facc8d7092467780d55ca01a)) + * **filters:** Grid State filters should always include an operator ([#238](https://github.com/ghiscoding/slickgrid-universal/issues/238)) ([f64ed37](https://github.com/ghiscoding/slickgrid-universal/commit/f64ed37f7ffe01346c8f68d4bd170ffdce54839d)) + * **frozen:** hiding multiple columns when using pinning gets out of sync ([#243](https://github.com/ghiscoding/slickgrid-universal/issues/243)) ([b255220](https://github.com/ghiscoding/slickgrid-universal/commit/b255220ec37dbdc9df4f3ecccb4397656cf9f2a6)) + * **lint:** add eslint as a pre task when bundling & fix linting errors ([#246](https://github.com/ghiscoding/slickgrid-universal/issues/246)) ([6f7ccd8](https://github.com/ghiscoding/slickgrid-universal/commit/6f7ccd8ee4cc5e005034965a2c2dcc0499f06a73)) + * **pinning:** recalculate frozen idx properly when column shown changes ([#241](https://github.com/ghiscoding/slickgrid-universal/issues/241)) ([3b55972](https://github.com/ghiscoding/slickgrid-universal/commit/3b559726acdff96970c68c10c8d256d0403d6c4f)) + * **plugins:** add missing Row Detail filtering code ([#239](https://github.com/ghiscoding/slickgrid-universal/issues/239)) ([d9cad63](https://github.com/ghiscoding/slickgrid-universal/commit/d9cad635840650d2b2dd91444ffa0121147f4140)) ### Features * **editors:** add Clone functionality to Composite Editor ([#236](https://github.com/ghiscoding/slickgrid-universal/issues/236)) ([df545e4](https://github.com/ghiscoding/slickgrid-universal/commit/df545e4ec64271307b1979feb5e786f449433639)) + * **editors:** change all private keyword to protected for extensability ([#247](https://github.com/ghiscoding/slickgrid-universal/issues/247)) ([089b6cb](https://github.com/ghiscoding/slickgrid-universal/commit/089b6cbbdd6284d94f765fdad08642e0d0d81ff0)) + * **filters:** change all private keyword to protected for extensability ([#245](https://github.com/ghiscoding/slickgrid-universal/issues/245)) ([52cc702](https://github.com/ghiscoding/slickgrid-universal/commit/52cc7022c4b847566d89e91a80c423373538a15a)) + * **formatters:** add grid option to auto add custom editor formatter ([#248](https://github.com/ghiscoding/slickgrid-universal/issues/248)) ([db77d46](https://github.com/ghiscoding/slickgrid-universal/commit/db77d464ee37eda573351e89d4c5acc9b5648649)) + * add nameCompositeEditor override to be used by Composite Editor ([fcdb2e9](https://github.com/ghiscoding/slickgrid-universal/commit/fcdb2e92ed736b09e947cdbcf39ee157afc4acab)) # [0.9.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.8.0...v0.9.0) (2021-01-06) @@ -1102,8 +1563,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **build:** upgrade to WebPack 5 ([#225](https://github.com/ghiscoding/slickgrid-universal/issues/225)) ([c6b3ad3](https://github.com/ghiscoding/slickgrid-universal/commit/c6b3ad3eb6fb64306bfd8bd300fcc1e86b27e5a6)) + * **ci:** replace CircleCI with GitHub Actions ([#211](https://github.com/ghiscoding/slickgrid-universal/issues/211)) ([4f91140](https://github.com/ghiscoding/slickgrid-universal/commit/4f9114031ca6236ef45f04b67dcba1a9981035c4)) + * **editors:** add Column Editor collectionOverride option ([#228](https://github.com/ghiscoding/slickgrid-universal/issues/228)) ([91421fc](https://github.com/ghiscoding/slickgrid-universal/commit/91421fc0154e432874fb2211e430a79032b996b8)) + * **styling:** add support for Bootstrap 5 ([#226](https://github.com/ghiscoding/slickgrid-universal/issues/226)) ([e35f116](https://github.com/ghiscoding/slickgrid-universal/commit/e35f116efc1989f675ef6e030d80a8a31a444373)) # [0.8.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.7.7...v0.8.0) (2020-12-22) @@ -1111,6 +1575,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** change moment/lodash imports so it works with ES6 module ([#210](https://github.com/ghiscoding/slickgrid-universal/issues/210)) ([2d25d3b](https://github.com/ghiscoding/slickgrid-universal/commit/2d25d3b99f7be93f2bc69f006fb67a39cf39ce7c)) + * **core:** use regular imports instead of require to load plugins ([#209](https://github.com/ghiscoding/slickgrid-universal/issues/209)) ([6816696](https://github.com/ghiscoding/slickgrid-universal/commit/6816696c98be0d2dd80c1ff49358bd49ee7caacb)) ### Features @@ -1138,6 +1603,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **editors:** fix BS3,BS4 styles & slider value not shown with undefined ([#204](https://github.com/ghiscoding/slickgrid-universal/issues/204)) ([3aca8f9](https://github.com/ghiscoding/slickgrid-universal/commit/3aca8f9053365c1987f6c5abc43f8ce5eca015fb)) + * **exports:** should be able to change export file name ([#205](https://github.com/ghiscoding/slickgrid-universal/issues/205)) ([9d26213](https://github.com/ghiscoding/slickgrid-universal/commit/9d262134b12da46ef1fea970f092d96ce875ed78)) ## [0.7.2](https://github.com/ghiscoding/slickgrid-universal/compare/v0.7.1...v0.7.2) (2020-12-17) @@ -1145,7 +1611,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** range default should be inclusive instead of exclusive ([#203](https://github.com/ghiscoding/slickgrid-universal/issues/203)) ([b7f74ad](https://github.com/ghiscoding/slickgrid-universal/commit/b7f74ad8a1539aed32ac643b4fe395fbdecf4459)) + * **sorting:** add cellValueCouldBeUndefined in grid option for sorting ([#202](https://github.com/ghiscoding/slickgrid-universal/issues/202)) ([865256e](https://github.com/ghiscoding/slickgrid-universal/commit/865256efe927a5715840963cb2945f16a402789b)) + * **stylings:** small alignment issue with the slider value elm height ([5a453b8](https://github.com/ghiscoding/slickgrid-universal/commit/5a453b8739c07e07f835e111d7d3ca5d627a0c2f)) ## [0.7.1](https://github.com/ghiscoding/slickgrid-universal/compare/v0.7.0...v0.7.1) (2020-12-17) @@ -1167,13 +1635,17 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** add console error if any of column def id includes dot ([#198](https://github.com/ghiscoding/slickgrid-universal/issues/198)) ([6ee40af](https://github.com/ghiscoding/slickgrid-universal/commit/6ee40af507b066602c39e057349b5ead6e7952f3)) + * **stylings:** composite editor styling fixes for BS4 ([#195](https://github.com/ghiscoding/slickgrid-universal/issues/195)) ([305eb90](https://github.com/ghiscoding/slickgrid-universal/commit/305eb90c75e6a4aa076c62b5364b904dc5c6518e)) + * **stylings:** re-align the svg icons & single/multiple-select icon+text ([#194](https://github.com/ghiscoding/slickgrid-universal/issues/194)) ([b730be7](https://github.com/ghiscoding/slickgrid-universal/commit/b730be7a75b3035c01aa7ca8f48a88df447ad461)) ### Features * **core:** add registerExternalResources for Components/Services ([#196](https://github.com/ghiscoding/slickgrid-universal/issues/196)) ([ee02f1d](https://github.com/ghiscoding/slickgrid-universal/commit/ee02f1d62d1a0601421352e43d17bd8c89e4348c)) + * **core:** refactor code using the container service everywhere ([#197](https://github.com/ghiscoding/slickgrid-universal/issues/197)) ([96ce9bd](https://github.com/ghiscoding/slickgrid-universal/commit/96ce9bdbf18330e522dad0cbb0eda09c41f6a3df)) + * **formatters:** add numberPrefix & Suffix to Decimal Formatter ([#193](https://github.com/ghiscoding/slickgrid-universal/issues/193)) ([0e4d30c](https://github.com/ghiscoding/slickgrid-universal/commit/0e4d30c0ee23bc598206fbba4e5ed406e4aeecfe)) ## [0.5.1](https://github.com/ghiscoding/slickgrid-universal/compare/v0.5.0...v0.5.1) (2020-12-10) @@ -1185,8 +1657,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **editors:** make sure select editor is defined before reading a prop ([763f981](https://github.com/ghiscoding/slickgrid-universal/commit/763f98111d03652b0ad903ba487a3b8c83a5ef5d)) + * **editors:** only translate button texts when enableTranslate is true ([b698c6b](https://github.com/ghiscoding/slickgrid-universal/commit/b698c6bd3f13af017c7f3c0113b8407269ba1e0d)) + * **editors:** Select Editor option to return flat data w/complex object ([#189](https://github.com/ghiscoding/slickgrid-universal/issues/189)) ([4695cd3](https://github.com/ghiscoding/slickgrid-universal/commit/4695cd3b6871dc1ceca4036fd30935eca8011b7e)) + * **exports:** when cell value is empty object return empty string ([#190](https://github.com/ghiscoding/slickgrid-universal/issues/190)) ([cd34901](https://github.com/ghiscoding/slickgrid-universal/commit/cd349012c82a8bdff113fb9f8ef23ea18c6e3035)) ### Features @@ -1208,6 +1683,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** properly export Enums, Interfaces, Services & Utilities ([#184](https://github.com/ghiscoding/slickgrid-universal/issues/184)) ([0c23398](https://github.com/ghiscoding/slickgrid-universal/commit/0c233984a6e9d718659c119b65a95d6c38d36b0c)) + * **core:** showing/hiding column shouldn't affect its freezing position ([#185](https://github.com/ghiscoding/slickgrid-universal/issues/185)) ([2a812ed](https://github.com/ghiscoding/slickgrid-universal/commit/2a812edb82c8004ab43df224c67ede228ab72c00)) ### Features @@ -1219,9 +1695,13 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** don't expose src folder on npm & update few npm package ([#168](https://github.com/ghiscoding/slickgrid-universal/issues/168)) ([3c05938](https://github.com/ghiscoding/slickgrid-universal/commit/3c059381b35bba88ea98d0206692c912c625f227)) + * **core:** rename i18n to translater & fix few other issues ([#174](https://github.com/ghiscoding/slickgrid-universal/issues/174)) ([34c963a](https://github.com/ghiscoding/slickgrid-universal/commit/34c963a2bcef1b841d3c62ea405a4bc49be98a5c)) + * **editors:** make sure editor element exist before focusing ([e57235b](https://github.com/ghiscoding/slickgrid-universal/commit/e57235b4339ffa1bee522c245665bb598d963fd1)) + * **extensions:** draggable grouping style change to look better ([#171](https://github.com/ghiscoding/slickgrid-universal/issues/171)) ([d00be88](https://github.com/ghiscoding/slickgrid-universal/commit/d00be8868370f3679555b8f52ef4ad85916c93ac)) + * **formatters:** date formatters should accept ISO input & output to US ([#172](https://github.com/ghiscoding/slickgrid-universal/issues/172)) ([85ce7cf](https://github.com/ghiscoding/slickgrid-universal/commit/85ce7cf3636d5bb43d3ef18ec6998bb0c423d218)) ## [0.2.13](https://github.com/ghiscoding/slickgrid-universal/compare/@slickgrid-universal/common@0.2.12...@slickgrid-universal/common@0.2.13) (2020-11-26) @@ -1281,6 +1761,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** don't expose src folder on npm & update few npm package ([#168](https://github.com/ghiscoding/slickgrid-universal/issues/168)) ([3c05938](https://github.com/ghiscoding/slickgrid-universal/commit/3c059381b35bba88ea98d0206692c912c625f227)) + * **editors:** make sure editor element exist before focusing ([e57235b](https://github.com/ghiscoding/slickgrid-universal/commit/e57235b4339ffa1bee522c245665bb598d963fd1)) # [0.2.0](https://github.com/ghiscoding/slickgrid-universal/compare/@slickgrid-universal/common@0.1.0...@slickgrid-universal/common@0.2.0) (2020-11-20) @@ -1288,48 +1769,87 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** clear dataset when disposing and fix few unsubscribed events to avoid leak ([#156](https://github.com/ghiscoding/slickgrid-universal/issues/156)) ([78c80b4](https://github.com/ghiscoding/slickgrid-universal/commit/78c80b43ca04fd4fff68791556f9d4ab37f06caa)) + * **core:** empty warning message should work with multiple grids ([#158](https://github.com/ghiscoding/slickgrid-universal/issues/158)) ([9e7c023](https://github.com/ghiscoding/slickgrid-universal/commit/9e7c023f7d33313400f4e55ddffd838d290b83dd)) + * **core:** fix some problems found with AutoComplete ([#74](https://github.com/ghiscoding/slickgrid-universal/issues/74)) ([00fb478](https://github.com/ghiscoding/slickgrid-universal/commit/00fb478263db832ec31d940ed19417d9fcbae04a)) + * **core:** Flatpickr is not destroyed properly & leaks detached elements ([#154](https://github.com/ghiscoding/slickgrid-universal/issues/154)) ([9633d4a](https://github.com/ghiscoding/slickgrid-universal/commit/9633d4a090c23ff4792cb614360afc58e76d74c3)) + * **core:** header columns grouping misbehave after hiding column ([#164](https://github.com/ghiscoding/slickgrid-universal/issues/164)) ([6b8232b](https://github.com/ghiscoding/slickgrid-universal/commit/6b8232b3b98d1b75412bebd6b4528ee5dea71d7a)) + * **core:** mem leaks w/orphan DOM elements when disposing ([#153](https://github.com/ghiscoding/slickgrid-universal/issues/153)) ([faba5a6](https://github.com/ghiscoding/slickgrid-universal/commit/faba5a6652fa2cf5e78f64b6b2e27bf9b85936ba)) + * **core:** properly remove event listeners when disposing ([#163](https://github.com/ghiscoding/slickgrid-universal/issues/163)) ([ecfb9a7](https://github.com/ghiscoding/slickgrid-universal/commit/ecfb9a7c623010504a7a2d312ffef185f16cec9e)) + * **editor:** SingleSelect Editor should show pick false value ([#75](https://github.com/ghiscoding/slickgrid-universal/issues/75)) ([fdb2c84](https://github.com/ghiscoding/slickgrid-universal/commit/fdb2c8433d443dd8f4fdd86f714354424cfb9ea3)) + * **editors:** autocomplete editor spinner aligned right in mass update ([#162](https://github.com/ghiscoding/slickgrid-universal/issues/162)) ([6ae5189](https://github.com/ghiscoding/slickgrid-universal/commit/6ae51897979d80f5639fb095406e83e182649252)) + * **filters:** disregard time when filtering date only format ([#134](https://github.com/ghiscoding/slickgrid-universal/issues/134)) ([7bd2d19](https://github.com/ghiscoding/slickgrid-universal/commit/7bd2d1964de2e809d8b08c737231eec31d146fae)) + * **pinning:** put back vertical scroll on grid after removing freezing ([75a47a6](https://github.com/ghiscoding/slickgrid-universal/commit/75a47a607d463854c1b51fe5a330d629c79ac2e2)) + * **select:** make a collection array copy to avoid change by ref ([#135](https://github.com/ghiscoding/slickgrid-universal/issues/135)) ([3237133](https://github.com/ghiscoding/slickgrid-universal/commit/323713382f1565ff8617ede08fdc8ed31ac3a594)) + * **styling:** support other unit of measure in SASS ([5b9adec](https://github.com/ghiscoding/slickgrid-universal/commit/5b9adec6d11230a870337f1adaac1b0f9e157438)) + * **styling:** SVG icon colors aren't showing up in SF with Firefox ([#131](https://github.com/ghiscoding/slickgrid-universal/issues/131)) ([2ed3cf5](https://github.com/ghiscoding/slickgrid-universal/commit/2ed3cf50358139374d4deeaedb5a8fdb7db27b98)) + * **translations:** HeaderMenu & Date Filters not translating ([#58](https://github.com/ghiscoding/slickgrid-universal/issues/58)) ([9416c4d](https://github.com/ghiscoding/slickgrid-universal/commit/9416c4d2642894c5660473419623cee9bebcac4b)) ### Features * **autocomplete:** add much more functionalities to the AutoComplete ([#69](https://github.com/ghiscoding/slickgrid-universal/issues/69)) ([93c3d0a](https://github.com/ghiscoding/slickgrid-universal/commit/93c3d0a9b8d5a30c7a933f95a4333937c95305a3)) + * **core:** add "Empty Data" warning message when grid is empty ([#155](https://github.com/ghiscoding/slickgrid-universal/issues/155)) ([13875b4](https://github.com/ghiscoding/slickgrid-universal/commit/13875b455d60f44918d8524aa803374773276e90)) + * **core:** add custom entry to Select Editor/Filter collections ([#133](https://github.com/ghiscoding/slickgrid-universal/issues/133)) ([66effcf](https://github.com/ghiscoding/slickgrid-universal/commit/66effcfddd8b5a9d78a1d1ab679ca2721067e4be)) + * **core:** add ESLint npm script and add to prebuild script ([#151](https://github.com/ghiscoding/slickgrid-universal/issues/151)) ([4064876](https://github.com/ghiscoding/slickgrid-universal/commit/40648760a33628f0ba85653f5fc99d8250b9a7a2)) + * **core:** add loading spinner to AutoComplete Editor/Filter ([#65](https://github.com/ghiscoding/slickgrid-universal/issues/65)) ([4ecd2bd](https://github.com/ghiscoding/slickgrid-universal/commit/4ecd2bd305f2fd2b509e48cf1c7166b666228be3)) + * **core:** rewrite "Empty Data" warning component to be in the canvas ([#157](https://github.com/ghiscoding/slickgrid-universal/issues/157)) ([78e2132](https://github.com/ghiscoding/slickgrid-universal/commit/78e213222d6058e1d1d768094801be42dbf4fb05)) + * **core:** update few npm packages ([#123](https://github.com/ghiscoding/slickgrid-universal/issues/123)) ([1c25b87](https://github.com/ghiscoding/slickgrid-universal/commit/1c25b87fdd738616879298baeb52074e30e9bf14)) + * **core:** update lib to latest jQuery version 3.5.1 ([#56](https://github.com/ghiscoding/slickgrid-universal/issues/56)) ([1af66d5](https://github.com/ghiscoding/slickgrid-universal/commit/1af66d5142bb5bc17cc84c819f9f273874af285c)), closes [#42](https://github.com/ghiscoding/slickgrid-universal/issues/42) + * **core:** update to latest SlickGrid version and update npm packages ([#140](https://github.com/ghiscoding/slickgrid-universal/issues/140)) ([d73a44e](https://github.com/ghiscoding/slickgrid-universal/commit/d73a44e338025da45e990a8a522fb0b9aa1c5279)) + * **core:** use barel export everywhere ([#57](https://github.com/ghiscoding/slickgrid-universal/issues/57)) ([d068fc5](https://github.com/ghiscoding/slickgrid-universal/commit/d068fc577566a44217f543f7486be0cc4edc5f69)) + * **editor:** add Composite Editor modal dialog ([#76](https://github.com/ghiscoding/slickgrid-universal/issues/76)) ([bba0b80](https://github.com/ghiscoding/slickgrid-universal/commit/bba0b804301195a166f87be610ee85fe77d4a134)) + * **editors:** add changeEditorOption to all Editors which supports it ([#142](https://github.com/ghiscoding/slickgrid-universal/issues/142)) ([97b1003](https://github.com/ghiscoding/slickgrid-universal/commit/97b1003f80a72859ae9fc4b4a0ade12e8ec373a5)) + * **editors:** add way to change or disable Composite Editor form input ([#139](https://github.com/ghiscoding/slickgrid-universal/issues/139)) ([2a5280f](https://github.com/ghiscoding/slickgrid-universal/commit/2a5280f216b2929c018f4019169db039361f2985)) + * **editors:** disable editor when collectionAsync, re-enable after ([#132](https://github.com/ghiscoding/slickgrid-universal/issues/132)) ([75b10de](https://github.com/ghiscoding/slickgrid-universal/commit/75b10de91adecfaab6627e677abe7f5ce91d8769)) + * **examples:** add mass update feat to Example 11 ([#31](https://github.com/ghiscoding/slickgrid-universal/issues/31)) ([84e9817](https://github.com/ghiscoding/slickgrid-universal/commit/84e98175686160dfc243435496ac65a757ec30aa)) + * **filters:** add Pre-Defined & Custom Filters saved in Local Storage ([#143](https://github.com/ghiscoding/slickgrid-universal/issues/143)) ([dea71ab](https://github.com/ghiscoding/slickgrid-universal/commit/dea71ababb4b06520b06f7e12f4acbd86051110a)) + * **formatters:** add AlignRight Formatter & alias AlignCenter=>Center ([#161](https://github.com/ghiscoding/slickgrid-universal/issues/161)) ([831580d](https://github.com/ghiscoding/slickgrid-universal/commit/831580d5234114d9510a578a71f608cbb3eda3ec)) + * **icons:** add more Material icons ([9f9377b](https://github.com/ghiscoding/slickgrid-universal/commit/9f9377b2768c0ad6c091731be36125ea73e2ad46)) + * **icons:** add some more material icons ([#124](https://github.com/ghiscoding/slickgrid-universal/issues/124)) ([b90fe2d](https://github.com/ghiscoding/slickgrid-universal/commit/b90fe2d231c1005ad137a7f0fbae8f6fb928cb79)) + * **plugins:** add "hidden" to all controls/plugins with menu items ([#128](https://github.com/ghiscoding/slickgrid-universal/issues/128)) ([99202de](https://github.com/ghiscoding/slickgrid-universal/commit/99202deb7b452b7ac8d67d4b98545901cf99005e)) + * **services:** add 2x new methods hideColumnById or ..byIds ([#160](https://github.com/ghiscoding/slickgrid-universal/issues/160)) ([d396653](https://github.com/ghiscoding/slickgrid-universal/commit/d3966530fab48ee72fab138b8caf97c4eb73ec91)) + * **services:** add Toggle Filtering/Sorting & Hide Column methods ([#126](https://github.com/ghiscoding/slickgrid-universal/issues/126)) ([08fe2e1](https://github.com/ghiscoding/slickgrid-universal/commit/08fe2e19c5778941050e42ca207d55dc27564ba8)) + * **styling:** add frozen on all possible elements with SASS variables ([#138](https://github.com/ghiscoding/slickgrid-universal/issues/138)) ([c61da91](https://github.com/ghiscoding/slickgrid-universal/commit/c61da911c449949570f54343724bc80523f77bcb)), closes [#537](https://github.com/ghiscoding/slickgrid-universal/issues/537) + * **styling:** add Pagination button height sass variable ([#136](https://github.com/ghiscoding/slickgrid-universal/issues/136)) ([43deeee](https://github.com/ghiscoding/slickgrid-universal/commit/43deeee99aee1887a62ec4238f68dce9e37fca69)) + * **styling:** find way to add colors to SVGs used by the lib ([#73](https://github.com/ghiscoding/slickgrid-universal/issues/73)) ([8a07c16](https://github.com/ghiscoding/slickgrid-universal/commit/8a07c16ec3238533ab16fb22f8b748168cd5f18c)) + * **tests:** add more Cypress E2E tests for grouping ([#125](https://github.com/ghiscoding/slickgrid-universal/issues/125)) ([814dec0](https://github.com/ghiscoding/slickgrid-universal/commit/814dec0dbad7cf59e98654a732dbf6d46de37a1a)) # [0.1.0](https://github.com/ghiscoding/slickgrid-universal/compare/@slickgrid-universal/common@0.0.2...@slickgrid-universal/common@0.1.0) (2020-07-28) @@ -1337,108 +1857,209 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **build:** vscode chrome debugger + webpack prod build should both work ([e148090](https://github.com/ghiscoding/slickgrid-universal/commit/e148090b967119c911c5da2fc7cb2cfdf4c3de39)) + * **components:** add "cssText" option to both Footer/Pagination ([abd4fcd](https://github.com/ghiscoding/slickgrid-universal/commit/abd4fcd6ea6c990e1192afaca450dd6b7847e590)) + * **components:** both Footer/Pagination should always be 100% width ([#27](https://github.com/ghiscoding/slickgrid-universal/issues/27)) ([e587ef5](https://github.com/ghiscoding/slickgrid-universal/commit/e587ef5084d469c6342c84c5c2f6a0dc65ae4493)) + * **context:** change copy cell command to make it work in SF ([#8](https://github.com/ghiscoding/slickgrid-universal/issues/8)) ([c0b8ad9](https://github.com/ghiscoding/slickgrid-universal/commit/c0b8ad943dbd6baf08f41c36d6d266382b758206)) + * **core:** add missing use of custom datasetIdPropertyName ([917f044](https://github.com/ghiscoding/slickgrid-universal/commit/917f044b1489b19917b15bd146a2d40f8924ea23)) + * **debug:** chrome debugger with webpack & TS breakpoints ([6c3ab52](https://github.com/ghiscoding/slickgrid-universal/commit/6c3ab521be42265edd33d30002f342493f12c54b)) + * **editor:** disregard Flatpickr error on Date Editor ([e7d7ba5](https://github.com/ghiscoding/slickgrid-universal/commit/e7d7ba57c6a68309aafb0c2082b4e642194067f3)) + * **editor:** disregard Flatpickr error on Date Editor and fix output format ([140c48e](https://github.com/ghiscoding/slickgrid-universal/commit/140c48e7fe18eea76d59b44bb6625d3cb89aaf55)) + * **editor:** float validator min/max values should be inclusive ([3e193aa](https://github.com/ghiscoding/slickgrid-universal/commit/3e193aabd8bdf515d53da938c19bc931b29c8438)) + * **editor:** float validator should accept decimal even without 0 suffix ([87808ce](https://github.com/ghiscoding/slickgrid-universal/commit/87808ce1f0c10e4dd070518b78e35e986580de30)) + * **editor:** number validators should be ok with null value on init ([1aadc86](https://github.com/ghiscoding/slickgrid-universal/commit/1aadc86787d88de8e18a193853e40ee88e795f93)) + * **editor:** shouldn't call cell changed when cell value is undefined ([d5796a1](https://github.com/ghiscoding/slickgrid-universal/commit/d5796a1c3d45d5592c56dc9001231b2943f56cc0)) + * **editors:** add saveOutputType to finally have proper save format ([#17](https://github.com/ghiscoding/slickgrid-universal/issues/17)) ([ebfd715](https://github.com/ghiscoding/slickgrid-universal/commit/ebfd71582642abe136317dbef8cedee68d472aa7)) + * **editors:** Editors should work with undefined item properties ([#25](https://github.com/ghiscoding/slickgrid-universal/issues/25)) ([9bc6f5a](https://github.com/ghiscoding/slickgrid-universal/commit/9bc6f5ad617d7144d8787d4afcfe3b888966dcb7)) + * **editors:** invalid date should trigger onvalidationerror ([#19](https://github.com/ghiscoding/slickgrid-universal/issues/19)) ([041087e](https://github.com/ghiscoding/slickgrid-universal/commit/041087ea928b9c53ef118a198b6837a028933b7a)) + * **editors:** make sure appendChild exist before using it to add Editor ([90d4a67](https://github.com/ghiscoding/slickgrid-universal/commit/90d4a670824eb979fc2813d0d42a5803dacd3739)) + * **filter:** recreate filter when toggling header row ([e839464](https://github.com/ghiscoding/slickgrid-universal/commit/e839464fa5dbb1db274ebda69daf3f71808f0c93)) + * **filter:** string filter should also work when using Contains ([fc54f9a](https://github.com/ghiscoding/slickgrid-universal/commit/fc54f9a03b974e000cde4ea4a18ddb261572f003)) + * **filter:** when entering filter operator it shouldn't do any filtering ([81c465b](https://github.com/ghiscoding/slickgrid-universal/commit/81c465b61ca4c0883c4c4308a5b154ef7410039e)) + * **formatter:** add possibility to parse a date formatter as a UTC date ([e72bcad](https://github.com/ghiscoding/slickgrid-universal/commit/e72bcadae652bb00cb8b51f92ff2b2cf67de37a4)) + * **formatters:** decimalSeparator & thousandSeparator work tgt ([62de7c2](https://github.com/ghiscoding/slickgrid-universal/commit/62de7c2713c140ef757d821d7538a965ea625b7e)) + * **header:** re-create header grouping title after changing picker cols ([872c780](https://github.com/ghiscoding/slickgrid-universal/commit/872c7808d27cae30c414d1e3769728aa083910e7)) + * **menu:** context menu to copy cell with queryFieldNameGetterFn ([#21](https://github.com/ghiscoding/slickgrid-universal/issues/21)) ([53c50f9](https://github.com/ghiscoding/slickgrid-universal/commit/53c50f9d716725330681d3617082b1fa33f90c12)) + * **pagination:** get pagination working in SF as well ([#24](https://github.com/ghiscoding/slickgrid-universal/issues/24)) ([1132f2e](https://github.com/ghiscoding/slickgrid-universal/commit/1132f2edec251e2f65cce860ebfa57dbe35cf852)) + * **picker:** add missing pre-header title grouping extractor ([fa3148b](https://github.com/ghiscoding/slickgrid-universal/commit/fa3148bd90487cad6bcd01b782ab27570336f741)) + * **resize:** add a patch to fix autoresize on Chrome ([02faae4](https://github.com/ghiscoding/slickgrid-universal/commit/02faae44118dd5adbda57a5363567a84c84e7cb2)) + * **sanitizer:** add optional grid option sanitizer anywhere possible ([#9](https://github.com/ghiscoding/slickgrid-universal/issues/9)) ([a6c7997](https://github.com/ghiscoding/slickgrid-universal/commit/a6c7997d75d27cc14892de4460dea28b529b392e)) + * **select:** revert to jQuery 3.4.1 since latest version seems ([e839a5e](https://github.com/ghiscoding/slickgrid-universal/commit/e839a5e0f8ef8ab21a341ee2e2961c5a07736805)) + * **sort:** header menu sorting should include columnId property ([2c5d2e0](https://github.com/ghiscoding/slickgrid-universal/commit/2c5d2e0547179f4cbe8f491a83af5202ba3410f9)) + * **sort:** header menu sorting should include columnId property ([666a831](https://github.com/ghiscoding/slickgrid-universal/commit/666a83166ec21062bba9be287d65a242f7b52a1a)) + * **styling:** cell menu is re-position incorrectly below the grid ([6fd3552](https://github.com/ghiscoding/slickgrid-universal/commit/6fd3552b568faef252e77b0446f2ab08d2a6ccde)) + * **styling:** cell/context menus get re-position below the grid ([7db862a](https://github.com/ghiscoding/slickgrid-universal/commit/7db862ad6d7a939d1a285141068e2095c3295541)) + * **styling:** sass variable should be interpolate before using calc ([42e7e3d](https://github.com/ghiscoding/slickgrid-universal/commit/42e7e3d51e6750f11a17f11d259fe97851505385)) + * **tests:** fix failing unit test ([f19745d](https://github.com/ghiscoding/slickgrid-universal/commit/f19745d91d264d3da450a674b9ca9c78bf157294)) + * **types:** fix TS type warnings ([d22ee64](https://github.com/ghiscoding/slickgrid-universal/commit/d22ee64dfaabae5b0e497ade62192b1c5595e0c3)) ### Features * **backend:** add OData & GraphQL packages ([#2](https://github.com/ghiscoding/slickgrid-universal/issues/2)) ([53cf08b](https://github.com/ghiscoding/slickgrid-universal/commit/53cf08bff2eea18e677770f70eedef1bda9aefcc)) + * **browser:** add browserslist for packages who uses it ([fc69908](https://github.com/ghiscoding/slickgrid-universal/commit/fc69908a4eccfaedeb1835eb9d00719e7926065f)) + * **build:** add correct TS types to all packages ([5ab0833](https://github.com/ghiscoding/slickgrid-universal/commit/5ab0833e07b89504ac603c3d356d2a6bdb0dfee2)) + * **build:** tweak build to use tsc and test with sf lwc ([e4964b3](https://github.com/ghiscoding/slickgrid-universal/commit/e4964b34513e828d5cc9f2b278d794d892895277)) + * **colspan:** add Header Grouping & Column Span example ([b9a155d](https://github.com/ghiscoding/slickgrid-universal/commit/b9a155dcf58c9a7c984ea1b6426883af0ae2f9ca)) + * **core:** add `collectionAsync` option for both the Editors & Filters ([#16](https://github.com/ghiscoding/slickgrid-universal/issues/16)) ([f9488ab](https://github.com/ghiscoding/slickgrid-universal/commit/f9488ab350421be771f356b1775559a8e0d8e0c0)) + * **core:** add Translation into demo with fetch locale from json file ([#23](https://github.com/ghiscoding/slickgrid-universal/issues/23)) ([b5608e9](https://github.com/ghiscoding/slickgrid-universal/commit/b5608e958f659b839a8460ffee4a555c66774893)) + * **core:** dynamically add/remove columns ([#13](https://github.com/ghiscoding/slickgrid-universal/issues/13)) ([959097c](https://github.com/ghiscoding/slickgrid-universal/commit/959097cf8363330c7166d0844048cfde57a5cabc)) + * **core:** expose all Extensions in new getter prop & fix draggable ([#29](https://github.com/ghiscoding/slickgrid-universal/issues/29)) ([07257b2](https://github.com/ghiscoding/slickgrid-universal/commit/07257b2564d86cbfad4f69bb4e910e04d7df5688)) + * **core:** expose all services, slickgrid, dataview instances ([a33e387](https://github.com/ghiscoding/slickgrid-universal/commit/a33e3876b1134f6839aac10a67193448997ae7c5)) + * **core:** use DataView transactions with multiple item changes ([#14](https://github.com/ghiscoding/slickgrid-universal/issues/14)) ([8cbd03a](https://github.com/ghiscoding/slickgrid-universal/commit/8cbd03a678bc6a2a89495685cc781b12946ec404)) + * **demo:** add prod build for github page sample ([13eb721](https://github.com/ghiscoding/slickgrid-universal/commit/13eb721f88114461e1dda70eeba0461b69a89f46)) + * **editor:** add more Editors ([f08864d](https://github.com/ghiscoding/slickgrid-universal/commit/f08864d0d583d01dece58570ea5bf8d1a195cdc9)) + * **editor:** add operatorConditionalType (inclusive or exclusive) ([e300b31](https://github.com/ghiscoding/slickgrid-universal/commit/e300b313ae0d04ad2ec65f932e243d2b4150eca3)) + * **editor:** add readonly option to DualInput Editor ([4217c41](https://github.com/ghiscoding/slickgrid-universal/commit/4217c411304d6056a6de6489351497418b72d9e6)) + * **editor:** fully working dual input editor ([773fb49](https://github.com/ghiscoding/slickgrid-universal/commit/773fb49c1dbb6876bf8c2d2c53a1f823a84dd655)) + * **editor:** start working on a Compound Editor ([49107c1](https://github.com/ghiscoding/slickgrid-universal/commit/49107c14ca841edf7c279e9a0ffe334f1d5dc71a)) + * **editor:** tweak Dual Input Editor and add full unit tests ([c48e321](https://github.com/ghiscoding/slickgrid-universal/commit/c48e32189db48ced3c68e3427c64583db2d8d1d7)) + * **editors:** add Autocomplete Editor ([011df55](https://github.com/ghiscoding/slickgrid-universal/commit/011df552c48defb32e81a1552e8b4e38f25be028)) + * **editors:** add combo input editor poc code ([5918c73](https://github.com/ghiscoding/slickgrid-universal/commit/5918c73ea82e13183e8a6c14021f38ddf0f2b0fd)) + * **editors:** add min/max length options to text editors ([#30](https://github.com/ghiscoding/slickgrid-universal/issues/30)) ([318c70c](https://github.com/ghiscoding/slickgrid-universal/commit/318c70ccbf0f071e328457d6290b6b1e078a1564)) + * **editors:** add missing Date Editor ([c897c7c](https://github.com/ghiscoding/slickgrid-universal/commit/c897c7c426c179282766bba3345f4b44317aee44)) + * **editors:** add more Editors and rewrite some in vanilla JS ([9308d4b](https://github.com/ghiscoding/slickgrid-universal/commit/9308d4b78a77a86a4b86fd10fb1de34746276a9e)) + * **editors:** add more Editors and update all npm packages ([14b10a1](https://github.com/ghiscoding/slickgrid-universal/commit/14b10a17642b2c7f889f90b58dd3fef084e983b9)) + * **editors:** extract most of the Editor Validators into separate files ([a9a45e6](https://github.com/ghiscoding/slickgrid-universal/commit/a9a45e6f2ce3536f9be846ef932337f174569897)) + * **examples:** add more Tree View with checkbox selector code ([7d7c644](https://github.com/ghiscoding/slickgrid-universal/commit/7d7c644b0ecc8c3b61dd706d37d31edd0cf92fca)) + * **examples:** add new sample to showcase queued editing ([#28](https://github.com/ghiscoding/slickgrid-universal/issues/28)) ([3b8fec6](https://github.com/ghiscoding/slickgrid-universal/commit/3b8fec6e890fc0b8dc9754495c1022d898740b3e)) + * **extension:** add latest slickgrid with RowMove improvements ([c10fffd](https://github.com/ghiscoding/slickgrid-universal/commit/c10fffdb2bd8a8ce0221e570cf0bfb4cf03c7c29)) + * **extensions:** add more Extensions and all their unit tests ([30af496](https://github.com/ghiscoding/slickgrid-universal/commit/30af496c48233ff84ce548648994398db068dbcb)) + * **filter:** add Filter Service, Filter Conditions and few unit tests ([2baed7f](https://github.com/ghiscoding/slickgrid-universal/commit/2baed7fa0c31d73437b3d08d2d48c91b05602ff9)) + * **filter:** refactor Filter Service by adding a debounce fn ([#7](https://github.com/ghiscoding/slickgrid-universal/issues/7)) ([3ba243c](https://github.com/ghiscoding/slickgrid-universal/commit/3ba243ce3b4ade48531ca323a12b465b5ad0b091)) + * **filters:** add Autocomplete Filter ([82bda77](https://github.com/ghiscoding/slickgrid-universal/commit/82bda776c9cb72c9d44aca24ecf289c839e6e24f)) + * **filters:** add few Filters and their unit tests ([c7e5897](https://github.com/ghiscoding/slickgrid-universal/commit/c7e5897d2e2af93339ea28a2fabc5263015d7d2c)) + * **filters:** add few more Filters ([76b4177](https://github.com/ghiscoding/slickgrid-universal/commit/76b41771bd55e846ee67c9100b0de29ddb0a9276)) + * **filters:** add missing Date Filters ([76c66a3](https://github.com/ghiscoding/slickgrid-universal/commit/76c66a3ec2da4b1ff1b296851f46bf58967adc18)) + * **footer:** add Custom Footer ([0d3e1da](https://github.com/ghiscoding/slickgrid-universal/commit/0d3e1dabf29c4bc354df598a3b166030f61769fc)) + * **footer:** add Custom Footer component ([#5](https://github.com/ghiscoding/slickgrid-universal/issues/5)) ([59d0ba8](https://github.com/ghiscoding/slickgrid-universal/commit/59d0ba8921c2e0886b0c34705ac5a74f35ab4e43)) + * **grouping:** add missing Grouping interface properties ([7c83fd0](https://github.com/ghiscoding/slickgrid-universal/commit/7c83fd09acff960b86f62a0bd0c1f4b654b25f9c)) + * **grouping:** add more Grouping & Aggregators code ([8c20808](https://github.com/ghiscoding/slickgrid-universal/commit/8c20808d9a8b0a6166f4fb8fe013d33ae57a223c)) + * **package:** add new Excel Export package ([808785e](https://github.com/ghiscoding/slickgrid-universal/commit/808785e0ea9508f817453211d8ed808398aa9c01)) + * **package:** add new Export (csv, txt) package ([d6adc5c](https://github.com/ghiscoding/slickgrid-universal/commit/d6adc5ce7aa466fde3c1e1377bd47c9a6cd8b53b)) + * **pinning:** add "Freezen Columns" to header menu ([#4](https://github.com/ghiscoding/slickgrid-universal/issues/4)) ([1c7d49f](https://github.com/ghiscoding/slickgrid-universal/commit/1c7d49f838a8cadb093dfbdf81c215ed250fbe14)) + * **presets:** add missing row selections preset option ([#11](https://github.com/ghiscoding/slickgrid-universal/issues/11)) ([e0a729c](https://github.com/ghiscoding/slickgrid-universal/commit/e0a729cfbbe7aa75a18301b4db994ac9d3330f10)) + * **query:** add queryFieldNameGetterFn callback know which field to use ([6d8955c](https://github.com/ghiscoding/slickgrid-universal/commit/6d8955c1933a88683c2284d9162e43248bc578a2)) + * **service:** add GridEvent Service to the lib ([4a4bf6f](https://github.com/ghiscoding/slickgrid-universal/commit/4a4bf6f86ebdb6cbf911d838714440cceee4e07f)) + * **services:** add Pagination & Grid State Services ([c15e6e6](https://github.com/ghiscoding/slickgrid-universal/commit/c15e6e63edce6f07751f3380229e9e1777c43d84)) + * **services:** add registerServices in Grid Options ([#1](https://github.com/ghiscoding/slickgrid-universal/issues/1)) ([e7c2e91](https://github.com/ghiscoding/slickgrid-universal/commit/e7c2e91842eac2044ccdd82673bfade20b24ab4f)) + * **sort:** add valueCouldBeUndefined column flag to help sorting ([6d2b6a6](https://github.com/ghiscoding/slickgrid-universal/commit/6d2b6a6b7521511470c27c17ce65784258a87868)) + * **sorting:** header menu clear sort, reset sorting when nothing left ([032886b](https://github.com/ghiscoding/slickgrid-universal/commit/032886bf6da9e3d711a17d23481c47ccf81af353)) + * **style:** tweak Editors styling and add Sort icon hint on hover ([aba4182](https://github.com/ghiscoding/slickgrid-universal/commit/aba41826659844519da1ef170f0b3641a0d91af0)) + * **styling:** add a Salesforce theme ([3b62101](https://github.com/ghiscoding/slickgrid-universal/commit/3b62101413dc3eb4eeb5df7772db3b885d7ae7c5)) + * **styling:** add css autoprefixer ([2e89c28](https://github.com/ghiscoding/slickgrid-universal/commit/2e89c287ea0ed5a508f2e977cae21ecc35ed414d)) + * **styling:** add edit icon when hovering editable cell with SF Theme ([eef4403](https://github.com/ghiscoding/slickgrid-universal/commit/eef4403b8e9168ff119eb97ca5c663101104abae)) + * **styling:** add material design icons to npm & scss instead of html ([9e9a1ca](https://github.com/ghiscoding/slickgrid-universal/commit/9e9a1ca7794eb807494bfbd837aa7e17ad4b42b2)) + * **styling:** add more material design stylings ([680788b](https://github.com/ghiscoding/slickgrid-universal/commit/680788b9b456c6d87875234d9f2c033cfbb7e18f)) + * **styling:** material theme, replace all built-in Font char to SVG ([ed25d6a](https://github.com/ghiscoding/slickgrid-universal/commit/ed25d6ae4848b614c84da111ff894eedb5be6400)) + * **styling:** salesforce theme, replace all built-in Font char to SVG ([1c5f341](https://github.com/ghiscoding/slickgrid-universal/commit/1c5f3414d8bafea7cb393033c9753aef4ad66b2f)) + * **styling:** update Material Design font and some material styling ([c7ecbf9](https://github.com/ghiscoding/slickgrid-universal/commit/c7ecbf91b000e0758df04f87f49c35c1293f0abe)) + * **tests:** add export abstract classes and add few more unit tests ([13a1bca](https://github.com/ghiscoding/slickgrid-universal/commit/13a1bcac7c21666f2b006f3488036175b29b1b3d)) + * **tests:** add Jest to lib root and add few more unit tests ([5811c96](https://github.com/ghiscoding/slickgrid-universal/commit/5811c96568c5255376ea6b97b132f4f0fded0647)) + * **tests:** add more Jest unit tests & commands ([d4da547](https://github.com/ghiscoding/slickgrid-universal/commit/d4da547aaae797767140d73289d7f50874fdd09e)) + * **tests:** add queryFieldNameGetterFn callback unit tests ([6426793](https://github.com/ghiscoding/slickgrid-universal/commit/64267931dd6ad5506c52da2b19854d2a56d2104f)) + * **tests:** rename to slick-vanilla-grid-bundle and add unit tests ([#12](https://github.com/ghiscoding/slickgrid-universal/issues/12)) ([006c302](https://github.com/ghiscoding/slickgrid-universal/commit/006c30251ea1d473e5d1ae54d20c050fccf0e6a4)) + * **translate:** add namespace prefix + separator grid option ([90b1b2e](https://github.com/ghiscoding/slickgrid-universal/commit/90b1b2ec0c1a55d23ebcc47b6a88d972c9bbcdb7)) + * **tree:** add Collapse/Expand All comands in context menu ([0b58d5e](https://github.com/ghiscoding/slickgrid-universal/commit/0b58d5e3727541fa088a1eeb9e49bb55f367b7c5)) + * **tree:** add Tree Data multi-column Filtering support ([f9b4863](https://github.com/ghiscoding/slickgrid-universal/commit/f9b4863810da47138be7f83222ee49d87b4e20c0)) + * **tree:** fixed recursive methods to sort hierarchical array ([6bc2915](https://github.com/ghiscoding/slickgrid-universal/commit/6bc29158395e6f3c9e3fbf87358d3ecb5fb12b75)) + * **tree:** get a functional Tree View example working with add item ([c07cdb5](https://github.com/ghiscoding/slickgrid-universal/commit/c07cdb545106fd845a105a28014daabaa2860137)) diff --git a/packages/common/README.md b/packages/common/README.md index 53901ca1f..c3d9624d7 100644 --- a/packages/common/README.md +++ b/packages/common/README.md @@ -3,6 +3,7 @@ [![lerna--lite](https://img.shields.io/badge/maintained%20with-lerna--lite-e137ff)](https://github.com/ghiscoding/lerna-lite) [![npm](https://img.shields.io/npm/v/@slickgrid-universal/common.svg)](https://www.npmjs.com/package/@slickgrid-universal/common) [![npm](https://img.shields.io/npm/dy/@slickgrid-universal/common)](https://www.npmjs.com/package/@slickgrid-universal/common) +[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/common?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/common) [![Actions Status](https://github.com/ghiscoding/slickgrid-universal/actions/workflows/main.yml/badge.svg)](https://github.com/ghiscoding/slickgrid-universal/actions) [![Cypress.io](https://img.shields.io/badge/tested%20with-Cypress-04C38E.svg)](https://www.cypress.io/) diff --git a/packages/common/package.json b/packages/common/package.json index 6357ab611..a999e2e5c 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -1,6 +1,6 @@ { "name": "@slickgrid-universal/common", - "version": "4.7.0", + "version": "5.0.0-beta.3", "description": "SlickGrid-Universal Common Code", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", @@ -46,11 +46,10 @@ "bundle:esm": "tsc --project tsconfig.bundle.json --outDir dist/esm --module esnext --target es2021", "bundle:types": "tsc --emitDeclarationOnly --declarationMap --outDir dist/types", "sass-build-task:scss-compile:bootstrap": "sass src/styles/slickgrid-theme-bootstrap.scss dist/styles/css/slickgrid-theme-bootstrap.css --style=compressed --quiet-deps --no-source-map --load-path=node_modules", + "sass-build-task:scss-compile:bootstrap-lite": "sass src/styles/slickgrid-theme-bootstrap.lite.scss dist/styles/css/slickgrid-theme-bootstrap.lite.css --style=compressed --quiet-deps --no-source-map --load-path=node_modules", "sass-build-task:scss-compile:material": "sass src/styles/slickgrid-theme-material.scss dist/styles/css/slickgrid-theme-material.css --style=compressed --quiet-deps --no-source-map --load-path=node_modules", - "sass-build-task:scss-compile:material-bare": "sass src/styles/slickgrid-theme-material.bare.scss dist/styles/css/slickgrid-theme-material.bare.css --style=compressed --quiet-deps --no-source-map --load-path=node_modules", "sass-build-task:scss-compile:material-lite": "sass src/styles/slickgrid-theme-material.lite.scss dist/styles/css/slickgrid-theme-material.lite.css --style=compressed --quiet-deps --no-source-map --load-path=node_modules", "sass-build-task:scss-compile:salesforce": "sass src/styles/slickgrid-theme-salesforce.scss dist/styles/css/slickgrid-theme-salesforce.css --style=compressed --quiet-deps --no-source-map --load-path=node_modules", - "sass-build-task:scss-compile:salesforce-bare": "sass src/styles/slickgrid-theme-salesforce.bare.scss dist/styles/css/slickgrid-theme-salesforce.bare.css --style=compressed --quiet-deps --no-source-map --load-path=node_modules", "sass-build-task:scss-compile:salesforce-lite": "sass src/styles/slickgrid-theme-salesforce.lite.scss dist/styles/css/slickgrid-theme-salesforce.lite.css --style=compressed --quiet-deps --no-source-map --load-path=node_modules", "sass:build": "run-p sass-build-task:scss-compile:*", "postsass:build": "postcss --no-map --use cssnano --use autoprefixer --dir dist/styles/css dist/styles/css --style=compressed --quiet-deps --no-source-map", @@ -67,20 +66,18 @@ "not dead" ], "dependencies": { + "@formkit/tempo": "^0.1.1", "@slickgrid-universal/binding": "workspace:~", "@slickgrid-universal/event-pub-sub": "workspace:~", "@slickgrid-universal/utils": "workspace:~", - "@types/dompurify": "^3.0.5", "@types/sortablejs": "^1.15.8", "autocompleter": "^9.2.1", "dequal": "^2.0.3", "excel-builder-vanilla": "3.0.1", - "flatpickr": "^4.6.13", - "isomorphic-dompurify": "^2.9.0", - "moment-mini": "^2.29.4", "multiple-select-vanilla": "^3.2.0", "sortablejs": "^1.15.2", - "un-flatten-tree": "^2.0.12" + "un-flatten-tree": "^2.0.12", + "vanilla-calendar-picker": "^2.11.5" }, "devDependencies": { "autoprefixer": "^10.4.19", diff --git a/packages/common/src/commonEditorFilter/commonEditorFilterUtils.ts b/packages/common/src/commonEditorFilter/commonEditorFilterUtils.ts index 9133e6780..b433620e2 100644 --- a/packages/common/src/commonEditorFilter/commonEditorFilterUtils.ts +++ b/packages/common/src/commonEditorFilter/commonEditorFilterUtils.ts @@ -1,6 +1,10 @@ +import { format } from '@formkit/tempo'; import type { AutocompleteItem } from 'autocompleter'; +import type { IOptions } from 'vanilla-calendar-picker'; -import type { AutocompleterOption } from '../interfaces/index'; +import type { AutocompleterOption, Column, ColumnEditor, ColumnFilter } from '../interfaces/index'; +import { FieldType } from '../enums'; +import { formatDateByFieldType, mapTempoDateFormatWithFieldType, tryParseDate } from '../services/dateUtils'; /** * add loading class ".slick-autocomplete-loading" to the Kraaden Autocomplete input element @@ -27,4 +31,32 @@ export function addAutocompleteLoadingByOverridingFetch format(p, isoFormat)).join(':')], + month: pickerDates[0].getMonth(), + year: pickerDates[0].getFullYear(), + time: inputFormat === 'ISO8601' || (inputFormat || '').toLowerCase().includes('h') ? format(pickerDates[0], 'HH:mm') : undefined, + }; + } + dateInputElm.value = initialDates.length ? pickerDates.map(p => formatDateByFieldType(p, undefined, outputFieldType)).join(' — ') : ''; + } } \ No newline at end of file diff --git a/packages/common/src/core/__tests__/slickDataView.spec.ts b/packages/common/src/core/__tests__/slickDataView.spec.ts index daf3f0b76..08ed55718 100644 --- a/packages/common/src/core/__tests__/slickDataView.spec.ts +++ b/packages/common/src/core/__tests__/slickDataView.spec.ts @@ -3,7 +3,6 @@ import { SortDirectionNumber } from '../../enums'; import { GridOption, Grouping } from '../../interfaces'; import { SortComparers } from '../../sortComparers'; import { SlickDataView } from '../slickDataview'; -import 'flatpickr'; import { SlickGrid } from '../slickGrid'; import { SlickRowSelectionModel } from '../../extensions/slickRowSelectionModel'; import { SlickEventData } from '../slickCore'; diff --git a/packages/common/src/core/__tests__/slickGrid.spec.ts b/packages/common/src/core/__tests__/slickGrid.spec.ts index 9ba598086..7b59a9293 100644 --- a/packages/common/src/core/__tests__/slickGrid.spec.ts +++ b/packages/common/src/core/__tests__/slickGrid.spec.ts @@ -811,16 +811,6 @@ describe('SlickGrid core file', () => { expect(divElm.outerHTML).toBe('
only text kept
'); }); - it('should be able to supply differnt sanitizer options to use with DOMPurify before applying html code', () => { - const divElm = document.createElement('div'); - const htmlStr = 'only text kept'; - - grid = new SlickGrid('#myGrid', dv, columns, defaultOptions); - grid.applyHtmlCode(divElm, htmlStr, { sanitizerOptions: { ALLOW_ARIA_ATTR: false } }); - - expect(divElm.outerHTML).toBe('
only text kept
'); - }); - it('should expect HTML string to be kept as a string and not be converted (but html escaped) when "enableHtmlRendering" grid option is disabled', () => { const divElm = document.createElement('div'); const htmlStr = 'only text kept'; diff --git a/packages/common/src/core/slickGrid.ts b/packages/common/src/core/slickGrid.ts index 111f67634..c7f0926a0 100644 --- a/packages/common/src/core/slickGrid.ts +++ b/packages/common/src/core/slickGrid.ts @@ -1,5 +1,4 @@ import Sortable, { type SortableEvent } from 'sortablejs'; -import DOMPurify from 'isomorphic-dompurify'; import { BindingEventService } from '@slickgrid-universal/binding'; import { classNameToList, @@ -588,22 +587,17 @@ export class SlickGrid = Column, O e return; // same result, just skip it } - let sanitizedText = val; - if (typeof sanitizedText === 'number' || typeof sanitizedText === 'boolean') { - target.textContent = String(sanitizedText); + if (typeof val === 'number' || typeof val === 'boolean') { + target.textContent = String(val); } else { - if (typeof this._options?.sanitizer === 'function') { - sanitizedText = this._options.sanitizer(val as string); - } else if (typeof DOMPurify?.sanitize === 'function') { - const purifyOptions = (options?.sanitizerOptions ?? this._options.sanitizerOptions ?? { ADD_ATTR: ['level'], RETURN_TRUSTED_TYPE: true }) as DOMPurify.Config; - sanitizedText = DOMPurify.sanitize(val as string, purifyOptions) as unknown as string; - } + const sanitizedText = this.sanitizeHtmlString(val); - // apply HTML when enableHtmlRendering is enabled but make sure we do have a value (without a value, it will simply use `textContent` to clear text content) + // apply HTML when enableHtmlRendering is enabled + // but make sure we do have a value (without a value, it will simply use `textContent` to clear text content) if (this._options.enableHtmlRendering && sanitizedText) { - target.innerHTML = sanitizedText; + target.innerHTML = sanitizedText as unknown as string; } else { - target.textContent = sanitizedText; + target.textContent = sanitizedText as unknown as string; } } } @@ -645,7 +639,7 @@ export class SlickGrid = Column, O e this._container.style.overflow = 'hidden'; this._container.style.outline = String(0); this._container.classList.add(this.uid); - this._container.classList.add('ui-widget'); + this._container.classList.add('slick-widget'); this._container.setAttribute('role', 'grid'); const containerStyles = window.getComputedStyle(this._container); @@ -664,12 +658,12 @@ export class SlickGrid = Column, O e this._paneBottomR = createDomElement('div', { className: 'slick-pane slick-pane-bottom slick-pane-right', tabIndex: 0 }, this._container); if (this._options.createPreHeaderPanel) { - this._preHeaderPanelScroller = createDomElement('div', { className: 'slick-preheader-panel ui-state-default slick-state-default', style: { overflow: 'hidden', position: 'relative' } }, this._paneHeaderL); + this._preHeaderPanelScroller = createDomElement('div', { className: 'slick-preheader-panel slick-state-default', style: { overflow: 'hidden', position: 'relative' } }, this._paneHeaderL); this._preHeaderPanelScroller.appendChild(document.createElement('div')); this._preHeaderPanel = createDomElement('div', null, this._preHeaderPanelScroller); this._preHeaderPanelSpacer = createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._preHeaderPanelScroller); - this._preHeaderPanelScrollerR = createDomElement('div', { className: 'slick-preheader-panel ui-state-default slick-state-default', style: { overflow: 'hidden', position: 'relative' } }, this._paneHeaderR); + this._preHeaderPanelScrollerR = createDomElement('div', { className: 'slick-preheader-panel slick-state-default', style: { overflow: 'hidden', position: 'relative' } }, this._paneHeaderR); this._preHeaderPanelR = createDomElement('div', null, this._preHeaderPanelScrollerR); this._preHeaderPanelSpacerR = createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._preHeaderPanelScrollerR); @@ -680,8 +674,8 @@ export class SlickGrid = Column, O e } // Append the header scroller containers - this._headerScrollerL = createDomElement('div', { className: 'slick-header ui-state-default slick-state-default slick-header-left' }, this._paneHeaderL); - this._headerScrollerR = createDomElement('div', { className: 'slick-header ui-state-default slick-state-default slick-header-right' }, this._paneHeaderR); + this._headerScrollerL = createDomElement('div', { className: 'slick-header slick-state-default slick-header-left' }, this._paneHeaderL); + this._headerScrollerR = createDomElement('div', { className: 'slick-header slick-state-default slick-header-right' }, this._paneHeaderR); // Cache the header scroller containers this._headerScroller.push(this._headerScrollerL); @@ -694,8 +688,8 @@ export class SlickGrid = Column, O e // Cache the header columns this._headers = [this._headerL, this._headerR]; - this._headerRowScrollerL = createDomElement('div', { className: 'slick-headerrow ui-state-default slick-state-default' }, this._paneTopL); - this._headerRowScrollerR = createDomElement('div', { className: 'slick-headerrow ui-state-default slick-state-default' }, this._paneTopR); + this._headerRowScrollerL = createDomElement('div', { className: 'slick-headerrow slick-state-default' }, this._paneTopL); + this._headerRowScrollerR = createDomElement('div', { className: 'slick-headerrow slick-state-default' }, this._paneTopR); this._headerRowScroller = [this._headerRowScrollerL, this._headerRowScrollerR]; @@ -708,8 +702,8 @@ export class SlickGrid = Column, O e this._headerRows = [this._headerRowL, this._headerRowR]; // Append the top panel scroller - this._topPanelScrollerL = createDomElement('div', { className: 'slick-top-panel-scroller ui-state-default slick-state-default' }, this._paneTopL); - this._topPanelScrollerR = createDomElement('div', { className: 'slick-top-panel-scroller ui-state-default slick-state-default' }, this._paneTopR); + this._topPanelScrollerL = createDomElement('div', { className: 'slick-top-panel-scroller slick-state-default' }, this._paneTopL); + this._topPanelScrollerR = createDomElement('div', { className: 'slick-top-panel-scroller slick-state-default' }, this._paneTopR); this._topPanelScrollers = [this._topPanelScrollerL, this._topPanelScrollerR]; @@ -782,8 +776,8 @@ export class SlickGrid = Column, O e // footer Row if (this._options.createFooterRow) { - this._footerRowScrollerR = createDomElement('div', { className: 'slick-footerrow ui-state-default slick-state-default' }, this._paneTopR); - this._footerRowScrollerL = createDomElement('div', { className: 'slick-footerrow ui-state-default slick-state-default' }, this._paneTopL); + this._footerRowScrollerR = createDomElement('div', { className: 'slick-footerrow slick-state-default' }, this._paneTopR); + this._footerRowScrollerL = createDomElement('div', { className: 'slick-footerrow slick-state-default' }, this._paneTopL); this._footerRowScroller = [this._footerRowScrollerL, this._footerRowScrollerR]; @@ -1349,7 +1343,7 @@ export class SlickGrid = Column, O e * @param {string | HTMLElement | DocumentFragment} [title] New column name. * @param {String} [toolTip] New column tooltip. */ - updateColumnHeader(columnId: number | string, title?: string | HTMLElement | DocumentFragment, toolTip?: string) { + updateColumnHeader(columnId: number | string, title?: string | HTMLElement | DocumentFragment, toolTip?: string): HTMLElement | void { if (this.initialized) { const idx = this.getColumnIndex(columnId); if (!isDefined(idx)) { @@ -1383,6 +1377,8 @@ export class SlickGrid = Column, O e grid: this }); } + + return header; } } @@ -1502,7 +1498,7 @@ export class SlickGrid = Column, O e continue; } - const footerRowCell = createDomElement('div', { className: `ui-state-default slick-state-default slick-footerrow-column l${i} r${i}` }, this.hasFrozenColumns() && (i > this._options.frozenColumn!) ? this._footerRowR : this._footerRowL); + const footerRowCell = createDomElement('div', { className: `slick-state-default slick-footerrow-column l${i} r${i}` }, this.hasFrozenColumns() && (i > this._options.frozenColumn!) ? this._footerRowR : this._footerRowL); const className = this.hasFrozenColumns() && i <= this._options.frozenColumn! ? 'frozen' : null; if (className) { footerRowCell.classList.add(className); @@ -1520,11 +1516,11 @@ export class SlickGrid = Column, O e } protected handleHeaderMouseHoverOn(e: Event | SlickEventData) { - (e as any)?.target.classList.add('ui-state-hover', 'slick-state-hover'); + (e as any)?.target.classList.add('slick-state-hover'); } protected handleHeaderMouseHoverOff(e: Event | SlickEventData) { - (e as any)?.target.classList.remove('ui-state-hover', 'slick-state-hover'); + (e as any)?.target.classList.remove('slick-state-hover'); } protected createColumnHeaders() { @@ -1606,7 +1602,7 @@ export class SlickGrid = Column, O e const headerTarget = this.hasFrozenColumns() ? ((i <= this._options.frozenColumn!) ? this._headerL : this._headerR) : this._headerL; const headerRowTarget = this.hasFrozenColumns() ? ((i <= this._options.frozenColumn!) ? this._headerRowL : this._headerRowR) : this._headerRowL; - const header = createDomElement('div', { id: `${this.uid + m.id}`, dataset: { id: String(m.id) }, role: 'columnheader', className: 'ui-state-default slick-state-default slick-header-column' }, headerTarget); + const header = createDomElement('div', { id: `${this.uid + m.id}`, dataset: { id: String(m.id) }, role: 'columnheader', className: 'slick-state-default slick-header-column' }, headerTarget); if (m.toolTip) { header.title = m.toolTip; } @@ -1662,7 +1658,7 @@ export class SlickGrid = Column, O e }); if (this._options.showHeaderRow) { - const headerRowCell = createDomElement('div', { className: `ui-state-default slick-state-default slick-headerrow-column l${i} r${i}` }, headerRowTarget); + const headerRowCell = createDomElement('div', { className: `slick-state-default slick-headerrow-column l${i} r${i}` }, headerRowTarget); const frozenClasses = this.hasFrozenColumns() && i <= this._options.frozenColumn! ? 'frozen' : null; if (frozenClasses) { headerRowCell.classList.add(frozenClasses); @@ -1683,7 +1679,7 @@ export class SlickGrid = Column, O e } if (this._options.createFooterRow && this._options.showFooterRow) { const footerRowTarget = this.hasFrozenColumns() ? ((i <= this._options.frozenColumn!) ? this._footerRow[0] : this._footerRow[1]) : this._footerRow[0]; - const footerRowCell = createDomElement('div', { className: `ui-state-default slick-state-default slick-footerrow-column l${i} r${i}` }, footerRowTarget); + const footerRowCell = createDomElement('div', { className: `slick-state-default slick-footerrow-column l${i} r${i}` }, footerRowTarget); Utils.storage.put(footerRowCell, 'column', m); this.triggerEvent(this.onFooterRowCellRendered, { @@ -1785,7 +1781,7 @@ export class SlickGrid = Column, O e previousSortColumns, sortCols: this.sortColumns.map((col) => { const tempCol = this.columns[this.getColumnIndex(col.columnId)]; - return !tempCol ? null : { columnId: tempCol.id, sortCol: tempCol, sortAsc: col.sortAsc }; + return (!tempCol || tempCol.hidden) ? null : { columnId: tempCol.id, sortCol: tempCol, sortAsc: col.sortAsc }; }).filter((el) => el) }; } @@ -2329,7 +2325,7 @@ export class SlickGrid = Column, O e this.headerColumnWidthDiff = this.headerColumnHeightDiff = 0; this.cellWidthDiff = this.cellHeightDiff = 0; - let el = createDomElement('div', { className: 'ui-state-default slick-state-default slick-header-column', style: { visibility: 'hidden' }, textContent: '-' }, header); + let el = createDomElement('div', { className: 'slick-state-default slick-header-column', style: { visibility: 'hidden' }, textContent: '-' }, header); let style = getComputedStyle(el); if (style.boxSizing !== 'border-box') { h.forEach((val) => this.headerColumnWidthDiff += Utils.toFloat(style[val as any])); @@ -3308,7 +3304,7 @@ export class SlickGrid = Column, O e const frozenRowOffset = this.getFrozenRowOffset(row); - const rowDiv = createDomElement('div', { className: `ui-widget-content ${rowCss}`, role: 'row', style: { top: `${this.getRowTop(row) - frozenRowOffset}px` } }); + const rowDiv = createDomElement('div', { className: `slick-widget-content ${rowCss}`, role: 'row', style: { top: `${this.getRowTop(row) - frozenRowOffset}px` } }); let rowDivR: HTMLElement | undefined; divArrayL.push(rowDiv); @@ -6299,12 +6295,15 @@ export class SlickGrid = Column, O e } } - /** html sanitizer to avoid scripting attack */ - sanitizeHtmlString(dirtyHtml: string) { - if (!this._options.sanitizer || typeof dirtyHtml !== 'string') { - return dirtyHtml; + /** + * Sanitize possible dirty html string (remove any potential XSS code like scripts and others) when provided via `sanitizer` grid option. + * The logic will only call the sanitizer if it exists and is a defined string, anything else will be skipped (number, boolean, TrustedHTML will all be skipped) + * @param {*} dirtyHtml: dirty html string + */ + sanitizeHtmlString(dirtyHtml: unknown): T { + if (typeof this._options?.sanitizer !== 'function' || !dirtyHtml || typeof dirtyHtml !== 'string') { + return dirtyHtml as T; } - - return this._options.sanitizer(dirtyHtml); + return this._options.sanitizer(dirtyHtml) as T; } } \ No newline at end of file diff --git a/packages/common/src/editors/__tests__/autocompleterEditor.spec.ts b/packages/common/src/editors/__tests__/autocompleterEditor.spec.ts index efb7d67ec..7bd9fd8c3 100644 --- a/packages/common/src/editors/__tests__/autocompleterEditor.spec.ts +++ b/packages/common/src/editors/__tests__/autocompleterEditor.spec.ts @@ -3,7 +3,7 @@ import 'jest-extended'; import { Editors } from '../index'; import { AutocompleterEditor } from '../autocompleterEditor'; import { FieldType } from '../../enums/index'; -import { AutocompleterOption, Column, ColumnEditor, Editor, EditorArguments, GridOption } from '../../interfaces/index'; +import { AutocompleterOption, Column, Editor, EditorArguments, GridOption } from '../../interfaces/index'; import { TranslateServiceStub } from '../../../../../test/translateServiceStub'; import { SlickDataView, SlickEvent, type SlickGrid } from '../../core/index'; @@ -38,6 +38,7 @@ const gridStub = { render: jest.fn(), onBeforeEditCell: new SlickEvent(), onCompositeEditorChange: new SlickEvent(), + sanitizeHtmlString: (str) => str, } as unknown as SlickGrid; describe('AutocompleterEditor', () => { @@ -745,7 +746,7 @@ describe('AutocompleterEditor', () => { editor = new AutocompleterEditor(editorArguments); const clearSpy = jest.spyOn(editor, 'clear'); - const clearBtnElm = divContainer.querySelector('.btn.icon-clear') as HTMLButtonElement; + const clearBtnElm = divContainer.querySelector('.btn.btn-clear') as HTMLButtonElement; clearBtnElm.dispatchEvent(new Event('click')); expect(clearSpy).toHaveBeenCalled(); diff --git a/packages/common/src/editors/__tests__/dateEditor.spec.ts b/packages/common/src/editors/__tests__/dateEditor.spec.ts index 033fb2b51..622f3d670 100644 --- a/packages/common/src/editors/__tests__/dateEditor.spec.ts +++ b/packages/common/src/editors/__tests__/dateEditor.spec.ts @@ -1,17 +1,13 @@ -import moment from 'moment-mini'; +import { format } from '@formkit/tempo'; +import { VanillaCalendar } from 'vanilla-calendar-picker'; import { Editors } from '../index'; import { DateEditor } from '../dateEditor'; import { FieldType } from '../../enums/index'; -import { Column, ColumnEditor, Editor, EditorArguments, GridOption } from '../../interfaces/index'; +import { Column, Editor, EditorArguments, GridOption } from '../../interfaces/index'; import { TranslateServiceStub } from '../../../../../test/translateServiceStub'; import { SlickEvent, type SlickDataView, type SlickGrid } from '../../core/index'; -const containerId = 'demo-container'; - -// define a
container to simulate the grid container -const template = `
`; - const dataViewStub = { refresh: jest.fn(), } as unknown as SlickDataView; @@ -38,8 +34,30 @@ const gridStub = { render: jest.fn(), onBeforeEditCell: new SlickEvent(), onCompositeEditorChange: new SlickEvent(), + sanitizeHtmlString: (str) => str, } as unknown as SlickGrid; +const gridId = 'grid1'; +const gridUid = 'slickgrid_124343'; +const template = + `
+
+
+
+
+
+
+ +
+
+
+
+
+
+
`; + +jest.useFakeTimers(); + describe('DateEditor', () => { let translateService: TranslateServiceStub; let divContainer: HTMLDivElement; @@ -108,18 +126,17 @@ describe('DateEditor', () => { expect(editorCount).toBe(1); }); - it('should initialize the editor and expect to focus on the element after a small delay', (done) => { + it('should initialize the editor and expect to focus on the element after a small delay', () => { const focusSpy = jest.spyOn(editor, 'focus'); - const showSpy = jest.spyOn(editor, 'focus'); + const showSpy = jest.spyOn(editor, 'show'); editor = new DateEditor(editorArguments); const editorCount = divContainer.querySelectorAll('input.editor-text.editor-startDate').length; - setTimeout(() => { - expect(editorCount).toBe(1); - expect(focusSpy).toHaveBeenCalled(); - expect(showSpy).toHaveBeenCalled(); - done(); - }, 51); + jest.runAllTimers(); + + expect(editorCount).toBe(1); + expect(focusSpy).toHaveBeenCalled(); + expect(showSpy).toHaveBeenCalled(); }); it('should have a placeholder when defined in its column definition', () => { @@ -153,16 +170,22 @@ describe('DateEditor', () => { expect(editor.columnEditor).toEqual(mockColumn.editor); }); - it('should call "setValue" and expect the DOM element value to be the same string when calling "getValue"', () => { + it('should call "setValue" and expect the DOM element value to be the same string when calling "getValue"', async () => { editor = new DateEditor(editorArguments); - editor.setValue('2001-01-02T11:02:02.000Z'); - expect(editor.getValue()).toBe('2001-01-02T11:02:02.000Z'); + jest.runAllTimers(); + + editor.setValue('2001-01-02T11:02:00.000Z'); + + expect(editor.getValue()).toBe('2001-01-02T11:02:00.000Z'); }); it('should call "setValue" with value & apply value flag and expect the DOM element to have same value and also expect the value to be applied to the item object', () => { mockColumn.type = FieldType.dateIso; editor = new DateEditor(editorArguments); + + jest.runAllTimers(); + editor.setValue('2001-01-02', true); expect(editor.getValue()).toBe('2001-01-02'); @@ -172,17 +195,19 @@ describe('DateEditor', () => { it('should define an item datacontext containing a string as cell value and expect this value to be loaded in the editor when calling "loadValue"', () => { mockItemData = { id: 1, startDate: '2001-01-02T11:02:02.000Z', isActive: true }; editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.loadValue(mockItemData); - const editorElm = editor.editorDomElement; - expect(editor.getValue()).toBe('2001-01-02T11:02:02.000Z'); - expect(editorElm.defaultValue).toBe('2001-01-02T11:02:02.000Z'); + expect(editor.getValue()).toBe('2001-01-02'); }); it('should hide the DOM element when the "hide" method is called', () => { editor = new DateEditor(editorArguments); - const spy = jest.spyOn(editor.flatInstance, 'close'); - const calendarElm = document.body.querySelector('.flatpickr-calendar'); + + jest.runAllTimers(); + + const spy = jest.spyOn(editor.calendarInstance!, 'hide'); + const calendarElm = document.body.querySelector('.vanilla-calendar'); editor.hide(); expect(calendarElm).toBeTruthy(); @@ -191,100 +216,108 @@ describe('DateEditor', () => { it('should show the DOM element when the "show" method is called', () => { editor = new DateEditor(editorArguments); - const spy = jest.spyOn(editor.flatInstance, 'open'); - const calendarElm = document.body.querySelector('.flatpickr-calendar'); - editor.show(); - editor.focus(); - expect(gridStub.focus).toHaveBeenCalled(); - expect(calendarElm).toBeTruthy(); - expect(spy).toHaveBeenCalled(); - }); + jest.runAllTimers(); - it('should enable Dark Mode and expect ".slick-dark-mode" CSS class to be found on parent element', () => { - gridOptionMock.darkMode = true; - editor = new DateEditor(editorArguments); - const spy = jest.spyOn(editor.flatInstance, 'open'); - const calendarElm = document.body.querySelector('.flatpickr-calendar'); + const spy = jest.spyOn(editor.calendarInstance!, 'show'); + const calendarElm = document.body.querySelector('.vanilla-calendar'); editor.show(); editor.focus(); expect(gridStub.focus).toHaveBeenCalled(); - expect(calendarElm?.classList.contains('slick-dark-mode')).toBeTruthy(); + expect(calendarElm).toBeTruthy(); expect(spy).toHaveBeenCalled(); }); - it('should call the "changeEditorOption" method and expect new option to be merged with the previous Editor options and also expect to call Flatpickr "set" method', () => { + it('should call the "changeEditorOption" method and expect new option to be merged with the previous Editor options', () => { editor = new DateEditor(editorArguments); - const spy = jest.spyOn(editor.flatInstance, 'set'); - const calendarElm = document.body.querySelector('.flatpickr-calendar'); - editor.changeEditorOption('minDate', 'today'); + const calendarElm = document.body.querySelector('.vanilla-calendar'); + editor.changeEditorOption('range', { disablePast: true }); + editor.changeEditorOption('selected', { dates: ['2001-02-04'], month: 2 }); expect(calendarElm).toBeTruthy(); - expect(spy).toHaveBeenCalledWith('minDate', 'today'); + expect(editor.pickerOptions.settings?.range?.disablePast).toBeTruthy(); + expect(editor.pickerOptions.settings?.selected).toEqual({ dates: ['2001-02-04'], month: 2 }); + + editor.changeEditorOption('range', { edgesOnly: true }); + editor.changeEditorOption('selected', { dates: ['2020-03-10', 'today'] }); + + expect(editor.pickerOptions.settings?.range).toEqual({ disablePast: true, edgesOnly: true }); + expect(editor.pickerOptions.settings?.selected).toEqual({ dates: ['2020-03-10', 'today'], month: 2 }); }); describe('isValueChanged method', () => { it('should return True when date is changed in the picker', () => { - // change to allow input value only for testing purposes & use the regular flatpickr input to test that one too - mockColumn.editor!.editorOptions = { allowInput: true, altInput: false }; + const dateMock = '2024-04-02'; mockItemData = { id: 1, startDate: '2001-01-02T11:02:02.000Z', isActive: true }; editor = new DateEditor(editorArguments); + jest.runAllTimers(); + editor.loadValue(mockItemData); editor.focus(); - const editorInputElm = divContainer.querySelector('.flatpickr input') as HTMLInputElement; + const editorInputElm = editor.editorDomElement; editorInputElm.value = '2024-04-02T16:02:02.239Z'; - editorInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); + editor.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: [dateMock], selectedHours: 11, selectedMinutes: 2 } as unknown as VanillaCalendar); + editor.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: [dateMock], selectedHours: 11, selectedMinutes: 2, hide: jest.fn() } as unknown as VanillaCalendar); expect(editor.isValueChanged()).toBe(true); expect(editor.isValueTouched()).toBe(true); }); it('should return True when date is reset by the clear date button', () => { - // change to allow input value only for testing purposes & use the regular flatpickr input to test that one too - mockColumn.editor!.editorOptions = { allowInput: true, altInput: false }; mockItemData = { id: 1, startDate: '2001-01-02T11:02:02.000Z', isActive: true }; editor = new DateEditor(editorArguments); + jest.runAllTimers(); + editor.loadValue(mockItemData); editor.focus(); - const clearBtnElm = divContainer.querySelector('.btn.icon-clear') as HTMLInputElement; - const editorInputElm = divContainer.querySelector('.flatpickr input') as HTMLInputElement; + const clearBtnElm = divContainer.querySelector('.btn-clear') as HTMLInputElement; + const editorInputElm = divContainer.querySelector('input.date-picker') as HTMLInputElement; clearBtnElm.click(); - editorInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); + editor.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: [] } as unknown as VanillaCalendar); + editor.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: [], hide: jest.fn() } as unknown as VanillaCalendar); + expect(editor.calendarInstance?.settings.selected.dates).toEqual([]); expect(editorInputElm.value).toBe(''); expect(editor.isValueChanged()).toBe(true); expect(editor.isValueTouched()).toBe(true); }); it('should also return True when date is reset by the clear date button even if the previous date was empty', () => { - // change to allow input value only for testing purposes & use the regular flatpickr input to test that one too - mockColumn.editor!.editorOptions = { allowInput: true, altInput: false }; mockItemData = { id: 1, startDate: '', isActive: true }; editor = new DateEditor(editorArguments); + jest.runAllTimers(); + editor.loadValue(mockItemData); editor.focus(); - const clearBtnElm = divContainer.querySelector('.btn.icon-clear') as HTMLInputElement; - const editorInputElm = divContainer.querySelector('.flatpickr input') as HTMLInputElement; + const clearBtnElm = divContainer.querySelector('.btn-clear') as HTMLInputElement; + const editorInputElm = divContainer.querySelector('input.date-picker') as HTMLInputElement; + editor.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: [] } as unknown as VanillaCalendar); + editor.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: [], hide: jest.fn() } as unknown as VanillaCalendar); clearBtnElm.click(); expect(editorInputElm.value).toBe(''); + expect(editor.calendarInstance?.settings.selected.dates).toEqual([]); expect(editor.isValueChanged()).toBe(true); expect(editor.isValueTouched()).toBe(true); }); it('should return False when date in the picker is the same as the current date', () => { - mockItemData = { id: 1, startDate: '2001-01-02T11:02:02.000Z', isActive: true }; - mockColumn.editor!.editorOptions = { allowInput: true }; // change to allow input value only for testing purposes + mockItemData = { id: 1, startDate: '2001-01-02', isActive: true }; + mockColumn.type = FieldType.dateIso; editor = new DateEditor(editorArguments); + jest.runAllTimers(); + editor.loadValue(mockItemData); - const editorInputElm = divContainer.querySelector('input.flatpickr-alt-input') as HTMLInputElement; - editorInputElm.value = '2001-01-02T11:02:02.000Z'; - editorInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); + + const editorInputElm = divContainer.querySelector('input.date-picker') as HTMLInputElement; + editorInputElm.value = '2001-01-02'; + editor.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: ['2001-01-02'] } as unknown as VanillaCalendar); + editor.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: ['2001-01-02'], hide: jest.fn() } as unknown as VanillaCalendar); expect(editor.isValueChanged()).toBe(false); expect(editor.isValueTouched()).toBe(true); @@ -293,13 +326,16 @@ describe('DateEditor', () => { it('should return False when input date is invalid', () => { mockItemData = { id: 1, startDate: '1900-02-32', isActive: true }; mockColumn.type = FieldType.dateUs; - mockColumn.editor!.editorOptions = { allowInput: true }; // change to allow input value only for testing purposes + const dateMock = '1900-02-32'; editor = new DateEditor(editorArguments); + jest.runAllTimers(); + editor.loadValue(mockItemData); - const editorInputElm = divContainer.querySelector('input.flatpickr-alt-input') as HTMLInputElement; - editorInputElm.value = '1900-02-32'; - editorInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); + const editorInputElm = divContainer.querySelector('input.date-picker') as HTMLInputElement; + editorInputElm.value = dateMock; + editor.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: [dateMock] } as unknown as VanillaCalendar); + editor.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: [dateMock], hide: jest.fn() } as unknown as VanillaCalendar); expect(editor.isValueChanged()).toBe(false); expect(editor.isValueTouched()).toBe(true); @@ -314,25 +350,27 @@ describe('DateEditor', () => { const newDate = new Date(Date.UTC(2001, 0, 2, 16, 2, 2, 0)); editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.applyValue(mockItemData, newDate); // @ts-ignore:2349 - expect(mockItemData).toEqual({ id: 1, startDate: moment(newDate).format('YYYY-MM-DD'), isActive: true }); + expect(mockItemData).toEqual({ id: 1, startDate: format(newDate, 'YYYY-MM-DD'), isActive: true }); }); it('should apply the value to the startDate property with "outputType" format with a field having dot notation (complex object) that passes validation', () => { mockColumn.editor!.validator = null as any; mockColumn.type = FieldType.date; - mockColumn.outputType = FieldType.dateTimeIsoAmPm; + mockColumn.outputType = FieldType.dateTimeShortEuro; mockColumn.field = 'employee.startDate'; mockItemData = { id: 1, employee: { startDate: '2001-04-05T11:33:42.000Z' }, isActive: true }; - const newDate = new Date(Date.UTC(2001, 0, 2, 16, 2, 2, 0)); + const newDate = new Date(Date.UTC(2001, 10, 23, 16, 2, 2, 0)); editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.applyValue(mockItemData, newDate); // @ts-ignore:2349 - expect(mockItemData).toEqual({ id: 1, employee: { startDate: moment(newDate).format('YYYY-MM-DD hh:mm:ss a') }, isActive: true }); + expect(mockItemData).toEqual({ id: 1, employee: { startDate: format(newDate, 'D/M/YYYY HH:mm') }, isActive: true }); }); it('should apply the value to the startDate property with output format defined by "saveOutputType" when it passes validation', () => { @@ -343,10 +381,11 @@ describe('DateEditor', () => { const newDate = new Date(Date.UTC(2001, 0, 2, 16, 2, 2, 0)); editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.applyValue(mockItemData, newDate); // @ts-ignore:2349 - expect(mockItemData).toEqual({ id: 1, startDate: moment(newDate).format('YYYY-MM-DD hh:mm:ss a'), isActive: true }); + expect(mockItemData).toEqual({ id: 1, startDate: format(newDate, 'YYYY-MM-DD hh:mm:ss a', 'en-US'), isActive: true }); }); it('should return item data with an empty string in its value when it fails the custom validation', () => { @@ -359,6 +398,7 @@ describe('DateEditor', () => { mockItemData = { id: 1, startDate: '2001-04-05T11:33:42.000Z', isActive: true }; editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.applyValue(mockItemData, '2001-01-02T16:02:02.000+05:00'); expect(mockItemData).toEqual({ id: 1, startDate: '', isActive: true }); @@ -371,6 +411,7 @@ describe('DateEditor', () => { mockItemData = { id: 1, startDate: '2001-01-02T16:02:02.000+05:00', isActive: true }; editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.loadValue(mockItemData); const output = editor.serializeValue(); @@ -381,6 +422,7 @@ describe('DateEditor', () => { mockItemData = { id: 1, startDate: '', isActive: true }; editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.loadValue(mockItemData); const output = editor.serializeValue(); @@ -391,6 +433,7 @@ describe('DateEditor', () => { mockItemData = { id: 1, startDate: null, isActive: true }; editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.loadValue(mockItemData); const output = editor.serializeValue(); @@ -403,6 +446,7 @@ describe('DateEditor', () => { mockItemData = { id: 1, employee: { startDate: '2001-01-02T16:02:02.000+05:00' }, isActive: true }; editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.loadValue(mockItemData); const output = editor.serializeValue(); @@ -421,6 +465,7 @@ describe('DateEditor', () => { const spy = jest.spyOn(gridStub.getEditorLock(), 'commitCurrentEdit'); editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.loadValue(mockItemData); editor.setValue('2022-03-02T16:02:02.000+05:00'); editor.save(); @@ -434,6 +479,7 @@ describe('DateEditor', () => { const spy = jest.spyOn(editorArguments, 'commitChanges'); editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.loadValue(mockItemData); editor.setValue('2022-03-02T16:02:02.000+05:00'); editor.save(); @@ -448,24 +494,27 @@ describe('DateEditor', () => { const spy = jest.spyOn(gridStub.getEditorLock(), 'commitCurrentEdit'); editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.loadValue(mockItemData); editor.save(); expect(spy).not.toHaveBeenCalled(); }); - it('should not throw any error when date is invalid when lower than required "minDate" defined in the "editorOptions" and "autoCommitEdit" is enabled', () => { - // change to allow input value only for testing purposes & use the regular flatpickr input to test that one too - mockColumn.editor!.editorOptions = { minDate: 'today', altInput: true }; + it('should not throw any error when date is lower than required "minDate" defined in the "editorOptions" and "autoCommitEdit" is enabled', () => { + mockColumn.editor!.editorOptions = { range: { min: 'today' } }; mockItemData = { id: 1, startDate: '500-01-02T11:02:02.000Z', isActive: true }; gridOptionMock.autoCommitEdit = true; gridOptionMock.autoEdit = true; gridOptionMock.editable = true; editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.loadValue(mockItemData); - editor.flatInstance.toggle(); - const editorInputElm = divContainer.querySelector('.flatpickr input') as HTMLInputElement; + editor.calendarInstance?.show(); + const editorInputElm = divContainer.querySelector('input.date-picker') as HTMLInputElement; + editor.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: [] } as unknown as VanillaCalendar); + editor.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: [], hide: jest.fn() } as unknown as VanillaCalendar); expect(editor.pickerOptions).toBeTruthy(); expect(editorInputElm.value).toBe(''); @@ -473,9 +522,9 @@ describe('DateEditor', () => { }); it('should not throw any error when date is invalid when lower than required "minDate" defined in the global default editorOptions and "autoCommitEdit" is enabled', () => { - // change to allow input value only for testing purposes & use the regular flatpickr input to test that one too + // change to allow input value only for testing purposes & use the regular date picker input to test that one too gridOptionMock.defaultEditorOptions = { - date: { minDate: 'today', altInput: true } + date: { range: { min: 'today' } } }; mockItemData = { id: 1, startDate: '500-01-02T11:02:02.000Z', isActive: true }; gridOptionMock.autoCommitEdit = true; @@ -483,9 +532,12 @@ describe('DateEditor', () => { gridOptionMock.editable = true; editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.loadValue(mockItemData); - editor.flatInstance.toggle(); - const editorInputElm = divContainer.querySelector('.flatpickr input') as HTMLInputElement; + editor.calendarInstance?.show(); + const editorInputElm = divContainer.querySelector('input.date-picker') as HTMLInputElement; + editor.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: [] } as unknown as VanillaCalendar); + editor.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: [], hide: jest.fn() } as unknown as VanillaCalendar); expect(editor.pickerOptions).toBeTruthy(); expect(editorInputElm.value).toBe(''); @@ -497,6 +549,7 @@ describe('DateEditor', () => { it('should return False when field is required and field is empty', () => { mockColumn.editor!.required = true; editor = new DateEditor(editorArguments); + jest.runAllTimers(); const validation = editor.validate(null, ''); expect(validation).toEqual({ valid: false, msg: 'Field is required' }); @@ -505,6 +558,7 @@ describe('DateEditor', () => { it('should return True when field is required and input is a valid input value', () => { mockColumn.editor!.required = true; editor = new DateEditor(editorArguments); + jest.runAllTimers(); const validation = editor.validate(null, 'text'); expect(validation).toEqual({ valid: true, msg: null }); @@ -512,36 +566,20 @@ describe('DateEditor', () => { }); describe('with different locale', () => { - it('should display a console warning when locale is not previously imported', (done) => { - const consoleSpy = jest.spyOn(global.console, 'warn').mockReturnValue(); - - gridOptionMock.translater = translateService; - - translateService.use('zz-yy'); // will be trimmed to 2 chars "zz" - editor = new DateEditor(editorArguments); - setTimeout(() => { - expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining(`[Slickgrid-Universal] Flatpickr missing locale imports (zz), will revert to English as the default locale.`)); - done(); - }); - }); - it('should display text in new locale', async () => { - await (await import('flatpickr/dist/l10n/fr')).French; gridOptionMock.translater = translateService; translateService.use('fr'); editor = new DateEditor(editorArguments); + jest.runAllTimers(); - const spy = jest.spyOn(editor.flatInstance, 'open'); - const calendarElm = document.body.querySelector('.flatpickr-calendar') as HTMLDivElement; - const selectonOptionElms = calendarElm.querySelectorAll(' .flatpickr-monthDropdown-months option'); - - editor.show(); + const calendarElm = document.body.querySelector('.vanilla-calendar') as HTMLDivElement; + const monthElm = calendarElm.querySelector('.vanilla-calendar-month') as HTMLButtonElement; expect(calendarElm).toBeTruthy(); - expect(selectonOptionElms.length).toBe(12); - expect(selectonOptionElms[0].textContent).toBe('janvier'); - expect(spy).toHaveBeenCalled(); + expect(monthElm).toBeTruthy(); + expect(editor.calendarInstance?.settings.lang).toBe('fr'); + // expect(monthElm.textContent).toBe('janvier'); }); }); }); @@ -566,6 +604,7 @@ describe('DateEditor', () => { } as any); mockColumn.type = FieldType.dateIso; editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.setValue('2001-01-02', true); expect(editor.getValue()).toContain('2001-01-02'); @@ -583,6 +622,7 @@ describe('DateEditor', () => { } as any); editor = new DateEditor(editorArguments); + jest.runAllTimers(); const disableSpy = jest.spyOn(editor, 'disable'); editor.show(); @@ -602,6 +642,7 @@ describe('DateEditor', () => { } as any); editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.loadValue(mockItemData); const disableSpy = jest.spyOn(editor, 'disable'); editor.show(); @@ -613,8 +654,8 @@ describe('DateEditor', () => { formValues: { startDate: '' }, editors: {}, triggeredBy: 'user', }, expect.anything()); expect(disableSpy).toHaveBeenCalledWith(true); - expect(editor.flatInstance._input.disabled).toEqual(true); - expect(editor.flatInstance._input.value).toEqual(''); + expect(editor.calendarInstance?.HTMLInputElement?.disabled).toEqual(true); + expect(editor.calendarInstance?.HTMLInputElement?.value).toEqual(''); }); it('should call "show" and expect the DOM element to become disabled and empty when "onBeforeEditCell" returns false and also expect "onBeforeComposite" to not be called because the value is blank', () => { @@ -631,6 +672,7 @@ describe('DateEditor', () => { }; editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.loadValue(mockItemData); const disableSpy = jest.spyOn(editor, 'disable'); editor.show(); @@ -639,8 +681,8 @@ describe('DateEditor', () => { expect(onBeforeEditSpy).toHaveBeenCalledWith({ ...activeCellMock, column: mockColumn, item: mockItemData, grid: gridStub, target: 'composite', compositeEditorOptions: editorArguments.compositeEditorOptions }); expect(onCompositeEditorSpy).not.toHaveBeenCalled(); expect(disableSpy).toHaveBeenCalledWith(true); - expect(editor.flatInstance._input.disabled).toEqual(true); - expect(editor.flatInstance._input.value).toEqual(''); + expect(editor.calendarInstance?.HTMLInputElement?.disabled).toEqual(true); + expect(editor.calendarInstance?.HTMLInputElement?.value).toEqual(''); }); it('should call "disable" method and expect the DOM element to become disabled and have an empty formValues be passed in the onCompositeEditorChange event', () => { @@ -654,6 +696,7 @@ describe('DateEditor', () => { }; editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.loadValue({ ...mockItemData, startDate: '2020-01-01' }); editor.show(); editor.disable(); @@ -663,13 +706,13 @@ describe('DateEditor', () => { ...activeCellMock, column: mockColumn, item: mockItemData, grid: gridStub, formValues: {}, editors: {}, triggeredBy: 'user', }, expect.anything()); - expect(editor.flatInstance._input.disabled).toEqual(true); - expect(editor.flatInstance._input.value).toEqual(''); + expect(editor.calendarInstance?.HTMLInputElement?.disabled).toEqual(true); + expect(editor.calendarInstance?.HTMLInputElement?.value).toEqual(''); }); it('should expect "onCompositeEditorChange" to have been triggered with the new value showing up in its "formValues" object', () => { const activeCellMock = { row: 0, cell: 0 }; - mockColumn.editor!.editorOptions = { allowInput: true, altInput: false }; + const dateMock = '2001-01-02'; mockColumn.type = FieldType.dateIso; const getCellSpy = jest.spyOn(gridStub, 'getActiveCell').mockReturnValue(activeCellMock); const onBeforeEditSpy = jest.spyOn(gridStub.onBeforeEditCell, 'notify').mockReturnValue({ @@ -679,20 +722,22 @@ describe('DateEditor', () => { getReturnValue: () => false } as any); gridOptionMock.autoCommitEdit = true; - mockItemData = { id: 1, startDate: '2001-01-02', isActive: true }; + mockItemData = { id: 1, startDate: dateMock, isActive: true }; editor = new DateEditor(editorArguments); + jest.runAllTimers(); editor.loadValue(mockItemData); editor.focus(); - const editorInputElm = divContainer.querySelector('.flatpickr input') as HTMLInputElement; - editorInputElm.value = '2001-01-02'; - editorInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); + const editorInputElm = divContainer.querySelector('input.date-picker') as HTMLInputElement; + editorInputElm.value = dateMock; + editor.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: [dateMock] } as unknown as VanillaCalendar); + editor.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: editorInputElm, selectedDates: [dateMock], hide: jest.fn() } as unknown as VanillaCalendar); expect(getCellSpy).toHaveBeenCalled(); expect(onBeforeEditSpy).toHaveBeenCalledWith({ ...activeCellMock, column: mockColumn, item: mockItemData, grid: gridStub, target: 'composite', compositeEditorOptions: editorArguments.compositeEditorOptions }); expect(onCompositeEditorSpy).toHaveBeenCalledWith({ ...activeCellMock, column: mockColumn, item: mockItemData, grid: gridStub, - formValues: { startDate: '2001-01-02' }, editors: {}, triggeredBy: 'user', + formValues: { startDate: dateMock }, editors: {}, triggeredBy: 'user', }, expect.anything()); }); }); diff --git a/packages/common/src/editors/__tests__/floatEditor.spec.ts b/packages/common/src/editors/__tests__/floatEditor.spec.ts index a0b655538..24936def2 100644 --- a/packages/common/src/editors/__tests__/floatEditor.spec.ts +++ b/packages/common/src/editors/__tests__/floatEditor.spec.ts @@ -101,7 +101,7 @@ describe('FloatEditor', () => { editor = new FloatEditor(editorArguments); const editorElm = divContainer.querySelector('input.editor-text.editor-price') as HTMLInputElement; - expect(editorElm.ariaLabel).toBe('Price Number Editor'); + expect(editorElm.ariaLabel).toBe('Price Input Editor'); }); it('should initialize the editor and focus on the element after a small delay', () => { diff --git a/packages/common/src/editors/__tests__/inputEditor.spec.ts b/packages/common/src/editors/__tests__/inputEditor.spec.ts index 1b592357f..52bc4d6df 100644 --- a/packages/common/src/editors/__tests__/inputEditor.spec.ts +++ b/packages/common/src/editors/__tests__/inputEditor.spec.ts @@ -390,6 +390,24 @@ describe('InputEditor (TextEditor)', () => { expect(spyCommit).toHaveBeenCalled(); expect(spySave).toHaveBeenCalled(); }); + + it('should call "getEditorLock" and "save" methods when "hasAutoCommitEdit" is enabled and the event "blur" is triggered', () => { + mockItemData = { id: 1, title: 'task', isActive: true }; + gridOptionMock.autoCommitEdit = true; + const spyCommit = jest.spyOn(gridStub.getEditorLock(), 'commitCurrentEdit'); + + editor = new InputEditor(editorArguments, 'text'); + editor.loadValue(mockItemData); + editor.setValue('task 21'); + const spySave = jest.spyOn(editor, 'save'); + const editorElm = editor.editorDomElement; + + editorElm.dispatchEvent(new (window.window as any).Event('blur')); + jest.runAllTimers(); // fast-forward timer + + expect(spyCommit).toHaveBeenCalled(); + expect(spySave).toHaveBeenCalled(); + }); }); describe('validate method', () => { diff --git a/packages/common/src/editors/__tests__/integerEditor.spec.ts b/packages/common/src/editors/__tests__/integerEditor.spec.ts index 3a98aa326..2d81e32cc 100644 --- a/packages/common/src/editors/__tests__/integerEditor.spec.ts +++ b/packages/common/src/editors/__tests__/integerEditor.spec.ts @@ -101,7 +101,7 @@ describe('IntegerEditor', () => { editor = new IntegerEditor(editorArguments); const editorElm = divContainer.querySelector('input.editor-text.editor-price') as HTMLInputElement; - expect(editorElm.ariaLabel).toBe('Price Slider Editor'); + expect(editorElm.ariaLabel).toBe('Price Input Editor'); }); it('should initialize the editor and focus on the element after a small delay', () => { diff --git a/packages/common/src/editors/__tests__/multipleSelectEditor.spec.ts b/packages/common/src/editors/__tests__/multipleSelectEditor.spec.ts index 2c2efaa12..242246506 100644 --- a/packages/common/src/editors/__tests__/multipleSelectEditor.spec.ts +++ b/packages/common/src/editors/__tests__/multipleSelectEditor.spec.ts @@ -89,11 +89,11 @@ describe('MultipleSelectEditor', () => { gridOptionMock.translater = translateService; editor = new MultipleSelectEditor(editorArguments, 0); const editorCount = document.body.querySelectorAll('select.ms-filter.editor-gender').length; - const spy = jest.spyOn(editor, 'show'); + jest.runAllTimers(); // fast-forward timer - expect(spy).toHaveBeenCalled(); expect(editorCount).toBe(1); + expect(editor.msInstance?.getOptions().isOpen).toBeTruthy(); }); it('should call "setValue" with a single string and expect the string to be returned as an array when calling "getValue"', () => { diff --git a/packages/common/src/editors/__tests__/selectEditor.spec.ts b/packages/common/src/editors/__tests__/selectEditor.spec.ts index 5e622622d..3562cbf5c 100644 --- a/packages/common/src/editors/__tests__/selectEditor.spec.ts +++ b/packages/common/src/editors/__tests__/selectEditor.spec.ts @@ -41,6 +41,7 @@ const gridStub = { render: jest.fn(), onBeforeEditCell: new SlickEvent(), onCompositeEditorChange: new SlickEvent(), + sanitizeHtmlString: (str) => str, } as unknown as SlickGrid; describe('SelectEditor', () => { @@ -630,6 +631,38 @@ describe('SelectEditor', () => { expect(saveSpy).toHaveBeenCalledWith(false); }); + it('should cancel changes when Escape key is pressed and should not call "save()"', () => { + mockItemData = { id: 1, gender: 'male', isActive: true }; + gridOptionMock.autoCommitEdit = false; + + editor = new SelectEditor(editorArguments, true); + const cancelSpy = jest.spyOn(editor, 'cancel'); + const saveSpy = jest.spyOn(editor, 'save'); + + editor.loadValue(mockItemData); + editor.msInstance?.close('key.escape'); + editor.destroy(); + + expect(cancelSpy).toHaveBeenCalled(); + expect(saveSpy).not.toHaveBeenCalled(); + }); + + it('should not "save()" when clicking ouside the select on body', () => { + mockItemData = { id: 1, gender: 'male', isActive: true }; + gridOptionMock.autoCommitEdit = false; + + editor = new SelectEditor(editorArguments, true); + const cancelSpy = jest.spyOn(editor, 'cancel'); + const saveSpy = jest.spyOn(editor, 'save'); + + editor.loadValue(mockItemData); + editor.msInstance?.close('body.click'); + editor.destroy(); + + expect(cancelSpy).not.toHaveBeenCalled(); + expect(saveSpy).not.toHaveBeenCalled(); + }); + it('should not call "commitCurrentEdit" when "hasAutoCommitEdit" is disabled', () => { mockItemData = { id: 1, gender: 'male', isActive: true }; gridOptionMock.autoCommitEdit = false; @@ -840,7 +873,7 @@ describe('SelectEditor', () => { it('should create the multi-select editor with a default search term and have the HTML rendered when "enableRenderHtml" is set', () => { mockColumn.editor = { enableRenderHtml: true, - collection: [{ value: true, label: 'True', labelPrefix: ` ` }, { value: false, label: 'False' }], + collection: [{ value: true, label: 'True', labelPrefix: ` ` }, { value: false, label: 'False' }], customStructure: { value: 'isEffort', label: 'label', @@ -854,41 +887,13 @@ describe('SelectEditor', () => { editorBtnElm.click(); expect(editorListElm.length).toBe(2); - expect(editorListElm[0].innerHTML).toBe(' True'); - }); - - it('should create the multi-select editor with a default search term and have the HTML rendered and sanitized when "enableRenderHtml" is set and has ` }, { isEffort: false, label: 'False' }], - collectionOptions: { - separatorBetweenTextLabels: ': ', - includePrefixSuffixToSelectedValues: true, - }, - customStructure: { - value: 'isEffort', - label: 'label', - labelPrefix: 'labelPrefix', - }, - }; - mockItemData = { id: 1, gender: 'male', isEffort: false }; - - editor = new SelectEditor(editorArguments, true, 0); - editor.loadValue(mockItemData); - editor.setValue([false]); - const editorBtnElm = divContainer.querySelector('.ms-parent.ms-filter.editor-gender button.ms-choice') as HTMLButtonElement; - const editorListElm = divContainer.querySelectorAll(`[data-name=editor-gender].ms-drop ul>li span`); - editorBtnElm.click(); - - expect(editor.getValue()).toEqual(['']); - expect(editorListElm.length).toBe(2); - expect(editorListElm[0].innerHTML).toBe(' : True'); + expect(editorListElm[0].innerHTML).toBe(' True'); }); - it('should create the multi-select editor with a default search term and have the HTML rendered and sanitized when using a custom "sanitizer" and "enableRenderHtml" flag is set and has ` }, { isEffort: false, label: 'False' }], + collection: [{ isEffort: true, label: 'True', labelPrefix: ` ` }, { isEffort: false, label: 'False' }], collectionOptions: { separatorBetweenTextLabels: ': ', includePrefixSuffixToSelectedValues: true, @@ -900,7 +905,6 @@ describe('SelectEditor', () => { }, }; mockItemData = { id: 1, gender: 'male', isEffort: false }; - gridOptionMock.sanitizer = (dirtyHtml) => dirtyHtml.replace(/( ` }, { isEffort: false, label: 'False' }], + collection: [{ isEffort: true, label: 'True', labelPrefix: ` ` }, { isEffort: false, label: 'False' }], collectionOptions: { separatorBetweenTextLabels: ': ', includePrefixSuffixToSelectedValues: true, @@ -281,9 +282,9 @@ describe('SingleSelectEditor', () => { editorListElm[0].click(); expect(editorBtnElm).toBeTruthy(); - expect(editor.getValue()).toEqual(` : true`); + expect(editor.getValue()).toEqual(` : true`); expect(editorListElm.length).toBe(2); - expect(editorListElm[0].innerHTML).toBe(' : True'); + expect(editorListElm[0].innerHTML).toBe(' : True'); }); }); }); diff --git a/packages/common/src/editors/autocompleterEditor.ts b/packages/common/src/editors/autocompleterEditor.ts index 69b73fed8..91025a790 100644 --- a/packages/common/src/editors/autocompleterEditor.ts +++ b/packages/common/src/editors/autocompleterEditor.ts @@ -22,7 +22,6 @@ import type { } from '../interfaces/index'; import { textValidator } from '../editorValidators/textValidator'; import { addAutocompleteLoadingByOverridingFetch } from '../commonEditorFilter'; -import { sanitizeTextByAvailableSanitizer, } from '../services/domUtilities'; import { findOrDefault, getDescendantProperty, } from '../services/utilities'; import type { TranslaterService } from '../services/translater.service'; import { SlickEventData, type SlickGrid } from '../core/index'; @@ -516,7 +515,7 @@ export class AutocompleterEditor implements Ed // sanitize any unauthorized html tags like script and others // for the remaining allowed tags we'll permit all attributes - const sanitizedText = sanitizeTextByAvailableSanitizer(this.gridOptions, finalText) || ''; + const sanitizedText = this.grid.sanitizeHtmlString(finalText) || ''; const div = document.createElement('div'); div[isRenderHtmlEnabled ? 'innerHTML' : 'textContent'] = sanitizedText; @@ -530,7 +529,8 @@ export class AutocompleterEditor implements Ed this._editorInputGroupElm = createDomElement('div', { className: 'autocomplete-container input-group' }); const closeButtonGroupElm = createDomElement('span', { className: 'input-group-btn input-group-append', dataset: { clear: '' } }); - this._clearButtonElm = createDomElement('button', { type: 'button', className: 'btn btn-default icon-clear' }); + this._clearButtonElm = createDomElement('button', { type: 'button', className: 'btn btn-default btn-clear' }); + this._clearButtonElm.appendChild(createDomElement('i', { className: 'icon-clear' })); this._inputElm = createDomElement( 'input', { @@ -553,7 +553,7 @@ export class AutocompleterEditor implements Ed } this._bindEventService.bind(this._inputElm, 'focus', () => this._inputElm?.select()); - this._bindEventService.bind(this._inputElm, 'keydown', ((event: KeyboardEvent) => { + this._bindEventService.bind(this._inputElm, 'keydown', ((event: KeyboardEvent & { target: HTMLInputElement; }) => { this._lastInputKeyEvent = event; if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') { event.stopImmediatePropagation(); @@ -561,10 +561,8 @@ export class AutocompleterEditor implements Ed // in case the user wants to save even an empty value, // we need to subscribe to the onKeyDown event for that use case and clear the current value - if (this.columnEditor.alwaysSaveOnEnterKey) { - if (event.key === 'Enter') { - this._currentValue = null; - } + if (event.key === 'Enter' && event.target.value === '' && this.columnEditor.alwaysSaveOnEnterKey) { + this._currentValue = null; } }) as EventListener); diff --git a/packages/common/src/editors/dateEditor.ts b/packages/common/src/editors/dateEditor.ts index 0d52581c8..48a548188 100644 --- a/packages/common/src/editors/dateEditor.ts +++ b/packages/common/src/editors/dateEditor.ts @@ -1,10 +1,7 @@ import { BindingEventService } from '@slickgrid-universal/binding'; -import { createDomElement, destroyAllElementProps, emptyElement, setDeepValue } from '@slickgrid-universal/utils'; -import flatpickr from 'flatpickr'; -import type { BaseOptions as FlatpickrBaseOptions } from 'flatpickr/dist/types/options'; -import type { Instance as FlatpickrInstance } from 'flatpickr/dist/types/instance'; -import * as moment_ from 'moment-mini'; -const moment = (moment_ as any)['default'] || moment_; +import { createDomElement, emptyElement, extend, setDeepValue } from '@slickgrid-universal/utils'; +import { parse } from '@formkit/tempo'; +import { VanillaCalendar, type IOptions } from 'vanilla-calendar-picker'; import { Constants } from './../constants'; import { FieldType } from '../enums/index'; @@ -16,30 +13,31 @@ import type { EditorArguments, EditorValidator, EditorValidationResult, - FlatpickrOption, GridOption, + VanillaCalendarOption, } from './../interfaces/index'; -import { getDescendantProperty, mapFlatpickrDateFormatWithFieldType, mapMomentDateFormatWithFieldType, } from './../services/utilities'; +import { getDescendantProperty, } from './../services/utilities'; import type { TranslaterService } from '../services/translater.service'; import { SlickEventData, type SlickGrid } from '../core/index'; +import { setPickerDates } from '../commonEditorFilter'; +import { formatDateByFieldType, mapTempoDateFormatWithFieldType } from '../services/dateUtils'; /* - * An example of a date picker editor using Flatpickr - * https://chmln.github.io/flatpickr + * An example of a date picker editor using Vanilla-Calendar-Picker */ export class DateEditor implements Editor { protected _bindEventService: BindingEventService; protected _clearButtonElm!: HTMLButtonElement; protected _editorInputGroupElm!: HTMLDivElement; protected _inputElm!: HTMLInputElement; - protected _inputWithDataElm!: HTMLInputElement | null; protected _isValueTouched = false; + protected _lastClickIsDate = false; protected _lastTriggeredByClearDate = false; protected _originalDate?: string; - protected _pickerMergedOptions!: FlatpickrOption; - - flatInstance!: FlatpickrInstance; + protected _pickerMergedOptions!: IOptions; + calendarInstance?: VanillaCalendar; defaultDate?: string; + hasTimePicker = false; /** is the Editor disabled? */ disabled = false; @@ -86,8 +84,8 @@ export class DateEditor implements Editor { return this._inputElm; } - /** Get Flatpickr options passed to the editor by the user */ - get editorOptions(): FlatpickrOption { + /** Get options passed to the editor by the user */ + get editorOptions(): IOptions { return { ...this.gridOptions.defaultEditorOptions?.date, ...this.columnEditor?.editorOptions }; } @@ -95,7 +93,7 @@ export class DateEditor implements Editor { return this.gridOptions.autoCommitEdit ?? false; } - get pickerOptions(): FlatpickrOption { + get pickerOptions(): IOptions { return this._pickerMergedOptions; } @@ -104,112 +102,151 @@ export class DateEditor implements Editor { return this.columnEditor?.validator ?? this.columnDef?.validator; } - init(): void { + async init() { if (this.args && this.columnDef) { const compositeEditorOptions = this.args.compositeEditorOptions; const columnId = this.columnDef?.id ?? ''; - const gridOptions = (this.args.grid.getOptions() || {}) as GridOption; - this.defaultDate = (this.args.item) ? this.args.item[this.columnDef.field] : null; - const inputFormat = mapFlatpickrDateFormatWithFieldType(this.columnEditor.type || this.columnDef.type || FieldType.dateUtc); - const outputFormat = mapFlatpickrDateFormatWithFieldType(this.columnDef.outputType || this.columnEditor.type || this.columnDef.type || FieldType.dateUtc); - let currentLocale = this._translaterService?.getCurrentLanguage?.() || gridOptions.locale || 'en'; - if (currentLocale.length > 2) { - currentLocale = currentLocale.substring(0, 2); + const gridOptions: GridOption = this.args.grid.getOptions() || {}; + this.defaultDate = this.args.item?.[this.columnDef.field]; + const outputFieldType = this.columnDef.outputType || this.columnEditor.type || this.columnDef.type || FieldType.dateUtc; + const outputFormat = mapTempoDateFormatWithFieldType(outputFieldType); + const currentLocale = this._translaterService?.getCurrentLanguage?.() || gridOptions.locale || 'en'; + + // add the time picker when format is UTC (TZ - ISO8601) or has the 'h' (meaning hours) + if (outputFormat && (outputFormat === 'ISO8601' || outputFormat.toLowerCase().includes('h'))) { + this.hasTimePicker = true; } - - const pickerOptions: FlatpickrOption = { - defaultDate: this.defaultDate as string, - altInput: true, - altFormat: outputFormat, - dateFormat: inputFormat, - closeOnSelect: true, - wrap: true, - locale: currentLocale, - onChange: () => this.handleOnDateChange(), - errorHandler: (error: Error) => { - if (error.toString().includes('invalid locale')) { - console.warn(`[Slickgrid-Universal] Flatpickr missing locale imports (${currentLocale}), will revert to English as the default locale. - See Flatpickr Localization for more info, for example if we want to use French, then we can import it with: import 'flatpickr/dist/l10n/fr';`); + const pickerFormat = mapTempoDateFormatWithFieldType(this.hasTimePicker ? FieldType.dateTimeIsoAM_PM : FieldType.dateIso); + + const pickerOptions: IOptions = { + input: true, + jumpToSelectedDate: true, + sanitizer: (dirtyHtml) => this.grid.sanitizeHtmlString(dirtyHtml), + toggleSelected: false, + actions: { + clickDay: () => { + this._lastClickIsDate = true; + }, + changeToInput: (_e, self) => { + if (self.HTMLInputElement) { + let selectedDate = ''; + if (self.selectedDates[0]) { + selectedDate = self.selectedDates[0]; + self.HTMLInputElement.value = formatDateByFieldType(self.selectedDates[0], undefined, outputFieldType); + } else { + self.HTMLInputElement.value = ''; + } + + if (selectedDate && this.hasTimePicker) { + const tempoDate = parse(selectedDate, pickerFormat); + tempoDate.setHours(+(self.selectedHours || 0)); + tempoDate.setMinutes(+(self.selectedMinutes || 0)); + self.HTMLInputElement.value = formatDateByFieldType(tempoDate, undefined, outputFieldType); + } + + if (this._lastClickIsDate) { + this.handleOnDateChange(); + self.hide(); + } + } } - // for any other error do nothing - // Flatpickr is a little too sensitive and will throw an error when provided date is lower than minDate so just disregard the error completely - } + }, + settings: { + lang: currentLocale, + iso8601: false, + visibility: { + theme: this.gridOptions?.darkMode ? 'dark' : 'light', + positionToInput: 'auto', + weekend: false, + }, + }, }; - // merge options with optional user's custom options - this._pickerMergedOptions = { ...pickerOptions, ...(this.editorOptions as FlatpickrOption) }; - const inputCssClasses = `.editor-text.editor-${columnId}.form-control`; - if (this._pickerMergedOptions.altInput) { - this._pickerMergedOptions.altInputClass = 'flatpickr-alt-input form-control'; + // add the time picker when format includes time (hours/minutes) + if (this.hasTimePicker) { + pickerOptions.settings!.selection = { + time: 24 + }; } - this._editorInputGroupElm = createDomElement('div', { className: 'flatpickr input-group' }); + // merge options with optional user's custom options + this._pickerMergedOptions = extend(true, {}, pickerOptions, { settings: this.editorOptions, type: 'default' }); + + const inputCssClasses = `.editor-text.date-picker.editor-${columnId}.form-control.input-group-editor`; + this._editorInputGroupElm = createDomElement('div', { className: 'vanilla-picker input-group' }); const closeButtonGroupElm = createDomElement('span', { className: 'input-group-btn input-group-append', dataset: { clear: '' } }); - this._clearButtonElm = createDomElement('button', { type: 'button', className: 'btn btn-default icon-clear' }); + this._clearButtonElm = createDomElement('button', { type: 'button', className: 'btn btn-default btn-clear' }); + this._clearButtonElm.appendChild(createDomElement('i', { className: 'icon-clear' })); this._inputElm = createDomElement( 'input', { placeholder: this.columnEditor?.placeholder ?? '', title: this.columnEditor && this.columnEditor.title || '', className: inputCssClasses.replace(/\./g, ' '), - dataset: { input: '', defaultdate: this.defaultDate } + dataset: { input: '', defaultdate: this.defaultDate }, + readOnly: true, }, this._editorInputGroupElm ); + this.args.container.appendChild(this._editorInputGroupElm); + // show clear date button (unless user specifically doesn't want it) - if (!(this.editorOptions as FlatpickrOption)?.hideClearButton) { + if (!(this.columnEditor.editorOptions as any)?.hideClearButton) { closeButtonGroupElm.appendChild(this._clearButtonElm); this._editorInputGroupElm.appendChild(closeButtonGroupElm); - this._bindEventService.bind(this._clearButtonElm, 'click', () => this._lastTriggeredByClearDate = true); + this._bindEventService.bind(this._clearButtonElm, 'click', () => { + this.clear(); + this.handleOnDateChange(); + }); } - this.args.container.appendChild(this._editorInputGroupElm); - this.flatInstance = flatpickr(this._editorInputGroupElm, this._pickerMergedOptions as unknown as Partial); - - // add dark mode CSS class when enabled - if (this.gridOptions?.darkMode) { - this.flatInstance.calendarContainer.classList.add('slick-dark-mode'); - } - - // when we're using an alternate input to display data, we'll consider this input as the one to do the focus later on - // else just use the top one - this._inputWithDataElm = (this._pickerMergedOptions?.altInput) ? document.querySelector(`${inputCssClasses}.flatpickr-alt-input`) : this._inputElm; - - if (!compositeEditorOptions) { - setTimeout(() => { + setTimeout(() => { + this.calendarInstance = new VanillaCalendar(this._inputElm, this._pickerMergedOptions); + this.calendarInstance.init(); + if (!compositeEditorOptions) { this.show(); this.focus(); - }, 50); - } + } + if (this.calendarInstance) { + setPickerDates(this._inputElm, this.calendarInstance, this.defaultDate, this.columnDef, this.columnEditor); + this.calendarInstance.update({ + dates: true, + month: true, + year: true, + time: true, + }); + } + }); } } destroy() { this.hide(); this._bindEventService.unbindAll(); + this.calendarInstance?.destroy(); - if (typeof this.flatInstance?.destroy === 'function') { - this.flatInstance.destroy(); - if (this.flatInstance?.element) { - setTimeout(() => destroyAllElementProps(this.flatInstance)); - } - } emptyElement(this._editorInputGroupElm); - emptyElement(this._inputWithDataElm); emptyElement(this._inputElm); - this._editorInputGroupElm?.remove?.(); - this._inputWithDataElm?.remove?.(); - this._inputElm?.remove?.(); + this._editorInputGroupElm?.remove(); + this._inputElm?.remove(); + } + + clear() { + this._lastTriggeredByClearDate = true; + if (this.calendarInstance) { + this.calendarInstance.settings.selected.dates = []; + this._inputElm.value = ''; + } } disable(isDisabled = true) { const prevIsDisabled = this.disabled; this.disabled = isDisabled; - if (this.flatInstance?._input) { + if (this._inputElm) { if (isDisabled) { - this.flatInstance._input.setAttribute('disabled', 'disabled'); + this._inputElm.setAttribute('disabled', 'disabled'); this._clearButtonElm.disabled = true; // clear picker when it's newly disabled and not empty @@ -218,7 +255,7 @@ export class DateEditor implements Editor { this.reset('', true, true); } } else { - this.flatInstance._input.removeAttribute('disabled'); + this._inputElm.removeAttribute('disabled'); this._clearButtonElm.disabled = false; } } @@ -227,16 +264,15 @@ export class DateEditor implements Editor { /** * Dynamically change an Editor option, this is especially useful with Composite Editor * since this is the only way to change option after the Editor is created (for example dynamically change "minDate" or another Editor) - * @param {string} optionName - Flatpickr option name - * @param {newValue} newValue - Flatpickr new option value + * @param {string} optionName + * @param {newValue} newValue */ - changeEditorOption(optionName: keyof FlatpickrBaseOptions, newValue: any) { + changeEditorOption>(optionName: T, newValue: K) { if (!this.columnEditor.editorOptions) { this.columnEditor.editorOptions = {}; } this.columnEditor.editorOptions[optionName] = newValue; - this._pickerMergedOptions = { ...this._pickerMergedOptions, [optionName]: newValue }; - this.flatInstance.set(optionName, newValue); + this._pickerMergedOptions = extend(true, {}, this._pickerMergedOptions, { settings: { [optionName]: newValue } }); } focus() { @@ -245,22 +281,16 @@ export class DateEditor implements Editor { this.show(); this._inputElm?.focus(); - if (this._inputWithDataElm?.focus) { - this._inputWithDataElm.focus(); - this._inputWithDataElm.select(); - } } hide() { - if (this.flatInstance && typeof this.flatInstance.close === 'function') { - this.flatInstance.close(); - } + this.calendarInstance?.hide(); } show() { const isCompositeEditor = !!this.args?.compositeEditorOptions; - if (!isCompositeEditor && this.flatInstance && typeof this.flatInstance.open === 'function' && this.flatInstance._input) { - this.flatInstance.open(); + if (!isCompositeEditor && this.calendarInstance) { + this.calendarInstance.show(); } else if (isCompositeEditor) { // when it's a Composite Editor, we'll check if the Editor is editable (by checking onBeforeEditCell) and if not Editable we'll disable the Editor this.applyInputUsabilityState(); @@ -272,7 +302,9 @@ export class DateEditor implements Editor { } setValue(val: string, isApplyingValue = false, triggerOnCompositeEditorChange = true) { - this.flatInstance.setDate(val); + if (this.calendarInstance) { + setPickerDates(this._inputElm, this.calendarInstance, val, this.columnDef, this.columnEditor); + } if (isApplyingValue) { this.applyValue(this.args.item, this.serializeValue()); @@ -286,21 +318,21 @@ export class DateEditor implements Editor { } applyValue(item: any, state: any) { - const fieldName = this.columnDef && this.columnDef.field; - if (fieldName !== undefined) { - const outputTypeFormat = mapMomentDateFormatWithFieldType((this.columnDef && (this.columnDef.outputType || this.columnEditor.type || this.columnDef.type)) || FieldType.dateUtc); - const saveTypeFormat = mapMomentDateFormatWithFieldType((this.columnDef && (this.columnDef.saveOutputType || this.columnDef.outputType || this.columnEditor.type || this.columnDef.type)) || FieldType.dateUtc); - const isComplexObject = fieldName?.indexOf('.') > 0; // is the field a complex object, "address.streetNumber" + const fieldName = this.columnDef?.field; + if (this.columnDef && fieldName !== undefined) { + const saveFieldType = this.columnDef.saveOutputType || this.columnDef.outputType || this.columnEditor.type || this.columnDef.type || FieldType.dateUtc; + const outputFieldType = this.columnDef.outputType || this.columnEditor.type || this.columnDef.type || FieldType.dateUtc; + const isComplexObject = fieldName.indexOf('.') > 0; // is the field a complex object, "address.streetNumber" // validate the value before applying it (if not valid we'll set an empty string) const validation = this.validate(null, state); - const newValue = (state && validation && validation.valid) ? moment(state, outputTypeFormat).format(saveTypeFormat) : ''; + const newValue = (state && validation?.valid) ? formatDateByFieldType(state, outputFieldType, saveFieldType) : ''; // set the new value to the item datacontext if (isComplexObject) { // when it's a complex object, user could override the object path (where the editable object is located) // else we use the path provided in the Field Column Definition - const objectPath = this.columnEditor?.complexObjectPath ?? fieldName ?? ''; + const objectPath = this.columnEditor?.complexObjectPath ?? fieldName; setDeepValue(item, objectPath, newValue); } else { item[fieldName] = newValue; @@ -309,15 +341,12 @@ export class DateEditor implements Editor { } isValueChanged(): boolean { - const elmValue = this._inputElm.value; - const inputFormat = mapMomentDateFormatWithFieldType(this.columnEditor.type || this.columnDef?.type || FieldType.dateIso); - const outputTypeFormat = mapMomentDateFormatWithFieldType((this.columnDef && (this.columnDef.outputType || this.columnEditor.type || this.columnDef.type)) || FieldType.dateUtc); - const elmDateStr = elmValue ? moment(elmValue, inputFormat, false).format(outputTypeFormat) : ''; - const orgDateStr = this._originalDate ? moment(this._originalDate, inputFormat, false).format(outputTypeFormat) : ''; - if (elmDateStr === 'Invalid date' || orgDateStr === 'Invalid date') { - return false; + let isChanged = false; + const elmDateStr = this.getValue(); + + if (this.columnDef) { + isChanged = this._lastTriggeredByClearDate || (!(elmDateStr === '' && this._originalDate === '')) && (elmDateStr !== this._originalDate); } - const isChanged = this._lastTriggeredByClearDate || (!(elmDateStr === '' && orgDateStr === '')) && (elmDateStr !== orgDateStr); return isChanged; } @@ -327,15 +356,17 @@ export class DateEditor implements Editor { } loadValue(item: any) { - const fieldName = this.columnDef && this.columnDef.field; + const fieldName = this.columnDef?.field; - if (item && fieldName !== undefined) { + if (item && this.columnDef && fieldName !== undefined) { // is the field a complex object, "address.streetNumber" const isComplexObject = fieldName?.indexOf('.') > 0; - const value = (isComplexObject) ? getDescendantProperty(item, fieldName) : item[fieldName]; + const value = isComplexObject ? getDescendantProperty(item, fieldName) : item[fieldName]; + const inputFieldType = this.columnEditor.type || this.columnDef?.type || FieldType.dateIso; + const outputFieldType = this.columnDef.outputType || this.columnEditor.type || this.columnDef.type || FieldType.dateIso; - this._originalDate = value; - this.flatInstance.setDate(value); + this._originalDate = formatDateByFieldType(value, inputFieldType, outputFieldType); + this._inputElm.value = this._originalDate; } } @@ -345,11 +376,12 @@ export class DateEditor implements Editor { */ reset(value?: string, triggerCompositeEventWhenExist = true, clearByDisableCommand = false) { const inputValue = value ?? this._originalDate ?? ''; - if (this.flatInstance) { + if (this.calendarInstance) { this._originalDate = inputValue; - this.flatInstance.setDate(inputValue); + this.calendarInstance.settings.selected.dates = [inputValue]; if (!inputValue) { - this.flatInstance.clear(); + this.calendarInstance.settings.selected.dates = []; + this._inputElm.value = ''; } } this._isValueTouched = false; @@ -363,7 +395,7 @@ export class DateEditor implements Editor { save() { const validation = this.validate(); - const isValid = (validation && validation.valid) || false; + const isValid = validation?.valid ?? false; if (this.hasAutoCommitEdit && isValid) { // do not use args.commitChanges() as this sets the focus to the next row. @@ -375,22 +407,17 @@ export class DateEditor implements Editor { } serializeValue() { - const domValue: string = this._inputElm.value; - + const domValue = this.getValue(); if (!domValue) { return ''; } - const inputFormat = mapMomentDateFormatWithFieldType(this.columnEditor.type || this.columnDef?.type || FieldType.dateIso); - const outputTypeFormat = mapMomentDateFormatWithFieldType((this.columnDef && (this.columnDef.outputType || this.columnEditor.type || this.columnDef.type)) || FieldType.dateIso); - const value = moment(domValue, inputFormat, false).format(outputTypeFormat); - - return value; + return domValue; } validate(_targetElm?: any, inputValue?: any): EditorValidationResult { const isRequired = this.args?.compositeEditorOptions ? false : this.columnEditor.required; - const elmValue = (inputValue !== undefined) ? inputValue : this._inputElm?.value; + const elmValue = inputValue ?? this._inputElm?.value; const errorMsg = this.columnEditor.errorMessage; // when using Composite Editor, we also want to recheck if the field if disabled/enabled since it might change depending on other inputs on the composite form @@ -430,9 +457,8 @@ export class DateEditor implements Editor { protected handleOnDateChange() { this._isValueTouched = true; - const currentFlatpickrOptions = this.flatInstance?.config ?? this._pickerMergedOptions; - if (this.args && currentFlatpickrOptions?.closeOnSelect) { + if (this.args) { const compositeEditorOptions = this.args.compositeEditorOptions; if (compositeEditorOptions) { this.handleChangeOnCompositeEditor(compositeEditorOptions); diff --git a/packages/common/src/editors/editors.index.ts b/packages/common/src/editors/editors.index.ts index 1e4cee0be..3ea7648f3 100644 --- a/packages/common/src/editors/editors.index.ts +++ b/packages/common/src/editors/editors.index.ts @@ -18,7 +18,7 @@ export const Editors = { /** Checkbox Editor (uses native checkbox DOM element) */ checkbox: CheckboxEditor, - /** Date Picker Editor (which uses 3rd party lib "flatpickr") */ + /** Date Picker Editor (which uses 3rd party lib "vanilla-calendar-picker") */ date: DateEditor, /** Dual Input Editor, default input type is text but it could be (integer/float/number/password/text) */ diff --git a/packages/common/src/editors/floatEditor.ts b/packages/common/src/editors/floatEditor.ts index 8dde76ff7..55665b7aa 100644 --- a/packages/common/src/editors/floatEditor.ts +++ b/packages/common/src/editors/floatEditor.ts @@ -1,83 +1,13 @@ -import { createDomElement, toSentenceCase } from '@slickgrid-universal/utils'; - import type { EditorArguments, EditorValidationResult } from '../interfaces/index'; import { floatValidator } from '../editorValidators/floatValidator'; import { InputEditor } from './inputEditor'; import { getDescendantProperty } from '../services/utilities'; -const DEFAULT_DECIMAL_PLACES = 0; - export class FloatEditor extends InputEditor { constructor(protected readonly args: EditorArguments) { super(args, 'number'); } - /** Initialize the Editor */ - init() { - if (this.columnDef && this.columnEditor && this.args) { - const columnId = this.columnDef?.id ?? ''; - const compositeEditorOptions = this.args.compositeEditorOptions; - - this._input = createDomElement('input', { - type: 'number', autocomplete: 'off', ariaAutoComplete: 'none', - ariaLabel: this.columnEditor?.ariaLabel ?? `${toSentenceCase(columnId + '')} Number Editor`, - className: `editor-text editor-${columnId}`, - placeholder: this.columnEditor?.placeholder ?? '', - title: this.columnEditor?.title ?? '', - step: `${(this.columnEditor.valueStep !== undefined) ? this.columnEditor.valueStep : this.getInputDecimalSteps()}`, - }); - const cellContainer = this.args.container; - if (cellContainer && typeof cellContainer.appendChild === 'function') { - cellContainer.appendChild(this._input); - } - - this._bindEventService.bind(this._input, 'focus', () => this._input?.select()); - this._bindEventService.bind(this._input, 'keydown', ((event: KeyboardEvent) => { - this._lastInputKeyEvent = event; - if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') { - event.stopImmediatePropagation(); - } - }) as EventListener); - - // the lib does not get the focus out event for some reason - // so register it here - if (this.hasAutoCommitEdit && !compositeEditorOptions) { - this._bindEventService.bind(this._input, 'focusout', () => { - this._isValueTouched = true; - this.save(); - }); - } - - if (compositeEditorOptions) { - this._bindEventService.bind(this._input, ['input', 'paste'], this.handleOnInputChange.bind(this) as EventListener); - this._bindEventService.bind(this._input, 'wheel', this.handleOnMouseWheel.bind(this) as EventListener, { passive: true }); - } - } - } - - getDecimalPlaces(): number { - // returns the number of fixed decimal places or null - let rtn = this.columnEditor?.decimal ?? this.columnEditor?.params?.decimalPlaces ?? undefined; - - if (rtn === undefined) { - rtn = DEFAULT_DECIMAL_PLACES; - } - return (!rtn && rtn !== 0 ? null : rtn); - } - - getInputDecimalSteps(): string { - const decimals = this.getDecimalPlaces(); - let zeroString = ''; - for (let i = 1; i < decimals; i++) { - zeroString += '0'; - } - - if (decimals > 0) { - return `0.${zeroString}1`; - } - return '1'; - } - loadValue(item: any) { const fieldName = this.columnDef && this.columnDef.field; @@ -137,17 +67,4 @@ export class FloatEditor extends InputEditor { validator: this.validator, }); } - - // -- - // protected functions - // ------------------ - - /** When the input value changes (this will cover the input spinner arrows on the right) */ - protected handleOnMouseWheel(event: KeyboardEvent) { - this._isValueTouched = true; - const compositeEditorOptions = this.args.compositeEditorOptions; - if (compositeEditorOptions) { - this.handleChangeOnCompositeEditor(event, compositeEditorOptions); - } - } } \ No newline at end of file diff --git a/packages/common/src/editors/inputEditor.ts b/packages/common/src/editors/inputEditor.ts index dec519f7d..55c42969d 100644 --- a/packages/common/src/editors/inputEditor.ts +++ b/packages/common/src/editors/inputEditor.ts @@ -15,6 +15,8 @@ import { getDescendantProperty } from '../services/utilities'; import { textValidator } from '../editorValidators/textValidator'; import { SlickEventData, type SlickGrid } from '../core/index'; +const DEFAULT_DECIMAL_PLACES = 0; + /* * An example of a 'detached' editor. * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter. @@ -92,13 +94,18 @@ export class InputEditor implements Editor { const compositeEditorOptions = this.args.compositeEditorOptions; this._input = createDomElement('input', { - type: this._inputType || 'text', - autocomplete: 'off', ariaAutoComplete: 'none', + type: this._inputType || 'text', autocomplete: 'off', ariaAutoComplete: 'none', ariaLabel: this.columnEditor?.ariaLabel ?? `${toSentenceCase(columnId + '')} Input Editor`, + className: `editor-text editor-${columnId}`, placeholder: this.columnEditor?.placeholder ?? '', title: this.columnEditor?.title ?? '', - className: `editor-text editor-${columnId}`, }); + + // add "step" attribute when editor type is integer/float + if (this.inputType === 'number') { + this._input.step = `${(this.columnEditor.valueStep !== undefined) ? this.columnEditor.valueStep : this.getInputDecimalSteps()}`; + } + const cellContainer = this.args.container; if (cellContainer && typeof cellContainer.appendChild === 'function') { cellContainer.appendChild(this._input); @@ -113,10 +120,9 @@ export class InputEditor implements Editor { } }) as EventListener); - // the lib does not get the focus out event for some reason - // so register it here + // listen to focusout or blur to automatically call a save if (this.hasAutoCommitEdit && !compositeEditorOptions) { - this._bindEventService.bind(this._input, 'focusout', () => { + this._bindEventService.bind(this._input, ['focusout', 'blur'], () => { this._isValueTouched = true; this.save(); }); @@ -124,6 +130,11 @@ export class InputEditor implements Editor { if (compositeEditorOptions) { this._bindEventService.bind(this._input, ['input', 'paste'], this.handleOnInputChange.bind(this) as EventListener); + + // add an extra mousewheel listener when editor type is integer/float + if (this.inputType === 'number') { + this._bindEventService.bind(this._input, 'wheel', this.handleOnMouseWheel.bind(this) as EventListener, { passive: true }); + } } } @@ -157,6 +168,30 @@ export class InputEditor implements Editor { this._input?.focus(); } + getDecimalPlaces(): number { + // returns the number of fixed decimal places or null + let rtn = this.columnEditor?.decimal ?? this.columnEditor?.params?.decimalPlaces ?? undefined; + + if (rtn === undefined) { + rtn = DEFAULT_DECIMAL_PLACES; + } + return (!rtn && rtn !== 0 ? null : rtn); + } + + /** when editor is a float input editor, we'll want to know how many decimals to show */ + getInputDecimalSteps(): string { + const decimals = this.getDecimalPlaces(); + let zeroString = ''; + for (let i = 1; i < decimals; i++) { + zeroString += '0'; + } + + if (decimals > 0) { + return `0.${zeroString}1`; + } + return '1'; + } + show() { const isCompositeEditor = !!this.args?.compositeEditorOptions; if (isCompositeEditor) { @@ -338,4 +373,13 @@ export class InputEditor implements Editor { this._timer = setTimeout(() => this.handleChangeOnCompositeEditor(event, compositeEditorOptions), typingDelay); } } + + /** When the input value changes (this will cover the input spinner arrows on the right) */ + protected handleOnMouseWheel(event: KeyboardEvent) { + this._isValueTouched = true; + const compositeEditorOptions = this.args.compositeEditorOptions; + if (compositeEditorOptions) { + this.handleChangeOnCompositeEditor(event, compositeEditorOptions); + } + } } diff --git a/packages/common/src/editors/integerEditor.ts b/packages/common/src/editors/integerEditor.ts index 1ae1ccdec..d6752d60c 100644 --- a/packages/common/src/editors/integerEditor.ts +++ b/packages/common/src/editors/integerEditor.ts @@ -1,5 +1,3 @@ -import { createDomElement, toSentenceCase } from '@slickgrid-universal/utils'; - import type { EditorArguments, EditorValidationResult } from '../interfaces/index'; import { integerValidator } from '../editorValidators/integerValidator'; import { InputEditor } from './inputEditor'; @@ -10,49 +8,6 @@ export class IntegerEditor extends InputEditor { super(args, 'number'); } - /** Initialize the Editor */ - init() { - if (this.columnDef && this.columnEditor && this.args) { - const columnId = this.columnDef?.id ?? ''; - const compositeEditorOptions = this.args.compositeEditorOptions; - - this._input = createDomElement('input', { - type: 'number', autocomplete: 'off', ariaAutoComplete: 'none', - ariaLabel: this.columnEditor?.ariaLabel ?? `${toSentenceCase(columnId + '')} Slider Editor`, - placeholder: this.columnEditor?.placeholder ?? '', - title: this.columnEditor?.title ?? '', - step: `${(this.columnEditor.valueStep !== undefined) ? this.columnEditor.valueStep : '1'}`, - className: `editor-text editor-${columnId}`, - }); - const cellContainer = this.args.container; - if (cellContainer && typeof cellContainer.appendChild === 'function') { - cellContainer.appendChild(this._input); - } - - this._bindEventService.bind(this._input, 'focus', () => this._input?.select()); - this._bindEventService.bind(this._input, 'keydown', ((event: KeyboardEvent) => { - this._lastInputKeyEvent = event; - if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') { - event.stopImmediatePropagation(); - } - }) as EventListener); - - // the lib does not get the focus out event for some reason - // so register it here - if (this.hasAutoCommitEdit && !compositeEditorOptions) { - this._bindEventService.bind(this._input, 'focusout', () => { - this._isValueTouched = true; - this.save(); - }); - } - - if (compositeEditorOptions) { - this._bindEventService.bind(this._input, ['input', 'paste'], this.handleOnInputChange.bind(this) as EventListener); - this._bindEventService.bind(this._input, 'wheel', this.handleOnMouseWheel.bind(this) as EventListener, { passive: true }); - } - } - } - loadValue(item: any) { const fieldName = this.columnDef && this.columnDef.field; diff --git a/packages/common/src/editors/longTextEditor.ts b/packages/common/src/editors/longTextEditor.ts index 5ceaeb00e..2ca203515 100644 --- a/packages/common/src/editors/longTextEditor.ts +++ b/packages/common/src/editors/longTextEditor.ts @@ -52,14 +52,14 @@ export class LongTextEditor implements Editor { throw new Error('[Slickgrid-Universal] Something is wrong with this grid, an Editor must always have valid arguments.'); } this.grid = args.grid; - this.gridOptions = args.grid && args.grid.getOptions() as GridOption; + this.gridOptions = args.grid?.getOptions() as GridOption; const options = this.gridOptions || this.args.column.params || {}; if (options?.translater) { this._translater = options.translater; } // get locales provided by user in forRoot or else use default English locales via the Constants - this._locales = this.gridOptions && this.gridOptions.locales || Constants.locales; + this._locales = this.gridOptions?.locales || Constants.locales; this._bindEventService = new BindingEventService(); this.init(); @@ -258,7 +258,7 @@ export class LongTextEditor implements Editor { // validate the value before applying it (if not valid we'll set an empty string) const validation = this.validate(undefined, state); - const newValue = (validation && validation.valid) ? state : ''; + const newValue = validation?.valid ? state : ''; // set the new value to the item datacontext if (isComplexObject) { @@ -409,24 +409,24 @@ export class LongTextEditor implements Editor { this.disable(isCellEditable === false); } - protected handleKeyDown(event: KeyboardEvent) { - const key = event.key; + protected handleKeyDown(e: KeyboardEvent) { + const key = e.key; this._isValueTouched = true; if (!this.args.compositeEditorOptions) { - if ((key === 'Enter' && event.ctrlKey) || (event.ctrlKey && event.key.toUpperCase() === 'S')) { - event.preventDefault(); + if ((key === 'Enter' && e.ctrlKey) || (e.ctrlKey && e.key.toUpperCase() === 'S')) { + e.preventDefault(); this.save(); } else if (key === 'Escape') { - event.preventDefault(); + e.preventDefault(); this.cancel(); - } else if (key === 'Tab' && event.shiftKey) { - event.preventDefault(); + } else if (key === 'Tab' && e.shiftKey) { + e.preventDefault(); if (this.args && this.grid) { this.grid.navigatePrev(); } } else if (key === 'Tab') { - event.preventDefault(); + e.preventDefault(); if (this.args && this.grid) { this.grid.navigateNext(); } diff --git a/packages/common/src/editors/selectEditor.ts b/packages/common/src/editors/selectEditor.ts index 621adf1f5..76b960349 100644 --- a/packages/common/src/editors/selectEditor.ts +++ b/packages/common/src/editors/selectEditor.ts @@ -19,7 +19,7 @@ import type { Locale, SelectOption, } from './../interfaces/index'; -import { buildMsSelectCollectionList, CollectionService, findOrDefault, sanitizeTextByAvailableSanitizer, type TranslaterService } from '../services/index'; +import { buildMsSelectCollectionList, CollectionService, findOrDefault, type TranslaterService } from '../services/index'; import { getDescendantProperty, getTranslationPrefix, } from '../services/utilities'; import { SlickEventData, type SlickGrid } from '../core/index'; @@ -120,11 +120,18 @@ export class SelectEditor implements Editor { single: true, singleRadio: true, renderOptionLabelAsHtml: this.columnEditor?.enableRenderHtml ?? false, - sanitizer: (dirtyHtml: string) => sanitizeTextByAvailableSanitizer(this.gridOptions, dirtyHtml), + sanitizer: (dirtyHtml: string) => this.grid.sanitizeHtmlString(dirtyHtml), onClick: () => this._isValueTouched = true, onCheckAll: () => this._isValueTouched = true, onUncheckAll: () => this._isValueTouched = true, - onClose: () => { + onClose: (reason) => { + if (reason === 'key.escape' || reason === 'body.click' || (!this.hasAutoCommitEdit && !this.isValueChanged())) { + if (reason === 'key.escape') { + this.cancel(); + } + return; + } + if (compositeEditorOptions) { this.handleChangeOnCompositeEditor(compositeEditorOptions); } else { @@ -364,6 +371,12 @@ export class SelectEditor implements Editor { } } + cancel() { + if (this.args?.cancelChanges) { + this.args.cancelChanges(); + } + } + hide() { if (this._msInstance) { this._msInstance.close(); @@ -754,7 +767,7 @@ export class SelectEditor implements Editor { this._msInstance = multipleSelect(selectElement, this.editorElmOptions) as MultipleSelectInstance; this.editorElm = this._msInstance.getParentElement(); if (!this.isCompositeEditor) { - this.delayOpening >= 0 ? setTimeout(() => this.show()) : this.show(); + this.show(this.delayOpening); } } diff --git a/packages/common/src/extensions/__tests__/slickCellExcelCopyManager.spec.ts b/packages/common/src/extensions/__tests__/slickCellExcelCopyManager.spec.ts index 283a25993..c05ab7c26 100644 --- a/packages/common/src/extensions/__tests__/slickCellExcelCopyManager.spec.ts +++ b/packages/common/src/extensions/__tests__/slickCellExcelCopyManager.spec.ts @@ -6,8 +6,6 @@ import { SlickCellExternalCopyManager } from '../slickCellExternalCopyManager'; import { SlickEvent, SlickEventData, SlickGrid, SlickRange } from '../../core/index'; import { Editors } from '../../editors'; -jest.mock('flatpickr', () => { }); - const getEditorLockMock = { isActive: jest.fn(), commitCurrentEdit: jest.fn(), @@ -364,7 +362,7 @@ describe('CellExcelCopyManager', () => { (gridStub.getCellEditor as jest.Mock).mockReturnValue({}); (gridStub.getActiveCell as jest.Mock).mockReturnValue({ row: 6, cell: 6 }); - const output = plugin.addonOptions!.dataItemColumnValueExtractor!({ firstName: 'John', lastName: 'Doe' }, { id: 'firstName', field: 'firstName', exportWithFormatter: true, editor: { model: Editors.text }, formatter: myBoldFormatter}, 6, 6); + const output = plugin.addonOptions!.dataItemColumnValueExtractor!({ firstName: 'John', lastName: 'Doe' }, { id: 'firstName', field: 'firstName', exportWithFormatter: true, editor: { model: Editors.text }, formatter: myBoldFormatter }, 6, 6); expect(output).toBeNull(); }); diff --git a/packages/common/src/extensions/__tests__/slickCellExternalCopyManager.spec.ts b/packages/common/src/extensions/__tests__/slickCellExternalCopyManager.spec.ts index 5a990b7d3..26ef2e661 100644 --- a/packages/common/src/extensions/__tests__/slickCellExternalCopyManager.spec.ts +++ b/packages/common/src/extensions/__tests__/slickCellExternalCopyManager.spec.ts @@ -8,8 +8,6 @@ import { InputEditor } from '../../editors/inputEditor'; import { SlickEvent, SlickEventData, SlickGrid, SlickRange } from '../../core/index'; import { BasePubSubService } from '@slickgrid-universal/event-pub-sub'; -jest.mock('flatpickr', () => { }); - const pubSubServiceStub = { publish: jest.fn(), subscribe: jest.fn(), diff --git a/packages/common/src/extensions/__tests__/slickCellMenu.plugin.spec.ts b/packages/common/src/extensions/__tests__/slickCellMenu.plugin.spec.ts index 2e2a90d58..26013358c 100644 --- a/packages/common/src/extensions/__tests__/slickCellMenu.plugin.spec.ts +++ b/packages/common/src/extensions/__tests__/slickCellMenu.plugin.spec.ts @@ -96,7 +96,7 @@ const commandItemsMock = [ { command: 'command3', title: 'Command 3', positionOrder: 70, }, { command: 'command4', title: 'Command 4', positionOrder: 71, }, { - command: 'more-sub-commands', title: 'More Sub Commands', subMenuTitle: 'Sub Command Title 2', subMenuTitleCssClass: 'color-warning', commandItems: [ + command: 'more-sub-commands', title: 'More Sub Commands', subMenuTitle: 'Sub Command Title 2', subMenuTitleCssClass: 'text-color-warning', commandItems: [ { command: 'command5', title: 'Command 5', positionOrder: 72, }, ] } @@ -655,7 +655,7 @@ describe('CellMenu Plugin', () => { expect(commandList2Elm.querySelectorAll('.slick-menu-item').length).toBe(3); expect(commandContentElm2.textContent).toBe('Sub Commands'); expect(subMenuTitleElm.textContent).toBe('Sub Command Title 2'); - expect(subMenuTitleElm.className).toBe('slick-menu-title color-warning'); + expect(subMenuTitleElm.className).toBe('slick-menu-title text-color-warning'); expect(commandChevronElm.className).toBe('sub-item-chevron mdi mdi-chevron-right'); expect(subCommand3Elm.textContent).toContain('Command 3'); expect(subCommand5Elm.textContent).toContain('Command 5'); @@ -706,7 +706,7 @@ describe('CellMenu Plugin', () => { expect(commandList2Elm.querySelectorAll('.slick-menu-item').length).toBe(3); expect(commandContentElm2.textContent).toBe('Sub Commands'); expect(subMenuTitleElm.textContent).toBe('Sub Command Title 2'); - expect(subMenuTitleElm.className).toBe('slick-menu-title color-warning'); + expect(subMenuTitleElm.className).toBe('slick-menu-title text-color-warning'); expect(commandChevronElm.className).toBe('sub-item-chevron mdi mdi-chevron-right'); expect(subCommand3Elm.textContent).toContain('Command 3'); expect(subCommand5Elm.textContent).toContain('Command 5'); diff --git a/packages/common/src/extensions/__tests__/slickCellRangeDecorator.spec.ts b/packages/common/src/extensions/__tests__/slickCellRangeDecorator.spec.ts index f9b47724a..834184574 100644 --- a/packages/common/src/extensions/__tests__/slickCellRangeDecorator.spec.ts +++ b/packages/common/src/extensions/__tests__/slickCellRangeDecorator.spec.ts @@ -4,8 +4,6 @@ import type { GridOption } from '../../interfaces/index'; import { SlickCellRangeDecorator } from '../slickCellRangeDecorator'; import { SlickGrid } from '../../core'; -jest.mock('flatpickr', () => { }); - const gridStub = { getActiveCell: jest.fn(), getActiveCanvasNode: jest.fn(), diff --git a/packages/common/src/extensions/__tests__/slickCellRangeSelector.spec.ts b/packages/common/src/extensions/__tests__/slickCellRangeSelector.spec.ts index 33e2ed70b..01d36033d 100644 --- a/packages/common/src/extensions/__tests__/slickCellRangeSelector.spec.ts +++ b/packages/common/src/extensions/__tests__/slickCellRangeSelector.spec.ts @@ -6,7 +6,6 @@ import { SlickEvent, SlickGrid } from '../../core/index'; import { BasePubSubService } from '@slickgrid-universal/event-pub-sub'; const GRID_UID = 'slickgrid_12345'; -jest.mock('flatpickr', () => { }); const addVanillaEventPropagation = function (event) { Object.defineProperty(event, 'isPropagationStopped', { writable: true, configurable: true, value: jest.fn() }); diff --git a/packages/common/src/extensions/__tests__/slickCellSelectionModel.spec.ts b/packages/common/src/extensions/__tests__/slickCellSelectionModel.spec.ts index 5a1a2c733..5785a92de 100644 --- a/packages/common/src/extensions/__tests__/slickCellSelectionModel.spec.ts +++ b/packages/common/src/extensions/__tests__/slickCellSelectionModel.spec.ts @@ -9,7 +9,6 @@ import { BasePubSubService } from '@slickgrid-universal/event-pub-sub'; const GRID_UID = 'slickgrid_12345'; const NB_ITEMS = 200; const CALCULATED_PAGE_ROW_COUNT = 23; // pageRowCount with our mocked sizes is 23 => ((600 - 17) / 25) -jest.mock('flatpickr', () => { }); const addVanillaEventPropagation = function (event, commandKeys: string[] = [], keyName = '') { Object.defineProperty(event, 'isPropagationStopped', { writable: true, configurable: true, value: jest.fn() }); diff --git a/packages/common/src/extensions/__tests__/slickCheckboxSelectColumn.spec.ts b/packages/common/src/extensions/__tests__/slickCheckboxSelectColumn.spec.ts index 6cf0e7e54..df2d02b38 100644 --- a/packages/common/src/extensions/__tests__/slickCheckboxSelectColumn.spec.ts +++ b/packages/common/src/extensions/__tests__/slickCheckboxSelectColumn.spec.ts @@ -295,13 +295,13 @@ describe('SlickCheckboxSelectColumn Plugin', () => { plugin.init(gridStub); gridStub.onHeaderRowCellRendered.notify({ column: { id: '_checkbox_selector', field: '_checkbox_selector' }, node: nodeElm, grid: gridStub }); plugin.setOptions({ hideInColumnTitleRow: true, hideInFilterHeaderRow: false, hideSelectAllCheckbox: false, }); - let filterSelectAll = plugin.headerRowNode!.querySelector(`#filter-checkbox-selectall-container`) as HTMLSpanElement; + let filterSelectAll = plugin.headerRowNode!.querySelector('#filter-checkbox-selectall-container') as HTMLSpanElement; expect(plugin).toBeTruthy(); expect(updateColHeaderSpy).toHaveBeenCalledWith('_checkbox_selector', '', ''); expect(filterSelectAll.style.display).toEqual('flex'); - filterSelectAll = plugin.headerRowNode!.querySelector(`#filter-checkbox-selectall-container`) as HTMLSpanElement; + filterSelectAll = plugin.headerRowNode!.querySelector('#filter-checkbox-selectall-container') as HTMLSpanElement; plugin.hideSelectAllFromColumnHeaderFilterRow(); expect(filterSelectAll.style.display).toEqual('none'); }); @@ -424,10 +424,11 @@ describe('SlickCheckboxSelectColumn Plugin', () => { resizable: false, sortable: false, width: 30, + maxWidth: 30, name: expect.any(DocumentFragment), formatter: expect.toBeFunction(), }); - expect(nameHtmlOutput).toBe(``); + expect(nameHtmlOutput).toBe(``); }); it('should create the plugin and add the Toggle All checkbox in the filter header row and expect toggle all to work when clicked', () => { @@ -439,7 +440,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => { plugin.init(gridStub); gridStub.onHeaderRowCellRendered.notify({ column: { id: '_checkbox_selector', field: '_checkbox_selector' }, node: nodeElm, grid: gridStub }); - const checkboxContainerElm = nodeElm.querySelector('span#filter-checkbox-selectall-container') as HTMLDivElement; + const checkboxContainerElm = nodeElm.querySelector('div.icon-checkbox-container') as HTMLDivElement; const inputCheckboxElm = checkboxContainerElm.querySelector('input[type=checkbox]') as HTMLDivElement; inputCheckboxElm.dispatchEvent(new Event('click', { bubbles: true, cancelable: true })); @@ -464,6 +465,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => { sortable: false, toolTip: 'Select/Deselect All', width: 30, + maxWidth: 30, }; plugin.create(mockColumns, { checkboxSelector: { columnId: 'chk-id' } }); @@ -475,7 +477,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => { }); expect(plugin).toBeTruthy(); expect(mockColumns[0]).toEqual(expect.objectContaining({ ...checkboxColumnMock, formatter: expect.toBeFunction() })); - expect(nameHtmlOutput).toBe(``); + expect(nameHtmlOutput).toBe(``); }); @@ -501,8 +503,9 @@ describe('SlickCheckboxSelectColumn Plugin', () => { sortable: false, toolTip: 'Select/Deselect All', width: 30, + maxWidth: 30, }); - expect(nameHtmlOutput).toBe(``); + expect(nameHtmlOutput).toBe(``); }); it('should add a "name" and "hideSelectAllCheckbox: true" and call the "create" method and expect plugin to be created with a column name and without a checkbox', () => { @@ -527,6 +530,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => { sortable: false, toolTip: '', width: 30, + maxWidth: 30, }); }); diff --git a/packages/common/src/extensions/__tests__/slickColumnPicker.spec.ts b/packages/common/src/extensions/__tests__/slickColumnPicker.spec.ts index bdfe27f55..651270920 100644 --- a/packages/common/src/extensions/__tests__/slickColumnPicker.spec.ts +++ b/packages/common/src/extensions/__tests__/slickColumnPicker.spec.ts @@ -21,6 +21,7 @@ const gridStub = { setColumns: jest.fn(), setOptions: jest.fn(), setSelectedRows: jest.fn(), + onClick: new SlickEvent(), onColumnsReordered: new SlickEvent(), onHeaderContextMenu: new SlickEvent(), } as unknown as SlickGrid; @@ -147,10 +148,15 @@ describe('ColumnPickerControl', () => { gridStub.onHeaderContextMenu.notify({ column: columnsMock[1], grid: gridStub }, eventData as any, gridStub); control.menuElement!.querySelector('input[type="checkbox"]')!.dispatchEvent(new Event('click', { bubbles: true })); - expect(handlerSpy).toHaveBeenCalledTimes(2); + expect(handlerSpy).toHaveBeenCalledTimes(3); expect(readjustSpy).toHaveBeenCalledWith(0, columnsMock, columnsMock); expect(control.getAllColumns()).toEqual(columnsMock); expect(control.getVisibleColumns()).toEqual(columnsMock); + + // cell click should close it + gridStub.onClick.notify({ row: 1, cell: 2, grid: gridStub }, eventData as any, gridStub); + + expect(control.menuElement).toBeFalsy(); }); it('should query an input checkbox change event and expect "headerColumnValueExtractor" method to be called when defined', () => { @@ -166,11 +172,11 @@ describe('ColumnPickerControl', () => { control.menuElement!.querySelector('input[type="checkbox"]')!.dispatchEvent(new Event('click', { bubbles: true })); const liElmList = control.menuElement!.querySelectorAll('li'); - expect(handlerSpy).toHaveBeenCalledTimes(2); + expect(handlerSpy).toHaveBeenCalledTimes(3); expect(readjustSpy).toHaveBeenCalledWith(0, columnsMock, columnsMock); expect(control.getAllColumns()).toEqual(columnsMock); expect(control.getVisibleColumns()).toEqual(columnsMock); - expect(liElmList[2].textContent).toBe('Billing - Field 3') + expect(liElmList[2].textContent).toBe('Billing - Field 3'); }); it('should open the column picker via "onHeaderContextMenu" and expect "Forcefit" to be checked when "hideForceFitButton" is false', () => { @@ -187,11 +193,11 @@ describe('ColumnPickerControl', () => { const inputForcefitElm = control.menuElement!.querySelector('#slickgrid_124343-colpicker-forcefit') as HTMLInputElement; const labelSyncElm = control.menuElement!.querySelector('label[for=slickgrid_124343-colpicker-forcefit]') as HTMLDivElement; - expect(handlerSpy).toHaveBeenCalledTimes(2); + expect(handlerSpy).toHaveBeenCalledTimes(3); expect(control.getAllColumns()).toEqual(columnsMock); expect(control.getVisibleColumns()).toEqual(columnsMock); expect(inputForcefitElm.checked).toBeTruthy(); - expect(inputForcefitElm.dataset.option).toBe('autoresize') + expect(inputForcefitElm.dataset.option).toBe('autoresize'); expect(labelSyncElm.textContent).toBe('Force fit columns'); }); @@ -209,7 +215,7 @@ describe('ColumnPickerControl', () => { const inputSyncElm = control.menuElement!.querySelector('#slickgrid_124343-colpicker-syncresize') as HTMLInputElement; const labelSyncElm = control.menuElement!.querySelector('label[for=slickgrid_124343-colpicker-syncresize]') as HTMLDivElement; - expect(handlerSpy).toHaveBeenCalledTimes(2); + expect(handlerSpy).toHaveBeenCalledTimes(3); expect(control.getAllColumns()).toEqual(columnsMock); expect(control.getVisibleColumns()).toEqual(columnsMock); expect(inputSyncElm.checked).toBeTruthy(); @@ -238,7 +244,7 @@ describe('ColumnPickerControl', () => { visibleColumns: columnsMock, grid: gridStub, }; - expect(handlerSpy).toHaveBeenCalledTimes(2); + expect(handlerSpy).toHaveBeenCalledTimes(3); expect(control.getAllColumns()).toEqual(columnsMock); expect(control.getVisibleColumns()).toEqual(columnsMock); expect(onColChangedMock).toBeCalledWith(expect.anything(), expectedCallbackArgs); @@ -262,7 +268,7 @@ describe('ColumnPickerControl', () => { const labelSyncElm = control.menuElement!.querySelector('label[for=slickgrid_124343-colpicker-forcefit]') as HTMLDivElement; inputForcefitElm.dispatchEvent(new Event('click', { bubbles: true })); - expect(handlerSpy).toHaveBeenCalledTimes(2); + expect(handlerSpy).toHaveBeenCalledTimes(3); expect(control.getAllColumns()).toEqual(columnsMock); expect(inputForcefitElm.checked).toBeTruthy(); expect(inputForcefitElm.dataset.option).toBe('autoresize'); @@ -288,7 +294,7 @@ describe('ColumnPickerControl', () => { const labelSyncElm = control.menuElement!.querySelector('label[for=slickgrid_124343-colpicker-syncresize]') as HTMLDivElement; inputSyncElm.dispatchEvent(new Event('click', { bubbles: true })); - expect(handlerSpy).toHaveBeenCalledTimes(2); + expect(handlerSpy).toHaveBeenCalledTimes(3); expect(control.getAllColumns()).toEqual(columnsMock); expect(inputSyncElm.checked).toBeTruthy(); expect(inputSyncElm.dataset.option).toBe('syncresize'); @@ -334,7 +340,7 @@ describe('ColumnPickerControl', () => { control.menuElement!.querySelector('input[type="checkbox"]')!.dispatchEvent(new Event('click', { bubbles: true })); const col4 = control.menuElement!.querySelector('li.hidden input[data-columnid=field4]'); - expect(handlerSpy).toHaveBeenCalledTimes(2); + expect(handlerSpy).toHaveBeenCalledTimes(3); expect(control.getAllColumns()).toEqual(columnsMock); expect(control.getVisibleColumns()).toEqual(columnsMock); expect(control.columns).toEqual(columnsMock); @@ -362,7 +368,7 @@ describe('ColumnPickerControl', () => { const labelForcefitElm = control.menuElement!.querySelector('label[for=slickgrid_124343-colpicker-forcefit]') as HTMLDivElement; const labelSyncElm = control.menuElement!.querySelector('label[for=slickgrid_124343-colpicker-syncresize]') as HTMLDivElement; - expect(handlerSpy).toHaveBeenCalledTimes(2); + expect(handlerSpy).toHaveBeenCalledTimes(3); expect(labelForcefitElm.textContent).toBe('Ajustement forcé des colonnes'); expect(labelSyncElm.textContent).toBe('Redimension synchrone'); expect(utilitySpy).toHaveBeenCalled(); diff --git a/packages/common/src/extensions/__tests__/slickContextMenu.spec.ts b/packages/common/src/extensions/__tests__/slickContextMenu.spec.ts index d8b711a98..f594f0657 100644 --- a/packages/common/src/extensions/__tests__/slickContextMenu.spec.ts +++ b/packages/common/src/extensions/__tests__/slickContextMenu.spec.ts @@ -1,12 +1,11 @@ import { BasePubSubService } from '@slickgrid-universal/event-pub-sub'; import { deepCopy } from '@slickgrid-universal/utils'; -import { type SlickDataView, SlickEvent, SlickEventData, SlickGrid } from '../../core/index'; +import { type SlickDataView, SlickEvent, SlickEventData, SlickGrid } from '../../core/index'; import { DelimiterType, FileType } from '../../enums/index'; import type { ContextMenu, Column, ElementPosition, GridOption, MenuCommandItem, MenuOptionItem, Formatter } from '../../interfaces/index'; import { BackendUtilityService, ExcelExportService, SharedService, TextExportService, TreeDataService, } from '../../services/index'; import { ExtensionUtility } from '../../extensions/extensionUtility'; -import { Formatters } from '../../formatters'; import { TranslateServiceStub } from '../../../../../test/translateServiceStub'; import { SlickContextMenu } from '../slickContextMenu'; @@ -26,7 +25,7 @@ const commandItemsMock = [ { command: 'command3', title: 'Command 3', positionOrder: 70, }, { command: 'command4', title: 'Command 4', positionOrder: 71, }, { - command: 'more-sub-commands', title: 'More Sub Commands', subMenuTitle: 'Sub Command Title 2', subMenuTitleCssClass: 'color-warning', commandItems: [ + command: 'more-sub-commands', title: 'More Sub Commands', subMenuTitle: 'Sub Command Title 2', subMenuTitleCssClass: 'text-color-warning', commandItems: [ { command: 'command5', title: 'Command 5', positionOrder: 72, }, ] } @@ -281,6 +280,12 @@ describe('ContextMenu Plugin', () => { expect(contextMenuElm).toBeTruthy(); expect(contextMenuElm.classList.contains('slick-dark-mode')).toBeTruthy(); + + // cell click should close it + gridStub.onClick.notify({ row: 1, cell: 2, grid: gridStub }, eventData as any, gridStub); + contextMenuElm = document.body.querySelector('.slick-context-menu.slickgrid12345') as HTMLDivElement; + + expect(contextMenuElm).toBeNull(); }); it('should "autoAlignSide" and expect menu to aligned left with a calculate offset when showing menu', () => { @@ -703,7 +708,7 @@ describe('ContextMenu Plugin', () => { expect(commandList2Elm.querySelectorAll('.slick-menu-item').length).toBe(3); expect(commandContentElm2.textContent).toBe('Sub Commands'); expect(subMenuTitleElm.textContent).toBe('Sub Command Title 2'); - expect(subMenuTitleElm.className).toBe('slick-menu-title color-warning'); + expect(subMenuTitleElm.className).toBe('slick-menu-title text-color-warning'); expect(commandChevronElm.className).toBe('sub-item-chevron mdi mdi-chevron-right'); expect(subCommand3Elm.textContent).toContain('Command 3'); expect(subCommand5Elm.textContent).toContain('Command 5'); @@ -832,7 +837,7 @@ describe('ContextMenu Plugin', () => { expect(closeBtnElm).toBeTruthy(); expect(commandListElm.querySelectorAll('.slick-menu-item').length).toBe(1); expect(commandItemElm1.classList.contains('slick-menu-item-disabled')).toBeFalsy(); - expect(commandIconElm1.classList.contains('fa-clone')).toBeTruthy(); + expect(commandIconElm1.classList.contains('mdi-content-copy')).toBeTruthy(); expect(commandLabelElm1.textContent).toBe('Copy'); commandItemElm1.dispatchEvent(new CustomEvent('click')); diff --git a/packages/common/src/extensions/__tests__/slickDraggableGrouping.spec.ts b/packages/common/src/extensions/__tests__/slickDraggableGrouping.spec.ts index 3e8273fbd..bff30f9d8 100644 --- a/packages/common/src/extensions/__tests__/slickDraggableGrouping.spec.ts +++ b/packages/common/src/extensions/__tests__/slickDraggableGrouping.spec.ts @@ -54,7 +54,7 @@ const gridOptionsMock = { enableDraggableGrouping: true, draggableGrouping: { hideToggleAllButton: false, - deleteIconCssClass: 'mdi mdi-close color-danger', + deleteIconCssClass: 'mdi mdi-close text-color-danger', }, showHeaderRow: false, showTopPanel: false, @@ -329,7 +329,7 @@ describe('Draggable Grouping Plugin', () => { it('should execute the "onEnd" callback of Sortable and expect sortable to be cancelled', () => { plugin.init(gridStub, { ...addonOptions }); - plugin.setAddonOptions({ deleteIconCssClass: 'mdi mdi-close color-danger' }); + plugin.setAddonOptions({ deleteIconCssClass: 'mdi mdi-close text-color-danger' }); const fn = plugin.setupColumnReorder(gridStub, mockHeaderLeftDiv1, {}, setColumnsSpy, setColumnResizeSpy, mockColumns, getColumnIndexSpy, GRID_UID, triggerSpy); fn.sortableLeftInstance!.options.onStart!({} as any); @@ -346,7 +346,7 @@ describe('Draggable Grouping Plugin', () => { it('should clear grouping and expect placeholder to be displayed when calling "onEnd" callback', () => { plugin.init(gridStub, { ...addonOptions }); - plugin.setAddonOptions({ deleteIconCssClass: 'mdi mdi-close color-danger' }); + plugin.setAddonOptions({ deleteIconCssClass: 'mdi mdi-close text-color-danger' }); const fn = plugin.setupColumnReorder(gridStub, mockHeaderLeftDiv1, {}, setColumnsSpy, setColumnResizeSpy, mockColumns, getColumnIndexSpy, GRID_UID, triggerSpy); fn.sortableLeftInstance!.options.onStart!({} as any); @@ -382,7 +382,7 @@ describe('Draggable Grouping Plugin', () => { it('should drag over dropzone and expect hover css class be added and removed when dragging outside of dropzone', () => { plugin.init(gridStub, { ...addonOptions }); - plugin.setAddonOptions({ deleteIconCssClass: 'mdi mdi-close color-danger' }); + plugin.setAddonOptions({ deleteIconCssClass: 'mdi mdi-close text-color-danger' }); const fn = plugin.setupColumnReorder(gridStub, mockHeaderLeftDiv1, {}, setColumnsSpy, setColumnResizeSpy, mockColumns, getColumnIndexSpy, GRID_UID, triggerSpy); fn.sortableLeftInstance!.options.onStart!({} as any); @@ -704,7 +704,7 @@ describe('Draggable Grouping Plugin', () => { it('should execute the "onEnd" callback of Sortable and expect sortable to be cancelled', () => { plugin.init(gridStub, { ...addonOptions }); - plugin.setAddonOptions({ deleteIconCssClass: 'mdi mdi-close color-danger' }); + plugin.setAddonOptions({ deleteIconCssClass: 'mdi mdi-close text-color-danger' }); const fn = plugin.setupColumnReorder(gridStub, [mockHeaderLeftDiv1, mockHeaderLeftDiv2], {}, setColumnsSpy, setColumnResizeSpy, mockColumns, getColumnIndexSpy, GRID_UID, triggerSpy); jest.spyOn(fn.sortableLeftInstance, 'toArray').mockReturnValue(['firstName', 'lastName', 'age']); jest.spyOn(fn.sortableRightInstance, 'toArray').mockReturnValue(['gender']); diff --git a/packages/common/src/extensions/__tests__/slickGridMenu.spec.ts b/packages/common/src/extensions/__tests__/slickGridMenu.spec.ts index e7e41d699..578374ef6 100644 --- a/packages/common/src/extensions/__tests__/slickGridMenu.spec.ts +++ b/packages/common/src/extensions/__tests__/slickGridMenu.spec.ts @@ -9,8 +9,6 @@ import { type SlickDataView, SlickEvent, SlickEventData, SlickGrid } from '../.. import { TranslateServiceStub } from '../../../../../test/translateServiceStub'; import { ExtensionUtility } from '../../extensions/extensionUtility'; -jest.mock('flatpickr', () => { }); - const gridId = 'grid1'; const gridUid = 'slickgrid_124343'; const containerId = 'demo-container'; @@ -64,6 +62,7 @@ const gridStub = { setOptions: jest.fn(), scrollColumnIntoView: jest.fn(), onBeforeDestroy: new SlickEvent(), + onClick: new SlickEvent(), onColumnsReordered: new SlickEvent(), onSetOptions: new SlickEvent(), } as unknown as SlickGrid; @@ -265,10 +264,15 @@ describe('GridMenuControl', () => { buttonElm.dispatchEvent(new Event('click', { bubbles: true, cancelable: true, composed: false })); control.menuElement!.querySelector('input[type="checkbox"]')!.dispatchEvent(new Event('click', { bubbles: true })); - expect(handlerSpy).toHaveBeenCalledTimes(3); + expect(handlerSpy).toHaveBeenCalledTimes(4); expect(readjustSpy).toHaveBeenCalledWith(0, columnsMock, columnsMock); expect(control.getAllColumns()).toEqual(columnsMock); expect(control.getVisibleColumns()).toEqual(columnsMock); + + // cell click should close it + gridStub.onClick.notify({ row: 1, cell: 2, grid: gridStub }, eventData as any, gridStub); + + expect(control.menuElement).toBeFalsy(); }); it('should query an input checkbox change event and expect "readjustFrozenColumnIndexWhenNeeded" method to be called when the grid is detected to be a frozen grid', () => { @@ -284,7 +288,7 @@ describe('GridMenuControl', () => { buttonElm.dispatchEvent(new Event('click', { bubbles: true, cancelable: true, composed: false })); control.menuElement!.querySelector('input[type="checkbox"]')!.dispatchEvent(new Event('click', { bubbles: true })); - expect(handlerSpy).toHaveBeenCalledTimes(3); + expect(handlerSpy).toHaveBeenCalledTimes(4); expect(readjustSpy).toHaveBeenCalledWith(0, columnsMock, columnsMock); expect(control.getAllColumns()).toEqual(columnsMock); expect(control.getVisibleColumns()).toEqual(columnsMock); @@ -317,7 +321,7 @@ describe('GridMenuControl', () => { control.menuElement!.querySelector('input[type="checkbox"]')!.dispatchEvent(new Event('click', { bubbles: true })); const liElmList = control.menuElement!.querySelectorAll('li'); - expect(handlerSpy).toHaveBeenCalledTimes(3); + expect(handlerSpy).toHaveBeenCalledTimes(4); expect(readjustSpy).toHaveBeenCalledWith(0, columnsMock, columnsMock); expect(control.getAllColumns()).toEqual(columnsMock); expect(control.getVisibleColumns()).toEqual(columnsMock); @@ -339,7 +343,7 @@ describe('GridMenuControl', () => { control.menuElement!.querySelector('input[type="checkbox"]')!.dispatchEvent(new Event('click', { bubbles: true })); const liElmList = control.menuElement!.querySelectorAll('li'); - expect(handlerSpy).toHaveBeenCalledTimes(3); + expect(handlerSpy).toHaveBeenCalledTimes(4); expect(readjustSpy).toHaveBeenCalledWith(0, columnsMock, columnsMock); expect(control.getAllColumns()).toEqual(columnsMock); expect(control.getVisibleColumns()).toEqual(columnsMock); @@ -381,7 +385,7 @@ describe('GridMenuControl', () => { const repositionSpy = jest.spyOn(control, 'repositionMenu'); control.init(); - const spanEvent = new MouseEvent('click', { bubbles: true, cancelable: true, composed: false }) + const spanEvent = new MouseEvent('click', { bubbles: true, cancelable: true, composed: false }); const spanBtnElm = document.createElement('span'); const buttonElm = document.createElement('button'); spanBtnElm.textContent = 'Grid Menu'; @@ -400,7 +404,7 @@ describe('GridMenuControl', () => { const repositionSpy = jest.spyOn(control, 'repositionMenu'); control.init(); - const spanEvent = new MouseEvent('click', { bubbles: true, cancelable: true, composed: false }) + const spanEvent = new MouseEvent('click', { bubbles: true, cancelable: true, composed: false }); const spanBtnElm = document.createElement('span'); const buttonElm = document.createElement('button'); spanBtnElm.textContent = 'Grid Menu'; @@ -429,11 +433,11 @@ describe('GridMenuControl', () => { const inputForcefitElm = control.menuElement!.querySelector('#slickgrid_124343-gridmenu-colpicker-forcefit') as HTMLInputElement; const labelSyncElm = control.menuElement!.querySelector('label[for=slickgrid_124343-gridmenu-colpicker-forcefit]') as HTMLLabelElement; - expect(handlerSpy).toHaveBeenCalledTimes(3); + expect(handlerSpy).toHaveBeenCalledTimes(4); expect(control.getAllColumns()).toEqual(columnsMock); expect(control.getVisibleColumns()).toEqual(columnsMock); expect(inputForcefitElm.checked).toBeTruthy(); - expect(inputForcefitElm.dataset.option).toBe('autoresize') + expect(inputForcefitElm.dataset.option).toBe('autoresize'); expect(labelSyncElm.textContent).toBe('Force fit columns'); }); @@ -452,7 +456,7 @@ describe('GridMenuControl', () => { const inputSyncElm = control.menuElement!.querySelector('#slickgrid_124343-gridmenu-colpicker-syncresize') as HTMLInputElement; const labelSyncElm = control.menuElement!.querySelector('label[for=slickgrid_124343-gridmenu-colpicker-syncresize]') as HTMLLabelElement; - expect(handlerSpy).toHaveBeenCalledTimes(3); + expect(handlerSpy).toHaveBeenCalledTimes(4); expect(control.getAllColumns()).toEqual(columnsMock); expect(control.getVisibleColumns()).toEqual(columnsMock); expect(inputSyncElm.checked).toBeTruthy(); @@ -482,7 +486,7 @@ describe('GridMenuControl', () => { visibleColumns: columnsMock, grid: gridStub, }; - expect(handlerSpy).toHaveBeenCalledTimes(3); + expect(handlerSpy).toHaveBeenCalledTimes(4); expect(control.getAllColumns()).toEqual(columnsMock); expect(control.getVisibleColumns()).toEqual(columnsMock); expect(onColChangedMock).toBeCalledWith(expect.anything(), expectedCallbackArgs); @@ -507,7 +511,7 @@ describe('GridMenuControl', () => { const labelSyncElm = control.menuElement!.querySelector('label[for=slickgrid_124343-gridmenu-colpicker-forcefit]') as HTMLLabelElement; inputForcefitElm.dispatchEvent(new Event('click', { bubbles: true })); - expect(handlerSpy).toHaveBeenCalledTimes(3); + expect(handlerSpy).toHaveBeenCalledTimes(4); expect(control.getAllColumns()).toEqual(columnsMock); expect(inputForcefitElm.checked).toBeTruthy(); expect(inputForcefitElm.dataset.option).toBe('autoresize'); @@ -534,7 +538,7 @@ describe('GridMenuControl', () => { const labelSyncElm = control.menuElement!.querySelector('label[for=slickgrid_124343-gridmenu-colpicker-syncresize]') as HTMLLabelElement; inputSyncElm.dispatchEvent(new Event('click', { bubbles: true })); - expect(handlerSpy).toHaveBeenCalledTimes(3); + expect(handlerSpy).toHaveBeenCalledTimes(4); expect(control.getAllColumns()).toEqual(columnsMock); expect(inputSyncElm.checked).toBeTruthy(); expect(inputSyncElm.dataset.option).toBe('syncresize'); @@ -913,7 +917,7 @@ describe('GridMenuControl', () => { { command: 'command3', title: 'Command 3', positionOrder: 70, }, { command: 'command4', title: 'Command 4', positionOrder: 71, }, { - command: 'more-sub-commands', title: 'More Sub Commands', subMenuTitle: 'Sub Command Title 2', subMenuTitleCssClass: 'color-warning', commandItems: [ + command: 'more-sub-commands', title: 'More Sub Commands', subMenuTitle: 'Sub Command Title 2', subMenuTitleCssClass: 'text-color-warning', commandItems: [ { command: 'command5', title: 'Command 5', positionOrder: 72, }, ] } @@ -963,7 +967,7 @@ describe('GridMenuControl', () => { expect(commandList2Elm.querySelectorAll('.slick-menu-item').length).toBe(3); expect(commandContentElm2.textContent).toBe('Sub Commands'); expect(subMenuTitleElm.textContent).toBe('Sub Command Title 2'); - expect(subMenuTitleElm.className).toBe('slick-menu-title color-warning'); + expect(subMenuTitleElm.className).toBe('slick-menu-title text-color-warning'); expect(commandChevronElm.className).toBe('sub-item-chevron mdi mdi-chevron-right'); expect(subCommand3Elm.textContent).toContain('Command 3'); expect(subCommand5Elm.textContent).toContain('Command 5'); @@ -1019,7 +1023,7 @@ describe('GridMenuControl', () => { expect(commandList2Elm.querySelectorAll('.slick-menu-item').length).toBe(3); expect(commandContentElm2.textContent).toBe('Sub Commands'); expect(subMenuTitleElm.textContent).toBe('Sub Command Title 2'); - expect(subMenuTitleElm.className).toBe('slick-menu-title color-warning'); + expect(subMenuTitleElm.className).toBe('slick-menu-title text-color-warning'); expect(commandChevronElm.className).toBe('sub-item-chevron mdi mdi-chevron-right'); expect(subCommand3Elm.textContent).toContain('Command 3'); expect(subCommand5Elm.textContent).toContain('Command 5'); @@ -1053,7 +1057,7 @@ describe('GridMenuControl', () => { const gridMenu2Elm = document.body.querySelector('.slick-grid-menu.slick-menu-level-1') as HTMLDivElement; Object.defineProperty(gridMenu2Elm, 'clientHeight', { writable: true, configurable: true, value: 320 }); - const divEvent = new MouseEvent('click', { bubbles: true, cancelable: true, composed: false }) + const divEvent = new MouseEvent('click', { bubbles: true, cancelable: true, composed: false }); const subMenuElm = document.createElement('div'); const menuItem = document.createElement('div'); menuItem.className = 'slick-menu-item'; @@ -1094,7 +1098,7 @@ describe('GridMenuControl', () => { control.columns = columnsMock; control.init(); expect(SharedService.prototype.gridOptions.gridMenu!.commandItems).toEqual([ - { iconCssClass: 'fa fa-times', titleKey: 'CLEAR_PINNING', title: 'Dégeler les colonnes/rangées', disabled: false, command: 'clear-pinning', positionOrder: 52 }, + { iconCssClass: 'mdi mdi-pin-off-outline', titleKey: 'CLEAR_PINNING', title: 'Dégeler les colonnes/rangées', disabled: false, command: 'clear-pinning', positionOrder: 52 }, ]); }); @@ -1106,9 +1110,9 @@ describe('GridMenuControl', () => { control.init(); control.init(); // calling 2x register to make sure it doesn't duplicate commands expect(SharedService.prototype.gridOptions.gridMenu!.commandItems).toEqual([ - { iconCssClass: 'fa fa-filter text-danger', titleKey: 'CLEAR_ALL_FILTERS', title: 'Supprimer tous les filtres', disabled: false, command: 'clear-filter', positionOrder: 50 }, - { iconCssClass: 'fa fa-random', titleKey: 'TOGGLE_FILTER_ROW', title: 'Basculer la ligne des filtres', disabled: false, command: 'toggle-filter', positionOrder: 53 }, - { iconCssClass: 'fa fa-refresh', titleKey: 'REFRESH_DATASET', title: 'Rafraîchir les données', disabled: false, command: 'refresh-dataset', positionOrder: 58 } + { iconCssClass: 'mdi mdi-filter-remove-outline', titleKey: 'CLEAR_ALL_FILTERS', title: 'Supprimer tous les filtres', disabled: false, command: 'clear-filter', positionOrder: 50 }, + { iconCssClass: 'mdi mdi-flip-vertical', titleKey: 'TOGGLE_FILTER_ROW', title: 'Basculer la ligne des filtres', disabled: false, command: 'toggle-filter', positionOrder: 53 }, + { iconCssClass: 'mdi mdi-sync', titleKey: 'REFRESH_DATASET', title: 'Rafraîchir les données', disabled: false, command: 'refresh-dataset', positionOrder: 58 } ]); }); @@ -1124,7 +1128,7 @@ describe('GridMenuControl', () => { control.init(); control.init(); // calling 2x register to make sure it doesn't duplicate commands expect(SharedService.prototype.gridOptions.gridMenu!.commandItems).toEqual([ - { iconCssClass: 'fa fa-filter text-danger', titleKey: 'CLEAR_ALL_FILTERS', title: 'Supprimer tous les filtres', disabled: false, command: 'clear-filter', positionOrder: 50 } + { iconCssClass: 'mdi mdi-filter-remove-outline', titleKey: 'CLEAR_ALL_FILTERS', title: 'Supprimer tous les filtres', disabled: false, command: 'clear-filter', positionOrder: 50 } ]); }); @@ -1140,7 +1144,7 @@ describe('GridMenuControl', () => { control.init(); control.init(); // calling 2x register to make sure it doesn't duplicate commands expect(SharedService.prototype.gridOptions.gridMenu!.commandItems).toEqual([ - { iconCssClass: 'fa fa-random', titleKey: 'TOGGLE_FILTER_ROW', title: 'Basculer la ligne des filtres', disabled: false, command: 'toggle-filter', positionOrder: 53 }, + { iconCssClass: 'mdi mdi-flip-vertical', titleKey: 'TOGGLE_FILTER_ROW', title: 'Basculer la ligne des filtres', disabled: false, command: 'toggle-filter', positionOrder: 53 }, ]); }); @@ -1157,7 +1161,7 @@ describe('GridMenuControl', () => { control.init(); control.init(); // calling 2x register to make sure it doesn't duplicate commands expect(SharedService.prototype.gridOptions.gridMenu!.commandItems).toEqual([ - { iconCssClass: 'fa fa-random', titleKey: 'TOGGLE_DARK_MODE', title: 'Basculer le mode clair/sombre', disabled: false, command: 'toggle-dark-mode', positionOrder: 54 }, + { iconCssClass: 'mdi mdi-brightness-4', titleKey: 'TOGGLE_DARK_MODE', title: 'Basculer le mode clair/sombre', disabled: false, command: 'toggle-dark-mode', positionOrder: 54 }, ]); }); @@ -1173,7 +1177,7 @@ describe('GridMenuControl', () => { control.init(); control.init(); // calling 2x register to make sure it doesn't duplicate commands expect(SharedService.prototype.gridOptions.gridMenu!.commandItems).toEqual([ - { iconCssClass: 'fa fa-refresh', titleKey: 'REFRESH_DATASET', title: 'Rafraîchir les données', disabled: false, command: 'refresh-dataset', positionOrder: 58 } + { iconCssClass: 'mdi mdi-sync', titleKey: 'REFRESH_DATASET', title: 'Rafraîchir les données', disabled: false, command: 'refresh-dataset', positionOrder: 58 } ]); }); @@ -1185,7 +1189,7 @@ describe('GridMenuControl', () => { control.init(); control.init(); // calling 2x register to make sure it doesn't duplicate commands expect(SharedService.prototype.gridOptions.gridMenu!.commandItems).toEqual([ - { iconCssClass: 'fa fa-random', titleKey: 'TOGGLE_PRE_HEADER_ROW', title: 'Basculer la ligne de pré-en-tête', disabled: false, command: 'toggle-preheader', positionOrder: 53 } + { iconCssClass: 'mdi mdi-flip-vertical', titleKey: 'TOGGLE_PRE_HEADER_ROW', title: 'Basculer la ligne de pré-en-tête', disabled: false, command: 'toggle-preheader', positionOrder: 53 } ]); }); @@ -1211,7 +1215,7 @@ describe('GridMenuControl', () => { control.init(); control.init(); // calling 2x register to make sure it doesn't duplicate commands expect(SharedService.prototype.gridOptions.gridMenu!.commandItems).toEqual([ - { iconCssClass: 'fa fa-unsorted text-danger', titleKey: 'CLEAR_ALL_SORTING', title: 'Supprimer tous les tris', disabled: false, command: 'clear-sorting', positionOrder: 51 } + { iconCssClass: 'mdi mdi-sort-variant-off', titleKey: 'CLEAR_ALL_SORTING', title: 'Supprimer tous les tris', disabled: false, command: 'clear-sorting', positionOrder: 51 } ]); }); @@ -1241,7 +1245,7 @@ describe('GridMenuControl', () => { control.init(); control.init(); // calling 2x register to make sure it doesn't duplicate commands expect(SharedService.prototype.gridOptions.gridMenu!.commandItems).toEqual([ - { iconCssClass: 'fa fa-download', titleKey: 'EXPORT_TO_CSV', title: 'Exporter en format CSV', disabled: false, command: 'export-csv', positionOrder: 55 } + { iconCssClass: 'mdi mdi-download', titleKey: 'EXPORT_TO_CSV', title: 'Exporter en format CSV', disabled: false, command: 'export-csv', positionOrder: 55 } ]); }); @@ -1271,7 +1275,7 @@ describe('GridMenuControl', () => { control.init(); control.init(); // calling 2x register to make sure it doesn't duplicate commands expect(SharedService.prototype.gridOptions.gridMenu!.commandItems).toEqual([ - { iconCssClass: 'fa fa-file-excel-o text-success', titleKey: 'EXPORT_TO_EXCEL', title: 'Exporter vers Excel', disabled: false, command: 'export-excel', positionOrder: 56 } + { iconCssClass: 'mdi mdi-file-excel-outline text-success', titleKey: 'EXPORT_TO_EXCEL', title: 'Exporter vers Excel', disabled: false, command: 'export-excel', positionOrder: 56 } ]); }); @@ -1287,7 +1291,7 @@ describe('GridMenuControl', () => { control.init(); control.init(); // calling 2x register to make sure it doesn't duplicate commands expect(SharedService.prototype.gridOptions.gridMenu!.commandItems).toEqual([ - { iconCssClass: 'fa fa-download', titleKey: 'EXPORT_TO_TAB_DELIMITED', title: 'Exporter en format texte (délimité par tabulation)', disabled: false, command: 'export-text-delimited', positionOrder: 57 } + { iconCssClass: 'mdi mdi-download', titleKey: 'EXPORT_TO_TAB_DELIMITED', title: 'Exporter en format texte (délimité par tabulation)', disabled: false, command: 'export-text-delimited', positionOrder: 57 } ]); }); @@ -1574,7 +1578,7 @@ describe('GridMenuControl', () => { gridStub.onColumnsReordered.notify({ impactedColumns: columnsUnorderedMock, grid: gridStub }, eventData as any, gridStub); control.menuElement!.querySelector('input[type="checkbox"]')!.dispatchEvent(new Event('click', { bubbles: true })); - expect(handlerSpy).toHaveBeenCalledTimes(3); + expect(handlerSpy).toHaveBeenCalledTimes(4); expect(control.getAllColumns()).toEqual(columnsMock); expect(control.getVisibleColumns()).toEqual(columnsMock); expect(control.columns).toEqual(columnsMock); @@ -1616,7 +1620,7 @@ describe('GridMenuControl', () => { const labelForcefitElm = control.menuElement!.querySelector('label[for=slickgrid_124343-gridmenu-colpicker-forcefit]') as HTMLLabelElement; const labelSyncElm = control.menuElement!.querySelector('label[for=slickgrid_124343-gridmenu-colpicker-syncresize]') as HTMLLabelElement; - expect(handlerSpy).toHaveBeenCalledTimes(3); + expect(handlerSpy).toHaveBeenCalledTimes(4); expect(labelForcefitElm.textContent).toBe('Ajustement forcé des colonnes'); expect(labelSyncElm.textContent).toBe('Redimension synchrone'); expect(utilitySpy).toHaveBeenCalled(); diff --git a/packages/common/src/extensions/__tests__/slickHeaderButtons.spec.ts b/packages/common/src/extensions/__tests__/slickHeaderButtons.spec.ts index 9dc5ae00f..a50e5a1a4 100644 --- a/packages/common/src/extensions/__tests__/slickHeaderButtons.spec.ts +++ b/packages/common/src/extensions/__tests__/slickHeaderButtons.spec.ts @@ -98,7 +98,7 @@ describe('HeaderButton Plugin', () => { plugin.init(); plugin.addonOptions = { buttonCssClass: 'some-class' - } + }; expect(plugin.addonOptions).toEqual({ buttonCssClass: 'some-class', diff --git a/packages/common/src/extensions/__tests__/slickHeaderMenu.spec.ts b/packages/common/src/extensions/__tests__/slickHeaderMenu.spec.ts index e42fa336a..0fb51e20a 100644 --- a/packages/common/src/extensions/__tests__/slickHeaderMenu.spec.ts +++ b/packages/common/src/extensions/__tests__/slickHeaderMenu.spec.ts @@ -59,6 +59,7 @@ const gridStub = { updateColumnHeader: jest.fn(), onBeforeSetColumns: new SlickEvent(), onBeforeHeaderCellDestroy: new SlickEvent(), + onClick: new SlickEvent(), onHeaderCellRendered: new SlickEvent(), onHeaderMouseEnter: new SlickEvent(), onMouseEnter: new SlickEvent(), @@ -605,7 +606,7 @@ describe('HeaderMenu Plugin', () => { { command: 'command3', title: 'Command 3', positionOrder: 70, }, { command: 'command4', title: 'Command 4', positionOrder: 71, }, { - command: 'more-sub-commands', title: 'More Sub Commands', subMenuTitle: 'Sub Command Title 2', subMenuTitleCssClass: 'color-warning', commandItems: [ + command: 'more-sub-commands', title: 'More Sub Commands', subMenuTitle: 'Sub Command Title 2', subMenuTitleCssClass: 'text-color-warning', commandItems: [ { command: 'command5', title: 'Command 5', positionOrder: 72, }, ] } @@ -661,7 +662,7 @@ describe('HeaderMenu Plugin', () => { expect(commandList2Elm.querySelectorAll('.slick-menu-item').length).toBe(3); expect(commandContentElm2.textContent).toBe('Sub Commands'); expect(subMenuTitleElm.textContent).toBe('Sub Command Title 2'); - expect(subMenuTitleElm.className).toBe('slick-menu-title color-warning'); + expect(subMenuTitleElm.className).toBe('slick-menu-title text-color-warning'); expect(commandChevronElm.className).toBe('sub-item-chevron'); expect(subCommand3Elm.textContent).toContain('Command 3'); expect(subCommand5Elm.textContent).toContain('Command 5'); @@ -717,7 +718,7 @@ describe('HeaderMenu Plugin', () => { expect(commandList2Elm.querySelectorAll('.slick-menu-item').length).toBe(3); expect(commandContentElm2.textContent).toBe('Sub Commands'); expect(subMenuTitleElm.textContent).toBe('Sub Command Title 2'); - expect(subMenuTitleElm.className).toBe('slick-menu-title color-warning'); + expect(subMenuTitleElm.className).toBe('slick-menu-title text-color-warning'); expect(commandChevronElm.className).toBe('sub-item-chevron mdi mdi-chevron-right'); expect(subCommand3Elm.textContent).toContain('Command 3'); expect(subCommand5Elm.textContent).toContain('Command 5'); @@ -735,6 +736,7 @@ describe('HeaderMenu Plugin', () => { }); it('should create a Grid Menu item with commands sub-menu commandItems and expect sub-menu to be positioned on top (dropup)', () => { + const hideMenuSpy = jest.spyOn(plugin, 'hideMenu'); const onCommandMock = jest.fn(); Object.defineProperty(document.documentElement, 'clientWidth', { writable: true, configurable: true, value: 50 }); jest.spyOn(gridStub, 'getColumns').mockReturnValueOnce(columnsMock); @@ -751,7 +753,7 @@ describe('HeaderMenu Plugin', () => { const subCommands1Elm = commandList1Elm.querySelector('[data-command="sub-commands"]') as HTMLDivElement; Object.defineProperty(headerMenu1Elm, 'clientHeight', { writable: true, configurable: true, value: 77 }); Object.defineProperty(headerMenu1Elm, 'clientWidth', { writable: true, configurable: true, value: 225 }); - const divEvent1 = new MouseEvent('click', { bubbles: true, cancelable: true, composed: false }) + const divEvent1 = new MouseEvent('click', { bubbles: true, cancelable: true, composed: false }); Object.defineProperty(divEvent1, 'target', { writable: true, configurable: true, value: headerButtonElm }); subCommands1Elm!.dispatchEvent(new Event('click')); @@ -759,7 +761,7 @@ describe('HeaderMenu Plugin', () => { const headerMenu2Elm = document.body.querySelector('.slick-header-menu.slick-menu-level-1') as HTMLDivElement; Object.defineProperty(headerMenu2Elm, 'clientHeight', { writable: true, configurable: true, value: 320 }); - const divEvent = new MouseEvent('click', { bubbles: true, cancelable: true, composed: false }) + const divEvent = new MouseEvent('click', { bubbles: true, cancelable: true, composed: false }); const subMenuElm = document.createElement('div'); const menuItem = document.createElement('div'); menuItem.className = 'slick-menu-item'; @@ -775,6 +777,11 @@ describe('HeaderMenu Plugin', () => { expect(headerMenu2Elm2.classList.contains('dropup')).toBeTruthy(); expect(headerMenu2Elm2.classList.contains('dropdown')).toBeFalsy(); + + // cell click should close it + gridStub.onClick.notify({ row: 1, cell: 2, grid: gridStub }, eventData as any, gridStub); + + expect(hideMenuSpy).toHaveBeenCalled(); }); }); @@ -813,7 +820,7 @@ describe('HeaderMenu Plugin', () => { const commandDivElm = gridContainerDiv.querySelector('[data-command="freeze-columns"]') as HTMLDivElement; expect((originalColumnDefinitions[1] as any).header!.menu!.commandItems!).toEqual([ - { iconCssClass: 'fa fa-thumb-tack', title: 'Freeze Columns', titleKey: 'FREEZE_COLUMNS', command: 'freeze-columns', positionOrder: 47 }, + { iconCssClass: 'mdi mdi-pin-outline', title: 'Freeze Columns', titleKey: 'FREEZE_COLUMNS', command: 'freeze-columns', positionOrder: 47 }, { divider: true, command: '', positionOrder: 49 }, ]); expect(commandDivElm).toBeFalsy(); @@ -834,12 +841,12 @@ describe('HeaderMenu Plugin', () => { headerButtonElm.dispatchEvent(new Event('click', { bubbles: true, cancelable: true, composed: false })); const clearFilterSpy = jest.spyOn(filterServiceStub, 'clearFilterByColumnId'); - const headerMenuExpected = [{ iconCssClass: 'fa fa-filter', title: 'Remove Filter', titleKey: 'REMOVE_FILTER', command: 'clear-filter', positionOrder: 53 }]; + const headerMenuExpected = [{ iconCssClass: 'mdi mdi-filter-remove-outline', title: 'Remove Filter', titleKey: 'REMOVE_FILTER', command: 'clear-filter', positionOrder: 53 }]; const commandDivElm = gridContainerDiv.querySelector('[data-command="clear-filter"]') as HTMLDivElement; const commandIconElm = commandDivElm.querySelector('.slick-menu-icon') as HTMLDivElement; const commandLabelElm = commandDivElm.querySelector('.slick-menu-content') as HTMLDivElement; expect(columnsMock[1].header!.menu!.commandItems!).toEqual(headerMenuExpected); - expect(commandIconElm.classList.contains('fa-filter')).toBeTruthy(); + expect(commandIconElm.classList.contains('mdi-filter-remove-outline')).toBeTruthy(); expect(commandLabelElm.textContent).toBe('Remove Filter'); const clickEvent = new Event('click'); @@ -870,15 +877,15 @@ describe('HeaderMenu Plugin', () => { const pubSubSpy = jest.spyOn(pubSubServiceStub, 'publish'); const headerMenuExpected = [ - { iconCssClass: 'fa fa-arrows-h', title: 'Resize by Content', titleKey: 'COLUMN_RESIZE_BY_CONTENT', command: 'column-resize-by-content', positionOrder: 48 }, + { iconCssClass: 'mdi mdi-arrow-expand-horizontal', title: 'Resize by Content', titleKey: 'COLUMN_RESIZE_BY_CONTENT', command: 'column-resize-by-content', positionOrder: 48 }, { divider: true, command: '', positionOrder: 49 }, - { iconCssClass: 'fa fa-times', title: 'Hide Column', titleKey: 'HIDE_COLUMN', command: 'hide-column', positionOrder: 55 } + { iconCssClass: 'mdi mdi-close', title: 'Hide Column', titleKey: 'HIDE_COLUMN', command: 'hide-column', positionOrder: 55 } ]; const commandDivElm = gridContainerDiv.querySelector('[data-command="column-resize-by-content"]') as HTMLDivElement; const commandIconElm = commandDivElm.querySelector('.slick-menu-icon') as HTMLDivElement; const commandLabelElm = commandDivElm.querySelector('.slick-menu-content') as HTMLDivElement; expect(columnsMock[1].header!.menu!.commandItems!).toEqual(headerMenuExpected); - expect(commandIconElm.classList.contains('fa-arrows-h')).toBeTruthy(); + expect(commandIconElm.classList.contains('mdi-arrow-expand-horizontal')).toBeTruthy(); expect(commandLabelElm.textContent).toBe('Resize by Content'); const clickEvent = new Event('click'); @@ -904,15 +911,15 @@ describe('HeaderMenu Plugin', () => { const autosizeSpy = jest.spyOn(gridStub, 'autosizeColumns'); const headerMenuExpected = [ - { iconCssClass: 'fa fa-thumb-tack', title: 'Freeze Columns', titleKey: 'FREEZE_COLUMNS', command: 'freeze-columns', positionOrder: 47 }, + { iconCssClass: 'mdi mdi-pin-outline', title: 'Freeze Columns', titleKey: 'FREEZE_COLUMNS', command: 'freeze-columns', positionOrder: 47 }, { divider: true, command: '', positionOrder: 49 }, - { iconCssClass: 'fa fa-times', title: 'Hide Column', titleKey: 'HIDE_COLUMN', command: 'hide-column', positionOrder: 55 } + { iconCssClass: 'mdi mdi-close', title: 'Hide Column', titleKey: 'HIDE_COLUMN', command: 'hide-column', positionOrder: 55 } ]; const commandDivElm = gridContainerDiv.querySelector('[data-command="hide-column"]') as HTMLDivElement; const commandIconElm = commandDivElm.querySelector('.slick-menu-icon') as HTMLDivElement; const commandLabelElm = commandDivElm.querySelector('.slick-menu-content') as HTMLDivElement; expect(columnsMock[1].header!.menu!.commandItems!).toEqual(headerMenuExpected); - expect(commandIconElm.classList.contains('fa-times')).toBeTruthy(); + expect(commandIconElm.classList.contains('mdi-close')).toBeTruthy(); expect(commandLabelElm.textContent).toBe('Hide Column'); commandDivElm.dispatchEvent(new Event('click')); @@ -933,12 +940,12 @@ describe('HeaderMenu Plugin', () => { headerButtonElm.dispatchEvent(new Event('click', { bubbles: true, cancelable: true, composed: false })); const clearFilterSpy = jest.spyOn(filterServiceStub, 'clearFilterByColumnId'); - const headerMenuExpected = [{ iconCssClass: 'fa fa-filter', title: 'Remove Filter', titleKey: 'REMOVE_FILTER', command: 'clear-filter', positionOrder: 53 }]; + const headerMenuExpected = [{ iconCssClass: 'mdi mdi-filter-remove-outline', title: 'Remove Filter', titleKey: 'REMOVE_FILTER', command: 'clear-filter', positionOrder: 53 }]; const commandDivElm = gridContainerDiv.querySelector('[data-command="clear-filter"]') as HTMLDivElement; const commandIconElm = commandDivElm.querySelector('.slick-menu-icon') as HTMLDivElement; const commandLabelElm = commandDivElm.querySelector('.slick-menu-content') as HTMLDivElement; expect(columnsMock[1].header!.menu!.commandItems!).toEqual(headerMenuExpected); - expect(commandIconElm.classList.contains('fa-filter')).toBeTruthy(); + expect(commandIconElm.classList.contains('mdi-filter-remove-outline')).toBeTruthy(); expect(commandLabelElm.textContent).toBe('Remove Filter'); const clickEvent = new Event('click'); @@ -964,21 +971,21 @@ describe('HeaderMenu Plugin', () => { const commandIconElm = commandDivElm.querySelector('.slick-menu-icon') as HTMLDivElement; const commandLabelElm = commandDivElm.querySelector('.slick-menu-content') as HTMLDivElement; expect(columnsMock[1].header!.menu!.commandItems!).toEqual([ - { iconCssClass: 'fa fa-sort-asc', title: 'Sort Ascending', titleKey: 'SORT_ASCENDING', command: 'sort-asc', positionOrder: 50 }, - { iconCssClass: 'fa fa-sort-desc', title: 'Sort Descending', titleKey: 'SORT_DESCENDING', command: 'sort-desc', positionOrder: 51 }, + { iconCssClass: 'mdi mdi-sort-ascending', title: 'Sort Ascending', titleKey: 'SORT_ASCENDING', command: 'sort-asc', positionOrder: 50 }, + { iconCssClass: 'mdi mdi-sort-descending', title: 'Sort Descending', titleKey: 'SORT_DESCENDING', command: 'sort-desc', positionOrder: 51 }, { divider: true, command: '', positionOrder: 52 }, - { iconCssClass: 'fa fa-unsorted', title: 'Remove Sort', titleKey: 'REMOVE_SORT', command: 'clear-sort', positionOrder: 54 }, + { iconCssClass: 'mdi mdi-sort-variant-off', title: 'Remove Sort', titleKey: 'REMOVE_SORT', command: 'clear-sort', positionOrder: 54 }, ]); - expect(commandIconElm.classList.contains('fa-unsorted')).toBeTruthy(); + expect(commandIconElm.classList.contains('mdi-sort-variant-off')).toBeTruthy(); expect(commandLabelElm.textContent).toBe('Remove Sort'); translateService.use('fr'); plugin.translateHeaderMenu(); expect(columnsMock[1].header!.menu!.commandItems!).toEqual([ - { iconCssClass: 'fa fa-sort-asc', title: 'Trier par ordre croissant', titleKey: 'SORT_ASCENDING', command: 'sort-asc', positionOrder: 50 }, - { iconCssClass: 'fa fa-sort-desc', title: 'Trier par ordre décroissant', titleKey: 'SORT_DESCENDING', command: 'sort-desc', positionOrder: 51 }, + { iconCssClass: 'mdi mdi-sort-ascending', title: 'Trier par ordre croissant', titleKey: 'SORT_ASCENDING', command: 'sort-asc', positionOrder: 50 }, + { iconCssClass: 'mdi mdi-sort-descending', title: 'Trier par ordre décroissant', titleKey: 'SORT_DESCENDING', command: 'sort-desc', positionOrder: 51 }, { divider: true, command: '', positionOrder: 52 }, - { iconCssClass: 'fa fa-unsorted', title: 'Supprimer le tri', titleKey: 'REMOVE_SORT', command: 'clear-sort', positionOrder: 54 }, + { iconCssClass: 'mdi mdi-sort-variant-off', title: 'Supprimer le tri', titleKey: 'REMOVE_SORT', command: 'clear-sort', positionOrder: 54 }, ]); const clickEvent = new Event('click'); @@ -1005,16 +1012,16 @@ describe('HeaderMenu Plugin', () => { const commandIconElm = commandDivElm.querySelector('.slick-menu-icon') as HTMLDivElement; const commandLabelElm = commandDivElm.querySelector('.slick-menu-content') as HTMLDivElement; expect(columnsMock[1].header!.menu!.commandItems!).toEqual([ - { iconCssClass: 'fa fa-thumb-tack', title: 'Freeze Columns', titleKey: 'FREEZE_COLUMNS', command: 'freeze-columns', positionOrder: 47 }, + { iconCssClass: 'mdi mdi-pin-outline', title: 'Freeze Columns', titleKey: 'FREEZE_COLUMNS', command: 'freeze-columns', positionOrder: 47 }, { divider: true, command: '', positionOrder: 49 }, ]); - expect(commandIconElm.classList.contains('fa-thumb-tack')).toBeTruthy(); + expect(commandIconElm.classList.contains('mdi-pin-outline')).toBeTruthy(); expect(commandLabelElm.textContent).toBe('Freeze Columns'); translateService.use('fr'); plugin.translateHeaderMenu(); expect(columnsMock[1].header!.menu!.commandItems!).toEqual([ - { iconCssClass: 'fa fa-thumb-tack', title: 'Geler les colonnes', titleKey: 'FREEZE_COLUMNS', command: 'freeze-columns', positionOrder: 47 }, + { iconCssClass: 'mdi mdi-pin-outline', title: 'Geler les colonnes', titleKey: 'FREEZE_COLUMNS', command: 'freeze-columns', positionOrder: 47 }, { divider: true, command: '', positionOrder: 49 }, ]); @@ -1038,7 +1045,7 @@ describe('HeaderMenu Plugin', () => { const commandDivElm = gridContainerDiv.querySelector('[data-command="freeze-columns"]') as HTMLDivElement; expect(columnsMock[2].header!.menu!.commandItems!).toEqual([ - { iconCssClass: 'fa fa-thumb-tack', title: 'Freeze Columns', titleKey: 'FREEZE_COLUMNS', command: 'freeze-columns', positionOrder: 47 }, + { iconCssClass: 'mdi mdi-pin-outline', title: 'Freeze Columns', titleKey: 'FREEZE_COLUMNS', command: 'freeze-columns', positionOrder: 47 }, { divider: true, command: '', positionOrder: 49 }, ]); @@ -1066,7 +1073,7 @@ describe('HeaderMenu Plugin', () => { const commandDivElm = gridContainerDiv.querySelector('[data-command="freeze-columns"]') as HTMLDivElement; expect((originalColumnDefinitions[1] as any).header!.menu!.commandItems!).toEqual([ - { iconCssClass: 'fa fa-thumb-tack', title: 'Freeze Columns', titleKey: 'FREEZE_COLUMNS', command: 'freeze-columns', positionOrder: 47 }, + { iconCssClass: 'mdi mdi-pin-outline', title: 'Freeze Columns', titleKey: 'FREEZE_COLUMNS', command: 'freeze-columns', positionOrder: 47 }, { divider: true, command: '', positionOrder: 49 }, ]); @@ -1093,10 +1100,10 @@ describe('HeaderMenu Plugin', () => { const commandDivElm = gridContainerDiv.querySelector('[data-command="sort-asc"]') as HTMLDivElement; expect(columnsMock[1].header!.menu!.commandItems!).toEqual([ - { iconCssClass: 'fa fa-sort-asc', title: 'Sort Ascending', titleKey: 'SORT_ASCENDING', command: 'sort-asc', positionOrder: 50 }, - { iconCssClass: 'fa fa-sort-desc', title: 'Sort Descending', titleKey: 'SORT_DESCENDING', command: 'sort-desc', positionOrder: 51 }, + { iconCssClass: 'mdi mdi-sort-ascending', title: 'Sort Ascending', titleKey: 'SORT_ASCENDING', command: 'sort-asc', positionOrder: 50 }, + { iconCssClass: 'mdi mdi-sort-descending', title: 'Sort Descending', titleKey: 'SORT_DESCENDING', command: 'sort-desc', positionOrder: 51 }, { divider: true, command: '', positionOrder: 52 }, - { iconCssClass: 'fa fa-unsorted', title: 'Remove Sort', titleKey: 'REMOVE_SORT', command: 'clear-sort', positionOrder: 54 }, + { iconCssClass: 'mdi mdi-sort-variant-off', title: 'Remove Sort', titleKey: 'REMOVE_SORT', command: 'clear-sort', positionOrder: 54 }, ]); const clickEvent = new Event('click'); @@ -1125,10 +1132,10 @@ describe('HeaderMenu Plugin', () => { const commandDivElm = gridContainerDiv.querySelector('[data-command="sort-desc"]') as HTMLDivElement; expect(columnsMock[1].header!.menu!.commandItems!).toEqual([ - { iconCssClass: 'fa fa-sort-asc', title: 'Sort Ascending', titleKey: 'SORT_ASCENDING', command: 'sort-asc', positionOrder: 50 }, - { iconCssClass: 'fa fa-sort-desc', title: 'Sort Descending', titleKey: 'SORT_DESCENDING', command: 'sort-desc', positionOrder: 51 }, + { iconCssClass: 'mdi mdi-sort-ascending', title: 'Sort Ascending', titleKey: 'SORT_ASCENDING', command: 'sort-asc', positionOrder: 50 }, + { iconCssClass: 'mdi mdi-sort-descending', title: 'Sort Descending', titleKey: 'SORT_DESCENDING', command: 'sort-desc', positionOrder: 51 }, { divider: true, command: '', positionOrder: 52 }, - { iconCssClass: 'fa fa-unsorted', title: 'Remove Sort', titleKey: 'REMOVE_SORT', command: 'clear-sort', positionOrder: 54 }, + { iconCssClass: 'mdi mdi-sort-variant-off', title: 'Remove Sort', titleKey: 'REMOVE_SORT', command: 'clear-sort', positionOrder: 54 }, ]); const clickEvent = new Event('click'); diff --git a/packages/common/src/extensions/__tests__/slickRowMoveManager.spec.ts b/packages/common/src/extensions/__tests__/slickRowMoveManager.spec.ts index 93d89312f..0e008f5b4 100644 --- a/packages/common/src/extensions/__tests__/slickRowMoveManager.spec.ts +++ b/packages/common/src/extensions/__tests__/slickRowMoveManager.spec.ts @@ -6,7 +6,6 @@ import { SlickRowMoveManager } from '../slickRowMoveManager'; import { SlickEvent, SlickGrid } from '../../core/index'; const GRID_UID = 'slickgrid_12345'; -jest.mock('flatpickr', () => { }); const addVanillaEventPropagation = function (event, target?: HTMLElement) { Object.defineProperty(event, 'isPropagationStopped', { writable: true, configurable: true, value: jest.fn() }); @@ -230,7 +229,7 @@ describe('SlickRowMoveManager Plugin', () => { const output = plugin.getColumnDefinition().formatter!(0, 0, null, { id: '_move', field: '' } as Column, { firstName: 'John', lastName: 'Doe', age: 33 }, gridStub); expect(plugin).toBeTruthy(); - expect(output).toEqual({ addClasses: 'cell-reorder dnd slick-row-move-column', html: iconElm }); + expect(output).toEqual({ addClasses: 'cell-reorder dnd', html: iconElm }); }); it('should process the "checkboxSelectionFormatter" and expect necessary Formatter to return regular formatter when usabilityOverride is not a function', () => { @@ -242,7 +241,7 @@ describe('SlickRowMoveManager Plugin', () => { const output = plugin.getColumnDefinition().formatter!(0, 0, null, { id: '_move', field: '' } as Column, { firstName: 'John', lastName: 'Doe', age: 33 }, gridStub); expect(plugin).toBeTruthy(); - expect(output).toEqual({ addClasses: 'cell-reorder dnd slick-row-move-column', html: iconElm }); + expect(output).toEqual({ addClasses: 'cell-reorder dnd', html: iconElm }); }); it('should create the plugin and trigger "dragInit" event and expect "stopImmediatePropagation" to be called', () => { diff --git a/packages/common/src/extensions/__tests__/slickRowSelectionModel.spec.ts b/packages/common/src/extensions/__tests__/slickRowSelectionModel.spec.ts index 602c4cb2f..4f83bfc0c 100644 --- a/packages/common/src/extensions/__tests__/slickRowSelectionModel.spec.ts +++ b/packages/common/src/extensions/__tests__/slickRowSelectionModel.spec.ts @@ -7,7 +7,6 @@ import { SlickRowSelectionModel } from '../slickRowSelectionModel'; import { BasePubSubService } from '@slickgrid-universal/event-pub-sub'; const GRID_UID = 'slickgrid_12345'; -jest.mock('flatpickr', () => { }); const addVanillaEventPropagation = function (event, commandKey = '', keyName = '') { Object.defineProperty(event, 'isPropagationStopped', { writable: true, configurable: true, value: jest.fn() }); diff --git a/packages/common/src/extensions/extensionCommonUtils.ts b/packages/common/src/extensions/extensionCommonUtils.ts index c6911d83a..a31158d28 100644 --- a/packages/common/src/extensions/extensionCommonUtils.ts +++ b/packages/common/src/extensions/extensionCommonUtils.ts @@ -5,6 +5,9 @@ import type { Column, ColumnPickerOption, DOMEvent, GridMenuOption } from '../in import { SlickColumnPicker } from './slickColumnPicker'; import { SlickGridMenu } from './slickGridMenu'; +const PICKER_CHECK_ICON = 'mdi-icon-picker-check'; +const PICKER_UNCHECK_ICON = 'mdi-icon-picker-uncheck'; + /** Create a Close button element and add it to the Menu element */ export function addCloseButtomElement(this: SlickColumnPicker | SlickGridMenu, menuElm: HTMLDivElement) { const context: any = this; @@ -37,28 +40,28 @@ export function addColumnTitleElementWhenDefined(this: SlickColumnPicker | Slick export function handleColumnPickerItemClick(this: SlickColumnPicker | SlickGridMenu, event: DOMEvent) { const context: any = this; const controlType = context instanceof SlickColumnPicker ? 'columnPicker' : 'gridMenu'; + const iconContainerElm = event.target?.closest('.icon-checkbox-container') as HTMLDivElement; + const iconElm = iconContainerElm?.querySelector('.mdi'); + const isChecked = !!(event.target.checked); + event.target.ariaChecked = String(isChecked); + togglePickerCheckbox(iconElm, isChecked); if (event.target.dataset.option === 'autoresize') { // when calling setOptions, it will resize with ALL Columns (even the hidden ones) // we can avoid this problem by keeping a reference to the visibleColumns before setOptions and then setColumns after const previousVisibleColumns = context.getVisibleColumns(); - event.target.ariaChecked = String(event.target.checked); - const isChecked = event.target.checked; context.grid.setOptions({ forceFitColumns: isChecked }); context.grid.setColumns(previousVisibleColumns); return; } if (event.target.dataset.option === 'syncresize') { - event.target.ariaChecked = String(event.target.checked); - context.grid.setOptions({ syncColumnCellResize: !!(event.target.checked) }); + context.grid.setOptions({ syncColumnCellResize: isChecked }); return; } if (event.target.type === 'checkbox') { context._areVisibleColumnDifferent = true; - event.target.ariaChecked = String(event.target.checked); - const isChecked = event.target.checked; const columnId = event.target.dataset.columnid || ''; const visibleColumns: Column[] = []; context._columnCheckboxes.forEach((columnCheckbox: HTMLInputElement, idx: number) => { @@ -69,6 +72,7 @@ export function handleColumnPickerItemClick(this: SlickColumnPicker | SlickGridM if (!visibleColumns.length) { event.target.checked = true; + togglePickerCheckbox(iconElm, true); return; } @@ -114,6 +118,32 @@ export function handleColumnPickerItemClick(this: SlickColumnPicker | SlickGridM } } +function togglePickerCheckbox(iconElm: HTMLDivElement | null, checked = false) { + if (iconElm) { + iconElm.className = `mdi ${checked ? PICKER_CHECK_ICON : PICKER_UNCHECK_ICON}`; + } +} + +function generatePickerCheckbox(columnLiElm: HTMLLIElement, inputId: string, inputData: any, checked = false) { + const labelElm = createDomElement('label', { className: 'checkbox-picker-label', htmlFor: inputId }); + const divElm = createDomElement('div', { className: 'icon-checkbox-container' }); + const inputElm = createDomElement('input', { id: inputId, type: 'checkbox', dataset: inputData }); + const colInputDivElm = createDomElement('div', { className: `mdi ${checked ? PICKER_CHECK_ICON : PICKER_UNCHECK_ICON}` }); + const labelSpanElm = createDomElement('span', { className: 'checkbox-label' }); + divElm.appendChild(inputElm); + divElm.appendChild(colInputDivElm); + labelElm.appendChild(divElm); + labelElm.appendChild(labelSpanElm); + columnLiElm.appendChild(labelElm); + + if (checked) { + inputElm.ariaChecked = 'true'; + inputElm.checked = true; + } + + return { inputElm, labelElm, labelSpanElm }; +} + export function populateColumnPicker(this: SlickColumnPicker | SlickGridMenu, addonOptions: ColumnPickerOption | GridMenuOption) { const context: any = this; const menuPrefix = context instanceof SlickGridMenu ? 'gridmenu-' : ''; @@ -125,24 +155,15 @@ export function populateColumnPicker(this: SlickColumnPicker | SlickGridMenu, ad columnLiElm.className = 'hidden'; } - const colInputElm = createDomElement('input', { - type: 'checkbox', id: `${context._gridUid}-${menuPrefix}colpicker-${columnId}`, - dataset: { columnid: `${columnId}` } - }); - const colIndex = context.grid.getColumnIndex(columnId); - if (colIndex >= 0) { - colInputElm.ariaChecked = 'true'; - colInputElm.checked = true; - } - columnLiElm.appendChild(colInputElm); - context._columnCheckboxes.push(colInputElm); + const inputId = `${context._gridUid}-${menuPrefix}colpicker-${columnId}`; + const isChecked = context.grid.getColumnIndex(columnId) >= 0; + const { inputElm, labelElm, labelSpanElm } = generatePickerCheckbox(columnLiElm, inputId, { columnid: `${columnId}` }, isChecked); + context._columnCheckboxes.push(inputElm); const headerColumnValueExtractorFn = typeof addonOptions?.headerColumnValueExtractor === 'function' ? addonOptions.headerColumnValueExtractor : context._defaults.headerColumnValueExtractor; const columnLabel = headerColumnValueExtractorFn!(column, context.gridOptions); - const labelElm = document.createElement('label'); - labelElm.htmlFor = `${context._gridUid}-${menuPrefix}colpicker-${columnId}`; - this.grid.applyHtmlCode(labelElm, columnLabel); + this.grid.applyHtmlCode(labelSpanElm, columnLabel); columnLiElm.appendChild(labelElm); context._listElm.appendChild(columnLiElm); } @@ -153,39 +174,17 @@ export function populateColumnPicker(this: SlickColumnPicker | SlickGridMenu, ad if (!(addonOptions?.hideForceFitButton)) { const fitLiElm = document.createElement('li'); - fitLiElm.appendChild( - createDomElement('input', { - type: 'checkbox', id: `${context._gridUid}-${menuPrefix}colpicker-forcefit`, - ariaChecked: String(context.gridOptions.forceFitColumns), - checked: context.gridOptions.forceFitColumns, - dataset: { option: 'autoresize' } - }) - ); - fitLiElm.appendChild( - createDomElement('label', { - htmlFor: `${context._gridUid}-${menuPrefix}colpicker-forcefit`, - textContent: addonOptions?.forceFitTitle ?? '', - }) - ); + const inputId = `${context._gridUid}-${menuPrefix}colpicker-forcefit`; + const { labelSpanElm } = generatePickerCheckbox(fitLiElm, inputId, { option: 'autoresize' }, context.gridOptions.forceFitColumns); + labelSpanElm.textContent = addonOptions?.forceFitTitle ?? ''; context._listElm.appendChild(fitLiElm); } if (!(addonOptions?.hideSyncResizeButton)) { const syncLiElm = document.createElement('li'); - syncLiElm.appendChild( - createDomElement('input', { - type: 'checkbox', id: `${context._gridUid}-${menuPrefix}colpicker-syncresize`, - ariaChecked: String(context.gridOptions.syncColumnCellResize), - checked: context.gridOptions.syncColumnCellResize, - dataset: { option: 'syncresize' } - }) - ); - syncLiElm.appendChild( - createDomElement('label', { - htmlFor: `${context._gridUid}-${menuPrefix}colpicker-syncresize`, - textContent: addonOptions?.syncResizeTitle ?? '' - }) - ); + const inputId = `${context._gridUid}-${menuPrefix}colpicker-syncresize`; + const { labelSpanElm } = generatePickerCheckbox(syncLiElm, inputId, { option: 'syncresize' }, context.gridOptions.forceFitColumns); + labelSpanElm.textContent = addonOptions?.syncResizeTitle ?? ''; context._listElm.appendChild(syncLiElm); } } diff --git a/packages/common/src/extensions/slickCheckboxSelectColumn.ts b/packages/common/src/extensions/slickCheckboxSelectColumn.ts index f3543dacf..fc3cd1dcf 100644 --- a/packages/common/src/extensions/slickCheckboxSelectColumn.ts +++ b/packages/common/src/extensions/slickCheckboxSelectColumn.ts @@ -9,6 +9,9 @@ import type { SelectionModel } from '../enums/index'; export interface RowLookup { [row: number]: boolean; } +const CHECK_ICON = 'mdi-icon-check'; +const UNCHECK_ICON = 'mdi-icon-uncheck'; + export class SlickCheckboxSelectColumn { pluginName: 'CheckboxSelectColumn' = 'CheckboxSelectColumn' as const; protected _defaults = { @@ -219,12 +222,16 @@ export class SlickCheckboxSelectColumn { */ createCheckboxElement(inputId: string, checked = false) { const fragmentElm = new DocumentFragment(); - fragmentElm.appendChild( + const labelElm = createDomElement('label', { className: 'checkbox-selector-label', htmlFor: inputId }); + const divElm = createDomElement('div', { className: 'icon-checkbox-container' }); + divElm.appendChild( createDomElement('input', { id: inputId, type: 'checkbox', checked, ariaChecked: String(checked) }) ); - fragmentElm.appendChild( - createDomElement('label', { htmlFor: inputId }) + divElm.appendChild( + createDomElement('div', { className: `mdi ${checked ? CHECK_ICON : UNCHECK_ICON}` }) ); + labelElm.appendChild(divElm); + fragmentElm.appendChild(labelElm); return fragmentElm; } @@ -250,6 +257,7 @@ export class SlickCheckboxSelectColumn { reorderable: this._addonOptions.reorderable, sortable: false, width: this._addonOptions.width || 30, + maxWidth: this._addonOptions.width || 30, formatter: this.checkboxSelectionFormatter.bind(this), } as Column; } @@ -287,7 +295,7 @@ export class SlickCheckboxSelectColumn { // user can optionally execute a callback defined in its grid options prior to toggling the row const previousSelectedRows = this._grid.getSelectedRows(); - if (this._addonOptions.onRowToggleStart) { + if (typeof this._addonOptions.onRowToggleStart === 'function') { this._addonOptions.onRowToggleStart(event, { row, previousSelectedRows }); } @@ -320,18 +328,22 @@ export class SlickCheckboxSelectColumn { if (args.column.field === (this._addonOptions.field || '_checkbox_selector')) { emptyElement(args.node); - // - const spanElm = createDomElement('span', { id: 'filter-checkbox-selectall-container', ariaChecked: 'false' }); - spanElm.appendChild( - createDomElement('input', { type: 'checkbox', id: `header-filter-selector${this._selectAll_UID}` }) + const inputId = `header-filter-selector${this._selectAll_UID}`; + const labelElm = createDomElement('label', { id: 'filter-checkbox-selectall-container', htmlFor: inputId }); + const divElm = createDomElement('div', { className: 'icon-checkbox-container' }); + divElm.appendChild( + createDomElement('input', { id: inputId, type: 'checkbox', ariaChecked: 'false' }) ); - spanElm.appendChild( - createDomElement('label', { htmlFor: `header-filter-selector${this._selectAll_UID}` }) + divElm.appendChild( + createDomElement('div', { className: 'mdi mdi-icon-uncheck' }) ); - args.node.appendChild(spanElm); + + labelElm.appendChild(divElm); + args.node.appendChild(labelElm); this._headerRowNode = args.node; + this._headerRowNode.classList.add('checkbox-header'); - this._bindEventService.bind(spanElm, 'click', ((e: DOMMouseOrTouchEvent) => this.handleHeaderClick(e, args)) as EventListener); + this._bindEventService.bind(labelElm, 'click', ((e: DOMMouseOrTouchEvent) => this.handleHeaderClick(e, args)) as EventListener); } }); } @@ -392,10 +404,14 @@ export class SlickCheckboxSelectColumn { } if (!this._addonOptions.hideInFilterHeaderRow) { const selectAllElm = this.headerRowNode?.querySelector(`#header-filter-selector${this._selectAll_UID}`); + const selectAllIconElm = this.headerRowNode?.querySelector('.icon-checkbox-container .mdi'); if (selectAllElm) { selectAllElm.ariaChecked = String(this._isSelectAllChecked); selectAllElm.checked = this._isSelectAllChecked; } + if (selectAllIconElm) { + selectAllIconElm.className = `mdi ${this._isSelectAllChecked ? CHECK_ICON : UNCHECK_ICON}`; + } } } @@ -562,10 +578,11 @@ export class SlickCheckboxSelectColumn { } protected renderSelectAllCheckbox(isSelectAllChecked: boolean) { - this._grid.updateColumnHeader( + const colHeaderElm = this._grid.updateColumnHeader( this._addonOptions.columnId || '', this.createCheckboxElement(`header-selector${this._selectAll_UID}`, !!isSelectAllChecked), this._addonOptions.toolTip ); + colHeaderElm?.classList.add('header-checkbox-selectall'); } } \ No newline at end of file diff --git a/packages/common/src/extensions/slickColumnPicker.ts b/packages/common/src/extensions/slickColumnPicker.ts index fbdc4b3e3..0fd5a410d 100644 --- a/packages/common/src/extensions/slickColumnPicker.ts +++ b/packages/common/src/extensions/slickColumnPicker.ts @@ -101,6 +101,7 @@ export class SlickColumnPicker { this._eventHandler.subscribe(this.grid.onHeaderContextMenu, this.handleHeaderContextMenu.bind(this)); this._eventHandler.subscribe(this.grid.onColumnsReordered, updateColumnPickerOrder.bind(this)); + this._eventHandler.subscribe(this.grid.onClick, this.disposeMenu.bind(this)); // Hide the menu on outside click. this._bindEventService.bind(document.body, 'mousedown', this.handleBodyMouseDown.bind(this) as EventListener, undefined, 'body'); diff --git a/packages/common/src/extensions/slickContextMenu.ts b/packages/common/src/extensions/slickContextMenu.ts index 2049d997f..8100d5b96 100644 --- a/packages/common/src/extensions/slickContextMenu.ts +++ b/packages/common/src/extensions/slickContextMenu.ts @@ -75,6 +75,7 @@ export class SlickContextMenu extends MenuFromCellBaseClass { this.sortMenuItems(); this._eventHandler.subscribe(this.grid.onContextMenu, this.handleOnContextMenu.bind(this)); + this._eventHandler.subscribe(this.grid.onClick, this.hideMenu.bind(this)); if (this._addonOptions.hideMenuOnScroll) { this._eventHandler.subscribe(this.grid.onScroll, this.closeMenu.bind(this)); @@ -169,7 +170,7 @@ export class SlickContextMenu extends MenuFromCellBaseClass { if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { menuCommandItems.push( { - iconCssClass: contextMenu.iconCopyCellValueCommand || 'fa fa-clone', + iconCssClass: contextMenu.iconCopyCellValueCommand || 'mdi mdi-content-copy', titleKey: `${translationPrefix}COPY`, disabled: false, command: commandName, @@ -202,7 +203,7 @@ export class SlickContextMenu extends MenuFromCellBaseClass { if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { menuCommandItems.push( { - iconCssClass: contextMenu.iconExportCsvCommand || 'fa fa-download', + iconCssClass: contextMenu.iconExportCsvCommand || 'mdi mdi-download', titleKey: `${translationPrefix}EXPORT_TO_CSV`, disabled: false, command: commandName, @@ -230,7 +231,7 @@ export class SlickContextMenu extends MenuFromCellBaseClass { if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { menuCommandItems.push( { - iconCssClass: contextMenu.iconExportExcelCommand || 'fa fa-file-excel-o text-success', + iconCssClass: contextMenu.iconExportExcelCommand || 'mdi mdi-file-excel-outline text-success', titleKey: `${translationPrefix}EXPORT_TO_EXCEL`, disabled: false, command: commandName, @@ -255,7 +256,7 @@ export class SlickContextMenu extends MenuFromCellBaseClass { if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { menuCommandItems.push( { - iconCssClass: contextMenu.iconExportTextDelimitedCommand || 'fa fa-download', + iconCssClass: contextMenu.iconExportTextDelimitedCommand || 'mdi mdi-download', titleKey: `${translationPrefix}EXPORT_TO_TAB_DELIMITED`, disabled: false, command: commandName, @@ -290,7 +291,7 @@ export class SlickContextMenu extends MenuFromCellBaseClass { if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { menuCommandItems.push( { - iconCssClass: contextMenu.iconClearGroupingCommand || 'fa fa-times', + iconCssClass: contextMenu.iconClearGroupingCommand || 'mdi mdi-close', titleKey: `${translationPrefix}CLEAR_ALL_GROUPING`, disabled: false, command: commandName, @@ -315,7 +316,7 @@ export class SlickContextMenu extends MenuFromCellBaseClass { if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { menuCommandItems.push( { - iconCssClass: contextMenu.iconCollapseAllGroupsCommand || 'fa fa-compress', + iconCssClass: contextMenu.iconCollapseAllGroupsCommand || 'mdi mdi-arrow-collapse', titleKey: `${translationPrefix}COLLAPSE_ALL_GROUPS`, disabled: false, command: commandName, @@ -347,7 +348,7 @@ export class SlickContextMenu extends MenuFromCellBaseClass { if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { menuCommandItems.push( { - iconCssClass: contextMenu.iconExpandAllGroupsCommand || 'fa fa-expand', + iconCssClass: contextMenu.iconExpandAllGroupsCommand || 'mdi mdi-arrow-expand', titleKey: `${translationPrefix}EXPAND_ALL_GROUPS`, disabled: false, command: commandName, diff --git a/packages/common/src/extensions/slickDraggableGrouping.ts b/packages/common/src/extensions/slickDraggableGrouping.ts index 7b6568fa8..1782910ad 100644 --- a/packages/common/src/extensions/slickDraggableGrouping.ts +++ b/packages/common/src/extensions/slickDraggableGrouping.ts @@ -320,7 +320,7 @@ export class SlickDraggableGrouping { draggablePlaceholderElm.style.display = 'none'; } if (groupTogglerElm) { - groupTogglerElm.style.display = 'inline-block'; + groupTogglerElm.style.display = 'inline-flex'; } } @@ -488,7 +488,7 @@ export class SlickDraggableGrouping { // show the "Toggle All" when feature is enabled if (this._groupToggler && this.columnsGroupBy.length > 0) { - this._groupToggler.style.display = 'inline-block'; + this._groupToggler.style.display = 'inline-flex'; } } } diff --git a/packages/common/src/extensions/slickGridMenu.ts b/packages/common/src/extensions/slickGridMenu.ts index 9dbd8d55c..71dfd7b08 100644 --- a/packages/common/src/extensions/slickGridMenu.ts +++ b/packages/common/src/extensions/slickGridMenu.ts @@ -114,6 +114,7 @@ export class SlickGridMenu extends MenuBaseClass { initEventHandlers() { // when grid columns are reordered then we also need to update/resync our picker column in the same order this._eventHandler.subscribe(this.grid.onColumnsReordered, updateColumnPickerOrder.bind(this)); + this._eventHandler.subscribe(this.grid.onClick, (e) => this.hideMenu(e as any)); // subscribe to the grid, when it's destroyed, we should also destroy the Grid Menu this._eventHandler.subscribe(this.grid.onBeforeDestroy, this.dispose.bind(this)); @@ -570,7 +571,7 @@ export class SlickGridMenu extends MenuBaseClass { const commandName = 'clear-pinning'; if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { gridMenuCommandItems.push({ - iconCssClass: this._addonOptions.iconClearFrozenColumnsCommand || 'fa fa-times', + iconCssClass: this._addonOptions.iconClearFrozenColumnsCommand || 'mdi mdi-pin-off-outline', titleKey: `${translationPrefix}${commandLabels?.clearFrozenColumnsCommandKey ?? 'CLEAR_PINNING'}`, disabled: false, command: commandName, @@ -585,7 +586,7 @@ export class SlickGridMenu extends MenuBaseClass { const commandName = 'clear-filter'; if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { gridMenuCommandItems.push({ - iconCssClass: this._addonOptions.iconClearAllFiltersCommand || 'fa fa-filter text-danger', + iconCssClass: this._addonOptions.iconClearAllFiltersCommand || 'mdi mdi-filter-remove-outline', titleKey: `${translationPrefix}${commandLabels?.clearAllFiltersCommandKey ?? 'CLEAR_ALL_FILTERS'}`, disabled: false, command: commandName, @@ -599,7 +600,7 @@ export class SlickGridMenu extends MenuBaseClass { const commandName = 'toggle-filter'; if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { gridMenuCommandItems.push({ - iconCssClass: this._addonOptions.iconToggleFilterCommand || 'fa fa-random', + iconCssClass: this._addonOptions.iconToggleFilterCommand || 'mdi mdi-flip-vertical', titleKey: `${translationPrefix}${commandLabels?.toggleFilterCommandKey ?? 'TOGGLE_FILTER_ROW'}`, disabled: false, command: commandName, @@ -613,7 +614,7 @@ export class SlickGridMenu extends MenuBaseClass { const commandName = 'refresh-dataset'; if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { gridMenuCommandItems.push({ - iconCssClass: this._addonOptions.iconRefreshDatasetCommand || 'fa fa-refresh', + iconCssClass: this._addonOptions.iconRefreshDatasetCommand || 'mdi mdi-sync', titleKey: `${translationPrefix}${commandLabels?.refreshDatasetCommandKey ?? 'REFRESH_DATASET'}`, disabled: false, command: commandName, @@ -628,7 +629,7 @@ export class SlickGridMenu extends MenuBaseClass { const commandName = 'toggle-dark-mode'; if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { gridMenuCommandItems.push({ - iconCssClass: this._addonOptions.iconToggleDarkModeCommand || 'fa fa-random', + iconCssClass: this._addonOptions.iconToggleDarkModeCommand || 'mdi mdi-brightness-4', titleKey: `${translationPrefix}${commandLabels?.toggleDarkModeCommandKey ?? 'TOGGLE_DARK_MODE'}`, disabled: false, command: commandName, @@ -643,7 +644,7 @@ export class SlickGridMenu extends MenuBaseClass { const commandName = 'toggle-preheader'; if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { gridMenuCommandItems.push({ - iconCssClass: this._addonOptions.iconTogglePreHeaderCommand || 'fa fa-random', + iconCssClass: this._addonOptions.iconTogglePreHeaderCommand || 'mdi mdi-flip-vertical', titleKey: `${translationPrefix}${commandLabels?.togglePreHeaderCommandKey ?? 'TOGGLE_PRE_HEADER_ROW'}`, disabled: false, command: commandName, @@ -659,7 +660,7 @@ export class SlickGridMenu extends MenuBaseClass { const commandName = 'clear-sorting'; if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { gridMenuCommandItems.push({ - iconCssClass: this._addonOptions.iconClearAllSortingCommand || 'fa fa-unsorted text-danger', + iconCssClass: this._addonOptions.iconClearAllSortingCommand || 'mdi mdi-sort-variant-off', titleKey: `${translationPrefix}${commandLabels?.clearAllSortingCommandKey ?? 'CLEAR_ALL_SORTING'}`, disabled: false, command: commandName, @@ -674,7 +675,7 @@ export class SlickGridMenu extends MenuBaseClass { const commandName = 'export-csv'; if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { gridMenuCommandItems.push({ - iconCssClass: this._addonOptions.iconExportCsvCommand || 'fa fa-download', + iconCssClass: this._addonOptions.iconExportCsvCommand || 'mdi mdi-download', titleKey: `${translationPrefix}${commandLabels?.exportCsvCommandKey ?? 'EXPORT_TO_CSV'}`, disabled: false, command: commandName, @@ -688,7 +689,7 @@ export class SlickGridMenu extends MenuBaseClass { const commandName = 'export-excel'; if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { gridMenuCommandItems.push({ - iconCssClass: this._addonOptions.iconExportExcelCommand || 'fa fa-file-excel-o text-success', + iconCssClass: this._addonOptions.iconExportExcelCommand || 'mdi mdi-file-excel-outline text-success', titleKey: `${translationPrefix}${commandLabels?.exportExcelCommandKey ?? 'EXPORT_TO_EXCEL'}`, disabled: false, command: commandName, @@ -702,7 +703,7 @@ export class SlickGridMenu extends MenuBaseClass { const commandName = 'export-text-delimited'; if (!originalCommandItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) { gridMenuCommandItems.push({ - iconCssClass: this._addonOptions.iconExportTextDelimitedCommand || 'fa fa-download', + iconCssClass: this._addonOptions.iconExportTextDelimitedCommand || 'mdi mdi-download', titleKey: `${translationPrefix}${commandLabels?.exportTextDelimitedCommandKey ?? 'EXPORT_TO_TAB_DELIMITED'}`, disabled: false, command: commandName, @@ -830,7 +831,7 @@ export class SlickGridMenu extends MenuBaseClass { columnTitle: this.extensionUtility.getPickerTitleOutputString('columnTitle', 'gridMenu'), forceFitTitle: this.extensionUtility.getPickerTitleOutputString('forceFitTitle', 'gridMenu'), syncResizeTitle: this.extensionUtility.getPickerTitleOutputString('syncResizeTitle', 'gridMenu'), - iconCssClass: 'fa fa-bars', + iconCssClass: 'mdi mdi-menu', menuWidth: 18, commandItems: [], hideClearAllFiltersCommand: false, diff --git a/packages/common/src/extensions/slickHeaderMenu.ts b/packages/common/src/extensions/slickHeaderMenu.ts index 3a5b5ec81..f5e57643f 100644 --- a/packages/common/src/extensions/slickHeaderMenu.ts +++ b/packages/common/src/extensions/slickHeaderMenu.ts @@ -79,6 +79,7 @@ export class SlickHeaderMenu extends MenuBaseClass { }); this._eventHandler.subscribe(this.grid.onHeaderCellRendered, this.handleHeaderCellRendered.bind(this)); this._eventHandler.subscribe(this.grid.onBeforeHeaderCellDestroy, this.handleBeforeHeaderCellDestroy.bind(this)); + this._eventHandler.subscribe(this.grid.onClick, this.hideMenu.bind(this)); // force the grid to re-render the header after the events are hooked up. this.grid.setColumns(this.grid.getColumns()); @@ -357,7 +358,7 @@ export class SlickHeaderMenu extends MenuBaseClass { hasFrozenOrResizeCommand = true; if (!columnHeaderMenuItems.some(item => item !== 'divider' && item?.command === 'freeze-columns')) { columnHeaderMenuItems.push({ - iconCssClass: headerMenuOptions.iconFreezeColumns || 'fa fa-thumb-tack', + iconCssClass: headerMenuOptions.iconFreezeColumns || 'mdi mdi-pin-outline', titleKey: `${translationPrefix}FREEZE_COLUMNS`, command: 'freeze-columns', positionOrder: 47 @@ -370,7 +371,7 @@ export class SlickHeaderMenu extends MenuBaseClass { hasFrozenOrResizeCommand = true; if (!columnHeaderMenuItems.some(item => item !== 'divider' && item?.command === 'column-resize-by-content')) { columnHeaderMenuItems.push({ - iconCssClass: headerMenuOptions.iconColumnResizeByContentCommand || 'fa fa-arrows-h', + iconCssClass: headerMenuOptions.iconColumnResizeByContentCommand || 'mdi mdi-arrow-expand-horizontal', titleKey: `${translationPrefix}COLUMN_RESIZE_BY_CONTENT`, command: 'column-resize-by-content', positionOrder: 48 @@ -387,7 +388,7 @@ export class SlickHeaderMenu extends MenuBaseClass { if (gridOptions.enableSorting && columnDef.sortable && headerMenuOptions && !headerMenuOptions.hideSortCommands) { if (!columnHeaderMenuItems.some(item => item !== 'divider' && item?.command === 'sort-asc')) { columnHeaderMenuItems.push({ - iconCssClass: headerMenuOptions.iconSortAscCommand || 'fa fa-sort-asc', + iconCssClass: headerMenuOptions.iconSortAscCommand || 'mdi mdi-sort-ascending', titleKey: `${translationPrefix}SORT_ASCENDING`, command: 'sort-asc', positionOrder: 50 @@ -395,7 +396,7 @@ export class SlickHeaderMenu extends MenuBaseClass { } if (!columnHeaderMenuItems.some(item => item !== 'divider' && item?.command === 'sort-desc')) { columnHeaderMenuItems.push({ - iconCssClass: headerMenuOptions.iconSortDescCommand || 'fa fa-sort-desc', + iconCssClass: headerMenuOptions.iconSortDescCommand || 'mdi mdi-sort-descending', titleKey: `${translationPrefix}SORT_DESCENDING`, command: 'sort-desc', positionOrder: 51 @@ -409,7 +410,7 @@ export class SlickHeaderMenu extends MenuBaseClass { if (!headerMenuOptions.hideClearSortCommand && !columnHeaderMenuItems.some(item => item !== 'divider' && item?.command === 'clear-sort')) { columnHeaderMenuItems.push({ - iconCssClass: headerMenuOptions.iconClearSortCommand || 'fa fa-unsorted', + iconCssClass: headerMenuOptions.iconClearSortCommand || 'mdi mdi-sort-variant-off', titleKey: `${translationPrefix}REMOVE_SORT`, command: 'clear-sort', positionOrder: 54 @@ -421,7 +422,7 @@ export class SlickHeaderMenu extends MenuBaseClass { if (gridOptions.enableFiltering && columnDef.filterable && headerMenuOptions && !headerMenuOptions.hideFilterCommand) { if (!headerMenuOptions.hideClearFilterCommand && !columnHeaderMenuItems.some(item => item !== 'divider' && item?.command === 'clear-filter')) { columnHeaderMenuItems.push({ - iconCssClass: headerMenuOptions.iconClearFilterCommand || 'fa fa-filter', + iconCssClass: headerMenuOptions.iconClearFilterCommand || 'mdi mdi-filter-remove-outline', titleKey: `${translationPrefix}REMOVE_FILTER`, command: 'clear-filter', positionOrder: 53 @@ -432,7 +433,7 @@ export class SlickHeaderMenu extends MenuBaseClass { // Hide Column Command if (headerMenuOptions && !headerMenuOptions.hideColumnHideCommand && !columnHeaderMenuItems.some(item => item !== 'divider' && item?.command === 'hide-column')) { columnHeaderMenuItems.push({ - iconCssClass: headerMenuOptions.iconColumnHideCommand || 'fa fa-times', + iconCssClass: headerMenuOptions.iconColumnHideCommand || 'mdi mdi-close', titleKey: `${translationPrefix}HIDE_COLUMN`, command: 'hide-column', positionOrder: 55 diff --git a/packages/common/src/extensions/slickRowBasedEdit.ts b/packages/common/src/extensions/slickRowBasedEdit.ts index 29d9afbd9..7a5765bec 100644 --- a/packages/common/src/extensions/slickRowBasedEdit.ts +++ b/packages/common/src/extensions/slickRowBasedEdit.ts @@ -439,7 +439,7 @@ export class SlickRowBasedEdit { .appendChild( createDomElement('span', { className: - options.rowBasedEditOptions?.actionButtons?.iconEditButtonClassName || 'mdi mdi-table-edit color-primary', + options.rowBasedEditOptions?.actionButtons?.iconEditButtonClassName || 'mdi mdi-table-edit text-color-primary', }) ); actionFragment @@ -455,7 +455,7 @@ export class SlickRowBasedEdit { .appendChild( createDomElement('span', { className: - options.rowBasedEditOptions?.actionButtons?.iconDeleteButtonClassName || 'mdi mdi-close color-danger', + options.rowBasedEditOptions?.actionButtons?.iconDeleteButtonClassName || 'mdi mdi-close text-color-danger', }) ); actionFragment @@ -471,7 +471,7 @@ export class SlickRowBasedEdit { .appendChild( createDomElement('span', { className: - options.rowBasedEditOptions?.actionButtons?.iconUpdateButtonClassName || 'mdi mdi-check-bold color-success', + options.rowBasedEditOptions?.actionButtons?.iconUpdateButtonClassName || 'mdi mdi-check-bold text-color-success', }) ); actionFragment @@ -487,7 +487,7 @@ export class SlickRowBasedEdit { .appendChild( createDomElement('span', { className: - options.rowBasedEditOptions?.actionButtons?.iconCancelButtonClassName || 'mdi mdi-cancel color-danger', + options.rowBasedEditOptions?.actionButtons?.iconCancelButtonClassName || 'mdi mdi-cancel text-color-danger', }) ); diff --git a/packages/common/src/extensions/slickRowMoveManager.ts b/packages/common/src/extensions/slickRowMoveManager.ts index e989d252e..7bdd91c17 100644 --- a/packages/common/src/extensions/slickRowMoveManager.ts +++ b/packages/common/src/extensions/slickRowMoveManager.ts @@ -320,7 +320,7 @@ export class SlickRowMoveManager { return ''; } else { return { - addClasses: `cell-reorder dnd ${this._addonOptions.cssClass || ''}`, + addClasses: `cell-reorder dnd`, html: createDomElement('div', { className: this._addonOptions.cssClass || '' }), }; } diff --git a/packages/common/src/filter-conditions/__tests__/dateEuroShortFilterCondition.spec.ts b/packages/common/src/filter-conditions/__tests__/dateEuroShortFilterCondition.spec.ts index f8b7e49cc..0d8d5c4b3 100644 --- a/packages/common/src/filter-conditions/__tests__/dateEuroShortFilterCondition.spec.ts +++ b/packages/common/src/filter-conditions/__tests__/dateEuroShortFilterCondition.spec.ts @@ -74,38 +74,77 @@ describe('dateEuroShortFilterCondition method', () => { expect(output).toBe(false); }); - it('should return True when input value is in the range of search terms', () => { - const searchTerms = ['01/12/93..31/12/93']; - const options = { dataKey: '', operator: 'EQ', cellValue: '25/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; - const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); - expect(output).toBe(true); - }); + describe('without zero padding dates', () => { + it('should return True when input value is in the range of search terms with short US dates and without zero padding', () => { + const searchTerms = ['1/12/93..31/12/93']; + const options = { dataKey: '', operator: 'EQ', cellValue: '25/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); + expect(output).toBe(true); + }); - it('should return False when input value is not in the range of search terms', () => { - const searchTerms = ['01/12/93..31/12/93']; - const options = { dataKey: '', operator: 'EQ', cellValue: '25/11/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; - const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); - expect(output).toBe(false); - }); + it('should return False when input value is not in the range of search terms with short US dates and without zero padding', () => { + const searchTerms = ['1/12/93..31/12/93']; + const options = { dataKey: '', operator: 'EQ', cellValue: '25/11/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); + expect(output).toBe(false); + }); - it('should return True when input value equals the search terms min inclusive value and operator is set to "rangeInclusive"', () => { - const searchTerms = ['01/12/93..31/12/93']; - const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '01/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; - const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); - expect(output).toBe(true); - }); + it('should return True when input value equals the search terms min inclusive value and operator is set to "rangeInclusive"', () => { + const searchTerms = ['1/12/93..31/12/93']; + const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '1/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); + expect(output).toBe(true); + }); - it('should return False when input value equals the search terms min inclusive value and operator is set to "RangeExclusive"', () => { - const searchTerms = ['01/12/93..31/12/93']; - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '01/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; - const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); - expect(output).toBe(false); + it('should return False when input value equals the search terms min inclusive value and operator is set to "RangeExclusive"', () => { + const searchTerms = ['1/12/93..31/12/93']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); + expect(output).toBe(false); + }); + + it('should return False when any of the 2 search term value is not a valid date', () => { + const searchTerms = ['1/12/93..60/12/93']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '05/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); + expect(output).toBe(false); + }); }); - it('should return False when any of the 2 search term value is not a valid date', () => { - const searchTerms = ['01/12/93..60/12/93']; - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '05/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; - const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); - expect(output).toBe(false); + describe('zero padding dates', () => { + it('should return True when input value is in the range of search terms', () => { + const searchTerms = ['01/12/93..31/12/93']; + const options = { dataKey: '', operator: 'EQ', cellValue: '25/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); + expect(output).toBe(true); + }); + + it('should return False when input value is not in the range of search terms', () => { + const searchTerms = ['01/12/93..31/12/93']; + const options = { dataKey: '', operator: 'EQ', cellValue: '25/11/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); + expect(output).toBe(false); + }); + + it('should return True when input value equals the search terms min inclusive value and operator is set to "rangeInclusive"', () => { + const searchTerms = ['01/12/93..31/12/93']; + const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '1/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); + expect(output).toBe(true); + }); + + it('should return False when input value equals the search terms min inclusive value and operator is set to "RangeExclusive"', () => { + const searchTerms = ['01/12/93..31/12/93']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); + expect(output).toBe(false); + }); + + it('should return False when any of the 2 search term value is not a valid date', () => { + const searchTerms = ['01/12/93..60/12/93']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '05/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); + expect(output).toBe(false); + }); }); }); diff --git a/packages/common/src/filter-conditions/__tests__/dateUsShortFilterCondition.spec.ts b/packages/common/src/filter-conditions/__tests__/dateUsShortFilterCondition.spec.ts index ad6149193..deaa413d4 100644 --- a/packages/common/src/filter-conditions/__tests__/dateUsShortFilterCondition.spec.ts +++ b/packages/common/src/filter-conditions/__tests__/dateUsShortFilterCondition.spec.ts @@ -40,14 +40,14 @@ describe('dateUsShortFilterCondition method', () => { }); it('should return False when cell value is not the same value as the searchTerm', () => { - const searchTerms = ['03/03/2003']; + const searchTerms = ['3/3/2003']; const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms } as FilterConditionOption; const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); }); it('should return False even when the cell value is found in the searchTerms since it only compares first term', () => { - const searchTerms = ['03/14/03', '12/25/93']; + const searchTerms = ['3/14/03', '12/25/93']; const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms } as FilterConditionOption; const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); @@ -82,36 +82,36 @@ describe('dateUsShortFilterCondition method', () => { }); it('should return True when input value is in the range of search terms', () => { - const searchTerms = ['12/01/93..12/31/93']; + const searchTerms = ['12/1/93..12/31/93']; const options = { dataKey: '', operator: 'EQ', cellValue: '12/25/93', fieldType: FieldType.dateUsShort, searchTerms } as FilterConditionOption; const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(true); }); it('should return False when input value is not in the range of search terms', () => { - const searchTerms = ['12/01/93..12/31/93']; + const searchTerms = ['12/1/93..12/31/93']; const options = { dataKey: '', operator: 'EQ', cellValue: '11/25/93', fieldType: FieldType.dateUsShort, searchTerms } as FilterConditionOption; const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); }); it('should return True when input value equals the search terms min inclusive value and operator is set to "rangeInclusive"', () => { - const searchTerms = ['12/01/93..12/31/93']; - const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '12/01/93', fieldType: FieldType.dateUsShort, searchTerms } as FilterConditionOption; + const searchTerms = ['12/1/93..12/31/93']; + const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '12/1/93', fieldType: FieldType.dateUsShort, searchTerms } as FilterConditionOption; const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(true); }); it('should return False when input value equals the search terms min inclusive value and operator is set to "RangeExclusive"', () => { - const searchTerms = ['12/01/93..12/31/93']; - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '12/01/93', fieldType: FieldType.dateUsShort, searchTerms } as FilterConditionOption; + const searchTerms = ['12/1/93..12/31/93']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '12/1/93', fieldType: FieldType.dateUsShort, searchTerms } as FilterConditionOption; const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); }); it('should return False when any of the 2 search term value is not a valid date', () => { - const searchTerms = ['12/01/93..12/60/93']; - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '12/05/93', fieldType: FieldType.dateUsShort, searchTerms } as FilterConditionOption; + const searchTerms = ['12/1/93..12/60/93']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '12/5/93', fieldType: FieldType.dateUsShort, searchTerms } as FilterConditionOption; const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); }); diff --git a/packages/common/src/filter-conditions/__tests__/filterConditionProcesses.spec.ts b/packages/common/src/filter-conditions/__tests__/filterConditionProcesses.spec.ts index cd0e6d7b7..b838316b3 100644 --- a/packages/common/src/filter-conditions/__tests__/filterConditionProcesses.spec.ts +++ b/packages/common/src/filter-conditions/__tests__/filterConditionProcesses.spec.ts @@ -1,5 +1,3 @@ -import moment from 'moment-mini'; - import { getParsedSearchTermsByFieldType } from '../filterConditionProcesses'; describe('getParsedSearchTermsByFieldType method', () => { @@ -13,15 +11,6 @@ describe('getParsedSearchTermsByFieldType method', () => { expect(result2).toEqual(true); }); - it('should get a moment date object when parsing any date type', () => { - const inputDate = '2001-03-03T10:11:22.456Z'; - const result = getParsedSearchTermsByFieldType([inputDate], 'dateUtc'); - - expect(result![0]).toBeObject(); - expect(moment.isMoment(result![0])).toBeTrue(); - expect(result![0].format('YYYY-MM-DD')).toBe('2001-03-03'); - }); - it('should get parsed result as a number array when providing an array of searchTerms that are string of numbers', () => { const input1 = ['0']; const input2 = ['0', 12]; diff --git a/packages/common/src/filter-conditions/dateFilterCondition.ts b/packages/common/src/filter-conditions/dateFilterCondition.ts index 7a04a1299..89892605a 100644 --- a/packages/common/src/filter-conditions/dateFilterCondition.ts +++ b/packages/common/src/filter-conditions/dateFilterCondition.ts @@ -1,29 +1,31 @@ -import moment from 'moment-mini'; +import { dayStart } from '@formkit/tempo'; import { FieldType, OperatorType, type SearchTerm } from '../enums/index'; import type { FilterConditionOption } from '../interfaces/index'; -import { mapMomentDateFormatWithFieldType } from '../services/utilities'; import { testFilterCondition } from './filterUtilities'; +import { mapTempoDateFormatWithFieldType, tryParseDate } from '../services'; /** * Execute Date filter condition check on each cell and use correct date format depending on it's field type (or filterSearchType when that is provided) */ -export function executeDateFilterCondition(options: FilterConditionOption, parsedSearchDates: any[]): boolean { +export function executeDateFilterCondition(options: FilterConditionOption, parsedSearchDates: Array): boolean { const filterSearchType = options && (options.filterSearchType || options.fieldType) || FieldType.dateIso; - const FORMAT = mapMomentDateFormatWithFieldType(filterSearchType); + const FORMAT = mapTempoDateFormatWithFieldType(filterSearchType); const [searchDate1, searchDate2] = parsedSearchDates; - // cell value in moment format - const dateCell = moment(options.cellValue, FORMAT, true); + // cell value in Date format + const dateCell = tryParseDate(options.cellValue, FORMAT, true); // return when cell value is not a valid date - if ((!searchDate1 && !searchDate2) || !dateCell.isValid()) { + if ((!searchDate1 && !searchDate2) || !dateCell) { return false; } // when comparing with Dates only (without time), we need to disregard the time portion, we can do so by setting our time to start at midnight // ref, see https://stackoverflow.com/a/19699447/1212166 - const dateCellTimestamp = FORMAT.toLowerCase().includes('h') ? dateCell.valueOf() : dateCell.clone().startOf('day').valueOf(); + const dateCellTimestamp = FORMAT === 'ISO8601' || FORMAT.toLowerCase().includes('h') + ? dateCell.valueOf() + : dayStart(new Date(dateCell)).valueOf(); // having 2 search dates, we assume that it's a date range filtering and we'll compare against both dates if (searchDate1 && searchDate2) { @@ -38,18 +40,20 @@ export function executeDateFilterCondition(options: FilterConditionOption, parse } // comparing against a single search date - const dateSearchTimestamp1 = FORMAT.toLowerCase().includes('h') ? searchDate1.valueOf() : searchDate1.clone().startOf('day').valueOf(); + const dateSearchTimestamp1 = FORMAT === 'ISO8601' || FORMAT.toLowerCase().includes('h') + ? searchDate1.valueOf() + : dayStart(new Date(searchDate1)).valueOf(); return testFilterCondition(options.operator || '==', dateCellTimestamp, dateSearchTimestamp1); } /** - * From our search filter value(s), get the parsed value(s), they are parsed as Moment object(s). + * From our search filter value(s), get the parsed value(s), they are parsed as Date objects. * This is called only once per filter before running the actual filter condition check on each cell */ export function getFilterParsedDates(inputSearchTerms: SearchTerm[] | undefined, inputFilterSearchType: typeof FieldType[keyof typeof FieldType]): SearchTerm[] { const searchTerms = Array.isArray(inputSearchTerms) && inputSearchTerms || []; const filterSearchType = inputFilterSearchType || FieldType.dateIso; - const FORMAT = mapMomentDateFormatWithFieldType(filterSearchType); + const FORMAT = mapTempoDateFormatWithFieldType(filterSearchType); const parsedSearchValues: any[] = []; @@ -57,18 +61,18 @@ export function getFilterParsedDates(inputSearchTerms: SearchTerm[] | undefined, const searchValues = (searchTerms.length === 2) ? searchTerms : (searchTerms[0] as string).split('..'); const searchValue1 = (Array.isArray(searchValues) && searchValues[0] || '') as Date | string; const searchValue2 = (Array.isArray(searchValues) && searchValues[1] || '') as Date | string; - const searchDate1 = moment(searchValue1, FORMAT, true); - const searchDate2 = moment(searchValue2, FORMAT, true); + const searchDate1 = tryParseDate(searchValue1, FORMAT, true); + const searchDate2 = tryParseDate(searchValue2, FORMAT, true); // return if any of the 2 values are invalid dates - if (!searchDate1.isValid() || !searchDate2.isValid()) { + if (!searchDate1 || !searchDate2) { return []; } parsedSearchValues.push(searchDate1, searchDate2); } else { // return if the search term is an invalid date - const searchDate1 = moment(searchTerms[0] as Date | string, FORMAT, true); - if (!searchDate1.isValid()) { + const searchDate1 = tryParseDate(searchTerms[0] as Date | string, FORMAT, true); + if (!searchDate1) { return []; } parsedSearchValues.push(searchDate1); diff --git a/packages/common/src/filter-conditions/filterConditionProcesses.ts b/packages/common/src/filter-conditions/filterConditionProcesses.ts index ffae472c1..95b1bd3d2 100644 --- a/packages/common/src/filter-conditions/filterConditionProcesses.ts +++ b/packages/common/src/filter-conditions/filterConditionProcesses.ts @@ -44,7 +44,7 @@ export const executeFilterConditionTest: FilterCondition = ((options: FilterCond }) as FilterCondition; /** - * From our search filter value(s), get their parsed value(s), for example a "dateIso" filter will be parsed as Moment object. + * From our search filter value(s), get their parsed value(s), for example a "dateIso" filter will be parsed as Date object. * Then later when we execute the filtering checks, we won't need to re-parse all search value(s) again and again. * So this is called only once, for each search filter that is, prior to running the actual filter condition checks on each cell afterward. */ diff --git a/packages/common/src/filters/__tests__/autocompleterFilter.spec.ts b/packages/common/src/filters/__tests__/autocompleterFilter.spec.ts index 1e81d0444..5efd7f03d 100644 --- a/packages/common/src/filters/__tests__/autocompleterFilter.spec.ts +++ b/packages/common/src/filters/__tests__/autocompleterFilter.spec.ts @@ -28,6 +28,7 @@ const gridStub = { getColumns: jest.fn(), getHeaderRowColumn: jest.fn(), render: jest.fn(), + sanitizeHtmlString: (str) => str, } as unknown as SlickGrid; describe('AutocompleterFilter', () => { @@ -309,7 +310,7 @@ describe('AutocompleterFilter', () => { jest.runAllTimers(); // fast-forward timer - expect(filter.filterDomElement.classList.contains('slick-autocomplete-loading')).toBeTrue(); + expect(filter.filterDomElement.classList.contains('slick-autocomplete-loading')).toBe(true); expect(callbackMock).toHaveBeenCalledWith('female'); expect(renderSpy).toHaveBeenCalledTimes(1); }); diff --git a/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts b/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts index 4e473abfd..7c03a7901 100644 --- a/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts +++ b/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts @@ -1,10 +1,14 @@ import 'jest-extended'; +import { format } from '@formkit/tempo'; +import { VanillaCalendar } from 'vanilla-calendar-picker'; + import { Filters } from '../filters.index'; import { FieldType, OperatorType } from '../../enums/index'; import { Column, FilterArguments, GridOption } from '../../interfaces/index'; import { CompoundDateFilter } from '../compoundDateFilter'; import { TranslateServiceStub } from '../../../../../test/translateServiceStub'; import { SlickGrid } from '../../core/index'; +import { mapTempoDateFormatWithFieldType } from '../../services/dateUtils'; const containerId = 'demo-container'; @@ -26,8 +30,11 @@ const gridStub = { getColumns: jest.fn(), getHeaderRowColumn: jest.fn(), render: jest.fn(), + sanitizeHtmlString: (str) => str, } as unknown as SlickGrid; +jest.useFakeTimers(); + describe('CompoundDateFilter', () => { let divContainer: HTMLDivElement; let filter: CompoundDateFilter; @@ -83,15 +90,17 @@ describe('CompoundDateFilter', () => { mockColumn.filter!.placeholder = testValue; filter.init(filterArguments); - const filterElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; + const filterElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; expect(filterElm.placeholder).toBe(testValue); }); it('should hide the DOM element when the "hide" method is called', () => { filter.init(filterArguments); - const spy = jest.spyOn(filter.flatInstance, 'close'); - const calendarElm = document.body.querySelector('.flatpickr-calendar') as HTMLDivElement; + const spy = jest.spyOn(filter.calendarInstance!, 'hide'); + const inputElm = document.body.querySelector('input.date-picker') as HTMLInputElement; + inputElm.dispatchEvent(new MouseEvent('click')); + const calendarElm = document.body.querySelector('.vanilla-calendar') as HTMLDivElement; filter.hide(); expect(calendarElm).toBeTruthy(); @@ -100,44 +109,37 @@ describe('CompoundDateFilter', () => { it('should show the DOM element when the "show" method is called', () => { filter.init(filterArguments); - const spy = jest.spyOn(filter.flatInstance, 'open'); - const calendarElm = document.body.querySelector('.flatpickr-calendar') as HTMLDivElement; + const spy = jest.spyOn(filter.calendarInstance!, 'show'); filter.show(); + const calendarElm = document.body.querySelector('.vanilla-calendar') as HTMLDivElement; expect(calendarElm).toBeTruthy(); expect(spy).toHaveBeenCalled(); }); - it('should enable Dark Mode and expect ".slick-dark-mode" CSS class to be found on parent element', () => { - jest.spyOn(gridStub, 'getOptions').mockReturnValue({ - ...gridOptionMock, darkMode: true - }); - - filter.init(filterArguments); - const spy = jest.spyOn(filter.flatInstance, 'open'); - const calendarElm = document.body.querySelector('.flatpickr-calendar') as HTMLDivElement; - filter.show(); - - expect(calendarElm.classList.contains('slick-dark-mode')).toBeTruthy(); - expect(spy).toHaveBeenCalled(); - }); - - it('should be able to retrieve default flatpickr options through the Getter', () => { + it('should be able to retrieve default picker options through the Getter', () => { filter.init(filterArguments); - expect(filter.flatInstance).toBeTruthy(); - expect(filter.flatpickrOptions).toEqual({ - altFormat: 'Y-m-d', - altInput: true, - closeOnSelect: true, - dateFormat: 'Y-m-d', - defaultDate: '', - errorHandler: expect.toBeFunction(), - locale: 'en', - mode: 'single', - onChange: expect.anything(), - theme: 'light', - wrap: true, + expect(filter.calendarInstance).toBeTruthy(); + expect(filter.pickerOptions).toEqual({ + actions: { + changeToInput: expect.any(Function), + clickDay: expect.any(Function), + }, + input: true, + jumpToSelectedDate: true, + sanitizer: expect.any(Function), + toggleSelected: false, + settings: { + iso8601: false, + lang: 'en', + visibility: { + positionToInput: 'auto', + theme: 'light', + weekend: false, + }, + }, + type: 'default' }); }); @@ -167,14 +169,14 @@ describe('CompoundDateFilter', () => { }); it('should trigger input change event and expect the callback to be called with the date provided in the input', () => { - mockColumn.filter!.filterOptions = { allowInput: true }; // change to allow input value only for testing purposes mockColumn.filter!.operator = '>'; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; filterInputElm.value = '2001-01-02T16:02:02.239Z'; - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: ['2001-01-02'], hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: ['2001-01-02'], hide: jest.fn() } as unknown as VanillaCalendar); const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); @@ -183,15 +185,29 @@ describe('CompoundDateFilter', () => { }); }); + it('should trigger input change event with empty value and still expect the callback to be called with the date provided in the input', () => { + mockColumn.filter!.operator = '>'; + + filter.init(filterArguments); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; + filterInputElm.value = '2001-01-02T16:02:02.239Z'; + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: [], hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: [], hide: jest.fn() } as unknown as VanillaCalendar); + const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); + + expect(filterFilledElms.length).toBe(0); + expect(filterInputElm.value).toBe(''); + }); + it('should pass a different operator then trigger an input change event and expect the callback to be called with the date provided in the input', () => { - mockColumn.filter!.filterOptions = { allowInput: true }; // change to allow input value only for testing purposes mockColumn.filter!.operator = '>'; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; filterInputElm.value = '2001-01-02T16:02:02.239Z'; - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: ['2001-01-02'], hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: ['2001-01-02'], hide: jest.fn() } as unknown as VanillaCalendar); const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); @@ -199,12 +215,11 @@ describe('CompoundDateFilter', () => { }); it('should change operator dropdown without a date entered and not expect the callback to be called', () => { - mockColumn.filter!.filterOptions = { allowInput: true }; // change to allow input value only for testing purposes mockColumn.filter!.operator = '>'; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; const filterSelectElm = divContainer.querySelector('.search-filter.filter-finish select') as HTMLInputElement; filterInputElm.value = undefined as any; filterSelectElm.value = '<='; @@ -214,13 +229,12 @@ describe('CompoundDateFilter', () => { }); it('should change operator dropdown without a date entered and expect the callback to be called when "skipCompoundOperatorFilterWithNullInput" is defined as False', () => { - mockColumn.filter!.filterOptions = { allowInput: true }; // change to allow input value only for testing purposes mockColumn.filter!.operator = '>'; mockColumn.filter!.skipCompoundOperatorFilterWithNullInput = false; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; const filterSelectElm = divContainer.querySelector('.search-filter.filter-finish select') as HTMLInputElement; filterInputElm.value = undefined as any; filterSelectElm.value = '<='; @@ -229,24 +243,111 @@ describe('CompoundDateFilter', () => { expect(spyCallback).toHaveBeenCalled(); }); - it('should create the input filter with a default search term when passed as a filter argument', () => { + it('should hide picker when pressing Escape key', () => { + const hideSpy = jest.spyOn(filter, 'hide'); + + filter.init(filterArguments); + filter.show(); + const calendarElm = document.body.querySelector('.vanilla-calendar') as HTMLDivElement; + + expect(calendarElm).toBeTruthy(); + + calendarElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true })); + expect(hideSpy).toHaveBeenCalled(); + }); + + it('should hide picker when pressing Tab key', () => { + const hideSpy = jest.spyOn(filter, 'hide'); + + filter.init(filterArguments); + filter.show(); + const calendarElm = document.body.querySelector('.vanilla-calendar') as HTMLDivElement; + + expect(calendarElm).toBeTruthy(); + + calendarElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { key: 'Tab', bubbles: true, cancelable: true })); + expect(hideSpy).toHaveBeenCalled(); + }); + + it('should clear picker when pressing Backspace key', () => { + filterArguments.searchTerms = ['2000-01-01']; + mockColumn.filter!.operator = '<='; + const clearSpy = jest.spyOn(filter, 'clear'); + + filter.init(filterArguments); + filter.show(); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; + const calendarElm = document.body.querySelector('.vanilla-calendar') as HTMLDivElement; + + expect(calendarElm).toBeTruthy(); + expect(filterInputElm.value).toBe('2000-01-01'); + + filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { key: 'Backspace', bubbles: true, cancelable: true })); + expect(clearSpy).toHaveBeenCalled(); + expect(filterInputElm.value).toBe(''); + }); + + it('should create the input filter with a default search terms when passed as a filter argument', () => { filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z']; mockColumn.filter!.operator = '<='; + mockColumn.type = FieldType.dateUtc; + mockColumn.outputType = FieldType.dateUtc; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; filterInputElm.focus(); - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true })); + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: ['2000-01-01T05:00:00.000Z'], hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: ['2000-01-01T05:00:00.000Z'], hide: jest.fn() } as unknown as VanillaCalendar); const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - expect(filter.currentDateOrDates).toBe('2000-01-01T05:00:00.000Z'); - expect(filterInputElm.value).toBe('2000-01-01'); + expect(filter.currentDateOrDates![0].toISOString()).toBe('2000-01-01T05:00:00.000Z'); + expect(filterInputElm.value).toBe('2000-01-01T05:00:00.000Z'); expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '<=', searchTerms: ['2000-01-01T05:00:00.000Z'], shouldTriggerQuery: true }); }); + it('should create the input filter with a default input dates when passed as a filter options', () => { + mockColumn.filter!.operator = '<='; + mockColumn.filter!.filterOptions = { + selected: { dates: ['2001-01-02'] } + }; + const spyCallback = jest.spyOn(filterArguments, 'callback'); + + filter.init(filterArguments); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; + + filterInputElm.focus(); + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: ['2000-01-02'], hide: jest.fn() } as unknown as VanillaCalendar); + const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); + + expect(filterFilledElms.length).toBe(1); + expect(format(filter.currentDateOrDates![0], mapTempoDateFormatWithFieldType(FieldType.dateTimeIso))).toBe('2000-01-02 00:00:00'); + expect(filterInputElm.value).toBe('2000-01-02'); + expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, operator: '<=', searchTerms: ['2000-01-02'], shouldTriggerQuery: true }); + }); + + it('should have a value with date & time in the picker when "enableTime" option is set as a global default filter option and we trigger a change', () => { + gridOptionMock.defaultFilterOptions = { + date: { selected: { dates: ['2001-01-02'] } } + }; + mockColumn.filter!.operator = '<='; + const spyCallback = jest.spyOn(filterArguments, 'callback'); + + filter.init(filterArguments); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; + + filterInputElm.focus(); + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: ['2000-01-02'], hide: jest.fn() } as unknown as VanillaCalendar); + const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); + + expect(filterFilledElms.length).toBe(1); + expect(format(filter.currentDateOrDates![0], mapTempoDateFormatWithFieldType(FieldType.dateTimeIso))).toBe('2000-01-02 00:00:00'); + expect(filterInputElm.value).toBe('2000-01-02'); + expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, operator: '<=', searchTerms: ['2000-01-02'], shouldTriggerQuery: true }); + }); + it('should trigger an operator change event and expect the callback to be called with the searchTerms and operator defined', () => { filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z']; mockColumn.filter!.operator = '>'; @@ -267,67 +368,45 @@ describe('CompoundDateFilter', () => { const mockDate = '2001-01-02T16:02:02.239Z'; filter.init(filterArguments); filter.setValues(mockDate); - let filledInputElm = divContainer.querySelector('.search-filter.filter-finish .filled') as HTMLInputElement; + let filledInputElm = divContainer.querySelector('.search-filter.filter-finish.filled') as HTMLInputElement; expect(filter.currentDateOrDates).toEqual(mockDate); expect(filledInputElm).toBeTruthy(); filter.setValues(''); - filledInputElm = divContainer.querySelector('.search-filter.filter-finish .filled') as HTMLInputElement; + filledInputElm = divContainer.querySelector('.search-filter.filter-finish.filled') as HTMLInputElement; expect(filledInputElm).toBeFalsy(); }); it('should work with different locale when locale is changed', async () => { - await (await import('flatpickr/dist/l10n/fr')).French; - translateService.use('fr'); filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z']; mockColumn.filter!.operator = '<='; + mockColumn.type = FieldType.dateUtc; + mockColumn.outputType = FieldType.dateUtc; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; - const calendarElm = document.body.querySelector('.flatpickr-calendar') as HTMLDivElement; - const selectonOptionElms = calendarElm.querySelectorAll(' .flatpickr-monthDropdown-months option'); + filter.show(); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; + const calendarElm = document.body.querySelector('.vanilla-calendar') as HTMLDivElement; + const monthElm = calendarElm.querySelector('.vanilla-calendar-month') as HTMLButtonElement; filter.show(); filterInputElm.focus(); - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true })); + + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: ['2000-01-01T05:00:00.000Z'], hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: ['2000-01-01T05:00:00.000Z'], hide: jest.fn() } as unknown as VanillaCalendar); const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - expect(filter.currentDateOrDates).toBe('2000-01-01T05:00:00.000Z'); - expect(filterInputElm.value).toBe('2000-01-01'); + expect(filter.currentDateOrDates![0].toISOString()).toBe('2000-01-01T05:00:00.000Z'); + expect(filterInputElm.value).toBe('2000-01-01T05:00:00.000Z'); expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '<=', searchTerms: ['2000-01-01T05:00:00.000Z'], shouldTriggerQuery: true }); expect(calendarElm).toBeTruthy(); - expect(selectonOptionElms.length).toBe(12); - expect(selectonOptionElms[0].textContent).toBe('janvier'); - }); - - it('should display a console warning when locale is not previously imported', (done) => { - const consoleSpy = jest.spyOn(global.console, 'warn').mockReturnValue(); - - translateService.use('zz-yy'); // will be trimmed to 2 chars "zz" - filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z']; - mockColumn.filter!.operator = '<='; - - filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; - const calendarElm = document.body.querySelector('.flatpickr-calendar') as HTMLDivElement; - const selectonOptionElms = calendarElm.querySelectorAll(' .flatpickr-monthDropdown-months option'); - - filter.show(); - - filterInputElm.focus(); - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true })); - - setTimeout(() => { - expect(selectonOptionElms.length).toBe(12); - expect(selectonOptionElms[0].textContent).toBe('January'); - expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining(`[Slickgrid-Universal] Flatpickr missing locale imports (zz), will revert to English as the default locale.`)); - done(); - }); + expect(monthElm).toBeTruthy(); + // expect(monthElm.textContent).toBe('janvier'); }); it('should trigger a callback with the clear filter set when calling the "clear" method', () => { @@ -335,13 +414,14 @@ describe('CompoundDateFilter', () => { const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); + filter.show(); filter.clear(); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); expect(filterInputElm.value).toBe(''); expect(filterFilledElms.length).toBe(0); - expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, clearFilterTriggered: true, shouldTriggerQuery: true }); + expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, clearFilterTriggered: true, shouldTriggerQuery: true }); }); it('should trigger a callback with the clear filter but without querying when when calling the "clear" method with False as argument', () => { @@ -350,71 +430,48 @@ describe('CompoundDateFilter', () => { filter.init(filterArguments); filter.clear(false); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); expect(filterInputElm.value).toBe(''); expect(filterFilledElms.length).toBe(0); - expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, clearFilterTriggered: true, shouldTriggerQuery: false }); + expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, clearFilterTriggered: true, shouldTriggerQuery: false }); }); it('should have a value with date & time in the picker when "enableTime" option is set and we trigger a change', () => { - mockColumn.filter!.filterOptions = { enableTime: true, allowInput: true }; // change to allow input value only for testing purposes - mockColumn.outputType = FieldType.dateTimeIsoAmPm; + mockColumn.outputType = FieldType.dateTimeShortEuro; mockColumn.filter!.operator = '>'; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; - filterInputElm.value = '2001-01-02T16:02:02.000+05:00'; - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; + filterInputElm.value = '2001-01-02T16:02:00.000Z'; + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: ['2001-01-02'], hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: ['2001-01-02'], selectedHours: 16, selectedMinutes: 2, hide: jest.fn() } as unknown as VanillaCalendar); const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - // expect(filter.currentDateOrDates.toISOString()).toBe('2001-01-02T21:02:02.000Z'); - expect(filterInputElm.value).toBe('2001-01-02 4:02:02 PM'); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { - columnDef: mockColumn, operator: '>', searchTerms: ['2001-01-02'], shouldTriggerQuery: true - }); - }); - - it('should have a value with date & time in the picker when "enableTime" option is set as a global default filter option and we trigger a change', () => { - gridOptionMock.defaultFilterOptions = { - date: { enableTime: true, allowInput: true } - }; - mockColumn.outputType = FieldType.dateTimeIsoAmPm; - mockColumn.filter!.operator = '>'; - const spyCallback = jest.spyOn(filterArguments, 'callback'); - - filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; - filterInputElm.value = '2001-01-02T16:02:02.000+05:00'; - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); - const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); - - expect(filterFilledElms.length).toBe(1); - // expect(filter.currentDateOrDates.toISOString()).toBe('2001-01-02T21:02:02.000Z'); - expect(filterInputElm.value).toBe('2001-01-02 4:02:02 PM'); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { - columnDef: mockColumn, operator: '>', searchTerms: ['2001-01-02'], shouldTriggerQuery: true - }); + expect(filterInputElm.value).toBe('2/1/2001 16:02'); + expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '>', searchTerms: ['2001-01-02'], shouldTriggerQuery: true }); }); it('should have a value with date & time in the picker when using no "outputType" which will default to UTC date', () => { + mockColumn.type = FieldType.dateUtc; mockColumn.outputType = null as any; - filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z']; + filterArguments.searchTerms = ['2000-01-01T05:00']; mockColumn.filter!.operator = '<='; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-finish .flatpickr input.input') as HTMLInputElement; + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; filterInputElm.focus(); - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true })); + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: ['2000-01-01'], hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: ['2000-01-01'], hide: jest.fn() } as unknown as VanillaCalendar); const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - expect(filter.currentDateOrDates).toBe('2000-01-01T05:00:00.000Z'); + expect(filter.currentDateOrDates![0].toISOString()).toBe('2000-01-01T05:00:00.000Z'); expect(filterInputElm.value).toBe('2000-01-01T05:00:00.000Z'); expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '<=', searchTerms: ['2000-01-01T05:00:00.000Z'], shouldTriggerQuery: true }); }); diff --git a/packages/common/src/filters/__tests__/dateRangeFilter.spec.ts b/packages/common/src/filters/__tests__/dateRangeFilter.spec.ts index ddc728a8b..4035d0ec2 100644 --- a/packages/common/src/filters/__tests__/dateRangeFilter.spec.ts +++ b/packages/common/src/filters/__tests__/dateRangeFilter.spec.ts @@ -1,4 +1,6 @@ import 'jest-extended'; +import { VanillaCalendar } from 'vanilla-calendar-picker'; + import { FieldType } from '../../enums/index'; import { Column, FilterArguments, GridOption } from '../../interfaces/index'; import { Filters } from '../filters.index'; @@ -21,6 +23,7 @@ const gridStub = { getColumns: jest.fn(), getHeaderRowColumn: jest.fn(), render: jest.fn(), + sanitizeHtmlString: (str) => str, } as unknown as SlickGrid; describe('DateRangeFilter', () => { @@ -39,7 +42,7 @@ describe('DateRangeFilter', () => { document.body.appendChild(divContainer); spyGetHeaderRow = jest.spyOn(gridStub, 'getHeaderRowColumn').mockReturnValue(divContainer); - mockColumn = { id: 'finish', field: 'finish', filterable: true, filter: { model: Filters.dateRange, operator: 'RangeInclusive' } }; + mockColumn = { id: 'finish', field: 'finish', type: FieldType.dateIso, filterable: true, filter: { model: Filters.dateRange, operator: 'RangeInclusive' } }; filterArguments = { grid: gridStub, columnDef: mockColumn, @@ -64,7 +67,7 @@ describe('DateRangeFilter', () => { it('should initialize the filter', () => { filter.init(filterArguments); - const filterCount = divContainer.querySelectorAll('.flatpickr.search-filter.filter-finish').length; + const filterCount = divContainer.querySelectorAll('.date-picker.search-filter.filter-finish').length; expect(spyGetHeaderRow).toHaveBeenCalled(); expect(filterCount).toBe(1); @@ -75,15 +78,17 @@ describe('DateRangeFilter', () => { mockColumn.filter!.placeholder = testValue; filter.init(filterArguments); - const filterElm = divContainer.querySelector('.flatpickr.search-filter.filter-finish input') as HTMLInputElement; + const filterElm = divContainer.querySelector('.date-picker.search-filter.filter-finish input') as HTMLInputElement; expect(filterElm.placeholder).toBe(testValue); }); it('should hide the DOM element when the "hide" method is called', () => { filter.init(filterArguments); - const spy = jest.spyOn(filter.flatInstance, 'close'); - const calendarElm = document.body.querySelector('.flatpickr-calendar') as HTMLDivElement; + const spy = jest.spyOn(filter.calendarInstance!, 'hide'); + const inputElm = document.body.querySelector('input.date-picker') as HTMLInputElement; + inputElm.dispatchEvent(new MouseEvent('click')); + const calendarElm = document.body.querySelector('.vanilla-calendar') as HTMLDivElement; filter.hide(); expect(calendarElm).toBeTruthy(); @@ -92,31 +97,42 @@ describe('DateRangeFilter', () => { it('should show the DOM element when the "show" method is called', () => { filter.init(filterArguments); - const spy = jest.spyOn(filter.flatInstance, 'open'); - const calendarElm = document.body.querySelector('.flatpickr-calendar') as HTMLDivElement; + const spy = jest.spyOn(filter.calendarInstance!, 'show'); filter.show(); + const calendarElm = document.body.querySelector('.vanilla-calendar') as HTMLDivElement; expect(calendarElm).toBeTruthy(); expect(spy).toHaveBeenCalled(); }); - it('should be able to retrieve default flatpickr options through the Getter', () => { + it('should be able to retrieve default date picker options through the Getter', () => { filter.init(filterArguments); - expect(filter.flatInstance).toBeTruthy(); - expect(filter.flatpickrOptions).toEqual({ - altFormat: 'Z', - altInput: true, - closeOnSelect: true, - dateFormat: 'Y-m-d', - defaultDate: [], - enableTime: true, - errorHandler: expect.toBeFunction(), - locale: 'en', - mode: 'range', - onChange: expect.anything(), - theme: 'light', - wrap: true, + expect(filter.calendarInstance).toBeTruthy(); + expect(filter.pickerOptions).toEqual({ + actions: { + changeToInput: expect.any(Function), + clickDay: expect.any(Function), + }, + input: true, + jumpMonths: 2, + jumpToSelectedDate: true, + months: 2, + sanitizer: expect.any(Function), + settings: { + iso8601: false, + lang: 'en', + range: { edgesOnly: true }, + selection: { day: 'multiple-ranged', }, + visibility: { + daysOutside: false, + positionToInput: 'auto', + theme: 'light', + weekend: false, + }, + }, + toggleSelected: false, + type: 'multiple' }); }); @@ -135,73 +151,92 @@ describe('DateRangeFilter', () => { }); it('should trigger input change event and expect the callback to be called with the date provided in the input', () => { - mockColumn.filter!.filterOptions = { allowInput: true }; // change to allow input value only for testing purposes mockColumn.filter!.operator = 'RangeInclusive'; const spyCallback = jest.spyOn(filterArguments, 'callback'); + const selectedDates = ['2001-01-02', '2001-01-13']; filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.flatpickr.search-filter.filter-finish input.input') as HTMLInputElement; - filterInputElm.value = '2001-01-02T16:02:02.239Z to 2001-01-31T16:02:02.239Z'; - filterInputElm.dispatchEvent(new CustomEvent('change')); - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); - const filterFilledElms = divContainer.querySelectorAll('.flatpickr.search-filter.filter-finish.filled'); + const filterInputElm = divContainer.querySelector('div.date-picker.search-filter.filter-finish input.date-picker') as HTMLInputElement; + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + const filterFilledElms = divContainer.querySelectorAll('.date-picker.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'RangeInclusive', searchTerms: ['2001-01-02', '2001-01-31'], shouldTriggerQuery: true }); + expect(filterInputElm.value).toBe('2001-01-02 — 2001-01-13'); + expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, operator: 'RangeInclusive', searchTerms: ['2001-01-02', '2001-01-13'], shouldTriggerQuery: true }); + }); + + it('should trigger input change event with empty value and still expect the callback to be called with the date provided in the input', () => { + mockColumn.filter!.operator = 'RangeInclusive'; + + filter.init(filterArguments); + const filterInputElm = divContainer.querySelector('.search-filter.filter-finish input.date-picker') as HTMLInputElement; + filterInputElm.value = '2001-01-02T16:02:02.239Z'; + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates: [], hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.changeToInput!(new Event('click'), { HTMLInputElement: filterInputElm, selectedDates: [], hide: jest.fn() } as unknown as VanillaCalendar); + const filterFilledElms = divContainer.querySelectorAll('.form-group.search-filter.filter-finish.filled'); + + expect(filterFilledElms.length).toBe(0); + expect(filterInputElm.value).toBe(''); }); it('should pass a different operator then trigger an input change event and expect the callback to be called with the date provided in the input', () => { - mockColumn.filter!.filterOptions = { allowInput: true, enableTime: false }; // change to allow input value only for testing purposes mockColumn.filter!.operator = 'RangeExclusive'; const spyCallback = jest.spyOn(filterArguments, 'callback'); + const selectedDates = ['2001-01-02', '2001-01-13']; filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.flatpickr.search-filter.filter-finish input.input') as HTMLInputElement; - filterInputElm.value = '2001-01-02T16:02:02.239Z to 2001-01-31T16:02:02.239Z'; - filterInputElm.dispatchEvent(new CustomEvent('change')); - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); - const filterFilledElms = divContainer.querySelectorAll('.flatpickr.search-filter.filter-finish.filled'); + const filterInputElm = divContainer.querySelector('.date-picker.search-filter.filter-finish input.date-picker') as HTMLInputElement; + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + const filterFilledElms = divContainer.querySelectorAll('.date-picker.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'RangeExclusive', searchTerms: ['2001-01-02', '2001-01-31'], shouldTriggerQuery: true }); + expect(filterInputElm.value).toBe('2001-01-02 — 2001-01-13'); + expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, operator: 'RangeExclusive', searchTerms: ['2001-01-02', '2001-01-13'], shouldTriggerQuery: true }); }); - it('should create the input filter with a default search term when passed as a filter argument', () => { - filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z', '2000-01-31T05:00:00.000Z']; + it('should create the input filter with a default search terms when passed as a filter argument', () => { + const selectedDates = ['2001-01-02', '2001-01-13']; + filterArguments.searchTerms = ['2001-01-02', '2001-01-13']; mockColumn.filter!.operator = 'RangeInclusive'; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.flatpickr.search-filter.filter-finish input.input') as HTMLInputElement; + const filterInputElm = divContainer.querySelector('.date-picker.search-filter.filter-finish input.date-picker') as HTMLInputElement; filterInputElm.focus(); - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true })); - const filterFilledElms = divContainer.querySelectorAll('.flatpickr.search-filter.filter-finish.filled'); + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + const filterFilledElms = divContainer.querySelectorAll('.date-picker.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - expect(filterInputElm.value).toBe('2000-01-01T05:00:00.000Z to 2000-01-31T05:00:00.000Z'); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'RangeInclusive', searchTerms: ['2000-01-01', '2000-01-31'], shouldTriggerQuery: true }); + expect(filterInputElm.value).toBe('2001-01-02 — 2001-01-13'); + expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, operator: 'RangeInclusive', searchTerms: ['2001-01-02', '2001-01-13'], shouldTriggerQuery: true }); }); it('should create the input filter with a default search term when passed as a filter argument with 2 dots (..) notation', () => { - filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z..2000-01-31T05:00:00.000Z']; + const selectedDates = ['2001-01-01', '2001-01-02', '2001-01-03']; + filterArguments.searchTerms = ['2001-01-01..2001-01-03']; mockColumn.filter!.operator = 'RangeInclusive'; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.flatpickr.search-filter.filter-finish input.input') as HTMLInputElement; + const filterInputElm = divContainer.querySelector('.date-picker.search-filter.filter-finish input.date-picker') as HTMLInputElement; filterInputElm.focus(); - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true })); - const filterFilledElms = divContainer.querySelectorAll('.flatpickr.search-filter.filter-finish.filled'); + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + + const filterFilledElms = divContainer.querySelectorAll('.date-picker.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - expect(filterInputElm.value).toBe('2000-01-01T05:00:00.000Z to 2000-01-31T05:00:00.000Z'); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'RangeInclusive', searchTerms: ['2000-01-01', '2000-01-31'], shouldTriggerQuery: true }); + expect(filterInputElm.value).toBe('2001-01-01 — 2001-01-03'); + expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, operator: 'RangeInclusive', searchTerms: ['2001-01-01', '2001-01-03'], shouldTriggerQuery: true }); }); it('should be able to call "setValues" and set empty values and the picker input to not have the "filled" css class', () => { - const mockDates = ['2000-01-01T05:00:00.000Z', '2000-01-31T05:00:00.000Z']; + const mockDates = ['2001-01-02T05:00:00.000Z', '2001-01-13T05:00:00.000Z']; filter.init(filterArguments); filter.setValues(mockDates); let filledInputElm = divContainer.querySelector('.search-filter.filter-finish.filled') as HTMLInputElement; @@ -215,65 +250,41 @@ describe('DateRangeFilter', () => { }); it('should work with different locale when locale is changed', async () => { - await (await import('flatpickr/dist/l10n/fr')).French; - translateService.use('fr'); - filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z', '2000-01-31T05:00:00.000Z']; + const selectedDates = ['2001-01-01', '2001-01-02', '2001-01-03']; + filterArguments.searchTerms = ['2001-01-01', '2001-01-03']; mockColumn.filter!.operator = 'RangeInclusive'; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.flatpickr.search-filter.filter-finish input.input') as HTMLInputElement; - const calendarElm = document.body.querySelector('.flatpickr-calendar') as HTMLDivElement; - const selectonOptionElms = calendarElm.querySelectorAll(' .flatpickr-monthDropdown-months option'); + filter.show(); + const filterInputElm = divContainer.querySelector('.date-picker.search-filter.filter-finish input.date-picker') as HTMLInputElement; + const calendarElm = document.body.querySelector('.vanilla-calendar') as HTMLDivElement; + const monthElm = calendarElm.querySelector('.vanilla-calendar-month') as HTMLButtonElement; filter.show(); filterInputElm.focus(); - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true })); - const filterFilledElms = divContainer.querySelectorAll('.flatpickr.search-filter.filter-finish.filled'); + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + const filterFilledElms = divContainer.querySelectorAll('.date-picker.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - expect(filterInputElm.value).toBe('2000-01-01T05:00:00.000Z au 2000-01-31T05:00:00.000Z'); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'RangeInclusive', searchTerms: ['2000-01-01', '2000-01-31'], shouldTriggerQuery: true }); + expect(filterInputElm.value).toBe('2001-01-01 — 2001-01-03'); + expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, operator: 'RangeInclusive', searchTerms: ['2001-01-01', '2001-01-03'], shouldTriggerQuery: true }); expect(calendarElm).toBeTruthy(); - expect(selectonOptionElms.length).toBe(12); - expect(selectonOptionElms[0].textContent).toBe('janvier'); - }); - - it('should display a console warning when locale is not previously imported', (done) => { - const consoleSpy = jest.spyOn(global.console, 'warn').mockReturnValue(); - - translateService.use('zz-yy'); // will be trimmed to 2 chars "zz" - filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z', '2000-01-31T05:00:00.000Z']; - mockColumn.filter!.operator = 'RangeInclusive'; - - filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.flatpickr.search-filter.filter-finish input.input') as HTMLInputElement; - const calendarElm = document.body.querySelector('.flatpickr-calendar') as HTMLDivElement; - const selectonOptionElms = calendarElm.querySelectorAll(' .flatpickr-monthDropdown-months option'); - - filter.show(); - - filterInputElm.focus(); - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true })); - - setTimeout(() => { - expect(selectonOptionElms.length).toBe(12); - expect(selectonOptionElms[0].textContent).toBe('January'); - expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining(`[Slickgrid-Universal] Flatpickr missing locale imports (zz), will revert to English as the default locale.`)); - done(); - }); + expect(monthElm).toBeTruthy(); + // expect(monthElm.textContent).toBe('janvier'); }); it('should trigger a callback with the clear filter set when calling the "clear" method', () => { - filterArguments.searchTerms = ['2000-01-01', '2000-01-31']; + filterArguments.searchTerms = ['2001-01-01', '2001-01-03']; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); filter.clear(); - const filterInputElm = divContainer.querySelector('.flatpickr.search-filter.filter-finish input.input') as HTMLInputElement; - const filterFilledElms = divContainer.querySelectorAll('.flatpickr.search-filter.filter-finish.filled'); + const filterInputElm = divContainer.querySelector('.date-picker.search-filter.filter-finish input.date-picker') as HTMLInputElement; + const filterFilledElms = divContainer.querySelectorAll('.date-picker.search-filter.filter-finish.filled'); expect(filterInputElm.value).toBe(''); expect(filterFilledElms.length).toBe(0); @@ -281,13 +292,13 @@ describe('DateRangeFilter', () => { }); it('should trigger a callback with the clear filter but without querying when when calling the "clear" method with False as argument', () => { - filterArguments.searchTerms = ['2000-01-01', '2000-01-31']; + filterArguments.searchTerms = ['2001-01-01', '2001-01-31']; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); filter.clear(false); - const filterInputElm = divContainer.querySelector('.flatpickr.search-filter.filter-finish input.input') as HTMLInputElement; - const filterFilledElms = divContainer.querySelectorAll('.flatpickr.search-filter.filter-finish.filled'); + const filterInputElm = divContainer.querySelector('.date-picker.search-filter.filter-finish input.date-picker') as HTMLInputElement; + const filterFilledElms = divContainer.querySelectorAll('.date-picker.search-filter.filter-finish.filled'); expect(filterInputElm.value).toBe(''); expect(filterFilledElms.length).toBe(0); @@ -295,44 +306,47 @@ describe('DateRangeFilter', () => { }); it('should have a value with date & time in the picker when "enableTime" option is set and we trigger a change', () => { - mockColumn.filter!.filterOptions = { enableTime: true, allowInput: true }; // change to allow input value only for testing purposes mockColumn.outputType = FieldType.dateTimeIsoAmPm; mockColumn.filter!.operator = '>'; const spyCallback = jest.spyOn(filterArguments, 'callback'); + const selectedDates = ['2001-01-02', '2001-01-13']; filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.flatpickr.search-filter.filter-finish input.input') as HTMLInputElement; - filterInputElm.value = '2000-01-01T05:00:00.000+05:00 to 2000-01-31T05:00:00.000+05:00'; - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); - const filterFilledElms = divContainer.querySelectorAll('.flatpickr.search-filter.filter-finish.filled'); + const filterInputElm = divContainer.querySelector('.date-picker.search-filter.filter-finish input.date-picker') as HTMLInputElement; + filterInputElm.value = '2001-01-02 — 2001-01-13'; + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + + const filterFilledElms = divContainer.querySelectorAll('.date-picker.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - // expect(filter.currentDateOrDates.map((date) => date.toISOString())).toEqual(['2000-01-01T05:00:00.000Z', '2000-01-31T05:00:00.000Z']); - expect(filterInputElm.value).toBe('2000-01-01 5:00:00 AM to 2000-01-31 5:00:00 AM'); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { - columnDef: mockColumn, operator: '>', searchTerms: ['2000-01-01 05:00:00 am', '2000-01-31 05:00:00 am'], shouldTriggerQuery: true + // expect(filter.currentDateOrDates.map((date) => date.toISOString())).toEqual(['2001-01-01T05:00:00.000Z', '2001-01-31T05:00:00.000Z']); + expect(filterInputElm.value).toBe('2001-01-02 12:00:00 am — 2001-01-13 12:00:00 am'); + expect(spyCallback).toHaveBeenCalledWith(undefined, { + columnDef: mockColumn, operator: '>', searchTerms: ['2001-01-02', '2001-01-13'], shouldTriggerQuery: true }); }); it('should have a value with date & time in the picker when "enableTime" option is set as a global default filter option and we trigger a change', () => { gridOptionMock.defaultFilterOptions = { - date: { enableTime: true, allowInput: true } }; mockColumn.outputType = FieldType.dateTimeIsoAmPm; mockColumn.filter!.operator = '>'; const spyCallback = jest.spyOn(filterArguments, 'callback'); + const selectedDates = ['2001-01-02', '2001-01-13']; filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.flatpickr.search-filter.filter-finish input.input') as HTMLInputElement; - filterInputElm.value = '2000-01-01T05:00:00.000+05:00 to 2000-01-31T05:00:00.000+05:00'; - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keydown', { keyCode: 13, bubbles: true, cancelable: true })); - const filterFilledElms = divContainer.querySelectorAll('.flatpickr.search-filter.filter-finish.filled'); + const filterInputElm = divContainer.querySelector('div.date-picker.search-filter.filter-finish input.date-picker') as HTMLInputElement; + filterInputElm.value = '2001-01-02 — 2001-01-13'; + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + const filterFilledElms = divContainer.querySelectorAll('.date-picker.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); // expect(filter.currentDateOrDates.map((date) => date.toISOString())).toEqual(['2000-01-01T05:00:00.000Z', '2000-01-31T05:00:00.000Z']); - expect(filterInputElm.value).toBe('2000-01-01 5:00:00 AM to 2000-01-31 5:00:00 AM'); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { - columnDef: mockColumn, operator: '>', searchTerms: ['2000-01-01 05:00:00 am', '2000-01-31 05:00:00 am'], shouldTriggerQuery: true + expect(filterInputElm.value).toBe('2001-01-02 12:00:00 am — 2001-01-13 12:00:00 am'); + expect(spyCallback).toHaveBeenCalledWith(undefined, { + columnDef: mockColumn, operator: '>', searchTerms: ['2001-01-02', '2001-01-13'], shouldTriggerQuery: true }); }); @@ -341,17 +355,19 @@ describe('DateRangeFilter', () => { filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z', '2000-01-31T05:00:00.000Z']; mockColumn.filter!.operator = '<='; const spyCallback = jest.spyOn(filterArguments, 'callback'); + const selectedDates = ['2001-01-02', '2001-01-13']; filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.flatpickr.search-filter.filter-finish input.flatpickr-input') as HTMLInputElement; + const filterInputElm = divContainer.querySelector('div.date-picker.search-filter.filter-finish input.date-picker') as HTMLInputElement; filterInputElm.focus(); - filterInputElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true })); - const filterFilledElms = divContainer.querySelectorAll('.flatpickr.search-filter.filter-finish.filled'); + filterInputElm.value = '2001-01-02 — 2001-01-13'; + filter.calendarInstance!.actions!.changeToInput!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + filter.calendarInstance!.actions!.clickDay!(new MouseEvent('click'), { HTMLInputElement: filterInputElm, selectedDates, hide: jest.fn() } as unknown as VanillaCalendar); + const filterFilledElms = divContainer.querySelectorAll('.date-picker.search-filter.filter-finish.filled'); expect(filterFilledElms.length).toBe(1); - expect(filter.currentDateOrDates).toEqual(['2000-01-01T05:00:00.000Z', '2000-01-31T05:00:00.000Z']); - expect(filterInputElm.value).toBe('2000-01-01 to 2000-01-31'); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '<=', searchTerms: ['2000-01-01', '2000-01-31'], shouldTriggerQuery: true }); + expect(filterInputElm.value).toBe('2001-01-02 — 2001-01-13'); + expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, operator: '<=', searchTerms: ['2001-01-02', '2001-01-13'], shouldTriggerQuery: true }); }); }); diff --git a/packages/common/src/filters/__tests__/nativeSelectFilter.spec.ts b/packages/common/src/filters/__tests__/nativeSelectFilter.spec.ts deleted file mode 100644 index 5f936f839..000000000 --- a/packages/common/src/filters/__tests__/nativeSelectFilter.spec.ts +++ /dev/null @@ -1,420 +0,0 @@ -import { Column, FilterArguments, GridOption } from '../../interfaces/index'; -import { Filters } from '../filters.index'; -import { NativeSelectFilter } from '../nativeSelectFilter'; -import { TranslateServiceStub } from '../../../../../test/translateServiceStub'; -import { SlickGrid } from '../../core/index'; - -jest.useFakeTimers(); - -const containerId = 'demo-container'; - -// define a
container to simulate the grid container -const template = `
`; - -const gridOptionMock = { - enableFiltering: true, - enableFilterTrimWhiteSpace: true, -} as GridOption; - -const gridStub = { - getOptions: () => gridOptionMock, - getColumns: jest.fn(), - getHeaderRowColumn: jest.fn(), - render: jest.fn(), -} as unknown as SlickGrid; - -describe('NativeSelectFilter', () => { - let translateService: TranslateServiceStub; - let divContainer: HTMLDivElement; - let filter: NativeSelectFilter; - let filterArguments: FilterArguments; - let spyGetHeaderRow; - let mockColumn: Column; - - beforeEach(() => { - translateService = new TranslateServiceStub(); - - divContainer = document.createElement('div'); - divContainer.innerHTML = template; - document.body.appendChild(divContainer); - spyGetHeaderRow = jest.spyOn(gridStub, 'getHeaderRowColumn').mockReturnValue(divContainer); - - mockColumn = { - id: 'gender', field: 'gender', filterable: true, - filter: { - model: Filters.select, - } - }; - - filterArguments = { - grid: gridStub, - columnDef: mockColumn, - callback: jest.fn(), - filterContainerElm: gridStub.getHeaderRowColumn(mockColumn.id) - }; - - filter = new NativeSelectFilter(translateService); - }); - - afterEach(() => { - filter.destroy(); - }); - - it('should throw an error when trying to call init without any arguments', () => { - expect(() => filter.init(null as any)).toThrowError('[Slickgrid-Universal] A filter must always have an "init()" with valid arguments.'); - }); - - it('should throw an error when there is no collection provided in the filter property', (done) => { - try { - mockColumn.filter!.collection = undefined; - filter.init(filterArguments); - } catch (e) { - expect(e.toString()).toContain(`[Slickgrid-Universal] You need to pass a "collection" for the Native Select Filter to work correctly.`); - done(); - } - }); - - it('should throw an error when collection is not a valid array', (done) => { - try { - mockColumn.filter!.collection = { hello: 'world' } as any; - filter.init(filterArguments); - } catch (e) { - expect(e.toString()).toContain(`The "collection" passed to the Native Select Filter is not a valid array.`); - done(); - } - }); - - it('should throw an error when collection is not a valid value/label pair array', (done) => { - try { - mockColumn.filter!.collection = [{ hello: 'world' }]; - filter.init(filterArguments); - } catch (e) { - expect(e.toString()).toContain(`A collection with value/label (or value/labelKey when using Locale) is required to populate the Native Select Filter list`); - done(); - } - }); - - it('should throw an error when "enableTranslateLabel" is set without a valid I18N Service', (done) => { - try { - translateService = undefined as any; - mockColumn.filter!.enableTranslateLabel = true; - mockColumn.filter!.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }]; - filter = new NativeSelectFilter(translateService); - - filter.init(filterArguments); - } catch (e) { - expect(e.message).toContain(`The I18N Service is required for the Native Select Filter to work correctly when "enableTranslateLabel" is set.`); - done(); - } - }); - - it('should initialize the filter', () => { - mockColumn.filter!.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }]; - filter.init(filterArguments); - const filterCount = divContainer.querySelectorAll('select.form-control.search-filter.filter-gender').length; - - expect(spyGetHeaderRow).toHaveBeenCalled(); - expect(filterCount).toBe(1); - }); - - it('should have an aria-label when creating the filter', () => { - mockColumn.filter!.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }]; - filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('select.form-control.search-filter.filter-gender') as HTMLInputElement; - - expect(filterInputElm.ariaLabel).toBe('Gender Search Filter'); - }); - - it('should trigger select change event and expect the callback to be called with the search terms we select from dropdown list', () => { - const spyCallback = jest.spyOn(filterArguments, 'callback'); - mockColumn.filter!.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }]; - - filter.init(filterArguments); - const filterSelectElm = divContainer.querySelector(`select.search-filter.filter-gender`) as HTMLInputElement; - const filterListElm = divContainer.querySelectorAll(`select.search-filter.filter-gender option`); - - filterSelectElm.value = 'female'; - filterSelectElm.dispatchEvent(new CustomEvent('change')); - - const filterFilledElms = divContainer.querySelectorAll('select.search-filter.filter-gender.filled'); - expect(filterListElm.length).toBe(2); - expect(filterFilledElms.length).toBe(1); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['female'], shouldTriggerQuery: true }); - }); - - it('should trigger select change event and expect this to work with a regular array of strings', () => { - const spyCallback = jest.spyOn(filterArguments, 'callback'); - - mockColumn.filter!.collection = ['male', 'female']; - filter.init(filterArguments); - const filterSelectElm = divContainer.querySelector(`select.search-filter.filter-gender`) as HTMLInputElement; - const filterListElm = divContainer.querySelectorAll(`select.search-filter.filter-gender option`); - - filterSelectElm.value = 'female'; - filterSelectElm.dispatchEvent(new CustomEvent('change')); - - const filterFilledElms = divContainer.querySelectorAll('select.search-filter.filter-gender.filled'); - expect(filterListElm.length).toBe(2); - expect(filterFilledElms.length).toBe(1); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['female'], shouldTriggerQuery: true }); - }); - - it('should trigger select change event and expect the callback to be called with numbers converted as string in the option values', () => { - const spyCallback = jest.spyOn(filterArguments, 'callback'); - mockColumn.filter!.collection = [{ value: 1, label: 'male' }, { value: 2, label: 'female' }]; - - filter.init(filterArguments); - const filterSelectElm = divContainer.querySelector(`select.search-filter.filter-gender`) as HTMLInputElement; - const filterListElm = divContainer.querySelectorAll(`select.search-filter.filter-gender option`); - - filterSelectElm.value = '2'; - filterSelectElm.dispatchEvent(new CustomEvent('change')); - - const filterFilledElms = divContainer.querySelectorAll('select.search-filter.filter-gender.filled'); - expect(filterListElm.length).toBe(2); - expect(filterFilledElms.length).toBe(1); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['2'], shouldTriggerQuery: true }); - }); - - it('should trigger select change event and expect the callback to be called with booleans converted as string in the option values', () => { - const spyCallback = jest.spyOn(filterArguments, 'callback'); - mockColumn.filter!.collection = [{ value: true, label: 'True' }, { value: false, label: 'False' }]; - - filter.init(filterArguments); - const filterSelectElm = divContainer.querySelector(`select.search-filter.filter-gender`) as HTMLInputElement; - const filterListElm = divContainer.querySelectorAll(`select.search-filter.filter-gender option`); - - filterSelectElm.value = 'false'; - filterSelectElm.dispatchEvent(new CustomEvent('change')); - - const filterFilledElms = divContainer.querySelectorAll('select.search-filter.filter-gender.filled'); - expect(filterListElm.length).toBe(2); - expect(filterFilledElms.length).toBe(1); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['false'], shouldTriggerQuery: true }); - }); - - it('should pass a different operator then trigger an input change event and expect the callback to be called with the search terms we select from dropdown list', () => { - mockColumn.filter!.operator = 'NE'; - mockColumn.filter!.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }]; - const spyCallback = jest.spyOn(filterArguments, 'callback'); - - filter.init(filterArguments); - const filterSelectElm = divContainer.querySelector(`select.search-filter.filter-gender`) as HTMLInputElement; - const filterListElm = divContainer.querySelectorAll(`select.search-filter.filter-gender option`); - - filterSelectElm.value = 'female'; - filterSelectElm.dispatchEvent(new CustomEvent('change')); - - const filterFilledElms = divContainer.querySelectorAll('select.search-filter.filter-gender.filled'); - expect(filterListElm.length).toBe(2); - expect(filterFilledElms.length).toBe(1); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'NE', searchTerms: ['female'], shouldTriggerQuery: true }); - }); - - it('should have same value in "getValues" after being set in "setValues" with a single value', () => { - mockColumn.filter!.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }]; - filter.init(filterArguments); - filter.setValues('female'); - const values = filter.getValues(); - - expect(values).toEqual(['female']); - expect(values.length).toBe(1); - }); - - it('should have same value in "getValues" after being set in "setValues" with an array having a single value', () => { - mockColumn.filter!.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }]; - filter.init(filterArguments); - filter.setValues(['female']); - const values = filter.getValues(); - - expect(values).toEqual(['female']); - expect(values.length).toBe(1); - }); - - it('should have empty array returned from "getValues" when nothing is set', () => { - mockColumn.filter!.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }]; - filter.init(filterArguments); - const values = filter.getValues(); - - expect(values).toEqual([]); - expect(values.length).toBe(0); - }); - - it('should have empty array returned from "getValues" even when filter is not yet created', () => { - const values = filter.getValues(); - - expect(values).toEqual([]); - expect(values.length).toBe(0); - }); - - it('should create the select filter with "customStructure" with a default search term when passed as a filter argument', () => { - const spyCallback = jest.spyOn(filterArguments, 'callback'); - mockColumn.filter = { - collection: [{ value: 'other', description: 'other' }, { value: 'male', description: 'male' }, { value: 'female', description: 'female' }], - customStructure: { - value: 'value', - label: 'description', - }, - }; - - filterArguments.searchTerms = ['female']; - filter.init(filterArguments); - const filterSelectElm = divContainer.querySelector(`select.search-filter.filter-gender`) as HTMLInputElement; - const filterListElm = divContainer.querySelectorAll(`select.search-filter.filter-gender option`); - - filterSelectElm.dispatchEvent(new CustomEvent('change')); - - const filterFilledElms = divContainer.querySelectorAll('select.search-filter.filter-gender.filled'); - expect(filterListElm.length).toBe(3); - expect(filterListElm[0].textContent).toBe('other'); - expect(filterListElm[1].textContent).toBe('male'); - expect(filterListElm[2].textContent).toBe('female'); - expect(filterFilledElms.length).toBe(1); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['female'], shouldTriggerQuery: true }); - }); - - it('should create the select filter with a default search term when passed as a filter argument', () => { - mockColumn.filter!.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }]; - const spyCallback = jest.spyOn(filterArguments, 'callback'); - - filterArguments.searchTerms = ['female']; - filter.init(filterArguments); - const filterSelectElm = divContainer.querySelector(`select.search-filter.filter-gender`) as HTMLInputElement; - const filterListElm = divContainer.querySelectorAll(`select.search-filter.filter-gender option`); - - filterSelectElm.dispatchEvent(new CustomEvent('change')); - - const filterFilledElms = divContainer.querySelectorAll('select.search-filter.filter-gender.filled'); - expect(filterListElm.length).toBe(2); - expect(filterFilledElms.length).toBe(1); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['female'], shouldTriggerQuery: true }); - }); - - it('should create the select filter with empty search term when passed an empty string as a filter argument and not expect "filled" css class either', () => { - mockColumn.filter!.collection = [{ value: '', label: '' }, { value: 'male', label: 'male' }, { value: 'female', label: 'female' }]; - const spyCallback = jest.spyOn(filterArguments, 'callback'); - - filterArguments.searchTerms = ['']; - filter.init(filterArguments); - const filterSelectElm = divContainer.querySelector(`select.search-filter.filter-gender`) as HTMLInputElement; - const filterListElm = divContainer.querySelectorAll(`select.search-filter.filter-gender option`); - - filterSelectElm.dispatchEvent(new CustomEvent('change')); - - const filterFilledElms = divContainer.querySelectorAll('select.search-filter.filter-gender.filled'); - expect(filterListElm.length).toBe(3); - expect(filterFilledElms.length).toBe(0); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: [''], shouldTriggerQuery: true }); - }); - - it('should create the select filter with a default boolean search term that is converted to strings as option values and pre-selected as option', () => { - mockColumn.filter!.collection = [{ value: true, label: 'True' }, { value: false, label: 'False' }]; - const spyCallback = jest.spyOn(filterArguments, 'callback'); - - filterArguments.searchTerms = [false]; - filter.init(filterArguments); - const filterSelectElm = divContainer.querySelector(`select.search-filter.filter-gender`) as HTMLInputElement; - const filterListElm = divContainer.querySelectorAll(`select.search-filter.filter-gender option`); - - filterSelectElm.dispatchEvent(new CustomEvent('change')); - - const filterFilledElms = divContainer.querySelectorAll('select.search-filter.filter-gender.filled'); - expect(filterListElm.length).toBe(2); - expect(filterFilledElms.length).toBe(1); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['false'], shouldTriggerQuery: true }); - }); - - it('should create the select filter with a default number search term that is converted to strings as option values and pre-selected as option', () => { - mockColumn.filter!.collection = [{ value: 1, label: 'male' }, { value: 2, label: 'female' }]; - const spyCallback = jest.spyOn(filterArguments, 'callback'); - - filterArguments.searchTerms = [2]; - filter.init(filterArguments); - const filterSelectElm = divContainer.querySelector(`select.search-filter.filter-gender`) as HTMLInputElement; - const filterListElm = divContainer.querySelectorAll(`select.search-filter.filter-gender option`); - - filterSelectElm.dispatchEvent(new CustomEvent('change')); - - const filterFilledElms = divContainer.querySelectorAll('select.search-filter.filter-gender.filled'); - expect(filterListElm.length).toBe(2); - expect(filterFilledElms.length).toBe(1); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['2'], shouldTriggerQuery: true }); - }); - - it('should trigger a callback with the clear filter set when calling the "clear" method', () => { - filterArguments.searchTerms = ['female']; - mockColumn.filter!.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }]; - const spyCallback = jest.spyOn(filterArguments, 'callback'); - - filter.init(filterArguments); - filter.clear(); - const filterFilledElms = divContainer.querySelectorAll('select.search-filter.filter-gender.filled'); - - expect(filter.searchTerms.length).toBe(0); - expect(filterFilledElms.length).toBe(0); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, clearFilterTriggered: true, shouldTriggerQuery: true }); - }); - - it('should trigger a callback with the clear filter but without querying when when calling the "clear" method with False as argument', () => { - mockColumn.filter!.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }]; - const spyCallback = jest.spyOn(filterArguments, 'callback'); - - filterArguments.searchTerms = ['female']; - filter.init(filterArguments); - filter.clear(false); - const filterFilledElms = divContainer.querySelectorAll('select.search-filter.filter-gender.filled'); - - expect(filter.searchTerms.length).toBe(0); - expect(filterFilledElms.length).toBe(0); - expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, clearFilterTriggered: true, shouldTriggerQuery: false }); - }); - - it('should work with English locale when locale is changed', () => { - translateService.use('en'); - gridOptionMock.enableTranslate = true; - mockColumn.filter = { - enableTranslateLabel: true, - collection: [ - { value: 'other', labelKey: 'OTHER' }, - { value: 'male', labelKey: 'MALE' }, - { value: 'female', labelKey: 'FEMALE' } - ], - filterOptions: { minimumCountSelected: 1 } - }; - - filterArguments.searchTerms = ['male', 'female']; - filter.init(filterArguments); - jest.runAllTimers(); // fast-forward timer - - const filterListElm = divContainer.querySelectorAll(`select.search-filter.filter-gender option`); - - expect(filterListElm.length).toBe(3); - expect(filterListElm[0].textContent).toBe('Other'); - expect(filterListElm[1].textContent).toBe('Male'); - expect(filterListElm[2].textContent).toBe('Female'); - }); - - it('should work with French locale when locale is changed', () => { - translateService.use('fr'); - gridOptionMock.enableTranslate = true; - mockColumn.filter = { - enableTranslateLabel: true, - collection: [ - { value: 'other', labelKey: 'OTHER' }, - { value: 'male', labelKey: 'MALE' }, - { value: 'female', labelKey: 'FEMALE' } - ], - filterOptions: { minimumCountSelected: 1 } - }; - - filterArguments.searchTerms = ['male', 'female']; - filter.init(filterArguments); - const filterListElm = divContainer.querySelectorAll(`select.search-filter.filter-gender option`); - jest.runAllTimers(); // fast-forward timer - - expect(filterListElm.length).toBe(3); - expect(filterListElm[0].textContent).toBe('Autre'); - expect(filterListElm[1].textContent).toBe('Mâle'); - expect(filterListElm[2].textContent).toBe('Femme'); - }); -}); diff --git a/packages/common/src/filters/__tests__/selectFilter.spec.ts b/packages/common/src/filters/__tests__/selectFilter.spec.ts index a33286d3d..1dcaf9bd5 100644 --- a/packages/common/src/filters/__tests__/selectFilter.spec.ts +++ b/packages/common/src/filters/__tests__/selectFilter.spec.ts @@ -1,5 +1,6 @@ // import 3rd party lib multiple-select for the tests import 'multiple-select-vanilla'; +import type { MultipleSelectOption } from 'multiple-select-vanilla'; import { of, Subject } from 'rxjs'; import { FieldType, OperatorType } from '../../enums/index'; @@ -11,7 +12,6 @@ import { SlickGrid } from '../../core/index'; import { HttpStub } from '../../../../../test/httpClientStub'; import { RxJsResourceStub } from '../../../../../test/rxjsResourceStub'; import { TranslateServiceStub } from '../../../../../test/translateServiceStub'; -import type { MultipleSelectOption } from 'multiple-select-vanilla'; jest.useFakeTimers(); @@ -30,6 +30,7 @@ const gridStub = { getColumns: jest.fn(), getHeaderRowColumn: jest.fn(), render: jest.fn(), + sanitizeHtmlString: (str) => str, } as unknown as SlickGrid; describe('SelectFilter', () => { @@ -502,7 +503,7 @@ describe('SelectFilter', () => { it('should create the multi-select filter with a default search term and have the HTML rendered when "enableRenderHtml" is set', () => { mockColumn.filter = { enableRenderHtml: true, - collection: [{ value: true, label: 'True', labelPrefix: ` ` }, { value: false, label: 'False' }], + collection: [{ value: true, label: 'True', labelPrefix: ` ` }, { value: false, label: 'False' }], customStructure: { value: 'isEffort', label: 'label', @@ -519,27 +520,7 @@ describe('SelectFilter', () => { expect(filter.selectOptions.renderOptionLabelAsHtml).toBeTruthy(); expect(filter.selectOptions.useSelectOptionLabelToHtml).toBeFalsy(); expect(filterListElm.length).toBe(2); - expect(filterListElm[0].innerHTML).toBe(' True'); - }); - - it('should create the multi-select filter with a default search term and have the HTML rendered and sanitized when "enableRenderHtml" is set and has ` }, { value: false, label: 'False' }], - customStructure: { - value: 'isEffort', - label: 'label', - labelPrefix: 'labelPrefix', - }, - }; - - filter.init(filterArguments); - const filterBtnElm = divContainer.querySelector('.ms-parent.ms-filter.search-filter.filter-gender button.ms-choice') as HTMLButtonElement; - const filterListElm = divContainer.querySelectorAll(`[data-name=filter-gender].ms-drop ul>li span`); - filterBtnElm.click(); - - expect(filterListElm.length).toBe(2); - expect(filterListElm[0].innerHTML).toBe(' True'); + expect(filterListElm[0].innerHTML).toBe(' True'); }); it('should create the multi-select filter with a blank entry at the beginning of the collection when "addBlankEntry" is set in the "collectionOptions" property', () => { diff --git a/packages/common/src/filters/autocompleterFilter.ts b/packages/common/src/filters/autocompleterFilter.ts index 6bb186bd9..f91859bbd 100644 --- a/packages/common/src/filters/autocompleterFilter.ts +++ b/packages/common/src/filters/autocompleterFilter.ts @@ -27,7 +27,6 @@ import type { import { addAutocompleteLoadingByOverridingFetch } from '../commonEditorFilter'; import type { CollectionService } from '../services/collection.service'; import { collectionObserver, propertyObserver } from '../services/observers'; -import { sanitizeTextByAvailableSanitizer, } from '../services/domUtilities'; import { getDescendantProperty, unsubscribeAll } from '../services/utilities'; import type { TranslaterService } from '../services/translater.service'; import { renderCollectionOptionsAsync } from './filterUtilities'; @@ -586,7 +585,7 @@ export class AutocompleterFilter implements Fi // sanitize any unauthorized html tags like script and others // for the remaining allowed tags we'll permit all attributes - const sanitizedText = sanitizeTextByAvailableSanitizer(this.gridOptions, finalText) || ''; + const sanitizedText = this.grid.sanitizeHtmlString(finalText) || ''; const div = document.createElement('div'); div[isRenderHtmlEnabled ? 'innerHTML' : 'textContent'] = sanitizedText; diff --git a/packages/common/src/filters/dateFilter.ts b/packages/common/src/filters/dateFilter.ts index f6309b055..0fbefdc3a 100644 --- a/packages/common/src/filters/dateFilter.ts +++ b/packages/common/src/filters/dateFilter.ts @@ -1,11 +1,7 @@ import { BindingEventService } from '@slickgrid-universal/binding'; -import { createDomElement, destroyAllElementProps, emptyElement, } from '@slickgrid-universal/utils'; -import flatpickr from 'flatpickr'; -import * as moment_ from 'moment-mini'; -const moment = (moment_ as any)['default'] || moment_; - -import type { BaseOptions as FlatpickrBaseOptions } from 'flatpickr/dist/types/options'; -import type { Instance as FlatpickrInstance } from 'flatpickr/dist/types/instance'; +import { createDomElement, emptyElement, extend, } from '@slickgrid-universal/utils'; +import { format, parse } from '@formkit/tempo'; +import { VanillaCalendar, type IOptions } from 'vanilla-calendar-picker'; import { FieldType, @@ -19,29 +15,32 @@ import type { Filter, FilterArguments, FilterCallback, - FlatpickrOption, GridOption, OperatorDetail, } from '../interfaces/index'; import { buildSelectOperator, compoundOperatorNumeric } from './filterUtilities'; -import { mapFlatpickrDateFormatWithFieldType, mapMomentDateFormatWithFieldType, mapOperatorToShorthandDesignation } from '../services/utilities'; +import { formatDateByFieldType, mapTempoDateFormatWithFieldType } from '../services/dateUtils'; +import { mapOperatorToShorthandDesignation } from '../services/utilities'; import type { TranslaterService } from '../services/translater.service'; import type { SlickGrid } from '../core/index'; +import { setPickerDates } from '../commonEditorFilter'; export class DateFilter implements Filter { protected _bindEventService: BindingEventService; protected _clearFilterTriggered = false; protected _currentValue?: string; - protected _currentDateOrDates?: Date | Date[] | string[]; + protected _currentDateOrDates?: Date | Date[] | string | string[]; protected _currentDateStrings?: string[]; - protected _flatpickrOptions!: FlatpickrOption; + protected _lastClickIsDate = false; + protected _pickerOptions!: IOptions; protected _filterElm!: HTMLDivElement; - protected _filterDivInputElm!: HTMLDivElement; + protected _dateInputElm!: HTMLInputElement; protected _operator!: OperatorType | OperatorString; protected _selectOperatorElm?: HTMLSelectElement; protected _shouldTriggerQuery = true; + hasTimePicker = false; inputFilterType: 'compound' | 'range' = 'range'; - flatInstance!: FlatpickrInstance; + calendarInstance?: VanillaCalendar; grid!: SlickGrid; searchTerms: SearchTerm[] = []; columnDef!: Column; @@ -74,13 +73,13 @@ export class DateFilter implements Filter { : (this.gridOptions.defaultFilterRangeOperator || OperatorType.rangeInclusive); } - get filterOptions(): FlatpickrOption { - return { ...this.gridOptions.defaultFilterOptions?.date, ...this.columnFilter?.filterOptions }; + /** Getter for the date picker options */ + get pickerOptions(): IOptions { + return this._pickerOptions || {}; } - /** Getter for the Flatpickr Options */ - get flatpickrOptions(): FlatpickrOption { - return this._flatpickrOptions || {}; + get filterOptions(): IOptions { + return { ...this.gridOptions.defaultFilterOptions?.date, ...this.columnFilter?.filterOptions }; } /** Getter for the Filter Operator */ @@ -100,9 +99,7 @@ export class DateFilter implements Filter { } } - /** - * Initialize the Filter - */ + /** Initialize the Filter */ init(args: FilterArguments) { if (!args) { throw new Error('[Slickgrid-Universal] A filter must always have an "init()" with valid arguments.'); @@ -125,62 +122,70 @@ export class DateFilter implements Filter { // step 1, create the DOM Element of the filter which contain the compound Operator+Input this._filterElm = this.createDomFilterElement(searchValues); + // if there's a search term, we will add the "filled" class for styling purposes + if (this.searchTerms.length) { + this._filterElm.classList.add('filled'); + } + // step 3, subscribe to the keyup event and run the callback when that happens // also add/remove "filled" class for styling purposes - this._bindEventService.bind(this._filterDivInputElm, 'keyup', this.onTriggerEvent.bind(this)); if (this._selectOperatorElm) { this._bindEventService.bind(this._selectOperatorElm, 'change', this.onTriggerEvent.bind(this)); } + + // close picker on Esc/Tab keys + this._bindEventService.bind(document.body, 'keydown', ((e: KeyboardEvent) => { + if (e.key === 'Escape' || e.key === 'Tab') { + this.hide(); + } + }) as EventListener); + + // clear date picker + compound operator when Backspace is pressed + this._bindEventService.bind(this._dateInputElm, 'keydown', ((e: KeyboardEvent) => { + if (e.key === 'Backspace') { + this.clear(true); + } + }) as EventListener); } - /** - * Clear the filter value - */ + /** Clear the filter value */ clear(shouldTriggerQuery = true) { - if (this.flatInstance) { + if (this.calendarInstance) { this._clearFilterTriggered = true; this._shouldTriggerQuery = shouldTriggerQuery; this.searchTerms = []; if (this._selectOperatorElm) { this._selectOperatorElm.selectedIndex = 0; } - if (this.flatInstance.input) { - this.flatInstance.clear(); + if (this.calendarInstance.input) { + this.calendarInstance.settings.selected.dates = []; + this._dateInputElm.value = ''; } } + this.onTriggerEvent(new Event('keyup')); this._filterElm.classList.remove('filled'); - this._filterDivInputElm.classList.remove('filled'); } - /** - * destroy the filter - */ + /** Destroy the filter */ destroy() { this._bindEventService.unbindAll(); + this.calendarInstance?.destroy(); - if (typeof this.flatInstance?.destroy === 'function') { - this.flatInstance.destroy(); - if (this.flatInstance.element) { - destroyAllElementProps(this.flatInstance); - } - } emptyElement(this.filterContainerElm); - emptyElement(this._filterDivInputElm); - this._filterDivInputElm?.remove(); this.filterContainerElm?.remove(); this._selectOperatorElm?.remove(); this._filterElm?.remove(); } hide() { - if (typeof this.flatInstance?.close === 'function') { - this.flatInstance.close(); + if (typeof this.calendarInstance?.hide === 'function') { + this.calendarInstance.hide(); } } show() { - if (typeof this.flatInstance?.open === 'function') { - this.flatInstance.open(); + if (typeof this.calendarInstance?.show === 'function') { + this.calendarInstance.show(); } } @@ -197,7 +202,6 @@ export class DateFilter implements Filter { if (this.inputFilterType === 'compound') { pickerValues = Array.isArray(values) ? values[0] : values; - } else { // get the picker values, if it's a string with the "..", we'll do the split else we'll use the array of search terms if (typeof values === 'string' || (Array.isArray(values) && typeof values[0] === 'string') && (values[0] as string).indexOf('..') > 0) { @@ -207,18 +211,16 @@ export class DateFilter implements Filter { } } - if (this.flatInstance) { + if (this.calendarInstance && pickerValues !== undefined) { + setPickerDates(this._dateInputElm, this.calendarInstance, pickerValues, this.columnDef, this.columnFilter); this._currentDateOrDates = (values && pickerValues) ? pickerValues : undefined; - this.flatInstance.setDate(this._currentDateOrDates || ''); } const currentValueOrValues = this.getValues() || []; if (this.getValues() || (Array.isArray(currentValueOrValues) && currentValueOrValues.length > 0 && values)) { this._filterElm.classList.add('filled'); - this._filterDivInputElm.classList.add('filled'); } else { this._filterElm.classList.remove('filled'); - this._filterDivInputElm.classList.remove('filled'); } // set the operator when defined @@ -232,17 +234,21 @@ export class DateFilter implements Filter { // // protected functions // ------------------ - protected buildDatePickerInput(searchTerms?: SearchTerm | SearchTerm[]): HTMLDivElement { + protected buildDatePickerInput(searchTerms?: SearchTerm | SearchTerm[]) { const columnId = this.columnDef?.id ?? ''; - const inputFormat = mapFlatpickrDateFormatWithFieldType(this.columnFilter.type || this.columnDef.type || FieldType.dateIso); - const outputFormat = mapFlatpickrDateFormatWithFieldType(this.columnDef.outputType || this.columnFilter.type || this.columnDef.type || FieldType.dateUtc); - const userFilterOptions = this.filterOptions as FlatpickrOption; + const columnFieldType = this.columnFilter.type || this.columnDef.type || FieldType.dateIso; + const outputFieldType = this.columnDef.outputType || this.columnFilter.type || this.columnDef.type || FieldType.dateUtc; + const outputFormat = mapTempoDateFormatWithFieldType(outputFieldType); + const inputFieldType = this.columnFilter.type || this.columnDef.type || FieldType.dateIso; + + // add the time picker when format is UTC (TZ - ISO8601) or has the 'h' (meaning hours) + if (outputFormat && this.inputFilterType !== 'range' && (outputFormat === 'ISO8601' || outputFormat.toLowerCase().includes('h'))) { + this.hasTimePicker = true; + } + const pickerFormat = mapTempoDateFormatWithFieldType(this.hasTimePicker ? FieldType.dateTimeIsoAM_PM : FieldType.dateIso); // get current locale, if user defined a custom locale just use or get it the Translate Service if it exist else just use English - let currentLocale = (userFilterOptions?.locale ?? this.translaterService?.getCurrentLanguage?.()) || this.gridOptions.locale || 'en'; - if (currentLocale?.length > 2) { - currentLocale = currentLocale.substring(0, 2); - } + const currentLocale = ((this.filterOptions?.locale ?? this.translaterService?.getCurrentLanguage?.()) || this.gridOptions.locale || 'en') as string; let pickerValues: any | any[]; @@ -262,79 +268,141 @@ export class DateFilter implements Filter { // if we are preloading searchTerms, we'll keep them for reference if (Array.isArray(pickerValues)) { this._currentDateOrDates = pickerValues as Date[]; - const outFormat = mapMomentDateFormatWithFieldType(this.columnFilter.type || this.columnDef.type || FieldType.dateIso); - this._currentDateStrings = pickerValues.map(date => moment(date).format(outFormat)); + this._currentDateStrings = pickerValues.map(date => formatDateByFieldType(date, undefined, inputFieldType)); } } - const pickerOptions: FlatpickrOption = { - defaultDate: (pickerValues || '') as string | string[], - altInput: true, - altFormat: outputFormat, - dateFormat: inputFormat, - mode: this.inputFilterType === 'range' ? 'range' : 'single', - wrap: true, - closeOnSelect: true, - locale: currentLocale, - theme: this.gridOptions?.darkMode ? 'dark' : 'light', - onChange: (selectedDates: Date[] | Date, dateStr: string) => { - if (this.inputFilterType === 'compound') { - this._currentValue = dateStr; - this._currentDateOrDates = Array.isArray(selectedDates) && selectedDates[0] || undefined; - } else { - if (Array.isArray(selectedDates)) { - this._currentDateOrDates = selectedDates; - const outFormat = mapMomentDateFormatWithFieldType(this.columnDef.outputType || this.columnFilter.type || this.columnDef.type || FieldType.dateIso); - this._currentDateStrings = selectedDates.map(date => moment(date).format(outFormat)); - this._currentValue = this._currentDateStrings.join('..'); + const pickerOptions: IOptions = { + input: true, + jumpToSelectedDate: true, + type: this.inputFilterType === 'range' ? 'multiple' : 'default', + sanitizer: (dirtyHtml) => this.grid.sanitizeHtmlString(dirtyHtml), + toggleSelected: false, + actions: { + clickDay: (_e) => { + this._lastClickIsDate = true; + }, + changeToInput: (_e, self) => { + if (self.HTMLInputElement) { + let outDates: Array = []; + let firstDate = ''; + let lastDate = ''; // when using date range + + if (self.selectedDates[1]) { + self.selectedDates.sort((a, b) => +new Date(a) - +new Date(b)); + firstDate = self.selectedDates[0]; + lastDate = self.selectedDates[self.selectedDates.length - 1]; + const firstDisplayDate = format(self.selectedDates[0], outputFormat, 'en-US'); + const lastDisplayDate = format(lastDate, outputFormat, 'en-US'); + self.HTMLInputElement.value = `${firstDisplayDate} — ${lastDisplayDate}`; + outDates = [firstDate, lastDate]; + } else if (self.selectedDates[0]) { + firstDate = self.selectedDates[0]; + self.HTMLInputElement.value = formatDateByFieldType(firstDate, FieldType.dateIso, outputFieldType); + outDates = self.selectedDates; + } else { + self.HTMLInputElement.value = ''; + } + + if (this.hasTimePicker && firstDate) { + const tempoDate = parse(firstDate, pickerFormat); + tempoDate.setHours(+(self.selectedHours || 0)); + tempoDate.setMinutes(+(self.selectedMinutes || 0)); + self.HTMLInputElement.value = formatDateByFieldType(tempoDate, undefined, outputFieldType); + outDates = [tempoDate]; + } + + if (this.inputFilterType === 'compound') { + this._currentValue = formatDateByFieldType(outDates[0], undefined, columnFieldType); + } else { + if (Array.isArray(outDates)) { + this._currentDateStrings = outDates.map(date => formatDateByFieldType(date, undefined, columnFieldType)); + this._currentValue = this._currentDateStrings.join('..'); + } + } + + this._currentDateOrDates = outDates.map(d => d instanceof Date ? d : parse(d, pickerFormat)); + + // when using the time picker, we can simulate a keyup event to avoid multiple backend request + // since backend request are only executed after user start typing, changing the time should be treated the same way + if (this._currentValue) { + const newEvent = this.hasTimePicker ? new Event('keyup') : undefined; + this.onTriggerEvent(newEvent); + } + + // when using date range and we're not yet having 2 dates, then don't close picker just yet + if (this.inputFilterType === 'range' && self.selectedDates.length < 2) { + this._lastClickIsDate = false; + } + // if you want to hide the calendar after picking a date + if (this._lastClickIsDate) { + self.hide(); + this._lastClickIsDate = false; + } } } - - // when using the time picker, we can simulate a keyup event to avoid multiple backend request - // since backend request are only executed after user start typing, changing the time should be treated the same way - const newEvent = pickerOptions.enableTime ? new Event('keyup') : undefined; - this.onTriggerEvent(newEvent); }, - errorHandler: (error) => { - if (error.toString().includes('invalid locale')) { - console.warn(`[Slickgrid-Universal] Flatpickr missing locale imports (${currentLocale}), will revert to English as the default locale. - See Flatpickr Localization for more info, for example if we want to use French, then we can import it with: import 'flatpickr/dist/l10n/fr';`); - } - } + settings: { + lang: currentLocale, + iso8601: false, + visibility: { + theme: this.gridOptions?.darkMode ? 'dark' : 'light', + positionToInput: 'auto', + weekend: false, + }, + }, }; - // add the time picker when format is UTC (Z) or has the 'h' (meaning hours) - if (outputFormat && (outputFormat === 'Z' || outputFormat.toLowerCase().includes('h'))) { - pickerOptions.enableTime = true; + if (this.inputFilterType === 'range') { + pickerOptions.type = 'multiple'; + pickerOptions.months = 2; + pickerOptions.jumpMonths = 2; + pickerOptions.settings = { + ...pickerOptions.settings, + range: { + edgesOnly: true, + }, + selection: { + day: 'multiple-ranged', + }, + visibility: { + ...pickerOptions.settings?.visibility, + daysOutside: false, + }, + }; + } + + // add the time picker when format includes time (hours/minutes) + if (this.hasTimePicker) { + pickerOptions.settings!.selection ??= {}; + pickerOptions.settings!.selection.time = 24; } // merge options with optional user's custom options - this._flatpickrOptions = { ...pickerOptions, ...userFilterOptions }; + this._pickerOptions = extend(true, {}, pickerOptions, { settings: this.filterOptions }); let placeholder = this.gridOptions?.defaultFilterPlaceholder ?? ''; if (this.columnFilter?.placeholder) { placeholder = this.columnFilter.placeholder; } - const filterDivInputElm = createDomElement('div', { className: 'flatpickr' }); - if (this.inputFilterType === 'range') { - filterDivInputElm.classList.add('search-filter', `filter-${columnId}`); - } - filterDivInputElm.appendChild( - createDomElement('input', { - type: 'text', className: 'form-control', - placeholder, - dataset: { input: '', columnid: `${columnId}` } - }) - ); - this.flatInstance = flatpickr(filterDivInputElm, this._flatpickrOptions as unknown as Partial); - - // add dark mode CSS class when enabled - if (this.gridOptions?.darkMode) { - this.flatInstance.calendarContainer.classList.add('slick-dark-mode'); + this._dateInputElm = createDomElement('input', { + type: 'text', className: 'form-control date-picker', + placeholder, + readOnly: true, + dataset: { input: '', columnid: `${columnId}` } + }); + + this.calendarInstance = new VanillaCalendar(this._dateInputElm, this._pickerOptions); + this.calendarInstance.init(); + + if (this._pickerOptions.settings?.selected?.dates) { + pickerValues = this._pickerOptions.settings.selected.dates; } - return filterDivInputElm; + if (pickerValues) { + setPickerDates(this._dateInputElm, pickerOptions, pickerValues, this.columnDef, this.columnFilter); + } } /** Get the available operator option values to populate the operator select dropdown list */ @@ -355,42 +423,40 @@ export class DateFilter implements Filter { emptyElement(this.filterContainerElm); // create the DOM element filter container - this._filterDivInputElm = this.buildDatePickerInput(searchTerms); + this.buildDatePickerInput(searchTerms); if (this.inputFilterType === 'range') { // if there's a search term, we will add the "filled" class for styling purposes + const inputContainerElm = createDomElement('div', { className: `date-picker form-group search-filter filter-${columnId}` }); + if (Array.isArray(searchTerms) && searchTerms.length > 0 && searchTerms[0] !== '') { - this._filterDivInputElm.classList.add('filled'); this._currentDateOrDates = searchTerms as Date[]; this._currentValue = searchTerms[0] as string; } + inputContainerElm.appendChild(this._dateInputElm); // append the new DOM element to the header row - if (this._filterDivInputElm) { - this.filterContainerElm.appendChild(this._filterDivInputElm); + if (inputContainerElm) { + this.filterContainerElm.appendChild(inputContainerElm); } - return this._filterDivInputElm; + return inputContainerElm; } else { this._selectOperatorElm = buildSelectOperator(this.getOperatorOptionValues(), this.grid); - const filterContainerElm = createDomElement('div', { className: `form-group search-filter filter-${columnId}` }); - const containerInputGroupElm = createDomElement('div', { className: 'input-group flatpickr' }, filterContainerElm); + const filterContainerElm = createDomElement('div', { className: `date-picker form-group search-filter filter-${columnId}` }); + const containerInputGroupElm = createDomElement('div', { className: 'input-group date-picker' }, filterContainerElm); const operatorInputGroupAddonElm = createDomElement('div', { className: 'input-group-addon input-group-prepend operator' }, containerInputGroupElm); operatorInputGroupAddonElm.appendChild(this._selectOperatorElm); - containerInputGroupElm.appendChild(this._filterDivInputElm); + containerInputGroupElm.appendChild(this._dateInputElm); if (this.operator) { const operatorShorthand = mapOperatorToShorthandDesignation(this.operator); this._selectOperatorElm.value = operatorShorthand; } - // if there's a search term, we will add the "filled" class for styling purposes - if (searchTerms !== '') { - this._filterDivInputElm.classList.add('filled'); - this._currentDateOrDates = searchTerms as Date; - this._currentValue = searchTerms as string; - } + this._currentDateOrDates = searchTerms as Date; + this._currentValue = searchTerms as string; // append the new DOM element to the header row if (filterContainerElm) { @@ -411,7 +477,7 @@ export class DateFilter implements Filter { this.callback(e, { columnDef: this.columnDef, searchTerms: (this._currentDateStrings ? this._currentDateStrings : [this._currentValue as string]), operator: this.operator || '', shouldTriggerQuery: this._shouldTriggerQuery }); } else if (this.inputFilterType === 'compound' && this._selectOperatorElm) { const selectedOperator = this._selectOperatorElm.value as OperatorString; - (this._currentValue) ? this._filterElm.classList.add('filled') : this._filterElm.classList.remove('filled'); + this._currentValue ? this._filterElm.classList.add('filled') : this._filterElm.classList.remove('filled'); // when changing compound operator, we don't want to trigger the filter callback unless the date input is also provided const skipCompoundOperatorFilterWithNullInput = this.columnFilter.skipCompoundOperatorFilterWithNullInput ?? this.gridOptions.skipCompoundOperatorFilterWithNullInput ?? this.gridOptions.skipCompoundOperatorFilterWithNullInput === undefined; diff --git a/packages/common/src/filters/filters.index.ts b/packages/common/src/filters/filters.index.ts index 6a6af96d8..a1b0b4ea3 100644 --- a/packages/common/src/filters/filters.index.ts +++ b/packages/common/src/filters/filters.index.ts @@ -9,7 +9,6 @@ import { InputMaskFilter } from './inputMaskFilter'; import { InputNumberFilter } from './inputNumberFilter'; import { InputPasswordFilter } from './inputPasswordFilter'; import { MultipleSelectFilter } from './multipleSelectFilter'; -import { NativeSelectFilter } from './nativeSelectFilter'; import { DateRangeFilter } from './dateRangeFilter'; import { SingleSelectFilter } from './singleSelectFilter'; import { SingleSliderFilter } from './singleSliderFilter'; @@ -61,9 +60,6 @@ export const Filters = { /** Multiple Select filter, which uses 3rd party lib "multiple-select.js" */ multipleSelect: MultipleSelectFilter, - /** Select filter, which uses native DOM element select */ - select: NativeSelectFilter, - /** Single Select filter, which uses 3rd party lib "multiple-select.js" */ singleSelect: SingleSelectFilter, diff --git a/packages/common/src/filters/index.ts b/packages/common/src/filters/index.ts index 7a21b0bea..1c89aa56b 100644 --- a/packages/common/src/filters/index.ts +++ b/packages/common/src/filters/index.ts @@ -13,7 +13,6 @@ export * from './inputMaskFilter'; export * from './inputNumberFilter'; export * from './inputPasswordFilter'; export * from './multipleSelectFilter'; -export * from './nativeSelectFilter'; export * from './selectFilter'; export * from './singleSelectFilter'; export * from './singleSliderFilter'; diff --git a/packages/common/src/filters/nativeSelectFilter.ts b/packages/common/src/filters/nativeSelectFilter.ts deleted file mode 100644 index 76c3b8d6d..000000000 --- a/packages/common/src/filters/nativeSelectFilter.ts +++ /dev/null @@ -1,230 +0,0 @@ -import { BindingEventService } from '@slickgrid-universal/binding'; -import { createDomElement, emptyElement, toSentenceCase } from '@slickgrid-universal/utils'; - -import type { - Column, - ColumnFilter, - Filter, - FilterArguments, - FilterCallback, - GridOption, -} from '../interfaces/index'; -import { OperatorType, type OperatorString, type SearchTerm } from '../enums/index'; -import type { TranslaterService } from '../services/translater.service'; -import { type SlickGrid } from '../core/index'; - -export class NativeSelectFilter implements Filter { - protected _bindEventService: BindingEventService; - protected _clearFilterTriggered = false; - protected _shouldTriggerQuery = true; - protected _currentValues: any | any[] = []; - filterElm!: HTMLSelectElement; - grid!: SlickGrid; - searchTerms: SearchTerm[] = []; - columnDef!: Column; - callback!: FilterCallback; - filterContainerElm!: HTMLDivElement; - - constructor(protected readonly translater?: TranslaterService) { - this._bindEventService = new BindingEventService(); - } - - /** Getter for the Column Filter itself */ - protected get columnFilter(): ColumnFilter { - return this.columnDef?.filter ?? {}; - } - - /** Getter to know what would be the default operator when none is specified */ - get defaultOperator(): OperatorType | OperatorString { - return OperatorType.equal; - } - - /** Getter for the Grid Options pulled through the Grid Object */ - protected get gridOptions(): GridOption { - return this.grid?.getOptions() ?? {}; - } - - /** Getter for the current Operator */ - get operator(): OperatorType | OperatorString { - return this.columnFilter?.operator ?? this.defaultOperator; - } - - /** Setter for the filter operator */ - set operator(operator: OperatorType | OperatorString) { - if (this.columnFilter) { - this.columnFilter.operator = operator; - } - } - - /** - * Initialize the Filter - */ - init(args: FilterArguments) { - if (!args) { - throw new Error('[Slickgrid-Universal] A filter must always have an "init()" with valid arguments.'); - } - this.grid = args.grid; - this.callback = args.callback; - this.columnDef = args.columnDef; - this.searchTerms = (args.hasOwnProperty('searchTerms') ? args.searchTerms : []) || []; - this.filterContainerElm = args.filterContainerElm; - - if (!this.grid || !this.columnDef || !this.columnFilter || !this.columnFilter.collection) { - throw new Error(`[Slickgrid-Universal] You need to pass a "collection" for the Native Select Filter to work correctly.`); - } - - if (this.columnFilter.enableTranslateLabel && !this.gridOptions.enableTranslate && (!this.translater || typeof this.translater.translate !== 'function')) { - throw new Error(`The I18N Service is required for the Native Select Filter to work correctly when "enableTranslateLabel" is set.`); - } - - // filter input can only have 1 search term, so we will use the 1st array index if it exist - let searchTerm = (Array.isArray(this.searchTerms) && this.searchTerms.length >= 0) ? this.searchTerms[0] : ''; - if (typeof searchTerm === 'boolean' || typeof searchTerm === 'number') { - searchTerm = `${searchTerm ?? ''}`; - } - - // step 1, create the DOM Element of the filter & initialize it if searchTerm is filled - this.filterElm = this.createFilterElement(searchTerm); - - // step 2, subscribe to the change event and run the callback when that happens - // also add/remove "filled" class for styling purposes - this._bindEventService.bind(this.filterElm, 'change', this.handleOnChange.bind(this)); - } - - /** - * Clear the filter values - */ - clear(shouldTriggerQuery = true) { - if (this.filterElm) { - this._clearFilterTriggered = true; - this._shouldTriggerQuery = shouldTriggerQuery; - this.searchTerms = []; - this._currentValues = []; - this.filterElm.value = ''; - this.filterElm.classList.remove('filled'); - this.filterElm.dispatchEvent(new Event('change')); - } - } - - /** - * destroy the filter - */ - destroy() { - this._bindEventService.unbindAll(); - this.filterElm?.remove?.(); - } - - /** - * Get selected values retrieved from the select element - * @params selected items - */ - getValues(): any[] { - return this._currentValues || []; - } - - /** Set value(s) on the DOM element */ - setValues(values: SearchTerm | SearchTerm[], operator?: OperatorType | OperatorString) { - if (Array.isArray(values)) { - this.filterElm.value = `${values[0] ?? ''}`; - this._currentValues = values; - } else if (values) { - this.filterElm.value = `${values ?? ''}`; - this._currentValues = [values]; - } - this.getValues().length > 0 ? this.filterElm.classList.add('filled') : this.filterElm.classList.remove('filled'); - - // set the operator when defined - this.operator = operator || this.defaultOperator; - } - - // - // protected functions - // ------------------ - - /** - * Create and return a select dropdown HTML element created from a collection - * @param {Array} values - list of option values/labels - * @returns {Object} selectElm - Select Dropdown HTML Element - */ - buildFilterSelectFromCollection(collection: any[]): HTMLSelectElement { - const columnId = this.columnDef?.id ?? ''; - const selectElm = createDomElement('select', { - className: `form-control search-filter filter-${columnId}`, - ariaLabel: this.columnFilter?.ariaLabel ?? `${toSentenceCase(columnId + '')} Search Filter` - }); - - const labelName = this.columnFilter.customStructure?.label ?? 'label'; - const valueName = this.columnFilter.customStructure?.value ?? 'value'; - const isEnabledTranslate = this.columnFilter?.enableTranslateLabel ?? false; - - // collection could be an Array of Strings OR Objects - if (collection.every(x => typeof x === 'string')) { - collection.forEach(option => { - selectElm.appendChild( - createDomElement('option', { value: option, label: option, textContent: option }) - ); - }); - } else { - collection.forEach(option => { - if (!option || (option[labelName] === undefined && option.labelKey === undefined)) { - throw new Error(`A collection with value/label (or value/labelKey when using Locale) is required to populate the Native Select Filter list, for example:: { filter: model: Filters.select, collection: [ { value: '1', label: 'One' } ]')`); - } - - const labelKey = option.labelKey || option[labelName]; - const textLabel = ((option.labelKey || isEnabledTranslate) && this.translater !== undefined && this.translater?.getCurrentLanguage?.()) ? this.translater.translate(labelKey || ' ') : labelKey; - - selectElm.appendChild( - createDomElement('option', { value: option[valueName], textContent: textLabel }) - ); - }); - } - - return selectElm; - } - - /** - * From the html template string, create a DOM element - * @param filterTemplate - */ - protected createFilterElement(searchTerm?: SearchTerm): HTMLSelectElement { - const columnId = this.columnDef?.id ?? ''; - emptyElement(this.filterContainerElm); - - // create the DOM element & add an ID and filter class - const searchTermInput = (searchTerm || '') as string; - - const collection = this.columnFilter?.collection ?? []; - if (!Array.isArray(collection)) { - throw new Error('The "collection" passed to the Native Select Filter is not a valid array.'); - } - - const selectElm = this.buildFilterSelectFromCollection(collection); - selectElm.value = searchTermInput; - selectElm.dataset.columnid = `${columnId || ''}`; - - if (searchTermInput) { - this._currentValues = [searchTermInput]; - } - - this.filterContainerElm.appendChild(selectElm); - - return selectElm; - } - - protected handleOnChange(e: any) { - const value = e && e.target && e.target.value || ''; - this._currentValues = [value]; - - if (this._clearFilterTriggered) { - this.callback(e, { columnDef: this.columnDef, clearFilterTriggered: this._clearFilterTriggered, shouldTriggerQuery: this._shouldTriggerQuery }); - this.filterElm.classList.remove('filled'); - } else { - value === '' ? this.filterElm.classList.remove('filled') : this.filterElm.classList.add('filled'); - this.callback(e, { columnDef: this.columnDef, operator: this.operator, searchTerms: [value], shouldTriggerQuery: this._shouldTriggerQuery }); - } - - // reset both flags for next use - this._clearFilterTriggered = false; - this._shouldTriggerQuery = true; - } -} diff --git a/packages/common/src/filters/selectFilter.ts b/packages/common/src/filters/selectFilter.ts index d0376537a..897afc628 100644 --- a/packages/common/src/filters/selectFilter.ts +++ b/packages/common/src/filters/selectFilter.ts @@ -17,7 +17,7 @@ import type { import type { CollectionService } from '../services/collection.service'; import { collectionObserver, propertyObserver } from '../services/observers'; import { getDescendantProperty, getTranslationPrefix, unsubscribeAll } from '../services/utilities'; -import { buildMsSelectCollectionList, type RxJsFacade, sanitizeTextByAvailableSanitizer, type Subscription, type TranslaterService } from '../services/index'; +import { buildMsSelectCollectionList, type RxJsFacade, type Subscription, type TranslaterService } from '../services/index'; import { renderCollectionOptionsAsync } from './filterUtilities'; import type { SlickGrid } from '../core/index'; @@ -430,7 +430,7 @@ export class SelectFilter implements Filter { singleRadio: true, showSearchClear: true, renderOptionLabelAsHtml: this.columnFilter?.enableRenderHtml ?? false, - sanitizer: (dirtyHtml: string) => sanitizeTextByAvailableSanitizer(this.gridOptions, dirtyHtml), + sanitizer: (dirtyHtml: string) => this.grid.sanitizeHtmlString(dirtyHtml), // we will subscribe to the onClose event for triggering our callback // also add/remove "filled" class for styling purposes onClose: () => this.onTriggerEvent(), diff --git a/packages/common/src/formatters/__tests__/checkmarkFormatter.spec.ts b/packages/common/src/formatters/__tests__/checkmarkFormatter.spec.ts deleted file mode 100644 index c3e4b1f93..000000000 --- a/packages/common/src/formatters/__tests__/checkmarkFormatter.spec.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Column } from '../../interfaces/index'; -import { checkmarkFormatter } from '../checkmarkFormatter'; - -describe('the Checkmark Formatter', () => { - it('should return an empty string when no value is passed', () => { - const value = null; - const result = checkmarkFormatter(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe(''); - }); - - it('should return an empty string when False is provided', () => { - const value = false; - const result = checkmarkFormatter(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe(''); - }); - - it('should return an empty string when the string "FALSE" (case insensitive) is provided', () => { - const value = 'FALSE'; - const result1 = checkmarkFormatter(0, 0, value.toLowerCase(), {} as Column, {}, {} as any); - const result2 = checkmarkFormatter(0, 0, value.toUpperCase(), {} as Column, {}, {} as any); - expect(result1).toBe(''); - expect(result2).toBe(''); - }); - - it('should return the Font Awesome Checkmark icon when the string "True" (case insensitive) is provided', () => { - const value = 'True'; - const result1 = checkmarkFormatter(0, 0, value.toLowerCase(), {} as Column, {}, {} as any); - const result2 = checkmarkFormatter(0, 0, value.toUpperCase(), {} as Column, {}, {} as any); - expect((result1 as HTMLElement).outerHTML).toBe(''); - expect((result2 as HTMLElement).outerHTML).toBe(''); - }); - - it('should return the Font Awesome Checkmark icon when input is True', () => { - const value = true; - const result = checkmarkFormatter(0, 0, value, {} as Column, {}, {} as any); - expect((result as HTMLElement).outerHTML).toBe(''); - }); - - it('should return the Font Awesome Checkmark icon when input is a string even if it start with 0', () => { - const value = '005A00ABC'; - const result1 = checkmarkFormatter(0, 0, value, {} as Column, {}, {} as any); - expect((result1 as HTMLElement).outerHTML).toBe(''); - }); - - it('should return an empty string when the string "0" is provided', () => { - const value = '0'; - const result = checkmarkFormatter(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe(''); - }); - - it('should return the Font Awesome Checkmark icon when input is a number greater than 0', () => { - const value = 0.000001; - const result1 = checkmarkFormatter(0, 0, value, {} as Column, {}, {} as any); - expect((result1 as HTMLElement).outerHTML).toBe(''); - }); - - it('should return the Font Awesome Checkmark icon when input is a number as a text greater than 0', () => { - const value = '0.000001'; - const result1 = checkmarkFormatter(0, 0, value, {} as Column, {}, {} as any); - expect((result1 as HTMLElement).outerHTML).toBe(''); - }); - - it('should return an empty string when input is a number lower or equal to 0', () => { - const value1 = 0; - const value2 = -0.5; - const result1 = checkmarkFormatter(0, 0, value1, {} as Column, {}, {} as any); - const result2 = checkmarkFormatter(0, 0, value2, {} as Column, {}, {} as any); - expect(result1).toBe(''); - expect(result2).toBe(''); - }); - - it('should return an empty string when input is a number as a text and lower or equal to 0', () => { - const value1 = '0'; - const value2 = '-0.5'; - const result1 = checkmarkFormatter(0, 0, value1, {} as Column, {}, {} as any); - const result2 = checkmarkFormatter(0, 0, value2, {} as Column, {}, {} as any); - expect(result1).toBe(''); - expect(result2).toBe(''); - }); - - it('should return an empty string when input is type null or undefined', () => { - const value1 = null; - const value2 = undefined; - const result1 = checkmarkFormatter(0, 0, value1, {} as Column, {}, {} as any); - const result2 = checkmarkFormatter(0, 0, value2, {} as Column, {}, {} as any); - expect(result1).toBe(''); - expect(result2).toBe(''); - }); - - it('should return the Font Awesome Checkmark icon when input is the "null" or "undefined"', () => { - const value1 = 'null'; - const value2 = 'undefined'; - const result1 = checkmarkFormatter(0, 0, value1, {} as Column, {}, {} as any); - const result2 = checkmarkFormatter(0, 0, value2, {} as Column, {}, {} as any); - expect((result1 as HTMLElement).outerHTML).toBe(''); - expect((result2 as HTMLElement).outerHTML).toBe(''); - }); -}); diff --git a/packages/common/src/formatters/__tests__/checkmarkMaterialFormatter.spec.ts b/packages/common/src/formatters/__tests__/checkmarkMaterialFormatter.spec.ts index 92c483b93..e1a896ebb 100644 --- a/packages/common/src/formatters/__tests__/checkmarkMaterialFormatter.spec.ts +++ b/packages/common/src/formatters/__tests__/checkmarkMaterialFormatter.spec.ts @@ -22,7 +22,7 @@ describe('the Checkmark Formatter with Material Design Icon', () => { expect(result2).toBe(''); }); - it('should return the Font Awesome Checkmark icon when the string "True" (case insensitive) is provided', () => { + it('should return the Material Checkmark icon when the string "True" (case insensitive) is provided', () => { const value = 'True'; const result1 = checkmarkMaterialFormatter(0, 0, value.toLowerCase(), {} as Column, {}, {} as any); const result2 = checkmarkMaterialFormatter(0, 0, value.toUpperCase(), {} as Column, {}, {} as any); @@ -30,13 +30,13 @@ describe('the Checkmark Formatter with Material Design Icon', () => { expect((result2 as HTMLElement).outerHTML).toBe(''); }); - it('should return the Font Awesome Checkmark icon when input is True', () => { + it('should return the Material Checkmark icon when input is True', () => { const value = true; const result = checkmarkMaterialFormatter(0, 0, value, {} as Column, {}, {} as any); expect((result as HTMLElement).outerHTML).toBe(''); }); - it('should return the Font Awesome Checkmark icon when input is a string even if it start with 0', () => { + it('should return the Material Checkmark icon when input is a string even if it start with 0', () => { const value = '005A00ABC'; const result1 = checkmarkMaterialFormatter(0, 0, value, {} as Column, {}, {} as any); expect((result1 as HTMLElement).outerHTML).toBe(''); @@ -48,13 +48,13 @@ describe('the Checkmark Formatter with Material Design Icon', () => { expect(result).toBe(''); }); - it('should return the Font Awesome Checkmark icon when input is a number greater than 0', () => { + it('should return the Material Checkmark icon when input is a number greater than 0', () => { const value = 0.000001; const result1 = checkmarkMaterialFormatter(0, 0, value, {} as Column, {}, {} as any); expect((result1 as HTMLElement).outerHTML).toBe(''); }); - it('should return the Font Awesome Checkmark icon when input is a number as a text greater than 0', () => { + it('should return the Material Checkmark icon when input is a number as a text greater than 0', () => { const value = '0.000001'; const result1 = checkmarkMaterialFormatter(0, 0, value, {} as Column, {}, {} as any); expect((result1 as HTMLElement).outerHTML).toBe(''); @@ -87,7 +87,7 @@ describe('the Checkmark Formatter with Material Design Icon', () => { expect(result2).toBe(''); }); - it('should return the Font Awesome Checkmark icon when input is the "null" or "undefined"', () => { + it('should return the Material Checkmark icon when input is the "null" or "undefined"', () => { const value1 = 'null'; const value2 = 'undefined'; const result1 = checkmarkMaterialFormatter(0, 0, value1, {} as Column, {}, {} as any); diff --git a/packages/common/src/formatters/__tests__/collectionEditorFormatter.spec.ts b/packages/common/src/formatters/__tests__/collectionEditorFormatter.spec.ts index 26b1c5064..6a31ad5b7 100644 --- a/packages/common/src/formatters/__tests__/collectionEditorFormatter.spec.ts +++ b/packages/common/src/formatters/__tests__/collectionEditorFormatter.spec.ts @@ -2,8 +2,6 @@ import { Column } from '../../interfaces/index'; import { collectionEditorFormatter } from '../collectionEditorFormatter'; import { Editors } from '../../editors'; -jest.mock('flatpickr', () => { }); - describe('the CollectionEditor Formatter', () => { let columnDef: Column; diff --git a/packages/common/src/formatters/__tests__/collectionFormatter.spec.ts b/packages/common/src/formatters/__tests__/collectionFormatter.spec.ts index e72020e24..69a9b0ad1 100644 --- a/packages/common/src/formatters/__tests__/collectionFormatter.spec.ts +++ b/packages/common/src/formatters/__tests__/collectionFormatter.spec.ts @@ -1,8 +1,6 @@ import { Column } from '../../interfaces/index'; import { collectionFormatter } from '../collectionFormatter'; -jest.mock('flatpickr', () => { }); - describe('the Collection Formatter', () => { it('should return same output when no value is passed', () => { const valueArray = null; diff --git a/packages/common/src/formatters/__tests__/dateEuroShortFormatter.spec.ts b/packages/common/src/formatters/__tests__/dateEuroShortFormatter.spec.ts index 79a3a066b..c61cede1d 100644 --- a/packages/common/src/formatters/__tests__/dateEuroShortFormatter.spec.ts +++ b/packages/common/src/formatters/__tests__/dateEuroShortFormatter.spec.ts @@ -17,18 +17,18 @@ describe('the DateEuroShort Formatter', () => { it('should provide a dateIso formatted input and return a formatted date value without time when valid date value is provided', () => { const value = '2019-05-01 02:36:07'; const result = Formatters.dateEuroShort(0, 0, value, { type: 'dateIso' } as unknown as Column, {}, {} as any); - expect(result).toBe('1/5/19'); + expect(result).toBe('01/05/19'); }); it('should return a formatted date value in the morning when valid date value is provided', () => { const value = new Date('2019-05-01T02:36:07'); const result = Formatters.dateEuroShort(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('1/5/19'); + expect(result).toBe('01/05/19'); }); it('should return a formatted date value in the afternoon when valid date value is provided', () => { const value = new Date('2019-05-01T20:36:07'); const result = Formatters.dateEuroShort(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('1/5/19'); + expect(result).toBe('01/05/19'); }); }); diff --git a/packages/common/src/formatters/__tests__/dateTimeEuroShortAM_PMFormatter.spec.ts b/packages/common/src/formatters/__tests__/dateTimeEuroShortAM_PMFormatter.spec.ts index a0048e9fe..78831202d 100644 --- a/packages/common/src/formatters/__tests__/dateTimeEuroShortAM_PMFormatter.spec.ts +++ b/packages/common/src/formatters/__tests__/dateTimeEuroShortAM_PMFormatter.spec.ts @@ -17,18 +17,18 @@ describe('the DateTimeEuroShortAM_PM Formatter', () => { it('should provide a dateIso formatted input and return a formatted date value without time when valid date value is provided', () => { const value = '2019-05-01 02:36:07'; const result = Formatters.dateTimeEuroShortAM_PM(0, 0, value, { type: 'dateIso' } as unknown as Column, {}, {} as any); - expect(result).toBe('1/5/19 2:36:7 AM'); + expect(result).toBe('01/05/19 02:36:07 AM'); }); it('should return a formatted date value in the morning when valid date value is provided', () => { const value = new Date('2019-05-01T02:36:07'); const result = Formatters.dateTimeEuroShortAM_PM(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('1/5/19 2:36:7 AM'); + expect(result).toBe('01/05/19 02:36:07 AM'); }); it('should return a formatted date value in the afternoon when valid date value is provided', () => { const value = new Date('2019-05-01T20:36:07'); const result = Formatters.dateTimeEuroShortAM_PM(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('1/5/19 8:36:7 PM'); + expect(result).toBe('01/05/19 08:36:07 PM'); }); }); diff --git a/packages/common/src/formatters/__tests__/dateTimeEuroShortAmPmFormatter.spec.ts b/packages/common/src/formatters/__tests__/dateTimeEuroShortAmPmFormatter.spec.ts index 79fe87bf8..0e80bfe7b 100644 --- a/packages/common/src/formatters/__tests__/dateTimeEuroShortAmPmFormatter.spec.ts +++ b/packages/common/src/formatters/__tests__/dateTimeEuroShortAmPmFormatter.spec.ts @@ -17,18 +17,18 @@ describe('the DateTimeEuroShortAmPm Formatter', () => { it('should provide a dateIso formatted input and return a formatted date value without time when valid date value is provided', () => { const value = '2019-05-01 02:36:07'; const result = Formatters.dateTimeEuroShortAmPm(0, 0, value, { type: 'dateIso' } as unknown as Column, {}, {} as any); - expect(result).toBe('1/5/19 2:36:7 am'); + expect(result).toBe('01/05/19 02:36:07 am'); }); it('should return a formatted date value in the morning when valid date value is provided', () => { const value = new Date('2019-05-01T02:36:07'); const result = Formatters.dateTimeEuroShortAmPm(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('1/5/19 2:36:7 am'); + expect(result).toBe('01/05/19 02:36:07 am'); }); it('should return a formatted date value in the afternoon when valid date value is provided', () => { const value = new Date('2019-05-01T20:36:07'); const result = Formatters.dateTimeEuroShortAmPm(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('1/5/19 8:36:7 pm'); + expect(result).toBe('01/05/19 08:36:07 pm'); }); }); diff --git a/packages/common/src/formatters/__tests__/dateTimeEuroShortFormatter.spec.ts b/packages/common/src/formatters/__tests__/dateTimeEuroShortFormatter.spec.ts index 5fa2d03d4..b8a12bb1f 100644 --- a/packages/common/src/formatters/__tests__/dateTimeEuroShortFormatter.spec.ts +++ b/packages/common/src/formatters/__tests__/dateTimeEuroShortFormatter.spec.ts @@ -17,18 +17,18 @@ describe('the DateTimeEuroShort Formatter', () => { it('should provide a dateIso formatted input and return a formatted date value without time when valid date value is provided', () => { const value = '2019-05-01 02:36:07'; const result = Formatters.dateTimeEuroShort(0, 0, value, { type: 'dateIso' } as unknown as Column, {}, {} as any); - expect(result).toBe('1/5/19 2:36:7'); + expect(result).toBe('01/05/19 02:36:07'); }); it('should return a formatted date value in the morning when valid date value is provided', () => { const value = new Date('2019-05-01T02:36:07'); const result = Formatters.dateTimeEuroShort(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('1/5/19 2:36:7'); + expect(result).toBe('01/05/19 02:36:07'); }); it('should return a formatted date value in the afternoon when valid date value is provided', () => { const value = new Date('2019-05-01T20:36:07'); const result = Formatters.dateTimeEuroShort(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('1/5/19 20:36:7'); + expect(result).toBe('01/05/19 20:36:07'); }); }); diff --git a/packages/common/src/formatters/__tests__/dateTimeUsShortAM_PMFormatter.spec.ts b/packages/common/src/formatters/__tests__/dateTimeUsShortAM_PMFormatter.spec.ts index 58363f1f4..ad4c64f24 100644 --- a/packages/common/src/formatters/__tests__/dateTimeUsShortAM_PMFormatter.spec.ts +++ b/packages/common/src/formatters/__tests__/dateTimeUsShortAM_PMFormatter.spec.ts @@ -17,18 +17,18 @@ describe('the DateTimeUsShortAM_PM Formatter', () => { it('should provide a dateIso formatted input and return a formatted date value without time when valid date value is provided', () => { const value = '2019-05-01 02:36:07'; const result = Formatters.dateTimeUsShortAM_PM(0, 0, value, { type: 'dateIso' } as unknown as Column, {}, {} as any); - expect(result).toBe('5/1/19 2:36:7 AM'); + expect(result).toBe('05/01/19 02:36:07 AM'); }); it('should return a formatted date value in the morning when valid date value is provided', () => { const value = new Date('2019-05-01T02:36:07'); const result = Formatters.dateTimeUsShortAM_PM(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('5/1/19 2:36:7 AM'); + expect(result).toBe('05/01/19 02:36:07 AM'); }); it('should return a formatted date value in the afternoon when valid date value is provided', () => { const value = new Date('2019-05-01T20:36:07'); const result = Formatters.dateTimeUsShortAM_PM(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('5/1/19 8:36:7 PM'); + expect(result).toBe('05/01/19 08:36:07 PM'); }); }); diff --git a/packages/common/src/formatters/__tests__/dateTimeUsShortAmPmFormatter.spec.ts b/packages/common/src/formatters/__tests__/dateTimeUsShortAmPmFormatter.spec.ts index 7ffcb961a..e47f4f1ab 100644 --- a/packages/common/src/formatters/__tests__/dateTimeUsShortAmPmFormatter.spec.ts +++ b/packages/common/src/formatters/__tests__/dateTimeUsShortAmPmFormatter.spec.ts @@ -17,18 +17,18 @@ describe('the DateTimeUsShortAmPm Formatter', () => { it('should provide a dateIso formatted input and return a formatted date value without time when valid date value is provided', () => { const value = '2019-05-01 02:36:07'; const result = Formatters.dateTimeUsShortAmPm(0, 0, value, { type: 'dateIso' } as unknown as Column, {}, {} as any); - expect(result).toBe('5/1/19 2:36:7 am'); + expect(result).toBe('05/01/19 02:36:07 am'); }); it('should return a formatted date value in the morning when valid date value is provided', () => { const value = new Date('2019-05-01T02:36:07'); const result = Formatters.dateTimeUsShortAmPm(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('5/1/19 2:36:7 am'); + expect(result).toBe('05/01/19 02:36:07 am'); }); it('should return a formatted date value in the afternoon when valid date value is provided', () => { const value = new Date('2019-05-01T20:36:07'); const result = Formatters.dateTimeUsShortAmPm(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('5/1/19 8:36:7 pm'); + expect(result).toBe('05/01/19 08:36:07 pm'); }); }); diff --git a/packages/common/src/formatters/__tests__/dateTimeUsShortFormatter.spec.ts b/packages/common/src/formatters/__tests__/dateTimeUsShortFormatter.spec.ts index 0ca980ad7..265e675b1 100644 --- a/packages/common/src/formatters/__tests__/dateTimeUsShortFormatter.spec.ts +++ b/packages/common/src/formatters/__tests__/dateTimeUsShortFormatter.spec.ts @@ -17,18 +17,18 @@ describe('the DateTimeUsShort Formatter', () => { it('should provide a dateIso formatted input and return a formatted date value without time when valid date value is provided', () => { const value = '2019-05-01 02:36:07'; const result = Formatters.dateTimeUsShort(0, 0, value, { type: 'dateIso' } as unknown as Column, {}, {} as any); - expect(result).toBe('5/1/19 2:36:7'); + expect(result).toBe('05/01/19 02:36:07'); }); it('should return a formatted date value in the morning when valid date value is provided', () => { const value = new Date('2019-05-01T02:36:07'); const result = Formatters.dateTimeUsShort(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('5/1/19 2:36:7'); + expect(result).toBe('05/01/19 02:36:07'); }); it('should return a formatted date value in the afternoon when valid date value is provided', () => { const value = new Date('2019-05-01T20:36:07'); const result = Formatters.dateTimeUsShort(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('5/1/19 20:36:7'); + expect(result).toBe('05/01/19 20:36:07'); }); }); diff --git a/packages/common/src/formatters/__tests__/dateUsShortFormatter.spec.ts b/packages/common/src/formatters/__tests__/dateUsShortFormatter.spec.ts index eeba6e7f1..c85b45a32 100644 --- a/packages/common/src/formatters/__tests__/dateUsShortFormatter.spec.ts +++ b/packages/common/src/formatters/__tests__/dateUsShortFormatter.spec.ts @@ -17,18 +17,18 @@ describe('the DateUsShort Formatter', () => { it('should provide a dateIso formatted input and return a formatted date value without time when valid date value is provided', () => { const value = '2019-05-01 02:36:07'; const result = Formatters.dateUsShort(0, 0, value, { type: 'dateIso' } as unknown as Column, {}, {} as any); - expect(result).toBe('5/1/19'); + expect(result).toBe('05/01/19'); }); it('should return a formatted date value in the morning when valid date value is provided', () => { const value = new Date('2019-05-01T02:36:07'); const result = Formatters.dateUsShort(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('5/1/19'); + expect(result).toBe('05/01/19'); }); it('should return a formatted date value in the afternoon when valid date value is provided', () => { const value = new Date('2019-05-01T20:36:07'); const result = Formatters.dateUsShort(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('5/1/19'); + expect(result).toBe('05/01/19'); }); }); diff --git a/packages/common/src/formatters/__tests__/dateUtcFormatter.spec.ts b/packages/common/src/formatters/__tests__/dateUtcFormatter.spec.ts index e6369c5d1..ff666b297 100644 --- a/packages/common/src/formatters/__tests__/dateUtcFormatter.spec.ts +++ b/packages/common/src/formatters/__tests__/dateUtcFormatter.spec.ts @@ -17,18 +17,18 @@ describe('the DateUtc Formatter', () => { it('should provide a dateIso formatted input and return a formatted date value without time when valid date value is provided', () => { const value = new Date('2019-05-01T02:36:07Z'); const result = Formatters.dateUtc(0, 0, value, { type: 'dateIso' } as unknown as Column, {}, {} as any); - expect(result).toBe('2019-04-30T21:36:07.000-05:00'); + expect(result).toBe('2019-05-01T02:36:07.000Z'); }); it('should return a formatted date value in the morning when valid date value is provided', () => { const value = new Date('2019-05-01T02:36:07Z'); const result = Formatters.dateUtc(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('2019-04-30T21:36:07.000-05:00'); + expect(result).toBe('2019-05-01T02:36:07.000Z'); }); it('should return a formatted date value in the afternoon when valid date value is provided', () => { const value = new Date('2019-05-01T20:36:07Z'); const result = Formatters.dateUtc(0, 0, value, {} as Column, {}, {} as any); - expect(result).toBe('2019-05-01T15:36:07.000-05:00'); + expect(result).toBe('2019-05-01T20:36:07.000Z'); }); }); diff --git a/packages/common/src/formatters/__tests__/hyperlinkFormatter.spec.ts b/packages/common/src/formatters/__tests__/hyperlinkFormatter.spec.ts index 76732ae4b..9918bcccd 100644 --- a/packages/common/src/formatters/__tests__/hyperlinkFormatter.spec.ts +++ b/packages/common/src/formatters/__tests__/hyperlinkFormatter.spec.ts @@ -5,6 +5,7 @@ import { SlickGrid } from '../../core/index'; const gridStub = { getData: jest.fn(), getOptions: jest.fn(), + sanitizeHtmlString: (str) => str } as unknown as SlickGrid; describe('the Hyperlink Formatter', () => { @@ -29,13 +30,6 @@ describe('the Hyperlink Formatter', () => { expect(result1).toBe(inputValue); }); - it('should not permit sanitize/remove any bad script code', () => { - const inputValue = 'http://company.com'; - const sanitizedValue = 'http://company.com'; - const result = hyperlinkFormatter(0, 0, inputValue, {} as Column, {}, gridStub); - expect((result as HTMLElement).outerHTML).toBe(`${sanitizedValue}`); - }); - it('should return original value when value is not a valid hyperlink', () => { const inputValue1 = 'http:/something.com'; const inputValue2 = 'https//something.com'; diff --git a/packages/common/src/formatters/__tests__/iconBooleanFormatter.spec.ts b/packages/common/src/formatters/__tests__/iconBooleanFormatter.spec.ts index 2fe208421..44b638a1e 100644 --- a/packages/common/src/formatters/__tests__/iconBooleanFormatter.spec.ts +++ b/packages/common/src/formatters/__tests__/iconBooleanFormatter.spec.ts @@ -9,75 +9,75 @@ describe('the Checkmark Formatter', () => { it('should return an empty string when no value is passed', () => { const value = null; - const cssClass = 'fa fa-check'; + const cssClass = 'mdi mdi-check'; const result = iconBooleanFormatter(0, 0, value, { field: 'user', params: { cssClass } } as Column, {}, {} as any); expect(result).toBe(''); }); it('should return an empty string when False is provided', () => { const value = false; - const cssClass = 'fa fa-check'; + const cssClass = 'mdi mdi-check'; const result = iconBooleanFormatter(0, 0, value, { field: 'user', params: { cssClass } } as Column, {}, {} as any); expect(result).toBe(''); }); it('should return an empty string when the string "FALSE" (case insensitive) is provided', () => { const value = 'FALSE'; - const cssClass = 'fa fa-check'; + const cssClass = 'mdi mdi-check'; const result1 = iconBooleanFormatter(0, 0, value.toLowerCase(), { field: 'user', params: { cssClass } } as Column, {}, {} as any); const result2 = iconBooleanFormatter(0, 0, value.toUpperCase(), { field: 'user', params: { cssClass } } as Column, {}, {} as any); expect(result1).toBe(''); expect(result2).toBe(''); }); - it('should return the Font Awesome Checkmark icon when the string "True" (case insensitive) is provided', () => { + it('should return the Checkmark icon when the string "True" (case insensitive) is provided', () => { const value = 'True'; - const cssClass = 'fa fa-check'; + const cssClass = 'mdi mdi-check'; const result1 = iconBooleanFormatter(0, 0, value.toLowerCase(), { field: 'user', params: { cssClass } } as Column, {}, {} as any); const result2 = iconBooleanFormatter(0, 0, value.toUpperCase(), { field: 'user', params: { cssClass } } as Column, {}, {} as any); - expect((result1 as HTMLElement).outerHTML).toBe(''); - expect((result2 as HTMLElement).outerHTML).toBe(''); + expect((result1 as HTMLElement).outerHTML).toBe(''); + expect((result2 as HTMLElement).outerHTML).toBe(''); }); - it('should return the Font Awesome Checkmark icon when input is True', () => { + it('should return the Checkmark icon when input is True', () => { const value = true; - const cssClass = 'fa fa-check'; + const cssClass = 'mdi mdi-check'; const result = iconBooleanFormatter(0, 0, value, { field: 'user', params: { cssClass } } as Column, {}, {} as any); - expect((result as HTMLElement).outerHTML).toBe(''); + expect((result as HTMLElement).outerHTML).toBe(''); }); - it('should return the Font Awesome Checkmark icon when input is a string even if it start with 0', () => { + it('should return the Checkmark icon when input is a string even if it start with 0', () => { const value = '005A00ABC'; - const cssClass = 'fa fa-check'; + const cssClass = 'mdi mdi-check'; const result1 = iconBooleanFormatter(0, 0, value, { field: 'user', params: { cssClass } } as Column, {}, {} as any); - expect((result1 as HTMLElement).outerHTML).toBe(''); + expect((result1 as HTMLElement).outerHTML).toBe(''); }); it('should return an empty string when the string "0" is provided', () => { const value = '0'; - const cssClass = 'fa fa-check'; + const cssClass = 'mdi mdi-check'; const result = iconBooleanFormatter(0, 0, value, { field: 'user', params: { cssClass } } as Column, {}, {} as any); expect(result).toBe(''); }); - it('should return the Font Awesome Checkmark icon when input is a number greater than 0', () => { + it('should return the Checkmark icon when input is a number greater than 0', () => { const value = 0.000001; - const cssClass = 'fa fa-check'; + const cssClass = 'mdi mdi-check'; const result1 = iconBooleanFormatter(0, 0, value, { field: 'user', params: { cssClass } } as Column, {}, {} as any); - expect((result1 as HTMLElement).outerHTML).toBe(''); + expect((result1 as HTMLElement).outerHTML).toBe(''); }); - it('should return the Font Awesome Checkmark icon when input is a number as a text greater than 0', () => { + it('should return the Checkmark icon when input is a number as a text greater than 0', () => { const value = '0.000001'; - const cssClass = 'fa fa-check'; + const cssClass = 'mdi mdi-check'; const result1 = iconBooleanFormatter(0, 0, value, { field: 'user', params: { cssClass } } as Column, {}, {} as any); - expect((result1 as HTMLElement).outerHTML).toBe(''); + expect((result1 as HTMLElement).outerHTML).toBe(''); }); it('should return an empty string when input is a number lower or equal to 0', () => { const value1 = 0; const value2 = -0.5; - const cssClass = 'fa fa-check'; + const cssClass = 'mdi mdi-check'; const result1 = iconBooleanFormatter(0, 0, value1, { field: 'user', params: { cssClass } } as Column, {}, {} as any); const result2 = iconBooleanFormatter(0, 0, value2, { field: 'user', params: { cssClass } } as Column, {}, {} as any); expect(result1).toBe(''); @@ -87,7 +87,7 @@ describe('the Checkmark Formatter', () => { it('should return an empty string when input is a number as a text and lower or equal to 0', () => { const value1 = '0'; const value2 = '-0.5'; - const cssClass = 'fa fa-check'; + const cssClass = 'mdi mdi-check'; const result1 = iconBooleanFormatter(0, 0, value1, { field: 'user', params: { cssClass } } as Column, {}, {} as any); const result2 = iconBooleanFormatter(0, 0, value2, { field: 'user', params: { cssClass } } as Column, {}, {} as any); expect(result1).toBe(''); @@ -97,20 +97,20 @@ describe('the Checkmark Formatter', () => { it('should return an empty string when input is type null or undefined', () => { const value1 = null; const value2 = undefined; - const cssClass = 'fa fa-check'; + const cssClass = 'mdi mdi-check'; const result1 = iconBooleanFormatter(0, 0, value1, { field: 'user', params: { cssClass } } as Column, {}, {} as any); const result2 = iconBooleanFormatter(0, 0, value2, { field: 'user', params: { cssClass } } as Column, {}, {} as any); expect(result1).toBe(''); expect(result2).toBe(''); }); - it('should return the Font Awesome Checkmark icon when input is the "null" or "undefined"', () => { + it('should return the Checkmark icon when input is the "null" or "undefined"', () => { const value1 = 'null'; const value2 = 'undefined'; - const cssClass = 'fa fa-check'; + const cssClass = 'mdi mdi-check'; const result1 = iconBooleanFormatter(0, 0, value1, { field: 'user', params: { cssClass } } as Column, {}, {} as any); const result2 = iconBooleanFormatter(0, 0, value2, { field: 'user', params: { cssClass } } as Column, {}, {} as any); - expect((result1 as HTMLElement).outerHTML).toBe(''); - expect((result2 as HTMLElement).outerHTML).toBe(''); + expect((result1 as HTMLElement).outerHTML).toBe(''); + expect((result2 as HTMLElement).outerHTML).toBe(''); }); }); diff --git a/packages/common/src/formatters/__tests__/iconFormatter.spec.ts b/packages/common/src/formatters/__tests__/iconFormatter.spec.ts index 3fc6760ec..aef8cd42a 100644 --- a/packages/common/src/formatters/__tests__/iconFormatter.spec.ts +++ b/packages/common/src/formatters/__tests__/iconFormatter.spec.ts @@ -2,8 +2,6 @@ import { Column } from '../../interfaces/index'; import { iconFormatter } from '../iconFormatter'; describe('the Icon Formatter', () => { - const consoleWarnSpy = jest.spyOn(global.console, 'warn').mockReturnValue(); - it('should throw an error when omitting to pass "propertyNames" to "params"', () => { expect(() => iconFormatter(0, 0, 'anything', {} as Column, {}, {} as any)) .toThrowError('[Slickgrid-Universal] When using `Formatters.icon`, you must provide the "iconCssClass" via the generic "params"'); @@ -11,23 +9,15 @@ describe('the Icon Formatter', () => { it('should always return a with the icon class name provided in the "icon" property from "params"', () => { const input = null; - const icon = 'fa fa-search'; + const icon = 'mdi mdi-magnify'; const result = iconFormatter(0, 0, input, { field: 'user', params: { icon } } as Column, {}, {} as any); expect((result as HTMLElement).outerHTML).toBe(``); }); it('should always return a with the icon class name provided in the "formatterIcon" property from "params"', () => { const input = null; - const icon = 'fa fa-search'; + const icon = 'mdi mdi-magnify'; const result = iconFormatter(0, 0, input, { field: 'user', params: { formatterIcon: icon } } as Column, {}, {} as any); expect((result as HTMLElement).outerHTML).toBe(``); }); - - it('should show console warning when using deprecated icon/formatterIcon params', () => { - const input = null; - const icon = 'fa fa-search'; - const result = iconFormatter(0, 0, input, { field: 'user', params: { icon } } as Column, {}, {} as any); - expect((result as HTMLElement).outerHTML).toBe(``); - expect(consoleWarnSpy).toHaveBeenCalledWith('[Slickgrid-Universal] deprecated params.icon or params.formatterIcon are deprecated when using `Formatters.icon` in favor of params.iconCssClass. (e.g.: `{ formatter: Formatters.icon, params: { iconCssClass: "fa fa-search" }}`'); - }); }); diff --git a/packages/common/src/formatters/checkmarkFormatter.ts b/packages/common/src/formatters/checkmarkFormatter.ts deleted file mode 100644 index ebb66da43..000000000 --- a/packages/common/src/formatters/checkmarkFormatter.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { createDomElement, isNumber } from '@slickgrid-universal/utils'; - -import type { Formatter } from './../interfaces/index'; - -/** - * When value is filled, or if the value is a number and is bigger than 0, it will display a Font-Awesome icon (fa-check). - * The icon will NOT be displayed when the value is any of the following ("false", false, "0", 0, -0.5, null, undefined) - * Anything else than the condition specified will display the icon, so a text with "00123" will display the icon but "0" will not. - * Also note that a string ("null", "undefined") will display the icon but (null, undefined) will not, so the typeof is also important - */ -export const checkmarkFormatter: Formatter = (_row, _cell, value) => { - let isChecked = false; - const isValidNumber = isNumber(value); - - if (isValidNumber) { - value = +value; // convert to number before doing next condition - } - - if (value === true || (isValidNumber && +value > 0) || (typeof value === 'string' && value.length > 0 && value.toLowerCase() !== 'false' && value !== '0')) { - isChecked = true; - } - - return isChecked ? createDomElement('i', { className: 'fa fa-check checkmark-icon', ariaHidden: 'true' }) : ''; -}; diff --git a/packages/common/src/formatters/formatterUtilities.ts b/packages/common/src/formatters/formatterUtilities.ts index ac83b11c9..c0f970311 100644 --- a/packages/common/src/formatters/formatterUtilities.ts +++ b/packages/common/src/formatters/formatterUtilities.ts @@ -1,12 +1,12 @@ +import { format } from '@formkit/tempo'; import { getHtmlStringOutput, isPrimitiveOrHTML, stripTags } from '@slickgrid-universal/utils'; -import moment from 'moment-mini'; import { FieldType } from '../enums/fieldType.enum'; import type { Column, ExcelExportOption, Formatter, FormatterResultWithHtml, FormatterResultWithText, GridOption, TextExportOption } from '../interfaces/index'; -import { mapMomentDateFormatWithFieldType } from '../services/utilities'; import { multipleFormatter } from './multipleFormatter'; import { Constants } from '../constants'; import { type SlickGrid } from '../core/index'; +import { mapTempoDateFormatWithFieldType, toUtcDate, tryParseDate } from '../services/dateUtils'; export type FormatterType = 'group' | 'cell'; export type NumberType = 'decimal' | 'currency' | 'percent' | 'regular'; @@ -96,19 +96,23 @@ export function getValueFromParamsOrFormatterOptions(optionName: string, columnD /** From a FieldType, return the associated date Formatter */ export function getAssociatedDateFormatter(fieldType: typeof FieldType[keyof typeof FieldType], defaultSeparator: string): Formatter { - const defaultDateFormat = mapMomentDateFormatWithFieldType(fieldType); + const defaultDateFormat = mapTempoDateFormatWithFieldType(fieldType, true); return (_row: number, _cell: number, value: any, columnDef: Column, _dataContext: any, grid: SlickGrid) => { const gridOptions = ((grid && typeof grid.getOptions === 'function') ? grid.getOptions() : {}) as GridOption; const customSeparator = gridOptions?.formatterOptions?.dateSeparator ?? defaultSeparator; const inputType = columnDef?.type ?? FieldType.date; - const inputDateFormat = mapMomentDateFormatWithFieldType(inputType); + const inputDateFormat = mapTempoDateFormatWithFieldType(inputType, true); const isParsingAsUtc = columnDef?.params?.parseDateAsUtc ?? false; - const isDateValid = moment(value, inputDateFormat, false).isValid(); + const date = tryParseDate(value, inputDateFormat); let outputDate = value; - if (value && isDateValid) { - outputDate = isParsingAsUtc ? moment.utc(value).format(defaultDateFormat) : moment(value).format(defaultDateFormat); + if (date) { + let d = value; + if (isParsingAsUtc) { + d = toUtcDate(date); + } + outputDate = format(d, defaultDateFormat, 'en-US'); } // user can customize the separator through the "formatterOptions" diff --git a/packages/common/src/formatters/formatters.index.ts b/packages/common/src/formatters/formatters.index.ts index 94530933d..c685b5bbd 100644 --- a/packages/common/src/formatters/formatters.index.ts +++ b/packages/common/src/formatters/formatters.index.ts @@ -2,7 +2,6 @@ import { FieldType } from '../enums/index'; import { getAssociatedDateFormatter } from './formatterUtilities'; import { arrayObjectToCsvFormatter } from './arrayObjectToCsvFormatter'; import { arrayToCsvFormatter } from './arrayToCsvFormatter'; -import { checkmarkFormatter } from './checkmarkFormatter'; import { checkmarkMaterialFormatter } from './checkmarkMaterialFormatter'; import { currencyFormatter } from './currencyFormatter'; import { collectionFormatter } from './collectionFormatter'; @@ -42,14 +41,6 @@ export const Formatters = { /** Takes an array of string and converts it to a comma delimited string */ arrayToCsv: arrayToCsvFormatter, - /** - * When value is filled, or if the value is a number and is bigger than 0, it will display a Font-Awesome icon (fa-check). - * The icon will NOT be displayed when the value is any of the following ("false", false, "0", 0, -0.5, null, undefined) - * Anything else than the condition specified will display the icon, so a text with "00123" will display the icon but "0" will not. - * Also note that a string ("null", "undefined") will display the icon but (null, undefined) will not, so the typeof is also important - */ - checkmark: checkmarkFormatter, - /** * When value is filled, or if the value is a number and is bigger than 0, it will display a Material Design check icon (mdi-check). * The icon will NOT be displayed when the value is any of the following ("false", false, "0", 0, -0.5, null, undefined) @@ -197,11 +188,11 @@ export const Formatters = { */ hyperlink: hyperlinkFormatter, - /** Display whichever icon you want (library agnostic, it could be Font-Awesome or any other) */ + /** Display whichever icon you want (library agnostic, it could be Font-Awesome, Material or any other icons set) */ icon: iconFormatter, /** - * Display whichever icon but only for boolean truthy values (library agnostic, it could be Font-Awesome or any other) + * Display whichever icon but only for boolean truthy values (library agnostic, it could be Font-Awesome, Material or any other icons set) * Note: a value of "false", null, undefined, "1" or any number below 0 are all considered falsy and will not display the icon */ iconBoolean: iconBooleanFormatter, diff --git a/packages/common/src/formatters/hyperlinkFormatter.ts b/packages/common/src/formatters/hyperlinkFormatter.ts index 4bac597f7..9569cd712 100644 --- a/packages/common/src/formatters/hyperlinkFormatter.ts +++ b/packages/common/src/formatters/hyperlinkFormatter.ts @@ -1,7 +1,6 @@ import { createDomElement } from '@slickgrid-universal/utils'; import { type Formatter } from './../interfaces/index'; -import { sanitizeTextByAvailableSanitizer, } from '../services/domUtilities'; /** * Takes an hyperlink cell value and transforms it into a real hyperlink, given that the value starts with 1 of these (http|ftp|https). @@ -15,13 +14,11 @@ import { sanitizeTextByAvailableSanitizer, } from '../services/domUtilities'; */ export const hyperlinkFormatter: Formatter = (_row, _cell, value, columnDef, _dataContext, grid) => { const columnParams = columnDef && columnDef.params || {}; - const gridOptions = grid?.getOptions() ?? {}; - let displayedText = columnParams.hyperlinkText ? columnParams.hyperlinkText : value; - displayedText = sanitizeTextByAvailableSanitizer(gridOptions, displayedText); + displayedText = grid.sanitizeHtmlString(displayedText); let outputLink = columnParams.hyperlinkUrl ? columnParams.hyperlinkUrl : value; - outputLink = sanitizeTextByAvailableSanitizer(gridOptions, outputLink); + outputLink = grid.sanitizeHtmlString(outputLink); const matchUrl = outputLink.match(/^(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-.,@?^=%&:/~+#]*[\w\-@?^=%&/~+#])?/i); diff --git a/packages/common/src/formatters/iconBooleanFormatter.ts b/packages/common/src/formatters/iconBooleanFormatter.ts index 447aab3be..5d30e5704 100644 --- a/packages/common/src/formatters/iconBooleanFormatter.ts +++ b/packages/common/src/formatters/iconBooleanFormatter.ts @@ -2,13 +2,13 @@ import { createDomElement } from '@slickgrid-universal/utils'; import { type Formatter } from './../interfaces/index'; -/** Display whichever icon for a boolean value (library agnostic, it could be Font-Awesome or any other) */ +/** Display whichever icon for a boolean value (library agnostic, it could be Font-Awesome, Material or any other icons set) */ export const iconBooleanFormatter: Formatter = (_row, _cell, value, columnDef) => { const columnParams = columnDef?.params || {}; const cssClasses = columnParams.cssClass; if (!cssClasses) { - throw new Error('[Slickgrid-Universal] When using `Formatters.iconBoolean`, you must provide You must provide the "cssClass", e.g.: { formatter: Formatters.iconBoolean, params: { cssClass: "fa fa-check" }}'); + throw new Error('[Slickgrid-Universal] When using `Formatters.iconBoolean`, you must provide You must provide the "cssClass", e.g.: { formatter: Formatters.iconBoolean, params: { cssClass: "mdi mdi-check" }}'); } let isTruthy = false; diff --git a/packages/common/src/formatters/iconFormatter.ts b/packages/common/src/formatters/iconFormatter.ts index b0a3fba37..4b39f7788 100644 --- a/packages/common/src/formatters/iconFormatter.ts +++ b/packages/common/src/formatters/iconFormatter.ts @@ -1,17 +1,13 @@ import { createDomElement } from '@slickgrid-universal/utils'; -import { type Formatter } from './../interfaces/index'; +import { type Formatter } from './../interfaces/index'; -/** Display whichever icon you want (library agnostic, it could be Font-Awesome or any other) */ +/** Display whichever icon you want (library agnostic, it could be Font-Awesome, Material or any other icons set) */ export const iconFormatter: Formatter = (_row, _cell, _value, columnDef) => { const columnParams = columnDef?.params ?? {}; const cssClasses = columnParams.iconCssClass || columnParams.icon || columnParams.formatterIcon; - if (columnParams.icon || columnParams.formatterIcon) { - console.warn('[Slickgrid-Universal] deprecated params.icon or params.formatterIcon are deprecated when using `Formatters.icon` in favor of params.iconCssClass. (e.g.: `{ formatter: Formatters.icon, params: { iconCssClass: "fa fa-search" }}`'); - } - if (!cssClasses) { - throw new Error('[Slickgrid-Universal] When using `Formatters.icon`, you must provide the "iconCssClass" via the generic "params". (e.g.: `{ formatter: Formatters.icon, params: { iconCssClass: "fa fa-search" }}`'); + throw new Error('[Slickgrid-Universal] When using `Formatters.icon`, you must provide the "iconCssClass" via the generic "params". (e.g.: `{ formatter: Formatters.icon, params: { iconCssClass: "mdi mdi-magnify" }}`'); } return createDomElement('i', { className: cssClasses, ariaHidden: 'true' }); }; diff --git a/packages/common/src/formatters/index.ts b/packages/common/src/formatters/index.ts index 1ab3c19a7..2829d3cdf 100644 --- a/packages/common/src/formatters/index.ts +++ b/packages/common/src/formatters/index.ts @@ -1,7 +1,6 @@ export * from './arrayObjectToCsvFormatter'; export * from './arrayToCsvFormatter'; export * from './checkmarkMaterialFormatter'; -export * from './checkmarkFormatter'; export * from './collectionEditorFormatter'; export * from './collectionFormatter'; export * from './complexObjectFormatter'; diff --git a/packages/common/src/global-grid-options.ts b/packages/common/src/global-grid-options.ts index e2a837de2..ca8896a5e 100644 --- a/packages/common/src/global-grid-options.ts +++ b/packages/common/src/global-grid-options.ts @@ -69,13 +69,13 @@ export const GlobalGridOptions: Partial = { hideExportTextDelimitedCommand: true, hideMenuOnScroll: true, hideOptionSection: false, - iconCollapseAllGroupsCommand: 'fa fa-compress mdi mdi-arrow-collapse', - iconExpandAllGroupsCommand: 'fa fa-expand mdi mdi-arrow-expand', - iconClearGroupingCommand: 'fa fa-times mdi mdi-close', - iconCopyCellValueCommand: 'fa fa-clone mdi mdi-content-copy', - iconExportCsvCommand: 'fa fa-download mdi mdi-download', - iconExportExcelCommand: 'fa fa-file-excel-o mdi mdi-file-excel-outline', - iconExportTextDelimitedCommand: 'fa fa-download mdi mdi-download', + iconCollapseAllGroupsCommand: 'mdi mdi-arrow-collapse', + iconExpandAllGroupsCommand: 'mdi mdi-arrow-expand', + iconClearGroupingCommand: 'mdi mdi-close', + iconCopyCellValueCommand: 'mdi mdi-content-copy', + iconExportCsvCommand: 'mdi mdi-download', + iconExportExcelCommand: 'mdi mdi-file-excel-outline', + iconExportTextDelimitedCommand: 'mdi mdi-download', showBulletWhenIconMissing: true, subItemChevronClass: 'mdi mdi-chevron-down mdi-rotate-270', }, @@ -198,17 +198,17 @@ export const GlobalGridOptions: Partial = { hideToggleFilterCommand: false, hideToggleDarkModeCommand: true, hideTogglePreHeaderCommand: false, - iconCssClass: 'fa fa-bars mdi mdi-menu', - iconClearAllFiltersCommand: 'fa fa-filter mdi mdi-filter-remove-outline', - iconClearAllSortingCommand: 'fa fa-unsorted mdi mdi-swap-vertical', - iconClearFrozenColumnsCommand: 'fa fa-times mdi mdi-pin-off-outline', - iconExportCsvCommand: 'fa fa-download mdi mdi-download', - iconExportExcelCommand: 'fa fa-file-excel-o mdi mdi-file-excel-outline', - iconExportTextDelimitedCommand: 'fa fa-download mdi mdi-download', - iconRefreshDatasetCommand: 'fa fa-refresh mdi mdi-sync', - iconToggleDarkModeCommand: 'fa fa-moon-o mdi mdi-brightness-4', - iconToggleFilterCommand: 'fa fa-random mdi mdi-flip-vertical', - iconTogglePreHeaderCommand: 'fa fa-random mdi mdi-flip-vertical', + iconCssClass: 'mdi mdi-menu', + iconClearAllFiltersCommand: 'mdi mdi-filter-remove-outline', + iconClearAllSortingCommand: 'mdi mdi-sort-variant-off', + iconClearFrozenColumnsCommand: 'mdi mdi-pin-off-outline', + iconExportCsvCommand: 'mdi mdi-download', + iconExportExcelCommand: 'mdi mdi-file-excel-outline', + iconExportTextDelimitedCommand: 'mdi mdi-download', + iconRefreshDatasetCommand: 'mdi mdi-sync', + iconToggleDarkModeCommand: 'mdi mdi-brightness-4', + iconToggleFilterCommand: 'mdi mdi-flip-vertical', + iconTogglePreHeaderCommand: 'mdi mdi-flip-vertical', menuWidth: 16, resizeOnShowHeaderRow: true, showBulletWhenIconMissing: true, @@ -219,13 +219,13 @@ export const GlobalGridOptions: Partial = { autoAlign: true, autoAlignOffset: 4, minWidth: 140, - iconClearFilterCommand: 'fa fa-filter mdi mdi mdi-filter-remove-outline', - iconClearSortCommand: 'fa fa-unsorted mdi mdi-swap-vertical', - iconFreezeColumns: 'fa fa-thumb-tack mdi mdi-pin-outline', - iconSortAscCommand: 'fa fa-sort-amount-asc mdi mdi-flip-v mdi-sort-ascending', - iconSortDescCommand: 'fa fa-sort-amount-desc mdi mdi-flip-v mdi-sort-descending', - iconColumnHideCommand: 'fa fa-times mdi mdi-close', - iconColumnResizeByContentCommand: 'fa fa-arrows-h mdi mdi-arrow-expand-horizontal', + iconClearFilterCommand: 'mdi mdi-filter-remove-outline', + iconClearSortCommand: 'mdi mdi-sort-variant-off', + iconFreezeColumns: 'mdi mdi-pin-outline', + iconSortAscCommand: 'mdi mdi-sort-ascending', + iconSortDescCommand: 'mdi mdi-sort-descending', + iconColumnHideCommand: 'mdi mdi-close', + iconColumnResizeByContentCommand: 'mdi mdi-arrow-expand-horizontal', hideColumnResizeByContentCommand: false, hideColumnHideCommand: false, hideClearFilterCommand: false, @@ -261,7 +261,6 @@ export const GlobalGridOptions: Partial = { maxItemToInspectSingleColumnWidthByContent: 5000, widthToRemoveFromExceededWidthReadjustment: 50, }, - sanitizerOptions: { ADD_ATTR: ['level'], RETURN_TRUSTED_TYPE: true }, // our default DOMPurify options treeDataOptions: { exportIndentMarginLeft: 5, exportIndentationLeadingChar: '͏͏͏͏͏͏͏͏͏·', diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index a9e348e4f..38eaaedaf 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -44,5 +44,6 @@ const Utilities = { ...BackendUtilities, ...Observers, ...ServiceUtilities, ...S export { Utilities }; export { SlickgridConfig } from './slickgrid-config'; -// re-export MultipleSelectOption to avoid breaking previous code implementation -export type { MultipleSelectOption } from 'multiple-select-vanilla'; +// re-export MultipleSelectOption type for convenience +// and also to avoid asking the user to install it on their side without hoisting deps +export { type MultipleSelectOption } from 'multiple-select-vanilla'; \ No newline at end of file diff --git a/packages/common/src/interfaces/column.interface.ts b/packages/common/src/interfaces/column.interface.ts index 2029819e4..02acd1e02 100644 --- a/packages/common/src/interfaces/column.interface.ts +++ b/packages/common/src/interfaces/column.interface.ts @@ -205,13 +205,6 @@ export interface Column { /** ID of the column, each column definition ID must be unique or else SlickGrid will throw an error. */ id: number | string; - /** - * @deprecated @use `editor` for the editor definition or use `editorClass` for the SlickGrid editor class. - * This is a RESERVED property and is used internally by the library to copy over the Column Editor Options. - * You can read this property if you wish, but DO NOT override it (unless you know what you're doing) since could cause serious problems with your editors. - */ - internalColumnEditor?: ColumnEditor; - /** Label key, for example this could be used as a property key for complex object label display (e.g. labelKey: 'name') */ labelKey?: string; diff --git a/packages/common/src/interfaces/columnEditor.interface.ts b/packages/common/src/interfaces/columnEditor.interface.ts index 3bf58456a..abcd9b600 100644 --- a/packages/common/src/interfaces/columnEditor.interface.ts +++ b/packages/common/src/interfaces/columnEditor.interface.ts @@ -68,7 +68,8 @@ export interface ColumnEditor { /** * Options that could be provided to the Editor, example: { container: 'body', maxHeight: 250} * - * Please note that if you use options that have existed model interfaces, you should cast with "as X", + * Please note that if you use options that have existed model interfaces, + * you should always cast it with the "as X" (where X is the external lib options interface), * for example { editorOptions: {maxHeight: 250} as MultipleSelectOption } */ editorOptions?: any; diff --git a/packages/common/src/interfaces/columnFilter.interface.ts b/packages/common/src/interfaces/columnFilter.interface.ts index a72c468c9..72f186180 100644 --- a/packages/common/src/interfaces/columnFilter.interface.ts +++ b/packages/common/src/interfaces/columnFilter.interface.ts @@ -88,7 +88,8 @@ export interface ColumnFilter { /** * Options that could be provided to the Filter, example: { container: 'body', maxHeight: 250} * - * Please note that if you use options that have existed model interfaces, you should cast with "as X", + * Please note that if you use options that have existed model interfaces, + * you should always cast it with the "as X" (where X is the external lib options interface), * for example { filterOptions: {maxHeight: 250} as MultipleSelectOption } */ filterOptions?: any; diff --git a/packages/common/src/interfaces/flatpickrOption.interface.ts b/packages/common/src/interfaces/flatpickrOption.interface.ts deleted file mode 100644 index 8a902964a..000000000 --- a/packages/common/src/interfaces/flatpickrOption.interface.ts +++ /dev/null @@ -1,178 +0,0 @@ -import type { Instance as FlatpickrInstance } from 'flatpickr/dist/types/instance'; -import type { Locale } from 'flatpickr/dist/types/locale'; - -export interface FlatpickrOption { - /** defaults to "F j, Y", exactly the same as date format, but for the altInput field */ - altFormat?: string; - - /** default to false, show the user a readable date (as per altFormat), but return something totally different to the server. */ - altInput?: boolean; - - /** defaults to false, allows the user to enter a date directly input the input field. By default, direct entry is disabled. */ - allowInput?: boolean; - - /** defaults to false, allows the user to input date and/or date format that might be partially invalid. */ - allowInvalidPreload?: boolean; - - /** This class will be added to the input element created by the altInput option. Note that altInput already inherits classes from the original input. */ - altInputClass?: string; - - /** Instead of body, appends the calendar to the specified node instead*. */ - appendTo?: HTMLElement; - - /** defaults to "F j, Y", defines how the date will be formatted in the aria-label for calendar days, using the same tokens as dateFormat. If you change this, you should choose a value that will make sense if a screen reader reads it out loud. */ - ariaDateFormat?: string; - - /** defaults to true, whether clicking on the input should open the picker. You could disable this if you wish to open the calendar manually with.open() */ - clickOpens?: boolean; - - /** defaults to false, closes the date picker after selecting a date */ - closeOnSelect?: boolean; - - /** defaults to "Y-m-d", a string of characters which are used to define how the date will be displayed in the input box. The supported characters are defined in the table below. */ - dateFormat?: string; - - /** - * Sets the initial selected date(s). - * If you're using mode?: "multiple" or a range calendar supply an Array of Date objects or an Array of date strings which follow your dateFormat. - * Otherwise, you can supply a single Date object or a date string. - */ - defaultDate?: string | string[] | Date | Date[]; - - /** defaults to 12, initial value of the hour element. */ - defaultHour?: number; - - /** defaults to 0, initial value of the minute element. */ - defaultMinute?: number; - - /** defaults to 0, initial value of the seconds element. */ - defaultSeconds?: number; - - /** See Disabling dates */ - disable?: any[]; - - /** - * defaults to false. - * Set disableMobile to true to always use the non-native picker. - * By default, flatpickr utilizes native datetime widgets unless certain options (e.g. disable) are used. - */ - disableMobile?: boolean; - - /** See Enabling dates */ - enable?: any[]; - - /** defaults to false, enables seconds in the time picker. */ - enableSeconds?: boolean; - - /** defaults to false, enables time picker */ - enableTime?: boolean; - - /** - * callback method when Flapickr detects an error. - * For example if a minDate is specified and setDate is called with a date that is lower than minDate it will throw an error. - */ - errorHandler?: (error: any) => void; - - /** Allows using a custom date formatting function instead of the built-in handling for date formats using dateFormat, altFormat, etc. */ - formatDate?: (dateObj: Date, format: string, locale: Locale) => string; - - /** defaults to false, do we want to hide the clear date button? */ - hideClearButton?: boolean; - - /** defaults to 1, adjusts the step for the hour input (incl. scrolling) */ - hourIncrement?: number; - - /** defaults to false, displays the calendar inline */ - inline?: boolean; - - /** provide a custom set of locales */ - locale?: any; - - /** The maximum date that a user can pick to (inclusive). */ - maxDate?: string | Date; - - /** The minimum date that a user can start picking from (inclusive). */ - minDate?: string | Date; - - /** defaults to 5, adjusts the step for the minute input (incl. scrolling) */ - minuteIncrement?: number; - - /** defaults to "dropdown", the selector type to change the month */ - monthSelectorType?: 'dropdown' | 'static'; - - /** defaults to single, what mode to use the picker */ - mode?: 'single' | 'multiple' | 'range'; - - /** defaults to ">", HTML for the arrow icon, used to switch months. */ - nextArrow?: string; - - /** defaults to false, Hides the day selection in calendar. Use it along with enableTime to create a time picker. */ - noCalendar?: boolean; - - /** defaults to false, function that expects a date string and must return a Date object */ - parseDate?: (date: Date, format: string) => void; - - /** Provide external flatpickr plugin(s) */ - plugins?: any | any[]; - - /** Where the calendar is rendered relative to the input. */ - position?: 'auto' | 'above' | 'below'; - - /** defaults to "<"", HTML for the left arrow icon. */ - prevArrow?: string; - - /** defaults to false, show the month using the shorthand version (ie, Sep instead of September). */ - shorthandCurrentMonth?: boolean; - - /** defaults to 1, number of months to show */ - showMonths?: number; - - /** defaults to false, position the calendar inside the wrapper and next to the input element*. */ - static?: boolean; - - /** defaults to 'light', use a theme of your choice. */ - theme?: 'dark' | 'light' | 'material_blue' | 'material_green' | 'material_red' | 'material_orange' | 'airbnb' | 'confetti'; - - /** defaults to false, displays time picker in 24 hour mode without AM/PM selection when enabled. */ - time_24hr?: boolean; - - /** defaults to false, enables display of week numbers in calendar. */ - weekNumbers?: boolean; - - /** defaults to false, custom elements and input groups */ - wrap?: boolean; - - // -- - // Events - // ----------------- - - /** Function(s) to trigger on every date selection. See Events API */ - onChange?: (selectedDates: Date[] | Date, dateStr: string, instance: FlatpickrInstance) => void; - - /** Function(s) to trigger on every time the calendar is closed. See Events API */ - onClose?: (selectedDates: Date[] | Date, dateStr: string, instance: FlatpickrInstance) => void; - - /** Function(s) to trigger on every time the calendar gets created. See Events API */ - onDayCreate?: (date: Date | Date[]) => void; - - /** Function(s) to trigger when the date picker gets drestroyed. See Events API */ - onDestroy?: (day: Date) => void; - - /** Function(s) to trigger when the date picker gets drestroyed. See Events API */ - onKeyDown?: (selectedDates: Date[] | Date, dateStr: string, instance: FlatpickrInstance) => void; - - /** Function(s) to trigger on every time the month changes. See Events API */ - onMonthChange?: (selectedDates: Date[] | Date, dateStr: string, instance: FlatpickrInstance) => void; - - /** Function(s) to trigger on every time the calendar is opened. See Events API */ - onOpen?: (selectedDates: Date[] | Date, dateStr: string, instance: FlatpickrInstance) => void; - - /** Function to trigger when the calendar is ready. See Events API */ - onReady?: () => void; - - /** Function(s) to trigger on every time the value input associated with the calendar get updated. See Events API */ - onValueUpdate?: (selectedDates: Date[] | Date, dateStr: string, instance: FlatpickrInstance) => void; - - /** Function(s) to trigger on every time the year changes. See Events API */ - onYearChange?: (selectedDates: Date[] | Date, dateStr: string, instance: FlatpickrInstance) => void; -} diff --git a/packages/common/src/interfaces/gridOption.interface.ts b/packages/common/src/interfaces/gridOption.interface.ts index 132adc8a9..576805ae3 100644 --- a/packages/common/src/interfaces/gridOption.interface.ts +++ b/packages/common/src/interfaces/gridOption.interface.ts @@ -1,4 +1,5 @@ import type { EventNamingStyle } from '@slickgrid-universal/event-pub-sub'; +import type { MultipleSelectOption } from 'multiple-select-vanilla'; import type { AutoResizeOption, @@ -20,7 +21,6 @@ import type { ExcelCopyBufferOption, ExcelExportOption, ExternalResource, - FlatpickrOption, Formatter, FormatterOption, GridMenu, @@ -42,11 +42,11 @@ import type { SliderRangeOption, TextExportOption, TreeDataOption, + VanillaCalendarOption, } from './index'; import type { ColumnReorderFunction, OperatorString, OperatorType, } from '../enums/index'; import type { TranslaterService } from '../services/translater.service'; import type { DataViewOption, SlickEditorLock } from '../core/index'; -import type { MultipleSelectOption } from 'multiple-select-vanilla'; export interface CellViewportRange { bottom: number; @@ -226,7 +226,7 @@ export interface GridOption { /** * Dark Mode Theme (disabled by default, which mean light mode). * Enabling this option will add `.slick-dark-mode` CSS class to the grid parent elements - * and any other elements that are appended to the html body (e.g. Flatpickr, LongTextEditor, ...) + * and any other elements that are appended to the html body (e.g. SlickCompositeEditor, LongTextEditor, ...) */ darkMode?: boolean; @@ -274,7 +274,7 @@ export interface GridOption { autocompleter?: AutocompleterOption, /** Default option(s) to use by both the CompoundDate and/or DateRange editors */ - date?: FlatpickrOption, + date?: Partial, /** Default option(s) to use by the LongText editor */ longText?: LongTextEditorOption, @@ -292,7 +292,7 @@ export interface GridOption { autocompleter?: AutocompleterOption, /** Default option(s) to use by both the CompoundDate and/or DateRange filters */ - date?: FlatpickrOption, + date?: Partial, /** Default option(s) to use by both the CompoundSelect and/or SelectRange filters */ select?: Partial, @@ -304,7 +304,7 @@ export interface GridOption { /** The default filter model to use when none is specified (defaults to input text filter). */ defaultFilter?: any; - /** Default placeholder to use in Filters that support placeholder (autocomplete, input, flatpickr, select, ...) */ + /** Default placeholder to use in Filters that support placeholder (autocomplete, input, date picker, select, ...) */ defaultFilterPlaceholder?: string; /** Defaults to 'RangeInclusive', allows to change the default filter range operator */ @@ -710,18 +710,12 @@ export interface GridOption { /** Row selection options */ rowSelectionOptions?: RowSelectionModelOption; - /** - * Optionally pass some options to the 3rd party lib "cure53/DOMPurify" used in some Filters. - * For this to work, "enableRenderHtml" as to be enabled. - */ - sanitizerOptions?: unknown; - /** * By default the lib will use DOMPurify to sanitize any HTML strings before passing them to `innerHTML`, * however you could optionally provide your own sanitizer callback instead of using DOMPurify. * e.g.: DOMPurify doesn't work in Salesforce, so a custom sanitizer is required */ - sanitizer?: (dirtyHtml: string) => string; + sanitizer?: (dirtyHtml: string) => string | TrustedHTML; /** Defaults to 50, render throttling when scrolling large dataset */ scrollRenderThrottling?: number; diff --git a/packages/common/src/interfaces/index.ts b/packages/common/src/interfaces/index.ts index b496438ea..4dcd4eaf2 100644 --- a/packages/common/src/interfaces/index.ts +++ b/packages/common/src/interfaces/index.ts @@ -67,7 +67,6 @@ export * from './filterCallback.interface'; export * from './filterChangedArgs.interface'; export * from './filterCondition.interface'; export * from './filterConditionOption.interface'; -export * from './flatpickrOption.interface'; export * from './formatter.interface'; export * from './formatterOption.interface'; export * from './formatterResultObject.interface'; @@ -145,3 +144,4 @@ export * from './textExportOption.interface'; export * from './treeDataOption.interface'; export * from './treeToggledItem.interface'; export * from './treeToggleStateChange.interface'; +export * from './vanillaCalendarOption.interface'; diff --git a/packages/common/src/interfaces/vanillaCalendarOption.interface.ts b/packages/common/src/interfaces/vanillaCalendarOption.interface.ts new file mode 100644 index 000000000..adb402ab3 --- /dev/null +++ b/packages/common/src/interfaces/vanillaCalendarOption.interface.ts @@ -0,0 +1,8 @@ +import type { IPartialSettings } from 'vanilla-calendar-picker'; + +export interface VanillaCalendarOption extends Partial { + //-- extra options used by SlickGrid + + /** defaults to false, do we want to hide the clear date button? */ + hideClearButton?: boolean; +} diff --git a/packages/common/src/services/__tests__/backend-utilities.spec.ts b/packages/common/src/services/__tests__/backend-utilities.spec.ts index e49587036..b27ce7655 100644 --- a/packages/common/src/services/__tests__/backend-utilities.spec.ts +++ b/packages/common/src/services/__tests__/backend-utilities.spec.ts @@ -4,8 +4,6 @@ import { BackendServiceApi, GridOption } from '../../interfaces/index'; import { BackendUtilityService } from '../backendUtility.service'; import { RxJsResourceStub } from '../../../../../test/rxjsResourceStub'; -jest.mock('flatpickr', () => { }); - const graphqlServiceMock = { buildQuery: jest.fn(), updateFilters: jest.fn(), diff --git a/packages/common/src/services/__tests__/dateUtils.spec.ts b/packages/common/src/services/__tests__/dateUtils.spec.ts new file mode 100644 index 000000000..205c23839 --- /dev/null +++ b/packages/common/src/services/__tests__/dateUtils.spec.ts @@ -0,0 +1,170 @@ +import 'jest-extended'; + +import { FieldType } from '../../enums/index'; +import { mapTempoDateFormatWithFieldType, parseUtcDate } from '../dateUtils'; + +describe('Service/Utilies', () => { + describe('mapTempoDateFormatWithFieldType method', () => { + it('should return a Date in dateTime/dateTimeIso format', () => { + const output1 = mapTempoDateFormatWithFieldType(FieldType.dateTime); + const output2 = mapTempoDateFormatWithFieldType(FieldType.dateTimeIso); + expect(output1).toBe('YYYY-MM-DD HH:mm:ss'); + expect(output2).toBe('YYYY-MM-DD HH:mm:ss'); + }); + + it('should return a Date in dateTimeShortIso format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeShortIso); + expect(output).toBe('YYYY-MM-DD HH:mm'); + }); + + it('should return a Date in dateTimeIsoAmPm format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeIsoAmPm); + expect(output).toBe('YYYY-MM-DD hh:mm:ss a'); + }); + + it('should return a Date in dateTimeIsoAM_PM format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeIsoAM_PM); + expect(output).toBe('YYYY-MM-DD hh:mm:ss A'); + }); + + it('should return a Date in dateEuro format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateEuro); + expect(output).toBe('DD/MM/YYYY'); + }); + + it('should return a Date in dateEuroShort format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateEuroShort); + expect(output).toEqual('D/M/YY'); + }); + + it('should return a Date in dateEuroShort format with zero padding', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateEuroShort, true); + expect(output).toEqual('DD/MM/YY'); + }); + + it('should return a Date in dateTimeEuro format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeEuro); + expect(output).toBe('DD/MM/YYYY HH:mm:ss'); + }); + + it('should return a Date in dateTimeShortEuro format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeShortEuro); + expect(output).toEqual('D/M/YYYY H:m'); + }); + + it('should return a Date in dateTimeShortEuro format with zero padding', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeShortEuro, true); + expect(output).toEqual('DD/MM/YYYY HH:mm'); + }); + + it('should return a Date in dateTimeEuroAmPm format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeEuroAmPm); + expect(output).toBe('DD/MM/YYYY hh:mm:ss a'); + }); + + it('should return a Date in dateTimeEuroAM_PM format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeEuroAM_PM); + expect(output).toBe('DD/MM/YYYY hh:mm:ss A'); + }); + + it('should return a Date in dateTimeEuroShort format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeEuroShort); + expect(output).toEqual('D/M/YY H:m:s'); + }); + + it('should return a Date in dateTimeEuroShort format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeEuroShort, true); + expect(output).toEqual('DD/MM/YY HH:mm:ss'); + }); + + it('should return a Date in dateTimeEuroShortAmPm format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeEuroShortAmPm); + expect(output).toEqual('D/M/YY h:m:s a'); + }); + + it('should return a Date in dateTimeEuroShortAmPm format with zero padding', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeEuroShortAmPm, true); + expect(output).toEqual('DD/MM/YY hh:mm:ss a'); + }); + + it('should return a Date in dateUs format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateUs); + expect(output).toBe('MM/DD/YYYY'); + }); + + it('should return a Date in dateUsShort format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateUsShort); + expect(output).toEqual('M/D/YY'); + }); + + it('should return a Date in dateUsShort format with zero padding', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateUsShort, true); + expect(output).toEqual('MM/DD/YY'); + }); + + it('should return a Date in dateTimeUs format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeUs); + expect(output).toBe('MM/DD/YYYY HH:mm:ss'); + }); + + it('should return a Date in dateTimeShortUs format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeShortUs); + expect(output).toEqual('M/D/YYYY H:m'); + }); + + it('should return a Date in dateTimeShortUs format with zero padding', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeShortUs, true); + expect(output).toEqual('MM/DD/YYYY HH:mm'); + }); + + it('should return a Date in dateTimeUsAmPm format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeUsAmPm); + expect(output).toBe('MM/DD/YYYY hh:mm:ss a'); + }); + + it('should return a Date in dateTimeUsAM_PM format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeUsAM_PM); + expect(output).toBe('MM/DD/YYYY hh:mm:ss A'); + }); + + it('should return a Date in dateTimeUsShort format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeUsShort); + expect(output).toEqual('M/D/YY H:m:s'); + }); + + it('should return a Date in dateTimeUsShort format with zero padding', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeUsShort, true); + expect(output).toEqual('MM/DD/YY HH:mm:ss'); + }); + + it('should return a Date in dateTimeUsShortAmPm format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeUsShortAmPm); + expect(output).toEqual('M/D/YY h:m:s a'); + }); + + it('should return a Date in dateTimeUsShortAmPm format with zero padding', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateTimeUsShortAmPm, true); + expect(output).toEqual('MM/DD/YY hh:mm:ss a'); + }); + + it('should return a Date in dateUtc format', () => { + const output = mapTempoDateFormatWithFieldType(FieldType.dateUtc); + expect(output).toBe('ISO8601'); + }); + + it('should return a Date in date/dateIso format', () => { + const output1 = mapTempoDateFormatWithFieldType(FieldType.date); + const output2 = mapTempoDateFormatWithFieldType(FieldType.dateIso); + expect(output1).toBe('YYYY-MM-DD'); + expect(output2).toBe('YYYY-MM-DD'); + }); + }); + + describe('parseUtcDate method', () => { + it('should return a TZ date parsed as UTC but without milliseconds', () => { + const input = '2012-01-01'; + const output = parseUtcDate(input); + expect(output).toBe('2012-01-01T00:00:00Z'); + }); + }); +}); diff --git a/packages/common/src/services/__tests__/domUtilities.spec.ts b/packages/common/src/services/__tests__/domUtilities.spec.ts deleted file mode 100644 index e20e308ea..000000000 --- a/packages/common/src/services/__tests__/domUtilities.spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -import 'jest-extended'; -import { GridOption } from '../../interfaces'; -import { sanitizeTextByAvailableSanitizer, } from '../domUtilities'; - -describe('Service/domUtilies', () => { - describe('sanitizeTextByAvailableSanitizer method', () => { - describe('use default DOMPurify sanitizer when no sanitizer exist', () => { - const gridOptions = {} as GridOption; - - it('should return original value when input does not include any HTML tags', () => { - const input = 'foo bar'; - const output = sanitizeTextByAvailableSanitizer(gridOptions, input); - expect(output).toBe('foo bar'); - }); - - it('should return original value when input does not include any bad HTML tags', () => { - const input = '
Something
'; - const output = sanitizeTextByAvailableSanitizer(gridOptions, input); - expect(output).toBe('
Something
'); - }); - - it('should return empty string when some javascript script tags are included', () => { - const input = ''; - const output = sanitizeTextByAvailableSanitizer(gridOptions, input); - expect(output).toBe(''); - }); - - it('should return an empty link tag when "javascript:" is part of the dirty html', () => { - const input = ''; - const output = sanitizeTextByAvailableSanitizer(gridOptions, input); - expect(output).toBe(''); - }); - }); - - describe('use custom sanitizer when provided in the grid options', () => { - const gridOptions = { - sanitizer: (dirtyHtml) => (dirtyHtml.replace(/(\b)(on\S+)(\s*)=|javascript:([^>]*)[^>]*|(<\s*)(\/*)script([<>]*).*(<\s*)(\/*)script([<>]*)/gi, '')), - } as GridOption; - - it('should return original value when input does not include any HTML tags', () => { - const input = 'foo bar'; - const output = sanitizeTextByAvailableSanitizer(gridOptions, input); - expect(output).toBe('foo bar'); - }); - - it('should return original value when input does not include any bad HTML tags', () => { - const input = '
Something
'; - const output = sanitizeTextByAvailableSanitizer(gridOptions, input); - expect(output).toBe('
Something
'); - }); - - it('should return empty string when some javascript script tags are included', () => { - const input = ''; - const output = sanitizeTextByAvailableSanitizer(gridOptions, input); - expect(output).toBe(''); - }); - - it('should return text without the word "javascript:" when that is part of the dirty html', () => { - const input = 'javascript:alert("Hello World")'; - const output = sanitizeTextByAvailableSanitizer(gridOptions, input); - expect(output).toBe(''); - }); - - it('should return an empty link tag when "javascript:" is part of the dirty html', () => { - const input = ''; - const output = sanitizeTextByAvailableSanitizer(gridOptions, input); - expect(output).toBe(' { const filterFirstExpectation = { columnDef: mockColumn1, columnId: 'firstName', operator: 'EQ', searchTerms: ['John'], parsedSearchTerms: ['John'], targetSelector: '', type: FieldType.string }; const filterLastExpectation = { columnDef: mockColumn2, columnId: 'lastName', operator: 'NE', searchTerms: ['Doe'], parsedSearchTerms: ['Doe'], targetSelector: '', type: FieldType.string }; - const newEvent = new Event('mouseup'); + const newEvent = new SlickEventData(new CustomEvent(`mouseup`)); const spyClear = jest.spyOn(service.getFiltersMetadata()[2], 'clear'); const spyFilterChange = jest.spyOn(service, 'onBackendFilterChange'); const spyEmitter = jest.spyOn(service, 'emitFilterChanged'); @@ -640,9 +640,9 @@ describe('FilterService', () => { const spyClear = jest.spyOn(service.getFiltersMetadata()[0], 'clear'); const spyEmitter = jest.spyOn(service, 'emitFilterChanged'); const pubSubSpy = jest.spyOn(pubSubServiceStub, 'publish'); - + const newEvent = new SlickEventData(new CustomEvent(`mouseup`)); const filterCountBefore = Object.keys(service.getColumnFilters()).length; - await service.clearFilterByColumnId(new CustomEvent(`mouseup`), 'firstName'); + await service.clearFilterByColumnId(newEvent, 'firstName'); const filterCountAfter = Object.keys(service.getColumnFilters()).length; expect(pubSubSpy).toHaveBeenCalledWith(`onBeforeFilterClear`, { columnId: 'firstName' }, 0); @@ -1210,7 +1210,7 @@ describe('FilterService', () => { gridOptionMock.enableTreeData = false; gridOptionMock.backendServiceApi = undefined; mockColumn1 = { id: 'firstName', name: 'firstName', field: 'firstName', filterable: true, filter: { model: Filters.inputText } }; - mockColumn2 = { id: 'isActive', name: 'isActive', field: 'isActive', type: FieldType.boolean, filterable: true, filter: { model: Filters.select, collection: [{ value: true, label: 'True' }, { value: false, label: 'False' }], } }; + mockColumn2 = { id: 'isActive', name: 'isActive', field: 'isActive', type: FieldType.boolean, filterable: true, filter: { model: Filters.singleSelect, collection: [{ value: true, label: 'True' }, { value: false, label: 'False' }], } }; mockArgs1 = { grid: gridStub, column: mockColumn1, node: document.getElementById(DOM_ELEMENT_ID) }; mockArgs2 = { grid: gridStub, column: mockColumn2, node: document.getElementById(DOM_ELEMENT_ID) }; mockNewFilters = [ @@ -1674,7 +1674,7 @@ describe('FilterService', () => { gridOptionMock.enableTreeData = false; gridOptionMock.backendServiceApi = undefined; mockColumn1 = { id: 'firstName', name: 'firstName', field: 'firstName', filterable: true, filter: { model: Filters.inputText } }; - mockColumn2 = { id: 'isActive', name: 'isActive', field: 'isActive', type: FieldType.boolean, filterable: true, filter: { model: Filters.select, collection: [{ value: true, label: 'True' }, { value: false, label: 'False' }], } }; + mockColumn2 = { id: 'isActive', name: 'isActive', field: 'isActive', type: FieldType.boolean, filterable: true, filter: { model: Filters.singleSelect, collection: [{ value: true, label: 'True' }, { value: false, label: 'False' }], } }; mockColumn3 = { id: 'name', field: 'name', filterable: true, filter: { model: Filters.inputText } }; mockArgs1 = { grid: gridStub, column: mockColumn1, node: document.getElementById(DOM_ELEMENT_ID) }; mockArgs2 = { grid: gridStub, column: mockColumn2, node: document.getElementById(DOM_ELEMENT_ID) }; @@ -1835,7 +1835,7 @@ describe('FilterService', () => { gridOptionMock.enableFiltering = true; gridOptionMock.backendServiceApi = undefined; mockColumn1 = { id: 'file', name: 'file', field: 'file', filterable: true, filter: { model: Filters.inputText } }; - mockColumn2 = { id: 'dateModified', name: 'dateModified', field: 'dateModified', filterable: true, filter: { model: Filters.select, collection: [{ value: true, label: 'True' }, { value: false, label: 'False' }], } }; + mockColumn2 = { id: 'dateModified', name: 'dateModified', field: 'dateModified', filterable: true, filter: { model: Filters.singleSelect, collection: [{ value: true, label: 'True' }, { value: false, label: 'False' }], } }; mockColumn3 = { id: 'size', name: 'size', field: 'size', filterable: true, filter: { model: Filters.inputText } }; mockArgs1 = { grid: gridStub, column: mockColumn1, node: document.getElementById(DOM_ELEMENT_ID) }; mockArgs2 = { grid: gridStub, column: mockColumn2, node: document.getElementById(DOM_ELEMENT_ID) }; diff --git a/packages/common/src/services/__tests__/grid.service.spec.ts b/packages/common/src/services/__tests__/grid.service.spec.ts index 726843c6d..81d207bfa 100644 --- a/packages/common/src/services/__tests__/grid.service.spec.ts +++ b/packages/common/src/services/__tests__/grid.service.spec.ts @@ -6,8 +6,6 @@ import { GridOption, CellArgs, Column, OnEventArgs } from '../../interfaces/inde import { SlickRowSelectionModel } from '../../extensions/slickRowSelectionModel'; import { type SlickDataView, SlickEvent, type SlickGrid } from '../../core/index'; -jest.mock('flatpickr', () => { }); - const mockRowSelectionModel = { constructor: jest.fn(), init: jest.fn(), @@ -23,7 +21,6 @@ const mockRowSelectionModel = { jest.mock('../../extensions/slickRowSelectionModel', () => ({ SlickRowSelectionModel: jest.fn().mockImplementation(() => mockRowSelectionModel), })); -jest.mock('flatpickr', () => { }); const filterServiceStub = { clearFilters: jest.fn(), diff --git a/packages/common/src/services/__tests__/groupingAndColspan.service.spec.ts b/packages/common/src/services/__tests__/groupingAndColspan.service.spec.ts index 21ade981c..d688ff068 100644 --- a/packages/common/src/services/__tests__/groupingAndColspan.service.spec.ts +++ b/packages/common/src/services/__tests__/groupingAndColspan.service.spec.ts @@ -76,7 +76,7 @@ const template =
-
+
All your colums div here
diff --git a/packages/common/src/services/__tests__/shared.service.spec.ts b/packages/common/src/services/__tests__/shared.service.spec.ts index 894b7d0f4..8449557d0 100644 --- a/packages/common/src/services/__tests__/shared.service.spec.ts +++ b/packages/common/src/services/__tests__/shared.service.spec.ts @@ -6,8 +6,6 @@ import { ExcelExportService } from '../excelExport.service'; import type { SlickDataView, SlickGrid } from '../../core'; import { SlickGroupItemMetadataProvider } from '../../extensions'; -jest.mock('flatpickr', () => { }); - const dataviewStub = { onRowCountChanged: jest.fn(), onRowsChanged: jest.fn(), diff --git a/packages/common/src/services/__tests__/sort.service.spec.ts b/packages/common/src/services/__tests__/sort.service.spec.ts index cb6b98d85..01aa0753d 100644 --- a/packages/common/src/services/__tests__/sort.service.spec.ts +++ b/packages/common/src/services/__tests__/sort.service.spec.ts @@ -33,7 +33,7 @@ const gridOptionMock = { command: 'clear-sorting', disabled: false, hidden: true, - iconCssClass: 'fa fa-unsorted mdi mdi-swap-vertical', + iconCssClass: 'mdi mdi-sort-variant-off', positionOrder: 51, title: 'Clear all Sorting' }] @@ -139,7 +139,7 @@ describe('SortService', () => { const backendSortSpy = jest.spyOn(service, 'onBackendSortChanged'); const setSortSpy = jest.spyOn(gridStub, 'setSortColumns'); - const mockMouseEvent = new Event('mouseup'); + const mockMouseEvent = new SlickEventData(new Event('mouseup')); service.bindBackendOnSort(gridStub); service.clearSortByColumnId(mockMouseEvent, 'firstName'); @@ -155,7 +155,7 @@ describe('SortService', () => { const emitSortChangedSpy = jest.spyOn(service, 'emitSortChanged'); const setSortSpy = jest.spyOn(gridStub, 'setSortColumns'); - const mockMouseEvent = new Event('mouseup'); + const mockMouseEvent = new SlickEventData(new Event('mouseup')); service.bindLocalOnSort(gridStub); service.clearSortByColumnId(mockMouseEvent, 'firstName'); @@ -175,7 +175,7 @@ describe('SortService', () => { const emitSortChangedSpy = jest.spyOn(service, 'emitSortChanged'); const setSortSpy = jest.spyOn(gridStub, 'setSortColumns'); - const mockMouseEvent = new Event('mouseup'); + const mockMouseEvent = new SlickEventData(new Event('mouseup')); service.bindLocalOnSort(gridStub); service.clearSortByColumnId(mockMouseEvent, 'lastName'); @@ -195,7 +195,7 @@ describe('SortService', () => { const gridSortSpy = jest.spyOn(gridStub.onSort, 'notify'); gridStub.getData = () => null as any; // fake a custom dataview by removing the dataView in shared - const mockMouseEvent = new Event('mouseup'); + const mockMouseEvent = new SlickEventData(new Event('mouseup')); service.bindLocalOnSort(gridStub); service.clearSortByColumnId(mockMouseEvent, 'firstName'); @@ -213,7 +213,7 @@ describe('SortService', () => { const sortDefaultSpy = jest.spyOn(service, 'sortLocalGridByDefaultSortFieldId'); const setSortSpy = jest.spyOn(gridStub, 'setSortColumns'); - const mockMouseEvent = new Event('mouseup'); + const mockMouseEvent = new SlickEventData(new Event('mouseup')); service.bindLocalOnSort(gridStub); service.clearSortByColumnId(mockMouseEvent, 'firstName'); @@ -238,7 +238,7 @@ describe('SortService', () => { const sortDefaultSpy = jest.spyOn(service, 'sortLocalGridByDefaultSortFieldId'); const setSortSpy = jest.spyOn(gridStub, 'setSortColumns'); - const mockMouseEvent = new Event('mouseup'); + const mockMouseEvent = new SlickEventData(new Event('mouseup')); service.bindLocalOnSort(gridStub); service.clearSortByColumnId(mockMouseEvent, 'firstName'); diff --git a/packages/common/src/services/__tests__/utilities.spec.ts b/packages/common/src/services/__tests__/utilities.spec.ts index 168650609..10139ebe1 100644 --- a/packages/common/src/services/__tests__/utilities.spec.ts +++ b/packages/common/src/services/__tests__/utilities.spec.ts @@ -21,12 +21,9 @@ import { getDescendantProperty, getTranslationPrefix, isColumnDateType, - mapMomentDateFormatWithFieldType, - mapFlatpickrDateFormatWithFieldType, mapOperatorByFieldType, mapOperatorToShorthandDesignation, mapOperatorType, - parseUtcDate, thousandSeparatorFormatted, unsubscribeAll, } from '../utilities'; @@ -709,233 +706,6 @@ describe('Service/Utilies', () => { }); }); - describe('mapMomentDateFormatWithFieldType method', () => { - it('should return a moment.js dateTime/dateTimeIso format', () => { - const output1 = mapMomentDateFormatWithFieldType(FieldType.dateTime); - const output2 = mapMomentDateFormatWithFieldType(FieldType.dateTimeIso); - expect(output1).toBe('YYYY-MM-DD HH:mm:ss'); - expect(output2).toBe('YYYY-MM-DD HH:mm:ss'); - }); - - it('should return a moment.js dateTimeShortIso format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateTimeShortIso); - expect(output).toBe('YYYY-MM-DD HH:mm'); - }); - - it('should return a moment.js dateTimeIsoAmPm format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateTimeIsoAmPm); - expect(output).toBe('YYYY-MM-DD hh:mm:ss a'); - }); - - it('should return a moment.js dateTimeIsoAM_PM format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateTimeIsoAM_PM); - expect(output).toBe('YYYY-MM-DD hh:mm:ss A'); - }); - - it('should return a moment.js dateEuro format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateEuro); - expect(output).toBe('DD/MM/YYYY'); - }); - - it('should return a moment.js dateEuroShort format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateEuroShort); - expect(output).toBe('D/M/YY'); - }); - - it('should return a moment.js dateTimeEuro format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateTimeEuro); - expect(output).toBe('DD/MM/YYYY HH:mm:ss'); - }); - - it('should return a moment.js dateTimeShortEuro format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateTimeShortEuro); - expect(output).toBe('DD/MM/YYYY HH:mm'); - }); - - it('should return a moment.js dateTimeEuroAmPm format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateTimeEuroAmPm); - expect(output).toBe('DD/MM/YYYY hh:mm:ss a'); - }); - - it('should return a moment.js dateTimeEuroAM_PM format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateTimeEuroAM_PM); - expect(output).toBe('DD/MM/YYYY hh:mm:ss A'); - }); - - it('should return a moment.js dateTimeEuroShort format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateTimeEuroShort); - expect(output).toBe('D/M/YY H:m:s'); - }); - - it('should return a moment.js dateTimeEuroShortAmPm format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateTimeEuroShortAmPm); - expect(output).toBe('D/M/YY h:m:s a'); - }); - - it('should return a moment.js dateUs format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateUs); - expect(output).toBe('MM/DD/YYYY'); - }); - - it('should return a moment.js dateUsShort format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateUsShort); - expect(output).toBe('M/D/YY'); - }); - - it('should return a moment.js dateTimeUs format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateTimeUs); - expect(output).toBe('MM/DD/YYYY HH:mm:ss'); - }); - - it('should return a moment.js dateTimeShortUs format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateTimeShortUs); - expect(output).toBe('MM/DD/YYYY HH:mm'); - }); - - it('should return a moment.js dateTimeUsAmPm format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateTimeUsAmPm); - expect(output).toBe('MM/DD/YYYY hh:mm:ss a'); - }); - - it('should return a moment.js dateTimeUsAM_PM format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateTimeUsAM_PM); - expect(output).toBe('MM/DD/YYYY hh:mm:ss A'); - }); - - it('should return a moment.js dateTimeUsShort format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateTimeUsShort); - expect(output).toBe('M/D/YY H:m:s'); - }); - - it('should return a moment.js dateTimeUsShortAmPm format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateTimeUsShortAmPm); - expect(output).toBe('M/D/YY h:m:s a'); - }); - - it('should return a moment.js dateUtc format', () => { - const output = mapMomentDateFormatWithFieldType(FieldType.dateUtc); - expect(output).toBe('YYYY-MM-DDTHH:mm:ss.SSSZ'); - }); - - it('should return a moment.js date/dateIso format', () => { - const output1 = mapMomentDateFormatWithFieldType(FieldType.date); - const output2 = mapMomentDateFormatWithFieldType(FieldType.dateIso); - expect(output1).toBe('YYYY-MM-DD'); - expect(output2).toBe('YYYY-MM-DD'); - }); - }); - - describe('mapFlatpickrDateFormatWithFieldType method', () => { - it('should return a Flatpickr dateTime format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateTime); - expect(output).toBe('Y-m-d H:i:S'); - }); - - it('should return a Flatpickr dateTimeShortIso format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateTimeShortIso); - expect(output).toBe('Y-m-d H:i'); - }); - - it('should return a Flatpickr dateTimeIsoAmPm/dateTimeIsoAM_PM format', () => { - const output1 = mapFlatpickrDateFormatWithFieldType(FieldType.dateTimeIsoAmPm); - const output2 = mapFlatpickrDateFormatWithFieldType(FieldType.dateTimeIsoAM_PM); - expect(output1).toBe('Y-m-d h:i:S K'); - expect(output2).toBe('Y-m-d h:i:S K'); - }); - - it('should return a Flatpickr dateEuro format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateEuro); - expect(output).toBe('d/m/Y'); - }); - - it('should return a Flatpickr dateEuroShort format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateEuroShort); - expect(output).toBe('d/m/y'); - }); - - it('should return a Flatpickr dateTimeEuro format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateTimeEuro); - expect(output).toBe('d/m/Y H:i:S'); - }); - - it('should return a Flatpickr dateTimeShortEuro format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateTimeShortEuro); - expect(output).toBe('d/m/y H:i'); - }); - - it('should return a Flatpickr dateTimeEuroAmPm format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateTimeEuroAmPm); - expect(output).toBe('d/m/Y h:i:S K'); - }); - - it('should return a Flatpickr dateTimeEuroAM_PM format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateTimeEuroAM_PM); - expect(output).toBe('d/m/Y h:i:s K'); - }); - - it('should return a Flatpickr dateTimeEuroShort format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateTimeEuroShort); - expect(output).toBe('d/m/y H:i:s'); - }); - - it('should return a Flatpickr dateTimeEuroShortAmPm format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateTimeEuroShortAmPm); - expect(output).toBe('d/m/y h:i:s K'); - }); - - it('should return a Flatpickr dateUs format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateUs); - expect(output).toBe('m/d/Y'); - }); - - it('should return a Flatpickr dateUsShort format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateUsShort); - expect(output).toBe('m/d/y'); - }); - - it('should return a Flatpickr dateTimeUs format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateTimeUs); - expect(output).toBe('m/d/Y H:i:S'); - }); - - it('should return a Flatpickr dateTimeShortUs format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateTimeShortUs); - expect(output).toBe('m/d/y H:i'); - }); - - it('should return a Flatpickr dateTimeUsAmPm format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateTimeUsAmPm); - expect(output).toBe('m/d/Y h:i:S K'); - }); - - it('should return a Flatpickr dateTimeUsAM_PM format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateTimeUsAM_PM); - expect(output).toBe('m/d/Y h:i:s K'); - }); - - it('should return a Flatpickr dateTimeUsShort format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateTimeUsShort); - expect(output).toBe('m/d/y H:i:s'); - }); - - it('should return a Flatpickr dateTimeUsShortAmPm format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateTimeUsShortAmPm); - expect(output).toBe('m/d/y h:i:s K'); - }); - - it('should return a Flatpickr dateUtc format', () => { - const output = mapFlatpickrDateFormatWithFieldType(FieldType.dateUtc); - expect(output).toBe('Z'); - }); - - it('should return a Flatpickr dateédateIso format', () => { - const output1 = mapFlatpickrDateFormatWithFieldType(FieldType.date); - const output2 = mapFlatpickrDateFormatWithFieldType(FieldType.dateIso); - expect(output1).toBe('Y-m-d'); - expect(output2).toBe('Y-m-d'); - }); - }); - describe('mapOperatorType method', () => { it('should return OperatoryType associated to "<"', () => { const expectation = OperatorType.lessThan; @@ -1233,25 +1003,6 @@ describe('Service/Utilies', () => { }); }); - describe('parseUtcDate method', () => { - it('should return null when date provided is not an ISO date (date only accepted)', () => { - const input1 = '2012-01-01 02:02:02'; - const input2 = '2012-01-01T02:02:02Z'; - - const output1 = parseUtcDate(input1); - const output2 = parseUtcDate(input2); - - expect(output1).toBe(''); - expect(output2).toBe(''); - }); - - it('should return a date parsed as UTC when input is a date (without time) of ISO format', () => { - const input = '2012-01-01'; - const output = parseUtcDate(input, true); - expect(output).toBe('2012-01-01T00:00:00Z'); - }); - }); - describe('thousandSeparatorFormatted method', () => { it('should return original value when input provided is null', () => { const input = null as any; diff --git a/packages/common/src/services/dateUtils.ts b/packages/common/src/services/dateUtils.ts new file mode 100644 index 000000000..f70a411ac --- /dev/null +++ b/packages/common/src/services/dateUtils.ts @@ -0,0 +1,189 @@ +import { format, offset, parse, removeOffset, tzDate } from '@formkit/tempo'; + +import { FieldType } from '../enums/index'; + +/** + * From a Date FieldType, return it's equivalent TempoJS format, + * refer to TempoJS docs for the format tokens being used: https://tempo.formkit.com/#format + * @param fieldType + * @param withZeroPadding - should we include zero padding in format (e.g.: 03:04:54) + */ +export function mapTempoDateFormatWithFieldType(fieldType: typeof FieldType[keyof typeof FieldType], withZeroPadding = false): string { + let map: string; + switch (fieldType) { + case FieldType.dateTime: + case FieldType.dateTimeIso: + map = 'YYYY-MM-DD HH:mm:ss'; + break; + case FieldType.dateTimeIsoAmPm: + map = 'YYYY-MM-DD hh:mm:ss a'; + break; + case FieldType.dateTimeIsoAM_PM: + map = 'YYYY-MM-DD hh:mm:ss A'; + break; + case FieldType.dateTimeShortIso: + map = 'YYYY-MM-DD HH:mm'; + break; + // all Euro Formats (date/month/year) + case FieldType.dateEuro: + map = 'DD/MM/YYYY'; + break; + case FieldType.dateEuroShort: + map = withZeroPadding + ? 'DD/MM/YY' + : 'D/M/YY'; + break; + case FieldType.dateTimeEuro: + map = 'DD/MM/YYYY HH:mm:ss'; + break; + case FieldType.dateTimeShortEuro: + map = withZeroPadding + ? 'DD/MM/YYYY HH:mm' + : 'D/M/YYYY H:m'; + break; + case FieldType.dateTimeEuroAmPm: + map = 'DD/MM/YYYY hh:mm:ss a'; + break; + case FieldType.dateTimeEuroAM_PM: + map = 'DD/MM/YYYY hh:mm:ss A'; + break; + case FieldType.dateTimeEuroShort: + map = withZeroPadding + ? 'DD/MM/YY HH:mm:ss' + : 'D/M/YY H:m:s'; + break; + case FieldType.dateTimeEuroShortAmPm: + map = withZeroPadding + ? 'DD/MM/YY hh:mm:ss a' + : 'D/M/YY h:m:s a'; + break; + case FieldType.dateTimeEuroShortAM_PM: + map = withZeroPadding + ? 'DD/MM/YY hh:mm:ss A' + : 'D/M/YY h:m:s A'; + break; + // all US Formats (month/date/year) + case FieldType.dateUs: + map = 'MM/DD/YYYY'; + break; + case FieldType.dateUsShort: + map = withZeroPadding + ? 'MM/DD/YY' + : 'M/D/YY'; + break; + case FieldType.dateTimeUs: + map = 'MM/DD/YYYY HH:mm:ss'; + break; + case FieldType.dateTimeUsAmPm: + map = 'MM/DD/YYYY hh:mm:ss a'; + break; + case FieldType.dateTimeUsAM_PM: + map = 'MM/DD/YYYY hh:mm:ss A'; + break; + case FieldType.dateTimeUsShort: + map = withZeroPadding + ? 'MM/DD/YY HH:mm:ss' + : 'M/D/YY H:m:s'; + break; + case FieldType.dateTimeUsShortAmPm: + map = withZeroPadding + ? 'MM/DD/YY hh:mm:ss a' + : 'M/D/YY h:m:s a'; + break; + case FieldType.dateTimeUsShortAM_PM: + map = withZeroPadding + ? 'MM/DD/YY hh:mm:ss A' + : 'M/D/YY h:m:s A'; + break; + case FieldType.dateTimeShortUs: + map = withZeroPadding + ? 'MM/DD/YYYY HH:mm' + : 'M/D/YYYY H:m'; + break; + case FieldType.dateUtc: + map = 'ISO8601'; + break; + case FieldType.date: + case FieldType.dateIso: + default: + map = 'YYYY-MM-DD'; + break; + } + return map; +} + +/** + * Format a date using Tempo and a defined input/output field types + * @param {string|Date} inputDate + * @param {FieldType} inputFieldType + * @param {FieldType} outputFieldType + * @returns + */ +export function formatDateByFieldType(inputDate: Date | string, inputFieldType: typeof FieldType[keyof typeof FieldType] | undefined, outputFieldType: typeof FieldType[keyof typeof FieldType]): string { + const inputFormat = inputFieldType ? mapTempoDateFormatWithFieldType(inputFieldType) : undefined; + const outputFormat = mapTempoDateFormatWithFieldType(outputFieldType); + const date = inputDate instanceof Date ? inputDate : tryParseDate(inputDate, inputFormat as string); + + if (date && inputDate !== undefined) { + if (outputFieldType === FieldType.dateUtc) { + return date.toISOString(); + } + return format(date, outputFormat, 'en-US'); + } + return ''; +} + +/** + * Try to parse date with Tempo or return `false` (instead of throwing) if Date is invalid. + * When using strict mode, it will detect if the date is invalid when outside of the calendar (e.g. "2011-11-31"). + * However in non-strict mode, it will roll the date backward if out of calendar (e.g. "2011-11-31" would return "2011-11-30"). + * @param {string|Date} [inputDate] - input date (or null) + * @param {string} [inputFormat] - optional input format to use when parsing + * @param {Boolean} [strict] - are we using strict mode? + * @returns + */ +export function tryParseDate(inputDate?: string | Date, inputFormat?: string, strict = false): Date | false { + try { + if (!inputDate) { + return false; + } + return inputDate instanceof Date ? inputDate : parse({ + date: inputDate, + format: inputFormat as string, + dateOverflow: strict ? 'throw' : 'backward', + locale: 'en-US' + }); + } catch (_e) { + return false; + } +} + +/** + * Parse a Date as a UTC date (without local TZ offset) + * @param inputDate + * @returns + */ +export function toUtcDate(inputDate: string | Date) { + // to parse as UTC in Tempo, we need to remove the offset (which is a simple inversed offset to cancel itself) + return removeOffset(inputDate, offset(inputDate, 'utc')); +}; + +/** + * Parse a date passed as a string (Date only, without time) and return a TZ Date (without milliseconds) + * @param inputDateString + * @returns TZ UTC date formatted + */ +export function parseUtcDate(inputDateString: string): string { + let outputFormattedDate = ''; + + if (typeof inputDateString === 'string' && /^[0-9\-/]*$/.test(inputDateString)) { + // get the UTC datetime but make sure to decode the value so that it's valid text + const dateString = decodeURIComponent(inputDateString); + const date = tzDate(dateString, 'utc'); + if (date) { + outputFormattedDate = date.toISOString().replace(/(.*)([.\d]{4})(Z)/gi, '$1$3'); + } + } + + return outputFormattedDate; +} \ No newline at end of file diff --git a/packages/common/src/services/domUtilities.ts b/packages/common/src/services/domUtilities.ts index 3c9b3672f..738937f82 100644 --- a/packages/common/src/services/domUtilities.ts +++ b/packages/common/src/services/domUtilities.ts @@ -1,9 +1,8 @@ import { createDomElement } from '@slickgrid-universal/utils'; import type { OptionRowData } from 'multiple-select-vanilla'; -import DOMPurify from 'isomorphic-dompurify'; import type { SearchTerm } from '../enums/index'; -import type { Column, GridOption, SelectOption } from '../interfaces/index'; +import type { Column, SelectOption } from '../interfaces/index'; import type { SlickGrid } from '../core/index'; import type { TranslaterService } from './translater.service'; @@ -27,7 +26,6 @@ export function buildMsSelectCollectionList(type: 'editor' | 'filter', collectio const enableTranslateLabel = columnFilterOrEditor?.enableTranslateLabel ?? false; const isTranslateEnabled = gridOptions?.enableTranslate ?? false; const isRenderHtmlEnabled = columnFilterOrEditor?.enableRenderHtml ?? false; - const sanitizedOptions = gridOptions?.sanitizerOptions ?? {}; const labelName = columnFilterOrEditor?.customStructure?.label ?? 'label'; const labelPrefixName = columnFilterOrEditor?.customStructure?.labelPrefix ?? 'labelPrefix'; const labelSuffixName = columnFilterOrEditor?.customStructure?.labelSuffix ?? 'labelSuffix'; @@ -89,7 +87,7 @@ export function buildMsSelectCollectionList(type: 'editor' | 'filter', collectio if (isRenderHtmlEnabled) { // sanitize any unauthorized html tags like script and others // for the remaining allowed tags we'll permit all attributes - optionText = sanitizeTextByAvailableSanitizer(gridOptions, optionText, sanitizedOptions); + optionText = grid.sanitizeHtmlString(optionText); } selectOption.text = optionText; @@ -116,22 +114,3 @@ export function buildMsSelectCollectionList(type: 'editor' | 'filter', collectio return { selectElement, dataCollection, hasFoundSearchTerm }; } - -/** - * Sanitize possible dirty html string (remove any potential XSS code like scripts and others), we will use 2 possible sanitizer - * 1. optional sanitizer method defined in the grid options - * 2. DOMPurify sanitizer (defaults) - * @param gridOptions: grid options - * @param dirtyHtml: dirty html string - * @param sanitizerOptions: optional DOMPurify options when using that sanitizer - */ -export function sanitizeTextByAvailableSanitizer(gridOptions: GridOption, dirtyHtml: string, sanitizerOptions?: DOMPurify.Config): string { - let sanitizedText = dirtyHtml; - if (typeof gridOptions?.sanitizer === 'function') { - sanitizedText = gridOptions.sanitizer(dirtyHtml || ''); - } else if (typeof DOMPurify?.sanitize === 'function') { - sanitizedText = (DOMPurify.sanitize(dirtyHtml || '', sanitizerOptions || { ADD_ATTR: ['level'], RETURN_TRUSTED_TYPE: true }) || '').toString(); - } - - return sanitizedText; -} diff --git a/packages/common/src/services/filter.service.ts b/packages/common/src/services/filter.service.ts index 159701e05..297823895 100644 --- a/packages/common/src/services/filter.service.ts +++ b/packages/common/src/services/filter.service.ts @@ -1,5 +1,5 @@ import { type BasePubSubService } from '@slickgrid-universal/event-pub-sub'; -import { deepCopy, extend, stripTags } from '@slickgrid-universal/utils'; +import { extend, stripTags } from '@slickgrid-universal/utils'; import { dequal } from 'dequal/lite'; import { Constants } from '../constants'; @@ -393,7 +393,7 @@ export class FilterService { /** * Loop through each form input search filter and parse their searchTerms, - * for example a CompoundDate Filter will be parsed as a Moment object. + * for example a CompoundDate Filter will be parsed as a Date object. * Also if we are dealing with a text filter input, * an operator can optionally be part of the filter itself and we need to extract it from there, * for example a filter of "John*" will be analyzed as { operator: StartsWith, searchTerms: ['John'] } @@ -402,7 +402,7 @@ export class FilterService { * @returns FilterConditionOption */ parseFormInputFilterConditions(inputSearchTerms: SearchTerm[] | undefined, columnFilter: Omit): Omit { - const searchValues: SearchTerm[] = deepCopy(inputSearchTerms) || []; + const searchValues: SearchTerm[] = extend(true, [], inputSearchTerms) || []; let fieldSearchValue = (Array.isArray(searchValues) && searchValues.length === 1) ? searchValues[0] : ''; const columnDef = columnFilter.columnDef; const fieldType = columnDef.filter?.type ?? columnDef.type ?? FieldType.string; @@ -570,13 +570,13 @@ export class FilterService { delete (treeObj as any)[inputItem[primaryDataId]].__used; }); - // Step 1. prepare search filter by getting their parsed value(s), for example if it's a date filter then parse it to a Moment object + // Step 1. prepare search filter by getting their parsed value(s), for example if it's a date filter then parse it to a Date object // loop through all column filters once and get parsed filter search value then save a reference in the columnFilter itself // it is much more effective to do it outside and prior to Step 2 so that we don't re-parse search filter for no reason while checking every row if (typeof columnFilters === 'object') { Object.keys(columnFilters).forEach(columnId => { const columnFilter = columnFilters[columnId] as SearchColumnFilter; - const searchValues: SearchTerm[] = columnFilter?.searchTerms ? deepCopy(columnFilter.searchTerms) : []; + const searchValues: SearchTerm[] = columnFilter?.searchTerms ? extend(true, [], columnFilter.searchTerms) : []; const inputSearchConditions = this.parseFormInputFilterConditions(searchValues, columnFilter); const columnDef = columnFilter.columnDef; diff --git a/packages/common/src/services/groupingAndColspan.service.ts b/packages/common/src/services/groupingAndColspan.service.ts index 64ea6f0be..37bcdf50d 100644 --- a/packages/common/src/services/groupingAndColspan.service.ts +++ b/packages/common/src/services/groupingAndColspan.service.ts @@ -145,7 +145,7 @@ export class GroupingAndColspanService { } else { widthTotal = colDef.width || 0; headerElm = createDomElement('div', { - className: `ui-state-default slick-header-column ${isFrozenGrid ? 'frozen' : ''}`, + className: `slick-state-default slick-header-column ${isFrozenGrid ? 'frozen' : ''}`, style: { width: `${widthTotal - headerColumnWidthDiff}px` } }); diff --git a/packages/common/src/services/index.ts b/packages/common/src/services/index.ts index dd3701f89..9d1ed0024 100644 --- a/packages/common/src/services/index.ts +++ b/packages/common/src/services/index.ts @@ -1,6 +1,7 @@ export * from './backendUtility.service'; export * from './collection.service'; export * from './container.service'; +export * from './dateUtils'; export * from './domUtilities'; export * from './excelExport.service'; export * from './extension.service'; diff --git a/packages/common/src/services/utilities.ts b/packages/common/src/services/utilities.ts index 6b97af9b1..d26b97a86 100644 --- a/packages/common/src/services/utilities.ts +++ b/packages/common/src/services/utilities.ts @@ -1,7 +1,5 @@ import type { EventSubscription } from '@slickgrid-universal/event-pub-sub'; import { flatten } from 'un-flatten-tree'; -import * as moment_ from 'moment-mini'; -const moment = (moment_ as any)['default'] || moment_; import { Constants } from '../constants'; import { FieldType, type OperatorString, OperatorType } from '../enums/index'; @@ -400,198 +398,6 @@ export function isColumnDateType(fieldType: typeof FieldType[keyof typeof FieldT } } -/** - * From a Date FieldType, return it's equivalent moment.js format - * refer to moment.js for the format standard used: https://momentjs.com/docs/#/parsing/string-format/ - * @param fieldType - */ -export function mapMomentDateFormatWithFieldType(fieldType: typeof FieldType[keyof typeof FieldType]): string { - let map: string; - switch (fieldType) { - case FieldType.dateTime: - case FieldType.dateTimeIso: - map = 'YYYY-MM-DD HH:mm:ss'; - break; - case FieldType.dateTimeIsoAmPm: - map = 'YYYY-MM-DD hh:mm:ss a'; - break; - case FieldType.dateTimeIsoAM_PM: - map = 'YYYY-MM-DD hh:mm:ss A'; - break; - case FieldType.dateTimeShortIso: - map = 'YYYY-MM-DD HH:mm'; - break; - // all Euro Formats (date/month/year) - case FieldType.dateEuro: - map = 'DD/MM/YYYY'; - break; - case FieldType.dateEuroShort: - map = 'D/M/YY'; - break; - case FieldType.dateTimeEuro: - map = 'DD/MM/YYYY HH:mm:ss'; - break; - case FieldType.dateTimeShortEuro: - map = 'DD/MM/YYYY HH:mm'; - break; - case FieldType.dateTimeEuroAmPm: - map = 'DD/MM/YYYY hh:mm:ss a'; - break; - case FieldType.dateTimeEuroAM_PM: - map = 'DD/MM/YYYY hh:mm:ss A'; - break; - case FieldType.dateTimeEuroShort: - map = 'D/M/YY H:m:s'; - break; - case FieldType.dateTimeEuroShortAmPm: - map = 'D/M/YY h:m:s a'; - break; - case FieldType.dateTimeEuroShortAM_PM: - map = 'D/M/YY h:m:s A'; - break; - // all US Formats (month/date/year) - case FieldType.dateUs: - map = 'MM/DD/YYYY'; - break; - case FieldType.dateUsShort: - map = 'M/D/YY'; - break; - case FieldType.dateTimeUs: - map = 'MM/DD/YYYY HH:mm:ss'; - break; - case FieldType.dateTimeUsAmPm: - map = 'MM/DD/YYYY hh:mm:ss a'; - break; - case FieldType.dateTimeUsAM_PM: - map = 'MM/DD/YYYY hh:mm:ss A'; - break; - case FieldType.dateTimeUsShort: - map = 'M/D/YY H:m:s'; - break; - case FieldType.dateTimeUsShortAmPm: - map = 'M/D/YY h:m:s a'; - break; - case FieldType.dateTimeUsShortAM_PM: - map = 'M/D/YY h:m:s A'; - break; - case FieldType.dateTimeShortUs: - map = 'MM/DD/YYYY HH:mm'; - break; - case FieldType.dateUtc: - map = 'YYYY-MM-DDTHH:mm:ss.SSSZ'; - break; - case FieldType.date: - case FieldType.dateIso: - default: - map = 'YYYY-MM-DD'; - break; - } - return map; -} - -/** - * From a Date FieldType, return it's equivalent Flatpickr format - * refer to Flatpickr for the format standard used: https://chmln.github.io/flatpickr/formatting/#date-formatting-tokens - * also note that they seem very similar to PHP format (except for am/pm): http://php.net/manual/en/function.date.php - * @param fieldType - */ -export function mapFlatpickrDateFormatWithFieldType(fieldType: typeof FieldType[keyof typeof FieldType]): string { - /* - d: Day of the month, 2 digits with leading zeros 01 to 31 - D: A textual representation of a day Mon through Sun - l: (lowercase 'L') A full textual representation of the day of the week Sunday through Saturday - j: Day of the month without leading zeros 1 to 31 - J: Day of the month without leading zeros and ordinal suffix 1st, 2nd, to 31st - w: Numeric representation of the day of the week 0 (for Sunday) through 6 (for Saturday) - F: A full textual representation of a month January through December - m: Numeric representation of a month, with leading zero 01 through 12 - n: Numeric representation of a month, without leading zeros 1 through 12 - M: A short textual representation of a month Jan through Dec - U: The number of seconds since the Unix Epoch 1413704993 - y: A two digit representation of a year 99 or 03 - Y: A full numeric representation of a year, 4 digits 1999 or 2003 - H: Hours (24 hours) 00 to 23 - h: Hours 1 to 12 - i: Minutes 00 to 59 - S: Seconds, 2 digits 00 to 59 - s: Seconds 0, 1 to 59 - K: AM/PM AM or PM - */ - let map: string; - switch (fieldType) { - case FieldType.dateTime: - case FieldType.dateTimeIso: - map = 'Y-m-d H:i:S'; - break; - case FieldType.dateTimeShortIso: - map = 'Y-m-d H:i'; - break; - case FieldType.dateTimeIsoAmPm: - case FieldType.dateTimeIsoAM_PM: - map = 'Y-m-d h:i:S K'; // there is no lowercase in Flatpickr :( - break; - // all Euro Formats (date/month/year) - case FieldType.dateEuro: - map = 'd/m/Y'; - break; - case FieldType.dateEuroShort: - map = 'd/m/y'; - break; - case FieldType.dateTimeEuro: - map = 'd/m/Y H:i:S'; - break; - case FieldType.dateTimeShortEuro: - map = 'd/m/y H:i'; - break; - case FieldType.dateTimeEuroAmPm: - map = 'd/m/Y h:i:S K'; // there is no lowercase in Flatpickr :( - break; - case FieldType.dateTimeEuroAM_PM: - map = 'd/m/Y h:i:s K'; - break; - case FieldType.dateTimeEuroShort: - map = 'd/m/y H:i:s'; - break; - case FieldType.dateTimeEuroShortAmPm: - map = 'd/m/y h:i:s K'; // there is no lowercase in Flatpickr :( - break; - // all US Formats (month/date/year) - case FieldType.dateUs: - map = 'm/d/Y'; - break; - case FieldType.dateUsShort: - map = 'm/d/y'; - break; - case FieldType.dateTimeUs: - map = 'm/d/Y H:i:S'; - break; - case FieldType.dateTimeShortUs: - map = 'm/d/y H:i'; - break; - case FieldType.dateTimeUsAmPm: - map = 'm/d/Y h:i:S K'; // there is no lowercase in Flatpickr :( - break; - case FieldType.dateTimeUsAM_PM: - map = 'm/d/Y h:i:s K'; - break; - case FieldType.dateTimeUsShort: - map = 'm/d/y H:i:s'; - break; - case FieldType.dateTimeUsShortAmPm: - map = 'm/d/y h:i:s K'; // there is no lowercase in Flatpickr :( - break; - case FieldType.dateUtc: - map = 'Z'; - break; - case FieldType.date: - case FieldType.dateIso: - default: - map = 'Y-m-d'; - break; - } - return map; -} - /** * Mapper for query operators (ex.: <= is "le", > is "gt") * @param string operator @@ -756,26 +562,6 @@ export function objectWithoutKey(obj: T, omitKey: keyof T): T { }, {}) as unknown as T; } -/** - * Parse a date passed as a string (Date only, without time) and return a Date object (if valid) - * @param inputDateString - * @returns string date formatted - */ -export function parseUtcDate(inputDateString: any, useUtc?: boolean): string { - let date = ''; - - if (typeof inputDateString === 'string' && /^[0-9\-/]*$/.test(inputDateString)) { - // get the UTC datetime with moment.js but we need to decode the value so that it's valid text - const dateString = decodeURIComponent(inputDateString); - const dateMoment = moment(new Date(dateString)); - if (dateMoment.isValid() && dateMoment.year().toString().length === 4) { - date = (useUtc) ? dateMoment.utc().format() : dateMoment.format(); - } - } - - return date; -} - /** * Format a number or a string into a string that is separated every thousand, * the default separator is a comma but user can optionally pass a different one diff --git a/packages/common/src/sortComparers/__tests__/dateEuroShortSortComparer.spec.ts b/packages/common/src/sortComparers/__tests__/dateEuroShortSortComparer.spec.ts index 918e21bce..55eea91ee 100644 --- a/packages/common/src/sortComparers/__tests__/dateEuroShortSortComparer.spec.ts +++ b/packages/common/src/sortComparers/__tests__/dateEuroShortSortComparer.spec.ts @@ -4,30 +4,30 @@ import { FieldType, SortDirectionNumber } from '../../enums/index'; describe('the Date Euro Short Sorter', () => { it('should return an array of dates sorted ascending when only valid dates are provided', () => { const direction = SortDirectionNumber.asc; - const inputArray = ['8/8/98', '8/10/98', '8/8/98', '01/01/18', '14/12/98']; + const inputArray = ['8/8/98', '8/10/98', '8/8/98', '1/1/18', '14/12/98']; inputArray.sort((value1, value2) => sortByFieldType(FieldType.dateEuroShort, value1, value2, direction)); - expect(inputArray).toEqual(['8/8/98', '8/8/98', '8/10/98', '14/12/98', '01/01/18']); + expect(inputArray).toEqual(['8/8/98', '8/8/98', '8/10/98', '14/12/98', '1/1/18']); }); it('should return an array of dates sorted descending when only valid dates are provided', () => { const direction = SortDirectionNumber.desc; - const inputArray = ['8/8/98', '8/10/98', null, '8/8/98', '01/01/18', '14/12/98']; + const inputArray = ['8/8/98', '8/10/98', null, '8/8/98', '1/1/18', '14/12/98']; inputArray.sort((value1, value2) => sortByFieldType(FieldType.dateEuroShort, value1, value2, direction)); - expect(inputArray).toEqual(['01/01/18', '14/12/98', '8/10/98', '8/8/98', '8/8/98', null]); + expect(inputArray).toEqual(['1/1/18', '14/12/98', '8/10/98', '8/8/98', '8/8/98', null]); }); it(`should return an array with unsorted characters showing at the beginning then comes numbers sorted ascending when digits and chars are provided`, () => { const direction = SortDirectionNumber.asc; - const inputArray = ['8/10/98', 'y', '8/8/98', '01/01/18', '14/12/98']; + const inputArray = ['8/10/98', 'y', '8/8/98', '1/1/18', '14/12/98']; inputArray.sort((value1, value2) => sortByFieldType(FieldType.dateEuroShort, value1, value2, direction)); - expect(inputArray).toEqual(['y', '8/8/98', '8/10/98', '14/12/98', '01/01/18']); + expect(inputArray).toEqual(['y', '8/8/98', '8/10/98', '14/12/98', '1/1/18']); }); it(`should return an array with dates sorted descending showing at the beginning then characters`, () => { const direction = SortDirectionNumber.desc; - const inputArray = ['8/10/98', null, '8/8/98', '01/01/18', '14/12/98']; + const inputArray = ['8/10/98', null, '8/8/98', '1/1/18', '14/12/98']; inputArray.sort((value1, value2) => sortByFieldType(FieldType.dateEuroShort, value1, value2, direction)); - expect(inputArray).toEqual(['01/01/18', '14/12/98', '8/10/98', '8/8/98', null]); + expect(inputArray).toEqual(['1/1/18', '14/12/98', '8/10/98', '8/8/98', null]); }); }); diff --git a/packages/common/src/sortComparers/__tests__/dateUsShortSortComparer.spec.ts b/packages/common/src/sortComparers/__tests__/dateUsShortSortComparer.spec.ts index 420474326..64a00bf77 100644 --- a/packages/common/src/sortComparers/__tests__/dateUsShortSortComparer.spec.ts +++ b/packages/common/src/sortComparers/__tests__/dateUsShortSortComparer.spec.ts @@ -4,30 +4,30 @@ import { FieldType, SortDirectionNumber } from '../../enums/index'; describe('the Date US Short Sorter', () => { it('should return an array of US dates sorted ascending when only valid dates are provided', () => { const direction = SortDirectionNumber.asc; - const inputArray = ['8/8/98', '10/8/98', '8/8/98', '01/01/18', '12/14/98']; + const inputArray = ['8/8/98', '10/8/98', '8/8/98', '1/1/18', '12/14/98']; inputArray.sort((value1, value2) => sortByFieldType(FieldType.dateUsShort, value1, value2, direction)); - expect(inputArray).toEqual(['8/8/98', '8/8/98', '10/8/98', '12/14/98', '01/01/18']); + expect(inputArray).toEqual(['8/8/98', '8/8/98', '10/8/98', '12/14/98', '1/1/18']); }); it('should return an array of US dates sorted descending when only valid dates are provided', () => { const direction = SortDirectionNumber.desc; - const inputArray = ['8/8/98', '10/8/98', null, '8/8/98', '01/01/18', '12/14/98']; + const inputArray = ['8/8/98', '10/8/98', null, '8/8/98', '1/1/18', '12/14/98']; inputArray.sort((value1, value2) => sortByFieldType(FieldType.dateUsShort, value1, value2, direction)); - expect(inputArray).toEqual(['01/01/18', '12/14/98', '10/8/98', '8/8/98', '8/8/98', null]); + expect(inputArray).toEqual(['1/1/18', '12/14/98', '10/8/98', '8/8/98', '8/8/98', null]); }); it(`should return an array with unsorted characters showing at the beginning then comes numbers sorted ascending when digits and chars are provided`, () => { const direction = SortDirectionNumber.asc; - const inputArray = ['10/8/98', 'y', '8/8/98', '01/01/18', '12/14/98']; + const inputArray = ['10/8/98', 'y', '8/8/98', '1/1/18', '12/14/98']; inputArray.sort((value1, value2) => sortByFieldType(FieldType.dateUsShort, value1, value2, direction)); - expect(inputArray).toEqual(['y', '8/8/98', '10/8/98', '12/14/98', '01/01/18']); + expect(inputArray).toEqual(['y', '8/8/98', '10/8/98', '12/14/98', '1/1/18']); }); it(`should return an array with dates sorted descending showing at the beginning then characters`, () => { const direction = SortDirectionNumber.desc; - const inputArray = ['10/8/98', null, '8/8/98', '01/01/18', '12/14/98']; + const inputArray = ['10/8/98', null, '8/8/98', '1/1/18', '12/14/98']; inputArray.sort((value1, value2) => sortByFieldType(FieldType.dateUsShort, value1, value2, direction)); - expect(inputArray).toEqual(['01/01/18', '12/14/98', '10/8/98', '8/8/98', null]); + expect(inputArray).toEqual(['1/1/18', '12/14/98', '10/8/98', '8/8/98', null]); }); }); diff --git a/packages/common/src/sortComparers/dateUtilities.ts b/packages/common/src/sortComparers/dateUtilities.ts index 7615557a6..2a03bb397 100644 --- a/packages/common/src/sortComparers/dateUtilities.ts +++ b/packages/common/src/sortComparers/dateUtilities.ts @@ -1,29 +1,26 @@ -import * as moment_ from 'moment-mini'; -const moment = (moment_ as any)['default'] || moment_; - import { FieldType } from '../enums/fieldType.enum'; import type { SortComparer } from '../interfaces/index'; -import { mapMomentDateFormatWithFieldType } from '../services/utilities'; +import { mapTempoDateFormatWithFieldType, tryParseDate } from '../services/dateUtils'; -export function compareDates(value1: any, value2: any, sortDirection: number, format: string | moment_.MomentBuiltinFormat, strict?: boolean) { +export function compareDates(value1: any, value2: any, sortDirection: number, format?: string, strict?: boolean) { let diff = 0; if (value1 === value2) { diff = 0; } else { - // use moment to validate the date - let date1: moment_.Moment | Date = moment(value1, format, strict); - let date2: moment_.Moment | Date = moment(value2, format, strict); + // try to parse the Date and validate it + let date1: Date | boolean = tryParseDate(value1, format, strict); + let date2: Date | boolean = tryParseDate(value2, format, strict); - // when moment date is invalid, we'll create a temporary old Date - if (!(date1 as moment_.Moment).isValid()) { + // when date is invalid (false), we'll create a temporary old Date + if (!date1) { date1 = new Date(1001, 1, 1); } - if (!(date2 as moment_.Moment).isValid()) { + if (!date2) { date2 = new Date(1001, 1, 1); } - // we can use valueOf on both moment & Date to sort + // we can use Date valueOf to sort diff = date1.valueOf() - date2.valueOf(); } @@ -32,10 +29,10 @@ export function compareDates(value1: any, value2: any, sortDirection: number, fo /** From a FieldType, return the associated Date SortComparer */ export function getAssociatedDateSortComparer(fieldType: typeof FieldType[keyof typeof FieldType]): SortComparer { - const FORMAT = (fieldType === FieldType.date) ? moment.ISO_8601 : mapMomentDateFormatWithFieldType(fieldType); + const FORMAT = (fieldType === FieldType.date) ? undefined : mapTempoDateFormatWithFieldType(fieldType); return ((value1: any, value2: any, sortDirection: number) => { - if (FORMAT === moment.ISO_8601) { + if (FORMAT === undefined) { return compareDates(value1, value2, sortDirection, FORMAT, false) as number; } return compareDates(value1, value2, sortDirection, FORMAT, true) as number; diff --git a/packages/common/src/sortComparers/sortComparers.index.ts b/packages/common/src/sortComparers/sortComparers.index.ts index 6d08376a1..0256c7b90 100644 --- a/packages/common/src/sortComparers/sortComparers.index.ts +++ b/packages/common/src/sortComparers/sortComparers.index.ts @@ -12,7 +12,7 @@ export const SortComparers = { /** SortComparer method to sort values as regular strings */ boolean: booleanSortComparer, - /** SortComparer method to sort values by Date object type (uses Moment.js ISO_8601 standard format, optionally include time) */ + /** SortComparer method to sort values by Date object type (uses Tempo ISO_8601 standard format, optionally include time) */ date: getAssociatedDateSortComparer(FieldType.date), /** diff --git a/packages/common/src/styles/_private.scss b/packages/common/src/styles/_private.scss deleted file mode 100644 index 29728d511..000000000 --- a/packages/common/src/styles/_private.scss +++ /dev/null @@ -1,27 +0,0 @@ -@use 'sass:math'; -@use 'sass:meta'; -@use 'sass:list'; - -// Private polyfill for the `math.div` function from Sass to be used until we can update the -// minimum required Sass version to 1.34.0 or above. -// TODO: replace with `math.div` eventually, maybe in 6 months or a year from now. -@function private-div($a, $b) { - @if (meta.function-exists('div', 'math')) { - @return math.div($a, $b); - } - @else { - @return $a / $b; - } -} - -// Private polyfill for the `list.slash` function from Sass to be used until we can update the -// minimum required Sass version to 1.34.0 or above. -// TODO: replace with `list.slash` eventually, maybe in 6 months or a year from now. -@function private-slash($a, $b) { - @if (meta.function-exists('slash', 'list')) { - @return list.slash($a, $b); - } - @else { - @return #{$a}#{' / '}#{$b}; - } -} \ No newline at end of file diff --git a/packages/common/src/styles/_variables-theme-material.scss b/packages/common/src/styles/_variables-theme-material.scss index 97aa452e4..70143e7c1 100644 --- a/packages/common/src/styles/_variables-theme-material.scss +++ b/packages/common/src/styles/_variables-theme-material.scss @@ -1,19 +1,15 @@ -@import './sass-utilities'; - /** * This is a bare version of "slickgrid-theme-material.scss", - * Few files were removed and aren't included in this styling theme (while they are in original theme) - * - (colors, extra-styling, material-svg-icons, material-svg-utilities, slick-without-bootstrap-min-styling) + * A few files were removed and aren't included in this styling theme (while they are in original theme) + * - (colors, extra-styling, slickgrid-icons, slickgrid-icons-svg-utils, slick-without-bootstrap-min-styling) */ $slick-primary-color: #009530 !default; $slick-highlight-color: #48c774 !default; $slick-font-family: Roboto, "Helvetica Neue", sans-serif !default; $slick-font-size-base-value: 14 !default; -$slick-icon-color: #3f3e3e !default; -$slick-icon-font-family: "Material Design Icons" !default; +$slick-icon-color: inherit !default; $slick-icon-font-size: 18px !default; -$slick-icon-width: 18px !default; $slick-group-totals-formatter-color: #666666 !default; $slick-cell-border-top: none !default; $slick-cell-font-weight: 400 !default; @@ -43,28 +39,14 @@ $slick-container-border-bottom: 1px solid #ccc !defa $slick-container-border-left: 1px solid #ccc !default; $slick-container-border-right: 1px solid #ccc !default; $slick-icon-sort-color: $slick-primary-color !default; -$slick-icon-sort-asc: url('data:image/svg+xml,') !default; -$slick-icon-sort-desc: url('data:image/svg+xml,') !default; -$slick-icon-sort-font-size: $slick-icon-width !default; -$slick-icon-sort-position-right: 14px !default; -$slick-icon-sort-width: $slick-icon-width !default; -$slick-checkbox-selector-size: 22px !default; -$slick-checkbox-selector-color: $slick-primary-color !default; -$slick-checkbox-selector-icon-width: $slick-checkbox-selector-size !default; -$slick-checkbox-selector-icon-checked: url('data:image/svg+xml,') !default; -$slick-checkbox-selector-icon-unchecked: url('data:image/svg+xml,') !default; -$slick-checkbox-selector-opacity: 1 !default; -$slick-checkbox-selector-opacity-hover: 0.9 !default; -$slick-column-picker-checkbox-color: $slick-primary-color !default; -$slick-column-picker-checkbox-size: $slick-icon-width !default; -$slick-column-picker-checkbox-font-weight: normal !default; -$slick-column-picker-checkbox-icon-checked: url('data:image/svg+xml,') !default; -$slick-column-picker-checkbox-icon-unchecked: $slick-column-picker-checkbox-icon-checked !default; -$slick-column-picker-checkbox-width: $slick-icon-width !default; +$slick-checkbox-icon-color: $slick-primary-color !default; +$slick-checkbox-icon-container-bg-color: transparent !default; +$slick-checkbox-icon-checked-svg-path: "M10,17L5,12L6.41,10.58L10,14.17L17.59,6.58L19,8M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3Z" !default; +$slick-checkbox-icon-unchecked-svg-path: "M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M19,5V19H5V5H19Z" !default; +$slick-checkbox-opacity-hover: 0.9 !default; +$slick-checkbox-unchecked-opacity: 1 !default; $slick-column-picker-close-btn-font-size: 23px !default; $slick-column-picker-item-font-size: 14px !default; -$slick-column-picker-checkbox-icon-line-height: 16px !default; -$slick-column-picker-checkbox-icon-vertical-align: middle !default; $slick-column-picker-item-height: 26px !default; $slick-column-picker-item-line-height: 16px !default; $slick-column-picker-title-font-size: 17px !default; @@ -74,24 +56,13 @@ $slick-menu-icon-line-height: 18px !default; $slick-menu-icon-min-width: 18px !default; $slick-menu-icon-width: 18px !default; $slick-menu-title-font-size: 17px !default; -$slick-icon-group-width: 22px !default; $slick-icon-group-color: $slick-primary-color !default; -$slick-icon-group-collapsed: url('data:image/svg+xml,') !default; -$slick-icon-group-expanded: url('data:image/svg+xml,') !default; -$slick-icon-group-font-weight: normal !default; -$slick-icon-group-height: auto !default; -$slick-icon-group-vertical-align: bottom !default; $slick-draggable-group-drop-border-top: 0px !default; $slick-draggable-group-drop-border-left: 0px !default; $slick-draggable-group-drop-border-right: 0px !default; $slick-draggable-group-drop-width: 100% !default; $slick-draggable-group-drop-radius: 0 !default; $slick-draggable-group-delete-vertical-align: middle !default; -$slick-draggable-group-toggle-all-icon-height: $slick-icon-font-size !default; -$slick-draggable-group-toggle-all-icon-width: $slick-icon-font-size !default; -$slick-draggable-group-toggle-all-icon-vertical-align: text-bottom !default; -$slick-draggable-group-toggle-collapsed-icon: $slick-icon-group-collapsed !default; -$slick-draggable-group-toggle-expanded-icon: $slick-icon-group-expanded !default; $slick-draggable-group-title-height: 24px !default; $slick-draggable-group-title-line-height: 24px !default; $slick-draggable-group-title-vertical-align: top !default; @@ -99,49 +70,19 @@ $slick-header-button-hidden-margin-right: -6px !default; $slick-header-button-height: 18px !default; $slick-header-button-width: 18px !default; $slick-header-button-margin: -4px 0 100px 0 !default; -$slick-header-menu-button-height: 25px !default; -$slick-header-menu-button-icon-font-size: 24px !default; -$slick-header-menu-button-icon-width: 24px !default; $slick-header-menu-button-icon-color: $slick-icon-color !default; -$slick-header-menu-button-icon: url('data:image/svg+xml,') !default; -$slick-header-menu-button-margin-right: 8px !default; $slick-header-menu-display: inline-block !default; -$slick-autocomplete-loading-icon-color: $slick-icon-color !default; -$slick-autocomplete-loading-icon: url('data:image/svg+xml,') !default; -$slick-autocomplete-loading-icon-width: 22px !default; -$slick-autocomplete-loading-icon-margin: 2px 0 0 -26px !default; -$slick-autocomplete-loading-icon-line-height: 0px !default; -$slick-autocomplete-loading-icon-vertical-align: sub !default; $slick-compound-filter-operator-select-border: 1px solid #{lighten($slick-primary-color, 10%)} !default; $slick-compound-filter-text-color: darken($slick-primary-color, 20%) !default; $slick-preheader-border-right: 1px solid #e2e2e2 !default; $slick-row-move-plugin-cursor: grab !default; $slick-row-move-plugin-icon-color: $slick-icon-color !default; -$slick-row-move-plugin-icon-vertical-align: -webkit-baseline-middle !default; -$slick-row-move-plugin-icon: url('data:image/svg+xml,') !default; $slick-editor-input-height: 100% !default; $slick-editor-input-group-clear-btn-icon-color: $slick-icon-color !default; -$slick-editor-input-group-clear-btn-icon: url('data:image/svg+xml,') !default; $slick-editor-input-group-clear-btn-icon-padding: 1px 6px !default; -$slick-editor-input-group-clear-btn-icon-size: calc(#{$slick-icon-font-size} + 2px) !default; -$slick-editor-input-group-clear-btn-icon-width: 14px !default; $slick-row-mouse-hover-color: #ebfaef !default; $slick-row-selected-color: #d4f6d7 !default; -$slick-detail-view-icon-collapse-color: $slick-primary-color !default; -$slick-detail-view-icon-expand-color: $slick-primary-color !default; -$slick-detail-view-icon-collapse: url('data:image/svg+xml,') !default; -$slick-detail-view-icon-expand: url('data:image/svg+xml,') !default; $slick-pagination-icon-color: $slick-primary-color !default; -$slick-pagination-icon-height: $slick-icon-width !default; -$slick-pagination-icon-seek-first: url('data:image/svg+xml,') !default; -$slick-pagination-icon-seek-end: url('data:image/svg+xml,') !default; -$slick-pagination-icon-seek-next: url('data:image/svg+xml,') !default; -$slick-pagination-icon-seek-prev: url('data:image/svg+xml, ') !default; -$slick-pagination-icon-seek-first-width: $slick-icon-width !default; -$slick-pagination-icon-seek-prev-width: $slick-icon-width !default; -$slick-pagination-icon-seek-next-width: $slick-icon-width !default; -$slick-pagination-icon-seek-end-width: $slick-icon-width !default; -$slick-pagination-button-padding: 6px 9px !default; $slick-pagination-button-border-radius: 2px !default; $slick-pagination-page-input-border-radius: 3px !default; @@ -150,12 +91,12 @@ $slick-pagination-page-input-border-radius: 3px !default; .ms-dark-mode, .ms-drop.ms-dark-mode, .slick-dark-mode .ms-dark-mode, +.slick-dark-mode .icon-checkbox-container, .slick-dark-mode { - --slick-base-dark-menu-bg-color: #212121; --slick-primary-color: #66bb6a; - --slick-button-primary-bg-color: var(--slick-primary-color); + --slick-base-dark-menu-bg-color: #212121; + --slick-button-primary-bg-color: #66bb6a; --slick-cell-box-shadow: none; - --slick-column-picker-checkbox-color: #49a54e; --slick-compound-filter-text-color: #66bb6a; --slick-compound-filter-operator-select-border: 1px solid #66bb6a; --slick-header-filter-row-border-bottom: 1px solid #505050; @@ -167,16 +108,17 @@ $slick-pagination-page-input-border-radius: 3px !default; --slick-filled-filter-color: #66bb6a; --slick-highlight-color: #49a54e; --slick-pagination-icon-color: #49a54e; - --slick-checkbox-selector-opacity: 1; - --slick-checkbox-selector-checked-color: #66bb6a; + --slick-checkbox-icon-color: #4dae52; --slick-row-mouse-hover-box-shadow: none; --slick-row-mouse-hover-color: #575757; --slick-row-selected-color: #4b4b4b; - --slick-checkbox-selector-icon-height: 22px; - --slick-checkbox-selector-icon-bg-color: transparent; - --slick-checkbox-selector-icon-border: none; - --slick-multiselect-icon-radio-color: var(--slick-primary-color); - --ms-checkbox-color: var(--slick-primary-color); + --slick-checkbox-icon-color: #59c55f; + --slick-checkbox-icon-height: 22px; + --slick-checkbox-icon-bg-color: transparent; + --slick-checkbox-icon-border: none; + --slick-icon-sort-color: #66bb6a; + --slick-multiselect-icon-radio-color: #66bb6a; + --ms-checkbox-color: #66bb6a; --ms-checkbox-hover-color: #{lighten(#49a54e, 13%)}; --ms-ok-button-text-color: #66bb6a; --ms-ok-button-text-hover-color: #{lighten(#66bb6a, 5%)}; diff --git a/packages/common/src/styles/_variables-theme-salesforce.scss b/packages/common/src/styles/_variables-theme-salesforce.scss index 6cb033377..8ffcc064f 100644 --- a/packages/common/src/styles/_variables-theme-salesforce.scss +++ b/packages/common/src/styles/_variables-theme-salesforce.scss @@ -1,10 +1,7 @@ -/** Salesforce Theme (includes all external lib styling) */ -@import './sass-utilities'; - /** * This is a bare version of "slickgrid-theme-salesforce.scss", - * Few files were removed and aren't included in this styling theme (while they are in original theme) - * - (colors, extra-styling, material-svg-icons, material-svg-utilities, slick-without-bootstrap-min-styling) + * A few files were removed and aren't included in this styling theme (while they are in original theme) + * - (colors, extra-styling, slickgrid-icons, slickgrid-icons-svg-utils, slick-without-bootstrap-min-styling) */ $slick-primary-color: #006DCC !default; @@ -13,18 +10,18 @@ $slick-highlight-color: #0070D2 !default; $slick-button-primary-bg-color: $slick-primary-color-dark !default; $slick-button-primary-color: $slick-primary-color-dark !default; $slick-bare-color: #b5b5b5 !default; -$slick-icon-color: #777777 !default; +$slick-icon-color: inherit !default; +$slick-checkbox-icon-font-size: 20px !default; $slick-font-family: var(--lwc-fontFamily,'Salesforce Sans', 'SalesforceSans-Regular', Arial, sans-serif) !default; +$slick-icon-font-size: 18px !default; $slick-cell-active-box-shadow: inset 0 0 0 1px #{$slick-highlight-color} !default; $slick-cell-border-top: none !default; $slick-cell-border-bottom: none !default; $slick-cell-box-shadow: 0px 1px 0px #dddbda, 0px -1px 0px #dddbda !default; $slick-cell-font-weight: 400 !default; $slick-cell-odd-background-color: #f3f2f2 !default; -$slick-cell-text-color: #080707 !default; +$slick-cell-text-color: #333 !default; $slick-font-size-base-value: 13 !default; -$slick-icon-font-size: 18px !default; -$slick-icon-width: 18px !default; $slick-frozen-border-bottom: 1px solid #{$slick-highlight-color} !default; $slick-frozen-border-right: 1px solid #{$slick-highlight-color} !default; $slick-group-totals-formatter-color: #666666 !default; @@ -50,36 +47,17 @@ $slick-container-border-bottom: 1px solid #ccc !de $slick-container-border-left: 0px solid #ccc !default; $slick-container-border-right: 0px solid #ccc !default; $slick-icon-sort-color: $slick-highlight-color !default; -$slick-icon-sort-asc: url('data:image/svg+xml,') !default; -$slick-icon-sort-desc: url('data:image/svg+xml,') !default; -$slick-icon-sort-font-size: 13px !default; -$slick-icon-sort-width: 13px !default; -$slick-icon-sort-position-right: 12px !default; -$slick-checkbox-selector-checked-color: $slick-highlight-color !default; -$slick-checkbox-selector-unchecked-color: $slick-bare-color !default; -$slick-checkbox-selector-size: 12px !default; -$slick-checkbox-selector-icon-font-weight: normal !default; -$slick-checkbox-selector-icon-height: calc(#{$slick-checkbox-selector-size} + 4px) !default; -$slick-checkbox-selector-icon-width: calc(#{$slick-checkbox-selector-size} + 4px) !default; -$slick-checkbox-selector-icon-margin: 2px 0 0 0 !default; -$slick-checkbox-selector-icon-border: 1px solid #d6d4d4 !default; -$slick-checkbox-selector-icon-border-radius: 0.125rem !default; -$slick-checkbox-selector-icon-bg-color: white !default; -$slick-checkbox-selector-color: $slick-highlight-color !default; -$slick-checkbox-selector-icon-checked: url('data:image/svg+xml,') !default; -$slick-checkbox-selector-icon-unchecked: url('data:image/svg+xml,') !default; -$slick-checkbox-selector-opacity: 1 !default; -$slick-checkbox-selector-opacity-hover: 0.9 !default; -$slick-column-picker-checkbox-color: $slick-primary-color !default; -$slick-column-picker-checkbox-size: $slick-icon-width !default; -$slick-column-picker-checkbox-font-weight: normal !default; -$slick-column-picker-checkbox-icon-checked: url('data:image/svg+xml,') !default; -$slick-column-picker-checkbox-icon-unchecked: $slick-column-picker-checkbox-icon-checked !default; -$slick-column-picker-checkbox-width: 13px !default; +$slick-checkbox-icon-color: $slick-highlight-color !default; +$slick-checkbox-icon-border: 1px solid #d6d4d4 !default; +$slick-checkbox-icon-border-radius: 0.125rem !default; +$slick-checkbox-icon-container-bg-color: white !default; +$slick-checkbox-icon-container-size: 1.05rem !default; +$slick-checkbox-icon-unchecked-svg-path: "" !default; +$slick-checkbox-icon-unchecked-color-visibility: hidden !default; +$slick-checkbox-opacity-hover: 0.9 !default; +$slick-checkbox-unchecked-opacity: 1 !default; $slick-column-picker-close-btn-font-size: 23px !default; $slick-column-picker-item-font-size: 14px !default; -$slick-column-picker-checkbox-icon-line-height: 16px !default; -$slick-column-picker-checkbox-icon-vertical-align: middle !default; $slick-column-picker-item-height: 26px !default; $slick-column-picker-item-line-height: 16px !default; $slick-column-picker-title-font-size: 17px !default; @@ -87,15 +65,8 @@ $slick-menu-item-font-size: 14px !default; $slick-menu-item-height: 26px !default; $slick-menu-icon-line-height: 18px !default; $slick-menu-icon-min-width: 18px !default; -$slick-menu-icon-width: 18px !default; $slick-menu-title-font-size: 17px !default; $slick-icon-group-color: $slick-primary-color !default; -$slick-icon-group-collapsed: url('data:image/svg+xml,') !default; -$slick-icon-group-expanded: url('data:image/svg+xml,') !default; -$slick-icon-group-font-weight: normal !default; -$slick-icon-group-height: auto !default; -$slick-icon-group-vertical-align: bottom !default; -$slick-icon-group-width: 15px !default; $slick-filled-filter-color: $slick-primary-color-dark !default; $slick-filled-filter-border: 1px solid #{$slick-primary-color} !default; $slick-filled-filter-box-shadow: inset 0 0 0 1px #{lighten($slick-primary-color, 30%)} !default; @@ -104,11 +75,6 @@ $slick-draggable-group-drop-border-top: 0px !default; $slick-draggable-group-drop-width: 100% !default; $slick-draggable-group-drop-radius: 0px !default; $slick-draggable-group-delete-vertical-align: middle !default; -$slick-draggable-group-toggle-all-icon-height: $slick-icon-font-size !default; -$slick-draggable-group-toggle-all-icon-width: $slick-icon-font-size !default; -$slick-draggable-group-toggle-all-icon-vertical-align: text-bottom !default; -$slick-draggable-group-toggle-collapsed-icon: $slick-icon-group-collapsed !default; -$slick-draggable-group-toggle-expanded-icon: $slick-icon-group-expanded !default; $slick-draggable-group-title-height: 24px !default; $slick-draggable-group-title-line-height: 24px !default; $slick-draggable-group-title-vertical-align: top !default; @@ -116,17 +82,7 @@ $slick-header-button-hidden-margin-right: -6px !default; $slick-header-button-height: 18px !default; $slick-header-button-width: 18px !default; $slick-header-button-margin: -4px 0 100px 0 !default; -$slick-header-menu-button-height: 25px !default; -$slick-header-menu-button-icon-font-size: 26px !default; -$slick-header-menu-button-icon-color: #706e6b !default; -$slick-header-menu-button-icon: url('data:image/svg+xml,') !default; -$slick-header-menu-button-margin-right: 8px !default; -$slick-autocomplete-loading-icon-color: $slick-icon-color !default; -$slick-autocomplete-loading-icon: url('data:image/svg+xml,') !default; -$slick-autocomplete-loading-icon-width: 22px !default; -$slick-autocomplete-loading-icon-margin: 2px 0 0 -26px !default; -$slick-autocomplete-loading-icon-line-height: 0px !default; -$slick-autocomplete-loading-icon-vertical-align: sub !default; +$slick-header-menu-button-icon-color: inherit !default; $slick-compound-filter-operator-select-border: 1px solid #6cb6ff !default; $slick-compound-filter-text-color: $slick-primary-color-dark !default; $slick-multiselect-icon-checked-color: $slick-highlight-color !default; @@ -139,15 +95,9 @@ $slick-preheader-font-size: 14px !default; $slick-preheader-height: 21px !default; $slick-row-move-plugin-icon-color: $slick-icon-color !default; $slick-row-move-plugin-cursor: grab !default; -$slick-row-move-plugin-icon-width: 18px !default; -$slick-row-move-plugin-icon-vertical-align: -webkit-baseline-middle !default; -$slick-row-move-plugin-icon: url('data:image/svg+xml,') !default; $slick-editor-input-height: 100% !default; $slick-editor-input-group-clear-btn-icon-color: $slick-icon-color !default; -$slick-editor-input-group-clear-btn-icon: url('data:image/svg+xml,') !default; $slick-editor-input-group-clear-btn-icon-padding: 1px 6px !default; -$slick-editor-input-group-clear-btn-icon-size: calc(#{$slick-icon-font-size} + 2px) !default; -$slick-editor-input-group-clear-btn-icon-width: 14px !default; $slick-editor-focus-box-shadow: 0 0 3px $slick-primary-color !default; $slick-editor-modal-container-radius: var(--lwc-borderRadiusMedium, 0.25rem) !default; $slick-editor-modal-close-btn-outside-color: #ffffff !default; @@ -168,21 +118,7 @@ $slick-row-selected-color: #ECEBEA !default; $slick-row-highlight-background-color: lighten($slick-highlight-color, 50%) !default; $slick-row-mouse-hover-color: #f3f2f2 !default; $slick-row-mouse-hover-box-shadow: 0 0 0 2px #dddbda !default; -$slick-detail-view-icon-collapse-color: $slick-primary-color !default; -$slick-detail-view-icon-expand-color: $slick-primary-color !default; -$slick-detail-view-icon-collapse: url('data:image/svg+xml,') !default; -$slick-detail-view-icon-expand: url('data:image/svg+xml,') !default; $slick-pagination-icon-color: $slick-primary-color !default; -$slick-pagination-icon-height: $slick-icon-width !default; -$slick-pagination-icon-seek-first: url('data:image/svg+xml,') !default; -$slick-pagination-icon-seek-end: url('data:image/svg+xml,') !default; -$slick-pagination-icon-seek-next: url('data:image/svg+xml,') !default; -$slick-pagination-icon-seek-prev: url('data:image/svg+xml, ') !default; -$slick-pagination-icon-seek-first-width: $slick-icon-width !default; -$slick-pagination-icon-seek-prev-width: $slick-icon-width !default; -$slick-pagination-icon-seek-next-width: $slick-icon-width !default; -$slick-pagination-icon-seek-end-width: $slick-icon-width !default; -$slick-pagination-button-padding: 6px 9px !default; $slick-pagination-button-border-radius: 2px !default; $slick-pagination-page-input-border-radius: 3px !default; @@ -191,19 +127,25 @@ $slick-pagination-page-input-border-radius: 3px !default; .ms-dark-mode, .ms-drop.ms-dark-mode, .slick-dark-mode .ms-dark-mode, +.slick-dark-mode .icon-checkbox-container, .slick-dark-mode { - --ms-checkbox-color: #3a9ef5; - --ms-ok-button-text-color: #3a9ef5; - --slick-button-primary-bg-color: #0057ac; - --slick-multiselect-icon-checked-color: #3a9ef5; + --slick-primary-color: #66b8ff; + --ms-checkbox-color: #66b8ff; + --ms-ok-button-text-color: #66b8ff; + --slick-button-primary-bg-color: #0064c9; + --slick-multiselect-icon-checked-color: #66b8ff; --slick-base-dark-menu-bg-color: #212121; + --slick-cell-active-box-shadow: inset 0 0 0 1px #3ca4ff; --slick-cell-box-shadow: 0px 1px 0px #303030, 0px -1px 0px #303030; - --slick-column-picker-checkbox-color: #3a9ef5; + --slick-checkbox-icon-container-bg-color: #2d2d2d; + --slick-highlight-color: #3ca4ff; + --slick-column-picker-icon-color: #66b8ff; + --slick-checkbox-icon-color: #66b8ff; + --slick-checkbox-icon-border: 1px solid #5e5e5e; --slick-compound-filter-text-color: #66b8ff; --slick-filled-filter-color: #66b8ff; - --slick-header-filter-row-border-bottom: 2px solid #0389ff; - --slick-highlight-color: #0389ff; - --slick-pagination-icon-color: #1190ff; + --slick-icon-sort-color: #66b8ff; + --slick-header-filter-row-border-bottom: 2px solid #0389ff; + --slick-pagination-icon-color: #66b8ff; --slick-row-mouse-hover-box-shadow: 0 0 0 2px #3a3a3a; - --slick-checkbox-selector-icon-border: 1px solid #888888; } diff --git a/packages/common/src/styles/_variables.scss b/packages/common/src/styles/_variables.scss index 430c74d64..2c1369330 100644 --- a/packages/common/src/styles/_variables.scss +++ b/packages/common/src/styles/_variables.scss @@ -1,3 +1,9 @@ +// import external lib CSS files (without the .css extension) +@import 'vanilla-calendar-picker/build/vanilla-calendar.min'; + +// SASS utils to generate SVGs +@import './svg-utilities'; + /* * SlickGrid-Universal theming variables, used by all Themes * Lib Website (https://github.com/ghiscoding/slickgrid-universal) @@ -25,9 +31,9 @@ $slick-button-primary-bg-color-disabled: #bebebe !default; $slick-button-primary-color: inherit !default; $slick-button-border-color: #c7c7c7 !default; $slick-button-style-bg-color: #fff !default; -$slick-flatpickr-bgcolor: #ffffff !default; $slick-filter-placeholder-font-family: 'Segoe UI Symbol' !default; $slick-focus-color: rgb(115, 179, 229) !default; +$slick-date-picker-bg-color: #fff !default; $slick-form-control-bg-color: #fff !default; $slick-form-control-border: 1px solid #ccc !default; @@ -66,13 +72,15 @@ $slick-table-background: transparent !default $slick-scrollbar-color: #c1c1c1 #f1f1f1 !default; $slick-hover-header-color: $slick-text-color; $slick-sorting-header-color: #333; +$slick-placeholder-color: #c9c9c9 !default; /* cell */ $slick-cell-active-border: none !default; $slick-cell-active-box-shadow: inset 0 0 0 1px #aaaaaa !default; $slick-cell-active-z-index: 6 !default; $slick-cell-box-shadow: none !default; -$slick-cell-text-color: #000000 !default; +$slick-cell-display: block !default; +$slick-cell-text-color: #333 !default; $slick-cell-font-family: $slick-font-family !default; $slick-cell-font-weight: normal !default; $slick-cell-border-top: 1px solid #{$slick-border-color} !default; @@ -85,6 +93,7 @@ $slick-cell-odd-active-background-color: darken($slick-grid-c $slick-cell-padding-top-bottom: 5px !default; $slick-cell-padding-left-right: 6px !default; $slick-cell-padding: $slick-cell-padding-top-bottom $slick-cell-padding-left-right !default; +$slick-icon-with-text-valign: middle !default; /** 4x available slick-pane (top, bottom, left, right) */ $slick-pane-top-border-top: none !default; @@ -122,7 +131,7 @@ $slick-header-column-height: calc(17px * #{$slick $slick-header-column-background-active: darken($slick-grid-header-background, 5%) !default; $slick-header-column-background-hover: darken($slick-grid-header-background, 2%) !default; $slick-header-column-sortable-background-hover: #e0e0e0 !default; -$slick-header-column-name-margin-right: 5px !default; +$slick-header-column-name-margin-right: 0 !default; $slick-header-column-border-top: 0 none !default; // header, column titles, that is without the Filters $slick-header-column-border-right: 0 none !default; $slick-header-column-border-bottom: 0 none !default; @@ -165,37 +174,32 @@ $slick-frozen-header-row-border-right: $slick-frozen-border $slick-frozen-filter-row-border-right: $slick-frozen-border-right !default; $slick-frozen-overflow-right: scroll !default; // typically we would like to always have the scroll displayed when using hamburger menu (top right) -/* icon font is using Font-Awesome by default but could be changed to any other icon package like Glyphicons, ... */ -$slick-icon-color: #4a4a4a !default; -$slick-icon-font-family: "FontAwesome" !default; // or Glyphicons Halflings */ -$slick-icon-font-size: 14px !default; +/* icons */ +$slick-icon-color: inherit !default; +$slick-icon-font-size: 18px !default; $slick-icon-group-color: $slick-primary-color !default; -$slick-icon-group-expanded: "\f107" !default; -$slick-icon-group-collapsed: "\f105" !default; -$slick-icon-group-font-size: calc(#{$slick-icon-font-size} + 4px) !default; -$slick-icon-group-font-weight: bold !default; +$slick-icon-group-collapsed-svg-path: "M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z" !default; +$slick-icon-group-expanded-svg-path: "M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" !default; +$slick-icon-group-font-size: calc(#{$slick-icon-font-size} + 6px) !default; $slick-icon-group-margin-right: 2px !default; -$slick-icon-group-height: 20px !default; -$slick-icon-group-vertical-align: middle !default; -$slick-icon-group-width: 14px !default; /* Kraaden AutoComplete */ -$slick-autocomplete-bg-color: #ffffff !default; -$slick-autocomplete-group-bg-color: #eeeeee !default; -$slick-autocomplete-border: 1px solid rgba(0, 0, 0, 0.15) !default; -$slick-autocomplete-hover-bg-color: darken($slick-row-mouse-hover-color, 3%) !default; -$slick-autocomplete-loading-input-bg-color: transparent !default; -$slick-autocomplete-loading-icon: "\f021" !default; -$slick-autocomplete-loading-icon-color: $slick-icon-color !default; -$slick-autocomplete-loading-icon-width: inherit !default; -$slick-autocomplete-loading-icon-margin: 0 0 0 -16px !default; -$slick-autocomplete-loading-icon-line-height: 0px !default; -$slick-autocomplete-loading-icon-vertical-align: inherit !default; -$slick-autocomplete-max-height: 25vh !default; -$slick-autocomplete-min-height: 75px !default; -$slick-autocomplete-min-width: 110px !default; -$slick-autocomplete-text-color: #333333 !default; -$slick-autocomplete-z-index: 9999 !default; +$slick-autocomplete-bg-color: #ffffff !default; +$slick-autocomplete-group-bg-color: #eeeeee !default; +$slick-autocomplete-border: 1px solid rgba(0, 0, 0, 0.15) !default; +$slick-autocomplete-hover-bg-color: darken($slick-row-mouse-hover-color, 3%) !default; +$slick-autocomplete-loading-input-bg-color: transparent !default; +$slick-autocomplete-loading-icon-color: #777777 !default; +$slick-autocomplete-loading-icon: url('data:image/svg+xml,') !default; +$slick-autocomplete-loading-icon-width: 22px !default; +$slick-autocomplete-loading-icon-margin: 0 0 0 -26px !default; +$slick-autocomplete-loading-icon-line-height: 0px !default; +$slick-autocomplete-loading-icon-vertical-align: sub !default; +$slick-autocomplete-max-height: 25vh !default; +$slick-autocomplete-min-height: 75px !default; +$slick-autocomplete-min-width: 110px !default; +$slick-autocomplete-text-color: #333333 !default; +$slick-autocomplete-z-index: 9999 !default; /** Kraaden AutoComplete with Custom Styling (2 rows) */ $slick-autocomplete-tpl2-font-size: 12px !default; @@ -248,13 +252,12 @@ $slick-autocomplete-tpl4-top-right-font-weight: bold !default; $slick-autocomplete-tpl4-top-right-max-width: 100px !default; /* Sorting */ -$slick-icon-sort-asc: "\f0d8" !default; -$slick-icon-sort-desc: "\f0d7" !default; +$slick-icon-sort-desc-icon-svg-path: "M16.707 13.293a.999.999 0 0 0-1.414 0L13 15.586V8a1 1 0 1 0-2 0v7.586l-2.293-2.293a.999.999 0 1 0-1.414 1.414L12 19.414l4.707-4.707a.999.999 0 0 0 0-1.414Z"; +$slick-icon-sort-asc-icon-svg-path: "M13 5.586l-4.707 4.707a.999.999 0 1 0 1.414 1.414L12 9.414V17a1 1 0 1 0 2 0V9.414l2.293 2.293a.997.997 0 0 0 1.414 0a.999.999 0 0 0 0-1.414Z"; $slick-icon-sort-color: $slick-primary-color !default; -$slick-icon-sort-font-size: $slick-icon-font-size !default; -$slick-icon-sort-width: $slick-icon-font-size !default; -$slick-icon-sort-position-right: 10px !default; -$slick-icon-sort-position-top: calc((15px * #{$slick-header-row-count}) - 15px) !default; +$slick-icon-sort-font-size: 23px !default; +$slick-icon-sort-position-right: 3px !default; +$slick-icon-sort-position-top: calc((15px * #{$slick-header-row-count}) - 9px) !default; $slick-sort-indicator-number-font-size: 10px !default; $slick-sort-indicator-number-width: 8px !default; $slick-sort-indicator-number-left: auto !default; @@ -267,18 +270,14 @@ $slick-group-border-bottom: 2px solid silver !de $slick-group-totals-formatter-color: gray !default; $slick-group-totals-formatter-bgcolor: #fff !default; $slick-group-totals-formatter-font-size: 14px !default; -$slick-group-totals-text-background: white !default; -$slick-group-totals-text-color: gray !default; -/** Detail View Plugin */ -$slick-detail-view-icon-collapse: "\f056" !default; -$slick-detail-view-icon-collapse-color: $slick-primary-color !default; -$slick-detail-view-icon-collapse-color-hover: darken($slick-detail-view-icon-collapse-color, 10%) !default; -$slick-detail-view-icon-expand: "\f055" !default; -$slick-detail-view-icon-expand-color: lighten($slick-primary-color, 25%) !default; -$slick-detail-view-icon-expand-color-hover: darken($slick-detail-view-icon-expand-color, 10%) !default; -$slick-detail-view-icon-size: calc(#{$slick-icon-font-size} + 2px) !default; -$slick-detail-view-icon-width: 18px !default; +/** Row Detail View Plugin */ +$slick-detail-view-icon-color: $slick-primary-color !default; +$slick-detail-view-icon-color-hover: darken($slick-detail-view-icon-color, 10%) !default; +$slick-detail-view-icon-opacity-hover: 1 !default; +$slick-detail-view-icon-collapse-svg-path: "M17,13H7V11H17M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"; +$slick-detail-view-icon-expand-svg-path: "M17,13H13V17H11V13H7V11H11V7H13V11H17M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"; +$slick-detail-view-icon-font-size: 18px !default; $slick-detail-view-container-bgcolor: #f7f7f7 !default; $slick-detail-view-container-border: 1px solid #c0c0c0 !default; $slick-detail-view-container-left: 0 !default; @@ -301,16 +300,6 @@ $slick-column-picker-background-color: #ffffff !default; $slick-column-picker-border: 1px solid #b8b8b8 !default; $slick-column-picker-border-radius: 2px !default; $slick-column-picker-box-shadow: none !default; -$slick-column-picker-checkbox-color: $slick-primary-color !default; -$slick-column-picker-checkbox-size: 13px !default; -$slick-column-picker-checkbox-font-weight: bold !default; -$slick-column-picker-checkbox-icon-unchecked: "\f00c" !default; -$slick-column-picker-checkbox-icon-checked: "\f00c" !default; -$slick-column-picker-checkbox-icon-line-height: calc(#{$slick-icon-font-size} + 2px) !default; -$slick-column-picker-checkbox-icon-vertical-align: baseline !default; -$slick-column-picker-checkbox-opacity: 0.15 !default; -$slick-column-picker-checkbox-opacity-hover: 0.35 !default; -$slick-column-picker-checkbox-width: 13px !default; $slick-column-picker-close-btn-bg-color: #ffffff !default; $slick-column-picker-close-btn-color: #909090 !default; $slick-column-picker-close-btn-color-hover: darken($slick-column-picker-close-btn-color, 25%) !default; @@ -326,6 +315,16 @@ $slick-column-picker-close-btn-opacity: 0.5 !default; $slick-column-picker-close-btn-opacity-hover: 1 !default; $slick-column-picker-close-btn-position-right: 5px !default; $slick-column-picker-close-btn-position-top: 0px !default; +$slick-column-picker-icon-color: $slick-primary-color !default; +$slick-column-picker-icon-border: none !default; +$slick-column-picker-icon-border-radius: none !default; +$slick-column-picker-icon-container-bg-color: transparent !default; +$slick-column-picker-icon-font-size: 14px !default; +$slick-column-picker-icon-container-line-height: 12px !default; +$slick-column-picker-icon-container-size: 1rem !default; +$slick-column-picker-icon-checked-svg-path: "M8.8 19.6L1.2 12c-.3-.3-.3-.8 0-1.1l1-1c.3-.3.8-.3 1 0L9 15.7c.1.2.5.2.6 0L20.9 4.4c.2-.3.7-.3 1 0l1 1c.3.3.3.7 0 1L9.8 19.6c-.2.3-.7.3-1 0z" !default; +$slick-column-picker-icon-unchecked-svg-path: $slick-column-picker-icon-checked-svg-path !default; +$slick-column-picker-icon-unchecked-color-visibility: visible !default; // make this "hidden" when uncheck icon is not provided (e.g. Salesforce Theme) $slick-column-picker-min-width: 150px !default; $slick-column-picker-padding: 6px !default; $slick-column-picker-list-width-firefox: calc(100% + 12px) !default; @@ -343,8 +342,11 @@ $slick-column-picker-item-hover-border: 1px solid #d5d5d5 !d $slick-column-picker-item-hover-color: #fafafa !default; $slick-column-picker-label-margin: 4px !default; $slick-column-picker-label-font-weight: normal !default; +$slick-column-picker-label-text-padding-left: 4px !default; $slick-column-picker-link-background-color: #ffffff !default; $slick-column-picker-list-margin-bottom: 8px !default; +$slick-column-picker-opacity-hover: 0.45 !default; +$slick-column-picker-unchecked-opacity: 0.25 !default; $slick-column-picker-title-border-bottom: 1px solid #d6d6d6 !default; $slick-column-picker-title-font-size: calc(#{$slick-column-picker-item-font-size} + 2px) !default; $slick-column-picker-title-font-weight: normal !default; @@ -401,7 +403,6 @@ $slick-menu-icon-line-height: calc(#{$slick-menu-i $slick-menu-item-width-when-button: calc(100% - #{$slick-menu-close-btn-width}) !default; $slick-menu-icon-margin-right: 4px !default; $slick-menu-icon-min-width: 16px !default; -$slick-menu-icon-width: 16px !default; $slick-menu-line-height: 24px !default; $slick-menu-min-width: 140px !default; $slick-menu-option-list-margin-bottom: 6px !default; @@ -427,55 +428,44 @@ $slick-header-button-margin: 1px 0 100px 0 !defau $slick-header-button-height: 15px !default; $slick-header-button-width: 15px !default; $slick-header-button-hidden-margin-right: -5px !default; -$slick-header-button-hidden-transition: 0.2s width !default; +$slick-header-button-hidden-transition: 0.2s visibility !default; $slick-header-button-vertical-align: top !default; /* Header Menu Plugin */ $slick-header-menu-border: 1px solid #BFBDBD !default; $slick-header-menu-button-border: $slick-header-menu-border !default; $slick-header-menu-button-border-width: 0px !default; -$slick-header-menu-button-height: 35px !default; -$slick-header-menu-button-icon: "\f13a" !default; +$slick-header-menu-button-icon-svg-path: "M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" !default; $slick-header-menu-button-icon-color: $slick-icon-color !default; -$slick-header-menu-button-icon-font-size: 14px !default; -$slick-header-menu-button-icon-font-weight: normal !default; -$slick-header-menu-button-icon-width: 14px !default; +$slick-header-menu-button-icon-size: 22px !default; $slick-header-menu-button-padding: 0px !default; $slick-header-menu-button-margin-right: 3px !default; -$slick-header-menu-button-width: 14px !default; $slick-header-menu-display: none !default; /* can be none or inline-block */ /* Checkbox Selector / Row Selection */ -$slick-checkbox-selector-color: $slick-primary-color !default; -$slick-checkbox-selector-checked-color: $slick-checkbox-selector-color !default; -$slick-checkbox-selector-unchecked-color: $slick-checkbox-selector-color !default; -$slick-checkbox-selector-size: calc(#{$slick-icon-font-size} - 1px) !default; -$slick-checkbox-selector-icon: "\f00c" !default; -$slick-checkbox-selector-icon-bg-color: inherit !default; -$slick-checkbox-selector-icon-font-weight: bold !default; -$slick-checkbox-selector-icon-height: $slick-icon-font-size !default; -$slick-checkbox-selector-icon-margin: 0 !default; -$slick-checkbox-selector-icon-width: $slick-icon-font-size !default; -$slick-checkbox-selector-icon-checked: $slick-checkbox-selector-icon !default; -$slick-checkbox-selector-icon-unchecked: $slick-checkbox-selector-icon !default; -$slick-checkbox-selector-icon-border: none !default; -$slick-checkbox-selector-icon-border-radius: none !default; -$slick-checkbox-selector-opacity: 0.15 !default; -$slick-checkbox-selector-opacity-hover: 0.35 !default; +$slick-checkbox-icon-color: $slick-primary-color !default; +$slick-checkbox-icon-border: none !default; +$slick-checkbox-icon-border-radius: none !default; +$slick-checkbox-icon-container-bg-color: transparent !default; +$slick-checkbox-icon-font-size: 16px !default; +$slick-checkbox-icon-container-line-height: 12px !default; +$slick-checkbox-icon-container-size: 1rem !default; +$slick-checkbox-icon-checked-svg-path: "M9,20.42L2.79,14.21L5.62,11.38L9,14.77L18.88,4.88L21.71,7.71L9,20.42Z" !default; +$slick-checkbox-icon-unchecked-svg-path: $slick-checkbox-icon-checked-svg-path !default; +$slick-checkbox-icon-unchecked-color-visibility: visible !default; // make this "hidden" when uncheck icon is not provided (e.g. Salesforce Theme) +$slick-checkbox-label-text-padding-left: 8px !default; +$slick-checkbox-opacity-hover: 0.45 !default; +$slick-checkbox-unchecked-opacity: 0.25 !default; /* Editors */ $slick-editor-bg-color: transparent !default; -$slick-editor-placeholder-color: #c9c9c9 !default; $slick-editor-input-border-radius: 3px !default; $slick-editor-input-disabled-color: #ececec !default; $slick-editor-input-height: 24px !default; $slick-editor-focus-border-color: $slick-input-focus-border-color !default; $slick-editor-focus-box-shadow: $slick-input-focus-box-shadow !default; -$slick-editor-input-group-clear-btn-icon: "\f00d" !default; +$slick-editor-input-group-clear-btn-icon-svg-path: "M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" !default; $slick-editor-input-group-clear-btn-icon-padding: 6px !default; -$slick-editor-input-group-clear-btn-icon-size: inherit !default; -$slick-editor-input-group-clear-btn-icon-height: auto !default; -$slick-editor-input-group-clear-btn-icon-width: initial !default; $slick-date-editor-input-padding: 0 0 0 2px !default; $slick-date-editor-focus-border-color: $slick-input-focus-border-color !default; $slick-date-editor-focus-box-shadow: $slick-input-focus-box-shadow !default; @@ -495,7 +485,8 @@ $slick-large-editor-text-color: #333 !default; $slick-text-editor-border: 1px solid #e2e2e2 !default; $slick-text-editor-border-radius: $slick-editor-input-border-radius !default; $slick-text-editor-background: #ffffff !default; -$slick-text-editor-margin-bottom: 2px !default; +$slick-text-editor-color: #333 !default; +$slick-text-editor-margin-bottom: 0 !default; $slick-text-editor-margin-left: -2px !default; /* negative number to cancel inside padding */ $slick-text-editor-right-input-margin-left: calc(#{$slick-text-editor-margin-left} + 9px) !default; $slick-text-editor-margin-right: 0px !default; @@ -667,8 +658,8 @@ $slick-draggable-group-column-border: 1px solid #d3d3d3 !d $slick-draggable-group-column-border-radius: 20px !default; $slick-draggable-group-column-padding: 0 10px !default; $slick-draggable-group-column-margin-right: 8px !default; -$slick-draggable-group-drop-border-hover: 1px dashed #ff9e9e !default; $slick-draggable-group-drop-border: 1px solid #e0e0e0 !default; +$slick-draggable-group-drop-border-hover: 1px dashed #ff9e9e !default; $slick-draggable-group-drop-border-top: $slick-draggable-group-drop-border !default; $slick-draggable-group-drop-border-bottom: $slick-draggable-group-drop-border !default; $slick-draggable-group-drop-border-right: $slick-draggable-group-drop-border !default; @@ -683,20 +674,14 @@ $slick-draggable-group-droppable-active-bgcolor: #fafafa !default; $slick-draggable-group-droppable-hover-bgcolor: #ffffff !default; $slick-draggable-group-placeholder-font-style: italic !default; $slick-draggable-group-placeholder-color: #616161 !default; -$slick-draggable-group-by-remove-icon: "\f00d" !default; -$slick-draggable-group-by-remove-icon-size: calc(#{$slick-icon-font-size} + 2px) !default; -$slick-draggable-group-sort-asc-icon: $slick-icon-sort-asc !default; -$slick-draggable-group-sort-asc-icon-size: calc(#{$slick-icon-font-size} + 2px) !default; -$slick-draggable-group-sort-desc-icon: $slick-icon-sort-desc !default; -$slick-draggable-group-sort-desc-icon-size: calc(#{$slick-icon-font-size} + 2px) !default; $slick-draggable-group-sort-icon-color: $slick-icon-color !default; -$slick-draggable-group-sort-icon-hover-color: darken($slick-icon-color, 5%) !default; +$slick-draggable-group-sort-icon-hover-color: $slick-icon-color !default; $slick-draggable-group-sort-icon-margin-left: 2px !default; $slick-draggable-group-sort-icon-padding-left: 5px !default; $slick-draggable-group-sort-icon-padding-right: 0px !default; $slick-draggable-group-sort-icon-font-size: 16px !default; $slick-draggable-group-sort-icon-vertical-align: baseline !default; -$slick-draggable-group-delete-color: pink !default; +$slick-draggable-group-delete-color: #ff3c5c !default; $slick-draggable-group-delete-hover-color: red !default; $slick-draggable-group-delete-margin-left: 2px !default; $slick-draggable-group-delete-padding-left: 5px !default; @@ -705,22 +690,19 @@ $slick-draggable-group-delete-font-size: 16px !default; $slick-draggable-group-delete-vertical-align: baseline !default; $slick-draggable-group-toggle-all-border: 1px solid #c7c7c7 !default; $slick-draggable-group-toggle-all-border-radius: 3px !default; -$slick-draggable-group-toggle-all-color: $slick-icon-group-color !default; -$slick-draggable-group-toggle-all-display: none !default; +$slick-draggable-group-toggle-all-icon-color: $slick-icon-group-color !default; $slick-draggable-group-toggle-all-margin-right: 15px !default; $slick-draggable-group-toggle-all-padding: 0 8px !default; $slick-draggable-group-toggle-all-position: relative !default; $slick-draggable-group-toggle-all-top: 0px !default; $slick-draggable-group-toggle-all-right: unset !default; -$slick-draggable-group-toggle-all-icon-vertical-align: middle !default; $slick-draggable-group-toggle-all-text-font-size: 15px !default; $slick-draggable-group-toggle-all-text-margin: 0 0 0 2px !default; -$slick-draggable-group-toggle-all-icon-height: inherit !default; -$slick-draggable-group-toggle-all-icon-width: $slick-icon-font-size !default; -$slick-draggable-group-toggle-collapsed-icon: "\f0fe" !default; -$slick-draggable-group-toggle-expanded-icon: "\f146" !default; -$slick-draggable-group-title-height: $slick-icon-group-height !default; -$slick-draggable-group-title-line-height: $slick-icon-group-height !default; +$slick-draggable-group-toggle-all-icon-font-size: 24px !default; +$slick-draggable-group-toggle-collapsed-icon-svg-path: $slick-icon-group-collapsed-svg-path !default; +$slick-draggable-group-toggle-expanded-icon-svg-path: $slick-icon-group-expanded-svg-path !default; +$slick-draggable-group-title-height: 20px !default; +$slick-draggable-group-title-line-height: 20px !default; $slick-draggable-group-title-vertical-align: none !default; $slick-draggable-group-column-icon-font-weight: normal !default; $slick-draggable-group-column-icon-color: #707070 !default; @@ -777,10 +759,10 @@ $slick-multiselect-item-height: 26px !default; $slick-multiselect-item-border: 1px solid transparent !default; $slick-multiselect-item-hover-bg-color: #fafafa !default; $slick-multiselect-item-hover-border: 1px solid #d5d5d5 !default; -$slick-multiselect-item-line-height: calc(#{$slick-multiselect-icon-font-size} + 2px) !default; +$slick-multiselect-item-line-height: 20px !default; $slick-multiselect-item-padding: 2px 4px !default; $slick-multiselect-placeholder-bg-color: transparent !default; -$slick-multiselect-placeholder-color: $slick-editor-placeholder-color !default; +$slick-multiselect-placeholder-color: $slick-placeholder-color !default; $slick-multiselect-placeholder-font-family: $slick-filter-placeholder-font-family !default; $slick-multiselect-ok-button-bg-color: #fff !default; $slick-multiselect-ok-button-bg-hover-color: #f9f9f9 !default; @@ -805,29 +787,6 @@ $slick-multiselect-select-all-padding: 6px 10px !default; $slick-multiselect-select-all-text-color: darken($slick-primary-color, 5%) !default; $slick-multiselect-select-all-text-hover-color: transparent !default; -// @deprecated, to be removed in next major -// (they are actually no longer associated to anything but removing them now would possibly break user's usage) -$slick-multiselect-icon-height: 20px !default; -$slick-multiselect-icon-margin: 0 !default; -$slick-multiselect-icon-width: 20px !default; -$slick-multiselect-icon-arrow-font-size: $slick-multiselect-icon-font-size !default; -$slick-multiselect-icon-border: none !default; -$slick-multiselect-icon-border-radius: none !default; -$slick-multiselect-icon-radio-border: $slick-multiselect-icon-border !default; -$slick-multiselect-icon-radio-border-radius: $slick-multiselect-icon-border-radius !default; -$slick-multiselect-icon-checked: "\f14a" !default; -$slick-multiselect-icon-radio-color: $slick-primary-color !default; -$slick-multiselect-icon-radio-checked: "\f192" !default; -$slick-multiselect-icon-radio-height: $slick-multiselect-icon-height !default; -$slick-multiselect-icon-radio-margin: $slick-multiselect-icon-margin !default; -$slick-multiselect-icon-radio-unchecked: "\f10c" !default; -$slick-multiselect-icon-radio-width: $slick-multiselect-icon-width !default; -$slick-multiselect-icon-unchecked: "\f096" !default; -$slick-multiselect-icon-unchecked-color: $slick-multiselect-icon-color !default; -$slick-multiselect-icon-vertical-align: middle !default; -$slick-multiselect-icon-search-margin-right: 8px !default; -$slick-multiselect-unchecked-opacity: 0.6 !default; - // override some multiple-select SASS variables with our variables $ms-drop-color: $slick-text-color; $ms-checkbox-color: $slick-multiselect-icon-checked-color; @@ -844,7 +803,7 @@ $ms-drop-hide-radio-selected-bgcolor: unset; $ms-icon-color: $slick-icon-color; $ms-icon-size: $slick-multiselect-icon-font-size; $ms-chevron-icon-size: #{$slick-multiselect-icon-font-size + 3px}; -$ms-placeholder-color: $slick-editor-placeholder-color; +$ms-placeholder-color: $slick-placeholder-color; $ms-label-padding: $slick-multiselect-item-padding; $ms-ok-button-bg-color: $slick-multiselect-ok-button-bg-color; $ms-ok-button-bg-hover-color: $slick-multiselect-ok-button-bg-hover-color; @@ -861,11 +820,12 @@ $ms-select-all-text-color: $slick-multiselect-s /* pagination variables */ $slick-pagination-border-color: #ddd !default; $slick-pagination-button-bg-color: #fff !default; -$slick-pagination-button-border-color: #acacac !default; +$slick-pagination-button-border-color: #b3b3b3 !default; +$slick-pagination-button-border-disabled-color: #dedede !default; $slick-pagination-button-border-radius: 4px !default; $slick-pagination-button-height: 32px !default; $slick-pagination-button-hover-color: #E6E6E6 !default; -$slick-pagination-button-padding: 6px 12px !default; +$slick-pagination-button-padding: 5px 8px !default; $slick-pagination-button-border: 1px solid #{$slick-pagination-button-border-color} !default; $slick-pagination-border-top: 0 none !default; $slick-pagination-border-right: 0 none !default; @@ -876,20 +836,13 @@ $slick-pagination-font-size: calc(#{$slick-font-s $slick-pagination-height: 40px !default; $slick-pagination-icon-color: $slick-primary-color !default; $slick-pagination-icon-font-size: calc(#{$slick-icon-font-size} - 1px) !default; -$slick-pagination-icon-line-height: calc(#{$slick-icon-font-size} + 4px) !default; -$slick-pagination-icon-height: initial !default; -$slick-pagination-icon-seek-first: "\f100" !default; -$slick-pagination-icon-seek-end: "\f101" !default; -$slick-pagination-icon-seek-next: "\f105" !default; -$slick-pagination-icon-seek-prev: "\f104" !default; -$slick-pagination-icon-seek-first-width: initial !default; -$slick-pagination-icon-seek-end-width: initial !default; -$slick-pagination-icon-seek-next-width: initial !default; -$slick-pagination-icon-seek-prev-width: initial !default; -$slick-pagination-icon-seek-disabled-color: #b8b8b8 !default; +$slick-pagination-icon-size: 20px !default; +$slick-pagination-icon-seek-first-svg-path: "M18.41,16.59L13.82,12L18.41,7.41L17,6L11,12L17,18L18.41,16.59M6,6H8V18H6V6Z" !default; +$slick-pagination-icon-seek-end-svg-path: "M5.59,7.41L10.18,12L5.59,16.59L7,18L13,12L7,6L5.59,7.41M16,6H18V18H16V6Z" !default; +$slick-pagination-icon-seek-next-svg-path: "M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z" !default; +$slick-pagination-icon-seek-prev-svg-path: "M15.41,16.58L10.83,12L15.41,7.41L14,6L8,12L14,18L15.41,16.58Z" !default; +$slick-pagination-icon-seek-disabled-color: darkgray !default; $slick-pagination-icon-seek-disabled-bg-color: rgb(249, 249, 249) !default; -$slick-pagination-icon-seek-disabled-border-color: #dedede !default; -$slick-pagination-icon-seek-text-stroke: 0.4px !default; $slick-pagination-page-input-border-radius: 4px !default; $slick-pagination-page-input-bgcolor: #fafbed !default; $slick-pagination-page-input-height: 26px !default; @@ -904,10 +857,9 @@ $slick-pagination-page-select-font-size: calc(#{$slick-font-s $slick-pagination-text-color: #808080 !default; /* Row Move Manager Plugin */ -$slick-row-move-plugin-icon: "\f0c9" !default; -$slick-row-move-plugin-icon-vertical-align: bottom !default; -$slick-row-move-plugin-icon-width: $slick-icon-font-size !default; -$slick-row-move-plugin-size: $slick-icon-font-size !default; +$slick-row-move-plugin-icon-color: $slick-icon-color !default; +$slick-row-move-plugin-icon-font-size: calc(#{$slick-icon-font-size} + 2px) !default; +$slick-row-move-plugin-icon-svg-path: "M11,18 C11,19.1 10.1,20 9,20 C7.9,20 7,19.1 7,18 C7,16.9 7.9,16 9,16 C10.1,16 11,16.9 11,18 Z M9,10 C7.9,10 7,10.9 7,12 C7,13.1 7.9,14 9,14 C10.1,14 11,13.1 11,12 C11,10.9 10.1,10 9,10 Z M9,4 C7.9,4 7,4.9 7,6 C7,7.1 7.9,8 9,8 C10.1,8 11,7.1 11,6 C11,4.9 10.1,4 9,4 Z M15,8 C16.1,8 17,7.1 17,6 C17,4.9 16.1,4 15,4 C13.9,4 13,4.9 13,6 C13,7.1 13.9,8 15,8 Z M15,10 C13.9,10 13,10.9 13,12 C13,13.1 13.9,14 15,14 C16.1,14 17,13.1 17,12 C17,10.9 16.1,10 15,10 Z M15,16 C13.9,16 13,16.9 13,18 C13,19.1 13.9,20 15,20 C16.1,20 17,19.1 17,18 C17,16.9 16.1,16 15,16 Z" !default; $slick-row-move-plugin-cursor: move !default; $slick-row-move-plugin-guide-bg-color: blue !default; $slick-row-move-plugin-guide-height: 2px !default; @@ -993,15 +945,15 @@ $slick-empty-data-warning-z-index: 10 !default; .slick-dark-mode { // Bootstrap --bs-body-bg: #212529 // local common CSS vars for dark mode - --primary-color: #{lighten($primary-color, 15%)}; - --slick-base-dark-text-color: #cccccc; + --slick-primary-color: #{lighten($primary-color, 15%)}; + --slick-base-dark-text-color: #d4d4d4; --slick-base-dark-menu-bg-color: #252525; --slick-base-dark-menu-border: 1px solid #505050; --slick-base-dark-menu-item-border: 1px solid #5a5a5a; --slick-base-dark-menu-item-hover-color: #363b40; --slick-base-dark-invalid-color: #ea868f; - --slick-highlight-color: var(--primary-color); - --slick-text-color: #cccccc; + --slick-highlight-color: var(--slick-primary-color); + --slick-text-color: #d4d4d4; --slick-autocomplete-bg-color: var(--slick-base-dark-menu-bg-color); --slick-autocomplete-hover-bg-color: #2c3034; @@ -1015,38 +967,41 @@ $slick-empty-data-warning-z-index: 10 !default; --slick-btn-default-bg-color: #383838; --slick-cell-even-background-color: #141618; --slick-cell-odd-background-color: #2c3034; - --slick-cell-text-color: #cdcdcd; + --slick-cell-text-color: #d4d4d4; --slick-cell-border-top: 1px solid #474747; --slick-column-picker-background-color: var(--slick-base-dark-menu-bg-color); --slick-column-picker-box-shadow: 0 0 1px #606060; --slick-column-picker-border: var(--slick-base-dark-menu-border); --slick-column-picker-close-btn-color: #bbbbbb; - --slick-column-picker-checkbox-opacity: 0.25; - --slick-column-picker-checkbox-opacity-hover: 0.45; --slick-column-picker-close-btn-bg-color: transparent; - --slick-column-picker-item-hover-color: var(--slick-base-dark-menu-bg-color); --slick-column-picker-hr-bg-color: #434343; --slick-column-picker-hr-divider-border: 1px solid #525252; - --slick-column-picker-item-hover-color: var(--slick-base-dark-menu-item-hover-color); + --slick-column-picker-icon-color: var(--slick-highlight-color); --slick-column-picker-item-hover-border: var(--slick-base-dark-menu-item-border); + --slick-column-picker-item-hover-color: var(--slick-base-dark-menu-item-hover-color); --slick-column-picker-title-border-bottom: 1px solid #525252; - --slick-checkbox-selector-opacity: 0.7; - --slick-checkbox-selector-opacity-hover: 0.85; - --slick-checkbox-selector-checked-color: var(--slick-highlight-color); - --slick-checkbox-selector-icon-bg-color: #444444; - --slick-checkbox-selector-icon-bg-color: transparent; - --slick-checkbox-selector-unchecked-color: #{lighten($primary-color, 10%)}; + --slick-checkbox-opacity-hover: 0.7; + --slick-checkbox-icon-bg-color: #444444; + --slick-checkbox-icon-bg-color: transparent; + --slick-checkbox-unchecked-color: #{lighten($primary-color, 10%)}; + --slick-checkbox-unchecked-opacity: 0.4; + --slick-detail-view-icon-color: var(--slick-primary-color); + --slick-detail-view-icon-color-hover: var(--slick-primary-color); + --slick-detail-view-icon-opacity-hover: 0.75; + --slick-detail-view-container-border: 1px solid #525252; + --slick-detail-view-container-bgcolor: #3c4349; --slick-btn-default-border-color: #565656; - --slick-grid-menu-icon-btn-color: #bbbbbb; + --slick-grid-menu-icon-btn-color: #ededed; --slick-row-mouse-hover-color: #2c3034; --slick-header-background-color: #1c1c1c; - --slick-header-text-color: var(--slick-base-dark-text-color); + --slick-header-text-color: #e4e4e4; --slick-hover-header-color: var(--slick-base-dark-text-color); --slick-header-row-background-color: #2d2d2d; --slick-preheader-border-right: 1px solid #3e3e3e; --slick-pane-top-border-top: 1px solid #606060; --slick-empty-data-warning-color: var(--slick-base-dark-text-color); --slick-grid-header-background: #2d2d2d; + --slick-icon-sort-color: var(--slick-primary-color); --slick-header-column-background-active: #535353; --slick-slider-filter-input-bgcolor: var(--slick-base-dark-menu-bg-color); --slick-menu-bg-color: var(--slick-base-dark-menu-bg-color); @@ -1054,15 +1009,16 @@ $slick-empty-data-warning-z-index: 10 !default; --slick-menu-box-shadow: 0 0 1px #606060; --slick-menu-close-btn-bg-color: transparent; --slick-menu-close-btn-color: #bbbbbb; - --slick-menu-color: #bbbbbb; + --slick-menu-color: #ededed; + --slick-menu-item-disabled-color: #686868; --slick-menu-divider-color: #606060; --slick-menu-item-hover-color: var(--slick-base-dark-menu-bg-color); --slick-menu-item-hover-color: var(--slick-base-dark-menu-item-hover-color); --slick-menu-item-hover-border: var(--slick-base-dark-menu-item-border); --slick-menu-title-border-bottom: 1px solid #525252; - --slick-menu-title-color: #bababa; + --slick-menu-title-color: #cecece; --slick-slider-filter-border: var(--slick-base-dark-menu-item-border); - --slick-slider-filter-thumb-color: #d0d0d0; + --slick-slider-filter-thumb-color: #d0d0d0; --slick-font-color: #d3d3d3; --slick-form-control-border: var(--slick-base-dark-menu-item-border); --slick-form-control-bg-color: var(--slick-base-dark-menu-bg-color); @@ -1074,15 +1030,29 @@ $slick-empty-data-warning-z-index: 10 !default; --slick-input-group-btn-border: var(--slick-base-dark-menu-item-border); --slick-input-group-append-bg-color: #383838; --slick-compound-filter-bgcolor: var(--slick-base-dark-menu-bg-color); - --slick-flatpickr-bgcolor: var(--slick-base-dark-menu-bg-color); + --slick-date-picker-bg-color: var(--slick-base-dark-menu-bg-color); --slick-footer-left-text-color: #acacac; --slick-footer-right-text-color: #acacac; --slick-grid-header-unorderable-bg-color: #1c1c1c; --slick-slider-filter-runnable-track-bgcolor: #787878; + --slick-draggable-group-placeholder-color: #999; + --slick-draggable-group-drop-bgcolor: #2c3034; + --slick-draggable-group-droppable-hover-bgcolor: #353a3f; + --slick-draggable-group-drop-border: #3e3e3e; + --slick-draggable-group-drop-border-top: var(--slick-draggable-group-drop-border); + --slick-draggable-group-drop-border-bottom: var(--slick-draggable-group-drop-border); + --slick-draggable-group-drop-border-right: var(--slick-draggable-group-drop-border); + --slick-draggable-group-drop-border-left: var(--slick-draggable-group-drop-border); + --slick-draggable-group-toggle-all-border: 1px solid #626262; + --slick-draggable-group-toggle-all-icon-color: var(--slick-primary-color); + --slick-draggable-group-column-border: 1px solid #626262; + --slick-group-totals-formatter-bgcolor: #1f2225; + --slick-group-totals-formatter-color: #f3f3f3; + --slick-icon-group-color: var(--slick-primary-color); --slick-editing-field-bg-color: #333333; --slick-editing-field-border: 1px solid #7c7c7c; --slick-editor-input-disabled-color: #404040; - --slick-editor-placeholder-color: #999; + --slick-placeholder-color: #999; --slick-editor-modal-default-btn-disabled-bg-color: #3f3f3f; --slick-editor-modal-default-btn-disabled-color: #5b5b5b; --slick-editor-modal-detail-container-border-modified: 1px solid #cc8400; @@ -1112,20 +1082,20 @@ $slick-empty-data-warning-z-index: 10 !default; --slick-large-editor-background-color: var(--slick-base-dark-menu-bg-color); --slick-large-editor-border: 2px solid #565656; --slick-large-editor-text-color: var(--slick-base-dark-text-color); + --slick-text-editor-color: var(--slick-base-dark-text-color); --slick-header-menu-button-icon-color: var(--slick-menu-color); --slick-text-editor-background: var(--slick-base-dark-menu-bg-color); - --slick-pagination-button-border-color: #4b4b4b; --slick-pagination-button-border: 1px solid #696969; + --slick-pagination-button-border-color: #4b4b4b; + --slick-pagination-button-border-disabled-color: #565656; --slick-pagination-button-bg-color: #1e1e1e; --slick-pagination-button-hover-color: #2b2b2b; --slick-pagination-icon-seek-background-color: #434343; - --slick-pagination-icon-seek-disabled-color: #b8b8b8; --slick-pagination-icon-seek-disabled-bg-color: #434343; - --slick-pagination-icon-seek-disabled-border-color: #828282; - --slick-pagination-icon-seek-border-color: #828282; + --slick-pagination-icon-seek-disabled-color: gray; --slick-pagination-page-input-bgcolor: #2b2f34; --slick-pagination-page-select-bg-color: #1c1c1c; - --slick-pagination-text-color: #b4b4b4; + --slick-pagination-text-color: #cfcfcf; --slick-scrollbar-color: #828282 #424242; --slick-sorting-header-color: var(--slick-base-dark-text-color); --slick-row-selected-color: #474747; @@ -1148,4 +1118,20 @@ $slick-empty-data-warning-z-index: 10 !default; --ms-ok-button-bg-hover-color: #373c42; --ms-placeholder-color: #999; --ms-select-all-label-hover-border: var(--slick-base-dark-menu-item-border); + + .text-color-primary { + color: var(--slick-primary-color); + } +} + +.dark-mode { + --slick-button-border-color: #626262; + --slick-button-primary-color: #bababa; + --slick-button-style-bg-color: #252525; + .text-color-primary { + --text-color-primary: var(--slick-primary-color, #{lighten($primary-color, 15%)}); + } + .text-color-secondary { + --text-color-secondary: rgba(222, 226, 230, 0.75); + } } \ No newline at end of file diff --git a/packages/common/src/styles/colors-from-filters.scss b/packages/common/src/styles/colors-from-filters.scss deleted file mode 100644 index 319af5b91..000000000 --- a/packages/common/src/styles/colors-from-filters.scss +++ /dev/null @@ -1,87 +0,0 @@ -@import './sass-utilities'; - -/* icon/text colors */ -// we'll use the same color set as text-colors defined in Bootstrap 4 (ref: https://getbootstrap.com/docs/4.5/utilities/colors/) -// we also use CSS Filter to color on top of SVG icons, we use this codepen to calculate the Filter Color (https://codepen.io/sosuke/pen/Pjoqqp) -// since our icon are not pure black, we also need to prepend "brightness(0) saturate(100%)" to the filter -// NOTE: remember that we are using CSS "filter" and that is NOT the same as a using regular color/background-color, it behaves differently - -$color-primary: $slick-primary-color !default; -$color-secondary: #6c757d !default; -$color-success: #28a745 !default; -$color-danger: #dc3545 !default; -$color-warning: #ffc107 !default; -$color-info: #17a2b8 !default; -$color-light: #f8f9fa !default; -$color-dark: #343a40 !default; -$color-body: #212529 !default; -$color-muted: #6c757d !default; -$color-white: #ffffff !default; -$color-disabled: #DDDBDA !default; -$color-disabled-dark: #cccccc !default; -$color-alt-default: #1e87f0 !default; -$color-alt-warning: #faa05a !default; -$color-alt-danger: #f0506e !default; -$color-alt-success: #32d296 !default; -$color-se-primary: #3dcd58 !default; -$color-se-link: #42b4e6 !default; -$color-se-link-dark: #337ab7 !default; -$color-se-danger: #b10043 !default; -$color-se-secondary: #9fa0a4 !default; -$color-se-warning: #e47f00 !default; -$color-se-warning-light: #ffd100 !default; -$color-sf-highlight: #0070D2 !default; -$color-sf-primary: #006DCC !default; -$color-sf-primary-dark: #004487 !default; - -.color-primary { filter: brightness(0) saturate(100%) invert(31%) sepia(57%) saturate(6822%) hue-rotate(194deg) brightness(93%) contrast(102%); } -.color-secondary { filter: brightness(0) saturate(100%) invert(49%) sepia(14%) saturate(290%) hue-rotate(167deg) brightness(89%) contrast(89%); } -.color-success { filter: brightness(0) saturate(100%) invert(46%) sepia(96%) saturate(377%) hue-rotate(81deg) brightness(94%) contrast(91%); } -.color-danger { filter: brightness(0) saturate(100%) invert(35%) sepia(56%) saturate(4390%) hue-rotate(334deg) brightness(88%) contrast(95%); } -.color-warning { filter: brightness(0) saturate(100%) invert(68%) sepia(73%) saturate(596%) hue-rotate(354deg) brightness(105%) contrast(101%); } -.color-info { filter: brightness(0) saturate(100%) invert(51%) sepia(59%) saturate(588%) hue-rotate(140deg) brightness(92%) contrast(94%); } -.color-light { filter: brightness(0) saturate(100%) invert(91%) sepia(4%) saturate(576%) hue-rotate(200deg) brightness(109%) contrast(96%); } -.color-dark { filter: brightness(0) saturate(100%) invert(18%) sepia(6%) saturate(1291%) hue-rotate(169deg) brightness(89%) contrast(82%); } -.color-body { filter: brightness(0) saturate(100%) invert(12%) sepia(9%) saturate(824%) hue-rotate(169deg) brightness(94%) contrast(91%); } -.color-muted { filter: brightness(0) saturate(100%) invert(50%) sepia(2%) saturate(2378%) hue-rotate(168deg) brightness(89%) contrast(84%); } -.color-white { filter: brightness(0) saturate(100%) invert(100%) sepia(0%) saturate(0%) hue-rotate(54deg) brightness(109%) contrast(101%); } -.color-disabled { filter: brightness(0) saturate(100%) invert(81%) sepia(2%) saturate(180%) hue-rotate(335deg) brightness(108%) contrast(96%); } -.color-disabled-dark { filter: brightness(0) saturate(100%) invert(91%) sepia(0%) saturate(0%) hue-rotate(185deg) brightness(95%) contrast(84%); } -.color-alt-default { filter: brightness(0) saturate(100%) invert(46%) sepia(70%) saturate(3992%) hue-rotate(193deg) brightness(99%) contrast(90%); } -.color-alt-warning { filter: brightness(0) saturate(100%) invert(59%) sepia(94%) saturate(289%) hue-rotate(341deg) brightness(98%) contrast(99%); } -.color-alt-danger { filter: brightness(0) saturate(100%) invert(37%) sepia(84%) saturate(805%) hue-rotate(308deg) brightness(99%) contrast(90%); } -.color-alt-success { filter: brightness(0) saturate(100%) invert(80%) sepia(11%) saturate(2532%) hue-rotate(99deg) brightness(87%) contrast(89%); } -.color-se-primary { filter: brightness(0) saturate(100%) invert(67%) sepia(14%) saturate(2047%) hue-rotate(79deg) brightness(97%) contrast(90%); } -.color-se-link { filter: brightness(0) saturate(100%) invert(71%) sepia(47%) saturate(2213%) hue-rotate(167deg) brightness(93%) contrast(94%); } -.color-se-link-dark { filter: brightness(0) saturate(100%) invert(42%) sepia(23%) saturate(1361%) hue-rotate(166deg) brightness(98%) contrast(93%); } -.color-se-danger { filter: brightness(0) saturate(100%) invert(14%) sepia(84%) saturate(3919%) hue-rotate(325deg) brightness(79%) contrast(112%); } -.color-se-secondary { filter: brightness(0) saturate(100%) invert(71%) sepia(5%) saturate(181%) hue-rotate(191deg) brightness(91%) contrast(86%); } -.color-se-warning { filter: brightness(0) saturate(100%) invert(76%) sepia(49%) saturate(7416%) hue-rotate(7deg) brightness(95%) contrast(101%); } -.color-se-warning-light { filter: brightness(0) saturate(100%) invert(85%) sepia(31%) saturate(3980%) hue-rotate(359deg) brightness(103%) contrast(106%); } -.color-sf-highlight { filter: brightness(0) saturate(100%) invert(23%) sepia(97%) saturate(3081%) hue-rotate(195deg) brightness(96%) contrast(101%); } -.color-sf-primary { filter: brightness(0) saturate(100%) invert(26%) sepia(75%) saturate(2018%) hue-rotate(191deg) brightness(99%) contrast(102%); } -.color-sf-primary-dark { filter: brightness(0) saturate(100%) invert(10%) sepia(97%) saturate(4590%) hue-rotate(200deg) brightness(90%) contrast(102%); } - -.color-primary-light { filter: brightness(0) saturate(100%) invert(33%) sepia(82%) saturate(3926%) hue-rotate(193deg) brightness(100%) contrast(101%); } -.color-primary-dark { filter: brightness(0) saturate(100%) invert(21%) sepia(67%) saturate(5693%) hue-rotate(196deg) brightness(85%) contrast(101%); } -.color-secondary-light { filter: brightness(0) saturate(100%) invert(56%) sepia(14%) saturate(260%) hue-rotate(169deg) brightness(90%) contrast(90%); } -.color-secondary-dark { filter: brightness(0) saturate(100%) invert(41%) sepia(5%) saturate(796%) hue-rotate(166deg) brightness(92%) contrast(90%); } -.color-success-light { filter: brightness(0) saturate(100%) invert(71%) sepia(10%) saturate(2988%) hue-rotate(80deg) brightness(84%) contrast(94%); } -.color-success-dark { filter: brightness(0) saturate(100%) invert(39%) sepia(90%) saturate(416%) hue-rotate(82deg) brightness(95%) contrast(88%); } -.color-danger-light { filter: brightness(0) saturate(100%) invert(56%) sepia(45%) saturate(5329%) hue-rotate(322deg) brightness(89%) contrast(96%); } -.color-danger-dark { filter: brightness(0) saturate(100%) invert(16%) sepia(80%) saturate(4275%) hue-rotate(345deg) brightness(90%) contrast(85%); } -.color-warning-light { filter: brightness(0) saturate(100%) invert(95%) sepia(47%) saturate(2254%) hue-rotate(329deg) brightness(99%) contrast(102%); } -.color-warning-dark { filter: brightness(0) saturate(100%) invert(60%) sepia(98%) saturate(1494%) hue-rotate(10deg) brightness(103%) contrast(101%); } -.color-info-light { filter: brightness(0) saturate(100%) invert(64%) sepia(88%) saturate(916%) hue-rotate(142deg) brightness(88%) contrast(87%); } -.color-info-dark { filter: brightness(0) saturate(100%) invert(43%) sepia(87%) saturate(490%) hue-rotate(140deg) brightness(86%) contrast(85%); } -.color-muted-light { filter: brightness(0) saturate(100%) invert(56%) sepia(10%) saturate(370%) hue-rotate(169deg) brightness(89%) contrast(85%); } -.color-muted-dark { filter: brightness(0) saturate(100%) invert(38%) sepia(18%) saturate(224%) hue-rotate(166deg) brightness(95%) contrast(88%); } -.color-alt-warning-light { filter: brightness(0) saturate(100%) invert(80%) sepia(36%) saturate(783%) hue-rotate(321deg) brightness(99%) contrast(99%); } -.color-alt-warning-dark { filter: brightness(0) saturate(100%) invert(70%) sepia(17%) saturate(3850%) hue-rotate(332deg) brightness(100%) contrast(96%); } -.color-alt-default-light { filter: brightness(0) saturate(100%) invert(71%) sepia(91%) saturate(4393%) hue-rotate(189deg) brightness(96%) contrast(97%); } -.color-alt-default-dark { filter: brightness(0) saturate(100%) invert(32%) sepia(56%) saturate(3175%) hue-rotate(196deg) brightness(94%) contrast(89%); } -.color-alt-danger-light { filter: brightness(0) saturate(100%) invert(62%) sepia(44%) saturate(3309%) hue-rotate(311deg) brightness(103%) contrast(111%); } -.color-alt-danger-dark { filter: brightness(0) saturate(100%) invert(32%) sepia(51%) saturate(3649%) hue-rotate(329deg) brightness(94%) contrast(97%); } -.color-alt-success-light { filter: brightness(0) saturate(100%) invert(77%) sepia(87%) saturate(336%) hue-rotate(90deg) brightness(90%) contrast(87%); } -.color-alt-success-dark { filter: brightness(0) saturate(100%) invert(53%) sepia(76%) saturate(371%) hue-rotate(106deg) brightness(97%) contrast(99%); } -.color-se-secondary-light { filter: brightness(0) saturate(100%) invert(77%) sepia(9%) saturate(72%) hue-rotate(187deg) brightness(94%) contrast(87%); } diff --git a/packages/common/src/styles/colors.scss b/packages/common/src/styles/colors.scss index e94b1b8b9..0042de2b9 100644 --- a/packages/common/src/styles/colors.scss +++ b/packages/common/src/styles/colors.scss @@ -1,4 +1,4 @@ -@import './sass-utilities'; +@import './svg-utilities'; /* icon/text colors */ // we'll use the same color set as text-colors defined in Bootstrap 4 (ref: https://getbootstrap.com/docs/4.5/utilities/colors/) @@ -6,87 +6,88 @@ // NOTE: remember that we are using CSS "filter" and that is NOT the same as a using regular color/background-color, it behaves differently -$color-lighten-percentage: 6% !default; -$color-darken-percentage: 6% !default; +$text-color-lighten-percentage: 6% !default; +$text-color-darken-percentage: 6% !default; -$color-primary: $slick-primary-color !default; -$color-secondary: #6c757d !default; -$color-success: #28a745 !default; -$color-danger: #dc3545 !default; -$color-warning: #ffc107 !default; -$color-info: #17a2b8 !default; -$color-light: #f8f9fa !default; -$color-dark: #343a40 !default; -$color-body: #212529 !default; -$color-muted: #6c757d !default; -$color-white: #ffffff !default; -$color-disabled: #DDDBDA !default; -$color-disabled-dark: #cccccc !default; -$color-alt-default: #1e87f0 !default; -$color-alt-warning: #faa05a !default; -$color-alt-danger: #f0506e !default; -$color-alt-success: #32d296 !default; -$color-se-primary: #3dcd58 !default; -$color-se-link: #42b4e6 !default; -$color-se-link-dark: #337ab7 !default; -$color-se-danger: #b10043 !default; -$color-se-secondary: #9fa0a4 !default; -$color-se-warning: #e47f00 !default; -$color-se-warning-light: #ffd100 !default; -$color-sf-highlight: #0070D2 !default; -$color-sf-primary: #006DCC !default; -$color-sf-primary-dark: #004487 !default; +$text-color-primary: $slick-primary-color !default; +$text-color-secondary: #6c757d !default; +$text-color-success: #28a745 !default; +$text-color-danger: #dc3545 !default; +$text-color-warning: #ffc107 !default; +$text-color-info: #17a2b8 !default; +$text-color-light: #f8f9fa !default; +$text-color-dark: #343a40 !default; +$text-color-body: #212529 !default; +$text-color-muted: #6c757d !default; +$text-color-white: #ffffff !default; +$text-color-disabled: #DDDBDA !default; +$text-color-disabled-dark: #cccccc !default; +$text-color-alt-default: #1e87f0 !default; +$text-color-alt-warning: #faa05a !default; +$text-color-alt-danger: #f0506e !default; +$text-color-alt-success: #32d296 !default; +$text-color-se-primary: #3dcd58 !default; +$text-color-se-link: #42b4e6 !default; +$text-color-se-link-dark: #337ab7 !default; +$text-color-se-danger: #b10043 !default; +$text-color-se-secondary: #9fa0a4 !default; +$text-color-se-warning: #e47f00 !default; +$text-color-se-warning-light: #ffd100 !default; +$text-color-sf-highlight: #0070D2 !default; +$text-color-sf-primary: #006DCC !default; +$text-color-sf-primary-dark: #004487 !default; -.color-primary { @include recolor($color-primary, 1); } -.color-secondary { @include recolor($color-secondary, 1); } -.color-success { @include recolor($color-success, 1); } -.color-danger { @include recolor($color-danger, 1); } -.color-warning { @include recolor($color-warning, 1); } -.color-info { @include recolor($color-info, 1); } -.color-light { @include recolor($color-light, 1); } -.color-dark { @include recolor($color-dark, 1); } -.color-body { @include recolor($color-body, 1); } -.color-muted { @include recolor($color-muted, 1); } -.color-white { @include recolor($color-white, 1); } -.color-disabled { @include recolor($color-disabled, 1); } -.color-disabled-dark { @include recolor($color-disabled-dark, 1); } -.color-alt-default { @include recolor($color-alt-default, 1); } -.color-alt-warning { @include recolor($color-alt-warning, 1); } -.color-alt-danger { @include recolor($color-alt-danger, 1); } -.color-alt-success { @include recolor($color-alt-success, 1); } -.color-se-primary { @include recolor($color-se-primary, 1); } -.color-se-link { @include recolor($color-se-link, 1); } -.color-se-link-dark { @include recolor($color-se-link-dark, 1); } -.color-se-danger { @include recolor($color-se-danger, 1); } -.color-se-secondary { @include recolor($color-se-secondary, 1); } -.color-se-warning { @include recolor($color-se-warning, 1); } -.color-se-warning-light { @include recolor($color-se-warning-light, 1); } -.color-sf-highlight { @include recolor($color-sf-highlight, 1); } -.color-sf-primary { @include recolor($color-sf-primary, 1); } -.color-sf-primary-dark { @include recolor($color-sf-primary-dark, 1); } +// new simple +.text-color-primary { color: var(--text-color-primary, $text-color-primary); } +.text-color-secondary { color: var(--text-color-secondary, $text-color-secondary); } +.text-color-success { color: var(--text-color-success, $text-color-success); } +.text-color-danger { color: var(--text-color-danger, $text-color-danger); } +.text-color-warning { color: var(--text-color-warning, $text-color-warning); } +.text-color-info { color: var(--text-color-info, $text-color-info); } +.text-color-light { color: var(--text-color-light, $text-color-light); } +.text-color-dark { color: var(--text-color-dark, $text-color-dark); } +.text-color-body { color: var(--text-color-body, $text-color-body); } +.text-color-muted { color: var(--text-color-muted, $text-color-muted); } +.text-color-white { color: var(--text-color-white, $text-color-white); } +.text-color-disabled { color: var(--text-color-disabled, $text-color-disabled); } +.text-color-disabled-dark { color: var(--text-color-disabled-dark, $text-color-disabled-dark); } +.text-color-alt-default { color: var(--text-color-alt-default, $text-color-alt-default); } +.text-color-alt-warning { color: var(--text-color-alt-warning, $text-color-alt-warning); } +.text-color-alt-danger { color: var(--text-color-alt-danger, $text-color-alt-danger); } +.text-color-alt-success { color: var(--text-color-alt-success, $text-color-alt-success); } +.text-color-se-primary { color: var(--text-color-se-primary, $text-color-se-primary); } +.text-color-se-link { color: var(--text-color-se-link, $text-color-se-link); } +.text-color-se-link-dark { color: var(--text-color-se-link-dark, $text-color-se-link-dark); } +.text-color-se-danger { color: var(--text-color-se-danger, $text-color-se-danger); } +.text-color-se-secondary { color: var(--text-color-se-secondary, $text-color-se-secondary); } +.text-color-se-warning { color: var(--text-color-se-warning, $text-color-se-warning); } +.text-color-se-warning-light { color: var(--text-color-se-warning-light, $text-color-se-warning-light); } +.text-color-sf-highlight { color: var(--text-color-sf-highlight, $text-color-sf-highlight); } +.text-color-sf-primary { color: var(--text-color-sf-primary, $text-color-sf-primary); } +.text-color-sf-primary-dark { color: var(--text-color-sf-primary-dark, $text-color-sf-primary-dark); } -.color-primary-light { @include recolor(lighten($color-primary, $color-lighten-percentage), 1); } -.color-primary-dark { @include recolor(darken($color-primary, $color-darken-percentage), 1); } -.color-secondary-light { @include recolor(lighten($color-secondary, $color-lighten-percentage), 1); } -.color-secondary-dark { @include recolor(darken($color-secondary, $color-darken-percentage), 1); } -.color-success-light { @include recolor(lighten($color-success, $color-lighten-percentage), 1); } -.color-success-dark { @include recolor(darken($color-success, $color-darken-percentage), 1); } -.color-danger-light { @include recolor(lighten($color-danger, $color-lighten-percentage), 1); } -.color-danger-dark { @include recolor(darken($color-danger, $color-darken-percentage), 1); } -.color-warning-light { @include recolor(lighten($color-warning, $color-lighten-percentage), 1); } -.color-warning-dark { @include recolor(darken($color-warning, $color-darken-percentage), 1); } -.color-info-light { @include recolor(lighten($color-info, $color-lighten-percentage), 1); } -.color-info-dark { @include recolor(darken($color-info, $color-darken-percentage), 1); } -.color-body-light { @include recolor(lighten($color-body, $color-lighten-percentage), 1); } -.color-body-dark { @include recolor(darken($color-body, $color-darken-percentage), 1); } -.color-muted-light { @include recolor(lighten($color-muted, $color-lighten-percentage), 1); } -.color-muted-dark { @include recolor(darken($color-muted, $color-darken-percentage), 1); } -.color-alt-warning-light { @include recolor(lighten($color-alt-warning, $color-lighten-percentage), 1); } -.color-alt-warning-dark { @include recolor(darken($color-alt-warning, $color-darken-percentage), 1); } -.color-alt-default-light { @include recolor(lighten($color-alt-default, $color-lighten-percentage), 1); } -.color-alt-default-dark { @include recolor(darken($color-alt-default, $color-darken-percentage), 1); } -.color-alt-danger-light { @include recolor(lighten($color-alt-danger, $color-lighten-percentage), 1); } -.color-alt-danger-dark { @include recolor(darken($color-alt-danger, $color-darken-percentage), 1); } -.color-alt-success-light { @include recolor(lighten($color-alt-success, $color-lighten-percentage), 1); } -.color-alt-success-dark { @include recolor(darken($color-alt-success, $color-darken-percentage), 1); } -.color-se-secondary-light { @include recolor(lighten($color-se-secondary, $color-lighten-percentage), 1); } +.text-color-primary-light { color: lighten($text-color-primary, $text-color-lighten-percentage); } +.text-color-primary-dark { color: darken($text-color-primary, $text-color-darken-percentage); } +.text-color-secondary-light { color: lighten($text-color-secondary, $text-color-lighten-percentage); } +.text-color-secondary-dark { color: darken($text-color-secondary, $text-color-darken-percentage); } +.text-color-success-light { color: lighten($text-color-success, $text-color-lighten-percentage); } +.text-color-success-dark { color: darken($text-color-success, $text-color-darken-percentage); } +.text-color-danger-light { color: lighten($text-color-danger, $text-color-lighten-percentage); } +.text-color-danger-dark { color: darken($text-color-danger, $text-color-darken-percentage); } +.text-color-warning-light { color: lighten($text-color-warning, $text-color-lighten-percentage); } +.text-color-warning-dark { color: darken($text-color-warning, $text-color-darken-percentage); } +.text-color-info-light { color: lighten($text-color-info, $text-color-lighten-percentage); } +.text-color-info-dark { color: darken($text-color-info, $text-color-darken-percentage); } +.text-color-body-light { color: lighten($text-color-body, $text-color-lighten-percentage); } +.text-color-body-dark { color: darken($text-color-body, $text-color-darken-percentage); } +.text-color-muted-light { color: lighten($text-color-muted, $text-color-lighten-percentage); } +.text-color-muted-dark { color: darken($text-color-muted, $text-color-darken-percentage); } +.text-color-alt-warning-light { color: lighten($text-color-alt-warning, $text-color-lighten-percentage); } +.text-color-alt-warning-dark { color: darken($text-color-alt-warning, $text-color-darken-percentage); } +.text-color-alt-default-light { color: lighten($text-color-alt-default, $text-color-lighten-percentage); } +.text-color-alt-default-dark { color: darken($text-color-alt-default, $text-color-darken-percentage); } +.text-color-alt-danger-light { color: lighten($text-color-alt-danger, $text-color-lighten-percentage); } +.text-color-alt-danger-dark { color: darken($text-color-alt-danger, $text-color-darken-percentage); } +.text-color-alt-success-light { color: lighten($text-color-alt-success, $text-color-lighten-percentage); } +.text-color-alt-success-dark { color: darken($text-color-alt-success, $text-color-darken-percentage); } +.text-color-se-secondary-light { color: lighten($text-color-se-secondary, $text-color-lighten-percentage); } \ No newline at end of file diff --git a/packages/common/src/styles/extra-styling.scss b/packages/common/src/styles/extra-styling.scss index 8e3c10d1f..ae26ece81 100644 --- a/packages/common/src/styles/extra-styling.scss +++ b/packages/common/src/styles/extra-styling.scss @@ -29,29 +29,28 @@ $slick-padding-max-count: 30; .delete-icon { &:hover { - color: #b14c4a; + color: #b14c4a; } } .edit-icon, .info-icon { &:hover { - color: rgb(0, 153, 255); + color: rgb(0, 153, 255); } } -// margin-0px up to margin-30px -@for $slick-i from 0 through $slick-margin-max-count { - .margin-#{$slick-i}px { margin: #{$slick-i}px; } +@for $percent from 1 through 10 { + .height-#{$percent * 10} { height: #{$percent * 10%} !important; } } -// padding-0px up to padding-30px -@for $slick-i from 0 through $slick-padding-max-count { - .padding-#{$slick-i}px { padding: #{$slick-i}px; } +// margin-0px up to margin-30px +@for $i from 0 through $slick-margin-max-count { + .margin-#{$i}px { margin: #{$i}px; } } -// font-5px up to font-50px -@for $slick-i from 5 through $slick-font-size-count { - .font-#{$slick-i}px { font-size: #{$slick-i}px; } +// padding-0px up to padding-30px +@for $i from 0 through $slick-padding-max-count { + .padding-#{$i}px { padding: #{$i}px; } } .margin-auto { @@ -68,15 +67,17 @@ $slick-padding-max-count: 30; .text-uppercase { text-transform: uppercase !important; } .text-underline { text-decoration: underline !important; } -.vertical-align-bottom { +.vertical-align-bottom, +.vertical-align-middle, +.vertical-align-top { display: inline-block; +} +.vertical-align-bottom { vertical-align: bottom; } .vertical-align-middle { - display: inline-block; vertical-align: middle; } .vertical-align-top { - display: inline-block; vertical-align: top; } diff --git a/packages/common/src/styles/flatpickr-dark.scss b/packages/common/src/styles/flatpickr-dark.scss deleted file mode 100644 index c21192436..000000000 --- a/packages/common/src/styles/flatpickr-dark.scss +++ /dev/null @@ -1,107 +0,0 @@ -/* Flatpickr Dark Theme - only an extract to darken the picker by using .slick-dark-mode */ -.flatpickr-calendar.slick-dark-mode { - background-color: #212121; - box-shadow: 0 1px 2px rgb(255 255 255 / 20%); - border: 1px solid #505050; - - &.arrowTop:before { - border-bottom-color: #505050; - } - &.arrowTop:after { - border-bottom-color: #212121; - } - &.arrowBottom:before { - border-top-color: #20222c; - } - &.arrowBottom:after { - border-top-color: #212121; - } - - .flatpickr-day { - color: rgba(255, 255, 255, 0.95); - &.today { - border-color: #eee; - } - } - .flatpickr-months .flatpickr-prev-month, - .flatpickr-months .flatpickr-next-month { - color: #fff; - fill: #fff; - } - .flatpickr-day.flatpickr-disabled, - .flatpickr-day.flatpickr-disabled:hover, - .flatpickr-day.prevMonthDay, - .flatpickr-day.nextMonthDay, - .flatpickr-day.notAllowed, - .flatpickr-day.notAllowed.prevMonthDay, - .flatpickr-day.notAllowed.nextMonthDay { - color: rgba(255, 255, 255, 0.3); - } - .flatpickr-current-month input.cur-year, - .flatpickr-current-month .flatpickr-monthDropdown-months { - background: #212121; - color: #fff; - } - .flatpickr-time .numInputWrapper span.arrowUp:after, - .flatpickr-current-month .numInputWrapper span.arrowUp:after { - border-bottom-color: #fff; - } - .flatpickr-time .numInputWrapper span.arrowDown:after, - .flatpickr-current-month .numInputWrapper span.arrowDown:after { - border-top-color: #fff; - } - .flatpickr-day.inRange, - .flatpickr-day.prevMonthDay.inRange, - .flatpickr-day.nextMonthDay.inRange, - .flatpickr-day.today.inRange, - .flatpickr-day.prevMonthDay.today.inRange, - .flatpickr-day.nextMonthDay.today.inRange, - .flatpickr-day:hover, - .flatpickr-day.prevMonthDay:hover, - .flatpickr-day.nextMonthDay:hover, - .flatpickr-day:focus, - .flatpickr-day.prevMonthDay:focus, - .flatpickr-day.nextMonthDay:focus { - background: rgb(100, 108, 140); - border-color: rgb(100, 108, 140); - } - - .flatpickr-day.selected { - background: rgb(128, 203, 196); - color: rgb(255, 255, 255); - border-color: rgb(128, 203, 196); - } - &.hasTime .flatpickr-time { - border-top: 1px solid #20222c; - } - .flatpickr-time .flatpickr-time-separator, - .flatpickr-time .flatpickr-am-pm, - .flatpickr-time input { - color: #fff; - } - .numInputWrapper span { - border: 1px solid rgba(255, 255, 255, 0.15); - } - .numInputWrapper:hover { - background: rgba(192, 187, 167, 0.05); - } - .numInputWrapper:hover span { - opacity: 1; - } - .numInputWrapper span:hover, - .numInputWrapper:hover, - .flatpickr-am-pm:hover, - .flatpickr-time input:hover, - .flatpickr-time .flatpickr-am-pm:hover, - .flatpickr-time input:focus, - .flatpickr-time .flatpickr-am-pm:focus, - .flatpickr-current-month .flatpickr-monthDropdown-months:hover { - background: rgba(192, 187, 167, 0.1); - } - .flatpickr-current-month .flatpickr-monthDropdown-months .flatpickr-monthDropdown-month { - background-color: #2e2e2e; - } - span.flatpickr-weekday { - color: #fff; - } -} \ No newline at end of file diff --git a/packages/common/src/styles/flatpickr.min.scss b/packages/common/src/styles/flatpickr.min.scss deleted file mode 100644 index 46c57b7cc..000000000 --- a/packages/common/src/styles/flatpickr.min.scss +++ /dev/null @@ -1,13 +0,0 @@ -.flatpickr-calendar{background:transparent;opacity:0;display:none;text-align:center;visibility:hidden;padding:0;-webkit-animation:none;animation:none;direction:ltr;border:0;font-size:14px;line-height:24px;border-radius:5px;position:absolute;width:307.875px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-touch-action:manipulation;touch-action:manipulation;background:#fff;-webkit-box-shadow:1px 0 0 #e6e6e6,-1px 0 0 #e6e6e6,0 1px 0 #e6e6e6,0 -1px 0 #e6e6e6,0 3px 13px rgba(0,0,0,0.08);box-shadow:1px 0 0 #e6e6e6,-1px 0 0 #e6e6e6,0 1px 0 #e6e6e6,0 -1px 0 #e6e6e6,0 3px 13px rgba(0,0,0,0.08);}.flatpickr-calendar.open,.flatpickr-calendar.inline{opacity:1;max-height:640px;visibility:visible}.flatpickr-calendar.open{display:inline-block;z-index:99999}.flatpickr-calendar.animate.open{-webkit-animation:fpFadeInDown 300ms cubic-bezier(.23,1,.32,1);animation:fpFadeInDown 300ms cubic-bezier(.23,1,.32,1)}.flatpickr-calendar.inline{display:block;position:relative;top:2px}.flatpickr-calendar.static{position:absolute;top:calc(100% + 2px);}.flatpickr-calendar.static.open{z-index:999;display:block}.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+1) .flatpickr-day.inRange:nth-child(7n+7){-webkit-box-shadow:none !important;box-shadow:none !important}.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+2) .flatpickr-day.inRange:nth-child(7n+1){-webkit-box-shadow:-2px 0 0 #e6e6e6,5px 0 0 #e6e6e6;box-shadow:-2px 0 0 #e6e6e6,5px 0 0 #e6e6e6}.flatpickr-calendar .hasWeeks .dayContainer,.flatpickr-calendar .hasTime .dayContainer{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.flatpickr-calendar .hasWeeks .dayContainer{border-left:0}.flatpickr-calendar.showTimeInput.hasTime .flatpickr-time{height:40px;border-top:1px solid #e6e6e6}.flatpickr-calendar.noCalendar.hasTime .flatpickr-time{height:auto}.flatpickr-calendar:before,.flatpickr-calendar:after{position:absolute;display:block;pointer-events:none;border:solid transparent;content:'';height:0;width:0;left:22px}.flatpickr-calendar.rightMost:before,.flatpickr-calendar.rightMost:after{left:auto;right:22px}.flatpickr-calendar:before{border-width:5px;margin:0 -5px}.flatpickr-calendar:after{border-width:4px;margin:0 -4px}.flatpickr-calendar.arrowTop:before,.flatpickr-calendar.arrowTop:after{bottom:100%}.flatpickr-calendar.arrowTop:before{border-bottom-color:#e6e6e6}.flatpickr-calendar.arrowTop:after{border-bottom-color:#fff}.flatpickr-calendar.arrowBottom:before,.flatpickr-calendar.arrowBottom:after{top:100%}.flatpickr-calendar.arrowBottom:before{border-top-color:#e6e6e6}.flatpickr-calendar.arrowBottom:after{border-top-color:#fff}.flatpickr-calendar:focus{outline:0}.flatpickr-wrapper{position:relative;display:inline-block}.flatpickr-months{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}.flatpickr-months .flatpickr-month{background:transparent;color:rgba(0,0,0,0.9);fill:rgba(0,0,0,0.9);height:34px;line-height:1;text-align:center;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:hidden;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}.flatpickr-months .flatpickr-prev-month,.flatpickr-months .flatpickr-next-month{text-decoration:none;cursor:pointer;position:absolute;top:0;height:34px;padding:10px;z-index:3;color:rgba(0,0,0,0.9);fill:rgba(0,0,0,0.9);}.flatpickr-months .flatpickr-prev-month.flatpickr-disabled,.flatpickr-months .flatpickr-next-month.flatpickr-disabled{display:none}.flatpickr-months .flatpickr-prev-month i,.flatpickr-months .flatpickr-next-month i{position:relative}.flatpickr-months .flatpickr-prev-month.flatpickr-prev-month,.flatpickr-months .flatpickr-next-month.flatpickr-prev-month{/* - /*rtl:begin:ignore*/left:0;/* - /*rtl:end:ignore*/}/* - /*rtl:begin:ignore*/ -/* - /*rtl:end:ignore*/ -.flatpickr-months .flatpickr-prev-month.flatpickr-next-month,.flatpickr-months .flatpickr-next-month.flatpickr-next-month{/* - /*rtl:begin:ignore*/right:0;/* - /*rtl:end:ignore*/}/* - /*rtl:begin:ignore*/ -/* - /*rtl:end:ignore*/ -.flatpickr-months .flatpickr-prev-month:hover,.flatpickr-months .flatpickr-next-month:hover{color:#959ea9;}.flatpickr-months .flatpickr-prev-month:hover svg,.flatpickr-months .flatpickr-next-month:hover svg{fill:#f64747}.flatpickr-months .flatpickr-prev-month svg,.flatpickr-months .flatpickr-next-month svg{width:14px;height:14px;}.flatpickr-months .flatpickr-prev-month svg path,.flatpickr-months .flatpickr-next-month svg path{-webkit-transition:fill .1s;transition:fill .1s;fill:inherit}.numInputWrapper{position:relative;height:auto;}.numInputWrapper input,.numInputWrapper span{display:inline-block}.numInputWrapper input{width:100%;}.numInputWrapper input::-ms-clear{display:none}.numInputWrapper input::-webkit-outer-spin-button,.numInputWrapper input::-webkit-inner-spin-button{margin:0;-webkit-appearance:none}.numInputWrapper span{position:absolute;right:0;width:14px;padding:0 4px 0 2px;height:50%;line-height:50%;opacity:0;cursor:pointer;border:1px solid rgba(57,57,57,0.15);-webkit-box-sizing:border-box;box-sizing:border-box;}.numInputWrapper span:hover{background:rgba(0,0,0,0.1)}.numInputWrapper span:active{background:rgba(0,0,0,0.2)}.numInputWrapper span:after{display:block;content:"";position:absolute}.numInputWrapper span.arrowUp{top:0;border-bottom:0;}.numInputWrapper span.arrowUp:after{border-left:4px solid transparent;border-right:4px solid transparent;border-bottom:4px solid rgba(57,57,57,0.6);top:26%}.numInputWrapper span.arrowDown{top:50%;}.numInputWrapper span.arrowDown:after{border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid rgba(57,57,57,0.6);top:40%}.numInputWrapper span svg{width:inherit;height:auto;}.numInputWrapper span svg path{fill:rgba(0,0,0,0.5)}.numInputWrapper:hover{background:rgba(0,0,0,0.05);}.numInputWrapper:hover span{opacity:1}.flatpickr-current-month{font-size:135%;line-height:inherit;font-weight:300;color:inherit;position:absolute;width:75%;left:12.5%;padding:7.48px 0 0 0;line-height:1;height:34px;display:inline-block;text-align:center;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);}.flatpickr-current-month span.cur-month{font-family:inherit;font-weight:700;color:inherit;display:inline-block;margin-left:.5ch;padding:0;}.flatpickr-current-month span.cur-month:hover{background:rgba(0,0,0,0.05)}.flatpickr-current-month .numInputWrapper{width:6ch;width:7ch\0;display:inline-block;}.flatpickr-current-month .numInputWrapper span.arrowUp:after{border-bottom-color:rgba(0,0,0,0.9)}.flatpickr-current-month .numInputWrapper span.arrowDown:after{border-top-color:rgba(0,0,0,0.9)}.flatpickr-current-month input.cur-year{background:transparent;-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;cursor:text;padding:0 0 0 .5ch;margin:0;display:inline-block;font-size:inherit;font-family:inherit;font-weight:300;line-height:inherit;height:auto;border:0;border-radius:0;vertical-align:initial;-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield;}.flatpickr-current-month input.cur-year:focus{outline:0}.flatpickr-current-month input.cur-year[disabled],.flatpickr-current-month input.cur-year[disabled]:hover{font-size:100%;color:rgba(0,0,0,0.5);background:transparent;pointer-events:none}.flatpickr-current-month .flatpickr-monthDropdown-months{appearance:menulist;background:transparent;border:none;border-radius:0;box-sizing:border-box;color:inherit;cursor:pointer;font-size:inherit;font-family:inherit;font-weight:300;height:auto;line-height:inherit;margin:-1px 0 0 0;outline:none;padding:0 0 0 .5ch;position:relative;vertical-align:initial;-webkit-box-sizing:border-box;-webkit-appearance:menulist;-moz-appearance:menulist;width:auto;}.flatpickr-current-month .flatpickr-monthDropdown-months:focus,.flatpickr-current-month .flatpickr-monthDropdown-months:active{outline:none}.flatpickr-current-month .flatpickr-monthDropdown-months:hover{background:rgba(0,0,0,0.05)}.flatpickr-current-month .flatpickr-monthDropdown-months .flatpickr-monthDropdown-month{background-color:transparent;outline:none;padding:0}.flatpickr-weekdays{background:transparent;text-align:center;overflow:hidden;width:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;height:28px;}.flatpickr-weekdays .flatpickr-weekdaycontainer{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}span.flatpickr-weekday{cursor:default;font-size:90%;background:transparent;color:rgba(0,0,0,0.54);line-height:1;margin:0;text-align:center;display:block;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;font-weight:bolder}.dayContainer,.flatpickr-weeks{padding:1px 0 0 0}.flatpickr-days{position:relative;overflow:hidden;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:start;-webkit-align-items:flex-start;-ms-flex-align:start;align-items:flex-start;width:307.875px;}.flatpickr-days:focus{outline:0}.dayContainer{padding:0;outline:0;text-align:left;width:307.875px;min-width:307.875px;max-width:307.875px;-webkit-box-sizing:border-box;box-sizing:border-box;display:inline-block;display:-ms-flexbox;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-wrap:wrap;-ms-flex-pack:justify;-webkit-justify-content:space-around;justify-content:space-around;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1;}.dayContainer + .dayContainer{-webkit-box-shadow:-1px 0 0 #e6e6e6;box-shadow:-1px 0 0 #e6e6e6}.flatpickr-day{background:none;border:1px solid transparent;border-radius:150px;-webkit-box-sizing:border-box;box-sizing:border-box;color:#393939;cursor:pointer;font-weight:400;width:14.2857143%;-webkit-flex-basis:14.2857143%;-ms-flex-preferred-size:14.2857143%;flex-basis:14.2857143%;max-width:39px;height:39px;line-height:39px;margin:0;display:inline-block;position:relative;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;}.flatpickr-day.inRange,.flatpickr-day.prevMonthDay.inRange,.flatpickr-day.nextMonthDay.inRange,.flatpickr-day.today.inRange,.flatpickr-day.prevMonthDay.today.inRange,.flatpickr-day.nextMonthDay.today.inRange,.flatpickr-day:hover,.flatpickr-day.prevMonthDay:hover,.flatpickr-day.nextMonthDay:hover,.flatpickr-day:focus,.flatpickr-day.prevMonthDay:focus,.flatpickr-day.nextMonthDay:focus{cursor:pointer;outline:0;background:#e6e6e6;border-color:#e6e6e6}.flatpickr-day.today{border-color:#959ea9;}.flatpickr-day.today:hover,.flatpickr-day.today:focus{border-color:#959ea9;background:#959ea9;color:#fff}.flatpickr-day.selected,.flatpickr-day.startRange,.flatpickr-day.endRange,.flatpickr-day.selected.inRange,.flatpickr-day.startRange.inRange,.flatpickr-day.endRange.inRange,.flatpickr-day.selected:focus,.flatpickr-day.startRange:focus,.flatpickr-day.endRange:focus,.flatpickr-day.selected:hover,.flatpickr-day.startRange:hover,.flatpickr-day.endRange:hover,.flatpickr-day.selected.prevMonthDay,.flatpickr-day.startRange.prevMonthDay,.flatpickr-day.endRange.prevMonthDay,.flatpickr-day.selected.nextMonthDay,.flatpickr-day.startRange.nextMonthDay,.flatpickr-day.endRange.nextMonthDay{background:#569ff7;-webkit-box-shadow:none;box-shadow:none;color:#fff;border-color:#569ff7}.flatpickr-day.selected.startRange,.flatpickr-day.startRange.startRange,.flatpickr-day.endRange.startRange{border-radius:50px 0 0 50px}.flatpickr-day.selected.endRange,.flatpickr-day.startRange.endRange,.flatpickr-day.endRange.endRange{border-radius:0 50px 50px 0}.flatpickr-day.selected.startRange + .endRange:not(:nth-child(7n+1)),.flatpickr-day.startRange.startRange + .endRange:not(:nth-child(7n+1)),.flatpickr-day.endRange.startRange + .endRange:not(:nth-child(7n+1)){-webkit-box-shadow:-10px 0 0 #569ff7;box-shadow:-10px 0 0 #569ff7}.flatpickr-day.selected.startRange.endRange,.flatpickr-day.startRange.startRange.endRange,.flatpickr-day.endRange.startRange.endRange{border-radius:50px}.flatpickr-day.inRange{border-radius:0;-webkit-box-shadow:-5px 0 0 #e6e6e6,5px 0 0 #e6e6e6;box-shadow:-5px 0 0 #e6e6e6,5px 0 0 #e6e6e6}.flatpickr-day.flatpickr-disabled,.flatpickr-day.flatpickr-disabled:hover,.flatpickr-day.prevMonthDay,.flatpickr-day.nextMonthDay,.flatpickr-day.notAllowed,.flatpickr-day.notAllowed.prevMonthDay,.flatpickr-day.notAllowed.nextMonthDay{color:rgba(57,57,57,0.3);background:transparent;border-color:transparent;cursor:default}.flatpickr-day.flatpickr-disabled,.flatpickr-day.flatpickr-disabled:hover{cursor:not-allowed;color:rgba(57,57,57,0.1)}.flatpickr-day.week.selected{border-radius:0;-webkit-box-shadow:-5px 0 0 #569ff7,5px 0 0 #569ff7;box-shadow:-5px 0 0 #569ff7,5px 0 0 #569ff7}.flatpickr-day.hidden{visibility:hidden}.rangeMode .flatpickr-day{margin-top:1px}.flatpickr-weekwrapper{float:left;}.flatpickr-weekwrapper .flatpickr-weeks{padding:0 12px;-webkit-box-shadow:1px 0 0 #e6e6e6;box-shadow:1px 0 0 #e6e6e6}.flatpickr-weekwrapper .flatpickr-weekday{float:none;width:100%;line-height:28px}.flatpickr-weekwrapper span.flatpickr-day,.flatpickr-weekwrapper span.flatpickr-day:hover{display:block;width:100%;max-width:none;color:rgba(57,57,57,0.3);background:transparent;cursor:default;border:none}.flatpickr-innerContainer{display:block;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;}.flatpickr-rContainer{display:inline-block;padding:0;-webkit-box-sizing:border-box;box-sizing:border-box}.flatpickr-time{text-align:center;outline:0;display:block;height:0;line-height:40px;max-height:40px;-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}.flatpickr-time:after{content:"";display:table;clear:both}.flatpickr-time .numInputWrapper{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;width:40%;height:40px;float:left;}.flatpickr-time .numInputWrapper span.arrowUp:after{border-bottom-color:#393939}.flatpickr-time .numInputWrapper span.arrowDown:after{border-top-color:#393939}.flatpickr-time.hasSeconds .numInputWrapper{width:26%}.flatpickr-time.time24hr .numInputWrapper{width:49%}.flatpickr-time input{background:transparent;-webkit-box-shadow:none;box-shadow:none;border:0;border-radius:0;text-align:center;margin:0;padding:0;height:inherit;line-height:inherit;color:#393939;font-size:14px;position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield;}.flatpickr-time input.flatpickr-hour{font-weight:bold}.flatpickr-time input.flatpickr-minute,.flatpickr-time input.flatpickr-second{font-weight:400}.flatpickr-time input:focus{outline:0;border:0}.flatpickr-time .flatpickr-time-separator,.flatpickr-time .flatpickr-am-pm{height:inherit;float:left;line-height:inherit;color:#393939;font-weight:bold;width:2%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-align-self:center;-ms-flex-item-align:center;align-self:center}.flatpickr-time .flatpickr-am-pm{outline:0;width:18%;cursor:pointer;text-align:center;font-weight:400}.flatpickr-time input:hover,.flatpickr-time .flatpickr-am-pm:hover,.flatpickr-time input:focus,.flatpickr-time .flatpickr-am-pm:focus{background:#eee}.flatpickr-input[readonly]{cursor:pointer}@-webkit-keyframes fpFadeInDown{from{opacity:0;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:1;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes fpFadeInDown{from{opacity:0;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:1;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}} \ No newline at end of file diff --git a/packages/common/src/styles/material-svg-utilities.scss b/packages/common/src/styles/material-svg-utilities.scss deleted file mode 100644 index 544755289..000000000 --- a/packages/common/src/styles/material-svg-utilities.scss +++ /dev/null @@ -1,82 +0,0 @@ -$slick-icon-width-min-size: 8; -$slick-icon-width-max-size: 50; - -@-webkit-keyframes md-spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} -@keyframes md-spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} -@mixin md-icon-rotate($degrees, $rotation) { - transform: rotate($degrees); -} - -.mdi { - &.mdi-v-align-bottom:before { - vertical-align: bottom; - } - &.mdi-v-align-middle:before { - vertical-align: middle; - } - &.mdi-v-align-sub:before { - vertical-align: sub; - } - &.mdi-v-align-super:before { - vertical-align: super; - } - &.mdi-v-align-text-bottom:before { - vertical-align: text-bottom; - } - &.mdi-v-align-text-top:before { - vertical-align: text-top; - } - &.mdi-v-align-top:before { - vertical-align: top; - } - - &.mdi-flip-h { - transform: scaleX(-1); - } - &.mdi-flip-v { - transform: scaleY(-1); - } - &.mdi-pulse { - animation: md-spin 1s infinite steps(8); - } - /* use mdi-spin or mdi-spin-1s to change the speed */ - &.mdi-spin { - align-items: center; - display: inline-flex; - justify-content: center; - animation: md-spin 2s infinite linear; - } - @for $i from 1 through 5 { - &.mdi-spin-#{$i}s { - align-items: center; - display: inline-flex; - justify-content: center; - animation: md-spin #{$i}s infinite linear; - } - } - &.mdi-rotate-45 { @include md-icon-rotate(45deg, 1); } - &.mdi-rotate-90 { @include md-icon-rotate(90deg, 1); } - &.mdi-rotate-135 { @include md-icon-rotate(135deg, 2); } - &.mdi-rotate-180 { @include md-icon-rotate(180deg, 2); } - &.mdi-rotate-220 { @include md-icon-rotate(220deg, 3); } - &.mdi-rotate-270 { @include md-icon-rotate(270deg, 3); } - &.mdi-rotate-315 { @include md-icon-rotate(315deg, 3); } - &.mdi-rotate-45, .mdi-rotate-90, .mdi-rotate-135, .mdi-rotate-180, .mdi-rotate-220 .mdi-rotate-270, .mdi-rotate-315 { - filter: none; - } - - @for $i from $slick-icon-width-min-size through $slick-icon-width-max-size { - &.mdi-#{$i}px { - &:before { - height: #{$i}px; - width: #{$i}px; - } - } - } -} diff --git a/packages/common/src/styles/sass-utilities.scss b/packages/common/src/styles/sass-utilities.scss deleted file mode 100644 index 935f9f7a8..000000000 --- a/packages/common/src/styles/sass-utilities.scss +++ /dev/null @@ -1,48 +0,0 @@ -@use './private'; -$svg-icon-vertical-align: bottom !default; - -@function encodecolor($string) { - @if type-of($string) == 'color' { - $hex: str-slice(ie-hex-str($string), 4); - $string:unquote("#{$hex}"); - } - $string: '%23' + $string; - @return $string; -} - -@mixin recolor($color: #000, $opacity: 1) { - $r: private.private-div(red($color), 255); - $g: private.private-div(green($color), 255); - $b: private.private-div(blue($color), 255); - $a: $opacity; - - // grayscale fallback if SVG from data url is not supported - $lightness: lightness($color); - filter: saturate(0%) brightness(0%) invert($lightness) opacity($opacity); - - // color filter - $svg-filter-id: "recolor"; - filter: url('data:image/svg+xml;utf8,\ - \ - \ - \ - \ - \ - ##{$svg-filter-id}'); -} - -@mixin loadsvg($icon-class, $path-drawing, $fill, $height: 18px, $width: 18px, $display: inline-block, $viewBox: 24) { - #{$icon-class}:before { - height: $height; - width: $width; - display: $display; - vertical-align: $svg-icon-vertical-align; - // margin-top: -1px; // small patch to remove padding all around the SVG - content: url('data:image/svg+xml,'); - } -} diff --git a/packages/common/src/styles/slick-autocomplete.scss b/packages/common/src/styles/slick-autocomplete.scss index 635d45469..a9525d4e7 100644 --- a/packages/common/src/styles/slick-autocomplete.scss +++ b/packages/common/src/styles/slick-autocomplete.scss @@ -48,7 +48,6 @@ & + span:after { animation: md-spin 2s infinite linear; display: inline-block; - font-family: var(--slick-icon-font-family, $slick-icon-font-family); color: var(--slick-autocomplete-loading-icon-color, $slick-autocomplete-loading-icon-color); content: var(--slick-autocomplete-loading-icon, $slick-autocomplete-loading-icon); width: var(--slick-autocomplete-loading-icon-width, $slick-autocomplete-loading-icon-width); diff --git a/packages/common/src/styles/slick-bootstrap.scss b/packages/common/src/styles/slick-bootstrap.scss deleted file mode 100644 index 68cd0b045..000000000 --- a/packages/common/src/styles/slick-bootstrap.scss +++ /dev/null @@ -1,462 +0,0 @@ -/* Mixins for SlickGrid */ -@import './variables'; - -@keyframes fade { - 0%, 100% { background: none } - 50% { background: var(--slick-row-highlight-background-color, $slick-row-highlight-background-color) } -} - -.slickgrid-container { - border-top: var(--slick-container-border-top, $slick-container-border-top); - border-bottom: var(--slick-container-border-bottom, $slick-container-border-bottom); - border-left: var(--slick-container-border-left, $slick-container-border-left); - border-right: var(--slick-container-border-right, $slick-container-border-right); - position: relative; - font-family: var(--slick-font-family, $slick-font-family); - width: 100%; - - @mixin resetSlickCell() { - padding: var(--slick-cell-padding, $slick-cell-padding); - font-size: var(--slick-font-size-base, $slick-font-size-base); - td { - font-size: var(--slick-font-size-base, $slick-font-size-base); - } - body & { - line-height: 20px; - } - } - - // Reset the margin of the checkboxes. The grid - // needs a selection checbox column. Bootstrap gives - // these elements a 4px top margin, which we have to reset - // by aligning to baseline. - input[type="checkbox"] { - vertical-align: baseline; - margin: 0; - } - - .slick-viewport { - height: 100%; - border-top: var(--slick-viewport-border-top, $slick-viewport-border-top); - border-bottom: var(--slick-viewport-border-bottom, $slick-viewport-border-bottom); - border-left: var(--slick-viewport-border-left, $slick-viewport-border-left); - border-right: var(--slick-viewport-border-right, $slick-viewport-border-right); - } - - .grid-canvas { - .slick-row { - position: absolute; - width: 100%; - color: var(--slick-cell-text-color, $slick-cell-text-color); - font-family: var(--slick-cell-font-family, $slick-cell-font-family); - font-weight: var(--slick-cell-font-weight, $slick-cell-font-weight); - - &:hover { - background-color: var(--slick-row-mouse-hover-color, $slick-row-mouse-hover-color); - box-shadow: var(--slick-row-mouse-hover-box-shadow, $slick-row-mouse-hover-box-shadow); - z-index: var(--slick-row-mouse-hover-z-index, $slick-row-mouse-hover-z-index); - } - &.active { - padding: var(--slick-cell-padding, $slick-cell-padding); - } - &.highlighter { - background: orange !important; - transition-property: background; - transition-duration: 3s; - transition-timing-function: ease-in; - } - &.copied { - background: var(--slick-copied-cell-bg-color-transition, $slick-copied-cell-bg-color-transition); - transition: var(--slick-copied-cell-transition, $slick-copied-cell-transition); - } - &.odd { - background-color: var(--slick-cell-odd-background-color, $slick-cell-odd-background-color); - &:hover { - background-color: var(--slick-row-mouse-hover-color, $slick-row-mouse-hover-color); - } - } - &.odd .slick-cell { - &.selected { - background-color: var(--slick-row-selected-color, $slick-row-selected-color); - } - &.copied { - background: var(--slick-copied-cell-bg-color-transition, $slick-copied-cell-bg-color-transition); - transition: var(--slick-copied-cell-transition, $slick-copied-cell-transition); - } - background: inherit; - } - &.highlight { - background: var(--slick-row-highlight-background-color, $slick-row-highlight-background-color); - } - &.highlight-animate { - background: var(--slick-row-highlight-background-color, $slick-row-highlight-background-color) !important; - animation: fade var(--slick-row-highlight-fade-animation, $slick-row-highlight-fade-animation); - } - &.slick-group-totals { - color: var(--slick-group-totals-formatter-color, $slick-group-totals-formatter-color); - background: var(--slick-group-totals-formatter-bgcolor, $slick-group-totals-formatter-bgcolor); - .slick-cell { - font-size: var(--slick-group-totals-formatter-font-size, $slick-group-totals-formatter-font-size); - } - } - - &.slick-rbe-editmode.active .slick-cell, - &.slick-rbe-editmode .slick-cell { - background-color: var(--slick-row-based-edit-editmode-bgcolor, $slick-row-based-edit-editmode-bgcolor); - - &:hover { - background-color: var(--slick-row-based-edit-editmode-hover-bgcolor, $slick-row-based-edit-editmode-hover-bgcolor); - - .active { - background-color: var(--slick-row-based-edit-editmode-active-hover-bgcolor, $slick-row-based-edit-editmode-active-hover-bgcolor) !important; - } - } - - .active { - background-color: var(--slick-row-based-edit-editmode-active-bgcolor, $slick-row-based-edit-editmode-active-bgcolor); - - &:hover { - background-color: var(--slick-row-based-edit-editmode-active-hover-bgcolor, $slick-row-based-edit-editmode-active-hover-bgcolor); - } - } - } - } - .slick-cell, .slick-headerrow-column { - border-top: var(--slick-cell-border-top, $slick-cell-border-top); - border-bottom: var(--slick-cell-border-bottom, $slick-cell-border-bottom); - border-left: var(--slick-cell-border-left, $slick-cell-border-left); - border-right: var(--slick-cell-border-right, $slick-cell-border-right); - box-shadow: var(--slick-cell-box-shadow, $slick-cell-box-shadow); - } - - .even { - background-color: var(--slick-cell-even-background-color, $slick-cell-even-background-color); - } - - - .slick-cell { - @include resetSlickCell(); - - &.slick-rbe-unsaved-cell { - background-color: var(--slick-row-based-edit-unsaved-cell-bgcolor, $slick-row-based-edit-unsaved-cell-bgcolor) !important; - } - - a, a:visited, .ui-widget-content a, .ui-widget-content a:visited { - color: var(--slick-link-color, $slick-link-color); - } - a:hover, .ui-widget-content a:hover { - color: var(--slick-link-color-hover, $slick-link-color-hover); - border-bottom: none; - } - table { - height: 100%; - padding: 0; - background: none; - } - td { - padding: 0; - vertical-align: middle; - text-align: left; - } - &.selected { - background-color: var(--slick-row-selected-color, $slick-row-selected-color); - } - &.copied { - background: var(--slick-copied-cell-bg-color-transition, $slick-copied-cell-bg-color-transition); - transition: var(--slick-copied-cell-transition, $slick-copied-cell-transition); - } - select:not([multiple]).form-control { - height: 100%; - padding: 0; - } - .slick-group-title { - height: var(--slick-draggable-group-title-height, $slick-draggable-group-title-height); - line-height: var(--slick-draggable-group-title-line-height, $slick-draggable-group-title-line-height); - vertical-align: var(--slick-draggable-group-title-vertical-align, $slick-draggable-group-title-vertical-align); - } - .slick-group-toggle { - cursor: pointer; - display: inline-block; - color: var(--slick-icon-group-color, $slick-icon-group-color); - font-weight: var(--slick-icon-group-font-weight, $slick-icon-group-font-weight); - width: var(--slick-icon-group-width, $slick-icon-group-width); - height: var(--slick-icon-group-height, $slick-icon-group-height); - margin-right: var(--slick-icon-group-margin-right, $slick-icon-group-margin-right); - - &.expanded:before { - display: inline-block; - content: var(--slick-icon-group-expanded, $slick-icon-group-expanded); - font-family: var(--slick-icon-font-family, $slick-icon-font-family); - font-size: var(--slick-icon-group-font-size, $slick-icon-group-font-size); - width: var(--slick-icon-group-width, $slick-icon-group-width); - vertical-align: var(--slick-icon-group-vertical-align, $slick-icon-group-vertical-align); - } - - &.collapsed:before { - display: inline-block; - content: var(--slick-icon-group-collapsed, $slick-icon-group-collapsed); - font-family: var(--slick-icon-font-family, $slick-icon-font-family); - font-size: var(--slick-icon-group-font-size, $slick-icon-group-font-size); - width: var(--slick-icon-group-width, $slick-icon-group-width); - vertical-align: var(--slick-icon-group-vertical-align, $slick-icon-group-vertical-align); - } - } - } - } - - .slick-header { - border-top: var(--slick-header-border-top, $slick-header-border-top); - border-right: var(--slick-header-border-right, $slick-header-border-right); - border-bottom: var(--slick-header-border-bottom, $slick-header-border-bottom); - border-left: var(--slick-header-border-left, $slick-header-border-left); - width: 100%; - box-shadow: none !important; - } - - .slick-headerrow { - border-bottom: var(--slick-header-filter-row-border-bottom, $slick-header-filter-row-border-bottom); - border-top: var(--slick-header-filter-row-border-top, $slick-header-filter-row-border-top); - border-left: var(--slick-header-filter-row-border-left, $slick-header-filter-row-border-left); - border-right: var(--slick-header-filter-row-border-right, $slick-header-filter-row-border-right); - - .slick-headerrow-columns { - .slick-headerrow-column { - border: none; - padding: var(--slick-header-row-filter-padding, $slick-header-row-filter-padding); - background: var(--slick-header-row-background-color, $slick-header-row-background-color); - } - .slick-headerrow-column input, - .slick-headerrow-column select, - .slick-headerrow-column textarea { - margin-right: 0; - padding: var(--slick-header-input-padding, $slick-header-input-padding); - height: var(--slick-header-input-height, $slick-header-input-height); - box-sizing: border-box; - } - } - } - - .slick-header-columns { - background: var(--slick-grid-header-background, $slick-grid-header-background); - background-color: var(--slick-header-background-color, $slick-header-background-color); - width: calc(100% - #{var(--slick-header-scroll-width-to-remove, $slick-header-scroll-width-to-remove)}); - - [id$="checkbox_selector"] { - justify-content: center; - display: flex; - } - - .slick-header-sortable { - .slick-column-name { - margin-left: 0; - } - } - - .slick-header-column { - height: var(--slick-header-column-height, $slick-header-column-height); - line-height: var(--slick-font-size-base, $slick-font-size-base); - margin: 0; - border-top: var(--slick-header-column-border-top, $slick-header-column-border-top); - border-right: var(--slick-header-column-border-right, $slick-header-column-border-right); - border-bottom: var(--slick-header-column-border-bottom, $slick-header-column-border-bottom); - border-left: var(--slick-header-column-border-left, $slick-header-column-border-left); - white-space: normal; - &.ui-state-default { - @include resetSlickCell(); - } - .slick-column-name { - margin-right: var(--slick-header-column-name-margin-right, $slick-header-column-name-margin-right); - } - - @mixin ResetColumns () { - /* like TH */ - background: var(--slick-header-background-color, $slick-header-background-color); - font-family: var(--slick-font-family, $slick-font-family); - color: var(--slick-header-text-color, $slick-header-text-color); - font-size: var(--slick-header-font-size, $slick-header-font-size); - font-weight: var(--slick-header-font-weight, $slick-header-font-weight); - a, a:visited { - color: var(--slick-text-color, $slick-text-color); - } - a:hover { - color: var(--slick-hover-header-color, $slick-hover-header-color); - } - } - - @include ResetColumns (); - &.ui-state-default { - @include ResetColumns (); - } - - &.slick-header-column-sorted { - font-style: normal; - color: var(--slick-sorting-header-color, $slick-sorting-header-color); - } - &:hover { - color: var(--slick-hover-header-color, $slick-hover-header-color); - } - - /* when sorting is possible and there's not yet a sort applied on the column - we could display the sort ascending icon (with an opacity) as a hint */ - &.ui-sortable-handle.ui-state-hover:not(.slick-header-column-sorted) { - .slick-sort-indicator:before { - content: var(--slick-icon-sort-asc, $slick-icon-sort-asc); - font-family: var(--slick-icon-font-family, $slick-icon-font-family); - font-size: var(--slick-icon-sort-font-size, $slick-icon-sort-font-size); - opacity: var(--slick-sort-indicator-hint-opacity, $slick-sort-indicator-hint-opacity); - display: inline-block; - width: var(--slick-icon-sort-width, $slick-icon-sort-width); - } - } - - .slick-sort-indicator { - background: none; - font-family: var(--slick-icon-font-family, $slick-icon-font-family); - font-size: var(--slick-icon-font-size, $slick-icon-font-size); - position: absolute; - display: inline-block; - color: var(--slick-icon-sort-color, $slick-icon-sort-color); - width: 8px; - height: 5px; - left: auto; - right: var(--slick-icon-sort-position-right, $slick-icon-sort-position-right); - top: var(--slick-icon-sort-position-top, $slick-icon-sort-position-top); - } - .slick-sort-indicator-numbered { - font-family: var(--slick-font-family, $slick-font-family); - font-size: var(--slick-sort-indicator-number-font-size, $slick-sort-indicator-number-font-size); - position: absolute; - display: inline-block; - color: var(--slick-icon-sort-color, $slick-icon-sort-color); - width: var(--slick-sort-indicator-number-width, $slick-sort-indicator-number-width); - left: var(--slick-sort-indicator-number-left, $slick-sort-indicator-number-left); - right: var(--slick-sort-indicator-number-right, $slick-sort-indicator-number-right); - top: var(--slick-sort-indicator-number-top, $slick-sort-indicator-number-top); - } - .slick-sort-indicator-asc:before { - content: var(--slick-icon-sort-asc, $slick-icon-sort-asc); - font-family: var(--slick-icon-font-family, $slick-icon-font-family); - font-size: var(--slick-icon-sort-font-size, $slick-icon-sort-font-size); - opacity: 1; - display: inline-block; - width: var(--slick-icon-sort-width, $slick-icon-sort-width); - } - .slick-sort-indicator-desc:before { - content: var(--slick-icon-sort-desc, $slick-icon-sort-desc); - display: inline-block; - opacity: 1; - font-size: var(--slick-icon-sort-font-size, $slick-icon-sort-font-size); - width: var(--slick-icon-sort-width, $slick-icon-sort-width); - } - .slick-resizable-handle { - width: 7px; - right: 0; - z-index: 1; - &:hover { - border-bottom: var(--slick-header-resizable-hover-border-bottom, $slick-header-resizable-hover-border-bottom); - border-left: var(--slick-header-resizable-hover-border-left, $slick-header-resizable-hover-border-left); - border-right: var(--slick-header-resizable-hover-border-right, $slick-header-resizable-hover-border-right); - border-top: var(--slick-header-resizable-hover-border-top, $slick-header-resizable-hover-border-top); - width: var(--slick-header-resizable-hover-width, $slick-header-resizable-hover-width); - border-radius: var(--slick-header-resizable-hover-border-radius, $slick-header-resizable-hover-border-radius); - right: var(--slick-header-resizable-hover-right, $slick-header-resizable-hover-right); - height: var(--slick-header-resizable-hover-height, $slick-header-resizable-hover-height); - top: var(--slick-header-resizable-hover-top, $slick-header-resizable-hover-top); - opacity: var(--slick-header-resizable-hover-opacity, $slick-header-resizable-hover-opacity); - } - } - &.unorderable { - background-color: var(--slick-grid-header-unorderable-bg-color, $slick-grid-header-unorderable-bg-color); - } - } - } - - /** Header Grouping **/ - .slick-preheader-panel.ui-state-default { - border-bottom: var(--slick-preheader-border-bottom, $slick-preheader-border-bottom); - - .slick-header-columns { - border-top: var(--slick-preheader-border-top, $slick-preheader-border-top); - - .slick-header-column { - height: var(--slick-preheader-height, $slick-preheader-height); - border-left: var(--slick-preheader-border-left, $slick-preheader-border-left); - border-right: var(--slick-preheader-border-right, $slick-preheader-border-right); - font-size: var(--slick-preheader-font-size, $slick-preheader-font-size); - justify-content: var(--slick-preheader-grouped-title-justify, $slick-preheader-grouped-title-justify); - display: var(--slick-preheader-grouped-title-display, $slick-preheader-grouped-title-display); - } - .slick-header-column:first-child { - border-left: var(--slick-preheader-border-left-first-element, $slick-preheader-border-left-first-element); - } - .slick-header-column:last-child { - border-right: var(--slick-preheader-border-right-last-element, $slick-preheader-border-right-last-element); - } - } - } - - /** Frozen/Pinned styling */ - - .slick-row .slick-cell.frozen:last-child, - .slick-footerrow-column.frozen:last-child { - border-right: var(--slick-frozen-border-right, $slick-frozen-border-right); - } - .slick-header-column.frozen:last-child { - border-right: var(--slick-frozen-header-row-border-right, $slick-frozen-header-row-border-right); - } - .slick-pane-left { - .slick-preheader-panel .slick-header-column.frozen:last-child { - border-right: var(--slick-frozen-preheader-row-border-right, $slick-frozen-preheader-row-border-right); - } - } - .slick-headerrow-column.frozen:last-child { - border-right: var(--slick-frozen-filter-row-border-right, $slick-frozen-filter-row-border-right); - } - - .slick-pane-bottom { - border-top: var(--slick-frozen-border-bottom, $slick-frozen-border-bottom); - } - .slick-viewport-bottom.slick-viewport-right { - overflow-y: var(--slick-frozen-overflow-right, $slick-frozen-overflow-right) !important; - } - .input-group { - display: flex; - - > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) { - margin-left: 0; - &.ui-slider-horizontal { - margin-left: 10px; - } - } - - .input-group-append, - .input-group-prepend { - display: inline-flex; - width: auto; - } - - .input-group-addon { - input { - flex: 1 1 auto; - width: 1%; - } - .input-group-text { - height: 100%; - } - &.input-group-append { - .input-group-text { - margin-left: -1px; - border-top-left-radius: 0; - border-bottom-left-radius: 0; - } - } - &.input-group-prepend { - .input-group-text { - margin-right: -1px; - border-top-right-radius: 0; - border-bottom-right-radius: 0; - } - } - } - } -} diff --git a/packages/common/src/styles/slick-component.scss b/packages/common/src/styles/slick-component.scss index 424e47d3a..477eaa548 100644 --- a/packages/common/src/styles/slick-component.scss +++ b/packages/common/src/styles/slick-component.scss @@ -1,5 +1,6 @@ /* pagination/pagination variables */ @import './variables'; +@import './svg-utilities'; // ---------------------------------------------- // Slick Footer Component @@ -44,6 +45,9 @@ // ---------------------------------------------- .slick-empty-data-warning { + display: flex; + align-items: center; + column-gap: 5px; position: relative; color: var(--slick-empty-data-warning-color, $slick-empty-data-warning-color); font-family: var(--slick-empty-data-warning-font-family, $slick-empty-data-warning-font-family); @@ -53,6 +57,11 @@ margin: var(--slick-empty-data-warning-margin, $slick-empty-data-warning-margin); padding: var(--slick-empty-data-warning-padding, $slick-empty-data-warning-padding); z-index: var(--slick-empty-data-warning-z-index, $slick-empty-data-warning-z-index); + div { + display: flex; + align-items: center; + column-gap: 5px; + } } @@ -80,7 +89,7 @@ padding: 6px; } - .ui-icon-container { + .slick-icon-container { display: inline-block; border-color: var(--slick-pagination-border-color, $slick-pagination-border-color); } @@ -96,9 +105,11 @@ .slick-page-number { vertical-align: top; - margin-top: 6px; - display: inline-block; + display: inline-flex; + align-items: center; + column-gap: 4px; padding: 0 5px; + height: inherit; input { background-color: var(--slick-pagination-page-input-bgcolor, $slick-pagination-page-input-bgcolor); @@ -125,66 +136,65 @@ .page-item { cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + border: 1px solid; + padding: var(--slick-pagination-button-padding, $slick-pagination-button-padding); + border-color: var(--slick-pagination-button-border-color, $slick-pagination-button-border-color); - a[class*="icon-seek-"] { - border-color: var(--slick-pagination-button-border-color, $slick-pagination-button-border-color); - color: var(--slick-pagination-icon-color, $slick-pagination-icon-color); - text-decoration: none; - font-family: var(--slick-icon-font-family, $slick-icon-font-family); - line-height: var(--slick-pagination-icon-line-height, $slick-pagination-icon-line-height); - -webkit-text-stroke: var(--slick-pagination-icon-seek-text-stroke, $slick-pagination-icon-seek-text-stroke); - padding: var(--slick-pagination-button-padding, $slick-pagination-button-padding); - } - a[class*="icon-seek-"]:hover { + &:hover { background-color: var(--slick-pagination-button-hover-color, $slick-pagination-button-hover-color); } &:first-child { - a, span { - border-top-left-radius: var(--slick-pagination-button-border-radius, $slick-pagination-button-border-radius); - border-bottom-left-radius: var(--slick-pagination-button-border-radius, $slick-pagination-button-border-radius); - } + border-top-left-radius: var(--slick-pagination-button-border-radius, $slick-pagination-button-border-radius); + border-bottom-left-radius: var(--slick-pagination-button-border-radius, $slick-pagination-button-border-radius); } &:last-child { - a, span { - border-top-right-radius: var(--slick-pagination-button-border-radius, $slick-pagination-button-border-radius); - border-bottom-right-radius: var(--slick-pagination-button-border-radius, $slick-pagination-button-border-radius); - } + border-top-right-radius: var(--slick-pagination-button-border-radius, $slick-pagination-button-border-radius); + border-bottom-right-radius: var(--slick-pagination-button-border-radius, $slick-pagination-button-border-radius); } - .icon-seek-first:before { - content: var(--slick-pagination-icon-seek-first, $slick-pagination-icon-seek-first); - width: var(--slick-pagination-icon-seek-first-width, $slick-pagination-icon-seek-first-width); + // to make button borders overlap + &.seek-prev, &.seek-end { + margin-left: -1px; } - .icon-seek-prev:before { - content: var(--slick-pagination-icon-seek-prev, $slick-pagination-icon-seek-prev); - width: var(--slick-pagination-icon-seek-prev-width, $slick-pagination-icon-seek-prev-width); + + a.icon-seek-first, + a.icon-seek-prev, + a.icon-seek-next, + a.icon-seek-end { + background-color: currentColor; + height: var(--slick-pagination-icon-size, $slick-pagination-icon-size); + width: var(--slick-pagination-icon-size, $slick-pagination-icon-size); } - .icon-seek-next:before { - content: var(--slick-pagination-icon-seek-next, $slick-pagination-icon-seek-next); - width: var(--slick-pagination-icon-seek-next-width, $slick-pagination-icon-seek-next-width); + a.icon-seek-first { + @include generateSvgStyle('slick-pagination-icon-seek-first-svg', $slick-pagination-icon-seek-first-svg-path); } - .icon-seek-end:before { - content: var(--slick-pagination-icon-seek-end, $slick-pagination-icon-seek-end); - - width: var(--slick-pagination-icon-seek-end-width, $slick-pagination-icon-seek-end-width); + a.icon-seek-prev { + @include generateSvgStyle('slick-pagination-icon-seek-prev-svg', $slick-pagination-icon-seek-prev-svg-path); + margin-left: -1px; } - .icon-seek-first:before, - .icon-seek-prev:before, - .icon-seek-next:before, - .icon-seek-end:before { - display: block; - height: var(--slick-pagination-icon-height, $slick-pagination-icon-height); + a.icon-seek-next { + @include generateSvgStyle('slick-pagination-icon-seek-next-svg', $slick-pagination-icon-seek-next-svg-path); + } + a.icon-seek-end { + @include generateSvgStyle('slick-pagination-icon-seek-end-svg', $slick-pagination-icon-seek-end-svg-path); + margin-left: -1px; } - } - .page-item.disabled { - cursor: not-allowed; - font-weight: normal; a[class*="icon-seek-"] { - color: var(--slick-pagination-icon-seek-color, $slick-pagination-icon-seek-disabled-color); + color: var(--slick-pagination-icon-color, $slick-pagination-icon-color); + } + + &.disabled { + cursor: not-allowed; background-color: var(--slick-pagination-icon-seek-background-color, $slick-pagination-icon-seek-disabled-bg-color); - border-color: var(--slick-pagination-icon-seek-border-color, $slick-pagination-icon-seek-disabled-border-color); + border-color: var(--slick-pagination-button-border-disabled-color, $slick-pagination-button-border-disabled-color); + a[class*="icon-seek-"] { + color: var(--slick-pagination-icon-seek-disabled-color, $slick-pagination-icon-seek-disabled-color); + } } } } diff --git a/packages/common/src/styles/slick-editors.scss b/packages/common/src/styles/slick-editors.scss index 6d1601dd8..f8c99763e 100644 --- a/packages/common/src/styles/slick-editors.scss +++ b/packages/common/src/styles/slick-editors.scss @@ -1,5 +1,6 @@ @import './variables'; @import './slick.layout'; +@import './svg-utilities'; .slick-cell { input.dual-editor-text, @@ -7,6 +8,7 @@ border: var(--slick-text-editor-border, $slick-text-editor-border); border-radius: var(--slick-text-editor-border-radius, $slick-text-editor-border-radius); background: var(--slick-text-editor-background, $slick-text-editor-background); + color: var(--slick-text-editor-color, $slick-text-editor-color); padding-bottom: var(--slick-text-editor-padding-bottom, $slick-text-editor-padding-bottom); padding-left: var(--slick-text-editor-padding-left, $slick-text-editor-padding-left); padding-right: var(--slick-text-editor-padding-right, $slick-text-editor-padding-right); @@ -32,9 +34,12 @@ margin-left: var(--slick-text-editor-right-input-margin-left, $slick-text-editor-right-input-margin-left); } - &[readonly] { + &[readonly]:not(.date-picker) { background-color: var(--slick-text-editor-readonly-color, $slick-text-editor-readonly-color); } + &.date-picker { + cursor: pointer; + } } .slider-editor { @@ -65,11 +70,20 @@ } .autocomplete-container.input-group, - .flatpickr.input-group { + .vanilla-picker.input-group { + display: flex; + align-items: center; + flex: 1; height: var(--slick-date-editor-height, $slick-date-editor-height); .input-group-btn { &.input-group-append { + display: inline-flex; + align-items: center; + height: 100%; + .btn { + display: inline-flex; + align-items: center; border-top-left-radius: 0px; border-bottom-left-radius: 0px; margin-left: -1px; @@ -86,36 +100,15 @@ &:hover:not([disabled]) { background-color: var(--slick-input-group-btn-hover-bg-color, $slick-input-group-btn-hover-bg-color); // 1px solid #6c757d; } - &.icon-clear { + .icon-clear { display: flex; align-items: center; - } - &.icon-clear:before { - font-family: var(--slick-icon-font-family, $slick-icon-font-family); - font-size: var(--slick-editor-input-group-clear-btn-icon-size, $slick-editor-input-group-clear-btn-icon-size); - content: var(--slick-editor-input-group-clear-btn-icon, $slick-editor-input-group-clear-btn-icon); - display: inline-block; - height: var(--slick-editor-input-group-clear-btn-icon-height, $slick-editor-input-group-clear-btn-icon-height); - width: var(--slick-editor-input-group-clear-btn-icon-width, $slick-editor-input-group-clear-btn-icon-width); - } - } - } - } - .flatpickr-alt-input { - cursor: pointer; - height: var(--slick-date-editor-height, $slick-date-editor-height); - border-top-left-radius: var(--slick-text-editor-border-radius, $slick-text-editor-border-radius) !important; - border-bottom-left-radius: var(--slick-text-editor-border-radius, $slick-text-editor-border-radius) !important; - padding: var(--slick-date-editor-input-padding, $slick-date-editor-input-padding); + background-color: currentColor; + height: 1em; + width: 1em; - &.editor-text { - cursor: pointer; - background-color: var(--slick-flatpickr-bgcolor, $slick-flatpickr-bgcolor); - - &:focus { - outline: 0; - border-color: var(--slick-date-editor-focus-border-color, $slick-date-editor-focus-border-color); - box-shadow: var(--slick-date-editor-focus-box-shadow, $slick-date-editor-focus-box-shadow); + @include generateSvgStyle('slick-editor-input-group-clear-btn-icon-svg', $slick-editor-input-group-clear-btn-icon-svg-path); + } } } } @@ -218,12 +211,16 @@ color: var(--slick-editor-modal-reset-btn-color, $slick-editor-modal-reset-btn-color); background-color: var(--slick-editor-modal-reset-btn-bg-color, $slick-editor-modal-reset-btn-bg-color); float: right; + span.mdi { + margin-right: 5px; + } } } .btn-editor-reset, .reset-form.btn, .footer-buttons .btn { + display: inline-flex; margin: var(--slick-editor-modal-footer-btn-margin, $slick-editor-modal-footer-btn-margin); height: var(--slick-editor-modal-footer-btn-height, $slick-editor-modal-footer-btn-height); border: var(--slick-editor-modal-footer-btn-border, $slick-editor-modal-footer-btn-border); @@ -462,9 +459,12 @@ } .autocomplete-container.input-group, - .flatpickr.input-group { - height: var(--slick-date-editor-height, $slick-date-editor-height); + .vanilla-picker.input-group { + display: flex; + align-items: center; + height: 100%; .input-group-btn { + height: 100%; min-width: 28px; .btn { min-width: 28px; @@ -474,8 +474,9 @@ } } } - .flatpickr-input.form-control, .flatpickr-alt-input[readonly] { - background-color: var(--slick-flatpickr-bgcolor, $slick-flatpickr-bgcolor); + .vanilla-picker.form-control { + cursor: pointer; + background-color: var(--slick-date-picker-bg-color, $slick-date-picker-bg-color); &:disabled { background-color: var(--slick-editor-input-disabled-color, $slick-editor-input-disabled-color); cursor: initial; diff --git a/packages/common/src/styles/slick-filters.scss b/packages/common/src/styles/slick-filters.scss index e020d9648..a1aa78699 100644 --- a/packages/common/src/styles/slick-filters.scss +++ b/packages/common/src/styles/slick-filters.scss @@ -10,7 +10,7 @@ $slick-filled-filter-font-weight: 400 !default; .slick-headerrow { input.search-filter.filled, .search-filter.filled input, - .search-filter.filled input.flatpickr-input, + .search-filter.filled .date-picker input, .search-filter.filled .input-group-addon.slider-value, .search-filter.filled .input-group-addon.slider-range-value, .search-filter.filled .input-group-addon select { @@ -32,6 +32,8 @@ $slick-filled-filter-font-weight: 400 !default; box-shadow: var(--slick-filled-filter-box-shadow, $slick-filled-filter-box-shadow); border: var(--slick-filled-filter-border, $slick-filled-filter-border); span { + display: inline-flex; + align-items: center; font-weight: var(--slick-filled-filter-font-weight, $slick-filled-filter-font-weight); color: var(--slick-filled-filter-color, $slick-filled-filter-color); } diff --git a/packages/common/src/styles/slick-grid.scss b/packages/common/src/styles/slick-grid.scss index 1b2ee7987..13fc63c2e 100644 --- a/packages/common/src/styles/slick-grid.scss +++ b/packages/common/src/styles/slick-grid.scss @@ -1,16 +1,17 @@ @import './variables'; // ---------------------------------------------- -// default theme +// Slick Grid default theme // ---------------------------------------------- +@keyframes fade { + 0%, 100% { background: none } + 50% { background: var(--slick-row-highlight-background-color, $slick-row-highlight-background-color) } +} + @keyframes slickgrid-invalid-highlight { - from { - box-shadow: 0 0 6px red; - } - to { - box-shadow: none; - } + from { box-shadow: 0 0 6px red; } + to { box-shadow: none; } } .full-height { @@ -19,76 +20,119 @@ .grid-pane { width: 100%; } +.pointer { + cursor: pointer; +} - .pointer { - cursor: pointer; - } - .slickgrid-container { - .slick-header-columns, - .slick-header-column { - box-sizing: content-box !important; /* this here only for Firefox! */ - } - .slick-header-column:hover { - background: $slick-header-column-background-hover - } - - .slick-header-column-active { - background-color: var(--slick-header-column-background-active, $slick-header-column-background-active) !important; - } - - .slick-headerrow { - background: var(--slick-grid-header-background, $slick-grid-header-background); - } - .grid-canvas { - background: var(--slick-canvas-bg-color, $slick-canvas-bg-color); - } - - .slick-row { - background: inherit; - border: 0; - line-height: 20px; - - .slick-cell { - background: inherit; - border: 1px transparent; - box-sizing: border-box; - - &.invalid { - border-color: red; - animation-duration: 0.2s; - animation-name: slickgrid-invalid-highlight; - } - - &.active { - box-shadow: var(--slick-cell-active-box-shadow, $slick-cell-active-box-shadow); - border: var(--slick-cell-active-border, $slick-cell-active-border); - z-index: var(--slick-cell-active-z-index, $slick-cell-active-z-index); - - // We compensate for the all-around border (now 1px at top and left too!) - padding: var(--slick-cell-padding, $slick-cell-padding); - - input.dual-editor-text { - width: calc(50% + 1px - 5px); // 1px (is 2px / 2) and 5px (is space between the 2 inputs) - height: 100%; - outline: 0; - transform: translate(0, -2px); - } - } - - &.slick-rbe-unsaved-cell { - background-color: var(--slick-row-based-edit-unsaved-cell-bgcolor, $slick-row-based-edit-unsaved-cell-bgcolor) !important; - } - } +.slickgrid-container { + overflow: hidden; + outline: 0; + position: relative; + box-sizing: content-box; + width: 100%; + border-top: var(--slick-container-border-top, $slick-container-border-top); + border-bottom: var(--slick-container-border-bottom, $slick-container-border-bottom); + border-left: var(--slick-container-border-left, $slick-container-border-left); + border-right: var(--slick-container-border-right, $slick-container-border-right); + font-family: var(--slick-font-family, $slick-font-family); + + // Reset the margin of the checkboxes. The grid + // needs a selection checbox column. Bootstrap gives + // these elements a 4px top margin, which we have to reset + // by aligning to baseline. + input[type="checkbox"] { + vertical-align: baseline; + margin: 0; + } + + .slick-group-header-column, + .slick-header-columns, + .slick-header-column { + box-sizing: content-box !important; /* this here only for Firefox! */ + } + .slick-header-column:hover { + background: var(--slick-header-column-background-hover, $slick-header-column-background-hover); + } + + .slick-header-column-active { + background-color: var(--slick-header-column-background-active, $slick-header-column-background-active) !important; + } + + .slick-headerrow { + background: var(--slick-grid-header-background, $slick-grid-header-background); + } + .grid-canvas { + background: var(--slick-canvas-bg-color, $slick-canvas-bg-color); + } - &.active-row .slick-cell { - background-color: rgb(226, 255, 253); - } + .slick-group { + border-bottom: var(--slick-group-border-bottom, $slick-group-border-bottom); + } - &.active-row.odd .slick-cell { - background-color: $slick-cell-odd-active-background-color; - } + .slick-sortable-placeholder { + background: var(--slick-header-column-sortable-background-hover, $slick-header-column-sortable-background-hover); + } - &.slick-rbe-editmode .slick-cell { + .slick-row { + position: absolute; + width: 100%; + border: 0; + line-height: 20px; + color: var(--slick-cell-text-color, $slick-cell-text-color); + font-family: var(--slick-cell-font-family, $slick-cell-font-family); + font-weight: var(--slick-cell-font-weight, $slick-cell-font-weight); + + &:hover { + background-color: var(--slick-row-mouse-hover-color, $slick-row-mouse-hover-color); + box-shadow: var(--slick-row-mouse-hover-box-shadow, $slick-row-mouse-hover-box-shadow); + z-index: var(--slick-row-mouse-hover-z-index, $slick-row-mouse-hover-z-index); + } + &.active { + padding: var(--slick-cell-padding, $slick-cell-padding); + } + &.highlighter { + background: orange !important; + transition-property: background; + transition-duration: 3s; + transition-timing-function: ease-in; + } + &.copied { + background: var(--slick-copied-cell-bg-color-transition, $slick-copied-cell-bg-color-transition); + transition: var(--slick-copied-cell-transition, $slick-copied-cell-transition); + } + &.odd { + background-color: var(--slick-cell-odd-background-color, $slick-cell-odd-background-color); + &:hover { + background-color: var(--slick-row-mouse-hover-color, $slick-row-mouse-hover-color); + } + } + &.odd .slick-cell { + &.selected { + background-color: var(--slick-row-selected-color, $slick-row-selected-color); + } + &.copied { + background: var(--slick-copied-cell-bg-color-transition, $slick-copied-cell-bg-color-transition); + transition: var(--slick-copied-cell-transition, $slick-copied-cell-transition); + } + background: inherit; + } + &.highlight { + background: var(--slick-row-highlight-background-color, $slick-row-highlight-background-color); + } + &.highlight-animate { + background: var(--slick-row-highlight-background-color, $slick-row-highlight-background-color) !important; + animation: fade var(--slick-row-highlight-fade-animation, $slick-row-highlight-fade-animation); + } + &.slick-group-totals { + color: var(--slick-group-totals-formatter-color, $slick-group-totals-formatter-color); + background: var(--slick-group-totals-formatter-bgcolor, $slick-group-totals-formatter-bgcolor); + .slick-cell { + font-size: var(--slick-group-totals-formatter-font-size, $slick-group-totals-formatter-font-size); + } + } + + &.slick-rbe-editmode.active .slick-cell, + &.slick-rbe-editmode .slick-cell { background-color: var(--slick-row-based-edit-editmode-bgcolor, $slick-row-based-edit-editmode-bgcolor); &:hover { @@ -107,42 +151,63 @@ } } } - } - .slick-group { - border-bottom: var(--slick-group-border-bottom, $slick-group-border-bottom); - } + .slick-cell { + &.invalid { + border-color: red; + animation-duration: 0.2s; + animation-name: slickgrid-invalid-highlight; + } - .slick-group-toggle { - width: 9px; - height: 9px; - margin-right: 5px; - } + &.active { + box-shadow: var(--slick-cell-active-box-shadow, $slick-cell-active-box-shadow); + border: var(--slick-cell-active-border, $slick-cell-active-border); + z-index: var(--slick-cell-active-z-index, $slick-cell-active-z-index); - .slick-group-toggle.expanded, - .slick-group-toggle.collapsed { - background: none; - } + // We compensate for the all-around border (now 1px at top and left too!) + padding: var(--slick-cell-padding, $slick-cell-padding); - .slick-group-totals { - background: var(--slick-group-totals-text-background, $slick-group-totals-text-background); - color: var(--slick-group-totals-text-color, $slick-group-totals-text-color); - } + input.dual-editor-text { + width: calc(50% + 1px - 5px); // 1px (is 2px / 2) and 5px (is space between the 2 inputs) + height: 100%; + outline: 0; + transform: translate(0, -2px); + } + } - .slick-sortable-placeholder { - background: var(--slick-header-column-sortable-background-hover, $slick-header-column-sortable-background-hover); - } -} + &.slick-rbe-unsaved-cell { + background-color: var(--slick-row-based-edit-unsaved-cell-bgcolor, $slick-row-based-edit-unsaved-cell-bgcolor) !important; + } + } -// ---------------------------------------------- -// Slick Grid theme -// ---------------------------------------------- + &.active-row .slick-cell { + background-color: rgb(226, 255, 253); + } -.slickgrid-container { - overflow: hidden; - outline: 0; - position: relative; - box-sizing: content-box; + &.active-row.odd .slick-cell { + background-color: $slick-cell-odd-active-background-color; + } + + &.slick-rbe-editmode .slick-cell { + background-color: var(--slick-row-based-edit-editmode-bgcolor, $slick-row-based-edit-editmode-bgcolor); + + &:hover { + background-color: var(--slick-row-based-edit-editmode-hover-bgcolor, $slick-row-based-edit-editmode-hover-bgcolor); + + .active { + background-color: var(--slick-row-based-edit-editmode-active-hover-bgcolor, $slick-row-based-edit-editmode-active-hover-bgcolor) !important; + } + } + + .active { + background-color: var(--slick-row-based-edit-editmode-active-bgcolor, $slick-row-based-edit-editmode-active-bgcolor); + + &:hover { + background-color: var(--slick-row-based-edit-editmode-active-hover-bgcolor, $slick-row-based-edit-editmode-active-hover-bgcolor); + } + } + } + } .slick-group-header-columns { position: relative; @@ -157,10 +222,9 @@ border-left: 0px; } - .slick-group-header-column.ui-state-default { + .slick-group-header-column.slick-state-default { position: relative; display: inline-block; - box-sizing: content-box !important; /* this here only for Firefox! */ overflow: hidden; text-overflow: ellipsis; height: 16px; @@ -209,7 +273,12 @@ } .slick-viewport { + height: 100%; overflow: auto; + border-top: var(--slick-viewport-border-top, $slick-viewport-border-top); + border-bottom: var(--slick-viewport-border-bottom, $slick-viewport-border-bottom); + border-left: var(--slick-viewport-border-left, $slick-viewport-border-left); + border-right: var(--slick-viewport-border-right, $slick-viewport-border-right); ::-webkit-scrollbar { -webkit-appearance: none; } @@ -273,30 +342,22 @@ } } - .slick-header-column.ui-state-default { + .slick-header-column.slick-state-default { position: relative; display: inline-block; - box-sizing: content-box !important; overflow: hidden; text-overflow: ellipsis; height: 16px; line-height: 16px; margin: 0; padding: 4px; - border-right: 1px solid $slick-grid-border-color; + border-right: 1px solid var(--slick-grid-border-color, $slick-grid-border-color); border-left: 0px !important; border-top: 0px !important; border-bottom: 0px !important; float: left; } - - .slick-cell { - box-sizing: border-box; - border-style: var(--slick-grid-border-style, $slick-grid-border-style); - padding: 1px 2px 1px 2px; - } - .slick-header-column { padding: var(--slick-header-padding, $slick-header-padding); } @@ -306,39 +367,7 @@ outline: 0; } - .slick-row { - position: absolute; - border: 0; - width: 100%; - } - - .slick-header-column-sorted { - font-style: italic; - } - - .slick-sort-indicator { - display: inline-block; - width: 8px; - height: 5px; - margin-left: 4px; - margin-top: 6px; - position: absolute; - left: 0; - } - - .slick-sort-indicator-desc:before { - content: "\f0d7"; - } - - .slick-sort-indicator-asc:before { - content: "\f0d8"; - } - - .slick-header-sortable .slick-column-name { - margin-left: 10px; - } - - .slick-header.ui-state-default { + .slick-header.slick-state-default { box-shadow: 0 1px 2px rgba(0,0,0,.1); } @@ -349,27 +378,14 @@ -webkit-line-clamp: var(--slick-header-row-count, $slick-header-row-count); } - .slick-resizable-handle { - position: absolute; - font-size: 0.1px; - display: block; - cursor: col-resize; - width: 4px; - right: 0; - top: 0; - height: 100%; - } - - .slick-resizable-handle-hover { - background-color: #ccc; - } - - .slick-sortable-placeholder { - background: var(--slick-header-column-sortable-background-hover, $slick-header-column-sortable-background-hover); - } - - .slick-group-toggle { - display: inline-block; + .slick-cell { + background: inherit; + border: 1px transparent; + box-sizing: border-box; + border-style: var(--slick-grid-border-style, $slick-grid-border-style); + display: var(--slick-cell-display, $slick-cell-display); + padding: 1px 2px; + align-items: center; } .slick-cell { @@ -415,49 +431,357 @@ z-index: 999999; box-shadow: var(--slick-row-move-plugin-shadow-row-box-shadow, $slick-row-move-plugin-shadow-row-box-shadow); } +} - .slick-reorder-shadow-row { - position: absolute; - z-index: 999999; - box-shadow: rgb(0 0 0 / 20%) 8px 2px 8px 4px, rgb(0 0 0 / 19%) 2px 2px 0px 0px; +.scrollbar-fix { + &::-webkit-scrollbar { + -webkit-appearance: none; } +} - .slick-selection { - z-index: 10; - position: absolute; - border: 2px dashed black; +.slickgrid-container { + @mixin resetSlickCell() { + padding: var(--slick-cell-padding, $slick-cell-padding); + font-size: var(--slick-font-size-base, $slick-font-size-base); + td { + font-size: var(--slick-font-size-base, $slick-font-size-base); + } + body & { + line-height: 20px; + } } - .slick-pane { - position: absolute; - outline: 0; - overflow: hidden; + .grid-canvas { + .slick-cell, .slick-headerrow-column { + border-top: var(--slick-cell-border-top, $slick-cell-border-top); + border-bottom: var(--slick-cell-border-bottom, $slick-cell-border-bottom); + border-left: var(--slick-cell-border-left, $slick-cell-border-left); + border-right: var(--slick-cell-border-right, $slick-cell-border-right); + box-shadow: var(--slick-cell-box-shadow, $slick-cell-box-shadow); + } + + .slick-cell { + @include resetSlickCell(); + + &.even { + background-color: var(--slick-cell-even-background-color, $slick-cell-even-background-color); + } + &.slick-rbe-unsaved-cell { + background-color: var(--slick-row-based-edit-unsaved-cell-bgcolor, $slick-row-based-edit-unsaved-cell-bgcolor) !important; + } + + a, a:visited, .slick-widget-content a, .slick-widget-content a:visited { + color: var(--slick-link-color, $slick-link-color); + } + a:hover, .slick-widget-content a:hover { + color: var(--slick-link-color-hover, $slick-link-color-hover); + border-bottom: none; + } + table { + height: 100%; + padding: 0; + background: none; + } + td { + padding: 0; + vertical-align: middle; + text-align: left; + } + &.selected { + background-color: var(--slick-row-selected-color, $slick-row-selected-color); + } + &.copied { + background: var(--slick-copied-cell-bg-color-transition, $slick-copied-cell-bg-color-transition); + transition: var(--slick-copied-cell-transition, $slick-copied-cell-transition); + } + select:not([multiple]).form-control { + height: 100%; + padding: 0; + } + .slick-group-title { + height: var(--slick-draggable-group-title-height, $slick-draggable-group-title-height); + line-height: var(--slick-draggable-group-title-line-height, $slick-draggable-group-title-line-height); + vertical-align: var(--slick-draggable-group-title-vertical-align, $slick-draggable-group-title-vertical-align); + } + + .slick-group-toggle { + cursor: pointer; + display: inline-block; + width: 1em; + height: 1em; + color: var(--slick-icon-group-color, $slick-icon-group-color); + font-size: var(--slick-icon-group-font-size, $slick-icon-group-font-size); + margin-right: var(--slick-icon-group-margin-right, $slick-icon-group-margin-right); + + &.expanded { + @include generateSvgStyle('slick-icon-group-expanded-svg', $slick-icon-group-expanded-svg-path); + } + &.collapsed { + @include generateSvgStyle('slick-icon-group-collapsed-svg', $slick-icon-group-collapsed-svg-path); + } + &.expanded, + &.collapsed { + background-color: currentColor; + } + } + // fix alignment when slick-cell includes slickgrid icons (align bottom will in fact center the icon & text), for example Tree Data/Grouping + .slick-group-toggle, + .mdi { + vertical-align: var(--slick-icon-with-text-valign, $slick-icon-with-text-valign); + } + } + } + + .slick-header { + border-top: var(--slick-header-border-top, $slick-header-border-top); + border-right: var(--slick-header-border-right, $slick-header-border-right); + border-bottom: var(--slick-header-border-bottom, $slick-header-border-bottom); + border-left: var(--slick-header-border-left, $slick-header-border-left); width: 100%; + box-shadow: none !important; } -} -.flatpickr-wrapper { - z-index: 10000; -} + .slick-headerrow { + border-bottom: var(--slick-header-filter-row-border-bottom, $slick-header-filter-row-border-bottom); + border-top: var(--slick-header-filter-row-border-top, $slick-header-filter-row-border-top); + border-left: var(--slick-header-filter-row-border-left, $slick-header-filter-row-border-left); + border-right: var(--slick-header-filter-row-border-right, $slick-header-filter-row-border-right); + + .slick-headerrow-columns { + .slick-headerrow-column { + border: none; + padding: var(--slick-header-row-filter-padding, $slick-header-row-filter-padding); + background: var(--slick-header-row-background-color, $slick-header-row-background-color); + } + .slick-headerrow-column input, + .slick-headerrow-column select, + .slick-headerrow-column textarea { + margin-right: 0; + padding: var(--slick-header-input-padding, $slick-header-input-padding); + height: var(--slick-header-input-height, $slick-header-input-height); + box-sizing: border-box; + } + } + } -.interact-placeholder { - background: red !important; - display: inline-block; - float: left; - transform: translate(0px, -100%); -} + .slick-header-columns { + background: var(--slick-grid-header-background, $slick-grid-header-background); + background-color: var(--slick-header-background-color, $slick-header-background-color); + width: calc(100% - #{var(--slick-header-scroll-width-to-remove, $slick-header-scroll-width-to-remove)}); -.interact-drop-active { - box-shadow: inset 0 0 8px rgba(7, 67, 128, 0.5); -} + [id$="checkbox_selector"] { + justify-content: center; + display: flex; + } -.interact-can-drop { - opacity: .9; -} + .slick-header-sortable .slick-column-name { + margin-left: 0; + } + .slick-header-column { + height: var(--slick-header-column-height, $slick-header-column-height); + line-height: var(--slick-font-size-base, $slick-font-size-base); + margin: 0; + border-top: var(--slick-header-column-border-top, $slick-header-column-border-top); + border-right: var(--slick-header-column-border-right, $slick-header-column-border-right); + border-bottom: var(--slick-header-column-border-bottom, $slick-header-column-border-bottom); + border-left: var(--slick-header-column-border-left, $slick-header-column-border-left); + white-space: normal; + &.slick-state-default { + @include resetSlickCell(); + } + .slick-column-name { + margin-right: var(--slick-header-column-name-margin-right, $slick-header-column-name-margin-right); + } -.scrollbar-fix { - &::-webkit-scrollbar { - -webkit-appearance: none; + @mixin ResetColumns () { + /* like TH */ + background: var(--slick-header-background-color, $slick-header-background-color); + font-family: var(--slick-font-family, $slick-font-family); + color: var(--slick-header-text-color, $slick-header-text-color); + font-size: var(--slick-header-font-size, $slick-header-font-size); + font-weight: var(--slick-header-font-weight, $slick-header-font-weight); + a, a:visited { + color: var(--slick-text-color, $slick-text-color); + } + a:hover { + color: var(--slick-hover-header-color, $slick-hover-header-color); + } + } + + @include ResetColumns (); + &.slick-state-default { + @include ResetColumns (); + } + + &.slick-header-column-sorted { + font-style: normal; + color: var(--slick-sorting-header-color, $slick-sorting-header-color); + } + &:hover { + color: var(--slick-hover-header-color, $slick-hover-header-color); + } + + .slick-sort-indicator , + .slick-sort-indicator-numbered { + display: inline-block; + position: absolute; + color: var(--slick-icon-sort-color, $slick-icon-sort-color); + } + + .slick-sort-indicator { + height: 1em; + width: 1em; + left: auto; + font-size: var(--slick-icon-sort-font-size, $slick-icon-sort-font-size); + right: var(--slick-icon-sort-position-right, $slick-icon-sort-position-right); + top: var(--slick-icon-sort-position-top, $slick-icon-sort-position-top); + } + .slick-sort-indicator-numbered { + font-family: var(--slick-font-family, $slick-font-family); + font-size: var(--slick-sort-indicator-number-font-size, $slick-sort-indicator-number-font-size); + width: var(--slick-sort-indicator-number-width, $slick-sort-indicator-number-width); + left: var(--slick-sort-indicator-number-left, $slick-sort-indicator-number-left); + right: var(--slick-sort-indicator-number-right, $slick-sort-indicator-number-right); + top: var(--slick-sort-indicator-number-top, $slick-sort-indicator-number-top); + } + + // when sorting is possible and there's not yet a sort applied on the column + // we could display the sort ascending icon (with an opacity) as a hint */ + &.slick-header-sortable.slick-state-hover:not(.slick-header-column-sorted) { + .slick-sort-indicator { + opacity: var(--slick-sort-indicator-hint-opacity, $slick-sort-indicator-hint-opacity); + @include generateSvgStyle('slick-icon-sort-asc-icon-svg', $slick-icon-sort-asc-icon-svg-path); + } + } + .slick-sort-indicator-asc { + @include generateSvgStyle('slick-icon-sort-asc-icon-svg', $slick-icon-sort-asc-icon-svg-path); + } + .slick-sort-indicator-desc { + @include generateSvgStyle('slick-icon-sort-desc-icon-svg', $slick-icon-sort-desc-icon-svg-path); + } + .slick-sort-indicator-asc, + .slick-sort-indicator-desc { + opacity: 1; + background-color: currentColor; + } + + .slick-resizable-handle { + position: absolute; + font-size: 0.1px; + display: block; + cursor: col-resize; + top: 0; + height: 100%; + width: 7px; + right: 0; + z-index: 1; + + &:hover { + border-bottom: var(--slick-header-resizable-hover-border-bottom, $slick-header-resizable-hover-border-bottom); + border-left: var(--slick-header-resizable-hover-border-left, $slick-header-resizable-hover-border-left); + border-right: var(--slick-header-resizable-hover-border-right, $slick-header-resizable-hover-border-right); + border-top: var(--slick-header-resizable-hover-border-top, $slick-header-resizable-hover-border-top); + border-radius: var(--slick-header-resizable-hover-border-radius, $slick-header-resizable-hover-border-radius); + width: var(--slick-header-resizable-hover-width, $slick-header-resizable-hover-width); + right: var(--slick-header-resizable-hover-right, $slick-header-resizable-hover-right); + height: var(--slick-header-resizable-hover-height, $slick-header-resizable-hover-height); + top: var(--slick-header-resizable-hover-top, $slick-header-resizable-hover-top); + opacity: var(--slick-header-resizable-hover-opacity, $slick-header-resizable-hover-opacity); + } + } + &.unorderable { + background-color: var(--slick-grid-header-unorderable-bg-color, $slick-grid-header-unorderable-bg-color); + } + } + } + + /** Header Grouping **/ + .slick-preheader-panel.slick-state-default { + border-bottom: var(--slick-preheader-border-bottom, $slick-preheader-border-bottom); + + .slick-header-columns { + border-top: var(--slick-preheader-border-top, $slick-preheader-border-top); + + .slick-header-column { + height: var(--slick-preheader-height, $slick-preheader-height); + border-left: var(--slick-preheader-border-left, $slick-preheader-border-left); + border-right: var(--slick-preheader-border-right, $slick-preheader-border-right); + font-size: var(--slick-preheader-font-size, $slick-preheader-font-size); + justify-content: var(--slick-preheader-grouped-title-justify, $slick-preheader-grouped-title-justify); + display: var(--slick-preheader-grouped-title-display, $slick-preheader-grouped-title-display); + } + .slick-header-column:first-child { + border-left: var(--slick-preheader-border-left-first-element, $slick-preheader-border-left-first-element); + } + .slick-header-column:last-child { + border-right: var(--slick-preheader-border-right-last-element, $slick-preheader-border-right-last-element); + } + } + } + + /** Frozen/Pinned styling */ + + .slick-row .slick-cell.frozen:last-child, + .slick-footerrow-column.frozen:last-child { + border-right: var(--slick-frozen-border-right, $slick-frozen-border-right); + } + .slick-header-column.frozen:last-child { + border-right: var(--slick-frozen-header-row-border-right, $slick-frozen-header-row-border-right); + } + .slick-pane-left { + .slick-preheader-panel .slick-header-column.frozen:last-child { + border-right: var(--slick-frozen-preheader-row-border-right, $slick-frozen-preheader-row-border-right); + } + } + .slick-headerrow-column.frozen:last-child { + border-right: var(--slick-frozen-filter-row-border-right, $slick-frozen-filter-row-border-right); + } + + .slick-pane-bottom { + border-top: var(--slick-frozen-border-bottom, $slick-frozen-border-bottom); + } + .slick-viewport-bottom.slick-viewport-right { + overflow-y: var(--slick-frozen-overflow-right, $slick-frozen-overflow-right) !important; + } + .input-group { + display: flex; + + > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) { + margin-left: 0; + &.slick-slider-horizontal { + margin-left: 10px; + } + } + + .input-group-append, + .input-group-prepend { + display: inline-flex; + width: auto; + } + + .input-group-addon { + input { + flex: 1 1 auto; + width: 1%; + } + .input-group-text { + height: 100%; + } + &.input-group-append { + .input-group-text { + margin-left: -1px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + } + &.input-group-prepend { + .input-group-text { + margin-right: -1px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + } + } } } diff --git a/packages/common/src/styles/slick-plugins.scss b/packages/common/src/styles/slick-plugins.scss index bced7dfd0..85d75c52b 100644 --- a/packages/common/src/styles/slick-plugins.scss +++ b/packages/common/src/styles/slick-plugins.scss @@ -1,6 +1,6 @@ /* sass variables */ @import './variables'; -@import 'multiple-select-vanilla/dist/styles/sass/multiple-select.scss'; +@import './svg-utilities'; // ---------------------------------------------- // Column Picker & Grid Menu Controls @@ -130,36 +130,60 @@ li.hidden { width: auto; } - /* replace checkboxes by Font-Awesome icons */ - input[type=checkbox] { - display:none; /* to hide the checkbox itself */ - margin-left: 4px; - margin-top: 3px; + label { + line-height: var(--slick-column-picker-icon-container-line-height, $slick-column-picker-icon-container-line-height); + display: inline-flex; + align-items: center; + justify-content: center; } - input[type=checkbox] + label:before { - cursor: pointer; - content: var(--slick-column-picker-checkbox-icon-unchecked, $slick-column-picker-checkbox-icon-unchecked); - color: var(--slick-column-picker-checkbox-color, $slick-column-picker-checkbox-color); - display: inline-block; - font-weight: var(--slick-column-picker-checkbox-font-weight, $slick-column-picker-checkbox-font-weight); - font-family: var(--slick-icon-font-family, $slick-icon-font-family); - font-size: var(--slick-column-picker-checkbox-size, $slick-column-picker-checkbox-size); - line-height: var(--slick-column-picker-checkbox-icon-line-height, $slick-column-picker-checkbox-icon-line-height); - opacity: var(--slick-column-picker-checkbox-opacity, $slick-column-picker-checkbox-opacity); /* unchecked icon */ - margin-right: 4px; - vertical-align: var(--slick-column-picker-checkbox-icon-vertical-align, $slick-column-picker-checkbox-icon-vertical-align); - width: var(--slick-column-picker-checkbox-width, $slick-column-picker-checkbox-width); + &.disabled { + cursor: default; } - - input[type=checkbox] + label:hover:before { - opacity: var(--slick-column-picker-checkbox-opacity-hover, $slick-column-picker-checkbox-opacity-hover); + input[type=checkbox] { + // hide original input checkbox since we use an SVG on top of it + opacity: 0; + width: 0; + margin-left: 0; } - input[type=checkbox]:checked + label:before { - opacity: 1; /* checked icon */ - content: var(--slick-column-picker-checkbox-icon-checked, $slick-column-picker-checkbox-icon-checked); - width: var(--slick-column-picker-checkbox-width, $slick-column-picker-checkbox-width); + .icon-checkbox-container { + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + background-color: var(--slick-column-picker-icon-container-bg-color, $slick-column-picker-icon-container-bg-color); + height: var(--slick-column-picker-icon-container-size, $slick-column-picker-icon-container-size); + width: var(--slick-column-picker-icon-container-size, $slick-column-picker-icon-container-size); + border: var(--slick-column-picker-icon-border, $slick-column-picker-icon-border); + border-radius: var(--slick-column-picker-icon-border-radius, $slick-column-picker-icon-border-radius); + + div.mdi { + opacity: 1; + font-size: var(--slick-column-picker-icon-font-size, $slick-column-picker-icon-font-size); + color: var(--slick-column-picker-icon-color, $slick-column-picker-icon-color); + + &.mdi-icon-picker-check { + @include generateSvgStyle('slick-column-picker-icon-checked-svg', $slick-column-picker-icon-checked-svg-path); + } + &.mdi-icon-picker-uncheck { + @include generateSvgStyle('slick-column-picker-icon-unchecked-svg', $slick-column-picker-icon-unchecked-svg-path); + opacity: var(--slick-column-picker-unchecked-opacity, $slick-column-picker-unchecked-opacity); /* unchecked icon */ + &:hover { + opacity: var(--slick-column-picker-opacity-hover, $slick-column-picker-opacity-hover); + } + + // since we use the div container with a border, we don't actually need an icon for unchecked + // BUT since we want to keep the same size, we can simply hide the mask to keep the same size + visibility: var(--slick-column-picker-icon-unchecked-color-visibility, $slick-column-picker-icon-unchecked-color-visibility); + } + } + & + span.checkbox-label { + display: inline-flex; + align-items: center; + gap: 3px; + padding-left: var(--slick-column-picker-label-text-padding-left, $slick-column-picker-label-text-padding-left); + } } } @@ -333,7 +357,6 @@ li.hidden { margin-right: var(--slick-menu-icon-margin-right, $slick-menu-icon-margin-right); vertical-align: middle; min-width: var(--slick-menu-icon-min-width, $slick-menu-icon-min-width); - width: var(--slick-menu-icon-width, $slick-menu-icon-width); } .slick-menu-content { @@ -474,16 +497,17 @@ li.hidden { background-repeat: no-repeat; background-position: center center; cursor: pointer; + visibility: visible; } .slick-header-button-hidden { - width: 0; + visibility: hidden; margin-right: var(--slick-header-button-hidden-margin-right, $slick-header-button-hidden-margin-right); - transition: 0.2s width; + transition: var(--slick-header-button-hidden-transition, $slick-header-button-hidden-transition); } .slick-header-column:hover > .slick-header-button { - width: var(--slick-header-button-width, $slick-header-button-width); + visibility: visible; } // ---------------------------------------------- @@ -491,12 +515,9 @@ li.hidden { // ---------------------------------------------- .slick-header-menu-button { - background-position: center center; - background-repeat: no-repeat; + background-color: currentColor; cursor: pointer; - display: none; position: absolute; - height: var(--slick-header-menu-button-height, $slick-header-menu-button-height); border: var(--slick-header-menu-button-border, $slick-header-menu-button-border); border-width: var(--slick-header-menu-button-border-width, $slick-header-menu-button-border-width); padding: var(--slick-header-menu-button-padding, $slick-header-menu-button-padding); @@ -504,17 +525,12 @@ li.hidden { // The next few items are already defined in the slick-headermenu file and it should stay that way, *unless* you also replace the button image included there. bottom: 0; - right: var(--slick-header-menu-button-margin-right, $slick-header-menu-button-margin-right); top: 0; - width: var(--slick-header-menu-button-width, $slick-header-menu-button-width); -} -.slick-header-menu-button:before { - display: inline-block; - content: var(--slick-header-menu-button-icon, $slick-header-menu-button-icon); - font-family: var(--slick-icon-font-family, $slick-icon-font-family); - font-size: var(--slick-header-menu-button-icon-font-size, $slick-header-menu-button-icon-font-size); - font-weight: var(--slick-header-menu-button-icon-font-weight, $slick-header-menu-button-icon-font-weight); - width: var(--slick-header-menu-button-icon-width, $slick-header-menu-button-icon-width); + right: var(--slick-header-menu-button-margin-right, $slick-header-menu-button-margin-right); + height: var(--slick-header-menu-button-icon-size, $slick-header-menu-button-icon-size); + width: var(--slick-header-menu-button-icon-size, $slick-header-menu-button-icon-size); + + @include generateSvgStyle('slick-header-menu-button-icon-svg', $slick-header-menu-button-icon-svg-path); } .slick-header-column { @@ -532,78 +548,91 @@ li.hidden { // ---------------------------------------------- // Row Move Manager Plugin // ---------------------------------------------- -.slick-cell.cell-reorder:before { - display: inline-block; - font-family: var(--slick-icon-font-family, $slick-icon-font-family); - font-size: var(--slick-row-move-plugin-size, $slick-row-move-plugin-size); - content: var(--slick-row-move-plugin-icon, $slick-row-move-plugin-icon); - width: var(--slick-row-move-plugin-icon-width, $slick-row-move-plugin-icon-width); - vertical-align: var(--slick-row-move-plugin-icon-vertical-align, $slick-row-move-plugin-icon-vertical-align); -} .slick-cell.cell-reorder { - cursor: var(--slick-row-move-plugin-cursor, $slick-row-move-plugin-cursor); + text-align: center; + + .slick-row-move-column { + background-color: currentColor; + display: block; + height: 1em; + width: 1em; + font-size: var(--slick-row-move-plugin-icon-font-size, $slick-row-move-plugin-icon-font-size); + color: var(--slick-row-move-plugin-icon-color, $slick-row-move-plugin-icon-color); + cursor: var(--slick-row-move-plugin-cursor, $slick-row-move-plugin-cursor); + @include generateSvgStyle('slick-row-move-plugin-icon-svg', $slick-row-move-plugin-icon-svg-path); + } } // ---------------------------------------------- // Checkbox Selector Plugin // ---------------------------------------------- -.slick-headerrow-column, + +.slick-headerrow-column.checkbox-header { + display: inline-flex; + justify-content: center; +} + .slick-column-name, +.slick-headerrow-column.checkbox-header, .slick-cell-checkboxsel { text-align: center; + + label { + line-height: var(--slick-checkbox-icon-container-line-height, $slick-checkbox-icon-container-line-height); + } #filter-checkbox-selectall-container { - display: flex; + display: inline-flex; align-items: center; justify-content: center; - height: 100%; - // line-height: 0; } - input[type=checkbox], - #filter-checkbox-selectall-container > input[type=checkbox] { - display:none; /* to hide the checkbox itself */ + &.disabled { + cursor: default; } - - input[type=checkbox], - #filter-checkbox-selectall-container > input[type=checkbox] + label { - margin: 0; + input[type=checkbox] { + // hide original input checkbox since we use an SVG on top of it + opacity: 0; + width: 0; + margin-left: 0; } - input[type=checkbox] + label:before, - #filter-checkbox-selectall-container > input[type=checkbox] + label:before { + .icon-checkbox-container { cursor: pointer; - content: var(--slick-checkbox-selector-icon-unchecked, $slick-checkbox-selector-icon-unchecked); - background-color: var(--slick-checkbox-selector-icon-bg-color, $slick-checkbox-selector-icon-bg-color); - color: var(--slick-checkbox-selector-unchecked-color, $slick-checkbox-selector-unchecked-color); - display: inline-block; - font-weight: var(--slick-checkbox-selector-icon-font-weight, $slick-checkbox-selector-icon-font-weight); - font-family: var(--slick-icon-font-family, $slick-icon-font-family); - font-size: var(--slick-checkbox-selector-size, $slick-checkbox-selector-size); - opacity: var(--slick-checkbox-selector-opacity, $slick-checkbox-selector-opacity); /* unchecked icon */ - margin: var(--slick-checkbox-selector-icon-margin, $slick-checkbox-selector-icon-margin); - } + display: inline-flex; + align-items: center; + justify-content: center; + background-color: var(--slick-checkbox-icon-container-bg-color, $slick-checkbox-icon-container-bg-color); + height: var(--slick-checkbox-icon-container-size, $slick-checkbox-icon-container-size); + width: var(--slick-checkbox-icon-container-size, $slick-checkbox-icon-container-size); + border: var(--slick-checkbox-icon-border, $slick-checkbox-icon-border); + border-radius: var(--slick-checkbox-icon-border-radius, $slick-checkbox-icon-border-radius); + + div.mdi { + opacity: 1; + font-size: var(--slick-checkbox-icon-font-size, $slick-checkbox-icon-font-size); + color: var(--slick-checkbox-icon-color, $slick-checkbox-icon-color); + + &.mdi-icon-check { + @include generateSvgStyle('slick-checkbox-icon-checked-svg', $slick-checkbox-icon-checked-svg-path); + } + &.mdi-icon-uncheck { + @include generateSvgStyle('slick-checkbox-icon-unchecked-svg', $slick-checkbox-icon-unchecked-svg-path); + opacity: var(--slick-checkbox-unchecked-opacity, $slick-checkbox-unchecked-opacity); /* unchecked icon */ + &:hover { + opacity: var(--slick-checkbox-opacity-hover, $slick-checkbox-opacity-hover); + } - input[type=checkbox] + label:hover:before, - #filter-checkbox-selectall-container > input[type=checkbox] + label:hover:before { - opacity: var(--slick-checkbox-selector-opacity-hover, $slick-checkbox-selector-opacity-hover); + // since we use the div container with a border, we don't actually need an icon for unchecked + // BUT since we want to keep the same size, we can simply hide the mask to keep the same size + visibility: var(--slick-checkbox-icon-unchecked-color-visibility, $slick-checkbox-icon-unchecked-color-visibility); + } + } } +} - input[type=checkbox]:checked + label:before, - #filter-checkbox-selectall-container > input[type=checkbox]:checked + label:before { - content: var(--slick-checkbox-selector-icon-checked, $slick-checkbox-selector-icon-checked); - color: var(--slick-checkbox-selector-checked-color, $slick-checkbox-selector-checked-color); - opacity: 1; /* checked icon */ - - } - input[type=checkbox] + label:before, - input[type=checkbox]:checked + label:before, - #filter-checkbox-selectall-container > input[type=checkbox] + label:before, - #filter-checkbox-selectall-container > input[type=checkbox]:checked + label:before { - height: var(--slick-checkbox-selector-icon-height, $slick-checkbox-selector-icon-height); - width: var(--slick-checkbox-selector-icon-width, $slick-checkbox-selector-icon-width); - border: var(--slick-checkbox-selector-icon-border, $slick-checkbox-selector-icon-border); - border-radius: var(--slick-checkbox-selector-icon-border-radius, $slick-checkbox-selector-icon-border-radius); - } +.slick-header-column.header-checkbox-selectall .slick-column-name { + text-align: center; + margin-right: 0; } .slick-group { @@ -675,10 +704,7 @@ li.hidden { label { span { cursor: pointer; - display: inline-flex; margin-left: var(--slick-multiselect-checkbox-margin-left, $slick-multiselect-checkbox-margin-left); - position: relative; - top: 1px; } } .ms-select-all { @@ -787,9 +813,9 @@ input.search-filter { &.compound-input { border-radius: var(--slick-compound-filter-border-radius, $slick-compound-filter-border-radius) !important; border-left: none; - &::placeholder { - color: var(--slick-editor-placeholder-color, $slick-editor-placeholder-color); - } + } + &::placeholder { + color: var(--slick-placeholder-color, $slick-placeholder-color); } } input.compound-slider { @@ -800,7 +826,7 @@ input.search-filter { .slick-headerrow { .slick-headerrow-columns { .slick-headerrow-column { - .input-group-prepend + .flatpickr { + .input-group-prepend + .date-picker { input.compound-input { border-top-left-radius: 0; border-bottom-left-radius: 0; @@ -815,50 +841,51 @@ input.search-filter { // Date Picker Filter // ---------------------------------------------- +.vanilla-calendar { + padding: 0.9rem; + z-index: 9999; +} + .search-filter.form-group { - .input-group.flatpickr input.form-control { + .input-group.date-picker input.form-control { border-bottom-left-radius: 0px; border-top-left-radius: 0px; } } -.search-filter .flatpickr { +.search-filter .date-picker { input.form-control { border-left: none; &::placeholder { - color: var(--slick-editor-placeholder-color, $slick-editor-placeholder-color); + color: var(--slick-placeholder-color, $slick-placeholder-color); } } } -.search-filter.flatpickr, -.search-filter .flatpickr { +.search-filter .date-picker { flex: 1; cursor: pointer; - input.flatpickr.form-control, - .flatpickr-input.form-control { - background-color: var(--slick-flatpickr-bgcolor, $slick-flatpickr-bgcolor); + .date-picker input.form-control { + background-color: var(--slick-date-picker-bg-color, $slick-date-picker-bg-color); font-family: var(--slick-filter-placeholder-font-family, $slick-filter-placeholder-font-family); font-size: var(--slick-font-size-base, $slick-font-size-base); border-radius: var(--slick-compound-filter-border-radius, $slick-compound-filter-border-radius); width: 100%; &[readonly] { - background-color: var(--slick-flatpickr-bgcolor, $slick-flatpickr-bgcolor); + background-color: var(--slick-date-picker-bg-color, $slick-date-picker-bg-color); } } - .form-control[readonly], - .flatpickr.form-control[readonly] { + .form-control[readonly] { cursor: pointer; - background-color: var(--slick-flatpickr-bgcolor, $slick-flatpickr-bgcolor); + background-color: var(--slick-date-picker-bg-color, $slick-date-picker-bg-color); } } -input.flatpickr-input.form-control, -input.flatpickr.form-control { +.date-picker input.form-control { cursor: pointer; font-family: var(--slick-filter-placeholder-font-family, $slick-filter-placeholder-font-family); font-size: var(--slick-font-size-base, $slick-font-size-base); border-radius: var(--slick-date-range-filter-border-radius, $slick-date-range-filter-border-radius); &[readonly] { - background-color: var(--slick-flatpickr-bgcolor, $slick-flatpickr-bgcolor); + background-color: var(--slick-date-picker-bg-color, $slick-date-picker-bg-color); } } @@ -887,30 +914,33 @@ input.flatpickr.form-control { } .slick-group-toggle-all { + display: inline-flex; + align-items: center; cursor: pointer; - border: var(--draggable-group-toggle-all-border, $slick-draggable-group-toggle-all-border); - border-radius: var(--draggable-group-toggle-all-border-radius, $slick-draggable-group-toggle-all-border-radius); - display: var(--slick-draggable-group-toggle-all-display, $slick-draggable-group-toggle-all-display); + border: var(--slick-draggable-group-toggle-all-border, $slick-draggable-group-toggle-all-border); + border-radius: var(--slick-draggable-group-toggle-all-border-radius, $slick-draggable-group-toggle-all-border-radius); margin-right: var(--slick-draggable-group-toggle-all-margin-right, $slick-draggable-group-toggle-all-margin-right); padding: var(--slick-draggable-group-toggle-all-padding, $slick-draggable-group-toggle-all-padding); position: var(--draggable-group-toggle-all-position, $slick-draggable-group-toggle-all-position); top: var(--slick-draggable-group-toggle-all-top, $slick-draggable-group-toggle-all-top); right: var(--slick-draggable-group-toggle-all-right, $slick-draggable-group-toggle-all-right); - .slick-group-toggle-all-icon.expanded:before { - content: var(--slick-draggable-group-toggle-expanded-icon, $slick-draggable-group-toggle-expanded-icon); - } - .slick-group-toggle-all-icon.collapsed:before { - content: var(--slick-draggable-group-toggle-collapsed-icon, $slick-draggable-group-toggle-collapsed-icon); - } - .slick-group-toggle-all-icon:before { + .slick-group-toggle-all-icon { + cursor: pointer; display: inline-block; - color: var(--slick-draggable-group-toggle-all-color, $slick-draggable-group-toggle-all-color); - font-family: var(--slick-icon-font-family, $slick-icon-font-family); - vertical-align: var(--slick-draggable-group-toggle-all-icon-vertical-align, $slick-draggable-group-toggle-all-icon-vertical-align); - height: var(--slick-draggable-group-toggle-all-icon-height, $slick-draggable-group-toggle-all-icon-height); - width: var(--slick-draggable-group-toggle-all-icon-width, $slick-draggable-group-toggle-all-icon-width); + background-color: currentColor; + width: 1em; + height: 1em; + color: var(--slick-draggable-group-toggle-all-icon-color, $slick-draggable-group-toggle-all-icon-color); + font-size: var(--slick-draggable-group-toggle-all-icon-font-size, $slick-draggable-group-toggle-all-icon-font-size); + &.expanded { + @include generateSvgStyle('slick-draggable-group-toggle-expanded-icon-svg', $slick-draggable-group-toggle-expanded-icon-svg-path); + } + &.collapsed { + @include generateSvgStyle('slick-draggable-group-toggle-collapsed-icon-svg', $slick-draggable-group-toggle-collapsed-icon-svg-path); + } } + .slick-group-toggle-all-text { font-size: var(--slick-draggable-group-toggle-all-text-font-size, $slick-draggable-group-toggle-all-text-font-size); margin: var(--slick-draggable-group-toggle-all-text-margin, $slick-draggable-group-toggle-all-text-margin); @@ -956,24 +986,6 @@ input.flatpickr.form-control { color: var(--slick-draggable-group-delete-hover-color, $slick-draggable-group-delete-hover-color); } } - - .slick-groupby-remove-icon::before { - font-size: var(--slick-draggable-group-by-remove-icon-size, $slick-draggable-group-by-remove-icon-size); - content: var(--slick-draggable-group-by-remove-icon, $slick-draggable-group-by-remove-icon); - } - .slick-groupby-sort-asc-icon::before { - font-size: var(--slick-draggable-group-sort-asc-icon-size, $slick-draggable-group-sort-asc-icon-size); - content: var(--slick-draggable-group-sort-asc-icon, $slick-draggable-group-sort-asc-icon); - } - .slick-groupby-sort-desc-icon::before { - font-size: var(--slick-draggable-group-sort-desc-icon-size, $slick-draggable-group-sort-desc-icon-size); - content: var(--slick-draggable-group-sort-desc-icon, $slick-draggable-group-sort-desc-icon); - } - .slick-groupby-remove-icon::before, - .slick-groupby-sort-asc-icon::before, - .slick-groupby-sort-desc-icon::before { - font-family: var(--slick-icon-font-family, $slick-icon-font-family); - } } .slick-dropzone-hover { background-color: var(--slick-draggable-group-droppable-hover-bgcolor, $slick-draggable-group-droppable-hover-bgcolor); @@ -1008,6 +1020,7 @@ input.flatpickr.form-control { .slider-container { display: flex; height: 100%; + flex: 1; input[type=range] { /*removes default webkit styles*/ @@ -1119,7 +1132,7 @@ input.flatpickr.form-control { height: var(--slick-header-input-height, $slick-header-input-height); &::placeholder { - color: var(--slick-editor-placeholder-color, $slick-editor-placeholder-color); + color: var(--slick-placeholder-color, $slick-placeholder-color); } .input-group-text { @@ -1245,36 +1258,24 @@ input.flatpickr.form-control { display: inline-block; &.expand { - display: inline-block; - color: var(--slick-detail-view-icon-expand-color, $slick-detail-view-icon-expand-color); - - &:hover { - color: var(--slick-detail-view-icon-expand-color-hover, $slick-detail-view-icon-expand-color-hover); - } - &:before { - content: var(--slick-detail-view-icon-expand, $slick-detail-view-icon-expand); - } + @include generateSvgStyle('slick-detail-view-icon-expand-svg', $slick-detail-view-icon-expand-svg-path); } &.collapse { - display: inline-block; - color: var(--slick-detail-view-icon-collapse-color, $slick-detail-view-icon-collapse-color); - &:hover { - color: var(--slick-detail-view-icon-collapse-color-hover, $slick-detail-view-icon-collapse-color-hover); - } - &:before { - content: var(--slick-detail-view-icon-collapse, $slick-detail-view-icon-collapse); - } + @include generateSvgStyle('slick-detail-view-icon-collapse-svg', $slick-detail-view-icon-collapse-svg-path); } &.expand, &.collapse { cursor: pointer; - } - &.expand:before, - &.collapse:before { + background-color: currentColor; display: inline-block; - font-family: var(--slick-icon-font-family, $slick-icon-font-family); - font-size: var(--slick-detail-view-icon-size, $slick-detail-view-icon-size); - width: var(--slick-detail-view-icon-width, $slick-detail-view-icon-width); + height: 1em; + width: 1em; + color: var(--slick-detail-view-icon-color, $slick-detail-view-icon-color); + font-size: var(--slick-detail-view-icon-font-size, $slick-detail-view-icon-font-size); + &:hover { + color: var(--slick-detail-view-icon-color-hover, $slick-detail-view-icon-color-hover); + opacity: var(--slick-detail-view-icon-opacity-hover, $slick-detail-view-icon-opacity-hover); + } } } diff --git a/packages/common/src/styles/slick-without-bootstrap-min-styling.scss b/packages/common/src/styles/slick-without-bootstrap-min-styling.scss index 0b8b365e6..0c6058efd 100644 --- a/packages/common/src/styles/slick-without-bootstrap-min-styling.scss +++ b/packages/common/src/styles/slick-without-bootstrap-min-styling.scss @@ -18,7 +18,7 @@ } .btn-default { - color: var(--slick-button-primary-color, $slick-button-primary-color); + color: var(--slick-cell-text-color, $slick-cell-text-color); background-color: var(--slick-btn-default-bg-color, $slick-btn-default-bg-color); border-color: var(--slick-btn-default-border-color, $slick-btn-default-border-color); } diff --git a/packages/common/src/styles/slick.layout.scss b/packages/common/src/styles/slick.layout.scss index 304fe5596..742b2a714 100644 --- a/packages/common/src/styles/slick.layout.scss +++ b/packages/common/src/styles/slick.layout.scss @@ -1,9 +1,9 @@ -@use './private'; +@use 'sass:math'; /* Medium devices (landscape tablets, 768px and up) */ @media only screen and (min-width : 768px) { @for $i from 1 through 12 { - $width: private.private-div($i, 12) * 100%; + $width: math.div($i, 12) * 100%; .slick-col-medium-#{$i} { flex-basis: $width; } @@ -13,7 +13,7 @@ /* Large devices (laptops/desktops, 992px and up) */ @media only screen and (min-width : 992px) { @for $i from 1 through 12 { - $width: private.private-div($i, 12) * 100%; + $width: math.div($i, 12) * 100%; .slick-col-large-#{$i} { flex-basis: $width; } @@ -23,7 +23,7 @@ /* Extra large devices (large laptops and desktops, 1200px and up) */ @media only screen and (min-width: 1200px) { @for $i from 1 through 12 { - $width: private.private-div($i, 12) * 100%; + $width: math.div($i, 12) * 100%; .slick-col-xlarge-#{$i} { flex-basis: $width; } diff --git a/packages/common/src/styles/slickgrid-examples.scss b/packages/common/src/styles/slickgrid-examples.scss index f12b731fd..b9df4f87b 100644 --- a/packages/common/src/styles/slickgrid-examples.scss +++ b/packages/common/src/styles/slickgrid-examples.scss @@ -1,18 +1,19 @@ @import './variables'; /* Individual cell styles */ -.percent-complete-bar { +.percent-complete-bar, +.percent-complete-bar-with-text { display: inline-block; - height: 6px; border-radius: 3px; background-color: transparent; } +.percent-complete-bar { + height: 6px; +} + .percent-complete-bar-with-text { - display: inline-block; height: 20px; - border-radius: 3px; - background-color: transparent; line-height: 20px; min-width: 25px; text-align: center; diff --git a/packages/common/src/styles/slickgrid-icons-svg-utils.scss b/packages/common/src/styles/slickgrid-icons-svg-utils.scss new file mode 100644 index 000000000..e22b50b48 --- /dev/null +++ b/packages/common/src/styles/slickgrid-icons-svg-utils.scss @@ -0,0 +1,58 @@ +$slick-icon-width-min-size: 5; +$slick-icon-width-max-size: 50; + +@-webkit-keyframes sg-spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} +@keyframes sg-spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.mdi { + &.mdi-flip-h { + transform: scaleX(-1); + } + &.mdi-flip-v { + transform: scaleY(-1); + } + &.mdi-pulse { + animation: sg-spin 1s infinite steps(8); + } + /* use mdi-spin or mdi-spin-1s to change the speed */ + &.mdi-spin, + &.mdi-spin-1s, + &.mdi-spin-2s, + &.mdi-spin-3s, + &.mdi-spin-4s, + &.mdi-spin-5s { + align-items: center; + display: inline-flex; + justify-content: center; + } + &.mdi-spin { + animation: sg-spin 2s infinite linear; + } + @for $i from 1 through 5 { + &.mdi-spin-#{$i}s { + animation: sg-spin #{$i}s infinite linear; + } + } + &.mdi-rotate-45 { transform: rotate(45deg); } + &.mdi-rotate-90 { transform: rotate(90deg); } + &.mdi-rotate-135 { transform: rotate(135deg); } + &.mdi-rotate-180 { transform: rotate(180deg); } + &.mdi-rotate-225 { transform: rotate(225deg); } + &.mdi-rotate-270 { transform: rotate(270deg); } + &.mdi-rotate-315 { transform: rotate(315deg); } +} + +// font-5px up to 50px / mdi-5px to 50px +// since SVG icons are now pure CSS, we can merge font-x with mdi-x +@for $i from $slick-icon-width-min-size through $slick-icon-width-max-size { + .mdi.mdi-#{$i}px, + .font-#{$i}px { + font-size: #{$i}px !important; + } +} diff --git a/packages/common/src/styles/material-svg-icons.scss b/packages/common/src/styles/slickgrid-icons.scss similarity index 55% rename from packages/common/src/styles/material-svg-icons.scss rename to packages/common/src/styles/slickgrid-icons.scss index 320c31f81..8727cc6ed 100644 --- a/packages/common/src/styles/material-svg-icons.scss +++ b/packages/common/src/styles/slickgrid-icons.scss @@ -1,1043 +1,1054 @@ -$slick-icon-height: $slick-icon-width; +/* SlickGrid Material icons (which all came from Material Design Icons) */ +@include generateSvgClass( + "mdi-account", + "M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z" +); + +@include generateSvgClass( + "mdi-account-box", + "M6,17C6,15 10,13.9 12,13.9C14,13.9 18,15 18,17V18H6M15,9A3,3 0 0,1 12,12A3,3 0 0,1 9,9A3,3 0 0,1 12,6A3,3 0 0,1 15,9M3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3H5C3.89,3 3,3.9 3,5Z" +); + +@include generateSvgClass( + "mdi-account-box-outline", + "M19,19H5V5H19M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M16.5,16.25C16.5,14.75 13.5,14 12,14C10.5,14 7.5,14.75 7.5,16.25V17H16.5M12,12.25A2.25,2.25 0 0,0 14.25,10A2.25,2.25 0 0,0 12,7.75A2.25,2.25 0 0,0 9.75,10A2.25,2.25 0 0,0 12,12.25Z" +); + +@include generateSvgClass( + "mdi-account-circle", + "M12,19.2C9.5,19.2 7.29,17.92 6,16C6.03,14 10,12.9 12,12.9C14,12.9 17.97,14 18,16C16.71,17.92 14.5,19.2 12,19.2M12,5A3,3 0 0,1 15,8A3,3 0 0,1 12,11A3,3 0 0,1 9,8A3,3 0 0,1 12,5M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z" +); + +@include generateSvgClass( + "mdi-account-edit", + "M21.7,13.35L20.7,14.35L18.65,12.3L19.65,11.3C19.86,11.09 20.21,11.09 20.42,11.3L21.7,12.58C21.91,12.79 21.91,13.14 21.7,13.35M12,18.94L18.06,12.88L20.11,14.93L14.06,21H12V18.94M12,14C7.58,14 4,15.79 4,18V20H10V18.11L14,14.11C13.34,14.03 12.67,14 12,14M12,4A4,4 0 0,0 8,8A4,4 0 0,0 12,12A4,4 0 0,0 16,8A4,4 0 0,0 12,4Z" +); + +@include generateSvgClass( + "mdi-account-minus", + "M15,14C12.33,14 7,15.33 7,18V20H23V18C23,15.33 17.67,14 15,14M1,10V12H9V10M15,12A4,4 0 0,0 19,8A4,4 0 0,0 15,4A4,4 0 0,0 11,8A4,4 0 0,0 15,12Z" +); + +@include generateSvgClass( + "mdi-account-off", + "M12,4A4,4 0 0,1 16,8C16,9.95 14.6,11.58 12.75,11.93L8.07,7.25C8.42,5.4 10.05,4 12,4M12.28,14L18.28,20L20,21.72L18.73,23L15.73,20H4V18C4,16.16 6.5,14.61 9.87,14.14L2.78,7.05L4.05,5.78L12.28,14M20,18V19.18L15.14,14.32C18,14.93 20,16.35 20,18Z" +); + +@include generateSvgClass( + "mdi-account-plus", + "M15,14C12.33,14 7,15.33 7,18V20H23V18C23,15.33 17.67,14 15,14M6,10V7H4V10H1V12H4V15H6V12H9V10M15,12A4,4 0 0,0 19,8A4,4 0 0,0 15,4A4,4 0 0,0 11,8A4,4 0 0,0 15,12Z" +); + +@include generateSvgClass( + "mdi-account-search", + "M15.5,12C18,12 20,14 20,16.5C20,17.38 19.75,18.21 19.31,18.9L22.39,22L21,23.39L17.88,20.32C17.19,20.75 16.37,21 15.5,21C13,21 11,19 11,16.5C11,14 13,12 15.5,12M15.5,14A2.5,2.5 0 0,0 13,16.5A2.5,2.5 0 0,0 15.5,19A2.5,2.5 0 0,0 18,16.5A2.5,2.5 0 0,0 15.5,14M10,4A4,4 0 0,1 14,8C14,8.91 13.69,9.75 13.18,10.43C12.32,10.75 11.55,11.26 10.91,11.9L10,12A4,4 0 0,1 6,8A4,4 0 0,1 10,4M2,20V18C2,15.88 5.31,14.14 9.5,14C9.18,14.78 9,15.62 9,16.5C9,17.79 9.38,19 10,20H2Z" +); + +@include generateSvgClass( + "mdi-alarm", + "M12,20A7,7 0 0,1 5,13A7,7 0 0,1 12,6A7,7 0 0,1 19,13A7,7 0 0,1 12,20M12,4A9,9 0 0,0 3,13A9,9 0 0,0 12,22A9,9 0 0,0 21,13A9,9 0 0,0 12,4M12.5,8H11V14L15.75,16.85L16.5,15.62L12.5,13.25V8M7.88,3.39L6.6,1.86L2,5.71L3.29,7.24L7.88,3.39M22,5.72L17.4,1.86L16.11,3.39L20.71,7.25L22,5.72Z" +); + +@include generateSvgClass( + "mdi-alarm-check", + "M10.54,14.53L8.41,12.4L7.35,13.46L10.53,16.64L16.53,10.64L15.47,9.58L10.54,14.53M12,20A7,7 0 0,1 5,13A7,7 0 0,1 12,6A7,7 0 0,1 19,13A7,7 0 0,1 12,20M12,4A9,9 0 0,0 3,13A9,9 0 0,0 12,22A9,9 0 0,0 21,13A9,9 0 0,0 12,4M7.88,3.39L6.6,1.86L2,5.71L3.29,7.24L7.88,3.39M22,5.72L17.4,1.86L16.11,3.39L20.71,7.25L22,5.72Z" +); + +@include generateSvgClass( + "mdi-alarm-off", + "M8,3.28L6.6,1.86L5.74,2.57L7.16,4M16.47,18.39C15.26,19.39 13.7,20 12,20A7,7 0 0,1 5,13C5,11.3 5.61,9.74 6.61,8.53M2.92,2.29L1.65,3.57L3,4.9L1.87,5.83L3.29,7.25L4.4,6.31L5.2,7.11C3.83,8.69 3,10.75 3,13A9,9 0 0,0 12,22C14.25,22 16.31,21.17 17.89,19.8L20.09,22L21.36,20.73L3.89,3.27L2.92,2.29M22,5.72L17.4,1.86L16.11,3.39L20.71,7.25L22,5.72M12,6A7,7 0 0,1 19,13C19,13.84 18.84,14.65 18.57,15.4L20.09,16.92C20.67,15.73 21,14.41 21,13A9,9 0 0,0 12,4C10.59,4 9.27,4.33 8.08,4.91L9.6,6.43C10.35,6.16 11.16,6 12,6Z" +); + +@include generateSvgClass( + "mdi-alert", + "M13 14H11V9H13M13 18H11V16H13M1 21H23L12 2L1 21Z" +); + +@include generateSvgClass( + "mdi-alert-box", + "M5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3M13,13V7H11V13H13M13,17V15H11V17H13Z" +); + +@include generateSvgClass( + "mdi-alert-box-outline", + "M19,19H5V5H19M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M11,15H13V17H11V15M11,7H13V13H11V7" +); + +@include generateSvgClass( + "mdi-alert-circle", + "M13,13H11V7H13M13,17H11V15H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" +); + +@include generateSvgClass( + "mdi-alert-octagon", + "M13 13H11V7H13M11 15H13V17H11M15.73 3H8.27L3 8.27V15.73L8.27 21H15.73L21 15.73V8.27L15.73 3Z" +); + +@include generateSvgClass( + "mdi-alert-outline", + "M12,2L1,21H23M12,6L19.53,19H4.47M11,10V14H13V10M11,16V18H13V16" +); + +@include generateSvgClass( + "mdi-alert-rhombus", + "M12 2C11.5 2 11 2.19 10.59 2.59L2.59 10.59C1.8 11.37 1.8 12.63 2.59 13.41L10.59 21.41C11.37 22.2 12.63 22.2 13.41 21.41L21.41 13.41C22.2 12.63 22.2 11.37 21.41 10.59L13.41 2.59C13 2.19 12.5 2 12 2M11 7H13V13H11V7M11 15H13V17H11V15Z" +); + +@include generateSvgClass( + "mdi-alert-rhombus-outline", + "M12 2C11.5 2 11 2.19 10.59 2.59L2.59 10.59C1.8 11.37 1.8 12.63 2.59 13.41L10.59 21.41C11.37 22.2 12.63 22.2 13.41 21.41L21.41 13.41C22.2 12.63 22.2 11.37 21.41 10.59L13.41 2.59C13 2.19 12.5 2 12 2M12 4L20 12L12 20L4 12M11 7V13H13V7M11 15V17H13V15Z" +); + +@include generateSvgClass( + "mdi-arrow-collapse", + "M19.5,3.09L15,7.59V4H13V11H20V9H16.41L20.91,4.5L19.5,3.09M4,13V15H7.59L3.09,19.5L4.5,20.91L9,16.41V20H11V13H4Z" +); + +@include generateSvgClass( + "mdi-arrow-down", + "M11,4H13V16L18.5,10.5L19.92,11.92L12,19.84L4.08,11.92L5.5,10.5L11,16V4Z" +); + +@include generateSvgClass( + "mdi-arrow-down-bold", + "M9,4H15V12H19.84L12,19.84L4.16,12H9V4Z" +); + +@include generateSvgClass( + "mdi-arrow-down-bold-box", + "M5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3M12,17L17,12H14V8H10V12H7L12,17Z" +); + +@include generateSvgClass( + "mdi-arrow-down-bold-box-outline", + "M12,17L7,12H10V8H14V12H17L12,17M5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3M5,5V19H19V5H5Z" +); + +@include generateSvgClass( + "mdi-arrow-down-bold-outline", + "M22,11L12,21L2,11H8V3H16V11H22M12,18L17,13H14V5H10V13H7L12,18Z" +); + +@include generateSvgClass( + "mdi-arrow-expand", + "M10,21V19H6.41L10.91,14.5L9.5,13.09L5,17.59V14H3V21H10M14.5,10.91L19,6.41V10H21V3H14V5H17.59L13.09,9.5L14.5,10.91Z" +); + +@include generateSvgClass( + "mdi-arrow-expand-horizontal", + "M9,11H15V8L19,12L15,16V13H9V16L5,12L9,8V11M2,20V4H4V20H2M20,20V4H22V20H20Z" +); + +@include generateSvgClass( + "mdi-arrow-split-vertical", + "M18,16V13H15V22H13V2H15V11H18V8L22,12L18,16M2,12L6,16V13H9V22H11V2H9V11H6V8L2,12Z" +); + +@include generateSvgClass( + "mdi-arrow-up", + "M13,20H11V8L5.5,13.5L4.08,12.08L12,4.16L19.92,12.08L18.5,13.5L13,8V20Z" +); + +@include generateSvgClass( + "mdi-book-open-blank-variant-outline", + "M12 21.5C10.65 20.65 8.2 20 6.5 20C4.85 20 3.15 20.3 1.75 21.05C1.65 21.1 1.6 21.1 1.5 21.1C1.25 21.1 1 20.85 1 20.6V6C1.6 5.55 2.25 5.25 3 5C4.11 4.65 5.33 4.5 6.5 4.5C8.45 4.5 10.55 4.9 12 6C13.45 4.9 15.55 4.5 17.5 4.5C18.67 4.5 19.89 4.65 21 5C21.75 5.25 22.4 5.55 23 6V20.6C23 20.85 22.75 21.1 22.5 21.1C22.4 21.1 22.35 21.1 22.25 21.05C20.85 20.3 19.15 20 17.5 20C15.8 20 13.35 20.65 12 21.5M11 7.5C9.64 6.9 7.84 6.5 6.5 6.5C5.3 6.5 4.1 6.65 3 7V18.5C4.1 18.15 5.3 18 6.5 18C7.84 18 9.64 18.4 11 19V7.5M13 19C14.36 18.4 16.16 18 17.5 18C18.7 18 19.9 18.15 21 18.5V7C19.9 6.65 18.7 6.5 17.5 6.5C16.16 6.5 14.36 6.9 13 7.5V19Z" +); + +@include generateSvgClass( + "mdi-brightness-4", + "M12,18C11.11,18 10.26,17.8 9.5,17.45C11.56,16.5 13,14.42 13,12C13,9.58 11.56,7.5 9.5,6.55C10.26,6.2 11.11,6 12,6A6,6 0 0,1 18,12A6,6 0 0,1 12,18M20,8.69V4H15.31L12,0.69L8.69,4H4V8.69L0.69,12L4,15.31V20H8.69L12,23.31L15.31,20H20V15.31L23.31,12L20,8.69Z" +); + +@include generateSvgClass( + "mdi-calendar", + "M19,19H5V8H19M16,1V3H8V1H6V3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3H18V1M17,12H12V17H17V12Z" +); + +@include generateSvgClass( + "mdi-calendar-check", + "M19,19H5V8H19M19,3H18V1H16V3H8V1H6V3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M16.53,11.06L15.47,10L10.59,14.88L8.47,12.76L7.41,13.82L10.59,17L16.53,11.06Z" +); + +@include generateSvgClass( + "mdi-calendar-clock", + "M15,13H16.5V15.82L18.94,17.23L18.19,18.53L15,16.69V13M19,8H5V19H9.67C9.24,18.09 9,17.07 9,16A7,7 0 0,1 16,9C17.07,9 18.09,9.24 19,9.67V8M5,21C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3H6V1H8V3H16V1H18V3H19A2,2 0 0,1 21,5V11.1C22.24,12.36 23,14.09 23,16A7,7 0 0,1 16,23C14.09,23 12.36,22.24 11.1,21H5M16,11.15A4.85,4.85 0 0,0 11.15,16C11.15,18.68 13.32,20.85 16,20.85A4.85,4.85 0 0,0 20.85,16C20.85,13.32 18.68,11.15 16,11.15Z" +); + +@include generateSvgClass( + "mdi-calendar-edit", + "M19,3H18V1H16V3H8V1H6V3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H10V19H5V8H19V9H21V5A2,2 0 0,0 19,3M21.7,13.35L20.7,14.35L18.65,12.35L19.65,11.35C19.85,11.14 20.19,11.13 20.42,11.35L21.7,12.63C21.89,12.83 21.89,13.15 21.7,13.35M12,18.94L18.07,12.88L20.12,14.88L14.06,21H12V18.94Z" +); + +@include generateSvgClass( + "mdi-calendar-remove", + "M19,19H5V8H19M19,3H18V1H16V3H8V1H6V3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M9.31,17L11.75,14.56L14.19,17L15.25,15.94L12.81,13.5L15.25,11.06L14.19,10L11.75,12.44L9.31,10L8.25,11.06L10.69,13.5L8.25,15.94L9.31,17Z" +); + +@include generateSvgClass( + "mdi-calendar-search", + "M15.5,12C18,12 20,14 20,16.5C20,17.38 19.75,18.21 19.31,18.9L22.39,22L21,23.39L17.88,20.32C17.19,20.75 16.37,21 15.5,21C13,21 11,19 11,16.5C11,14 13,12 15.5,12M15.5,14A2.5,2.5 0 0,0 13,16.5A2.5,2.5 0 0,0 15.5,19A2.5,2.5 0 0,0 18,16.5A2.5,2.5 0 0,0 15.5,14M19,8H5V19H9.5C9.81,19.75 10.26,20.42 10.81,21H5C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3H6V1H8V3H16V1H18V3H19A2,2 0 0,1 21,5V13.03C20.5,12.22 19.8,11.54 19,11V8Z" +); + +@include generateSvgClass( + "mdi-call-split", + "M14,4L16.29,6.29L13.41,9.17L14.83,10.59L17.71,7.71L20,10V4M10,4H4V10L6.29,7.71L11,12.41V20H13V11.59L7.71,6.29" +); + +@include generateSvgClass( + "mdi-cancel", + "M12 2C17.5 2 22 6.5 22 12S17.5 22 12 22 2 17.5 2 12 6.5 2 12 2M12 4C10.1 4 8.4 4.6 7.1 5.7L18.3 16.9C19.3 15.5 20 13.8 20 12C20 7.6 16.4 4 12 4M16.9 18.3L5.7 7.1C4.6 8.4 4 10.1 4 12C4 16.4 7.6 20 12 20C13.9 20 15.6 19.4 16.9 18.3Z" +); + +@include generateSvgClass( + "mdi-cash-check", + "M3 6V18H13.32C13.1 17.33 13 16.66 13 16H7C7 14.9 6.11 14 5 14V10C6.11 10 7 9.11 7 8H17C17 9.11 17.9 10 19 10V10.06C19.67 10.06 20.34 10.18 21 10.4V6H3M12 9C10.3 9.03 9 10.3 9 12C9 13.7 10.3 14.94 12 15C12.38 15 12.77 14.92 13.14 14.77C13.41 13.67 13.86 12.63 14.97 11.61C14.85 10.28 13.59 8.97 12 9M21.63 12.27L17.76 16.17L16.41 14.8L15 16.22L17.75 19L23.03 13.68L21.63 12.27Z" +); + +@include generateSvgClass( + "mdi-cash-remove", + "M15.46 18.12L16.88 19.54L19 17.41L21.12 19.54L22.54 18.12L20.41 16L22.54 13.88L21.12 12.46L19 14.59L16.88 12.46L15.46 13.88L17.59 16M14.97 11.62C14.86 10.28 13.58 8.97 12 9C10.3 9.04 9 10.3 9 12C9 13.7 10.3 14.94 12 15C12.39 15 12.77 14.92 13.14 14.77C13.41 13.67 13.86 12.63 14.97 11.62M13 16H7C7 14.9 6.1 14 5 14V10C6.1 10 7 9.1 7 8H17C17 9.1 17.9 10 19 10V10.05C19.67 10.06 20.34 10.18 21 10.4V6H3V18H13.32C13.1 17.33 13 16.66 13 16Z" +); + +@include generateSvgClass( + "mdi-certificate", + "M4,3C2.89,3 2,3.89 2,5V15A2,2 0 0,0 4,17H12V22L15,19L18,22V17H20A2,2 0 0,0 22,15V8L22,6V5A2,2 0 0,0 20,3H16V3H4M12,5L15,7L18,5V8.5L21,10L18,11.5V15L15,13L12,15V11.5L9,10L12,8.5V5M4,5H9V7H4V5M4,9H7V11H4V9M4,13H9V15H4V13Z" +); + +@include generateSvgClass( + "mdi-certificate-outline", + "M13 21L15 20L17 21V14H13M17 9V7L15 8L13 7V9L11 10L13 11V13L15 12L17 13V11L19 10M20 3H4A2 2 0 0 0 2 5V15A2 2 0 0 0 4 17H11V15H4V5H20V15H19V17H20A2 2 0 0 0 22 15V5A2 2 0 0 0 20 3M11 8H5V6H11M9 11H5V9H9M11 14H5V12H11Z" +); + +@include generateSvgClass( + "mdi-change-record-type", + "M20 37.5c0-.8-.7-1.5-1.5-1.5h-15c-.8 0-1.5.7-1.5 1.5v11c0 .8.7 1.5 1.5 1.5h15c.8 0 1.5-.7 1.5-1.5v-11zM8.1 22H3.2c-1 0-1.5.9-.9 1.4l8 8.3c.4.3 1 .3 1.4 0l8-8.3c.6-.6.1-1.4-.9-1.4h-4.7c0-5 4.9-10 9.9-10V6C15 6 8.1 13 8.1 22zM41.8 20.3c-.4-.3-1-.3-1.4 0l-8 8.3c-.6.6-.1 1.4.9 1.4h4.8c0 6-4.1 10-10.1 10v6c9 0 16.1-7 16.1-16H49c1 0 1.5-.9.9-1.4l-8.1-8.3zM50 3.5c0-.8-.7-1.5-1.5-1.5h-15c-.8 0-1.5.7-1.5 1.5v11c0 .8.7 1.5 1.5 1.5h15c.8 0 1.5-.7 1.5-1.5v-11z" +); + +@include generateSvgClass( + "mdi-check", + "M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z" +); + +@include generateSvgClass( + "mdi-check-all", + "M0.41,13.41L6,19L7.41,17.58L1.83,12M22.24,5.58L11.66,16.17L7.5,12L6.07,13.41L11.66,19L23.66,7M18,7L16.59,5.58L10.24,11.93L11.66,13.34L18,7Z" +); + +@include generateSvgClass( + "mdi-check-bold", + "M9,20.42L2.79,14.21L5.62,11.38L9,14.77L18.88,4.88L21.71,7.71L9,20.42Z" +); + +@include generateSvgClass( + "mdi-checkbox-blank-outline", + "M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M19,5V19H5V5H19Z" +); + +@include generateSvgClass( + "mdi-checkbox-marked-circle-outline", + "M20,12A8,8 0 0,1 12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4C12.76,4 13.5,4.11 14.2,4.31L15.77,2.74C14.61,2.26 13.34,2 12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12M7.91,10.08L6.5,11.5L11,16L21,6L19.59,4.58L11,13.17L7.91,10.08Z" +); + +@include generateSvgClass( + "mdi-check-box-outline", + "M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M19,5V19H5V5H19M10,17L6,13L7.41,11.58L10,14.17L16.59,7.58L18,9" +); + +@include generateSvgClass( + "mdi-checkbox-marked", + "M10,17L5,12L6.41,10.58L10,14.17L17.59,6.58L19,8M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3Z" +); + +@include generateSvgClass( + "mdi-check-circle", + "M12 2C6.5 2 2 6.5 2 12S6.5 22 12 22 22 17.5 22 12 17.5 2 12 2M10 17L5 12L6.41 10.59L10 14.17L17.59 6.58L19 8L10 17Z" +); + +@include generateSvgClass( + "mdi-check-circle-outline", + "M12 2C6.5 2 2 6.5 2 12S6.5 22 12 22 22 17.5 22 12 17.5 2 12 2M12 20C7.59 20 4 16.41 4 12S7.59 4 12 4 20 7.59 20 12 16.41 20 12 20M16.59 7.58L10 14.17L7.41 11.59L6 13L10 17L18 9L16.59 7.58Z" +); + +@include generateSvgClass( + "mdi-check-outline", + "M19.78,2.2L24,6.42L8.44,22L0,13.55L4.22,9.33L8.44,13.55L19.78,2.2M19.78,5L8.44,16.36L4.22,12.19L2.81,13.55L8.44,19.17L21.19,6.42L19.78,5Z" +); + +@include generateSvgClass( + "mdi-check-underline", + "M21,5L9,17L3.5,11.5L4.91,10.09L9,14.17L19.59,3.59L21,5M3,21V19H21V21H3Z" +); + +@include generateSvgClass( + "mdi-chevron-down", + "M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" +); + +@include generateSvgClass( + "mdi-chevron-down-box", + "M19,3H5A2,2 0 0,0 3,5V19C3,20.11 3.9,21 5,21H19C20.11,21 21,20.11 21,19V5A2,2 0 0,0 19,3M12,15.71L6,9.71L7.41,8.29L12,12.88L16.59,8.29L18,9.71L12,15.71Z" +); + +@include generateSvgClass( + "mdi-chevron-down-box-outline", + "M19,3H5A2,2 0 0,0 3,5V19C3,20.11 3.9,21 5,21H19C20.11,21 21,20.11 21,19V5A2,2 0 0,0 19,3M19,19H5V5H19V19M7.41,8.29L12,12.88L16.59,8.29L18,9.71L12,15.71L6,9.71L7.41,8.29Z" +); + +@include generateSvgClass( + "mdi-chevron-down-circle", + "M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,12M6,10L12,16L18,10L16.6,8.6L12,13.2L7.4,8.6L6,10Z" +); + +@include generateSvgClass( + "mdi-chevron-down-circle-outline", + "M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,12M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12M6,10L12,16L18,10L16.6,8.6L12,13.2L7.4,8.6L6,10Z" +); + +@include generateSvgClass( + "mdi-circle", + "M12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" +); + +@include generateSvgClass( + "mdi-clipboard-check", + "M10,17L6,13L7.41,11.59L10,14.17L16.59,7.58L18,9M12,3A1,1 0 0,1 13,4A1,1 0 0,1 12,5A1,1 0 0,1 11,4A1,1 0 0,1 12,3M19,3H14.82C14.4,1.84 13.3,1 12,1C10.7,1 9.6,1.84 9.18,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3Z" +); + +@include generateSvgClass( + "mdi-clipboard-check-outline", + "M19,3H14.82C14.4,1.84 13.3,1 12,1C10.7,1 9.6,1.84 9.18,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M12,3A1,1 0 0,1 13,4A1,1 0 0,1 12,5A1,1 0 0,1 11,4A1,1 0 0,1 12,3M7,7H17V5H19V19H5V5H7V7M7.5,13.5L9,12L11,14L15.5,9.5L17,11L11,17L7.5,13.5Z" +); + +@include generateSvgClass( + "mdi-clipboard-edit", + "M21.04 12.13C21.18 12.13 21.31 12.19 21.42 12.3L22.7 13.58C22.92 13.79 22.92 14.14 22.7 14.35L21.7 15.35L19.65 13.3L20.65 12.3C20.76 12.19 20.9 12.13 21.04 12.13M19.07 13.88L21.12 15.93L15.06 22H13V19.94L19.07 13.88M19 3C20.1 3 21 3.9 21 5V9L11 19V21H5C3.9 21 3 20.1 3 19V5C3 3.9 3.9 3 5 3H9.18C9.6 1.84 10.7 1 12 1C13.3 1 14.4 1.84 14.82 3H19M12 3C11.45 3 11 3.45 11 4C11 4.55 11.45 5 12 5C12.55 5 13 4.55 13 4C13 3.45 12.55 3 12 3Z" +); + +@include generateSvgClass( + "mdi-clipboard-edit-outline", + "M21.04 12.13C21.18 12.13 21.31 12.19 21.42 12.3L22.7 13.58C22.92 13.79 22.92 14.14 22.7 14.35L21.7 15.35L19.65 13.3L20.65 12.3C20.76 12.19 20.9 12.13 21.04 12.13M19.07 13.88L21.12 15.93L15.06 22H13V19.94L19.07 13.88M11 19L9 21H5C3.9 21 3 20.1 3 19V5C3 3.9 3.9 3 5 3H9.18C9.6 1.84 10.7 1 12 1C13.3 1 14.4 1.84 14.82 3H19C20.1 3 21 3.9 21 5V9L19 11V5H17V7H7V5H5V19H11M12 3C11.45 3 11 3.45 11 4C11 4.55 11.45 5 12 5C12.55 5 13 4.55 13 4C13 3.45 12.55 3 12 3Z" +); + +@include generateSvgClass( + "mdi-clipboard-multiple", + "M4 7H2V21C2 22.1 2.9 23 4 23H18V21H4M20 3H16.8C16.4 1.8 15.3 1 14 1C12.7 1 11.6 1.8 11.2 3H8C6.9 3 6 3.9 6 5V17C6 18.1 6.9 19 8 19H20C21.1 19 22 18.1 22 17V5C22 3.9 21.1 3 20 3M14 3C14.6 3 15 3.5 15 4C15 4.5 14.5 5 14 5C13.5 5 13 4.5 13 4C13 3.5 13.4 3 14 3Z" +); + +@include generateSvgClass( + "mdi-clipboard-multiple-outline", + "M4 7V21H18V23H4C2.9 23 2 22.1 2 21V7H4M20 3C21.1 3 22 3.9 22 5V17C22 18.1 21.1 19 20 19H8C6.9 19 6 18.1 6 17V5C6 3.9 6.9 3 8 3H11.18C11.6 1.84 12.7 1 14 1C15.3 1 16.4 1.84 16.82 3H20M14 3C13.45 3 13 3.45 13 4C13 4.55 13.45 5 14 5C14.55 5 15 4.55 15 4C15 3.45 14.55 3 14 3M10 7V5H8V17H20V5H18V7H10Z" +); + +@include generateSvgClass( + "mdi-clipboard-outline", + "M19,3H14.82C14.4,1.84 13.3,1 12,1C10.7,1 9.6,1.84 9.18,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M12,3A1,1 0 0,1 13,4A1,1 0 0,1 12,5A1,1 0 0,1 11,4A1,1 0 0,1 12,3M7,7H17V5H19V19H5V5H7V7Z" +); + +@include generateSvgClass( + "mdi-close", + "M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" +); + +@include generateSvgClass( + "mdi-close-circle", + "M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z" +); + +@include generateSvgClass( + "mdi-close-circle-outline", + "M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2C6.47,2 2,6.47 2,12C2,17.53 6.47,22 12,22C17.53,22 22,17.53 22,12C22,6.47 17.53,2 12,2M14.59,8L12,10.59L9.41,8L8,9.41L10.59,12L8,14.59L9.41,16L12,13.41L14.59,16L16,14.59L13.41,12L16,9.41L14.59,8Z" +); + +@include generateSvgClass( + "mdi-close-thick", + "M20 6.91L17.09 4L12 9.09L6.91 4L4 6.91L9.09 12L4 17.09L6.91 20L12 14.91L17.09 20L20 17.09L14.91 12L20 6.91Z" +); + +@include generateSvgClass( + "mdi-coffee", + "M2,21H20V19H2M20,8H18V5H20M20,3H4V13A4,4 0 0,0 8,17H14A4,4 0 0,0 18,13V10H20A2,2 0 0,0 22,8V5C22,3.89 21.1,3 20,3Z" +); + +@include generateSvgClass( + "mdi-coffee-outline", + "M2,21V19H20V21H2M20,8V5H18V8H20M20,3A2,2 0 0,1 22,5V8A2,2 0 0,1 20,10H18V13A4,4 0 0,1 14,17H8A4,4 0 0,1 4,13V3H20M16,5H6V13A2,2 0 0,0 8,15H14A2,2 0 0,0 16,13V5Z" +); + +@include generateSvgClass( + "mdi-cog", + "M12,15.5A3.5,3.5 0 0,1 8.5,12A3.5,3.5 0 0,1 12,8.5A3.5,3.5 0 0,1 15.5,12A3.5,3.5 0 0,1 12,15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.5,12C4.5,12.33 4.53,12.65 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.03 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.67 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.03 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z" +); + +@include generateSvgClass( + "mdi-cog-outline", + "M12,8A4,4 0 0,1 16,12A4,4 0 0,1 12,16A4,4 0 0,1 8,12A4,4 0 0,1 12,8M12,10A2,2 0 0,0 10,12A2,2 0 0,0 12,14A2,2 0 0,0 14,12A2,2 0 0,0 12,10M10,22C9.75,22 9.54,21.82 9.5,21.58L9.13,18.93C8.5,18.68 7.96,18.34 7.44,17.94L4.95,18.95C4.73,19.03 4.46,18.95 4.34,18.73L2.34,15.27C2.21,15.05 2.27,14.78 2.46,14.63L4.57,12.97L4.5,12L4.57,11L2.46,9.37C2.27,9.22 2.21,8.95 2.34,8.73L4.34,5.27C4.46,5.05 4.73,4.96 4.95,5.05L7.44,6.05C7.96,5.66 8.5,5.32 9.13,5.07L9.5,2.42C9.54,2.18 9.75,2 10,2H14C14.25,2 14.46,2.18 14.5,2.42L14.87,5.07C15.5,5.32 16.04,5.66 16.56,6.05L19.05,5.05C19.27,4.96 19.54,5.05 19.66,5.27L21.66,8.73C21.79,8.95 21.73,9.22 21.54,9.37L19.43,11L19.5,12L19.43,13L21.54,14.63C21.73,14.78 21.79,15.05 21.66,15.27L19.66,18.73C19.54,18.95 19.27,19.04 19.05,18.95L16.56,17.95C16.04,18.34 15.5,18.68 14.87,18.93L14.5,21.58C14.46,21.82 14.25,22 14,22H10M11.25,4L10.88,6.61C9.68,6.86 8.62,7.5 7.85,8.39L5.44,7.35L4.69,8.65L6.8,10.2C6.4,11.37 6.4,12.64 6.8,13.8L4.68,15.36L5.43,16.66L7.86,15.62C8.63,16.5 9.68,17.14 10.87,17.38L11.24,20H12.76L13.13,17.39C14.32,17.14 15.37,16.5 16.14,15.62L18.57,16.66L19.32,15.36L17.2,13.81C17.6,12.64 17.6,11.37 17.2,10.2L19.31,8.65L18.56,7.35L16.15,8.39C15.38,7.5 14.32,6.86 13.12,6.62L12.75,4H11.25Z" +); + +@include generateSvgClass( + "mdi-content-copy", + "M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z" +); + +@include generateSvgClass( + "mdi-currency-usd", + "M7,15H9C9,16.08 10.37,17 12,17C13.63,17 15,16.08 15,15C15,13.9 13.96,13.5 11.76,12.97C9.64,12.44 7,11.78 7,9C7,7.21 8.47,5.69 10.5,5.18V3H13.5V5.18C15.53,5.69 17,7.21 17,9H15C15,7.92 13.63,7 12,7C10.37,7 9,7.92 9,9C9,10.1 10.04,10.5 12.24,11.03C14.36,11.56 17,12.22 17,15C17,16.79 15.53,18.31 13.5,18.82V21H10.5V18.82C8.47,18.31 7,16.79 7,15Z" +); + +@include generateSvgClass( + "mdi-currency-usd-off", + "M3,4.27L4.28,3L21,19.72L19.73,21L16.06,17.33C15.44,18 14.54,18.55 13.5,18.82V21H10.5V18.82C8.47,18.31 7,16.79 7,15H9C9,16.08 10.37,17 12,17C13.13,17 14.14,16.56 14.65,15.92L11.68,12.95C9.58,12.42 7,11.75 7,9C7,8.77 7,8.55 7.07,8.34L3,4.27M10.5,5.18V3H13.5V5.18C15.53,5.69 17,7.21 17,9H15C15,7.92 13.63,7 12,7C11.63,7 11.28,7.05 10.95,7.13L9.4,5.58L10.5,5.18Z" +); + +@include generateSvgClass( + "mdi-database-refresh", + "M12 3C16.42 3 20 4.79 20 7C20 9.21 16.42 11 12 11C7.58 11 4 9.21 4 7C4 4.79 7.58 3 12 3M4 9C4 11.21 7.58 13 12 13C13.11 13 14.18 12.89 15.14 12.68C14.19 13.54 13.5 14.67 13.18 15.96L12 16C7.58 16 4 14.21 4 12V9M20 9V11L19.5 11L18.9 11.03C19.6 10.43 20 9.74 20 9M4 14C4 16.21 7.58 18 12 18L13 17.97C13.09 19.03 13.42 20 13.95 20.88L12 21C7.58 21 4 19.21 4 17V14M19 13.5C20.11 13.5 21.11 13.95 21.83 14.67L23 13.5V17.5H19L20.77 15.73C20.32 15.28 19.69 15 19 15C17.62 15 16.5 16.12 16.5 17.5C16.5 18.88 17.62 20 19 20C19.82 20 20.54 19.61 21 19H22.71C22.12 20.47 20.68 21.5 19 21.5C16.79 21.5 15 19.71 15 17.5C15 15.29 16.79 13.5 19 13.5Z" +); + +@include generateSvgClass( + "mdi-delete", + "M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z" +); + +@include generateSvgClass( + "mdi-delete-outline", + "M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19M8,9H16V19H8V9M15.5,4L14.5,3H9.5L8.5,4H5V6H19V4H15.5Z" +); + +@include generateSvgClass( + "mdi-dots-grid", + "M12 16C13.1 16 14 16.9 14 18S13.1 20 12 20 10 19.1 10 18 10.9 16 12 16M12 10C13.1 10 14 10.9 14 12S13.1 14 12 14 10 13.1 10 12 10.9 10 12 10M12 4C13.1 4 14 4.9 14 6S13.1 8 12 8 10 7.1 10 6 10.9 4 12 4M6 16C7.1 16 8 16.9 8 18S7.1 20 6 20 4 19.1 4 18 4.9 16 6 16M6 10C7.1 10 8 10.9 8 12S7.1 14 6 14 4 13.1 4 12 4.9 10 6 10M6 4C7.1 4 8 4.9 8 6S7.1 8 6 8 4 7.1 4 6 4.9 4 6 4M18 16C19.1 16 20 16.9 20 18S19.1 20 18 20 16 19.1 16 18 16.9 16 18 16M18 10C19.1 10 20 10.9 20 12S19.1 14 18 14 16 13.1 16 12 16.9 10 18 10M18 4C19.1 4 20 4.9 20 6S19.1 8 18 8 16 7.1 16 6 16.9 4 18 4Z" +); + +@include generateSvgClass( + "mdi-dots-vertical", + "M12,16A2,2 0 0,1 14,18A2,2 0 0,1 12,20A2,2 0 0,1 10,18A2,2 0 0,1 12,16M12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12A2,2 0 0,1 12,10M12,4A2,2 0 0,1 14,6A2,2 0 0,1 12,8A2,2 0 0,1 10,6A2,2 0 0,1 12,4Z" +); + +@include generateSvgClass( + "mdi-download", + "M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z" +); + + @include generateSvgClass( + "mdi-drag", + "M7,19V17H9V19H7M11,19V17H13V19H11M15,19V17H17V19H15M7,15V13H9V15H7M11,15V13H13V15H11M15,15V13H17V15H15M7,11V9H9V11H7M11,11V9H13V11H11M15,11V9H17V11H15M7,7V5H9V7H7M11,7V5H13V7H11M15,7V5H17V7H15Z" +); + + @include generateSvgClass( + "mdi-drag-vertical", + "M9,3H11V5H9V3M13,3H15V5H13V3M9,7H11V9H9V7M13,7H15V9H13V7M9,11H11V13H9V11M13,11H15V13H13V11M9,15H11V17H9V15M13,15H15V17H13V15M9,19H11V21H9V19M13,19H15V21H13V19Z" +); + + @include generateSvgClass( + "mdi-eye-off-outline", + "M2,5.27L3.28,4L20,20.72L18.73,22L15.65,18.92C14.5,19.3 13.28,19.5 12,19.5C7,19.5 2.73,16.39 1,12C1.69,10.24 2.79,8.69 4.19,7.46L2,5.27M12,9A3,3 0 0,1 15,12C15,12.35 14.94,12.69 14.83,13L11,9.17C11.31,9.06 11.65,9 12,9M12,4.5C17,4.5 21.27,7.61 23,12C22.18,14.08 20.79,15.88 19,17.19L17.58,15.76C18.94,14.82 20.06,13.54 20.82,12C19.17,8.64 15.76,6.5 12,6.5C10.91,6.5 9.84,6.68 8.84,7L7.3,5.47C8.74,4.85 10.33,4.5 12,4.5M3.18,12C4.83,15.36 8.24,17.5 12,17.5C12.69,17.5 13.37,17.43 14,17.29L11.72,15C10.29,14.85 9.15,13.71 9,12.28L5.6,8.87C4.61,9.72 3.78,10.78 3.18,12Z" +); + + @include generateSvgClass( + "mdi-eye-outline", + "M12,9A3,3 0 0,1 15,12A3,3 0 0,1 12,15A3,3 0 0,1 9,12A3,3 0 0,1 12,9M12,4.5C17,4.5 21.27,7.61 23,12C21.27,16.39 17,19.5 12,19.5C7,19.5 2.73,16.39 1,12C2.73,7.61 7,4.5 12,4.5M3.18,12C4.83,15.36 8.24,17.5 12,17.5C15.76,17.5 19.17,15.36 20.82,12C19.17,8.64 15.76,6.5 12,6.5C8.24,6.5 4.83,8.64 3.18,12Z" +); + +@include generateSvgClass( + "mdi-file", + "M13,9V3.5L18.5,9M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6Z" +); + +@include generateSvgClass( + "mdi-file-alert", + "M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2M9 19H7V17H9M9 15H7V9H9M13 9V3.5L18.5 9H13Z" +); + +@include generateSvgClass( + "mdi-file-alert-outline", + "M10 18H8V16H10V18M10 14H8V8H10V14M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2M18 20H6V4H13V9H18V20Z" +); -/* Material Design Icons */ -@include loadsvg( - ".mdi.mdi-account", - "M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-cad", + "M6 2C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2M13 3.5L18.5 9H13M9.88 9.25H11.12V10.19C11.81 10.18 12.38 10.75 12.38 11.44V13.5L12.26 13.63L13.15 15.17C13.47 14.67 13.63 14.09 13.62 13.5H14.88C14.88 14.54 14.5 15.55 13.83 16.35L15.5 19.25V20.5L14.42 19.88L12.87 17.19C12.17 17.65 11.34 17.89 10.5 17.89C9.66 17.89 8.84 17.65 8.13 17.19L6.58 19.88L5.5 20.5V19.25L8.74 13.63L8.62 13.5V11.44C8.62 10.75 9.19 10.18 9.88 10.19M10.5 11.44C9.81 11.44 9.46 12.28 9.95 12.77C10.44 13.26 11.28 12.92 11.28 12.22C11.28 11.79 10.93 11.44 10.5 11.44M9.66 14.54L8.76 16.11C9.81 16.82 11.19 16.82 12.24 16.11L11.34 14.54C10.87 15 10.13 15 9.66 14.54Z" ); -@include loadsvg( - ".mdi.mdi-account-box", - "M6,17C6,15 10,13.9 12,13.9C14,13.9 18,15 18,17V18H6M15,9A3,3 0 0,1 12,12A3,3 0 0,1 9,9A3,3 0 0,1 12,6A3,3 0 0,1 15,9M3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3H5C3.89,3 3,3.9 3,5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-check", + "M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M11.2,18.46L15.95,13.71L14.78,12.3L11.2,15.88L9.61,14.3L8.45,15.46L11.2,18.46Z" ); -@include loadsvg( - ".mdi.mdi-account-box-outline", - "M19,19H5V5H19M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M16.5,16.25C16.5,14.75 13.5,14 12,14C10.5,14 7.5,14.75 7.5,16.25V17H16.5M12,12.25A2.25,2.25 0 0,0 14.25,10A2.25,2.25 0 0,0 12,7.75A2.25,2.25 0 0,0 9.75,10A2.25,2.25 0 0,0 12,12.25Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-check-outline", + "M14,2L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2H14M18,20V9H13V4H6V20H18M11.2,18.46L8.45,15.46L9.61,14.3L11.2,15.88L14.78,12.3L15.95,13.71L11.2,18.46Z" ); -@include loadsvg( - ".mdi.mdi-account-circle", - "M12,19.2C9.5,19.2 7.29,17.92 6,16C6.03,14 10,12.9 12,12.9C14,12.9 17.97,14 18,16C16.71,17.92 14.5,19.2 12,19.2M12,5A3,3 0 0,1 15,8A3,3 0 0,1 12,11A3,3 0 0,1 9,8A3,3 0 0,1 12,5M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-document-outline", + "M6,2A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6M6,4H13V9H18V20H6V4M8,12V14H16V12H8M8,16V18H13V16H8Z" ); -@include loadsvg( - ".mdi.mdi-account-edit", - "M21.7,13.35L20.7,14.35L18.65,12.3L19.65,11.3C19.86,11.09 20.21,11.09 20.42,11.3L21.7,12.58C21.91,12.79 21.91,13.14 21.7,13.35M12,18.94L18.06,12.88L20.11,14.93L14.06,21H12V18.94M12,14C7.58,14 4,15.79 4,18V20H10V18.11L14,14.11C13.34,14.03 12.67,14 12,14M12,4A4,4 0 0,0 8,8A4,4 0 0,0 12,12A4,4 0 0,0 16,8A4,4 0 0,0 12,4Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-excel-outline", + "M14 2H6C4.89 2 4 2.9 4 4V20C4 21.11 4.89 22 6 22H18C19.11 22 20 21.11 20 20V8L14 2M18 20H6V4H13V9H18V20M12.9 14.5L15.8 19H14L12 15.6L10 19H8.2L11.1 14.5L8.2 10H10L12 13.4L14 10H15.8L12.9 14.5Z" ); -@include loadsvg( - ".mdi.mdi-account-minus", - "M15,14C12.33,14 7,15.33 7,18V20H23V18C23,15.33 17.67,14 15,14M1,10V12H9V10M15,12A4,4 0 0,0 19,8A4,4 0 0,0 15,4A4,4 0 0,0 11,8A4,4 0 0,0 15,12Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-move", + "M14,17H18V14L23,18.5L18,23V20H14V17M13,9H18.5L13,3.5V9M6,2H14L20,8V12.34C19.37,12.12 18.7,12 18,12A6,6 0 0,0 12,18C12,19.54 12.58,20.94 13.53,22H6C4.89,22 4,21.1 4,20V4A2,2 0 0,1 6,2Z" ); -@include loadsvg( - ".mdi.mdi-account-off", - "M12,4A4,4 0 0,1 16,8C16,9.95 14.6,11.58 12.75,11.93L8.07,7.25C8.42,5.4 10.05,4 12,4M12.28,14L18.28,20L20,21.72L18.73,23L15.73,20H4V18C4,16.16 6.5,14.61 9.87,14.14L2.78,7.05L4.05,5.78L12.28,14M20,18V19.18L15.14,14.32C18,14.93 20,16.35 20,18Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-move-outline", + "M14 2H6C4.9 2 4 2.9 4 4V20C4 20.41 4.12 20.8 4.34 21.12C4.41 21.23 4.5 21.33 4.59 21.41C4.95 21.78 5.45 22 6 22H13.53C13 21.42 12.61 20.75 12.35 20H6V4H13V9H18V12C18.7 12 19.37 12.12 20 12.34V8L14 2M18 23L23 18.5L20 15.8L18 14V17H14V20H18V23Z" ); -@include loadsvg( - ".mdi.mdi-account-plus", - "M15,14C12.33,14 7,15.33 7,18V20H23V18C23,15.33 17.67,14 15,14M6,10V7H4V10H1V12H4V15H6V12H9V10M15,12A4,4 0 0,0 19,8A4,4 0 0,0 15,4A4,4 0 0,0 11,8A4,4 0 0,0 15,12Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-multiple", + "M15,7H20.5L15,1.5V7M8,0H16L22,6V18A2,2 0 0,1 20,20H8C6.89,20 6,19.1 6,18V2A2,2 0 0,1 8,0M4,4V22H20V24H4A2,2 0 0,1 2,22V4H4Z" ); -@include loadsvg( - ".mdi.mdi-account-search", - "M15.5,12C18,12 20,14 20,16.5C20,17.38 19.75,18.21 19.31,18.9L22.39,22L21,23.39L17.88,20.32C17.19,20.75 16.37,21 15.5,21C13,21 11,19 11,16.5C11,14 13,12 15.5,12M15.5,14A2.5,2.5 0 0,0 13,16.5A2.5,2.5 0 0,0 15.5,19A2.5,2.5 0 0,0 18,16.5A2.5,2.5 0 0,0 15.5,14M10,4A4,4 0 0,1 14,8C14,8.91 13.69,9.75 13.18,10.43C12.32,10.75 11.55,11.26 10.91,11.9L10,12A4,4 0 0,1 6,8A4,4 0 0,1 10,4M2,20V18C2,15.88 5.31,14.14 9.5,14C9.18,14.78 9,15.62 9,16.5C9,17.79 9.38,19 10,20H2Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-multiple-outline", + "M16 0H8C6.9 0 6 .9 6 2V18C6 19.1 6.9 20 8 20H20C21.1 20 22 19.1 22 18V6L16 0M20 18H8V2H15V7H20V18M4 4V22H20V24H4C2.9 24 2 23.1 2 22V4H4Z" ); -@include loadsvg( - ".mdi.mdi-alarm", - "M12,20A7,7 0 0,1 5,13A7,7 0 0,1 12,6A7,7 0 0,1 19,13A7,7 0 0,1 12,20M12,4A9,9 0 0,0 3,13A9,9 0 0,0 12,22A9,9 0 0,0 21,13A9,9 0 0,0 12,4M12.5,8H11V14L15.75,16.85L16.5,15.62L12.5,13.25V8M7.88,3.39L6.6,1.86L2,5.71L3.29,7.24L7.88,3.39M22,5.72L17.4,1.86L16.11,3.39L20.71,7.25L22,5.72Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-music-outline", + "M14,2L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2H14M18,20V9H13V4H6V20H18M13,10V12H11V17A2,2 0 0,1 9,19A2,2 0 0,1 7,17A2,2 0 0,1 9,15C9.4,15 9.7,15.1 10,15.3V10H13Z" ); -@include loadsvg( - ".mdi.mdi-alarm-check", - "M10.54,14.53L8.41,12.4L7.35,13.46L10.53,16.64L16.53,10.64L15.47,9.58L10.54,14.53M12,20A7,7 0 0,1 5,13A7,7 0 0,1 12,6A7,7 0 0,1 19,13A7,7 0 0,1 12,20M12,4A9,9 0 0,0 3,13A9,9 0 0,0 12,22A9,9 0 0,0 21,13A9,9 0 0,0 12,4M7.88,3.39L6.6,1.86L2,5.71L3.29,7.24L7.88,3.39M22,5.72L17.4,1.86L16.11,3.39L20.71,7.25L22,5.72Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-outline", + "M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z" ); -@include loadsvg( - ".mdi.mdi-alarm-off", - "M8,3.28L6.6,1.86L5.74,2.57L7.16,4M16.47,18.39C15.26,19.39 13.7,20 12,20A7,7 0 0,1 5,13C5,11.3 5.61,9.74 6.61,8.53M2.92,2.29L1.65,3.57L3,4.9L1.87,5.83L3.29,7.25L4.4,6.31L5.2,7.11C3.83,8.69 3,10.75 3,13A9,9 0 0,0 12,22C14.25,22 16.31,21.17 17.89,19.8L20.09,22L21.36,20.73L3.89,3.27L2.92,2.29M22,5.72L17.4,1.86L16.11,3.39L20.71,7.25L22,5.72M12,6A7,7 0 0,1 19,13C19,13.84 18.84,14.65 18.57,15.4L20.09,16.92C20.67,15.73 21,14.41 21,13A9,9 0 0,0 12,4C10.59,4 9.27,4.33 8.08,4.91L9.6,6.43C10.35,6.16 11.16,6 12,6Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-pdf-outline", + "M14,2L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2H14M18,20V9H13V4H6V20H18M10.92,12.31C10.68,11.54 10.15,9.08 11.55,9.04C12.95,9 12.03,12.16 12.03,12.16C12.42,13.65 14.05,14.72 14.05,14.72C14.55,14.57 17.4,14.24 17,15.72C16.57,17.2 13.5,15.81 13.5,15.81C11.55,15.95 10.09,16.47 10.09,16.47C8.96,18.58 7.64,19.5 7.1,18.61C6.43,17.5 9.23,16.07 9.23,16.07C10.68,13.72 10.9,12.35 10.92,12.31M11.57,13.15C11.17,14.45 10.37,15.84 10.37,15.84C11.22,15.5 13.08,15.11 13.08,15.11C11.94,14.11 11.59,13.16 11.57,13.15M14.71,15.32C14.71,15.32 16.46,15.97 16.5,15.71C16.57,15.44 15.17,15.2 14.71,15.32M9.05,16.81C8.28,17.11 7.54,18.39 7.72,18.39C7.9,18.4 8.63,17.79 9.05,16.81M11.57,11.26C11.57,11.21 12,9.58 11.57,9.53C11.27,9.5 11.56,11.22 11.57,11.26Z" ); -@include loadsvg( - ".mdi.mdi-alert", - "M13 14H11V9H13M13 18H11V16H13M1 21H23L12 2L1 21Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-question", + "M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6M13,3.5L18.5,9H13V3.5M12,11A3,3 0 0,1 15,14C15,15.88 12.75,16.06 12.75,17.75H11.25C11.25,15.31 13.5,15.5 13.5,14A1.5,1.5 0 0,0 12,12.5A1.5,1.5 0 0,0 10.5,14H9A3,3 0 0,1 12,11M11.25,18.5H12.75V20H11.25V18.5Z" ); -@include loadsvg( - ".mdi.mdi-alert-box", - "M5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3M13,13V7H11V13H13M13,17V15H11V17H13Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-question-outline", + "M14 2H6C4.89 2 4 2.9 4 4V20C4 21.11 4.89 22 6 22H18C19.11 22 20 21.11 20 20V8L14 2M18 20H6V4H13V9H18V20M15 13C15 14.89 12.75 15.07 12.75 16.76H11.25C11.25 14.32 13.5 14.5 13.5 13C13.5 12.18 12.83 11.5 12 11.5S10.5 12.18 10.5 13H9C9 11.35 10.34 10 12 10S15 11.35 15 13M12.75 17.5V19H11.25V17.5H12.75Z" ); -@include loadsvg( - ".mdi.mdi-alert-box-outline", - "M19,19H5V5H19M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M11,15H13V17H11V15M11,7H13V13H11V7", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-search-outline", + "M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H13C12.59,21.75 12.2,21.44 11.86,21.1C11.53,20.77 11.25,20.4 11,20H6V4H13V9H18V10.18C18.71,10.34 19.39,10.61 20,11V8L14,2M20.31,18.9C21.64,16.79 21,14 18.91,12.68C16.8,11.35 14,12 12.69,14.08C11.35,16.19 12,18.97 14.09,20.3C15.55,21.23 17.41,21.23 18.88,20.32L22,23.39L23.39,22L20.31,18.9M16.5,19A2.5,2.5 0 0,1 14,16.5A2.5,2.5 0 0,1 16.5,14A2.5,2.5 0 0,1 19,16.5A2.5,2.5 0 0,1 16.5,19Z" ); -@include loadsvg( - ".mdi.mdi-alert-circle", - "M13,13H11V7H13M13,17H11V15H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-send", + "M14,2H6C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M12.54,19.37V17.37H8.54V15.38H12.54V13.38L15.54,16.38L12.54,19.37M13,9V3.5L18.5,9H13Z" ); -@include loadsvg( - ".mdi.mdi-alert-octagon", - "M13 13H11V7H13M11 15H13V17H11M15.73 3H8.27L3 8.27V15.73L8.27 21H15.73L21 15.73V8.27L15.73 3Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-send-outline", + "M14 2H6C4.89 2 4 2.9 4 4V20C4 21.11 4.89 22 6 22H18C19.11 22 20 21.11 20 20V8L14 2M18 20H6V4H13V9H18V20M12.54 18.5V16.5H8.54V14.5H12.54V12.5L15.54 15.5L12.54 18.5Z" ); -@include loadsvg( - ".mdi.mdi-alert-outline", - "M12,2L1,21H23M12,6L19.53,19H4.47M11,10V14H13V10M11,16V18H13V16", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-tree", + "M3,3H9V7H3V3M15,10H21V14H15V10M15,17H21V21H15V17M13,13H7V18H13V20H7L5,20V9H7V11H13V13Z" ); -@include loadsvg( - ".mdi.mdi-alert-rhombus", - "M12 2C11.5 2 11 2.19 10.59 2.59L2.59 10.59C1.8 11.37 1.8 12.63 2.59 13.41L10.59 21.41C11.37 22.2 12.63 22.2 13.41 21.41L21.41 13.41C22.2 12.63 22.2 11.37 21.41 10.59L13.41 2.59C13 2.19 12.5 2 12 2M11 7H13V13H11V7M11 15H13V17H11V15Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-tree-outline", + "M12 13H7V18H12V20H5V10H7V11H12V13M8 4V6H4V4H8M10 2H2V8H10V2M20 11V13H16V11H20M22 9H14V15H22V9M20 18V20H16V18H20M22 16H14V22H22V16Z" ); -@include loadsvg( - ".mdi.mdi-alert-rhombus-outline", - "M12 2C11.5 2 11 2.19 10.59 2.59L2.59 10.59C1.8 11.37 1.8 12.63 2.59 13.41L10.59 21.41C11.37 22.2 12.63 22.2 13.41 21.41L21.41 13.41C22.2 12.63 22.2 11.37 21.41 10.59L13.41 2.59C13 2.19 12.5 2 12 2M12 4L20 12L12 20L4 12M11 7V13H13V7M11 15V17H13V15Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block +@include generateSvgClass( + "mdi-file-upload", + "M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M13.5,16V19H10.5V16H8L12,12L16,16H13.5M13,9V3.5L18.5,9H13Z" ); -@include loadsvg( - ".mdi.mdi-arrow-collapse", - "M19.5,3.09L15,7.59V4H13V11H20V9H16.41L20.91,4.5L19.5,3.09M4,13V15H7.59L3.09,19.5L4.5,20.91L9,16.41V20H11V13H4Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); +@include generateSvgClass( + "mdi-file-upload-outline", + "M14,2L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2H14M18,20V9H13V4H6V20H18M12,12L16,16H13.5V19H10.5V16H8L12,12Z" +); + +@include generateSvgClass( + "mdi-filter", + "M14,12V19.88C14.04,20.18 13.94,20.5 13.71,20.71C13.32,21.1 12.69,21.1 12.3,20.71L10.29,18.7C10.06,18.47 9.96,18.16 10,17.87V12H9.97L4.21,4.62C3.87,4.19 3.95,3.56 4.38,3.22C4.57,3.08 4.78,3 5,3V3H19V3C19.22,3 19.43,3.08 19.62,3.22C20.05,3.56 20.13,4.19 19.79,4.62L14.03,12H14Z" +); + +@include generateSvgClass( + "mdi-filter-minus-outline", + "M15 17H23V19H15V17M13 19.88C13.04 20.18 12.94 20.5 12.72 20.71C12.32 21.1 11.69 21.1 11.3 20.71L7.29 16.7C7.06 16.47 6.96 16.16 7 15.87V10.75L2.21 4.62C1.87 4.19 1.95 3.56 2.38 3.22C2.57 3.08 2.78 3 3 3V3H17V3C17.22 3 17.43 3.08 17.62 3.22C18.05 3.56 18.13 4.19 17.79 4.62L13 10.75V19.88M5.04 5L9 10.07V15.58L11 17.58V10.05L14.96 5H5.04Z" +); + +@include generateSvgClass( + "mdi-filter-off-outline", + "M2.39 1.73L1.11 3L9 10.89V15.87C8.96 16.16 9.06 16.47 9.29 16.7L13.3 20.71C13.69 21.1 14.32 21.1 14.71 20.71C14.94 20.5 15.04 20.18 15 19.88V16.89L20.84 22.73L22.11 21.46L15 14.35V14.34L13 12.35L11 10.34L4.15 3.5L2.39 1.73M6.21 3L8.2 5H16.96L13.11 9.91L15 11.8V10.75L19.79 4.62C20.13 4.19 20.05 3.56 19.62 3.22C19.43 3.08 19.22 3 19 3H6.21M11 12.89L13 14.89V17.58L11 15.58V12.89Z" +); + +@include generateSvgClass( + "mdi-filter-outline", + "M15,19.88C15.04,20.18 14.94,20.5 14.71,20.71C14.32,21.1 13.69,21.1 13.3,20.71L9.29,16.7C9.06,16.47 8.96,16.16 9,15.87V10.75L4.21,4.62C3.87,4.19 3.95,3.56 4.38,3.22C4.57,3.08 4.78,3 5,3V3H19V3C19.22,3 19.43,3.08 19.62,3.22C20.05,3.56 20.13,4.19 19.79,4.62L15,10.75V19.88M7.04,5L11,10.06V15.58L13,17.58V10.05L16.96,5H7.04Z" +); + +@include generateSvgClass( + "mdi-filter-plus-outline", + "M15 17H18V14H20V17H23V19H20V22H18V19H15V17M13 19.88C13.04 20.18 12.94 20.5 12.72 20.71C12.32 21.1 11.69 21.1 11.3 20.71L7.29 16.7C7.06 16.47 6.96 16.16 7 15.87V10.75L2.21 4.62C1.87 4.19 1.95 3.56 2.38 3.22C2.57 3.08 2.78 3 3 3V3H17V3C17.22 3 17.43 3.08 17.62 3.22C18.05 3.56 18.13 4.19 17.79 4.62L13 10.75V19.88M5.04 5L9 10.07V15.58L11 17.58V10.05L14.96 5H5.04Z" +); + +@include generateSvgClass( + "mdi-filter-remove-outline", + "M14.73,20.83L17.58,18L14.73,15.17L16.15,13.76L19,16.57L21.8,13.76L23.22,15.17L20.41,18L23.22,20.83L21.8,22.24L19,19.4L16.15,22.24L14.73,20.83M13,19.88C13.04,20.18 12.94,20.5 12.71,20.71C12.32,21.1 11.69,21.1 11.3,20.71L7.29,16.7C7.06,16.47 6.96,16.16 7,15.87V10.75L2.21,4.62C1.87,4.19 1.95,3.56 2.38,3.22C2.57,3.08 2.78,3 3,3V3H17V3C17.22,3 17.43,3.08 17.62,3.22C18.05,3.56 18.13,4.19 17.79,4.62L13,10.75V19.88M5.04,5L9,10.06V15.58L11,17.58V10.05L14.96,5H5.04Z" +); + +@include generateSvgClass( + "mdi-fire", + "M17.66 11.2C17.43 10.9 17.15 10.64 16.89 10.38C16.22 9.78 15.46 9.35 14.82 8.72C13.33 7.26 13 4.85 13.95 3C13 3.23 12.17 3.75 11.46 4.32C8.87 6.4 7.85 10.07 9.07 13.22C9.11 13.32 9.15 13.42 9.15 13.55C9.15 13.77 9 13.97 8.8 14.05C8.57 14.15 8.33 14.09 8.14 13.93C8.08 13.88 8.04 13.83 8 13.76C6.87 12.33 6.69 10.28 7.45 8.64C5.78 10 4.87 12.3 5 14.47C5.06 14.97 5.12 15.47 5.29 15.97C5.43 16.57 5.7 17.17 6 17.7C7.08 19.43 8.95 20.67 10.96 20.92C13.1 21.19 15.39 20.8 17.03 19.32C18.86 17.66 19.5 15 18.56 12.72L18.43 12.46C18.22 12 17.66 11.2 17.66 11.2M14.5 17.5C14.22 17.74 13.76 18 13.4 18.1C12.28 18.5 11.16 17.94 10.5 17.28C11.69 17 12.4 16.12 12.61 15.23C12.78 14.43 12.46 13.77 12.33 13C12.21 12.26 12.23 11.63 12.5 10.94C12.69 11.32 12.89 11.7 13.13 12C13.9 13 15.11 13.44 15.37 14.8C15.41 14.94 15.43 15.08 15.43 15.23C15.46 16.05 15.1 16.95 14.5 17.5H14.5Z" +); + +@include generateSvgClass( + "mdi-flip-vertical", + "M3 15V17H5V15M15 19V21H17V19M19 3H5C3.9 3 3 3.9 3 5V9H5V5H19V9H21V5C21 3.9 20.1 3 19 3M21 19H19V21C20.1 21 21 20.1 21 19M1 11V13H23V11M7 19V21H9V19M19 15V17H21V15M11 19V21H13V19M3 19C3 20.1 3.9 21 5 21V19Z" +); + +@include generateSvgClass( + "mdi-folder", + "M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z" +); + +@include generateSvgClass( + "mdi-folder-open", + "M19,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10L12,6H19A2,2 0 0,1 21,8H21L4,8V18L6.14,10H23.21L20.93,18.5C20.7,19.37 19.92,20 19,20Z" +); -@include loadsvg( - ".mdi.mdi-arrow-down", - "M11,4H13V16L18.5,10.5L19.92,11.92L12,19.84L4.08,11.92L5.5,10.5L11,16V4Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); +@include generateSvgClass( + "mdi-forum", + "M17,12V3A1,1 0 0,0 16,2H3A1,1 0 0,0 2,3V17L6,13H16A1,1 0 0,0 17,12M21,6H19V15H6V17A1,1 0 0,0 7,18H18L22,22V7A1,1 0 0,0 21,6Z" +); -@include loadsvg( - ".mdi.mdi-arrow-down-bold", - "M9,4H15V12H19.84L12,19.84L4.16,12H9V4Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); +@include generateSvgClass( + "mdi-forum-outline", + "M15,4V11H5.17L4,12.17V4H15M16,2H3A1,1 0 0,0 2,3V17L6,13H16A1,1 0 0,0 17,12V3A1,1 0 0,0 16,2M21,6H19V15H6V17A1,1 0 0,0 7,18H18L22,22V7A1,1 0 0,0 21,6Z" +); -@include loadsvg( - ".mdi.mdi-arrow-down-bold-box", - "M5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3M12,17L17,12H14V8H10V12H7L12,17Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); +@include generateSvgClass( + "mdi-github", + "M12,2A10,10 0 0,0 2,12C2,16.42 4.87,20.17 8.84,21.5C9.34,21.58 9.5,21.27 9.5,21C9.5,20.77 9.5,20.14 9.5,19.31C6.73,19.91 6.14,17.97 6.14,17.97C5.68,16.81 5.03,16.5 5.03,16.5C4.12,15.88 5.1,15.9 5.1,15.9C6.1,15.97 6.63,16.93 6.63,16.93C7.5,18.45 8.97,18 9.54,17.76C9.63,17.11 9.89,16.67 10.17,16.42C7.95,16.17 5.62,15.31 5.62,11.5C5.62,10.39 6,9.5 6.65,8.79C6.55,8.54 6.2,7.5 6.75,6.15C6.75,6.15 7.59,5.88 9.5,7.17C10.29,6.95 11.15,6.84 12,6.84C12.85,6.84 13.71,6.95 14.5,7.17C16.41,5.88 17.25,6.15 17.25,6.15C17.8,7.5 17.45,8.54 17.35,8.79C18,9.5 18.38,10.39 18.38,11.5C18.38,15.32 16.04,16.16 13.81,16.41C14.17,16.72 14.5,17.33 14.5,18.26C14.5,19.6 14.5,20.68 14.5,21C14.5,21.27 14.66,21.59 15.17,21.5C19.14,20.16 22,16.42 22,12A10,10 0 0,0 12,2Z" +); -@include loadsvg( - ".mdi.mdi-arrow-down-bold-box-outline", - "M12,17L7,12H10V8H14V12H17L12,17M5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3M5,5V19H19V5H5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); +@include generateSvgClass( + "mdi-help", + "M10,19H13V22H10V19M12,2C17.35,2.22 19.68,7.62 16.5,11.67C15.67,12.67 14.33,13.33 13.67,14.17C13,15 13,16 13,17H10C10,15.33 10,13.92 10.67,12.92C11.33,11.92 12.67,11.33 13.5,10.67C15.92,8.43 15.32,5.26 12,5A3,3 0 0,0 9,8H6A6,6 0 0,1 12,2Z" +); + +@include generateSvgClass( + "mdi-help-circle", + "M15.07,11.25L14.17,12.17C13.45,12.89 13,13.5 13,15H11V14.5C11,13.39 11.45,12.39 12.17,11.67L13.41,10.41C13.78,10.05 14,9.55 14,9C14,7.89 13.1,7 12,7A2,2 0 0,0 10,9H8A4,4 0 0,1 12,5A4,4 0 0,1 16,9C16,9.88 15.64,10.67 15.07,11.25M13,19H11V17H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z" +); + +@include generateSvgClass( + "mdi-help-circle-outline", + "M11,18H13V16H11V18M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,6A4,4 0 0,0 8,10H10A2,2 0 0,1 12,8A2,2 0 0,1 14,10C14,12 11,11.75 11,15H13C13,12.75 16,12.5 16,10A4,4 0 0,0 12,6Z" +); + +@include generateSvgClass( + "mdi-history", + "M13.5,8H12V13L16.28,15.54L17,14.33L13.5,12.25V8M13,3A9,9 0 0,0 4,12H1L4.96,16.03L9,12H6A7,7 0 0,1 13,5A7,7 0 0,1 20,12A7,7 0 0,1 13,19C11.07,19 9.32,18.21 8.06,16.94L6.64,18.36C8.27,20 10.5,21 13,21A9,9 0 0,0 22,12A9,9 0 0,0 13,3" +); + +@include generateSvgClass( + "mdi-information", + "M13,9H11V7H13M13,17H11V11H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" +); + +@include generateSvgClass( + "mdi-information-outline", + "M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,17H13V11H11V17Z" +); + +@include generateSvgClass( + "mdi-lightbulb", + "M12,2A7,7 0 0,0 5,9C5,11.38 6.19,13.47 8,14.74V17A1,1 0 0,0 9,18H15A1,1 0 0,0 16,17V14.74C17.81,13.47 19,11.38 19,9A7,7 0 0,0 12,2M9,21A1,1 0 0,0 10,22H14A1,1 0 0,0 15,21V20H9V21Z" +); + +@include generateSvgClass( + "mdi-lightbulb-off", + "M12,2C9.76,2 7.78,3.05 6.5,4.68L16.31,14.5C17.94,13.21 19,11.24 19,9A7,7 0 0,0 12,2M3.28,4L2,5.27L5.04,8.3C5,8.53 5,8.76 5,9C5,11.38 6.19,13.47 8,14.74V17A1,1 0 0,0 9,18H14.73L18.73,22L20,20.72L3.28,4M9,20V21A1,1 0 0,0 10,22H14A1,1 0 0,0 15,21V20H9Z" +); + +@include generateSvgClass( + "mdi-lightbulb-off-outline", + "M12,2C9.76,2 7.78,3.05 6.5,4.68L7.93,6.11C8.84,4.84 10.32,4 12,4A5,5 0 0,1 17,9C17,10.68 16.16,12.16 14.89,13.06L16.31,14.5C17.94,13.21 19,11.24 19,9A7,7 0 0,0 12,2M3.28,4L2,5.27L5.04,8.3C5,8.53 5,8.76 5,9C5,11.38 6.19,13.47 8,14.74V17A1,1 0 0,0 9,18H14.73L18.73,22L20,20.72L3.28,4M7.23,10.5L12.73,16H10V13.58C8.68,13 7.66,11.88 7.23,10.5M9,20V21A1,1 0 0,0 10,22H14A1,1 0 0,0 15,21V20H9Z" +); + +@include generateSvgClass( + "mdi-lightbulb-on", + "M12,6A6,6 0 0,1 18,12C18,14.22 16.79,16.16 15,17.2V19A1,1 0 0,1 14,20H10A1,1 0 0,1 9,19V17.2C7.21,16.16 6,14.22 6,12A6,6 0 0,1 12,6M14,21V22A1,1 0 0,1 13,23H11A1,1 0 0,1 10,22V21H14M20,11H23V13H20V11M1,11H4V13H1V11M13,1V4H11V1H13M4.92,3.5L7.05,5.64L5.63,7.05L3.5,4.93L4.92,3.5M16.95,5.63L19.07,3.5L20.5,4.93L18.37,7.05L16.95,5.63Z" +); + +@include generateSvgClass( + "mdi-lightbulb-on-outline", + "M20,11H23V13H20V11M1,11H4V13H1V11M13,1V4H11V1H13M4.92,3.5L7.05,5.64L5.63,7.05L3.5,4.93L4.92,3.5M16.95,5.63L19.07,3.5L20.5,4.93L18.37,7.05L16.95,5.63M12,6A6,6 0 0,1 18,12C18,14.22 16.79,16.16 15,17.2V19A1,1 0 0,1 14,20H10A1,1 0 0,1 9,19V17.2C7.21,16.16 6,14.22 6,12A6,6 0 0,1 12,6M14,21V22A1,1 0 0,1 13,23H11A1,1 0 0,1 10,22V21H14M11,18H13V15.87C14.73,15.43 16,13.86 16,12A4,4 0 0,0 12,8A4,4 0 0,0 8,12C8,13.86 9.27,15.43 11,15.87V18Z" +); + +@include generateSvgClass( + "mdi-lightbulb-outline", + "M12,2A7,7 0 0,1 19,9C19,11.38 17.81,13.47 16,14.74V17A1,1 0 0,1 15,18H9A1,1 0 0,1 8,17V14.74C6.19,13.47 5,11.38 5,9A7,7 0 0,1 12,2M9,21V20H15V21A1,1 0 0,1 14,22H10A1,1 0 0,1 9,21M12,4A5,5 0 0,0 7,9C7,11.05 8.23,12.81 10,13.58V16H14V13.58C15.77,12.81 17,11.05 17,9A5,5 0 0,0 12,4Z" +); + +@include generateSvgClass( + "mdi-link", + "M3.9,12C3.9,10.29 5.29,8.9 7,8.9H11V7H7A5,5 0 0,0 2,12A5,5 0 0,0 7,17H11V15.1H7C5.29,15.1 3.9,13.71 3.9,12M8,13H16V11H8V13M17,7H13V8.9H17C18.71,8.9 20.1,10.29 20.1,12C20.1,13.71 18.71,15.1 17,15.1H13V17H17A5,5 0 0,0 22,12A5,5 0 0,0 17,7Z" +); + +@include generateSvgClass( + "mdi-link-variant", + "M10.59,13.41C11,13.8 11,14.44 10.59,14.83C10.2,15.22 9.56,15.22 9.17,14.83C7.22,12.88 7.22,9.71 9.17,7.76V7.76L12.71,4.22C14.66,2.27 17.83,2.27 19.78,4.22C21.73,6.17 21.73,9.34 19.78,11.29L18.29,12.78C18.3,11.96 18.17,11.14 17.89,10.36L18.36,9.88C19.54,8.71 19.54,6.81 18.36,5.64C17.19,4.46 15.29,4.46 14.12,5.64L10.59,9.17C9.41,10.34 9.41,12.24 10.59,13.41M13.41,9.17C13.8,8.78 14.44,8.78 14.83,9.17C16.78,11.12 16.78,14.29 14.83,16.24V16.24L11.29,19.78C9.34,21.73 6.17,21.73 4.22,19.78C2.27,17.83 2.27,14.66 4.22,12.71L5.71,11.22C5.7,12.04 5.83,12.86 6.11,13.65L5.64,14.12C4.46,15.29 4.46,17.19 5.64,18.36C6.81,19.54 8.71,19.54 9.88,18.36L13.41,14.83C14.59,13.66 14.59,11.76 13.41,10.59C13,10.2 13,9.56 13.41,9.17Z" +); + +@include generateSvgClass( + "mdi-load", + "M12,4V2A10,10 0 0,0 2,12H4A8,8 0 0,1 12,4Z" +); + +@include generateSvgClass( + "mdi-magnify", + "M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z" +); + +@include generateSvgClass( + "mdi-map-marker-radius", + "M12,2C15.31,2 18,4.66 18,7.95C18,12.41 12,19 12,19C12,19 6,12.41 6,7.95C6,4.66 8.69,2 12,2M12,6A2,2 0 0,0 10,8A2,2 0 0,0 12,10A2,2 0 0,0 14,8A2,2 0 0,0 12,6M20,19C20,21.21 16.42,23 12,23C7.58,23 4,21.21 4,19C4,17.71 5.22,16.56 7.11,15.83L7.75,16.74C6.67,17.19 6,17.81 6,18.5C6,19.88 8.69,21 12,21C15.31,21 18,19.88 18,18.5C18,17.81 17.33,17.19 16.25,16.74L16.89,15.83C18.78,16.56 20,17.71 20,19Z" +); + +@include generateSvgClass( + "mdi-map-marker-radius-outline", + "M12 4C14.2 4 16 5.8 16 8C16 10.1 13.9 13.5 12 15.9C10.1 13.4 8 10.1 8 8C8 5.8 9.8 4 12 4M12 2C8.7 2 6 4.7 6 8C6 12.5 12 19 12 19S18 12.4 18 8C18 4.7 15.3 2 12 2M12 6C10.9 6 10 6.9 10 8S10.9 10 12 10 14 9.1 14 8 13.1 6 12 6M20 19C20 21.2 16.4 23 12 23S4 21.2 4 19C4 17.7 5.2 16.6 7.1 15.8L7.7 16.7C6.7 17.2 6 17.8 6 18.5C6 19.9 8.7 21 12 21S18 19.9 18 18.5C18 17.8 17.3 17.2 16.2 16.7L16.8 15.8C18.8 16.6 20 17.7 20 19Z" +); + +@include generateSvgClass( + "mdi-menu", + "M3,6H21V8H3V6M3,11H21V13H3V11M3,16H21V18H3V16Z" +); + +@include generateSvgClass( + "mdi-message-text", + "M20,2H4A2,2 0 0,0 2,4V22L6,18H20A2,2 0 0,0 22,16V4A2,2 0 0,0 20,2M6,9H18V11H6M14,14H6V12H14M18,8H6V6H18" +); + +@include generateSvgClass( + "mdi-message-text-outline", + "M20,2A2,2 0 0,1 22,4V16A2,2 0 0,1 20,18H6L2,22V4C2,2.89 2.9,2 4,2H20M4,4V17.17L5.17,16H20V4H4M6,7H18V9H6V7M6,11H15V13H6V11Z" +); + +@include generateSvgClass( + "mdi-microsoft-excel", + "M21.17 3.25Q21.5 3.25 21.76 3.5 22 3.74 22 4.08V19.92Q22 20.26 21.76 20.5 21.5 20.75 21.17 20.75H7.83Q7.5 20.75 7.24 20.5 7 20.26 7 19.92V17H2.83Q2.5 17 2.24 16.76 2 16.5 2 16.17V7.83Q2 7.5 2.24 7.24 2.5 7 2.83 7H7V4.08Q7 3.74 7.24 3.5 7.5 3.25 7.83 3.25M7 13.06L8.18 15.28H9.97L8 12.06L9.93 8.89H8.22L7.13 10.9L7.09 10.96L7.06 11.03Q6.8 10.5 6.5 9.96 6.25 9.43 5.97 8.89H4.16L6.05 12.08L4 15.28H5.78M13.88 19.5V17H8.25V19.5M13.88 15.75V12.63H12V15.75M13.88 11.38V8.25H12V11.38M13.88 7V4.5H8.25V7M20.75 19.5V17H15.13V19.5M20.75 15.75V12.63H15.13V15.75M20.75 11.38V8.25H15.13V11.38M20.75 7V4.5H15.13V7Z" +); + +@include generateSvgClass( + "mdi-minus", + "M19,13H5V11H19V13Z" +); + +@include generateSvgClass( + "mdi-minus-circle", + "M17,13H7V11H17M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" +); + +@include generateSvgClass( + "mdi-minus-circle-outline", + "M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M7,13H17V11H7" +); + +@include generateSvgClass( + "mdi-order-bool-ascending-variant", + "M4 13C2.89 13 2 13.89 2 15V19C2 20.11 2.89 21 4 21H8C9.11 21 10 20.11 10 19V15C10 13.89 9.11 13 8 13M8.2 14.5L9.26 15.55L5.27 19.5L2.74 16.95L3.81 15.9L5.28 17.39M4 3C2.89 3 2 3.89 2 5V9C2 10.11 2.89 11 4 11H8C9.11 11 10 10.11 10 9V5C10 3.89 9.11 3 8 3M4 5H8V9H4M12 5H22V7H12M12 19V17H22V19M12 11H22V13H12Z" +); + +@include generateSvgClass( + "mdi-page-first", + "M18.41,16.59L13.82,12L18.41,7.41L17,6L11,12L17,18L18.41,16.59M6,6H8V18H6V6Z" +); + +@include generateSvgClass( + "mdi-page-last", + "M5.59,7.41L10.18,12L5.59,16.59L7,18L13,12L7,6L5.59,7.41M16,6H18V18H16V6Z" +); + +@include generateSvgClass( + "mdi-paperclip", + "M16.5,6V17.5A4,4 0 0,1 12.5,21.5A4,4 0 0,1 8.5,17.5V5A2.5,2.5 0 0,1 11,2.5A2.5,2.5 0 0,1 13.5,5V15.5A1,1 0 0,1 12.5,16.5A1,1 0 0,1 11.5,15.5V6H10V15.5A2.5,2.5 0 0,0 12.5,18A2.5,2.5 0 0,0 15,15.5V5A4,4 0 0,0 11,1A4,4 0 0,0 7,5V17.5A5.5,5.5 0 0,0 12.5,23A5.5,5.5 0 0,0 18,17.5V6H16.5Z" +); + +@include generateSvgClass( + "mdi-pencil", + "M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z" +); + +@include generateSvgClass( + "mdi-pencil-outline", + "M14.06,9L15,9.94L5.92,19H5V18.08L14.06,9M17.66,3C17.41,3 17.15,3.1 16.96,3.29L15.13,5.12L18.88,8.87L20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18.17,3.09 17.92,3 17.66,3M14.06,6.19L3,17.25V21H6.75L17.81,9.94L14.06,6.19Z" +); + +@include generateSvgClass( + "mdi-pencil-box-multiple", + "M20.22 2H7.78C6.8 2 6 2.8 6 3.78V16.22C6 17.2 6.8 18 7.78 18H20.22C21.2 18 22 17.21 22 16.22V3.78C22 2.8 21.2 2 20.22 2M11.06 15H9V12.94L15.06 6.88L17.12 8.94L11.06 15M18.7 7.35L17.7 8.35L15.65 6.3L16.65 5.3C16.86 5.08 17.21 5.08 17.42 5.3L18.7 6.58C18.92 6.79 18.92 7.14 18.7 7.35M4 6H2V20C2 21.11 2.9 22 4 22H18V20H4V6Z" +); + +@include generateSvgClass( + "mdi-pencil-box-multiple-outline", + "M4 6H2V20C2 21.11 2.9 22 4 22H18V20H4V6M18.7 7.35L17.7 8.35L15.65 6.3L16.65 5.3C16.86 5.08 17.21 5.08 17.42 5.3L18.7 6.58C18.92 6.79 18.92 7.14 18.7 7.35M9 12.94L15.06 6.88L17.12 8.94L11.06 15H9V12.94M20 4L20 4L20 16L8 16L8 4H20M20 2H8C6.9 2 6 2.9 6 4V16C6 17.1 6.9 18 8 18H20C21.1 18 22 17.1 22 16V4C22 2.9 21.1 2 20 2Z" +); + +@include generateSvgClass( + "mdi-percent", + "M18.5,3.5L3.5,18.5L5.5,20.5L20.5,5.5M7,4A3,3 0 0,0 4,7A3,3 0 0,0 7,10A3,3 0 0,0 10,7A3,3 0 0,0 7,4M17,14A3,3 0 0,0 14,17A3,3 0 0,0 17,20A3,3 0 0,0 20,17A3,3 0 0,0 17,14Z" +); + +@include generateSvgClass( + "mdi-percent-outline", + "M18.5 3.5L20.5 5.5L5.5 20.5L3.5 18.5L18.5 3.5M7 4C8.66 4 10 5.34 10 7C10 8.66 8.66 10 7 10C5.34 10 4 8.66 4 7C4 5.34 5.34 4 7 4M17 14C18.66 14 20 15.34 20 17C20 18.66 18.66 20 17 20C15.34 20 14 18.66 14 17C14 15.34 15.34 14 17 14M7 6C6.45 6 6 6.45 6 7C6 7.55 6.45 8 7 8C7.55 8 8 7.55 8 7C8 6.45 7.55 6 7 6M17 16C16.45 16 16 16.45 16 17C16 17.55 16.45 18 17 18C17.55 18 18 17.55 18 17C18 16.45 17.55 16 17 16Z" +); + +@include generateSvgClass( + "mdi-pin-off-outline", + "M8,6.2V4H7V2H17V4H16V12L18,14V16H17.8L14,12.2V4H10V8.2L8,6.2M20,20.7L18.7,22L12.8,16.1V22H11.2V16H6V14L8,12V11.3L2,5.3L3.3,4L20,20.7M8.8,14H10.6L9.7,13.1L8.8,14Z" +); + +@include generateSvgClass( + "mdi-pin-outline", + "M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12M8.8,14L10,12.8V4H14V12.8L15.2,14H8.8Z" +); + +@include generateSvgClass( + "mdi-playlist-plus", + "M2,16H10V14H2M18,14V10H16V14H12V16H16V20H18V16H22V14M14,6H2V8H14M14,10H2V12H14V10Z" +); + +@include generateSvgClass( + "mdi-play-circle-outline", + "M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M10,16.5L16,12L10,7.5V16.5Z" +); + +@include generateSvgClass( + "mdi-playlist-remove", + "M2,6V8H14V6H2M2,10V12H11V10H2M14.17,10.76L12.76,12.17L15.59,15L12.76,17.83L14.17,19.24L17,16.41L19.83,19.24L21.24,17.83L18.41,15L21.24,12.17L19.83,10.76L17,13.59L14.17,10.76M2,14V16H11V14H2Z" +); + +@include generateSvgClass( + "mdi-plus-circle", + "M17,13H13V17H11V13H7V11H11V7H13V11H17M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" +); + +@include generateSvgClass( + "mdi-plus-circle-outline", + "M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M13,7H11V11H7V13H11V17H13V13H17V11H13V7Z" +); + +@include generateSvgClass( + "mdi-plus", + "M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z" +); + +@include generateSvgClass( + "mdi-progress-download", + "M13,2.03C17.73,2.5 21.5,6.25 21.95,11C22.5,16.5 18.5,21.38 13,21.93V19.93C16.64,19.5 19.5,16.61 19.96,12.97C20.5,8.58 17.39,4.59 13,4.05V2.05L13,2.03M11,2.06V4.06C9.57,4.26 8.22,4.84 7.1,5.74L5.67,4.26C7.19,3 9.05,2.25 11,2.06M4.26,5.67L5.69,7.1C4.8,8.23 4.24,9.58 4.05,11H2.05C2.25,9.04 3,7.19 4.26,5.67M2.06,13H4.06C4.24,14.42 4.81,15.77 5.69,16.9L4.27,18.33C3.03,16.81 2.26,14.96 2.06,13M7.1,18.37C8.23,19.25 9.58,19.82 11,20V22C9.04,21.79 7.18,21 5.67,19.74L7.1,18.37M12,16.5L7.5,12H11V8H13V12H16.5L12,16.5Z" +); + +@include generateSvgClass( + "mdi-redo", + "M18.4,10.6C16.55,9 14.15,8 11.5,8C6.85,8 2.92,11.03 1.54,15.22L3.9,16C4.95,12.81 7.95,10.5 11.5,10.5C13.45,10.5 15.23,11.22 16.62,12.38L13,16H22V7L18.4,10.6Z" +); + +@include generateSvgClass( + "mdi-refresh", + "M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z" +); + +@include generateSvgClass( + "mdi-shape-square-plus", + "M19,5H22V7H19V10H17V7H14V5H17V2H19V5M17,19V13H19V21H3V5H11V7H5V19H17Z" +); + +@include generateSvgClass( + "mdi-snowflake", + "M20.79,13.95L18.46,14.57L16.46,13.44V10.56L18.46,9.43L20.79,10.05L21.31,8.12L19.54,7.65L20,5.88L18.07,5.36L17.45,7.69L15.45,8.82L13,7.38V5.12L14.71,3.41L13.29,2L12,3.29L10.71,2L9.29,3.41L11,5.12V7.38L8.5,8.82L6.5,7.69L5.92,5.36L4,5.88L4.47,7.65L2.7,8.12L3.22,10.05L5.55,9.43L7.55,10.56V13.45L5.55,14.58L3.22,13.96L2.7,15.89L4.47,16.36L4,18.12L5.93,18.64L6.55,16.31L8.55,15.18L11,16.62V18.88L9.29,20.59L10.71,22L12,20.71L13.29,22L14.7,20.59L13,18.88V16.62L15.5,15.17L17.5,16.3L18.12,18.63L20,18.12L19.53,16.35L21.3,15.88L20.79,13.95M9.5,10.56L12,9.11L14.5,10.56V13.44L12,14.89L9.5,13.44V10.56Z" +); + +@include generateSvgClass( + "mdi-sort-ascending", + "M19 17H22L18 21L14 17H17V3H19M2 17H12V19H2M6 5V7H2V5M2 11H9V13H2V11Z" +); + +@include generateSvgClass( + "mdi-sort-descending", + "M19 7H22L18 3L14 7H17V21H19M2 17H12V19H2M6 5V7H2V5M2 11H9V13H2V11Z" +); + +@include generateSvgClass( + "mdi-sort-variant-off", + "M20.84 22.73L11.11 13H3V11H9.11L6.11 8H3V6H4.11L1.11 3L2.39 1.73L22.11 21.46L20.84 22.73M15 11H14.2L15 11.8V11M21 8V6H9.2L11.2 8H21M3 18H9V16H3V18Z" +); + +@include generateSvgClass( + "mdi-sort-variant-remove", + "M3 13H15V11H3M3 6V8H21V6M3 18H9V16H3V18M22.54 16.88L20.41 19L22.54 21.12L21.12 22.54L19 20.41L16.88 22.54L15.47 21.12L17.59 19L15.47 16.88L16.88 15.47L19 17.59L21.12 15.46L22.54 16.88" +); + +@include generateSvgClass( + "mdi-square-edit-outline", + "M5,3C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V12H19V19H5V5H12V3H5M17.78,4C17.61,4 17.43,4.07 17.3,4.2L16.08,5.41L18.58,7.91L19.8,6.7C20.06,6.44 20.06,6 19.8,5.75L18.25,4.2C18.12,4.07 17.95,4 17.78,4M15.37,6.12L8,13.5V16H10.5L17.87,8.62L15.37,6.12Z" +); + +@include generateSvgClass( + "mdi-star", + "M12,17.27L18.18,21L16.54,13.97L22,9.24L14.81,8.62L12,2L9.19,8.62L2,9.24L7.45,13.97L5.82,21L12,17.27Z" +); + +@include generateSvgClass( + "mdi-star-outline", + "M12,15.39L8.24,17.66L9.23,13.38L5.91,10.5L10.29,10.13L12,6.09L13.71,10.13L18.09,10.5L14.77,13.38L15.76,17.66M22,9.24L14.81,8.63L12,2L9.19,8.63L2,9.24L7.45,13.97L5.82,21L12,17.27L18.18,21L16.54,13.97L22,9.24Z" +); + +@include generateSvgClass( + "mdi-stop-circle-outline", + "M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4M9,9V15H15V9" +); + +@include generateSvgClass( + "mdi-subdirectory-arrow-right", + "M19,15L13,21L11.58,19.58L15.17,16H4V4H6V14H15.17L11.58,10.42L13,9L19,15Z" +); + +@include generateSvgClass( + "mdi-swap-horizontal", + "M21,9L17,5V8H10V10H17V13M7,11L3,15L7,19V16H14V14H7V11Z" +); + +@include generateSvgClass( + "mdi-swap-vertical", + "M9,3L5,7H8V14H10V7H13M16,17V10H14V17H11L15,21L19,17H16Z" +); + +@include generateSvgClass( + "mdi-sync", + "M12,18A6,6 0 0,1 6,12C6,11 6.25,10.03 6.7,9.2L5.24,7.74C4.46,8.97 4,10.43 4,12A8,8 0 0,0 12,20V23L16,19L12,15M12,4V1L8,5L12,9V6A6,6 0 0,1 18,12C18,13 17.75,13.97 17.3,14.8L18.76,16.26C19.54,15.03 20,13.57 20,12A8,8 0 0,0 12,4Z" +); + +@include generateSvgClass( + "mdi-sync-circle", + "M2 12A10 10 0 1 0 12 2A10 10 0 0 0 2 12M15.6 13.72A4 4 0 0 0 16 12A4 4 0 0 0 12 8V10L8.88 7L12 4V6A6 6 0 0 1 18 12A5.9 5.9 0 0 1 17.07 15.19M6 12A5.9 5.9 0 0 1 6.93 8.81L8.4 10.28A4 4 0 0 0 8 12A4 4 0 0 0 12 16V14L15 17L12 20V18A6 6 0 0 1 6 12Z" +); + +@include generateSvgClass( + "mdi-table-edit", + "M21.7,13.35L20.7,14.35L18.65,12.3L19.65,11.3C19.86,11.08 20.21,11.08 20.42,11.3L21.7,12.58C21.92,12.79 21.92,13.14 21.7,13.35M12,18.94L18.07,12.88L20.12,14.93L14.06,21H12V18.94M4,2H18A2,2 0 0,1 20,4V8.17L16.17,12H12V16.17L10.17,18H4A2,2 0 0,1 2,16V4A2,2 0 0,1 4,2M4,6V10H10V6H4M12,6V10H18V6H12M4,12V16H10V12H4Z" +); + +@include generateSvgClass( + "mdi-table-refresh", + "M18 14.5C19.11 14.5 20.11 14.95 20.83 15.67L22 14.5V18.5H18L19.77 16.73C19.32 16.28 18.69 16 18 16C16.62 16 15.5 17.12 15.5 18.5C15.5 19.88 16.62 21 18 21C18.82 21 19.55 20.61 20 20H21.71C21.12 21.47 19.68 22.5 18 22.5C15.79 22.5 14 20.71 14 18.5C14 16.29 15.79 14.5 18 14.5M4 3H18C19.11 3 20 3.9 20 5V12.17C19.5 12.06 19 12 18.5 12C17.23 12 16.04 12.37 15.04 13H12V17H12.18C12.06 17.5 12 18 12 18.5L12 19H4C2.9 19 2 18.11 2 17V5C2 3.9 2.9 3 4 3M4 7V11H10V7H4M12 7V11H18V7H12M4 13V17H10V13H4Z" +); + +@include generateSvgClass( + "mdi-text-box-remove", + "M14.46,15.88L15.88,14.46L18,16.59L20.12,14.46L21.54,15.88L19.41,18L21.54,20.12L20.12,21.54L18,19.41L15.88,21.54L14.46,20.12L16.59,18L14.46,15.88M12,17V15H7V17H12M17,11H7V13H14.69C13.07,14.07 12,15.91 12,18C12,19.09 12.29,20.12 12.8,21H5C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3H19A2,2 0 0,1 21,5V12.8C20.12,12.29 19.09,12 18,12L17,12.08V11M17,9V7H7V9H17Z" +); + +@include generateSvgClass( + "mdi-text-box-remove-outline", + "M14.46,15.88L15.88,14.46L18,16.59L20.12,14.46L21.54,15.88L19.41,18L21.54,20.12L20.12,21.54L18,19.41L15.88,21.54L14.46,20.12L16.59,18L14.46,15.88M5,3H19C20.11,3 21,3.89 21,5V12.8C20.39,12.45 19.72,12.2 19,12.08V5H5V19H12.08C12.2,19.72 12.45,20.39 12.8,21H5C3.89,21 3,20.11 3,19V5C3,3.89 3.89,3 5,3M7,7H17V9H7V7M7,11H17V12.08C16.15,12.22 15.37,12.54 14.68,13H7V11M7,15H12V17H7V15Z" +); + +@include generateSvgClass( + "mdi-text-box-search-outline", + "M15.5,12C18,12 20,14 20,16.5C20,17.38 19.75,18.21 19.31,18.9L22.39,22L21,23.39L17.88,20.32C17.19,20.75 16.37,21 15.5,21C13,21 11,19 11,16.5C11,14 13,12 15.5,12M15.5,14A2.5,2.5 0 0,0 13,16.5A2.5,2.5 0 0,0 15.5,19A2.5,2.5 0 0,0 18,16.5A2.5,2.5 0 0,0 15.5,14M5,3H19C20.11,3 21,3.89 21,5V13.03C20.5,12.23 19.81,11.54 19,11V5H5V19H9.5C9.81,19.75 10.26,20.42 10.81,21H5C3.89,21 3,20.11 3,19V5C3,3.89 3.89,3 5,3M7,7H17V9H7V7M7,11H12.03C11.23,11.5 10.54,12.19 10,13H7V11M7,15H9.17C9.06,15.5 9,16 9,16.5V17H7V15Z" +); + +@include generateSvgClass( + "mdi-theme-light-dark", + "M7.5,2C5.71,3.15 4.5,5.18 4.5,7.5C4.5,9.82 5.71,11.85 7.53,13C4.46,13 2,10.54 2,7.5A5.5,5.5 0 0,1 7.5,2M19.07,3.5L20.5,4.93L4.93,20.5L3.5,19.07L19.07,3.5M12.89,5.93L11.41,5L9.97,6L10.39,4.3L9,3.24L10.75,3.12L11.33,1.47L12,3.1L13.73,3.13L12.38,4.26L12.89,5.93M9.59,9.54L8.43,8.81L7.31,9.59L7.65,8.27L6.56,7.44L7.92,7.35L8.37,6.06L8.88,7.33L10.24,7.36L9.19,8.23L9.59,9.54M19,13.5A5.5,5.5 0 0,1 13.5,19C12.28,19 11.15,18.6 10.24,17.93L17.93,10.24C18.6,11.15 19,12.28 19,13.5M14.6,20.08L17.37,18.93L17.13,22.28L14.6,20.08M18.93,17.38L20.08,14.61L22.28,17.15L18.93,17.38M20.08,12.42L18.94,9.64L22.28,9.88L20.08,12.42M9.63,18.93L12.4,20.08L9.87,22.27L9.63,18.93Z" +); + +@include generateSvgClass( + "mdi-toggle-switch", + "M17,7H7A5,5 0 0,0 2,12A5,5 0 0,0 7,17H17A5,5 0 0,0 22,12A5,5 0 0,0 17,7M17,15A3,3 0 0,1 14,12A3,3 0 0,1 17,9A3,3 0 0,1 20,12A3,3 0 0,1 17,15Z" +); + +@include generateSvgClass( + "mdi-toggle-switch-off-outline", + "M7,10A2,2 0 0,1 9,12A2,2 0 0,1 7,14A2,2 0 0,1 5,12A2,2 0 0,1 7,10M17,7A5,5 0 0,1 22,12A5,5 0 0,1 17,17H7A5,5 0 0,1 2,12A5,5 0 0,1 7,7H17M7,9A3,3 0 0,0 4,12A3,3 0 0,0 7,15H17A3,3 0 0,0 20,12A3,3 0 0,0 17,9H7Z" +); + +@include generateSvgClass( + "mdi-translate", + "M12.87,15.07L10.33,12.56L10.36,12.53C12.1,10.59 13.34,8.36 14.07,6H17V4H10V2H8V4H1V6H12.17C11.5,7.92 10.44,9.75 9,11.35C8.07,10.32 7.3,9.19 6.69,8H4.69C5.42,9.63 6.42,11.17 7.67,12.56L2.58,17.58L4,19L9,14L12.11,17.11L12.87,15.07M18.5,10H16.5L12,22H14L15.12,19H19.87L21,22H23L18.5,10M15.88,17L17.5,12.67L19.12,17H15.88Z" +); + +@include generateSvgClass( + "mdi-trash-can", + "M9,3V4H4V6H5V19A2,2 0 0,0 7,21H17A2,2 0 0,0 19,19V6H20V4H15V3H9M9,8H11V17H9V8M13,8H15V17H13V8Z" +); + +@include generateSvgClass( + "mdi-trash-can-outline", + "M9,3V4H4V6H5V19A2,2 0 0,0 7,21H17A2,2 0 0,0 19,19V6H20V4H15V3H9M7,6H17V19H7V6M9,8V17H11V8H9M13,8V17H15V8H13Z" +); + +@include generateSvgClass( + "mdi-truck", + "M18,18.5A1.5,1.5 0 0,1 16.5,17A1.5,1.5 0 0,1 18,15.5A1.5,1.5 0 0,1 19.5,17A1.5,1.5 0 0,1 18,18.5M19.5,9.5L21.46,12H17V9.5M6,18.5A1.5,1.5 0 0,1 4.5,17A1.5,1.5 0 0,1 6,15.5A1.5,1.5 0 0,1 7.5,17A1.5,1.5 0 0,1 6,18.5M20,8H17V4H3C1.89,4 1,4.89 1,6V17H3A3,3 0 0,0 6,20A3,3 0 0,0 9,17H15A3,3 0 0,0 18,20A3,3 0 0,0 21,17H23V12L20,8Z" +); + +@include generateSvgClass( + "mdi-truck-delivery-outline", + "M18 18.5C18.83 18.5 19.5 17.83 19.5 17C19.5 16.17 18.83 15.5 18 15.5C17.17 15.5 16.5 16.17 16.5 17C16.5 17.83 17.17 18.5 18 18.5M19.5 9.5H17V12H21.46L19.5 9.5M6 18.5C6.83 18.5 7.5 17.83 7.5 17C7.5 16.17 6.83 15.5 6 15.5C5.17 15.5 4.5 16.17 4.5 17C4.5 17.83 5.17 18.5 6 18.5M20 8L23 12V17H21C21 18.66 19.66 20 18 20C16.34 20 15 18.66 15 17H9C9 18.66 7.66 20 6 20C4.34 20 3 18.66 3 17H1V6C1 4.89 1.89 4 3 4H17V8H20M3 6V15H3.76C4.31 14.39 5.11 14 6 14C6.89 14 7.69 14.39 8.24 15H15V6H3M10 7L13.5 10.5L10 14V11.5H5V9.5H10V7Z" +); + +@include generateSvgClass( + "mdi-tune", + "M3,17V19H9V17H3M3,5V7H13V5H3M13,21V19H21V17H13V15H11V21H13M7,9V11H3V13H7V15H9V9H7M21,13V11H11V13H21M15,9H17V7H21V5H17V3H15V9Z" +); + +@include generateSvgClass( + "mdi-tune-variant", + "M8 13C6.14 13 4.59 14.28 4.14 16H2V18H4.14C4.59 19.72 6.14 21 8 21S11.41 19.72 11.86 18H22V16H11.86C11.41 14.28 9.86 13 8 13M8 19C6.9 19 6 18.1 6 17C6 15.9 6.9 15 8 15S10 15.9 10 17C10 18.1 9.1 19 8 19M19.86 6C19.41 4.28 17.86 3 16 3S12.59 4.28 12.14 6H2V8H12.14C12.59 9.72 14.14 11 16 11S19.41 9.72 19.86 8H22V6H19.86M16 9C14.9 9 14 8.1 14 7C14 5.9 14.9 5 16 5S18 5.9 18 7C18 8.1 17.1 9 16 9Z" +); + +@include generateSvgClass( + "mdi-undo", + "M12.5,8C9.85,8 7.45,9 5.6,10.6L2,7V16H11L7.38,12.38C8.77,11.22 10.54,10.5 12.5,10.5C16.04,10.5 19.05,12.81 20.1,16L22.47,15.22C21.08,11.03 17.15,8 12.5,8Z" +); + +@include generateSvgClass( + "mdi-upload", + "M9,16V10H5L12,3L19,10H15V16H9M5,20V18H19V20H5Z" +); + +@include generateSvgClass( + "mdi-vanish", + "M16,13V11H21V13H16M14.83,7.76L17.66,4.93L19.07,6.34L16.24,9.17L14.83,7.76M11,16H13V21H11V16M11,3H13V8H11V3M4.93,17.66L7.76,14.83L9.17,16.24L6.34,19.07L4.93,17.66M4.93,6.34L6.34,4.93L9.17,7.76L7.76,9.17L4.93,6.34M8,13H3V11H8V13M19.07,17.66L17.66,19.07L14.83,16.24L16.24,14.83L19.07,17.66Z" +); + +@include generateSvgClass( + "mdi-wrench", + "M22.7,19L13.6,9.9C14.5,7.6 14,4.9 12.1,3C10.1,1 7.1,0.6 4.7,1.7L9,6L6,9L1.6,4.7C0.4,7.1 0.9,10.1 2.9,12.1C4.8,14 7.5,14.5 9.8,13.6L18.9,22.7C19.3,23.1 19.9,23.1 20.3,22.7L22.6,20.4C23.1,20 23.1,19.3 22.7,19Z" +); + +@include generateSvgClass( + "mdi-wrench-outline", + "M22.61,19L13.53,9.91C14.46,7.57 14,4.81 12.09,2.91C9.79,0.61 6.21,0.4 3.66,2.26L7.5,6.11L6.08,7.5L2.25,3.69C0.39,6.23 0.6,9.82 2.9,12.11C4.76,13.97 7.47,14.46 9.79,13.59L18.9,22.7C19.29,23.09 19.92,23.09 20.31,22.7L22.61,20.4C23,20 23,19.39 22.61,19M19.61,20.59L10.15,11.13C9.54,11.58 8.86,11.85 8.15,11.95C6.79,12.15 5.36,11.74 4.32,10.7C3.37,9.76 2.93,8.5 3,7.26L6.09,10.35L10.33,6.11L7.24,3C8.5,2.95 9.73,3.39 10.68,4.33C11.76,5.41 12.17,6.9 11.92,8.29C11.8,9 11.5,9.66 11.04,10.25L20.5,19.7L19.61,20.59Z" +); -@include loadsvg( - ".mdi.mdi-arrow-down-bold-outline", - "M22,11L12,21L2,11H8V3H16V11H22M12,18L17,13H14V5H10V13H7L12,18Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); -@include loadsvg( - ".mdi.mdi-arrow-expand", - "M10,21V19H6.41L10.91,14.5L9.5,13.09L5,17.59V14H3V21H10M14.5,10.91L19,6.41V10H21V3H14V5H17.59L13.09,9.5L14.5,10.91Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-arrow-expand-horizontal", - "M9,11H15V8L19,12L15,16V13H9V16L5,12L9,8V11M2,20V4H4V20H2M20,20V4H22V20H20Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-arrow-split-vertical", - "M18,16V13H15V22H13V2H15V11H18V8L22,12L18,16M2,12L6,16V13H9V22H11V2H9V11H6V8L2,12Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-arrow-up", - "M13,20H11V8L5.5,13.5L4.08,12.08L12,4.16L19.92,12.08L18.5,13.5L13,8V20Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-brightness-4", - "M12,18C11.11,18 10.26,17.8 9.5,17.45C11.56,16.5 13,14.42 13,12C13,9.58 11.56,7.5 9.5,6.55C10.26,6.2 11.11,6 12,6A6,6 0 0,1 18,12A6,6 0 0,1 12,18M20,8.69V4H15.31L12,0.69L8.69,4H4V8.69L0.69,12L4,15.31V20H8.69L12,23.31L15.31,20H20V15.31L23.31,12L20,8.69Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-calendar", - "M19,19H5V8H19M16,1V3H8V1H6V3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3H18V1M17,12H12V17H17V12Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-calendar-check", - "M19,19H5V8H19M19,3H18V1H16V3H8V1H6V3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M16.53,11.06L15.47,10L10.59,14.88L8.47,12.76L7.41,13.82L10.59,17L16.53,11.06Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-calendar-clock", - "M15,13H16.5V15.82L18.94,17.23L18.19,18.53L15,16.69V13M19,8H5V19H9.67C9.24,18.09 9,17.07 9,16A7,7 0 0,1 16,9C17.07,9 18.09,9.24 19,9.67V8M5,21C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3H6V1H8V3H16V1H18V3H19A2,2 0 0,1 21,5V11.1C22.24,12.36 23,14.09 23,16A7,7 0 0,1 16,23C14.09,23 12.36,22.24 11.1,21H5M16,11.15A4.85,4.85 0 0,0 11.15,16C11.15,18.68 13.32,20.85 16,20.85A4.85,4.85 0 0,0 20.85,16C20.85,13.32 18.68,11.15 16,11.15Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-calendar-edit", - "M19,3H18V1H16V3H8V1H6V3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H10V19H5V8H19V9H21V5A2,2 0 0,0 19,3M21.7,13.35L20.7,14.35L18.65,12.35L19.65,11.35C19.85,11.14 20.19,11.13 20.42,11.35L21.7,12.63C21.89,12.83 21.89,13.15 21.7,13.35M12,18.94L18.07,12.88L20.12,14.88L14.06,21H12V18.94Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-calendar-remove", - "M19,19H5V8H19M19,3H18V1H16V3H8V1H6V3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M9.31,17L11.75,14.56L14.19,17L15.25,15.94L12.81,13.5L15.25,11.06L14.19,10L11.75,12.44L9.31,10L8.25,11.06L10.69,13.5L8.25,15.94L9.31,17Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-calendar-search", - "M15.5,12C18,12 20,14 20,16.5C20,17.38 19.75,18.21 19.31,18.9L22.39,22L21,23.39L17.88,20.32C17.19,20.75 16.37,21 15.5,21C13,21 11,19 11,16.5C11,14 13,12 15.5,12M15.5,14A2.5,2.5 0 0,0 13,16.5A2.5,2.5 0 0,0 15.5,19A2.5,2.5 0 0,0 18,16.5A2.5,2.5 0 0,0 15.5,14M19,8H5V19H9.5C9.81,19.75 10.26,20.42 10.81,21H5C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3H6V1H8V3H16V1H18V3H19A2,2 0 0,1 21,5V13.03C20.5,12.22 19.8,11.54 19,11V8Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-call-split", - "M14,4L16.29,6.29L13.41,9.17L14.83,10.59L17.71,7.71L20,10V4M10,4H4V10L6.29,7.71L11,12.41V20H13V11.59L7.71,6.29", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-cancel", - "M12 2C17.5 2 22 6.5 22 12S17.5 22 12 22 2 17.5 2 12 6.5 2 12 2M12 4C10.1 4 8.4 4.6 7.1 5.7L18.3 16.9C19.3 15.5 20 13.8 20 12C20 7.6 16.4 4 12 4M16.9 18.3L5.7 7.1C4.6 8.4 4 10.1 4 12C4 16.4 7.6 20 12 20C13.9 20 15.6 19.4 16.9 18.3Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-cash-check", - "M3 6V18H13.32C13.1 17.33 13 16.66 13 16H7C7 14.9 6.11 14 5 14V10C6.11 10 7 9.11 7 8H17C17 9.11 17.9 10 19 10V10.06C19.67 10.06 20.34 10.18 21 10.4V6H3M12 9C10.3 9.03 9 10.3 9 12C9 13.7 10.3 14.94 12 15C12.38 15 12.77 14.92 13.14 14.77C13.41 13.67 13.86 12.63 14.97 11.61C14.85 10.28 13.59 8.97 12 9M21.63 12.27L17.76 16.17L16.41 14.8L15 16.22L17.75 19L23.03 13.68L21.63 12.27Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-cash-remove", - "M15.46 18.12L16.88 19.54L19 17.41L21.12 19.54L22.54 18.12L20.41 16L22.54 13.88L21.12 12.46L19 14.59L16.88 12.46L15.46 13.88L17.59 16M14.97 11.62C14.86 10.28 13.58 8.97 12 9C10.3 9.04 9 10.3 9 12C9 13.7 10.3 14.94 12 15C12.39 15 12.77 14.92 13.14 14.77C13.41 13.67 13.86 12.63 14.97 11.62M13 16H7C7 14.9 6.1 14 5 14V10C6.1 10 7 9.1 7 8H17C17 9.1 17.9 10 19 10V10.05C19.67 10.06 20.34 10.18 21 10.4V6H3V18H13.32C13.1 17.33 13 16.66 13 16Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-certificate", - "M4,3C2.89,3 2,3.89 2,5V15A2,2 0 0,0 4,17H12V22L15,19L18,22V17H20A2,2 0 0,0 22,15V8L22,6V5A2,2 0 0,0 20,3H16V3H4M12,5L15,7L18,5V8.5L21,10L18,11.5V15L15,13L12,15V11.5L9,10L12,8.5V5M4,5H9V7H4V5M4,9H7V11H4V9M4,13H9V15H4V13Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-certificate-outline", - "M13 21L15 20L17 21V14H13M17 9V7L15 8L13 7V9L11 10L13 11V13L15 12L17 13V11L19 10M20 3H4A2 2 0 0 0 2 5V15A2 2 0 0 0 4 17H11V15H4V5H20V15H19V17H20A2 2 0 0 0 22 15V5A2 2 0 0 0 20 3M11 8H5V6H11M9 11H5V9H9M11 14H5V12H11Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-change-record-type", - "M20 37.5c0-.8-.7-1.5-1.5-1.5h-15c-.8 0-1.5.7-1.5 1.5v11c0 .8.7 1.5 1.5 1.5h15c.8 0 1.5-.7 1.5-1.5v-11zM8.1 22H3.2c-1 0-1.5.9-.9 1.4l8 8.3c.4.3 1 .3 1.4 0l8-8.3c.6-.6.1-1.4-.9-1.4h-4.7c0-5 4.9-10 9.9-10V6C15 6 8.1 13 8.1 22zM41.8 20.3c-.4-.3-1-.3-1.4 0l-8 8.3c-.6.6-.1 1.4.9 1.4h4.8c0 6-4.1 10-10.1 10v6c9 0 16.1-7 16.1-16H49c1 0 1.5-.9.9-1.4l-8.1-8.3zM50 3.5c0-.8-.7-1.5-1.5-1.5h-15c-.8 0-1.5.7-1.5 1.5v11c0 .8.7 1.5 1.5 1.5h15c.8 0 1.5-.7 1.5-1.5v-11z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block, 52); - -@include loadsvg( - ".mdi.mdi-check", - "M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-check-all", - "M0.41,13.41L6,19L7.41,17.58L1.83,12M22.24,5.58L11.66,16.17L7.5,12L6.07,13.41L11.66,19L23.66,7M18,7L16.59,5.58L10.24,11.93L11.66,13.34L18,7Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-check-bold", - "M9,20.42L2.79,14.21L5.62,11.38L9,14.77L18.88,4.88L21.71,7.71L9,20.42Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-checkbox-blank-outline", - "M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M19,5V19H5V5H19Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-checkbox-marked-circle-outline", - "M20,12A8,8 0 0,1 12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4C12.76,4 13.5,4.11 14.2,4.31L15.77,2.74C14.61,2.26 13.34,2 12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12M7.91,10.08L6.5,11.5L11,16L21,6L19.59,4.58L11,13.17L7.91,10.08Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-check-box-outline", - "M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M19,5V19H5V5H19M10,17L6,13L7.41,11.58L10,14.17L16.59,7.58L18,9", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-checkbox-marked", - "M10,17L5,12L6.41,10.58L10,14.17L17.59,6.58L19,8M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-check-circle", - "M12 2C6.5 2 2 6.5 2 12S6.5 22 12 22 22 17.5 22 12 17.5 2 12 2M10 17L5 12L6.41 10.59L10 14.17L17.59 6.58L19 8L10 17Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-check-circle-outline", - "M12 2C6.5 2 2 6.5 2 12S6.5 22 12 22 22 17.5 22 12 17.5 2 12 2M12 20C7.59 20 4 16.41 4 12S7.59 4 12 4 20 7.59 20 12 16.41 20 12 20M16.59 7.58L10 14.17L7.41 11.59L6 13L10 17L18 9L16.59 7.58Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-check-outline", - "M19.78,2.2L24,6.42L8.44,22L0,13.55L4.22,9.33L8.44,13.55L19.78,2.2M19.78,5L8.44,16.36L4.22,12.19L2.81,13.55L8.44,19.17L21.19,6.42L19.78,5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-check-underline", - "M21,5L9,17L3.5,11.5L4.91,10.09L9,14.17L19.59,3.59L21,5M3,21V19H21V21H3Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-chevron-down", - "M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-chevron-down-box", - "M19,3H5A2,2 0 0,0 3,5V19C3,20.11 3.9,21 5,21H19C20.11,21 21,20.11 21,19V5A2,2 0 0,0 19,3M12,15.71L6,9.71L7.41,8.29L12,12.88L16.59,8.29L18,9.71L12,15.71Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-chevron-down-box-outline", - "M19,3H5A2,2 0 0,0 3,5V19C3,20.11 3.9,21 5,21H19C20.11,21 21,20.11 21,19V5A2,2 0 0,0 19,3M19,19H5V5H19V19M7.41,8.29L12,12.88L16.59,8.29L18,9.71L12,15.71L6,9.71L7.41,8.29Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-chevron-down-circle", - "M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,12M6,10L12,16L18,10L16.6,8.6L12,13.2L7.4,8.6L6,10Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-chevron-down-circle-outline", - "M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,12M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12M6,10L12,16L18,10L16.6,8.6L12,13.2L7.4,8.6L6,10Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-clipboard-check", - "M10,17L6,13L7.41,11.59L10,14.17L16.59,7.58L18,9M12,3A1,1 0 0,1 13,4A1,1 0 0,1 12,5A1,1 0 0,1 11,4A1,1 0 0,1 12,3M19,3H14.82C14.4,1.84 13.3,1 12,1C10.7,1 9.6,1.84 9.18,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-clipboard-check-outline", - "M19,3H14.82C14.4,1.84 13.3,1 12,1C10.7,1 9.6,1.84 9.18,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M12,3A1,1 0 0,1 13,4A1,1 0 0,1 12,5A1,1 0 0,1 11,4A1,1 0 0,1 12,3M7,7H17V5H19V19H5V5H7V7M7.5,13.5L9,12L11,14L15.5,9.5L17,11L11,17L7.5,13.5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-clipboard-edit", - "M21.04 12.13C21.18 12.13 21.31 12.19 21.42 12.3L22.7 13.58C22.92 13.79 22.92 14.14 22.7 14.35L21.7 15.35L19.65 13.3L20.65 12.3C20.76 12.19 20.9 12.13 21.04 12.13M19.07 13.88L21.12 15.93L15.06 22H13V19.94L19.07 13.88M19 3C20.1 3 21 3.9 21 5V9L11 19V21H5C3.9 21 3 20.1 3 19V5C3 3.9 3.9 3 5 3H9.18C9.6 1.84 10.7 1 12 1C13.3 1 14.4 1.84 14.82 3H19M12 3C11.45 3 11 3.45 11 4C11 4.55 11.45 5 12 5C12.55 5 13 4.55 13 4C13 3.45 12.55 3 12 3Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-clipboard-edit-outline", - "M21.04 12.13C21.18 12.13 21.31 12.19 21.42 12.3L22.7 13.58C22.92 13.79 22.92 14.14 22.7 14.35L21.7 15.35L19.65 13.3L20.65 12.3C20.76 12.19 20.9 12.13 21.04 12.13M19.07 13.88L21.12 15.93L15.06 22H13V19.94L19.07 13.88M11 19L9 21H5C3.9 21 3 20.1 3 19V5C3 3.9 3.9 3 5 3H9.18C9.6 1.84 10.7 1 12 1C13.3 1 14.4 1.84 14.82 3H19C20.1 3 21 3.9 21 5V9L19 11V5H17V7H7V5H5V19H11M12 3C11.45 3 11 3.45 11 4C11 4.55 11.45 5 12 5C12.55 5 13 4.55 13 4C13 3.45 12.55 3 12 3Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-clipboard-multiple", - "M4 7H2V21C2 22.1 2.9 23 4 23H18V21H4M20 3H16.8C16.4 1.8 15.3 1 14 1C12.7 1 11.6 1.8 11.2 3H8C6.9 3 6 3.9 6 5V17C6 18.1 6.9 19 8 19H20C21.1 19 22 18.1 22 17V5C22 3.9 21.1 3 20 3M14 3C14.6 3 15 3.5 15 4C15 4.5 14.5 5 14 5C13.5 5 13 4.5 13 4C13 3.5 13.4 3 14 3Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-clipboard-multiple-outline", - "M4 7V21H18V23H4C2.9 23 2 22.1 2 21V7H4M20 3C21.1 3 22 3.9 22 5V17C22 18.1 21.1 19 20 19H8C6.9 19 6 18.1 6 17V5C6 3.9 6.9 3 8 3H11.18C11.6 1.84 12.7 1 14 1C15.3 1 16.4 1.84 16.82 3H20M14 3C13.45 3 13 3.45 13 4C13 4.55 13.45 5 14 5C14.55 5 15 4.55 15 4C15 3.45 14.55 3 14 3M10 7V5H8V17H20V5H18V7H10Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-clipboard-outline", - "M19,3H14.82C14.4,1.84 13.3,1 12,1C10.7,1 9.6,1.84 9.18,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M12,3A1,1 0 0,1 13,4A1,1 0 0,1 12,5A1,1 0 0,1 11,4A1,1 0 0,1 12,3M7,7H17V5H19V19H5V5H7V7Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-close", - "M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-close-circle", - "M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-close-circle-outline", - "M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2C6.47,2 2,6.47 2,12C2,17.53 6.47,22 12,22C17.53,22 22,17.53 22,12C22,6.47 17.53,2 12,2M14.59,8L12,10.59L9.41,8L8,9.41L10.59,12L8,14.59L9.41,16L12,13.41L14.59,16L16,14.59L13.41,12L16,9.41L14.59,8Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-close-thick", - "M20 6.91L17.09 4L12 9.09L6.91 4L4 6.91L9.09 12L4 17.09L6.91 20L12 14.91L17.09 20L20 17.09L14.91 12L20 6.91Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-coffee", - "M2,21H20V19H2M20,8H18V5H20M20,3H4V13A4,4 0 0,0 8,17H14A4,4 0 0,0 18,13V10H20A2,2 0 0,0 22,8V5C22,3.89 21.1,3 20,3Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-coffee-outline", - "M2,21V19H20V21H2M20,8V5H18V8H20M20,3A2,2 0 0,1 22,5V8A2,2 0 0,1 20,10H18V13A4,4 0 0,1 14,17H8A4,4 0 0,1 4,13V3H20M16,5H6V13A2,2 0 0,0 8,15H14A2,2 0 0,0 16,13V5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-cog", - "M12,15.5A3.5,3.5 0 0,1 8.5,12A3.5,3.5 0 0,1 12,8.5A3.5,3.5 0 0,1 15.5,12A3.5,3.5 0 0,1 12,15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.5,12C4.5,12.33 4.53,12.65 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.03 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.67 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.03 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-cog-outline", - "M12,8A4,4 0 0,1 16,12A4,4 0 0,1 12,16A4,4 0 0,1 8,12A4,4 0 0,1 12,8M12,10A2,2 0 0,0 10,12A2,2 0 0,0 12,14A2,2 0 0,0 14,12A2,2 0 0,0 12,10M10,22C9.75,22 9.54,21.82 9.5,21.58L9.13,18.93C8.5,18.68 7.96,18.34 7.44,17.94L4.95,18.95C4.73,19.03 4.46,18.95 4.34,18.73L2.34,15.27C2.21,15.05 2.27,14.78 2.46,14.63L4.57,12.97L4.5,12L4.57,11L2.46,9.37C2.27,9.22 2.21,8.95 2.34,8.73L4.34,5.27C4.46,5.05 4.73,4.96 4.95,5.05L7.44,6.05C7.96,5.66 8.5,5.32 9.13,5.07L9.5,2.42C9.54,2.18 9.75,2 10,2H14C14.25,2 14.46,2.18 14.5,2.42L14.87,5.07C15.5,5.32 16.04,5.66 16.56,6.05L19.05,5.05C19.27,4.96 19.54,5.05 19.66,5.27L21.66,8.73C21.79,8.95 21.73,9.22 21.54,9.37L19.43,11L19.5,12L19.43,13L21.54,14.63C21.73,14.78 21.79,15.05 21.66,15.27L19.66,18.73C19.54,18.95 19.27,19.04 19.05,18.95L16.56,17.95C16.04,18.34 15.5,18.68 14.87,18.93L14.5,21.58C14.46,21.82 14.25,22 14,22H10M11.25,4L10.88,6.61C9.68,6.86 8.62,7.5 7.85,8.39L5.44,7.35L4.69,8.65L6.8,10.2C6.4,11.37 6.4,12.64 6.8,13.8L4.68,15.36L5.43,16.66L7.86,15.62C8.63,16.5 9.68,17.14 10.87,17.38L11.24,20H12.76L13.13,17.39C14.32,17.14 15.37,16.5 16.14,15.62L18.57,16.66L19.32,15.36L17.2,13.81C17.6,12.64 17.6,11.37 17.2,10.2L19.31,8.65L18.56,7.35L16.15,8.39C15.38,7.5 14.32,6.86 13.12,6.62L12.75,4H11.25Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-content-copy", - "M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-currency-usd", - "M7,15H9C9,16.08 10.37,17 12,17C13.63,17 15,16.08 15,15C15,13.9 13.96,13.5 11.76,12.97C9.64,12.44 7,11.78 7,9C7,7.21 8.47,5.69 10.5,5.18V3H13.5V5.18C15.53,5.69 17,7.21 17,9H15C15,7.92 13.63,7 12,7C10.37,7 9,7.92 9,9C9,10.1 10.04,10.5 12.24,11.03C14.36,11.56 17,12.22 17,15C17,16.79 15.53,18.31 13.5,18.82V21H10.5V18.82C8.47,18.31 7,16.79 7,15Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-currency-usd-off", - "M3,4.27L4.28,3L21,19.72L19.73,21L16.06,17.33C15.44,18 14.54,18.55 13.5,18.82V21H10.5V18.82C8.47,18.31 7,16.79 7,15H9C9,16.08 10.37,17 12,17C13.13,17 14.14,16.56 14.65,15.92L11.68,12.95C9.58,12.42 7,11.75 7,9C7,8.77 7,8.55 7.07,8.34L3,4.27M10.5,5.18V3H13.5V5.18C15.53,5.69 17,7.21 17,9H15C15,7.92 13.63,7 12,7C11.63,7 11.28,7.05 10.95,7.13L9.4,5.58L10.5,5.18Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-database-refresh", - "M12 3C16.42 3 20 4.79 20 7C20 9.21 16.42 11 12 11C7.58 11 4 9.21 4 7C4 4.79 7.58 3 12 3M4 9C4 11.21 7.58 13 12 13C13.11 13 14.18 12.89 15.14 12.68C14.19 13.54 13.5 14.67 13.18 15.96L12 16C7.58 16 4 14.21 4 12V9M20 9V11L19.5 11L18.9 11.03C19.6 10.43 20 9.74 20 9M4 14C4 16.21 7.58 18 12 18L13 17.97C13.09 19.03 13.42 20 13.95 20.88L12 21C7.58 21 4 19.21 4 17V14M19 13.5C20.11 13.5 21.11 13.95 21.83 14.67L23 13.5V17.5H19L20.77 15.73C20.32 15.28 19.69 15 19 15C17.62 15 16.5 16.12 16.5 17.5C16.5 18.88 17.62 20 19 20C19.82 20 20.54 19.61 21 19H22.71C22.12 20.47 20.68 21.5 19 21.5C16.79 21.5 15 19.71 15 17.5C15 15.29 16.79 13.5 19 13.5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-delete", - "M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-delete-outline", - "M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19M8,9H16V19H8V9M15.5,4L14.5,3H9.5L8.5,4H5V6H19V4H15.5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-dots-grid", - "M12 16C13.1 16 14 16.9 14 18S13.1 20 12 20 10 19.1 10 18 10.9 16 12 16M12 10C13.1 10 14 10.9 14 12S13.1 14 12 14 10 13.1 10 12 10.9 10 12 10M12 4C13.1 4 14 4.9 14 6S13.1 8 12 8 10 7.1 10 6 10.9 4 12 4M6 16C7.1 16 8 16.9 8 18S7.1 20 6 20 4 19.1 4 18 4.9 16 6 16M6 10C7.1 10 8 10.9 8 12S7.1 14 6 14 4 13.1 4 12 4.9 10 6 10M6 4C7.1 4 8 4.9 8 6S7.1 8 6 8 4 7.1 4 6 4.9 4 6 4M18 16C19.1 16 20 16.9 20 18S19.1 20 18 20 16 19.1 16 18 16.9 16 18 16M18 10C19.1 10 20 10.9 20 12S19.1 14 18 14 16 13.1 16 12 16.9 10 18 10M18 4C19.1 4 20 4.9 20 6S19.1 8 18 8 16 7.1 16 6 16.9 4 18 4Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-dots-vertical", - "M12,16A2,2 0 0,1 14,18A2,2 0 0,1 12,20A2,2 0 0,1 10,18A2,2 0 0,1 12,16M12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12A2,2 0 0,1 12,10M12,4A2,2 0 0,1 14,6A2,2 0 0,1 12,8A2,2 0 0,1 10,6A2,2 0 0,1 12,4Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-download", - "M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - - @include loadsvg( - ".mdi.mdi-drag", - "M7,19V17H9V19H7M11,19V17H13V19H11M15,19V17H17V19H15M7,15V13H9V15H7M11,15V13H13V15H11M15,15V13H17V15H15M7,11V9H9V11H7M11,11V9H13V11H11M15,11V9H17V11H15M7,7V5H9V7H7M11,7V5H13V7H11M15,7V5H17V7H15Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - - @include loadsvg( - ".mdi.mdi-drag-vertical", - "M9,3H11V5H9V3M13,3H15V5H13V3M9,7H11V9H9V7M13,7H15V9H13V7M9,11H11V13H9V11M13,11H15V13H13V11M9,15H11V17H9V15M13,15H15V17H13V15M9,19H11V21H9V19M13,19H15V21H13V19Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - - @include loadsvg( - ".mdi.mdi-eye-off-outline", - "M2,5.27L3.28,4L20,20.72L18.73,22L15.65,18.92C14.5,19.3 13.28,19.5 12,19.5C7,19.5 2.73,16.39 1,12C1.69,10.24 2.79,8.69 4.19,7.46L2,5.27M12,9A3,3 0 0,1 15,12C15,12.35 14.94,12.69 14.83,13L11,9.17C11.31,9.06 11.65,9 12,9M12,4.5C17,4.5 21.27,7.61 23,12C22.18,14.08 20.79,15.88 19,17.19L17.58,15.76C18.94,14.82 20.06,13.54 20.82,12C19.17,8.64 15.76,6.5 12,6.5C10.91,6.5 9.84,6.68 8.84,7L7.3,5.47C8.74,4.85 10.33,4.5 12,4.5M3.18,12C4.83,15.36 8.24,17.5 12,17.5C12.69,17.5 13.37,17.43 14,17.29L11.72,15C10.29,14.85 9.15,13.71 9,12.28L5.6,8.87C4.61,9.72 3.78,10.78 3.18,12Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - - @include loadsvg( - ".mdi.mdi-eye-outline", - "M12,9A3,3 0 0,1 15,12A3,3 0 0,1 12,15A3,3 0 0,1 9,12A3,3 0 0,1 12,9M12,4.5C17,4.5 21.27,7.61 23,12C21.27,16.39 17,19.5 12,19.5C7,19.5 2.73,16.39 1,12C2.73,7.61 7,4.5 12,4.5M3.18,12C4.83,15.36 8.24,17.5 12,17.5C15.76,17.5 19.17,15.36 20.82,12C19.17,8.64 15.76,6.5 12,6.5C8.24,6.5 4.83,8.64 3.18,12Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file", - "M13,9V3.5L18.5,9M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-alert", - "M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2M9 19H7V17H9M9 15H7V9H9M13 9V3.5L18.5 9H13Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-alert-outline", - "M10 18H8V16H10V18M10 14H8V8H10V14M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2M18 20H6V4H13V9H18V20Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-cad", - "M6 2C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2M13 3.5L18.5 9H13M9.88 9.25H11.12V10.19C11.81 10.18 12.38 10.75 12.38 11.44V13.5L12.26 13.63L13.15 15.17C13.47 14.67 13.63 14.09 13.62 13.5H14.88C14.88 14.54 14.5 15.55 13.83 16.35L15.5 19.25V20.5L14.42 19.88L12.87 17.19C12.17 17.65 11.34 17.89 10.5 17.89C9.66 17.89 8.84 17.65 8.13 17.19L6.58 19.88L5.5 20.5V19.25L8.74 13.63L8.62 13.5V11.44C8.62 10.75 9.19 10.18 9.88 10.19M10.5 11.44C9.81 11.44 9.46 12.28 9.95 12.77C10.44 13.26 11.28 12.92 11.28 12.22C11.28 11.79 10.93 11.44 10.5 11.44M9.66 14.54L8.76 16.11C9.81 16.82 11.19 16.82 12.24 16.11L11.34 14.54C10.87 15 10.13 15 9.66 14.54Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-check", - "M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M11.2,18.46L15.95,13.71L14.78,12.3L11.2,15.88L9.61,14.3L8.45,15.46L11.2,18.46Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-check-outline", - "M14,2L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2H14M18,20V9H13V4H6V20H18M11.2,18.46L8.45,15.46L9.61,14.3L11.2,15.88L14.78,12.3L15.95,13.71L11.2,18.46Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-document-outline", - "M6,2A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6M6,4H13V9H18V20H6V4M8,12V14H16V12H8M8,16V18H13V16H8Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-excel-outline", - "M14 2H6C4.89 2 4 2.9 4 4V20C4 21.11 4.89 22 6 22H18C19.11 22 20 21.11 20 20V8L14 2M18 20H6V4H13V9H18V20M12.9 14.5L15.8 19H14L12 15.6L10 19H8.2L11.1 14.5L8.2 10H10L12 13.4L14 10H15.8L12.9 14.5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-move", - "M14,17H18V14L23,18.5L18,23V20H14V17M13,9H18.5L13,3.5V9M6,2H14L20,8V12.34C19.37,12.12 18.7,12 18,12A6,6 0 0,0 12,18C12,19.54 12.58,20.94 13.53,22H6C4.89,22 4,21.1 4,20V4A2,2 0 0,1 6,2Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-move-outline", - "M14 2H6C4.9 2 4 2.9 4 4V20C4 20.41 4.12 20.8 4.34 21.12C4.41 21.23 4.5 21.33 4.59 21.41C4.95 21.78 5.45 22 6 22H13.53C13 21.42 12.61 20.75 12.35 20H6V4H13V9H18V12C18.7 12 19.37 12.12 20 12.34V8L14 2M18 23L23 18.5L20 15.8L18 14V17H14V20H18V23Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-multiple", - "M15,7H20.5L15,1.5V7M8,0H16L22,6V18A2,2 0 0,1 20,20H8C6.89,20 6,19.1 6,18V2A2,2 0 0,1 8,0M4,4V22H20V24H4A2,2 0 0,1 2,22V4H4Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-multiple-outline", - "M16 0H8C6.9 0 6 .9 6 2V18C6 19.1 6.9 20 8 20H20C21.1 20 22 19.1 22 18V6L16 0M20 18H8V2H15V7H20V18M4 4V22H20V24H4C2.9 24 2 23.1 2 22V4H4Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-music-outline", - "M14,2L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2H14M18,20V9H13V4H6V20H18M13,10V12H11V17A2,2 0 0,1 9,19A2,2 0 0,1 7,17A2,2 0 0,1 9,15C9.4,15 9.7,15.1 10,15.3V10H13Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-outline", - "M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-pdf-outline", - "M14,2L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2H14M18,20V9H13V4H6V20H18M10.92,12.31C10.68,11.54 10.15,9.08 11.55,9.04C12.95,9 12.03,12.16 12.03,12.16C12.42,13.65 14.05,14.72 14.05,14.72C14.55,14.57 17.4,14.24 17,15.72C16.57,17.2 13.5,15.81 13.5,15.81C11.55,15.95 10.09,16.47 10.09,16.47C8.96,18.58 7.64,19.5 7.1,18.61C6.43,17.5 9.23,16.07 9.23,16.07C10.68,13.72 10.9,12.35 10.92,12.31M11.57,13.15C11.17,14.45 10.37,15.84 10.37,15.84C11.22,15.5 13.08,15.11 13.08,15.11C11.94,14.11 11.59,13.16 11.57,13.15M14.71,15.32C14.71,15.32 16.46,15.97 16.5,15.71C16.57,15.44 15.17,15.2 14.71,15.32M9.05,16.81C8.28,17.11 7.54,18.39 7.72,18.39C7.9,18.4 8.63,17.79 9.05,16.81M11.57,11.26C11.57,11.21 12,9.58 11.57,9.53C11.27,9.5 11.56,11.22 11.57,11.26Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-question", - "M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6M13,3.5L18.5,9H13V3.5M12,11A3,3 0 0,1 15,14C15,15.88 12.75,16.06 12.75,17.75H11.25C11.25,15.31 13.5,15.5 13.5,14A1.5,1.5 0 0,0 12,12.5A1.5,1.5 0 0,0 10.5,14H9A3,3 0 0,1 12,11M11.25,18.5H12.75V20H11.25V18.5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-question-outline", - "M14 2H6C4.89 2 4 2.9 4 4V20C4 21.11 4.89 22 6 22H18C19.11 22 20 21.11 20 20V8L14 2M18 20H6V4H13V9H18V20M15 13C15 14.89 12.75 15.07 12.75 16.76H11.25C11.25 14.32 13.5 14.5 13.5 13C13.5 12.18 12.83 11.5 12 11.5S10.5 12.18 10.5 13H9C9 11.35 10.34 10 12 10S15 11.35 15 13M12.75 17.5V19H11.25V17.5H12.75Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-search-outline", - "M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H13C12.59,21.75 12.2,21.44 11.86,21.1C11.53,20.77 11.25,20.4 11,20H6V4H13V9H18V10.18C18.71,10.34 19.39,10.61 20,11V8L14,2M20.31,18.9C21.64,16.79 21,14 18.91,12.68C16.8,11.35 14,12 12.69,14.08C11.35,16.19 12,18.97 14.09,20.3C15.55,21.23 17.41,21.23 18.88,20.32L22,23.39L23.39,22L20.31,18.9M16.5,19A2.5,2.5 0 0,1 14,16.5A2.5,2.5 0 0,1 16.5,14A2.5,2.5 0 0,1 19,16.5A2.5,2.5 0 0,1 16.5,19Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-send", - "M14,2H6C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M12.54,19.37V17.37H8.54V15.38H12.54V13.38L15.54,16.38L12.54,19.37M13,9V3.5L18.5,9H13Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-send-outline", - "M14 2H6C4.89 2 4 2.9 4 4V20C4 21.11 4.89 22 6 22H18C19.11 22 20 21.11 20 20V8L14 2M18 20H6V4H13V9H18V20M12.54 18.5V16.5H8.54V14.5H12.54V12.5L15.54 15.5L12.54 18.5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-tree", - "M3,3H9V7H3V3M15,10H21V14H15V10M15,17H21V21H15V17M13,13H7V18H13V20H7L5,20V9H7V11H13V13Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-tree-outline", - "M12 13H7V18H12V20H5V10H7V11H12V13M8 4V6H4V4H8M10 2H2V8H10V2M20 11V13H16V11H20M22 9H14V15H22V9M20 18V20H16V18H20M22 16H14V22H22V16Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-upload", - "M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M13.5,16V19H10.5V16H8L12,12L16,16H13.5M13,9V3.5L18.5,9H13Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-file-upload-outline", - "M14,2L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2H14M18,20V9H13V4H6V20H18M12,12L16,16H13.5V19H10.5V16H8L12,12Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-filter", - "M14,12V19.88C14.04,20.18 13.94,20.5 13.71,20.71C13.32,21.1 12.69,21.1 12.3,20.71L10.29,18.7C10.06,18.47 9.96,18.16 10,17.87V12H9.97L4.21,4.62C3.87,4.19 3.95,3.56 4.38,3.22C4.57,3.08 4.78,3 5,3V3H19V3C19.22,3 19.43,3.08 19.62,3.22C20.05,3.56 20.13,4.19 19.79,4.62L14.03,12H14Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-filter-minus-outline", - "M15 17H23V19H15V17M13 19.88C13.04 20.18 12.94 20.5 12.72 20.71C12.32 21.1 11.69 21.1 11.3 20.71L7.29 16.7C7.06 16.47 6.96 16.16 7 15.87V10.75L2.21 4.62C1.87 4.19 1.95 3.56 2.38 3.22C2.57 3.08 2.78 3 3 3V3H17V3C17.22 3 17.43 3.08 17.62 3.22C18.05 3.56 18.13 4.19 17.79 4.62L13 10.75V19.88M5.04 5L9 10.07V15.58L11 17.58V10.05L14.96 5H5.04Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-filter-off-outline", - "M2.39 1.73L1.11 3L9 10.89V15.87C8.96 16.16 9.06 16.47 9.29 16.7L13.3 20.71C13.69 21.1 14.32 21.1 14.71 20.71C14.94 20.5 15.04 20.18 15 19.88V16.89L20.84 22.73L22.11 21.46L15 14.35V14.34L13 12.35L11 10.34L4.15 3.5L2.39 1.73M6.21 3L8.2 5H16.96L13.11 9.91L15 11.8V10.75L19.79 4.62C20.13 4.19 20.05 3.56 19.62 3.22C19.43 3.08 19.22 3 19 3H6.21M11 12.89L13 14.89V17.58L11 15.58V12.89Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-filter-outline", - "M15,19.88C15.04,20.18 14.94,20.5 14.71,20.71C14.32,21.1 13.69,21.1 13.3,20.71L9.29,16.7C9.06,16.47 8.96,16.16 9,15.87V10.75L4.21,4.62C3.87,4.19 3.95,3.56 4.38,3.22C4.57,3.08 4.78,3 5,3V3H19V3C19.22,3 19.43,3.08 19.62,3.22C20.05,3.56 20.13,4.19 19.79,4.62L15,10.75V19.88M7.04,5L11,10.06V15.58L13,17.58V10.05L16.96,5H7.04Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-filter-plus-outline", - "M15 17H18V14H20V17H23V19H20V22H18V19H15V17M13 19.88C13.04 20.18 12.94 20.5 12.72 20.71C12.32 21.1 11.69 21.1 11.3 20.71L7.29 16.7C7.06 16.47 6.96 16.16 7 15.87V10.75L2.21 4.62C1.87 4.19 1.95 3.56 2.38 3.22C2.57 3.08 2.78 3 3 3V3H17V3C17.22 3 17.43 3.08 17.62 3.22C18.05 3.56 18.13 4.19 17.79 4.62L13 10.75V19.88M5.04 5L9 10.07V15.58L11 17.58V10.05L14.96 5H5.04Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-filter-remove-outline", - "M14.73,20.83L17.58,18L14.73,15.17L16.15,13.76L19,16.57L21.8,13.76L23.22,15.17L20.41,18L23.22,20.83L21.8,22.24L19,19.4L16.15,22.24L14.73,20.83M13,19.88C13.04,20.18 12.94,20.5 12.71,20.71C12.32,21.1 11.69,21.1 11.3,20.71L7.29,16.7C7.06,16.47 6.96,16.16 7,15.87V10.75L2.21,4.62C1.87,4.19 1.95,3.56 2.38,3.22C2.57,3.08 2.78,3 3,3V3H17V3C17.22,3 17.43,3.08 17.62,3.22C18.05,3.56 18.13,4.19 17.79,4.62L13,10.75V19.88M5.04,5L9,10.06V15.58L11,17.58V10.05L14.96,5H5.04Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-fire", - "M17.66 11.2C17.43 10.9 17.15 10.64 16.89 10.38C16.22 9.78 15.46 9.35 14.82 8.72C13.33 7.26 13 4.85 13.95 3C13 3.23 12.17 3.75 11.46 4.32C8.87 6.4 7.85 10.07 9.07 13.22C9.11 13.32 9.15 13.42 9.15 13.55C9.15 13.77 9 13.97 8.8 14.05C8.57 14.15 8.33 14.09 8.14 13.93C8.08 13.88 8.04 13.83 8 13.76C6.87 12.33 6.69 10.28 7.45 8.64C5.78 10 4.87 12.3 5 14.47C5.06 14.97 5.12 15.47 5.29 15.97C5.43 16.57 5.7 17.17 6 17.7C7.08 19.43 8.95 20.67 10.96 20.92C13.1 21.19 15.39 20.8 17.03 19.32C18.86 17.66 19.5 15 18.56 12.72L18.43 12.46C18.22 12 17.66 11.2 17.66 11.2M14.5 17.5C14.22 17.74 13.76 18 13.4 18.1C12.28 18.5 11.16 17.94 10.5 17.28C11.69 17 12.4 16.12 12.61 15.23C12.78 14.43 12.46 13.77 12.33 13C12.21 12.26 12.23 11.63 12.5 10.94C12.69 11.32 12.89 11.7 13.13 12C13.9 13 15.11 13.44 15.37 14.8C15.41 14.94 15.43 15.08 15.43 15.23C15.46 16.05 15.1 16.95 14.5 17.5H14.5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-flip-vertical", - "M3 15V17H5V15M15 19V21H17V19M19 3H5C3.9 3 3 3.9 3 5V9H5V5H19V9H21V5C21 3.9 20.1 3 19 3M21 19H19V21C20.1 21 21 20.1 21 19M1 11V13H23V11M7 19V21H9V19M19 15V17H21V15M11 19V21H13V19M3 19C3 20.1 3.9 21 5 21V19Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-folder", - "M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-folder-open", - "M19,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10L12,6H19A2,2 0 0,1 21,8H21L4,8V18L6.14,10H23.21L20.93,18.5C20.7,19.37 19.92,20 19,20Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-forum", - "M17,12V3A1,1 0 0,0 16,2H3A1,1 0 0,0 2,3V17L6,13H16A1,1 0 0,0 17,12M21,6H19V15H6V17A1,1 0 0,0 7,18H18L22,22V7A1,1 0 0,0 21,6Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-forum-outline", - "M15,4V11H5.17L4,12.17V4H15M16,2H3A1,1 0 0,0 2,3V17L6,13H16A1,1 0 0,0 17,12V3A1,1 0 0,0 16,2M21,6H19V15H6V17A1,1 0 0,0 7,18H18L22,22V7A1,1 0 0,0 21,6Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-github", - "M12,2A10,10 0 0,0 2,12C2,16.42 4.87,20.17 8.84,21.5C9.34,21.58 9.5,21.27 9.5,21C9.5,20.77 9.5,20.14 9.5,19.31C6.73,19.91 6.14,17.97 6.14,17.97C5.68,16.81 5.03,16.5 5.03,16.5C4.12,15.88 5.1,15.9 5.1,15.9C6.1,15.97 6.63,16.93 6.63,16.93C7.5,18.45 8.97,18 9.54,17.76C9.63,17.11 9.89,16.67 10.17,16.42C7.95,16.17 5.62,15.31 5.62,11.5C5.62,10.39 6,9.5 6.65,8.79C6.55,8.54 6.2,7.5 6.75,6.15C6.75,6.15 7.59,5.88 9.5,7.17C10.29,6.95 11.15,6.84 12,6.84C12.85,6.84 13.71,6.95 14.5,7.17C16.41,5.88 17.25,6.15 17.25,6.15C17.8,7.5 17.45,8.54 17.35,8.79C18,9.5 18.38,10.39 18.38,11.5C18.38,15.32 16.04,16.16 13.81,16.41C14.17,16.72 14.5,17.33 14.5,18.26C14.5,19.6 14.5,20.68 14.5,21C14.5,21.27 14.66,21.59 15.17,21.5C19.14,20.16 22,16.42 22,12A10,10 0 0,0 12,2Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-help", - "M10,19H13V22H10V19M12,2C17.35,2.22 19.68,7.62 16.5,11.67C15.67,12.67 14.33,13.33 13.67,14.17C13,15 13,16 13,17H10C10,15.33 10,13.92 10.67,12.92C11.33,11.92 12.67,11.33 13.5,10.67C15.92,8.43 15.32,5.26 12,5A3,3 0 0,0 9,8H6A6,6 0 0,1 12,2Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-help-circle", - "M15.07,11.25L14.17,12.17C13.45,12.89 13,13.5 13,15H11V14.5C11,13.39 11.45,12.39 12.17,11.67L13.41,10.41C13.78,10.05 14,9.55 14,9C14,7.89 13.1,7 12,7A2,2 0 0,0 10,9H8A4,4 0 0,1 12,5A4,4 0 0,1 16,9C16,9.88 15.64,10.67 15.07,11.25M13,19H11V17H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-help-circle-outline", - "M11,18H13V16H11V18M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,6A4,4 0 0,0 8,10H10A2,2 0 0,1 12,8A2,2 0 0,1 14,10C14,12 11,11.75 11,15H13C13,12.75 16,12.5 16,10A4,4 0 0,0 12,6Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-history", - "M13.5,8H12V13L16.28,15.54L17,14.33L13.5,12.25V8M13,3A9,9 0 0,0 4,12H1L4.96,16.03L9,12H6A7,7 0 0,1 13,5A7,7 0 0,1 20,12A7,7 0 0,1 13,19C11.07,19 9.32,18.21 8.06,16.94L6.64,18.36C8.27,20 10.5,21 13,21A9,9 0 0,0 22,12A9,9 0 0,0 13,3", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-information", - "M13,9H11V7H13M13,17H11V11H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-information-outline", - "M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,17H13V11H11V17Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-lightbulb", - "M12,2A7,7 0 0,0 5,9C5,11.38 6.19,13.47 8,14.74V17A1,1 0 0,0 9,18H15A1,1 0 0,0 16,17V14.74C17.81,13.47 19,11.38 19,9A7,7 0 0,0 12,2M9,21A1,1 0 0,0 10,22H14A1,1 0 0,0 15,21V20H9V21Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-lightbulb-off", - "M12,2C9.76,2 7.78,3.05 6.5,4.68L16.31,14.5C17.94,13.21 19,11.24 19,9A7,7 0 0,0 12,2M3.28,4L2,5.27L5.04,8.3C5,8.53 5,8.76 5,9C5,11.38 6.19,13.47 8,14.74V17A1,1 0 0,0 9,18H14.73L18.73,22L20,20.72L3.28,4M9,20V21A1,1 0 0,0 10,22H14A1,1 0 0,0 15,21V20H9Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-lightbulb-off-outline", - "M12,2C9.76,2 7.78,3.05 6.5,4.68L7.93,6.11C8.84,4.84 10.32,4 12,4A5,5 0 0,1 17,9C17,10.68 16.16,12.16 14.89,13.06L16.31,14.5C17.94,13.21 19,11.24 19,9A7,7 0 0,0 12,2M3.28,4L2,5.27L5.04,8.3C5,8.53 5,8.76 5,9C5,11.38 6.19,13.47 8,14.74V17A1,1 0 0,0 9,18H14.73L18.73,22L20,20.72L3.28,4M7.23,10.5L12.73,16H10V13.58C8.68,13 7.66,11.88 7.23,10.5M9,20V21A1,1 0 0,0 10,22H14A1,1 0 0,0 15,21V20H9Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-lightbulb-on", - "M12,6A6,6 0 0,1 18,12C18,14.22 16.79,16.16 15,17.2V19A1,1 0 0,1 14,20H10A1,1 0 0,1 9,19V17.2C7.21,16.16 6,14.22 6,12A6,6 0 0,1 12,6M14,21V22A1,1 0 0,1 13,23H11A1,1 0 0,1 10,22V21H14M20,11H23V13H20V11M1,11H4V13H1V11M13,1V4H11V1H13M4.92,3.5L7.05,5.64L5.63,7.05L3.5,4.93L4.92,3.5M16.95,5.63L19.07,3.5L20.5,4.93L18.37,7.05L16.95,5.63Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-lightbulb-on-outline", - "M20,11H23V13H20V11M1,11H4V13H1V11M13,1V4H11V1H13M4.92,3.5L7.05,5.64L5.63,7.05L3.5,4.93L4.92,3.5M16.95,5.63L19.07,3.5L20.5,4.93L18.37,7.05L16.95,5.63M12,6A6,6 0 0,1 18,12C18,14.22 16.79,16.16 15,17.2V19A1,1 0 0,1 14,20H10A1,1 0 0,1 9,19V17.2C7.21,16.16 6,14.22 6,12A6,6 0 0,1 12,6M14,21V22A1,1 0 0,1 13,23H11A1,1 0 0,1 10,22V21H14M11,18H13V15.87C14.73,15.43 16,13.86 16,12A4,4 0 0,0 12,8A4,4 0 0,0 8,12C8,13.86 9.27,15.43 11,15.87V18Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-lightbulb-outline", - "M12,2A7,7 0 0,1 19,9C19,11.38 17.81,13.47 16,14.74V17A1,1 0 0,1 15,18H9A1,1 0 0,1 8,17V14.74C6.19,13.47 5,11.38 5,9A7,7 0 0,1 12,2M9,21V20H15V21A1,1 0 0,1 14,22H10A1,1 0 0,1 9,21M12,4A5,5 0 0,0 7,9C7,11.05 8.23,12.81 10,13.58V16H14V13.58C15.77,12.81 17,11.05 17,9A5,5 0 0,0 12,4Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-link", - "M3.9,12C3.9,10.29 5.29,8.9 7,8.9H11V7H7A5,5 0 0,0 2,12A5,5 0 0,0 7,17H11V15.1H7C5.29,15.1 3.9,13.71 3.9,12M8,13H16V11H8V13M17,7H13V8.9H17C18.71,8.9 20.1,10.29 20.1,12C20.1,13.71 18.71,15.1 17,15.1H13V17H17A5,5 0 0,0 22,12A5,5 0 0,0 17,7Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-link-variant", - "M10.59,13.41C11,13.8 11,14.44 10.59,14.83C10.2,15.22 9.56,15.22 9.17,14.83C7.22,12.88 7.22,9.71 9.17,7.76V7.76L12.71,4.22C14.66,2.27 17.83,2.27 19.78,4.22C21.73,6.17 21.73,9.34 19.78,11.29L18.29,12.78C18.3,11.96 18.17,11.14 17.89,10.36L18.36,9.88C19.54,8.71 19.54,6.81 18.36,5.64C17.19,4.46 15.29,4.46 14.12,5.64L10.59,9.17C9.41,10.34 9.41,12.24 10.59,13.41M13.41,9.17C13.8,8.78 14.44,8.78 14.83,9.17C16.78,11.12 16.78,14.29 14.83,16.24V16.24L11.29,19.78C9.34,21.73 6.17,21.73 4.22,19.78C2.27,17.83 2.27,14.66 4.22,12.71L5.71,11.22C5.7,12.04 5.83,12.86 6.11,13.65L5.64,14.12C4.46,15.29 4.46,17.19 5.64,18.36C6.81,19.54 8.71,19.54 9.88,18.36L13.41,14.83C14.59,13.66 14.59,11.76 13.41,10.59C13,10.2 13,9.56 13.41,9.17Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-load", - "M12,4V2A10,10 0 0,0 2,12H4A8,8 0 0,1 12,4Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-magnify", - "M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-map-marker-radius", - "M12,2C15.31,2 18,4.66 18,7.95C18,12.41 12,19 12,19C12,19 6,12.41 6,7.95C6,4.66 8.69,2 12,2M12,6A2,2 0 0,0 10,8A2,2 0 0,0 12,10A2,2 0 0,0 14,8A2,2 0 0,0 12,6M20,19C20,21.21 16.42,23 12,23C7.58,23 4,21.21 4,19C4,17.71 5.22,16.56 7.11,15.83L7.75,16.74C6.67,17.19 6,17.81 6,18.5C6,19.88 8.69,21 12,21C15.31,21 18,19.88 18,18.5C18,17.81 17.33,17.19 16.25,16.74L16.89,15.83C18.78,16.56 20,17.71 20,19Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-map-marker-radius-outline", - "M12 4C14.2 4 16 5.8 16 8C16 10.1 13.9 13.5 12 15.9C10.1 13.4 8 10.1 8 8C8 5.8 9.8 4 12 4M12 2C8.7 2 6 4.7 6 8C6 12.5 12 19 12 19S18 12.4 18 8C18 4.7 15.3 2 12 2M12 6C10.9 6 10 6.9 10 8S10.9 10 12 10 14 9.1 14 8 13.1 6 12 6M20 19C20 21.2 16.4 23 12 23S4 21.2 4 19C4 17.7 5.2 16.6 7.1 15.8L7.7 16.7C6.7 17.2 6 17.8 6 18.5C6 19.9 8.7 21 12 21S18 19.9 18 18.5C18 17.8 17.3 17.2 16.2 16.7L16.8 15.8C18.8 16.6 20 17.7 20 19Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-menu", - "M3,6H21V8H3V6M3,11H21V13H3V11M3,16H21V18H3V16Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-message-text", - "M20,2H4A2,2 0 0,0 2,4V22L6,18H20A2,2 0 0,0 22,16V4A2,2 0 0,0 20,2M6,9H18V11H6M14,14H6V12H14M18,8H6V6H18", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-message-text-outline", - "M20,2A2,2 0 0,1 22,4V16A2,2 0 0,1 20,18H6L2,22V4C2,2.89 2.9,2 4,2H20M4,4V17.17L5.17,16H20V4H4M6,7H18V9H6V7M6,11H15V13H6V11Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-microsoft-excel", - "M21.17 3.25Q21.5 3.25 21.76 3.5 22 3.74 22 4.08V19.92Q22 20.26 21.76 20.5 21.5 20.75 21.17 20.75H7.83Q7.5 20.75 7.24 20.5 7 20.26 7 19.92V17H2.83Q2.5 17 2.24 16.76 2 16.5 2 16.17V7.83Q2 7.5 2.24 7.24 2.5 7 2.83 7H7V4.08Q7 3.74 7.24 3.5 7.5 3.25 7.83 3.25M7 13.06L8.18 15.28H9.97L8 12.06L9.93 8.89H8.22L7.13 10.9L7.09 10.96L7.06 11.03Q6.8 10.5 6.5 9.96 6.25 9.43 5.97 8.89H4.16L6.05 12.08L4 15.28H5.78M13.88 19.5V17H8.25V19.5M13.88 15.75V12.63H12V15.75M13.88 11.38V8.25H12V11.38M13.88 7V4.5H8.25V7M20.75 19.5V17H15.13V19.5M20.75 15.75V12.63H15.13V15.75M20.75 11.38V8.25H15.13V11.38M20.75 7V4.5H15.13V7Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-minus", - "M19,13H5V11H19V13Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-minus-circle", - "M17,13H7V11H17M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-minus-circle-outline", - "M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M7,13H17V11H7", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-order-bool-ascending-variant", - "M4 13C2.89 13 2 13.89 2 15V19C2 20.11 2.89 21 4 21H8C9.11 21 10 20.11 10 19V15C10 13.89 9.11 13 8 13M8.2 14.5L9.26 15.55L5.27 19.5L2.74 16.95L3.81 15.9L5.28 17.39M4 3C2.89 3 2 3.89 2 5V9C2 10.11 2.89 11 4 11H8C9.11 11 10 10.11 10 9V5C10 3.89 9.11 3 8 3M4 5H8V9H4M12 5H22V7H12M12 19V17H22V19M12 11H22V13H12Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-page-first", - "M18.41,16.59L13.82,12L18.41,7.41L17,6L11,12L17,18L18.41,16.59M6,6H8V18H6V6Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-page-last", - "M5.59,7.41L10.18,12L5.59,16.59L7,18L13,12L7,6L5.59,7.41M16,6H18V18H16V6Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-paperclip", - "M16.5,6V17.5A4,4 0 0,1 12.5,21.5A4,4 0 0,1 8.5,17.5V5A2.5,2.5 0 0,1 11,2.5A2.5,2.5 0 0,1 13.5,5V15.5A1,1 0 0,1 12.5,16.5A1,1 0 0,1 11.5,15.5V6H10V15.5A2.5,2.5 0 0,0 12.5,18A2.5,2.5 0 0,0 15,15.5V5A4,4 0 0,0 11,1A4,4 0 0,0 7,5V17.5A5.5,5.5 0 0,0 12.5,23A5.5,5.5 0 0,0 18,17.5V6H16.5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-pencil", - "M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-pencil-outline", - "M14.06,9L15,9.94L5.92,19H5V18.08L14.06,9M17.66,3C17.41,3 17.15,3.1 16.96,3.29L15.13,5.12L18.88,8.87L20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18.17,3.09 17.92,3 17.66,3M14.06,6.19L3,17.25V21H6.75L17.81,9.94L14.06,6.19Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-pencil-box-multiple", - "M20.22 2H7.78C6.8 2 6 2.8 6 3.78V16.22C6 17.2 6.8 18 7.78 18H20.22C21.2 18 22 17.21 22 16.22V3.78C22 2.8 21.2 2 20.22 2M11.06 15H9V12.94L15.06 6.88L17.12 8.94L11.06 15M18.7 7.35L17.7 8.35L15.65 6.3L16.65 5.3C16.86 5.08 17.21 5.08 17.42 5.3L18.7 6.58C18.92 6.79 18.92 7.14 18.7 7.35M4 6H2V20C2 21.11 2.9 22 4 22H18V20H4V6Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-pencil-box-multiple-outline", - "M4 6H2V20C2 21.11 2.9 22 4 22H18V20H4V6M18.7 7.35L17.7 8.35L15.65 6.3L16.65 5.3C16.86 5.08 17.21 5.08 17.42 5.3L18.7 6.58C18.92 6.79 18.92 7.14 18.7 7.35M9 12.94L15.06 6.88L17.12 8.94L11.06 15H9V12.94M20 4L20 4L20 16L8 16L8 4H20M20 2H8C6.9 2 6 2.9 6 4V16C6 17.1 6.9 18 8 18H20C21.1 18 22 17.1 22 16V4C22 2.9 21.1 2 20 2Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-percent", - "M18.5,3.5L3.5,18.5L5.5,20.5L20.5,5.5M7,4A3,3 0 0,0 4,7A3,3 0 0,0 7,10A3,3 0 0,0 10,7A3,3 0 0,0 7,4M17,14A3,3 0 0,0 14,17A3,3 0 0,0 17,20A3,3 0 0,0 20,17A3,3 0 0,0 17,14Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-percent-outline", - "M18.5 3.5L20.5 5.5L5.5 20.5L3.5 18.5L18.5 3.5M7 4C8.66 4 10 5.34 10 7C10 8.66 8.66 10 7 10C5.34 10 4 8.66 4 7C4 5.34 5.34 4 7 4M17 14C18.66 14 20 15.34 20 17C20 18.66 18.66 20 17 20C15.34 20 14 18.66 14 17C14 15.34 15.34 14 17 14M7 6C6.45 6 6 6.45 6 7C6 7.55 6.45 8 7 8C7.55 8 8 7.55 8 7C8 6.45 7.55 6 7 6M17 16C16.45 16 16 16.45 16 17C16 17.55 16.45 18 17 18C17.55 18 18 17.55 18 17C18 16.45 17.55 16 17 16Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-pin-off-outline", - "M8,6.2V4H7V2H17V4H16V12L18,14V16H17.8L14,12.2V4H10V8.2L8,6.2M20,20.7L18.7,22L12.8,16.1V22H11.2V16H6V14L8,12V11.3L2,5.3L3.3,4L20,20.7M8.8,14H10.6L9.7,13.1L8.8,14Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-pin-outline", - "M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12M8.8,14L10,12.8V4H14V12.8L15.2,14H8.8Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-playlist-plus", - "M2,16H10V14H2M18,14V10H16V14H12V16H16V20H18V16H22V14M14,6H2V8H14M14,10H2V12H14V10Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-play-circle-outline", - "M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M10,16.5L16,12L10,7.5V16.5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-playlist-remove", - "M2,6V8H14V6H2M2,10V12H11V10H2M14.17,10.76L12.76,12.17L15.59,15L12.76,17.83L14.17,19.24L17,16.41L19.83,19.24L21.24,17.83L18.41,15L21.24,12.17L19.83,10.76L17,13.59L14.17,10.76M2,14V16H11V14H2Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-plus-circle", - "M17,13H13V17H11V13H7V11H11V7H13V11H17M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-plus-circle-outline", - "M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M13,7H11V11H7V13H11V17H13V13H17V11H13V7Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-plus", - "M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-progress-download", - "M13,2.03C17.73,2.5 21.5,6.25 21.95,11C22.5,16.5 18.5,21.38 13,21.93V19.93C16.64,19.5 19.5,16.61 19.96,12.97C20.5,8.58 17.39,4.59 13,4.05V2.05L13,2.03M11,2.06V4.06C9.57,4.26 8.22,4.84 7.1,5.74L5.67,4.26C7.19,3 9.05,2.25 11,2.06M4.26,5.67L5.69,7.1C4.8,8.23 4.24,9.58 4.05,11H2.05C2.25,9.04 3,7.19 4.26,5.67M2.06,13H4.06C4.24,14.42 4.81,15.77 5.69,16.9L4.27,18.33C3.03,16.81 2.26,14.96 2.06,13M7.1,18.37C8.23,19.25 9.58,19.82 11,20V22C9.04,21.79 7.18,21 5.67,19.74L7.1,18.37M12,16.5L7.5,12H11V8H13V12H16.5L12,16.5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-redo", - "M18.4,10.6C16.55,9 14.15,8 11.5,8C6.85,8 2.92,11.03 1.54,15.22L3.9,16C4.95,12.81 7.95,10.5 11.5,10.5C13.45,10.5 15.23,11.22 16.62,12.38L13,16H22V7L18.4,10.6Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-refresh", - "M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-shape-square-plus", - "M19,5H22V7H19V10H17V7H14V5H17V2H19V5M17,19V13H19V21H3V5H11V7H5V19H17Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-snowflake", - "M20.79,13.95L18.46,14.57L16.46,13.44V10.56L18.46,9.43L20.79,10.05L21.31,8.12L19.54,7.65L20,5.88L18.07,5.36L17.45,7.69L15.45,8.82L13,7.38V5.12L14.71,3.41L13.29,2L12,3.29L10.71,2L9.29,3.41L11,5.12V7.38L8.5,8.82L6.5,7.69L5.92,5.36L4,5.88L4.47,7.65L2.7,8.12L3.22,10.05L5.55,9.43L7.55,10.56V13.45L5.55,14.58L3.22,13.96L2.7,15.89L4.47,16.36L4,18.12L5.93,18.64L6.55,16.31L8.55,15.18L11,16.62V18.88L9.29,20.59L10.71,22L12,20.71L13.29,22L14.7,20.59L13,18.88V16.62L15.5,15.17L17.5,16.3L18.12,18.63L20,18.12L19.53,16.35L21.3,15.88L20.79,13.95M9.5,10.56L12,9.11L14.5,10.56V13.44L12,14.89L9.5,13.44V10.56Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-sort-ascending", - "M19 17H22L18 21L14 17H17V3H19M2 17H12V19H2M6 5V7H2V5M2 11H9V13H2V11Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-sort-descending", - "M19 7H22L18 3L14 7H17V21H19M2 17H12V19H2M6 5V7H2V5M2 11H9V13H2V11Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-sort-variant-remove", - "M3 13H15V11H3M3 6V8H21V6M3 18H9V16H3V18M22.54 16.88L20.41 19L22.54 21.12L21.12 22.54L19 20.41L16.88 22.54L15.47 21.12L17.59 19L15.47 16.88L16.88 15.47L19 17.59L21.12 15.46L22.54 16.88", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-square-edit-outline", - "M5,3C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V12H19V19H5V5H12V3H5M17.78,4C17.61,4 17.43,4.07 17.3,4.2L16.08,5.41L18.58,7.91L19.8,6.7C20.06,6.44 20.06,6 19.8,5.75L18.25,4.2C18.12,4.07 17.95,4 17.78,4M15.37,6.12L8,13.5V16H10.5L17.87,8.62L15.37,6.12Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-star", - "M12,17.27L18.18,21L16.54,13.97L22,9.24L14.81,8.62L12,2L9.19,8.62L2,9.24L7.45,13.97L5.82,21L12,17.27Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-star-outline", - "M12,15.39L8.24,17.66L9.23,13.38L5.91,10.5L10.29,10.13L12,6.09L13.71,10.13L18.09,10.5L14.77,13.38L15.76,17.66M22,9.24L14.81,8.63L12,2L9.19,8.63L2,9.24L7.45,13.97L5.82,21L12,17.27L18.18,21L16.54,13.97L22,9.24Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-stop-circle-outline", - "M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4M9,9V15H15V9", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-subdirectory-arrow-right", - "M19,15L13,21L11.58,19.58L15.17,16H4V4H6V14H15.17L11.58,10.42L13,9L19,15Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-swap-horizontal", - "M21,9L17,5V8H10V10H17V13M7,11L3,15L7,19V16H14V14H7V11Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-swap-vertical", - "M9,3L5,7H8V14H10V7H13M16,17V10H14V17H11L15,21L19,17H16Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-sync", - "M12,18A6,6 0 0,1 6,12C6,11 6.25,10.03 6.7,9.2L5.24,7.74C4.46,8.97 4,10.43 4,12A8,8 0 0,0 12,20V23L16,19L12,15M12,4V1L8,5L12,9V6A6,6 0 0,1 18,12C18,13 17.75,13.97 17.3,14.8L18.76,16.26C19.54,15.03 20,13.57 20,12A8,8 0 0,0 12,4Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-sync-circle", - "M2 12A10 10 0 1 0 12 2A10 10 0 0 0 2 12M15.6 13.72A4 4 0 0 0 16 12A4 4 0 0 0 12 8V10L8.88 7L12 4V6A6 6 0 0 1 18 12A5.9 5.9 0 0 1 17.07 15.19M6 12A5.9 5.9 0 0 1 6.93 8.81L8.4 10.28A4 4 0 0 0 8 12A4 4 0 0 0 12 16V14L15 17L12 20V18A6 6 0 0 1 6 12Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-table-edit", - "M21.7,13.35L20.7,14.35L18.65,12.3L19.65,11.3C19.86,11.08 20.21,11.08 20.42,11.3L21.7,12.58C21.92,12.79 21.92,13.14 21.7,13.35M12,18.94L18.07,12.88L20.12,14.93L14.06,21H12V18.94M4,2H18A2,2 0 0,1 20,4V8.17L16.17,12H12V16.17L10.17,18H4A2,2 0 0,1 2,16V4A2,2 0 0,1 4,2M4,6V10H10V6H4M12,6V10H18V6H12M4,12V16H10V12H4Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-table-refresh", - "M18 14.5C19.11 14.5 20.11 14.95 20.83 15.67L22 14.5V18.5H18L19.77 16.73C19.32 16.28 18.69 16 18 16C16.62 16 15.5 17.12 15.5 18.5C15.5 19.88 16.62 21 18 21C18.82 21 19.55 20.61 20 20H21.71C21.12 21.47 19.68 22.5 18 22.5C15.79 22.5 14 20.71 14 18.5C14 16.29 15.79 14.5 18 14.5M4 3H18C19.11 3 20 3.9 20 5V12.17C19.5 12.06 19 12 18.5 12C17.23 12 16.04 12.37 15.04 13H12V17H12.18C12.06 17.5 12 18 12 18.5L12 19H4C2.9 19 2 18.11 2 17V5C2 3.9 2.9 3 4 3M4 7V11H10V7H4M12 7V11H18V7H12M4 13V17H10V13H4Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-text-box-remove", - "M14.46,15.88L15.88,14.46L18,16.59L20.12,14.46L21.54,15.88L19.41,18L21.54,20.12L20.12,21.54L18,19.41L15.88,21.54L14.46,20.12L16.59,18L14.46,15.88M12,17V15H7V17H12M17,11H7V13H14.69C13.07,14.07 12,15.91 12,18C12,19.09 12.29,20.12 12.8,21H5C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3H19A2,2 0 0,1 21,5V12.8C20.12,12.29 19.09,12 18,12L17,12.08V11M17,9V7H7V9H17Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-text-box-remove-outline", - "M14.46,15.88L15.88,14.46L18,16.59L20.12,14.46L21.54,15.88L19.41,18L21.54,20.12L20.12,21.54L18,19.41L15.88,21.54L14.46,20.12L16.59,18L14.46,15.88M5,3H19C20.11,3 21,3.89 21,5V12.8C20.39,12.45 19.72,12.2 19,12.08V5H5V19H12.08C12.2,19.72 12.45,20.39 12.8,21H5C3.89,21 3,20.11 3,19V5C3,3.89 3.89,3 5,3M7,7H17V9H7V7M7,11H17V12.08C16.15,12.22 15.37,12.54 14.68,13H7V11M7,15H12V17H7V15Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-text-box-search-outline", - "M15.5,12C18,12 20,14 20,16.5C20,17.38 19.75,18.21 19.31,18.9L22.39,22L21,23.39L17.88,20.32C17.19,20.75 16.37,21 15.5,21C13,21 11,19 11,16.5C11,14 13,12 15.5,12M15.5,14A2.5,2.5 0 0,0 13,16.5A2.5,2.5 0 0,0 15.5,19A2.5,2.5 0 0,0 18,16.5A2.5,2.5 0 0,0 15.5,14M5,3H19C20.11,3 21,3.89 21,5V13.03C20.5,12.23 19.81,11.54 19,11V5H5V19H9.5C9.81,19.75 10.26,20.42 10.81,21H5C3.89,21 3,20.11 3,19V5C3,3.89 3.89,3 5,3M7,7H17V9H7V7M7,11H12.03C11.23,11.5 10.54,12.19 10,13H7V11M7,15H9.17C9.06,15.5 9,16 9,16.5V17H7V15Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-theme-light-dark", - "M7.5,2C5.71,3.15 4.5,5.18 4.5,7.5C4.5,9.82 5.71,11.85 7.53,13C4.46,13 2,10.54 2,7.5A5.5,5.5 0 0,1 7.5,2M19.07,3.5L20.5,4.93L4.93,20.5L3.5,19.07L19.07,3.5M12.89,5.93L11.41,5L9.97,6L10.39,4.3L9,3.24L10.75,3.12L11.33,1.47L12,3.1L13.73,3.13L12.38,4.26L12.89,5.93M9.59,9.54L8.43,8.81L7.31,9.59L7.65,8.27L6.56,7.44L7.92,7.35L8.37,6.06L8.88,7.33L10.24,7.36L9.19,8.23L9.59,9.54M19,13.5A5.5,5.5 0 0,1 13.5,19C12.28,19 11.15,18.6 10.24,17.93L17.93,10.24C18.6,11.15 19,12.28 19,13.5M14.6,20.08L17.37,18.93L17.13,22.28L14.6,20.08M18.93,17.38L20.08,14.61L22.28,17.15L18.93,17.38M20.08,12.42L18.94,9.64L22.28,9.88L20.08,12.42M9.63,18.93L12.4,20.08L9.87,22.27L9.63,18.93Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-toggle-switch", - "M17,7H7A5,5 0 0,0 2,12A5,5 0 0,0 7,17H17A5,5 0 0,0 22,12A5,5 0 0,0 17,7M17,15A3,3 0 0,1 14,12A3,3 0 0,1 17,9A3,3 0 0,1 20,12A3,3 0 0,1 17,15Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-toggle-switch-off-outline", - "M7,10A2,2 0 0,1 9,12A2,2 0 0,1 7,14A2,2 0 0,1 5,12A2,2 0 0,1 7,10M17,7A5,5 0 0,1 22,12A5,5 0 0,1 17,17H7A5,5 0 0,1 2,12A5,5 0 0,1 7,7H17M7,9A3,3 0 0,0 4,12A3,3 0 0,0 7,15H17A3,3 0 0,0 20,12A3,3 0 0,0 17,9H7Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-trash-can", - "M9,3V4H4V6H5V19A2,2 0 0,0 7,21H17A2,2 0 0,0 19,19V6H20V4H15V3H9M9,8H11V17H9V8M13,8H15V17H13V8Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-trash-can-outline", - "M9,3V4H4V6H5V19A2,2 0 0,0 7,21H17A2,2 0 0,0 19,19V6H20V4H15V3H9M7,6H17V19H7V6M9,8V17H11V8H9M13,8V17H15V8H13Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-truck", - "M18,18.5A1.5,1.5 0 0,1 16.5,17A1.5,1.5 0 0,1 18,15.5A1.5,1.5 0 0,1 19.5,17A1.5,1.5 0 0,1 18,18.5M19.5,9.5L21.46,12H17V9.5M6,18.5A1.5,1.5 0 0,1 4.5,17A1.5,1.5 0 0,1 6,15.5A1.5,1.5 0 0,1 7.5,17A1.5,1.5 0 0,1 6,18.5M20,8H17V4H3C1.89,4 1,4.89 1,6V17H3A3,3 0 0,0 6,20A3,3 0 0,0 9,17H15A3,3 0 0,0 18,20A3,3 0 0,0 21,17H23V12L20,8Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-truck-delivery-outline", - "M18 18.5C18.83 18.5 19.5 17.83 19.5 17C19.5 16.17 18.83 15.5 18 15.5C17.17 15.5 16.5 16.17 16.5 17C16.5 17.83 17.17 18.5 18 18.5M19.5 9.5H17V12H21.46L19.5 9.5M6 18.5C6.83 18.5 7.5 17.83 7.5 17C7.5 16.17 6.83 15.5 6 15.5C5.17 15.5 4.5 16.17 4.5 17C4.5 17.83 5.17 18.5 6 18.5M20 8L23 12V17H21C21 18.66 19.66 20 18 20C16.34 20 15 18.66 15 17H9C9 18.66 7.66 20 6 20C4.34 20 3 18.66 3 17H1V6C1 4.89 1.89 4 3 4H17V8H20M3 6V15H3.76C4.31 14.39 5.11 14 6 14C6.89 14 7.69 14.39 8.24 15H15V6H3M10 7L13.5 10.5L10 14V11.5H5V9.5H10V7Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-tune", - "M3,17V19H9V17H3M3,5V7H13V5H3M13,21V19H21V17H13V15H11V21H13M7,9V11H3V13H7V15H9V9H7M21,13V11H11V13H21M15,9H17V7H21V5H17V3H15V9Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-tune-variant", - "M8 13C6.14 13 4.59 14.28 4.14 16H2V18H4.14C4.59 19.72 6.14 21 8 21S11.41 19.72 11.86 18H22V16H11.86C11.41 14.28 9.86 13 8 13M8 19C6.9 19 6 18.1 6 17C6 15.9 6.9 15 8 15S10 15.9 10 17C10 18.1 9.1 19 8 19M19.86 6C19.41 4.28 17.86 3 16 3S12.59 4.28 12.14 6H2V8H12.14C12.59 9.72 14.14 11 16 11S19.41 9.72 19.86 8H22V6H19.86M16 9C14.9 9 14 8.1 14 7C14 5.9 14.9 5 16 5S18 5.9 18 7C18 8.1 17.1 9 16 9Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-undo", - "M12.5,8C9.85,8 7.45,9 5.6,10.6L2,7V16H11L7.38,12.38C8.77,11.22 10.54,10.5 12.5,10.5C16.04,10.5 19.05,12.81 20.1,16L22.47,15.22C21.08,11.03 17.15,8 12.5,8Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-upload", - "M9,16V10H5L12,3L19,10H15V16H9M5,20V18H19V20H5Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-vanish", - "M16,13V11H21V13H16M14.83,7.76L17.66,4.93L19.07,6.34L16.24,9.17L14.83,7.76M11,16H13V21H11V16M11,3H13V8H11V3M4.93,17.66L7.76,14.83L9.17,16.24L6.34,19.07L4.93,17.66M4.93,6.34L6.34,4.93L9.17,7.76L7.76,9.17L4.93,6.34M8,13H3V11H8V13M19.07,17.66L17.66,19.07L14.83,16.24L16.24,14.83L19.07,17.66Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-wrench", - "M22.7,19L13.6,9.9C14.5,7.6 14,4.9 12.1,3C10.1,1 7.1,0.6 4.7,1.7L9,6L6,9L1.6,4.7C0.4,7.1 0.9,10.1 2.9,12.1C4.8,14 7.5,14.5 9.8,13.6L18.9,22.7C19.3,23.1 19.9,23.1 20.3,22.7L22.6,20.4C23.1,20 23.1,19.3 22.7,19Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); - -@include loadsvg( - ".mdi.mdi-wrench-outline", - "M22.61,19L13.53,9.91C14.46,7.57 14,4.81 12.09,2.91C9.79,0.61 6.21,0.4 3.66,2.26L7.5,6.11L6.08,7.5L2.25,3.69C0.39,6.23 0.6,9.82 2.9,12.11C4.76,13.97 7.47,14.46 9.79,13.59L18.9,22.7C19.29,23.09 19.92,23.09 20.31,22.7L22.61,20.4C23,20 23,19.39 22.61,19M19.61,20.59L10.15,11.13C9.54,11.58 8.86,11.85 8.15,11.95C6.79,12.15 5.36,11.74 4.32,10.7C3.37,9.76 2.93,8.5 3,7.26L6.09,10.35L10.33,6.11L7.24,3C8.5,2.95 9.73,3.39 10.68,4.33C11.76,5.41 12.17,6.9 11.92,8.29C11.8,9 11.5,9.66 11.04,10.25L20.5,19.7L19.61,20.59Z", - encodecolor($slick-icon-color), $slick-icon-height, $slick-icon-width, inline-block); +.mdi { + display: inline-block; + align-items: center; + background-color: currentColor; + font-size: $slick-icon-font-size; + width: 1em; + height: 1em; + &.mdi-state-disabled { + opacity: 0.35; + } +} \ No newline at end of file diff --git a/packages/common/src/styles/slickgrid-theme-bootstrap.lite.scss b/packages/common/src/styles/slickgrid-theme-bootstrap.lite.scss new file mode 100644 index 000000000..286ffc0ee --- /dev/null +++ b/packages/common/src/styles/slickgrid-theme-bootstrap.lite.scss @@ -0,0 +1,18 @@ +/*! + * SlickGrid custom styling for Bootstrap (https://github.com/ghiscoding/slickgrid-universal) + * Licensed under MIT (https://github.com/ghiscoding/slickgrid-universal/blob/master/LICENSE) + * @author: Ghislain B. (ghiscoding) + */ + +/** + * SlickGrid Bootstrap Theme (lite) + * sames as `slickgrid-theme-bootstrap.scss` but without: + * colors, extra-styling, slickgrid-icons and slickgrid-icons-svg-utils + */ + +@import './slick-grid'; +@import './slick-editors'; +@import './slick-plugins'; +@import './slick-component'; +@import './slickgrid-examples'; +@import './slick-autocomplete'; \ No newline at end of file diff --git a/packages/common/src/styles/slickgrid-theme-bootstrap.scss b/packages/common/src/styles/slickgrid-theme-bootstrap.scss index 06d137a59..a2afd89e6 100644 --- a/packages/common/src/styles/slickgrid-theme-bootstrap.scss +++ b/packages/common/src/styles/slickgrid-theme-bootstrap.scss @@ -4,12 +4,12 @@ * @author: Ghislain B. (ghiscoding) */ - /** SlickGrid Bootstrap Theme */ -@import './flatpickr-dark'; +/** SlickGrid Bootstrap Theme */ @import './slick-grid'; @import './slick-editors'; @import './slick-plugins'; @import './slick-component'; @import './slickgrid-examples'; -@import './slick-bootstrap'; @import './slick-autocomplete'; +@import './slickgrid-icons-svg-utils'; +@import './slickgrid-icons'; \ No newline at end of file diff --git a/packages/common/src/styles/slickgrid-theme-material.bare.scss b/packages/common/src/styles/slickgrid-theme-material.bare.scss deleted file mode 100644 index dd5aec365..000000000 --- a/packages/common/src/styles/slickgrid-theme-material.bare.scss +++ /dev/null @@ -1,21 +0,0 @@ -/*! - * SlickGrid custom styling for Material (https://github.com/ghiscoding/slickgrid-universal) - * Licensed under MIT (https://github.com/ghiscoding/slickgrid-universal/blob/master/LICENSE) - * @author: Ghislain B. (ghiscoding) - */ - -// This is a bare version of "slickgrid-theme-material.scss", -// Few files were removed and aren't included in this styling theme (while they are in original theme) -// - (colors, extra-styling, material-svg-icons, material-svg-utilities, slick-without-bootstrap-min-styling) - -/** SlickGrid Material Theme */ -@import './flatpickr-dark'; -@import './sass-utilities'; -@import './variables-theme-material'; -@import './slick-grid'; -@import './slick-editors'; -@import './slick-plugins'; -@import './slick-component'; -@import './slickgrid-examples'; -@import './slick-bootstrap'; -@import './slick-autocomplete'; diff --git a/packages/common/src/styles/slickgrid-theme-material.lite.scss b/packages/common/src/styles/slickgrid-theme-material.lite.scss index 478353695..5efe950c5 100644 --- a/packages/common/src/styles/slickgrid-theme-material.lite.scss +++ b/packages/common/src/styles/slickgrid-theme-material.lite.scss @@ -4,14 +4,13 @@ * @author: Ghislain B. (ghiscoding) */ - /** - * SlickGrid Material Theme - * (sames as `slickgrid-theme-material.scss` but without Flatpickr & Multiple-Select styling) - * We also removed `slick-without-bootstrap-min-styling.scss` since that is causing issues with Bootstrap 4 +/** + * SlickGrid Material Theme (lite) + * sames as `slickgrid-theme-material.scss` but without: + * `slick-without-bootstrap-min-styling.scss`, colors, extra-styling, slickgrid-icons and slickgrid-icons-svg-utils */ /** SlickGrid Material Theme */ -@import './flatpickr-dark'; @import './variables-theme-material'; @import './roboto-font'; @import './slick-grid'; @@ -19,11 +18,4 @@ @import './slick-plugins'; @import './slick-component'; @import './slickgrid-examples'; -@import './slick-bootstrap'; -@import './slick-autocomplete'; -@import './material-svg-icons'; -@import './material-svg-utilities'; - -$link-color: var(--slick-primary-color, $slick-primary-color) !default; -@import './colors.scss'; -@import './extra-styling.scss'; +@import './slick-autocomplete'; \ No newline at end of file diff --git a/packages/common/src/styles/slickgrid-theme-material.scss b/packages/common/src/styles/slickgrid-theme-material.scss index 8163f06b7..e6356cfed 100644 --- a/packages/common/src/styles/slickgrid-theme-material.scss +++ b/packages/common/src/styles/slickgrid-theme-material.scss @@ -6,25 +6,21 @@ /** * SlickGrid Material Theme - * (sames as `slickgrid-theme-material.lite.scss` but includes all external 3rd party lib styling that is Flatpickr & Multiple-Select) + * sames as `slickgrid-theme-material.lite.scss` but includes all external 3rd party lib styling */ - @import './roboto-font'; - @import './flatpickr.min'; - @import './flatpickr-dark'; +@import './roboto-font'; +@import './variables-theme-material'; +@import './slick-without-bootstrap-min-styling'; +@import './slick-grid'; +@import './slick-editors'; +@import './slick-plugins'; +@import './slick-component'; +@import './slickgrid-examples'; +@import './slick-autocomplete'; +@import './slickgrid-icons-svg-utils'; +@import './slickgrid-icons'; - @import './variables-theme-material'; - @import './slick-without-bootstrap-min-styling'; - @import './slick-grid'; - @import './slick-editors'; - @import './slick-plugins'; - @import './slick-component'; - @import './slickgrid-examples'; - @import './slick-bootstrap'; - @import './slick-autocomplete'; - @import './material-svg-icons'; - @import './material-svg-utilities'; - - $link-color: var(--slick-primary-color, $slick-primary-color) !default; - @import './colors.scss'; - @import './extra-styling.scss'; +$link-color: var(--slick-primary-color, $slick-primary-color) !default; +@import './colors.scss'; +@import './extra-styling.scss'; diff --git a/packages/common/src/styles/slickgrid-theme-salesforce.bare.scss b/packages/common/src/styles/slickgrid-theme-salesforce.bare.scss deleted file mode 100644 index e8b25f9b0..000000000 --- a/packages/common/src/styles/slickgrid-theme-salesforce.bare.scss +++ /dev/null @@ -1,21 +0,0 @@ -/*! - * SlickGrid custom styling for Salesforce (https://github.com/ghiscoding/slickgrid-universal) - * Licensed under MIT (https://github.com/ghiscoding/slickgrid-universal/blob/master/LICENSE) - * @author: Ghislain B. (ghiscoding) - */ - -// This is a bare version of "slickgrid-theme-salesforce.scss", -// Few files were removed and aren't included in this styling theme (while they are in original theme) -// - (colors, extra-styling, material-svg-icons, material-svg-utilities, slick-without-bootstrap-min-styling) - -/** SlickGrid Salesforce Theme */ -@import './flatpickr-dark'; -@import './sass-utilities'; -@import './variables-theme-salesforce'; -@import './slick-grid'; -@import './slick-editors'; -@import './slick-plugins'; -@import './slick-component'; -@import './slickgrid-examples'; -@import './slick-bootstrap'; -@import './slick-autocomplete'; diff --git a/packages/common/src/styles/slickgrid-theme-salesforce.lite.scss b/packages/common/src/styles/slickgrid-theme-salesforce.lite.scss index f16efecb2..6a2849620 100644 --- a/packages/common/src/styles/slickgrid-theme-salesforce.lite.scss +++ b/packages/common/src/styles/slickgrid-theme-salesforce.lite.scss @@ -5,24 +5,15 @@ */ /** - * SlickGrid Salesforce Theme - * (sames as `slickgrid-theme-salesforce.scss` but without Flatpickr & Multiple-Select styling) - * We also removed `slick-without-bootstrap-min-styling.scss` since that is causing issues with Bootstrap 4 + * SlickGrid Salesforce Theme (lite) + * sames as `slickgrid-theme-salesforce.scss` but without: + * `slick-without-bootstrap-min-styling.scss`, colors, extra-styling, slick-filters, slickgrid-icons and slickgrid-icons-svg-utils */ -@import './flatpickr-dark'; -@import './sass-utilities'; @import './variables-theme-salesforce'; @import './slick-grid'; @import './slick-editors'; @import './slick-plugins'; @import './slick-component'; @import './slickgrid-examples'; -@import './slick-bootstrap'; -@import './slick-autocomplete'; -@import './material-svg-icons'; -@import './material-svg-utilities'; - -$link-color: var(--slick-primary-color, $slick-primary-color) !default; -@import './colors.scss'; -@import './extra-styling'; +@import './slick-autocomplete'; \ No newline at end of file diff --git a/packages/common/src/styles/slickgrid-theme-salesforce.scss b/packages/common/src/styles/slickgrid-theme-salesforce.scss index f65afd265..b474c9783 100644 --- a/packages/common/src/styles/slickgrid-theme-salesforce.scss +++ b/packages/common/src/styles/slickgrid-theme-salesforce.scss @@ -6,13 +6,9 @@ /** * SlickGrid Salesforce Theme - * (sames as `slickgrid-theme-salesforce.lite.scss` but includes all external 3rd party lib styling that is Flatpickr & Multiple-Select) + * (sames as `slickgrid-theme-salesforce.lite.scss` but includes all external 3rd party lib styling) */ -@import './flatpickr.min'; -@import './flatpickr-dark'; -@import './sass-utilities'; - @import './variables-theme-salesforce'; @import './slick-without-bootstrap-min-styling'; @import './slick-grid'; @@ -20,17 +16,16 @@ @import './slick-plugins'; @import './slick-component'; @import './slickgrid-examples'; -@import './slick-bootstrap'; @import './slick-filters'; @import './slick-autocomplete'; -@import './material-svg-icons'; -@import './material-svg-utilities'; +@import './slickgrid-icons-svg-utils'; +@import './slickgrid-icons'; $slick-editing-field-bg-color: #fff !default; $slick-editing-field-border: 1px solid #dddbda !default; $slick-editable-field-bg-color: rgba(227, 240, 251, 0.569) !default; $slick-editable-field-hover-icon-color: #b0adab !default; -$slick-editable-field-hover-icon: url('data:image/svg+xml,') !default; +$slick-editable-field-hover-icon: url('data:image/svg+xml,') !default; $slick-editable-field-hover-icon-margin-right: 8px !default; $slick-editable-field-hover-icon-margin-top: 8px !default; $slick-editable-field-hover-icon-width: 14px !default; @@ -94,5 +89,4 @@ $slick-editor-grid-cell-border-width-modified: 1px 6px 1px 1px !default; $link-color: var(--slick-primary-color, $slick-primary-color) !default; @import './colors'; -@import './colors-from-filters'; @import './extra-styling'; diff --git a/packages/common/src/styles/svg-utilities.scss b/packages/common/src/styles/svg-utilities.scss new file mode 100644 index 000000000..fdd75d194 --- /dev/null +++ b/packages/common/src/styles/svg-utilities.scss @@ -0,0 +1,19 @@ +$svg-icon-vertical-align: bottom !default; + +// credit goes to UnoCSS https://antfu.me/posts/icons-in-pure-css +@mixin generateSvgClass($cssVarName, $svgPath) { + .#{$cssVarName} { + @include generateSvgStyle(#{$cssVarName + '-icon-svg'}, $svgPath); // all icon will create css variable named "[icon name]-icon-svg" + } +} + +// create SVG as a url() and the url string must be html escaped, +// we will also use the name to create a CSS variable so that user could override any of the icon +// by providing the full url string without needing else since it was already created +@mixin generateSvgStyle($cssVarName, $svgPath) { + --#{$cssVarName}: url('data:image/svg+xml;utf8,%3Csvg viewBox="0 0 24 24" display="inline-block" height="1em" width="1em" vertical-align="text-bottom" xmlns="http://www.w3.org/2000/svg" %3E%3Cpath fill="currentColor" d="#{$svgPath}"/%3E%3C/svg%3E'); + -webkit-mask: var(--#{$cssVarName}) no-repeat; + mask: var(--#{$cssVarName}) no-repeat; + mask-size: 100% 100%; + -webkit-mask-size: 100% 100%; +} \ No newline at end of file diff --git a/packages/composite-editor-component/CHANGELOG.md b/packages/composite-editor-component/CHANGELOG.md index 6748b5973..59c23262d 100644 --- a/packages/composite-editor-component/CHANGELOG.md +++ b/packages/composite-editor-component/CHANGELOG.md @@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.0-beta.3](https://github.com/ghiscoding/slickgrid-universal/compare/v5.0.0-beta.2...v5.0.0-beta.3) (2024-05-09) + +**Note:** Version bump only for package @slickgrid-universal/composite-editor-component + +## [5.0.0-beta.2](https://github.com/ghiscoding/slickgrid-universal/compare/v4.7.0...v5.0.0-beta.2) (2024-05-07) + +### ⚠ BREAKING CHANGES + +* **common:** migrate from Flatpickr to Vanilla-Calendar (#1466) + +### Features + +* **common:** migrate from Flatpickr to Vanilla-Calendar ([#1466](https://github.com/ghiscoding/slickgrid-universal/issues/1466)) ([fb6e950](https://github.com/ghiscoding/slickgrid-universal/commit/fb6e950f429b4abd868fca86d9c304580a745b1c)) - by @ghiscoding + # [4.7.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.6.3...v4.7.0) (2024-04-20) **Note:** Version bump only for package @slickgrid-universal/composite-editor-component @@ -29,7 +43,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **deps:** simplify package TS Types exports ([#1402](https://github.com/ghiscoding/slickgrid-universal/issues/1402)) ([19bac52](https://github.com/ghiscoding/slickgrid-universal/commit/19bac52e5fcb8e523a26ab1f6564f0b6a2b93ef4)) - by @ghiscoding + * **editor:** add `onRendered` lifecycle callback option ([#1410](https://github.com/ghiscoding/slickgrid-universal/issues/1410)) ([9d348d6](https://github.com/ghiscoding/slickgrid-universal/commit/9d348d6e4b693e23a2959917e02a7bcfa55a0c90)) - by @ghiscoding + * **styling:** add Dark Mode grid option ([#1407](https://github.com/ghiscoding/slickgrid-universal/issues/1407)) ([855151b](https://github.com/ghiscoding/slickgrid-universal/commit/855151b9f47a5238e3069f8c85ba4ed8a5bf9bb6)) - by @ghiscoding ## [4.4.1](https://github.com/ghiscoding/slickgrid-universal/compare/v4.3.1...v4.4.1) (2024-02-13) @@ -37,6 +53,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * mouse cell selection with active editor ([#1382](https://github.com/ghiscoding/slickgrid-universal/issues/1382)) ([17549b8](https://github.com/ghiscoding/slickgrid-universal/commit/17549b89933b10688fe8d186ab18ab4c8b7e9f87)) - by @zewa666 + * **publish:** do not npm publish `tsconfig.tsbuildinfo` ([#1373](https://github.com/ghiscoding/slickgrid-universal/issues/1373)) ([9223338](https://github.com/ghiscoding/slickgrid-universal/commit/922333843852ae861015e4bbec053d4937222aa2)) - by @ghiscoding # [4.4.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.3.1...v4.4.0) (2024-02-12) @@ -44,6 +61,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * mouse cell selection with active editor ([#1382](https://github.com/ghiscoding/slickgrid-universal/issues/1382)) ([17549b8](https://github.com/ghiscoding/slickgrid-universal/commit/17549b89933b10688fe8d186ab18ab4c8b7e9f87)) - by @zewa666 + * **publish:** do not npm publish `tsconfig.tsbuildinfo` ([#1373](https://github.com/ghiscoding/slickgrid-universal/issues/1373)) ([9223338](https://github.com/ghiscoding/slickgrid-universal/commit/922333843852ae861015e4bbec053d4937222aa2)) - by @ghiscoding ## [4.3.1](https://github.com/ghiscoding/slickgrid-universal/compare/v4.3.0...v4.3.1) (2024-01-27) @@ -55,6 +73,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** allow extra spaces in `headerCssClass` & other `cssClass` ([#1303](https://github.com/ghiscoding/slickgrid-universal/issues/1303)) ([59ebaa6](https://github.com/ghiscoding/slickgrid-universal/commit/59ebaa65b6882ed3274a3185f457ecef4b2c5b51)) - by @ghiscoding + * **core:** EventHandler subscribed event should be SlickEventData type ([#1327](https://github.com/ghiscoding/slickgrid-universal/issues/1327)) ([2573310](https://github.com/ghiscoding/slickgrid-universal/commit/25733102dbcefcbacc2ce5d6f4c07bd9d1cce6a1)) - by @ghiscoding ### Features @@ -72,6 +91,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **composite:** `onSave` always include last dataContext on few inserts ([#1271](https://github.com/ghiscoding/slickgrid-universal/issues/1271)) ([14791e7](https://github.com/ghiscoding/slickgrid-universal/commit/14791e7edd99b84c8bfefff3d287399cbba9ffad)) - by @ghiscoding + * **npm:** publish src folder for source maps, fixes downstream builds ([#1269](https://github.com/ghiscoding/slickgrid-universal/issues/1269)) ([701da75](https://github.com/ghiscoding/slickgrid-universal/commit/701da752565384408e22857a201828379bfc26ff)) - by @ghiscoding ### Features @@ -383,6 +403,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **composite:** move SlickGrid Composite Editor factory into universal ([c813cea](https://github.com/ghiscoding/slickgrid-universal/commit/c813ceac1ed6535963df15e7933a444de3a8790a)) + * **sanitize:** make sure any string sent to innerHtml are sanitized ([fe55046](https://github.com/ghiscoding/slickgrid-universal/commit/fe550461d27d01cb5c54d93812db82fa7213f96b)) ## [0.16.2](https://github.com/ghiscoding/slickgrid-universal/compare/v0.16.1...v0.16.2) (2021-07-23) @@ -428,6 +449,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **editors:** add `onBeforeOpen` optional callback to Composite Editor ([#306](https://github.com/ghiscoding/slickgrid-universal/issues/306)) ([a642482](https://github.com/ghiscoding/slickgrid-universal/commit/a642482254009115366ca4992e2e60647f8ae9b0)) + * **editors:** add `target` to `onBeforeEditCell` w/called by composite ([#301](https://github.com/ghiscoding/slickgrid-universal/issues/301)) ([7440ff5](https://github.com/ghiscoding/slickgrid-universal/commit/7440ff58988acd7abd1ce249b1ceb72556cceb1d)) # [0.12.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.11.2...v0.12.0) (2021-03-24) @@ -463,14 +485,19 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **component:** Composite Editor sometime shows empty mass update form ([#244](https://github.com/ghiscoding/slickgrid-universal/issues/244)) ([d3ad4db](https://github.com/ghiscoding/slickgrid-universal/commit/d3ad4db45d259fa8ab977cd45c830a7d3bd342d8)) + * **core:** fix types index.d.ts url ([a76b3a3](https://github.com/ghiscoding/slickgrid-universal/commit/a76b3a3d97a6d211ec2e7e8d9060fd8dd0719f58)) + * **editors:** add blank disabled fields in Composite Editor form values ([#233](https://github.com/ghiscoding/slickgrid-universal/issues/233)) ([b634902](https://github.com/ghiscoding/slickgrid-universal/commit/b6349029b705991b7ac2d1df99f5b330fe69ef36)) + * **editors:** add option to skip missing composite editor ([#232](https://github.com/ghiscoding/slickgrid-universal/issues/232)) ([925dba8](https://github.com/ghiscoding/slickgrid-universal/commit/925dba86aca57825ab04d0cdc01484d52bf99265)) + * **editors:** fix clear date & blank disabled field w/Composite Editor ([#235](https://github.com/ghiscoding/slickgrid-universal/issues/235)) ([9aac97d](https://github.com/ghiscoding/slickgrid-universal/commit/9aac97d2d433c809facc8d7092467780d55ca01a)) ### Features * **editors:** add Clone functionality to Composite Editor ([#236](https://github.com/ghiscoding/slickgrid-universal/issues/236)) ([df545e4](https://github.com/ghiscoding/slickgrid-universal/commit/df545e4ec64271307b1979feb5e786f449433639)) + * add nameCompositeEditor override to be used by Composite Editor ([fcdb2e9](https://github.com/ghiscoding/slickgrid-universal/commit/fcdb2e92ed736b09e947cdbcf39ee157afc4acab)) # [0.9.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.8.0...v0.9.0) (2021-01-06) @@ -478,6 +505,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **build:** upgrade to WebPack 5 ([#225](https://github.com/ghiscoding/slickgrid-universal/issues/225)) ([c6b3ad3](https://github.com/ghiscoding/slickgrid-universal/commit/c6b3ad3eb6fb64306bfd8bd300fcc1e86b27e5a6)) + * **ci:** replace CircleCI with GitHub Actions ([#211](https://github.com/ghiscoding/slickgrid-universal/issues/211)) ([4f91140](https://github.com/ghiscoding/slickgrid-universal/commit/4f9114031ca6236ef45f04b67dcba1a9981035c4)) # [0.8.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.7.7...v0.8.0) (2020-12-22) @@ -523,6 +551,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **core:** add registerExternalResources for Components/Services ([#196](https://github.com/ghiscoding/slickgrid-universal/issues/196)) ([ee02f1d](https://github.com/ghiscoding/slickgrid-universal/commit/ee02f1d62d1a0601421352e43d17bd8c89e4348c)) + * **core:** refactor code using the container service everywhere ([#197](https://github.com/ghiscoding/slickgrid-universal/issues/197)) ([96ce9bd](https://github.com/ghiscoding/slickgrid-universal/commit/96ce9bdbf18330e522dad0cbb0eda09c41f6a3df)) ## [0.5.1](https://github.com/ghiscoding/slickgrid-universal/compare/v0.5.0...v0.5.1) (2020-12-10) diff --git a/packages/composite-editor-component/README.md b/packages/composite-editor-component/README.md index caf4ae318..1eb395b9e 100644 --- a/packages/composite-editor-component/README.md +++ b/packages/composite-editor-component/README.md @@ -3,6 +3,7 @@ [![lerna--lite](https://img.shields.io/badge/maintained%20with-lerna--lite-e137ff)](https://github.com/ghiscoding/lerna-lite) [![npm](https://img.shields.io/npm/v/@slickgrid-universal/composite-editor-component.svg)](https://www.npmjs.com/package/@slickgrid-universal/composite-editor-component) [![npm](https://img.shields.io/npm/dy/@slickgrid-universal/composite-editor-component)](https://www.npmjs.com/package/@slickgrid-universal/composite-editor-component) +[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/composite-editor-component?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/composite-editor-component) [![Actions Status](https://github.com/ghiscoding/slickgrid-universal/workflows/CI%20Build/badge.svg)](https://github.com/ghiscoding/slickgrid-universal/actions) [![Cypress.io](https://img.shields.io/badge/tested%20with-Cypress-04C38E.svg)](https://www.cypress.io/) diff --git a/packages/composite-editor-component/package.json b/packages/composite-editor-component/package.json index 7b55568c7..4d074afcb 100644 --- a/packages/composite-editor-component/package.json +++ b/packages/composite-editor-component/package.json @@ -1,6 +1,6 @@ { "name": "@slickgrid-universal/composite-editor-component", - "version": "4.7.0", + "version": "5.0.0-beta.3", "description": "Slick Composite Editor Component - Vanilla Implementation of a Composite Editor Modal Window Component", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", diff --git a/packages/composite-editor-component/src/compositeEditor.factory.spec.ts b/packages/composite-editor-component/src/compositeEditor.factory.spec.ts index 2c2f36a9a..0672606ca 100644 --- a/packages/composite-editor-component/src/compositeEditor.factory.spec.ts +++ b/packages/composite-editor-component/src/compositeEditor.factory.spec.ts @@ -67,7 +67,7 @@ const gridStub = { const columnsMock: Column[] = [ { id: 'productName', field: 'productName', width: 100, name: 'Product', nameKey: 'PRODUCT', editorClass: Editors.text as any }, { id: 'field2', field: 'field2', width: 75, name: 'Field 2' }, - { id: 'field3', field: 'field3', width: 75, name: 'Field 3', nameKey: 'DURATION', editorClass: Editors.date as any, columnGroup: 'Group Name', columnGroupKey: 'GROUP_NAME' }, + { id: 'field3', field: 'field3', width: 75, name: 'Field 3', nameKey: 'DURATION', editorClass: Editors.float as any, columnGroup: 'Group Name', columnGroupKey: 'GROUP_NAME' }, { id: 'zip', field: 'adress.zip', width: 75, name: 'Zip', editorClass: Editors.integer as any, columnGroup: 'Group Name', columnGroupKey: 'GROUP_NAME' } ]; const compositeEditorOptionsMock = { diff --git a/packages/composite-editor-component/src/slick-composite-editor.component.ts b/packages/composite-editor-component/src/slick-composite-editor.component.ts index e938660b0..aa58dbeef 100644 --- a/packages/composite-editor-component/src/slick-composite-editor.component.ts +++ b/packages/composite-editor-component/src/slick-composite-editor.component.ts @@ -1,5 +1,5 @@ import { BindingEventService } from '@slickgrid-universal/binding'; -import { deepCopy, deepMerge, emptyObject, setDeepValue, classNameToList, getHtmlStringOutput } from '@slickgrid-universal/utils'; +import { deepMerge, emptyObject, setDeepValue, classNameToList, getHtmlStringOutput, extend } from '@slickgrid-universal/utils'; import type { Column, CompositeEditorLabel, @@ -312,7 +312,7 @@ export class SlickCompositeEditorComponent implements ExternalResource { } else { const isWithMassChange = (modalType === 'mass-update' || modalType === 'mass-selection'); const dataContext = !isWithMassChange ? this.grid.getDataItem(activeRow) : {}; - this._originalDataContext = deepCopy(dataContext); + this._originalDataContext = extend(true, {}, dataContext); this._columnDefinitions = this.grid.getColumns(); const selectedRowsIndexes = this.hasRowSelectionEnabled() ? this.grid.getSelectedRows() : []; const fullDatasetLength = this.dataView?.getItemCount() ?? 0; @@ -567,7 +567,7 @@ export class SlickCompositeEditorComponent implements ExternalResource { /** Apply Mass Update Changes (form values) to the entire dataset */ protected applySaveMassUpdateChanges(formValues: any, _selection: DataSelection, applyToDataview = true): any[] { // not applying to dataView means that we're doing a preview of dataset and we should use a deep copy of it instead of applying changes directly to it - const data = applyToDataview ? this.dataView.getItems() : deepCopy(this.dataView.getItems()); + const data = applyToDataview ? this.dataView.getItems() : extend(true, [], this.dataView.getItems()); // from the "lastCompositeEditor" object that we kept as reference, it contains all the changes inside the "formValues" property // we can loop through these changes and apply them on the selected row indexes @@ -595,7 +595,7 @@ export class SlickCompositeEditorComponent implements ExternalResource { const selectedTmpItems = selectedItemIds.map(itemId => this.dataView.getItemById(itemId)); // not applying to dataView means that we're doing a preview of dataset and we should use a deep copy of it instead of applying changes directly to it - const selectedItems = applyToDataview ? selectedTmpItems : deepCopy(selectedTmpItems); + const selectedItems = applyToDataview ? selectedTmpItems : extend(true, [], selectedTmpItems); // from the "lastCompositeEditor" object that we kept as reference, it contains all the changes inside the "formValues" property // we can loop through these changes and apply them on the selected row indexes diff --git a/packages/custom-footer-component/CHANGELOG.md b/packages/custom-footer-component/CHANGELOG.md index 8d52a413e..66f396cf5 100644 --- a/packages/custom-footer-component/CHANGELOG.md +++ b/packages/custom-footer-component/CHANGELOG.md @@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.0-beta.3](https://github.com/ghiscoding/slickgrid-universal/compare/v5.0.0-beta.2...v5.0.0-beta.3) (2024-05-09) + +**Note:** Version bump only for package @slickgrid-universal/custom-footer-component + +## [5.0.0-beta.2](https://github.com/ghiscoding/slickgrid-universal/compare/v4.7.0...v5.0.0-beta.2) (2024-05-07) + +### ⚠ BREAKING CHANGES + +* migrate from Moment to Tempo (#1507) +* **common:** migrate from `moment` to `moment-tiny` (#1456) + +### Features + +* **common:** migrate from `moment` to `moment-tiny` ([#1456](https://github.com/ghiscoding/slickgrid-universal/issues/1456)) ([90690f4](https://github.com/ghiscoding/slickgrid-universal/commit/90690f4b6a4c8f8a7a221ddc1df69077384f48a9)) - by @ghiscoding +* migrate from Moment to Tempo ([#1507](https://github.com/ghiscoding/slickgrid-universal/issues/1507)) ([adef47f](https://github.com/ghiscoding/slickgrid-universal/commit/adef47f21a0e32bd32ec4efce931770dc252d3b5)) - by @ghiscoding + # [4.7.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.6.3...v4.7.0) (2024-04-20) **Note:** Version bump only for package @slickgrid-universal/custom-footer-component @@ -345,6 +361,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * make constructor arguments as readonly ([a4588ea](https://github.com/ghiscoding/slickgrid-universal/commit/a4588ea5722ae44b647b8c0d02cf8e2a60ff5963)) + * **services:** make everything extendable by using `protected` ([ecbb93a](https://github.com/ghiscoding/slickgrid-universal/commit/ecbb93a56abba39dd050bbd6019b86694495edd1)) # [0.15.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.14.1...v0.15.0) (2021-07-06) diff --git a/packages/custom-footer-component/README.md b/packages/custom-footer-component/README.md index f96615548..3ad720eb9 100644 --- a/packages/custom-footer-component/README.md +++ b/packages/custom-footer-component/README.md @@ -3,6 +3,7 @@ [![lerna--lite](https://img.shields.io/badge/maintained%20with-lerna--lite-e137ff)](https://github.com/ghiscoding/lerna-lite) [![npm](https://img.shields.io/npm/v/@slickgrid-universal/custom-footer-component.svg)](https://www.npmjs.com/package/@slickgrid-universal/custom-footer-component) [![npm](https://img.shields.io/npm/dy/@slickgrid-universal/custom-footer-component)](https://www.npmjs.com/package/@slickgrid-universal/custom-footer-component) +[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/custom-footer-component?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/custom-footer-component) [![Actions Status](https://github.com/ghiscoding/slickgrid-universal/workflows/CI%20Build/badge.svg)](https://github.com/ghiscoding/slickgrid-universal/actions) [![Cypress.io](https://img.shields.io/badge/tested%20with-Cypress-04C38E.svg)](https://www.cypress.io/) diff --git a/packages/custom-footer-component/package.json b/packages/custom-footer-component/package.json index 4dbfe32e6..308b89fb0 100644 --- a/packages/custom-footer-component/package.json +++ b/packages/custom-footer-component/package.json @@ -1,6 +1,6 @@ { "name": "@slickgrid-universal/custom-footer-component", - "version": "4.7.0", + "version": "5.0.0-beta.3", "description": "Slick Custom Footer Component - Vanilla Implementation of a Custom Footer Component", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", @@ -49,9 +49,9 @@ "not dead" ], "dependencies": { + "@formkit/tempo": "^0.1.1", "@slickgrid-universal/binding": "workspace:~", - "@slickgrid-universal/common": "workspace:~", - "moment-mini": "^2.29.4" + "@slickgrid-universal/common": "workspace:~" }, "devDependencies": { "@slickgrid-universal/event-pub-sub": "workspace:~" diff --git a/packages/custom-footer-component/src/slick-footer.component.ts b/packages/custom-footer-component/src/slick-footer.component.ts index b1b0248b0..88df52939 100644 --- a/packages/custom-footer-component/src/slick-footer.component.ts +++ b/packages/custom-footer-component/src/slick-footer.component.ts @@ -1,4 +1,4 @@ -import moment from 'moment-mini'; +import { format } from '@formkit/tempo'; import type { CustomFooterOption, GridOption, @@ -110,7 +110,7 @@ export class SlickFooterComponent { /** Render element attribute values */ renderMetrics(metrics: Metrics) { // get translated text & last timestamp - const lastUpdateTimestamp = moment(metrics.endTime).format(this.customFooterOptions.dateFormat); + const lastUpdateTimestamp = metrics?.endTime ? format(metrics.endTime, this.customFooterOptions.dateFormat, 'en-US') : ''; this._bindingHelper.setElementAttributeValue('span.last-update-timestamp', 'textContent', lastUpdateTimestamp); this._bindingHelper.setElementAttributeValue('span.item-count', 'textContent', metrics.itemCount); this._bindingHelper.setElementAttributeValue('span.total-count', 'textContent', metrics.totalItemCount); @@ -233,7 +233,7 @@ export class SlickFooterComponent { protected createFooterLastUpdate(): HTMLSpanElement { // get translated text & last timestamp const lastUpdateText = this.customFooterOptions?.metricTexts?.lastUpdate ?? 'Last Update'; - const lastUpdateTimestamp = moment(this.metrics?.endTime).format(this.customFooterOptions.dateFormat); + const lastUpdateTimestamp = this.metrics?.endTime ? format(this.metrics?.endTime, this.customFooterOptions.dateFormat, 'en-US') : ''; const lastUpdateContainerElm = createDomElement('span'); lastUpdateContainerElm.appendChild(createDomElement('span', { className: 'text-last-update', textContent: lastUpdateText })); diff --git a/packages/custom-tooltip-plugin/CHANGELOG.md b/packages/custom-tooltip-plugin/CHANGELOG.md index 71e22ba34..efec91cd8 100644 --- a/packages/custom-tooltip-plugin/CHANGELOG.md +++ b/packages/custom-tooltip-plugin/CHANGELOG.md @@ -4,6 +4,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.0-beta.3](https://github.com/ghiscoding/slickgrid-universal/compare/v5.0.0-beta.2...v5.0.0-beta.3) (2024-05-09) + +### Bug Fixes + +* make some more cleanup with now optional DOMPurify ([#1508](https://github.com/ghiscoding/slickgrid-universal/issues/1508)) ([7fafbcc](https://github.com/ghiscoding/slickgrid-universal/commit/7fafbcc21fccfcd83d3ab103f313398c9d4b82e2)) - by @ghiscoding +* **tooltip:** only show tooltip that has value ([#1511](https://github.com/ghiscoding/slickgrid-universal/issues/1511)) ([2ff15da](https://github.com/ghiscoding/slickgrid-universal/commit/2ff15da4a21cd98b63f251b9b248454658dac698)) - by @ghiscoding + +## [5.0.0-beta.2](https://github.com/ghiscoding/slickgrid-universal/compare/v4.7.0...v5.0.0-beta.2) (2024-05-07) + +### ⚠ BREAKING CHANGES + +* **common:** make DOMPurify as optional sanitizer grid option (#1503) +* **styling:** convert SVG icons to pure CSS (#1474) + +### Features + +* **common:** make DOMPurify as optional sanitizer grid option ([#1503](https://github.com/ghiscoding/slickgrid-universal/issues/1503)) ([0aa0859](https://github.com/ghiscoding/slickgrid-universal/commit/0aa085955f81303c0193fbdcd36ff220263814e3)) - by @ghiscoding +* **styling:** convert SVG icons to pure CSS ([#1474](https://github.com/ghiscoding/slickgrid-universal/issues/1474)) ([70cda8a](https://github.com/ghiscoding/slickgrid-universal/commit/70cda8aa9304ac8ea4bab06390dc1b4c4423df2e)) - by @ghiscoding + # [4.7.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.6.3...v4.7.0) (2024-04-20) **Note:** Version bump only for package @slickgrid-universal/custom-tooltip-plugin @@ -13,6 +32,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * revisit package `exports` to pass "are the types wrong" ([#1440](https://github.com/ghiscoding/slickgrid-universal/issues/1440)) ([20229f7](https://github.com/ghiscoding/slickgrid-universal/commit/20229f78adef51078f99fce3f5a46ac88280a048)) - by @ghiscoding + * **tooltip:** allow multiple tooltips per grid cell ([#1448](https://github.com/ghiscoding/slickgrid-universal/issues/1448)) ([061c4a0](https://github.com/ghiscoding/slickgrid-universal/commit/061c4a087484238f7285eb27a1c238ac75972f19)) - by @ghiscoding # [4.6.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.5.0...v4.6.0) (2024-03-23) @@ -50,6 +70,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** EventHandler subscribed event should be SlickEventData type ([#1327](https://github.com/ghiscoding/slickgrid-universal/issues/1327)) ([2573310](https://github.com/ghiscoding/slickgrid-universal/commit/25733102dbcefcbacc2ce5d6f4c07bd9d1cce6a1)) - by @ghiscoding + * **plugin:** CustomDataView for CellSelectionModel & SlickCustomTooltip ([#1306](https://github.com/ghiscoding/slickgrid-universal/issues/1306)) ([3bdd300](https://github.com/ghiscoding/slickgrid-universal/commit/3bdd30038b93af2db1f2f4a8b7df72ca6a06a06e)) - by @ghiscoding # [4.2.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.1.0...v4.2.0) (2023-12-30) @@ -205,6 +226,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **build:** package exports prop had invalid ESM import link ([#892](https://github.com/ghiscoding/slickgrid-universal/issues/892)) ([7f95f69](https://github.com/ghiscoding/slickgrid-universal/commit/7f95f698447f8178cb7ceec416c35f4957fddbe9)) - by @ghiscoding + * **deps:** update dependency dompurify to v3 ([#907](https://github.com/ghiscoding/slickgrid-universal/issues/907)) ([66c8b4d](https://github.com/ghiscoding/slickgrid-universal/commit/66c8b4d602d88d733070b2189468bf1b6508d7eb)) - by @renovate-bot ## [2.4.1](https://github.com/ghiscoding/slickgrid-universal/compare/v2.4.0...v2.4.1) (2023-02-04) @@ -248,7 +270,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **common:** changing Slider value(s) should update Tooltip instantly ([#800](https://github.com/ghiscoding/slickgrid-universal/issues/800)) ([9c6be27](https://github.com/ghiscoding/slickgrid-universal/commit/9c6be271a956876edaa03be7bf4bda9821840910)) - by @ghiscoding + * **deps:** update dependency dompurify to ^2.4.1 ([#806](https://github.com/ghiscoding/slickgrid-universal/issues/806)) ([a33d8fb](https://github.com/ghiscoding/slickgrid-universal/commit/a33d8fbf3e48bfa29b9173f9263620e61608fffb)) - by @renovate-bot + * **toolip:** left & right align were inverted ([#797](https://github.com/ghiscoding/slickgrid-universal/issues/797)) ([91c4a5c](https://github.com/ghiscoding/slickgrid-universal/commit/91c4a5c61a4f78478929f2be41a17e3e2d210a30)) - by @ghiscoding ### Features diff --git a/packages/custom-tooltip-plugin/README.md b/packages/custom-tooltip-plugin/README.md index 726ebfc66..22bb838ef 100644 --- a/packages/custom-tooltip-plugin/README.md +++ b/packages/custom-tooltip-plugin/README.md @@ -3,6 +3,7 @@ [![lerna--lite](https://img.shields.io/badge/maintained%20with-lerna--lite-e137ff)](https://github.com/ghiscoding/lerna-lite) [![npm](https://img.shields.io/npm/v/@slickgrid-universal/custom-tooltip-plugin.svg)](https://www.npmjs.com/package/@slickgrid-universal/custom-tooltip-plugin) [![npm](https://img.shields.io/npm/dy/@slickgrid-universal/custom-tooltip-plugin)](https://www.npmjs.com/package/@slickgrid-universal/custom-tooltip-plugin) +[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/custom-tooltip-plugin?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/custom-tooltip-plugin) [![Actions Status](https://github.com/ghiscoding/slickgrid-universal/workflows/CI%20Build/badge.svg)](https://github.com/ghiscoding/slickgrid-universal/actions) [![Cypress.io](https://img.shields.io/badge/tested%20with-Cypress-04C38E.svg)](https://www.cypress.io/) @@ -55,8 +56,5 @@ export class MyExample { ### Internal Dependencies - [@slickgrid-universal/common](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/common) -### External Dependencies -- [DOM Purify](https://github.com/cure53/DOMPurify) to sanitize HTML text - ### Installation Follow the instruction provided in the main [README](https://github.com/ghiscoding/slickgrid-universal#installation) diff --git a/packages/custom-tooltip-plugin/package.json b/packages/custom-tooltip-plugin/package.json index 27348cf71..740d3bfb7 100644 --- a/packages/custom-tooltip-plugin/package.json +++ b/packages/custom-tooltip-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@slickgrid-universal/custom-tooltip-plugin", - "version": "4.7.0", + "version": "5.0.0-beta.3", "description": "A plugin to add Custom Tooltip when hovering a cell, it subscribes to the cell", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", @@ -50,10 +50,6 @@ ], "dependencies": { "@slickgrid-universal/common": "workspace:~", - "@slickgrid-universal/utils": "workspace:~", - "isomorphic-dompurify": "^2.9.0" - }, - "devDependencies": { - "@types/dompurify": "^3.0.5" + "@slickgrid-universal/utils": "workspace:~" } } diff --git a/packages/custom-tooltip-plugin/src/__tests__/slickCustomTooltip.spec.ts b/packages/custom-tooltip-plugin/src/__tests__/slickCustomTooltip.spec.ts index d1380c7c3..67d05d14e 100644 --- a/packages/custom-tooltip-plugin/src/__tests__/slickCustomTooltip.spec.ts +++ b/packages/custom-tooltip-plugin/src/__tests__/slickCustomTooltip.spec.ts @@ -86,6 +86,7 @@ describe('SlickCustomTooltip plugin', () => { plugin.setOptions(mockOptions); expect(plugin.addonOptions).toEqual(mockOptions); + expect(plugin.className).toEqual('slick-custom-tooltip some-class'); expect(plugin.getOptions()).toEqual(mockOptions); }); @@ -315,7 +316,7 @@ describe('SlickCustomTooltip plugin', () => { const tooltipElm = document.body.querySelector('.slick-custom-tooltip') as HTMLDivElement; expect(tooltipElm).toBeTruthy(); expect(tooltipElm).toEqual(plugin.tooltipElm); - expect(plugin.cellAddonOptions).toBeTruthy(); + expect(plugin.addonOptions).toBeTruthy(); expect(tooltipElm.style.maxWidth).toBe('85px'); expect(tooltipElm.textContent).toBe('some text content'); expect(tooltipElm.classList.contains('arrow-down')).toBeTruthy(); diff --git a/packages/custom-tooltip-plugin/src/slickCustomTooltip.ts b/packages/custom-tooltip-plugin/src/slickCustomTooltip.ts index 41cdede1b..05061a214 100644 --- a/packages/custom-tooltip-plugin/src/slickCustomTooltip.ts +++ b/packages/custom-tooltip-plugin/src/slickCustomTooltip.ts @@ -22,10 +22,9 @@ import { createDomElement, findFirstAttribute, getOffset, - sanitizeTextByAvailableSanitizer, SlickEventHandler, } from '@slickgrid-universal/common'; -import { isPrimitiveOrHTML } from '@slickgrid-universal/utils'; +import { classNameToList, isPrimitiveOrHTML } from '@slickgrid-universal/utils'; type CellType = 'slick-cell' | 'slick-header-column' | 'slick-headerrow-column'; @@ -56,6 +55,10 @@ const SELECTOR_CLOSEST_TOOLTIP_ATTR = '[title], [data-slick-tooltip]'; * }, * }; */ + +// add a default CSS class name that is used and required by SlickGrid Theme +const DEFAULT_CLASS_NAME = 'slick-custom-tooltip'; + export class SlickCustomTooltip { name: 'CustomTooltip' = 'CustomTooltip' as const; @@ -74,7 +77,7 @@ export class SlickCustomTooltip { protected _hasMultipleTooltips = false; protected _defaultOptions = { bodyClassName: 'tooltip-body', - className: 'slick-custom-tooltip', + className: '', offsetArrow: 3, // same as `$slick-tooltip-arrow-side-margin` CSS/SASS variable offsetLeft: 0, offsetRight: 0, @@ -106,7 +109,13 @@ export class SlickCustomTooltip { return this._cellAddonOptions?.bodyClassName ?? 'tooltip-body'; } get className(): string { - return this._cellAddonOptions?.className ?? 'slick-custom-tooltip'; + // we'll always add our default class name for the CSS style to display as intended + // and then append any custom CSS class to default when provided + let className = DEFAULT_CLASS_NAME; + if (this._addonOptions?.className) { + className += ` ${this._addonOptions.className}`; + } + return className; } get dataView(): CustomDataView { return this._grid.getData() || {}; @@ -161,7 +170,8 @@ export class SlickCustomTooltip { hideTooltip() { this._cancellablePromise?.cancel(); this._observable$?.unsubscribe(); - const prevTooltip = document.body.querySelector(`.${this.className}${this.gridUidSelector}`); + const cssClasses = classNameToList(this.className).join('.'); + const prevTooltip = document.body.querySelector(`.${cssClasses}${this.gridUidSelector}`); prevTooltip?.remove(); } @@ -319,9 +329,9 @@ export class SlickCustomTooltip { if (typeof formatterOrText === 'function') { const tooltipResult = formatterOrText(cell.row, cell.cell, value, columnDef, item, this._grid); const formatterText = isPrimitiveOrHTML(tooltipResult) ? tooltipResult : (tooltipResult as FormatterResultWithHtml).html || (tooltipResult as FormatterResultWithText).text; - return sanitizeTextByAvailableSanitizer(this.gridOptions, (formatterText instanceof HTMLElement ? formatterText.textContent : formatterText as string) || ''); + return this._grid.sanitizeHtmlString((formatterText instanceof HTMLElement ? formatterText.textContent : formatterText as string) || ''); } else if (typeof formatterOrText === 'string') { - return sanitizeTextByAvailableSanitizer(this.gridOptions, formatterOrText); + return this._grid.sanitizeHtmlString(formatterOrText); } return ''; } @@ -400,7 +410,7 @@ export class SlickCustomTooltip { let finalOutputText = ''; if (!tooltipText || this._cellAddonOptions?.renderRegularTooltipAsHtml) { - finalOutputText = sanitizeTextByAvailableSanitizer(this.gridOptions, outputText); + finalOutputText = this._grid.sanitizeHtmlString(outputText); this._grid.applyHtmlCode(this._tooltipBodyElm, finalOutputText); this._tooltipBodyElm.style.whiteSpace = this._cellAddonOptions?.whiteSpace ?? this._defaultOptions.whiteSpace as string; } else { @@ -418,7 +428,7 @@ export class SlickCustomTooltip { } // when do have text to show, then append the new tooltip to the html body & reposition the tooltip - if (finalOutputText) { + if (finalOutputText.toString()) { document.body.appendChild(this._tooltipElm); // reposition the tooltip on top of the cell that triggered the mouse over event diff --git a/packages/empty-warning-component/CHANGELOG.md b/packages/empty-warning-component/CHANGELOG.md index 29d71f3e1..cc7e7866e 100644 --- a/packages/empty-warning-component/CHANGELOG.md +++ b/packages/empty-warning-component/CHANGELOG.md @@ -4,6 +4,24 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.0-beta.3](https://github.com/ghiscoding/slickgrid-universal/compare/v5.0.0-beta.2...v5.0.0-beta.3) (2024-05-09) + +**Note:** Version bump only for package @slickgrid-universal/empty-warning-component + +## [5.0.0-beta.2](https://github.com/ghiscoding/slickgrid-universal/compare/v4.7.0...v5.0.0-beta.2) (2024-05-07) + +### ⚠ BREAKING CHANGES + +* **styling:** convert SVG icons to pure CSS (#1474) + +### Features + +* **styling:** convert SVG icons to pure CSS ([#1474](https://github.com/ghiscoding/slickgrid-universal/issues/1474)) ([70cda8a](https://github.com/ghiscoding/slickgrid-universal/commit/70cda8aa9304ac8ea4bab06390dc1b4c4423df2e)) - by @ghiscoding + +### Bug Fixes + +* **styling:** empty warning should separate icon & text ([#1491](https://github.com/ghiscoding/slickgrid-universal/issues/1491)) ([240cbd3](https://github.com/ghiscoding/slickgrid-universal/commit/240cbd3b5a8cfb6a6cab563bc43d705332d59beb)) - by @ghiscoding + # [4.7.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.6.3...v4.7.0) (2024-04-20) **Note:** Version bump only for package @slickgrid-universal/empty-warning-component @@ -29,6 +47,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * mouse cell selection with active editor ([#1382](https://github.com/ghiscoding/slickgrid-universal/issues/1382)) ([17549b8](https://github.com/ghiscoding/slickgrid-universal/commit/17549b89933b10688fe8d186ab18ab4c8b7e9f87)) - by @zewa666 + * **publish:** do not npm publish `tsconfig.tsbuildinfo` ([#1373](https://github.com/ghiscoding/slickgrid-universal/issues/1373)) ([9223338](https://github.com/ghiscoding/slickgrid-universal/commit/922333843852ae861015e4bbec053d4937222aa2)) - by @ghiscoding # [4.4.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.3.1...v4.4.0) (2024-02-12) @@ -36,6 +55,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * mouse cell selection with active editor ([#1382](https://github.com/ghiscoding/slickgrid-universal/issues/1382)) ([17549b8](https://github.com/ghiscoding/slickgrid-universal/commit/17549b89933b10688fe8d186ab18ab4c8b7e9f87)) - by @zewa666 + * **publish:** do not npm publish `tsconfig.tsbuildinfo` ([#1373](https://github.com/ghiscoding/slickgrid-universal/issues/1373)) ([9223338](https://github.com/ghiscoding/slickgrid-universal/commit/922333843852ae861015e4bbec053d4937222aa2)) - by @ghiscoding ## [4.3.1](https://github.com/ghiscoding/slickgrid-universal/compare/v4.3.0...v4.3.1) (2024-01-27) @@ -405,7 +425,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **comp:** empty data warning should work with autoheight grid ([#240](https://github.com/ghiscoding/slickgrid-universal/issues/240)) ([8c9cb84](https://github.com/ghiscoding/slickgrid-universal/commit/8c9cb84847bfd08a678d333a8555ae6fc9295670)) + * **components:** empty data warning should work with autoheight grid ([#234](https://github.com/ghiscoding/slickgrid-universal/issues/234)) ([16daa36](https://github.com/ghiscoding/slickgrid-universal/commit/16daa368f0e46112fc1d1dd0b1a944ec2b60ced0)) + * **core:** fix types index.d.ts url ([a76b3a3](https://github.com/ghiscoding/slickgrid-universal/commit/a76b3a3d97a6d211ec2e7e8d9060fd8dd0719f58)) ### Features @@ -417,6 +439,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **build:** upgrade to WebPack 5 ([#225](https://github.com/ghiscoding/slickgrid-universal/issues/225)) ([c6b3ad3](https://github.com/ghiscoding/slickgrid-universal/commit/c6b3ad3eb6fb64306bfd8bd300fcc1e86b27e5a6)) + * **ci:** replace CircleCI with GitHub Actions ([#211](https://github.com/ghiscoding/slickgrid-universal/issues/211)) ([4f91140](https://github.com/ghiscoding/slickgrid-universal/commit/4f9114031ca6236ef45f04b67dcba1a9981035c4)) # [0.8.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.7.7...v0.8.0) (2020-12-22) diff --git a/packages/empty-warning-component/README.md b/packages/empty-warning-component/README.md index a58d38a70..92c41cf4a 100644 --- a/packages/empty-warning-component/README.md +++ b/packages/empty-warning-component/README.md @@ -3,6 +3,7 @@ [![lerna--lite](https://img.shields.io/badge/maintained%20with-lerna--lite-e137ff)](https://github.com/ghiscoding/lerna-lite) [![npm](https://img.shields.io/npm/v/@slickgrid-universal/empty-warning-component.svg)](https://www.npmjs.com/package/@slickgrid-universal/empty-warning-component) [![npm](https://img.shields.io/npm/dy/@slickgrid-universal/empty-warning-component)](https://www.npmjs.com/package/@slickgrid-universal/empty-warning-component) +[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/empty-warning-component?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/empty-warning-component) [![Actions Status](https://github.com/ghiscoding/slickgrid-universal/workflows/CI%20Build/badge.svg)](https://github.com/ghiscoding/slickgrid-universal/actions) [![Cypress.io](https://img.shields.io/badge/tested%20with-Cypress-04C38E.svg)](https://www.cypress.io/) diff --git a/packages/empty-warning-component/package.json b/packages/empty-warning-component/package.json index 5fa14fed9..4b3925ee6 100644 --- a/packages/empty-warning-component/package.json +++ b/packages/empty-warning-component/package.json @@ -1,6 +1,6 @@ { "name": "@slickgrid-universal/empty-warning-component", - "version": "4.7.0", + "version": "5.0.0-beta.3", "description": "Slick Empty Warning Component - Vanilla Implementation of an Empty Dataset Warning Component", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", diff --git a/packages/empty-warning-component/src/slick-empty-warning.component.ts b/packages/empty-warning-component/src/slick-empty-warning.component.ts index 85dadcd86..864ef066a 100644 --- a/packages/empty-warning-component/src/slick-empty-warning.component.ts +++ b/packages/empty-warning-component/src/slick-empty-warning.component.ts @@ -110,9 +110,9 @@ export class SlickEmptyWarningComponent implements ExternalResource { // when using a frozen/pinned grid, we also have extra options to hide left/right message if (this._warningLeftElement) { // display/hide right/left messages - let leftDisplay = isShowing ? 'block' : 'none'; + let leftDisplay = isShowing ? 'flex' : 'none'; if (isFrozenGrid && isShowing) { - leftDisplay = (mergedOptions.hideFrozenLeftWarning) ? 'none' : 'block'; + leftDisplay = (mergedOptions.hideFrozenLeftWarning) ? 'none' : 'flex'; } this._warningLeftElement.style.display = leftDisplay; @@ -123,9 +123,9 @@ export class SlickEmptyWarningComponent implements ExternalResource { if (this._warningRightElement) { // use correct left margin (defaults to 40% on regular grid or 10px on frozen grid) - let rightDisplay = isShowing ? 'block' : 'none'; + let rightDisplay = isShowing ? 'flex' : 'none'; if (isFrozenGrid && isShowing) { - rightDisplay = (mergedOptions.hideFrozenRightWarning) ? 'none' : 'block'; + rightDisplay = (mergedOptions.hideFrozenRightWarning) ? 'none' : 'flex'; } this._warningRightElement.style.display = rightDisplay; diff --git a/packages/empty-warning-component/src/slick-empty-warning.spec.ts b/packages/empty-warning-component/src/slick-empty-warning.spec.ts index 244fb4675..a70e546de 100644 --- a/packages/empty-warning-component/src/slick-empty-warning.spec.ts +++ b/packages/empty-warning-component/src/slick-empty-warning.spec.ts @@ -100,8 +100,8 @@ describe('Slick-Empty-Warning Component', () => { expect(component).toBeTruthy(); expect(component.constructor).toBeDefined(); expect(componentLeftElm).toBeTruthy(); - expect(componentLeftElm.style.display).toBe('block'); - expect(componentRightElm.style.display).toBe('block'); + expect(componentLeftElm.style.display).toBe('flex'); + expect(componentRightElm.style.display).toBe('flex'); expect(componentLeftElm.textContent).toBe('No data to display.'); expect(componentRightElm.textContent).toBe('No data to display.'); }); @@ -139,7 +139,7 @@ describe('Slick-Empty-Warning Component', () => { expect(component.constructor).toBeDefined(); expect(componentLeftElm).toBeTruthy(); expect(componentLeftElm.style.display).toBe('none'); - expect(componentRightElm.style.display).toBe('block'); + expect(componentRightElm.style.display).toBe('flex'); expect(componentLeftElm.style.marginLeft).toBe('0px'); expect(componentRightElm.style.marginLeft).toBe('0px'); expect(componentLeftElm.textContent).toBe('No data to display.'); @@ -159,8 +159,8 @@ describe('Slick-Empty-Warning Component', () => { expect(component).toBeTruthy(); expect(component.constructor).toBeDefined(); expect(componentLeftElm).toBeTruthy(); - expect(componentLeftElm.style.display).toBe('block'); - expect(componentRightElm.style.display).toBe('block'); + expect(componentLeftElm.style.display).toBe('flex'); + expect(componentRightElm.style.display).toBe('flex'); expect(componentLeftElm.style.marginLeft).toBe('40%'); expect(componentRightElm.style.marginLeft).toBe('0px'); expect(componentLeftElm.textContent).toBe('No data to display.'); @@ -183,8 +183,8 @@ describe('Slick-Empty-Warning Component', () => { expect(component).toBeTruthy(); expect(component.constructor).toBeDefined(); expect(componentLeftElm).toBeTruthy(); - expect(componentLeftElm.style.display).toBe('block'); - expect(componentRightElm.style.display).toBe('block'); + expect(componentLeftElm.style.display).toBe('flex'); + expect(componentRightElm.style.display).toBe('flex'); expect(componentLeftElm.style.marginLeft).toBe('40%'); expect(componentRightElm.style.marginLeft).toBe('0px'); expect(componentLeftElm.textContent).toBe('No data to display.'); @@ -215,8 +215,8 @@ describe('Slick-Empty-Warning Component', () => { expect(component).toBeTruthy(); expect(component.constructor).toBeDefined(); expect(componentLeftElm).toBeTruthy(); - expect(componentLeftElm.style.display).toBe('block'); - expect(componentRightElm.style.display).toBe('block'); + expect(componentLeftElm.style.display).toBe('flex'); + expect(componentRightElm.style.display).toBe('flex'); expect(componentLeftElm.style.marginLeft).toBe('40%'); expect(componentRightElm.style.marginLeft).toBe('0px'); expect(componentLeftElm.textContent).toBe('No data to display.'); @@ -269,8 +269,8 @@ describe('Slick-Empty-Warning Component', () => { expect(component).toBeTruthy(); expect(component.constructor).toBeDefined(); expect(componentLeftElm).toBeTruthy(); - expect(componentLeftElm.style.display).toBe('block'); - expect(componentRightElm.style.display).toBe('block'); + expect(componentLeftElm.style.display).toBe('flex'); + expect(componentRightElm.style.display).toBe('flex'); expect(componentLeftElm.style.marginLeft).toBe('0px'); expect(componentRightElm.style.marginLeft).toBe('40%'); expect(componentLeftElm.textContent).toBe('No data to display.'); @@ -291,8 +291,8 @@ describe('Slick-Empty-Warning Component', () => { expect(component).toBeTruthy(); expect(component.constructor).toBeDefined(); expect(componentLeftElm).toBeTruthy(); - expect(componentLeftElm.style.display).toBe('block'); - expect(componentRightElm.style.display).toBe('block'); + expect(componentLeftElm.style.display).toBe('flex'); + expect(componentRightElm.style.display).toBe('flex'); expect(componentLeftElm.style.marginLeft).toBe('15px'); expect(componentRightElm.style.marginLeft).toBe('0px'); expect(componentLeftElm.textContent).toBe('No data to display.'); @@ -313,8 +313,8 @@ describe('Slick-Empty-Warning Component', () => { expect(component).toBeTruthy(); expect(component.constructor).toBeDefined(); expect(componentLeftElm).toBeTruthy(); - expect(componentLeftElm.style.display).toBe('block'); - expect(componentRightElm.style.display).toBe('block'); + expect(componentLeftElm.style.display).toBe('flex'); + expect(componentRightElm.style.display).toBe('flex'); expect(componentLeftElm.style.marginLeft).toBe('0px'); expect(componentRightElm.style.marginLeft).toBe('22px'); expect(componentLeftElm.textContent).toBe('No data to display.'); @@ -335,14 +335,14 @@ describe('Slick-Empty-Warning Component', () => { expect(component).toBeTruthy(); expect(component.constructor).toBeDefined(); expect(componentLeftElm).toBeTruthy(); - expect(componentLeftElm.style.display).toBe('block'); + expect(componentLeftElm.style.display).toBe('flex'); expect(componentRightElm.style.display).toBe('none'); expect(componentLeftElm.textContent).toBe('No data to display.'); expect(componentRightElm.textContent).toBe('No data to display.'); }); it('should expect the Slick-Empty-Warning to change some options and display a different message when provided as an option', () => { - const mockOptions = { message: ' No Record found.', className: 'custom-class', marginTop: 22, marginLeft: 11 }; + const mockOptions = { message: ' No Record found.', className: 'custom-class', marginTop: 22, marginLeft: 11 }; component = new SlickEmptyWarningComponent(); component.init(gridStub, container); component.showEmptyDataMessage(true, mockOptions); @@ -352,14 +352,14 @@ describe('Slick-Empty-Warning Component', () => { expect(component).toBeTruthy(); expect(component.constructor).toBeDefined(); expect(componentElm).toBeTruthy(); - expect(componentElm.style.display).toBe('block'); + expect(componentElm.style.display).toBe('flex'); expect(componentElm.classList.contains('custom-class')).toBeTruthy(); - expect(componentElm.innerHTML).toBe(' No Record found.'); + expect(componentElm.innerHTML).toBe(' No Record found.'); }); it('should expect the Slick-Empty-Warning to change some options and display a different message is provided as a DocumentFragment', () => { const emptyWarningElm = new DocumentFragment(); - emptyWarningElm.appendChild(createDomElement('span', { className: 'fa fa-warning' })); + emptyWarningElm.appendChild(createDomElement('span', { className: 'mdi mdi-alert text-color-warning' })); emptyWarningElm.appendChild(document.createTextNode(' No Record found.')); const mockOptions = { message: emptyWarningElm, className: 'custom-class', marginTop: 22, marginLeft: 11 }; @@ -372,14 +372,14 @@ describe('Slick-Empty-Warning Component', () => { expect(component).toBeTruthy(); expect(component.constructor).toBeDefined(); expect(componentElm).toBeTruthy(); - expect(componentElm.style.display).toBe('block'); + expect(componentElm.style.display).toBe('flex'); expect(componentElm.classList.contains('custom-class')).toBeTruthy(); - expect(componentElm.innerHTML).toBe(' No Record found.'); + expect(componentElm.innerHTML).toBe(' No Record found.'); }); it('should expect the Slick-Empty-Warning to change some options and display a different message is provided as an HTMLElement', () => { const emptyWarningElm = createDomElement('div', { className: 'container' }); - emptyWarningElm.appendChild(createDomElement('span', { className: 'fa fa-warning' })); + emptyWarningElm.appendChild(createDomElement('span', { className: 'mdi mdi-alert text-color-warning' })); emptyWarningElm.appendChild(document.createTextNode(' No Record found.')); const mockOptions = { message: emptyWarningElm, className: 'custom-class', marginTop: 22, marginLeft: 11 }; @@ -392,9 +392,9 @@ describe('Slick-Empty-Warning Component', () => { expect(component).toBeTruthy(); expect(component.constructor).toBeDefined(); expect(componentElm).toBeTruthy(); - expect(componentElm.style.display).toBe('block'); + expect(componentElm.style.display).toBe('flex'); expect(componentElm.classList.contains('custom-class')).toBeTruthy(); - expect(componentElm.innerHTML).toBe('
No Record found.
'); + expect(componentElm.innerHTML).toBe('
No Record found.
'); }); it('should expect the Slick-Empty-Warning message to be translated to French when providing a Translater Service and "messageKey" property', () => { @@ -410,7 +410,7 @@ describe('Slick-Empty-Warning Component', () => { expect(component).toBeTruthy(); expect(component.constructor).toBeDefined(); expect(componentElm).toBeTruthy(); - expect(componentElm.style.display).toBe('block'); + expect(componentElm.style.display).toBe('flex'); expect(componentElm.textContent).toBe('Aucune donnée à afficher.'); }); }); diff --git a/packages/event-pub-sub/CHANGELOG.md b/packages/event-pub-sub/CHANGELOG.md index 68f395608..c28d7d815 100644 --- a/packages/event-pub-sub/CHANGELOG.md +++ b/packages/event-pub-sub/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.0-beta.3](https://github.com/ghiscoding/slickgrid-universal/compare/v5.0.0-beta.2...v5.0.0-beta.3) (2024-05-09) + +**Note:** Version bump only for package @slickgrid-universal/event-pub-sub + +## [5.0.0-beta.2](https://github.com/ghiscoding/slickgrid-universal/compare/v4.7.0...v5.0.0-beta.2) (2024-05-07) + +**Note:** Version bump only for package @slickgrid-universal/event-pub-sub + # [4.7.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.6.3...v4.7.0) (2024-04-20) **Note:** Version bump only for package @slickgrid-universal/event-pub-sub @@ -13,6 +21,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **pubsub:** externalize PubSub event to SlickEventData to stop bubbling ([#1444](https://github.com/ghiscoding/slickgrid-universal/issues/1444)) ([973d0ab](https://github.com/ghiscoding/slickgrid-universal/commit/973d0abb0a4df050ad68a6c7e6493bf7ae4abd52)) - by @ghiscoding + * revisit package `exports` to pass "are the types wrong" ([#1440](https://github.com/ghiscoding/slickgrid-universal/issues/1440)) ([20229f7](https://github.com/ghiscoding/slickgrid-universal/commit/20229f78adef51078f99fce3f5a46ac88280a048)) - by @ghiscoding # [4.6.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.5.0...v4.6.0) (2024-03-23) @@ -30,6 +39,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * mouse cell selection with active editor ([#1382](https://github.com/ghiscoding/slickgrid-universal/issues/1382)) ([17549b8](https://github.com/ghiscoding/slickgrid-universal/commit/17549b89933b10688fe8d186ab18ab4c8b7e9f87)) - by @zewa666 + * **publish:** do not npm publish `tsconfig.tsbuildinfo` ([#1373](https://github.com/ghiscoding/slickgrid-universal/issues/1373)) ([9223338](https://github.com/ghiscoding/slickgrid-universal/commit/922333843852ae861015e4bbec053d4937222aa2)) - by @ghiscoding # [4.4.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.3.1...v4.4.0) (2024-02-12) @@ -37,6 +47,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * mouse cell selection with active editor ([#1382](https://github.com/ghiscoding/slickgrid-universal/issues/1382)) ([17549b8](https://github.com/ghiscoding/slickgrid-universal/commit/17549b89933b10688fe8d186ab18ab4c8b7e9f87)) - by @zewa666 + * **publish:** do not npm publish `tsconfig.tsbuildinfo` ([#1373](https://github.com/ghiscoding/slickgrid-universal/issues/1373)) ([9223338](https://github.com/ghiscoding/slickgrid-universal/commit/922333843852ae861015e4bbec053d4937222aa2)) - by @ghiscoding # [4.3.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.2.0...v4.3.0) (2024-01-20) @@ -236,6 +247,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **binding:** make Binding Service a little smarter ([98a7661](https://github.com/ghiscoding/slickgrid-universal/commit/98a766173638246b6a17e31812929a9bba1eb52b)) + * **services:** add extra features to EventPubSub Service ([9bd02b5](https://github.com/ghiscoding/slickgrid-universal/commit/9bd02b5d92bcf6aaf89a828c4e6496a24e795c53)) ## [1.1.1](https://github.com/ghiscoding/slickgrid-universal/compare/v1.1.0...v1.1.1) (2021-12-11) @@ -293,4 +305,5 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **services:** decouple the EventPubSubService to separate package ([9f51665](https://github.com/ghiscoding/slickgrid-universal/commit/9f516655e9ce5f06e0cfeabc43536834dc38c70b)) + * **services:** move Resizer Service w/common services folder for reuse ([d127ac7](https://github.com/ghiscoding/slickgrid-universal/commit/d127ac797ee787ea7785e8ae9f4c0bcaed786afd)) diff --git a/packages/event-pub-sub/README.md b/packages/event-pub-sub/README.md index 326284956..f45a98f55 100644 --- a/packages/event-pub-sub/README.md +++ b/packages/event-pub-sub/README.md @@ -3,6 +3,7 @@ [![lerna--lite](https://img.shields.io/badge/maintained%20with-lerna--lite-e137ff)](https://github.com/ghiscoding/lerna-lite) [![npm](https://img.shields.io/npm/v/@slickgrid-universal/event-pub-sub.svg)](https://www.npmjs.com/package/@slickgrid-universal/event-pub-sub) [![npm](https://img.shields.io/npm/dy/@slickgrid-universal/event-pub-sub)](https://www.npmjs.com/package/@slickgrid-universal/event-pub-sub) +[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/event-pub-sub?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/event-pub-sub) [![Actions Status](https://github.com/ghiscoding/slickgrid-universal/workflows/CI%20Build/badge.svg)](https://github.com/ghiscoding/slickgrid-universal/actions) [![Cypress.io](https://img.shields.io/badge/tested%20with-Cypress-04C38E.svg)](https://www.cypress.io/) diff --git a/packages/event-pub-sub/package.json b/packages/event-pub-sub/package.json index fc537480c..0ef754801 100644 --- a/packages/event-pub-sub/package.json +++ b/packages/event-pub-sub/package.json @@ -1,6 +1,6 @@ { "name": "@slickgrid-universal/event-pub-sub", - "version": "4.7.0", + "version": "5.0.0-beta.3", "description": "Simple Vanilla Implementation of an Event PubSub Service to do simply publish/subscribe inter-communication while optionally providing data in the event", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", diff --git a/packages/excel-export/CHANGELOG.md b/packages/excel-export/CHANGELOG.md index 02b4a7425..3dada6880 100644 --- a/packages/excel-export/CHANGELOG.md +++ b/packages/excel-export/CHANGELOG.md @@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.0-beta.3](https://github.com/ghiscoding/slickgrid-universal/compare/v5.0.0-beta.2...v5.0.0-beta.3) (2024-05-09) + +**Note:** Version bump only for package @slickgrid-universal/excel-export + +## [5.0.0-beta.2](https://github.com/ghiscoding/slickgrid-universal/compare/v4.7.0...v5.0.0-beta.2) (2024-05-07) + +### ⚠ BREAKING CHANGES + +* migrate from Moment to Tempo (#1507) +* **common:** migrate from `moment` to `moment-tiny` (#1456) + +### Features + +* **common:** migrate from `moment` to `moment-tiny` ([#1456](https://github.com/ghiscoding/slickgrid-universal/issues/1456)) ([90690f4](https://github.com/ghiscoding/slickgrid-universal/commit/90690f4b6a4c8f8a7a221ddc1df69077384f48a9)) - by @ghiscoding +* migrate from Moment to Tempo ([#1507](https://github.com/ghiscoding/slickgrid-universal/issues/1507)) ([adef47f](https://github.com/ghiscoding/slickgrid-universal/commit/adef47f21a0e32bd32ec4efce931770dc252d3b5)) - by @ghiscoding + # [4.7.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.6.3...v4.7.0) (2024-04-20) **Note:** Version bump only for package @slickgrid-universal/excel-export @@ -31,6 +47,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * mouse cell selection with active editor ([#1382](https://github.com/ghiscoding/slickgrid-universal/issues/1382)) ([17549b8](https://github.com/ghiscoding/slickgrid-universal/commit/17549b89933b10688fe8d186ab18ab4c8b7e9f87)) - by @zewa666 + * **publish:** do not npm publish `tsconfig.tsbuildinfo` ([#1373](https://github.com/ghiscoding/slickgrid-universal/issues/1373)) ([9223338](https://github.com/ghiscoding/slickgrid-universal/commit/922333843852ae861015e4bbec053d4937222aa2)) - by @ghiscoding ### Features @@ -42,6 +59,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * mouse cell selection with active editor ([#1382](https://github.com/ghiscoding/slickgrid-universal/issues/1382)) ([17549b8](https://github.com/ghiscoding/slickgrid-universal/commit/17549b89933b10688fe8d186ab18ab4c8b7e9f87)) - by @zewa666 + * **publish:** do not npm publish `tsconfig.tsbuildinfo` ([#1373](https://github.com/ghiscoding/slickgrid-universal/issues/1373)) ([9223338](https://github.com/ghiscoding/slickgrid-universal/commit/922333843852ae861015e4bbec053d4937222aa2)) - by @ghiscoding ### Features @@ -215,6 +233,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **build:** package exports prop had invalid ESM import link ([#892](https://github.com/ghiscoding/slickgrid-universal/issues/892)) ([7f95f69](https://github.com/ghiscoding/slickgrid-universal/commit/7f95f698447f8178cb7ceec416c35f4957fddbe9)) - by @ghiscoding + * **export:** Excel export auto-detect number with Formatters.multiple ([#902](https://github.com/ghiscoding/slickgrid-universal/issues/902)) ([be33a68](https://github.com/ghiscoding/slickgrid-universal/commit/be33a68cadbdaed0c60b00bdcd123f3a4797fb8a)) - by @ghiscoding ## [2.4.1](https://github.com/ghiscoding/slickgrid-universal/compare/v2.4.0...v2.4.1) (2023-02-04) @@ -246,16 +265,23 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **export:** create custom Excel cell format with Formatters.decimal ([#844](https://github.com/ghiscoding/slickgrid-universal/issues/844)) ([a7a626c](https://github.com/ghiscoding/slickgrid-universal/commit/a7a626ccaaa510d084979d38d9a6b5a439f24e6d)) - by @ghiscoding + * **exports:** Date should always export w/Formatter unless false ([#856](https://github.com/ghiscoding/slickgrid-universal/issues/856)) ([1b249e8](https://github.com/ghiscoding/slickgrid-universal/commit/1b249e88e3033ff4c432346ae32ce3183537237b)) - by @ghiscoding + * **formatters:** Date Formatter should work with Date object ([#854](https://github.com/ghiscoding/slickgrid-universal/issues/854)) ([30b80e2](https://github.com/ghiscoding/slickgrid-universal/commit/30b80e27b209dbafda25963864116d980650a648)) - by @ghiscoding ### Features * Excel exporter will now observe if numeric type has dollar formatter. If it does, it will use the dollarFormatter stylesheet. ([#843](https://github.com/ghiscoding/slickgrid-universal/issues/843)) ([ebabbaf](https://github.com/ghiscoding/slickgrid-universal/commit/ebabbafa240f114c7bdbd11d5d29fe1864d5bcba)) - by @austinsimpson + * **exports:** add Excel auto-detect format by field types & formatters ([#848](https://github.com/ghiscoding/slickgrid-universal/issues/848)) ([27a18c4](https://github.com/ghiscoding/slickgrid-universal/commit/27a18c416e71a2a1f418d5c2c850fd331262bf7f)) - by @ghiscoding + * **exports:** add Excel custom cell (column) styling ([#851](https://github.com/ghiscoding/slickgrid-universal/issues/851)) ([dd92d44](https://github.com/ghiscoding/slickgrid-universal/commit/dd92d44e0ac27c94a72c98af314cfa23f525f94c)) - by @ghiscoding + * **exports:** add optional Excel export parser callback functions ([#852](https://github.com/ghiscoding/slickgrid-universal/issues/852)) ([975da5b](https://github.com/ghiscoding/slickgrid-universal/commit/975da5b1d87ac287c1240e7ec88be4760e22ca74)) - by @ghiscoding + * **exports:** add optional file MIME type to Excel export service ([#849](https://github.com/ghiscoding/slickgrid-universal/issues/849)) ([05402e5](https://github.com/ghiscoding/slickgrid-universal/commit/05402e5b3a4cec9306ed21a495cc89c31b3816d8)) - by @ghiscoding + * **formatters:** add Currency Formatter and GroupTotalFormatter ([#850](https://github.com/ghiscoding/slickgrid-universal/issues/850)) ([ad373ab](https://github.com/ghiscoding/slickgrid-universal/commit/ad373abd84468367d43bf4fa0feccb99ae22821c)) - by @ghiscoding ## [2.1.3](https://github.com/ghiscoding/slickgrid-universal/compare/v2.1.2...v2.1.3) (2022-12-08) @@ -455,7 +481,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** fix types index.d.ts url ([a76b3a3](https://github.com/ghiscoding/slickgrid-universal/commit/a76b3a3d97a6d211ec2e7e8d9060fd8dd0719f58)) + * **exports:** Excel Export custom width applies the width to next column ([#242](https://github.com/ghiscoding/slickgrid-universal/issues/242)) ([146f64f](https://github.com/ghiscoding/slickgrid-universal/commit/146f64f1b89005e6bb5e982721b5c7e43ecf5ac4)) + * **tsc:** running dev watch was overriding commonjs folder ([#249](https://github.com/ghiscoding/slickgrid-universal/issues/249)) ([e466f62](https://github.com/ghiscoding/slickgrid-universal/commit/e466f6214d9450b593daecfdee6682f1f7c9ed19)) # [0.9.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.8.0...v0.9.0) (2021-01-06) @@ -463,6 +491,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **build:** upgrade to WebPack 5 ([#225](https://github.com/ghiscoding/slickgrid-universal/issues/225)) ([c6b3ad3](https://github.com/ghiscoding/slickgrid-universal/commit/c6b3ad3eb6fb64306bfd8bd300fcc1e86b27e5a6)) + * **ci:** replace CircleCI with GitHub Actions ([#211](https://github.com/ghiscoding/slickgrid-universal/issues/211)) ([4f91140](https://github.com/ghiscoding/slickgrid-universal/commit/4f9114031ca6236ef45f04b67dcba1a9981035c4)) # [0.8.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.7.7...v0.8.0) (2020-12-22) @@ -610,8 +639,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **autocomplete:** add much more functionalities to the AutoComplete ([#69](https://github.com/ghiscoding/slickgrid-universal/issues/69)) ([93c3d0a](https://github.com/ghiscoding/slickgrid-universal/commit/93c3d0a9b8d5a30c7a933f95a4333937c95305a3)) + * **core:** add ESLint npm script and add to prebuild script ([#151](https://github.com/ghiscoding/slickgrid-universal/issues/151)) ([4064876](https://github.com/ghiscoding/slickgrid-universal/commit/40648760a33628f0ba85653f5fc99d8250b9a7a2)) + * **core:** update few npm packages ([#123](https://github.com/ghiscoding/slickgrid-universal/issues/123)) ([1c25b87](https://github.com/ghiscoding/slickgrid-universal/commit/1c25b87fdd738616879298baeb52074e30e9bf14)) + * **editor:** add Composite Editor modal dialog ([#76](https://github.com/ghiscoding/slickgrid-universal/issues/76)) ([bba0b80](https://github.com/ghiscoding/slickgrid-universal/commit/bba0b804301195a166f87be610ee85fe77d4a134)) # 0.1.0 (2020-07-28) @@ -619,15 +651,23 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **editors:** add saveOutputType to finally have proper save format ([#17](https://github.com/ghiscoding/slickgrid-universal/issues/17)) ([ebfd715](https://github.com/ghiscoding/slickgrid-universal/commit/ebfd71582642abe136317dbef8cedee68d472aa7)) + * **excel:** Excel Export add mime type to work in Firefox ([bc07790](https://github.com/ghiscoding/slickgrid-universal/commit/bc07790b78c8913251f55fffb537af56ed26cba7)) ### Features * **backend:** add OData & GraphQL packages ([#2](https://github.com/ghiscoding/slickgrid-universal/issues/2)) ([53cf08b](https://github.com/ghiscoding/slickgrid-universal/commit/53cf08bff2eea18e677770f70eedef1bda9aefcc)) + * **core:** expose all Extensions in new getter prop & fix draggable ([#29](https://github.com/ghiscoding/slickgrid-universal/issues/29)) ([07257b2](https://github.com/ghiscoding/slickgrid-universal/commit/07257b2564d86cbfad4f69bb4e910e04d7df5688)) + * **export:** add grouped header title (from pre-header) into exports ([465becb](https://github.com/ghiscoding/slickgrid-universal/commit/465becbe5db4fc1920be676b1439c14bcc814606)) + * **footer:** add Custom Footer component ([#5](https://github.com/ghiscoding/slickgrid-universal/issues/5)) ([59d0ba8](https://github.com/ghiscoding/slickgrid-universal/commit/59d0ba8921c2e0886b0c34705ac5a74f35ab4e43)) + * **package:** add new Excel Export package ([808785e](https://github.com/ghiscoding/slickgrid-universal/commit/808785e0ea9508f817453211d8ed808398aa9c01)) + * **services:** add registerServices in Grid Options ([#1](https://github.com/ghiscoding/slickgrid-universal/issues/1)) ([e7c2e91](https://github.com/ghiscoding/slickgrid-universal/commit/e7c2e91842eac2044ccdd82673bfade20b24ab4f)) + * **tests:** add Jest to lib root and add few more unit tests ([5811c96](https://github.com/ghiscoding/slickgrid-universal/commit/5811c96568c5255376ea6b97b132f4f0fded0647)) + * **translate:** add namespace prefix + separator grid option ([1746e1d](https://github.com/ghiscoding/slickgrid-universal/commit/1746e1d4726a2fcba64871fac175b09b2f177f65)) diff --git a/packages/excel-export/README.md b/packages/excel-export/README.md index a70ee1a75..033fba91e 100644 --- a/packages/excel-export/README.md +++ b/packages/excel-export/README.md @@ -3,6 +3,7 @@ [![lerna--lite](https://img.shields.io/badge/maintained%20with-lerna--lite-e137ff)](https://github.com/ghiscoding/lerna-lite) [![npm](https://img.shields.io/npm/v/@slickgrid-universal/excel-export.svg)](https://www.npmjs.com/package/@slickgrid-universal/excel-export) [![npm](https://img.shields.io/npm/dy/@slickgrid-universal/excel-export)](https://www.npmjs.com/package/@slickgrid-universal/excel-export) +[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/excel-export?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/excel-export) [![Actions Status](https://github.com/ghiscoding/slickgrid-universal/workflows/CI%20Build/badge.svg)](https://github.com/ghiscoding/slickgrid-universal/actions) [![Cypress.io](https://img.shields.io/badge/tested%20with-Cypress-04C38E.svg)](https://www.cypress.io/) diff --git a/packages/excel-export/package.json b/packages/excel-export/package.json index 7fe307073..e4f220e6d 100644 --- a/packages/excel-export/package.json +++ b/packages/excel-export/package.json @@ -1,6 +1,6 @@ { "name": "@slickgrid-universal/excel-export", - "version": "4.7.0", + "version": "5.0.0-beta.3", "description": "Excel Export (xls/xlsx) Service.", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", @@ -51,8 +51,7 @@ "dependencies": { "@slickgrid-universal/common": "workspace:~", "@slickgrid-universal/utils": "workspace:~", - "excel-builder-vanilla": "^3.0.1", - "moment-mini": "^2.29.4" + "excel-builder-vanilla": "^3.0.1" }, "devDependencies": { "@slickgrid-universal/event-pub-sub": "workspace:~" diff --git a/packages/excel-export/src/excelExport.service.ts b/packages/excel-export/src/excelExport.service.ts index 6878c0fb1..03fbc4803 100644 --- a/packages/excel-export/src/excelExport.service.ts +++ b/packages/excel-export/src/excelExport.service.ts @@ -33,7 +33,7 @@ import { getTranslationPrefix, isColumnDateType, } from '@slickgrid-universal/common'; -import { addWhiteSpaces, deepCopy, getHtmlStringOutput, stripTags, titleCase } from '@slickgrid-universal/utils'; +import { addWhiteSpaces, extend, getHtmlStringOutput, stripTags, titleCase } from '@slickgrid-universal/utils'; import { type ExcelFormatter, @@ -136,7 +136,7 @@ export class ExcelExportService implements ExternalResource, BaseExcelExportServ throw new Error('[Slickgrid-Universal] it seems that the SlickGrid & DataView objects and/or PubSubService are not initialized did you forget to enable the grid option flag "enableExcelExport"?'); } this._pubSubService?.publish(`onBeforeExportToExcel`, true); - this._excelExportOptions = deepCopy({ ...DEFAULT_EXPORT_OPTIONS, ...this._gridOptions.excelExportOptions, ...options }); + this._excelExportOptions = extend(true, {}, { ...DEFAULT_EXPORT_OPTIONS, ...this._gridOptions.excelExportOptions, ...options }); this._fileFormat = this._excelExportOptions.format || FileType.xlsx; // reset references of detected Excel formats diff --git a/packages/graphql/CHANGELOG.md b/packages/graphql/CHANGELOG.md index 95101102e..1a68ad594 100644 --- a/packages/graphql/CHANGELOG.md +++ b/packages/graphql/CHANGELOG.md @@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.0-beta.3](https://github.com/ghiscoding/slickgrid-universal/compare/v5.0.0-beta.2...v5.0.0-beta.3) (2024-05-09) + +**Note:** Version bump only for package @slickgrid-universal/graphql + +## [5.0.0-beta.2](https://github.com/ghiscoding/slickgrid-universal/compare/v4.7.0...v5.0.0-beta.2) (2024-05-07) + +### ⚠ BREAKING CHANGES + +* migrate from Moment to Tempo (#1507) +* **common:** migrate from `moment` to `moment-tiny` (#1456) + +### Features + +* **common:** migrate from `moment` to `moment-tiny` ([#1456](https://github.com/ghiscoding/slickgrid-universal/issues/1456)) ([90690f4](https://github.com/ghiscoding/slickgrid-universal/commit/90690f4b6a4c8f8a7a221ddc1df69077384f48a9)) - by @ghiscoding +* migrate from Moment to Tempo ([#1507](https://github.com/ghiscoding/slickgrid-universal/issues/1507)) ([adef47f](https://github.com/ghiscoding/slickgrid-universal/commit/adef47f21a0e32bd32ec4efce931770dc252d3b5)) - by @ghiscoding + # [4.7.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.6.3...v4.7.0) (2024-04-20) ### Bug Fixes @@ -427,6 +443,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** fix types index.d.ts url ([a76b3a3](https://github.com/ghiscoding/slickgrid-universal/commit/a76b3a3d97a6d211ec2e7e8d9060fd8dd0719f58)) + * **tsc:** running dev watch was overriding commonjs folder ([#249](https://github.com/ghiscoding/slickgrid-universal/issues/249)) ([e466f62](https://github.com/ghiscoding/slickgrid-universal/commit/e466f6214d9450b593daecfdee6682f1f7c9ed19)) # [0.9.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.8.0...v0.9.0) (2021-01-06) @@ -438,6 +455,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **build:** upgrade to WebPack 5 ([#225](https://github.com/ghiscoding/slickgrid-universal/issues/225)) ([c6b3ad3](https://github.com/ghiscoding/slickgrid-universal/commit/c6b3ad3eb6fb64306bfd8bd300fcc1e86b27e5a6)) + * **ci:** replace CircleCI with GitHub Actions ([#211](https://github.com/ghiscoding/slickgrid-universal/issues/211)) ([4f91140](https://github.com/ghiscoding/slickgrid-universal/commit/4f9114031ca6236ef45f04b67dcba1a9981035c4)) # [0.8.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.7.7...v0.8.0) (2020-12-22) @@ -505,6 +523,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** don't expose src folder on npm & update few npm package ([#168](https://github.com/ghiscoding/slickgrid-universal/issues/168)) ([3c05938](https://github.com/ghiscoding/slickgrid-universal/commit/3c059381b35bba88ea98d0206692c912c625f227)) + * **core:** rename i18n to translater & fix few other issues ([#174](https://github.com/ghiscoding/slickgrid-universal/issues/174)) ([34c963a](https://github.com/ghiscoding/slickgrid-universal/commit/34c963a2bcef1b841d3c62ea405a4bc49be98a5c)) ## [0.2.13](https://github.com/ghiscoding/slickgrid-universal/compare/@slickgrid-universal/graphql@0.2.12...@slickgrid-universal/graphql@0.2.13) (2020-11-26) @@ -570,7 +589,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **autocomplete:** add much more functionalities to the AutoComplete ([#69](https://github.com/ghiscoding/slickgrid-universal/issues/69)) ([93c3d0a](https://github.com/ghiscoding/slickgrid-universal/commit/93c3d0a9b8d5a30c7a933f95a4333937c95305a3)) + * **core:** add ESLint npm script and add to prebuild script ([#151](https://github.com/ghiscoding/slickgrid-universal/issues/151)) ([4064876](https://github.com/ghiscoding/slickgrid-universal/commit/40648760a33628f0ba85653f5fc99d8250b9a7a2)) + * **tests:** add more unit tests to vanilla bundle ([#51](https://github.com/ghiscoding/slickgrid-universal/issues/51)) ([10e5c5a](https://github.com/ghiscoding/slickgrid-universal/commit/10e5c5aa647c0af3e1c5804006acd216ca7d447b)) # 0.1.0 (2020-07-28) @@ -578,6 +599,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **backend:** add OData & GraphQL packages ([#2](https://github.com/ghiscoding/slickgrid-universal/issues/2)) ([53cf08b](https://github.com/ghiscoding/slickgrid-universal/commit/53cf08bff2eea18e677770f70eedef1bda9aefcc)) + * **core:** add Translation into demo with fetch locale from json file ([#23](https://github.com/ghiscoding/slickgrid-universal/issues/23)) ([b5608e9](https://github.com/ghiscoding/slickgrid-universal/commit/b5608e958f659b839a8460ffee4a555c66774893)) + * **core:** expose all Extensions in new getter prop & fix draggable ([#29](https://github.com/ghiscoding/slickgrid-universal/issues/29)) ([07257b2](https://github.com/ghiscoding/slickgrid-universal/commit/07257b2564d86cbfad4f69bb4e910e04d7df5688)) + * **footer:** add Custom Footer component ([#5](https://github.com/ghiscoding/slickgrid-universal/issues/5)) ([59d0ba8](https://github.com/ghiscoding/slickgrid-universal/commit/59d0ba8921c2e0886b0c34705ac5a74f35ab4e43)) diff --git a/packages/graphql/README.md b/packages/graphql/README.md index 35dafb96c..8d8354cb3 100644 --- a/packages/graphql/README.md +++ b/packages/graphql/README.md @@ -3,6 +3,7 @@ [![lerna--lite](https://img.shields.io/badge/maintained%20with-lerna--lite-e137ff)](https://github.com/ghiscoding/lerna-lite) [![npm](https://img.shields.io/npm/v/@slickgrid-universal/graphql.svg)](https://www.npmjs.com/package/@slickgrid-universal/graphql) [![npm](https://img.shields.io/npm/dy/@slickgrid-universal/graphql)](https://www.npmjs.com/package/@slickgrid-universal/graphql) +[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/graphql?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/graphql) [![Actions Status](https://github.com/ghiscoding/slickgrid-universal/workflows/CI%20Build/badge.svg)](https://github.com/ghiscoding/slickgrid-universal/actions) [![Cypress.io](https://img.shields.io/badge/tested%20with-Cypress-04C38E.svg)](https://www.cypress.io/) diff --git a/packages/graphql/package.json b/packages/graphql/package.json index 24911c888..1ff03bdf5 100644 --- a/packages/graphql/package.json +++ b/packages/graphql/package.json @@ -1,6 +1,6 @@ { "name": "@slickgrid-universal/graphql", - "version": "4.7.0", + "version": "5.0.0-beta.3", "description": "GraphQL Service to sync a grid with a GraphQL backend server", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", @@ -52,9 +52,6 @@ "@slickgrid-universal/common": "workspace:~", "@slickgrid-universal/utils": "workspace:~" }, - "devDependencies": { - "moment-mini": "^2.29.4" - }, "funding": { "type": "ko_fi", "url": "https://ko-fi.com/ghiscoding" diff --git a/packages/graphql/src/services/__tests__/graphqlQueryBuilder.spec.ts b/packages/graphql/src/services/__tests__/graphqlQueryBuilder.spec.ts index b7b999e79..d009fb0f7 100644 --- a/packages/graphql/src/services/__tests__/graphqlQueryBuilder.spec.ts +++ b/packages/graphql/src/services/__tests__/graphqlQueryBuilder.spec.ts @@ -1,4 +1,3 @@ -import moment from 'moment-mini'; import GraphqlQueryBuilder from '../graphqlQueryBuilder'; function removeSpaces(textS) { @@ -81,8 +80,8 @@ describe('GraphqlQueryBuilder', () => { it('should be able to Query a Date field', () => { const now = new Date(); - const expectation = `FetchLeeAndSam { lee: user(modified: "${moment(now).toISOString()}") { name, modified }, - sam: user(modified: "${moment(now).toISOString()}") { name, modified } }`; + const expectation = `FetchLeeAndSam { lee: user(modified: "${now.toISOString()}") { name, modified }, + sam: user(modified: "${now.toISOString()}") { name, modified } }`; const fetchLeeAndSam = new GraphqlQueryBuilder('FetchLeeAndSam'); diff --git a/packages/odata/CHANGELOG.md b/packages/odata/CHANGELOG.md index 234677a4b..5434ab6cd 100644 --- a/packages/odata/CHANGELOG.md +++ b/packages/odata/CHANGELOG.md @@ -4,11 +4,26 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.0-beta.3](https://github.com/ghiscoding/slickgrid-universal/compare/v5.0.0-beta.2...v5.0.0-beta.3) (2024-05-09) + +**Note:** Version bump only for package @slickgrid-universal/odata + +## [5.0.0-beta.2](https://github.com/ghiscoding/slickgrid-universal/compare/v4.7.0...v5.0.0-beta.2) (2024-05-07) + +### ⚠ BREAKING CHANGES + +* migrate from Moment to Tempo (#1507) + +### Features + +* migrate from Moment to Tempo ([#1507](https://github.com/ghiscoding/slickgrid-universal/issues/1507)) ([adef47f](https://github.com/ghiscoding/slickgrid-universal/commit/adef47f21a0e32bd32ec4efce931770dc252d3b5)) - by @ghiscoding + # [4.7.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.6.3...v4.7.0) (2024-04-20) ### Bug Fixes * **OData:** sorting columns via `id` instead of field property name, fixes [#1467](https://github.com/ghiscoding/slickgrid-universal/issues/1467) ([#1469](https://github.com/ghiscoding/slickgrid-universal/issues/1469)) ([0a4d402](https://github.com/ghiscoding/slickgrid-universal/commit/0a4d40255e240bddf752a2e7bf39a99ae234cc6e)) - by @zewa666 + * wrong operator comparison ([#1461](https://github.com/ghiscoding/slickgrid-universal/issues/1461)) ([abe772b](https://github.com/ghiscoding/slickgrid-universal/commit/abe772b9ad9480688ef000dddfa86d2cdc6b7e52)) - by @zewa666 ## [4.6.1](https://github.com/ghiscoding/slickgrid-universal/compare/v4.6.0...v4.6.1) (2024-03-31) @@ -366,6 +381,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **backend:** able to preset filters on hidden columns & all queried ([f1d92cd](https://github.com/ghiscoding/slickgrid-universal/commit/f1d92cda4cb3fabee00bb10dae36d68cd1d861e5)) + * **backend:** able to preset filters on hidden columns & all queried ([c610979](https://github.com/ghiscoding/slickgrid-universal/commit/c610979c54170c069b97a71864d95d0363d75e80)) ### Features @@ -409,6 +425,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **core:** fix types index.d.ts url ([a76b3a3](https://github.com/ghiscoding/slickgrid-universal/commit/a76b3a3d97a6d211ec2e7e8d9060fd8dd0719f58)) + * **tsc:** running dev watch was overriding commonjs folder ([#249](https://github.com/ghiscoding/slickgrid-universal/issues/249)) ([e466f62](https://github.com/ghiscoding/slickgrid-universal/commit/e466f6214d9450b593daecfdee6682f1f7c9ed19)) # [0.9.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.8.0...v0.9.0) (2021-01-06) @@ -554,6 +571,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **autocomplete:** add much more functionalities to the AutoComplete ([#69](https://github.com/ghiscoding/slickgrid-universal/issues/69)) ([93c3d0a](https://github.com/ghiscoding/slickgrid-universal/commit/93c3d0a9b8d5a30c7a933f95a4333937c95305a3)) + * **core:** add ESLint npm script and add to prebuild script ([#151](https://github.com/ghiscoding/slickgrid-universal/issues/151)) ([4064876](https://github.com/ghiscoding/slickgrid-universal/commit/40648760a33628f0ba85653f5fc99d8250b9a7a2)) # 0.1.0 (2020-07-28) @@ -561,5 +579,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **backend:** add OData & GraphQL packages ([#2](https://github.com/ghiscoding/slickgrid-universal/issues/2)) ([53cf08b](https://github.com/ghiscoding/slickgrid-universal/commit/53cf08bff2eea18e677770f70eedef1bda9aefcc)) + * **core:** expose all Extensions in new getter prop & fix draggable ([#29](https://github.com/ghiscoding/slickgrid-universal/issues/29)) ([07257b2](https://github.com/ghiscoding/slickgrid-universal/commit/07257b2564d86cbfad4f69bb4e910e04d7df5688)) + * **footer:** add Custom Footer component ([#5](https://github.com/ghiscoding/slickgrid-universal/issues/5)) ([59d0ba8](https://github.com/ghiscoding/slickgrid-universal/commit/59d0ba8921c2e0886b0c34705ac5a74f35ab4e43)) diff --git a/packages/odata/README.md b/packages/odata/README.md index b1f8e96e3..281186106 100644 --- a/packages/odata/README.md +++ b/packages/odata/README.md @@ -3,6 +3,7 @@ [![lerna--lite](https://img.shields.io/badge/maintained%20with-lerna--lite-e137ff)](https://github.com/ghiscoding/lerna-lite) [![npm](https://img.shields.io/npm/v/@slickgrid-universal/odata.svg)](https://www.npmjs.com/package/@slickgrid-universal/odata) [![npm](https://img.shields.io/npm/dy/@slickgrid-universal/odata)](https://www.npmjs.com/package/@slickgrid-universal/odata) +[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/odata?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/odata) [![Actions Status](https://github.com/ghiscoding/slickgrid-universal/workflows/CI%20Build/badge.svg)](https://github.com/ghiscoding/slickgrid-universal/actions) [![Cypress.io](https://img.shields.io/badge/tested%20with-Cypress-04C38E.svg)](https://www.cypress.io/) diff --git a/packages/odata/package.json b/packages/odata/package.json index ae1722b04..e5edc10d0 100644 --- a/packages/odata/package.json +++ b/packages/odata/package.json @@ -1,6 +1,6 @@ { "name": "@slickgrid-universal/odata", - "version": "4.7.0", + "version": "5.0.0-beta.3", "description": "Grid OData Service to sync a grid with an OData backend server", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", diff --git a/packages/odata/src/services/grid-odata.service.ts b/packages/odata/src/services/grid-odata.service.ts index f54cace12..ee60952c1 100644 --- a/packages/odata/src/services/grid-odata.service.ts +++ b/packages/odata/src/services/grid-odata.service.ts @@ -323,7 +323,7 @@ export class GridOdataService implements BackendService { fieldName = stripTags(fieldName.innerHTML); } const fieldType = columnDef.type || FieldType.string; - let searchTerms = (columnFilter && columnFilter.searchTerms ? [...columnFilter.searchTerms] : null) || []; + let searchTerms = (columnFilter?.searchTerms ? [...columnFilter.searchTerms] : null) || []; let fieldSearchValue = (Array.isArray(searchTerms) && searchTerms.length === 1) ? searchTerms[0] : ''; if (typeof fieldSearchValue === 'undefined') { fieldSearchValue = ''; @@ -643,7 +643,7 @@ export class GridOdataService implements BackendService { protected normalizeSearchValue(fieldType: typeof FieldType[keyof typeof FieldType], searchValue: any, version: number) { switch (fieldType) { case FieldType.date: - searchValue = parseUtcDate(searchValue as string, true); + searchValue = parseUtcDate(searchValue as string); searchValue = version >= 4 ? searchValue : `DateTime'${searchValue}'`; break; case FieldType.string: diff --git a/packages/pagination-component/CHANGELOG.md b/packages/pagination-component/CHANGELOG.md index 2208cebe4..03bf1b6dd 100644 --- a/packages/pagination-component/CHANGELOG.md +++ b/packages/pagination-component/CHANGELOG.md @@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.0-beta.3](https://github.com/ghiscoding/slickgrid-universal/compare/v5.0.0-beta.2...v5.0.0-beta.3) (2024-05-09) + +**Note:** Version bump only for package @slickgrid-universal/pagination-component + +## [5.0.0-beta.2](https://github.com/ghiscoding/slickgrid-universal/compare/v4.7.0...v5.0.0-beta.2) (2024-05-07) + +### ⚠ BREAKING CHANGES + +* **styling:** convert SVG icons to pure CSS (#1474) + +### Features + +* **styling:** convert SVG icons to pure CSS ([#1474](https://github.com/ghiscoding/slickgrid-universal/issues/1474)) ([70cda8a](https://github.com/ghiscoding/slickgrid-universal/commit/70cda8aa9304ac8ea4bab06390dc1b4c4423df2e)) - by @ghiscoding + # [4.7.0](https://github.com/ghiscoding/slickgrid-universal/compare/v4.6.3...v4.7.0) (2024-04-20) **Note:** Version bump only for package @slickgrid-universal/pagination-component @@ -167,6 +181,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **binding:** remove unnecessary sanitizer in BindingService ([#947](https://github.com/ghiscoding/slickgrid-universal/issues/947)) ([32a9a35](https://github.com/ghiscoding/slickgrid-universal/commit/32a9a35861647510ccb0d3dd14340cd3a1689fc1)) - by @ghiscoding + * **core:** add better aria accessibility missing on menus and checkboxes ([#968](https://github.com/ghiscoding/slickgrid-universal/issues/968)) ([8041c11](https://github.com/ghiscoding/slickgrid-universal/commit/8041c1189afd7460bbcc0226c49086878c3b5f90)) - by @ghiscoding ## [2.6.3](https://github.com/ghiscoding/slickgrid-universal/compare/v2.6.2...v2.6.3) (2023-03-23) @@ -336,6 +351,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **backend:** add cancellable Pagination change & revert on error ([7a8d903](https://github.com/ghiscoding/slickgrid-universal/commit/7a8d9038f230ba433f2773c02992a211a322ebd4)) + * **sanitize:** make sure any string sent to innerHtml are sanitized ([fe55046](https://github.com/ghiscoding/slickgrid-universal/commit/fe550461d27d01cb5c54d93812db82fa7213f96b)) ## [0.16.2](https://github.com/ghiscoding/slickgrid-universal/compare/v0.16.1...v0.16.2) (2021-07-23) @@ -351,6 +367,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * **aria:** add aria-label to all Editors/Filters & other html templates ([1a4f8f7](https://github.com/ghiscoding/slickgrid-universal/commit/1a4f8f7873d76b7da5a7d38debed598d3d395c10)) + * **services:** make everything extendable by using `protected` ([ecbb93a](https://github.com/ghiscoding/slickgrid-universal/commit/ecbb93a56abba39dd050bbd6019b86694495edd1)) # [0.15.0](https://github.com/ghiscoding/slickgrid-universal/compare/v0.14.1...v0.15.0) (2021-07-06) @@ -358,9 +375,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * **build:** the "files" property should be included in pkg.json ([3d8f12e](https://github.com/ghiscoding/slickgrid-universal/commit/3d8f12e5f55079445c6fb5cde767f8e0b4511ebb)) + * **pagination:** able to change translate pubsub event name in component ([4745063](https://github.com/ghiscoding/slickgrid-universal/commit/4745063930374a21986fc11d736d3bd05c9d6e41)) ### Features * **Pagination:** decouple the Pagination Component to separate package ([606795b](https://github.com/ghiscoding/slickgrid-universal/commit/606795b677956a88c2e4b5e943fddcaba3113b51)) + * **services:** decouple the EventPubSubService to separate package ([9f51665](https://github.com/ghiscoding/slickgrid-universal/commit/9f516655e9ce5f06e0cfeabc43536834dc38c70b)) diff --git a/packages/pagination-component/README.md b/packages/pagination-component/README.md index ad53abd84..9dbe856dd 100644 --- a/packages/pagination-component/README.md +++ b/packages/pagination-component/README.md @@ -3,6 +3,7 @@ [![lerna--lite](https://img.shields.io/badge/maintained%20with-lerna--lite-e137ff)](https://github.com/ghiscoding/lerna-lite) [![npm](https://img.shields.io/npm/v/@slickgrid-universal/pagination-component.svg)](https://www.npmjs.com/package/@slickgrid-universal/pagination-component) [![npm](https://img.shields.io/npm/dy/@slickgrid-universal/pagination-component)](https://www.npmjs.com/package/@slickgrid-universal/pagination-component) +[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@slickgrid-universal/pagination-component?color=success&label=gzip)](https://bundlephobia.com/result?p=@slickgrid-universal/pagination-component) [![Actions Status](https://github.com/ghiscoding/slickgrid-universal/workflows/CI%20Build/badge.svg)](https://github.com/ghiscoding/slickgrid-universal/actions) [![Cypress.io](https://img.shields.io/badge/tested%20with-Cypress-04C38E.svg)](https://www.cypress.io/) diff --git a/packages/pagination-component/package.json b/packages/pagination-component/package.json index cc4a6033f..8453d3ffc 100644 --- a/packages/pagination-component/package.json +++ b/packages/pagination-component/package.json @@ -1,6 +1,6 @@ { "name": "@slickgrid-universal/pagination-component", - "version": "4.7.0", + "version": "5.0.0-beta.3", "description": "Slick Pagination Component - Vanilla Implementation of a Pagination Component", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", diff --git a/packages/pagination-component/src/slick-pagination.component.ts b/packages/pagination-component/src/slick-pagination.component.ts index 674ac3d1f..b5ecf500b 100644 --- a/packages/pagination-component/src/slick-pagination.component.ts +++ b/packages/pagination-component/src/slick-pagination.component.ts @@ -10,13 +10,20 @@ import type { TranslaterService, } from '@slickgrid-universal/common'; import { Constants, createDomElement, getTranslationPrefix } from '@slickgrid-universal/common'; -import { BindingHelper } from '@slickgrid-universal/binding'; +import { BindingEventService, BindingHelper } from '@slickgrid-universal/binding'; export class SlickPaginationComponent { protected _bindingHelper: BindingHelper; + protected _bindingEventService: BindingEventService; protected _paginationElement!: HTMLDivElement; protected _enableTranslate = false; protected _gridParentContainerElm?: HTMLElement; + protected _itemPerPageElm!: HTMLSelectElement; + protected _spanInfoFromToElm!: HTMLSpanElement; + protected _seekFirstElm!: HTMLLIElement; + protected _seekPrevElm!: HTMLLIElement; + protected _seekNextElm!: HTMLLIElement; + protected _seekEndElm!: HTMLLIElement; protected _subscriptions: Subscription[] = []; currentPagination: ServicePagination; firstButtonClasses = ''; @@ -32,6 +39,7 @@ export class SlickPaginationComponent { constructor(protected readonly paginationService: PaginationService, protected readonly pubSubService: PubSubService, protected readonly sharedService: SharedService, protected readonly translaterService?: TranslaterService) { this._bindingHelper = new BindingHelper(); + this._bindingEventService = new BindingEventService(); this._bindingHelper.querySelectorPrefix = `.${this.gridUid} `; this.currentPagination = this.paginationService.getFullPagination(); this._enableTranslate = this.gridOptions?.enableTranslate ?? false; @@ -56,9 +64,8 @@ export class SlickPaginationComponent { (this.currentPagination as any)[key] = (paginationChanges as any)[key]; } this.updatePageButtonsUsability(); - const pageFromToElm = document.querySelector(`.${this.gridUid} span.page-info-from-to`); - if (pageFromToElm?.style) { - pageFromToElm.style.display = (this.currentPagination.totalItems === 0) ? 'none' : ''; + if (this._spanInfoFromToElm?.style) { + this._spanInfoFromToElm.style.display = (this.currentPagination.totalItems === 0) ? 'none' : ''; } }), this.pubSubService.subscribe('onPaginationSetCursorBased', () => { @@ -127,6 +134,7 @@ export class SlickPaginationComponent { dispose() { // also dispose of all Subscriptions this.pubSubService.unsubscribeAll(this._subscriptions); + this._bindingEventService.unbindAll(); this._bindingHelper.dispose(); this._paginationElement.remove(); @@ -136,19 +144,32 @@ export class SlickPaginationComponent { this._gridParentContainerElm = gridParentContainerElm; const paginationElm = this.createPaginationContainer(); const divNavContainerElm = createDomElement('div', { className: 'slick-pagination-nav' }); - const leftNavigationElm = this.createPageNavigation('Page navigation', [ - { liClass: 'page-item seek-first', aClass: 'page-link icon-seek-first', ariaLabel: 'First Page' }, - { liClass: 'page-item seek-prev', aClass: 'page-link icon-seek-prev', ariaLabel: 'Previous Page' }, - ]); + + // left nav + const leftNavElm = createDomElement('nav', { ariaLabel: 'Page navigation' }); + const leftUlElm = createDomElement('ul', { className: 'pagination' }); + this._seekFirstElm = createDomElement('li', { className: 'page-item seek-first' }, leftUlElm); + this._seekFirstElm.appendChild(createDomElement('a', { className: 'page-link icon-seek-first', ariaLabel: 'First Page', role: 'button' })); + this._seekPrevElm = createDomElement('li', { className: 'page-item seek-prev' }, leftUlElm); + this._seekPrevElm.appendChild(createDomElement('a', { className: 'page-link icon-seek-prev', ariaLabel: 'Previous Page', role: 'button' })); + leftNavElm.appendChild(leftUlElm); + const pageNumberSectionElm = this.createPageNumberSection(); - const rightNavigationElm = this.createPageNavigation('Page navigation', [ - { liClass: 'page-item seek-next', aClass: 'page-link icon-seek-next', ariaLabel: 'Next Page' }, - { liClass: 'page-item seek-end', aClass: 'page-link icon-seek-end', ariaLabel: 'Last Page' }, - ]); + + // right nav + const rightNavElm = createDomElement('nav', { ariaLabel: 'Page navigation' }); + const rightUlElm = createDomElement('ul', { className: 'pagination' }); + this._seekNextElm = createDomElement('li', { className: 'page-item seek-next' }, rightUlElm); + this._seekNextElm.appendChild(createDomElement('a', { className: 'page-link icon-seek-next', ariaLabel: 'Next Page', role: 'button' })); + this._seekEndElm = createDomElement('li', { className: 'page-item seek-end' }, rightUlElm); + this._seekEndElm.appendChild(createDomElement('a', { className: 'page-link icon-seek-end', ariaLabel: 'Last Page', role: 'button' })); + rightNavElm.appendChild(rightUlElm); + + // append both navs to container paginationElm.appendChild(divNavContainerElm); - divNavContainerElm.appendChild(leftNavigationElm); + divNavContainerElm.appendChild(leftNavElm); divNavContainerElm.appendChild(pageNumberSectionElm); - divNavContainerElm.appendChild(rightNavigationElm); + divNavContainerElm.appendChild(rightNavElm); const paginationSettingsElm = this.createPaginationSettingsSection(); paginationElm.appendChild(divNavContainerElm); @@ -166,10 +187,9 @@ export class SlickPaginationComponent { /** Render and fill the Page Sizes