@adaptabletools/adaptable 15.0.0-canary.6 → 15.0.0-canary.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/bundle.cjs.js +136 -134
  2. package/package.json +1 -1
  3. package/publishTimestamp.d.ts +1 -1
  4. package/publishTimestamp.js +1 -1
  5. package/src/Api/Implementation/TeamSharingApiImpl.js +11 -1
  6. package/src/Api/Implementation/ThemeApiImpl.d.ts +4 -0
  7. package/src/Api/Implementation/ThemeApiImpl.js +9 -0
  8. package/src/Api/Internal/ThemeInternalApi.d.ts +6 -0
  9. package/src/Api/Internal/ThemeInternalApi.js +25 -0
  10. package/src/Api/TeamSharingApi.d.ts +3 -3
  11. package/src/PredefinedConfig/TeamSharingState.d.ts +8 -4
  12. package/src/PredefinedConfig/ThemeState.d.ts +1 -0
  13. package/src/Redux/Store/AdaptableStore.js +2 -2
  14. package/src/Utilities/Services/ThemeService.js +3 -1
  15. package/src/View/CalculatedColumn/CalculatedColumnSummary.d.ts +1 -1
  16. package/src/View/Components/Popups/WindowPopups/windowFactory.d.ts +1 -0
  17. package/src/View/Components/Popups/WindowPopups/windowFactory.js +4 -1
  18. package/src/View/Components/ToolPanel/ToolPanelPopup.d.ts +1 -1
  19. package/src/View/Dashboard/CustomToolbarWrapper.js +1 -1
  20. package/src/View/Filter/FilterSummary.d.ts +1 -1
  21. package/src/View/Theme/ThemeEditor.d.ts +1 -0
  22. package/src/View/Theme/ThemeEditor.js +16 -29
  23. package/src/View/Theme/ThemeEditorWindow.d.ts +2 -0
  24. package/src/View/Theme/ThemeEditorWindow.js +15 -0
  25. package/src/View/Theme/ThemeField.d.ts +11 -0
  26. package/src/View/Theme/ThemeField.js +40 -0
  27. package/src/View/Theme/ThemePopup.d.ts +1 -0
  28. package/src/View/Theme/ThemePopup.js +6 -1
  29. package/src/View/Theme/VariantSelector.d.ts +7 -0
  30. package/src/View/Theme/VariantSelector.js +25 -0
  31. package/src/agGrid/Adaptable.js +41 -24
  32. package/src/metamodel/adaptable.metamodel.js +1 -1
  33. package/version.d.ts +1 -1
  34. package/version.js +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaptabletools/adaptable",
3
- "version": "15.0.0-canary.6",
3
+ "version": "15.0.0-canary.8",
4
4
  "description": "Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements",
5
5
  "keywords": [
6
6
  "web-components",
@@ -1,2 +1,2 @@
1
- declare const _default: 1676465416898;
1
+ declare const _default: 1676638781056;
2
2
  export default _default;
@@ -1,3 +1,3 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = 1676465416898;
3
+ exports.default = 1676638781056;
@@ -26,7 +26,17 @@ class TeamSharingApiImpl extends ApiBase_1.ApiBase {
26
26
  userName: this.adaptable.adaptableOptions.userName,
27
27
  adaptableApi: this.getAdaptableApi(),
28
28
  };
29
- const loadedSharedEntities = await teamSharingOptions.loadSharedEntities(sharedEntitiesContext);
29
+ let loadedSharedEntities = await teamSharingOptions.loadSharedEntities(sharedEntitiesContext);
30
+ // with v15 we introduced 2 types of SharedEntity: AdaptableSharedEntity (basically the old one) and the new CustomSharedEntity
31
+ // for backwards compatibility, we add default the 'EntityType' property to 'adaptableEntity'
32
+ loadedSharedEntities = loadedSharedEntities.map((sharedEntity) => {
33
+ if (sharedEntity.EntityType !== 'adaptableEntity' &&
34
+ sharedEntity.EntityType !== 'customEntity') {
35
+ // @ts-ignore
36
+ sharedEntity.EntityType = 'adaptableEntity';
37
+ }
38
+ return sharedEntity;
39
+ });
30
40
  const sharedEntities = teamSharingOptions.applySharedEntities(loadedSharedEntities, sharedEntitiesContext);
31
41
  return sharedEntities;
32
42
  }
@@ -1,7 +1,11 @@
1
1
  import { ApiBase } from './ApiBase';
2
2
  import { ThemeApi } from '../ThemeApi';
3
3
  import { AdaptableTheme, ThemeState } from '../../PredefinedConfig/ThemeState';
4
+ import { ThemeInternalApi } from '../Internal/ThemeInternalApi';
5
+ import { IAdaptable } from '../../AdaptableInterfaces/IAdaptable';
4
6
  export declare class ThemeApiImpl extends ApiBase implements ThemeApi {
7
+ internalApi: ThemeInternalApi;
8
+ constructor(adaptable: IAdaptable);
5
9
  getThemeState(): ThemeState;
6
10
  loadTheme(theme: string): void;
7
11
  loadLightTheme(): void;
@@ -7,7 +7,12 @@ const ModuleConstants = tslib_1.__importStar(require("../../Utilities/Constants/
7
7
  const ApiBase_1 = require("./ApiBase");
8
8
  const logDeprecation_1 = require("../../Utilities/logDeprecation");
9
9
  const themes_1 = require("../../themes");
10
+ const ThemeInternalApi_1 = require("../Internal/ThemeInternalApi");
10
11
  class ThemeApiImpl extends ApiBase_1.ApiBase {
12
+ constructor(adaptable) {
13
+ super(adaptable);
14
+ this.internalApi = new ThemeInternalApi_1.ThemeInternalApi(adaptable);
15
+ }
11
16
  getThemeState() {
12
17
  return this.getAdaptableState().Theme;
13
18
  }
@@ -94,6 +99,10 @@ class ThemeApiImpl extends ApiBase_1.ApiBase {
94
99
  editTheme(theme) {
95
100
  this.dispatchAction(ThemeRedux.ThemeEdit(theme));
96
101
  this.getEventApi().emit('ThemeEdited', theme);
102
+ const currentTheme = this.getCurrentTheme();
103
+ if (currentTheme === theme.Name) {
104
+ this.adaptable.applyAdaptableTheme(theme);
105
+ }
97
106
  }
98
107
  addUserTheme(theme) {
99
108
  this.dispatchAction(ThemeRedux.ThemeAdd(theme));
@@ -0,0 +1,6 @@
1
+ import { ApiBase } from '../Implementation/ApiBase';
2
+ export declare class ThemeInternalApi extends ApiBase {
3
+ isSystemTheme(themeName: string): boolean;
4
+ getThemeClassName(theme: string): string;
5
+ openInWindow(): void;
6
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ThemeInternalApi = void 0;
4
+ const windowFactory_1 = require("../../View/Components/Popups/WindowPopups/windowFactory");
5
+ const ApiBase_1 = require("../Implementation/ApiBase");
6
+ class ThemeInternalApi extends ApiBase_1.ApiBase {
7
+ isSystemTheme(themeName) {
8
+ return this.getThemeApi()
9
+ .getSystemThemes()
10
+ .some((theme) => theme.Name === themeName);
11
+ }
12
+ getThemeClassName(theme) {
13
+ return `ab--theme-${theme}`;
14
+ }
15
+ openInWindow() {
16
+ this.adaptable.api.internalApi.showPopupWindow({
17
+ id: windowFactory_1.SHOW_THEME_EDITOR,
18
+ title: 'Theme',
19
+ icon: 'theme',
20
+ factoryId: windowFactory_1.SHOW_THEME_EDITOR,
21
+ popupProps: {},
22
+ });
23
+ }
24
+ }
25
+ exports.ThemeInternalApi = ThemeInternalApi;
@@ -6,11 +6,11 @@ import { AdaptableModule, AdaptableSharedEntityConfig } from '../types';
6
6
  */
7
7
  export interface TeamSharingApi {
8
8
  /**
9
- * Retrieves all currently shared entities; async op leveraging `TeamSharingOptions.loadSharedEntities(...)` method
9
+ * Retrieves all currently shared entities; async operation leveraging `TeamSharingOptions.loadSharedEntities(...)` method
10
10
  */
11
11
  loadSharedEntities(): Promise<SharedEntity[]>;
12
12
  /**
13
- * Sets currently shared entities; async op leveraging `TeamSharingOptions.persistSharedEntities(...)` method
13
+ * Sets currently shared entities; async operation leveraging `TeamSharingOptions.persistSharedEntities(...)` method
14
14
  * @param sharedEntities the shared entities
15
15
  * @return either TRUE if the shared entities were successfully set or FALSE if the shared entities were not set
16
16
  */
@@ -50,7 +50,7 @@ export interface TeamSharingApi {
50
50
  */
51
51
  unshareEntity(entityId: string): void;
52
52
  /**
53
- * Import shared entry.
53
+ * Import the given Shared Entity. In case of `CustomSharedEntity`, the import logic will be delegated to `TeamSharingOptions.handleCustomSharedEntityImport(...)`.
54
54
  *
55
55
  * @param sharedEntity shared entry to import
56
56
  */
@@ -23,11 +23,11 @@ export interface TeamSharingState extends InternalState {
23
23
  importProcessInProgress: boolean;
24
24
  }
25
25
  /**
26
- * Defines an object used in Team Sharing
26
+ * Defines an object used in Team Sharing. The union type is discriminated by the `EntityType` property (`adaptableEntity` / `customEntity`).
27
27
  */
28
28
  export declare type SharedEntity = AdaptableSharedEntity | CustomSharedEntity;
29
29
  export declare const isAdaptableSharedEntity: (entity: SharedEntity) => entity is AdaptableSharedEntity;
30
- export declare const isCustomSharedEntity: (entity: SharedEntity) => entity is CustomSharedEntity;
30
+ export declare const isCustomSharedEntity: (entity: SharedEntity) => entity is CustomSharedEntity<any>;
31
31
  /**
32
32
  * Defines an AdaptableObject shared with Team Sharing
33
33
  */
@@ -80,7 +80,7 @@ export interface AdaptableSharedEntity extends AdaptableObject {
80
80
  /**
81
81
  *
82
82
  */
83
- export interface CustomSharedEntity {
83
+ export interface CustomSharedEntity<T = any> {
84
84
  /**
85
85
  * Type of shared entity (either Adaptable specific or custom object)
86
86
  */
@@ -100,7 +100,7 @@ export interface CustomSharedEntity {
100
100
  /**
101
101
  * Custom Object being shared
102
102
  */
103
- Entity: any;
103
+ Entity: T;
104
104
  /**
105
105
  * When the object was shared
106
106
  */
@@ -117,6 +117,10 @@ export interface CustomSharedEntity {
117
117
  * Last time when the object was changed
118
118
  */
119
119
  ChangedAt: number;
120
+ /**
121
+ * Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full')
122
+ */
123
+ IsReadOnly?: boolean;
120
124
  /**
121
125
  * List of Tags associated with the Object
122
126
  */
@@ -38,4 +38,5 @@ export interface AdaptableTheme extends AdaptableObject {
38
38
  * Variables to be applied at runtime
39
39
  */
40
40
  CSSVariables?: Record<string, string>;
41
+ Variant?: 'light' | 'dark';
41
42
  }
@@ -1358,8 +1358,8 @@ const adaptableMiddleware = (adaptable) => function (middlewareAPI) {
1358
1358
  if (needsOverwriteConfirmation) {
1359
1359
  let confirmation = {
1360
1360
  CancelButtonText: 'Cancel Import',
1361
- Header: 'Overwrite Config',
1362
- Msg: 'This import will overwrite one of your config. Do you want to continue?',
1361
+ Header: 'Overwriting Existing Object',
1362
+ Msg: 'This import will overwrite an existing object in your State. Do you wish to continue?',
1363
1363
  ConfirmButtonText: 'Import',
1364
1364
  CancelAction: null,
1365
1365
  ConfirmAction: processImportAction,
@@ -31,7 +31,9 @@ class ThemeService {
31
31
  applyNewThemeVariables(theme) {
32
32
  var _a;
33
33
  const variables = (_a = theme.CSSVariables) !== null && _a !== void 0 ? _a : {};
34
- let str = ':root {';
34
+ let str = `html.${this.api.themeApi.internalApi.getThemeClassName(theme.Name)} {
35
+ --ab-theme-loaded: custom-theme;
36
+ `;
35
37
  for (const [key, value] of Object.entries(variables)) {
36
38
  if (key.includes('--')) {
37
39
  str += `${key}: ${value};`;
@@ -15,4 +15,4 @@ export declare class CalculatedColumnSummaryComponent extends React.Component<Ca
15
15
  onCloseWizard(): void;
16
16
  onFinishWizard: (calculatedColumn: CalculatedColumn) => void;
17
17
  }
18
- export declare let CalculatedColumnSummary: import("react-redux").ConnectedComponent<typeof CalculatedColumnSummaryComponent, import("react-redux").Omit<React.ClassAttributes<CalculatedColumnSummaryComponent> & CalculatedColumnSummaryProps, "key" | "ref" | "onSuspend" | "api" | "accessLevel" | "modalContainer" | "CalculatedColumns" | "moduleInfo" | "onShare" | "onUnSuspend" | "teamSharingActivated" | "popupParams" | "onClearPopupParams" | "onClosePopup" | "onEdit" | "summarisedColumn" | "onDeleteConfirm">>;
18
+ export declare let CalculatedColumnSummary: import("react-redux").ConnectedComponent<typeof CalculatedColumnSummaryComponent, import("react-redux").Omit<React.ClassAttributes<CalculatedColumnSummaryComponent> & CalculatedColumnSummaryProps, "key" | "ref" | "onSuspend" | "api" | "accessLevel" | "modalContainer" | "CalculatedColumns" | "moduleInfo" | "popupParams" | "onClearPopupParams" | "teamSharingActivated" | "onClosePopup" | "onUnSuspend" | "onShare" | "onEdit" | "summarisedColumn" | "onDeleteConfirm">>;
@@ -3,4 +3,5 @@ import { WindowPopupChildProps } from './WindowPopups';
3
3
  export declare const WINDOW_QUERY_EDITOR = "WINDOW_QUERY_EDITOR";
4
4
  export declare const SHOW_PIVOT_COLUMN_DETAILS = "SHOW_PIVOT_COLUMN_DETAILS";
5
5
  export declare const SHOW_EXPORT_TABLE = "SHOW_EXPORT_TABLE";
6
+ export declare const SHOW_THEME_EDITOR = "SHOW_THEME_EDITOR";
6
7
  export declare const windowFactory: Record<string, React.FunctionComponent<WindowPopupChildProps>>;
@@ -1,14 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.windowFactory = exports.SHOW_EXPORT_TABLE = exports.SHOW_PIVOT_COLUMN_DETAILS = exports.WINDOW_QUERY_EDITOR = void 0;
3
+ exports.windowFactory = exports.SHOW_THEME_EDITOR = exports.SHOW_EXPORT_TABLE = exports.SHOW_PIVOT_COLUMN_DETAILS = exports.WINDOW_QUERY_EDITOR = void 0;
4
4
  const ExpandedQueryPopup_1 = require("../../../Query/ExpandedQueryPopup");
5
5
  const PivotDetailsPopoup_1 = require("../../../Layout/PivotDetailsPopoup");
6
6
  const ExportTablePopup_1 = require("../../../Export/ExportTablePopup");
7
+ const ThemeEditorWindow_1 = require("../../../Theme/ThemeEditorWindow");
7
8
  exports.WINDOW_QUERY_EDITOR = 'WINDOW_QUERY_EDITOR';
8
9
  exports.SHOW_PIVOT_COLUMN_DETAILS = 'SHOW_PIVOT_COLUMN_DETAILS';
9
10
  exports.SHOW_EXPORT_TABLE = 'SHOW_EXPORT_TABLE';
11
+ exports.SHOW_THEME_EDITOR = 'SHOW_THEME_EDITOR';
10
12
  exports.windowFactory = {
11
13
  [exports.WINDOW_QUERY_EDITOR]: ExpandedQueryPopup_1.ExpandedQueryPopup,
12
14
  [exports.SHOW_PIVOT_COLUMN_DETAILS]: PivotDetailsPopoup_1.PivotDetailsPopoup,
13
15
  [exports.SHOW_EXPORT_TABLE]: ExportTablePopup_1.ExportTablePopup,
16
+ [exports.SHOW_THEME_EDITOR]: ThemeEditorWindow_1.ThemeEditorWindow,
14
17
  };
@@ -23,5 +23,5 @@ declare class ToolPanelPopupComponent extends React.Component<ToolPanelPopupComp
23
23
  onShowGridPropertiesChanged(event: React.FormEvent<any>): void;
24
24
  onToolPanelToolPanelsChanged(selectedValues: AdaptableToolPanels): void;
25
25
  }
26
- export declare let ToolPanelPopup: import("react-redux").ConnectedComponent<typeof ToolPanelPopupComponent, import("react-redux").Omit<React.ClassAttributes<ToolPanelPopupComponent> & ToolPanelPopupComponentProps, "key" | "ref" | "onSuspend" | "api" | "accessLevel" | "modalContainer" | "moduleInfo" | "onUnSuspend" | "teamSharingActivated" | "ToolPanelState" | "popupParams" | "onClearPopupParams" | "onClosePopup" | "GridState" | "onToolPanelSetModuleButtons" | "onToolPanelSetToolPanels">>;
26
+ export declare let ToolPanelPopup: import("react-redux").ConnectedComponent<typeof ToolPanelPopupComponent, import("react-redux").Omit<React.ClassAttributes<ToolPanelPopupComponent> & ToolPanelPopupComponentProps, "key" | "ref" | "onSuspend" | "api" | "accessLevel" | "modalContainer" | "moduleInfo" | "popupParams" | "onClearPopupParams" | "teamSharingActivated" | "onClosePopup" | "onUnSuspend" | "ToolPanelState" | "GridState" | "onToolPanelSetModuleButtons" | "onToolPanelSetToolPanels">>;
27
27
  export {};
@@ -85,7 +85,7 @@ const CustomToolbarWrapper = (props) => {
85
85
  const disabled = button.disabled && button.disabled(button, dashboardContext);
86
86
  let buttonVariant = buttonStyle && buttonStyle.variant ? buttonStyle.variant : 'outlined';
87
87
  let buttonTone = buttonStyle && buttonStyle.tone ? buttonStyle.tone : 'neutral';
88
- return (React.createElement(SimpleButton_1.default, { style: { marginLeft: index ? 'var(--ab-space-1)' : 0 }, key: index, disabled: disabled, tooltip: buttonTooltip, icon: buttonIcon, variant: buttonVariant, tone: buttonTone, onClick: () => {
88
+ return (React.createElement(SimpleButton_1.default, { style: { marginLeft: index ? 'var(--ab-space-1)' : 0 }, key: index, disabled: disabled, tooltip: buttonTooltip, icon: buttonIcon, variant: buttonVariant, tone: buttonTone, className: (buttonStyle === null || buttonStyle === void 0 ? void 0 : buttonStyle.className) || '', onClick: () => {
89
89
  button.onClick ? button.onClick(button, dashboardContext) : null;
90
90
  setTimeout(() => {
91
91
  // mutate state to force a re-rendering
@@ -12,4 +12,4 @@ export declare class FilterSummaryComponent extends React.Component<FilterSummar
12
12
  render(): any;
13
13
  getDescription(columnFilter: ColumnFilter): string;
14
14
  }
15
- export declare let FilterSummary: import("react-redux").ConnectedComponent<typeof FilterSummaryComponent, import("react-redux").Omit<React.ClassAttributes<FilterSummaryComponent> & FilterSummaryProps, "ColumnFilters" | "onShare" | "onClearPopupParams" | "onClearFilter">>;
15
+ export declare let FilterSummary: import("react-redux").ConnectedComponent<typeof FilterSummaryComponent, import("react-redux").Omit<React.ClassAttributes<FilterSummaryComponent> & FilterSummaryProps, "ColumnFilters" | "onClearPopupParams" | "onShare" | "onClearFilter">>;
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { AccessLevel } from '../../types';
3
+ export declare type FieldType = 'color' | 'number' | 'text';
3
4
  export interface ThemeEditorProps {
4
5
  theme: string;
5
6
  accessLevel: AccessLevel;
@@ -3,15 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ThemeEditor = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const React = tslib_1.__importStar(require("react"));
6
- const ColorPicker_1 = require("../../components/ColorPicker");
7
6
  const FormLayout_1 = tslib_1.__importStar(require("../../components/FormLayout"));
8
- const StyleHelper_1 = require("../../Utilities/Helpers/StyleHelper");
9
7
  const AdaptableContext_1 = require("../AdaptableContext");
10
8
  const AdaptableInput_1 = tslib_1.__importDefault(require("../Components/AdaptableInput"));
11
9
  const throttle_1 = tslib_1.__importDefault(require("lodash/throttle"));
12
10
  const SimpleButton_1 = tslib_1.__importDefault(require("../../components/SimpleButton"));
13
11
  const rebass_1 = require("rebass");
14
12
  const Panel_1 = tslib_1.__importDefault(require("../../components/Panel"));
13
+ const ThemeField_1 = require("./ThemeField");
14
+ const VariantSelector_1 = require("./VariantSelector");
15
15
  const fields = [
16
16
  {
17
17
  name: 'Primary Color',
@@ -74,32 +74,6 @@ const fields = [
74
74
  variable: '--ab-color-text-on-defaultbackground',
75
75
  },
76
76
  ];
77
- const Field = (props) => {
78
- const adaptable = (0, AdaptableContext_1.useAdaptable)();
79
- let input = null;
80
- let value = props.value;
81
- const throttledOnChange = React.useMemo(() => {
82
- return (0, throttle_1.default)((value) => {
83
- props.onChange(value);
84
- }, 300);
85
- }, []);
86
- if (value === undefined) {
87
- value = (0, StyleHelper_1.getVariableColor)(`var(${props.variable})`);
88
- }
89
- switch (props.type) {
90
- case 'number':
91
- input = (React.createElement(AdaptableInput_1.default, { disabled: props.disabled, type: "number", onChange: (event) => throttledOnChange(event.target.value), value: value }));
92
- break;
93
- case 'color':
94
- input = (React.createElement(ColorPicker_1.ColorPicker, { disabled: props.disabled, includeAlpha: false, api: adaptable.api, value: value, onChange: (color) => throttledOnChange(color) }));
95
- break;
96
- }
97
- return (React.createElement(FormLayout_1.FormRow, { label: props.name },
98
- React.createElement(rebass_1.Flex, null,
99
- input,
100
- ' ',
101
- React.createElement(SimpleButton_1.default, { disabled: props.value === undefined, onClick: () => props.onChange(false) }, "Clear"))));
102
- };
103
77
  const ThemeEditor = (props) => {
104
78
  var _a, _b;
105
79
  const adaptable = (0, AdaptableContext_1.useAdaptable)();
@@ -152,6 +126,17 @@ const ThemeEditor = (props) => {
152
126
  setCurrentThemeObject((prev) => (Object.assign(Object.assign({}, prev), { Name: name })));
153
127
  handleNameDescriptionChangeThrottled('Name', name);
154
128
  };
129
+ const handleVariantChange = (variant) => {
130
+ const newTheme = Object.assign({}, currentThemeObject);
131
+ if (!variant) {
132
+ delete newTheme.Variant;
133
+ }
134
+ else {
135
+ newTheme.Variant = variant;
136
+ }
137
+ setCurrentThemeObject(newTheme);
138
+ adaptable.api.themeApi.editTheme(newTheme);
139
+ };
155
140
  const nameHasChanged = currentThemeObject.Name !== props.theme;
156
141
  const nameIsNotUnique = allThemes.some((theme) => theme.Uuid !== currentThemeObject.Uuid && currentThemeObject.Name === theme.Name);
157
142
  const saveNameDisabled = !nameHasChanged || nameIsNotUnique || currentThemeObject.Name === '';
@@ -166,8 +151,10 @@ const ThemeEditor = (props) => {
166
151
  nameIsNotUnique && (React.createElement(rebass_1.Text, { fontSize: 2, color: "var(--ab-color-error)" }, "Name must be unique."))),
167
152
  React.createElement(FormLayout_1.FormRow, { label: "Description" },
168
153
  React.createElement(AdaptableInput_1.default, { onChange: (event) => handleDescriptionChange('Description', event.target.value), value: (_b = currentThemeObject === null || currentThemeObject === void 0 ? void 0 : currentThemeObject.Description) !== null && _b !== void 0 ? _b : '' })),
154
+ React.createElement(FormLayout_1.FormRow, { label: "Variant" },
155
+ React.createElement(VariantSelector_1.VariantSelector, { onChange: handleVariantChange, theme: currentThemeObject })),
169
156
  fields.map((field) => {
170
- return (React.createElement(Field, { disabled: disabled, key: field.name, type: field.type, name: field.name, value: valuesFromTheme[field.variable], variable: field.variable, onChange: (val) => {
157
+ return (React.createElement(ThemeField_1.Field, { disabled: disabled, key: field.name, type: field.type, name: field.name, value: valuesFromTheme[field.variable], variable: field.variable, onChange: (val) => {
171
158
  // needs a fresh copy
172
159
  const currentThemeObject = adaptable.api.themeApi.getCurrentThemeObject();
173
160
  let newTheme = null;
@@ -0,0 +1,2 @@
1
+ import * as React from 'react';
2
+ export declare const ThemeEditorWindow: React.FunctionComponent;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ThemeEditorWindow = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const React = tslib_1.__importStar(require("react"));
6
+ const rebass_1 = require("rebass");
7
+ const AdaptableContext_1 = require("../AdaptableContext");
8
+ const ThemePopup_1 = require("./ThemePopup");
9
+ const ThemeEditorWindow = () => {
10
+ const adaptable = (0, AdaptableContext_1.useAdaptable)();
11
+ const moduleInfo = adaptable.ModuleService.getModuleInfoByModule('Theme');
12
+ return (React.createElement(rebass_1.Box, { p: 2 },
13
+ React.createElement(ThemePopup_1.ThemePopup, { hideShowInWindow: true, moduleInfo: moduleInfo, api: adaptable.api })));
14
+ };
15
+ exports.ThemeEditorWindow = ThemeEditorWindow;
@@ -0,0 +1,11 @@
1
+ import * as React from 'react';
2
+ import { FieldType } from './ThemeEditor';
3
+ export interface FieldProps {
4
+ type: FieldType;
5
+ name: string;
6
+ value: string;
7
+ variable: string;
8
+ onChange: (newVal: string | false) => void;
9
+ disabled: boolean;
10
+ }
11
+ export declare const Field: React.FunctionComponent<FieldProps>;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Field = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const React = tslib_1.__importStar(require("react"));
6
+ const throttle_1 = tslib_1.__importDefault(require("lodash/throttle"));
7
+ const AdaptableContext_1 = require("../AdaptableContext");
8
+ const StyleHelper_1 = require("../../Utilities/Helpers/StyleHelper");
9
+ const FormLayout_1 = require("../../components/FormLayout");
10
+ const SimpleButton_1 = tslib_1.__importDefault(require("../../components/SimpleButton"));
11
+ const rebass_1 = require("rebass");
12
+ const ColorPicker_1 = require("../../components/ColorPicker");
13
+ const AdaptableInput_1 = tslib_1.__importDefault(require("../Components/AdaptableInput"));
14
+ const Field = (props) => {
15
+ const adaptable = (0, AdaptableContext_1.useAdaptable)();
16
+ let input = null;
17
+ let value = props.value;
18
+ const throttledOnChange = React.useMemo(() => {
19
+ return (0, throttle_1.default)((value) => {
20
+ props.onChange(value);
21
+ }, 300);
22
+ }, []);
23
+ if (value === undefined) {
24
+ value = (0, StyleHelper_1.getVariableColor)(`var(${props.variable})`);
25
+ }
26
+ switch (props.type) {
27
+ case 'number':
28
+ input = (React.createElement(AdaptableInput_1.default, { disabled: props.disabled, type: "number", onChange: (event) => throttledOnChange(event.target.value), value: value }));
29
+ break;
30
+ case 'color':
31
+ input = (React.createElement(ColorPicker_1.ColorPicker, { disabled: props.disabled, includeAlpha: false, api: adaptable.api, value: value, onChange: (color) => throttledOnChange(color) }));
32
+ break;
33
+ }
34
+ return (React.createElement(FormLayout_1.FormRow, { label: props.name },
35
+ React.createElement(rebass_1.Flex, null,
36
+ input,
37
+ ' ',
38
+ React.createElement(SimpleButton_1.default, { disabled: props.value === undefined, onClick: () => props.onChange(false) }, "Clear"))));
39
+ };
40
+ exports.Field = Field;
@@ -6,6 +6,7 @@ interface ThemePopupProps extends ModuleViewPopupProps<ThemePopupComponent> {
6
6
  CurrentTheme: string;
7
7
  UserThemes: AdaptableTheme[];
8
8
  SelectTheme: (newTheme: string) => ThemeRedux.ThemeSelectAction;
9
+ hideShowInWindow?: boolean;
9
10
  }
10
11
  declare class ThemePopupComponent extends React.Component<ThemePopupProps, {}> {
11
12
  render(): JSX.Element;
@@ -12,6 +12,7 @@ const ThemeEditor_1 = require("./ThemeEditor");
12
12
  const rebass_1 = require("rebass");
13
13
  const ButtonNew_1 = require("../Components/Buttons/ButtonNew");
14
14
  const ObjectFactory_1 = tslib_1.__importDefault(require("../../Utilities/ObjectFactory"));
15
+ const SimpleButton_1 = tslib_1.__importDefault(require("../../components/SimpleButton"));
15
16
  class ThemePopupComponent extends React.Component {
16
17
  constructor() {
17
18
  super(...arguments);
@@ -49,7 +50,11 @@ class ThemePopupComponent extends React.Component {
49
50
  const isCustomTheme = this.props.api.themeApi
50
51
  .getUserThemes()
51
52
  .some((theme) => theme.Name === this.props.CurrentTheme);
52
- return (React.createElement(PopupPanel_1.PopupPanel, { headerText: this.props.moduleInfo.FriendlyName, glyphicon: this.props.moduleInfo.Glyph, infoLink: this.props.moduleInfo.HelpPage, infoLinkDisabled: !this.props.api.internalApi.isDocumentationLinksDisplayed(), button: React.createElement(ButtonNew_1.ButtonNew, { ml: 2, onClick: this.handleCreateNewTheme, accessLevel: this.props.accessLevel }) },
53
+ return (React.createElement(PopupPanel_1.PopupPanel, { headerText: this.props.moduleInfo.FriendlyName, glyphicon: this.props.moduleInfo.Glyph, infoLink: this.props.moduleInfo.HelpPage, infoLinkDisabled: !this.props.api.internalApi.isDocumentationLinksDisplayed(), button: React.createElement(React.Fragment, null,
54
+ !this.props.hideShowInWindow && (React.createElement(SimpleButton_1.default, { icon: "open-in-new", onClick: () => {
55
+ this.props.api.themeApi.internalApi.openInWindow();
56
+ } })),
57
+ React.createElement(ButtonNew_1.ButtonNew, { ml: 2, onClick: this.handleCreateNewTheme, accessLevel: this.props.accessLevel })) },
53
58
  React.createElement(FormLayout_1.default, null,
54
59
  React.createElement(FormLayout_1.FormRow, { label: "Current Theme:" },
55
60
  React.createElement(DropdownButton_1.default, { "data-name": "select-theme-dropdown", columns: ['label'], style: { width: '50%', minWidth: 200 }, placeholder: "Select theme", value: this.props.CurrentTheme, items: optionThemes, accessLevel: this.props.accessLevel }, currentThemeDescription))),
@@ -0,0 +1,7 @@
1
+ import * as React from 'react';
2
+ import { AdaptableTheme } from '../../types';
3
+ export interface VariantSelectorProps {
4
+ theme: AdaptableTheme;
5
+ onChange: (variant: AdaptableTheme['Variant'] | null) => void;
6
+ }
7
+ export declare const VariantSelector: React.FunctionComponent<VariantSelectorProps>;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VariantSelector = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const React = tslib_1.__importStar(require("react"));
6
+ const DropdownButton_1 = tslib_1.__importDefault(require("../../components/DropdownButton"));
7
+ const SimpleButton_1 = tslib_1.__importDefault(require("../../components/SimpleButton"));
8
+ const AdaptableContext_1 = require("../AdaptableContext");
9
+ const VariantSelector = (props) => {
10
+ var _a;
11
+ const adaptable = (0, AdaptableContext_1.useAdaptable)();
12
+ const systemTemes = adaptable.api.themeApi.getSystemThemes();
13
+ const options = systemTemes.map((theme) => ({
14
+ label: theme.Description,
15
+ value: theme.Name,
16
+ onClick: () => props.onChange(theme.Name),
17
+ }));
18
+ const label = props.theme.Variant
19
+ ? (_a = options.find((theme) => theme.value === props.theme.Variant)) === null || _a === void 0 ? void 0 : _a.label
20
+ : 'Select a theme';
21
+ return (React.createElement(React.Fragment, null,
22
+ React.createElement(DropdownButton_1.default, { mr: 2, columns: ['label'], items: options }, label),
23
+ React.createElement(SimpleButton_1.default, { onClick: () => props.onChange(null), disabled: !props.theme.Variant, icon: "delete" })));
24
+ };
25
+ exports.VariantSelector = VariantSelector;
@@ -4300,6 +4300,7 @@ class Adaptable {
4300
4300
  }
4301
4301
  applyAdaptableTheme(theme) {
4302
4302
  const themeName = typeof theme === 'string' ? theme : theme.Name;
4303
+ const isSystemTheme = this.api.themeApi.internalApi.isSystemTheme(themeName);
4303
4304
  const themeClassNamesToRemove = [];
4304
4305
  const themesToRemove = [];
4305
4306
  const allThemes = this.api.themeApi.getThemes().map((t) => {
@@ -4312,6 +4313,8 @@ class Adaptable {
4312
4313
  acc[theme.Name] = theme;
4313
4314
  return acc;
4314
4315
  }, {});
4316
+ const themeObject = allThemesMap[themeName];
4317
+ // REMOVE PREVIOUS THEME
4315
4318
  // const themePrefix = 'ab--theme-'
4316
4319
  const el = document.documentElement;
4317
4320
  el.classList.forEach((cssClassName) => {
@@ -4329,37 +4332,34 @@ class Adaptable {
4329
4332
  themesToRemove.forEach((theme) => {
4330
4333
  el.classList.remove(`infinite-${theme.Name}`);
4331
4334
  });
4332
- if (this.adaptableOptions.userInterfaceOptions &&
4333
- this.adaptableOptions.userInterfaceOptions.useCustomMacLikeScrollbars &&
4334
- (0, getScrollbarSize_1.default)() > 0) {
4335
- el.classList.add('ab--custom-mac-like-scrollbars');
4336
- }
4337
- else {
4338
- el.classList.remove('ab--custom-mac-like-scrollbars');
4335
+ // VARIANT
4336
+ let vairantTheme = '';
4337
+ if (!isSystemTheme && themeObject.Variant) {
4338
+ vairantTheme = themeObject.Variant;
4339
4339
  }
4340
+ // APPLY NEW THEME
4340
4341
  const newTheme = allThemesMap[themeName];
4341
- const newThemeClassName = GeneralConstants.THEME_STYLE + themeName;
4342
- el.classList.add(newThemeClassName);
4343
- // add infinite table classname for theme
4344
- el.classList.add(`infinite-${themeName}`);
4345
- const computedDocumentStyle = getComputedStyle(el);
4346
- const [abLoaded, abThemeLoaded] = ['--ab-loaded', '--ab-theme-loaded'].map((variable) => {
4347
- let val = computedDocumentStyle.getPropertyValue(variable);
4348
- if (typeof val === 'string' && val.trim) {
4349
- val = val.trim();
4350
- }
4351
- return val;
4352
- });
4353
- const systemThemes = this.api.themeApi.getSystemThemes();
4354
- const isSystemTheme = !!systemThemes.filter((t) => t.Name === themeName)[0];
4342
+ const getClassName = (theme) => GeneralConstants.THEME_STYLE + theme;
4343
+ el.classList.add(getClassName(themeName));
4344
+ if (vairantTheme) {
4345
+ el.classList.add(getClassName(vairantTheme));
4346
+ }
4347
+ if (isSystemTheme) {
4348
+ // add infinite table classname for theme
4349
+ el.classList.add(`infinite-${themeName}`);
4350
+ }
4351
+ else if (vairantTheme) {
4352
+ el.classList.add(`infinite-${vairantTheme}`);
4353
+ }
4354
+ // AG THEME CLASS NAME
4355
4355
  const container = this.getAgGridContainerElement();
4356
4356
  const getAgGridLightThemeName = () => this.getAgGridLightThemeName();
4357
4357
  const getAgGridDarkThemeName = () => getAgGridLightThemeName() + '-dark';
4358
- if (newTheme && isSystemTheme) {
4359
- if (themeName === GeneralConstants_1.LIGHT_THEME) {
4358
+ if (newTheme && (isSystemTheme || vairantTheme)) {
4359
+ if ((vairantTheme !== null && vairantTheme !== void 0 ? vairantTheme : themeName) === GeneralConstants_1.LIGHT_THEME) {
4360
4360
  newTheme.AgGridClassName = newTheme.AgGridClassName || getAgGridLightThemeName();
4361
4361
  }
4362
- if (themeName === GeneralConstants_1.DARK_THEME) {
4362
+ if ((vairantTheme !== null && vairantTheme !== void 0 ? vairantTheme : themeName) === GeneralConstants_1.DARK_THEME) {
4363
4363
  newTheme.AgGridClassName = newTheme.AgGridClassName || getAgGridDarkThemeName();
4364
4364
  }
4365
4365
  }
@@ -4391,6 +4391,23 @@ class Adaptable {
4391
4391
  container.classList.add('ab-Grid--indicate-filtered-columns');
4392
4392
  }
4393
4393
  }
4394
+ // MAC LIKE SCROLLBARS
4395
+ if (this.adaptableOptions.userInterfaceOptions &&
4396
+ this.adaptableOptions.userInterfaceOptions.useCustomMacLikeScrollbars &&
4397
+ (0, getScrollbarSize_1.default)() > 0) {
4398
+ el.classList.add('ab--custom-mac-like-scrollbars');
4399
+ }
4400
+ else {
4401
+ el.classList.remove('ab--custom-mac-like-scrollbars');
4402
+ }
4403
+ const computedDocumentStyle = getComputedStyle(el);
4404
+ const [abLoaded, abThemeLoaded] = ['--ab-loaded', '--ab-theme-loaded'].map((variable) => {
4405
+ let val = computedDocumentStyle.getPropertyValue(variable);
4406
+ if (typeof val === 'string' && val.trim) {
4407
+ val = val.trim();
4408
+ }
4409
+ return val;
4410
+ });
4394
4411
  if (abLoaded !== '777') {
4395
4412
  (0, LoggingHelper_1.ConsoleLogError)('Please import Adaptable styles from "@adaptabletools/adaptable/index.css"');
4396
4413
  }