From d33d387158957a84fd399a60ee50cf07a3286d5f Mon Sep 17 00:00:00 2001
From: webviewer-ui <72055195+webviewer-ui@users.noreply.github.com>
Date: Wed, 5 Jun 2024 09:42:18 -0700
Subject: [PATCH] =?UTF-8?q?[Bugfix]=20Modular=20UI=20-=20Fixing=20Custom?=
=?UTF-8?q?=20and=20Toggle=20button=20styles=20(#9067)=20(master=20?=
=?UTF-8?q?=E2=86=92=20master)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.storybook/main.js | 40 ++++++--
package.json | 3 +-
.../AppStories/App.stories.js | 99 +++++++++----------
.../CustomButton/CustomButton.scss | 57 +++++++++++
.../CustomButton/CustomButton.stories.js | 72 ++++++++++++++
.../ToggleElementButton.scss | 10 +-
.../ToggleElementButton.stories.js | 17 +++-
7 files changed, 232 insertions(+), 66 deletions(-)
create mode 100644 src/components/ModularComponents/CustomButton/CustomButton.scss
create mode 100644 src/components/ModularComponents/CustomButton/CustomButton.stories.js
diff --git a/.storybook/main.js b/.storybook/main.js
index fbcd8d2f2..4887d385b 100644
--- a/.storybook/main.js
+++ b/.storybook/main.js
@@ -3,15 +3,19 @@ const path = require('path');
const appDirectory = path.join(__dirname, '..');
module.exports = {
- stories: [
- "../src/**/*.stories.mdx",
- "../src/**/*.stories.@(js|jsx|ts|tsx)"
- ],
+ stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
staticDirs: ['./static'],
+
addons: [
"@storybook/addon-links",
- "@storybook/addon-essentials"
+ "@storybook/addon-essentials",
+ '@storybook/addon-webpack5-compiler-swc',
+ '@chromatic-com/storybook',
+ '@storybook/addon-interactions',
+ '@storybook/addon-a11y',
+ 'storybook-addon-pseudo-states'
],
+
webpackFinal: async (config, { configType }) => {
// `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
// You can change the configuration based on that.
@@ -72,5 +76,29 @@ module.exports = {
return config;
},
- framework: '@storybook/react',
+
+ framework: {
+ name: '@storybook/react-webpack5',
+ options: {}
+ },
+
+ docs: {},
+
+ swcLoaderOptions: {
+ jsc: {
+ parser: {
+ syntax: 'ecmascript',
+ jsx: true,
+ },
+ transform: {
+ react: {
+ runtime: 'automatic'
+ }
+ }
+ }
+ },
+
+ typescript: {
+ reactDocgen: 'react-docgen-typescript'
+ }
}
diff --git a/package.json b/package.json
index 8f483576d..08d0b8860 100644
--- a/package.json
+++ b/package.json
@@ -130,6 +130,7 @@
"sass": "^1.34.0",
"sass-loader": "^8.0.2",
"storybook": "^8.1.0",
+ "storybook-addon-pseudo-states": "^3.1.1",
"style-loader": "^1.1.3",
"svg-inline-loader": "^0.8.0",
"typescript": "^5.4.5",
@@ -139,4 +140,4 @@
"webpack-dev-middleware": "^7.2.1",
"webpack-hot-middleware": "^2.26.1"
}
-}
\ No newline at end of file
+}
diff --git a/src/components/ModularComponents/AppStories/App.stories.js b/src/components/ModularComponents/AppStories/App.stories.js
index 66044b485..09526fff1 100644
--- a/src/components/ModularComponents/AppStories/App.stories.js
+++ b/src/components/ModularComponents/AppStories/App.stories.js
@@ -1,67 +1,62 @@
-import React from 'react';
-import { Provider } from 'react-redux';
-import { configureStore } from '@reduxjs/toolkit';
import App from 'components/App';
-import initialState from 'src/redux/initialState';
-import rootReducer from 'reducers/rootReducer';
import { mockHeadersNormalized, mockModularComponents } from './mockAppState';
+import { userEvent, within, expect } from '@storybook/test';
+import { createTemplate } from 'helpers/storybookHelper';
export default {
title: 'ModularComponents/App',
component: App,
+ includeStories: ['DefaultUI', 'ActiveGroupHeaderTest', 'HeaderButtonsWithLabelsAndIcons'],
+ excludeStories: ['CreateTemplate'],
};
-const noop = () => { };
+export const DefaultUI = createTemplate({ headers: mockHeadersNormalized, components: mockModularComponents });
-const MockApp = ({ initialState }) => {
- return (
- getDefaultMiddleware({ serializableCheck: false })
- })}>
-
-
- );
+export const ActiveGroupHeaderTest = createTemplate({ headers: mockHeadersNormalized, components: mockModularComponents });
+ActiveGroupHeaderTest.play = async ({ canvasElement }) => {
+ const canvas = within(canvasElement);
+ // We should be able to find the underline button since the default selected group is annotateGroupedItems
+ await canvas.findAllByRole('button', { name: 'Underline' });
+ // Now if we click on ribbon
+ const viewRibbon = await canvas.findByLabelText('View');
+ await userEvent.click(viewRibbon);
+ // the underline button should not be visible anymore as the header is hidden
+ expect(await canvas.queryByRole('button', { name: 'Underline' })).toBeNull();
};
-const Template = (args) => {
- const stateWithHeaders = {
- ...initialState,
- viewer: {
- ...initialState.viewer,
- modularHeaders: args.headers,
- modularComponents: args.components,
- openElements: {},
- genericPanels: [{
- dataElement: 'stylePanel',
- render: 'stylePanel',
- location: 'left',
- }],
- activeGroupedItems: ['annotateGroupedItems'],
- lastPickedToolForGroupedItems: {
- annotateGroupedItems: 'AnnotationCreateTextUnderline',
- },
- activeCustomRibbon: 'annotations-ribbon-item',
- lastPickedToolAndGroup: {
- tool: 'AnnotationCreateTextUnderline',
- group: ['annotateGroupedItems'],
- },
- activeToolName: 'AnnotationCreateTextUnderline'
- },
- featureFlags: {
- customizableUI: true,
- },
- };
- return ;
+const customHeaders = {
+ ...mockHeadersNormalized,
+ 'default-top-header': {
+ ...mockHeadersNormalized['default-top-header'],
+ 'items': [
+ ...mockHeadersNormalized['default-top-header'].items,
+ 'labelButton',
+ 'labelAndIconButton'
+ ]
+ }
};
-function createTemplate({ headers, components }) {
- const template = Template.bind({});
- template.args = { headers, components };
- template.parameters = { layout: 'fullscreen' };
- return template;
-}
+const labelAndIconButton = {
+ 'dataElement': 'labelAndIconButton',
+ 'title': 'Export button',
+ 'type': 'customButton',
+ 'label': 'Export',
+ 'img': 'icon-save',
+ 'onClick': () => {},
+};
-export const DefaultUI = createTemplate({ headers: mockHeadersNormalized, components: mockModularComponents });
+const labelButton = {
+ 'dataElement': 'labelButton',
+ 'title': 'Toggle the visibility of Flyout',
+ 'type': 'toggleButton',
+ 'label': 'Custom Flyout',
+ 'toggleElement': 'myCustomFlyout'
+};
+
+const customComponents = {
+ ...mockModularComponents,
+ 'labelAndIconButton': labelAndIconButton,
+ 'labelButton': labelButton
+};
+export const HeaderButtonsWithLabelsAndIcons = createTemplate({ headers: customHeaders, components: customComponents });
\ No newline at end of file
diff --git a/src/components/ModularComponents/CustomButton/CustomButton.scss b/src/components/ModularComponents/CustomButton/CustomButton.scss
new file mode 100644
index 000000000..e8ea021c1
--- /dev/null
+++ b/src/components/ModularComponents/CustomButton/CustomButton.scss
@@ -0,0 +1,57 @@
+@import '../../../constants/styles';
+
+.CustomButton {
+ padding: 5px;
+ width: fit-content;
+ min-width: 32px;
+
+ &:hover,
+ &:active {
+ @extend %custom-button-hover;
+ }
+
+ &:active {
+ color: var(--view-header-icon-active-fill);
+ cursor: default;
+
+ .Icon svg path {
+ fill: var(--view-header-icon-active-fill)
+ }
+ }
+}
+
+.confirm-button {
+ background-color: var(--primary-button);
+ border: 1px solid var(--primary-button);
+ color: var(--primary-button-text);
+ padding: 7px 14px;
+ width: -webkit-fit-content;
+ width: -moz-fit-content;
+ width: fit-content;
+ border-radius: 5px;
+ height: 30px;
+ cursor: pointer;
+
+ &:hover {
+ background: var(--primary-button-hover) !important;
+ border: 1px solid var(--primary-button-hover) !important;
+ border-radius: 5px !important;
+ }
+}
+
+.cancel-button {
+ color: var(--secondary-button-text);
+ background-color: transparent;
+ padding: 7px 14px;
+ width: -webkit-fit-content;
+ width: -moz-fit-content;
+ width: fit-content;
+ border-radius: 5px;
+ height: 30px;
+ cursor: pointer;
+
+ &:hover {
+ color: var(--secondary-button-hover);
+ background: transparent;
+ }
+}
\ No newline at end of file
diff --git a/src/components/ModularComponents/CustomButton/CustomButton.stories.js b/src/components/ModularComponents/CustomButton/CustomButton.stories.js
new file mode 100644
index 000000000..8533a40e7
--- /dev/null
+++ b/src/components/ModularComponents/CustomButton/CustomButton.stories.js
@@ -0,0 +1,72 @@
+import React from 'react';
+import CustomButton from './CustomButton';
+import initialState from 'src/redux/initialState';
+import { Provider } from 'react-redux';
+import { configureStore } from '@reduxjs/toolkit';
+
+export default {
+ title: 'Components/CustomButton',
+ component: CustomButton,
+};
+
+const store = configureStore({
+ reducer: () => initialState
+});
+
+const BasicComponent = (props) => {
+ return (
+
+
+
+ );
+};
+
+export const DefaultButton = BasicComponent.bind({});
+DefaultButton.args = {
+ dataElement: 'button-data-element',
+ title: 'Button title',
+ disabled: false,
+ label: 'Click',
+ img: 'icon-save',
+ onClick: () => {
+ alert('Clicked!');
+ }
+};
+
+export const DefaultButtonOnHover = BasicComponent.bind({});
+DefaultButtonOnHover.args = {
+ dataElement: 'button-data-element',
+ title: 'Button title',
+ disabled: false,
+ label: 'Click',
+ img: 'icon-save',
+ onClick: () => {
+ alert('Clicked!');
+ }
+};
+
+DefaultButtonOnHover.parameters = {
+ pseudo: { hover: true },
+};
+
+export const ConfirmButton = BasicComponent.bind({});
+ConfirmButton.args = {
+ dataElement: 'button-data-element',
+ title: 'Apply Fields',
+ label: 'Apply Fields',
+ preset: 'confirm',
+ onClick: () => {
+ alert('Apply Fields button clicked!');
+ }
+};
+
+export const CancelButton = BasicComponent.bind({});
+CancelButton.args = {
+ dataElement: 'button-data-element',
+ title: 'Cancel',
+ label: 'Cancel',
+ preset: 'cancel',
+ onClick: () => {
+ alert('Cancel button clicked!');
+ }
+};
\ No newline at end of file
diff --git a/src/components/ModularComponents/ToggleElementButton/ToggleElementButton.scss b/src/components/ModularComponents/ToggleElementButton/ToggleElementButton.scss
index a17071a88..cddbf9f8d 100644
--- a/src/components/ModularComponents/ToggleElementButton/ToggleElementButton.scss
+++ b/src/components/ModularComponents/ToggleElementButton/ToggleElementButton.scss
@@ -2,15 +2,17 @@
.ToggleElementButton {
.Button {
- width: 32px;
+ width: auto;
+ min-width: 32px;
height: 32px;
+ padding: 5px;
- &:hover {
- background: var(--tools-button-hover);
+ &:hover,
+ &.active {
+ @extend %custom-button-hover;
}
&.active {
- background: var(--tools-button-active);
color: var(--view-header-icon-active-fill);
cursor: default;
diff --git a/src/components/ModularComponents/ToggleElementButton/ToggleElementButton.stories.js b/src/components/ModularComponents/ToggleElementButton/ToggleElementButton.stories.js
index 7bad08a54..ee64334de 100644
--- a/src/components/ModularComponents/ToggleElementButton/ToggleElementButton.stories.js
+++ b/src/components/ModularComponents/ToggleElementButton/ToggleElementButton.stories.js
@@ -6,6 +6,9 @@ import { Provider } from 'react-redux';
export default {
title: 'ModularComponents/ToggleElementButton',
component: ToggleElementButton,
+ parameters: {
+ customizableUI: true,
+ },
};
const initialState = {
@@ -44,8 +47,16 @@ const store = configureStore({
export const ToggleElementButtonComponent = () => (
-
-
-
+
);
+
+export const ToggleElementButtonWithLabelOnHoverState = () => (
+
+
+
+);
+
+ToggleElementButtonWithLabelOnHoverState.parameters = {
+ pseudo: { hover: true },
+};