From 3ebb213a0bd02cc2882185b40d724d941333ef55 Mon Sep 17 00:00:00 2001 From: Arturo Reuschenbach Date: Fri, 24 May 2024 11:27:44 +0200 Subject: [PATCH] [migration] remove migrated libs (#608) --- libs/communicator/.gitignore | 1 - libs/communicator/LICENSE | 201 --- libs/communicator/README.md | 172 -- libs/communicator/dev/build.js | 183 -- libs/communicator/dev/build.js.map | 7 - libs/communicator/dev/index.html | 113 -- libs/communicator/dev/index.js | 170 -- libs/communicator/esbuild.config.js | 51 - libs/communicator/package.json | 41 - libs/communicator/src/index.js | 290 ---- libs/communicator/src/index.test.js | 216 --- libs/juno-ui-components/.gitignore | 3 - libs/juno-ui-components/.npmignore | 9 - libs/juno-ui-components/.storybook/.babelrc | 8 - .../.storybook/juno-addon/Decorator.jsx | 52 - .../.storybook/juno-addon/DocsContainer.jsx | 32 - .../.storybook/juno-addon/README.md | 41 - .../.storybook/juno-addon/ThemeToggle.jsx | 46 - .../.storybook/juno-addon/constants.js | 17 - .../.storybook/juno-addon/manager.js | 22 - .../.storybook/juno-addon/preview.js | 29 - .../.storybook/juno-addon/themes.js | 117 -- libs/juno-ui-components/.storybook/main.js | 93 - libs/juno-ui-components/.storybook/preview.js | 111 -- libs/juno-ui-components/LICENSE | 201 --- libs/juno-ui-components/README.md | 57 - libs/juno-ui-components/babel.config.json | 9 - libs/juno-ui-components/lib/variables.scss | 635 ------- libs/juno-ui-components/package.json | 112 -- libs/juno-ui-components/postcss.config.js | 8 - libs/juno-ui-components/rollup.config.js | 153 -- libs/juno-ui-components/setupTests.js | 48 - .../components/AppBody/AppBody.component.js | 37 - .../src/components/AppBody/AppBody.stories.js | 35 - .../src/components/AppBody/AppBody.test.js | 59 - .../src/components/AppBody/index.js | 6 - .../components/AppIntro/AppIntro.component.js | 34 - .../components/AppIntro/AppIntro.stories.js | 40 - .../src/components/AppIntro/AppIntro.test.js | 41 - .../src/components/AppIntro/index.js | 6 - .../components/AppShell/AppShell.component.js | 121 -- .../components/AppShell/AppShell.stories.js | 202 --- .../src/components/AppShell/AppShell.test.js | 143 -- .../src/components/AppShell/index.js | 6 - .../AppShellProvider.component.js | 61 - .../AppShellProvider.stories.js | 128 -- .../AppShellProvider/AppShellProvider.test.js | 20 - .../src/components/AppShellProvider/index.js | 6 - .../src/components/Badge/Badge.component.js | 135 -- .../src/components/Badge/Badge.stories.js | 103 -- .../src/components/Badge/Badge.test.js | 82 - .../src/components/Badge/index.js | 6 - .../src/components/Box/Box.component.js | 52 - .../src/components/Box/Box.stories.js | 41 - .../src/components/Box/Box.test.js | 46 - .../src/components/Box/index.js | 6 - .../Breadcrumb/Breadcrumb.component.js | 51 - .../Breadcrumb/Breadcrumb.stories.js | 40 - .../components/Breadcrumb/Breadcrumb.test.js | 32 - .../src/components/Breadcrumb/index.js | 6 - .../BreadcrumbItem.component.js | 113 -- .../BreadcrumbItem/BreadcrumbItem.stories.js | 110 -- .../BreadcrumbItem/BreadcrumbItem.test.js | 88 - .../src/components/BreadcrumbItem/index.js | 6 - .../src/components/Button/Button.component.js | 241 --- .../src/components/Button/Button.stories.js | 453 ----- .../src/components/Button/Button.test.js | 140 -- .../src/components/Button/button.scss | 73 - .../src/components/Button/index.js | 6 - .../ButtonRow/ButtonRow.component.js | 40 - .../components/ButtonRow/ButtonRow.stories.js | 39 - .../components/ButtonRow/ButtonRow.test.js | 38 - .../src/components/ButtonRow/index.js | 6 - .../components/Checkbox/Checkbox.component.js | 380 ---- .../components/Checkbox/Checkbox.stories.js | 97 -- .../src/components/Checkbox/Checkbox.test.js | 174 -- .../src/components/Checkbox/index.js | 6 - .../CheckboxGroup/CheckboxGroup.component.js | 271 --- .../CheckboxGroup/CheckboxGroup.stories.js | 213 --- .../CheckboxGroup/CheckboxGroup.test.js | 202 --- .../src/components/CheckboxGroup/index.js | 6 - .../CheckboxRow/CheckboxRow.component.js | 103 -- .../CheckboxRow/CheckboxRow.stories.js | 106 -- .../CheckboxRow/CheckboxRow.test.js | 117 -- .../src/components/CheckboxRow/index.js | 6 - .../src/components/Code/Code.component.js | 35 - .../src/components/Code/Code.stories.js | 46 - .../src/components/Code/Code.test.js | 50 - .../src/components/Code/index.js | 6 - .../CodeBlock/CodeBlock.component.js | 224 --- .../components/CodeBlock/CodeBlock.stories.js | 210 --- .../components/CodeBlock/CodeBlock.test.js | 185 -- .../src/components/CodeBlock/index.js | 6 - .../components/ComboBox/ComboBox.component.js | 534 ------ .../components/ComboBox/ComboBox.stories.js | 886 ---------- .../src/components/ComboBox/ComboBox.test.js | 401 ----- .../src/components/ComboBox/index.js | 6 - .../ComboBoxOption.component.js | 123 -- .../ComboBoxOption/ComboBoxOption.stories.js | 47 - .../ComboBoxOption/ComboBoxOption.test.js | 98 -- .../src/components/ComboBoxOption/index.js | 6 - .../Container/Container.component.js | 51 - .../components/Container/Container.stories.js | 60 - .../components/Container/Container.test.js | 64 - .../src/components/Container/index.js | 6 - .../ContentArea/ContentArea.component.js | 44 - .../ContentArea/ContentArea.stories.js | 33 - .../ContentArea/ContentArea.test.js | 74 - .../src/components/ContentArea/index.js | 6 - .../ContentAreaToolbar.component.js | 46 - .../ContentAreaToolbar.stories.js | 40 - .../ContentAreaToolbar.test.js | 50 - .../components/ContentAreaToolbar/index.js | 6 - .../ContentAreaWrapper.component.js | 40 - .../ContentAreaWrapper.stories.js | 44 - .../ContentAreaWrapper.test.js | 62 - .../components/ContentAreaWrapper/index.js | 6 - .../ContentContainer.component.js | 40 - .../ContentContainer.stories.js | 35 - .../ContentContainer/ContentContainer.test.js | 51 - .../src/components/ContentContainer/index.js | 6 - .../ContentHeading.component.js | 44 - .../ContentHeading/ContentHeading.stories.js | 33 - .../ContentHeading/ContentHeading.test.js | 58 - .../src/components/ContentHeading/index.js | 6 - .../ContextMenu/ContextMenu.component.js | 94 - .../ContextMenu/ContextMenu.stories.js | 98 -- .../ContextMenu/ContextMenu.test.js | 28 - .../src/components/ContextMenu/index.js | 6 - .../components/DataGrid/DataGrid.component.js | 105 -- .../components/DataGrid/DataGrid.stories.js | 242 --- .../src/components/DataGrid/DataGrid.test.js | 23 - .../src/components/DataGrid/index.js | 6 - .../DataGridCell/DataGridCell.component.js | 77 - .../DataGridCell/DataGridCell.stories.js | 85 - .../DataGridCell/DataGridCell.test.js | 24 - .../src/components/DataGridCell/index.js | 6 - .../DataGridCheckboxCell.component.js | 41 - .../DataGridCheckboxCell.stories.js | 65 - .../DataGridCheckboxCell.test.js | 39 - .../components/DataGridCheckboxCell/index.js | 6 - .../DataGridFoot/DataGridFoot.component.js | 31 - .../DataGridFoot/DataGridFoot.stories.js | 53 - .../DataGridFoot/DataGridFoot.test.js | 27 - .../src/components/DataGridFoot/index.js | 6 - .../DataGridHeadCell.component.js | 74 - .../DataGridHeadCell.stories.js | 85 - .../DataGridHeadCell/DataGridHeadCell.test.js | 23 - .../src/components/DataGridHeadCell/index.js | 6 - .../DataGridRow/DataGridRow.component.js | 65 - .../DataGridRow/DataGridRow.stories.js | 59 - .../DataGridRow/DataGridRow.test.js | 24 - .../src/components/DataGridRow/index.js | 6 - .../DataGridToolbar.component.js | 56 - .../DataGridToolbar.stories.js | 68 - .../DataGridToolbar/DataGridToolbar.test.js | 35 - .../src/components/DataGridToolbar/index.js | 6 - .../components/DataList/DataList.component.js | 46 - .../components/DataList/DataList.stories.js | 160 -- .../src/components/DataList/DataList.test.js | 23 - .../src/components/DataList/index.js | 6 - .../DataListCell/DataListCell.component.js | 151 -- .../DataListCell/DataListCell.stories.js | 42 - .../DataListCell/DataListCell.test.js | 23 - .../src/components/DataListCell/index.js | 6 - .../DataListCheckboxCell.component.js | 51 - .../DataListCheckboxCell.stories.js | 56 - .../DataListCheckboxCell.test.js | 30 - .../components/DataListCheckboxCell/index.js | 6 - .../DataListRow/DataListRow.component.js | 62 - .../DataListRow/DataListRow.stories.js | 160 -- .../DataListRow/DataListRow.test.js | 23 - .../src/components/DataListRow/index.js | 6 - .../DateTimePicker.component.js | 711 -------- .../DateTimePicker/DateTimePicker.stories.js | 500 ------ .../DateTimePicker/DateTimePicker.test.js | 684 -------- .../DateTimePicker/datetimepicker.scss | 831 --------- .../src/components/DateTimePicker/index.js | 6 - .../FilterInput/FilterInput.component.js | 232 --- .../FilterInput/FilterInput.stories.js | 50 - .../FilterInput/FilterInput.test.js | 281 --- .../src/components/FilterInput/index.js | 6 - .../FilterPill/FilterPill.component.js | 100 -- .../FilterPill/FilterPill.stories.js | 22 - .../components/FilterPill/FilterPill.test.js | 133 -- .../src/components/FilterPill/index.js | 6 - .../components/Filters/Filters.component.js | 167 -- .../src/components/Filters/Filters.stories.js | 121 -- .../src/components/Filters/Filters.test.js | 204 --- .../src/components/Filters/index.js | 6 - .../src/components/Form/Form.component.js | 50 - .../src/components/Form/Form.stories.js | 132 -- .../src/components/Form/Form.test.js | 41 - .../src/components/Form/index.js | 6 - .../components/FormHint/FormHint.component.js | 66 - .../components/FormHint/FormHint.stories.js | 69 - .../src/components/FormHint/FormHint.test.js | 70 - .../src/components/FormHint/index.js | 6 - .../components/FormRow/FormRow.component.js | 40 - .../src/components/FormRow/FormRow.stories.js | 28 - .../src/components/FormRow/FormRow.test.js | 34 - .../src/components/FormRow/index.js | 6 - .../FormSection/FormSection.component.js | 53 - .../FormSection/FormSection.stories.js | 57 - .../FormSection/FormSection.test.js | 41 - .../src/components/FormSection/index.js | 6 - .../src/components/Grid/Grid.component.js | 49 - .../src/components/Grid/Grid.stories.js | 159 -- .../src/components/Grid/Grid.test.js | 30 - .../src/components/Grid/index.js | 6 - .../GridColumn/GridColumn.component.js | 152 -- .../GridColumn/GridColumn.stories.js | 50 - .../components/GridColumn/GridColumn.test.js | 38 - .../src/components/GridColumn/index.js | 6 - .../components/GridRow/GridRow.component.js | 40 - .../src/components/GridRow/GridRow.stories.js | 46 - .../src/components/GridRow/GridRow.test.js | 22 - .../src/components/GridRow/index.js | 6 - .../src/components/Icon/Icon.component.js | 826 --------- .../src/components/Icon/Icon.stories.js | 403 ----- .../src/components/Icon/Icon.test.js | 381 ----- .../src/components/Icon/icons/home_sharp.svg | 6 - .../src/components/Icon/icons/juno-danger.svg | 8 - .../Icon/icons/juno_severity_critical.svg | 10 - .../Icon/icons/juno_severity_high.svg | 11 - .../Icon/icons/juno_severity_low.svg | 11 - .../Icon/icons/juno_severity_medium.svg | 11 - .../src/components/Icon/icons/place.svg | 6 - .../src/components/Icon/index.js | 6 - .../InputGroup/InputGroup.component.js | 56 - .../InputGroup/InputGroup.stories.js | 141 -- .../components/InputGroup/InputGroup.test.js | 105 -- .../src/components/InputGroup/index.js | 6 - .../components/InputGroup/input-group.scss | 32 - .../components/IntroBox/IntroBox.component.js | 114 -- .../components/IntroBox/IntroBox.stories.js | 48 - .../src/components/IntroBox/IntroBox.test.js | 99 -- .../src/components/IntroBox/index.js | 6 - .../JsonViewer/JsonViewer.component.js | 543 ------ .../JsonViewer/JsonViewer.stories.js | 110 -- .../components/JsonViewer/JsonViewer.test.js | 29 - .../src/components/JsonViewer/index.js | 6 - .../src/components/JsonViewer/themes.js | 42 - .../src/components/Label/Label.component.js | 113 -- .../src/components/Label/Label.stories.js | 33 - .../src/components/Label/Label.test.js | 57 - .../src/components/Label/index.js | 6 - .../LoadingIndicator.component.js | 44 - .../LoadingIndicator.stories.js | 37 - .../LoadingIndicator/LoadingIndicator.test.js | 44 - .../src/components/LoadingIndicator/index.js | 6 - .../LoadingIndicator/loading-indicator.svg | 37 - .../MainContainer/MainContainer.component.js | 44 - .../MainContainer/MainContainer.stories.js | 35 - .../MainContainer/MainContainer.test.js | 46 - .../src/components/MainContainer/index.js | 6 - .../MainContainerInner.component.js | 69 - .../MainContainerInner.test.js | 64 - .../components/MainContainerInner/index.js | 6 - .../components/MainTabs/MainTabs.component.js | 53 - .../components/MainTabs/MainTabs.stories.js | 99 -- .../src/components/MainTabs/MainTabs.test.js | 188 -- .../src/components/MainTabs/index.js | 6 - .../src/components/Menu/Menu.component.js | 83 - .../src/components/Menu/Menu.stories.js | 118 -- .../src/components/Menu/Menu.test.js | 55 - .../src/components/Menu/index.js | 6 - .../components/MenuItem/MenuItem.component.js | 133 -- .../components/MenuItem/MenuItem.stories.js | 114 -- .../src/components/MenuItem/MenuItem.test.js | 86 - .../src/components/MenuItem/index.js | 6 - .../MenuSection/MenuSection.component.js | 48 - .../MenuSection/MenuSection.stories.js | 44 - .../MenuSection/MenuSection.test.js | 18 - .../src/components/MenuSection/index.js | 6 - .../components/Message/Message.component.js | 237 --- .../src/components/Message/Message.stories.js | 65 - .../src/components/Message/Message.test.js | 184 -- .../src/components/Message/index.js | 6 - .../src/components/Modal/Modal.component.js | 276 --- .../src/components/Modal/Modal.stories.js | 228 --- .../src/components/Modal/Modal.test.js | 251 --- .../src/components/Modal/index.js | 6 - .../ModalFooter/ModalFooter.component.js | 99 -- .../ModalFooter/ModalFooter.stories.js | 59 - .../ModalFooter/ModalFooter.test.js | 80 - .../src/components/ModalFooter/index.js | 6 - .../NativeSelect/NativeSelect.component.js | 251 --- .../NativeSelect/NativeSelect.stories.js | 115 -- .../NativeSelect/NativeSelect.test.js | 123 -- .../src/components/NativeSelect/index.js | 6 - .../NativeSelectOption.component.js | 45 - .../NativeSelectOption.stories.js | 28 - .../NativeSelectOption/SelectOption.test.js | 47 - .../components/NativeSelectOption/index.js | 6 - .../NativeSelectOptionGroup.component.js | 44 - .../NativeSelectOptionGroup.stories.js | 62 - .../NativeSelectOptionGroup.test.js | 51 - .../NativeSelectOptionGroup/index.js | 6 - .../Navigation/Navigation.component.js | 134 -- .../Navigation/Navigation.stories.js | 155 -- .../components/Navigation/Navigation.test.js | 1524 ----------------- .../src/components/Navigation/index.js | 6 - .../NavigationItem.component.js | 216 --- .../NavigationItem/NavigationItem.stories.js | 75 - .../NavigationItem/NavigationItem.test.js | 150 -- .../src/components/NavigationItem/index.js | 6 - .../PageFooter/PageFooter.component.js | 57 - .../PageFooter/PageFooter.stories.js | 35 - .../components/PageFooter/PageFooter.test.js | 47 - .../src/components/PageFooter/index.js | 6 - .../PageHeader/PageHeader.component.js | 87 - .../PageHeader/PageHeader.stories.js | 49 - .../components/PageHeader/PageHeader.test.js | 55 - .../src/components/PageHeader/index.js | 6 - .../Pagination/Pagination.component.js | 168 -- .../Pagination/Pagination.stories.js | 78 - .../components/Pagination/Pagination.test.js | 106 -- .../src/components/Pagination/index.js | 6 - .../src/components/Panel/Panel.component.js | 163 -- .../src/components/Panel/Panel.stories.js | 57 - .../src/components/Panel/Panel.test.js | 81 - .../src/components/Panel/index.js | 6 - .../PanelBody/PanelBody.component.js | 46 - .../components/PanelBody/PanelBody.stories.js | 66 - .../components/PanelBody/PanelBody.test.js | 62 - .../src/components/PanelBody/index.js | 6 - .../PanelFooter/PanelFooter.component.js | 42 - .../PanelFooter/PanelFooter.stories.js | 53 - .../PanelFooter/PanelFooter.test.js | 49 - .../src/components/PanelFooter/index.js | 6 - .../src/components/Pill/Pill.component.js | 126 -- .../src/components/Pill/Pill.stories.js | 47 - .../src/components/Pill/Pill.test.js | 154 -- .../src/components/Pill/index.js | 6 - .../PortalProvider.component.js | 88 - .../PortalProvider/PortalProvider.stories.js | 67 - .../PortalProvider/PortalProvider.test.js | 40 - .../src/components/PortalProvider/index.js | 6 - .../src/components/Radio/Radio.component.js | 355 ---- .../src/components/Radio/Radio.stories.js | 108 -- .../src/components/Radio/Radio.test.js | 182 -- .../src/components/Radio/index.js | 6 - .../RadioGroup/RadioGroup.component.js | 267 --- .../RadioGroup/RadioGroup.stories.js | 226 --- .../components/RadioGroup/RadioGroup.test.js | 186 -- .../src/components/RadioGroup/index.js | 6 - .../components/RadioRow/RadioRow.component.js | 97 -- .../components/RadioRow/RadioRow.stories.js | 112 -- .../src/components/RadioRow/RadioRow.test.js | 111 -- .../src/components/RadioRow/index.js | 6 - .../SearchInput/SearchInput.component.js | 212 --- .../SearchInput/SearchInput.stories.js | 35 - .../SearchInput/SearchInput.test.js | 143 -- .../src/components/SearchInput/index.js | 6 - .../components/SearchInput/searchinput.scss | 6 - .../src/components/Select/Select.component.js | 479 ------ .../src/components/Select/Select.stories.js | 529 ------ .../src/components/Select/Select.test.js | 421 ----- .../src/components/Select/index.js | 6 - .../src/components/Select/select.scss | 84 - .../SelectDivider/SelectDivider.component.js | 31 - .../SelectDivider/SelectDivider.stories.js | 32 - .../SelectDivider/SelectDivider.test.js | 30 - .../src/components/SelectDivider/index.js | 6 - .../SelectOption/SelectOption.component.js | 127 -- .../SelectOption/SelectOption.stories.js | 62 - .../SelectOption/SelectOption.test.js | 98 -- .../src/components/SelectOption/index.js | 6 - .../SelectRow/SelectRow.component.js | 132 -- .../components/SelectRow/SelectRow.stories.js | 335 ---- .../components/SelectRow/SelectRow.test.js | 214 --- .../src/components/SelectRow/index.js | 6 - .../ShadowRoot/ShadowRoot.component.js | 83 - .../ShadowRoot/ShadowRoot.stories.js | 31 - .../src/components/ShadowRoot/index.js | 6 - .../SideNavigation.component.js | 65 - .../SideNavigation/SideNavigation.stories.js | 100 -- .../SideNavigation/SideNavigation.test.js | 264 --- .../src/components/SideNavigation/index.js | 6 - .../SideNavigationItem.component.js | 103 -- .../SideNavigationItem.stories.js | 68 - .../SideNavigationItem.test.js | 152 -- .../components/SideNavigationItem/index.js | 6 - .../components/Spinner/Spinner.component.js | 118 -- .../src/components/Spinner/Spinner.stories.js | 59 - .../src/components/Spinner/Spinner.test.js | 109 -- .../src/components/Spinner/index.js | 6 - .../src/components/Stack/Stack.component.js | 183 -- .../src/components/Stack/Stack.stories.js | 282 --- .../src/components/Stack/Stack.test.js | 106 -- .../src/components/Stack/index.js | 6 - .../src/components/StyleProvider/Fonts.js | 53 - .../components/StyleProvider/GlobalStyles.js | 38 - .../StyleProvider/StyleProvider.component.js | 142 -- .../StyleProvider/StyleProvider.stories.js | 61 - .../StyleProvider/StyleProvider.test.js | 24 - .../src/components/StyleProvider/index.js | 6 - .../src/components/Switch/Switch.component.js | 297 ---- .../src/components/Switch/Switch.stories.js | 135 -- .../src/components/Switch/Switch.test.js | 181 -- .../src/components/Switch/index.js | 6 - .../SwitchRow/SwitchRow.component.js | 103 -- .../components/SwitchRow/SwitchRow.stories.js | 234 --- .../components/SwitchRow/SwitchRow.test.js | 133 -- .../src/components/SwitchRow/index.js | 6 - .../src/components/Tab/Tab.component.js | 76 - .../src/components/Tab/Tab.stories.js | 37 - .../src/components/Tab/Tab.test.js | 49 - .../src/components/Tab/index.js | 6 - .../components/TabList/TabList.component.js | 73 - .../src/components/TabList/TabList.stories.js | 54 - .../src/components/TabList/TabList.test.js | 42 - .../src/components/TabList/index.js | 6 - .../TabNavigation/TabNavigation.component.js | 78 - .../TabNavigation/TabNavigation.stories.js | 128 -- .../TabNavigation/TabNavigation.test.js | 278 --- .../src/components/TabNavigation/index.js | 6 - .../TabNavigationItem.component.js | 111 -- .../TabNavigationItem.stories.js | 65 - .../TabNavigationItem.test.js | 152 -- .../src/components/TabNavigationItem/index.js | 6 - .../components/TabPanel/TabPanel.component.js | 45 - .../components/TabPanel/TabPanel.stories.js | 23 - .../src/components/TabPanel/TabPanel.test.js | 30 - .../src/components/TabPanel/index.js | 6 - .../src/components/Tabs/Tabs.component.js | 84 - .../src/components/Tabs/Tabs.stories.js | 130 -- .../src/components/Tabs/Tabs.test.js | 211 --- .../src/components/Tabs/index.js | 6 - .../TextInput/TextInput.component.js | 331 ---- .../components/TextInput/TextInput.stories.js | 128 -- .../components/TextInput/TextInput.test.js | 187 -- .../src/components/TextInput/index.js | 6 - .../src/components/TextInput/textinput.scss | 6 - .../TextInputRow/TextInputRow.component.js | 124 -- .../TextInputRow/TextInputRow.stories.js | 179 -- .../TextInputRow/TextInputRow.test.js | 206 --- .../src/components/TextInputRow/index.js | 6 - .../components/Textarea/Textarea.component.js | 326 ---- .../components/Textarea/Textarea.stories.js | 98 -- .../src/components/Textarea/Textarea.test.js | 158 -- .../src/components/Textarea/index.js | 6 - .../TextareaRow/TextareaRow.component.js | 102 -- .../TextareaRow/TextareaRow.stories.js | 124 -- .../TextareaRow/TextareaRow.test.js | 136 -- .../src/components/TextareaRow/index.js | 6 - .../src/components/Toast/Toast.component.js | 121 -- .../src/components/Toast/Toast.stories.js | 64 - .../src/components/Toast/Toast.test.js | 99 -- .../src/components/Toast/index.js | 6 - .../components/Tooltip/Tooltip.component.js | 97 -- .../src/components/Tooltip/Tooltip.stories.js | 232 --- .../src/components/Tooltip/Tooltip.test.js | 144 -- .../src/components/Tooltip/index.js | 7 - .../src/components/Tooltip/useTooltip.js | 124 -- .../TooltipContent.component.js | 92 - .../TooltipContent/TooltipContent.stories.js | 34 - .../TooltipContent/TooltipContent.test.js | 43 - .../src/components/TooltipContent/index.js | 6 - .../TooltipTrigger.component.js | 69 - .../TooltipTrigger/TooltipTrigger.stories.js | 59 - .../TooltipTrigger/TooltipTrigger.test.js | 43 - .../src/components/TooltipTrigger/index.js | 7 - .../TopNavigation/TopNavigation.component.js | 68 - .../TopNavigation/TopNavigation.stories.js | 102 -- .../TopNavigation/TopNavigation.test.js | 201 --- .../src/components/TopNavigation/index.js | 7 - .../TopNavigationItem.component.js | 107 -- .../TopNavigationItem.stories.js | 66 - .../TopNavigationItem.test.js | 129 -- .../src/components/TopNavigationItem/index.js | 7 - .../withDeprecationWarning/index.js | 6 - .../withDeprecationWarning.component.js | 23 - .../withDeprecationWarning.test.js | 35 - .../src/docs/ColorPalette/ColorCard.jsx | 40 - .../src/docs/ColorPalette/ColorPalette.jsx | 53 - .../docs/ColorPalette/JunoColorPalette.jsx | 29 - .../src/docs/ColorPalette/TailwindColors.js | 121 -- .../src/docs/ColorPalette/TextColorCard.jsx | 42 - .../generateTailwindThemeClassesJson.js | 109 -- .../JunoComponentWrapper.jsx | 48 - libs/juno-ui-components/src/docs/colors.mdx | 35 - .../src/docs/img/Schwan.jpg | Bin 59573 -> 0 bytes .../src/docs/navigation.mdx | 115 -- .../src/docsHidden/examplePage.mdx | 44 - .../src/dummyComponents/DummyComponent.js | 26 - .../src/dummyComponents/DummyComponentList.js | 19 - libs/juno-ui-components/src/global.scss | 48 - .../src/hooks/useTimeout.js | 31 - .../src/img/app_bg_example.svg | 18 - .../src/img/ccloud_shape.svg | 8 - .../src/img/icon_arrow_down.svg | 18 - libs/juno-ui-components/src/img/sap_logo.svg | 20 - libs/juno-ui-components/src/index.js | 118 -- libs/juno-ui-components/src/utils.js | 68 - libs/juno-ui-components/tailwind.config.js | 340 ---- .../test/__mocks__/styleMock.js | 6 - libs/juno-ui-components/test/__mocks__/svg.js | 32 - .../test/__mocks__/svgLib.js | 13 - libs/oauth/LICENSE | 201 --- libs/oauth/README.md | 198 --- libs/oauth/__tests__/__utils__/globalsMock.js | 34 - libs/oauth/__tests__/__utils__/idTokenMock.js | 21 - .../__tests__/__utils__/oidcConfigMock.js | 42 - libs/oauth/__tests__/codeFlow.test.js | 243 --- libs/oauth/__tests__/implicitFlow.test.js | 123 -- libs/oauth/__tests__/mockedSession.test.js | 144 -- libs/oauth/__tests__/oidcConfig.test.js | 81 - libs/oauth/__tests__/oidcSession.test.js | 106 -- libs/oauth/__tests__/tokenHelpers.test.js | 240 --- libs/oauth/esbuild.config.js | 28 - libs/oauth/package.json | 45 - libs/oauth/src/codeFlow.js | 130 -- libs/oauth/src/implicitFlow.js | 53 - libs/oauth/src/index.js | 8 - libs/oauth/src/mockedSession.js | 91 - libs/oauth/src/oidcConfig.js | 38 - libs/oauth/src/oidcSession.js | 331 ---- libs/oauth/src/oidcState.js | 67 - libs/oauth/src/tokenHelpers.js | 114 -- libs/oauth/src/utils.js | 49 - libs/policy-engine/LICENSE | 201 --- libs/policy-engine/README.md | 117 -- libs/policy-engine/package.json | 39 - libs/policy-engine/rollup.config.js | 57 - libs/policy-engine/src/debugTrace.js | 32 - libs/policy-engine/src/debugTrace.test.js | 36 - libs/policy-engine/src/engine.js | 106 -- libs/policy-engine/src/engine.test.js | 293 ---- libs/policy-engine/src/evaluator.js | 170 -- libs/policy-engine/src/evaluator.test.js | 400 ----- libs/policy-engine/src/index.js | 9 - libs/policy-engine/src/lexer.js | 37 - libs/policy-engine/src/lexer.test.js | 116 -- libs/policy-engine/src/parser.js | 286 ---- libs/policy-engine/src/parser.test.js | 545 ------ 537 files changed, 50423 deletions(-) delete mode 100644 libs/communicator/.gitignore delete mode 100644 libs/communicator/LICENSE delete mode 100644 libs/communicator/README.md delete mode 100644 libs/communicator/dev/build.js delete mode 100644 libs/communicator/dev/build.js.map delete mode 100644 libs/communicator/dev/index.html delete mode 100644 libs/communicator/dev/index.js delete mode 100644 libs/communicator/esbuild.config.js delete mode 100644 libs/communicator/package.json delete mode 100644 libs/communicator/src/index.js delete mode 100644 libs/communicator/src/index.test.js delete mode 100644 libs/juno-ui-components/.gitignore delete mode 100644 libs/juno-ui-components/.npmignore delete mode 100644 libs/juno-ui-components/.storybook/.babelrc delete mode 100644 libs/juno-ui-components/.storybook/juno-addon/Decorator.jsx delete mode 100644 libs/juno-ui-components/.storybook/juno-addon/DocsContainer.jsx delete mode 100644 libs/juno-ui-components/.storybook/juno-addon/README.md delete mode 100644 libs/juno-ui-components/.storybook/juno-addon/ThemeToggle.jsx delete mode 100644 libs/juno-ui-components/.storybook/juno-addon/constants.js delete mode 100644 libs/juno-ui-components/.storybook/juno-addon/manager.js delete mode 100644 libs/juno-ui-components/.storybook/juno-addon/preview.js delete mode 100644 libs/juno-ui-components/.storybook/juno-addon/themes.js delete mode 100644 libs/juno-ui-components/.storybook/main.js delete mode 100644 libs/juno-ui-components/.storybook/preview.js delete mode 100644 libs/juno-ui-components/LICENSE delete mode 100644 libs/juno-ui-components/README.md delete mode 100644 libs/juno-ui-components/babel.config.json delete mode 100644 libs/juno-ui-components/lib/variables.scss delete mode 100644 libs/juno-ui-components/package.json delete mode 100644 libs/juno-ui-components/postcss.config.js delete mode 100644 libs/juno-ui-components/rollup.config.js delete mode 100644 libs/juno-ui-components/setupTests.js delete mode 100644 libs/juno-ui-components/src/components/AppBody/AppBody.component.js delete mode 100644 libs/juno-ui-components/src/components/AppBody/AppBody.stories.js delete mode 100644 libs/juno-ui-components/src/components/AppBody/AppBody.test.js delete mode 100644 libs/juno-ui-components/src/components/AppBody/index.js delete mode 100644 libs/juno-ui-components/src/components/AppIntro/AppIntro.component.js delete mode 100644 libs/juno-ui-components/src/components/AppIntro/AppIntro.stories.js delete mode 100644 libs/juno-ui-components/src/components/AppIntro/AppIntro.test.js delete mode 100644 libs/juno-ui-components/src/components/AppIntro/index.js delete mode 100644 libs/juno-ui-components/src/components/AppShell/AppShell.component.js delete mode 100644 libs/juno-ui-components/src/components/AppShell/AppShell.stories.js delete mode 100644 libs/juno-ui-components/src/components/AppShell/AppShell.test.js delete mode 100644 libs/juno-ui-components/src/components/AppShell/index.js delete mode 100644 libs/juno-ui-components/src/components/AppShellProvider/AppShellProvider.component.js delete mode 100644 libs/juno-ui-components/src/components/AppShellProvider/AppShellProvider.stories.js delete mode 100644 libs/juno-ui-components/src/components/AppShellProvider/AppShellProvider.test.js delete mode 100644 libs/juno-ui-components/src/components/AppShellProvider/index.js delete mode 100644 libs/juno-ui-components/src/components/Badge/Badge.component.js delete mode 100644 libs/juno-ui-components/src/components/Badge/Badge.stories.js delete mode 100644 libs/juno-ui-components/src/components/Badge/Badge.test.js delete mode 100644 libs/juno-ui-components/src/components/Badge/index.js delete mode 100644 libs/juno-ui-components/src/components/Box/Box.component.js delete mode 100644 libs/juno-ui-components/src/components/Box/Box.stories.js delete mode 100644 libs/juno-ui-components/src/components/Box/Box.test.js delete mode 100644 libs/juno-ui-components/src/components/Box/index.js delete mode 100644 libs/juno-ui-components/src/components/Breadcrumb/Breadcrumb.component.js delete mode 100644 libs/juno-ui-components/src/components/Breadcrumb/Breadcrumb.stories.js delete mode 100644 libs/juno-ui-components/src/components/Breadcrumb/Breadcrumb.test.js delete mode 100644 libs/juno-ui-components/src/components/Breadcrumb/index.js delete mode 100644 libs/juno-ui-components/src/components/BreadcrumbItem/BreadcrumbItem.component.js delete mode 100644 libs/juno-ui-components/src/components/BreadcrumbItem/BreadcrumbItem.stories.js delete mode 100644 libs/juno-ui-components/src/components/BreadcrumbItem/BreadcrumbItem.test.js delete mode 100644 libs/juno-ui-components/src/components/BreadcrumbItem/index.js delete mode 100644 libs/juno-ui-components/src/components/Button/Button.component.js delete mode 100644 libs/juno-ui-components/src/components/Button/Button.stories.js delete mode 100644 libs/juno-ui-components/src/components/Button/Button.test.js delete mode 100644 libs/juno-ui-components/src/components/Button/button.scss delete mode 100644 libs/juno-ui-components/src/components/Button/index.js delete mode 100644 libs/juno-ui-components/src/components/ButtonRow/ButtonRow.component.js delete mode 100644 libs/juno-ui-components/src/components/ButtonRow/ButtonRow.stories.js delete mode 100644 libs/juno-ui-components/src/components/ButtonRow/ButtonRow.test.js delete mode 100644 libs/juno-ui-components/src/components/ButtonRow/index.js delete mode 100644 libs/juno-ui-components/src/components/Checkbox/Checkbox.component.js delete mode 100644 libs/juno-ui-components/src/components/Checkbox/Checkbox.stories.js delete mode 100644 libs/juno-ui-components/src/components/Checkbox/Checkbox.test.js delete mode 100644 libs/juno-ui-components/src/components/Checkbox/index.js delete mode 100644 libs/juno-ui-components/src/components/CheckboxGroup/CheckboxGroup.component.js delete mode 100644 libs/juno-ui-components/src/components/CheckboxGroup/CheckboxGroup.stories.js delete mode 100644 libs/juno-ui-components/src/components/CheckboxGroup/CheckboxGroup.test.js delete mode 100644 libs/juno-ui-components/src/components/CheckboxGroup/index.js delete mode 100644 libs/juno-ui-components/src/components/CheckboxRow/CheckboxRow.component.js delete mode 100644 libs/juno-ui-components/src/components/CheckboxRow/CheckboxRow.stories.js delete mode 100644 libs/juno-ui-components/src/components/CheckboxRow/CheckboxRow.test.js delete mode 100644 libs/juno-ui-components/src/components/CheckboxRow/index.js delete mode 100644 libs/juno-ui-components/src/components/Code/Code.component.js delete mode 100644 libs/juno-ui-components/src/components/Code/Code.stories.js delete mode 100644 libs/juno-ui-components/src/components/Code/Code.test.js delete mode 100644 libs/juno-ui-components/src/components/Code/index.js delete mode 100644 libs/juno-ui-components/src/components/CodeBlock/CodeBlock.component.js delete mode 100644 libs/juno-ui-components/src/components/CodeBlock/CodeBlock.stories.js delete mode 100644 libs/juno-ui-components/src/components/CodeBlock/CodeBlock.test.js delete mode 100644 libs/juno-ui-components/src/components/CodeBlock/index.js delete mode 100644 libs/juno-ui-components/src/components/ComboBox/ComboBox.component.js delete mode 100644 libs/juno-ui-components/src/components/ComboBox/ComboBox.stories.js delete mode 100644 libs/juno-ui-components/src/components/ComboBox/ComboBox.test.js delete mode 100644 libs/juno-ui-components/src/components/ComboBox/index.js delete mode 100644 libs/juno-ui-components/src/components/ComboBoxOption/ComboBoxOption.component.js delete mode 100644 libs/juno-ui-components/src/components/ComboBoxOption/ComboBoxOption.stories.js delete mode 100644 libs/juno-ui-components/src/components/ComboBoxOption/ComboBoxOption.test.js delete mode 100644 libs/juno-ui-components/src/components/ComboBoxOption/index.js delete mode 100644 libs/juno-ui-components/src/components/Container/Container.component.js delete mode 100644 libs/juno-ui-components/src/components/Container/Container.stories.js delete mode 100644 libs/juno-ui-components/src/components/Container/Container.test.js delete mode 100644 libs/juno-ui-components/src/components/Container/index.js delete mode 100644 libs/juno-ui-components/src/components/ContentArea/ContentArea.component.js delete mode 100644 libs/juno-ui-components/src/components/ContentArea/ContentArea.stories.js delete mode 100644 libs/juno-ui-components/src/components/ContentArea/ContentArea.test.js delete mode 100644 libs/juno-ui-components/src/components/ContentArea/index.js delete mode 100644 libs/juno-ui-components/src/components/ContentAreaToolbar/ContentAreaToolbar.component.js delete mode 100644 libs/juno-ui-components/src/components/ContentAreaToolbar/ContentAreaToolbar.stories.js delete mode 100644 libs/juno-ui-components/src/components/ContentAreaToolbar/ContentAreaToolbar.test.js delete mode 100644 libs/juno-ui-components/src/components/ContentAreaToolbar/index.js delete mode 100644 libs/juno-ui-components/src/components/ContentAreaWrapper/ContentAreaWrapper.component.js delete mode 100644 libs/juno-ui-components/src/components/ContentAreaWrapper/ContentAreaWrapper.stories.js delete mode 100644 libs/juno-ui-components/src/components/ContentAreaWrapper/ContentAreaWrapper.test.js delete mode 100644 libs/juno-ui-components/src/components/ContentAreaWrapper/index.js delete mode 100644 libs/juno-ui-components/src/components/ContentContainer/ContentContainer.component.js delete mode 100644 libs/juno-ui-components/src/components/ContentContainer/ContentContainer.stories.js delete mode 100644 libs/juno-ui-components/src/components/ContentContainer/ContentContainer.test.js delete mode 100644 libs/juno-ui-components/src/components/ContentContainer/index.js delete mode 100644 libs/juno-ui-components/src/components/ContentHeading/ContentHeading.component.js delete mode 100644 libs/juno-ui-components/src/components/ContentHeading/ContentHeading.stories.js delete mode 100644 libs/juno-ui-components/src/components/ContentHeading/ContentHeading.test.js delete mode 100644 libs/juno-ui-components/src/components/ContentHeading/index.js delete mode 100644 libs/juno-ui-components/src/components/ContextMenu/ContextMenu.component.js delete mode 100644 libs/juno-ui-components/src/components/ContextMenu/ContextMenu.stories.js delete mode 100644 libs/juno-ui-components/src/components/ContextMenu/ContextMenu.test.js delete mode 100644 libs/juno-ui-components/src/components/ContextMenu/index.js delete mode 100644 libs/juno-ui-components/src/components/DataGrid/DataGrid.component.js delete mode 100644 libs/juno-ui-components/src/components/DataGrid/DataGrid.stories.js delete mode 100644 libs/juno-ui-components/src/components/DataGrid/DataGrid.test.js delete mode 100644 libs/juno-ui-components/src/components/DataGrid/index.js delete mode 100644 libs/juno-ui-components/src/components/DataGridCell/DataGridCell.component.js delete mode 100644 libs/juno-ui-components/src/components/DataGridCell/DataGridCell.stories.js delete mode 100644 libs/juno-ui-components/src/components/DataGridCell/DataGridCell.test.js delete mode 100644 libs/juno-ui-components/src/components/DataGridCell/index.js delete mode 100644 libs/juno-ui-components/src/components/DataGridCheckboxCell/DataGridCheckboxCell.component.js delete mode 100644 libs/juno-ui-components/src/components/DataGridCheckboxCell/DataGridCheckboxCell.stories.js delete mode 100644 libs/juno-ui-components/src/components/DataGridCheckboxCell/DataGridCheckboxCell.test.js delete mode 100644 libs/juno-ui-components/src/components/DataGridCheckboxCell/index.js delete mode 100644 libs/juno-ui-components/src/components/DataGridFoot/DataGridFoot.component.js delete mode 100644 libs/juno-ui-components/src/components/DataGridFoot/DataGridFoot.stories.js delete mode 100644 libs/juno-ui-components/src/components/DataGridFoot/DataGridFoot.test.js delete mode 100644 libs/juno-ui-components/src/components/DataGridFoot/index.js delete mode 100644 libs/juno-ui-components/src/components/DataGridHeadCell/DataGridHeadCell.component.js delete mode 100644 libs/juno-ui-components/src/components/DataGridHeadCell/DataGridHeadCell.stories.js delete mode 100644 libs/juno-ui-components/src/components/DataGridHeadCell/DataGridHeadCell.test.js delete mode 100644 libs/juno-ui-components/src/components/DataGridHeadCell/index.js delete mode 100644 libs/juno-ui-components/src/components/DataGridRow/DataGridRow.component.js delete mode 100644 libs/juno-ui-components/src/components/DataGridRow/DataGridRow.stories.js delete mode 100644 libs/juno-ui-components/src/components/DataGridRow/DataGridRow.test.js delete mode 100644 libs/juno-ui-components/src/components/DataGridRow/index.js delete mode 100644 libs/juno-ui-components/src/components/DataGridToolbar/DataGridToolbar.component.js delete mode 100644 libs/juno-ui-components/src/components/DataGridToolbar/DataGridToolbar.stories.js delete mode 100644 libs/juno-ui-components/src/components/DataGridToolbar/DataGridToolbar.test.js delete mode 100644 libs/juno-ui-components/src/components/DataGridToolbar/index.js delete mode 100644 libs/juno-ui-components/src/components/DataList/DataList.component.js delete mode 100644 libs/juno-ui-components/src/components/DataList/DataList.stories.js delete mode 100644 libs/juno-ui-components/src/components/DataList/DataList.test.js delete mode 100644 libs/juno-ui-components/src/components/DataList/index.js delete mode 100644 libs/juno-ui-components/src/components/DataListCell/DataListCell.component.js delete mode 100644 libs/juno-ui-components/src/components/DataListCell/DataListCell.stories.js delete mode 100644 libs/juno-ui-components/src/components/DataListCell/DataListCell.test.js delete mode 100644 libs/juno-ui-components/src/components/DataListCell/index.js delete mode 100644 libs/juno-ui-components/src/components/DataListCheckboxCell/DataListCheckboxCell.component.js delete mode 100644 libs/juno-ui-components/src/components/DataListCheckboxCell/DataListCheckboxCell.stories.js delete mode 100644 libs/juno-ui-components/src/components/DataListCheckboxCell/DataListCheckboxCell.test.js delete mode 100644 libs/juno-ui-components/src/components/DataListCheckboxCell/index.js delete mode 100644 libs/juno-ui-components/src/components/DataListRow/DataListRow.component.js delete mode 100644 libs/juno-ui-components/src/components/DataListRow/DataListRow.stories.js delete mode 100644 libs/juno-ui-components/src/components/DataListRow/DataListRow.test.js delete mode 100644 libs/juno-ui-components/src/components/DataListRow/index.js delete mode 100644 libs/juno-ui-components/src/components/DateTimePicker/DateTimePicker.component.js delete mode 100644 libs/juno-ui-components/src/components/DateTimePicker/DateTimePicker.stories.js delete mode 100644 libs/juno-ui-components/src/components/DateTimePicker/DateTimePicker.test.js delete mode 100644 libs/juno-ui-components/src/components/DateTimePicker/datetimepicker.scss delete mode 100644 libs/juno-ui-components/src/components/DateTimePicker/index.js delete mode 100644 libs/juno-ui-components/src/components/FilterInput/FilterInput.component.js delete mode 100644 libs/juno-ui-components/src/components/FilterInput/FilterInput.stories.js delete mode 100644 libs/juno-ui-components/src/components/FilterInput/FilterInput.test.js delete mode 100644 libs/juno-ui-components/src/components/FilterInput/index.js delete mode 100644 libs/juno-ui-components/src/components/FilterPill/FilterPill.component.js delete mode 100644 libs/juno-ui-components/src/components/FilterPill/FilterPill.stories.js delete mode 100644 libs/juno-ui-components/src/components/FilterPill/FilterPill.test.js delete mode 100644 libs/juno-ui-components/src/components/FilterPill/index.js delete mode 100644 libs/juno-ui-components/src/components/Filters/Filters.component.js delete mode 100644 libs/juno-ui-components/src/components/Filters/Filters.stories.js delete mode 100644 libs/juno-ui-components/src/components/Filters/Filters.test.js delete mode 100644 libs/juno-ui-components/src/components/Filters/index.js delete mode 100644 libs/juno-ui-components/src/components/Form/Form.component.js delete mode 100644 libs/juno-ui-components/src/components/Form/Form.stories.js delete mode 100644 libs/juno-ui-components/src/components/Form/Form.test.js delete mode 100644 libs/juno-ui-components/src/components/Form/index.js delete mode 100644 libs/juno-ui-components/src/components/FormHint/FormHint.component.js delete mode 100644 libs/juno-ui-components/src/components/FormHint/FormHint.stories.js delete mode 100644 libs/juno-ui-components/src/components/FormHint/FormHint.test.js delete mode 100644 libs/juno-ui-components/src/components/FormHint/index.js delete mode 100644 libs/juno-ui-components/src/components/FormRow/FormRow.component.js delete mode 100644 libs/juno-ui-components/src/components/FormRow/FormRow.stories.js delete mode 100644 libs/juno-ui-components/src/components/FormRow/FormRow.test.js delete mode 100644 libs/juno-ui-components/src/components/FormRow/index.js delete mode 100644 libs/juno-ui-components/src/components/FormSection/FormSection.component.js delete mode 100644 libs/juno-ui-components/src/components/FormSection/FormSection.stories.js delete mode 100644 libs/juno-ui-components/src/components/FormSection/FormSection.test.js delete mode 100644 libs/juno-ui-components/src/components/FormSection/index.js delete mode 100644 libs/juno-ui-components/src/components/Grid/Grid.component.js delete mode 100644 libs/juno-ui-components/src/components/Grid/Grid.stories.js delete mode 100644 libs/juno-ui-components/src/components/Grid/Grid.test.js delete mode 100644 libs/juno-ui-components/src/components/Grid/index.js delete mode 100644 libs/juno-ui-components/src/components/GridColumn/GridColumn.component.js delete mode 100644 libs/juno-ui-components/src/components/GridColumn/GridColumn.stories.js delete mode 100644 libs/juno-ui-components/src/components/GridColumn/GridColumn.test.js delete mode 100644 libs/juno-ui-components/src/components/GridColumn/index.js delete mode 100644 libs/juno-ui-components/src/components/GridRow/GridRow.component.js delete mode 100644 libs/juno-ui-components/src/components/GridRow/GridRow.stories.js delete mode 100644 libs/juno-ui-components/src/components/GridRow/GridRow.test.js delete mode 100644 libs/juno-ui-components/src/components/GridRow/index.js delete mode 100644 libs/juno-ui-components/src/components/Icon/Icon.component.js delete mode 100644 libs/juno-ui-components/src/components/Icon/Icon.stories.js delete mode 100644 libs/juno-ui-components/src/components/Icon/Icon.test.js delete mode 100644 libs/juno-ui-components/src/components/Icon/icons/home_sharp.svg delete mode 100644 libs/juno-ui-components/src/components/Icon/icons/juno-danger.svg delete mode 100644 libs/juno-ui-components/src/components/Icon/icons/juno_severity_critical.svg delete mode 100644 libs/juno-ui-components/src/components/Icon/icons/juno_severity_high.svg delete mode 100644 libs/juno-ui-components/src/components/Icon/icons/juno_severity_low.svg delete mode 100644 libs/juno-ui-components/src/components/Icon/icons/juno_severity_medium.svg delete mode 100644 libs/juno-ui-components/src/components/Icon/icons/place.svg delete mode 100644 libs/juno-ui-components/src/components/Icon/index.js delete mode 100644 libs/juno-ui-components/src/components/InputGroup/InputGroup.component.js delete mode 100644 libs/juno-ui-components/src/components/InputGroup/InputGroup.stories.js delete mode 100644 libs/juno-ui-components/src/components/InputGroup/InputGroup.test.js delete mode 100644 libs/juno-ui-components/src/components/InputGroup/index.js delete mode 100644 libs/juno-ui-components/src/components/InputGroup/input-group.scss delete mode 100644 libs/juno-ui-components/src/components/IntroBox/IntroBox.component.js delete mode 100644 libs/juno-ui-components/src/components/IntroBox/IntroBox.stories.js delete mode 100644 libs/juno-ui-components/src/components/IntroBox/IntroBox.test.js delete mode 100644 libs/juno-ui-components/src/components/IntroBox/index.js delete mode 100644 libs/juno-ui-components/src/components/JsonViewer/JsonViewer.component.js delete mode 100644 libs/juno-ui-components/src/components/JsonViewer/JsonViewer.stories.js delete mode 100644 libs/juno-ui-components/src/components/JsonViewer/JsonViewer.test.js delete mode 100644 libs/juno-ui-components/src/components/JsonViewer/index.js delete mode 100644 libs/juno-ui-components/src/components/JsonViewer/themes.js delete mode 100644 libs/juno-ui-components/src/components/Label/Label.component.js delete mode 100644 libs/juno-ui-components/src/components/Label/Label.stories.js delete mode 100644 libs/juno-ui-components/src/components/Label/Label.test.js delete mode 100644 libs/juno-ui-components/src/components/Label/index.js delete mode 100644 libs/juno-ui-components/src/components/LoadingIndicator/LoadingIndicator.component.js delete mode 100644 libs/juno-ui-components/src/components/LoadingIndicator/LoadingIndicator.stories.js delete mode 100644 libs/juno-ui-components/src/components/LoadingIndicator/LoadingIndicator.test.js delete mode 100644 libs/juno-ui-components/src/components/LoadingIndicator/index.js delete mode 100644 libs/juno-ui-components/src/components/LoadingIndicator/loading-indicator.svg delete mode 100644 libs/juno-ui-components/src/components/MainContainer/MainContainer.component.js delete mode 100644 libs/juno-ui-components/src/components/MainContainer/MainContainer.stories.js delete mode 100644 libs/juno-ui-components/src/components/MainContainer/MainContainer.test.js delete mode 100644 libs/juno-ui-components/src/components/MainContainer/index.js delete mode 100644 libs/juno-ui-components/src/components/MainContainerInner/MainContainerInner.component.js delete mode 100644 libs/juno-ui-components/src/components/MainContainerInner/MainContainerInner.test.js delete mode 100644 libs/juno-ui-components/src/components/MainContainerInner/index.js delete mode 100644 libs/juno-ui-components/src/components/MainTabs/MainTabs.component.js delete mode 100644 libs/juno-ui-components/src/components/MainTabs/MainTabs.stories.js delete mode 100644 libs/juno-ui-components/src/components/MainTabs/MainTabs.test.js delete mode 100644 libs/juno-ui-components/src/components/MainTabs/index.js delete mode 100644 libs/juno-ui-components/src/components/Menu/Menu.component.js delete mode 100644 libs/juno-ui-components/src/components/Menu/Menu.stories.js delete mode 100644 libs/juno-ui-components/src/components/Menu/Menu.test.js delete mode 100644 libs/juno-ui-components/src/components/Menu/index.js delete mode 100644 libs/juno-ui-components/src/components/MenuItem/MenuItem.component.js delete mode 100644 libs/juno-ui-components/src/components/MenuItem/MenuItem.stories.js delete mode 100644 libs/juno-ui-components/src/components/MenuItem/MenuItem.test.js delete mode 100644 libs/juno-ui-components/src/components/MenuItem/index.js delete mode 100644 libs/juno-ui-components/src/components/MenuSection/MenuSection.component.js delete mode 100644 libs/juno-ui-components/src/components/MenuSection/MenuSection.stories.js delete mode 100644 libs/juno-ui-components/src/components/MenuSection/MenuSection.test.js delete mode 100644 libs/juno-ui-components/src/components/MenuSection/index.js delete mode 100644 libs/juno-ui-components/src/components/Message/Message.component.js delete mode 100644 libs/juno-ui-components/src/components/Message/Message.stories.js delete mode 100644 libs/juno-ui-components/src/components/Message/Message.test.js delete mode 100644 libs/juno-ui-components/src/components/Message/index.js delete mode 100644 libs/juno-ui-components/src/components/Modal/Modal.component.js delete mode 100644 libs/juno-ui-components/src/components/Modal/Modal.stories.js delete mode 100644 libs/juno-ui-components/src/components/Modal/Modal.test.js delete mode 100644 libs/juno-ui-components/src/components/Modal/index.js delete mode 100644 libs/juno-ui-components/src/components/ModalFooter/ModalFooter.component.js delete mode 100644 libs/juno-ui-components/src/components/ModalFooter/ModalFooter.stories.js delete mode 100644 libs/juno-ui-components/src/components/ModalFooter/ModalFooter.test.js delete mode 100644 libs/juno-ui-components/src/components/ModalFooter/index.js delete mode 100644 libs/juno-ui-components/src/components/NativeSelect/NativeSelect.component.js delete mode 100644 libs/juno-ui-components/src/components/NativeSelect/NativeSelect.stories.js delete mode 100644 libs/juno-ui-components/src/components/NativeSelect/NativeSelect.test.js delete mode 100644 libs/juno-ui-components/src/components/NativeSelect/index.js delete mode 100644 libs/juno-ui-components/src/components/NativeSelectOption/NativeSelectOption.component.js delete mode 100644 libs/juno-ui-components/src/components/NativeSelectOption/NativeSelectOption.stories.js delete mode 100644 libs/juno-ui-components/src/components/NativeSelectOption/SelectOption.test.js delete mode 100644 libs/juno-ui-components/src/components/NativeSelectOption/index.js delete mode 100644 libs/juno-ui-components/src/components/NativeSelectOptionGroup/NativeSelectOptionGroup.component.js delete mode 100644 libs/juno-ui-components/src/components/NativeSelectOptionGroup/NativeSelectOptionGroup.stories.js delete mode 100644 libs/juno-ui-components/src/components/NativeSelectOptionGroup/NativeSelectOptionGroup.test.js delete mode 100644 libs/juno-ui-components/src/components/NativeSelectOptionGroup/index.js delete mode 100644 libs/juno-ui-components/src/components/Navigation/Navigation.component.js delete mode 100644 libs/juno-ui-components/src/components/Navigation/Navigation.stories.js delete mode 100644 libs/juno-ui-components/src/components/Navigation/Navigation.test.js delete mode 100644 libs/juno-ui-components/src/components/Navigation/index.js delete mode 100644 libs/juno-ui-components/src/components/NavigationItem/NavigationItem.component.js delete mode 100644 libs/juno-ui-components/src/components/NavigationItem/NavigationItem.stories.js delete mode 100644 libs/juno-ui-components/src/components/NavigationItem/NavigationItem.test.js delete mode 100644 libs/juno-ui-components/src/components/NavigationItem/index.js delete mode 100644 libs/juno-ui-components/src/components/PageFooter/PageFooter.component.js delete mode 100644 libs/juno-ui-components/src/components/PageFooter/PageFooter.stories.js delete mode 100644 libs/juno-ui-components/src/components/PageFooter/PageFooter.test.js delete mode 100644 libs/juno-ui-components/src/components/PageFooter/index.js delete mode 100644 libs/juno-ui-components/src/components/PageHeader/PageHeader.component.js delete mode 100644 libs/juno-ui-components/src/components/PageHeader/PageHeader.stories.js delete mode 100644 libs/juno-ui-components/src/components/PageHeader/PageHeader.test.js delete mode 100644 libs/juno-ui-components/src/components/PageHeader/index.js delete mode 100644 libs/juno-ui-components/src/components/Pagination/Pagination.component.js delete mode 100644 libs/juno-ui-components/src/components/Pagination/Pagination.stories.js delete mode 100644 libs/juno-ui-components/src/components/Pagination/Pagination.test.js delete mode 100644 libs/juno-ui-components/src/components/Pagination/index.js delete mode 100644 libs/juno-ui-components/src/components/Panel/Panel.component.js delete mode 100644 libs/juno-ui-components/src/components/Panel/Panel.stories.js delete mode 100644 libs/juno-ui-components/src/components/Panel/Panel.test.js delete mode 100644 libs/juno-ui-components/src/components/Panel/index.js delete mode 100644 libs/juno-ui-components/src/components/PanelBody/PanelBody.component.js delete mode 100644 libs/juno-ui-components/src/components/PanelBody/PanelBody.stories.js delete mode 100644 libs/juno-ui-components/src/components/PanelBody/PanelBody.test.js delete mode 100644 libs/juno-ui-components/src/components/PanelBody/index.js delete mode 100644 libs/juno-ui-components/src/components/PanelFooter/PanelFooter.component.js delete mode 100644 libs/juno-ui-components/src/components/PanelFooter/PanelFooter.stories.js delete mode 100644 libs/juno-ui-components/src/components/PanelFooter/PanelFooter.test.js delete mode 100644 libs/juno-ui-components/src/components/PanelFooter/index.js delete mode 100644 libs/juno-ui-components/src/components/Pill/Pill.component.js delete mode 100644 libs/juno-ui-components/src/components/Pill/Pill.stories.js delete mode 100644 libs/juno-ui-components/src/components/Pill/Pill.test.js delete mode 100644 libs/juno-ui-components/src/components/Pill/index.js delete mode 100644 libs/juno-ui-components/src/components/PortalProvider/PortalProvider.component.js delete mode 100644 libs/juno-ui-components/src/components/PortalProvider/PortalProvider.stories.js delete mode 100644 libs/juno-ui-components/src/components/PortalProvider/PortalProvider.test.js delete mode 100644 libs/juno-ui-components/src/components/PortalProvider/index.js delete mode 100644 libs/juno-ui-components/src/components/Radio/Radio.component.js delete mode 100644 libs/juno-ui-components/src/components/Radio/Radio.stories.js delete mode 100644 libs/juno-ui-components/src/components/Radio/Radio.test.js delete mode 100644 libs/juno-ui-components/src/components/Radio/index.js delete mode 100644 libs/juno-ui-components/src/components/RadioGroup/RadioGroup.component.js delete mode 100644 libs/juno-ui-components/src/components/RadioGroup/RadioGroup.stories.js delete mode 100644 libs/juno-ui-components/src/components/RadioGroup/RadioGroup.test.js delete mode 100644 libs/juno-ui-components/src/components/RadioGroup/index.js delete mode 100644 libs/juno-ui-components/src/components/RadioRow/RadioRow.component.js delete mode 100644 libs/juno-ui-components/src/components/RadioRow/RadioRow.stories.js delete mode 100644 libs/juno-ui-components/src/components/RadioRow/RadioRow.test.js delete mode 100644 libs/juno-ui-components/src/components/RadioRow/index.js delete mode 100644 libs/juno-ui-components/src/components/SearchInput/SearchInput.component.js delete mode 100644 libs/juno-ui-components/src/components/SearchInput/SearchInput.stories.js delete mode 100644 libs/juno-ui-components/src/components/SearchInput/SearchInput.test.js delete mode 100644 libs/juno-ui-components/src/components/SearchInput/index.js delete mode 100644 libs/juno-ui-components/src/components/SearchInput/searchinput.scss delete mode 100644 libs/juno-ui-components/src/components/Select/Select.component.js delete mode 100644 libs/juno-ui-components/src/components/Select/Select.stories.js delete mode 100644 libs/juno-ui-components/src/components/Select/Select.test.js delete mode 100644 libs/juno-ui-components/src/components/Select/index.js delete mode 100644 libs/juno-ui-components/src/components/Select/select.scss delete mode 100644 libs/juno-ui-components/src/components/SelectDivider/SelectDivider.component.js delete mode 100644 libs/juno-ui-components/src/components/SelectDivider/SelectDivider.stories.js delete mode 100644 libs/juno-ui-components/src/components/SelectDivider/SelectDivider.test.js delete mode 100644 libs/juno-ui-components/src/components/SelectDivider/index.js delete mode 100644 libs/juno-ui-components/src/components/SelectOption/SelectOption.component.js delete mode 100644 libs/juno-ui-components/src/components/SelectOption/SelectOption.stories.js delete mode 100644 libs/juno-ui-components/src/components/SelectOption/SelectOption.test.js delete mode 100644 libs/juno-ui-components/src/components/SelectOption/index.js delete mode 100644 libs/juno-ui-components/src/components/SelectRow/SelectRow.component.js delete mode 100644 libs/juno-ui-components/src/components/SelectRow/SelectRow.stories.js delete mode 100644 libs/juno-ui-components/src/components/SelectRow/SelectRow.test.js delete mode 100644 libs/juno-ui-components/src/components/SelectRow/index.js delete mode 100644 libs/juno-ui-components/src/components/ShadowRoot/ShadowRoot.component.js delete mode 100644 libs/juno-ui-components/src/components/ShadowRoot/ShadowRoot.stories.js delete mode 100644 libs/juno-ui-components/src/components/ShadowRoot/index.js delete mode 100644 libs/juno-ui-components/src/components/SideNavigation/SideNavigation.component.js delete mode 100644 libs/juno-ui-components/src/components/SideNavigation/SideNavigation.stories.js delete mode 100644 libs/juno-ui-components/src/components/SideNavigation/SideNavigation.test.js delete mode 100644 libs/juno-ui-components/src/components/SideNavigation/index.js delete mode 100644 libs/juno-ui-components/src/components/SideNavigationItem/SideNavigationItem.component.js delete mode 100644 libs/juno-ui-components/src/components/SideNavigationItem/SideNavigationItem.stories.js delete mode 100644 libs/juno-ui-components/src/components/SideNavigationItem/SideNavigationItem.test.js delete mode 100644 libs/juno-ui-components/src/components/SideNavigationItem/index.js delete mode 100644 libs/juno-ui-components/src/components/Spinner/Spinner.component.js delete mode 100644 libs/juno-ui-components/src/components/Spinner/Spinner.stories.js delete mode 100644 libs/juno-ui-components/src/components/Spinner/Spinner.test.js delete mode 100644 libs/juno-ui-components/src/components/Spinner/index.js delete mode 100644 libs/juno-ui-components/src/components/Stack/Stack.component.js delete mode 100644 libs/juno-ui-components/src/components/Stack/Stack.stories.js delete mode 100644 libs/juno-ui-components/src/components/Stack/Stack.test.js delete mode 100644 libs/juno-ui-components/src/components/Stack/index.js delete mode 100644 libs/juno-ui-components/src/components/StyleProvider/Fonts.js delete mode 100644 libs/juno-ui-components/src/components/StyleProvider/GlobalStyles.js delete mode 100644 libs/juno-ui-components/src/components/StyleProvider/StyleProvider.component.js delete mode 100644 libs/juno-ui-components/src/components/StyleProvider/StyleProvider.stories.js delete mode 100644 libs/juno-ui-components/src/components/StyleProvider/StyleProvider.test.js delete mode 100644 libs/juno-ui-components/src/components/StyleProvider/index.js delete mode 100644 libs/juno-ui-components/src/components/Switch/Switch.component.js delete mode 100644 libs/juno-ui-components/src/components/Switch/Switch.stories.js delete mode 100644 libs/juno-ui-components/src/components/Switch/Switch.test.js delete mode 100644 libs/juno-ui-components/src/components/Switch/index.js delete mode 100644 libs/juno-ui-components/src/components/SwitchRow/SwitchRow.component.js delete mode 100644 libs/juno-ui-components/src/components/SwitchRow/SwitchRow.stories.js delete mode 100644 libs/juno-ui-components/src/components/SwitchRow/SwitchRow.test.js delete mode 100644 libs/juno-ui-components/src/components/SwitchRow/index.js delete mode 100644 libs/juno-ui-components/src/components/Tab/Tab.component.js delete mode 100644 libs/juno-ui-components/src/components/Tab/Tab.stories.js delete mode 100644 libs/juno-ui-components/src/components/Tab/Tab.test.js delete mode 100644 libs/juno-ui-components/src/components/Tab/index.js delete mode 100644 libs/juno-ui-components/src/components/TabList/TabList.component.js delete mode 100644 libs/juno-ui-components/src/components/TabList/TabList.stories.js delete mode 100644 libs/juno-ui-components/src/components/TabList/TabList.test.js delete mode 100644 libs/juno-ui-components/src/components/TabList/index.js delete mode 100644 libs/juno-ui-components/src/components/TabNavigation/TabNavigation.component.js delete mode 100644 libs/juno-ui-components/src/components/TabNavigation/TabNavigation.stories.js delete mode 100644 libs/juno-ui-components/src/components/TabNavigation/TabNavigation.test.js delete mode 100644 libs/juno-ui-components/src/components/TabNavigation/index.js delete mode 100644 libs/juno-ui-components/src/components/TabNavigationItem/TabNavigationItem.component.js delete mode 100644 libs/juno-ui-components/src/components/TabNavigationItem/TabNavigationItem.stories.js delete mode 100644 libs/juno-ui-components/src/components/TabNavigationItem/TabNavigationItem.test.js delete mode 100644 libs/juno-ui-components/src/components/TabNavigationItem/index.js delete mode 100644 libs/juno-ui-components/src/components/TabPanel/TabPanel.component.js delete mode 100644 libs/juno-ui-components/src/components/TabPanel/TabPanel.stories.js delete mode 100644 libs/juno-ui-components/src/components/TabPanel/TabPanel.test.js delete mode 100644 libs/juno-ui-components/src/components/TabPanel/index.js delete mode 100644 libs/juno-ui-components/src/components/Tabs/Tabs.component.js delete mode 100644 libs/juno-ui-components/src/components/Tabs/Tabs.stories.js delete mode 100644 libs/juno-ui-components/src/components/Tabs/Tabs.test.js delete mode 100644 libs/juno-ui-components/src/components/Tabs/index.js delete mode 100644 libs/juno-ui-components/src/components/TextInput/TextInput.component.js delete mode 100644 libs/juno-ui-components/src/components/TextInput/TextInput.stories.js delete mode 100644 libs/juno-ui-components/src/components/TextInput/TextInput.test.js delete mode 100644 libs/juno-ui-components/src/components/TextInput/index.js delete mode 100644 libs/juno-ui-components/src/components/TextInput/textinput.scss delete mode 100644 libs/juno-ui-components/src/components/TextInputRow/TextInputRow.component.js delete mode 100644 libs/juno-ui-components/src/components/TextInputRow/TextInputRow.stories.js delete mode 100644 libs/juno-ui-components/src/components/TextInputRow/TextInputRow.test.js delete mode 100644 libs/juno-ui-components/src/components/TextInputRow/index.js delete mode 100644 libs/juno-ui-components/src/components/Textarea/Textarea.component.js delete mode 100644 libs/juno-ui-components/src/components/Textarea/Textarea.stories.js delete mode 100644 libs/juno-ui-components/src/components/Textarea/Textarea.test.js delete mode 100644 libs/juno-ui-components/src/components/Textarea/index.js delete mode 100644 libs/juno-ui-components/src/components/TextareaRow/TextareaRow.component.js delete mode 100644 libs/juno-ui-components/src/components/TextareaRow/TextareaRow.stories.js delete mode 100644 libs/juno-ui-components/src/components/TextareaRow/TextareaRow.test.js delete mode 100644 libs/juno-ui-components/src/components/TextareaRow/index.js delete mode 100644 libs/juno-ui-components/src/components/Toast/Toast.component.js delete mode 100644 libs/juno-ui-components/src/components/Toast/Toast.stories.js delete mode 100644 libs/juno-ui-components/src/components/Toast/Toast.test.js delete mode 100644 libs/juno-ui-components/src/components/Toast/index.js delete mode 100644 libs/juno-ui-components/src/components/Tooltip/Tooltip.component.js delete mode 100644 libs/juno-ui-components/src/components/Tooltip/Tooltip.stories.js delete mode 100644 libs/juno-ui-components/src/components/Tooltip/Tooltip.test.js delete mode 100644 libs/juno-ui-components/src/components/Tooltip/index.js delete mode 100644 libs/juno-ui-components/src/components/Tooltip/useTooltip.js delete mode 100644 libs/juno-ui-components/src/components/TooltipContent/TooltipContent.component.js delete mode 100644 libs/juno-ui-components/src/components/TooltipContent/TooltipContent.stories.js delete mode 100644 libs/juno-ui-components/src/components/TooltipContent/TooltipContent.test.js delete mode 100644 libs/juno-ui-components/src/components/TooltipContent/index.js delete mode 100644 libs/juno-ui-components/src/components/TooltipTrigger/TooltipTrigger.component.js delete mode 100644 libs/juno-ui-components/src/components/TooltipTrigger/TooltipTrigger.stories.js delete mode 100644 libs/juno-ui-components/src/components/TooltipTrigger/TooltipTrigger.test.js delete mode 100644 libs/juno-ui-components/src/components/TooltipTrigger/index.js delete mode 100644 libs/juno-ui-components/src/components/TopNavigation/TopNavigation.component.js delete mode 100644 libs/juno-ui-components/src/components/TopNavigation/TopNavigation.stories.js delete mode 100644 libs/juno-ui-components/src/components/TopNavigation/TopNavigation.test.js delete mode 100644 libs/juno-ui-components/src/components/TopNavigation/index.js delete mode 100644 libs/juno-ui-components/src/components/TopNavigationItem/TopNavigationItem.component.js delete mode 100644 libs/juno-ui-components/src/components/TopNavigationItem/TopNavigationItem.stories.js delete mode 100644 libs/juno-ui-components/src/components/TopNavigationItem/TopNavigationItem.test.js delete mode 100644 libs/juno-ui-components/src/components/TopNavigationItem/index.js delete mode 100644 libs/juno-ui-components/src/components/withDeprecationWarning/index.js delete mode 100644 libs/juno-ui-components/src/components/withDeprecationWarning/withDeprecationWarning.component.js delete mode 100644 libs/juno-ui-components/src/components/withDeprecationWarning/withDeprecationWarning.test.js delete mode 100644 libs/juno-ui-components/src/docs/ColorPalette/ColorCard.jsx delete mode 100644 libs/juno-ui-components/src/docs/ColorPalette/ColorPalette.jsx delete mode 100644 libs/juno-ui-components/src/docs/ColorPalette/JunoColorPalette.jsx delete mode 100644 libs/juno-ui-components/src/docs/ColorPalette/TailwindColors.js delete mode 100644 libs/juno-ui-components/src/docs/ColorPalette/TextColorCard.jsx delete mode 100644 libs/juno-ui-components/src/docs/ColorPalette/generateTailwindThemeClassesJson.js delete mode 100644 libs/juno-ui-components/src/docs/JunoComponentWrapper/JunoComponentWrapper.jsx delete mode 100644 libs/juno-ui-components/src/docs/colors.mdx delete mode 100644 libs/juno-ui-components/src/docs/img/Schwan.jpg delete mode 100644 libs/juno-ui-components/src/docs/navigation.mdx delete mode 100644 libs/juno-ui-components/src/docsHidden/examplePage.mdx delete mode 100644 libs/juno-ui-components/src/dummyComponents/DummyComponent.js delete mode 100644 libs/juno-ui-components/src/dummyComponents/DummyComponentList.js delete mode 100644 libs/juno-ui-components/src/global.scss delete mode 100644 libs/juno-ui-components/src/hooks/useTimeout.js delete mode 100644 libs/juno-ui-components/src/img/app_bg_example.svg delete mode 100644 libs/juno-ui-components/src/img/ccloud_shape.svg delete mode 100644 libs/juno-ui-components/src/img/icon_arrow_down.svg delete mode 100644 libs/juno-ui-components/src/img/sap_logo.svg delete mode 100644 libs/juno-ui-components/src/index.js delete mode 100644 libs/juno-ui-components/src/utils.js delete mode 100644 libs/juno-ui-components/tailwind.config.js delete mode 100644 libs/juno-ui-components/test/__mocks__/styleMock.js delete mode 100644 libs/juno-ui-components/test/__mocks__/svg.js delete mode 100644 libs/juno-ui-components/test/__mocks__/svgLib.js delete mode 100644 libs/oauth/LICENSE delete mode 100644 libs/oauth/README.md delete mode 100644 libs/oauth/__tests__/__utils__/globalsMock.js delete mode 100644 libs/oauth/__tests__/__utils__/idTokenMock.js delete mode 100644 libs/oauth/__tests__/__utils__/oidcConfigMock.js delete mode 100644 libs/oauth/__tests__/codeFlow.test.js delete mode 100644 libs/oauth/__tests__/implicitFlow.test.js delete mode 100644 libs/oauth/__tests__/mockedSession.test.js delete mode 100644 libs/oauth/__tests__/oidcConfig.test.js delete mode 100644 libs/oauth/__tests__/oidcSession.test.js delete mode 100644 libs/oauth/__tests__/tokenHelpers.test.js delete mode 100644 libs/oauth/esbuild.config.js delete mode 100644 libs/oauth/package.json delete mode 100644 libs/oauth/src/codeFlow.js delete mode 100644 libs/oauth/src/implicitFlow.js delete mode 100644 libs/oauth/src/index.js delete mode 100644 libs/oauth/src/mockedSession.js delete mode 100644 libs/oauth/src/oidcConfig.js delete mode 100644 libs/oauth/src/oidcSession.js delete mode 100644 libs/oauth/src/oidcState.js delete mode 100644 libs/oauth/src/tokenHelpers.js delete mode 100644 libs/oauth/src/utils.js delete mode 100644 libs/policy-engine/LICENSE delete mode 100644 libs/policy-engine/README.md delete mode 100644 libs/policy-engine/package.json delete mode 100644 libs/policy-engine/rollup.config.js delete mode 100644 libs/policy-engine/src/debugTrace.js delete mode 100644 libs/policy-engine/src/debugTrace.test.js delete mode 100644 libs/policy-engine/src/engine.js delete mode 100644 libs/policy-engine/src/engine.test.js delete mode 100644 libs/policy-engine/src/evaluator.js delete mode 100644 libs/policy-engine/src/evaluator.test.js delete mode 100644 libs/policy-engine/src/index.js delete mode 100644 libs/policy-engine/src/lexer.js delete mode 100644 libs/policy-engine/src/lexer.test.js delete mode 100644 libs/policy-engine/src/parser.js delete mode 100644 libs/policy-engine/src/parser.test.js diff --git a/libs/communicator/.gitignore b/libs/communicator/.gitignore deleted file mode 100644 index 378eac25d..000000000 --- a/libs/communicator/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build diff --git a/libs/communicator/LICENSE b/libs/communicator/LICENSE deleted file mode 100644 index 261eeb9e9..000000000 --- a/libs/communicator/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/libs/communicator/README.md b/libs/communicator/README.md deleted file mode 100644 index 0df050baf..000000000 --- a/libs/communicator/README.md +++ /dev/null @@ -1,172 +0,0 @@ -# Communicator - -The "Communicator" library empowers seamless message exchange across various contexts, including multiple tabs on the same origin, by utilizing events. It offers a versatile range of communication options, including broadcast events for widespread interaction and one-to-one messaging capabilities. - -The library employs a set of methods, each complementing its counterpart: - -- **broadcast <-> watch**: These methods enable efficient communication between sender and receiver. When a sender employs the `broadcast` method to transmit an event, it must be monitored by a recipient using the `watch` method. This mechanism ensures that information is disseminated to the intended audience. - -- **get <-> onGet**: These methods are tailor-made for one-to-one communication, allowing precise exchanges between sender and recipient. Similar to broadcast and watch, if a sender utilizes the `get` method, the corresponding recipient should listen and respond using the `onGet` method. This approach ensures that data flows seamlessly in a directed manner. - -The Communicator library introduces the `crossWindow` option, which enhances its capabilities by enabling cross-tab communication. This feature facilitates communication between tabs, providing additional flexibility and expanding the library's utility. - -## Installation - -You can install the library in various ways: - -1. Via `package.json`: - - ```json - "dependencies": { - "communicator": "https://assets.juno.global.cloud.sap/libs/communicator@latest/package.tgz" - } - ``` - -2. Via `import`: - - ```javascript - import { - broadcast, - watch, - get, - onGet, - } from "https://assets.juno.global.cloud.sap/libs/communicator@latest/build/index.js" - ``` - -3. Via `importmap`: - - ```html - - - - ``` - -## Usage - -To use the library, you can import the necessary functions: - -```javascript -import { broadcast, watch, get, onGet } from "communicator" -``` - -### `broadcast(name, data, options) ⇒ void` - -Use this function to send messages via BroadcastChannel across different contexts, such as multiple tabs on the same origin. - -- `name` (required): The message name. -- `data` (required, null is allowed): The message data. -- `options` (optional): An object with options - - `debug` (boolean, false by default): Set this to `true` for debugging purposes. - - `crossWindow` (boolean, false by default): Set this to `true` to enable cross-window communication. - -Example: - -```javascript -import { broadcast } from "communicator" - -broadcast( - "AUTH_TOKEN_UPDATED", - { token: "TOKEN" }, - { - debug: true, - crossWindow: false, - } -) -``` - -### `watch(name, callback, options) ⇒ function` - -Register a listener for a specific message. Messages are observed across contexts. - -- `name` (required): The message name. -- `callback` (required): A function that is executed when a message is sent for the registered name. It should have the following signature: `(data, { sourceWindowId, thisWindowId }) => void`. - -For the `options` object, you can mention that it includes the following properties: - -- `debug` (boolean, false by default): Set this to `true` for debugging purposes. - -Example: - -```javascript -import { watch } from "communicator" - -const unwatch = watch( - "AUTH_TOKEN_UPDATED", - (data, { sourceWindowId, thisWindowId }) => { - // Receive message data - console.log(data) - }, - { - debug: false, // Default - } -) - -// To unregister the listener, call unwatch() -unwatch() -``` - -### `get(name, callback, options) ⇒ function` - -Request a message by name and receive the data with the callback. - -- `name` (required): The message name. -- `callback` (required): A function that is executed upon receiving a response. -- `options` (optional): An object with the following properties: - - `getOptions` (object): An object that allows customization of the get request. - - `debug` (boolean, false by default): Set this to `true` for debugging purposes. - -Example: - -```javascript -import { get } from "communicator" - -const cancel = get( - "AUTH_TOKEN_UPDATED", - (data, { sourceWindowId, thisWindowId }) => { - // Receive message data - console.log(data) - }, - { - debug: false, // Default - } -) - -// To cancel the request, call cancel() -cancel() -``` - -### `onGet(name, callback, options) ⇒ function` - -Use this function to respond to get messages. - -- `name` (required): The message name. -- `callback` (required): A function that is executed when get events occur and returns the data. -- `options` (optional): An object with the following properties: - - - `debug` (boolean, false by default): Set this to `true` for debugging purposes. - -Example: - -```javascript -import { onGet } from "communicator" - -const unwatch = onGet( - "AUTH_TOKEN_UPDATED", - (getOptions, { sourceWindowId, thisWindowId }) => { - // Return data - return { name: "test" } - }, - { - debug: false, // Default - } -) - -// To unregister the response, call unwatch() -unwatch() -``` diff --git a/libs/communicator/dev/build.js b/libs/communicator/dev/build.js deleted file mode 100644 index ce05871b9..000000000 --- a/libs/communicator/dev/build.js +++ /dev/null @@ -1,183 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -// src/index.js -var uniqString = () => Math.random().toString(36).substring(2); -window.__junoCommunicatorTabId = window.__junoCommunicatorTabId || uniqString(); -window.__junoEventListeners = window.__junoEventListeners || { - broadcast: {}, - get: {} -}; -var log = (...params) => console.log("Communicator Debug:", ...params); -var warn = (...params) => console.warn("Communicator Warning:", ...params); -var error = (...params) => console.error("Communicator Error:", ...params); -var addListener = (type, event, listener) => { - if (!window.__junoEventListeners[type]?.[event]) { - window.__junoEventListeners[type][event] = []; - } - window.__junoEventListeners[type][event].push(listener); -}; -var removeListener = (type, event, listener) => { - if (!window.__junoEventListeners[type]?.[event]) - return; - window.__junoEventListeners[type][event] = window.__junoEventListeners[type][event].filter((l) => l !== listener); -}; -var listenerWrapper = (callback) => (data, options = {}) => { - return new Promise(async (resolve) => { - callback(data, options); - resolve(); - }); -}; -if (typeof BroadcastChannel === "undefined") { - console.log( - "BroadcastChannel is not supported in this browser. Use fake BroadcastChannel." - ); - window.BroadcastChannel = function() { - return { - postMessage: () => null, - onmessage: () => null, - close: () => null - }; - }; -} else { - console.log("BroadcastChannel is supported in this browser."); -} -var crossWindowEventBridge = new BroadcastChannel( - "__JUNO_CROSS_WINDOW_EVENT_BRIDGE__" -); -crossWindowEventBridge.onmessage = (e) => { - const { type, name, data, sourceWindowId } = e.data || {}; - if (type === "broadcast") { - window.__junoEventListeners["broadcast"]?.[name]?.forEach((listener) => { - try { - listener(data, { - crossWindow: true, - sourceWindowId, - thisWindowId: window.__junoCommunicatorTabId - }); - } catch (e2) { - warn(e2); - } - }); - } -}; -var broadcast = (name, data, options = {}) => { - try { - if (typeof name !== "string") - throw new Error("(broadcast) the message name must be given."); - if (data === void 0) - data = null; - const { debug, crossWindow: crossWindow2 = false, ...unknownOptions } = options || {}; - const unknownOptionsKeys = Object.keys(unknownOptions); - if (unknownOptionsKeys.length > 0) - warn(`(broadcast) unknown options: ${unknownOptionsKeys.join(", ")}`); - if (debug != void 0 && typeof debug !== "boolean") - warn("(broadcast) debug must be a boolean"); - if (typeof crossWindow2 !== "boolean") - warn("(broadcast) crossWindow must be a boolean"); - if (debug) { - console.log("===================1"); - log( - `broadcast ${crossWindow2 ? "cross-window" : "intra-window"} message ${name} with data `, - data - ); - console.log("===================2"); - } - window.__junoEventListeners["broadcast"]?.[name]?.forEach((listener) => { - try { - listener(data, { - sourceWindowId: window.__junoCommunicatorTabId, - thisWindowId: window.__junoCommunicatorTabId - }); - } catch (e) { - warn(e); - } - }); - if (crossWindow2) { - crossWindowEventBridge.postMessage({ - type: "broadcast", - name, - data, - sourceWindowId: window.__junoCommunicatorTabId - }); - } - } catch (e) { - error(e.message); - } -}; -var watch = (name, callback, options = {}) => { - try { - if (typeof name !== "string") - throw new Error("(watch) the message name must be given."); - if (typeof callback !== "function") - throw new Error("(watch) the callback parameter must be a function."); - const { debug, ...unknownOptions } = options || {}; - const unknownOptionsKeys = Object.keys(unknownOptions); - if (unknownOptionsKeys.length > 0) - warn(`(watch) unknown options: ${unknownOptionsKeys.join(", ")}`); - if (debug) - log( - `watch for ${crossWindow ? "cross-window" : "intra-window"} message ${name}` - ); - addListener("broadcast", name, listenerWrapper(callback)); - return () => removeListener("broadcast", name, listenerWrapper(callback)); - } catch (e) { - error(e.message); - } -}; -var get = (name, callback, options = {}) => { - try { - if (typeof name !== "string") - throw new Error("(get) the message name must be given."); - if (typeof callback !== "function") - throw new Error("(get) the callback parameter must be a function."); - const { debug, getOptions, ...unknownOptions } = options || {}; - const unknownOptionsKeys = Object.keys(unknownOptions); - if (unknownOptionsKeys.length > 0) - warn(`(get) unknown options: ${unknownOptionsKeys.join(", ")}`); - if (debug) - log(`get data for intra-window message ${name}`); - if (window.__junoEventListeners["get"]?.[name]?.length === 0) - return; - window.__junoEventListeners["get"][name]?.forEach((listener) => { - try { - const data = listener(options?.getOptions); - callback(data, { - sourceWindowId: window.__junoCommunicatorTabId, - thisWindowId: window.__junoCommunicatorTabId - }); - } catch (e) { - warn(e); - } - }); - } catch (e) { - error(e.message); - } -}; -var onGet = (name, callback, options = {}) => { - try { - if (typeof name !== "string") - throw new Error("(onGet) the message name must be given."); - if (typeof callback !== "function") - throw new Error("(onGet) the callback parameter must be a function."); - const { debug, crossWindow: crossWindow2 = false, ...unknownOptions } = options || {}; - const unknownOptionsKeys = Object.keys(unknownOptions); - if (unknownOptionsKeys.length > 0) - warn(`(onGet) unknown options: ${unknownOptionsKeys.join(", ")}`); - if (debug) - log(`send data for intra-window message ${name}`); - addListener("get", name, listenerWrapper(callback)); - return () => removeListener("get", name, listenerWrapper(callback)); - } catch (e) { - error(e.message); - } -}; -export { - broadcast, - get, - onGet, - watch -}; -//# sourceMappingURL=build.js.map diff --git a/libs/communicator/dev/build.js.map b/libs/communicator/dev/build.js.map deleted file mode 100644 index a537077c0..000000000 --- a/libs/communicator/dev/build.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../src/index.js"], - "sourcesContent": ["/**\n *\n * @returns epoch timestamp (count of seconds since 1970)\n */\nconst uniqString = () => Math.random().toString(36).substring(2)\n\n// create an uniq id for current window (current context)\n// this id is used to identify the current when intra-window communication is used\nwindow.__junoCommunicatorTabId = window.__junoCommunicatorTabId || uniqString()\n\nwindow.__junoEventListeners = window.__junoEventListeners || {\n broadcast: {},\n get: {},\n}\n\nconst log = (...params) => console.log(\"Communicator Debug:\", ...params)\nconst warn = (...params) => console.warn(\"Communicator Warning:\", ...params)\nconst error = (...params) => console.error(\"Communicator Error:\", ...params)\n\nconst addListener = (type, event, listener) => {\n if (!window.__junoEventListeners[type]?.[event]) {\n window.__junoEventListeners[type][event] = []\n }\n window.__junoEventListeners[type][event].push(listener)\n}\n\nconst removeListener = (type, event, listener) => {\n if (!window.__junoEventListeners[type]?.[event]) return\n window.__junoEventListeners[type][event] = window.__junoEventListeners[type][\n event\n ].filter((l) => l !== listener)\n}\n\nconst listenerWrapper =\n (callback) =>\n (data, options = {}) => {\n // Create a promise that will be resolved when the listener is executed\n return new Promise(async (resolve) => {\n callback(data, options)\n resolve()\n })\n }\n\nif (typeof BroadcastChannel === \"undefined\") {\n // BroadcastChannel is not available\n console.log(\n \"BroadcastChannel is not supported in this browser. Use fake BroadcastChannel.\"\n )\n window.BroadcastChannel = function () {\n return {\n postMessage: () => null,\n onmessage: () => null,\n close: () => null,\n }\n }\n} else {\n // BroadcastChannel is available\n console.log(\"BroadcastChannel is supported in this browser.\")\n}\n\nconst crossWindowEventBridge = new BroadcastChannel(\n \"__JUNO_CROSS_WINDOW_EVENT_BRIDGE__\"\n)\n\ncrossWindowEventBridge.onmessage = (e) => {\n const { type, name, data, sourceWindowId } = e.data || {}\n\n if (type === \"broadcast\") {\n window.__junoEventListeners[\"broadcast\"]?.[name]?.forEach((listener) => {\n try {\n listener(data, {\n crossWindow: true,\n sourceWindowId,\n thisWindowId: window.__junoCommunicatorTabId,\n })\n } catch (e) {\n warn(e)\n }\n })\n }\n}\n\n/**\n * Send messages via BroadcastChannel across contexts (e.g. several tabs on\n * the same origin). The last message is stored by default. However, it\n * is possible to influence the storage period using the expire option.\n * @param {string} name\n * @param {any} data\n * @param {object} options (optional) allowed options are debug:undefined|boolean and expires:undefined|number\n * @returns void\n */\nconst broadcast = (name, data, options = {}) => {\n try {\n if (typeof name !== \"string\")\n throw new Error(\"(broadcast) the message name must be given.\")\n if (data === undefined) data = null\n\n const { debug, crossWindow = false, ...unknownOptions } = options || {}\n const unknownOptionsKeys = Object.keys(unknownOptions)\n if (unknownOptionsKeys.length > 0)\n warn(`(broadcast) unknown options: ${unknownOptionsKeys.join(\", \")}`)\n if (debug != undefined && typeof debug !== \"boolean\")\n warn(\"(broadcast) debug must be a boolean\")\n if (typeof crossWindow !== \"boolean\")\n warn(\"(broadcast) crossWindow must be a boolean\")\n\n if (debug) {\n console.log(\"===================1\")\n log(\n `broadcast ${\n crossWindow ? \"cross-window\" : \"intra-window\"\n } message ${name} with data `,\n data\n )\n console.log(\"===================2\")\n }\n\n window.__junoEventListeners[\"broadcast\"]?.[name]?.forEach((listener) => {\n try {\n listener(data, {\n sourceWindowId: window.__junoCommunicatorTabId,\n thisWindowId: window.__junoCommunicatorTabId,\n })\n } catch (e) {\n warn(e)\n }\n })\n\n if (crossWindow) {\n crossWindowEventBridge.postMessage({\n type: \"broadcast\",\n name,\n data,\n sourceWindowId: window.__junoCommunicatorTabId,\n })\n }\n } catch (e) {\n error(e.message)\n }\n}\n\n/**\n * Register a listener for a specific message. Messages are observed\n * across contexts (e.g. several tabs on the same origin).\n * If a current saved message already exists for the name,\n * then the listener is executed immediately with this message.\n * The expires option set by the \"send\" method has an effect here.\n * In addition, the age of the listened messages can be determined\n * with the youngerThan option.\n * @param {string} name\n * @param {function} callback:(data) => void\n * @param {object} options\n * @returns {function} unregister:()=>void, a function to stop listening\n */\nconst watch = (name, callback, options = {}) => {\n try {\n if (typeof name !== \"string\")\n throw new Error(\"(watch) the message name must be given.\")\n if (typeof callback !== \"function\")\n throw new Error(\"(watch) the callback parameter must be a function.\")\n\n const { debug, ...unknownOptions } = options || {}\n const unknownOptionsKeys = Object.keys(unknownOptions)\n if (unknownOptionsKeys.length > 0)\n warn(`(watch) unknown options: ${unknownOptionsKeys.join(\", \")}`)\n\n if (debug)\n log(\n `watch for ${\n crossWindow ? \"cross-window\" : \"intra-window\"\n } message ${name}`\n )\n\n addListener(\"broadcast\", name, listenerWrapper(callback))\n\n return () => removeListener(\"broadcast\", name, listenerWrapper(callback))\n } catch (e) {\n error(e.message)\n }\n}\n\n/**\n * This function implements a 1:1 communication\n * @param {string} name\n * @param {function} callback\n * @param {object} options\n * @returns cancel function\n */\nconst get = (name, callback, options = {}) => {\n try {\n if (typeof name !== \"string\")\n throw new Error(\"(get) the message name must be given.\")\n if (typeof callback !== \"function\")\n throw new Error(\"(get) the callback parameter must be a function.\")\n const { debug, getOptions, ...unknownOptions } = options || {}\n const unknownOptionsKeys = Object.keys(unknownOptions)\n if (unknownOptionsKeys.length > 0)\n warn(`(get) unknown options: ${unknownOptionsKeys.join(\", \")}`)\n if (debug) log(`get data for intra-window message ${name}`)\n\n if (window.__junoEventListeners[\"get\"]?.[name]?.length === 0) return\n\n // console.log(\"==============get\", window.__junoEventListeners[\"get\"]?.[name])\n window.__junoEventListeners[\"get\"][name]?.forEach((listener) => {\n try {\n const data = listener(options?.getOptions)\n callback(data, {\n sourceWindowId: window.__junoCommunicatorTabId,\n thisWindowId: window.__junoCommunicatorTabId,\n })\n } catch (e) {\n warn(e)\n }\n })\n } catch (e) {\n error(e.message)\n }\n}\n\n/**\n * Listen to get messages\n * @param {string} name\n * @param {function} callback\n * @param {object} options\n * @returns cancel function\n */\nconst onGet = (name, callback, options = {}) => {\n try {\n if (typeof name !== \"string\")\n throw new Error(\"(onGet) the message name must be given.\")\n if (typeof callback !== \"function\")\n throw new Error(\"(onGet) the callback parameter must be a function.\")\n const { debug, crossWindow = false, ...unknownOptions } = options || {}\n const unknownOptionsKeys = Object.keys(unknownOptions)\n if (unknownOptionsKeys.length > 0)\n warn(`(onGet) unknown options: ${unknownOptionsKeys.join(\", \")}`)\n if (debug) log(`send data for intra-window message ${name}`)\n\n addListener(\"get\", name, listenerWrapper(callback))\n\n return () => removeListener(\"get\", name, listenerWrapper(callback))\n } catch (e) {\n error(e.message)\n }\n}\n\nexport { broadcast, watch, get, onGet }\n"], - "mappings": ";AAIA,IAAM,aAAa,MAAM,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC;AAI/D,OAAO,0BAA0B,OAAO,2BAA2B,WAAW;AAE9E,OAAO,uBAAuB,OAAO,wBAAwB;AAAA,EAC3D,WAAW,CAAC;AAAA,EACZ,KAAK,CAAC;AACR;AAEA,IAAM,MAAM,IAAI,WAAW,QAAQ,IAAI,uBAAuB,GAAG,MAAM;AACvE,IAAM,OAAO,IAAI,WAAW,QAAQ,KAAK,yBAAyB,GAAG,MAAM;AAC3E,IAAM,QAAQ,IAAI,WAAW,QAAQ,MAAM,uBAAuB,GAAG,MAAM;AAE3E,IAAM,cAAc,CAAC,MAAM,OAAO,aAAa;AAC7C,MAAI,CAAC,OAAO,qBAAqB,IAAI,IAAI,KAAK,GAAG;AAC/C,WAAO,qBAAqB,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA,EAC9C;AACA,SAAO,qBAAqB,IAAI,EAAE,KAAK,EAAE,KAAK,QAAQ;AACxD;AAEA,IAAM,iBAAiB,CAAC,MAAM,OAAO,aAAa;AAChD,MAAI,CAAC,OAAO,qBAAqB,IAAI,IAAI,KAAK;AAAG;AACjD,SAAO,qBAAqB,IAAI,EAAE,KAAK,IAAI,OAAO,qBAAqB,IAAI,EACzE,KACF,EAAE,OAAO,CAAC,MAAM,MAAM,QAAQ;AAChC;AAEA,IAAM,kBACJ,CAAC,aACD,CAAC,MAAM,UAAU,CAAC,MAAM;AAEtB,SAAO,IAAI,QAAQ,OAAO,YAAY;AACpC,aAAS,MAAM,OAAO;AACtB,YAAQ;AAAA,EACV,CAAC;AACH;AAEF,IAAI,OAAO,qBAAqB,aAAa;AAE3C,UAAQ;AAAA,IACN;AAAA,EACF;AACA,SAAO,mBAAmB,WAAY;AACpC,WAAO;AAAA,MACL,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM;AAAA,MACjB,OAAO,MAAM;AAAA,IACf;AAAA,EACF;AACF,OAAO;AAEL,UAAQ,IAAI,gDAAgD;AAC9D;AAEA,IAAM,yBAAyB,IAAI;AAAA,EACjC;AACF;AAEA,uBAAuB,YAAY,CAAC,MAAM;AACxC,QAAM,EAAE,MAAM,MAAM,MAAM,eAAe,IAAI,EAAE,QAAQ,CAAC;AAExD,MAAI,SAAS,aAAa;AACxB,WAAO,qBAAqB,WAAW,IAAI,IAAI,GAAG,QAAQ,CAAC,aAAa;AACtE,UAAI;AACF,iBAAS,MAAM;AAAA,UACb,aAAa;AAAA,UACb;AAAA,UACA,cAAc,OAAO;AAAA,QACvB,CAAC;AAAA,MACH,SAASA,IAAP;AACA,aAAKA,EAAC;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAWA,IAAM,YAAY,CAAC,MAAM,MAAM,UAAU,CAAC,MAAM;AAC9C,MAAI;AACF,QAAI,OAAO,SAAS;AAClB,YAAM,IAAI,MAAM,6CAA6C;AAC/D,QAAI,SAAS;AAAW,aAAO;AAE/B,UAAM,EAAE,OAAO,aAAAC,eAAc,OAAO,GAAG,eAAe,IAAI,WAAW,CAAC;AACtE,UAAM,qBAAqB,OAAO,KAAK,cAAc;AACrD,QAAI,mBAAmB,SAAS;AAC9B,WAAK,gCAAgC,mBAAmB,KAAK,IAAI,GAAG;AACtE,QAAI,SAAS,UAAa,OAAO,UAAU;AACzC,WAAK,qCAAqC;AAC5C,QAAI,OAAOA,iBAAgB;AACzB,WAAK,2CAA2C;AAElD,QAAI,OAAO;AACT,cAAQ,IAAI,sBAAsB;AAClC;AAAA,QACE,aACEA,eAAc,iBAAiB,0BACrB;AAAA,QACZ;AAAA,MACF;AACA,cAAQ,IAAI,sBAAsB;AAAA,IACpC;AAEA,WAAO,qBAAqB,WAAW,IAAI,IAAI,GAAG,QAAQ,CAAC,aAAa;AACtE,UAAI;AACF,iBAAS,MAAM;AAAA,UACb,gBAAgB,OAAO;AAAA,UACvB,cAAc,OAAO;AAAA,QACvB,CAAC;AAAA,MACH,SAAS,GAAP;AACA,aAAK,CAAC;AAAA,MACR;AAAA,IACF,CAAC;AAED,QAAIA,cAAa;AACf,6BAAuB,YAAY;AAAA,QACjC,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,gBAAgB,OAAO;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,EACF,SAAS,GAAP;AACA,UAAM,EAAE,OAAO;AAAA,EACjB;AACF;AAeA,IAAM,QAAQ,CAAC,MAAM,UAAU,UAAU,CAAC,MAAM;AAC9C,MAAI;AACF,QAAI,OAAO,SAAS;AAClB,YAAM,IAAI,MAAM,yCAAyC;AAC3D,QAAI,OAAO,aAAa;AACtB,YAAM,IAAI,MAAM,oDAAoD;AAEtE,UAAM,EAAE,OAAO,GAAG,eAAe,IAAI,WAAW,CAAC;AACjD,UAAM,qBAAqB,OAAO,KAAK,cAAc;AACrD,QAAI,mBAAmB,SAAS;AAC9B,WAAK,4BAA4B,mBAAmB,KAAK,IAAI,GAAG;AAElE,QAAI;AACF;AAAA,QACE,aACE,cAAc,iBAAiB,0BACrB;AAAA,MACd;AAEF,gBAAY,aAAa,MAAM,gBAAgB,QAAQ,CAAC;AAExD,WAAO,MAAM,eAAe,aAAa,MAAM,gBAAgB,QAAQ,CAAC;AAAA,EAC1E,SAAS,GAAP;AACA,UAAM,EAAE,OAAO;AAAA,EACjB;AACF;AASA,IAAM,MAAM,CAAC,MAAM,UAAU,UAAU,CAAC,MAAM;AAC5C,MAAI;AACF,QAAI,OAAO,SAAS;AAClB,YAAM,IAAI,MAAM,uCAAuC;AACzD,QAAI,OAAO,aAAa;AACtB,YAAM,IAAI,MAAM,kDAAkD;AACpE,UAAM,EAAE,OAAO,YAAY,GAAG,eAAe,IAAI,WAAW,CAAC;AAC7D,UAAM,qBAAqB,OAAO,KAAK,cAAc;AACrD,QAAI,mBAAmB,SAAS;AAC9B,WAAK,0BAA0B,mBAAmB,KAAK,IAAI,GAAG;AAChE,QAAI;AAAO,UAAI,qCAAqC,MAAM;AAE1D,QAAI,OAAO,qBAAqB,KAAK,IAAI,IAAI,GAAG,WAAW;AAAG;AAG9D,WAAO,qBAAqB,KAAK,EAAE,IAAI,GAAG,QAAQ,CAAC,aAAa;AAC9D,UAAI;AACF,cAAM,OAAO,SAAS,SAAS,UAAU;AACzC,iBAAS,MAAM;AAAA,UACb,gBAAgB,OAAO;AAAA,UACvB,cAAc,OAAO;AAAA,QACvB,CAAC;AAAA,MACH,SAAS,GAAP;AACA,aAAK,CAAC;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH,SAAS,GAAP;AACA,UAAM,EAAE,OAAO;AAAA,EACjB;AACF;AASA,IAAM,QAAQ,CAAC,MAAM,UAAU,UAAU,CAAC,MAAM;AAC9C,MAAI;AACF,QAAI,OAAO,SAAS;AAClB,YAAM,IAAI,MAAM,yCAAyC;AAC3D,QAAI,OAAO,aAAa;AACtB,YAAM,IAAI,MAAM,oDAAoD;AACtE,UAAM,EAAE,OAAO,aAAAA,eAAc,OAAO,GAAG,eAAe,IAAI,WAAW,CAAC;AACtE,UAAM,qBAAqB,OAAO,KAAK,cAAc;AACrD,QAAI,mBAAmB,SAAS;AAC9B,WAAK,4BAA4B,mBAAmB,KAAK,IAAI,GAAG;AAClE,QAAI;AAAO,UAAI,sCAAsC,MAAM;AAE3D,gBAAY,OAAO,MAAM,gBAAgB,QAAQ,CAAC;AAElD,WAAO,MAAM,eAAe,OAAO,MAAM,gBAAgB,QAAQ,CAAC;AAAA,EACpE,SAAS,GAAP;AACA,UAAM,EAAE,OAAO;AAAA,EACjB;AACF;", - "names": ["e", "crossWindow"] -} diff --git a/libs/communicator/dev/index.html b/libs/communicator/dev/index.html deleted file mode 100644 index e21248f37..000000000 --- a/libs/communicator/dev/index.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - Communicator Dev - - - - - -

Communicator Dev Test

-
- - diff --git a/libs/communicator/dev/index.js b/libs/communicator/dev/index.js deleted file mode 100644 index 1f02658e6..000000000 --- a/libs/communicator/dev/index.js +++ /dev/null @@ -1,170 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -const buttonCss = - "padding: 10px; margin: 0 10px; background-color: rgb(67 75 95); border: 1px solid rgb(67 75 95); color: white; border-radius: 5px; cursor: pointer" -const displayCss = "margin: 20px 10px 0 10px;" - -import("./build.js").then(({ broadcast, watch, get, onGet }) => { - console.log("================READY") - - self.broadcast = broadcast - self.watch = watch - self.get = get - self.onGet = onGet - - const root = document.getElementById("root") - - Tester(root) -}) - -const logTemplate = ({ source, target, text, data }) => ` -
-
- Date: ${new Date().toLocaleString()} - Source tab: ${source} - Target tab: ${target} -
-

${text}

-
- ${JSON.stringify(data, null, 2)} -
-
` - -const Tester = (root) => { - const buttonGet = document.createElement("button") - const buttonBroadcast = document.createElement("button") - const buttonGetIntraWindow = document.createElement("button") - const buttonBroadcastIntraWindow = document.createElement("button") - - buttonGet.style.cssText = buttonCss - buttonBroadcast.style.cssText = buttonCss - buttonGetIntraWindow.style.cssText = buttonCss - buttonBroadcastIntraWindow.style.cssText = buttonCss - - const display = document.createElement("div") - display.style.cssText = displayCss - const header = `
Log
` - display.innerHTML = header - const content = document.createElement("div") - content.id = "content" - display.appendChild(content) - - const log = (source, target, text, data) => { - content.innerHTML = `${content.innerHTML}
${logTemplate({ - source, - target, - text, - data, - })}` - } - - watch( - "TEST_BROADCAST", - (data, { sourceWindowId, thisWindowId }) => { - log( - sourceWindowId, - thisWindowId, - `${thisWindowId} (watch): receive data for event TEST_BROADCAST from ${sourceWindowId}`, - data - ) - }, - { crossWindow: true } - ) - - watch( - "TEST_BROADCAST_INTRA_WINDOW", - (data, { sourceWindowId, thisWindowId }) => { - log( - sourceWindowId, - thisWindowId, - `${thisWindowId} (watch): receive data for event TEST_BROADCAST_INTRA_WINDOW from ${sourceWindowId}`, - data - ) - } - ) - - onGet( - "TEST_GET", - (getOptions, { sourceWindowId, thisWindowId }) => { - log( - sourceWindowId, - thisWindowId, - `${thisWindowId} (onGet): send data for event TEST_GET to ${sourceWindowId}`, - getOptions - ) - return `data for event TEST_GET` - }, - { crossWindow: true, debug: false } - ) - - onGet( - "TEST_GET_INTRA_WINDOW", - (getOptions, { sourceWindowId, thisWindowId }) => { - log( - sourceWindowId, - thisWindowId, - `${thisWindowId} (onGet): send data for event TEST_GET_INTRA_WINDOW to ${sourceWindowId}`, - getOptions - ) - return `data for event TEST_GET_INTRA_WINDOW` - } - ) - - buttonGet.innerHTML = "GET (CROSS WINDOW)" - buttonGet.addEventListener("click", () => { - log("", "", `Requesting data for event TEST_GET`, "") - get( - "TEST_GET", - (data, { sourceWindowId, thisWindowId }) => - log( - sourceWindowId, - thisWindowId, - `${thisWindowId} (get): receive data for event TEST_GET from ${sourceWindowId}`, - data - ), - { - debug: false, - crossWindow: true, - } - ) - }) - - buttonBroadcast.innerHTML = "BROADCAST (CROSS WINDOW)" - buttonBroadcast.addEventListener("click", () => { - log("", "", `Broadcasting data for event TEST_BROADCAST`, "") - broadcast("TEST_BROADCAST", `TEST_BROADCAST_DATA`, { - debug: false, - crossWindow: true, - }) - }) - - buttonGetIntraWindow.innerHTML = "GET (INTRA WINDOW)" - buttonGetIntraWindow.addEventListener("click", () => { - log("", "", `Requesting data for event TEST_GET_INTRA_WINDOW`, "") - get("TEST_GET_INTRA_WINDOW", (data, { sourceWindowId, thisWindowId }) => - log( - sourceWindowId, - thisWindowId, - `${thisWindowId} (get): receive data for event TEST_GET_INTRA_WINDOW from ${sourceWindowId}`, - data - ) - ) - }) - - buttonBroadcastIntraWindow.innerHTML = "BROADCAST (INTRA WINDOW)" - buttonBroadcastIntraWindow.addEventListener("click", () => { - log("", "", `Broadcasting data for event TEST_BROADCAST_INTRA_WINDOW`, "") - broadcast("TEST_BROADCAST_INTRA_WINDOW", `TEST_BROADCAST_INTRA_WINDOW_DATA`) - }) - - root.appendChild(buttonGet) - root.appendChild(buttonBroadcast) - root.appendChild(buttonGetIntraWindow) - root.appendChild(buttonBroadcastIntraWindow) - - root.appendChild(display) - //console.log(root) -} diff --git a/libs/communicator/esbuild.config.js b/libs/communicator/esbuild.config.js deleted file mode 100644 index b2bd17d78..000000000 --- a/libs/communicator/esbuild.config.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -const esbuild = require("esbuild") -const pkg = require("./package.json") - -if (!/.+\/.+\.js/.test(pkg.module)) - throw new Error( - "module value is incorrect, use DIR/FILE.js like build/index.js" - ) - -const isProduction = process.env.NODE_ENV === "production" -const IGNORE_EXTERNALS = process.env.IGNORE_EXTERNALS === "true" -const DEV_FOLDER = "dev" -const outfile = isProduction ? pkg.module : `${DEV_FOLDER}/build.js` -const args = process.argv.slice(2) -const watch = args.indexOf("--watch") >= 0 - -esbuild - .context({ - entryPoints: [pkg.source], - outfile, - bundle: true, - minify: isProduction, - target: ["es2020"], - format: "esm", - sourcemap: true, - external: - isProduction && !IGNORE_EXTERNALS - ? Object.keys(pkg.peerDependencies || {}) - : [], - }) - .then(async (ctx) => { - if (watch) { - ctx.watch() - console.log("watching...") - ctx - .serve({ - host: "0.0.0.0", - port: parseInt(process.env.APP_PORT), - servedir: DEV_FOLDER, - }) - .then(({ host, port }) => console.log("serve on", `${host}:${port}`)) - } else { - await ctx.rebuild() - await ctx.dispose() - } - }) - .catch((error) => console.error(error)) diff --git a/libs/communicator/package.json b/libs/communicator/package.json deleted file mode 100644 index 672dbfef3..000000000 --- a/libs/communicator/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "communicator", - "version": "2.2.6", - "description": "Send and receive across tabs", - "author": "UI-Team", - "contributors": [ - "Andreas Pfau" - ], - "repository": "https://github.com/sapcc/juno/tree/main/libs/communicator", - "license": "Apache-2.0", - "source": "src/index.js", - "main": "build/index.js", - "module": "build/index.js", - "scripts": { - "dev": "NODE_ENV=development node ./esbuild.config.js --watch", - "build": "NODE_ENV=production node ./esbuild.config.js", - "test": "jest" - }, - "devDependencies": { - "@babel/preset-env": "^7.20.2", - "babel-jest": "^29.4.2", - "esbuild": "^0.17.6", - "jest": "^29.4.2" - }, - "babel": { - "presets": [ - "@babel/preset-env" - ] - }, - "jest": { - "testEnvironment": "jsdom", - "verbose": true, - "transform": { - "\\.js$": "babel-jest" - }, - "watchPathIgnorePatterns": [ - "/dev/", - "/build/" - ] - } -} diff --git a/libs/communicator/src/index.js b/libs/communicator/src/index.js deleted file mode 100644 index 2ab3fec20..000000000 --- a/libs/communicator/src/index.js +++ /dev/null @@ -1,290 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -const CHANNEL_PREFIX = "JUNO_COMMUNICATOR#" -/** - * - * @returns epoch timestamp (count of seconds since 1970) - */ -const uniqString = () => Math.random().toString(36).substring(2) - -// create an uniq id for current window (current context) -// this id is used to identify the current when intra-window communication is used -window.__junoCommunicatorTabId = window.__junoCommunicatorTabId || uniqString() - -window.__junoEventListeners = window.__junoEventListeners || { - broadcast: {}, - get: {}, -} - -const log = (...params) => console.log("Communicator Debug:", ...params) -const warn = (...params) => console.warn("Communicator Warning:", ...params) -const error = (...params) => console.error("Communicator Error:", ...params) - -const addListener = (type, event, listener) => { - if (!window.__junoEventListeners[type]?.[event]) { - window.__junoEventListeners[type][event] = [] - } - window.__junoEventListeners[type][event].push(listener) -} - -const removeListener = (type, event, listener) => { - if (!window.__junoEventListeners[type]?.[event]) return - window.__junoEventListeners[type][event] = window.__junoEventListeners[type][ - event - ].filter((l) => l !== listener) -} - -// encapsulate the listener in a wrapper that returns a promise -// we don't want to wait for the listener to be executed -const listenerWrapper = - (callback) => - (data, options = {}) => { - // Create a promise that will be resolved when the listener is executed - return new Promise(async (resolve) => { - const result = callback(data, options) - resolve(result) - }) - } - -if (typeof BroadcastChannel === "undefined") { - // BroadcastChannel is not available - console.log( - "BroadcastChannel is not supported in this browser. Use fake BroadcastChannel." - ) - window.BroadcastChannel = function () { - return { - postMessage: () => null, - onmessage: () => null, - close: () => null, - } - } -} else { - // BroadcastChannel is available - console.log("BroadcastChannel is supported in this browser.") -} - -const crossWindowEventBridge = new BroadcastChannel( - "__JUNO_CROSS_WINDOW_EVENT_BRIDGE__" -) - -crossWindowEventBridge.onmessage = (e) => { - const { type, name, data, sourceWindowId } = e.data || {} - - if (type === "broadcast") { - window.__junoEventListeners["broadcast"]?.[name]?.forEach((listener) => { - try { - listener(data, { - crossWindow: true, - sourceWindowId, - thisWindowId: window.__junoCommunicatorTabId, - }) - } catch (e) { - warn(e) - } - }) - } -} - -/** - * Send messages via BroadcastChannel across contexts (e.g. several tabs on - * the same origin). The last message is stored by default. However, it - * is possible to influence the storage period using the expire option. - * @param {string} name - * @param {any} data - * @param {object} options (optional) allowed options are debug:undefined|boolean and expires:undefined|number - * @returns void - */ -const broadcast = (name, data, options = {}) => { - try { - if (typeof name !== "string") - throw new Error("(broadcast) the message name must be given.") - if (data === undefined) data = null - - const { - debug, - crossWindow = false, - consumerID, - ...unknownOptions - } = options || {} - const unknownOptionsKeys = Object.keys(unknownOptions) - if (unknownOptionsKeys.length > 0) - warn(`(broadcast) unknown options: ${unknownOptionsKeys.join(", ")}`) - if (debug != undefined && typeof debug !== "boolean") - warn("(broadcast) debug must be a boolean") - if (typeof crossWindow !== "boolean") - warn("(broadcast) crossWindow must be a boolean") - - // backward compatibility - name = CHANNEL_PREFIX + name - - if (debug) { - log( - `${consumerID ? `(${consumerID})` : ""} broadcast ${ - crossWindow ? "cross-window" : "intra-window" - } message ${name} with data `, - data - ) - // log(`${consumerID ? `(${consumerID})` : ""} broadcast EVENT: ${name}`) - } - - window.__junoEventListeners["broadcast"]?.[name]?.forEach((listener) => { - try { - listener(data, { - sourceWindowId: window.__junoCommunicatorTabId, - thisWindowId: window.__junoCommunicatorTabId, - }) - } catch (e) { - warn(e) - } - }) - - if (crossWindow) { - crossWindowEventBridge.postMessage({ - type: "broadcast", - name, - data, - sourceWindowId: window.__junoCommunicatorTabId, - }) - } - } catch (e) { - error(e.message) - } -} - -/** - * Register a listener for a specific message. Messages are observed - * across contexts (e.g. several tabs on the same origin). - * If a current saved message already exists for the name, - * then the listener is executed immediately with this message. - * The expires option set by the "send" method has an effect here. - * In addition, the age of the listened messages can be determined - * with the youngerThan option. - * @param {string} name - * @param {function} callback:(data) => void - * @param {object} options - * @returns {function} unregister:()=>void, a function to stop listening - */ -const watch = (name, callback, options = {}) => { - try { - if (typeof name !== "string") - throw new Error("(watch) the message name must be given.") - if (typeof callback !== "function") - throw new Error("(watch) the callback parameter must be a function.") - - const { debug, consumerID, ...unknownOptions } = options || {} - const unknownOptionsKeys = Object.keys(unknownOptions) - if (unknownOptionsKeys.length > 0) - warn(`(watch) unknown options: ${unknownOptionsKeys.join(", ")}`) - - // backward compatibility - name = CHANNEL_PREFIX + name - - if (debug) { - log(`${consumerID ? `(${consumerID})` : ""} watch for message ${name}`) - // log(`${consumerID ? `(${consumerID})` : ""} watch EVENT: ${name}`) - } - - addListener("broadcast", name, listenerWrapper(callback)) - - return () => removeListener("broadcast", name, listenerWrapper(callback)) - } catch (e) { - error(e.message) - } -} - -/** - * This function implements a 1:1 communication - * @param {string} name - * @param {function} callback - * @param {object} options - * @returns cancel function - */ -const get = (name, callback, options = {}) => { - try { - if (typeof name !== "string") - throw new Error("(get) the message name must be given.") - if (typeof callback !== "function") - throw new Error("(get) the callback parameter must be a function.") - const { debug, getOptions, consumerID, ...unknownOptions } = options || {} - const unknownOptionsKeys = Object.keys(unknownOptions) - if (unknownOptionsKeys.length > 0) - warn(`(get) unknown options: ${unknownOptionsKeys.join(", ")}`) - - // backward compatibility - name = CHANNEL_PREFIX + "GET:" + name - - if (debug) { - log( - `${ - consumerID ? `(${consumerID})` : "" - } get data for intra-window message ${name}` - ) - // log(`${consumerID ? `(${consumerID})` : ""} get EVENT: ${name}`) - } - - if (window.__junoEventListeners["get"]?.[name]?.length === 0) return - - // console.log("==============get", window.__junoEventListeners["get"]?.[name]) - window.__junoEventListeners["get"][name]?.forEach((onGetListener) => { - try { - // get data from onGetListener - onGetListener(options?.getOptions).then((data) => { - callback(data, { - sourceWindowId: window.__junoCommunicatorTabId, - thisWindowId: window.__junoCommunicatorTabId, - }) - }) - } catch (e) { - warn(e) - } - }) - } catch (e) { - error(e.message) - } -} - -/** - * Listen to get messages - * @param {string} name - * @param {function} callback - * @param {object} options - * @returns cancel function - */ -const onGet = (name, getDataCallback, options = {}) => { - try { - if (typeof name !== "string") - throw new Error("(onGet) the message name must be given.") - if (typeof getDataCallback !== "function") - throw new Error("(onGet) the callback parameter must be a function.") - const { debug, consumerID, ...unknownOptions } = options || {} - const unknownOptionsKeys = Object.keys(unknownOptions) - if (unknownOptionsKeys.length > 0) - warn(`(onGet) unknown options: ${unknownOptionsKeys.join(", ")}`) - - // backward compatibility - name = CHANNEL_PREFIX + "GET:" + name - - if (debug) { - log( - `${ - consumerID ? `(${consumerID})` : "" - } send data for intra-window message ${name}` - ) - // log(`${consumerID ? `(${consumerID})` : ""} onGet EVENT: ${name}`) - } - - // is a function (data, options = {}) => data - const onGetListener = listenerWrapper(getDataCallback) - - addListener("get", name, onGetListener) - - return () => removeListener("get", name, listenerWrapper(getDataCallback)) - } catch (e) { - error(e.message) - } -} - -export { broadcast, watch, get, onGet } diff --git a/libs/communicator/src/index.test.js b/libs/communicator/src/index.test.js deleted file mode 100644 index 16f011ef6..000000000 --- a/libs/communicator/src/index.test.js +++ /dev/null @@ -1,216 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -test("HI", () => expect(true).toEqual(true)) -globalThis.console.log = jest.fn() -globalThis.console.warn = jest.fn() -globalThis.console.error = jest.fn() - -const bc = { - postMessage: jest.fn(), - close: jest.fn(() => true), -} - -globalThis.BroadcastChannel = jest.fn().mockImplementation(() => { - return bc -}) - -const { broadcast, watch, get, onGet } = require("./index") - -describe("Communicator", () => { - afterEach(() => { - jest.clearAllMocks() - }) - - // ################ BROADCAST ##################### - describe("broadcast", () => { - test("log error on missing name", () => { - broadcast() - expect(globalThis.console.error).toHaveBeenCalledWith( - "Communicator Error:", - "(broadcast) the message name must be given." - ) - }) - test("log warning on missing data", () => { - let callback = jest.fn() - watch("TEST", callback) - broadcast("TEST", "data") - expect(callback).toHaveBeenCalledWith("data", { - sourceWindowId: expect.anything(), - thisWindowId: expect.anything(), - }) - }) - - test("unknown options", () => { - broadcast("TEST", { test: "test" }, { unknownOption: true }) - expect(globalThis.console.warn).toHaveBeenCalledWith( - "Communicator Warning:", - "(broadcast) unknown options: unknownOption" - ) - }) - - test("create new broadcast channel", () => { - let callback = jest.fn() - watch("TEST_12345", callback) - broadcast("TEST_12345", { name: "test" }) - expect(callback).toHaveBeenCalledWith({ name: "test" }, expect.anything()) - }) - - test("include options in message payload", () => { - let callback = jest.fn() - watch("TEST_123456", callback) - broadcast("TEST_123456", { name: "test" }, { debug: true }) - expect(callback).toHaveBeenCalledWith( - { name: "test" }, - { sourceWindowId: expect.anything(), thisWindowId: expect.anything() } - ) - }) - - test("log error if wrong debug value", () => { - broadcast("TEST", { name: "test" }, { debug: "true" }) - - expect(globalThis.console.warn).toHaveBeenCalledWith( - "Communicator Warning:", - "(broadcast) debug must be a boolean" - ) - }) - - test("close channel after broadcast", () => { - broadcast("TEST", { name: "test" }, { crossWindow: true }) - - expect(bc.postMessage).toHaveBeenCalled() - }) - }) - - // ################## WATCH ################### - describe("watch", () => { - test("log error on missing name", () => { - watch() - expect(globalThis.console.error).toHaveBeenCalledWith( - "Communicator Error:", - "(watch) the message name must be given." - ) - }) - test("log error on missing callback", () => { - watch("TEST") - expect(globalThis.console.error).toHaveBeenCalledWith( - "Communicator Error:", - "(watch) the callback parameter must be a function." - ) - }) - - test("log error if callback is not a function", () => { - watch("TEST", "callback") - expect(globalThis.console.error).toHaveBeenCalledWith( - "Communicator Error:", - "(watch) the callback parameter must be a function." - ) - }) - - test("unknown options", () => { - watch("TEST", () => null, { unknownOption: true }) - expect(globalThis.console.warn).toHaveBeenCalledWith( - "Communicator Warning:", - "(watch) unknown options: unknownOption" - ) - }) - - test("watch for events", () => { - let callback = jest.fn() - watch("TEST", callback) - broadcast("TEST") - expect(callback).toHaveBeenCalled() - }) - - test("multiple watchers", () => { - let callback1 = jest.fn() - let callback2 = jest.fn() - watch("TEST", callback1) - watch("TEST", callback2) - broadcast("TEST") - expect(callback1).toHaveBeenCalled() - expect(callback2).toHaveBeenCalled() - }) - }) - - // ############### GET ################## - describe("get", () => { - test("log error on missing name", () => { - get() - expect(globalThis.console.error).toHaveBeenCalledWith( - "Communicator Error:", - "(get) the message name must be given." - ) - }) - test("log error on missing callback", () => { - get("TEST") - expect(globalThis.console.error).toHaveBeenCalledWith( - "Communicator Error:", - "(get) the callback parameter must be a function." - ) - }) - - test("log error if callback is not a function", () => { - get("TEST", "callback") - expect(globalThis.console.error).toHaveBeenCalledWith( - "Communicator Error:", - "(get) the callback parameter must be a function." - ) - }) - - test("unknown options", () => { - get("TEST", () => null, { unknownOption: true }) - expect(globalThis.console.warn).toHaveBeenCalledWith( - "Communicator Warning:", - "(get) unknown options: unknownOption" - ) - }) - - test("execute callback", () => { - let callback = jest.fn() - onGet("TEST_12345", callback) - get("TEST_12345", callback) - expect(callback).toHaveBeenCalled() - }) - }) - - // ############### ON GET ################## - describe("onGet", () => { - test("log error on missing name", () => { - onGet() - expect(globalThis.console.error).toHaveBeenCalledWith( - "Communicator Error:", - "(onGet) the message name must be given." - ) - }) - - test("log error on missing callback", () => { - onGet("TEST") - expect(globalThis.console.error).toHaveBeenCalledWith( - "Communicator Error:", - "(onGet) the callback parameter must be a function." - ) - }) - test("log error if callback is not a function", () => { - onGet("TEST", "callback") - expect(globalThis.console.error).toHaveBeenCalledWith( - "Communicator Error:", - "(onGet) the callback parameter must be a function." - ) - }) - test("unknown options", () => { - onGet("TEST", () => null, { unknownOption: true }) - expect(globalThis.console.warn).toHaveBeenCalledWith( - "Communicator Warning:", - "(onGet) unknown options: unknownOption" - ) - }) - - test("returns a function", () => { - const cancel = onGet("TEST", () => null) - expect(typeof cancel).toEqual("function") - }) - }) -}) diff --git a/libs/juno-ui-components/.gitignore b/libs/juno-ui-components/.gitignore deleted file mode 100644 index 15003e7a7..000000000 --- a/libs/juno-ui-components/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/build -/node_modules -/storybook-static diff --git a/libs/juno-ui-components/.npmignore b/libs/juno-ui-components/.npmignore deleted file mode 100644 index 7a4b23010..000000000 --- a/libs/juno-ui-components/.npmignore +++ /dev/null @@ -1,9 +0,0 @@ -.storybook -src -test -.babelrc -.gitignore -.npm -postcss.config.js -rollup* -setupTests diff --git a/libs/juno-ui-components/.storybook/.babelrc b/libs/juno-ui-components/.storybook/.babelrc deleted file mode 100644 index 7f27b1c49..000000000 --- a/libs/juno-ui-components/.storybook/.babelrc +++ /dev/null @@ -1,8 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -{ - "presets": ["@babel/env", "@babel/preset-react"] -} \ No newline at end of file diff --git a/libs/juno-ui-components/.storybook/juno-addon/Decorator.jsx b/libs/juno-ui-components/.storybook/juno-addon/Decorator.jsx deleted file mode 100644 index ea91cbe92..000000000 --- a/libs/juno-ui-components/.storybook/juno-addon/Decorator.jsx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import "../../src/global.scss" -import { StyleProvider } from "../../src/components/StyleProvider" -import { ContentContainer } from "../../src/components/ContentContainer/index" -import { Container } from "../../src/components/Container/index" -import React, { useEffect } from "react" -import { useChannel, addons } from "@storybook/preview-api" -import { getCurrentTheme, getCurrentThemeMode } from "./themes" - -const fixBodyBg = () => { - document.body.style.setProperty( - "background-color", - getCurrentTheme().appContentBg, - "important" - ) -} - -fixBodyBg() - -export default (Story, context) => { - const [theme, setTheme] = React.useState("theme-" + getCurrentThemeMode()) - - useEffect(() => { - const updateThemeClass = (mode) => { - // console.log("=======UPDATE JUNO THEME CLASS=======", mode) - setTheme(`theme-${mode}`) - fixBodyBg() - } - const channel = addons.getChannel() - if (channel) { - channel.on("JUNO_THEME_CHANGE", updateThemeClass) - } - updateThemeClass(getCurrentThemeMode()) - return () => { - if (channel) channel.off("JUNO_THEME_CHANGE", updateThemeClass) - } - }, []) - - return ( - - - - - - - - ) -} diff --git a/libs/juno-ui-components/.storybook/juno-addon/DocsContainer.jsx b/libs/juno-ui-components/.storybook/juno-addon/DocsContainer.jsx deleted file mode 100644 index 58d319b46..000000000 --- a/libs/juno-ui-components/.storybook/juno-addon/DocsContainer.jsx +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import { DocsContainer as BaseContainer } from "@storybook/addon-docs" -import { JUNO_THEME_CHANGE } from "./constants" -import { getCurrentTheme } from "./themes" - -export default ({ theme, ...props }) => { - // store the current theme in state so that we can update the theme when the theme changes - const [currentTheme, setCurrentTheme] = React.useState(getCurrentTheme()) - - // listen for theme change events and update the theme in state - React.useEffect(() => { - const updateDocsTheme = (mode) => setCurrentTheme(getCurrentTheme()) - - // get channel from context and listen to our custom event - // the event is emitted from the theme toggle tool - const channel = props.context?.channel - if (channel) { - channel.on(JUNO_THEME_CHANGE, updateDocsTheme) - } - return () => { - // remove the listener when the component unmounts - if (channel) channel.off(JUNO_THEME_CHANGE, updateDocsTheme) - } - }, []) - - return -} diff --git a/libs/juno-ui-components/.storybook/juno-addon/README.md b/libs/juno-ui-components/.storybook/juno-addon/README.md deleted file mode 100644 index 608710e39..000000000 --- a/libs/juno-ui-components/.storybook/juno-addon/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Juno UI Theme Switcher Addon for Storybook - -## Overview - -The **Juno UI Theme Switcher** is a Storybook addon designed specifically for Juno UI. It provides a seamless way to switch between dark and light themes, not just within the preview section but globally throughout your Storybook environment. This powerful addon ensures that your UI components are presented in the right theme, making it an essential tool for development and testing. - -## How It Works - -### 1. Conversion of Variables.scss - -The process begins with the conversion of the `Variables.scss` file into CSS. The resulting CSS file is then placed in a static folder named "assets." This conversion and file placement take place within the `main.js` file. The `Variables.css` file contains color variables for both dark and light modes. - -### 2. Theme Selection - -The theme is selected based on the class added to the `` element. When the class `theme-dark` is applied, the dark theme variables are used. Conversely, when `theme-light` is applied, the light theme variables are used. - -### 3. Integration with Storybook - -The Theme Switcher addon integrates with Storybook through various components: - -#### - Link Element in Manager UI - -Using the DOM API, a link element is added to the Manager UI of Storybook. This link element loads the CSS variables required for the selected theme. Simultaneously, the appropriate theme class is added to the ``. - -#### - Theme Switcher Button - -The addon defines a Theme Switcher button. When this button is clicked, it changes the theme class in the Manager UI and sends an event with the new theme mode using the Channel API. This process occurs in the `manager.js` file. - -#### - Variables in Preview Part - -In the Preview section (`preview.js`), the Variables CSS file is loaded into the `` of the iframe using a link tag. The corresponding theme class is applied to the ``. Additionally, a listener is defined using the Channel API, which listens for Theme Change Events triggered in the Manager UI. It dynamically updates the theme class in the Preview section to match the selected theme. - -### 4. Theme-Aware Decorator - -In addition to the theme switching functionality, the Theme Switcher addon defines a decorator. This decorator serves two crucial purposes: - -- **Styles for Juno Components**: Juno components are encapsulated within the shadow root by default. This means styles must be applied within the Shadow DOM. The decorator uses a StyleProvider from Juno UI to supply styles to Juno components, ensuring they are rendered correctly. - -- **Dynamic Theme Mode**: The decorator also listens for theme mode changes and updates the theme mode within the StyleProvider, ensuring that Juno components are always styled correctly for the selected theme. - -With the Juno UI Theme Switcher addon for Storybook, you can efficiently develop and test your Juno UI components in the desired theme, enhancing your workflow and user interface testing. diff --git a/libs/juno-ui-components/.storybook/juno-addon/ThemeToggle.jsx b/libs/juno-ui-components/.storybook/juno-addon/ThemeToggle.jsx deleted file mode 100644 index 35f0b2dbc..000000000 --- a/libs/juno-ui-components/.storybook/juno-addon/ThemeToggle.jsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import { addons, types } from "@storybook/manager-api" -const ADDON_ID = "juno-addon" -const TOOL_ID = `${ADDON_ID}/theme-toggle` -import { Icons, IconButton } from "@storybook/components" -import { JUNO_THEME_CHANGE } from "./constants" -import { dark, getCurrentThemeMode, light, setCurrentThemeMode } from "./themes" - -addons.register(ADDON_ID, (api) => { - addons.add(TOOL_ID, { - type: types.TOOL, - title: "Toggle Dark Mode", - matches: ({ viewMode }) => viewMode === "story" || viewMode === "docs", - - render: () => { - const [mode, setMode] = React.useState(getCurrentThemeMode()) - - const toggleTheme = React.useCallback(() => { - const newMode = mode === "dark" ? "light" : "dark" - api.emit(JUNO_THEME_CHANGE, newMode) - setMode(newMode) - setCurrentThemeMode(newMode) - api.setOptions({ - theme: newMode === "dark" ? dark : light, - }) - }, [mode]) - - return ( - { - toggleTheme() - }} - > - - - ) - }, - }) -}) diff --git a/libs/juno-ui-components/.storybook/juno-addon/constants.js b/libs/juno-ui-components/.storybook/juno-addon/constants.js deleted file mode 100644 index f6b409c92..000000000 --- a/libs/juno-ui-components/.storybook/juno-addon/constants.js +++ /dev/null @@ -1,17 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -// export const THEME_PARAM_KEY = "junoThemeMode" -export const STORAGE_KEY = "__junoThemeMode" - -export const JUNO_THEME_CHANGE = "JUNO_THEME_CHANGE" - -export const ICON_DATA_URL = - "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTAiIGhlaWdodD0iNTAiIHZpZXdCb3g9IjAgMCA1MCA1MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTEuNzEwNzIgMEMwLjc2NTkxNiAwIDAgMC43NjU5MTQgMCAxLjcxMDcyVjQ4LjI4OTNDMCA0OS4yMzQxIDAuNzY1OTE0IDUwIDEuNzEwNzIgNTBIOC42MDE2M0M2Ljg4NjIgNDcuODYgNS44NjAxMSA0NS4xNDM2IDUuODYwMTEgNDIuMTg3NkM1Ljg2MDExIDM1LjgxMTkgMTAuNjMzNSAzMC41NTEgMTYuODAxNSAyOS43ODM4QzE3LjU3NzUgMjMuMTMxNSAyMy4yMzIzIDE3Ljk2ODkgMzAuMDkyOSAxNy45Njg5QzM0LjgzNDQgMTcuOTY4OSAzOSAyMC40MzQ4IDQxLjM3NzEgMjQuMTU0MUM0Mi4zMTM1IDIzLjk1OTYgNDMuMjgzNyAyMy44NTczIDQ0LjI3NzggMjMuODU3M0M0Ni4zMTM5IDIzLjg1NzMgNDguMjQ5OCAyNC4yODYzIDUwIDI1LjA1ODhWMS43MTA3MkM1MCAwLjc2NTkxNiA0OS4yMzQxIDAgNDguMjg5MyAwSDEuNzEwNzJaTTUwIDI4LjkyNDFDNDguMzQyNCAyNy44ODE3IDQ2LjM4MDUgMjcuMjc4OCA0NC4yNzc4IDI3LjI3ODhDNDMuNTE4OSAyNy4yNzg4IDQyLjc4MiAyNy4zNTY4IDQyLjA3MzIgMjcuNTA0TDM5Ljc2NDIgMjcuOTgzOEwzOC40OTQyIDI1Ljk5NjdDMzYuNzE5MiAyMy4yMTk0IDMzLjYxODUgMjEuMzkwMyAzMC4wOTI5IDIxLjM5MDNDMjQuOTg4OCAyMS4zOTAzIDIwLjc3NzEgMjUuMjMyMyAyMC4xOTk5IDMwLjE4MDNMMTkuODg4NyAzMi44NDc2TDE3LjIyMzggMzMuMTc5MUMxMi43NDc2IDMzLjczNTkgOS4yODE1NSAzNy41NTk2IDkuMjgxNTUgNDIuMTg3NkM5LjI4MTU1IDQ1LjUwOSAxMS4wNjcxIDQ4LjQxNzQgMTMuNzMxMSA1MEg0OC4yODkzQzQ5LjIzNDEgNTAgNTAgNDkuMjM0MSA1MCA0OC4yODkzVjI4LjkyNDFaIiBmaWxsPSIjRjBBQjAwIj48L3BhdGg+PC9zdmc+" -export const LOGO_DARK_DATA_URL = - "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDAiIGhlaWdodD0iNDUiIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCAyMDAgNDUiPgogIDxwYXRoIGZpbGw9IiNGMEFCMDAiIGQ9Ik0xLjQgMEExLjQgMS40IDAgMCAwIDAgMS40djQyLjAwM2ExLjQgMS40IDAgMCAwIDEuNCAxLjRoNi4zMDdhMTEuMTUzIDExLjE1MyAwIDAgMS0yLjQ1Ny03YzAtNS43MTMgNC4yNzctMTAuNDI3IDkuODA1LTExLjExNS42OTUtNS45NiA1Ljc2Mi0xMC41ODcgMTEuOTEtMTAuNTg3IDQuMjQ4IDAgNy45OCAyLjIxIDEwLjExMSA1LjU0Mi44NC0uMTc0IDEuNzA5LS4yNjYgMi42LS4yNjYgMS44MjQgMCAzLjU2LjM4NSA1LjEyOCAxLjA3N1YxLjRhMS40IDEuNCAwIDAgMC0xLjQtMS40SDEuNFoiLz4KICA8cGF0aCBmaWxsPSIjRjBBQjAwIiBkPSJNNDQuODA0IDI1LjYwNmE5Ljk2MyA5Ljk2MyAwIDAgMC03LjE1OC0xLjIybC0xLjg5LjM5Mi0xLjA0LTEuNjI3YTkuMTkzIDkuMTkzIDAgMCAwLTE2Ljg4IDMuODYxbC0uMjU1IDIuMTg0LTIuMTguMjdhOC40MDMgOC40MDMgMCAwIDAtMy41OTYgMTUuMzM3aDMxLjU5OGExLjQgMS40IDAgMCAwIDEuNC0xLjRWMjUuNjA2WiIvPgogIDxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik0xNzQuMDMzIDM3di00LjUxOGgzLjM2VjE1LjQ1NmgtMy4zNnYtNC41MThoMTIuMzk2djQuNTE4aC0zLjM2MXYxNy4wMjZoMy4zNjFWMzdoLTEyLjM5NlptLTE5LjU0MS0yNi4wNjJ2MTUuOThjMCAxLjg0My4zNjEgMy4yMjQgMS4wODMgNC4xNDUuNzIyLjg5NiAxLjkyOSAxLjM0NCAzLjYyMiAxLjM0NCAxLjY5MyAwIDIuOS0uNDQ4IDMuNjIyLTEuMzQ0LjcyMi0uOTIgMS4wODMtMi4zMDIgMS4wODMtNC4xNDR2LTE1Ljk4aDUuNTI2VjI2LjMyYzAgMS45MTctLjE4NyAzLjU4NS0uNTYxIDUuMDA0LS4zNDggMS4zOTQtLjkzMyAyLjU1MS0xLjc1NCAzLjQ3Mi0uODIyLjg5Ni0xLjg4IDEuNTY4LTMuMTc0IDIuMDE2LTEuMjk1LjQyMy0yLjg3NS42MzUtNC43NDIuNjM1cy0zLjQ0OC0uMjEyLTQuNzQyLS42MzVjLTEuMjk0LS40NDgtMi4zNTItMS4xMi0zLjE3NC0yLjAxNi0uODIxLS45Mi0xLjQxOS0yLjA3OC0xLjc5Mi0zLjQ3Mi0uMzQ4LTEuNDItLjUyMy0zLjA4Ny0uNTIzLTUuMDA0VjEwLjkzOGg1LjUyNlptLTI3LjYyMSAyNi41MWMtMS40NDQgMC0yLjczOS0uMjM2LTMuODg0LS43MWE3LjkyIDcuOTIgMCAwIDEtMi44NzUtMi4wNTNjLS43NzEtLjg5Ni0xLjM2OS0xLjk3OS0xLjc5Mi0zLjI0OC0uNDIzLTEuMjctLjYzNS0yLjY4OS0uNjM1LTQuMjU3IDAtMS41NjguMjEyLTIuOTg3LjYzNS00LjI1Ni40MjMtMS4yNyAxLjAyMS0yLjM0IDEuNzkyLTMuMjExYTcuOTIgNy45MiAwIDAgMSAyLjg3NS0yLjA1NGMxLjE0NS0uNDczIDIuNDQtLjcxIDMuODg0LS43MSAxLjQ0MyAwIDIuNzI1LjIzNyAzLjg0NS43MWE3LjUxNCA3LjUxNCAwIDAgMSAyLjg3NSAyLjA1NGMuNzk3Ljg3IDEuNDA3IDEuOTQxIDEuODMgMy4yMS40MjMgMS4yNy42MzUgMi42ODkuNjM1IDQuMjU3IDAgMS41NjgtLjIxMiAyLjk4Ny0uNjM1IDQuMjU3LS40MjMgMS4yNy0xLjAzMyAyLjM1Mi0xLjgzIDMuMjQ4LS43NzEuODk2LTEuNzMgMS41OC0yLjg3NSAyLjA1NC0xLjEyLjQ3My0yLjQwMi43MS0zLjg0NS43MVptMC00LjM2OGMxLjA5NSAwIDEuOTQxLS4zMzcgMi41MzgtMS4wMDkuNTk4LS42NzIuODk3LTEuNjMuODk3LTIuODc1di0zLjk5NWMwLTEuMjQ0LS4yOTktMi4yMDMtLjg5Ny0yLjg3NS0uNTk3LS42NzItMS40NDMtMS4wMDgtMi41MzgtMS4wMDgtMS4wOTYgMC0xLjk0Mi4zMzYtMi41MzkgMS4wMDgtLjU5OC42NzItLjg5NyAxLjYzLS44OTcgMi44NzV2My45OTVjMCAxLjI0NS4yOTkgMi4yMDMuODk3IDIuODc1LjU5Ny42NzIgMS40NDMgMS4wMDkgMi41MzkgMS4wMDlaTTk2LjY3NSAzN1YxNy4zOThoNS41MjZ2My4zMjNoLjIyNGMuMzQ5LTEuMDIuOTU5LTEuOTA0IDEuODMtMi42NTEuODcxLS43NDcgMi4wNzgtMS4xMiAzLjYyMi0xLjEyIDIuMDE2IDAgMy41MzQuNjcyIDQuNTU1IDIuMDE2IDEuMDQ1IDEuMzQ0IDEuNTY4IDMuMjYgMS41NjggNS43NVYzN2gtNS41MjZWMjUuMTY0YzAtMS4yNy0uMTk5LTIuMjAzLS41OTctMi44LS4zOTktLjYyMy0xLjEwOC0uOTM0LTIuMTI5LS45MzRhNC42IDQuNiAwIDAgMC0xLjMwNi4xODcgMy4yNiAzLjI2IDAgMCAwLTEuMTU4LjUyM2MtLjMyNC4yNDgtLjU4NS41Ni0uNzg0LjkzMy0uMTk5LjM0OS0uMjk5Ljc2LS4yOTkgMS4yMzJWMzdoLTUuNTI2Wm0tMTAuNjY3LTMuMjg2aC0uMTg3Yy0uMTc0LjQ5OC0uNDEuOTcxLS43MSAxLjQyYTQuNDU2IDQuNDU2IDAgMCAxLTEuMDgyIDEuMTk0IDUuMTQgNS4xNCAwIDAgMS0xLjYwNi44MjFjLS41OTcuMi0xLjI5NC4zLTIuMDkuMy0yLjAxNyAwLTMuNTQ4LS42Ni00LjU5My0xLjk4LTEuMDItMS4zNDQtMS41MzEtMy4yNi0xLjUzMS01Ljc1VjE3LjM5OGg1LjUyNnYxMS44MzZjMCAxLjE5NC4yMTIgMi4xMTUuNjM1IDIuNzYzLjQyMy42NDcgMS4xNDUuOTcgMi4xNjUuOTcuNDI0IDAgLjg0Ny0uMDYyIDEuMjctLjE4NmEzLjg2OSAzLjg2OSAwIDAgMCAxLjEyLS41MjNjLjMyNC0uMjQ5LjU4NS0uNTQ4Ljc4NC0uODk2LjItLjM0OC4yOTktLjc2LjI5OS0xLjIzMlYxNy4zOThoNS41MjZWMzdoLTUuNTI2di0zLjI4NlpNNjkuMTQ2IDEwLjkzOHYxOC41MmMwIDEuMTk1LS4xOTkgMi4yOS0uNTk3IDMuMjg1YTYuNjMgNi42MyAwIDAgMS0xLjY4IDIuNTAyYy0uNzQ3LjY3Mi0xLjY1NiAxLjIwNy0yLjcyNiAxLjYwNi0xLjA0Ni4zNzMtMi4yNC41Ni0zLjU4NC41Ni0xLjI5NSAwLTIuNDQtLjE3NS0zLjQzNi0uNTIzYTcuNjA5IDcuNjA5IDAgMCAxLTIuNTM5LTEuNDkzIDguMDE4IDguMDE4IDAgMCAxLTEuNzE3LTIuMzE2IDEwLjIzMiAxMC4yMzIgMCAwIDEtLjkzNC0yLjk4Nmw1LjMwMi0xLjA0NmMuNDI0IDIuMjY1IDEuNTA2IDMuMzk4IDMuMjQ5IDMuMzk4LjgyMSAwIDEuNTE4LS4yNjIgMi4wOS0uNzg0LjU5OC0uNTIzLjg5Ny0xLjM0NS44OTctMi40NjVWMTUuNDkzaC03LjkxNnYtNC41NTVoMTMuNTkxWiIvPgo8L3N2Zz4K" - -export const LOGO_LIGHT_DATA_URL = - "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDAiIGhlaWdodD0iNDUiIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCAyMDAgNDUiPgogIDxwYXRoIGZpbGw9IiNGMEFCMDAiIGQ9Ik0xLjQgMEExLjQgMS40IDAgMCAwIDAgMS40djQyLjAwM2ExLjQgMS40IDAgMCAwIDEuNCAxLjRoNi4zMDdhMTEuMTUzIDExLjE1MyAwIDAgMS0yLjQ1Ny03YzAtNS43MTMgNC4yNzctMTAuNDI3IDkuODA1LTExLjExNS42OTUtNS45NiA1Ljc2Mi0xMC41ODcgMTEuOTEtMTAuNTg3IDQuMjQ4IDAgNy45OCAyLjIxIDEwLjExMSA1LjU0Mi44NC0uMTc0IDEuNzA5LS4yNjYgMi42LS4yNjYgMS44MjQgMCAzLjU2LjM4NSA1LjEyOCAxLjA3N1YxLjRhMS40IDEuNCAwIDAgMC0xLjQtMS40SDEuNFoiLz4KICA8cGF0aCBmaWxsPSIjRjBBQjAwIiBkPSJNNDQuODA0IDI1LjYwNmE5Ljk2MyA5Ljk2MyAwIDAgMC03LjE1OC0xLjIybC0xLjg5LjM5Mi0xLjA0LTEuNjI3YTkuMTkzIDkuMTkzIDAgMCAwLTE2Ljg4IDMuODYxbC0uMjU1IDIuMTg0LTIuMTguMjdhOC40MDMgOC40MDMgMCAwIDAtMy41OTYgMTUuMzM3aDMxLjU5OGExLjQgMS40IDAgMCAwIDEuNC0xLjRWMjUuNjA2WiIvPgogIDxwYXRoIGZpbGw9IiMwMDAiIGQ9Ik0xNzQuMDMzIDM3di00LjUxOGgzLjM2VjE1LjQ1NmgtMy4zNnYtNC41MThoMTIuMzk2djQuNTE4aC0zLjM2MXYxNy4wMjZoMy4zNjFWMzdoLTEyLjM5NlptLTE5LjU0MS0yNi4wNjJ2MTUuOThjMCAxLjg0My4zNjEgMy4yMjQgMS4wODMgNC4xNDUuNzIyLjg5NiAxLjkyOSAxLjM0NCAzLjYyMiAxLjM0NCAxLjY5MyAwIDIuOS0uNDQ4IDMuNjIyLTEuMzQ0LjcyMi0uOTIgMS4wODMtMi4zMDIgMS4wODMtNC4xNDR2LTE1Ljk4aDUuNTI2VjI2LjMyYzAgMS45MTctLjE4NyAzLjU4NS0uNTYxIDUuMDA0LS4zNDggMS4zOTQtLjkzMyAyLjU1MS0xLjc1NCAzLjQ3Mi0uODIyLjg5Ni0xLjg4IDEuNTY4LTMuMTc0IDIuMDE2LTEuMjk1LjQyMy0yLjg3NS42MzUtNC43NDIuNjM1cy0zLjQ0OC0uMjEyLTQuNzQyLS42MzVjLTEuMjk0LS40NDgtMi4zNTItMS4xMi0zLjE3NC0yLjAxNi0uODIxLS45Mi0xLjQxOS0yLjA3OC0xLjc5Mi0zLjQ3Mi0uMzQ4LTEuNDItLjUyMy0zLjA4Ny0uNTIzLTUuMDA0VjEwLjkzOGg1LjUyNlptLTI3LjYyMSAyNi41MWMtMS40NDQgMC0yLjczOS0uMjM2LTMuODg0LS43MWE3LjkyIDcuOTIgMCAwIDEtMi44NzUtMi4wNTNjLS43NzEtLjg5Ni0xLjM2OS0xLjk3OS0xLjc5Mi0zLjI0OC0uNDIzLTEuMjctLjYzNS0yLjY4OS0uNjM1LTQuMjU3IDAtMS41NjguMjEyLTIuOTg3LjYzNS00LjI1Ni40MjMtMS4yNyAxLjAyMS0yLjM0IDEuNzkyLTMuMjExYTcuOTIgNy45MiAwIDAgMSAyLjg3NS0yLjA1NGMxLjE0NS0uNDczIDIuNDQtLjcxIDMuODg0LS43MSAxLjQ0MyAwIDIuNzI1LjIzNyAzLjg0NS43MWE3LjUxNCA3LjUxNCAwIDAgMSAyLjg3NSAyLjA1NGMuNzk3Ljg3IDEuNDA3IDEuOTQxIDEuODMgMy4yMS40MjMgMS4yNy42MzUgMi42ODkuNjM1IDQuMjU3IDAgMS41NjgtLjIxMiAyLjk4Ny0uNjM1IDQuMjU3LS40MjMgMS4yNy0xLjAzMyAyLjM1Mi0xLjgzIDMuMjQ4LS43NzEuODk2LTEuNzMgMS41OC0yLjg3NSAyLjA1NC0xLjEyLjQ3My0yLjQwMi43MS0zLjg0NS43MVptMC00LjM2OGMxLjA5NSAwIDEuOTQxLS4zMzcgMi41MzgtMS4wMDkuNTk4LS42NzIuODk3LTEuNjMuODk3LTIuODc1di0zLjk5NWMwLTEuMjQ0LS4yOTktMi4yMDMtLjg5Ny0yLjg3NS0uNTk3LS42NzItMS40NDMtMS4wMDgtMi41MzgtMS4wMDgtMS4wOTYgMC0xLjk0Mi4zMzYtMi41MzkgMS4wMDgtLjU5OC42NzItLjg5NyAxLjYzLS44OTcgMi44NzV2My45OTVjMCAxLjI0NS4yOTkgMi4yMDMuODk3IDIuODc1LjU5Ny42NzIgMS40NDMgMS4wMDkgMi41MzkgMS4wMDlaTTk2LjY3NSAzN1YxNy4zOThoNS41MjZ2My4zMjNoLjIyNGMuMzQ5LTEuMDIuOTU5LTEuOTA0IDEuODMtMi42NTEuODcxLS43NDcgMi4wNzgtMS4xMiAzLjYyMi0xLjEyIDIuMDE2IDAgMy41MzQuNjcyIDQuNTU1IDIuMDE2IDEuMDQ1IDEuMzQ0IDEuNTY4IDMuMjYgMS41NjggNS43NVYzN2gtNS41MjZWMjUuMTY0YzAtMS4yNy0uMTk5LTIuMjAzLS41OTctMi44LS4zOTktLjYyMy0xLjEwOC0uOTM0LTIuMTI5LS45MzRhNC42IDQuNiAwIDAgMC0xLjMwNi4xODcgMy4yNiAzLjI2IDAgMCAwLTEuMTU4LjUyM2MtLjMyNC4yNDgtLjU4NS41Ni0uNzg0LjkzMy0uMTk5LjM0OS0uMjk5Ljc2LS4yOTkgMS4yMzJWMzdoLTUuNTI2Wm0tMTAuNjY3LTMuMjg2aC0uMTg3Yy0uMTc0LjQ5OC0uNDEuOTcxLS43MSAxLjQyYTQuNDU2IDQuNDU2IDAgMCAxLTEuMDgyIDEuMTk0IDUuMTQgNS4xNCAwIDAgMS0xLjYwNi44MjFjLS41OTcuMi0xLjI5NC4zLTIuMDkuMy0yLjAxNyAwLTMuNTQ4LS42Ni00LjU5My0xLjk4LTEuMDItMS4zNDQtMS41MzEtMy4yNi0xLjUzMS01Ljc1VjE3LjM5OGg1LjUyNnYxMS44MzZjMCAxLjE5NC4yMTIgMi4xMTUuNjM1IDIuNzYzLjQyMy42NDcgMS4xNDUuOTcgMi4xNjUuOTcuNDI0IDAgLjg0Ny0uMDYyIDEuMjctLjE4NmEzLjg2OSAzLjg2OSAwIDAgMCAxLjEyLS41MjNjLjMyNC0uMjQ5LjU4NS0uNTQ4Ljc4NC0uODk2LjItLjM0OC4yOTktLjc2LjI5OS0xLjIzMlYxNy4zOThoNS41MjZWMzdoLTUuNTI2di0zLjI4NlpNNjkuMTQ2IDEwLjkzOHYxOC41MmMwIDEuMTk1LS4xOTkgMi4yOS0uNTk3IDMuMjg1YTYuNjMgNi42MyAwIDAgMS0xLjY4IDIuNTAyYy0uNzQ3LjY3Mi0xLjY1NiAxLjIwNy0yLjcyNiAxLjYwNi0xLjA0Ni4zNzMtMi4yNC41Ni0zLjU4NC41Ni0xLjI5NSAwLTIuNDQtLjE3NS0zLjQzNi0uNTIzYTcuNjA5IDcuNjA5IDAgMCAxLTIuNTM5LTEuNDkzIDguMDE4IDguMDE4IDAgMCAxLTEuNzE3LTIuMzE2IDEwLjIzMiAxMC4yMzIgMCAwIDEtLjkzNC0yLjk4Nmw1LjMwMi0xLjA0NmMuNDI0IDIuMjY1IDEuNTA2IDMuMzk4IDMuMjQ5IDMuMzk4LjgyMSAwIDEuNTE4LS4yNjIgMi4wOS0uNzg0LjU5OC0uNTIzLjg5Ny0xLjM0NS44OTctMi40NjVWMTUuNDkzaC03LjkxNnYtNC41NTVoMTMuNTkxWiIvPgo8L3N2Zz4K" diff --git a/libs/juno-ui-components/.storybook/juno-addon/manager.js b/libs/juno-ui-components/.storybook/juno-addon/manager.js deleted file mode 100644 index 38331e7ad..000000000 --- a/libs/juno-ui-components/.storybook/juno-addon/manager.js +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import "./ThemeToggle" -import { addons } from "@storybook/manager-api" -import { getCurrentTheme } from "./themes" -import { ICON_DATA_URL } from "./constants" - -// -const favicon = document.head.querySelector("link[rel='icon']") -if (favicon) favicon.setAttribute("href", ICON_DATA_URL) - -addons.setConfig({ - theme: getCurrentTheme(), - toolbar: { - "storybook/background": { hidden: true }, - }, -}) - -console.log("Juno Addon Loaded") diff --git a/libs/juno-ui-components/.storybook/juno-addon/preview.js b/libs/juno-ui-components/.storybook/juno-addon/preview.js deleted file mode 100644 index 0a8a1f342..000000000 --- a/libs/juno-ui-components/.storybook/juno-addon/preview.js +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import Decorator from "./Decorator" -import { getCurrentTheme } from "./themes" -import DocsContainer from "./DocsContainer" - -import { - Title, - Subtitle, - Description, - Primary, - ArgsTable, - PRIMARY_STORY, - Stories, -} from "@storybook/addon-docs" - -export const decorators = [Decorator] - -export default { - parameters: { - docs: { - theme: getCurrentTheme(), - container: DocsContainer, - }, - }, -} diff --git a/libs/juno-ui-components/.storybook/juno-addon/themes.js b/libs/juno-ui-components/.storybook/juno-addon/themes.js deleted file mode 100644 index d2583fc7d..000000000 --- a/libs/juno-ui-components/.storybook/juno-addon/themes.js +++ /dev/null @@ -1,117 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { create } from "@storybook/theming/create" -import { - LOGO_DARK_DATA_URL, - LOGO_LIGHT_DATA_URL, - STORAGE_KEY, -} from "./constants" -// import { themes } from "@storybook/theming" -// console.log(themes.dark) - -const staticOptions = { - brandTitle: "Juno UI", - brandUrl: "https://assets.juno.global.cloud.sap", - brandTarget: "_self", - // Fonts - fontBase: - '"Nunito Sans", -apple-system, ".SFNSText-Regular", "San Francisco", BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif', - fontCode: - 'ui-monospace, Menlo, Monaco, "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro", "Droid Sans Mono", "Courier New", monospace', -} - -const dark = create({ - ...staticOptions, - base: "dark", - brandImage: LOGO_DARK_DATA_URL, - // - colorPrimary: "rgb(15, 167, 180)", - colorSecondary: "rgb(21, 208, 224)", - - // UI - appBg: "rgb(36, 42, 49)", - appContentBg: "rgb(18, 25, 32)", - appBorderColor: "rgba(255,255,255,.1)", - appBorderRadius: 4, - - //Buttons - booleanBg: "rgb(23, 30, 37)", - booleanSelectedBg: "#2E3438", - buttonBg: "rgb(23, 30, 37)", - buttonBorder: "rgba(255,255,255,.1)", - - // Text colors - textColor: "rgb(187,187,187)", - textInverseColor: "rgb(76, 76, 76)", - - // Toolbar default and active colors - barTextColor: "rgb(187,187,187)", - barSelectedColor: "rgb(187,187,187)", - barBg: "rgb(36, 42, 49)", - - // Form colors - inputBg: "rgb(23, 30, 37)", - inputBorder: "rgba(255,255,255,.1)", - inputTextColor: "rgb(187, 187, 187)", - inputBorderRadius: 2, - - // Menu - - textMutedColor: "rgb(122, 122, 122)", -}) - -const light = create({ - ...staticOptions, - base: "light", - brandImage: LOGO_LIGHT_DATA_URL, - - // - colorPrimary: "rgb(30, 106, 146)", - colorSecondary: "rgb(0, 125, 184)", - - // UI - appBg: "rgb(249, 249, 249)", - appContentBg: "rgb(255, 255, 255)", - appBorderColor: "rgba(64, 64, 64, .1)", - appBorderRadius: 4, - - //Buttons - booleanBg: "rgb(233, 233, 233)", - booleanSelectedBg: "#2E3438", - buttonBg: "rgb(233, 233, 233)", - buttonBorder: "rgba(64, 64, 64, .1)", - - // Text colors - textColor: "rgb(76, 76, 76)", - textInverseColor: "rgb(76, 76, 76)", - - // Toolbar default and active colors - barTextColor: "rgb(76, 76, 76)", - barSelectedColor: "rgb(76, 76, 76)", - barBg: "rgb(249, 249, 249)", - - // Form colors - inputBg: "rgb(233, 233, 233)", - inputBorder: "rgba(64, 64, 64, .1)", - inputTextColor: "rgb(76, 76, 76)", - inputBorderRadius: 2, - - // Menu - - textMutedColor: "rgb(122, 122, 122)", -}) - -const setCurrentThemeMode = (mode) => localStorage.setItem(STORAGE_KEY, mode) -const getCurrentThemeMode = () => localStorage.getItem(STORAGE_KEY) || "dark" -const getCurrentTheme = () => (getCurrentThemeMode() === "dark" ? dark : light) - -export { - dark, - light, - getCurrentTheme, - setCurrentThemeMode, - getCurrentThemeMode, -} diff --git a/libs/juno-ui-components/.storybook/main.js b/libs/juno-ui-components/.storybook/main.js deleted file mode 100644 index d4232a2c6..000000000 --- a/libs/juno-ui-components/.storybook/main.js +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -/** @type { import('@storybook/react-webpack5').StorybookConfig } */ - -const path = require("path") -const globImporter = require("node-sass-glob-importer") - -const config = { - stories: ["../src/docs/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"], - addons: [ - "@storybook/addon-links", - "@storybook/addon-essentials", - "@storybook/addon-docs", - "@storybook/addon-mdx-gfm", - "./juno-addon", - ], - webpackFinal: async (config) => { - // Default rule for images /\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/ - // Exclude SVG files so that they can be loaded via svgr - const fileLoaderRule = config.module.rules.find( - (rule) => rule.test && rule.test.test(".svg") - ) - fileLoaderRule.exclude = /\.svg$/ - - config.module.rules.push({ - test: /\.svg$/i, - type: "asset", - resourceQuery: /url/, // import filename: *.svg?url - }) - - config.module.rules.push({ - test: /\.svg$/i, - enforce: "pre", - issuer: /\.jsx?$/, - resourceQuery: { not: [/url/] }, // exclude react component if import filename *.svg?url - loader: require.resolve("@svgr/webpack"), - options: { - svgo: false, - titleProp: true, - }, - }) - - // this is for background svgs in css - config.module.rules.push({ - test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, - issuer: /\.s?css$/, - type: "asset", - }) - - // other images - config.module.rules.push({ - test: /\.(png|jpg)$/i, - type: "asset", - }) - - config.module.rules.push({ - test: /\.scss$/, - use: [ - "css-loader", - { - loader: "postcss-loader", - // important! use local installed postcss (version 8) - options: { - implementation: require("postcss"), - }, - }, - { - loader: "sass-loader", - options: { - sassOptions: { - importer: globImporter(), - }, - }, - }, - ], - include: [path.resolve(__dirname, "../src")], - }) - - return config - }, - - framework: { - name: "@storybook/react-webpack5", - options: {}, - }, - docs: { - autodocs: true, - }, -} -export default config diff --git a/libs/juno-ui-components/.storybook/preview.js b/libs/juno-ui-components/.storybook/preview.js deleted file mode 100644 index 71d87aa36..000000000 --- a/libs/juno-ui-components/.storybook/preview.js +++ /dev/null @@ -1,111 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -// import { useDarkMode } from "storybook-dark-mode" -// import { DocsContainer } from "./components/DocsContainer" -// import { themes } from "@storybook/theming" - -// import { -// Title, -// Subtitle, -// Description, -// Primary, -// ArgsTable, -// PRIMARY_STORY, -// Stories, -// } from "@storybook/addon-docs" -// import React from "react" -// import "../src/global.scss" -// import { StyleProvider } from "../src/components/StyleProvider" -// import { ContentArea } from "../src/components/ContentArea/index" -// import { Container } from "../src/components/Container/index" - -// export const parameters = { -// options: { -// storySort: { -// order: ["Components", "Forms", "Layout", "*", "WiP", "Internal"], -// method: "alphabetical", -// }, -// }, -// actions: { argTypesRegex: "^on[A-Z].*" }, -// backgrounds: { disable: true }, -// darkMode: { -// stylePreview: true, -// classTarget: "html", -// darkClass: "theme-dark", -// lightClass: "theme-light", -// // one additional piece of the puzzle to make dark mode work properly is the preview-head.html in this folder -// // in there we are able to set the background color of stories using inbuilt CSS escape hatches. -// // See documentation here: https://github.com/storybookjs/storybook/blob/master/addons/docs/docs/theming.md#storybook-theming -// }, -// docs: { -// /** -// * A custom docs container seems to be necessary because we want the docs container theme to switch depending on -// * the result of the useDarkMode hook from the storybook-dark-mode addon. -// * See more info in ./components/DocsContainer -// */ -// container: DocsContainer, -// /** -// * We're using a custom docs page setup here at the moment because by default the storybook docspage renders the first -// * story from the stories file as a special "primary" story that is adjustable with the args table but it does not -// * include the primary story below with the list of other stories. This leads to the description for the primary -// * story not being displayed anywhere on the docspage which is annoying. Therefore I've adjusted the default Docs Page -// * to include the primary story with the story list. There's an open issue that might fix this issue and render the -// * need for a custom page obsolete: https://github.com/storybookjs/storybook/issues/8093 -// * -// * Also there's still an open issue regarding the descriptions of stories. Ideally it would be possible to write standard -// * jsdoc descriptions for stories but currently this doesn't work. Instead you have to pass the description as a parameter. -// * This issue is here: https://github.com/storybookjs/storybook/issues/8527 -// */ -// page: () => ( -// <> -// -// <Subtitle /> -// <Description /> -// <Primary /> -// <ArgsTable story={PRIMARY_STORY} /> -// <Stories includePrimary={true} title="" /> -// </> -// ), -// // ensure that decorators aren't rendered for dynamic code display in stories -// // if decorators should be rendered for a story or component add the below to the component's config under parameters: { docs: { source: ...} } -// // and set excludeDecorators to false -// source: { -// type: "dynamic", -// excludeDecorators: true, -// }, -// }, -// controls: { -// expanded: true, -// matchers: { -// //color: /(background|color)$/i, // comment out to prevent storybook from rendering their custom color input -// date: /Date$/, -// }, -// }, -// } -// import "../src/global.scss" - -/** @type { import('@storybook/react').Preview } */ -const preview = { - parameters: { - // layout: "centered", - options: { - storySort: { - order: ["Components", "Forms", "Layout", "*", "WiP", "Internal"], - method: "alphabetical", - }, - }, - actions: { argTypesRegex: "^on[A-Z].*" }, - controls: { - expanded: true, - matchers: { - //color: /(background|color)$/i, // comment out to prevent storybook from rendering their custom color input - date: /Date$/, - }, - }, - }, -} - -export default preview diff --git a/libs/juno-ui-components/LICENSE b/libs/juno-ui-components/LICENSE deleted file mode 100644 index 261eeb9e9..000000000 --- a/libs/juno-ui-components/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/libs/juno-ui-components/README.md b/libs/juno-ui-components/README.md deleted file mode 100644 index 03c13cb2a..000000000 --- a/libs/juno-ui-components/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# Juno UI Components Library - -## Installation - -To include Juno UI components as a dev dependency in your app install with npm: - -```bash -npm add --dev juno-ui-components -``` - -…or declare manually as a dev-dependency: - -```js -// package.json -"devDependencies": { - ... - "juno-ui-components": ">= 0" - ... -} -``` - -```bash -npm --workspaces install -``` - -## Working With Tailwind - -Juno comes with [Tailwind](https://tailwindcss.com/) included, so when using Juno you automatically can use tailwind in your project. - -To be able to make full use of the predefined colors and other custom properties from the Juno UI components library you will need to include the ui components tailwind config into your application's tailwind config like this: - -```js -module.exports = { - presets: [ - require("juno-ui-components/build/lib/tailwind.config") - ], - ... -} -``` - -Doing this lets you use Tailwind classnames from the Juno UI Components library. - -## Development - -In order to work ON (NOT WITH) the Juno Design System and its components run storybook with: - -```bash -npm -w juno-ui-components run storybook -``` - -or just run from the root directory of this repository `npm run ui-components` - -Run the test suite: - -```bash -npm -w juno-ui-components run test -``` diff --git a/libs/juno-ui-components/babel.config.json b/libs/juno-ui-components/babel.config.json deleted file mode 100644 index 3e71ca2d5..000000000 --- a/libs/juno-ui-components/babel.config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "presets": ["@babel/preset-react"], - "env": { - "test": { - "presets": ["@babel/env"] - } - }, - "plugins": ["@babel/plugin-transform-parameters"] -} diff --git a/libs/juno-ui-components/lib/variables.scss b/libs/juno-ui-components/lib/variables.scss deleted file mode 100644 index 0edb699fc..000000000 --- a/libs/juno-ui-components/lib/variables.scss +++ /dev/null @@ -1,635 +0,0 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors -// SPDX-License-Identifier: Apache-2.0 - -// Juno - -/* Color Definitions */ -/* The Mother of Colors – The single source of truth of colors in Juno. - Here we define all relevant colors as triples of their rgb values. - We use these to generate CSS variables: one is the triple itself for use with tailwind opacity functions, one is the rgb( r, g, b) color definition for direct use. - -*/ - -/* Global Color Definitions */ -$color-map: ( - - "white": (255, 255, 255), - "black": (0, 0, 0), - - "sap-grey-1": (255, 255, 255), - "sap-grey-2": (225, 225, 225), - "sap-grey-3": (204, 204, 204), - "sap-grey-4": (153, 153, 153), - "sap-grey-5": (127, 127, 127), - "sap-grey-6": (102, 102, 102), - "sap-grey-7": (75, 75, 75), - "sap-grey-8": (0, 0, 0), - - "sap-blue-1": (15, 170, 25), - "sap-blue-2": (0, 143, 211), - "sap-blue-3": (0, 118, 203), - "sap-blue-4": (15, 70, 167), - "sap-blue-5": (0, 50, 131), - "sap-blue-6": (0, 25, 90), - - "sap-gold": (240, 171, 0), - - "sap-purple-1": (220, 0, 150), - "sap-purple-2": (190, 0, 140), - "sap-purple-3": (151, 10, 130), - "sap-purple-4": (118, 10, 133), - "sap-purple-5": (69, 21, 126), - "sap-purple-6": (60, 20, 100), - - "sap-green-1": (188, 220, 80), - "sap-green-2": (147, 201, 57), - "sap-green-3": (79, 184, 28), - "sap-green-4": (52, 139, 38), - "sap-green-5": (36, 114, 48), - "sap-green-6": (15, 75, 60), - - "sap-orange-1": (255, 175, 0), - "sap-orange-2": (250, 145, 0), - "sap-orange-3": (235, 115, 0), - "sap-orange-4": (227, 85, 0), - "sap-orange-5": (208, 69, 18), - "sap-orange-6": (188, 54, 24), - - "juno-grey-blue-1": (64, 70, 75), - "juno-grey-blue-2": (48, 54, 60), - "juno-grey-blue-3": (41, 47, 54), - "juno-grey-blue-4": (38, 44, 51), - "juno-grey-blue-5": (36, 42, 49), - "juno-grey-blue-6": (31, 38, 45), - "juno-grey-blue-7": (28, 35, 42), - "juno-grey-blue-8": (23, 30, 37), - "juno-grey-blue-9": (18, 25, 32), - "juno-grey-blue-10": (13, 20, 28), - "juno-grey-blue-11": (0, 8, 16), - - "juno-grey-light-1": (249, 249, 249), - "juno-grey-light-2": (247, 247, 247), - "juno-grey-light-3": (244, 244, 244), - "juno-grey-light-4": (241, 241, 241), - "juno-grey-light-5": (238, 238, 238), - "juno-grey-light-6": (235, 235, 235), - "juno-grey-light-7": (233, 233, 233), - "juno-grey-light-8": (230, 230, 230), - "juno-grey-light-9": (227, 227, 227), - "juno-grey-light-10": (215, 215, 215), - - "juno-blue-1": (203, 232, 247), - "juno-blue-2": (165, 211, 234), - "juno-blue-3": (137, 201, 232), - "juno-blue-4": (67, 162, 208), - "juno-blue-5": (0, 125, 184), - "juno-blue-6": (30, 106, 146), - "juno-blue-7": (10, 103, 153), - "juno-blue-8": (7, 85, 128), - "juno-blue-9": (5, 70, 105), - "juno-blue-10": (3, 55, 84), - - "juno-turquoise-1": (197, 247, 255), - "juno-turquoise-2": (132, 241, 255), - "juno-turquoise-3": (25, 232, 250), - "juno-turquoise-4": (22, 217, 234), - "juno-turquoise-5": (21, 208, 224), - "juno-turquoise-6": (15, 167, 180), - "juno-turquoise-7": (9, 133, 144), - "juno-turquoise-8": (5, 100, 109), - "juno-turquoise-9": (2, 69, 75), - "juno-turquoise-10": (1, 41, 4), - - "juno-primary-blue-1": (15, 170, 255), - "juno-primary-blue-2": (0, 143, 211), - "juno-primary-blue-3": (0, 118, 203), - "juno-primary-blue-4": (15, 70, 167), - "juno-primary-blue-5": (0, 50, 131), - "juno-primary-blue-6": (0, 25, 90), - -); - -/* Light Theme Color Definitions */ -$light-theme-color-map: ( - "accent": (0, 118, 203), - - "info": (0, 118, 203), - "success": (79, 184, 28), - "warning": (255, 175, 0), - "danger": (199, 0, 0), - "error": (199, 0, 0), - - "juno-text-light": (150, 150, 150), - "juno-text-default": (76, 76, 76), - "juno-text-high": (64, 64, 64), - "juno-text-highest": (0, 0, 0), - "juno-text-disabled": (183, 183, 183), - - "juno-primary-danger-1": (235, 146, 146), - "juno-primary-danger-2": (218, 93, 93), - "juno-primary-danger-3": (213, 64, 64), - "juno-primary-danger-4": (199, 0, 0), - "juno-primary-danger-5": (165,11,11), -); - -/* Dark Theme Color Definitions */ -$dark-theme-color-map: ( - "accent": (21, 208, 224), - - "info": (21, 208, 224), - "success": (59, 255, 91), - "warning": (255, 198, 0), - "danger": (255, 65, 16), - "error": (255, 65, 16), - - "juno-text-light": (122, 122, 122), - "juno-text-default": (187, 187, 187), - "juno-text-high": (222, 223, 224), - "juno-text-highest": (255, 254, 253), - "juno-text-disabled": (92, 92, 92), - - "juno-primary-danger-1": (231, 163, 137), - "juno-primary-danger-2": (222, 126, 91), - "juno-primary-danger-3": (208, 69, 18), - "juno-primary-danger-4": (187, 62, 16), - "juno-primary-danger-5": (164, 54, 14), -); - - - -/* Global Color Variables */ -:root, -:host { - - @each $name, $value in $color-map { - --color-#{$name}: rgb(#{$value}); - --color-#{$name}-raw: #{$value}; - } - -} - -/* Light Theme Color Variables */ -.theme-light { - @each $name, $value in $light-theme-color-map { - --color-#{$name}: rgb(#{$value}); - --color-#{$name}-raw: #{$value}; - } -} - -/* Dark Theme Color Variables */ -.theme-dark { - @each $name, $value in $dark-theme-color-map { - --color-#{$name}: rgb(#{$value}); - --color-#{$name}-raw: #{$value}; - } -} - - -/* Color Assignments */ - -/* ----- LIGHT THEME ----- */ -.theme-light { - // LT Background Colors - --color-background-lvl-0: var(--color-white); - --color-background-lvl-1: var(--color-juno-grey-light-1); - --color-background-lvl-2: var(--color-juno-grey-light-3); - --color-background-lvl-3: var(--color-juno-grey-light-7); - --color-background-lvl-4: var(--color-juno-grey-light-9); - --color-background-lvl-5: var(--color-juno-grey-light-10); - - --color-background-lvl-0-raw: var(--color-white-raw); - --color-background-lvl-1-raw: var(--color-juno-grey-light-1-raw); - --color-background-lvl-2-raw: var(--color-juno-grey-light-3-raw); - --color-background-lvl-3-raw: var(--color-juno-grey-light-7-raw); - --color-background-lvl-4-raw: var(--color-juno-grey-light-9-raw); - --color-background-lvl-5-raw: var(--color-juno-grey-light-10-raw); - - // LT Global - --color-global-bg: var(--color-juno-grey-light-1); - --color-global-bg-raw: var(--color-juno-grey-light-1-raw); - - --color-global-text: var(--color-juno-text-default-raw); - --color-content-area-bg: var(--color-background-lvl-0); - --color-content-area-bg-raw: var(--color-background-lvl-0-raw); - // LT FOCUS - --color-focus: var(--color-accent); - --color-focus-raw: var(--color-accent-raw); - // LT Text - --color-text-highest: var(--color-juno-text-highest); - --color-text-high: var(--color-juno-text-high); - --color-text-default: var(--color-juno-text-default); - --color-text-light: var(--color-juno-text-light); - --color-text-disabled: var(--color-juno-text-disabled); - --color-text-link: var(--color-accent); - --color-text-highest-raw: var(--color-juno-text-highest-raw); - --color-text-high-raw: var(--color-juno-text-high-raw); - --color-text-default-raw: var(--color-juno-text-default-raw); - --color-text-light-raw: var(--color-juno-text-light-raw); - --color-text-disabled-raw: var(--color-juno-text-disabled-raw); - --color-text-link-raw: var(--color-accent-raw); - - // LT Badge - --color-badge-default-bg: var(--color-juno-grey-light-3); - - // LT Button - // LT Primary Button - --color-button-primary-text: var(--color-white); - --color-button-primary-bg: var(--color-juno-primary-blue-3); - // |-- LT Primary Button :hover - --color-button-primary-hover-text: var(--color-white); - --color-button-primary-hover-bg: var(--color-juno-primary-blue-2); - // |-- LT Primary Button :active - --color-button-primary-active-text: var(--color-white); - --color-button-primary-active-bg: var(--color-juno-primary-blue-5); - - // LT Default Button - --color-button-default-text: var(--color-text-high); - --color-button-default-bg: var(--color-background-lvl-4); - --color-button-default-border: var(--color-background-lvl-4); - // |-- LT Default Button :hover - --color-button-default-hover-text: var(--color-text-high); - --color-button-default-hover-bg: var(--color-background-lvl-3); - --color-button-default-hover-border: var(--color-background-lvl-3); - // |-- LT Default Button :active - --color-button-default-active-text: var(--color-text-high); - --color-button-default-active-bg: var(--color-background-lvl-2); - --color-button-default-active-border: var(--color-background-lvl-4); - - // LT Subdued Button - --color-button-subdued-text: var(--color-text-default); - --color-button-subdued-icon: var(--color-text-default); - --color-button-subdued-bg: var(--color-background-lvl-3); - --color-button-subdued-border: var(--color-background-lvl-4); - // |-- LT Subdued Button :hover - --color-button-subdued-hover-text: var(--color-text-default); - --color-button-subdued-hover-bg: var(--color-background-lvl-1); - --color-button-subdued-hover-border: var(--color-background-lvl-4); - // |-- LT Subdued Button :active - --color-button-subdued-active-text: var(--color-text-default); - --color-button-subdued-active-bg: var(--color-background-lvl-0); - --color-button-subdued-active-border: var(--color-background-lvl-4); - - // LT Primary Danger Button - --color-button-primary-danger-text: var(--color-white); - --color-button-primary-danger-bg: var(--color-juno-primary-danger-4); - // |-- LT Primary Danger Button :hover - --color-button-primary-danger-hover-text: var(--color-white); - --color-button-primary-danger-hover-bg: var(--color-juno-primary-danger-3); - // |-- LT Primary Danger Button :active - --color-button-primary-danger-active-text: var(--color-white); - --color-button-primary-danger-active-bg: var(--color-juno-primary-danger-5); - - // LT Icon - --color-icon-danger: var(--color-juno-red-raw); - --color-icon-info: var(--color-accent-raw); - --color-icon-success: var(--color-sap-green-raw); - --color-icon-warning: var(--color-warning-raw); - // LT Message - --color-message-danger-border: var(--color-danger-raw); - --gradient-message-danger-bg: linear-gradient( - 90deg, - rgb(255, 231, 224) 0%, - rgb(255, 180, 158) 100% - ); - --color-message-default-border: var(--color-info-raw); - --gradient-message-default-bg: linear-gradient( - 90deg, - rgb(229, 244, 248) 0%, - rgb(46, 168, 196) 100% - ); - --color-message-error-border: var(--color-error-raw); - --gradient-message-error-bg: linear-gradient( - 90deg, - rgb(255, 231, 224) 0%, - rgb(255, 180, 158) 100% - ); - --color-message-warning-border: var(--color-warning-raw); - --gradient-message-warning-bg: linear-gradient( - 90deg, - rgb(253, 245, 226) 0%, - rgb(255, 231, 147) 100% - ); - --color-message-success-border: var(--color-success-raw); - --gradient-message-success-bg: linear-gradient( - 90deg, - rgb(230, 247, 233) 0%, - rgb(170, 229, 180) 100% - ); - - // LT Introbox - --color-introbox-bg: var(--color-background-lvl-2-raw); - --color-introbox-border: var(--color-accent-raw); - // LT (Text-) Input - --color-textinput-bg: var(--color-background-lvl-3-raw); - --color-textinput-default-border: var(--color-background-lvl-4-raw); - --color-textinput-text: var(--color-juno-text-high-raw); - --color-textinput-placeholder-text: var(--color-juno-text-high-raw); - --color-textinput-focus-border: var(--color-accent-raw); - --color-textinput-autofill-text: var(--color-black); - --color-textinput-autofill-bg: var(--color-juno-blue-1); - --color-textinput-autofill-label: var(--color-juno-text-default); - // LT Select - --color-select-bg: var(--color-background-lvl-3-raw); - // LT Checkbox - --color-checkbox-bg: var(--color-background-lvl-5-raw); - --color-checkbox-checked-color: var(--color-accent-raw); - // LT Radio - --color-radio-bg: var(--color-background-lvl-5-raw); - --color-radio-checked-bg: var(--color-accent-raw); - // LT Switch - --color-switch-default-border: var(--color-juno-text-default-raw); - --color-switch-handle-bg: var(--color-juno-text-default-raw); - --color-switch-handle-checked-bg: var(--color-accent-raw); - // LT Required - --color-required-bg: var(--color-accent-raw); - // LT Spinner - --color-spinner-primary: var(--color-accent-raw); - // LT Syntax Highlighting - --color-syntax-highlight-base00: var(--color-codeblock-bg); // bg - --color-syntax-highlight-base01: var(--color-juno-grey-light-3); // ? - --color-syntax-highlight-base02: var(--color-sap-grey-3); // lines and boxes - --color-syntax-highlight-base03: var(--color-sap-grey-3); - --color-syntax-highlight-base04: var(--color-sap-grey-3); - --color-syntax-highlight-base05: var(--color-juno-text-high); - --color-syntax-highlight-base06: red; - --color-syntax-highlight-base07: var(--color-juno-text-high); - --color-syntax-highlight-base08: var(--color-juno-grey-blue-6); // NULL - --color-syntax-highlight-base09: var(--color-juno-blue-4); // String value - --color-syntax-highlight-base0A: var(--color-juno-grey-blue-6); // NaN - --color-syntax-highlight-base0B: var(--color-juno-blue-4); // float value - --color-syntax-highlight-base0C: var(--color-sap-gold); // array index - --color-syntax-highlight-base0D: var(--color-sap-gold); // expanded icon - --color-syntax-highlight-base0E: var(--color-juno-blue-4); - // LT bool + collapsed icon - --color-syntax-highlight-base0F: var(--color-juno-blue-4); // integer value - // LT DataGrid - --color-datagridrow-selected: var(--color-accent-raw); - // LT DataList - --color-datalist-row-border: var(--color-background-lvl-1-raw); - --color-datalistrow-selected: var(--color-accent-raw); - // LT CodeBlock - --color-codeblock-bg: var(--color-background-lvl-2-raw); - --color-codeblock-bar-border: var(--color-background-lvl-4-raw); - // LT Panel - // --color-panel-bg-raw: var(--color-white-raw); - --color-panel-bg: rgba(252, 252, 252, 0.8); - // LT TabNavigation - --color-tabnavigation-top-bg: var(--color-juno-grey-light-5-raw); - --color-tabnavigation-content-bottom-border: var(--color-background-lvl-4-raw); - // LT Filters - --color-filters-bg: var(--color-background-lvl-1-raw); - --color-filter-input-bg: var(--color-background-lvl-0-raw); - --color-filter-input-border: var(--color-background-lvl-4-raw); - --color-filter-input-textinput-bg: transparent; - --color-filter-pill-border: var(--color-background-lvl-4-raw); - --color-filter-pill-key-bg: var(--color-background-lvl-4-raw); - // LT Modal - --color-modal-backdrop-bg: rgba(0, 0, 0, 0.2); - // LT Box - --color-box-bg: var(--color-background-lvl-1); - --color-box-border: var(--color-background-lvl-3); - // DT SideNavigation - --color-sidenavigation-item-active: var(--color-black); - --color-sidenavigation-item-active-bg: var(--color-background-lvl-0); - // DT TopNavigation - --color-topnavigation-item-active: var(--color-black); - --color-topnavigation-item-bg: var(--color-sap-grey-1); - --color-topnavigation-item-active-bg: var(--color-sap-grey-3); - - // DT Datepicker - --color-datepicker-calendar-bg: var(--color-background-lvl-1); - -} - -/* ----- LIGHT THEME END -----*/ -/* ----- */ -/* ----- */ -/* ----- */ -/* ----- */ -/* ----- DARK THEME ----- */ - -.theme-dark { - // DT Background Colors - --color-background-lvl-0: var(--color-juno-grey-blue-9); - --color-background-lvl-1: var(--color-juno-grey-blue-7); - --color-background-lvl-2: var(--color-juno-grey-blue-5); - --color-background-lvl-3: var(--color-juno-grey-blue-3); - --color-background-lvl-4: var(--color-juno-grey-blue-2); - --color-background-lvl-5: var(--color-juno-grey-blue-1); - - --color-background-lvl-0-raw: var(--color-juno-grey-blue-9-raw); - --color-background-lvl-1-raw: var(--color-juno-grey-blue-7-raw); - --color-background-lvl-2-raw: var(--color-juno-grey-blue-5-raw); - --color-background-lvl-3-raw: var(--color-juno-grey-blue-3-raw); - --color-background-lvl-4-raw: var(--color-juno-grey-blue-2-raw); - --color-background-lvl-5-raw: var(--color-juno-grey-blue-1-raw); - - // DT Global - --color-global-bg: var(--color-juno-grey-blue-10); - --color-global-bg-raw: var(--color-juno-grey-blue-10-raw); - - --color-global-text: var(--color-juno-text-default-raw); - --color-content-area-bg: var(--color-background-lvl-0); - --color-content-area-bg-raw: var(--color-background-lvl-0-raw); - - // DT FOCUS - --color-focus: var(--color-accent); - --color-focus-raw: var(--color-accent-raw); - --color-focus-border: var(--color-accent-raw); - // DT Text - --color-text-highest: var(--color-juno-text-highest); - --color-text-high: var(--color-juno-text-high); - --color-text-default: var(--color-juno-text-default); - --color-text-light: var(--color-juno-text-light); - --color-text-disabled: var(--color-juno-text-disabled); - --color-text-link: var(--color-accent); - --color-text-highest-raw: var(--color-juno-text-highest-raw); - --color-text-high-raw: var(--color-juno-text-high-raw); - --color-text-default-raw: var(--color-juno-text-default-raw); - --color-text-light-raw: var(--color-juno-text-light-raw); - --color-text-disabled-raw: var(--color-juno-text-disabled-raw); - --color-text-link-raw: var(--color-accent-raw); - - // DT Badge - --color-badge-default-bg: var(--color-juno-grey-blue-3); - - // DT Button - // DT Primary Button - --color-button-primary-bg: var(--color-juno-turquoise-7); - --color-button-primary-text: var(--color-white); - // |-- DT Primary Button :hover - --color-button-primary-hover-bg: var(--color-juno-turquoise-5); - --color-button-primary-hover-text: var(--color-white); - // |-- DT Primary Button :active - --color-button-primary-active-bg: var(--color-juno-turquoise-9); - --color-button-primary-active-text: var(--color-white); - - // DT Default Button - --color-button-default-text: var(--color-text-high); - --color-button-default-icon: var(--color-text-high); - --color-button-default-bg: var(--color-background-lvl-5); - --color-button-default-border: var(--color-background-lvl-5); - // |-- DT Default Button :hover - --color-button-default-hover-text: var(--color-text-high); - --color-button-default-hover-bg: var(--color-background-lvl-3); - --color-button-default-hover-border: var(--color-background-lvl-3); - // |-- DT Default Button :active - --color-button-default-active-text: var(--color-text-high); - --color-button-default-active-bg: var(--color-background-lvl-2); - --color-button-default-active-border: var(--color-background-lvl-4); - - // DT Subdued Button - --color-button-subdued-text: var(--color-text-default); - --color-button-subdued-icon: var(--color-text-default); - --color-button-subdued-bg: var(--color-background-lvl-3); - --color-button-subdued-border: var(--color-background-lvl-4); - // |-- DT Subdued Button :hover - --color-button-subdued-hover-text: var(--color-text-default); - --color-button-subdued-hover-bg: var(--color-background-lvl-2); - --color-button-subdued-hover-border: var(--color-background-lvl-4); - // |-- DT Subdued Button :active - --color-button-subdued-active-text: var(--color-text-default); - --color-button-subdued-active-bg: var(--color-background-lvl-0); - --color-button-subdued-active-border: var(--color-background-lvl-4); - - // DT Primary-Danger Button - --color-button-primary-danger-text: var(--color-white); - --color-button-primary-danger-bg: var(--color-juno-primary-danger-4); - // |-- DT Primary Danger Button :hover - --color-button-primary-danger-hover-text: var(--color-white); - --color-button-primary-danger-hover-bg: var(--color-juno-primary-danger-3); - // |-- DT Primary Danger Button :active - --color-button-primary-danger-active-text: var(--color-white); - --color-button-primary-danger-active-bg: var(--color-juno-primary-danger-5); - - // DT Icon - --color-icon-danger: var(--color-juno-red-5-raw); - --color-icon-info: var(--color-accent-raw); - --color-icon-success: var(--color-sap-green-5-raw); - --color-icon-warning: var(--color-warning-raw); - // DT Message - --color-message-danger-border: var(--color-danger-raw); - --gradient-message-danger-bg: linear-gradient( - 90deg, - rgb(57, 39, 38) 0%, - rgb(124, 48, 30) 100% - ); - --color-message-default-border: var(--color-info-raw); - --gradient-message-default-bg: linear-gradient( - 90deg, - rgb(28, 57, 65) 0%, - rgb(25, 108, 119) 100% - ); - --color-message-error-border: var(--color-error-raw); - --gradient-message-error-bg: linear-gradient( - 90deg, - rgb(57, 39, 38) 0%, - rgb(124, 48, 30) 100% - ); - --color-message-warning-border: var(--color-warning-raw); - --gradient-message-warning-bg: linear-gradient( - 90deg, - rgb(57, 56, 36) 0%, - rgb(124, 104, 24) 100% - ); - --color-message-success-border: var(--color-success-raw); - --gradient-message-success-bg: linear-gradient( - 90deg, - rgb(32, 55, 46) 0%, - rgb(39, 102, 57) 100% - ); - // DT Introbox - --color-introbox-bg: var(--color-background-lvl-2-raw); - --color-introbox-border: var(--color-accent-raw); - // DT (Text-)Input - --color-textinput-bg: var(--color-background-lvl-3-raw); - --color-textinput-default-border: var(--color-background-lvl-4-raw); - --color-textinput-text: var(--color-juno-text-high-raw); - --color-textinput-placeholder-text: var(--color-juno-text-high-raw); - --color-textinput-focus-border: var(--color-accent-raw); - --color-textinput-autofill-text: var(--color-black); - --color-textinput-autofill-bg: var(--color-juno-blue-1); - --color-textinput-autofill-label: var(--color-black); - // DT Select - --color-select-bg: var(--color-background-lvl-4-raw); - // DT Checkbox - --color-checkbox-bg: var(--color-background-lvl-5-raw); - --color-checkbox-checked-color: var(--color-accent-raw); - // DT Radio - --color-radio-bg: var(--color-background-lvl-5-raw); - --color-radio-checked-bg: var(--color-accent-raw); - // DT Switch - --color-switch-default-border: var(--color-juno-text-high-raw); - --color-switch-handle-bg: var(--color-juno-text-high-raw); - --color-switch-handle-checked-bg: var(--color-accent-raw); - --color-switch-hover-border: var(--color-accent-raw); - // DT Required - --color-required-bg: var(--color-accent-raw); - // DT Spinner - --color-spinner-primary: var(--color-accent-raw); - // DT Syntax Highlighting - --color-syntax-highlight-base00: var(--color-codeblock-bg); // bg - --color-syntax-highlight-base01: var(--color-juno-grey-blue-3); // ? - --color-syntax-highlight-base02: #bbb; // lines and boxes - --color-syntax-highlight-base03: var(--color-sap-grey-3); - --color-syntax-highlight-base04: var(--color-sap-grey-3); - --color-syntax-highlight-base05: #dedfe0; - --color-syntax-highlight-base06: red; - --color-syntax-highlight-base07: #dedfe0; - --color-syntax-highlight-base08: var(--color-juno-grey-blue-6); // NULL - --color-syntax-highlight-base09: var(--color-juno-blue-4); // String value - --color-syntax-highlight-base0A: var(--color-juno-grey-blue-6); // NaN - --color-syntax-highlight-base0B: var(--color-juno-blue-4); // float value - --color-syntax-highlight-base0C: var(--color-sap-gold); // array index - --color-syntax-highlight-base0D: var(--color-sap-gold); // DT expanded icon - --color-syntax-highlight-base0E: var(--color-juno-blue-4); // DT bool + collapsed icon - --color-syntax-highlight-base0F: var(--color-juno-blue-4); // integer value - // DT DataGrid - --color-datagridrow-selected: var(--color-accent-raw); - // DT DataList - --color-datalist-row-border: var(--color-background-lvl-1-raw); - --color-datalistrow-selected: var(--color-accent-raw); - // DT CodeBlock - --color-codeblock-bg: var(--color-background-lvl-2-raw); - --color-codeblock-bar-border: var(--color-background-lvl-4-raw); - // DT Panel - --color-panel-bg: rgba(var(--color-juno-grey-blue-11-raw), 0.75); - - // DT TabNavigation - --color-tabnavigation-top-bg: var(--color-juno-grey-blue-8-raw); - --color-tabnavigation-content-bottom-border: var(--color-background-lvl-4-raw); - // DT Filters - --color-filters-bg: var(--color-background-lvl-1-raw); - --color-filter-input-bg: var(--color-background-lvl-0-raw); - --color-filter-input-border: var(--color-background-lvl-4-raw); - --color-filter-input-textinput-bg: transparent; - --color-filter-pill-border: var(--color-background-lvl-4-raw); - --color-filter-pill-key-bg: var(--color-background-lvl-4-raw); - // DT Modal - --color-modal-backdrop-bg: rgba(60, 70, 75, 0.6); - // DT Box - --color-box-bg: var(--color-background-lvl-1); - --color-box-border: var(--color-background-lvl-3); - // DT SideNavigation - --color-sidenavigation-item-active: var(--color-white); - --color-sidenavigation-item-active-bg: var(--color-background-lvl-0); - // DT TopNavigation - --color-topnavigation-item-active: var(--color-white); - --color-topnavigation-item-bg: var(--color-juno-grey-blue-7); - --color-topnavigation-item-active-bg: var(--color-juno-grey-blue-2); - // DT Datepicker - --color-datepicker-calendar-bg: var(--color-background-lvl-1); -} - -/* ----- DARK THEME END ----- */ - -// Grid configuration -:root, -:host { - --grid-columns: 12; - --grid-row-margin-x: -0.5rem; - --grid-column-flex-grow: 0; - --grid-column-flex-shrink: 1; - --grid-column-flex-basis: auto; - --grid-column-default-width: 8.333333%; -} \ No newline at end of file diff --git a/libs/juno-ui-components/package.json b/libs/juno-ui-components/package.json deleted file mode 100644 index c77e16232..000000000 --- a/libs/juno-ui-components/package.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "name": "juno-ui-components", - "private": true, - "main": "build/index.js", - "module": "build/index.js", - "source": "src/index.js", - "style": "build/lib/variables.css", - "version": "2.14.0", - "files": [ - "src/colors.css", - "tailwind.config.js" - ], - "author": "UI-Team", - "contributors": [ - "Esther Schmitz", - "Franz Heidl" - ], - "repository": "https://github.com/sapcc/juno/tree/main/libs/juno-ui-components", - "license": "Apache-2.0", - "devDependencies": { - "@babel/plugin-transform-parameters": "^7.22.5", - "@babel/preset-env": "^7.20.2", - "@babel/preset-react": "^7.18.6", - "@floating-ui/react": "^0.25.1", - "@headlessui-float/react": "^0.11.2", - "@headlessui/react": "^1.7.15", - "@material-design-icons/svg": "^0.14.4", - "@mdx-js/react": "^1.6.22", - "@rollup/plugin-babel": "^6.0.3", - "@rollup/plugin-commonjs": "^24.0.0", - "@rollup/plugin-node-resolve": "^13.1.3", - "@storybook/addon-docs": "^7.5.3", - "@storybook/addon-essentials": "^7.5.3", - "@storybook/addon-interactions": "^7.5.3", - "@storybook/addon-links": "^7.5.3", - "@storybook/addon-mdx-gfm": "^7.5.3", - "@storybook/addon-postcss": "^2.0.0", - "@storybook/blocks": "^7.5.3", - "@storybook/manager-api": "^7.5.3", - "@storybook/react": "^7.5.3", - "@storybook/react-webpack5": "^7.5.3", - "@storybook/testing-library": "^0.2.2", - "@svgr/rollup": "^6.2.1", - "@svgr/webpack": "^6.2.1", - "@testing-library/dom": "^8.19.0", - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^13.4.0", - "@testing-library/user-event": "^14.4.3", - "add": "^2.0.6", - "autoprefixer": "^10.4.2", - "babel-jest": "^29.3.1", - "babel-loader": "^8.2.3", - "css-loader": "^6.6.0", - "focus-trap-react": "^10.2.3", - "glob": "^8.1.0", - "jest": "^29.3.1", - "jest-environment-jsdom": "^29.3.1", - "node-sass-glob-importer": "^3.0.2", - "postcss": "^8.4.6", - "postcss-loader": "^6.2.1", - "prop-types": "^15.8.1", - "react": "18.2.0", - "react-dom": "^18.2.0", - "react-jss": "^10.8.1", - "react-tabs": "^4.2.1", - "regenerator-runtime": "^0.13.9", - "rollup": "^3.4.0", - "rollup-plugin-analyzer": "^4.0.0", - "rollup-plugin-babel-minify": "^10.0.0", - "rollup-plugin-delete": "^2.0.0", - "rollup-plugin-includepaths": "^0.2.4", - "rollup-plugin-node-resolve": "^5.2.0", - "rollup-plugin-postcss": "^4.0.2", - "sass": "^1.49.7", - "sass-loader": "^12.4.0", - "storybook": "^7.6.17", - "style-loader": "^3.3.1", - "tailwindcss": "^3.3.1", - "flatpickr": "4.6.13" - }, - "peerDependencies": { - "prop-types": "15.8.1", - "react": "18.2.0", - "react-dom": "^18.2.0" - }, - "scripts": { - "storybook": "storybook dev -p $APP_PORT --ci --no-open", - "build-storybook": "storybook build", - "build": "rollup -c", - "test": "jest", - "test:watch": "jest --watchAll" - }, - "jest": { - "verbose": true, - "testEnvironment": "jsdom", - "transformIgnorePatterns": [ - "node_modules/(?!(react-merge-refs)/)" - ], - "setupFilesAfterEnv": [ - "./setupTests.js" - ], - "transform": { - "\\.[jt]sx?$": "babel-jest", - "\\.mjs$": "babel-jest", - "^.+\\.svg$": "<rootDir>/test/__mocks__/svg.js" - }, - "moduleNameMapper": { - "^.+\\.(css|scss)$": "<rootDir>/test/__mocks__/styleMock.js", - "@material-design-icons/svg/.+\\.svg$": "<rootDir>/test/__mocks__/svgLib.js" - } - } -} diff --git a/libs/juno-ui-components/postcss.config.js b/libs/juno-ui-components/postcss.config.js deleted file mode 100644 index 0627e0e4b..000000000 --- a/libs/juno-ui-components/postcss.config.js +++ /dev/null @@ -1,8 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -module.exports = { - plugins: [require("tailwindcss"), require("autoprefixer")], -} diff --git a/libs/juno-ui-components/rollup.config.js b/libs/juno-ui-components/rollup.config.js deleted file mode 100644 index c38f584ec..000000000 --- a/libs/juno-ui-components/rollup.config.js +++ /dev/null @@ -1,153 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -const { babel } = require("@rollup/plugin-babel") -const del = require("rollup-plugin-delete") -const postcss = require("rollup-plugin-postcss") -const pkg = require("./package.json") -const fs = require("fs") -const minify = require("rollup-plugin-babel-minify") -const analyze = require("rollup-plugin-analyzer") -const { nodeResolve } = require("@rollup/plugin-node-resolve") -const commonjs = require("@rollup/plugin-commonjs") -const svgr = require("@svgr/rollup") -const glob = require("glob") -const { - generateTailwindThemeClassesJson, -} = require("./src/docs/ColorPalette/generateTailwindThemeClassesJson") - -// generates tailwind classes for documentation usages. -generateTailwindThemeClassesJson() - -// IMPORTANT! -// package.json is single source of truth policy - -if (!/.+\/.+\.js/.test(pkg.module)) - throw new Error( - "module value is incorrect, use DIR/FILE.js like build/index.js" - ) -const buildDir = pkg.module.slice(0, pkg.module.lastIndexOf("/")) -// filename is extracted from module key in package.json -// because of single source of truth policy -const filename = pkg.module.slice( - pkg.module.lastIndexOf("/") + 1, - pkg.module.lastIndexOf(".") -) - -const isProduction = process.env.NODE_ENV === "production" -const IGNORE_EXTERNALS = process.env.IGNORE_EXTERNALS === "true" - -// define plugins here to use it in different configs -const plugins = [ - svgr({ - svgo: false, - titleProp: true, - }), - postcss({ - config: { - path: "./postcss.config.js", - }, - extract: false, - minimize: false, //true, - inject: false, - extensions: [".scss", ".css"], - use: ["sass", "glob-imports"], - loaders: [ - // custom loader!!! to load all scss files in globals.scss - { - name: "glob-imports", - test: /\.(sass|scss)$/, - process({ code }) { - // handle glob import - return new Promise((resolve, reject) => { - const match = [...code.matchAll(/@import\s+(.*\*+.*);/g)] - match.forEach((m) => { - const files = glob.sync("./src/" + m[1].replace(/"|'/g, "")) - let result = files.map((f) => `@import "${f}";`).join("\n") - code = code.replace(m[0], result) - }) - resolve({ code }) - }) - }, - }, - ], - }), - - nodeResolve(), - babel({ - // babelrc: false, - // // exclude: "node_modules/**", - // presets: ["@babel/preset-react"], - babelHelpers: "bundled", - }), - commonjs(), - - minify({ comments: false }), - analyze({ - summaryOnly: true, - limit: 0, - }), -] - -const config = [ - // bundle all components - { - input: fs.readdirSync("./src/components").reduce((map, file) => { - map[file] = `src/components/${file}/index.js` - return map - }, {}), - output: [ - // { dir: "lib", format: "cjs", preserveModules: false }, - { - dir: buildDir, - format: "esm", - preserveModules: false, - compact: true, - }, - ], - - plugins: [del({ targets: [`${buildDir}/**/*`] }), ...plugins], - }, - { - input: "tailwind.config.js", - output: { - file: `${buildDir}/lib/tailwind.config.js`, - }, - }, - { - input: pkg.source, - output: { - file: `${buildDir}/index.js`, - format: "esm", - preserveModules: false, - compact: true, - }, - plugins, - - external: ["react", "react-dom", "prop-types"].concat( - isProduction && !IGNORE_EXTERNALS - ? Object.keys(pkg.peerDependencies || {}) - : [] - ), - }, - { - input: "lib/variables.scss", - output: { - file: `${buildDir}/lib/variables.css`, - }, - plugins: [ - postcss({ - config: { - path: "./postcss.config.js", - }, - extract: true, - minimize: true, - inject: false, - }), - ], - }, -] - -module.exports = config diff --git a/libs/juno-ui-components/setupTests.js b/libs/juno-ui-components/setupTests.js deleted file mode 100644 index d59db8eee..000000000 --- a/libs/juno-ui-components/setupTests.js +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -// jest-dom adds custom jest matchers for asserting on DOM nodes. -// allows you to do things like: -// expect(element).toHaveTextContent(/react/i) -// learn more: https://github.com/testing-library/jest-dom -import "@testing-library/jest-dom" -import "regenerator-runtime/runtime" - -/* -Mock ResizeObserver. -Required to test Radix-UI-based components. -https://github.com/ZeeCoder/use-resize-observer/issues/40 -https://stackoverflow.com/questions/64558062/how-to-mock-resizeobserver-to-work-in-unit-tests-using-react-testing-library -*/ -class ResizeObserver { - observe() {} - unobserve() {} - disconnect() {} -} - -window.ResizeObserver = ResizeObserver - - -/** - * Required to test Radix-UI-based components: - * JSDOM doesn't implement PointerEvent so we need to mock our own implementation - * Default to mouse left click interaction - * https://github.com/radix-ui/primitives/issues/1822 - * https://github.com/jsdom/jsdom/pull/2666 - */ - -class MockPointerEvent extends Event { - constructor(type, props) { - super(type, props) - this.button = props.button || 0 - this.ctrlKey = props.ctrlKey || false - this.pointerType = props.pointerType || "mouse" - } -} - -window.PointerEvent = MockPointerEvent -window.HTMLElement.prototype.scrollIntoView = jest.fn() -window.HTMLElement.prototype.releasePointerCapture = jest.fn() -window.HTMLElement.prototype.hasPointerCapture = jest.fn() diff --git a/libs/juno-ui-components/src/components/AppBody/AppBody.component.js b/libs/juno-ui-components/src/components/AppBody/AppBody.component.js deleted file mode 100644 index f00ad41c8..000000000 --- a/libs/juno-ui-components/src/components/AppBody/AppBody.component.js +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -const containerStyles = ` - jn-flex - jn-flex-col - jn-h-full -` - -/** - * Only needed if you want to build your app's scaffold manually. In most cases it is better to use the AppShell component instead. - * Body of the app. Treat this like the body tag of an html page. - */ -export const AppBody = ({ className, children, ...props }) => { - return ( - <div - className={`juno-body ${containerStyles} ${className}`} - {...props} - > - {children} - </div> - ) -} - -AppBody.propTypes = { - /** Add custom class name */ - className: PropTypes.string, -} - -AppBody.defaultProps = { - className: "", -} diff --git a/libs/juno-ui-components/src/components/AppBody/AppBody.stories.js b/libs/juno-ui-components/src/components/AppBody/AppBody.stories.js deleted file mode 100644 index 964f638a3..000000000 --- a/libs/juno-ui-components/src/components/AppBody/AppBody.stories.js +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; - -import { AppBody } from './index.js'; - -export default { - title: 'Internal/AppBody', - component: AppBody, - argTypes: { - children: { - control: false, - }, - }, -}; - -const Template = (args) => <AppBody {...args}></AppBody>; - -export const Body = { - render: Template, - - parameters: { - docs: { - description: { - story: - "Only needed if you want to build your app's scaffold manually. In most cases it is better to use the AppShell component instead. Body of the app. Treat this like the body tag of an html page.", - }, - }, - }, - - args: {}, -}; diff --git a/libs/juno-ui-components/src/components/AppBody/AppBody.test.js b/libs/juno-ui-components/src/components/AppBody/AppBody.test.js deleted file mode 100644 index e7c4faf55..000000000 --- a/libs/juno-ui-components/src/components/AppBody/AppBody.test.js +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { AppBody } from "./index" - -describe("AppBody", () => { - test("renders an app body", async () => { - render(<AppBody data-testid="app-body" />) - expect(screen.getByTestId("app-body")).toBeInTheDocument() - expect(screen.getByTestId("app-body")).toHaveClass("juno-body") - }) - - test("renders an app body with flex column", async () => { - render(<AppBody data-testid="app-body" />) - expect(screen.getByTestId("app-body")).toBeInTheDocument() - expect(screen.getByTestId("app-body")).toHaveClass( - "jn-flex-col" - ) - }) - - test("renders an app body with full height", async () => { - render(<AppBody data-testid="app-body" />) - expect(screen.getByTestId("app-body")).toBeInTheDocument() - expect(screen.getByTestId("app-body")).toHaveClass("jn-h-full") - }) - - test("renders children as passed", async () => { - render( - <AppBody data-testid="app-body"> - <button></button> - </AppBody> - ) - expect(screen.getByTestId("app-body")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render( - <AppBody data-testid="app-body" className="my-custom-classname" /> - ) - expect(screen.getByTestId("app-body")).toBeInTheDocument() - expect(screen.getByTestId("app-body")).toHaveClass( - "my-custom-classname" - ) - }) - - test("renders all props", async () => { - render(<AppBody data-testid="app-body" data-lolol="some-prop" />) - expect(screen.getByTestId("app-body")).toBeInTheDocument() - expect(screen.getByTestId("app-body")).toHaveAttribute( - "data-lolol", - "some-prop" - ) - }) -}) diff --git a/libs/juno-ui-components/src/components/AppBody/index.js b/libs/juno-ui-components/src/components/AppBody/index.js deleted file mode 100644 index a26de8d50..000000000 --- a/libs/juno-ui-components/src/components/AppBody/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { AppBody } from "./AppBody.component" diff --git a/libs/juno-ui-components/src/components/AppIntro/AppIntro.component.js b/libs/juno-ui-components/src/components/AppIntro/AppIntro.component.js deleted file mode 100644 index d9559e857..000000000 --- a/libs/juno-ui-components/src/components/AppIntro/AppIntro.component.js +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -const introStyles = ` - jn-pt-16 - jn-pb-14 - jn-text-xl - in-pr-[45%] -` - -/** - * OBSOLETE: Will be deleted! - */ -export const AppIntro = ({ className, children, ...props }) => { - return ( - <div className={`juno-app-intro ${introStyles} ${className}`} {...props}> - {children} - </div> - ) -} - -AppIntro.propTypes = { - /** Add custom class name */ - className: PropTypes.string, -} - -AppIntro.defaultProps = { - className: "", -} diff --git a/libs/juno-ui-components/src/components/AppIntro/AppIntro.stories.js b/libs/juno-ui-components/src/components/AppIntro/AppIntro.stories.js deleted file mode 100644 index 7516f13e0..000000000 --- a/libs/juno-ui-components/src/components/AppIntro/AppIntro.stories.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; - -import { AppIntro } from './index.js'; - -export default { - title: 'Layout/AppIntro', - component: AppIntro, - argTypes: { - children: { - control: false, - }, - }, -}; - -const Template = (args) => ( - <AppIntro {...args}> - Intro text here. Explain what this app is in a short lead text. Lorem ipsum dolor sit amet. At - vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata - sanctus est. Lorem ipsum dolor sit amet. - </AppIntro> -); - -export const Intro = { - render: Template, - - parameters: { - docs: { - description: { - story: 'OBSOLETE: Will be deleted!', - }, - }, - }, - - args: {}, -}; diff --git a/libs/juno-ui-components/src/components/AppIntro/AppIntro.test.js b/libs/juno-ui-components/src/components/AppIntro/AppIntro.test.js deleted file mode 100644 index 10650dbaf..000000000 --- a/libs/juno-ui-components/src/components/AppIntro/AppIntro.test.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { AppIntro } from "./index" - -describe("AppIntro", () => { - test("renders an app intro", async () => { - render(<AppIntro data-testid="app-intro" />) - expect(screen.getByTestId("app-intro")).toBeInTheDocument() - expect(screen.getByTestId("app-intro")).toHaveClass("juno-app-intro") - }) - - test("renders children as passed", async () => { - render( - <AppIntro data-testid="app-intro"> - <button></button> - </AppIntro> - ) - expect(screen.getByTestId("app-intro")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<AppIntro data-testid="app-intro" className="my-custom-classname" />) - expect(screen.getByTestId("app-intro")).toBeInTheDocument() - expect(screen.getByTestId("app-intro")).toHaveClass("my-custom-classname") - }) - - test("renders all props", async () => { - render(<AppIntro data-testid="app-intro" data-lolol="some-prop" />) - expect(screen.getByTestId("app-intro")).toBeInTheDocument() - expect(screen.getByTestId("app-intro")).toHaveAttribute( - "data-lolol", - "some-prop" - ) - }) -}) diff --git a/libs/juno-ui-components/src/components/AppIntro/index.js b/libs/juno-ui-components/src/components/AppIntro/index.js deleted file mode 100644 index 57440f414..000000000 --- a/libs/juno-ui-components/src/components/AppIntro/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { AppIntro } from "./AppIntro.component" diff --git a/libs/juno-ui-components/src/components/AppShell/AppShell.component.js b/libs/juno-ui-components/src/components/AppShell/AppShell.component.js deleted file mode 100644 index c6626778d..000000000 --- a/libs/juno-ui-components/src/components/AppShell/AppShell.component.js +++ /dev/null @@ -1,121 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" -import { AppBody } from "../AppBody/index" -import { PageHeader } from "../PageHeader/index" -import { MainContainer } from "../MainContainer/index" -import { MainContainerInner } from "../MainContainerInner/index" -import { ContentContainer } from "../ContentContainer/index" -import { ContentHeading } from "../ContentHeading/index" -import { ContentArea } from "../ContentArea/index" -import { PageFooter } from "../PageFooter/index" -import { SideNavigation } from "../SideNavigation/" - -/** - * Body of the app. Treat this like the body tag of an html page. - */ -export const AppShell = ({ - children, - className, - contentHeading, - embedded, - fullWidthContent, - pageHeader, - pageFooter, - sideNavigation, - topNavigation, - ...props -}) => { - - // Determine whether to pass set fullWidth to true in embedded mode or not: - // In non-embedded mode, fullWidthContent should default to false, unless explicitly set to true. - // In embedded mode though, fullWidthContent should default to true, unless explicitly passed as false. - - return ( - <AppBody className={className} {...props}> - - { contentHeading && contentHeading.length ? - console.warn("AppShell: The contentHeading prop is obsolete and will be removed in a future version. In order to render a content heading, use a ContentHeading element as a child in your main content.") - : - "" - } - - { embedded ? - <MainContainer> - <MainContainerInner fullWidth={fullWidthContent === false ? false : true} hasSideNav={ sideNavigation ? true : false }> - { sideNavigation && sideNavigation } - <ContentContainer> - {children} - </ContentContainer> - </MainContainerInner> - </MainContainer> - - : - - <> - { pageHeader && (typeof pageHeader === 'string' || pageHeader instanceof String) ? - <PageHeader heading={pageHeader} /> - : - pageHeader - } - { topNavigation && topNavigation } - {/* Wrap everything except page header and footer and navigations in a main container. Add top margin to MainContainerInner as we are not in embedded mode here. */} - <MainContainer> - <MainContainerInner fullWidth={fullWidthContent === true ? true : false } hasSideNav={ sideNavigation ? true : false } className="jn-mt-[3.875rem]"> - { sideNavigation && sideNavigation } - {/* Content Container. This is the place to add the app's main content. Render left margin only if no SideNavigation is present. */} - <ContentContainer className={ sideNavigation ? "" : "jn-ml-8"}> - {children} - </ContentContainer> - </MainContainerInner> - </MainContainer> - - { pageFooter ? - pageFooter - : - <PageFooter /> - } - </> - } - - </AppBody> - ) -} - -AppShell.propTypes = { - /** Pass either the `<PageHeader>` component or if you don't need to add any content to the page header pass a string to be used as the app name in the standard page header. */ - pageHeader: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.element - ]), - /** Optional. If specified pass a `<PageFooter>` component. If undefined will use default PageFooter */ - pageFooter: PropTypes.element, - /** Optional. If specified expects a `<TopNavigation>` component. If undefined no top navigation is rendered. */ - topNavigation: PropTypes.element, - /** Optional. If specified expects a `<SideNavigation>` component. If undefined no side navigation is rendered. */ - sideNavigation: PropTypes.element, - /** OBSOLETE: The contentHeading prop is obsolete and will be removed in a future version. In order to render a content heading, use a `<ContentHeading>` element as a child in your main content. */ - contentHeading: PropTypes.string, - /** Optional: Defaults to false. Set embedded to true if app is to be rendered embedded in another app/page. - * In this case only the content area and children are rendered, no header/footer or remaining layout components */ - embedded: PropTypes.bool, - /** Whether the main page / view content can spread over the full available width of the viewport or not. Default is `false` (resulting in a width-constrained, centred content column on very wide screens) UNLESS the AppShell is rendered with embedded as true, then the main content will be full-width by default. In embedded mode, `fullWidthContent` can still be passed as `false` explicitly. */ - fullWidthContent: PropTypes.bool, - /** Add a custom class name */ - className: PropTypes.string, -} - -AppShell.defaultProps = { - pageHeader: <PageHeader />, - pageFooter: <PageFooter />, - topNavigation: undefined, - sideNavigation: undefined, - contentHeading: "", - embedded: false, - fullWidthContent: undefined, - className: "", -} diff --git a/libs/juno-ui-components/src/components/AppShell/AppShell.stories.js b/libs/juno-ui-components/src/components/AppShell/AppShell.stories.js deleted file mode 100644 index 4e94b7a70..000000000 --- a/libs/juno-ui-components/src/components/AppShell/AppShell.stories.js +++ /dev/null @@ -1,202 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" - -import { AppShell } from "./index.js" -import { PageHeader } from "../PageHeader/index" -import { PageFooter } from "../PageFooter/index" -import { SideNavigation } from "../SideNavigation/" -import { SideNavigationItem } from "../SideNavigationItem/" -import { TopNavigation } from "../TopNavigation/index" -import { TopNavigationItem } from "../TopNavigationItem/index" -import { TabNavigation } from "../TabNavigation/index" -import { TabNavigationItem } from "../TabNavigationItem/index" -import { ContentHeading } from "../ContentHeading/index" - -export default { - title: "Layout/AppShell", - component: AppShell, - argTypes: { - pageHeader: { - control: false - }, - pageFooter: { - control: false - }, - topNavigation: { - control: false - }, - sideNavigation: { - control: false - }, - children: { - control: false - }, - }, -} - -const Template = ({children, ...args}) => <AppShell {...args}> - { children } - </AppShell> - -export const Default = Template.bind({}) -Default.parameters = { - docs: { - description: { - story: - "Responsive shell for your application with content heading and default header and footer.", - }, - }, -} -Default.args = { - children: [ - <ContentHeading key="1">My Page</ContentHeading>, - <p key="2">Content goes here</p> - ] -} - -export const AppName = Template.bind({}) -AppName.parameters = { - docs: { - description: { - story: - "Responsive shell for your application with provided app name for the header and default footer.", - }, - }, -} -AppName.args = { - pageHeader: "My App", - children: [ - <ContentHeading key="1">My Page</ContentHeading>, - <p key="2">Content goes here</p> - ] -} - -export const CustomPageHeader = Template.bind({}) -CustomPageHeader.parameters = { - docs: { - description: { - story: - "Responsive shell for your application with custom page header and default footer.", - }, - }, -} -CustomPageHeader.args = { - pageHeader: <PageHeader heading="My Custom Header" />, - children: [ - <ContentHeading key="1">My Page</ContentHeading>, - <p key="2">Content goes here</p> - ] -} - -export const CustomPageFooter = Template.bind({}) -CustomPageFooter.parameters = { - docs: { - description: { - story: - "Responsive shell for your application with default header and custom footer.", - }, - }, -} -CustomPageFooter.args = { - pageFooter: <PageFooter>My custom footer</PageFooter>, - children: [ - <ContentHeading key="1">My Page</ContentHeading>, - <p key="2">Content goes here</p> - ] -} - -export const WithSideNavigation = Template.bind({}) -WithSideNavigation.parameters = { - docs: { - description: { - story: - "Responsive shell for your application with a side navigation.", - }, - }, -} -WithSideNavigation.args = { - sideNavigation: <SideNavigation> - <SideNavigationItem active label="Item 1"/> - <SideNavigationItem label="Item 2" /> - <SideNavigationItem label="Item 3" /> - </SideNavigation>, - children: [ - <ContentHeading key="1">My Page</ContentHeading>, - <p key="2">Content goes here</p> - ] -} - -export const WithTopNavigation = Template.bind({}) -WithTopNavigation.parameters = { - docs: { - description: { - story: - "Responsive shell for your application with top navigation.", - }, - }, -} -WithTopNavigation.args = { - topNavigation: <TopNavigation> - <TopNavigationItem - icon="home" - label="Home" - /> - <TopNavigationItem - active - label="Navigation Item" - /> - </TopNavigation>, - children: [ - <ContentHeading key="1">My Page</ContentHeading>, - <p key="2">Content goes here</p> - ] -} - -export const WithSideAndTopNavigation = Template.bind({}) -WithSideAndTopNavigation.parameters = { - docs: { - description: { - story: - "Responsive shell for your application with both a top navigation and side navigation.", - }, - }, -} -WithSideAndTopNavigation.args = { - topNavigation: <TopNavigation> - <TopNavigationItem - icon="home" - label="Home" - /> - <TopNavigationItem - active - label="Navigation Item" - /> - </TopNavigation>, - sideNavigation: <SideNavigation> - <SideNavigationItem active label="Item 1"/> - <SideNavigationItem label="Item 2" /> - <SideNavigationItem label="Item 3" /> - </SideNavigation>, - children: [ - <ContentHeading key="1">My Page</ContentHeading>, - <p key="2">Content goes here</p> - ] -} - -export const WithTabNavigation = Template.bind({}) -WithTabNavigation.parameters = {} -WithTabNavigation.args = { - children: [ - <TabNavigation key="1"> - <TabNavigationItem label="Item 1" active /> - <TabNavigationItem label="Item 2" /> - <TabNavigationItem label="Item 3" /> - </TabNavigation>, - <ContentHeading key="2">My Page</ContentHeading> - ] - -} diff --git a/libs/juno-ui-components/src/components/AppShell/AppShell.test.js b/libs/juno-ui-components/src/components/AppShell/AppShell.test.js deleted file mode 100644 index 7c6671ef9..000000000 --- a/libs/juno-ui-components/src/components/AppShell/AppShell.test.js +++ /dev/null @@ -1,143 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { cleanup, render, screen } from "@testing-library/react" -import { AppShell } from "./index" -import { PageHeader } from "../PageHeader/PageHeader.component" -import { PageFooter } from "../PageFooter/PageFooter.component" -import { TopNavigation } from "../TopNavigation/TopNavigation.component" -import { SideNavigation } from "../SideNavigation/SideNavigation.component" - -describe("AppShell", () => { - - afterEach(() => { - cleanup(); - jest.clearAllMocks() - }) - - test("renders an app shell", async () => { - render(<AppShell data-testid="app-shell" />) - expect(screen.getByTestId("app-shell")).toBeInTheDocument() - expect(screen.getByTestId("app-shell")).toHaveClass("juno-body") - }) - - test("logs a deprecation warning to the console when user passed obsolete contentHeading prop", async () => { - const consoleWarnSpy = jest.spyOn(console, 'warn') - render(<AppShell contentHeading="My Content Heading" />) - expect(consoleWarnSpy).toHaveBeenCalled() - expect(consoleWarnSpy).toHaveBeenCalledWith( - "AppShell: The contentHeading prop is obsolete and will be removed in a future version. In order to render a content heading, use a ContentHeading element as a child in your main content." - ) - }) - - test("renders an app shell with page header passed as String", async () => { - render(<AppShell data-testid="app-shell" pageHeader="My Page Header" />) - expect(screen.getByTestId("app-shell")).toBeInTheDocument() - expect(screen.getByText("My Page Header")).toBeInTheDocument() - }) - - test("renders an app shell with page header passed as component", async () => { - render(<AppShell data-testid="app-shell" pageHeader={<PageHeader data-testid="page-header" heading="My Page Header" />} />) - expect(screen.getByTestId("app-shell")).toBeInTheDocument() - expect(screen.getByTestId("page-header")).toBeInTheDocument() - expect(screen.getByText("My Page Header")).toBeInTheDocument() - }) - - test("renders an app shell with custom page footer passed as component", async () => { - render(<AppShell data-testid="app-shell" pageFooter={<PageFooter data-testid="page-footer">My Page Footer</PageFooter>} />) - expect(screen.getByTestId("app-shell")).toBeInTheDocument() - expect(screen.getByTestId("page-footer")).toBeInTheDocument() - expect(screen.getByText("My Page Footer")).toBeInTheDocument() - }) - - test("renders an app shell with top navigation passed as component", async () => { - render(<AppShell data-testid="app-shell" topNavigation={<TopNavigation data-testid="top-navigation"></TopNavigation>} />) - expect(screen.getByTestId("app-shell")).toBeInTheDocument() - expect(screen.getByTestId("top-navigation")).toBeInTheDocument() - }) - - test("renders an app shell with a side navigation passed as a component", async () => { - render( - <AppShell - data-testid="app-shell" - sideNavigation={<SideNavigation />} - /> - ) - expect(screen.getByTestId("app-shell")).toBeInTheDocument() - expect(screen.getByRole("navigation")).toBeInTheDocument() - expect(screen.getByRole("navigation")).toHaveClass("juno-sidenavigation") - }) - - test("renders an app shell with both a side and a top navigation as passed", async () => { - render( - <AppShell - data-testid="app-shell" - sideNavigation={<SideNavigation data-testid="side-nav" />} - topNavigation={<TopNavigation data-testid="top-nav" />} - /> - ) - expect(screen.getByTestId("app-shell")).toBeInTheDocument() - expect(screen.getAllByRole("navigation")).toHaveLength(2) - expect(screen.getByTestId("side-nav")).toBeInTheDocument() - expect(screen.getByTestId("top-nav")).toBeInTheDocument() - }) - - test("renders an embeddable app shell without page heading or footer", async () => { - render(<AppShell data-testid="app-shell" embedded={true} pageHeader={<PageHeader data-testid="page-header" heading="My Page Heading" />} pageFooter={<PageFooter data-testid="page-footer">My Page Footer</PageFooter>} />) - expect(screen.getByTestId("app-shell")).toBeInTheDocument() - expect(screen.queryByTestId("page-header")).not.toBeInTheDocument() - expect(screen.queryByText("My Page Heading")).not.toBeInTheDocument() - expect(screen.queryByTestId("page-footer")).not.toBeInTheDocument() - expect(screen.queryByText("My Page Footer")).not.toBeInTheDocument() - }) - - test("renders children as passed", async () => { - render( - <AppShell data-testid="app-shell"> - <button></button> - </AppShell> - ) - expect(screen.getByTestId("app-shell")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeInTheDocument() - }) - - - // The following test whether the MainContainerInner element rendered by AppShell does the right thing depending of props passed to AppShell: - test("does not render a fullwidth main container in non-embedded mode by default", async () => { - render(<AppShell><button></button></AppShell>) - expect(document.querySelector(".juno-main-inner")).not.toHaveClass("juno-main-inner-fullwidth") - }) - - test("renders a fullwidth main container in non-embedded mode if passed explicitly", async () => { - render(<AppShell fullWidthContent={true}><button></button></AppShell>) - expect(document.querySelector(".juno-main-inner")).toHaveClass("juno-main-inner-fullwidth") - }) - - test("renders a fullwidth main inner container in embedded mode by default", async () => { - render(<AppShell embedded><button></button></AppShell>) - expect(document.querySelector(".juno-main-inner")).toHaveClass("juno-main-inner-fullwidth") - }) - - test("renders a non-fullwidth, size-restricted main inner container in embedded mode if passed explicitly", async () => { - render(<AppShell embedded fullWidthContent={false}><button></button></AppShell>) - expect(document.querySelector(".juno-main-inner")).not.toHaveClass("juno-main-inner-fullwidth") - }) - - test("renders a custom className", async () => { - render(<AppShell data-testid="app-shell" className="my-custom-classname" />) - expect(screen.getByTestId("app-shell")).toBeInTheDocument() - expect(screen.getByTestId("app-shell")).toHaveClass("my-custom-classname") - }) - - test("renders all props", async () => { - render(<AppShell data-testid="app-shell" data-lolol="some-prop" />) - expect(screen.getByTestId("app-shell")).toBeInTheDocument() - expect(screen.getByTestId("app-shell")).toHaveAttribute( - "data-lolol", - "some-prop" - ) - }) -}) diff --git a/libs/juno-ui-components/src/components/AppShell/index.js b/libs/juno-ui-components/src/components/AppShell/index.js deleted file mode 100644 index d6146507a..000000000 --- a/libs/juno-ui-components/src/components/AppShell/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { AppShell } from "./AppShell.component" diff --git a/libs/juno-ui-components/src/components/AppShellProvider/AppShellProvider.component.js b/libs/juno-ui-components/src/components/AppShellProvider/AppShellProvider.component.js deleted file mode 100644 index eab5cf74a..000000000 --- a/libs/juno-ui-components/src/components/AppShellProvider/AppShellProvider.component.js +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -import { StyleProvider } from "../StyleProvider/StyleProvider.component" -import { ShadowRoot } from "../ShadowRoot/ShadowRoot.component" -import { PortalProvider } from "../PortalProvider/PortalProvider.component" - -/** - * This provider acts as a wrapper for Juno apps. It renders a StyleProvider and PortalProvider - */ -export const AppShellProvider = ({ - shadowRoot, - shadowRootMode, - stylesWrapper, - theme, - children, -}) => { - const Wrapper = React.useCallback( - ({ children }) => - shadowRoot ? ( - <ShadowRoot mode={shadowRootMode}>{children}</ShadowRoot> - ) : ( - children - ), - [shadowRoot, shadowRootMode] - ) - return ( - <Wrapper> - <StyleProvider - theme={theme} - stylesWrapper={shadowRoot ? "inline" : stylesWrapper} - > - <PortalProvider>{children}</PortalProvider> - </StyleProvider> - </Wrapper> - ) -} - -AppShellProvider.propTypes = { - /** Whether the app is rendered inside a ShadowRoot. Only choose false if the app is meant to run as a stand-alone application. */ - shadowRoot: PropTypes.bool, - /** Shadow root mode */ - shadowRootMode: PropTypes.oneOf(["open", "closed"]), - /** Where app stylesheets are imported. This is only relevant if shadowRoot === false. If you use a ShadowRoot the styles must be inline. */ - stylesWrapper: PropTypes.oneOf(["head", "inline"]), - /** theme: theme-dark or theme-light */ - theme: PropTypes.string, -} - -// define default values -AppShellProvider.defaultProps = { - shadowRoot: true, - shadowRootMode: "open", - stylesWrapper: "inline", - theme: null, -} diff --git a/libs/juno-ui-components/src/components/AppShellProvider/AppShellProvider.stories.js b/libs/juno-ui-components/src/components/AppShellProvider/AppShellProvider.stories.js deleted file mode 100644 index 2e51c9beb..000000000 --- a/libs/juno-ui-components/src/components/AppShellProvider/AppShellProvider.stories.js +++ /dev/null @@ -1,128 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { AppShellProvider } from '.'; -import { CodeBlock } from '../CodeBlock/index.js'; -import { Message } from '../Message/Message.component'; - -export default { - title: 'Layout/AppShellProvider', - component: AppShellProvider, - argTypes: { - children: { - control: false, - }, - }, -}; - -const Template = (args) => <AppShellProvider {...args}>{args.children}</AppShellProvider>; - -export const Default = { - render: Template, - - args: { - children: [ - <Message key={0}>Juno styles are added inline</Message>, - <CodeBlock key={1}> - {` - export default (props) => { - return ( - <AppShellProvider> - <style>{/* app styles */}</style> - <App {...props} /> - </AppShellProvider> - ) - }`} - </CodeBlock>, - ], - }, -}; - -export const NoShadowRoot = { - render: Template, - - args: { - shadowRoot: false, - children: [ - <Message key={0}>No ShadowRoot, but the styles are still inline (default)</Message>, - <CodeBlock key={1}> - {` - export default (props) => { - return ( - <AppShellProvider shadowRoot={false}> - <style>{/* app styles */}</style> - <App {...props} /> - </AppShellProvider> - ) - }`} - </CodeBlock>, - ], - }, -}; - -export const StylesInHead = { - render: Template, - - args: { - shadowRoot: false, - stylesWrapper: 'head', - children: [ - <Message key={0}>Juno styles are added to the head tag</Message>, - <CodeBlock key={1}> - {` - export default (props) => { - return ( - <AppShellProvider shadowRoot={false} stylesWrapper="head"> - <style>{/* app styles */}</style> - <App {...props} /> - </AppShellProvider> - ) - }`} - </CodeBlock>, - ], - }, -}; - -export const StylesInline = { - render: Template, - - args: { - shadowRoot: false, - stylesWrapper: 'inline', - children: [ - <Message key={0}>Juno style are added inline</Message>, - <CodeBlock key={1}> - {` - export default (props) => { - return ( - <AppShellProvider shadowRoot={false} stylesWrapper="inline"> - <style>{/* app styles */}</style> - <App {...props} /> - </AppShellProvider> - ) - }`} - </CodeBlock>, - ], - }, -}; - -export const ThemeLight = { - render: Template, - - args: { - theme: 'theme-light', - children: [ - <Message key={0}>Light Theme</Message>, - <CodeBlock key={1}>{` - <AppShellProvider theme="theme-light"> - <style>{/* app styles */}</style> - <App> - {/* App Body */} - </App> - </AppShellProvider>`}</CodeBlock>, - ], - }, -}; diff --git a/libs/juno-ui-components/src/components/AppShellProvider/AppShellProvider.test.js b/libs/juno-ui-components/src/components/AppShellProvider/AppShellProvider.test.js deleted file mode 100644 index 909cdda7d..000000000 --- a/libs/juno-ui-components/src/components/AppShellProvider/AppShellProvider.test.js +++ /dev/null @@ -1,20 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { AppShellProvider } from "./index" - -describe("AppShellProvider", () => { - test("renders an AppShellProvider wrapper div with 'theme-dark' theme class by default", async () => { - render(<AppShellProvider shadowRoot={false} />) - expect(document.querySelector(".juno-app-body")).toHaveClass("theme-dark") - }) - - test("renders an AppShellProvider wrapper div with theme class as passed", async () => { - render(<AppShellProvider shadowRoot={false} theme="my-theme" />) - expect(document.querySelector("div.juno-app-body")).toHaveClass("my-theme") - }) -}) diff --git a/libs/juno-ui-components/src/components/AppShellProvider/index.js b/libs/juno-ui-components/src/components/AppShellProvider/index.js deleted file mode 100644 index 3af34f51c..000000000 --- a/libs/juno-ui-components/src/components/AppShellProvider/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { AppShellProvider } from "./AppShellProvider.component" diff --git a/libs/juno-ui-components/src/components/Badge/Badge.component.js b/libs/juno-ui-components/src/components/Badge/Badge.component.js deleted file mode 100644 index 4a0451dfb..000000000 --- a/libs/juno-ui-components/src/components/Badge/Badge.component.js +++ /dev/null @@ -1,135 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -import { Icon, knownIcons } from "../Icon/Icon.component.js" - -const badgeBaseStyles = ` - jn-rounded - jn-text-sm - jn-text-theme-default - jn-py-0.5 - jn-px-1 - jn-justify-center - jn-items-center -` - -const defaultStyles = `jn-bg-theme-badge-default` - -const infoStyles = `jn-bg-theme-info/25` - -const successStyles = `jn-bg-theme-success/25` - -const warningStyles = `jn-bg-theme-warning/25` - -const dangerStyles = `jn-bg-theme-danger/25` - -const criticalStyles = `jn-bg-theme-danger/70 jn-text-theme-high` - -const errorStyles = `jn-bg-theme-error/25` - -const iconStyles = `jn-mr-1 jn-items-center` - -const knownVariants = [ - "info", - "success", - "warning", - "danger", - "error", - "critical", -] - -const getVariantStyle = (variant) => { - switch (variant) { - case "info": - return infoStyles - case "success": - return successStyles - case "warning": - return warningStyles - case "danger": - return dangerStyles - case "error": - return errorStyles - case "critical": - return criticalStyles - default: - return defaultStyles - } -} - -/** -A Badge component to visually indicate properties or states of an entity. Besides the default, there are also semantic versions. Can optionally contain an icon to emphasize their meaning. -*/ -export const Badge = ({ - variant, - icon, - text, - className, - children, - ...props -}) => { - const getIcon = (icon, variant) => { - if (icon && knownIcons.includes(icon)) { - // if icon is an available icon, return as passed: - return icon - } else if (icon === true) { - // otherwise return icon as per variant if === "true" (map if not congruent!): - return variant - } else { - return null - } - } - - const getIconColor = (icon, variant) => { - if (icon === true) { - // if icon is set to true this means the icon will be chosen according to the variant. In this case make sure the color matches the variant - return `jn-text-theme-${variant}` - } else { - return undefined - } - } - - return ( - <span - className={` - juno-badge - juno-badge-${variant} - ${badgeBaseStyles} - ${getVariantStyle(variant)} - ${icon ? "jn-inline-flex" : ""} - ${className}`} - {...props} - > - {icon ? ( - <Icon - icon={getIcon(icon, variant)} - size="1.125rem" - className={`${iconStyles}`} - color={getIconColor(icon, variant)} - /> - ) : null} - {children ? children : text} - </span> - ) -} - -Badge.propTypes = { - variant: PropTypes.oneOf(["default", ...knownVariants]), - icon: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(knownIcons)]), - text: PropTypes.string, - className: PropTypes.string, - children: PropTypes.node, -} - -Badge.defaultProps = { - variant: "default", - icon: false, - text: "", - className: "", - children: null, -} diff --git a/libs/juno-ui-components/src/components/Badge/Badge.stories.js b/libs/juno-ui-components/src/components/Badge/Badge.stories.js deleted file mode 100644 index f58713f20..000000000 --- a/libs/juno-ui-components/src/components/Badge/Badge.stories.js +++ /dev/null @@ -1,103 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { Badge } from './index'; -import { knownIcons } from '../Icon/Icon.component.js'; - -export default { - title: 'Components/Badge', - component: Badge, - parameters: { - text: 'default', - }, - argTypes: { - icon: { - options: ['default', ...knownIcons], - control: { type: 'select' }, - }, - children: { - control: false, - }, - }, -}; - -export const WithDefaultIcon = { - args: { - text: 'With Icon', - icon: true, - }, -}; - -export const Info = { - args: { - variant: 'info', - text: 'info', - }, -}; -export const InfoWithIcon = { - args: { - variant: 'info', - text: 'info', - icon: true, - }, -}; - -export const Success = { - args: { - variant: 'success', - text: 'success', - }, -}; - -export const SuccessWithIcon = { - args: { variant: 'success', text: 'success', icon: true }, -}; - -export const Warning = { args: { variant: 'warning', text: 'warning' } }; - -export const WarningWithIcon = { - args: { - variant: 'warning', - text: 'warning', - icon: true, - }, -}; - -export const Danger = { - args: { - variant: 'danger', - text: 'danger', - }, -}; - -export const DangerWithIcon = { - args: { - variant: 'danger', - text: 'danger', - icon: true, - }, -}; - -export const Error = { - args: { - variant: 'error', - text: 'error', - }, -}; - -export const ErrorWithIcon = { - args: { - variant: 'error', - text: 'error', - icon: true, - }, -}; - -export const DefaultWithAnyIcon = { - args: { - text: 'deleted', - icon: 'deleteForever', - }, -}; diff --git a/libs/juno-ui-components/src/components/Badge/Badge.test.js b/libs/juno-ui-components/src/components/Badge/Badge.test.js deleted file mode 100644 index aec1a239e..000000000 --- a/libs/juno-ui-components/src/components/Badge/Badge.test.js +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { Badge } from "./index" - -describe("Badge", () => { - test("renders a badge with text as passed", async () => { - render(<Badge text="default badge" data-testid="badge" />) - expect(screen.getByTestId("badge")).toBeInTheDocument() - expect(screen.getByTestId("badge")).toHaveTextContent("default badge") - }) - - test("renders a badge with children", async () => { - render(<Badge data-testid="badge">Children inside</Badge>) - expect(screen.getByTestId("badge")).toBeInTheDocument() - expect(screen.getByTestId("badge")).toHaveTextContent("Children inside") - }) - - test("renders an info badge variant as passed", async () => { - render(<Badge variant="info" data-testid="badge" />) - expect(screen.getByTestId("badge")).toBeInTheDocument() - expect(screen.getByTestId("badge")).toHaveClass("juno-badge-info") - }) - - test("renders a success badge variant as passed", async () => { - render(<Badge variant="success" data-testid="badge" />) - expect(screen.getByTestId("badge")).toBeInTheDocument() - expect(screen.getByTestId("badge")).toHaveClass("juno-badge-success") - }) - - test("renders a warning badge variant as passed", async () => { - render(<Badge variant="warning" data-testid="badge" />) - expect(screen.getByTestId("badge")).toBeInTheDocument() - expect(screen.getByTestId("badge")).toHaveClass("juno-badge-warning") - }) - - test("renders a danger badge variant as passed", async () => { - render(<Badge variant="danger" data-testid="badge" />) - expect(screen.getByTestId("badge")).toBeInTheDocument() - expect(screen.getByTestId("badge")).toHaveClass("juno-badge-danger") - }) - - test("renders an error badge variant as passed", async () => { - render(<Badge variant="error" data-testid="badge" />) - expect(screen.getByTestId("badge")).toBeInTheDocument() - expect(screen.getByTestId("badge")).toHaveClass("juno-badge-error") - }) - - test("renders a critical badge variant as passed", async () => { - render(<Badge variant="critical" data-testid="badge" />) - expect(screen.getByTestId("badge")).toBeInTheDocument() - expect(screen.getByTestId("badge")).toHaveClass("juno-badge-critical") - }) - - test("renders a default icon as passed", async () => { - render(<Badge icon={true} />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveClass("juno-icon-default") - }) - - test("renders the correct variant-specific icon as passed", async () => { - render(<Badge variant="warning" icon={true} />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveClass("juno-icon-warning") - }) - - test("renders any available icon as passed", async () => { - render(<Badge icon="comment" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveClass("juno-icon-comment") - }) - - test("renders all props as passed", async () => { - render(<Badge data-testid="badge" data-lolol={true} />) - expect(screen.getByTestId("badge")).toBeInTheDocument() - expect(screen.getByTestId("badge")).toHaveAttribute("data-lolol") - }) -}) diff --git a/libs/juno-ui-components/src/components/Badge/index.js b/libs/juno-ui-components/src/components/Badge/index.js deleted file mode 100644 index 8bc09e27b..000000000 --- a/libs/juno-ui-components/src/components/Badge/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { Badge } from "./Badge.component" diff --git a/libs/juno-ui-components/src/components/Box/Box.component.js b/libs/juno-ui-components/src/components/Box/Box.component.js deleted file mode 100644 index 66847f38d..000000000 --- a/libs/juno-ui-components/src/components/Box/Box.component.js +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -const boxstyles = ` - jn-text-sm - jn-rounded - jn-bg-theme-box-default - jn-border - jn-border-theme-box-default -` - -/* When adjusting the padding update tests accordingly as we are testing for rendering padded and unpadded Box */ -const boxpadding = ` - jn-py-1 - jn-px-2 -` -/** -A generic Box element with padding and a light border. - -Use for annotations, further explanations, and remarks where Message or InfoBox would be visually too emphasized. - -Will typically contain (small) text, but can be passed any child element(s) as desired. -*/ -export const Box = ({ - children, - unpad, - className, - ...props -}) => { - return ( - <div className={`juno-box ${boxstyles} ${ unpad ? "" : boxpadding } ${className}`} {...props} > - { children } - </div> - ) -} - -Box.propTypes = { - children: PropTypes.node, - unpad: PropTypes.bool, - className: PropTypes.string, -} - -Box.defaultProps = { - children: null, - unpad: false, - className: "", -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Box/Box.stories.js b/libs/juno-ui-components/src/components/Box/Box.stories.js deleted file mode 100644 index fcd15c1d8..000000000 --- a/libs/juno-ui-components/src/components/Box/Box.stories.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { Box } from './index'; - -export default { - title: 'Components/Box', - component: Box, - argTypes: {}, -}; - -export const Default = { - parameters: { - docs: { - description: { - story: 'A default Box', - }, - }, - }, - - args: { - children: 'Some content in a Box.', - }, -}; - -export const UnpaddedBox = { - parameters: { - docs: { - description: { - story: 'To remove the padding, set `unpad` prop.', - }, - }, - }, - - args: { - children: 'Unpadded Box', - unpad: true, - }, -}; diff --git a/libs/juno-ui-components/src/components/Box/Box.test.js b/libs/juno-ui-components/src/components/Box/Box.test.js deleted file mode 100644 index d3c8c26ba..000000000 --- a/libs/juno-ui-components/src/components/Box/Box.test.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { Box } from "./index" - - -describe("Box", () => { - - test("renders a box with children", async () => { - render(<Box data-testid="box" >Children inside</Box>) - expect(screen.getByTestId("box")).toBeInTheDocument() - expect(screen.getByTestId("box")).toHaveTextContent("Children inside") - }) - - test("renders a padded Box by default", async () => { - render(<Box data-testid="box"/>) - expect(screen.getByTestId("box")).toBeInTheDocument() - expect(screen.getByTestId("box")).toHaveClass('jn-py-1') - expect(screen.getByTestId("box")).toHaveClass('jn-px-2') - }) - - test("renders an unpadded Box as passed", async () => { - render(<Box data-testid="box" unpad />) - expect(screen.getByTestId("box")).toBeInTheDocument() - expect(screen.getByTestId("box")).not.toHaveClass('jn-py-1') - expect(screen.getByTestId("box")).not.toHaveClass('jn-px-2') - }) - - test("renders all classNames as passed", async () => { - render(<Box data-testid="box" className="my-custom-class"/>) - expect(screen.getByTestId("box")).toBeInTheDocument() - expect(screen.getByTestId("box")).toHaveClass('my-custom-class') - }) - - test("renders all props as passed", async () => { - render(<Box data-testid="box" data-lolol={true}/>) - expect(screen.getByTestId("box")).toBeInTheDocument() - expect(screen.getByTestId("box")).toHaveAttribute('data-lolol') - }) - -}) - diff --git a/libs/juno-ui-components/src/components/Box/index.js b/libs/juno-ui-components/src/components/Box/index.js deleted file mode 100644 index 44663c5dc..000000000 --- a/libs/juno-ui-components/src/components/Box/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { Box } from "./Box.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Breadcrumb/Breadcrumb.component.js b/libs/juno-ui-components/src/components/Breadcrumb/Breadcrumb.component.js deleted file mode 100644 index b7d8c182e..000000000 --- a/libs/juno-ui-components/src/components/Breadcrumb/Breadcrumb.component.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { Children } from "react" -import PropTypes from "prop-types" -import { BreadcrumbItem } from "../BreadcrumbItem/index" -import { Stack } from "../Stack/Stack.component" -import { Icon } from "../Icon/Icon.component" - -const breadcrumbstyles = ` - -` -/** Generic breadcrumb component. Use this to Wrap `Breadcrumb` items or custom children in a breadcrumb. */ -export const Breadcrumb = ({ children, className, ...props }) => { - const breadcrumbArray = Children.toArray(children) - const breadcrumbArrayWithSeparators = [] - - breadcrumbArray.forEach((child, i) => { - breadcrumbArrayWithSeparators.push( - <React.Fragment key={i}> - <BreadcrumbItem {...child.props} /> - {i < breadcrumbArray.length - 1 ? <Icon icon="chevronRight" /> : null} - </React.Fragment> - ) - }) - - return ( - <Stack - className={`juno-breadcrumb ${breadcrumbstyles} ${className}`} - gap="1" - key="stck" - {...props} - > - {breadcrumbArrayWithSeparators} - </Stack> - ) -} - -Breadcrumb.propTypes = { - /** Pass a custom className */ - className: PropTypes.string, - /** The children to render. Typically use the BreadcrumbItem component. */ - children: PropTypes.node, -} - -Breadcrumb.defaultProps = { - className: "", - children: null, -} diff --git a/libs/juno-ui-components/src/components/Breadcrumb/Breadcrumb.stories.js b/libs/juno-ui-components/src/components/Breadcrumb/Breadcrumb.stories.js deleted file mode 100644 index 3ef170b69..000000000 --- a/libs/juno-ui-components/src/components/Breadcrumb/Breadcrumb.stories.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import { Breadcrumb } from "./index" -import { BreadcrumbItem } from "../BreadcrumbItem/index" -// import { Default as Item } from '../BreadcrumbItem/BreadcrumbItem.stories'; -// import { Home as HomeItem } from '../BreadcrumbItem/BreadcrumbItem.stories'; -// import { Active as ActiveItem } from '../BreadcrumbItem/BreadcrumbItem.stories'; -// import { Disabled as DisabledItem } from '../BreadcrumbItem/BreadcrumbItem.stories'; -// import { WithIcon as ItemWithIcon } from '../BreadcrumbItem/BreadcrumbItem.stories'; - -const Template = ({ children, ...args }) => { - return <Breadcrumb {...args}>{children}</Breadcrumb> -} - -export default { - title: "Components/Breadcrumb/Breadcrumb", - component: Breadcrumb, - argTypes: { - children: { - control: false, - }, - }, -} - -export const Default = { - render: Template, - args: { - children: [ - <BreadcrumbItem key="1" label="" icon="home" />, - <BreadcrumbItem key="2" label="Breadcrumb Item" />, - <BreadcrumbItem key="3" label="Breadcrumb Item with Icon" icon="place" />, - <BreadcrumbItem key="4" label="Disabled Item " disabled />, - <BreadcrumbItem key="5" label="Active Item" active />, - ], - }, -} diff --git a/libs/juno-ui-components/src/components/Breadcrumb/Breadcrumb.test.js b/libs/juno-ui-components/src/components/Breadcrumb/Breadcrumb.test.js deleted file mode 100644 index bac69c660..000000000 --- a/libs/juno-ui-components/src/components/Breadcrumb/Breadcrumb.test.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { Breadcrumb } from "./index" - - -describe("Breadcrumb", () => { - - test("renders a breadcrumb with text as passed", async () => { - render(<Breadcrumb data-testid="breadcrumb" />) - expect(screen.getByTestId("breadcrumb")).toBeInTheDocument() - expect(screen.getByTestId("breadcrumb")).toHaveClass("juno-breadcrumb") - }) - - test("renders a custom className as passed", async () => { - render(<Breadcrumb data-testid="breadcrumb" className="my-custom-class" />) - expect(screen.getByTestId("breadcrumb")).toBeInTheDocument() - expect(screen.getByTestId("breadcrumb")).toHaveClass('my-custom-class') - }) - - test("renders all props as passed", async () => { - render(<Breadcrumb data-testid="breadcrumb" data-lolol={true}/>) - expect(screen.getByTestId("breadcrumb")).toBeInTheDocument() - expect(screen.getByTestId("breadcrumb")).toHaveAttribute('data-lolol') - }) - -}) - diff --git a/libs/juno-ui-components/src/components/Breadcrumb/index.js b/libs/juno-ui-components/src/components/Breadcrumb/index.js deleted file mode 100644 index 3ae139fa1..000000000 --- a/libs/juno-ui-components/src/components/Breadcrumb/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { Breadcrumb } from "./Breadcrumb.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/BreadcrumbItem/BreadcrumbItem.component.js b/libs/juno-ui-components/src/components/BreadcrumbItem/BreadcrumbItem.component.js deleted file mode 100644 index 0323fb293..000000000 --- a/libs/juno-ui-components/src/components/BreadcrumbItem/BreadcrumbItem.component.js +++ /dev/null @@ -1,113 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" -import { Icon } from "../Icon/index.js" -import { knownIcons } from "../Icon/Icon.component.js" - -const breadcrumbitemstyles = ` - jn-text-sm - jn-text-theme-high - jn-flex - jn-gap-1 - jn-items-center -` - -const breadcrumblinkstyles = ` - jn-text-theme-high - jn-inline-flex -` - -const disabledstyles = ` - jn-text-theme-disabled - jn-pointer-events-none -` - -/** An individual item in a breadcrumb */ -export const BreadcrumbItem = ({ - icon, - href, - label, - ariaLabel, - active, - children, - onClick, - disabled, - className, - ...props -}) => { - - const icn = icon ? <Icon icon={icon} size="18" color="jn-text-theme-default" className={ label && label.length ? "jn-mr-1" : "" } /> : null - - const handleClick = (event) => { - onClick && onClick(event) - } - - return ( - - children ? - children - : - <span className={ - `juno-breadcrumb-item - ${breadcrumbitemstyles} - ${ disabled ? "juno-breadcrumb-item-disabled" : "" } - ${ active ? "juno-breadcrumb-item-active" : "" } - ${className}` - } {...props} - > - { active || disabled ? - <> - { icn } - { label } - </> - : - <a href={href} - className={`${breadcrumblinkstyles} `} - aria-label={ariaLabel || label} - onClick={ handleClick } - > - { icn } - { label } - </a> - } - </span> - - ) -} - -BreadcrumbItem.propTypes = { - /** pass an icon name */ - icon: PropTypes.oneOf(knownIcons), - /** The link of the path/route/page the breacrumb item points to */ - href: PropTypes.string, - /** The text to render in the breadcumb item */ - label: PropTypes.string, - /** Pass an aria-label */ - ariaLabel: PropTypes.string, - /** Whether the item is the last / active item */ - active: PropTypes.bool, - /** Pass an onClick handler */ - onClick: PropTypes.func, - /** Whether the item is disabled */ - disabled: PropTypes.bool, - /** Pass a custom className */ - className: PropTypes.string, - /** The children of the item */ - children: PropTypes.node, -} - -BreadcrumbItem.defaultProps = { - icon: null, - href: "#", - label: "Item", - ariaLabel: "", - active: false, - onClick: undefined, - disabled: false, - className: "", - children: null, -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/BreadcrumbItem/BreadcrumbItem.stories.js b/libs/juno-ui-components/src/components/BreadcrumbItem/BreadcrumbItem.stories.js deleted file mode 100644 index c7f24c4c5..000000000 --- a/libs/juno-ui-components/src/components/BreadcrumbItem/BreadcrumbItem.stories.js +++ /dev/null @@ -1,110 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { BreadcrumbItem } from './index'; -import { knownIcons } from '../Icon/Icon.component.js'; - -const Template = (args) => { - return <BreadcrumbItem {...args} />; -}; - -export default { - title: 'Components/Breadcrumb/BreadcrumbItem', - component: BreadcrumbItem, - argTypes: { - icon: { - options: ['default', ...knownIcons], - control: { type: 'select' }, - }, - children: { - control: false, - }, - }, -}; - -export const Default = { - render: Template, - - parameters: { - docs: { - description: { - story: 'A default breadcrumb item', - }, - }, - }, - - args: { - label: 'Breadcrumb Item', - }, -}; - -export const WithIcon = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Pass any available icon name to render an additional icon for the item.', - }, - }, - }, - - args: { - icon: 'place', - label: 'Breadcrumb Item with Icon', - }, -}; - -export const Active = { - render: Template, - - parameters: { - docs: { - description: { - story: 'An active item represents the current page.', - }, - }, - }, - - args: { - label: 'Active Breadcrumb Item', - active: true, - }, -}; - -export const Disabled = { - render: Template, - - parameters: { - docs: { - description: { - story: 'A disabled breadcrumb item.', - }, - }, - }, - - args: { - label: 'Disabled Breadcrumb Item', - disabled: true, - }, -}; - -export const Home = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Typically the first item in a breadcrumb.', - }, - }, - }, - - args: { - label: '', - icon: 'home', - }, -}; diff --git a/libs/juno-ui-components/src/components/BreadcrumbItem/BreadcrumbItem.test.js b/libs/juno-ui-components/src/components/BreadcrumbItem/BreadcrumbItem.test.js deleted file mode 100644 index b8776076c..000000000 --- a/libs/juno-ui-components/src/components/BreadcrumbItem/BreadcrumbItem.test.js +++ /dev/null @@ -1,88 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { BreadcrumbItem } from "./index" -import { Button } from "../Button/index" - - -describe("BreadcrumbItem", () => { - - test("renders a breadcrumb item with text as passed", async () => { - render(<BreadcrumbItem data-testid="breadcrumbitem" />) - expect(screen.getByTestId("breadcrumbitem")).toBeInTheDocument() - expect(screen.getByTestId("breadcrumbitem")).toHaveClass("juno-breadcrumb-item") - }) - - test("returns children as passed", async () => { - render( - <BreadcrumbItem> - <Button label="Test Button"/> - </BreadcrumbItem>) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveTextContent("Test Button") - }) - - test("renders an icon as passed", async () => { - render(<BreadcrumbItem icon="help" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("title", "Help") - }) - - test("renders a label as passed", async () => { - render(<BreadcrumbItem data-testid="breadcrumbitem" label="My Item" />) - expect(screen.getByTestId("breadcrumbitem")).toBeInTheDocument() - expect(screen.getByTestId("breadcrumbitem")).toHaveTextContent("My Item") - }) - - test("renders an aria-label as passed", async () => { - render(<BreadcrumbItem href="#" ariaLabel="My Item" />) - expect(screen.getByRole("link")).toBeInTheDocument() - expect(screen.getByRole("link")).toHaveAttribute("aria-label", "My Item") - }) - - test("renders the label as aria-label by default", async () => { - render(<BreadcrumbItem href="#" label="My Item" />) - expect(screen.getByRole("link")).toBeInTheDocument() - expect(screen.getByRole("link")).toHaveAttribute("aria-label", "My Item") - }) - - test("renders an active item that is not a link as passed", async () => { - render(<BreadcrumbItem href="#" active data-testid="breadcrumbitem"/>) - expect(screen.queryByRole("link")).not.toBeInTheDocument() - expect(screen.getByTestId("breadcrumbitem")).toBeInTheDocument() - expect(screen.getByTestId("breadcrumbitem")).toHaveClass("juno-breadcrumb-item-active") - }) - - test("renders a disabled item as passed", async () => { - const onClickSpy = jest.fn() - render(<BreadcrumbItem href="#" disabled data-testid="breadcrumbitem" onClick={onClickSpy} />) - expect(screen.getByTestId("breadcrumbitem")).toBeInTheDocument() - expect(screen.getByTestId("breadcrumbitem")).toHaveClass("juno-breadcrumb-item-disabled") - screen.getByTestId("breadcrumbitem").click() - expect(onClickSpy).not.toHaveBeenCalled() - }) - - test("executes an onClick handler as passed", async () => { - const onClickSpy = jest.fn() - render(<BreadcrumbItem onClick={onClickSpy} />) - screen.getByRole("link").click() - expect(onClickSpy).toHaveBeenCalled() - }) - - test("renders a custom className as passed", async () => { - render(<BreadcrumbItem data-testid="breadcrumbitem" className="my-custom-class" />) - expect(screen.getByTestId("breadcrumbitem")).toBeInTheDocument() - expect(screen.getByTestId("breadcrumbitem")).toHaveClass('my-custom-class') - }) - - test("renders all props as passed", async () => { - render(<BreadcrumbItem data-testid="breadcrumbitem" data-lolol={true}/>) - expect(screen.getByTestId("breadcrumbitem")).toBeInTheDocument() - expect(screen.getByTestId("breadcrumbitem")).toHaveAttribute('data-lolol') - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/BreadcrumbItem/index.js b/libs/juno-ui-components/src/components/BreadcrumbItem/index.js deleted file mode 100644 index 7dd3339a4..000000000 --- a/libs/juno-ui-components/src/components/BreadcrumbItem/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { BreadcrumbItem } from "./BreadcrumbItem.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Button/Button.component.js b/libs/juno-ui-components/src/components/Button/Button.component.js deleted file mode 100644 index 3a8520ca0..000000000 --- a/libs/juno-ui-components/src/components/Button/Button.component.js +++ /dev/null @@ -1,241 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" -import "./button.scss" -import { Icon } from "../Icon/index.js" -import { knownIcons } from "../Icon/Icon.component.js" -import { Spinner } from "../Spinner/index.js" - -const btnBase = ` - jn-font-bold - jn-inline-flex - jn-justify-center - jn-items-center - jn-rounded - jn-shadow-sm - jn-w-auto - focus:jn-outline-none - focus-visible:jn-ring-2 - focus-visible:jn-ring-theme-focus - focus-visible:jn-ring-offset-1 - focus-visible:jn-ring-offset-theme-focus - disabled:jn-opacity-50 - disabled:jn-cursor-not-allowed - disabled:jn-pointer-events-none -` - -const btnSmallBase = ` - jn-text-sm - jn-leading-5 -` - -const btnDefaultBase = ` - jn-text-base - jn-leading-6 -` - -const btnSmallDefaultPadding = ` - jn-py-[0.3125rem] - jn-px-[0.5rem] -` - -const btnSmallSubduedPadding = ` - jn-py-[0.25rem] - jn-px-[0.4375rem] -` - -const btnDefaultPadding = ` - jn-py-[0.4375rem] - jn-px-[0.625rem] -` - -const btnDefaultSubduedPadding = ` - jn-py-[0.375rem] - jn-px-[0.5625rem] -` - -const getButtonPadding = (size, variant) => { - if (size === "small") { - return (variant === "subdued" ? `${btnSmallSubduedPadding}` : `${btnSmallDefaultPadding}`) - } else { - return (variant === "subdued" ? `${btnDefaultSubduedPadding}`: `${btnDefaultPadding}`) - } -} - -const btnIconSmall = ` - jn-mr-2 -` - -const btnIconDefault = ` - jn-mr-2 -` - -const iconClasses = (size) => { - if (size === "small") { - return `${btnIconSmall}` - } else { - return `${btnIconDefault}` - } -} - -const progressClass = (progress) => { - const progClass = progress ? `in-progress` : `` - return progClass -} - -const spinnerColorClass = (variant, disabled) => { - switch ( variant ) { - case "default": - return "jn-text-theme-accent" - case "primary": - return "jn-text-white" - case "primary-danger": - return "jn-text-white" - default: - return "" - } -} - -/** - * The basic button component. Use this for `onClick` interactions. - */ -export const Button = React.forwardRef( - ( - { - label, - title, - variant, - size, - disabled, - href, - icon, - className, - onClick, - children, - progress, - progressLabel, - ...props - }, - ref - ) => { - const theVariant = variant || "default" - const titleValue = title || label || "" - - const buttonIcon = progress ? ( - <Spinner - size={ size === "small" ? "1.125rem" : "1.5rem" } - color={`${spinnerColorClass(theVariant, disabled)}`} - /> - ) : icon ? ( - <Icon - icon={icon} - className={`juno-button-icon ${ - label || children ? iconClasses(size) : "" - } `} - size={ size === "small" ? "1.125rem" : "1.5rem" } - /> - ) : null - - const buttonLabel = - progress && progressLabel ? progressLabel : label || children - - const handleClick = (event) => { - onClick && onClick(event) - } - - const button = ( - <button - type="button" - className={` - juno-button - juno-button-${theVariant} - juno-button-${size}-size - ${btnBase} - ${ size === 'small' ? btnSmallBase : btnDefaultBase } - ${ getButtonPadding(size, variant) } - ${progressClass(progress)} - ${className}` - } - disabled={disabled} - onClick={handleClick} - title={titleValue} - ref={ref} - {...props} - > - {buttonIcon} - {buttonLabel} - </button> - ) - - const anchor = ( - <a - href={href} - role="button" - className={` - juno-button - juno-button-${theVariant} - juno-button-${size}-size - ${btnBase} - ${ size === 'small' ? btnSmallBase : btnDefaultBase } - ${ getButtonPadding(size, variant) } - ${progressClass(progress)} - ${className} - `} - disabled={disabled} - onClick={onClick} - title={titleValue} - ref={ref} - {...props} - > - {buttonIcon} - {buttonLabel} - </a> - ) - - return href ? anchor : button - } -) - -Button.propTypes = { - /** Choose a variant for your purpose. May leave empty to get default button. */ - variant: PropTypes.oneOf(["primary", "primary-danger", "default", "subdued"]), - /** Leave empty for default size */ - size: PropTypes.oneOf(["small", "default"]), - /** Whether the button is disabled */ - disabled: PropTypes.bool, - /** Optionally specify an href. This will turn the Button into an <a> element */ - href: PropTypes.string, - /** Button label can be passed like this or as children */ - label: PropTypes.string, - /** Specify title for accessibility. Gets value of label if no title specified */ - title: PropTypes.string, - /** Pass the name of an icon the button should show. Can be any icon included with Juno. */ - icon: PropTypes.oneOf(knownIcons), - /** Pass a className */ - className: PropTypes.string, - /** Click handler */ - onClick: PropTypes.func, - /** Set to true to disable */ - disabled: PropTypes.bool, - /** Whether the button action is in progress */ - progress: PropTypes.bool, - /** Display an alternative label while the button action is in progress */ - progressLabel: PropTypes.string, -} - -Button.defaultProps = { - variant: undefined, - size: "default", - disabled: null, - icon: null, - className: "", - href: null, - title: null, - onClick: undefined, - progress: false, - progressLabel: "", -} diff --git a/libs/juno-ui-components/src/components/Button/Button.stories.js b/libs/juno-ui-components/src/components/Button/Button.stories.js deleted file mode 100644 index ffac07892..000000000 --- a/libs/juno-ui-components/src/components/Button/Button.stories.js +++ /dev/null @@ -1,453 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { Button } from './index'; -import { Icon } from '../Icon/index.js'; -import { knownIcons } from '../Icon/Icon.component.js'; -import { ContentArea } from '../ContentArea/index'; -import { Container } from '../Container/index'; - -export default { - title: 'Components/Button', - component: Button, - argTypes: { - icon: { - options: ['default', ...knownIcons], - control: { type: 'select' }, - }, - variant: { - options: ['default', 'primary', 'primary-danger', 'subdued'], - control: { type: 'select' }, - }, - }, -}; - -export const Default = { - parameters: { - docs: { - description: { - story: 'The default button is a neutral button that can be used multiple times on a page', - }, - }, - }, - - args: { - label: 'Default', - }, -}; - -export const Subdued = { - parameters: { - docs: { - description: { - story: - 'A subdued button variant, mostly used to create contrast to an primary button concerning the same usage context, or when multiple default buttons would be too much.', - }, - }, - }, - - args: { - variant: 'subdued', - label: 'Subdued', - }, -}; - -export const Primary = { - parameters: { - docs: { - description: { - story: - 'Only use the primary button **maximum once per page** for the preferred user action', - }, - }, - }, - - args: { - variant: 'primary', - label: 'Primary', - }, -}; - -export const PrimaryDanger = { - parameters: { - docs: { - description: { - story: 'Use this button sparingly and only for dangerous or destructive actions', - }, - }, - }, - - args: { - variant: 'primary-danger', - label: 'Primary Danger', - }, -}; - -export const DefaultSize = { - args: { - label: 'Default', - }, -}; - -export const Small = { - args: { - size: 'small', - label: 'Small', - }, -}; - -export const Disabled = { - parameters: { - docs: { - description: { story: 'Disable any button by adding `disabled` to it.' }, - }, - }, - - args: { - ...Default.args, - label: 'Default Disabled', - disabled: true, - }, -}; - -export const SubduedDisabled = { - parameters: { - docs: { - description: { story: 'Disable any button by adding `disabled` to it.' }, - }, - }, - - args: { - ...Subdued.args, - label: 'Subdued Disabled', - disabled: true, - }, -}; - -export const PrimaryDisabled = { - parameters: { - docs: { - description: { story: 'Disable any button by adding `disabled` to it.' }, - }, - }, - - args: { - ...Primary.args, - label: 'Primary Disabled', - disabled: true, - }, -}; - -export const PrimaryDangerDisabled = { - parameters: { - docs: { - description: { - story: 'Disable a Primary Danger button by adding `disabled` to it.', - }, - }, - }, - - args: { - ...PrimaryDanger.args, - disabled: true, - }, -}; - -export const DefaultWithIcon = { - parameters: { - docs: { - story: 'Default Button with icon', - }, - }, - - args: { - ...Default.args, - label: 'Default with Icon', - icon: 'warning', - }, -}; - -export const SubduedWithIcon = { - parameters: { - docs: { - description: { - story: 'Subdued Button with Icon', - }, - }, - }, - - args: { - ...Subdued.args, - icon: 'warning', - label: 'Subdued with Icon', - }, -}; - -export const SmallWithIcon = { - parameters: { - docs: { - description: { - story: 'Small Button with Icon', - }, - }, - }, - - args: { - ...Small.args, - icon: 'warning', - }, -}; - -export const IconOnlyButton = {}; -(IconOnlyButton.docs = { - description: { - story: 'A button with a Icon but no label. The icon name can be passed as a prop.', - }, -}), - (IconOnlyButton.args = { - icon: 'warning', - }); - -export const IconOnlyAsChild = {}; -(IconOnlyAsChild.docs = { - description: { - story: - 'A button with a Icon but no label, an Icon can also be passed as a child. Hover, active, etc. states of the icon ave to be handled manually when passing an icon as a child though.', - }, -}), - (IconOnlyAsChild.args = { - children: <Icon />, - }); - -export const LinkAsButton = { - parameters: { - docs: { - description: { - story: - 'If you want to render a link that looks like a button pass an "href" to the Button. All other props work the same as for regular buttons', - }, - }, - }, - - args: { - ...Primary.args, - label: 'Link as button', - href: '#link', - }, -}; - -export const LinkAsButtonWithIcon = { - parameters: { - docs: { - description: { - story: 'Link styled as a button including an icon.', - }, - }, - }, - - args: { - ...Primary.args, - icon: 'warning', - label: 'Link as button with Icon', - href: '#', - }, -}; - -export const DefaultButtonInProgress = { - parameters: { - docs: { - description: { - story: 'Default Button with an action in progress', - }, - }, - }, - - args: { - ...Default.args, - progress: true, - }, -}; - -export const IconButtonInProgress = { - parameters: { - docs: { - description: { - story: 'Icon Button with an action in progress', - }, - }, - }, - - args: { - ...Default.args, - label: 'Default with Icon', - icon: 'warning', - progress: true, - }, -}; - -export const DefaultButtonInProgressWithProgressLabel = { - parameters: { - docs: { - description: { - story: - 'Default Button with an action in oprogress and an alternate label while in progress', - }, - }, - }, - - args: { - ...Default.args, - label: 'Default with Icon', - icon: 'warning', - progress: true, - progressLabel: 'In Progress…', - }, -}; - -export const SubduedButtonInProgress = { - parameters: { - docs: { - description: { - story: 'Subdued Button with an action in progress', - }, - }, - }, - - args: { - ...Subdued.args, - progress: true, - progressLabel: 'Subdued Button in Progress…', - }, -}; - -export const PrimaryButtonWithIconInProgress = { - parameters: { - docs: { - description: { - story: 'Primary Button with action in progress', - }, - }, - }, - - args: { - ...Primary.args, - progress: true, - progressLabel: 'Primary Button in Progress…', - }, -}; - -export const PrimaryDangerButtonInProgress = { - parameters: { - docs: { - description: { - story: 'Primary Danger Button with action in progress', - }, - }, - }, - - args: { - ...PrimaryDanger.args, - progress: true, - progressLabel: 'Primary Danger Button in Progress…', - }, -}; - -export const LinkAsButtonInProgress = { - parameters: { - docs: { - description: { - story: - 'Link as button with action in progress. Should hardly ever be used, just to check consistent styling.', - }, - }, - }, - - args: { - ...LinkAsButton.args, - progress: true, - progressLabel: 'Link as button in Progress…', - }, -}; - -export const LinkAsButtonWithIconInProgress = { - parameters: { - docs: { - description: { - story: - 'Link as button with an icon and action in progress. Should hardly ever be used, just to check consistent styling.', - }, - }, - }, - - args: { - ...LinkAsButtonWithIcon.args, - progress: true, - progressLabel: 'Link as button with Icon in Progress…', - }, -}; - -export const DisabledInProgress = { - parameters: { - docs: { - description: { - story: 'Disabled Default Button in Progress', - }, - }, - }, - - args: { - ...Disabled.args, - progress: true, - }, -}; - -export const PrimaryDisabledInProgress = { - parameters: { - docs: { - description: { - story: 'Disabled Primnary Button with action in progress', - }, - }, - }, - - args: { - ...PrimaryDisabled.args, - progress: true, - progressLabel: 'Disabled Primary Button in Progress…', - }, -}; - -export const PrimaryDangerDisabledInProgress = { - parameters: { - docs: { - description: { - story: 'Disabled Primary Danger Button in Progress…', - }, - }, - }, - - args: { - ...PrimaryDangerDisabled.args, - progress: true, - progressLabel: 'Disabled Primary Danger Button in Progress…', - }, -}; - -export const SmallInProgress = { - parameters: { - docs: { - description: { - story: 'Small Button in Progress', - }, - }, - }, - - args: { - ...Small.args, - progress: true, - progressLabel: 'Small in Progress…', - }, -}; diff --git a/libs/juno-ui-components/src/components/Button/Button.test.js b/libs/juno-ui-components/src/components/Button/Button.test.js deleted file mode 100644 index 14ee7f6c2..000000000 --- a/libs/juno-ui-components/src/components/Button/Button.test.js +++ /dev/null @@ -1,140 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { Button } from "./index" - -describe("Button", () => { - test("renders a button with text passed as label", async () => { - render(<Button label="Click me"></Button>) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveTextContent("Click me") - }) - - test("renders a button with text passed as children", async () => { - render(<Button>Click me</Button>) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveTextContent("Click me") - }) - - test("renders a disabled button as passed", async () => { - render(<Button disabled />) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveAttribute("disabled") - }) - - // it seems we can't properly check whether it's an <a> element that is being rendered - // so for now ensure that it responds to the button aria role and has an href attribute - test("renders an <a> element with role button if href is passed", async () => { - render(<Button href="http://blah.com" />) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveAttribute("href") - }) - - test("onclick handler is called as passed", () => { - const onClickSpy = jest.fn() - render(<Button onClick={onClickSpy} />) - screen.getByRole("button").click() - expect(onClickSpy).toHaveBeenCalled() - }) - - test("onclick handler is not called when disabled", () => { - const onClickSpy = jest.fn() - render(<Button disabled onClick={onClickSpy} />) - screen.getByRole("button").click() - expect(onClickSpy).not.toHaveBeenCalled() - }) - - test("renders a title", async () => { - render(<Button title="Click me title">Click me</Button>) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveAttribute( - "title", - "Click me title" - ) - }) - - test("renders label as title if no title given", async () => { - render(<Button label="Click me label">Click me</Button>) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveAttribute( - "title", - "Click me label" - ) - }) - - test("renders a default button", async () => { - render(<Button>Click me</Button>) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveClass("juno-button-default") - }) - - test("renders a primary button", async () => { - render(<Button variant="primary">Click me</Button>) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveClass("juno-button-primary") - }) - - test("renders a primary-danger button", async () => { - render(<Button variant="primary-danger">Click me</Button>) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveClass("juno-button-primary-danger") - }) - - test("renders a disabled button", async () => { - render(<Button disabled>Click me</Button>) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveAttribute("disabled") - }) - - test("renders an icon as passed", async () => { - render(<Button icon="warning">Click Me</Button>) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "warning") - }) - - test("renders a small button", async () => { - render(<Button size="small">Click me</Button>) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveClass("juno-button-small-size") - }) - - test("renders a default sized button", async () => { - render(<Button>Click me</Button>) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveClass("juno-button-default-size") - }) - - test("renders a custom className as passed", async () => { - render(<Button className="my-custom-classname">Click me</Button>) - expect(screen.getByRole("button")).toHaveClass("my-custom-classname") - }) - - test("renders a default in progress button as passed", async () => { - render(<Button progress={true}>Click me</Button>) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveClass("in-progress") - expect(screen.getByRole("progressbar")).toHaveClass("juno-spinner") - }) - - test("renders a default in progress button with a progressLabel as passed", async () => { - render( - <Button progress={true} progressLabel="In Progress…"> - Click me - </Button> - ) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveClass("in-progress") - expect(screen.getByRole("button")).toHaveTextContent("In Progress…") - }) - - test("renders all props as passed", async () => { - render(<Button id="button-1" data-lolol={true} />) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveAttribute("id", "button-1") - expect(screen.getByRole("button")).toHaveAttribute("data-lolol") - }) -}) diff --git a/libs/juno-ui-components/src/components/Button/button.scss b/libs/juno-ui-components/src/components/Button/button.scss deleted file mode 100644 index 471bea4d0..000000000 --- a/libs/juno-ui-components/src/components/Button/button.scss +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors -// SPDX-License-Identifier: Apache-2.0 - -// handle button colours here, not in tw because of overall complexity, mostly singular colors, gradients, etc; and conflicting bg-colors and bg-images: - - -.juno-button-default { - background-color: var(--color-button-default-bg); - color: var(--color-button-default-text); - - &:hover { - background-color: var(--color-button-default-hover-bg); - color: var(--color-button-default-hover-text); - } - - &:active { - background-color: var(--color-button-default-active-bg); - border-color: var(--color-button-default-active-border); - color: var(--color-button-default-active-text); - } - -} - -.juno-button-subdued { - background-color: var(--color-button-subdued-bg); - border: 1px solid var(--color-button-subdued-border); - color: var(--color-button-subdued-text); - - &:hover { - background-color: var(--color-button-subdued-hover-bg); - border-color: var(--color-button-subdued-hover-border); - color: var(--color-button-subdued-hover-text); - } - - &:active { - background-color: var(--color-button-subdued-active-bg); - border-color: var(--color-button-subdued-active-border); - color: var(--color-button-subdued-active-text); - } - -} - -.juno-button-primary { - background-color: var(--color-button-primary-bg); - color: var(--color-button-primary-text); - - &:hover { - background-color: var(--color-button-primary-hover-bg); - color: var(--color-button-primary-hover-text); - } - - &:active { - background-color: var(--color-button-primary-active-bg); - color: var(--color-button-primary-active-text); - } - -} - -.juno-button-primary-danger { - background-color: var(--color-button-primary-danger-bg); - color: var(--color-button-primary-danger-text); - - &:hover { - background-color: var(--color-button-primary-danger-hover-bg); - color: var(--color-button-primary-danger-hover-text); - } - - &:active { - background-color: var(--color-button-primary-danger-active-bg); - color: var(--color-button-primary-danger-active-text); - } - -} diff --git a/libs/juno-ui-components/src/components/Button/index.js b/libs/juno-ui-components/src/components/Button/index.js deleted file mode 100644 index 43a0e64e4..000000000 --- a/libs/juno-ui-components/src/components/Button/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { Button } from "./Button.component" diff --git a/libs/juno-ui-components/src/components/ButtonRow/ButtonRow.component.js b/libs/juno-ui-components/src/components/ButtonRow/ButtonRow.component.js deleted file mode 100644 index 8b09503f0..000000000 --- a/libs/juno-ui-components/src/components/ButtonRow/ButtonRow.component.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" -import { Stack } from "../Stack/Stack.component" - -const buttonrowstyles = ` - jn-flex - jn-flex-row - jn-justify-end - jn-gap-2 -` - -/** A container to hold one or multiple buttons and space and align them. */ -export const ButtonRow = ({ - children, - className, - ...props -}) => { - return ( - <Stack gap="2" distribution="end" className={`juno-button-row ${className}`} {...props} > - {children} - </Stack> - ) -} - -ButtonRow.propTypes = { - /** Add a class to the ButtonRow */ - className: PropTypes.string, - /** Children to render in the ButtonRow */ - children: PropTypes.node, -} - -ButtonRow.defaultProps = { - children: null, - className: "", -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/ButtonRow/ButtonRow.stories.js b/libs/juno-ui-components/src/components/ButtonRow/ButtonRow.stories.js deleted file mode 100644 index 2f3007380..000000000 --- a/libs/juno-ui-components/src/components/ButtonRow/ButtonRow.stories.js +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import { ButtonRow } from "./index.js" -import { Button } from "../Button/index.js" - -export default { - title: "Forms/ButtonRow", - component: ButtonRow, - argTypes: { - items: { - table: { - disable: true, - }, - }, - children: { - control: false, - }, - }, -} - -const Template = ({ children, ...args }) => ( - <ButtonRow {...args}>{children}</ButtonRow> -) - -export const Default = { - render: Template, - - args: { - name: "Default ButtonRow", - children: [ - <Button label="Cancel" title="Cancel" />, - <Button label="Save" title="Save" variant="primary" />, - ], - }, -} diff --git a/libs/juno-ui-components/src/components/ButtonRow/ButtonRow.test.js b/libs/juno-ui-components/src/components/ButtonRow/ButtonRow.test.js deleted file mode 100644 index ec2b62073..000000000 --- a/libs/juno-ui-components/src/components/ButtonRow/ButtonRow.test.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { Button } from "../Button/index" -import { ButtonRow } from "./index" - -describe("ButtonRow", () => { - - - test("renders a ButtonRow", async () => { - render(<ButtonRow data-testid="button-row" />) - expect(screen.getByTestId("button-row")).toBeInTheDocument() - }) - - test("renders children as passed", async () => { - render( - <ButtonRow> - <Button label="My Button" title="My Button" /> - </ButtonRow> - ) - expect(screen.getByRole("button")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<ButtonRow data-testid="my-button-row" className="my-classname" />) - expect(screen.getByTestId("my-button-row")).toHaveClass("my-classname") - }) - - test("renders all props as passed", async () => { - render(<ButtonRow data-testid="my-button-row" data-lolol="some-prop" />) - expect(screen.getByTestId("my-button-row")).toHaveAttribute("data-lolol", 'some-prop') - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/ButtonRow/index.js b/libs/juno-ui-components/src/components/ButtonRow/index.js deleted file mode 100644 index 471af06ba..000000000 --- a/libs/juno-ui-components/src/components/ButtonRow/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { ButtonRow } from "./ButtonRow.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Checkbox/Checkbox.component.js b/libs/juno-ui-components/src/components/Checkbox/Checkbox.component.js deleted file mode 100644 index 2fed6ad0d..000000000 --- a/libs/juno-ui-components/src/components/Checkbox/Checkbox.component.js +++ /dev/null @@ -1,380 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useState, useEffect, useMemo, useContext, useId } from "react" -import PropTypes from "prop-types" -import { CheckboxGroupContext } from "../CheckboxGroup/CheckboxGroup.component" -import { Label } from "../Label/index" -import { Icon } from "../Icon/Icon.component" -import { FormHint } from "../FormHint/FormHint.component" - -const wrapperStyles = ` - jn-inline-flex - jn-items-center -` - -const inputstyles = ` - jn-w-4 - jn-h-4 - jn-opacity-0 - jn-z-50 -` - -const mockcheckboxstyles = ` - jn-relative - jn-w-4 - jn-h-4 - jn-rounded-sm - jn-bg-theme-checkbox - jn-cursor-pointer - focus:jn-outline-none - focus:jn-ring-2 - focus:jn-ring-theme-focus -` - -const mockfocusstyles = ` - jn-ring-2 - jn-ring-theme-focus -` - -const mockcheckmarkstyles = ` - jn-absolute - jn-top-0 - jn-left-0 - jn-text-theme-checkbox-checked - jn-fill-current -` - - -const mockindeterminatestyles = ` - jn-absolute - jn-w-2 - jn-h-0.5 - jn-top-1.5 - jn-left-[.2rem] - jn-inline-block - jn-bg-theme-focus -` - -const mockdisabledstyles = ` - jn-pointer-events-none - jn-opacity-50 - jn-cursor-not-allowed -` - -const noBorderStyles = ` - jn-border - jn-border-transparent -` - -const errorstyles = ` - jn-border - jn-border-theme-error -` - -const successstyles = ` - jn-border - jn-border-theme-success -` - -const labelStyles = ` - jn-leading-0 - jn-ml-2 -` - -const iconStyles = ` - jn-ml-1 -` - -const hintStyles = ` - jn-mt-0 - jn-ml-6 -` - - - -export const Checkbox = ({ - checked, - className, - disabled, - errortext, - helptext, - id, - indeterminate, - invalid, - label, - name, - onChange, - onClick, - required, - successtext, - valid, - value, - ...props -}) => { - - // Utility - const isNotEmptyString = (str) => { - return !(typeof str === 'string' && str.trim().length === 0) - } - - const uniqueId = () => ( - "juno-checkbox-" + useId() - ) - - // Consume and deconstruct the context so we won't get errors but 'undefined' when trying to access a group context property in case there is none: - const checkboxGroupContext = useContext(CheckboxGroupContext) - const { - selectedOptions: groupSelectedOptions, - name: groupName, - disabled: groupDisabled, - handleCheckboxChange: groupHandleCheckboxChange, - updateSelectedValue: updateGroupSelectedValue, - } = checkboxGroupContext || {} - - // Lazily initialise the Checkbox: - const initialChecked = () => { - if (checkboxGroupContext) { - if (groupSelectedOptions && groupSelectedOptions.includes(value)) { - return true - } else { - return false - } - } else { - return checked ? true : false - } - } - - - const [isChecked, setIsChecked] = useState( initialChecked() ) - const [isIndeterminate, setIsIndeterminate] = useState(false) - const [hasFocus, setHasFocus] = useState(false) - const [isInvalid, setIsInvalid] = useState(false) - const [isValid, setIsValid] = useState(false) - - // Run once to update the parent state to respect and reflect the checked prop if we are in a group context, but parent has no selected options set via its prop: - useEffect(() => { - if (checked && checkboxGroupContext) { - updateGroupSelectedValue(value) - } - }, [] ) - - useEffect(() => { - if (!checkboxGroupContext) { - setIsChecked(checked) - } - }, [checked] ) - - const invalidated = useMemo( - () => invalid || (errortext && isNotEmptyString(errortext) ? true : false), - [invalid, errortext] - ) - const validated = useMemo( - () => valid || (successtext && isNotEmptyString(successtext) ? true : false), - [valid, successtext] - ) - - useEffect( () => { - setIsIndeterminate(indeterminate) - }, [indeterminate]) - - useEffect( () => { - setIsInvalid(invalidated) - }, [invalidated]) - - useEffect( () => { - setIsValid(validated) - }, [validated]) - - const handleChange = (event) => { - setIsChecked(!isChecked) - // If we are in a context, update : - if (groupHandleCheckboxChange && typeof groupHandleCheckboxChange === "function") { - groupHandleCheckboxChange(value) - } - - onChange && onChange(event) - } - - const handleClick = (event) => { - onClick && onClick(event) - } - - const handleFocus = () => { - setHasFocus(true) - } - - const handleBlur = () => { - setHasFocus(false) - } - - const determineChecked = () => { - if (checkboxGroupContext) { - return groupSelectedOptions && groupSelectedOptions.includes(value) ? true : false - } else { - return isChecked - } - } - - const theId = id || uniqueId() - - return ( - <div className="jn-checkbox-outer"> - <div className={`jn-checkbox-wrapper ${wrapperStyles}`}> - <div - className={` - juno-checkbox - ${mockcheckboxstyles} - ${ hasFocus ? mockfocusstyles : "" } - ${ groupDisabled || disabled ? mockdisabledstyles : "" } - ${ isInvalid ? errorstyles : "" } - ${ isValid ? successstyles : "" } - ${ isInvalid || isValid ? "" : noBorderStyles } - ${className} - `} - {...props} - > - { determineChecked() ? <svg - xmlns="http://www.w3.org/2000/svg" - className={`${mockcheckmarkstyles}`} - width="16" - height="16" - viewBox="0 0 16 16"> - <polygon points="5.75 11.15 2.6 8 1.55 9.05 5.75 13.25 14.75 4.25 13.7 3.2"/> - </svg> - : - "" } - <input - checked={ determineChecked() } - className={` - ${inputstyles} - ${ isInvalid ? "juno-checkbox-invalid" : ""} - ${ isValid ? "juno-checkbox-valid" : ""} - ${ groupDisabled || disabled ? "jn-cursor-not-allowed" : ""} - `} - disabled={ groupDisabled || disabled } - id={theId} - name={groupName || name} - onBlur={handleBlur} - onChange={handleChange} - onClick={handleClick} - onFocus={handleFocus} - type="checkbox" - value={value} - /> - { isIndeterminate && !determineChecked() ? - <div className={`${mockindeterminatestyles}`}></div> - : - "" } - </div> - { label && isNotEmptyString(label) ? - <> - <Label - text={label} - htmlFor={theId} - disabled={groupDisabled || disabled} - required={required} - className={`${labelStyles}`} - /> - {isInvalid ? ( - <Icon - icon="dangerous" - color="jn-text-theme-error" - size="1.125rem" - className={` - ${iconStyles} - ${ groupDisabled || disabled ? "jn-opacity-50" :""} - `} - /> - ) : ""} - {isValid ? ( - <Icon - icon="checkCircle" - color="jn-text-theme-success" - size="1.125rem" - className={` - ${iconStyles} - ${disabled ? "jn-opacity-50" :""} - `} - /> - ) : ""} - </> - : - "" - } - </div> - { errortext && isNotEmptyString(errortext) ? - <FormHint text={errortext} variant="error" className={`${hintStyles}`} /> - : - "" - } - { successtext && isNotEmptyString(successtext) ? - <FormHint text={successtext} variant="success" className={`${hintStyles}`} /> - : - "" - } - { helptext && isNotEmptyString(helptext) ? - <FormHint text={helptext} className={`${hintStyles}`} /> - : - "" - } - </div> - ) -} - -Checkbox.propTypes = { - /** Whether the Checkbox is checked */ - checked: PropTypes.bool, - /** Pass a custom className */ - className: PropTypes.string, - /** Whether the Checkbox is disabled */ - disabled: PropTypes.bool, - /** A text to render when the Checkbox has an error or could not be validated */ - errortext: PropTypes.node, - /** A helptext to render to explain meaning and significance of the Checkbox */ - helptext: PropTypes.node, - /** The id of the Radio. An id will be automatically generated if not passed. */ - id: PropTypes.string, - /** Whether the Checkbox is indeterminate. Applicable ONLY if the Checkbox represents multiple child Checkboxes with non--identical checked state. */ - indeterminate: PropTypes.bool, - /** Whether the Checkbox was validated unsuccessfully */ - invalid: PropTypes.bool, - /** The label of the Checkbox */ - label: PropTypes.string, - /** The name of the Checkbox */ - name: PropTypes.string, - /** handler to be executed when the Checkbox changes. */ - onChange: PropTypes.func, - /** handler to be executed when the Checkbox is clicked. */ - onClick: PropTypes.func, - /** Whether the Checkbox is required */ - required: PropTypes.bool, - /** A text to render when the Checkbox was successfully validated */ - successtext: PropTypes.node, - /** Whether the Checkbox was successfully validated */ - valid: PropTypes.bool, - /** The value of the Checkbox */ - value: PropTypes.string, -} - -Checkbox.defaultProps = { - checked: false, - className: "", - disabled: false, - errortext: "", - helptext: "", - id: "", - indeterminate: false, - invalid: false, - label: undefined, - name: "", - onChange: undefined, - onClick: undefined, - required: false, - successtext: "", - valid: false, - value: undefined, -} - diff --git a/libs/juno-ui-components/src/components/Checkbox/Checkbox.stories.js b/libs/juno-ui-components/src/components/Checkbox/Checkbox.stories.js deleted file mode 100644 index c28421cc3..000000000 --- a/libs/juno-ui-components/src/components/Checkbox/Checkbox.stories.js +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { Checkbox } from './index.js'; - -export default { - title: 'Forms/Checkbox/Checkbox', - component: Checkbox, - argTypes: { - errortext: { - control: false, - }, - helptext: { - control: false, - }, - successtext: { - control: false, - }, - }, -}; - -export const Default = { - args: {}, -}; - -export const Checked = { - args: { - checked: true, - }, -}; - -export const WithLabel = { - args: { - label: 'Checkbox with Label', - }, -}; - -export const Required = { - args: { - required: true, - label: 'Required Checkbox', - }, -}; - -export const Disabled = { - args: { - disabled: true, - }, -}; - -export const Indeterminate = { - args: { - indeterminate: true, - }, -}; - -export const Valid = { - args: { - valid: true, - }, -}; - -export const Invalid = { - args: { - invalid: true, - }, -}; - -export const ValidWithLabel = { - args: { - valid: true, - label: 'Validated checkbox with label and icon', - successtext: 'This option is valid.', - helptext: 'Validation icons will only show when there is a label on the Checkbox', - }, -}; - -export const InvalidWithLabel = { - args: { - invalid: true, - label: 'Invalidated checkbox with label and icon', - errortext: 'This option is invalid.', - helptext: 'Validation icons will only show when there is a label on the Checkbox', - }, -}; - -export const IndeterminateWithLabel = { - args: { - indeterminate: true, - label: 'Indeterminate checkbox with label', - helptext: - 'A checkbox can be indeterminate as parent of multiple checkboxes with mixed checked states', - }, -}; diff --git a/libs/juno-ui-components/src/components/Checkbox/Checkbox.test.js b/libs/juno-ui-components/src/components/Checkbox/Checkbox.test.js deleted file mode 100644 index dc48ffb6b..000000000 --- a/libs/juno-ui-components/src/components/Checkbox/Checkbox.test.js +++ /dev/null @@ -1,174 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen, fireEvent } from "@testing-library/react" -import { act } from 'react-dom/test-utils'; -import { Checkbox } from "./index" - - -describe("Checkbox", () => { - - test("renders a valid html input type checkbox", async () => { - render(<Checkbox />) - expect(screen.getByRole("checkbox")).toBeInTheDocument() - expect(screen.getByRole("checkbox")).toHaveAttribute('type', "checkbox") - }) - - test("renders a checkbox with a name as passed", async () => { - render(<Checkbox name="My Checkbox" />) - expect(screen.getByRole("checkbox")).toBeInTheDocument() - expect(screen.getByRole("checkbox")).toHaveAttribute('name', "My Checkbox") - }) - - test("renders a checkbox with a label", async () => { - render(<Checkbox label="My Checkbox" id="my-checkbox"/>) - expect(screen.getByLabelText("My Checkbox")).toBeInTheDocument() - expect(document.querySelector(".juno-label")).toBeInTheDocument() - expect(document.querySelector(".juno-label")).toHaveTextContent("My Checkbox") - }) - - test("renders a checkbox with an id as passed", async () => { - render(<Checkbox id="my-checkbox" />) - expect(screen.getByRole("checkbox")).toBeInTheDocument() - expect(screen.getByRole("checkbox")).toHaveAttribute('id', "my-checkbox") - }) - - test("renders a Checkbox with an auto-generated id if no id was passed", async () => { - render(<Checkbox />) - expect(screen.getByRole("checkbox")).toBeInTheDocument() - expect(screen.getByRole("checkbox")).toHaveAttribute('id') - expect(screen.getByRole("checkbox").getAttribute("id")).toMatch("juno-checkbox") - }) - - test("renders a Checkbox with an associated label with an id as passed", async () => { - render(<Checkbox id="my-checkbox" label="My Checkbox"/>) - expect(screen.getByRole("checkbox")).toBeInTheDocument() - expect(screen.getByLabelText("My Checkbox")).toBeInTheDocument() - expect(document.querySelector(".juno-label")).toBeInTheDocument() - expect(document.querySelector(".juno-label")).toHaveTextContent("My Checkbox") - }) - - test("renders a Checkbox with a label associated by an auto-generated id if no id was passed ", async () => { - render(<Checkbox label="This is a Checkbox" />) - expect(screen.getByRole("checkbox")).toBeInTheDocument() - expect(screen.getByLabelText("This is a Checkbox")).toBeInTheDocument() - }) - - test("renders a checkbox with a value as passed", async () => { - render(<Checkbox value="ValueAsPassed" />) - expect(screen.getByRole("checkbox")).toBeInTheDocument() - expect(screen.getByRole("checkbox")).toHaveAttribute('value', "ValueAsPassed") - }) - - test("renders a checked checkbox as passed", async () => { - act(() => { - render(<Checkbox checked={true} />) - }) - const checkbox = screen.getByRole('checkbox') - expect(checkbox).toBeInTheDocument() - expect(checkbox).toBeChecked() - }) - - test("renders no checked attribute if false", async () => { - act(() => { - render(<Checkbox checked={false} />) - }) - const checkbox = screen.getByRole('checkbox') - expect(checkbox).toBeInTheDocument() - expect(checkbox).not.toBeChecked() - }) - - test("renders a disabled checkbox as passed", async () => { - render(<Checkbox disabled />) - const checkbox = screen.getByRole('checkbox') - expect(checkbox).toBeInTheDocument() - expect(checkbox).toBeDisabled() - }) - - test("renders an invalid Checkbox as passed", async () => { - render(<Checkbox invalid />) - expect(screen.getByRole("checkbox")).toBeInTheDocument() - expect(screen.getByRole("checkbox")).toHaveClass("juno-checkbox-invalid") - }) - - test("renders a valid Checkbox as passed", async () => { - render(<Checkbox valid />) - expect(screen.getByRole("checkbox")).toBeInTheDocument() - expect(screen.getByRole("checkbox")).toHaveClass("juno-checkbox-valid") - }) - - test("renders a helptext as passed", async () => { - render(<Checkbox helptext="this is a helptext"/>) - expect(document.querySelector(".juno-form-hint")).toBeInTheDocument() - expect(document.querySelector(".juno-form-hint")).toHaveClass("juno-form-hint-help") - expect(document.querySelector(".juno-form-hint")).toHaveTextContent("this is a helptext") - }) - - test("renders a successtext as passed and validates the Checkbox", async () => { - render(<Checkbox successtext="great success!" />) - expect(document.querySelector(".juno-form-hint")).toBeInTheDocument() - expect(document.querySelector(".juno-form-hint")).toHaveClass("juno-form-hint-success") - expect(document.querySelector(".juno-form-hint")).toHaveTextContent("great success!") - expect(screen.getByRole("checkbox")).toHaveClass("juno-checkbox-valid") - }) - - test("renders an errortext as passed and invalidates the Checkbox", async () => { - render(<Checkbox errortext="this is an error!" />) - expect(document.querySelector(".juno-form-hint")).toBeInTheDocument() - expect(document.querySelector(".juno-form-hint")).toHaveClass("juno-form-hint-error") - expect(document.querySelector(".juno-form-hint")).toHaveTextContent("this is an error!") - expect(screen.getByRole("checkbox")).toHaveClass("juno-checkbox-invalid") - }) - - test("fires handler on change as passed", async () => { - const onChangeSpy = jest.fn(); - render(<Checkbox onChange={onChangeSpy} />); - act(() => { - screen.getByRole('checkbox').click(); - }) - expect(onChangeSpy).toHaveBeenCalled(); - }) - - test("fires handler on click as passed", async () => { - const onClickSpy = jest.fn(); - render(<Checkbox onClick={onClickSpy} />); - act(() => { - screen.getByRole('checkbox').click(); - }) - expect(onClickSpy).toHaveBeenCalled(); - }) - - test("does not fire a handler on change when disabled", async () => { - const onChangeSpy = jest.fn(); - render(<Checkbox onChange={onChangeSpy} disabled />); - act(() => { - screen.getByRole('checkbox').click(); - }) - expect(onChangeSpy).not.toHaveBeenCalled(); - }) - - test("does not fire a handler on click when disabled", async () => { - const onClickSpy = jest.fn(); - render(<Checkbox onClick={onClickSpy} disabled />); - act(() => { - screen.getByRole('checkbox').click(); - }) - expect(onClickSpy).not.toHaveBeenCalled(); - }) - - test("renders a custom className as passed", async () => { - render(<Checkbox data-testid="23" className="my-custom-classname" />) - expect(screen.getByTestId("23")).toBeInTheDocument() - expect(screen.getByTestId("23")).toHaveClass('my-custom-classname') - }) - - test("renders all props as passed", async () => { - render(<Checkbox id="check-1" data-testid="23" data-lolol={true}/>) - expect(screen.getByTestId("23")).toBeInTheDocument() - expect(screen.getByTestId("23")).toHaveAttribute('data-lolol') - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Checkbox/index.js b/libs/juno-ui-components/src/components/Checkbox/index.js deleted file mode 100644 index 9bb072a7d..000000000 --- a/libs/juno-ui-components/src/components/Checkbox/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { Checkbox } from "./Checkbox.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/CheckboxGroup/CheckboxGroup.component.js b/libs/juno-ui-components/src/components/CheckboxGroup/CheckboxGroup.component.js deleted file mode 100644 index a9eb05386..000000000 --- a/libs/juno-ui-components/src/components/CheckboxGroup/CheckboxGroup.component.js +++ /dev/null @@ -1,271 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useState, useEffect, useMemo, createContext, useId } from "react" -import PropTypes from "prop-types" -import { Label } from "../Label/index.js" -import { Icon } from "../Icon/index" -import { FormHint } from "../FormHint/index" - -const checkboxgroupstyles = ` - jn-mb-4 - jn-last:mb-0 -` - -const checkboxgrouplabelstyles = ` - jn-inline-block - jn-mb-1 -` - -const groupstyles = ` - jn-relative - jn-rounded - jn-border - jn-py-1 -` - -const defaultgroupstyles = ` - jn-border-transparent -` - -const validgroupstyles = ` - jn-border-theme-success - jn-px-2 -` - -const invalidgroupstyles = ` - jn-border-theme-error - jn-px-2 -` - -const errortextstyles = ` - jn-text-xs - jn-text-theme-error - jn-mb-2 -` - -const successtextstyles = ` - jn-text-xs - jn-text-theme-success - jn-mb-2 -` - -const iconstyles = ` - jn-absolute - jn-right-2 - jn-top-1.5 -` - - -export const CheckboxGroupContext = createContext() - -export const CheckboxGroup = ({ - children, - className, - disabled, - errortext, - helptext, - id, - invalid, - label, - name, - onChange, - required, - selected, - successtext, - valid, - ...props -}) => { - - // Utility - const isNotEmptyString = (str) => { - return !(typeof str === 'string' && str.trim().length === 0) - } - - const uniqueId = () => ( - "juno-checkboxgroup-" + useId() - ) - - // Create unique identifiers for use with name and id of the group: - const groupName = name || uniqueId() - const groupId = id || uniqueId() - - // Init state variables: - const [selectedOptions, setSelectedOptions] = useState(selected) // undefined, empty array or array of values - const [isValid, setIsValid] = useState(false) - const [isInvalid, setIsInvalid] = useState(false) - - const validated = useMemo( - () => valid || (successtext && successtext.length ? true : false), - [valid, successtext] - ) - const invalidated = useMemo( - () => invalid || (errortext && errortext.length ? true : false), - [invalid, errortext] - ) - - useEffect(() => { - if (selected) { - setSelectedOptions(selected) - } - }, [selected]) - - useEffect(() => { - setIsValid(validated) - }, [validated]) - - useEffect(() => { - setIsInvalid(invalidated) - }, [invalidated]) - - // Callback function to be passed via context to individual checkboxes: - const handleCheckboxChange = (value) => { - const changedValue = value - if (selectedOptions && selectedOptions.includes(value)) { - setSelectedOptions( selectedOptions.filter((value) => {return value !== changedValue}) ) - } else if (selectedOptions && !selectedOptions.includes(value)) { - setSelectedOptions( (selectedOptions) => [...selectedOptions, changedValue] ) - } else { - setSelectedOptions([changedValue]) - } - onChange && onChange(value) - } - - // Callback function to be passed via the context to child Checkboxes so they can add their value to the groups' selectedOptions array in case selected has not been set on the parent (otherwise the parent select will trump whatever is set on the child in a group context). Called ONLY ONCE during initialization of the child Checkbox when we DON't want to execute any additional onChange handlers just yet: - const updateSelectedValue = (value) => { - if (!selected) { - setSelectedOptions( (selectedOptions) => [...selectedOptions || [], value] ) - } - } - - return ( - <CheckboxGroupContext.Provider - value={ - { - selectedOptions: selectedOptions, - name: groupName, - disabled: disabled, - handleCheckboxChange: handleCheckboxChange, - updateSelectedValue: updateSelectedValue, - } - } - > - <div - className={` - juno-checkboxgroup - ${ isValid ? "juno-checkboxgroup-valid" : "" } - ${ isInvalid ? "juno-checkboxgroup-invalid" : "" } - ${checkboxgroupstyles} - ${className} - `} - id={groupId} - role="group" - {...props} - > - { - label && isNotEmptyString(label) ? - <Label - text={label} - htmlFor={groupId} - disabled={disabled} - required={required} - /> - : - "" - } - <div - className={` - juno-checkbox-group-options - ${ groupstyles } - ${ isValid ? validgroupstyles : "" } - ${ isInvalid ? invalidgroupstyles : ""} - ${ isValid || isInvalid ? "" : defaultgroupstyles } - `} - > - {isInvalid ? ( - <Icon - icon="dangerous" - color="jn-text-theme-error" - className={`${iconstyles}`} - /> - ) : ""} - {isValid ? ( - <Icon - icon="checkCircle" - color="jn-text-theme-success" - className={`${iconstyles}`} - /> - ) : ""} - - { children } - - </div> - { errortext && isNotEmptyString(errortext) ? - <FormHint text={errortext} variant="error" /> - : - "" - } - { successtext && isNotEmptyString(successtext) ? - <FormHint text={successtext} variant="success" /> - : - "" - } - { helptext && isNotEmptyString(helptext) ? - <FormHint text={helptext} /> - : - "" - } - </div> - </CheckboxGroupContext.Provider> - ) - -} - -CheckboxGroup.propTypes = { - /** The Checkbox children of the CheckboxGroup */ - children: PropTypes.node, - /** Pass a custom className */ - className: PropTypes.string, - /** Whether all Checkboxes in the group are disabled */ - disabled: PropTypes.bool, - /** Text to display in case validation failed or there is an error. Will set the whole group to invalid when passed. */ - errortext: PropTypes.node, - /** A text to render to further explain meaning and significance of the group */ - helptext: PropTypes.node, - /** The id of the group. If not passed, a unique id will be created and used for the group as a whole. */ - id: PropTypes.string, - invalid: PropTypes.bool, - /*+ The label of the whole group. */ - label: PropTypes.string, - /** The name of all checkboxes in the group. If not passed, a unique name identifier will be created and used for the group as a whole. */ - name: PropTypes.string, - /** An onChange handler to execute when the selection of options changes */ - onChange: PropTypes.func, - /** Whether a selection in the group is required */ - required: PropTypes.bool, - /** Array of values of individual selected options in the group */ - selected: PropTypes.array, - /** Text to display in case validation is successful. When passed, will set the whole group to valid. */ - successtext: PropTypes.node, - /** Whether the CheckboxGroup was successfully validated */ - valid: PropTypes.bool, -} - -CheckboxGroup.defaultProps = { - children: null, - className: "", - disabled: false, - errortext: "", - helptext: "", - id: "", - invalid: false, - label: undefined, - name: "", - onChange: undefined, - required: false, - selected: undefined, - successtext: "", - valid: false, -} diff --git a/libs/juno-ui-components/src/components/CheckboxGroup/CheckboxGroup.stories.js b/libs/juno-ui-components/src/components/CheckboxGroup/CheckboxGroup.stories.js deleted file mode 100644 index 6d6efe63a..000000000 --- a/libs/juno-ui-components/src/components/CheckboxGroup/CheckboxGroup.stories.js +++ /dev/null @@ -1,213 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { CheckboxGroup } from './index.js'; -import { CheckboxRow } from '../CheckboxRow/index.js'; -import { Checkbox } from '../Checkbox/index.js'; - -export default { - title: 'Forms/Checkbox/CheckboxGroup', - component: CheckboxGroup, - argTypes: { - items: { - table: { - disable: true, - }, - }, - errortext: { - control: false, - }, - helptext: { - control: false, - }, - successtext: { - control: false, - }, - children: { - control: false, - }, - selected: { - control: false, - }, - }, -}; - -const Template = ({ children, ...args }) => <CheckboxGroup {...args}>{children}</CheckboxGroup>; - -export const Default = { - render: Template, - - args: { - children: [ - <Checkbox value="val-1" label="Option 1" key="1" />, - <Checkbox value="val-2" label="Option 2" key="2" />, - <Checkbox value="val-3" label="Option 3" key="3" />, - ], - }, -}; - -export const Selected = { - render: Template, - - args: { - selected: ['val-2'], - children: [ - <Checkbox value="val-1" label="Option 1" key="1" />, - <Checkbox value="val-2" label="Option 2" key="2" />, - <Checkbox value="val-3" label="Option 3" key="3" />, - ], - }, -}; - -export const IndividuallyChecked = { - render: Template, - - args: { - children: [ - <Checkbox value="val-1" label="Option 1" key="1" />, - <Checkbox value="val-2" label="Option 2" key="2" checked />, - <Checkbox value="val-3" label="Option 3" key="3" checked />, - <Checkbox value="val-4" label="Option 4" key="4" />, - ], - }, -}; - -export const WithLabel = { - render: Template, - - args: { - name: 'Labelled ChechboxGroup', - label: 'A Labelled CheckboxGroup', - children: [ - <Checkbox value="val-1" id="c-1" label="Option 1" key="1" />, - <Checkbox value="val-2" id="c-2" label="Option 2" key="2" />, - <Checkbox value="val-3" id="c-3" label="Option 3" key="3" />, - ], - }, -}; - -export const Required = { - render: Template, - - args: { - name: 'Required Labelled ChechboxGroup', - label: 'A Required, Labelled CheckboxGroup', - required: true, - children: [ - <Checkbox value="val-1" id="c-1" label="Option 1" key="1" />, - <Checkbox value="val-2" id="c-2" label="Option 2" key="2" />, - <Checkbox value="val-3" id="c-3" label="Option 3" key="3" />, - ], - }, -}; - -export const Disabled = { - render: Template, - - args: { - label: 'A disabled CheckboxGroup', - disabled: true, - children: [ - <Checkbox value="val-1" id="c-1" label="Option 1" key="1" />, - <Checkbox value="val-2" id="c-2" label="Option 2" key="2" />, - <Checkbox value="val-3" id="c-3" label="Option 3" key="3" />, - ], - }, -}; - -export const ValidCheckboxGroup = { - render: Template, - - args: { - name: 'valid-checkbox-group', - label: 'A valid CheckboxGroup', - valid: true, - children: [ - <Checkbox value="val-1" id="c-1" label="Option 1" key="1" />, - <Checkbox value="val-2" id="c-2" label="Option 2" key="2" />, - <Checkbox value="val-3" id="c-3" label="Option 3" key="3" />, - ], - }, -}; - -export const WithHelptext = { - render: Template, - - args: { - name: 'checkbox-group-with-helptext', - label: 'A CheckboxGroup with helptext', - helptext: 'A helptext', - children: [ - <Checkbox value="val-1" id="c-1" label="Option 1" key="1" />, - <Checkbox value="val-2" id="c-2" label="Option 2" key="2" />, - <Checkbox value="val-3" id="c-3" label="Option 3" key="3" />, - ], - }, -}; - -export const WithHelptextAsNode = { - render: Template, - - args: { - name: 'checkbox-group-with-helptext-as-node', - label: 'A CheckboxGroup with helptext as node', - helptext: ( - <> - This is a helptext with a <a href="#">Link</a> - </> - ), - children: [ - <Checkbox value="val-1" id="c-1" label="Option 1" key="1" />, - <Checkbox value="val-2" id="c-2" label="Option 2" key="2" />, - <Checkbox value="val-3" id="c-3" label="Option 3" key="3" />, - ], - }, -}; - -export const WithSuccesstext = { - render: Template, - - args: { - name: 'checkbox-group-with-success', - label: 'A CheckboxGroup with successful validation', - successtext: 'This group is valid.', - children: [ - <Checkbox value="val-1" id="c-1" label="Option 1" key="1" />, - <Checkbox value="val-2" id="c-2" label="Option 2" key="2" />, - <Checkbox value="val-3" id="c-3" label="Option 3" key="3" />, - ], - }, -}; - -export const InvalidCheckboxGroup = { - render: Template, - - args: { - name: 'invalid-checkbox-group', - label: 'An invalid CheckboxGroup', - invalid: true, - children: [ - <Checkbox value="val-1" id="c-1" label="Option 1" key="1" />, - <Checkbox value="val-2" id="c-2" label="Option 2" key="2" />, - <Checkbox value="val-3" id="c-3" label="Option 3" key="3" />, - ], - }, -}; - -export const WithErrortext = { - render: Template, - - args: { - name: 'checkbox-group-with-error', - label: 'A CheckboxGroup with an Error', - errortext: 'This group has an error.', - children: [ - <Checkbox value="val-1" id="c-1" label="Option 1" key="1" />, - <Checkbox value="val-2" id="c-2" label="Option 2" key="2" />, - <Checkbox value="val-3" id="c-3" label="Option 3" key="3" />, - ], - }, -}; diff --git a/libs/juno-ui-components/src/components/CheckboxGroup/CheckboxGroup.test.js b/libs/juno-ui-components/src/components/CheckboxGroup/CheckboxGroup.test.js deleted file mode 100644 index 0bfb8bb36..000000000 --- a/libs/juno-ui-components/src/components/CheckboxGroup/CheckboxGroup.test.js +++ /dev/null @@ -1,202 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen, fireEvent } from "@testing-library/react" -import { CheckboxGroup } from "./index" -import { Checkbox } from "../Checkbox/index" - -describe("CheckboxGroup", () => { - - test("renders a CheckboxGroup container", async () => { - render( - <CheckboxGroup name="my-checkboxgroup" data-testid="checkbox-group"> - </CheckboxGroup> - ) - expect(screen.getByTestId("checkbox-group")).toBeInTheDocument() - }) - - test("renders a CheckboxGroup with an id as passed ", async () => { - render(< CheckboxGroup data-testid="group" id="my-checkboxgroup-1"/>) - expect(screen.getByTestId("group")).toBeInTheDocument() - expect(screen.getByTestId("group")).toHaveAttribute("id", "my-checkboxgroup-1") - }) - - test("renders a CheckboxGroup with an auto-generated id if no id is passed", async () => { - render(< CheckboxGroup data-testid="group"/>) - expect(screen.getByTestId("group")).toBeInTheDocument() - expect(screen.getByTestId("group")).toHaveAttribute("id") - expect(screen.getByTestId("group").getAttribute("id")).toMatch("juno-checkboxgroup") - }) - - test("renders a CheckboxGroup with an associated label as passed", async () => { - render( - <CheckboxGroup name="my-checkboxgroup" label="My Group of Checkboxes"> - </CheckboxGroup> - ) - expect(screen.getByRole("group")).toBeInTheDocument() - expect(screen.getByText("My Group of Checkboxes")).toBeInTheDocument() - }) - - test("renders a required label as passed", async () => { - render( - <CheckboxGroup name="my-checkboxgroup" label="my-labeled-checkboxgroup" required > - </CheckboxGroup> - ) - expect(screen.getByRole("group")).toBeInTheDocument() - expect(document.querySelector('.juno-required')).toBeInTheDocument() - }) - - test("does not render any checkboxes if no children passed", async () => { - render( - <CheckboxGroup name="my-checkboxgroup"> - </CheckboxGroup> - ) - expect(() => { - screen.getByRole("checkbox"); - }).toThrow() - }) - - test("renders Checkboxes as passed", async () => { - render( - <CheckboxGroup> - <Checkbox /> - <Checkbox /> - <Checkbox /> - </CheckboxGroup> - ) - expect(screen.getAllByRole("checkbox")).toHaveLength(3) - }) - - test("renders individually named Checkboxes as passed", async () => { - render( - <CheckboxGroup name="my-checkboxgroup"> - <Checkbox /> - <Checkbox /> - <Checkbox /> - </CheckboxGroup> - ) - expect(screen.getAllByRole("checkbox")).toHaveLength(3) - }) - - test("renders Checkboxes with an auto-generated name if no name was passed", async () => { - render( - <CheckboxGroup> - <Checkbox /> - <Checkbox /> - </CheckboxGroup> - ) - const checkboxes = screen.getAllByRole("checkbox") - checkboxes.forEach( checkbox => expect(checkbox).toHaveAttribute('name') ) - }) - - test("renders Checkboxes as passed", async () => { - render( - <CheckboxGroup name="my-checkboxgroup"> - <Checkbox /> - </CheckboxGroup> - ) - expect(screen.getByRole("checkbox")).toHaveAttribute("name", "my-checkboxgroup") - }) - - test("renders checked Checkboxes as passed", async () => { - render( - <CheckboxGroup selected={["test-checkbox"]}> - <Checkbox value="test-checkbox"/> - </CheckboxGroup> - ) - expect(screen.getByRole("checkbox")).toBeChecked() - }) - - test("renders disabled child Checkboxes as passed", async () => { - render( - <CheckboxGroup disabled > - <Checkbox id="c-1" /> - <Checkbox id="c-2" /> - </CheckboxGroup> - ) - expect(document.getElementById("c-1")).toBeDisabled() - expect(document.getElementById("c-2")).toBeDisabled() - }) - - test("renders a valid CheckboxGroup as passed", async () => { - render( - <CheckboxGroup valid> - <Checkbox value="test-checkbox"/> - </CheckboxGroup> - ) - expect(screen.getByRole("group")).toBeInTheDocument() - expect(screen.getByRole("group")).toHaveClass("juno-checkboxgroup-valid") - expect(screen.getByTitle("CheckCircle")).toBeInTheDocument() - }) - - test("renders a valid CheckboxGroup when successtext is passed", async () => { - render( - <CheckboxGroup successtext="Great Success!"> - <Checkbox value="test-checkbox"/> - </CheckboxGroup> - ) - expect(screen.getByRole("group")).toBeInTheDocument() - expect(screen.getByRole("group")).toHaveClass("juno-checkboxgroup-valid") - expect(screen.getByTitle("CheckCircle")).toBeInTheDocument() - expect(screen.getByText("Great Success!")).toBeInTheDocument() - }) - - test("renders an invalid CheckboxGroup as passed", async () => { - render( - <CheckboxGroup invalid> - <Checkbox value="test-checkbox"/> - </CheckboxGroup> - ) - expect(screen.getByRole("group")).toBeInTheDocument() - expect(screen.getByRole("group")).toHaveClass("juno-checkboxgroup-invalid") - expect(screen.getByTitle("Dangerous")).toBeInTheDocument() - }) - - test("renders an invalid CheckboxGroup when errortext is passed", async () => { - render( - <CheckboxGroup errortext="Big Error!"> - <Checkbox value="test-checkbox"/> - </CheckboxGroup> - ) - expect(screen.getByRole("group")).toBeInTheDocument() - expect(screen.getByRole("group")).toHaveClass("juno-checkboxgroup-invalid") - expect(screen.getByTitle("Dangerous")).toBeInTheDocument() - expect(screen.getByText("Big Error!")).toBeInTheDocument() - }) - - test("renders a helptext as passed", async () => { - render( - <CheckboxGroup helptext="This is a helpful text"> - <Checkbox /> - <Checkbox /> - </CheckboxGroup> - ) - expect(document.querySelector(".juno-form-hint")).toBeInTheDocument() - expect(document.querySelector(".juno-form-hint")).toHaveClass("juno-form-hint-help") - expect(document.querySelector(".juno-form-hint")).toHaveTextContent("This is a helpful text") - }) - - test("renders a custom className", async () => { - render( - <CheckboxGroup name="my-checkboxgroup" className="my-custom-classname"> - <Checkbox value="test-checkbox"/> - </CheckboxGroup> - ) - expect(screen.getByRole("group")).toBeInTheDocument() - expect(screen.getByRole("group")).toHaveClass("my-custom-classname") - }) - - test("renders all props", async () => { - render( - <CheckboxGroup name="my-checkboxgroup" data-lolol="some-prop"> - <Checkbox value="test-checkbox"/> - </CheckboxGroup> - ) - expect(screen.getByRole("group")).toBeInTheDocument() - expect(screen.getByRole("group")).toHaveAttribute("data-lolol", 'some-prop') - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/CheckboxGroup/index.js b/libs/juno-ui-components/src/components/CheckboxGroup/index.js deleted file mode 100644 index 957fa556b..000000000 --- a/libs/juno-ui-components/src/components/CheckboxGroup/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { CheckboxGroup } from "./CheckboxGroup.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/CheckboxRow/CheckboxRow.component.js b/libs/juno-ui-components/src/components/CheckboxRow/CheckboxRow.component.js deleted file mode 100644 index 2094dc2b6..000000000 --- a/libs/juno-ui-components/src/components/CheckboxRow/CheckboxRow.component.js +++ /dev/null @@ -1,103 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useState, useEffect, useMemo } from "react" -import PropTypes from "prop-types" -import { Checkbox } from "../Checkbox/index.js" -import { withDeprecationWarning } from '../withDeprecationWarning/index.js' - -/** DEPRECATED: A single checkbox, associated label, and structural markup. This component is DEPRECATED, use Checkbox instead. */ -const CheckboxRow = ({ - value, - checked, - indeterminate, - name, - label, - id, - helptext, - required, - disabled, - invalid, - errortext, - valid, - successtext, - className, - onChange, - ...props -}) => { - return ( - <Checkbox - value={value} - checked={checked} - indeterminate={indeterminate} - name={name} - label={label} - id={id} - helptext={helptext} - disabled={disabled} - required={required} - invalid={invalid} - valid={valid} - errortext={errortext} - successtext={successtext} - className={className} - onChange={onChange} - {...props} - /> - ) -} - -CheckboxRow.propTypes = { - /** Optional initial value */ - value: PropTypes.string, - /** Pass checked state */ - checked: PropTypes.bool, - /** Whether the checkbox is indeterminate */ - indeterminate: PropTypes.bool, - /** Name attribute of the checkbox element */ - name: PropTypes.string, - /** Label text */ - label: PropTypes.string, - /** Id */ - id: PropTypes.string, - /** Help text */ - helptext: PropTypes.node, - /** Specify whether the checkbox is required */ - required: PropTypes.bool, - /** Disable the Checkbox */ - disabled: PropTypes.bool, - /** Whether the CheckboxRow is invalid */ - invalid: PropTypes.bool, - /** The error text to render with the CheckboxRow. If passed, the Checkbox row will be set to invalid automatically. */ - errortext: PropTypes.node, - /** Whether the CheckboxRow is valid */ - valid: PropTypes.bool, - /** The text to render when the field is validated. If passed, the Checkbox will be set to valid automatically. */ - successtext: PropTypes.node, - /** Pass a custom className */ - className: PropTypes.string, - /** Pass a handler to the checkbox element */ - onChange: PropTypes.func, -} - -CheckboxRow.defaultProps = { - value: "", - checked: false, - indeterminate: false, - name: null, - label: null, - id: null, - helptext: null, - required: null, - disabled: false, - invalid: false, - errortext: "", - valid: false, - successtext: "", - className: "", - onChange: undefined, -} - -export default withDeprecationWarning(CheckboxRow, "CheckboxRow is deprecated and will be removed in future versions. To be future-proof, use Checkbox instead.") \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/CheckboxRow/CheckboxRow.stories.js b/libs/juno-ui-components/src/components/CheckboxRow/CheckboxRow.stories.js deleted file mode 100644 index 0c2de48b8..000000000 --- a/libs/juno-ui-components/src/components/CheckboxRow/CheckboxRow.stories.js +++ /dev/null @@ -1,106 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { CheckboxRow } from './index.js'; - -export default { - title: 'Deprecated/CheckboxRow', - component: CheckboxRow, - parameters: { - docs: { - description: { - component: - 'DEPRECATED: A radio row containing a radio, associated label, and structural markup. This component is DEPRECATED, use Radio instead.', - }, - }, - }, - argTypes: {}, -}; - -export const Default = { - args: { - label: 'Default Checkbox Row', - id: 'default', - }, -}; - -export const Checked = { - args: { - label: 'Checked CheckboxRow', - id: 'checked', - checked: true, - }, -}; - -export const WithHelpText = { - args: { - name: 'my-input', - label: 'Checkbox Row with Help text', - helptext: 'Oh so helpful helptext', - id: 'withHelptext', - }, -}; - -export const WithHelpTextWithLink = { - args: { - name: 'my-input', - label: 'Checkbox Row with Help text', - helptext: ( - <> - Helptext with a <a href="#">Link</a> - </> - ), - id: 'withHelptext-withLink', - }, -}; - -export const Required = { - args: { - label: 'Required Checkbox Row', - required: true, - id: 'required', - }, -}; - -export const Disabled = { - args: { - label: 'Disabled Checkbox Row', - id: 'disabled-checkbox-row', - disabled: true, - }, -}; - -export const Invalid = { - args: { - label: 'Invalid Checkbox', - id: 'invalid-checkbox-row', - invalid: true, - }, -}; - -export const WithErrorText = { - args: { - label: 'Checkbox invalidated by errortext', - id: 'invalid-checkbox-by-errortext', - errortext: 'Pass an errortext to invalidate a CheckboxRow', - }, -}; - -export const Valid = { - args: { - label: 'Valid Checkbox', - id: 'valid-checkbox-row', - valid: true, - }, -}; - -export const WithSuccessText = { - args: { - label: 'Checkbox validated by successtext', - id: 'valid-checkbox-by-successtext', - successtext: 'Pass a successtext to validate a CheckboxRow', - }, -}; diff --git a/libs/juno-ui-components/src/components/CheckboxRow/CheckboxRow.test.js b/libs/juno-ui-components/src/components/CheckboxRow/CheckboxRow.test.js deleted file mode 100644 index 52b9cac57..000000000 --- a/libs/juno-ui-components/src/components/CheckboxRow/CheckboxRow.test.js +++ /dev/null @@ -1,117 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { act } from 'react-dom/test-utils' -import { CheckboxRow } from "./index" - -describe("CheckboxRow", () => { - - - test("renders a checkbox row", async () => { - render(<CheckboxRow data-testid="checkbox-row" />) - expect(screen.getByTestId("checkbox-row")).toBeInTheDocument() - }) - - test("renders a checked checkbox as passed", async () => { - act(() => { - render(<CheckboxRow checked />) - }) - expect(screen.getByRole("checkbox")).toBeChecked() - }) - - test("renders a checkbox row with a value as passed", async () => { - render(<CheckboxRow value="my-value" />) - expect(screen.getByRole("checkbox")).toHaveAttribute("value", 'my-value') - }) - - test("renders a checkbox row with a name as passed", async () => { - render(<CheckboxRow name="my-checkbox" />) - expect(screen.getByRole("checkbox")).toHaveAttribute("name", 'my-checkbox') - }) - - test("renders a checkbox row with an id as passed", async () => { - render(<CheckboxRow id="my-checkbox" />) - expect(screen.getByRole("checkbox")).toHaveAttribute("id", 'my-checkbox') - }) - - test("renders a checkbox row with a checkbox and an associated label with an id as passed", async () => { - render(<CheckboxRow data-testid="my-checkbox-row" label="My Checkbox Row" id="checkbox-row" />) - expect(screen.getByRole("checkbox")).toBeInTheDocument() - expect(screen.getByLabelText("My Checkbox Row")).toBeInTheDocument() - expect(screen.getByRole("checkbox")).toHaveAttribute("id", 'checkbox-row') - }) - - test("renders a help text as passed", async () => { - render(<CheckboxRow helptext="Helptext goes here" />) - expect(screen.getByText("Helptext goes here")).toBeInTheDocument() - }) - - test("renders a helpt text with a link as passed", async () => { - render(<CheckboxRow helptext={<a href="#">Link</a>} />) - expect(screen.getByRole("link")).toBeInTheDocument() - expect(screen.getByRole("link")).toHaveAttribute("href", "#") - expect(screen.getByRole("link")).toHaveTextContent("Link") - }) - - test("renders a required label as passed", async () => { - render(<CheckboxRow label="Required Input" required />) - expect(document.querySelector('.juno-required')).toBeInTheDocument() - }) - - test("renders a disabled Checkbox as passed", async () => { - act(() => { - render(<CheckboxRow disabled />) - }) - expect(screen.getByRole("checkbox")).toBeDisabled() - }) - - test("renders an invalid CheckboxRow as passed", async () => { - act(() => { - render(<CheckboxRow invalid label="invalid checkbox"/>) - }) - expect(screen.getByRole("checkbox")).toBeInTheDocument() - expect(screen.getByRole("checkbox")).toHaveClass("juno-checkbox-invalid") - expect(screen.getByTitle("Dangerous")).toBeInTheDocument() - }) - - test("renders an invalid CheckRow with an error text as passed", async () => { - render(<CheckboxRow errortext="This is an error text" label="Checkbox"/>) - expect(screen.getByRole("checkbox")).toBeInTheDocument() - expect(screen.getByRole("checkbox")).toHaveClass("juno-checkbox-invalid") - expect(screen.getByTitle("Dangerous")).toBeInTheDocument() - expect(screen.getByText("This is an error text")).toBeInTheDocument() - }) - - test("renders a valid CheckboxRow as passed", async () => { - act(() => { - render(<CheckboxRow valid label="valid checkbox"/>) - }) - expect(screen.getByRole("checkbox")).toBeInTheDocument() - expect(screen.getByRole("checkbox")).toHaveClass("juno-checkbox-valid") - expect(screen.getByTitle("CheckCircle")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<CheckboxRow data-testid="my-checkbox-row" className="my-classname" />) - expect(screen.getByTestId("my-checkbox-row")).toHaveClass("my-classname") - }) - - test("renders all props as passed", async () => { - render(<CheckboxRow data-testid="my-checkbox-row" data-lolol="some-prop" />) - expect(screen.getByTestId("my-checkbox-row")).toHaveAttribute("data-lolol", 'some-prop') - }) - - test("fire handler on change as passed", async () => { - const onChangeSpy = jest.fn(); - render(<CheckboxRow onChange={onChangeSpy} />); - act(() => { - screen.getByRole('checkbox').click(); - }) - expect(onChangeSpy).toHaveBeenCalled(); - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/CheckboxRow/index.js b/libs/juno-ui-components/src/components/CheckboxRow/index.js deleted file mode 100644 index c21067cd1..000000000 --- a/libs/juno-ui-components/src/components/CheckboxRow/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { default as CheckboxRow } from "./CheckboxRow.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Code/Code.component.js b/libs/juno-ui-components/src/components/Code/Code.component.js deleted file mode 100644 index 957f9ee8b..000000000 --- a/libs/juno-ui-components/src/components/Code/Code.component.js +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -const codeStyles = ` - jn-bg-theme-code-block - jn-text-sm -` - -/** A basic inline <code> component. - * Accepts "content" prop or renders children as passed. - */ -export const Code = ({ content, children, className, ...props }) => { - return ( - <code className={`juno-code ${codeStyles} ${className}`} {...props}> - {content || children} - </code> - ) -} - -Code.propTypes = { - content: PropTypes.string, - className: PropTypes.string, - children: PropTypes.node, -} - -Code.defaultProps = { - content: "", - className: "", - children: null, -} diff --git a/libs/juno-ui-components/src/components/Code/Code.stories.js b/libs/juno-ui-components/src/components/Code/Code.stories.js deleted file mode 100644 index 089a215fe..000000000 --- a/libs/juno-ui-components/src/components/Code/Code.stories.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; - -import { Code } from './index.js'; - -export default { - title: 'Components/Code', - component: Code, - argTypes: { - children: { - control: false, - }, - }, -}; - -export const Default = { - parameters: { - docs: { - description: { - story: 'Default inline code', - }, - }, - }, - - args: { - content: '<span>Some code passed as content prop.</span>', - }, -}; - -export const WithChildren = { - parameters: { - docs: { - description: { - story: 'Inline code with children', - }, - }, - }, - - args: { - children: '<Code>Some code with children</Code>', - }, -}; diff --git a/libs/juno-ui-components/src/components/Code/Code.test.js b/libs/juno-ui-components/src/components/Code/Code.test.js deleted file mode 100644 index ba13134e7..000000000 --- a/libs/juno-ui-components/src/components/Code/Code.test.js +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { Code } from "./index" - -describe("Code", () => { - test("renders inline code with content as passed", async () => { - render(<Code data-testid="code" content="some example code" />) - expect(screen.getByTestId("code")).toBeInTheDocument() - expect(screen.getByTestId("code")).toHaveTextContent("some example code") - }) - - test("renders inline code with children as passed", async () => { - render(<Code data-testid="code">Some example code as children</Code>) - expect(screen.getByTestId("code")).toBeInTheDocument() - expect(screen.getByTestId("code")).toHaveTextContent( - "Some example code as children" - ) - }) - - test("renders inline code with content as passed when both content and children were passed", async () => { - render( - <Code data-testid="code" content="Content is go"> - Children are meh - </Code> - ) - expect(screen.getByTestId("code")).toBeInTheDocument() - expect(screen.getByTestId("code")).toHaveTextContent("Content is go") - expect(screen.getByTestId("code")).not.toHaveTextContent("Children are meh") - }) - - test("renders inline code with a className as passed", async () => { - render(<Code data-testid="code" className="my-code-class"></Code>) - expect(screen.getByTestId("code")).toBeInTheDocument() - expect(screen.getByTestId("code")).toHaveClass("my-code-class") - }) - - test("renders inline code with all props as passed", async () => { - render(<Code data-testid="code" data-lolol="code-lang-js"></Code>) - expect(screen.getByTestId("code")).toBeInTheDocument() - expect(screen.getByTestId("code")).toHaveAttribute( - "data-lolol", - "code-lang-js" - ) - }) -}) diff --git a/libs/juno-ui-components/src/components/Code/index.js b/libs/juno-ui-components/src/components/Code/index.js deleted file mode 100644 index 89882583a..000000000 --- a/libs/juno-ui-components/src/components/Code/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { Code } from "./Code.component.js" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/CodeBlock/CodeBlock.component.js b/libs/juno-ui-components/src/components/CodeBlock/CodeBlock.component.js deleted file mode 100644 index e4b57fd0c..000000000 --- a/libs/juno-ui-components/src/components/CodeBlock/CodeBlock.component.js +++ /dev/null @@ -1,224 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useState, useEffect, useRef } from "react" -import PropTypes from "prop-types" -import { JsonViewer } from "../JsonViewer/JsonViewer.component" -import { Icon } from "../Icon/index" - -const wrapperStyles = ` - jn-bg-theme-code-block - jn-rounded -` - -const preStyles = (wrap) => { - return ` - jn-p-6 - ${ - wrap - ? "jn-break-words jn-break-all jn-whitespace-pre-wrap" - : "jn-overflow-x-auto" - } - ` -} - -const sizeStyles = (size) => { - switch (size) { - case "small": - return ` - juno-codeblock-pre-small - jn-max-h-64 - jn-overflow-y-auto - ` - case "medium": - return ` - juno-codeblock-pre-medium - jn-max-h-[32rem] - jn-overflow-y-auto - ` - case "large": - return ` - juno-codeblock-pre-large - jn-max-h-[56rem] - jn-overflow-y-auto - ` - default: - return `` - } -} - -const codeStyles = ` - jn-bg-theme-code-block - jn-text-sm -` - -const headingStyles = ` - jn-text-sm - jn-border-b-[1px] - jn-border-theme-codeblock-bar - jn-h-[3.4375rem] - jn-flex -` - -const headingInnerStyles = ` - jn-flex - jn-font-bold - jn-px-[1.5625rem] - jn-items-center -` - -const bottomBarStyles = ` - jn-flex - jn-justify-end - jn-px-3 - jn-py-2 - jn-border-t-[1px] - jn-border-theme-codeblock-bar -` - -const copyTextStyles = ` - jn-font-bold - jn-text-sm - jn-mr-4 - jn-mt-1 -` - -const jsonStyles = ` - jn-bg-theme-code-block -` - -const jsonViewStyles = { - fontFamily: "IBM Plex Mono", - fontSize: "0.875rem", - padding: "1.5rem", -} - -const jsonTheme = { - base00: "var(--color-syntax-highlight-base00)", //bg - base01: "var(--color-syntax-highlight-base01)", //? - base02: "var(--color-syntax-highlight-base02)", //lines and boxes - base03: "var(--color-syntax-highlight-base03)", - base04: "var(--color-syntax-highlight-base04)", - base05: "var(--color-syntax-highlight-base05)", - base06: "var(--color-syntax-highlight-base06)", - base07: "var(--color-syntax-highlight-base07)", - base08: "var(--color-syntax-highlight-base08)", // NULL - base09: "var(--color-syntax-highlight-base09)", // String value - base0A: "var(--color-syntax-highlight-base0A)", // NaN - base0B: "var(--color-syntax-highlight-base0B)", // float value - base0C: "var(--color-syntax-highlight-base0C)", // index - base0D: "var(--color-syntax-highlight-base0D)", // expanded icon - base0E: "var(--color-syntax-highlight-base0E)", // bool + collapsed icon - base0F: "var(--color-syntax-highlight-base0F)", // integer value -} - -/** A basic CodeBlock component. Accepts a content prop or children. Will render a pre-wrapped code element. */ -export const CodeBlock = ({ - content, - children, - heading, - wrap, - size, - copy, - lang, - className, - ...props -}) => { - const [isCopied, setIsCopied] = useState(false) - const timeoutRef = React.useRef(null) - - React.useEffect(() => { - return () => clearTimeout(timeoutRef.current) // clear when component is unmounted - }, []) - - const theCode = useRef(null) - - const handleCopyClick = () => { - const textToCopy = - lang === "json" - ? JSON.stringify(content || children) - : theCode.current.textContent - navigator.clipboard.writeText(textToCopy) - setIsCopied(true) - clearTimeout(timeoutRef.current) // clear any possibly existing Refs - timeoutRef.current = setTimeout(() => setIsCopied(false), 1000) - } - - return ( - <div - className={`juno-code-block ${wrapperStyles} ${ - lang ? `juno-code-block-lang-${lang}` : "" - } ${className}`} - data-lang={lang || null} - {...props} - > - {heading && heading.length ? ( - <div className={`juno-codeblock-heading ${headingStyles}`}> - <span className={`${headingInnerStyles}`}>{heading}</span> - </div> - ) : ( - "" - )} - {lang === "json" ? ( - <JsonViewer - data={content} - expanded={3} - theme={jsonTheme} - style={jsonViewStyles} - /> - ) : ( - <pre - className={`juno-code-block-pre ${preStyles(wrap)} ${sizeStyles( - size - )}`} - > - <code className={`${codeStyles}`} ref={theCode}> - {content || children} - </code> - </pre> - )} - - {copy ? ( - <div className={`juno-codeblock-bottombar ${bottomBarStyles}`}> - <span className={`${copyTextStyles}`}> - {isCopied ? "Copied!" : ""} - </span> - <Icon icon="contentCopy" onClick={handleCopyClick} /> - </div> - ) : ( - "" - )} - </div> - ) -} - -CodeBlock.propTypes = { - /** The content to render. Will override children if passed. */ - content: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), - /** The children to render. Will be overridden by content prop if passed as well. */ - children: PropTypes.oneOfType([PropTypes.node, PropTypes.object]), - /** Pass at title to render. Will look like a single tab. */ - heading: PropTypes.string, - /** Set whether the code should wrap or not. Default is true. */ - wrap: PropTypes.bool, - /** Set the size of the CodeBlock. Default is "auto" */ - size: PropTypes.oneOf(["auto", "small", "medium", "large"]), - /** Render a button to copy the code to the clipboard. Defaults to true */ - copy: PropTypes.bool, - /** Pass a lang prop. Passing "json" will render a fully-featured JsonView. Will also add a data-lang-attribute to the codeblock */ - lang: PropTypes.string, - /** Add a custom className to the wrapper of the CodeBlock */ - className: PropTypes.string, -} - -CodeBlock.defaultProps = { - content: "", - children: null, - wrap: true, - size: "auto", - copy: true, - lang: "", - className: "", -} diff --git a/libs/juno-ui-components/src/components/CodeBlock/CodeBlock.stories.js b/libs/juno-ui-components/src/components/CodeBlock/CodeBlock.stories.js deleted file mode 100644 index 1813adb6b..000000000 --- a/libs/juno-ui-components/src/components/CodeBlock/CodeBlock.stories.js +++ /dev/null @@ -1,210 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { CodeBlock } from './index.js'; -import { Tabs } from '../Tabs/index.js'; -import { TabList } from '../TabList/index.js'; -import { Tab } from '../Tab/index.js'; -import { Default as TabStory } from '../Tab/Tab.stories.js'; -import { TabPanel } from '../TabPanel/index.js'; - -export default { - title: 'Components/CodeBlock', - component: CodeBlock, - argTypes: { - size: { - options: ['auto', 'small', 'medium', 'large'], - control: { type: 'select' }, - }, - children: { - control: false, - }, - }, -}; - -const TabsTemplate = ({ tabs, codeBlocks, ...args }) => ( - <Tabs variant="codeblocks"> - <TabList> - {tabs.map((tab, t) => ( - <Tab {...tab} key={`t-${t}`}></Tab> - ))} - </TabList> - {codeBlocks.map((codeBlock, c) => ( - <TabPanel> - <CodeBlock {...codeBlock} key={`c-${c}`} /> - </TabPanel> - ))} - </Tabs> -); - -export const Default = { - parameters: { - docs: { - description: { - story: 'Default code block', - }, - }, - }, - - args: { - content: 'Some code goes here', - }, -}; - -export const DefaultWithChildren = { - parameters: { - docs: { - description: { - story: 'Code Block with children', - }, - }, - }, - - args: { - lang: 'html', - children: `<html lang="en"> - <head> - <title="Multi-line Html" /> - </head> - <body> - <main> - </main> - </body> - </html>`, - }, -}; - -export const DefaultWithHeading = { - parameters: { - docs: { - description: { - story: 'Code Block with Heading WIP', - }, - }, - }, - - args: { - children: `<CodeBlock> - <p>some code here</p> - </CodeBlock>`, - heading: 'CodeBlock.jsx', - }, -}; - -export const FixedSize = { - parameters: { - docs: { - description: { - story: 'Fixed size CodeBlock with overflow scrollbars', - }, - }, - }, - - args: { - size: 'small', - content: ` -------- BEGIN CERTIFICATE -------- - 30818902818100C4A06B7B52F8D17DC1C0 - B47362C64AB799AAE19E245A7559E9CEEC - 7D8AA4DF07CB0B21FDFD763C63A313A668 - FE9D764ED913C51A676788DB62AF624F42 - 2C2F112C1316922AA5D37823CD9F43D1FC - 54513D14B2-9E36991F08A042C42EAAEEE - 5FE8E2CB10167174A359CEBF6FACC2C9CA - 933AD403137EE2C3F4CBED9460129C72B0 - 030100030818902818100C4A06B7B52F8D - 17DC1CCB47362C64AB799AAE19E245A755 - 9E9CEEC7D8AA4DF07CB0B21FDFD763C63A - 313A668FE9D764ED913C51A676788DB62A - F624F422C2F112C1316922AA5D37823CD9 - F43D1FC54513D14B2-9E36991F08A042C4 - 2EAAEEE5FE8E2CB10167174A359CEBF6FA - CC2C9CA933AD403137E2C3F4CBED946012 - 9C72B020301000 - -------- END CERTIFICATE -------- `, - }, -}; - -export const NonWrappingCodeBlock = { - parameters: { - docs: { - description: { - story: 'Pass `wrap={false}` to disable line-wrapping', - }, - }, - }, - - args: { - wrap: false, - children: - '-------- BEGIN CERTIFICATE -------- 30818902818100C4A06B7B52F8D17DC1CCB47362C64AB799AAE19E245A7559E9CEEC7D8AA4DF07CB0B21FDFD763C63A313A668FE9D764ED913C51A676788DB62AF624F422C2F112C1316922AA5D37823CD9F43D1FC54513D14B2-9E36991F08A042C42EAAEEE5FE8E2CB10167174A359CEBF6FACC2C9CA933AD403137EE2C3F4CBED9460129C72B02030100030818902818100C4A06B7B52F8D17DC1CCB47362C64AB799AAE19E245A7559E9CEEC7D8AA4DF07CB0B21FDFD763C63A313A668FE9D764ED913C51A676788DB62AF624F422C2F112C1316922AA5D37823CD9F43D1FC54513D14B2-9E36991F08A042C42EAAEEE5FE8E2CB10167174A359CEBF6FACC2C9CA933AD403137E2C3F4CBED9460129C72B020301000 -------- END CERTIFICATE --------', - }, -}; - -export const JSONView = { - parameters: { - docs: { - description: { - story: 'Json View', - }, - }, - }, - - args: { - lang: 'json', - heading: 'Json CodeBlock', - content: { - someKey: 'some value', - someOtherKey: 'some other value', - nestedKeys: { - firstNestedKey: 'first nested value', - }, - }, - }, -}; - -export const CodeBlocksWithTabs = { - render: TabsTemplate, - - parameters: { - docs: { - description: { - story: - "Tabbed CodeBlocks can be composed using the `<Tabs>`, `<Tab>`, `<TabList>`, and `<TabPanel>` components. Make sure to pass `variant='codeblocks'` to the `<Tabs>` component.", - }, - }, - }, - - args: { - tabs: [ - { ...TabStory.args, children: 'UserData.jsx', key: 't-0' }, - { ...TabStory.args, children: 'data.json', key: 't-1' }, - { ...TabStory.args, children: 'UserData.html', key: 't-2' }, - ], - codeBlocks: [ - { content: "<UserData name='User' data={data.json} />" }, - { - lang: 'json', - content: { - firstName: 'Joan', - lastName: 'Clarke', - placeOfBirth: 'West Norwood, London, England', - }, - }, - { - content: `<div> - <dl> - <dt>First Name</dt> - <dd>Joan</dd> - <dt>Last Name</dt> - <dd>Clarke</dd> - <dt>Place of Birth</dt> - <dd>West Norwood, London, England</dd> - </dl> - </div>`, - }, - ], - }, -}; diff --git a/libs/juno-ui-components/src/components/CodeBlock/CodeBlock.test.js b/libs/juno-ui-components/src/components/CodeBlock/CodeBlock.test.js deleted file mode 100644 index 9be0d7e40..000000000 --- a/libs/juno-ui-components/src/components/CodeBlock/CodeBlock.test.js +++ /dev/null @@ -1,185 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { CodeBlock } from "./index" - -describe("CodeBlock", () => { - test("renders a CodeBlock with content as passed", async () => { - render(<CodeBlock data-testid="codeblock" content="some example code" />) - expect(screen.getByTestId("codeblock")).toBeInTheDocument() - expect(screen.getByTestId("codeblock")).toHaveClass("juno-code-block") - expect(screen.getByTestId("codeblock")).toHaveTextContent( - "some example code" - ) - }) - - test("renders a CodeBlock with children as passed", async () => { - render( - <CodeBlock data-testid="codeblock">{"some children here"}</CodeBlock> - ) - expect(screen.getByTestId("codeblock")).toBeInTheDocument() - expect(screen.getByTestId("codeblock")).toHaveClass("juno-code-block") - expect(screen.getByTestId("codeblock")).toHaveTextContent( - "some children here" - ) - }) - - test("renders a CodeBlock with a lang attribute as passed", async () => { - render(<CodeBlock data-testid="codeblock" lang="javascript" />) - expect(screen.getByTestId("codeblock")).toBeInTheDocument() - expect(screen.getByTestId("codeblock")).toHaveClass("juno-code-block") - expect(screen.getByTestId("codeblock")).toHaveAttribute( - "data-lang", - "javascript" - ) - }) - - test("renders a wrapping CodeBlock by default", async () => { - render(<CodeBlock data-testid="codeblock" />) - expect(screen.getByTestId("codeblock")).toBeInTheDocument() - expect(screen.getByTestId("codeblock")).toHaveClass("juno-code-block") - expect(document.querySelector("pre")).toHaveClass("jn-break-words") - expect(document.querySelector("pre")).toHaveClass("jn-break-all") - expect(document.querySelector("pre")).toHaveClass("jn-whitespace-pre-wrap") - expect(document.querySelector("pre")).not.toHaveClass("jn-overflow-x-auto") - }) - - test("renders a non-wrapping CodeBlock as passed", async () => { - render(<CodeBlock data-testid="codeblock" wrap={false} />) - expect(screen.getByTestId("codeblock")).toBeInTheDocument() - expect(screen.getByTestId("codeblock")).toHaveClass("juno-code-block") - expect(document.querySelector("pre")).not.toHaveClass("jn-break-words") - expect(document.querySelector("pre")).not.toHaveClass("jn-break-all") - expect(document.querySelector("pre")).not.toHaveClass( - "jn-whitespace-pre-wrap" - ) - expect(document.querySelector("pre")).toHaveClass("jn-overflow-x-auto") - }) - - test("renders a CodeBlock without height restrictions by default", async () => { - render(<CodeBlock content="123" />) - expect(document.querySelector("pre")).toBeInTheDocument() - expect(document.querySelector("pre")).not.toHaveClass( - "juno-codeblock-pre-small" - ) - expect(document.querySelector("pre")).not.toHaveClass( - "juno-codeblock-pre-medium" - ) - expect(document.querySelector("pre")).not.toHaveClass( - "juno-codeblock-pre-large" - ) - }) - - test("renders a small sized CodeBlock as passed", async () => { - render(<CodeBlock content="123" size="small" />) - expect(document.querySelector("pre")).toBeInTheDocument() - expect(document.querySelector("pre")).toHaveClass( - "juno-codeblock-pre-small" - ) - expect(document.querySelector("pre")).not.toHaveClass( - "juno-codeblock-pre-medium" - ) - expect(document.querySelector("pre")).not.toHaveClass( - "juno-codeblock-pre-large" - ) - }) - - test("renders a medium sized CodeBlock as passed", async () => { - render(<CodeBlock content="123" size="medium" />) - expect(document.querySelector("pre")).toBeInTheDocument() - expect(document.querySelector("pre")).not.toHaveClass( - "juno-codeblock-pre-small" - ) - expect(document.querySelector("pre")).toHaveClass( - "juno-codeblock-pre-medium" - ) - expect(document.querySelector("pre")).not.toHaveClass( - "juno-codeblock-pre-large" - ) - }) - - test("renders a medium sized CodeBlock as passed", async () => { - render(<CodeBlock content="123" size="large" />) - expect(document.querySelector("pre")).toBeInTheDocument() - expect(document.querySelector("pre")).not.toHaveClass( - "juno-codeblock-pre-small" - ) - expect(document.querySelector("pre")).not.toHaveClass( - "juno-codeblock-pre-medium" - ) - expect(document.querySelector("pre")).toHaveClass( - "juno-codeblock-pre-large" - ) - }) - - test("renders a heading as passed", async () => { - render( - <CodeBlock - data-testid="codeblock" - content="123" - heading="Look, a CodeBlock!" - /> - ) - expect(screen.getByTestId("codeblock")).toBeInTheDocument() - expect( - document.querySelector(".juno-codeblock-heading") - ).toBeInTheDocument() - expect(document.querySelector(".juno-codeblock-heading")).toHaveTextContent( - "Look, a CodeBlock!" - ) - }) - - test("renders a JSONView as passed", async () => { - const testJson = { - someKey: "some value", - someOtherKey: 12, - } - render(<CodeBlock data-testid="codeblock" lang="json" content={testJson} />) - expect(screen.getByTestId("codeblock")).toBeInTheDocument() - expect(screen.getByTestId("codeblock")).toHaveClass("juno-code-block") - expect(screen.getByTestId("codeblock")).toHaveAttribute("data-lang", "json") - expect(document.querySelector("[data-json-viewer]")).toBeInTheDocument() - }) - - test("renders a JSONView as passed with children", async () => { - const testObj = { - someKey: "some value", - someOtherKey: 12, - } - render( - <CodeBlock data-testid="codeblock" lang="json"> - {testObj} - </CodeBlock> - ) - expect(screen.getByTestId("codeblock")).toBeInTheDocument() - expect(screen.getByTestId("codeblock")).toHaveClass("juno-code-block") - expect(screen.getByTestId("codeblock")).toHaveAttribute("data-lang", "json") - expect(document.querySelector("[data-json-viewer]")).toBeInTheDocument() - }) - - test("renders a CodeBlock with a Copy button by default", async () => { - render(<CodeBlock />) - expect( - screen.getByRole("button", { name: "contentCopy" }) - ).toBeInTheDocument() - }) - - test("renders a CodeBlock with className as passed", async () => { - render(<CodeBlock data-testid="codeblock" className="my-class" />) - expect(screen.getByTestId("codeblock")).toBeInTheDocument() - expect(screen.getByTestId("codeblock")).toHaveClass("my-class") - }) - - test("renders a CodeBlock with all props as passed", async () => { - render(<CodeBlock data-testid="codeblock" data-lolol="code-lang-js" />) - expect(screen.getByTestId("codeblock")).toBeInTheDocument() - expect(screen.getByTestId("codeblock")).toHaveAttribute( - "data-lolol", - "code-lang-js" - ) - }) -}) diff --git a/libs/juno-ui-components/src/components/CodeBlock/index.js b/libs/juno-ui-components/src/components/CodeBlock/index.js deleted file mode 100644 index 4a2920a81..000000000 --- a/libs/juno-ui-components/src/components/CodeBlock/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { CodeBlock } from "./CodeBlock.component.js" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/ComboBox/ComboBox.component.js b/libs/juno-ui-components/src/components/ComboBox/ComboBox.component.js deleted file mode 100644 index 75d199f5e..000000000 --- a/libs/juno-ui-components/src/components/ComboBox/ComboBox.component.js +++ /dev/null @@ -1,534 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useState, useEffect, useId, useMemo, createContext } from "react" -import PropTypes from "prop-types" -import { Combobox } from "@headlessui/react" -import { Float } from "@headlessui-float/react" -import { Label } from "../Label/index.js" -import { FormHint } from "../FormHint/index.js" -import { Icon } from "../Icon/index.js" -import { Spinner } from "../Spinner/index.js" -import { flip, offset, shift, size } from '@floating-ui/react-dom' -import { usePortalRef } from "../PortalProvider/index" -import { createPortal } from "react-dom" - -// STYLES - -const inputWrapperStyles = ` - jn-relative -` - -const labelStyles = ` - jn-pointer-events-none - jn-top-2 - jn-left-[0.9375rem] -` - -const inputStyles = ` - jn-rounded-3px - jn-bg-theme-textinput - jn-text-theme-textinput - jn-border - jn-text-base - jn-leading-4 - jn-w-full - jn-px-4 - jn-h-textinput - jn-text-left - jn-overflow-hidden - jn-text-ellipsis - jn-whitespace-nowrap - focus:jn-outline-none - focus:jn-ring-2 - focus:jn-ring-theme-focus -` - -const withLabelInputStyles = ` - jn-pt-[1.125rem] - jn-pb-1 -` - -const noLabelInputStyles = ` - jn-py-4 -` - -const disabledInputStyles = ` - jn-cursor-not-allowed - jn-pointer-events-none - jn-opacity-50 -` - -const defaultBorderStyles = ` - jn-border-theme-textinput-default -` - -const validStyles = ` - jn-border-theme-success -` - -const invalidStyles = ` - jn-border-theme-error -` - -const buttonStyles = ` - jn-absolute - jn-top-0 - jn-right-0 - jn-h-textinput - jn-w-6 - jn-h-4 - jn-border-l-0 - jn-border-y-[1px] - jn-border-r-[1px] - jn-rounded-tr - jn-rounded-br - jn-appearance-none - jn-bg-theme-textinput - jn-text-theme-textinput -` - -const defaultButtonStyles = ` - jn-border-theme-textinput-default -` - -const invalidButtonStyles = ` - jn-border-theme-error -` - -const validButtonStyles = ` - jn-border-theme-success -` - -const disabledButtonStyles = ` - jn-cursor-not-allowed - jn-pointer-events-none - jn-bg-transparent - jn-opacity-50 -` - -const menuStyles = ` - jn-rounded - jn-bg-theme-background-lvl-1 - jn-w-full - jn-overflow-y-auto -` - -const iconContainerStyles = ` - jn-absolute - jn-top-[.4rem] - jn-right-6 -` - -const centeredIconStyles = ` - jn-absolute - jn-top-1/2 - jn-left-1/2 - jn-translate-y-[-50%] - jn-translate-x-[-0.75rem] -` - -// CONTEXT -export const ComboBoxContext = createContext() - -// COMBOBOX -export const ComboBox = ({ - ariaLabel, - children, - className, - defaultValue, - disabled, - error, - errortext, - helptext, - id, - invalid, - loading, - label, - name, - nullable, - onBlur, - onChange, - onFocus, - onInputChange, - placeholder, - required, - successtext, - truncateOptions, - valid, - value, - valueLabel, - width, - ...props -}) => { - - const isNotEmptyString = (str) => { - return !(typeof str === 'string' && str.trim().length === 0) - } - - const theId = id || "juno-combobox-" + useId() - const helptextId = "juno-combobox-helptext-" + useId() - - const [optionValuesAndLabels, setOptionValuesAndLabels] = useState(new Map()) - const [query, setQuery] = useState("") - const [selectedValue, setSelectedValue] = useState(value) - const [isLoading, setIsLoading] = useState(false) - const [hasError, setHasError] = useState(false) - const [hasFocus, setFocus] = useState(false) - const [isInvalid, setIsInvalid] = useState(false) - const [isValid, setIsValid] = useState(false) - - // This callback is for all ComboBoxOptions to send us their value, label and children so we can save them as a map in our state. - // We need this because the Select component wants to display the selected value, label or children in the ComboBox input field - // but from the eventHandler we only get the value, not the label or children - const addOptionValueAndLabel = (value, label, children) => { - // append new entry to optionValuesAndLabels map containing the passed value, label and children - // use callback syntax of setState function here since we want to merge the old state with the new entry - setOptionValuesAndLabels(oldMap => (new Map(oldMap).set(value || children, { val: value, label: label, children: children }))) - } - - const invalidated = useMemo( - () => invalid || (errortext && isNotEmptyString(errortext) ? true : false), - [invalid, errortext] - ) - const validated = useMemo( - () => valid || (successtext && isNotEmptyString(successtext) ? true : false), - [valid, successtext] - ) - - useEffect(() => { - setSelectedValue(value) - }, [value] ) - - useEffect(() => { - setHasError(error) - }, [error]) - - useEffect(() => { - setIsLoading(loading) - }, [loading]) - - useEffect(() => { - setIsInvalid(invalidated) - }, [invalidated]) - - useEffect(() => { - setIsValid(validated) - }, [validated]) - - const handleChange = (value) => { - setSelectedValue(value) - onChange && onChange(value) - } - - const handleInputChange = (event) => { - setQuery(event?.target?.value) - onInputChange && onInputChange(event) - } - - const handleFocus = (event) => { - setFocus(true) - onFocus && onFocus(event) - } - - const handleBlur = (event) => { - setFocus(false) - onBlur && onBlur(event) - } - - const portalContainerRef = usePortalRef() - - // Headless-UI-Float Middleware - const middleware = [ - offset(4), - shift(), - flip(), - size({ - boundary: 'viewport', - apply({availableWidth, availableHeight, elements}) { - Object.assign(elements.floating.style, { - maxWidth: `${availableWidth}px`, - maxHeight: `${availableHeight}px`, - overflowY: "auto" - }) - } - }) - ] - - const filteredChildren = - query === "" - ? children - : children.filter((child) => { - // ensure that we filter on the value that is displayed to the user. Apply the same logic as when rendering - // the options, i.e. match children if present, if not match label, lastly if neither label nor children exist, then check value - const optionDisplayValue = child.props.children?.toString() || child.props.label || child.props.value - return optionDisplayValue?.toLowerCase().includes(query.toLowerCase()) - } - ) - - - return ( - - - <ComboBoxContext.Provider value={{ - selectedValue: selectedValue, - truncateOptions: truncateOptions, - addOptionValueAndLabel: addOptionValueAndLabel - }} - > - - <div - className={` - juno-combobox-wrapper - jn-relative - ${ width == "auto" ? "jn-inline-block" : "jn-block" } - ${ width == "auto" ? "jn-w-auto" : "jn-w-full" } - `} - > - <Combobox - defaultValue={defaultValue} - disabled={ disabled || isLoading || hasError } - name={name} - nullable={nullable} - onChange={handleChange} - value={ selectedValue || defaultValue } - {...props} - > - - <Float - composable - adaptiveWidth - middleware={middleware} - > - - <Float.Reference> - <div - className={` - juno-combobox-input-wrapper - ${ inputWrapperStyles } - ${ disabled ? "jn-cursor-not-allowed" : "" } - `} - > - - { label && isNotEmptyString(label) && !isLoading && !hasError ? - <Label - text={label} - disabled={disabled} - required={required} - htmlFor={theId} - className={`${labelStyles}`} - floating - minimized={ placeholder || hasFocus || (query && isNotEmptyString(query) || (selectedValue && isNotEmptyString(selectedValue)) ) ? true : false} - /> - : - "" - } - - <Combobox.Input - autoComplete="off" - aria-label={ ariaLabel || label } - aria-describedby={ helptext ? helptextId : "" } - disabled={ disabled || isLoading || hasError } - id={theId} - onBlur={handleBlur} - onChange={handleInputChange} - onFocus={handleFocus} - placeholder={ !isLoading && !hasError ? placeholder : ""} - displayValue={ - (val) => - optionValuesAndLabels.get(val)?.children || optionValuesAndLabels.get(val)?.label || valueLabel || val - - - } // Headless-UI expects a callback here - className={` - juno-combobox-input - ${inputStyles} - ${ label && isNotEmptyString(label) ? withLabelInputStyles : noLabelInputStyles } - ${ disabled ? disabledInputStyles : "" } - ${ isInvalid ? "juno-combobox-invalid " + invalidStyles : "" } - ${ isValid ? "juno-combobox-valid " + validStyles : "" } - ${ isValid || isInvalid ? "" : defaultBorderStyles } - ${ isLoading ? "juno-combobox-loading jn-cursor-not-allowed" : "" } - ${ hasError ? "juno-combobox-error jn-cursor-not-allowed" : "" } - ${className} - `} - /> - - { - isLoading || hasError ? - <span className={`${centeredIconStyles}`}> - { isLoading ? - <Spinner className={"jn-cursor-not-allowed"} /> - : - <Icon icon="errorOutline" color="jn-text-theme-error" className={"jn-cursor-not-allowed"} /> - } - </span> - : - isValid || isInvalid ? - <span className={` - juno-combobox-icon-container - ${iconContainerStyles} - ${ disabled ? "jn-opacity-50" : "" } - `}> - <Icon - icon={ isValid ? "checkCircle" : "dangerous" } - color={ isValid ? "jn-text-theme-success" : "jn-text-theme-error" } - /> - </span> - : - "" - } - - { !hasError && !isLoading ? - - <Combobox.Button - disabled={disabled} - className={` - juno-combobox-toggle - ${buttonStyles} - ${ disabled ? disabledButtonStyles : "" } - ${ isInvalid ? "juno-combobox-toggle-invalid " + invalidButtonStyles : "" } - ${ isValid ? "juno-combobox-toggle-valid " + validButtonStyles : "" } - ${ isValid || isInvalid ? "" : defaultButtonStyles } - `} - > - {({open}) => ( - <Icon icon={ open ? "expandLess": "expandMore"} /> - )} - </Combobox.Button> - - : "" - } - </div> - </Float.Reference> - - - { createPortal( - <Float.Content> - <Combobox.Options - unmount={false} - className={` - juno-combobox-options - ${menuStyles} - `} - > - { filteredChildren } - </Combobox.Options> - </Float.Content> - , portalContainerRef ? portalContainerRef : document.body - )} - - </Float> - - </Combobox> - - { errortext && isNotEmptyString(errortext) ? - <FormHint text={errortext} variant="error"/> - : - "" - } - { successtext && isNotEmptyString(successtext) ? - <FormHint text={successtext} variant="success"/> - : - "" - } - { helptext && isNotEmptyString(helptext) ? - <FormHint text={helptext} id={helptextId} /> - : - "" - } - - </div> - - </ComboBoxContext.Provider> - - ) - -} - - -ComboBox.propTypes = { - /** The aria-label of the ComboBox. Defaults to the label if label was passed. */ - ariaLabel: PropTypes.string, - /** The children to Render. Use `ComboBox.Option` elements. */ - children: PropTypes.node, - /** A custom className. Will be passed to the text input element of the ComboBox */ - className: PropTypes.string, - /** Pass a defaultValue to use as an uncontrolled Component that will handle its state internally */ - defaultValue: PropTypes.string, - /** Whether the ComboBox is disabled */ - disabled: PropTypes.bool, - /** Whether the ComboBox has an error. Note this refers to an internal error like failing to load options etc., to indicate failed validation use `invalid` instead. */ - error: PropTypes.bool, - /** An errortext to display when the ComboBox failed validation or an internal error occurred. */ - errortext: PropTypes.node, - /** A helptext to render to explain meaning and significance of the ComboBox */ - helptext: PropTypes.node, - /** The Id of the ComboBox. Will be assigned to the text input part of the ComboBox. If not passed, an id will be auto-generated. */ - id: PropTypes.string, - /** Whether the ComboBox failed validation */ - invalid: PropTypes.bool, - /** The label of the ComboBox */ - label: PropTypes.string, - /** Whether the ComboBox is busy loading options */ - loading: PropTypes.bool, - /** The name attribute of the ComboBox when used as part of a form */ - name: PropTypes.string, - /** Whether the ComboBox can be reset to having no value selected by manually clearing the text and clicking outside of the ComboBox. Default is TRUE. When set to FALSE, the selected value can only be changed by selecting another value after the initial selection, but never back to no selected value at all. */ - nullable: PropTypes.bool, - /** A handler to execute when the ComboBox looses focus */ - onBlur: PropTypes.func, - /** A handler to execute when the ComboBox' selected value changes */ - onChange: PropTypes.func, - /** A handler to execute when the ComboBox input receives focus */ - onFocus: PropTypes.func, - /** Handler to execute when the ComboBox text input value changes */ - onInputChange: PropTypes.func, - /** A placeholder to render in the text input */ - placeholder: PropTypes.string, - /** Whether the ComboBox is required */ - required: PropTypes.bool, - /** A text to display in case the ComboBox was successfully validated. Will set the ComboBox to `valid` when passed. */ - successtext: PropTypes.node, - /** Whether the option labels should be truncated in case they are longer/wider than the available space in an option or not. Default is FALSE. */ - truncateOptions: PropTypes.bool, - /** Whether the ComboBox was successfully validated */ - valid: PropTypes.bool, - /** The selected value of the ComboBox in Controlled Mode. */ - value: PropTypes.string, - /** The label of the passed value or defaultValue. If you want to use controlled mode or pass as defaultValue in uncontrolled mode and additionally use labels for human-readable SelectOptions, you need to also pass the matching label for the passed value/defaultValue so that the Select component can render itself properly */ - valueLabel: PropTypes.string, - /** The width of the text input. Either 'full' (default) or 'auto'. */ - width: PropTypes.oneOf(["full", "auto"]) -} - -ComboBox.defaultProps = { - ariaLabel: undefined, - children: null, - className: "", - defaultValue: "", - disabled: false, - error: false, - errortext: "", - helptext: "", - id: "", - invalid: false, - label: undefined, - loading: false, - name: "", - nullable: true, - onBlur: undefined, - onChange: undefined, - onFocus: undefined, - onInputChange: undefined, - placeholder: "Select…", - required: false, - successtext: "", - truncateOptions: false, - valid: false, - value: "", - valueLabel: undefined, - width: "full", -} diff --git a/libs/juno-ui-components/src/components/ComboBox/ComboBox.stories.js b/libs/juno-ui-components/src/components/ComboBox/ComboBox.stories.js deleted file mode 100644 index b2eb4eed0..000000000 --- a/libs/juno-ui-components/src/components/ComboBox/ComboBox.stories.js +++ /dev/null @@ -1,886 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useState, useEffect } from 'react'; -import { ComboBox } from './index.js'; -import { ComboBoxOption } from '../ComboBoxOption/index.js'; -import { PortalProvider } from '../PortalProvider/PortalProvider.component'; - -export default { - title: 'Forms/ComboBox/ComboBox', - component: ComboBox, - argTypes: { - children: { - control: false, - }, - errortext: { - control: false, - }, - helptext: { - control: false, - }, - successtext: { - control: false, - }, - }, - decorators: [ - (Story) => ( - <div className="jn-pb-12"> - <PortalProvider> - <Story /> - </PortalProvider> - </div> - ), - ], -}; - -const Template = ({ children, ...args }) => { - return <ComboBox {...args}>{children}</ComboBox>; -}; - -const ConstrainedWidthTemplate = ({ children, ...args }) => { - return ( - <div style={{ width: '300px' }}> - <ComboBox {...args}>{children}</ComboBox> - </div> - ); -}; - -const ControlledTemplate = ({ value, children, ...args }) => { - const [v, setV] = useState(value); - - useEffect(() => { - setV(value); - }, [value]); - - return <ComboBox value={v}>{children}</ComboBox>; -}; - -export const Default = { - render: Template, - - args: { - children: [ - <ComboBoxOption value="Rhubarb" key="1"> - Rhubarb - </ComboBoxOption>, - <ComboBoxOption value="Carrots" key="2"> - Carrots - </ComboBoxOption>, - <ComboBoxOption value="Spinach" key="3"> - Spinach - </ComboBoxOption>, - <ComboBoxOption value="Tomatoes" key="4"> - Tomatoes - </ComboBoxOption>, - <ComboBoxOption value="Cucumbers" key="5"> - Cucumbers - </ComboBoxOption>, - <ComboBoxOption value="Cauliflower" key="6"> - Cauliflower - </ComboBoxOption>, - <ComboBoxOption value="Eggplant" key="7"> - Eggplant - </ComboBoxOption>, - <ComboBoxOption value="Zucchini" key="8"> - Zucchini - </ComboBoxOption>, - <ComboBoxOption value="Brussels sprouts" key="9"> - Brussels Sprouts - </ComboBoxOption>, - <ComboBoxOption value="Horseradish" key="10"> - Horseradish - </ComboBoxOption>, - <ComboBoxOption value="Green beans" key="11"> - Green Beans - </ComboBoxOption>, - <ComboBoxOption value="Mushrooms" key="12"> - Mushrooms - </ComboBoxOption>, - <ComboBoxOption value="Leek" key="13"> - Leek - </ComboBoxOption>, - <ComboBoxOption value="Artichokes" key="14"> - Artichokes - </ComboBoxOption>, - <ComboBoxOption value="Peas" key="15"> - Peas - </ComboBoxOption>, - <ComboBoxOption value="Potatoes" key="16"> - Potatoes - </ComboBoxOption>, - ], - }, -}; - -export const ControlledComboBox = { - render: ControlledTemplate, - - args: { - value: 'Houdini', - label: 'A controlled ComboBox', - children: [ - <ComboBoxOption value="Caligari" key="1"> - Caligari - </ComboBoxOption>, - <ComboBoxOption value="Houdini" key="2"> - Houdini - </ComboBoxOption>, - <ComboBoxOption value="Lencia" key="3"></ComboBoxOption>, - ], - }, -}; - -export const UncontrolledComboBox = { - render: Template, - - args: { - defaultValue: 'Lencia', - label: 'An uncontrolled ComboBox', - children: [ - <ComboBoxOption value="Caligari" key="1"> - Caligari - </ComboBoxOption>, - <ComboBoxOption value="Houdini" key="2"> - Houdini - </ComboBoxOption>, - <ComboBoxOption value="Lencia" key="3"></ComboBoxOption>, - ], - }, -}; - -export const WithLabel = { - render: Template, - - args: { - label: 'ComboBox', - placeholder: '', - children: [ - <ComboBoxOption value="Rhubarb" key="1"> - Rhubarb - </ComboBoxOption>, - <ComboBoxOption value="Carrots" key="2"> - Carrots - </ComboBoxOption>, - <ComboBoxOption value="Spinach" key="3"> - Spinach - </ComboBoxOption>, - <ComboBoxOption value="Tomatoes" key="4"> - Tomatoes - </ComboBoxOption>, - <ComboBoxOption value="Cucumbers" key="5"> - Cucumbers - </ComboBoxOption>, - <ComboBoxOption value="Cauliflower" key="6"> - Cauliflower - </ComboBoxOption>, - <ComboBoxOption value="Eggplant" key="7"> - Eggplant - </ComboBoxOption>, - <ComboBoxOption value="Zucchini" key="8"> - Zucchini - </ComboBoxOption>, - <ComboBoxOption value="Brussels sprouts" key="9"> - Brussels Sprouts - </ComboBoxOption>, - <ComboBoxOption value="Horseradish" key="10"> - Horseradish - </ComboBoxOption>, - <ComboBoxOption value="Green beans" key="11"> - Green Beans - </ComboBoxOption>, - <ComboBoxOption value="Mushrooms" key="12"> - Mushrooms - </ComboBoxOption>, - <ComboBoxOption value="Leek" key="13"> - Leek - </ComboBoxOption>, - <ComboBoxOption value="Artichokes" key="14"> - Artichokes - </ComboBoxOption>, - <ComboBoxOption value="Peas" key="15"> - Peas - </ComboBoxOption>, - <ComboBoxOption value="Potatoes" key="16"> - Potatoes - </ComboBoxOption>, - ], - }, -}; - -export const WithLabelAndPlaceholder = { - render: Template, - - args: { - label: 'ComboBox', - placeholder: 'Type or select an Option…', - children: [ - <ComboBoxOption value="Rhubarb" key="1"> - Rhubarb - </ComboBoxOption>, - <ComboBoxOption value="Carrots" key="2"> - Carrots - </ComboBoxOption>, - <ComboBoxOption value="Spinach" key="3"> - Spinach - </ComboBoxOption>, - <ComboBoxOption value="Tomatoes" key="4"> - Tomatoes - </ComboBoxOption>, - <ComboBoxOption value="Cucumbers" key="5"> - Cucumbers - </ComboBoxOption>, - <ComboBoxOption value="Cauliflower" key="6"> - Cauliflower - </ComboBoxOption>, - <ComboBoxOption value="Eggplant" key="7"> - Eggplant - </ComboBoxOption>, - <ComboBoxOption value="Zucchini" key="8"> - Zucchini - </ComboBoxOption>, - <ComboBoxOption value="Brussels sprouts" key="9"> - Brussels Sprouts - </ComboBoxOption>, - <ComboBoxOption value="Horseradish" key="10"> - Horseradish - </ComboBoxOption>, - <ComboBoxOption value="Green beans" key="11"> - Green Beans - </ComboBoxOption>, - <ComboBoxOption value="Mushrooms" key="12"> - Mushrooms - </ComboBoxOption>, - <ComboBoxOption value="Leek" key="13"> - Leek - </ComboBoxOption>, - <ComboBoxOption value="Artichokes" key="14"> - Artichokes - </ComboBoxOption>, - <ComboBoxOption value="Peas" key="15"> - Peas - </ComboBoxOption>, - <ComboBoxOption value="Potatoes" key="16"> - Potatoes - </ComboBoxOption>, - ], - }, -}; - -export const Required = { - render: Template, - - args: { - label: 'Required ComboBox', - required: true, - children: [ - <ComboBoxOption value="Rhubarb" key="1"> - Rhubarb - </ComboBoxOption>, - <ComboBoxOption value="Carrots" key="2"> - Carrots - </ComboBoxOption>, - <ComboBoxOption value="Spinach" key="3"> - Spinach - </ComboBoxOption>, - <ComboBoxOption value="Tomatoes" key="4"> - Tomatoes - </ComboBoxOption>, - <ComboBoxOption value="Cucumbers" key="5"> - Cucumbers - </ComboBoxOption>, - <ComboBoxOption value="Cauliflower" key="6"> - Cauliflower - </ComboBoxOption>, - <ComboBoxOption value="Eggplant" key="7"> - Eggplant - </ComboBoxOption>, - <ComboBoxOption value="Zucchini" key="8"> - Zucchini - </ComboBoxOption>, - <ComboBoxOption value="Brussels sprouts" key="9"> - Brussels Sprouts - </ComboBoxOption>, - <ComboBoxOption value="Horseradish" key="10"> - Horseradish - </ComboBoxOption>, - <ComboBoxOption value="Green beans" key="11"> - Green Beans - </ComboBoxOption>, - <ComboBoxOption value="Mushrooms" key="12"> - Mushrooms - </ComboBoxOption>, - <ComboBoxOption value="Leek" key="13"> - Leek - </ComboBoxOption>, - <ComboBoxOption value="Artichokes" key="14"> - Artichokes - </ComboBoxOption>, - <ComboBoxOption value="Peas" key="15"> - Peas - </ComboBoxOption>, - <ComboBoxOption value="Potatoes" key="16"> - Potatoes - </ComboBoxOption>, - ], - }, -}; - -export const Valid = { - render: Template, - - args: { - label: 'Valid ComboBox', - valid: true, - children: [ - <ComboBoxOption value="Rhubarb" key="1"> - Rhubarb - </ComboBoxOption>, - <ComboBoxOption value="Carrots" key="2"> - Carrots - </ComboBoxOption>, - <ComboBoxOption value="Spinach" key="3"> - Spinach - </ComboBoxOption>, - <ComboBoxOption value="Tomatoes" key="4"> - Tomatoes - </ComboBoxOption>, - <ComboBoxOption value="Cucumbers" key="5"> - Cucumbers - </ComboBoxOption>, - <ComboBoxOption value="Cauliflower" key="6"> - Cauliflower - </ComboBoxOption>, - <ComboBoxOption value="Eggplant" key="7"> - Eggplant - </ComboBoxOption>, - <ComboBoxOption value="Zucchini" key="8"> - Zucchini - </ComboBoxOption>, - <ComboBoxOption value="Brussels sprouts" key="9"> - Brussels Sprouts - </ComboBoxOption>, - <ComboBoxOption value="Horseradish" key="10"> - Horseradish - </ComboBoxOption>, - <ComboBoxOption value="Green beans" key="11"> - Green Beans - </ComboBoxOption>, - <ComboBoxOption value="Mushrooms" key="12"> - Mushrooms - </ComboBoxOption>, - <ComboBoxOption value="Leek" key="13"> - Leek - </ComboBoxOption>, - <ComboBoxOption value="Artichokes" key="14"> - Artichokes - </ComboBoxOption>, - <ComboBoxOption value="Peas" key="15"> - Peas - </ComboBoxOption>, - <ComboBoxOption value="Potatoes" key="16"> - Potatoes - </ComboBoxOption>, - ], - }, -}; - -export const Invalid = { - render: Template, - - args: { - label: 'invalid ComboBox', - invalid: true, - children: [ - <ComboBoxOption value="Rhubarb" key="1"> - Rhubarb - </ComboBoxOption>, - <ComboBoxOption value="Carrots" key="2"> - Carrots - </ComboBoxOption>, - <ComboBoxOption value="Spinach" key="3"> - Spinach - </ComboBoxOption>, - <ComboBoxOption value="Tomatoes" key="4"> - Tomatoes - </ComboBoxOption>, - <ComboBoxOption value="Cucumbers" key="5"> - Cucumbers - </ComboBoxOption>, - <ComboBoxOption value="Cauliflower" key="6"> - Cauliflower - </ComboBoxOption>, - <ComboBoxOption value="Eggplant" key="7"> - Eggplant - </ComboBoxOption>, - <ComboBoxOption value="Zucchini" key="8"> - Zucchini - </ComboBoxOption>, - <ComboBoxOption value="Brussels sprouts" key="9"> - Brussels Sprouts - </ComboBoxOption>, - <ComboBoxOption value="Horseradish" key="10"> - Horseradish - </ComboBoxOption>, - <ComboBoxOption value="Green beans" key="11"> - Green Beans - </ComboBoxOption>, - <ComboBoxOption value="Mushrooms" key="12"> - Mushrooms - </ComboBoxOption>, - <ComboBoxOption value="Leek" key="13"> - Leek - </ComboBoxOption>, - <ComboBoxOption value="Artichokes" key="14"> - Artichokes - </ComboBoxOption>, - <ComboBoxOption value="Peas" key="15"> - Peas - </ComboBoxOption>, - <ComboBoxOption value="Potatoes" key="16"> - Potatoes - </ComboBoxOption>, - ], - }, -}; - -export const Disabled = { - render: Template, - - args: { - label: 'Disabled ComboBox', - disabled: true, - children: [ - <ComboBoxOption value="Rhubarb" key="1"> - Rhubarb - </ComboBoxOption>, - <ComboBoxOption value="Carrots" key="2"> - Carrots - </ComboBoxOption>, - <ComboBoxOption value="Spinach" key="3"> - Spinach - </ComboBoxOption>, - <ComboBoxOption value="Tomatoes" key="4"> - Tomatoes - </ComboBoxOption>, - <ComboBoxOption value="Cucumbers" key="5"> - Cucumbers - </ComboBoxOption>, - <ComboBoxOption value="Cauliflower" key="6"> - Cauliflower - </ComboBoxOption>, - <ComboBoxOption value="Eggplant" key="7"> - Eggplant - </ComboBoxOption>, - <ComboBoxOption value="Zucchini" key="8"> - Zucchini - </ComboBoxOption>, - <ComboBoxOption value="Brussels sprouts" key="9"> - Brussels Sprouts - </ComboBoxOption>, - <ComboBoxOption value="Horseradish" key="10"> - Horseradish - </ComboBoxOption>, - <ComboBoxOption value="Green beans" key="11"> - Green Beans - </ComboBoxOption>, - <ComboBoxOption value="Mushrooms" key="12"> - Mushrooms - </ComboBoxOption>, - <ComboBoxOption value="Leek" key="13"> - Leek - </ComboBoxOption>, - <ComboBoxOption value="Artichokes" key="14"> - Artichokes - </ComboBoxOption>, - <ComboBoxOption value="Peas" key="15"> - Peas - </ComboBoxOption>, - <ComboBoxOption value="Potatoes" key="16"> - Potatoes - </ComboBoxOption>, - ], - }, -}; - -export const DisabledOption = { - render: Template, - - args: { - label: 'ComboBox with a Disabled Option', - helptext: 'Option Carrots should be disabled', - children: [ - <ComboBoxOption value="Rhubarb" key="1"> - Rhubarb - </ComboBoxOption>, - <ComboBoxOption value="Carrots" key="2" disabled> - Carrots - </ComboBoxOption>, - <ComboBoxOption value="Spinach" key="3"> - Spinach - </ComboBoxOption>, - ], - }, -}; - -export const WithHelpText = { - render: Template, - - args: { - label: 'ComboBox', - helptext: 'Helptext to describe meaning and significance of the ComboBox', - children: [ - <ComboBoxOption value="Rhubarb" key="1"> - Rhubarb - </ComboBoxOption>, - <ComboBoxOption value="Carrots" key="2"> - Carrots - </ComboBoxOption>, - <ComboBoxOption value="Spinach" key="3"> - Spinach - </ComboBoxOption>, - <ComboBoxOption value="Tomatoes" key="4"> - Tomatoes - </ComboBoxOption>, - <ComboBoxOption value="Cucumbers" key="5"> - Cucumbers - </ComboBoxOption>, - <ComboBoxOption value="Cauliflower" key="6"> - Cauliflower - </ComboBoxOption>, - <ComboBoxOption value="Eggplant" key="7"> - Eggplant - </ComboBoxOption>, - <ComboBoxOption value="Zucchini" key="8"> - Zucchini - </ComboBoxOption>, - <ComboBoxOption value="Brussels sprouts" key="9"> - Brussels Sprouts - </ComboBoxOption>, - <ComboBoxOption value="Horseradish" key="10"> - Horseradish - </ComboBoxOption>, - <ComboBoxOption value="Green beans" key="11"> - Green Beans - </ComboBoxOption>, - <ComboBoxOption value="Mushrooms" key="12"> - Mushrooms - </ComboBoxOption>, - <ComboBoxOption value="Leek" key="13"> - Leek - </ComboBoxOption>, - <ComboBoxOption value="Artichokes" key="14"> - Artichokes - </ComboBoxOption>, - <ComboBoxOption value="Peas" key="15"> - Peas - </ComboBoxOption>, - <ComboBoxOption value="Potatoes" key="16"> - Potatoes - </ComboBoxOption>, - ], - }, -}; - -export const WithHelpTextAsNode = { - render: Template, - - args: { - label: 'ComboBox', - helptext: ( - <> - This is a helptext with a <a href="#">Link</a> - </> - ), - children: [ - <ComboBoxOption value="Rhubarb" key="1"> - Rhubarb - </ComboBoxOption>, - <ComboBoxOption value="Carrots" key="2"> - Carrots - </ComboBoxOption>, - <ComboBoxOption value="Spinach" key="3"> - Spinach - </ComboBoxOption>, - <ComboBoxOption value="Tomatoes" key="4"> - Tomatoes - </ComboBoxOption>, - <ComboBoxOption value="Cucumbers" key="5"> - Cucumbers - </ComboBoxOption>, - <ComboBoxOption value="Cauliflower" key="6"> - Cauliflower - </ComboBoxOption>, - <ComboBoxOption value="Eggplant" key="7"> - Eggplant - </ComboBoxOption>, - <ComboBoxOption value="Zucchini" key="8"> - Zucchini - </ComboBoxOption>, - <ComboBoxOption value="Brussels sprouts" key="9"> - Brussels Sprouts - </ComboBoxOption>, - <ComboBoxOption value="Horseradish" key="10"> - Horseradish - </ComboBoxOption>, - <ComboBoxOption value="Green beans" key="11"> - Green Beans - </ComboBoxOption>, - <ComboBoxOption value="Mushrooms" key="12"> - Mushrooms - </ComboBoxOption>, - <ComboBoxOption value="Leek" key="13"> - Leek - </ComboBoxOption>, - <ComboBoxOption value="Artichokes" key="14"> - Artichokes - </ComboBoxOption>, - <ComboBoxOption value="Peas" key="15"> - Peas - </ComboBoxOption>, - <ComboBoxOption value="Potatoes" key="16"> - Potatoes - </ComboBoxOption>, - ], - }, -}; - -export const WithErrorText = { - render: Template, - - args: { - label: 'ComboBox', - errortext: 'Invalidated by passing an errortext', - children: [ - <ComboBoxOption value="Rhubarb" key="1"> - Rhubarb - </ComboBoxOption>, - <ComboBoxOption value="Carrots" key="2"> - Carrots - </ComboBoxOption>, - <ComboBoxOption value="Spinach" key="3"> - Spinach - </ComboBoxOption>, - <ComboBoxOption value="Tomatoes" key="4"> - Tomatoes - </ComboBoxOption>, - <ComboBoxOption value="Cucumbers" key="5"> - Cucumbers - </ComboBoxOption>, - <ComboBoxOption value="Cauliflower" key="6"> - Cauliflower - </ComboBoxOption>, - <ComboBoxOption value="Eggplant" key="7"> - Eggplant - </ComboBoxOption>, - <ComboBoxOption value="Zucchini" key="8"> - Zucchini - </ComboBoxOption>, - <ComboBoxOption value="Brussels sprouts" key="9"> - Brussels Sprouts - </ComboBoxOption>, - <ComboBoxOption value="Horseradish" key="10"> - Horseradish - </ComboBoxOption>, - <ComboBoxOption value="Green beans" key="11"> - Green Beans - </ComboBoxOption>, - <ComboBoxOption value="Mushrooms" key="12"> - Mushrooms - </ComboBoxOption>, - <ComboBoxOption value="Leek" key="13"> - Leek - </ComboBoxOption>, - <ComboBoxOption value="Artichokes" key="14"> - Artichokes - </ComboBoxOption>, - <ComboBoxOption value="Peas" key="15"> - Peas - </ComboBoxOption>, - <ComboBoxOption value="Potatoes" key="16"> - Potatoes - </ComboBoxOption>, - ], - }, -}; - -export const WithSuccessText = { - render: Template, - - args: { - label: 'ComboBox', - successtext: 'Validated by passing a successtext', - children: [ - <ComboBoxOption value="Rhubarb" key="1"> - Rhubarb - </ComboBoxOption>, - <ComboBoxOption value="Carrots" key="2"> - Carrots - </ComboBoxOption>, - <ComboBoxOption value="Spinach" key="3"> - Spinach - </ComboBoxOption>, - <ComboBoxOption value="Tomatoes" key="4"> - Tomatoes - </ComboBoxOption>, - <ComboBoxOption value="Cucumbers" key="5"> - Cucumbers - </ComboBoxOption>, - <ComboBoxOption value="Cauliflower" key="6"> - Cauliflower - </ComboBoxOption>, - <ComboBoxOption value="Eggplant" key="7"> - Eggplant - </ComboBoxOption>, - <ComboBoxOption value="Zucchini" key="8"> - Zucchini - </ComboBoxOption>, - <ComboBoxOption value="Brussels sprouts" key="9"> - Brussels Sprouts - </ComboBoxOption>, - <ComboBoxOption value="Horseradish" key="10"> - Horseradish - </ComboBoxOption>, - <ComboBoxOption value="Green beans" key="11"> - Green Beans - </ComboBoxOption>, - <ComboBoxOption value="Mushrooms" key="12"> - Mushrooms - </ComboBoxOption>, - <ComboBoxOption value="Leek" key="13"> - Leek - </ComboBoxOption>, - <ComboBoxOption value="Artichokes" key="14"> - Artichokes - </ComboBoxOption>, - <ComboBoxOption value="Peas" key="15"> - Peas - </ComboBoxOption>, - <ComboBoxOption value="Potatoes" key="16"> - Potatoes - </ComboBoxOption>, - ], - }, -}; - -export const NonNullable = { - render: Template, - - args: { - nullable: false, - label: 'Non-Nullable ComboBox', - helptext: - 'This Select can not be reset to having no value selected. The last selected value will remian selected when emptying the input field.', - children: [ - <ComboBoxOption value="Rhubarb" key="1"> - Rhubarb - </ComboBoxOption>, - <ComboBoxOption value="Carrots" key="2"> - Carrots - </ComboBoxOption>, - <ComboBoxOption value="Spinach" key="3"> - Spinach - </ComboBoxOption>, - <ComboBoxOption value="Tomatoes" key="4"> - Tomatoes - </ComboBoxOption>, - <ComboBoxOption value="Cucumbers" key="5"> - Cucumbers - </ComboBoxOption>, - <ComboBoxOption value="Cauliflower" key="6"> - Cauliflower - </ComboBoxOption>, - ], - }, -}; - -export const NonTruncatedOptions = { - render: ConstrainedWidthTemplate, - - args: { - children: [ - <ComboBoxOption - value="Option with a very long title that is so long it will most likely not fit into the menu width, not at all really." - key="1" - ></ComboBoxOption>, - <ComboBoxOption - value="Yet another option with a very long title that is so long it will most likely not fit into the menu width, not at all really." - key="2" - ></ComboBoxOption>, - ], - }, -}; - -export const TruncatedOptions = { - render: ConstrainedWidthTemplate, - - args: { - truncateOptions: true, - children: [ - <ComboBoxOption - value="Option with a very long title that is so long it will most likely not fit into the menu width, not at all really." - key="1" - ></ComboBoxOption>, - <ComboBoxOption - value="Yet another option with a very long title that is so long it will most likely not fit into the menu width, not at all really." - key="2" - ></ComboBoxOption>, - ], - }, -}; - -export const OptionsWithLabels = { - render: Template, - - parameters: { - docs: { - description: { - story: - 'If an option has both a label and a child, then the child is displayed instead of the label', - }, - }, - }, - - args: { - children: [ - <ComboBoxOption value="option1_value" label="Option 1 Label" key="1" />, - <ComboBoxOption value="option2_value" label="Option 2 Label" key="2"> - Option 2 child is displayed instead of label - </ComboBoxOption>, - ], - }, -}; - -export const Loading = { - render: Template, - - args: { - loading: true, - helptext: 'ComboBox busy loading options', - }, -}; - -export const Error = { - render: Template, - - args: { - error: true, - errortext: 'ComboBox having trouble loading options', - }, -}; - -export const ValueAndDefaultValue = { - render: Template, - - args: { - value: 'Option 1', - defaultValue: 'Option 2', - children: [ - <ComboBoxOption value="Option 1" key="1" />, - <ComboBoxOption value="Option 2" key="2" />, - <ComboBoxOption value="Option 3" key="3" />, - ], - }, -}; diff --git a/libs/juno-ui-components/src/components/ComboBox/ComboBox.test.js b/libs/juno-ui-components/src/components/ComboBox/ComboBox.test.js deleted file mode 100644 index 25958bdb4..000000000 --- a/libs/juno-ui-components/src/components/ComboBox/ComboBox.test.js +++ /dev/null @@ -1,401 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { cleanup, render, screen, fireEvent } from "@testing-library/react" -import userEvent from "@testing-library/user-event" -import { ComboBox } from "./index" -import { ComboBoxOption } from "../ComboBoxOption/index" - -const mockOnBlur = jest.fn() -const mockOnChange = jest.fn() -const mockOnFocus = jest.fn() -const mockOnInputChange = jest.fn() - -describe("ComboBox", () => { - afterEach(() => { - cleanup() - jest.clearAllMocks() - }) - - test("renders a ComboBox", async () => { - render(<ComboBox />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toHaveAttribute("type", "text") - expect(screen.getByRole("combobox")).toHaveClass("juno-combobox-input") - }) - - test("renders a ComboBox with a name as passed", async () => { - render( - <ComboBox name="my-wonderful-combobox"> - <ComboBoxOption value="Option 1">Option 1</ComboBoxOption> - </ComboBox> - ) - expect(screen.getByRole("combobox")).toBeInTheDocument() - /* Here we need to directly select the input, since headless - a) does not add the name to the visible input element but to another, hidden input element it keeps in sync, and - b) react-testing fails when trying to access hidden elements by role: */ - expect( - document.querySelector("input[name='my-wonderful-combobox']") - ).toBeInTheDocument() - }) - - test("renders a ComboBox with a label as passed", async () => { - render(<ComboBox label="My Label" />) - expect(document.querySelector(".juno-label")).toBeInTheDocument() - expect(document.querySelector(".juno-label")).toHaveTextContent("My Label") - }) - - test("renders options as passed", async () => { - render( - <ComboBox> - <ComboBoxOption value="Option 1">Option 1</ComboBoxOption> - </ComboBox> - ) - const cbox = screen.getByRole("combobox") - const cbutton = screen.getByRole("button") - expect(cbox).toBeInTheDocument() - expect(cbutton).toBeInTheDocument() - await userEvent.click(cbutton) - expect(screen.getByRole("listbox")).toBeInTheDocument() - expect(screen.getByRole("option")).toBeInTheDocument() - expect(screen.getByRole("option")).toHaveTextContent("Option 1") - }) - - test("renders an id as passed", async () => { - render(<ComboBox id="My Id" />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toHaveAttribute("id", "My Id") - }) - - test("renders the id of the ComboBox input as the for attribute of the label", async () => { - render(<ComboBox label="the label" />) - const cbox = screen.getByRole("combobox") - const label = document.querySelector(".juno-label") - expect(cbox).toBeInTheDocument() - expect(label).toBeInTheDocument() - expect(label.getAttribute("for")).toMatch(cbox.getAttribute("id")) - expect(screen.getByLabelText("the label")).toBeInTheDocument() - }) - - test("renders an aria-label as passed", async () => { - render(<ComboBox ariaLabel="my aria-label" />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toHaveAttribute( - "aria-label", - "my aria-label" - ) - }) - - test("renders the label as an aria-label if no aria-label was passed", async () => { - render(<ComboBox label="My Label" />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toHaveAttribute( - "aria-label", - "My Label" - ) - }) - - test("renders a ComboBox with a placeholder as passed", async () => { - render(<ComboBox placeholder="My Placeholder" />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toHaveAttribute( - "placeholder", - "My Placeholder" - ) - }) - - test("renders a disabled ComboBox as passed", async () => { - render(<ComboBox disabled />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toBeDisabled() - }) - - test("renders a required ComboBox as passed", async () => { - render(<ComboBox label="My Required ComboBox" required />) - expect(document.querySelector(".juno-label")).toBeInTheDocument() - expect(document.querySelector(".juno-required")).toBeInTheDocument() - }) - - test("renders a validated ComboBox as passed", async () => { - render(<ComboBox valid />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toHaveClass("juno-combobox-valid") - expect(screen.getByTitle("CheckCircle")).toBeInTheDocument() - }) - - test("renders a validated ComboBox when a successtext was passed", async () => { - render(<ComboBox successtext="Great Success!" />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toHaveClass("juno-combobox-valid") - expect(screen.getByTitle("CheckCircle")).toBeInTheDocument() - }) - - test("renders an invalidated ComboBox as passed", async () => { - render(<ComboBox invalid />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toHaveClass("juno-combobox-invalid") - expect(screen.getByTitle("Dangerous")).toBeInTheDocument() - }) - - test("renders an invalidated ComboBox when an errortext was passed", async () => { - render(<ComboBox errortext="Oh Snap!" />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toHaveClass("juno-combobox-invalid") - expect(screen.getByTitle("Dangerous")).toBeInTheDocument() - }) - - test("renders a helptext as passed", async () => { - render(<ComboBox helptext="A helptext goes here" />) - expect(document.querySelector(".juno-form-hint")).toBeInTheDocument() - expect(document.querySelector(".juno-form-hint")).toHaveClass( - "juno-form-hint-help" - ) - expect(document.querySelector(".juno-form-hint")).toHaveTextContent( - "A helptext goes here" - ) - }) - - test("renders an errortext as passed", async () => { - render(<ComboBox errortext="An errortext goes here" />) - expect(document.querySelector(".juno-form-hint")).toBeInTheDocument() - expect(document.querySelector(".juno-form-hint")).toHaveClass( - "juno-form-hint-error" - ) - expect(document.querySelector(".juno-form-hint")).toHaveTextContent( - "An errortext goes here" - ) - }) - - test("renders a successtext as passed", async () => { - render(<ComboBox successtext="A successtext goes here" />) - expect(document.querySelector(".juno-form-hint")).toBeInTheDocument() - expect(document.querySelector(".juno-form-hint")).toHaveClass( - "juno-form-hint-success" - ) - expect(document.querySelector(".juno-form-hint")).toHaveTextContent( - "A successtext goes here" - ) - }) - - test("renders a loading ComboBox with a Spinner as passed", async () => { - render(<ComboBox loading />) - expect(screen.getByRole("combobox")).toHaveClass("juno-combobox-loading") - expect(document.querySelector(".juno-spinner")).toBeInTheDocument() - }) - - test("renders a ComboBox in error state with an Error icon as passed", async () => { - render(<ComboBox error />) - expect(screen.getByRole("combobox")).toHaveClass("juno-combobox-error") - expect(screen.getByTitle("Error")).toBeInTheDocument() - }) - - test("fires an onBlur handler as passed when the ComboBox looses focus", async () => { - render(<ComboBox onBlur={mockOnBlur} />) - const user = userEvent.setup() - const cbox = screen.getByRole("combobox") - await user.click(cbox) // focus the element - await user.tab() // blur the element - expect(mockOnBlur).toHaveBeenCalled() - }) - - test("fires an onChange handler as passed when the user selects an option", async () => { - render( - <ComboBox onChange={mockOnChange}> - <ComboBoxOption value="option 1">Option 1</ComboBoxOption> - <ComboBoxOption value="option 2">Option 2</ComboBoxOption> - </ComboBox> - ) - const cbox = screen.getByRole("combobox") - const cbutton = screen.getByRole("button") - expect(cbox).toBeInTheDocument() - expect(cbutton).toBeInTheDocument() - await userEvent.click(cbutton) - expect(screen.getByRole("listbox")).toBeInTheDocument() - await userEvent.click(screen.getByRole("option", { name: "Option 2" })) - expect(mockOnChange).toHaveBeenCalled() - }) - - test("fires an onFocus handler as passed when the ComboBox receives focus", async () => { - render(<ComboBox onFocus={mockOnFocus} />) - const cbox = screen.getByRole("combobox") - await userEvent.click(cbox) - expect(mockOnFocus).toHaveBeenCalled() - }) - - test("fires an onInputChange handler when the user types into the ComboBox", async () => { - render( - <ComboBox onInputChange={mockOnInputChange}> - <ComboBoxOption value="something">Something</ComboBoxOption> - <ComboBoxOption value="something else">Something else</ComboBoxOption> - </ComboBox> - ) - const user = userEvent.setup() - const cbox = screen.getByRole("combobox") - await user.type(cbox, "a") - expect(mockOnInputChange).toHaveBeenCalled() - }) - - test("filters options as the user types", async () => { - render( - <ComboBox> - <ComboBoxOption value="aaa" name="aaa"> - aaa - </ComboBoxOption> - <ComboBoxOption value="aab" name="aab"> - aab - </ComboBoxOption> - <ComboBoxOption value="abc" name="abc"> - abc - </ComboBoxOption> - <ComboBoxOption value="123" name="123"> - 123 - </ComboBoxOption> - </ComboBox> - ) - const user = userEvent.setup() - const cbox = screen.getByRole("combobox") - expect(cbox).toBeInTheDocument() - await user.type(cbox, "a") - expect(screen.getByRole("listbox")).toBeInTheDocument() - expect(screen.getByRole("option", { name: "aaa" })).toBeInTheDocument() - expect(screen.getByRole("option", { name: "aab" })).toBeInTheDocument() - expect(screen.getByRole("option", { name: "abc" })).toBeInTheDocument() - expect( - screen.queryByRole("option", { name: "123" }) - ).not.toBeInTheDocument() - await user.type(cbox, "b") - expect( - screen.queryByRole("option", { name: "aaa" }) - ).not.toBeInTheDocument() - expect(screen.getByRole("option", { name: "aab" })).toBeInTheDocument() - expect(screen.getByRole("option", { name: "abc" })).toBeInTheDocument() - expect( - screen.queryByRole("option", { name: "123" }) - ).not.toBeInTheDocument() - await userEvent.clear(cbox) - expect(screen.getByRole("option", { name: "aaa" })).toBeInTheDocument() - expect(screen.getByRole("option", { name: "aab" })).toBeInTheDocument() - expect(screen.getByRole("option", { name: "abc" })).toBeInTheDocument() - expect(screen.getByRole("option", { name: "123" })).toBeInTheDocument() - await user.type(cbox, "1") - expect( - screen.queryByRole("option", { name: "aaa" }) - ).not.toBeInTheDocument() - expect( - screen.queryByRole("option", { name: "aab" }) - ).not.toBeInTheDocument() - expect( - screen.queryByRole("option", { name: "abc" }) - ).not.toBeInTheDocument() - expect(screen.getByRole("option", { name: "123" })).toBeInTheDocument() - }) - - test("selects an option when the user clicks it and closes the menu", async () => { - render( - <ComboBox> - <ComboBoxOption value="aaa" name="aaa"> - aaa - </ComboBoxOption> - <ComboBoxOption value="aab" name="aab"> - aab - </ComboBoxOption> - <ComboBoxOption value="abc" name="abc"> - abc - </ComboBoxOption> - <ComboBoxOption value="123" name="123"> - 123 - </ComboBoxOption> - </ComboBox> - ) - const cbox = screen.getByRole("combobox") - const cbutton = screen.getByRole("button") - expect(cbox).toBeInTheDocument() - expect(cbutton).toBeInTheDocument() - await userEvent.click(cbutton) - expect(screen.getByRole("listbox")).toBeInTheDocument() - await userEvent.click(screen.getByRole("option", { name: "abc" })) - expect(screen.queryByRole("listbox")).not.toBeInTheDocument() - expect(cbox).toHaveValue("abc") - }) - - test("works as a controlled component with a value as passed", async () => { - render( - <ComboBox value="aab"> - <ComboBoxOption value="aaa" name="aaa"> - aaa - </ComboBoxOption> - <ComboBoxOption value="aab" name="aab"> - aab - </ComboBoxOption> - <ComboBoxOption value="abc" name="abc"> - abc - </ComboBoxOption> - <ComboBoxOption value="123" name="123"> - 123 - </ComboBoxOption> - </ComboBox> - ) - const cbox = screen.getByRole("combobox") - const toggle = screen.getByRole("button") - expect(cbox).toBeInTheDocument() - expect(toggle).toBeInTheDocument() - expect(cbox).toHaveValue("aab") - await userEvent.click(toggle) - expect(screen.getByRole("listbox")).toBeInTheDocument() - const option123 = screen.getAllByRole("option")[3] - expect(option123).toHaveTextContent("123") - await userEvent.click(option123) - expect(cbox).toHaveValue("123") - }) - - test("works as an uncontrolled component with a defaultValue as passed", async () => { - render( - <ComboBox defaultValue="abc"> - <ComboBoxOption>aaa</ComboBoxOption> - <ComboBoxOption>aab</ComboBoxOption> - <ComboBoxOption>abc</ComboBoxOption> - <ComboBoxOption>123</ComboBoxOption> - </ComboBox> - ) - const cbox = screen.getByRole("combobox") - const toggle = screen.getByRole("button") - expect(cbox).toBeInTheDocument() - expect(toggle).toBeInTheDocument() - expect(cbox).toHaveValue("abc") - await userEvent.click(toggle) - expect(screen.getByRole("listbox")).toBeInTheDocument() - const option123 = screen.getAllByRole("option")[3] - expect(option123).toHaveTextContent("123") - await userEvent.click(option123) - expect(cbox).toHaveValue("123") - }) - - // Caution: The below test basically tests headless-ui behaviour, not our logic. This is here only for testing consistency and so that we know should headless ever change their behaviour: - test("works as a controlled component using value when both value and defaultValue have been passed", async () => { - render( - <ComboBox defaultValue="option 1" value="option 2"> - <ComboBoxOption value="option 1" /> - <ComboBoxOption value="option 2" /> - </ComboBox> - ) - const cbox = screen.getByRole("combobox") - expect(cbox).toBeInTheDocument() - expect(cbox).toHaveValue("option 2") - }) - - test("renders a ComboBox with a custom className as passed", async () => { - render(<ComboBox className="my-combobox" />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toHaveClass("my-combobox") - }) - - // Skipping because if we pass generic props to the ComboBox component it will be passed to the abstract headless Combobox component, but will not end up in the DOM: - test.skip("renders all props as passed", async () => { - render(<ComboBox data-lolo="1234" />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toHaveAttribute("data-lolo", "1234") - }) -}) diff --git a/libs/juno-ui-components/src/components/ComboBox/index.js b/libs/juno-ui-components/src/components/ComboBox/index.js deleted file mode 100644 index 1f4828da1..000000000 --- a/libs/juno-ui-components/src/components/ComboBox/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { ComboBox } from "./ComboBox.component.js" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/ComboBoxOption/ComboBoxOption.component.js b/libs/juno-ui-components/src/components/ComboBoxOption/ComboBoxOption.component.js deleted file mode 100644 index 4e39ccc55..000000000 --- a/libs/juno-ui-components/src/components/ComboBoxOption/ComboBoxOption.component.js +++ /dev/null @@ -1,123 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { Fragment, useState, useEffect, useContext } from "react" -import PropTypes from "prop-types" -import { Combobox } from "@headlessui/react" -import { ComboBoxContext } from "../ComboBox/ComboBox.component" -import { Icon } from "../Icon/Icon.component" - - -const optionStyles = ` - jn-flex - jn-pt-[0.6875rem] - jn-pb-[0.5rem] - jn-pr-[0.875rem] - jn-select-none - data-[headlessui-state=active]:jn-outline-none - data-[headlessui-state=active]:jn-ring-2 - data-[headlessui-state=active]:jn-ring-inset - data-[headlessui-state=active]:jn-ring-theme-focus - data-[headlessui-state=active]:jn-bg-theme-background-lvl-3 -` - -const unselectedOptionStyles = ` - jn-text-theme-default - jn-pl-[2.375rem] -` - -const selectedOptionStyles = ` - jn-text-theme-accent - jn-pl-3.5 -` - -const selectedIconStyles = ` - jn-inline-block - jn-mr-1.5 -` - -const disabledOptionLabelStyles = ` - jn-opacity-50 - jn-cursor-not-allowed -` - -const truncateOptionStyles = ` - jn-block - jn-h-6 - jn-overflow-hidden - jn-text-ellipsis - jn-whitespace-nowrap -` - -export const ComboBoxOption = ({ - children, - disabled, - value, - label, - className, - ...props -}) => { - - const comboBoxContext = useContext(ComboBoxContext) - const { - selectedValue: selectedValue, - truncateOptions: truncateOptions, - addOptionValueAndLabel: addOptionValueAndLabel - } = comboBoxContext || {} - - // send option metadata to the ComboBox parent component via Context - useEffect(() => { - addOptionValueAndLabel(value, label, children) - }, [value, label, children]) - - const theValue = value || children - - return ( - <Combobox.Option - value={theValue} - disabled={disabled} - as={Fragment} - > - <li - className={` - juno-combobox-option - ${ optionStyles} - ${ selectedValue === value ? selectedOptionStyles : unselectedOptionStyles } - ${ disabled ? "jn-cursor-not-allowed" : "" } - ${ className } - `} - {...props} - > - { selectedValue === theValue ? <Icon icon="check" size="18" className={`${selectedIconStyles}`} /> : "" } - <span - className={` - ${ disabled ? disabledOptionLabelStyles : "" } - ${ truncateOptions ? truncateOptionStyles : "" } - `} - > - { children || label || value } - </span> - </li> - - </Combobox.Option> - ) -} - - -ComboBoxOption.propTypes = { - children: PropTypes.string, - disabled: PropTypes.bool, - value: PropTypes.string, - label: PropTypes.string, - className: PropTypes.string, -} - -ComboBoxOption.defaultProps = { - children: undefined, - disabled: false, - value: "", - label: undefined, - className: "", -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/ComboBoxOption/ComboBoxOption.stories.js b/libs/juno-ui-components/src/components/ComboBoxOption/ComboBoxOption.stories.js deleted file mode 100644 index 19111cdce..000000000 --- a/libs/juno-ui-components/src/components/ComboBoxOption/ComboBoxOption.stories.js +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { ComboBox } from '../ComboBox/ComboBox.component'; -import { ComboBoxOption } from '../ComboBoxOption/ComboBoxOption.component'; - -export default { - title: 'Forms/ComboBox/ComboBoxOption', - component: ComboBoxOption, - argTypes: {}, -}; - -const Template = (args) => { - return ( - <ComboBox> - <ComboBoxOption {...args} /> - </ComboBox> - ); -}; - -export const Default = { - render: Template, - - args: { - value: 'Option 1', - }, -}; - -export const Disabled = { - render: Template, - - args: { - disabled: true, - value: 'Disabled Option', - }, -}; - -export const ChildrenOnly = { - render: Template, - - args: { - children: 'Option 1', - }, -}; diff --git a/libs/juno-ui-components/src/components/ComboBoxOption/ComboBoxOption.test.js b/libs/juno-ui-components/src/components/ComboBoxOption/ComboBoxOption.test.js deleted file mode 100644 index 9be5e7c25..000000000 --- a/libs/juno-ui-components/src/components/ComboBoxOption/ComboBoxOption.test.js +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { cleanup, render, screen } from "@testing-library/react" -import userEvent from "@testing-library/user-event" -import { ComboBox } from "../ComboBox/ComboBox.component" -import { ComboBoxOption } from "../ComboBoxOption/ComboBoxOption.component" - - -describe("ComboBoxOption", () => { - - afterEach(() => { - cleanup(); - jest.clearAllMocks(); - }); - - test("renders a ComboBoxOption", async () => { - render( - <ComboBox> - <ComboBoxOption value="Option 1" /> - </ComboBox> - ) - const toggle = screen.getByRole("button") - expect(toggle).toBeInTheDocument() - await userEvent.click(toggle) - expect(screen.getByRole("option")).toBeInTheDocument() - expect(screen.getByRole("option")).toHaveTextContent("Option 1") - }) - - test("renders a ComboBoxOption with label as passed", async () => { - render( - <ComboBox> - <ComboBoxOption value="option 1 value" label="Option 1 Label" /> - </ComboBox> - ) - const toggle = screen.getByRole("button") - expect(toggle).toBeInTheDocument() - await userEvent.click(toggle) - expect(screen.getByRole("option")).toBeInTheDocument() - expect(screen.getByRole("option")).toHaveTextContent("Option 1 Label") - }) - - test("renders a ComboBoxOption with children as passed", async () => { - render( - <ComboBox> - <ComboBoxOption value="option 1 value">Option 1 child</ComboBoxOption> - </ComboBox> - ) - const toggle = screen.getByRole("button") - expect(toggle).toBeInTheDocument() - await userEvent.click(toggle) - expect(screen.getByRole("option")).toBeInTheDocument() - expect(screen.getByRole("option")).toHaveTextContent("Option 1 child") - }) - - test("renders a ComboBoxOption with children if both label and children are passed", async () => { - render( - <ComboBox> - <ComboBoxOption value="option 1 value" label="Option 1 Label">Option 1 child</ComboBoxOption> - </ComboBox> - ) - const toggle = screen.getByRole("button") - expect(toggle).toBeInTheDocument() - await userEvent.click(toggle) - expect(screen.getByRole("option")).toBeInTheDocument() - expect(screen.getByRole("option")).toHaveTextContent("Option 1 child") - }) - - test("renders a className as passed", async () => { - render( - <ComboBox> - <ComboBoxOption className="my-fancy-class"/> - </ComboBox> - ) - const toggle = screen.getByRole("button") - expect(toggle).toBeInTheDocument() - await userEvent.click(toggle) - expect(screen.getByRole("option")).toBeInTheDocument() - expect(screen.getByRole("option")).toHaveClass("my-fancy-class") - }) - - test("renders all props as passed", async () => { - render( - <ComboBox> - <ComboBoxOption data-lolol="123"/> - </ComboBox> - ) - const toggle = screen.getByRole("button") - expect(toggle).toBeInTheDocument() - await userEvent.click(toggle) - expect(screen.getByRole("option")).toBeInTheDocument() - expect(screen.getByRole("option")).toHaveAttribute("data-lolol", "123") - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/ComboBoxOption/index.js b/libs/juno-ui-components/src/components/ComboBoxOption/index.js deleted file mode 100644 index d24e1f852..000000000 --- a/libs/juno-ui-components/src/components/ComboBoxOption/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { ComboBoxOption } from "./ComboBoxOption.component.js" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Container/Container.component.js b/libs/juno-ui-components/src/components/Container/Container.component.js deleted file mode 100644 index 356519ea3..000000000 --- a/libs/juno-ui-components/src/components/Container/Container.component.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -const containerStyles = (px, py) => { - return ` - ${ px ? "jn-px-6 " : " " } - ${ py ? " jn-py-6" : "" } - ` -} - -/** - * A very basic layout container with padding. - */ -export const Container = ({ - px, - py, - className, - children, - ...props -}) => { - return ( - <div - className={`juno-container ${containerStyles(px, py)} ${className}`} - {...props} - > - {children} - </div> - ) -} - -Container.propTypes = { - /** Choose false if you don't want horizontal padding to be added. */ - px: PropTypes.bool, - /** Set to true to add vertical padding. */ - py: PropTypes.bool, - /** Add custom class name */ - className: PropTypes.string, - children: PropTypes.node, -} - -Container.defaultProps = { - px: true, - py: false, - className: "", - children: null, -} diff --git a/libs/juno-ui-components/src/components/Container/Container.stories.js b/libs/juno-ui-components/src/components/Container/Container.stories.js deleted file mode 100644 index 6751085d0..000000000 --- a/libs/juno-ui-components/src/components/Container/Container.stories.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; - -import { Container } from './index.js'; - -export default { - title: 'Layout/Container', - component: Container, - argTypes: { - children: { - control: false, - }, - }, - parameters: { - docs: { - description: { - component: - 'A very basic layout element with padding. By default has padding all around. Can be set to have only vertical padding.', - }, - }, - }, -}; - -const Template = (args) => <Container {...args}>Content goes here</Container>; - -export const Basic = { - render: Template, - - parameters: { - docs: { - description: { - story: - "Section for content displayed in the main content area. Has padding. Typically you will want to use one of these sections to wrap your main content inside as the content area itself doesn't have padding to allow for full-width content or content to be placed at the very top or bottom.", - }, - }, - }, - - args: {}, -}; - -export const WithVerticalPadding = { - render: Template, - - parameters: { - docs: { - description: { - story: - 'A content container with vertical padding added. This will add padding to both the top and the bottom of the container.', - }, - }, - }, - - args: { - py: true, - }, -}; diff --git a/libs/juno-ui-components/src/components/Container/Container.test.js b/libs/juno-ui-components/src/components/Container/Container.test.js deleted file mode 100644 index 8a40eef40..000000000 --- a/libs/juno-ui-components/src/components/Container/Container.test.js +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { Container } from "./index" - -describe("Container", () => { - - test("renders children as passed", async () => { - render( - <Container data-testid="container"> - <button></button> - </Container> - ) - expect(screen.getByTestId("container")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeInTheDocument() - }) - - test("renders a container with horizontal padding by default", async () => { - render(<Container data-testid="container" />) - expect(screen.getByTestId("container")).toBeInTheDocument() - expect(screen.getByTestId("container")).toHaveClass("jn-px-6") - expect(screen.getByTestId("container")).not.toHaveClass("jn-py-6") - }) - - test("renders a container without horizontal padding as passed", async () => { - render(<Container data-testid="container" px={false} />) - expect(screen.getByTestId("container")).toBeInTheDocument() - expect(screen.getByTestId("container")).not.toHaveClass("jn-px-6") - expect(screen.getByTestId("container")).not.toHaveClass("jn-py-6") - }) - - test("renders a container with vertical padding as passed", async () => { - render(<Container data-testid="container" py={true} />) - expect(screen.getByTestId("container")).toBeInTheDocument() - expect(screen.getByTestId("container")).toHaveClass("jn-px-6") - expect(screen.getByTestId("container")).toHaveClass("jn-py-6") - }) - - test("renders a custom className", async () => { - render( - <Container - data-testid="container" - className="my-custom-classname" - /> - ) - expect(screen.getByTestId("container")).toBeInTheDocument() - expect(screen.getByTestId("container")).toHaveClass( - "my-custom-classname" - ) - }) - - test("renders all props", async () => { - render(<Container data-testid="container" data-lolol="some-prop" />) - expect(screen.getByTestId("container")).toBeInTheDocument() - expect(screen.getByTestId("container")).toHaveAttribute( - "data-lolol", - "some-prop" - ) - }) -}) diff --git a/libs/juno-ui-components/src/components/Container/index.js b/libs/juno-ui-components/src/components/Container/index.js deleted file mode 100644 index ae48fba60..000000000 --- a/libs/juno-ui-components/src/components/Container/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { Container } from "./Container.component" diff --git a/libs/juno-ui-components/src/components/ContentArea/ContentArea.component.js b/libs/juno-ui-components/src/components/ContentArea/ContentArea.component.js deleted file mode 100644 index 39b47c33a..000000000 --- a/libs/juno-ui-components/src/components/ContentArea/ContentArea.component.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" -import { withDeprecationWarning } from '../withDeprecationWarning/index.js' - -const containerStyles = ` - jn-bg-theme-content-area-bg - jn-relative - jn-grow -` - - - -/** - * Deprecated: This component used to be used internally by AppShell but has been removed there since. It was only needed to manually scaffold an app. Use AppShell to scaffold an app layout.. - */ -export const ContentArea = ({ className, children, ...props }) => { - - return ( - <div - className={`juno-content-area ${containerStyles} ${className}`} - {...props} - > - {children} - </div> - ) -} - -ContentArea.propTypes = { - /** Add custom class name */ - className: PropTypes.string, - children: PropTypes.node, -} - -ContentArea.defaultProps = { - className: "", - children: null, -} - -export default withDeprecationWarning(ContentArea, "ContentArea is deprecated and will be removed in future versions. To be future-proof, use AppShell to scaffold an app layout.") diff --git a/libs/juno-ui-components/src/components/ContentArea/ContentArea.stories.js b/libs/juno-ui-components/src/components/ContentArea/ContentArea.stories.js deleted file mode 100644 index 4bfb82b4a..000000000 --- a/libs/juno-ui-components/src/components/ContentArea/ContentArea.stories.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" - -import { ContentArea } from "./index.js" - -export default { - title: "Deprecated/ContentArea", - component: ContentArea, - argTypes: { - children: { - control: false - }, - }, -} - -const Template = (args) => ( - <ContentArea {...args}>Content goes here</ContentArea> -) - -export const Basic = Template.bind({}) -Basic.parameters = { - docs: { - description: { - story: - "Deprecated: This component used to be used internally by AppShell but has been removed there since. It was only needed to manually scaffold an app. Use AppShell to scaffold an app layout.", - }, - }, -} -Basic.args = {} diff --git a/libs/juno-ui-components/src/components/ContentArea/ContentArea.test.js b/libs/juno-ui-components/src/components/ContentArea/ContentArea.test.js deleted file mode 100644 index 062f5a9d9..000000000 --- a/libs/juno-ui-components/src/components/ContentArea/ContentArea.test.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { ContentArea } from "./index" - -describe("ContentArea", () => { - test("renders a content area", async () => { - render(<ContentArea data-testid="content-area" />) - expect(screen.getByTestId("content-area")).toBeInTheDocument() - expect(screen.getByTestId("content-area")).toHaveClass( - "juno-content-area" - ) - }) - - test("renders a deprecation warning to the console", async () => { - const consoleWarnSpy = jest.spyOn(console, 'warn') - render(<ContentArea/>) - expect(consoleWarnSpy).toHaveBeenCalled() - expect(consoleWarnSpy).toHaveBeenCalledWith( - "ContentArea is deprecated and will be removed in future versions. To be future-proof, use AppShell to scaffold an app layout." - ) - consoleWarnSpy.mockRestore() - }) - - test("renders a content area with content area background color", async () => { - render(<ContentArea data-testid="content-area" />) - expect(screen.getByTestId("content-area")).toBeInTheDocument() - expect(screen.getByTestId("content-area")).toHaveClass("jn-bg-theme-content-area-bg") - }) - - test("renders a content area with flex grow", async () => { - render(<ContentArea data-testid="content-area" />) - expect(screen.getByTestId("content-area")).toBeInTheDocument() - expect(screen.getByTestId("content-area")).toHaveClass("jn-grow") - }) - - test("renders children as passed", async () => { - render( - <ContentArea data-testid="content-area"> - <button></button> - </ContentArea> - ) - expect(screen.getByTestId("content-area")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render( - <ContentArea - data-testid="content-area" - className="my-custom-classname" - /> - ) - expect(screen.getByTestId("content-area")).toBeInTheDocument() - expect(screen.getByTestId("content-area")).toHaveClass( - "my-custom-classname" - ) - }) - - test("renders all props", async () => { - render( - <ContentArea data-testid="content-area" data-lolol="some-prop" /> - ) - expect(screen.getByTestId("content-area")).toBeInTheDocument() - expect(screen.getByTestId("content-area")).toHaveAttribute( - "data-lolol", - "some-prop" - ) - }) -}) diff --git a/libs/juno-ui-components/src/components/ContentArea/index.js b/libs/juno-ui-components/src/components/ContentArea/index.js deleted file mode 100644 index fc03983c3..000000000 --- a/libs/juno-ui-components/src/components/ContentArea/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { default as ContentArea } from "./ContentArea.component" diff --git a/libs/juno-ui-components/src/components/ContentAreaToolbar/ContentAreaToolbar.component.js b/libs/juno-ui-components/src/components/ContentAreaToolbar/ContentAreaToolbar.component.js deleted file mode 100644 index af3e0c15e..000000000 --- a/libs/juno-ui-components/src/components/ContentAreaToolbar/ContentAreaToolbar.component.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - - -const toolbarStyles = ` - jn-bg-theme-background-lvl-1 - jn-py-3 - jn-px-6 - jn-flex - jn-items-center - jn-justify-end -` - -/** - * This is the main toolbar of the content area. Add main actions for the current page here. - */ -export const ContentAreaToolbar = ({ - className, - children, - ...props -}) => { - return ( - <div - className={`juno-content-area-toolbar ${toolbarStyles} ${className}`} - {...props} - > - {children} - </div> - ) -} - -ContentAreaToolbar.propTypes = { - /** Add custom class name */ - className: PropTypes.string, - children: PropTypes.node, -} - -ContentAreaToolbar.defaultProps = { - className: "", - children: null, -} diff --git a/libs/juno-ui-components/src/components/ContentAreaToolbar/ContentAreaToolbar.stories.js b/libs/juno-ui-components/src/components/ContentAreaToolbar/ContentAreaToolbar.stories.js deleted file mode 100644 index 019c9f166..000000000 --- a/libs/juno-ui-components/src/components/ContentAreaToolbar/ContentAreaToolbar.stories.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; - -import { ContentAreaToolbar } from './index.js'; -import { Button } from '../Button/index.js'; - -export default { - title: 'Layout/ContentAreaToolbar', - component: ContentAreaToolbar, - argTypes: { - children: { - control: false, - }, - }, -}; - -const Template = (args) => ( - <ContentAreaToolbar {...args}> - <Button>Main Action</Button> - </ContentAreaToolbar> -); - -export const Basic = { - render: Template, - - parameters: { - docs: { - description: { - story: - 'This is the main toolbar of the content area. Add main actions, search bar, filters for the current page here.', - }, - }, - }, - - args: {}, -}; diff --git a/libs/juno-ui-components/src/components/ContentAreaToolbar/ContentAreaToolbar.test.js b/libs/juno-ui-components/src/components/ContentAreaToolbar/ContentAreaToolbar.test.js deleted file mode 100644 index 62b7c8985..000000000 --- a/libs/juno-ui-components/src/components/ContentAreaToolbar/ContentAreaToolbar.test.js +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { ContentAreaToolbar } from "./index" - -describe("ContentAreaToolbar", () => { - test("renders a content area toolbar", async () => { - render(<ContentAreaToolbar data-testid="content-area-toolbar" />) - expect(screen.getByTestId("content-area-toolbar")).toBeInTheDocument() - expect(screen.getByTestId("content-area-toolbar")).toHaveClass("juno-content-area-toolbar") - }) - - test("renders children as passed", async () => { - render( - <ContentAreaToolbar data-testid="content-area-toolbar"> - <button></button> - </ContentAreaToolbar> - ) - expect(screen.getByTestId("content-area-toolbar")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render( - <ContentAreaToolbar - data-testid="content-area-toolbar" - className="my-custom-classname" - /> - ) - expect(screen.getByTestId("content-area-toolbar")).toBeInTheDocument() - expect(screen.getByTestId("content-area-toolbar")).toHaveClass( - "my-custom-classname" - ) - }) - - test("renders all props", async () => { - render( - <ContentAreaToolbar data-testid="content-area-toolbar" data-lolol="some-prop" /> - ) - expect(screen.getByTestId("content-area-toolbar")).toBeInTheDocument() - expect(screen.getByTestId("content-area-toolbar")).toHaveAttribute( - "data-lolol", - "some-prop" - ) - }) -}) diff --git a/libs/juno-ui-components/src/components/ContentAreaToolbar/index.js b/libs/juno-ui-components/src/components/ContentAreaToolbar/index.js deleted file mode 100644 index 397f1281c..000000000 --- a/libs/juno-ui-components/src/components/ContentAreaToolbar/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { ContentAreaToolbar } from "./ContentAreaToolbar.component" diff --git a/libs/juno-ui-components/src/components/ContentAreaWrapper/ContentAreaWrapper.component.js b/libs/juno-ui-components/src/components/ContentAreaWrapper/ContentAreaWrapper.component.js deleted file mode 100644 index 6d6223c81..000000000 --- a/libs/juno-ui-components/src/components/ContentAreaWrapper/ContentAreaWrapper.component.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -const containerStyles = ` - jn-relative - jn-grow - jn-flex - jn-flex-col - jn-overflow-hidden -` - -/** - * OBSOLETE: Will be deleted! - */ -export const ContentAreaWrapper = ({ className, children, ...props }) => { - return ( - <div - className={`juno-content-area-wrapper ${containerStyles} ${className}`} - {...props} - > - {children} - </div> - ) -} - -ContentAreaWrapper.propTypes = { - /** Add custom class name */ - className: PropTypes.string, - children: PropTypes.node, -} - -ContentAreaWrapper.defaultProps = { - className: "", - children: null, -} diff --git a/libs/juno-ui-components/src/components/ContentAreaWrapper/ContentAreaWrapper.stories.js b/libs/juno-ui-components/src/components/ContentAreaWrapper/ContentAreaWrapper.stories.js deleted file mode 100644 index 991253549..000000000 --- a/libs/juno-ui-components/src/components/ContentAreaWrapper/ContentAreaWrapper.stories.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; - -import { ContentAreaWrapper } from './index.js'; -import { ContentArea } from '../ContentArea/index.js'; -import { ContentAreaToolbar } from '../ContentAreaToolbar/index.js'; -import { Button } from '../Button/index.js'; - -export default { - title: 'Internal/ContentAreaWrapper', - component: ContentAreaWrapper, - argTypes: { - children: { - control: false, - }, - }, -}; - -const Template = (args) => ( - <ContentAreaWrapper {...args}> - <ContentAreaToolbar> - <Button>Example</Button> - </ContentAreaToolbar> - <ContentArea>Content goes here</ContentArea> - </ContentAreaWrapper> -); - -export const Basic = { - render: Template, - - parameters: { - docs: { - description: { - story: 'OBSOLETE: Will be deleted!', - }, - }, - }, - - args: {}, -}; diff --git a/libs/juno-ui-components/src/components/ContentAreaWrapper/ContentAreaWrapper.test.js b/libs/juno-ui-components/src/components/ContentAreaWrapper/ContentAreaWrapper.test.js deleted file mode 100644 index 135829aef..000000000 --- a/libs/juno-ui-components/src/components/ContentAreaWrapper/ContentAreaWrapper.test.js +++ /dev/null @@ -1,62 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { ContentAreaWrapper } from "./index" - -describe("ContentAreaWrapper", () => { - test("renders a content area wrapper", async () => { - render(<ContentAreaWrapper data-testid="content-area-wrapper" />) - expect(screen.getByTestId("content-area-wrapper")).toBeInTheDocument() - expect(screen.getByTestId("content-area-wrapper")).toHaveClass("juno-content-area-wrapper") - }) - - test("renders a content area with flex grow", async () => { - render(<ContentAreaWrapper data-testid="content-area-wrapper" />) - expect(screen.getByTestId("content-area-wrapper")).toBeInTheDocument() - expect(screen.getByTestId("content-area-wrapper")).toHaveClass("jn-grow") - }) - - test("renders a content area with flex col layout", async () => { - render(<ContentAreaWrapper data-testid="content-area-wrapper" />) - expect(screen.getByTestId("content-area-wrapper")).toBeInTheDocument() - expect(screen.getByTestId("content-area-wrapper")).toHaveClass("jn-flex-col") - }) - - test("renders children as passed", async () => { - render( - <ContentAreaWrapper data-testid="content-area-wrapper"> - <button></button> - </ContentAreaWrapper> - ) - expect(screen.getByTestId("content-area-wrapper")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render( - <ContentAreaWrapper - data-testid="content-area-wrapper" - className="my-custom-classname" - /> - ) - expect(screen.getByTestId("content-area-wrapper")).toBeInTheDocument() - expect(screen.getByTestId("content-area-wrapper")).toHaveClass( - "my-custom-classname" - ) - }) - - test("renders all props", async () => { - render( - <ContentAreaWrapper data-testid="content-area-wrapper" data-lolol="some-prop" /> - ) - expect(screen.getByTestId("content-area-wrapper")).toBeInTheDocument() - expect(screen.getByTestId("content-area-wrapper")).toHaveAttribute( - "data-lolol", - "some-prop" - ) - }) -}) diff --git a/libs/juno-ui-components/src/components/ContentAreaWrapper/index.js b/libs/juno-ui-components/src/components/ContentAreaWrapper/index.js deleted file mode 100644 index 2e4f46d4d..000000000 --- a/libs/juno-ui-components/src/components/ContentAreaWrapper/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { ContentAreaWrapper } from "./ContentAreaWrapper.component" diff --git a/libs/juno-ui-components/src/components/ContentContainer/ContentContainer.component.js b/libs/juno-ui-components/src/components/ContentContainer/ContentContainer.component.js deleted file mode 100644 index 09f1ffbb6..000000000 --- a/libs/juno-ui-components/src/components/ContentContainer/ContentContainer.component.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - - -const containerStyles = ` - jn-flex-col - jn-grow - jn-bg-[right_top_1rem] - jn-bg-no-repeat - jn-bg-theme-content-area-bg - jn-relative -` - -/** - * Only needed if you want to build your app's scaffold manually. In most cases it is better to use the AppShell component instead. - * A container for app content. Will be centered on the screen when browser window is wider than the max breakpoint width. - */ -export const ContentContainer = ({ className, children, ...props }) => { - return ( - <div className={`juno-content-container ${containerStyles} ${className}`} {...props}> - {children} - </div> - ) -} - -ContentContainer.propTypes = { - /** Add custom class name */ - className: PropTypes.string, - children: PropTypes.node, -} - -ContentContainer.defaultProps = { - className: "", - children: null, -} diff --git a/libs/juno-ui-components/src/components/ContentContainer/ContentContainer.stories.js b/libs/juno-ui-components/src/components/ContentContainer/ContentContainer.stories.js deleted file mode 100644 index 339c1c501..000000000 --- a/libs/juno-ui-components/src/components/ContentContainer/ContentContainer.stories.js +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; - -import { ContentContainer } from './index.js'; - -export default { - title: 'Internal/ContentContainer', - component: ContentContainer, - argTypes: { - children: { - control: false, - }, - }, -}; - -const Template = (args) => <ContentContainer {...args}>content</ContentContainer>; - -export const Centered = { - render: Template, - - parameters: { - docs: { - description: { - story: - "Only needed if you want to build your app's scaffold manually. In most cases it is better to use the AppShell component instead. A wrapper for content components. Parent of ContentArea. Width will grow to the maximum breakpoint width and then be centered on the page if the browser is wider.", - }, - }, - }, - - args: {}, -}; diff --git a/libs/juno-ui-components/src/components/ContentContainer/ContentContainer.test.js b/libs/juno-ui-components/src/components/ContentContainer/ContentContainer.test.js deleted file mode 100644 index 70464ae7e..000000000 --- a/libs/juno-ui-components/src/components/ContentContainer/ContentContainer.test.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { ContentContainer } from "./index" - -describe("ContentContainer", () => { - test("renders a content container", async () => { - render(<ContentContainer data-testid="content-container" />) - expect(screen.getByTestId("content-container")).toBeInTheDocument() - expect(screen.getByTestId("content-container")).toHaveClass("juno-content-container") - }) - - test("renders a content container with flex col layout", async () => { - render(<ContentContainer data-testid="content-container" />) - expect(screen.getByTestId("content-container")).toBeInTheDocument() - expect(screen.getByTestId("content-container")).toHaveClass("jn-flex-col") - }) - - test("renders a content container with flex grow", async () => { - render(<ContentContainer data-testid="content-container" />) - expect(screen.getByTestId("content-container")).toBeInTheDocument() - expect(screen.getByTestId("content-container")).toHaveClass("jn-grow") - }) - - test("renders children as passed", async () => { - render( - <ContentContainer data-testid="content-container" > - <button></button> - </ContentContainer> - ) - expect(screen.getByTestId("content-container")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<ContentContainer data-testid="content-container" className="my-custom-classname" />) - expect(screen.getByTestId("content-container")).toBeInTheDocument() - expect(screen.getByTestId("content-container")).toHaveClass("my-custom-classname") - }) - - test("renders all props", async () => { - render(<ContentContainer data-testid="content-container" data-lolol="some-prop" />) - expect(screen.getByTestId("content-container")).toBeInTheDocument() - expect(screen.getByTestId("content-container")).toHaveAttribute("data-lolol", "some-prop") - }) - -}) diff --git a/libs/juno-ui-components/src/components/ContentContainer/index.js b/libs/juno-ui-components/src/components/ContentContainer/index.js deleted file mode 100644 index e77f3a250..000000000 --- a/libs/juno-ui-components/src/components/ContentContainer/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { ContentContainer } from "./ContentContainer.component" diff --git a/libs/juno-ui-components/src/components/ContentHeading/ContentHeading.component.js b/libs/juno-ui-components/src/components/ContentHeading/ContentHeading.component.js deleted file mode 100644 index cac169d32..000000000 --- a/libs/juno-ui-components/src/components/ContentHeading/ContentHeading.component.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -const headingStyles = ` - jn-font-bold - jn-text-lg - jn-text-theme-high - jn-pb-2 -` - -/** - - *The main heading of a page/View. Pass as a child into `<AppShell>` or, when scaffolding manually, into `<ContentContainer>`. - */ -export const ContentHeading = ({ heading, className, children, ...props }) => { - return ( - <h1 - className={`juno-content-heading ${headingStyles} ${className}`} - {...props} - > - {children || heading} - </h1> - ) -} - -ContentHeading.propTypes = { - /** Optionally render children. If children are present, heading will be ignored */ - children: PropTypes.node, - /** Text to use as a title */ - heading: PropTypes.string, - /** Add custom class name */ - className: PropTypes.string, -} - -ContentHeading.defaultProps = { - heading: "", - className: "", - children: null, -} diff --git a/libs/juno-ui-components/src/components/ContentHeading/ContentHeading.stories.js b/libs/juno-ui-components/src/components/ContentHeading/ContentHeading.stories.js deleted file mode 100644 index aed32bf77..000000000 --- a/libs/juno-ui-components/src/components/ContentHeading/ContentHeading.stories.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import { ContentHeading } from "./index.js" -import { Button } from "../Button/index.js" - -export default { - title: "Internal/ContentHeading", - component: ContentHeading, - argTypes: { - children: { - control: false - }, - }, -} - -const Template = (args) => <ContentHeading {...args} /> - -export const Default = Template.bind({}) -Default.parameters = { - docs: { - description: { - story: - "The the main heading of the content area of a page/view.", - }, - }, -} -Default.args = { - heading: "My Page Heading", -} diff --git a/libs/juno-ui-components/src/components/ContentHeading/ContentHeading.test.js b/libs/juno-ui-components/src/components/ContentHeading/ContentHeading.test.js deleted file mode 100644 index 63b77c3ef..000000000 --- a/libs/juno-ui-components/src/components/ContentHeading/ContentHeading.test.js +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { ContentHeading } from "./index" - -describe("ContentHeading", () => { - test("renders a content heading", async () => { - render(<ContentHeading heading="My Heading" />) - expect(screen.getByRole("heading")).toBeInTheDocument() - expect(screen.getByRole("heading")).toHaveClass( - "juno-content-heading" - ) - }) - - test("renders a content heading with the given text", async () => { - render(<ContentHeading heading="My Heading" />) - expect(screen.getByRole("heading")).toHaveTextContent("My Heading") - }) - - test("renders children as passed", async () => { - render( - <ContentHeading > - <button></button> - </ContentHeading> - ) - expect(screen.getByRole("heading")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render( - <ContentHeading - className="my-custom-classname" - /> - ) - expect(screen.getByRole("heading")).toBeInTheDocument() - expect(screen.getByRole("heading")).toHaveClass( - "my-custom-classname" - ) - }) - - test("renders all props", async () => { - render( - <ContentHeading - data-lolol="some-prop" - /> - ) - expect(screen.getByRole("heading")).toBeInTheDocument() - expect(screen.getByRole("heading")).toHaveAttribute( - "data-lolol", - "some-prop" - ) - }) -}) diff --git a/libs/juno-ui-components/src/components/ContentHeading/index.js b/libs/juno-ui-components/src/components/ContentHeading/index.js deleted file mode 100644 index ded12626d..000000000 --- a/libs/juno-ui-components/src/components/ContentHeading/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { ContentHeading } from "./ContentHeading.component" diff --git a/libs/juno-ui-components/src/components/ContextMenu/ContextMenu.component.js b/libs/juno-ui-components/src/components/ContextMenu/ContextMenu.component.js deleted file mode 100644 index 24c514429..000000000 --- a/libs/juno-ui-components/src/components/ContextMenu/ContextMenu.component.js +++ /dev/null @@ -1,94 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useState, useEffect } from "react" -import PropTypes from "prop-types" -import { Icon } from "../Icon/index.js" -import { Menu } from "@headlessui/react" -import { Float } from "@headlessui-float/react" - -/* -TODO: - -* close on [ESC] (prop?) -* close on click outside (prop?) -* keyboard navigation: arrow up/down moves focus -* for toggle styles (hover, active, etc.) -> expand icon (interactive) component or handle here (aka are these styles generically useful or specific to this component?) -* a11y -* docstrings -* fix stories -* don't ALWAYS render button!?! -*/ - -const menuStyles = ` - jn-overflow-hidden - jn-flex - jn-flex-col - jn-rounded - jn-bg-theme-background-lvl-1 -` - -const toggleStyles = ` - hover:jn-text-theme-accent - active:jn-text-theme-accent -` - -const toggleOpenStyle = ` - jn-text-theme-accent -` - -/** A context menu with a toggle. */ - -export const ContextMenu = ({ - icon, - className, - children, - open, - ...props -}) => { - const [isOpen, setIsOpen] = useState(false) - - const handleClick = (event) => { - setIsOpen(!isOpen) - } - - useEffect(() => { - setIsOpen(open) - }, [open]) - - return ( - <Menu> - <Float> - <Menu.Button - onClick={handleClick} - className={` - juno-contextmenu-toggle - ${toggleStyles} - ${ isOpen ? toggleOpenStyle : "" } - `}> - <Icon icon="moreVert"/> - </Menu.Button> - <Menu.Items - className={`${menuStyles}`} - > - {children} - </Menu.Items> - </Float> - </Menu> - ) -} - - -ContextMenu.propTypes = { - className: PropTypes.string, - children: PropTypes.node, - open: PropTypes.bool, -} - -ContextMenu.defaultProps = { - className: "", - children: null, - open: false, -} diff --git a/libs/juno-ui-components/src/components/ContextMenu/ContextMenu.stories.js b/libs/juno-ui-components/src/components/ContextMenu/ContextMenu.stories.js deleted file mode 100644 index de8c3e6aa..000000000 --- a/libs/juno-ui-components/src/components/ContextMenu/ContextMenu.stories.js +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import { ContextMenu } from "./index.js" -import { MenuItem } from "../MenuItem/MenuItem.component" -import { Button } from "../Button/index" -import { PortalProvider } from "../PortalProvider/PortalProvider.component" - -export default { - title: "WiP/ContextMenu/ContextMenu", - component: ContextMenu, - argTypes: { - children: { - control: false, - }, - }, -} - -const Template = ({ children, ...args }) => ( - <ContextMenu {...args}>{children}</ContextMenu> -) - -const PortalTemplate = ({ children, ...args }) => ( - <PortalProvider> - <PortalProvider.Portal> - <ContextMenu {...args}>{children}</ContextMenu> - </PortalProvider.Portal> - </PortalProvider> -) - -export const Default = { - render: Template, - - args: { - children: [ - <MenuItem - key="1" - label="Juno on Github" - href="https://github.com/sapcc/juno" - />, - <MenuItem key="2" label="This item does nothing" icon="help" />, - <MenuItem - key="3" - label="Disabled Item" - href="https://github.com/sapcc/juno" - disabled - />, - <MenuItem key="4"> - <Button - key={0} - label="Button as Child of MenuItem" - variant="subdued" - size="small" - className="jn-w-full" - /> - </MenuItem>, - <MenuItem - key="5" - onClick={() => {}} - label="Button as Item with OnClick" - icon="help" - />, - ], - }, -} - -export const InsidePortal = { - render: PortalTemplate, - - args: { - children: [ - <MenuItem - key="1" - label="Juno on Github" - href="https://github.com/sapcc/juno" - />, - <MenuItem key="2" label="This item does nothing" />, - <MenuItem - key="3" - label="Disabled Item" - href="https://github.com/sapcc/juno" - disabled - />, - <MenuItem key="4"> - <Button - key={0} - label="Button as Child of MenuItem" - variant="subdued" - size="small" - className="jn-w-full" - /> - </MenuItem>, - ], - }, -} diff --git a/libs/juno-ui-components/src/components/ContextMenu/ContextMenu.test.js b/libs/juno-ui-components/src/components/ContextMenu/ContextMenu.test.js deleted file mode 100644 index 9748c2719..000000000 --- a/libs/juno-ui-components/src/components/ContextMenu/ContextMenu.test.js +++ /dev/null @@ -1,28 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import userEvent from "@testing-library/user-event" -import { ContextMenu } from "./index.js" - -describe("ContextMenu", () => { - test("renders a ContextMenu Toggle", async () => { - render(<ContextMenu />) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveClass("juno-contextmenu-toggle") - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("title", "More") - }) - - test("toggles Context Menu on click", async () => { - render(<ContextMenu />) - expect(screen.queryByRole("menu")).not.toBeInTheDocument() - await userEvent.click(screen.getByRole("button")) - expect(screen.getByRole("menu")).toBeInTheDocument() - await userEvent.click(screen.getByRole("button")) - expect(screen.queryByRole("menu")).not.toBeInTheDocument() - }) -}) diff --git a/libs/juno-ui-components/src/components/ContextMenu/index.js b/libs/juno-ui-components/src/components/ContextMenu/index.js deleted file mode 100644 index 61bc91401..000000000 --- a/libs/juno-ui-components/src/components/ContextMenu/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { ContextMenu } from "./ContextMenu.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGrid/DataGrid.component.js b/libs/juno-ui-components/src/components/DataGrid/DataGrid.component.js deleted file mode 100644 index d3f5f8936..000000000 --- a/libs/juno-ui-components/src/components/DataGrid/DataGrid.component.js +++ /dev/null @@ -1,105 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useState, useEffect } from "react" -import PropTypes from "prop-types" - -const dataGridStyles = ` - jn-grid - jn-items-stretch -` - -const gridTemplate = (columns, columnMaxSize, columnMinSize, minContentColumns, gridColumnTemplate) => { - let styles - - // gridColumnTemplate was passed. Return it and ignore all other settings - if (gridColumnTemplate && gridColumnTemplate.length > 0) { - styles = { gridTemplateColumns: gridColumnTemplate } - return styles - } - - let generatedTemplate = "" - // if a configuration for min-content columns has been passed iteratively generate the gridTemplateColumn sizes, - // else generate a simpler statement using the repeat function - if ( minContentColumns && Array.isArray(minContentColumns) && minContentColumns.length > 0 ) { - // for each configured column check if it should have normal or min-content sizing and add the respective string to the template string - [...Array(columns)].map((_, i) => { - generatedTemplate += minContentColumns.includes(i) ? 'min-content ' : `minmax(${columnMinSize}, ${columnMaxSize}) ` - }) - } else { - generatedTemplate = `repeat(${columns}, minmax(${columnMinSize}, ${columnMaxSize}))` - } - - styles = { gridTemplateColumns: generatedTemplate } - return styles -} - -const DataGridContext = React.createContext() - -export const useDataGridContext = () => React.useContext(DataGridContext) - -// TODO: allow for passing in props addItems, addItemsLabel, search, etc.: -/** The DataGrid component is the main way to display lists of items that have a bunch of metadata that you want to display. - */ -export const DataGrid = ({ - columns, - columnMaxSize, - columnMinSize, - minContentColumns, - gridColumnTemplate, - cellVerticalAlignment, - className, - children, - ...props -}) => { - const dataGridConf = { - cellVerticalAlignment: cellVerticalAlignment - // selectable: selectable - } - return ( - <DataGridContext.Provider value={dataGridConf}> - <div - className={`juno-datagrid ${dataGridStyles} ${className}`} - style={gridTemplate(columns, columnMaxSize, columnMinSize, minContentColumns, gridColumnTemplate)} - role="grid" - {...props} > - {children} - </div> - </DataGridContext.Provider> - ) -} - -DataGrid.propTypes = { - /** Set number of columns */ - columns: PropTypes.number, - /** Set column max sizing. Default: auto. For equally sized columns use "1fr" */ - columnMaxSize: PropTypes.string, - /** Set column minimum size. Default: 0px */ - columnMinSize: PropTypes.string, - /** Specify which columns should be sized by minimum content size (i.e. as small as possible). Pass an array of column numbers (first column is 0) */ - minContentColumns: PropTypes.arrayOf(PropTypes.number), - /** Set the grid column template in CSS grid 'grid-template-columns' notation. If this prop is passed, all other template props (columns, columnMaxSize, - * columnMinSize, minContentColumns) are ignored. The easiest case where you might need this is e.g. if you want to set specific column widths for some - * or all columns, e.g. "20% auto auto 10%" (The first column is set to 20%, the next two to auto size, the last to 10%). */ - gridColumnTemplate: PropTypes.string, - /** Set the vertical alignment for all GridCells. Default: center. PLEASE NOTE: the center alignment is achieved by using a flexbox column layout, - * which means that all child elements of the cell will be stacked vertically. To avoid this, wrap the elements in their own div */ - cellVerticalAlignment: PropTypes.oneOf(["center", "top"]), - /** Children to render in the DataGrid */ - children: PropTypes.node, - /** Add a class name */ - className: PropTypes.string, -} - -DataGrid.defaultProps = { - columns: 1, - columnMaxSize: "auto", - columnMinSize: "0px", - minContentColumns: undefined, - gridColumnTemplate: undefined, - cellVerticalAlignment: "center", - className: "", - children: null, -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGrid/DataGrid.stories.js b/libs/juno-ui-components/src/components/DataGrid/DataGrid.stories.js deleted file mode 100644 index 17d7dd1e2..000000000 --- a/libs/juno-ui-components/src/components/DataGrid/DataGrid.stories.js +++ /dev/null @@ -1,242 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { DataGrid } from './index.js'; -import { DataGridRow } from '../DataGridRow/index.js'; -import { DataGridCell } from '../DataGridCell/index.js'; -// import { DataGridCheckboxCell } from "../DataGridCheckboxCell/index.js" -import { DataGridHeadCell } from '../DataGridHeadCell/index.js'; -import { ContentArea } from '../ContentArea/index.js'; -import { Container } from '../Container/index.js'; -import { PreseletedWithSearch as FiltersStory } from '../Filters/Filters.stories'; -import { Filters } from '../Filters/index.js'; -import { DataGridToolbar } from '../DataGridToolbar/index.js'; -import { Default as DataGridToolbarStory } from '../DataGridToolbar/DataGridToolbar.stories'; -import { Button } from '../Button/index.js'; - -export default { - title: 'Components/DataGrid/DataGrid', - component: DataGrid, - argTypes: { - children: { - control: false, - }, - }, -}; - -const defaultColumns = 3; - -const Template = ({ hideHead, includeColSpanRow, withToolbar, withFilters, ...args }) => ( - <> - {withFilters && <Filters {...FiltersStory.args}></Filters>} - {withToolbar && ( - <DataGridToolbar {...DataGridToolbarStory.args}> - <Button variant="primary">Add new</Button> - </DataGridToolbar> - )} - <DataGrid {...args}> - {!hideHead && ( - <DataGridRow> - {[...Array(args.columns || defaultColumns)].map((_, c) => ( - <DataGridHeadCell key={`h_${c}`}>{`Head cell ${c}`}</DataGridHeadCell> - ))} - </DataGridRow> - )} - {!includeColSpanRow && - [...Array(4)].map((_, r) => ( - <DataGridRow key={`b_${r}`}> - {[...Array(args.columns || defaultColumns)].map((_, c) => ( - <DataGridCell key={`b_${r}_${c}`}> - {c === args.columns - 2 - ? `Cell ${r}-${c} has more content than others` - : `Cell ${r}-${c}`} - </DataGridCell> - ))} - </DataGridRow> - ))} - {includeColSpanRow && ( - <DataGridRow> - <DataGridCell colSpan={args.columns}> - This is a cell with colspan spanning all available columns - </DataGridCell> - </DataGridRow> - )} - </DataGrid> - </> -); - -export const Default = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Juno DataGrid for displaying data. Example with 5 columns.', - }, - }, - }, - - args: { - columns: 5, - }, -}; - -export const EqualColumnSize = { - render: Template, - - parameters: { - docs: { - description: { - story: - "Example: change column max size to '1fr'. This ensures that all columns get the same width, even if some columns have more content than others", - }, - }, - }, - - args: { - columns: 5, - columnMaxSize: '1fr', - }, -}; - -export const ColumnMinSize = { - render: Template, - - parameters: { - docs: { - description: { - story: - "Example: set a minimum width for columns. Columns will always be at least this wide, even if they have very little content. This may cause horizontal scrollbars if the DataGrid doesn't fit into the container anymore", - }, - }, - }, - - args: { - columns: 5, - columnMinSize: '300px', - }, -}; - -export const MinimumSizedColumns = { - render: Template, - - parameters: { - docs: { - description: { - story: - 'Example: specify some columns that should be as small as possible (typically used for when you have a cell that contains only a button and you want to ensure the cell is only exactly as wide as the button', - }, - }, - }, - - args: { - columns: 5, - minContentColumns: [0, 4], - }, -}; - -export const CustomGridTemplate = { - render: Template, - - parameters: { - docs: { - description: { - story: - "Example: specify a completely custom css grid column template. The value passed is used for the css 'grid-template-columns' property. All other settings are ignored", - }, - }, - }, - - args: { - gridColumnTemplate: `20% repeat(${defaultColumns - 1}, auto)`, - }, -}; - -export const NoHead = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Without head cells', - }, - }, - }, - - args: { - columns: 5, - hideHead: true, - }, -}; - -export const ColSpanCell = { - render: Template, - - parameters: { - docs: { - description: { - story: 'With a col span cell', - }, - }, - }, - - args: { - columns: 5, - includeColSpanRow: true, - }, -}; - -export const WithToolbar = { - render: Template, - - parameters: { - docs: { - description: { - story: 'With toolbar', - }, - }, - }, - - args: { - columns: 5, - withToolbar: true, - }, -}; - -export const WithFilters = { - render: Template, - - parameters: { - docs: { - description: { - story: 'With filters', - }, - }, - }, - - args: { - columns: 5, - withFilters: true, - }, -}; - -export const WithToolbarAndFilters = { - render: Template, - - parameters: { - docs: { - description: { - story: 'With toolbar and filters', - }, - }, - }, - - args: { - columns: 5, - withFilters: true, - withToolbar: true, - }, -}; diff --git a/libs/juno-ui-components/src/components/DataGrid/DataGrid.test.js b/libs/juno-ui-components/src/components/DataGrid/DataGrid.test.js deleted file mode 100644 index acb42f929..000000000 --- a/libs/juno-ui-components/src/components/DataGrid/DataGrid.test.js +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { DataGrid } from "./index" - -describe("DataGrid", () => { - - test("renders a DataGrid", async () => { - render(<DataGrid />) - expect(screen.getByRole("grid")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<DataGrid className="my-custom-class"/>) - expect(screen.getByRole("grid")).toBeInTheDocument() - expect(screen.getByRole("grid")).toHaveClass("my-custom-class") - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGrid/index.js b/libs/juno-ui-components/src/components/DataGrid/index.js deleted file mode 100644 index f4cdec996..000000000 --- a/libs/juno-ui-components/src/components/DataGrid/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { DataGrid } from "./DataGrid.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGridCell/DataGridCell.component.js b/libs/juno-ui-components/src/components/DataGridCell/DataGridCell.component.js deleted file mode 100644 index 8152cd3a7..000000000 --- a/libs/juno-ui-components/src/components/DataGridCell/DataGridCell.component.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { forwardRef } from "react" -import PropTypes from "prop-types" - -import { useDataGridContext } from "../DataGrid/DataGrid.component.js" - -const cellBaseStyles = (nowrap, cellVerticalAlignment) => { - return ` - ${nowrap ? "jn-whitespace-nowrap" : ""} - ${ - cellVerticalAlignment === "center" - ? ` - jn-justify-center - jn-flex - jn-flex-col - ` - : "" - } - jn-px-5 - jn-py-3 - jn-border-b - jn-border-theme-background-lvl-2 - jn-h-full - ` -} - -const cellCustomStyles = (colSpan) => { - let styles - if (colSpan) { - styles = { gridColumn: `span ${colSpan} / span ${colSpan}` } - } - return styles -} - -export const DataGridCell = forwardRef( - ({ colSpan, nowrap, className, children, ...props }, ref) => { - const dataGridContext = useDataGridContext() || {} - const cellVerticalAlignment = dataGridContext.cellVerticalAlignment - - return ( - <div - className={`juno-datagrid-cell ${cellBaseStyles( - nowrap, - cellVerticalAlignment - )} ${className}`} - style={cellCustomStyles(colSpan)} - role="gridcell" - ref={ref} - {...props} - > - {children} - </div> - ) - } -) - -DataGridCell.propTypes = { - /** Add a col span to the cell. This works like a colspan in a normal html table, so you have to take care not to place too many cells in a row if some of them have a colspan. */ - colSpan: PropTypes.number, - /** Set nowrap to true if the cell content shouldn't wrap (this is achieved by adding white-space: nowrap;) */ - nowrap: PropTypes.bool, - /** Children to render in the DataGridCell */ - children: PropTypes.node, - /** Add a classname */ - className: PropTypes.string, -} - -DataGridCell.defaultProps = { - colSpan: undefined, - nowrap: false, - className: "", - children: null, -} diff --git a/libs/juno-ui-components/src/components/DataGridCell/DataGridCell.stories.js b/libs/juno-ui-components/src/components/DataGridCell/DataGridCell.stories.js deleted file mode 100644 index a7702edbe..000000000 --- a/libs/juno-ui-components/src/components/DataGridCell/DataGridCell.stories.js +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { DataGrid } from '../DataGrid/index.js'; -import { DataGridRow } from '../DataGridRow/index.js'; -import { DataGridCell } from './index.js'; - -export default { - title: 'Components/DataGrid/DataGridCell', - component: DataGridCell, - argTypes: { - children: { - control: false, - }, - }, - decorators: [ - (story) => ( - <DataGrid columns={3}> - <DataGridRow>{story()}</DataGridRow> - </DataGrid> - ), - ], - parameters: { - docs: { - source: { - excludeDecorators: false, - }, - }, - }, -}; - -const Template = (args) => <DataGridCell {...args}></DataGridCell>; - -export const Default = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Juno DataGridCell for use in DataGrid', - }, - }, - }, - - args: { - children: ['DataGridCell'], - }, -}; - -export const NoWrap = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Juno DataGridCell with nowrap option (content has white-space: nowrap;)', - }, - }, - }, - - args: { - nowrap: true, - children: ['DataGridCell does not wrap'], - }, -}; - -export const ColSpan = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Juno DataGridCell with colspan', - }, - }, - }, - - args: { - colSpan: 3, - children: ['DataGridCell with colspan'], - }, -}; diff --git a/libs/juno-ui-components/src/components/DataGridCell/DataGridCell.test.js b/libs/juno-ui-components/src/components/DataGridCell/DataGridCell.test.js deleted file mode 100644 index 026a62b3e..000000000 --- a/libs/juno-ui-components/src/components/DataGridCell/DataGridCell.test.js +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { DataGridCell } from "./index" - -describe("DataGridCell", () => { - - test("renders a DataGridCell", async () => { - render(<DataGridCell />) - expect(screen.getByRole("gridcell")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<DataGridCell className="my-custom-class"/>) - expect(screen.getByRole("gridcell")).toBeInTheDocument() - expect(screen.getByRole("gridcell")).toHaveClass("my-custom-class") - }) - - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGridCell/index.js b/libs/juno-ui-components/src/components/DataGridCell/index.js deleted file mode 100644 index 5ffb934c2..000000000 --- a/libs/juno-ui-components/src/components/DataGridCell/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { DataGridCell } from "./DataGridCell.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGridCheckboxCell/DataGridCheckboxCell.component.js b/libs/juno-ui-components/src/components/DataGridCheckboxCell/DataGridCheckboxCell.component.js deleted file mode 100644 index 099e8c1fa..000000000 --- a/libs/juno-ui-components/src/components/DataGridCheckboxCell/DataGridCheckboxCell.component.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" -import { Checkbox } from "../Checkbox/Checkbox.component.js" -import { DataGridCell } from "../DataGridCell/DataGridCell.component.js" - -export const DataGridCheckboxCell = ({ - selected, - disabled, - className, - onChange, - ...props -}) => { - return ( - <DataGridCell className={`juno-datagrid-checkbox-cell ${className}`} {...props}> - <Checkbox disabled={disabled} checked={selected} onChange={onChange} /> - </DataGridCell> - ) -} - -DataGridCheckboxCell.propTypes = { - /** Whether the row this cell belongs to is selected */ - selected: PropTypes.bool, - /** Whether the item is disabled */ - disabled: PropTypes.bool, - /** Add a classname to the cell */ - className: PropTypes.string, - /** Handler to change the selected state of the row */ - onChange: PropTypes.func, -} - -DataGridCheckboxCell.defaultProps = { - selected: false, - disabled: false, - className: "", - onChange: undefined, -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGridCheckboxCell/DataGridCheckboxCell.stories.js b/libs/juno-ui-components/src/components/DataGridCheckboxCell/DataGridCheckboxCell.stories.js deleted file mode 100644 index aadeab1db..000000000 --- a/libs/juno-ui-components/src/components/DataGridCheckboxCell/DataGridCheckboxCell.stories.js +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { DataGrid } from '../DataGrid/index.js'; -import { DataGridRow } from '../DataGridRow/index.js'; -import { DataGridCheckboxCell } from './index.js'; - -export default { - title: 'WiP/DataGrid/DataGridCheckboxCell', - component: DataGridCheckboxCell, - argTypes: { - children: { - control: false, - }, - }, - decorators: [ - (story) => ( - <DataGrid columns={3}> - <DataGridRow>{story()}</DataGridRow> - </DataGrid> - ), - ], - parameters: { - docs: { - source: { - excludeDecorators: false, - }, - }, - }, -}; - -const Template = (args) => <DataGridCheckboxCell {...args}></DataGridCheckboxCell>; - -export const Default = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Juno DataGridCheckboxCell for use in DataGrid', - }, - }, - }, - - args: {}, -}; - -export const Disabled = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Disabled Juno DataGridCheckboxCell for use in DataGrid', - }, - }, - }, - - args: { - disabled: true, - }, -}; diff --git a/libs/juno-ui-components/src/components/DataGridCheckboxCell/DataGridCheckboxCell.test.js b/libs/juno-ui-components/src/components/DataGridCheckboxCell/DataGridCheckboxCell.test.js deleted file mode 100644 index 88b33bc60..000000000 --- a/libs/juno-ui-components/src/components/DataGridCheckboxCell/DataGridCheckboxCell.test.js +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { DataGridCheckboxCell } from "./index" - -describe("DataGridCheckboxCell", () => { - - // test("renders a DataGridCheckboxCell containing a checkbox", async () => { - // const tablerow = document.createElement('tr') - // const {container} = render(<DataGridCheckboxCell data-testid="my-datagridcell" />, - // { container: document.body.appendChild(tablerow)}) - // expect(screen.getByTestId("my-datagridcell")).toBeInTheDocument() - // expect(screen.getByRole('checkbox')).toBeInTheDocument() - // }) - - // test("renders a DataGridCheckboxCell containing a checked checkbox if passed", async () => { - // const tablerow = document.createElement('tr') - // const {container} = render(<DataGridCheckboxCell data-testid="my-datagridcell" selected />, - // { container: document.body.appendChild(tablerow)}) - // expect(screen.getByRole('checkbox')).toBeInTheDocument() - // expect(screen.getByRole('checkbox')).toBeChecked() - // }) - - test("renders a DataGridCheckboxCell", async () => { - render(<DataGridCheckboxCell />) - expect(screen.getByRole("gridcell")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<DataGridCheckboxCell className="my-custom-class"/>) - expect(screen.getByRole("gridcell")).toBeInTheDocument() - expect(screen.getByRole("gridcell")).toHaveClass("my-custom-class") - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGridCheckboxCell/index.js b/libs/juno-ui-components/src/components/DataGridCheckboxCell/index.js deleted file mode 100644 index b1339882a..000000000 --- a/libs/juno-ui-components/src/components/DataGridCheckboxCell/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { DataGridCheckboxCell } from "./DataGridCheckboxCell.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGridFoot/DataGridFoot.component.js b/libs/juno-ui-components/src/components/DataGridFoot/DataGridFoot.component.js deleted file mode 100644 index c48f1e3f6..000000000 --- a/libs/juno-ui-components/src/components/DataGridFoot/DataGridFoot.component.js +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -export const DataGridFoot = ({ - className, - children, - ...props -}) => { - return ( - <tfoot className={`juno-datagrid-foot ${className}`} {...props}> - {children} - </tfoot> - ) -} - -DataGridFoot.propTypes = { - /** Children to render in the DataGridFoot */ - children: PropTypes.node, - /** Add a classname */ - className: PropTypes.string, -} - -DataGridFoot.defaultProps = { - className: "", - children: null, -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGridFoot/DataGridFoot.stories.js b/libs/juno-ui-components/src/components/DataGridFoot/DataGridFoot.stories.js deleted file mode 100644 index 3f736a59a..000000000 --- a/libs/juno-ui-components/src/components/DataGridFoot/DataGridFoot.stories.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { DataGridFoot } from './index.js'; -import { DataGridCell } from '../DataGridCell/index.js'; -import { Default as DataGridCellStory } from '../DataGridCell/DataGridCell.stories.js'; - -export default { - title: 'WiP/DataGrid/DataGridFoot', - component: DataGridFoot, - argTypes: { - children: { - control: false, - }, - }, - decorators: [(story) => <table>{story()}</table>], - parameters: { - docs: { - source: { - excludeDecorators: false, - }, - }, - }, -}; - -const Template = ({ items, ...args }) => ( - <DataGridFoot {...args}> - {/* {items.map((item, i) => ( - <DataGridFootRow key={`f_${i}`}> - {item.items.map((cell, c) => ( - <DataGridCell {...cell} key={`f_${i}_${c}`} /> - ))} - </DataGridFootRow> - ))} */} - </DataGridFoot> -); - -export const Default = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Juno DataGridFoot for use in DataGrid', - }, - }, - }, - - args: {}, -}; diff --git a/libs/juno-ui-components/src/components/DataGridFoot/DataGridFoot.test.js b/libs/juno-ui-components/src/components/DataGridFoot/DataGridFoot.test.js deleted file mode 100644 index 7b706b27f..000000000 --- a/libs/juno-ui-components/src/components/DataGridFoot/DataGridFoot.test.js +++ /dev/null @@ -1,27 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { DataGridFoot } from "./index" - -describe("DataGridFoot", () => { - - test("renders a DataGridFoot", async () => { - const table = document.createElement('table') - const {container} = render(<DataGridFoot data-testid="my-datagridfoot"/>, - { container: document.body.appendChild(table)}) - expect(screen.getByTestId("my-datagridfoot")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - const table = document.createElement('table') - const {container} = render(<DataGridFoot data-testid="my-datagridfoot" className="my-custom-class"/>, - { container: document.body.appendChild(table)}) - expect(screen.getByTestId("my-datagridfoot")).toBeInTheDocument() - expect(screen.getByTestId("my-datagridfoot")).toHaveClass("my-custom-class") - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGridFoot/index.js b/libs/juno-ui-components/src/components/DataGridFoot/index.js deleted file mode 100644 index afad71a5f..000000000 --- a/libs/juno-ui-components/src/components/DataGridFoot/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { DataGridFoot } from "./DataGridFoot.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGridHeadCell/DataGridHeadCell.component.js b/libs/juno-ui-components/src/components/DataGridHeadCell/DataGridHeadCell.component.js deleted file mode 100644 index dcc6ea3ca..000000000 --- a/libs/juno-ui-components/src/components/DataGridHeadCell/DataGridHeadCell.component.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { forwardRef } from "react" -import PropTypes from "prop-types" -import { DataGridCell } from "../DataGridCell/index.js" - -const headCellBaseStyles = ` - jn-font-bold - jn-text-theme-high - jn-bg-theme-background-lvl-1 - jn-border-theme-background-lvl-0 -` - -const sortIconStyles = ` - jn-ml-2 -` - -export const DataGridHeadCell = forwardRef( - ( - { - // sortable, - colSpan, - nowrap, - className, - children, - ...props - }, - ref - ) => { - return ( - <DataGridCell - colSpan={colSpan} - nowrap={nowrap} - className={`juno-datagrid-head-cell ${headCellBaseStyles} ${className}`} - role="columnheader" - ref={ref} - {...props} - > - {children} - </DataGridCell> - // <div - // className={`juno-datagrid-head-cell ${headCellBaseStyles} ${className}`} - // role="columnheader" - // {...props}> - // {children} - // {/* { sortable ? <Icon size={'1rem'} className={`${sortIconStyles}`}/> : ''} */} - // </div> - ) - } -) - -DataGridHeadCell.propTypes = { - /** Whether the DataGrid should be sortable by this column */ - // sortable: PropTypes.bool, - /** Add a col span to the cell. This works like a colspan in a normal html table, so you have to take care not to place too many cells in a row if some of them have a colspan. */ - colSpan: PropTypes.number, - /** Set nowrap to true if the cell content shouldn't wrap (this is achieved by adding white-space: nowrap;) */ - nowrap: PropTypes.bool, - /** Children to render in the DataGridHeadCell */ - children: PropTypes.node, - /** Add a classname */ - className: PropTypes.string, -} - -DataGridHeadCell.defaultProps = { - // sortable: false, - colSpan: undefined, - nowrap: false, - className: "", - children: null, -} diff --git a/libs/juno-ui-components/src/components/DataGridHeadCell/DataGridHeadCell.stories.js b/libs/juno-ui-components/src/components/DataGridHeadCell/DataGridHeadCell.stories.js deleted file mode 100644 index 1ccc0ca81..000000000 --- a/libs/juno-ui-components/src/components/DataGridHeadCell/DataGridHeadCell.stories.js +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { DataGrid } from '../DataGrid/index.js'; -import { DataGridRow } from '../DataGridRow/index.js'; -import { DataGridHeadCell } from './index.js'; - -export default { - title: 'Components/DataGrid/DataGridHeadCell', - component: DataGridHeadCell, - argTypes: { - children: { - control: false, - }, - }, - decorators: [ - (story) => ( - <DataGrid columns={3}> - <DataGridRow>{story()}</DataGridRow> - </DataGrid> - ), - ], - parameters: { - docs: { - source: { - excludeDecorators: false, - }, - }, - }, -}; - -const Template = (args) => <DataGridHeadCell {...args}></DataGridHeadCell>; - -export const Default = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Juno DataGridHeadCell for use in DataGrid', - }, - }, - }, - - args: { - children: ['DataGridHeadCell'], - }, -}; - -export const NoWrap = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Juno DataGridHeadCell with nowrap option (content has white-space: nowrap;)', - }, - }, - }, - - args: { - nowrap: true, - children: ['DataGridHeadCell does not wrap'], - }, -}; - -export const ColSpan = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Juno DataGridHeadCell with colspan', - }, - }, - }, - - args: { - colSpan: 3, - children: ['DataGridHeadCell with colspan'], - }, -}; diff --git a/libs/juno-ui-components/src/components/DataGridHeadCell/DataGridHeadCell.test.js b/libs/juno-ui-components/src/components/DataGridHeadCell/DataGridHeadCell.test.js deleted file mode 100644 index fb641d661..000000000 --- a/libs/juno-ui-components/src/components/DataGridHeadCell/DataGridHeadCell.test.js +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { DataGridHeadCell } from "./index" - -describe("DataGridHeadCell", () => { - - test("renders a DataGridHeadCell", async () => { - render(<DataGridHeadCell />) - expect(screen.getByRole("columnheader")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<DataGridHeadCell className="my-custom-class"/>) - expect(screen.getByRole("columnheader")).toBeInTheDocument() - expect(screen.getByRole("columnheader")).toHaveClass("my-custom-class") - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGridHeadCell/index.js b/libs/juno-ui-components/src/components/DataGridHeadCell/index.js deleted file mode 100644 index 9bea4b235..000000000 --- a/libs/juno-ui-components/src/components/DataGridHeadCell/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { DataGridHeadCell } from "./DataGridHeadCell.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGridRow/DataGridRow.component.js b/libs/juno-ui-components/src/components/DataGridRow/DataGridRow.component.js deleted file mode 100644 index 4950314c4..000000000 --- a/libs/juno-ui-components/src/components/DataGridRow/DataGridRow.component.js +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { forwardRef } from "react" -import PropTypes from "prop-types" - -const rowBaseStyle = ` - jn-contents -` -// const rowSelectedStyle = ` -// jn-bg-theme-datagridrow-selected -// ` - -export const DataGridRow = forwardRef( - ({ selected, disabled, className, children, onChange, ...props }, ref) => { - // const dataGridContext = useDataGridContext() || {} - // const selectable = dataGridContext.selectable - - // const [isSelected, setIsSelected] = useState(false) - // useEffect( () => { - // setIsSelected(selected) - // }, [selected]) - - // const toggleSelected = (event) => { - // setIsSelected(!isSelected) - // onChange(event) - // } - - // ${ selectable && isSelected ? rowSelectedStyle : '' } - return ( - <div - className={`juno-datagrid-row ${rowBaseStyle} ${className}`} - role="row" - ref={ref} - {...props} - > - {/* { selectable ? <DataGridCheckboxCell selected={selected} disabled={disabled} onChange={toggleSelected} /> : null } */} - {children} - </div> - ) - } -) - -DataGridRow.propTypes = { - // /** Whether the row / item is selected (only relevant in a `selectable` DataGrid */ - // selected: PropTypes.bool, - // /** Whether the row/item is disabled (only relevant in a `selectable` DataGrid */ - // disabled: PropTypes.bool, - /** Children to render in the DataGridRow */ - children: PropTypes.node, - /** Add a classname */ - className: PropTypes.string, - // /** Pass a handler to be executed when selected state changes */ - // onChange: PropTypes.func, -} - -DataGridRow.defaultProps = { - // selected: false, - // disabled: false, - className: "", - children: null, - // onChange: undefined, -} diff --git a/libs/juno-ui-components/src/components/DataGridRow/DataGridRow.stories.js b/libs/juno-ui-components/src/components/DataGridRow/DataGridRow.stories.js deleted file mode 100644 index a2084677d..000000000 --- a/libs/juno-ui-components/src/components/DataGridRow/DataGridRow.stories.js +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { DataGridRow } from './index.js'; -import { DataGridCell } from '../DataGridCell/index.js'; -import { Default as DataGridCellStory } from '../DataGridCell/DataGridCell.stories.js'; -import { DataGrid } from '../DataGrid/index.js'; - -const columns = 5; - -export default { - title: 'Components/DataGrid/DataGridRow', - component: DataGridRow, - argTypes: { - items: { - table: { - disable: true, - }, - }, - children: { - control: false, - }, - }, - decorators: [(story) => <DataGrid columns={columns}>{story()}</DataGrid>], - parameters: { - docs: { - source: { - excludeDecorators: false, - }, - }, - }, -}; - -const Template = ({ items, ...args }) => ( - <DataGridRow {...args}> - {items.map((item, i) => ( - <DataGridCell {...item} key={`${i}`} /> - ))} - </DataGridRow> -); - -export const Default = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Juno DataGridRow for use in DataGrid', - }, - }, - }, - - args: { - items: Array(columns).fill({ ...DataGridCellStory.args }), - }, -}; diff --git a/libs/juno-ui-components/src/components/DataGridRow/DataGridRow.test.js b/libs/juno-ui-components/src/components/DataGridRow/DataGridRow.test.js deleted file mode 100644 index 719f93755..000000000 --- a/libs/juno-ui-components/src/components/DataGridRow/DataGridRow.test.js +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { DataGridRow } from "./index" - -describe("DataGridRow", () => { - - test("renders a DataGridRow", async () => { - render(<DataGridRow />) - expect(screen.getByRole("row")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<DataGridRow className="my-custom-class"/>) - expect(screen.getByRole("row")).toBeInTheDocument() - expect(screen.getByRole("row")).toHaveClass("my-custom-class") - }) - - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGridRow/index.js b/libs/juno-ui-components/src/components/DataGridRow/index.js deleted file mode 100644 index 59cccabe6..000000000 --- a/libs/juno-ui-components/src/components/DataGridRow/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { DataGridRow } from "./DataGridRow.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGridToolbar/DataGridToolbar.component.js b/libs/juno-ui-components/src/components/DataGridToolbar/DataGridToolbar.component.js deleted file mode 100644 index b7ce287e7..000000000 --- a/libs/juno-ui-components/src/components/DataGridToolbar/DataGridToolbar.component.js +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -const datagridtoolbarstyles = ` - jn-flex - jn-items-center - jn-bg-theme-background-lvl-1 - jn-py-3 - jn-px-6 - jn-mb-px -` - -const childrenWrapperStyles = ` - jn-ml-auto -` - -/** This is the toolbar for use with a DataGrid. This is the place where you would put buttons and other controls that affect the items in the DataGrid (e.g. triggering batch actions). Optionally a search input can be added. */ -export const DataGridToolbar= ({ - search, - className, - children, - ...props -}) => { - return ( - <div className={`juno-datagrid-toolbar ${datagridtoolbarstyles} ${className}`} {...props} > - { search && - <div> - {search} - </div> - } - <div className={childrenWrapperStyles}> - {children} - </div> - </div> - ) -} - -DataGridToolbar.propTypes = { - /** Pass an optional SearchInput component */ - search: PropTypes.node, - /** Children to render in the DataGridToolbar */ - children: PropTypes.node, - /** Add a classname */ - className: PropTypes.string, -} - -DataGridToolbar.defaultProps = { - search: undefined, - className: "", - children: null, -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGridToolbar/DataGridToolbar.stories.js b/libs/juno-ui-components/src/components/DataGridToolbar/DataGridToolbar.stories.js deleted file mode 100644 index 1153a26c6..000000000 --- a/libs/juno-ui-components/src/components/DataGridToolbar/DataGridToolbar.stories.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { Button } from '../Button/index.js'; -import { ButtonRow } from '../ButtonRow/index.js'; -import { DataGridToolbar } from './index.js'; -import { SearchInput } from '../SearchInput/SearchInput.component'; - -export default { - title: 'Components/DataGrid/DataGridToolbar', - component: DataGridToolbar, - argTypes: { - children: { - control: false, - }, - search: { - control: false, - }, - }, -}; - -const Template = (args) => ( - <DataGridToolbar {...args}> - <ButtonRow> - <Button variant="subdued">Add other</Button> - <Button>Add new</Button> - </ButtonRow> - </DataGridToolbar> -); - -export const Default = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Optional toolbar for use in DataGrid. Use ButtonRow for multiple buttons', - }, - }, - }, - - args: {}, -}; - -export const WithSearch = { - render: Template, - - parameters: { - docs: { - description: { - story: 'DataGridToolbar with optional search input', - }, - }, - }, - - args: { - search: ( - <SearchInput - onSearch={() => { - console.log('Searching…'); - }} - /> - ), - }, -}; diff --git a/libs/juno-ui-components/src/components/DataGridToolbar/DataGridToolbar.test.js b/libs/juno-ui-components/src/components/DataGridToolbar/DataGridToolbar.test.js deleted file mode 100644 index 36a473d8f..000000000 --- a/libs/juno-ui-components/src/components/DataGridToolbar/DataGridToolbar.test.js +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { DataGridToolbar } from "./index" -import { SearchInput } from "../SearchInput/index" - -describe("DataGridToolbar", () => { - - test("renders a DataGridToolbar", async () => { - render(<DataGridToolbar data-testid="my-datagridtoolbar" />) - expect(screen.getByTestId("my-datagridtoolbar")).toBeInTheDocument() - }) - - test("renders a SearchInput as passed", async () => { - render(<DataGridToolbar search={<SearchInput/>}></DataGridToolbar>) - expect(screen.getByRole("searchbox")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<DataGridToolbar data-testid="my-datagridtoolbar" className="my-custom-class" />) - expect(screen.getByTestId("my-datagridtoolbar")).toBeInTheDocument() - expect(screen.getByTestId("my-datagridtoolbar")).toHaveClass("my-custom-class") - }) - - test("renders all props as passed", async () => { - render(<DataGridToolbar data-testid="23" data-lolol={true}/>) - expect(screen.getByTestId("23")).toBeInTheDocument() - expect(screen.getByTestId("23")).toHaveAttribute('data-lolol') - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataGridToolbar/index.js b/libs/juno-ui-components/src/components/DataGridToolbar/index.js deleted file mode 100644 index 6ac06c21b..000000000 --- a/libs/juno-ui-components/src/components/DataGridToolbar/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { DataGridToolbar } from "./DataGridToolbar.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataList/DataList.component.js b/libs/juno-ui-components/src/components/DataList/DataList.component.js deleted file mode 100644 index 246d974ad..000000000 --- a/libs/juno-ui-components/src/components/DataList/DataList.component.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -const DataListContext = React.createContext() - -export const useDataListContext = () => React.useContext(DataListContext) - -export const DataList = ({ - selectable, - className, - children, - ...props -}) => { - const dataListConf = { - selectable: selectable - } - return ( - <DataListContext.Provider value={dataListConf}> - <div className={`juno-datalist-container`}> - <ul className={`juno-datalist ${className}`} {...props} > - {children} - </ul> - </div> - </DataListContext.Provider> - ) -} - -DataList.propTypes = { - /** Whether the items of a DataList should be selectable */ - selectable: PropTypes.bool, - /** Custom classname */ - className: PropTypes.string, - /** Children to render in the DataList */ - children: PropTypes.node, -} - -DataList.defaultProps = { - selectable: false, - className: "", - children: null, -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataList/DataList.stories.js b/libs/juno-ui-components/src/components/DataList/DataList.stories.js deleted file mode 100644 index 3f30c8447..000000000 --- a/libs/juno-ui-components/src/components/DataList/DataList.stories.js +++ /dev/null @@ -1,160 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { DataList } from './index.js'; -import { DataListRow } from '../DataListRow/index.js'; -import { DataListCell } from '../DataListCell/index.js'; -import { Default as DataListRowStory } from '../DataListRow/DataListRow.stories.js'; -import { Default as DataListCellStory } from '../DataListCell/DataListCell.stories.js'; -import { Selectable as SelectableDataListRowStory } from '../DataListRow/DataListRow.stories.js'; -import { AutoWidth as AutoWidthDataListRowStory } from '../DataListRow/DataListRow.stories.js'; -import { PercentageWidths as PercentageWidthsDataListRowStory } from '../DataListRow/DataListRow.stories.js'; -import { GridFitted as GridFittedDataListRowStory } from '../DataListRow/DataListRow.stories.js'; - -export default { - title: 'Deprecated/DataList/DataList', - component: DataList, - argTypes: { - items: { - table: { - disable: true, - }, - }, - children: { - control: false, - }, - }, - parameters: { - docs: { - description: { - component: 'DataList is deprecated and will be removed. Please use DataGrid instead.', - }, - }, - }, -}; - -const Template = ({ items, ...args }) => ( - <DataList {...args}> - {items.map((item, i) => ( - <DataListRow key={`${i}`}> - {item.items.map((cell, c) => ( - <DataListCell {...cell} key={`${i}_${c}`} /> - ))} - </DataListRow> - ))} - </DataList> -); - -export const Default = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Default Juno DataList for displaying data', - }, - }, - }, - - args: { - items: [ - { ...DataListRowStory.args }, - { ...DataListRowStory.args }, - { ...DataListRowStory.args }, - { ...DataListRowStory.args }, - { ...DataListRowStory.args }, - ], - }, -}; - -export const Selectable = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Selectable Juno DataList for displaying and selecting data', - }, - }, - }, - - args: { - selectable: true, - items: [ - { ...SelectableDataListRowStory.args }, - { ...SelectableDataListRowStory.args }, - { ...SelectableDataListRowStory.args }, - { ...SelectableDataListRowStory.args }, - { ...SelectableDataListRowStory.args }, - ], - }, -}; - -export const Auto = { - render: Template, - - parameters: { - docs: { - description: { - story: "Juno DataList with one column set to 'auto' to maximize its width", - }, - }, - }, - - args: { - items: [ - { ...AutoWidthDataListRowStory.args }, - { ...AutoWidthDataListRowStory.args }, - { ...AutoWidthDataListRowStory.args }, - { ...AutoWidthDataListRowStory.args }, - { ...AutoWidthDataListRowStory.args }, - ], - }, -}; - -export const Percentage = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Juno DataList with percentage-based column widths', - }, - }, - }, - - args: { - items: [ - { ...PercentageWidthsDataListRowStory.args }, - { ...PercentageWidthsDataListRowStory.args }, - { ...PercentageWidthsDataListRowStory.args }, - { ...PercentageWidthsDataListRowStory.args }, - { ...PercentageWidthsDataListRowStory.args }, - ], - }, -}; - -export const GridFitted = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Juno DataList with grid column-based column widths', - }, - }, - }, - - args: { - items: [ - { ...GridFittedDataListRowStory.args }, - { ...GridFittedDataListRowStory.args }, - { ...GridFittedDataListRowStory.args }, - { ...GridFittedDataListRowStory.args }, - { ...GridFittedDataListRowStory.args }, - ], - }, -}; diff --git a/libs/juno-ui-components/src/components/DataList/DataList.test.js b/libs/juno-ui-components/src/components/DataList/DataList.test.js deleted file mode 100644 index ca69f7727..000000000 --- a/libs/juno-ui-components/src/components/DataList/DataList.test.js +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { DataList } from "./index" - -describe("DataList", () => { - - test("renders a DataList", async () => { - render(<DataList data-testid="my-datalist" />) - expect(screen.getByTestId("my-datalist")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<DataList data-testid="my-datalist" className="my-custom-class" />) - expect(screen.getByTestId("my-datalist")).toBeInTheDocument() - expect(screen.getByTestId("my-datalist")).toHaveClass("my-custom-class") - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataList/index.js b/libs/juno-ui-components/src/components/DataList/index.js deleted file mode 100644 index 0d373d23d..000000000 --- a/libs/juno-ui-components/src/components/DataList/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { DataList } from "./DataList.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataListCell/DataListCell.component.js b/libs/juno-ui-components/src/components/DataListCell/DataListCell.component.js deleted file mode 100644 index 316743589..000000000 --- a/libs/juno-ui-components/src/components/DataListCell/DataListCell.component.js +++ /dev/null @@ -1,151 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -const datalistcellbasestyles = ` - jn-flex - jn-p-2 - jn-overflow-hidden - jn-overflow-ellipsis - jn-grow-0 - jn-shrink-0 - jn-flex-basis-auto -` - -const datalistcellautostyles = ` - jn-grow - jn-shrink-0 - jn-flex-basis-0 -` - -const datalistcellgridstyles = ` - jn-p-grid-column -` - -const cols_1 = ` - jn-w-grid-col-1 -` - -const cols_2 = ` - jn-w-grid-col-2 -` - -const cols_3 = ` - jn-w-grid-col-3 -` - -const cols_4 = ` - jn-w-grid-col-4 -` - -const cols_5 = ` - jn-w-grid-col-6 -` - -const cols_6 = ` - jn-w-grid-col-6 -` - -const cols_7 = ` - jn-w-grid-col-7 -` - -const cols_8 = ` - jn-w-grid-col-8 -` - -const cols_9 = ` - jn-w-grid-col-9 -` - -const cols_10 = ` - jn-w-grid-col-10 -` - -const cols_11 = ` - jn-w-grid-col-11 -` - -const cols_12 = ` - jn-w-grid-col-12 -` - -const colsClass = (cols) => { -switch (cols) { - case 1: - return cols_1 - case 2: - return cols_2 - case 3: - return cols_3 - case 4: - return cols_4 - case 5: - return cols_5 - case 6: - return cols_6 - case 7: - return cols_7 - case 8: - return cols_8 - case 9: - return cols_9 - case 10: - return cols_10 - case 11: - return cols_11 - case 12: - return cols_12 - default: null -} -} - -export const DataListCell = ({ - cols, - width, - auto, - className, - children, - ...props -}) => { - // auto cell: - const autoStyles = { - flexGrow: "1", - flexShrink: "0", - flexBasis: "0" - } - // width cell: - const widthStyles = width ? { width: width + '%', flexGrow: "0", flexShrink: "0", flexBasis: width + '%' } : {} - // width overrides auto: - const cellStyles = width ? widthStyles : ( auto ? autoStyles : {} ) - return ( - <div className={`juno-datalist-cell ${datalistcellbasestyles} ${cols ? colsClass(cols) : '' } ${className}`} style={cellStyles} {...props} > - {children} - </div> - ) -} - -DataListCell.propTypes = { - /** The number of columns to span the column over when fitting to the grid. */ - cols: PropTypes.number, - /** The width in percent as a number without "%" for auto-layout grids TODO: or "auto". If a width is given, it will override the "cols" prop. */ - width: PropTypes.number, - /** Whether the colum should set an auto width */ - auto: PropTypes.bool, - /** Custom classname */ - className: PropTypes.string, - /** Children to render in the DataListCell */ - children: PropTypes.node, -} - -DataListCell.defaultProps = { - cols: null, - width: null, - auto: false, - className: "", - children: null, -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataListCell/DataListCell.stories.js b/libs/juno-ui-components/src/components/DataListCell/DataListCell.stories.js deleted file mode 100644 index c7d3b9e48..000000000 --- a/libs/juno-ui-components/src/components/DataListCell/DataListCell.stories.js +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { DataListCell } from './index.js'; - -export default { - title: 'Deprecated/DataList/DataListCell', - component: DataListCell, - argTypes: { - children: { - control: false, - }, - }, - parameters: { - docs: { - description: { - component: 'DataList is deprecated and will be removed. Please use DataGrid instead.', - }, - }, - }, -}; - -const Template = (args) => <DataListCell {...args}></DataListCell>; - -export const Default = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Juno DataListCell for displaying data', - }, - }, - }, - - args: { - children: ['DataListCell'], - }, -}; diff --git a/libs/juno-ui-components/src/components/DataListCell/DataListCell.test.js b/libs/juno-ui-components/src/components/DataListCell/DataListCell.test.js deleted file mode 100644 index 6c96b3f2c..000000000 --- a/libs/juno-ui-components/src/components/DataListCell/DataListCell.test.js +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { DataListCell } from "./index" - -describe("DataListCell", () => { - - test("renders a DataListCell", async () => { - render(<DataListCell data-testid="my-datalistcell" />) - expect(screen.getByTestId("my-datalistcell")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<DataListCell data-testid="my-datalistcell" className="my-custom-class" />) - expect(screen.getByTestId("my-datalistcell")).toBeInTheDocument() - expect(screen.getByTestId("my-datalistcell")).toHaveClass("my-custom-class") - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataListCell/index.js b/libs/juno-ui-components/src/components/DataListCell/index.js deleted file mode 100644 index 6e7a95108..000000000 --- a/libs/juno-ui-components/src/components/DataListCell/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { DataListCell } from "./DataListCell.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataListCheckboxCell/DataListCheckboxCell.component.js b/libs/juno-ui-components/src/components/DataListCheckboxCell/DataListCheckboxCell.component.js deleted file mode 100644 index 8a3638862..000000000 --- a/libs/juno-ui-components/src/components/DataListCheckboxCell/DataListCheckboxCell.component.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" -import { Checkbox } from "../Checkbox/Checkbox.component.js" -import { DataListCell } from "../DataListCell/DataListCell.component.js" - -const datalistcheckboxcellbasestyles = ` - jn-flex - jn-flex-col - jn-justify-center -` - -export const DataListCheckboxCell = ({ - selected, - disabled, - onChange, - className, - children, - ...props -}) => { - return ( - <DataListCell className={`juno-datalist-checkbox-cell ${datalistcheckboxcellbasestyles} ${className}`} {...props} > - <Checkbox disabled={disabled} checked={selected} onChange={onChange} /> - </DataListCell> - ) -} - -DataListCheckboxCell.propTypes = { - /** Whether the item this cell belongs to is selected */ - selected: PropTypes.bool, - /** Whether the item is disabled */ - disabled: PropTypes.bool, - /** Custom classname */ - className: PropTypes.string, - /** Children to render in the DataListCell */ - children: PropTypes.node, - /** Handler to execute when selected state changes */ - onChange: PropTypes.func, -} - -DataListCell.defaultProps = { - selected: false, - disabled: false, - className: "", - children: null, - onChange: undefined, -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataListCheckboxCell/DataListCheckboxCell.stories.js b/libs/juno-ui-components/src/components/DataListCheckboxCell/DataListCheckboxCell.stories.js deleted file mode 100644 index 6d8f6c3f5..000000000 --- a/libs/juno-ui-components/src/components/DataListCheckboxCell/DataListCheckboxCell.stories.js +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { DataListCheckboxCell } from './index.js'; - -export default { - title: 'Deprecated/DataList/DataListCheckboxCell', - component: DataListCheckboxCell, - argTypes: { - children: { - control: false, - }, - }, - parameters: { - docs: { - description: { - component: 'DataList is deprecated and will be removed. Please use DataGrid instead.', - }, - }, - }, -}; - -const Template = (args) => <DataListCheckboxCell {...args}></DataListCheckboxCell>; - -export const Default = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Juno DataListCheckboxCell for use in DataList', - }, - }, - }, - - args: {}, -}; - -export const Disabled = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Disabled Juno DataListCheckboxCell for use in DataList', - }, - }, - }, - - args: { - disabled: true, - }, -}; diff --git a/libs/juno-ui-components/src/components/DataListCheckboxCell/DataListCheckboxCell.test.js b/libs/juno-ui-components/src/components/DataListCheckboxCell/DataListCheckboxCell.test.js deleted file mode 100644 index acd41d292..000000000 --- a/libs/juno-ui-components/src/components/DataListCheckboxCell/DataListCheckboxCell.test.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { DataListCheckboxCell } from "./index" - -describe("DataListCheckboxCell", () => { - - test("renders a DataListCheckboxCell containing a checkbox", async () => { - render(<DataListCheckboxCell data-testid="my-datalistcell" />) - expect(screen.getByTestId("my-datalistcell")).toBeInTheDocument() - expect(screen.getByRole('checkbox')).toBeInTheDocument() - }) - - test("renders a DataListCheckboxCell containing a checked checkbox if passed", async () => { - render(<DataListCheckboxCell data-testid="my-datalistcell" selected />) - expect(screen.getByRole('checkbox')).toBeInTheDocument() - expect(screen.getByRole('checkbox')).toBeChecked() - }) - - test("renders a custom className", async () => { - render(<DataListCheckboxCell data-testid="my-datalistcell" className="my-custom-class"/>) - expect(screen.getByTestId("my-datalistcell")).toBeInTheDocument() - expect(screen.getByTestId("my-datalistcell")).toHaveClass("my-custom-class") - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataListCheckboxCell/index.js b/libs/juno-ui-components/src/components/DataListCheckboxCell/index.js deleted file mode 100644 index 7f7c2ac34..000000000 --- a/libs/juno-ui-components/src/components/DataListCheckboxCell/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { DataListCheckboxCell } from "./DataListCheckboxCell.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataListRow/DataListRow.component.js b/libs/juno-ui-components/src/components/DataListRow/DataListRow.component.js deleted file mode 100644 index 896ad5aff..000000000 --- a/libs/juno-ui-components/src/components/DataListRow/DataListRow.component.js +++ /dev/null @@ -1,62 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useState, useEffect } from "react" -import PropTypes from "prop-types" -import { useDataListContext } from "../DataList/DataList.component.js" -import { DataListCheckboxCell } from "../DataListCheckboxCell/DataListCheckboxCell.component.js" - -const datalistrowbasestyles = ` - jn-flex - jn-rounded-[3px] - jn-border - jn-border-theme-datalist-row - jn-mb-2 -` - -const rowselectedstyle = ` - jn-bg-theme-datalistrow-selected -` - -export const DataListRow = ({ - selected, - disabled, - onChange, - className, - children, - ...props -}) => { - const dataListContext = useDataListContext() || {} - const selectable = dataListContext.selectable - - const [isSelected, setIsSelected] = useState(false) - useEffect( () => { - setIsSelected(selected) - }, [selected]) - - const toggleSelected = (event) => { - setIsSelected(!isSelected) - onChange(event) - } - - return ( - <li className={`juno-datalist-row ${datalistrowbasestyles} ${ selectable && isSelected ? rowselectedstyle : '' }${className}`} {...props} > - { selectable ? <DataListCheckboxCell selected={selected} disabled={disabled} onChange={toggleSelected} /> : null } - {children} - </li> - ) -} - -DataListRow.propTypes = { - /** Custom classname */ - className: PropTypes.string, - /** Children to render in the DataListRow */ - children: PropTypes.node, -} - -DataListRow.defaultProps = { - className: "", - children: null, -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataListRow/DataListRow.stories.js b/libs/juno-ui-components/src/components/DataListRow/DataListRow.stories.js deleted file mode 100644 index 8ba320c2e..000000000 --- a/libs/juno-ui-components/src/components/DataListRow/DataListRow.stories.js +++ /dev/null @@ -1,160 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { DataListRow } from './index.js'; -import { DataListCell } from '../DataListCell/index.js'; -import { DataListCheckboxCell } from '../DataListCheckboxCell/index.js'; -import { Default as DataListCellStory } from '../DataListCell/DataListCell.stories.js'; -import { Default as DataListCheckboxCellStory } from '../DataListCheckboxCell/DataListCheckboxCell.stories.js'; - -export default { - title: 'Deprecated/DataList/DataListRow', - component: DataListRow, - argTypes: { - items: { - table: { - disable: true, - }, - }, - children: { - control: false, - }, - }, - parameters: { - docs: { - description: { - component: 'DataList is deprecated and will be removed. Please use DataGrid instead.', - }, - }, - }, -}; - -const Template = ({ items, ...args }) => ( - <DataListRow {...args}> - {items.map((item, i) => ( - <DataListCell {...item} key={`${i}`} /> - ))} - </DataListRow> -); - -const SelectableTemplate = ({ items, ...args }) => ( - <DataListRow {...args}> - <DataListCheckboxCell /> - {items.map((item, i) => ( - <DataListCell {...item} key={`${i}`} /> - ))} - </DataListRow> -); - -export const Default = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Juno DataListRow for displaying data', - }, - }, - }, - - args: { - items: [ - { ...DataListCellStory.args }, - { ...DataListCellStory.args }, - { ...DataListCellStory.args }, - { ...DataListCellStory.args }, - { ...DataListCellStory.args }, - ], - }, -}; - -export const Selectable = { - render: SelectableTemplate, - - parameters: { - docs: { - description: { - story: - 'Selectable DataListRow for displaying and selecting data. Note that highlighting the row will not work when rendered outside a DataList. ', - }, - }, - }, - - args: { - items: [ - { ...DataListCellStory.args }, - { ...DataListCellStory.args }, - { ...DataListCellStory.args }, - { ...DataListCellStory.args }, - { ...DataListCellStory.args }, - ], - }, -}; - -export const AutoWidth = { - render: Template, - - parameters: { - docs: { - description: { - story: "Row with one cell set to 'auto' in oder to maximize its width", - }, - }, - }, - - args: { - items: [ - { ...DataListCellStory.args }, - { ...DataListCellStory.args, auto: true, children: 'Auto DataListCell' }, - { ...DataListCellStory.args }, - { ...DataListCellStory.args }, - { ...DataListCellStory.args }, - ], - }, -}; - -export const PercentageWidths = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Row with Cells set to individual percentage widths', - }, - }, - }, - - args: { - items: [ - { ...DataListCellStory.args, width: 10 }, - { ...DataListCellStory.args, width: 45 }, - { ...DataListCellStory.args, width: 25 }, - { ...DataListCellStory.args, width: 10 }, - { ...DataListCellStory.args, width: 10 }, - ], - }, -}; - -export const GridFitted = { - render: Template, - - parameters: { - docs: { - description: { - story: 'Row with cells fitted to the Grid', - }, - }, - }, - - args: { - items: [ - { ...DataListCellStory.args, cols: 1, children: 'cols 1' }, - { ...DataListCellStory.args, cols: 6, children: 'cols 6' }, - { ...DataListCellStory.args, cols: 3, children: 'cols 3' }, - { ...DataListCellStory.args, cols: 2, children: 'cols 2' }, - ], - }, -}; diff --git a/libs/juno-ui-components/src/components/DataListRow/DataListRow.test.js b/libs/juno-ui-components/src/components/DataListRow/DataListRow.test.js deleted file mode 100644 index ce0ae96bc..000000000 --- a/libs/juno-ui-components/src/components/DataListRow/DataListRow.test.js +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { DataListRow } from "./index" - -describe("DataListRow", () => { - - test("renders a DataListRow", async () => { - render(<DataListRow data-testid="my-datalistrow" />) - expect(screen.getByTestId("my-datalistrow")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<DataListRow data-testid="my-datalistrow" className="my-custom-class" />) - expect(screen.getByTestId("my-datalistrow")).toBeInTheDocument() - expect(screen.getByTestId("my-datalistrow")).toHaveClass("my-custom-class") - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DataListRow/index.js b/libs/juno-ui-components/src/components/DataListRow/index.js deleted file mode 100644 index 7203e011c..000000000 --- a/libs/juno-ui-components/src/components/DataListRow/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { DataListRow } from "./DataListRow.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/DateTimePicker/DateTimePicker.component.js b/libs/juno-ui-components/src/components/DateTimePicker/DateTimePicker.component.js deleted file mode 100644 index cd9c41afe..000000000 --- a/libs/juno-ui-components/src/components/DateTimePicker/DateTimePicker.component.js +++ /dev/null @@ -1,711 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useEffect, useRef, useId, useMemo, useState } from "react" -import PropTypes from "prop-types" -import flatpickr from "flatpickr" -import { FormHint } from "../FormHint/" -import { Icon } from "../Icon/" -import { Label } from "../Label/" -import "./datetimepicker.scss" - -/* -TODO: -* add enable prop (or leave out if no success) -* add position prop (if possible, otherwise leave out) -* Allow to use the expected date format as a placeholder in the input element (placeholder="dateFormat" or smth similar?) when direct input is enabled? -*/ - -const inputWrapperStyles = ` - jn-relative -` - -const inputStyles = ` - jn-bg-theme-textinput - jn-bg-no-repeat - jn-bg-[top_0.375rem_right_1rem] - jn-text-theme-textinput - jn-fill-theme-textinput-default - jn-border - jn-text-base - jn-leading-4 - jn-px-4 - jn-h-textinput - jn-rounded-3px - focus:jn-outline-none - focus:jn-ring-2 - focus:jn-ring-theme-focus - disabled:jn-opacity-50 - disabled:jn-cursor-not-allowed - autofill:jn-bg-theme-textinput-autofill - autofill:jn-text-theme-textinput-autofill -` - -const inputWithLabelStyles = ` - jn-pt-[1.125rem] - jn-pb-1 -` - -const inputWithoutLabelStyles = ` - jn-py-4 -` - -const inputDefaultBorderStyles = ` - jn-border-theme-textinput-default -` - -const inputInvalidStyles = ` - jn-border-theme-error -` - -const inputValidStyles = ` - jn-border-theme-success -` - -const labelStyles = ` - peer-autofill:jn-text-theme-textinput-autofill-label - jn-pointer-events-none - jn-top-2 - jn-left-[0.9375rem] -` - -const iconContainerStyles = ` - jn-absolute - jn-inline-flex - jn-top-2 - jn-right-[2.75rem] - jn-gap-1.5 -` - -/** A all-purpose date and time picker component. Highly configurable, based on Flatpickr. */ - -export const DateTimePicker = ({ - allowInput, - allowInvalidPreload, - ariaDateFormat, - className, - conjunction, - dateFormat, - defaultHour, - defaultMinute, - defaultDate, - defaultValue, - disable, - disabled, - enableSeconds, - enableTime, - errortext, - helptext, - hourIncrement, - id, - invalid, - label, - locale, - maxDate, - minDate, - minuteIncrement, - mode, - monthSelectorType, - name, - noCalendar, - onBlur, - onChange, - onClear, - onClose, - onFocus, - onMonthChange, - onOpen, - onReady, - onYearChange, - placeholder, - required, - shorthandCurrentMonth, - showMonths, - successtext, - time_24hr, - valid, - value, - weekNumbers, - width, - ...props -}) => { - // always generate auto-id string using the useId hook to avoid "more hooks than in previous render" error when removing custom id: - const autoId = "juno-datetimepicker-" + useId() - const theId = id && id.length ? id : autoId - - const fpRef = useRef(null) // the dom node flatpickr instance will be bound to - let flatpickrInstanceRef = useRef({}) // The actual flatpickr instance - const calendarTargetRef = useRef(null) // The DOM node the flatpickr calendar should be rendered to - - const [theDate, setTheDate] = useState({}) - const [hasFocus, setHasFocus] = useState(false) - const [isOpen, setIsOpen] = useState(false) - const [isInvalid, setIsInvalid] = useState(false) - const [isValid, setIsValid] = useState(false) - - const updateFlatpickrInstance = (newKeys) => - (flatpickrInstanceRef.current = { - ...flatpickrInstanceRef.current, - ...Object.keys(newKeys).reduce((a, key) => { - a[key] = newKeys[key] - return a - }, {}), - }) - - const invalidated = useMemo( - () => (invalid || (errortext && errortext.length) ? true : false), - [invalid, errortext] - ) - const validated = useMemo( - () => (valid || (successtext && successtext.length) ? true : false), - [valid, successtext] - ) - - useEffect(() => { - setIsInvalid(invalidated) - }, [invalidated]) - - useEffect(() => { - setIsValid(validated) - }, [validated]) - - const handleBlur = () => { - setHasFocus(false) - onBlur && onBlur(theDate.selectedDate, theDate.selectedDateStr) - } - - const handleChange = (selectedDate, dateStr, instance) => { - setTheDate({ selectedDate: selectedDate, selectedDateStr: dateStr }) - onChange && onChange(selectedDate, dateStr) - } - - const handleClose = (selectedDate, dateStr, instance) => { - setIsOpen(false) - onClose && onClose(selectedDate, dateStr) - } - - const handleMonthChange = (selectedDate, dateStr, instance) => { - setTheDate({ selectedDate: selectedDate, selectedDateStr: dateStr }) - onMonthChange && onMonthChange(selectedDate, dateStr) - } - - const handleOpen = (selectedDate, dateStr, instance) => { - setIsOpen(true) - onOpen && onOpen(selectedDate, dateStr) - } - - const handleReady = (selectedDate, dateStr, instance) => { - onReady && onReady(selectedDate, dateStr) - } - - const handleYearChange = (selectedDate, dateStr, instance) => { - setTheDate({ selectedDate: selectedDate, selectedDateStr: dateStr }) - onYearChange && onYearChange(selectedDate, dateStr) - } - - const handleInputFocus = () => { - setHasFocus(true) - onFocus && onFocus(theDate.selectedDate, theDate.selectedDateStr) - } - - const handleClearIconClick = () => { - setTheDate({}) - flatpickrInstanceRef.current?.clear() - onClear && onClear([], "") - } - - // Create stringified versions of the value prop and its aliases in order to use them in a useEffect dependency array later. - const stringifiedValue = JSON.stringify(value) - const stringifiedDefaultDate = JSON.stringify(defaultDate) - const stringifiedDefaultValue = JSON.stringify(defaultValue) - - // Function to determine the date format. Will return the dateFormat if passed as a prop, or a useful defaultFormat depending on whether the DateTimePicker is set to show the time, seconds, or no calendar at all (time picker only). - const getDateFormat = () => { - const defaultDateFormat = enableTime - ? noCalendar - ? enableSeconds - ? "H:i:S" - : "H:i" - : enableSeconds - ? "Y-m-d H:i:S" - : "Y-m-d H:i" - : "Y-m-d" - - const theDateFormat = - dateFormat === undefined ? defaultDateFormat : dateFormat - - return theDateFormat - } - - const theDateFormat = getDateFormat() - - const createFlatpickrInstance = () => { - const options = { - allowInput: allowInput, - allowInvalidPreload: allowInvalidPreload, - ariaDateFormat: ariaDateFormat, - appendTo: calendarTargetRef.current, - conjunction: conjunction, - dateFormat: theDateFormat, - defaultDate: defaultDate || defaultValue, - defaultHour: defaultHour, - defaultMinute: defaultMinute, - disable: disable, - enableSeconds: enableSeconds, - enableTime: enableTime, - hourIncrement: hourIncrement, - locale: locale, - maxDate: maxDate, - minDate: minDate, - minuteIncrement: minuteIncrement, - mode: mode, - monthSelectorType, - noCalendar: noCalendar, - onChange: handleChange, - onClose: handleClose, - onMonthChange: handleMonthChange, - onOpen: handleOpen, - onReady: handleReady, - onYearChange: handleYearChange, - positionElement: calendarTargetRef.current, - shorthandCurrentMonth: shorthandCurrentMonth, - showMonths: showMonths, - time_24hr: time_24hr, - weekNumbers: weekNumbers, - } - const FP = - calendarTargetRef && fpRef.current && flatpickr(fpRef.current, options) - updateFlatpickrInstance(FP) - } - - const destroyFlatpickrInstance = () => { - flatpickrInstanceRef.current.destroy() - setTheDate({}) - flatpickrInstanceRef = null // Not sure if this is actually necessary? - } - - useEffect(() => { - createFlatpickrInstance() - return () => { - destroyFlatpickrInstance() - } - }, []) - - /* - Some config options on the flatpickr instance can not be set with immediate effect, a new instance needs to be created. - For the corresponding props we have some logic that makes sure we destroy the current instance and create a new one only when absolutely necessary. Also, we need to reduce doing that to only once, even if multiple of the props were updated at the same time for the sake of efficiency, and to make sure we do not call event handlers more often than needed and expected by the user. - */ - - // Store current props that will require creating a new instance when their value changes: - const prevRerenderingProps = useRef({ - allowInput: allowInput, - defaultHour: defaultHour, - defaultMinute: defaultMinute, - enableTime: enableTime, - enableSeconds: enableSeconds, - hourIncrement: hourIncrement, - minuteIncrement: minuteIncrement, - mode: mode, - noCalendar: noCalendar, - weekNumbers: weekNumbers, - }) - - // Apply a use effect to handle the logic bound to the props that require creating a new faltpickr instance: - useEffect(() => { - // set a variable to be set to true once we know we need to destroy the current instance and create a new one: - let hasChanged = false - - // For each of the props… - Object.keys(prevRerenderingProps.current).forEach((propKey) => { - const prevValue = prevRerenderingProps.current[propKey] - const currentValue = { - allowInput, - defaultHour, - defaultMinute, - enableTime, - enableSeconds, - hourIncrement, - minuteIncrement, - mode, - monthSelectorType, - noCalendar, - showMonths, - weekNumbers, - }[propKey] - - // … we need to check whether their value has actually changed - if (prevValue !== currentValue) { - hasChanged = true - } - }) - - // After we have checked if any one or multiple of the relevant props have changed, we actually destroy the curent instance and create a new one: - if (hasChanged) { - flatpickrInstanceRef?.current?.destroy() - createFlatpickrInstance() - } - - // Also make sure we update our stored props in order to be ready for the next update: - prevRerenderingProps.current = { - allowInput: allowInput, - defaultHour: defaultHour, - defaultMinute: defaultMinute, - enableTime: enableTime, - enableSeconds: enableSeconds, - hourIncrement: hourIncrement, - minuteIncrement: minuteIncrement, - mode: mode, - monthSelectorType: monthSelectorType, - noCalendar: noCalendar, - showMonths: showMonths, - weekNumbers: weekNumbers, - } - }, [ - allowInput, - defaultHour, - defaultMinute, - enableTime, - enableSeconds, - hourIncrement, - minuteIncrement, - mode, - monthSelectorType, - noCalendar, - showMonths, - weekNumbers, - ]) - - // useEffects for props that represent config options that can be set on an existing flatpickr instance with immediate effect: - useEffect(() => { - flatpickrInstanceRef.current?.set( - "allowInvalidPreload", - allowInvalidPreload - ) - }, [allowInvalidPreload]) - - useEffect(() => { - flatpickrInstanceRef.current?.set("ariaDateFormat", ariaDateFormat) - }, [ariaDateFormat]) - - useEffect(() => { - flatpickrInstanceRef.current?.set("conjunction", conjunction) - }, [conjunction]) - - useEffect(() => { - const newDateFormat = getDateFormat() - flatpickrInstanceRef.current?.set("dateFormat", newDateFormat) - }, [dateFormat]) - - useEffect(() => { - flatpickrInstanceRef.current?.set("disable", disable) - }, [disable]) - - useEffect(() => { - flatpickrInstanceRef.current?.set("hourIncrement", hourIncrement) - }, [hourIncrement]) - - useEffect(() => { - flatpickrInstanceRef.current?.set("locale", locale) - }, [locale]) - - useEffect(() => { - flatpickrInstanceRef.current?.set("maxDate", maxDate) - }, [maxDate]) - - useEffect(() => { - flatpickrInstanceRef.current?.set("minDate", minDate) - }, [minDate]) - - useEffect(() => { - flatpickrInstanceRef.current?.set( - "shorthandCurrentMonth", - shorthandCurrentMonth - ) - }, [shorthandCurrentMonth]) - - useEffect(() => { - flatpickrInstanceRef.current?.set("time_24hr", time_24hr) - }, [time_24hr]) - - // Update the flatpickr instance whenever the value prop (or any of its aliases) changes, and force the flatpickr instance to fire onChange event. These props may contain an array of one or multiple objects. These will never pass React's identity comparison, and will be regarded as a new object with any render regardless of their contents, thus creating an endless loop by updating the flatpickr instance updating the parent state (via onChange above) updating the flatpickr instance (…). We prevent this by checking on the stringified versions of the props in the dependency array. - useEffect(() => { - flatpickrInstanceRef.current?.setDate( - value || defaultDate || defaultValue, - true // enforce firing change event that in turn will update our state via handleChange. - ) - }, [stringifiedValue, stringifiedDefaultDate, stringifiedDefaultValue]) - - useEffect(() => { - flatpickrInstanceRef.current?.set("weekNumbers", weekNumbers) - }, [weekNumbers]) - - return ( - <div - className={` - juno-datetimepicker-wrapper - ${width == "auto" ? "jn-inline-block" : "jn-block"} - ${width == "auto" ? "jn-w-auto" : "jn-w-full"} - `} - > - <div - className={`juno-datetimepicker-input-wrapper ${inputWrapperStyles}`} - > - <input - className={` - juno-datetimepicker-input - ${inputStyles} - ${label ? inputWithLabelStyles : inputWithoutLabelStyles} - ${ - isInvalid - ? "juno-datetimepicker-input-invalid " + inputInvalidStyles - : "" - } - ${ - isValid - ? "juno-datetimepicker-input-valid" + inputValidStyles - : "" - } - ${isValid || isInvalid ? "" : inputDefaultBorderStyles} - ${width == "auto" ? "jn-w-auto" : "jn-w-full"} - ${ - enableTime && noCalendar - ? "juno-datetimepicker-input-timepicker" - : "juno-datetimepicker-input-default" - } - ${className} - `} - data-mode={mode} - disabled={disabled} - id={theId} - name={name && name.length ? name : null} - onBlur={handleBlur} - onChange={handleChange} - onFocus={handleInputFocus} - placeholder={placeholder} - ref={fpRef} - type="text" - {...props} - /> - - {label && label.length ? ( - <Label - text={label} - htmlFor={theId} - className={`${labelStyles}`} - disabled={disabled} - required={required} - floating - minimized={ - placeholder || - isOpen || - theDate.selectedDate?.length || - theDate.selectedDateStr?.length - ? true - : false - } - /> - ) : ( - "" - )} - - <div - className={`juno-datetimepicker-icon-container ${iconContainerStyles}`} - > - {theDate.selectedDate?.length || theDate.selectedDateStr?.length ? ( - <Icon - icon="close" - onClick={handleClearIconClick} - disabled={disabled} - title="Clear" - /> - ) : ( - "" - )} - {isInvalid ? ( - <Icon icon="dangerous" color="jn-text-theme-error" /> - ) : ( - "" - )} - {isValid ? ( - <Icon icon="checkCircle" color="jn-text-theme-success" /> - ) : ( - "" - )} - </div> - </div> - <div ref={calendarTargetRef}></div> - - {errortext && errortext.length ? ( - <FormHint text={errortext} variant="error" className="jn-mt-0" /> - ) : ( - "" - )} - {successtext && successtext.length ? ( - <FormHint text={successtext} variant="success" className="jn-mt-0" /> - ) : ( - "" - )} - {helptext && helptext.length ? ( - <FormHint text={helptext} className="jn-mt-0" /> - ) : ( - "" - )} - </div> - ) -} - -const datePropType = PropTypes.oneOfType([ - PropTypes.string, - PropTypes.array, - PropTypes.object, - PropTypes.number, -]) - -DateTimePicker.propTypes = { - /** Whether the DateTimePicker input element allows direct user keyboard input. Default is `false`. */ - allowInput: PropTypes.bool, - /** Allows the preloading of an invalid date (e.g. a date that hass been disable by passing `disable`). When disabled, the field will be cleared if the provided date is invalid */ - allowInvalidPreload: PropTypes.bool, - /** How the `aria-label` date for each day in the calendar will be formed. Uses the same rules/tokens as `dateFormat´ as described here: https://flatpickr.js.org/formatting/. When changing this, make sure the outcome makes sense when using a screenreader.*/ - ariaDateFormat: PropTypes.string, - /** Pass custom classNames. These will be appended to the input element of the DateTimePicker. */ - className: PropTypes.string, - /** A custom string to separate individual dates in `multiple` mode. */ - conjunction: PropTypes.string, - /** A string of characters to customize how a date will be formatted in the input field. Available options: https://flatpickr.js.org/formatting/ */ - dateFormat: PropTypes.string, - /** Sets the default date of the DateTimePicker. Same as `value`, only here for compatibility with the original Flatpickr library. If both `value` and `defaultDate` are being passed, `value` will win. Date Objects, timestamps, ISO date strings, chronological date strings `YYYY-MM-DD HH:MM` (must be compatible to current `dateFormat`), and the shortcut `today` are all accepted. */ - defaultDate: datePropType, - /** The initial value of the hour input element. Only effective if time is enabled. Note this will only set the hour input element to the value specified. Setting this options will not set a selected value on the DateTimePicker. */ - defaultHour: PropTypes.number, - /** The initial value of the minute input element. Only effective if time is enabled. Note this will only set the minute input element to the value specified. Setting this options will not set a selected value on the DateTimePicker. */ - defaultMinute: PropTypes.number, - /** Same as value, defaultDate */ - defaultValue: datePropType, - /** Pass an array of dates, date strings, date ranges or functions to disable dates. More on disabling dates: https://flatpickr.js.org/examples/#disabling-specific-dates */ - disable: PropTypes.array, - /** Whether the DateTimePicker is disabled */ - disabled: PropTypes.bool, - /** Whether to show seconds when showing a time picker. */ - enableSeconds: PropTypes.bool, - /** Whether to show a time picker. */ - enableTime: PropTypes.bool, - /** A text to render when the DateTimePicker has an error or could not be validated. */ - errortext: PropTypes.node, - /** A helptext to render to explain meaning and significance of the DateTimePicker. */ - helptext: PropTypes.node, - /** The step for the hour input. Only has an effect when a time picker is enabled via `enableTime`. */ - hourIncrement: PropTypes.number, - /** The id of the DateTimePicker input element. If none is passed, an automatically generated id will be used. */ - id: PropTypes.string, - /** Whether the DateTimePicker selected date was negatively validated. */ - invalid: PropTypes.bool, - /** The label of the DateTimePicker input element. */ - label: PropTypes.string, - /** Localization string or object. Can be used to set starting day of the week, e.g. Mondays instead of Sundays. More on localization: https://flatpickr.js.org/localization/ */ - locale: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), - /** The maximum / latest date a user can select (inclusive). */ - maxDate: datePropType, - /** The minimum / earliest date a user can select (inclusive). */ - minDate: datePropType, - /** The step for the minute input. Only has an effect when a time picker is enabled via `enableTime`. */ - minuteIncrement: PropTypes.number, - /** The mode of the Datepicker. */ - mode: PropTypes.oneOf(["single", "multiple", "range"]), - /** Whether to show a dropdown to select the current month. Default is "static". If `showMonths` is set to be greater than 1, it will always be displayed as static. Arrows to scroll through the months as well as through years will still be displayed and working. */ - monthSelectorType: PropTypes.oneOf(["static", "dropdown"]), - /** The name of the DateTimePicker input element */ - name: PropTypes.string, - /** Set to `true` to not display a calendar at all. To create a time picker, set `enableTime` to true, too. */ - noCalendar: PropTypes.bool, - /** A handler to be executed when the DateTimePicker input element looses focus. */ - onBlur: PropTypes.func, - /** A handler to be executed when the selected date(s), date range or time changes */ - onChange: PropTypes.func, - /** A handler to be executed when the DateTimePicker value is reset by clicking the clear icon. The onChnage handler will be fired in this event too, onClear is more specific. */ - onClear: PropTypes.func, - /** A handler to be executed when the DateTimePicker calendar closes */ - onClose: PropTypes.func, - /** A handler to be executed when the DateTimePicker input element receives focus. */ - onFocus: PropTypes.func, - /** A handler to be executed when the selected month changes */ - onMonthChange: PropTypes.func, - /** A handler to be executed when the DateTimePicker calendar opens */ - onOpen: PropTypes.func, - /** A handler to be executed when the DateTimePicker component is ready */ - onReady: PropTypes.func, - /** A handler to be executed when the selected year changes */ - onYearChange: PropTypes.func, - /** The placeholder of the DateTimePicker input element */ - placeholder: PropTypes.string, - /** Whether the DateTimePicker should be marked as required. Requires a `Label` to be set. */ - required: PropTypes.bool, - /** Whether the current month in the date picker should be displayed as shorthand, e.g. "Jan" instead of "January" */ - shorthandCurrentMonth: PropTypes.bool, - /** The number of months to show in the date picker */ - showMonths: PropTypes.number, - /** A text to render when the DateTimePicker was successfully validated */ - successtext: PropTypes.node, - /** Displays time picker in 24 hour mode without AM/PM selection when enabled. Requires `enableTime` to be set, too. Default is `false`. */ - time_24hr: PropTypes.bool, - /** Whether the DateTimePicker has been successfully validated */ - valid: PropTypes.bool, - /** The value of the datepicker. Date Objects, timestamps, ISO date strings, chronological date strings `YYYY-MM-DD HH:MM` (must be compatible to current `dateFormat`), and the shortcut `today` are all accepted. */ - value: datePropType, - /** Whether to render week numbers. Default is `false`. */ - weekNumbers: PropTypes.bool, - /** The width of the datepicker input. Either 'full' (default) or 'auto'. */ - width: PropTypes.oneOf(["full", "auto"]), -} - -DateTimePicker.defaultProps = { - allowInput: false, - allowInvalidPreload: false, - ariaDateFormat: "F j, Y", - className: "", - conjunction: ", ", - dateFormat: undefined, - defaultHour: 12, - defaultMinute: 0, - defaultDate: null, - defaultValue: "", - disable: [], - disabled: false, - enableSeconds: false, - enableTime: false, - errortext: "", - helptext: "", - hourIncrement: 1, - id: "", - invalid: false, - label: "", - locale: null, - maxDate: null, - minDate: null, - minuteIncrement: 1, - mode: "single", - monthSelectorType: "static", - name: "", - noCalendar: false, - onBlur: undefined, - onChange: undefined, - onClear: undefined, - onClose: undefined, - onFocus: undefined, - onMonthChange: undefined, - onOpen: undefined, - onReady: undefined, - onYearChange: undefined, - placeholder: "", - required: false, - shorthandCurrentMonth: false, - showMonths: 1, - successtext: "", - time_24hr: false, - valid: false, - value: "", - weekNumbers: false, - width: "full", -} diff --git a/libs/juno-ui-components/src/components/DateTimePicker/DateTimePicker.stories.js b/libs/juno-ui-components/src/components/DateTimePicker/DateTimePicker.stories.js deleted file mode 100644 index 947e6174b..000000000 --- a/libs/juno-ui-components/src/components/DateTimePicker/DateTimePicker.stories.js +++ /dev/null @@ -1,500 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useState } from "react" -import { DateTimePicker } from "./index.js" -import { PortalProvider } from "../PortalProvider/PortalProvider.component" -import { Form } from "../Form/" - -export default { - title: "WIP/DateTimePicker/DateTimePicker", - component: DateTimePicker, - argTypes: { - mode: { - options: ["single", "multiple", "range", "time"], - control: { type: "select" }, - }, - value: { - control: false, - }, - errortext: { - control: false, - }, - helptext: { - control: false, - }, - successtext: { - control: false, - }, - monthSelectorType: { - options: ["dropdown", "static"], - control: { type: "radio" }, - }, - width: { - options: ["auto", "full"], - control: { type: "radio" }, - }, - disable: { - control: false, - }, - }, -} - -// Not in use yet, useful for "enable" story once we have it, pls leave here: -const daysFromToday = (n) => { - const today = new Date() - return new Date(today.setDate(today.getDate() + n)) -} - -const Template = ({ ...args }) => <DateTimePicker {...args} /> - -export const Default = Template.bind({}) -Default.args = {} - -export const WithLabel = Template.bind({}) -WithLabel.args = { - label: "Select a date", -} - -export const Required = Template.bind({}) -Required.args = { - label: "Select a date", - required: true, -} - -export const Disabled = Template.bind({}) -Disabled.args = { - label: "Select a date", - disabled: true, -} - -export const WithPlaceholder = Template.bind({}) -WithPlaceholder.args = { - placeholder: "Select a date…", -} - -export const WithValue = Template.bind({}) -WithValue.parameters = { - docs: { - description: { - story: - "Set the selected date of the datePicker. `value`, `defaultValue`, and `defaultDate` do the exact same thing and can be used interchangeably.", - }, - }, -} -WithValue.args = { - value: new Date(), -} - -export const WithDefaultDate = Template.bind({}) -WithDefaultDate.parameters = { - docs: { - description: { - story: - "Set the selected date of the datePicker. `value`, `defaultValue`, and `defaultDate` do the exact same thing and can be used interchangeably.", - }, - }, -} -WithDefaultDate.args = { - defaultDate: new Date(), -} - -export const WithDefaultHourAndMinute = Template.bind({}) -WithDefaultHourAndMinute.parameters = { - docs: { - description: { - story: - "Pass `defaultHour` and `defaultMinute` to set default values for the date and time input elements. Note: this will not set a selected date with these values in the DateTimePicker input element, the user still has to make a selection.", - }, - }, -} -WithDefaultHourAndMinute.args = { - defaultHour: 9, - defaultMinute: 13, - enableTime: true, - helptext: - "The hour and minute input elements in the dropdown calendar have been set to default values (09:13 AM).", -} - -export const WithDefaultValue = Template.bind({}) -WithDefaultValue.parameters = { - docs: { - description: { - story: - "Set the selected date of the datePicker. `value`, `defaultValue`, and `defaultDate` do the exact same thing and can be used interchangeably.", - }, - }, -} -WithDefaultValue.args = { - defaultValue: new Date(), -} - -export const WithValueAsDateString = Template.bind({}) -WithValueAsDateString.parameters = { - docs: { - description: { - story: - 'Pass a string as a `value`, `defaultValue`, or `defaultDate` that is compatible with the current `dateFormat` prop, e.g. `"2024-01-24"` if the current `dateFormat` is `"Y-m-d"` (as is the default). The DateTimePicker component will not convert these.', - }, - }, -} -WithValueAsDateString.args = { - value: "2024-01-24", -} - -export const WithValueAsIsoDateString = Template.bind({}) -WithValueAsIsoDateString.parameters = { - docs: { - description: { - story: - "Pass an ISO-compatible date string to display the corresponding date in the Datepicker.", - }, - }, -} -WithValueAsIsoDateString.args = { - value: "2034-02-26T19:40:03.243Z", -} - -export const WithValueAsTimestamp = Template.bind({}) -WithValueAsTimestamp.parameters = { - docs: { - description: { - story: - "Pass a timestamp with milliseconds as `value` to display the corresponding date in the Datepicker.", - }, - }, -} -WithValueAsTimestamp.args = { - value: 1706273787000, -} - -export const WithValueAsTodayShortcut = Template.bind({}) -WithValueAsTodayShortcut.parameters = { - docs: { - description: { - story: - 'Pass `"today"` as `value` as a shortcut to display the current Date in the Datepicker.', - }, - }, -} -WithValueAsTodayShortcut.args = { - value: "today", -} - -export const WithCustomDateFormat = Template.bind() -WithCustomDateFormat.parameters = {} -WithCustomDateFormat.args = { - value: "today", - dateFormat: "F d, Y", -} - -export const WithTime = Template.bind({}) -WithTime.parameters = { - docs: { - description: { - story: - "To also show a time picker to allow users to select a date and a time, set `enableTime` to `true`. Set the `dateFormat` accordingly to have the selected time reflected in the DateTimePicker input element. More about formatting dates here: https://flatpickr.js.org/formatting/.", - }, - }, -} -WithTime.args = { - enableTime: true, -} - -export const WithTimeAndSeconds = Template.bind({}) -WithTimeAndSeconds.parameters = { - docs: { - description: { - story: - "To allow selecting seconds when showing a time picker, set `enableSeconds` to `true`. To reflect seconds in the selected date in the DateTimePicker, adjust the `dateFormat` accordingly: https://flatpickr.js.org/formatting/.", - }, - }, -} -WithTimeAndSeconds.args = { - enableTime: true, - enableSeconds: true, -} - -export const WithTimeWithCustomHourIncrement = Template.bind({}) -WithTimeWithCustomHourIncrement.parameters = { - docs: { - description: { - story: - "Set a custom hour increment by which to change the hour in the respective element.", - }, - }, -} -WithTimeWithCustomHourIncrement.args = { - enableTime: true, - hourIncrement: 6, - helptext: "The hour input of this DateTimePicker has a 6 hour increment.", -} - -export const WithTimeWithCustomMinuteIncrement = Template.bind({}) -WithTimeWithCustomMinuteIncrement.parameters = { - docs: { - description: { - story: - "Set a custom minute increment by which to change the minute in the respective element.", - }, - }, -} -WithTimeWithCustomMinuteIncrement.args = { - enableTime: true, - minuteIncrement: 5, - helptext: "The minute input of this DateTimePicker has a 5 minute increment.", -} - -export const With24hTime = Template.bind({}) -With24hTime.parameters = { - docs: { - description: { - story: - "Set the time picker to use 24h time mode without AM/PM selection.", - }, - }, -} -With24hTime.args = { - enableTime: true, - time_24hr: true, -} - -export const ShowTwoMonths = Template.bind({}) -ShowTwoMonths.parameters = { - docs: { - description: { - story: - "Set the number of months to be displayed side by side in the calendar.", - }, - }, -} -ShowTwoMonths.args = { - showMonths: 2, -} - -export const WithWeekNumbers = Template.bind({}) -WithWeekNumbers.parameters = { - docs: { - description: { - story: - "Set `weekNumbers` to `true` to display week numbers in the calendar.", - }, - }, -} -WithWeekNumbers.args = { - weekNumbers: true, -} - -export const WithShorthandCurrentMonth = Template.bind({}) -WithShorthandCurrentMonth.parameters = { - docs: { - description: { - story: - "Set `shorthandCurrentMonth` to `true` to show shorthand month names, e.g. 'Jan' instead of 'January'.", - }, - }, -} -WithShorthandCurrentMonth.args = { - shorthandCurrentMonth: true, -} - -export const WithMonthSelectorDropdown = Template.bind({}) -WithMonthSelectorDropdown.parameters = { - docs: { - description: { - story: - 'Set `monthSelectorType` to "dropdown" in order to show a select element to switch months in the calndar.', - }, - }, -} -WithMonthSelectorDropdown.args = { - monthSelectorType: "dropdown", -} - -export const AllowInput = Template.bind({}) -AllowInput.parameters = { - docs: { - description: { - story: - "Set `allowInput` to `true` to allow direct user input by typing into the DateTimePicker input element.", - }, - }, -} -AllowInput.args = { - allowInput: true, -} - -export const Multiple = Template.bind({}) -Multiple.parameters = { - docs: { - description: { - story: 'To select multiple dates, set `mode` to "multiple".', - }, - }, -} -Multiple.args = { - mode: "multiple", -} - -export const Range = Template.bind({}) -Range.parameters = { - docs: { - description: { - story: - 'To select a date range instead of individual date(s), set `mode` to "range".', - }, - }, -} -Range.args = { - mode: "range", -} - -export const TimePicker = Template.bind({}) -TimePicker.parameters = { - docs: { - description: { - story: - "In order to create a pure timepicker, set the `dateFormat` accordingly, and set `noCalendar` and `enableTime` to `true`. If seconds are required, set `enableSeconds` to `true`.", - }, - }, -} -TimePicker.args = { - enableTime: true, - noCalendar: true, - enableSeconds: true, -} - -export const WithMinDate = Template.bind({}) -WithMinDate.parameters = { - docs: { - description: { - story: "Set a `minDate` to allow selecting only later dates.", - }, - }, -} -WithMinDate.args = { - minDate: new Date(), - helptext: "Only dates in the future including today can be selected.", -} - -export const WithMaxDate = Template.bind({}) -WithMaxDate.parameters = { - docs: { - description: { - story: "Set a `maxDate` to allow selecting only earlier dates.", - }, - }, -} -WithMaxDate.args = { - maxDate: new Date(), - helptext: "Only dates in the past including today can be selected.", -} - -export const DisableDate = Template.bind({}) -;(DisableDate.parameters = { - docs: { - description: { - story: - "Pass an array of dates to be disabled, making it impossible for the user to select these dates.", - }, - }, -}), - (DisableDate.args = { - disable: [new Date()], - helptext: "The current date (today) can not be selected.", - }) - -export const DisableByFunction = Template.bind({}) -DisableByFunction.parameters = { - docs: { - description: { - story: - "Pass an array of functions such as `function(date) {// return true to disable date}` as `disable` to be run for each date in the calendar in order to disable dates that match custom criteria. Pass a locale string or object to modify the sequence of week days rendered in the calendar.", - }, - }, -} -DisableByFunction.args = { - disable: [ - function (date) { - return date.getDay() === 0 || date.getDay() === 6 - }, - ], - locale: { - firstDayOfWeek: 1, // set week to start on Monday - }, - helptext: - "Only work days can be selected, week in calendar starts with Monday.", -} - -export const Valid = Template.bind({}) -Valid.args = { - valid: true, -} - -export const Invalid = Template.bind({}) -Invalid.args = { - invalid: true, -} - -export const WithErrortext = Template.bind({}) -WithErrortext.args = { - errortext: "This DateTimePicker has an error or is invalid.", -} - -export const WithSuccesstext = Template.bind({}) -WithSuccesstext.args = { - successtext: "This DateTimePicker was susccessfully validated.", -} - -export const WithHelptext = Template.bind({}) -WithHelptext.args = { - helptext: "Some useful information goes here.", -} - -export const InvalidPreload = Template.bind({}) -InvalidPreload.parameters = { - docs: { - description: { - story: - "Normally, the text input element oif the datepicker would be cleared when passing a date as `value` or `defaultDate` that is disabled from selection. By setting `allowInvalidPreload` such dates can be initially displayed in the datepicker, even though they are not available for user selection in the calendar.", - }, - }, -} -InvalidPreload.args = { - allowInvalidPreload: true, - value: "2024-01-30", - disable: ["2024-01-30"], - helptext: - "The datpicker initially shows Jan 30, 2024 as value even though this date has been set as disabled and thus can not be selected by a user.", -} - -const ControlledTemplate = ({ ...args }) => { - const [testState, setTestState] = useState({ date: { end: null } }) - - const handleChange = (dObj, dStr) => { - setTestState({ date: { end: dObj } }) - } - - return ( - <DateTimePicker - {...args} - onChange={handleChange} - value={testState?.date?.end} - /> - ) -} - -export const ControlledDateTimePicker = { - render: ControlledTemplate, - parameters: { - docs: { - description: { - story: - "Example of controlled usage, using the date object array as returned by the onChange handler in the parent story state. This used to create an endless loop and should be fixed now.", - }, - }, - }, - args: {}, -} diff --git a/libs/juno-ui-components/src/components/DateTimePicker/DateTimePicker.test.js b/libs/juno-ui-components/src/components/DateTimePicker/DateTimePicker.test.js deleted file mode 100644 index ae0d466d4..000000000 --- a/libs/juno-ui-components/src/components/DateTimePicker/DateTimePicker.test.js +++ /dev/null @@ -1,684 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { cleanup, render, screen, fireEvent } from "@testing-library/react" -import userEvent from "@testing-library/user-event" -import { DateTimePicker } from "./index" - -const mockOnOpen = jest.fn() -const mockOnClear = jest.fn() -const mockOnClose = jest.fn() -const mockOnChange = jest.fn() -const mockOnMonthChange = jest.fn() -const mockOnYearChange = jest.fn() -const mockOnValueUpdate = jest.fn() - -describe("DateTimePicker", () => { - afterEach(() => { - cleanup() - jest.clearAllMocks() - }) - - test("renders a DateTimePicker", async () => { - render(<DateTimePicker />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute("type", "text") - expect(screen.getByRole("textbox")).toHaveClass("juno-datetimepicker-input") - }) - - test("renders a label as passed", async () => { - render( - <DateTimePicker label="The DateTimePicker Label" id="my-textinput" /> - ) - expect(document.querySelector(".juno-label")).toBeInTheDocument() - expect(document.querySelector(".juno-label")).toHaveTextContent( - "The DateTimePicker Label" - ) - }) - - test("renders an id as passed", async () => { - render(<DateTimePicker id="my-datetimepicker" />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute( - "id", - "my-datetimepicker" - ) - }) - - test("renders a name as passed", async () => { - render(<DateTimePicker name="my-name" />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute("name", "my-name") - }) - - test("renders a DateTimePicker with an auto-generated id if no id is passed", async () => { - render(<DateTimePicker />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute("id") - expect(screen.getByRole("textbox").getAttribute("id")).toMatch( - "juno-datetimepicker" - ) - }) - - test("renders a DateTimePicker with a label associated by an id as passed", async () => { - render(<DateTimePicker label="The DateTimePicker Label" id="dp-1" />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute("id") - expect(screen.getByRole("textbox").getAttribute("id")).toMatch("dp-1") - expect( - screen.getByLabelText("The DateTimePicker Label") - ).toBeInTheDocument() - }) - - test("renders a DateTimePicker with a label associated by an auto-generated id if no id was passed ", async () => { - render(<DateTimePicker label="This is a DateTimePicker" />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect( - screen.getByLabelText("This is a DateTimePicker") - ).toBeInTheDocument() - }) - - test("renders a DateTimePicker with a placholder as passed", async () => { - render(<DateTimePicker placeholder="This is a placeholder" />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute( - "placeholder", - "This is a placeholder" - ) - }) - - test("renders a disabled DateTimePicker as passed", async () => { - render(<DateTimePicker disabled />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toBeDisabled() - }) - - test("renders a Clear button if passed and when a date is set", async () => { - render(<DateTimePicker value="2027-01-12" />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByTitle("Clear")).toBeInTheDocument() - }) - - test("does not render a Clear button when no date is set", async () => { - render(<DateTimePicker />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.queryByTitle("Clear")).not.toBeInTheDocument() - }) - - test("renders a DateTimePicker marked as required", async () => { - // DateTimePicker needs a label passed since the Label subcomponent is responsible for rendering the Required marker: - render(<DateTimePicker label="Required DateTimePicker" required />) - expect(document.querySelector(".juno-required")).toBeInTheDocument() - }) - - test("renders a helptext as passed", async () => { - render(<DateTimePicker helptext="this is a helptext" />) - expect(document.querySelector(".juno-form-hint")).toBeInTheDocument() - expect(document.querySelector(".juno-form-hint")).toHaveClass( - "juno-form-hint-help" - ) - expect(document.querySelector(".juno-form-hint")).toHaveTextContent( - "this is a helptext" - ) - }) - - test("renders a valid DateTimePicker as passed", async () => { - render(<DateTimePicker valid />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveClass( - "juno-datetimepicker-input-valid" - ) - expect(screen.getByTitle("CheckCircle")).toBeInTheDocument() - }) - - test("renders an invalid DateTimePicker as passed", async () => { - render(<DateTimePicker invalid />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveClass( - "juno-datetimepicker-input-invalid" - ) - expect(screen.getByTitle("Dangerous")).toBeInTheDocument() - }) - - test("renders a successtext as passed and validates the element", async () => { - render(<DateTimePicker successtext="great success!" />) - expect(document.querySelector(".juno-form-hint")).toBeInTheDocument() - expect(document.querySelector(".juno-form-hint")).toHaveClass( - "juno-form-hint-success" - ) - expect(document.querySelector(".juno-form-hint")).toHaveTextContent( - "great success!" - ) - expect(screen.getByRole("textbox")).toHaveClass( - "juno-datetimepicker-input-valid" - ) - expect(screen.getByTitle("CheckCircle")).toBeInTheDocument() - }) - - test("renders an errortext as passed and invalidates the element", async () => { - render(<DateTimePicker errortext="this is an error!" />) - expect(document.querySelector(".juno-form-hint")).toBeInTheDocument() - expect(document.querySelector(".juno-form-hint")).toHaveClass( - "juno-form-hint-error" - ) - expect(document.querySelector(".juno-form-hint")).toHaveTextContent( - "this is an error!" - ) - expect(screen.getByRole("textbox")).toHaveClass( - "juno-datetimepicker-input-invalid" - ) - expect(screen.getByTitle("Dangerous")).toBeInTheDocument() - }) - - test("renders a DateTimePicker with a time picker as passed", async () => { - render(<DateTimePicker enableTime={true} dateFormat="Y-m-d H:i:S" />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(document.querySelector(".flatpickr-time")).toBeInTheDocument() - expect(screen.getByLabelText("Hour")).toBeInTheDocument() - expect(screen.getByLabelText("Minute")).toBeInTheDocument() - }) - - test("renders a DateTimePicker with a time picker with seconds as passed", async () => { - render(<DateTimePicker enableTime={true} enableSeconds={true} />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(document.querySelector(".flatpickr-time")).toBeInTheDocument() - expect(screen.getByLabelText("Hour")).toBeInTheDocument() - expect(screen.getByLabelText("Minute")).toBeInTheDocument() - // We need to check for the flatpickr className as flatpickr does not assign an aria-label to the seconds input: - expect(document.querySelector(".flatpickr-second")).toBeInTheDocument() - }) - - test("displays the date as passed as a date object", async () => { - render(<DateTimePicker value={new Date(2099, 0, 1)} />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue("2099-01-01") - }) - - test("displays the date as passed as a date string", async () => { - render(<DateTimePicker value="2024-01-26" />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue("2024-01-26") - }) - - test("diplays the date as passed as an ISO date string", async () => { - render(<DateTimePicker value="2034-02-26T19:40:03.243Z" />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue("2034-02-26") - }) - - test("displays the date as passed as a timestamp", async () => { - render(<DateTimePicker value={1706273787000} />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue("2024-01-26") - }) - - test("displays the date as passed by shortcut 'today'", async () => { - render(<DateTimePicker value="today" />) - const today = new Date() - const year = today.getFullYear() - const month = (today.getMonth() + 1).toString().padStart(2, "0") - const day = today.getDate().toString().padStart(2, "0") - const todayAsString = `${year}-${month}-${day}` - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue(todayAsString) - }) - - test("displays the date in a custom format as passed", async () => { - render(<DateTimePicker dateFormat="F d Y" value={1706273787000} />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue("January 26 2024") - }) - - test("uses the default dateFormat (Y-m-d) in default (non-time picker) mode)", async () => { - const today = new Date() - const fullYear = today.getFullYear() - const month = (today.getMonth() + 1).toString().padStart(2, "0") - const day = today.getDate().toString().padStart(2, "0") - const todayAsString = `${fullYear}-${month}-${day}` - render(<DateTimePicker value={today} />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue(todayAsString) - }) - - test("uses the correct default dateFormat (Y-m-d H:i) in date-time-picker mode without seconds", async () => { - const now = new Date() - const fullYear = now.getFullYear() - const month = (now.getMonth() + 1).toString().padStart(2, "0") - const day = now.getDate().toString().padStart(2, "0") - const hours = now.getHours().toString().padStart(2, "0") - const minutes = now.getMinutes().toString().padStart(2, "0") - const nowAsString = `${fullYear}-${month}-${day} ${hours}:${minutes}` - render(<DateTimePicker enableTime value={now} />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue(nowAsString) - }) - - test("uses the correct default dateFormat (Y-m-d H:i:S) in date-time-picker mode with seconds enabled", async () => { - const now = new Date() - const fullYear = now.getFullYear() - const month = (now.getMonth() + 1).toString().padStart(2, "0") - const day = now.getDate().toString().padStart(2, "0") - const hours = now.getHours().toString().padStart(2, "0") - const minutes = now.getMinutes().toString().padStart(2, "0") - const seconds = now.getSeconds().toString().padStart(2, "0") - const nowAsStringWithSeconds = `${fullYear}-${month}-${day} ${hours}:${minutes}:${seconds}` - render(<DateTimePicker enableTime enableSeconds value={now} />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue(nowAsStringWithSeconds) - }) - - test("uses the correct default dateFormat (H:i) in time-picker-only mode without seconds", async () => { - const now = new Date() - const hours = now.getHours().toString().padStart(2, "0") - const minutes = now.getMinutes().toString().padStart(2, "0") - const nowAsStringWithOnlyHoursAndMinutes = `${hours}:${minutes}` - render(<DateTimePicker enableTime noCalendar value={now} />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue( - nowAsStringWithOnlyHoursAndMinutes - ) - }) - - test("uses the correct defaultDateFormat (H:i:S) in time-picker-only mode with seconds enabled", async () => { - const now = new Date() - const hours = now.getHours().toString().padStart(2, "0") - const minutes = now.getMinutes().toString().padStart(2, "0") - const seconds = now.getSeconds().toString().padStart(2, "0") - const nowAsStringWithOnlyHoursMinutesAndSeconds = `${hours}:${minutes}:${seconds}` - render(<DateTimePicker enableTime enableSeconds noCalendar value={now} />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue( - nowAsStringWithOnlyHoursMinutesAndSeconds - ) - }) - - test("displays the date as passed as defaultDate instead of value or defaultDate", async () => { - render(<DateTimePicker defaultDate={new Date(2099, 0, 1)} />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue("2099-01-01") - }) - - test("displays the date as passed as defaultValue instead of value or defaultDate", async () => { - render(<DateTimePicker defaultValue={new Date(2099, 0, 1)} />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue("2099-01-01") - }) - - test("updates the date accordingly when value changes", async () => { - const { rerender } = render( - <DateTimePicker value={new Date(2024, 0, 12)} /> - ) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue("2024-01-12") - rerender(<DateTimePicker value={new Date(2025, 7, 18)} />) - expect(screen.getByRole("textbox")).toHaveValue("2025-08-18") - }) - - test("updates the date accordingly when defaultValue changes", async () => { - const { rerender } = render( - <DateTimePicker defaultValue={new Date(2024, 0, 12)} /> - ) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue("2024-01-12") - rerender(<DateTimePicker defaultValue={new Date(2025, 7, 18)} />) - expect(screen.getByRole("textbox")).toHaveValue("2025-08-18") - }) - - test("updates the date accordingly when defaultDate changes", async () => { - const { rerender } = render( - <DateTimePicker defaultDate={new Date(2024, 0, 12)} /> - ) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue("2024-01-12") - rerender(<DateTimePicker defaultDate={new Date(2025, 7, 18)} />) - expect(screen.getByRole("textbox")).toHaveValue("2025-08-18") - }) - - test("allows typing in the field when configured to do so", async () => { - render(<DateTimePicker allowInput />) - const input = screen.getByRole("textbox") - const user = userEvent.setup() - expect(input).toBeInTheDocument() - expect(input).toHaveValue("") - await userEvent.click(input) - await user.type(input, "12") - expect(input).toHaveValue("12") - }) - - test("updates accordingly when the allowInput prop changes", async () => { - const { rerender } = render(<DateTimePicker />) - const input = screen.getByRole("textbox") - const user = userEvent.setup() - expect(input).toBeInTheDocument() - expect(input).toHaveValue("") - expect(input).toHaveAttribute("readonly", "readonly") - rerender(<DateTimePicker allowInput />) - expect(input).toBeInTheDocument() - expect(input).toHaveValue("") - expect(input).not.toHaveAttribute("readonly") - await userEvent.click(input) - await user.type(input, "123") - expect(input).toHaveValue("123") - }) - - test("renders a DateTimePicker with week numbers as passed", async () => { - render(<DateTimePicker weekNumbers />) - const input = screen.getByRole("textbox") - const user = userEvent.setup() - expect(input).toBeInTheDocument() - // click to open the calendar: - await user.click(input) - expect(document.querySelector(".flatpickr-weekwrapper")).toBeInTheDocument() - expect(document.querySelector(".flatpickr-weekday")).toBeInTheDocument() - expect(document.querySelector(".flatpickr-weekday")).toHaveTextContent("Wk") - expect(document.querySelector(".flatpickr-weeks")).toBeInTheDocument() - expect(document.querySelector(".flatpickr-weeks").childElementCount).toBe(6) - }) - - test("renders a DateTimePicker in single mode per default", async () => { - render(<DateTimePicker />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute("data-mode", "single") - }) - - test("renders a DateTimePicker in multiple mode as passed", async () => { - render(<DateTimePicker mode="multiple" />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute("data-mode", "multiple") - }) - - test("renders a DateTimePicker in range mode as passed", async () => { - render(<DateTimePicker mode="range" />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute("data-mode", "range") - }) - - test("Updates the mode accordingly when the mode prop changes", async () => { - const { rerender } = render(<DateTimePicker />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute("data-mode", "single") - rerender(<DateTimePicker mode="range" />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute("data-mode", "range") - }) - - test("allows setting an otherwise invalid value on first load as configured ", async () => { - render( - <DateTimePicker - value="2024-01-30" - disable={["2024-01-30"]} - allowInvalidPreload - /> - ) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue("2024-01-30") - }) - - test("clicking the clear button clears the input", async () => { - render(<DateTimePicker value="2024-01-31" />) - const input = screen.getByRole("textbox") - const clearButton = screen.getByTitle("Clear") - const user = userEvent.setup() - expect(input).toBeInTheDocument() - expect(input).toHaveValue("2024-01-31") - expect(clearButton).toBeInTheDocument() - await user.click(clearButton) - expect(input).toHaveValue("") - }) - - test("sets a custom aria-label format for calendar dates as passed", async () => { - render(<DateTimePicker ariaDateFormat="l, F j, Y" />) - const input = screen.getByRole("textbox") - const user = userEvent.setup() - expect(input).toBeInTheDocument() - // click to open the calendar: - await user.click(input) - //Match something like "Monday, January 31, 2024" to pattern like [word, comma, space, word, space, one or two-digit number, comma, space, four-digit number] assuming this is precise enough: - expect( - document.querySelectorAll(".flatpickr-day")[0].getAttribute("aria-label") - ).toMatch(new RegExp(/^\b\w+\b, \b\w+\b \d{1,2}, \d{4}$/)) - }) - - test("uses a custom conjunction between dates in multiple mode as passed", async () => { - render( - <DateTimePicker - mode="multiple" - conjunction=" || " - value={["2024-02-01", "2099-03-12"]} - /> - ) - const input = screen.getByRole("textbox") - expect(input).toBeInTheDocument() - expect(input).toHaveValue("2024-02-01 || 2099-03-12") - }) - - test("updates the displayed value accordingly when the conjunction prop changes", async () => { - const { rerender } = render( - <DateTimePicker mode="multiple" value={["2024-02-01", "2099-03-12"]} /> - ) - const input = screen.getByRole("textbox") - expect(input).toBeInTheDocument() - expect(input).toHaveValue("2024-02-01, 2099-03-12") - rerender( - <DateTimePicker - mode="multiple" - value={["2024-02-01", "2099-03-12"]} - conjunction=" --- " - /> - ) - expect(input).toHaveValue("2024-02-01 --- 2099-03-12") - }) - - test("sets a default hour as passed", async () => { - render( - <DateTimePicker - enableTime={true} - dateFormat="Y-m-d H:i" - defaultHour={5} - /> - ) - const input = screen.getByRole("textbox") - const user = userEvent.setup() - expect(input).toBeInTheDocument() - await user.click(input) - const hourInput = document.querySelector("input.flatpickr-hour") - expect(hourInput).toHaveValue(5) - }) - - test("sets a default minute as passed", async () => { - render( - <DateTimePicker enableTime dateFormat="Y-m-d H:i" defaultMinute={13} /> - ) - const input = screen.getByRole("textbox") - const user = userEvent.setup() - expect(input).toBeInTheDocument() - await user.click(input) - const minuteInput = document.querySelector("input.flatpickr-minute") - expect(minuteInput).toHaveValue(13) - }) - - test("opens a calendar when clicking in the datepicker field", async () => { - render(<DateTimePicker />) - const input = screen.getByRole("textbox") - const calendar = document.querySelector(".flatpickr-calendar") - const user = userEvent.setup() - expect(input).toBeInTheDocument() - expect(calendar).toBeInTheDocument() - expect(calendar).not.toHaveClass("open") - await user.click(input) - expect(calendar).toHaveClass("open") - }) - - test("uses a custom hour increment as passed", async () => { - render( - <DateTimePicker enableTime dateFormat="Y-m-d H:i" hourIncrement={6} /> - ) - const hourInput = document.querySelector("input.flatpickr-hour") - expect(hourInput).toHaveAttribute("step", "6") - }) - - test("uses a custom minute increment as passed", async () => { - render( - <DateTimePicker enableTime dateFormat="Y-m-d H:i" minuteIncrement={7} /> - ) - const hourInput = document.querySelector("input.flatpickr-minute") - expect(hourInput).toHaveAttribute("step", "7") - }) - - test("does not allow selection of dates before a minDate as passed", async () => { - // Select yesterday element in calendar by label (formed like "January 31, 2024"), and test if disabled. - const user = userEvent.setup() - const today = new Date() - const yesterday = new Date() - yesterday.setDate(yesterday.getDate() - 1) - const fullMonth = yesterday.toLocaleString("default", { month: "long" }) - const day = yesterday.getDate() - const fullYear = yesterday.getFullYear() - const yesterdayLabel = `${fullMonth} ${day}, ${fullYear}` - render(<DateTimePicker minDate={today} />) - const input = screen.getByRole("textbox") - await user.click(input) - const yesterdayEl = screen.getByLabelText(yesterdayLabel) - expect(yesterdayEl).toHaveClass("flatpickr-disabled") - }) - - test("allows selection of dates after a minDate as passed", async () => { - const user = userEvent.setup() - const today = new Date() - const tomorrow = new Date() - tomorrow.setDate(tomorrow.getDate() + 1) - const fullMonth = tomorrow.toLocaleString("default", { month: "long" }) - const day = tomorrow.getDate() - const fullYear = tomorrow.getFullYear() - const tomorrowLabel = `${fullMonth} ${day}, ${fullYear}` - render(<DateTimePicker minDate={today} />) - const input = screen.getByRole("textbox") - await user.click(input) - const yesterdayEl = screen.getByLabelText(tomorrowLabel) - expect(yesterdayEl).not.toHaveClass("flatpickr-disabled") - }) - - test("does not allow selection of dates after a maxDate as passed", async () => { - const user = userEvent.setup() - const today = new Date() - const tomorrow = new Date() - tomorrow.setDate(tomorrow.getDate() + 1) - const tomorrowFullMonth = tomorrow.toLocaleString("default", { - month: "long", - }) - const tomorrowDay = tomorrow.getDate() - const tomorrowFullYear = tomorrow.getFullYear() - const tomorrowLabel = `${tomorrowFullMonth} ${tomorrowDay}, ${tomorrowFullYear}` - render(<DateTimePicker maxDate={today} />) - const input = screen.getByRole("textbox") - await user.click(input) - const tomorrowEl = screen.getByLabelText(tomorrowLabel) - expect(tomorrowEl).toHaveClass("flatpickr-disabled") - }) - - test("allows selection of dates before a maxDate as passed", async () => { - const user = userEvent.setup() - const today = new Date() - const tomorrow = new Date() - tomorrow.setDate(tomorrow.getDate() + 1) - const todayFullMonth = today.toLocaleString("default", { month: "long" }) - const todayDay = today.getDate() - const todayFullYear = today.getFullYear() - const todayLabel = `${todayFullMonth} ${todayDay}, ${todayFullYear}` - render(<DateTimePicker maxDate={tomorrow} />) - const input = screen.getByRole("textbox") - await user.click(input) - const todayEl = screen.getByLabelText(todayLabel) - expect(todayEl).not.toHaveClass("flatpickr-disabled") - }) - - test("renders a time picker only if configured to do so", async () => { - render(<DateTimePicker enableTime noCalendar />) - expect(document.querySelector(".flatpickr-days")).not.toBeInTheDocument() - expect(document.querySelector("input.flatpickr-hour")).toBeInTheDocument() - expect(document.querySelector("input.flatpickr-minute")).toBeInTheDocument() - }) - - test("executes an onOpen handler when the user clicks the Datepicker and the calendar opens", async () => { - const user = userEvent.setup() - render(<DateTimePicker onOpen={mockOnOpen} />) - const input = screen.getByRole("textbox") - await user.click(input) - expect(mockOnOpen).toHaveBeenCalled() - }) - - test("closes the calendar and executes an onClose handler when the user clicks outside the calendar", async () => { - const user = userEvent.setup() - render(<DateTimePicker onClose={mockOnClose} />) - const input = screen.getByRole("textbox") - await user.click(input) - await user.click(document.body) - expect(mockOnClose).toHaveBeenCalled() - }) - - test("executes an onClear handler when the user clears the DateTimePicker by clicking the clear icon", async () => { - render(<DateTimePicker value="2024-01-31" onClear={mockOnClear} />) - const input = screen.getByRole("textbox") - const clearButton = screen.getByTitle("Clear") - const user = userEvent.setup() - expect(input).toBeInTheDocument() - expect(input).toHaveValue("2024-01-31") - expect(clearButton).toBeInTheDocument() - await user.click(clearButton) - expect(mockOnClear).toHaveBeenCalled() - }) - - test("executes an onChange handler when the user changes the selected date", async () => { - const user = userEvent.setup() - const today = new Date() - const tomorrow = new Date() - tomorrow.setDate(tomorrow.getDate() + 1) - const tomorrowFullMonth = tomorrow.toLocaleString("default", { - month: "long", - }) - const tomorrowDay = tomorrow.getDate() - const tomorrowFullYear = tomorrow.getFullYear() - const tomorrowLabel = `${tomorrowFullMonth} ${tomorrowDay}, ${tomorrowFullYear}` - render(<DateTimePicker value={today} onChange={mockOnChange} />) - const input = screen.getByRole("textbox") - await user.click(input) - const tomorrowEl = screen.getByLabelText(tomorrowLabel) - await user.click(tomorrowEl) - expect(mockOnChange).toHaveBeenCalled() - }) - - test("executes an onYearChange handler when the user changes the year", async () => { - const user = userEvent.setup() - render(<DateTimePicker onYearChange={mockOnYearChange} />) - const input = screen.getByRole("textbox") - await user.click(input) - const yearInputUp = document.querySelector(".numInputWrapper > .arrowUp") - await user.click(yearInputUp) - expect(mockOnYearChange).toHaveBeenCalled() - }) - - test("executes an onMonthChange handler when the user changes the month by clicking an arrow", async () => { - const user = userEvent.setup() - render(<DateTimePicker onMonthChange={mockOnMonthChange} />) - const input = screen.getByRole("textbox") - await user.click(input) - const nextMonthButton = document.querySelector(".flatpickr-next-month") - await user.click(nextMonthButton) - expect(mockOnMonthChange).toHaveBeenCalled() - }) - - test("renders a className as passed", async () => { - render(<DateTimePicker className="my-custom-class" />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveClass("my-custom-class") - }) - - test("renders other props as passed", async () => { - render(<DateTimePicker data-lolol="527" />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute("data-lolol", "527") - }) -}) diff --git a/libs/juno-ui-components/src/components/DateTimePicker/datetimepicker.scss b/libs/juno-ui-components/src/components/DateTimePicker/datetimepicker.scss deleted file mode 100644 index 089f71a3c..000000000 --- a/libs/juno-ui-components/src/components/DateTimePicker/datetimepicker.scss +++ /dev/null @@ -1,831 +0,0 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors -// SPDX-License-Identifier: Apache-2.0 - -.theme-dark { - .juno-datetimepicker-input-default { - background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20width%3D'24'%20height%3D'24'%20viewBox%3D'0%200%2024%2024'%20fill%3D'rgb(222%2C%20223%2C%20224)'%3E%3Cpath%20d%3D'M20%203h-1V1h-2v2H7V1H5v2H4c-1.1%200-2%20.9-2%202v16c0%201.1.9%202%202%202h16c1.1%200%202-.9%202-2V5c0-1.1-.9-2-2-2zm0%2018H4V8h16v13z'%2F%3E%3C%2Fsvg%3E"); - } - .juno-datetimepicker-input-timepicker { - background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20width%3D'24'%20height%3D'24'%20viewBox%3D'0%200%2024%2024'%20fill%3D'rgb(222%2C%20223%2C%20224)'%3E%3Cpath%20d%3D'M11.99%202C6.47%202%202%206.48%202%2012s4.47%2010%209.99%2010C17.52%2022%2022%2017.52%2022%2012S17.52%202%2011.99%202zM12%2020c-4.42%200-8-3.58-8-8s3.58-8%208-8%208%203.58%208%208-3.58%208-8%208z'%2F%3E%3Cpath%20d%3D'M12.5%207H11v6l5.25%203.15.75-1.23-4.5-2.67z'%2F%3E%3C%2Fsvg%3E"); - } -} - -.theme-light { - .juno-datetimepicker-input-default { - background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20width%3D'24'%20height%3D'24'%20viewBox%3D'0%200%2024%2024'%20fill%3D'rgb(64%2C%2064%2C%2064)'%3E%3Cpath%20d%3D'M20%203h-1V1h-2v2H7V1H5v2H4c-1.1%200-2%20.9-2%202v16c0%201.1.9%202%202%202h16c1.1%200%202-.9%202-2V5c0-1.1-.9-2-2-2zm0%2018H4V8h16v13z'%2F%3E%3C%2Fsvg%3E"); - } - .juno-datetimepicker-input-timepicker { - background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20width%3D'24'%20height%3D'24'%20viewBox%3D'0%200%2024%2024'%20fill%3D'rgb(64%2C%2064%2C%2064)'%3E%3Cpath%20d%3D'M11.99%202C6.47%202%202%206.48%202%2012s4.47%2010%209.99%2010C17.52%2022%2022%2017.52%2022%2012S17.52%202%2011.99%202zM12%2020c-4.42%200-8-3.58-8-8s3.58-8%208-8%208%203.58%208%208-3.58%208-8%208z'%2F%3E%3Cpath%20d%3D'M12.5%207H11v6l5.25%203.15.75-1.23-4.5-2.67z'%2F%3E%3C%2Fsvg%3E"); - } -} - -.flatpickr-calendar { - background: transparent; - color: var(--color-text-default); - opacity: 0; - display: none; - text-align: center; - visibility: hidden; - padding: 0; - -webkit-animation: none; - animation: none; - direction: ltr; - border: 0; - font-size: 0.875rem; - line-height: 1.5rem; - 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: var(--color-datepicker-calendar-bg); - // -webkit-box-shadow: 1px 0 0 #20222c, -1px 0 0 #20222c, 0 1px 0 #20222c, 0 -1px 0 #20222c, 0 3px 13px rgba(0,0,0,0.08); - // box-shadow: 1px 0 0 #20222c, -1px 0 0 #20222c, 0 1px 0 #20222c, 0 -1px 0 #20222c, 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; - margin-top: 2px; -} -.flatpickr-calendar.open:not(.inline) { - &[style]:not(.inline) { - top: auto !important; - left: auto !important; - } -} -.flatpickr-calendar.animate.open { - -webkit-animation: fpFadeInDown 300ms cubic-bezier(0.23, 1, 0.32, 1); - animation: fpFadeInDown 300ms cubic-bezier(0.23, 1, 0.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.hasTime .flatpickr-time { - height: 40px; - // border-top: 1px solid #20222c; -} -.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.arrowRight:before, -// .flatpickr-calendar.rightMost:after, -// .flatpickr-calendar.arrowRight:after { -// left: auto; -// right: 22px; -// } -// .flatpickr-calendar.arrowCenter:before, -// .flatpickr-calendar.arrowCenter:after { -// left: 50%; -// right: 50%; -// } -// .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: #20222c; -// } -// .flatpickr-calendar.arrowTop:after { -// border-bottom-color: #3f4458; -// } -// .flatpickr-calendar.arrowBottom:before, -// .flatpickr-calendar.arrowBottom:after { -// top: 100%; -// } -// .flatpickr-calendar.arrowBottom:before { -// border-top-color: #20222c; -// } -// .flatpickr-calendar.arrowBottom:after { -// border-top-color: #3f4458; -//} -.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: var(--color-datepicker-calendar-bg); - color: #fff; - fill: #fff; - 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 { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - text-decoration: none; - cursor: pointer; - position: absolute; - top: 0; - height: 34px; - padding: 10px; - z-index: 3; - color: #fff; - fill: #fff; -} -.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: #eee; -} -.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 0.1s; - transition: fill 0.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(255, 255, 255, 0.15); - -webkit-box-sizing: border-box; - box-sizing: border-box; -} -.numInputWrapper span:hover { - background: rgba(192, 187, 167, 0.1); -} -.numInputWrapper span:active { - background: rgba(192, 187, 167, 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(255, 255, 255, 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(255, 255, 255, 0.6); - top: 40%; -} -.numInputWrapper span svg { - width: inherit; - height: auto; -} -.numInputWrapper span svg path { - fill: rgba(255, 255, 255, 0.5); -} -.numInputWrapper:hover { - background: rgba(192, 187, 167, 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(0px, 0px, 0px); - transform: translate3d(0px, 0px, 0px); -} -.flatpickr-current-month span.cur-month { - font-family: inherit; - font-weight: 700; - color: inherit; - display: inline-block; - margin-left: 0.5ch; - padding: 0; -} -.flatpickr-current-month span.cur-month:hover { - background: rgba(192, 187, 167, 0.05); -} -.flatpickr-current-month .numInputWrapper { - width: 6ch; - width: 7ch\0; - display: inline-block; -} -.flatpickr-current-month .numInputWrapper span.arrowUp:after { - border-bottom-color: #fff; -} -.flatpickr-current-month .numInputWrapper span.arrowDown:after { - border-top-color: #fff; -} -.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 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(255, 255, 255, 0.5); - background: transparent; - pointer-events: none; -} -.flatpickr-current-month .flatpickr-monthDropdown-months { - appearance: menulist; - background: var(--color-datepicker-calendar-bg); - border: none; - border-radius: 0; - box-sizing: border-box; - 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 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(192, 187, 167, 0.05); -} -.flatpickr-current-month - .flatpickr-monthDropdown-months - .flatpickr-monthDropdown-month { - background-color: #3f4458; - 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: #3f4458; - color: var(--color-text-default); - 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(0px, 0px, 0px); - transform: translate3d(0px, 0px, 0px); - opacity: 1; -} -.dayContainer + .dayContainer { - -webkit-box-shadow: -1px 0 0 #20222c; - box-shadow: -1px 0 0 #20222c; -} -.flatpickr-day { - background: none; - border: 1px solid transparent; - border-radius: 150px; - -webkit-box-sizing: border-box; - box-sizing: border-box; - color: var(--color-text-default); - 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: #646c8c; - border-color: #646c8c; -} -.flatpickr-day.today { - border-color: var(--color-text-default); -} -.flatpickr-day.today:hover, -.flatpickr-day.today:focus { - border-color: var(--color-text-default); - background: #eee; - color: var(--color-text-default); -} -.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: var(--color-accent); - -webkit-box-shadow: none; - box-shadow: none; - color: #fff; - border-color: var(--color-accent); -} -.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 #80cbc4; - box-shadow: -10px 0 0 #80cbc4; -} -.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 #646c8c, 5px 0 0 #646c8c; - box-shadow: -5px 0 0 #646c8c, 5px 0 0 #646c8c; -} -.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); - background: transparent; - border-color: transparent; - cursor: default; -} -.flatpickr-day.flatpickr-disabled, -.flatpickr-day.flatpickr-disabled:hover { - cursor: not-allowed; - color: rgba(255, 255, 255, 0.1); -} -.flatpickr-day.week.selected { - border-radius: 0; - -webkit-box-shadow: -5px 0 0 #80cbc4, 5px 0 0 #80cbc4; - box-shadow: -5px 0 0 #80cbc4, 5px 0 0 #80cbc4; -} -.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 #20222c; - box-shadow: 1px 0 0 #20222c; -} -.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(255, 255, 255, 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: rgba(255, 255, 255, 0.95); -} -.flatpickr-time .numInputWrapper span.arrowDown:after { - border-top-color: rgba(255, 255, 255, 0.95); -} -.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: var(--color-text-default); - 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: rgba(255, 255, 255, 0.95); - 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: #6a7395; -} -.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); - } -} diff --git a/libs/juno-ui-components/src/components/DateTimePicker/index.js b/libs/juno-ui-components/src/components/DateTimePicker/index.js deleted file mode 100644 index 8b93e8fd1..000000000 --- a/libs/juno-ui-components/src/components/DateTimePicker/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { DateTimePicker } from "./DateTimePicker.component.js" diff --git a/libs/juno-ui-components/src/components/FilterInput/FilterInput.component.js b/libs/juno-ui-components/src/components/FilterInput/FilterInput.component.js deleted file mode 100644 index b451b6d2f..000000000 --- a/libs/juno-ui-components/src/components/FilterInput/FilterInput.component.js +++ /dev/null @@ -1,232 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useState, useEffect } from "react" -import PropTypes from "prop-types" -import { NativeSelect } from "../NativeSelect/NativeSelect.component" -import { NativeSelectOption } from "../NativeSelectOption/NativeSelectOption.component" -import { TextInput } from "../TextInput/TextInput.component" -import { Icon } from "../Icon/Icon.component" - -const wrapperStyles = ` - jn-flex - jn-relative - jn-p-px - jn-border - jn-rounded - jn-bg-theme-filter-input -` - -const defaultWrapperStyles = ` - jn-border-theme-filter-input -` - -const errorWrapperStyles = ` - jn-border-theme-error -` - -const selectStyles = ` - jn-rounded-r-none -` - -const textInputStyles = ` - jn-grow - jn-rounded-l-none - jn-pr-16 - !jn-bg-theme-filter-input-textinput - focus:jn-z-40 -` - -const iconWrapperStyles = ` - jn-absolute - jn-flex - jn-right-2 - jn-top-1.5 - jn-z-50 -` - -/** --- Deprectated. For new implementations, use InputGroup and combine/compose input components as you need them. -- -A special Input to select key and value of a filter. -*/ -export const FilterInput = ({ - keyLabel, - options, - valueLabel, - className, - selectedFilterKey, - onSelectedFilterKeyChange, - filterValue, - valuePlaceholder, - onFilterValueChange, - onClear, - onKeyPress, - onFilter, - loading, - error, - ...props -}) => { - const [selectedFilter, setSelectedFilter] = useState(selectedFilterKey) - const [value, setValue] = useState(filterValue) - const [isLoading, setIsLoading] = useState(options.length < 1 || loading) - const [hasError, setHasError] = useState(error) - - useEffect(() => { - setValue(filterValue) - }, [filterValue]) - - useEffect(() => { - setSelectedFilter(selectedFilterKey) - }, [selectedFilterKey]) - - // Reset the (text input) value whenever the component is loading: - useEffect(() => { - if (options.length < 1 || loading) { - setIsLoading(true) - setValue("") - } else { - setIsLoading(false) - } - }, [options, loading]) - - useEffect(() => { - setHasError(error) - }, [error]) - - // Reset the (text input) value whenever the selected Filter key changes: - const handleSelectedFilterChange = (event) => { - setSelectedFilter(event.target.value) - setValue("") - onSelectedFilterKeyChange && onSelectedFilterKeyChange(event) - } - - const handleFilterValueChange = (event) => { - setValue(event.target.value) - onFilterValueChange && onFilterValueChange(event) - } - - const handleClearClick = (event) => { - setValue("") - onClear && onClear(event) - } - - const handleFilterClick = () => { - onFilter && onFilter(value) - } - - const handleKeyPress = (event) => { - if (event.key === "Enter" && onFilter) { - onFilter && onFilter(value) - } - onKeyPress && onKeyPress(event) - } - - return ( - <div - className={`juno-filter-input ${wrapperStyles} ${ - isLoading ? "juno-filter-input-loading " : "" - } ${hasError ? "juno-filter-input-error " : ""} ${ - hasError ? errorWrapperStyles : defaultWrapperStyles - } ${className}`} - {...props} - > - <div> - <NativeSelect - className={`juno-filter-input-select ${selectStyles}`} - aria-label={keyLabel} - value={selectedFilter} - onChange={handleSelectedFilterChange} - loading={isLoading} - error={hasError} - > - // First "Placeholder" option: - <NativeSelectOption label={keyLabel || "Select Filter"} value="" /> - // Options representing actual filter key values: - {options.map((option, i) => ( - <NativeSelectOption - label={option.label} - value={option.key} - key={`${i}`} - {...option} - /> - ))} - </NativeSelect> - </div> - <TextInput - value={value} - className={`${textInputStyles}`} - aria-label={valueLabel} - onChange={handleFilterValueChange} - onKeyPress={handleKeyPress} - disabled={isLoading || hasError} - placeholder={isLoading ? "Loading Filter Options…" : valuePlaceholder} - /> - <div className={`${iconWrapperStyles}`}> - {value && value.length ? ( - <Icon - icon="close" - title="Clear" - size="18" - className={`jn-mr-2`} - onClick={handleClearClick} - /> - ) : null} - <Icon - icon="filterAlt" - title="Filter" - disabled={isLoading || hasError} - onClick={handleFilterClick} - /> - </div> - </div> - ) -} - -FilterInput.propTypes = { - /** The label to display on the Filter Key Select */ - keyLabel: PropTypes.string, - /** The options for the Filter Select: `[{Label: "Filter 1", key: "filter-1"}, {...}]` - The array MUST have a length in order for the component to render. - */ - options: PropTypes.arrayOf(PropTypes.object), - /** The key of the current filter */ - selectedFilterKey: PropTypes.string, - /** Pass a handler to be executed when the filter key changes */ - onSelectedFilterKeyChange: PropTypes.func, - /** The aria-label of the Filter Value Text Input */ - valueLabel: PropTypes.string, // TODO -> valueLabel - /** The current value of the Filter Input */ - filterValue: PropTypes.string, - /** Optional: pass a placeholder for the filter value text input */ - valuePlaceholder: PropTypes.string, - /** Pass a handler to be executed when the filter value changes */ - onFilterValueChange: PropTypes.func, - /** Pass a handler to execute when the Filter Value Clear button is clicked */ - onClear: PropTypes.func, - /** Whether the filter is currently loading */ - loading: PropTypes.bool, - /** Pass a className to the wrapping element */ - className: PropTypes.string, - /** Pass a handler to execute when the Filter Value Filter button is clicked */ - onFilter: PropTypes.func, - /** Whether the FilterInput has an error */ - error: PropTypes.bool, -} - -FilterInput.defaultProps = { - keyLabel: "Select Filter", - options: [], - selectedFilterKey: "", - onSelectedFilterKeyChange: undefined, - valueLabel: "Filter by Value", - filterValue: "", - valuePlaceholder: "", - onFilterValueChange: undefined, - onClear: undefined, - onFilter: undefined, - loading: false, - className: "", - error: false, -} diff --git a/libs/juno-ui-components/src/components/FilterInput/FilterInput.stories.js b/libs/juno-ui-components/src/components/FilterInput/FilterInput.stories.js deleted file mode 100644 index 462de25f3..000000000 --- a/libs/juno-ui-components/src/components/FilterInput/FilterInput.stories.js +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { FilterInput } from './index.js'; - -export default { - title: 'Deprecated/Filter/FilterInput', - component: FilterInput, - argTypes: {}, -}; - -export const Default = { - args: { - valuePlaceholder: 'Enter a value', - options: [ - { label: 'Filter 1', key: 'filter-1' }, - { label: 'Filter 2', key: 'filter-2', disabled: true }, - { label: 'Filter 3', key: 'filter-3' }, - ], - }, -}; - -export const Preselected = { - args: { - keyLabel: 'Select a fancy Filter', - selectedFilterKey: 'filter-2', - options: [ - { label: 'Filter 1', key: 'filter-1' }, - { label: 'Filter 2', key: 'filter-2' }, - { label: 'Filter 3', key: 'filter-3' }, - ], - }, -}; - -export const Loading = { - args: { - options: [], - loading: true, - }, -}; - -export const WithError = { - args: { - options: [], - error: true, - }, -}; diff --git a/libs/juno-ui-components/src/components/FilterInput/FilterInput.test.js b/libs/juno-ui-components/src/components/FilterInput/FilterInput.test.js deleted file mode 100644 index 68cca4ea4..000000000 --- a/libs/juno-ui-components/src/components/FilterInput/FilterInput.test.js +++ /dev/null @@ -1,281 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen, fireEvent } from "@testing-library/react" -import userEvent from "@testing-library/user-event" -import { FilterInput } from "./index" - -describe("FilterInput", () => { - test("renders a FilterInput", async () => { - render(<FilterInput data-testid="filter-input" />) - expect(screen.getByTestId("filter-input")).toBeInTheDocument() - expect(screen.getByTestId("filter-input")).toHaveClass("juno-filter-input") - }) - - test("renders a FilterInput with a Select and a TextInput", async () => { - render(<FilterInput />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toBeInTheDocument() - }) - - test("renders a Select with an aria-label as passed", async () => { - render(<FilterInput keyLabel={"my select"} />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toHaveAttribute( - "aria-label", - "my select" - ) - }) - - test("renders a Select with a default option selected if no selectedFilterKey is passed", async () => { - render(<FilterInput />) - expect( - screen.getByRole("option", { name: "Select Filter" }) - ).toBeInTheDocument() - expect(screen.getByRole("option", { name: "Select Filter" }).selected).toBe( - true - ) - }) - - test("renders a Select with a default option as passed", async () => { - render(<FilterInput keyLabel="My Custom Key Label" />) - expect( - screen.getByRole("option", { name: "My Custom Key Label" }) - ).toBeInTheDocument() - expect( - screen.getByRole("option", { name: "My Custom Key Label" }).selected - ).toBe(true) - }) - - test("renders a select with options and values as passed", async () => { - render( - <FilterInput - options={[ - { label: "option 1", value: "option-1" }, - { label: "option 2", value: "option-2" }, - ]} - /> - ) - expect(screen.getByRole("option", { name: "option 1" })).toHaveValue( - "option-1" - ) - expect(screen.getByRole("option", { name: "option 2" })).toHaveValue( - "option-2" - ) - }) - - test("renders a select with arbitrary props for options", async () => { - render( - <FilterInput - options={[ - { label: "option 1", value: "option-1", disabled: true }, - { label: "option 2", value: "option-2" }, - ]} - /> - ) - expect(screen.getByRole("option", { name: "option 1" })).toHaveValue( - "option-1" - ) - expect(screen.getByRole("option", { name: "option 1" })).toBeDisabled() - }) - - test("renders a text input with an aria-label as passed", async () => { - render(<FilterInput valueLabel={"my value input"} />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute( - "aria-label", - "my value input" - ) - }) - - test("renders a text input with a placeholder as passed", async () => { - render( - <FilterInput - options={[ - { label: "option 1", value: "option-1", disabled: true }, - { label: "option 2", value: "option-2" }, - ]} - valuePlaceholder={"my value placeholder"} - /> - ) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute( - "placeholder", - "my value placeholder" - ) - }) - - test("renders a selected filter as passed", async () => { - const filterOptions = [ - { label: "OS", value: "byOs" }, - { label: "Region", value: "byRegion" }, - ] - render(<FilterInput options={filterOptions} selectedFilterKey="byRegion" />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("option", { name: "Region" }).selected).toBe(true) - }) - - test("allows users to change the filter key", async () => { - const filters = [ - { label: "OS", value: "byOs" }, - { label: "Region", value: "byRegion" }, - { label: "Time Zone", value: "byTimezone" }, - ] - render(<FilterInput options={filters} />) - await userEvent.selectOptions( - screen.getByRole("combobox"), - screen.getByRole("option", { name: "Time Zone" }) - ) - expect(screen.getByRole("option", { name: "Time Zone" }).selected).toBe( - true - ) - }) - - test("should reset the filter value when the selected filter key changes", async () => { - const filters = [ - { label: "OS", value: "byOs" }, - { label: "Region", value: "byRegion" }, - { label: "Time Zone", value: "byTimezone" }, - ] - render(<FilterInput options={filters} filterValue="MacOS" />) - expect(screen.getByRole("textbox")).toHaveValue("MacOS") - await userEvent.selectOptions( - screen.getByRole("combobox"), - screen.getByRole("option", { name: "Region" }) - ) - expect(screen.getByRole("textbox")).toHaveValue("") - }) - - test("executes a handler as passed when selected filter key changes", async () => { - const handleSelectedFilterChange = jest.fn() - const filters = [ - { label: "OS", key: "byOs" }, - { label: "Region", key: "byRegion" }, - { label: "Time Zone", key: "byTimezone" }, - ] - render( - <FilterInput - options={filters} - selectedFilterKey="byRegion" - onSelectedFilterKeyChange={handleSelectedFilterChange} - /> - ) - expect(screen.getByRole("option", { name: "Region" }).selected).toBe(true) - await userEvent.selectOptions( - screen.getByRole("combobox"), - screen.getByRole("option", { name: "OS" }) - ) - expect(screen.getByRole("option", { name: "OS" }).selected).toBe(true) - expect(handleSelectedFilterChange).toHaveBeenCalledTimes(1) - }) - - test("renders a FilterInput with a value as passed", async () => { - const opts = [{ label: "something", key: "something" }] - render(<FilterInput options={opts} filterValue="123abc" />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue("123abc") - }) - - test("renders a Close button when the Input has a value", async () => { - const opts = [{ label: "something", key: "something" }] - render(<FilterInput options={opts} filterValue="123" />) - expect(screen.getByTitle("Clear")).toBeInTheDocument() - }) - - test("executes a handler as passed when the input value changes", async () => { - const opts = [{ label: "A Filter", key: "a-filter" }] - const handleFilterValueChange = jest.fn() - render( - <FilterInput - options={opts} - onFilterValueChange={handleFilterValueChange} - /> - ) - await userEvent.type(screen.getByRole("textbox"), "987") - expect(handleFilterValueChange).toHaveBeenCalledTimes(3) - }) - - test("empties the field when Clear button is clicked", async () => { - const opts = [{ label: "something", key: "something" }] - render(<FilterInput options={opts} filterValue="abc" />) - expect(screen.getByTitle("Clear")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue("abc") - await userEvent.click(screen.getByTitle("Clear")) - expect(screen.getByRole("textbox")).toHaveValue("") - }) - - test("executes onFilter handler as passed when Filter icon is clicked and return the text input value", async () => { - const handleFilter = jest.fn() - const opts = [{ label: "A Filter", key: "a-filter" }] - render( - <FilterInput options={opts} filterValue="abc" onFilter={handleFilter} /> - ) - await userEvent.click(screen.getByTitle("Filter")) - expect(handleFilter).toHaveBeenCalledTimes(1) - expect(handleFilter).toHaveBeenCalledWith("abc") - }) - - test("executes onFilter handler as passed when the input has focus and the user presses enter and return the text input value", async () => { - const handleFilter = jest.fn() - const opts = [{ label: "A Filter", key: "a-filter" }] - render( - <FilterInput options={opts} filterValue="abc" onFilter={handleFilter} /> - ) - await userEvent.type(screen.getByRole("textbox"), "{enter}") - expect(handleFilter).toHaveBeenCalledTimes(1) - expect(handleFilter).toHaveBeenCalledWith("abc") - }) - - test("renders loading filter input as passed", async () => { - render(<FilterInput loading />) - expect(screen.getByRole("combobox")).toBeDisabled() - expect(screen.getByRole("textbox")).toBeDisabled() - expect(screen.getByRole("progressbar")).toBeInTheDocument() - }) - - test("renders a loading filter if passed options are present but empty", async () => { - const filters = [] - render(<FilterInput options={filters} />) - expect(screen.getByRole("combobox")).toBeDisabled() - expect(screen.getByRole("textbox")).toBeDisabled() - expect(screen.getByRole("progressbar")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeDisabled() - }) - - test("renders loading filter as passed even if options are present and not empty", async () => { - const opts = [{ label: "A Filter", key: "a-filter" }] - render(<FilterInput options={opts} loading />) - expect(screen.getByRole("combobox")).toBeDisabled() - expect(screen.getByRole("textbox")).toBeDisabled() - expect(screen.getByRole("progressbar")).toBeInTheDocument() - }) - - test("renders a filter input with an error as passed", async () => { - const opts = [{ label: "A Filter", key: "a-filter" }] - render(<FilterInput options={opts} error />) - expect(screen.getByRole("combobox")).toBeDisabled() - expect(screen.getByRole("textbox")).toBeDisabled() - expect(screen.getByTitle("Error")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeDisabled() - }) - - test("renders a custom class to the row as passed", async () => { - render( - <FilterInput data-testid="filter-input" className="my-custom-class" /> - ) - expect(screen.getByTestId("filter-input")).toBeInTheDocument() - expect(screen.getByTestId("filter-input")).toHaveClass("my-custom-class") - }) - - test("renders all props as passed", async () => { - render(<FilterInput data-testid="filter-input" data-lolol="some-prop" />) - expect(screen.getByTestId("filter-input")).toBeInTheDocument() - expect(screen.getByTestId("filter-input")).toHaveAttribute( - "data-lolol", - "some-prop" - ) - }) -}) diff --git a/libs/juno-ui-components/src/components/FilterInput/index.js b/libs/juno-ui-components/src/components/FilterInput/index.js deleted file mode 100644 index bcf866f65..000000000 --- a/libs/juno-ui-components/src/components/FilterInput/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { FilterInput } from "./FilterInput.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/FilterPill/FilterPill.component.js b/libs/juno-ui-components/src/components/FilterPill/FilterPill.component.js deleted file mode 100644 index 3fbb74e5f..000000000 --- a/libs/juno-ui-components/src/components/FilterPill/FilterPill.component.js +++ /dev/null @@ -1,100 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" -import { Icon } from "../Icon/Icon.component.js" - -const filterpillStyles = ` - jn-inline-flex - jn-basis-auto - jn-shrink - jn-items-center - jn-flex-nowrap - jn-text-xs - jn-p-px - jn-border - jn-rounded - jn-mr-2 - jn-border-theme-filter-pill - last:jn-mr-0 -` - -const filterkeyStyles = ` - jn-bg-theme-filter-pill-key - jn-px-1 - jn-py-0.5 - jn-rounded-sm - jn-text-theme-high - jn-inline-block -` - -const filtervalueStyles = ` - jn-px-1 - jn-py-0.5 - jn-text-theme-high - jn-inline-block -` - -/** --- Deprecated. For new implementations, use Pill instead.--\n -A Pill to represent Key and Value of a filter. Can be closed to un-apply the filter represented. -Mostly to be used inside a Filters component in conjunction with FilterInput. */ -export const FilterPill = ({ - uid, - filterKey, - filterKeyLabel, - filterValue, - filterValueLabel, - onClose, - className, - ...props -}) => { - const handleCloseClick = () => { - onClose && onClose(uid || filterKey) - } - - return ( - <div - className={`juno-filterpill ${filterpillStyles} ${className}`} - {...props} - > - <span className={`${filterkeyStyles}`}> - {filterKeyLabel || filterKey} - </span> - <span className={`${filtervalueStyles}`}> - {filterValueLabel || filterValue} - </span> - <Icon icon="close" size="18" onClick={handleCloseClick} /> - </div> - ) -} - -FilterPill.propTypes = { - /** The unique identifier of the pill. Returned by the onClose callback */ - uid: PropTypes.string, - /** The key of the filter the pill represents. Returned by the onClose callback if uid undefined */ - filterKey: PropTypes.string.isRequired, - /** The visible label to describe the filter key. If not set filterKey is used */ - filterKeyLabel: PropTypes.string, - /** The value of filter the pill represents */ - filterValue: PropTypes.string.isRequired, - /** The visible label to describe the filter value. If not set filterValue is used */ - filterValueLabel: PropTypes.string, - /** add custom classNames */ - className: PropTypes.string, - /** Pass a handler to be executed when closing the FilterPill */ - onClose: PropTypes.func, -} - -FilterPill.defaultProps = { - uid: "", - filterKey: "", - filterKeyLabel: "", - filterValue: "", - filterValueLabel: "", - onClose: undefined, - className: "", -} diff --git a/libs/juno-ui-components/src/components/FilterPill/FilterPill.stories.js b/libs/juno-ui-components/src/components/FilterPill/FilterPill.stories.js deleted file mode 100644 index 32c91be24..000000000 --- a/libs/juno-ui-components/src/components/FilterPill/FilterPill.stories.js +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { FilterPill } from './index.js'; - -export default { - title: 'Deprecated/Filter/FilterPill', - component: FilterPill, - argTypes: {}, -}; - -export const Default = { - args: { - filterKey: 'os', - filterKeyLabel: 'OS', - filterValue: 'mac_os', - filterValueLabel: 'Mac OS', - }, -}; diff --git a/libs/juno-ui-components/src/components/FilterPill/FilterPill.test.js b/libs/juno-ui-components/src/components/FilterPill/FilterPill.test.js deleted file mode 100644 index d33543200..000000000 --- a/libs/juno-ui-components/src/components/FilterPill/FilterPill.test.js +++ /dev/null @@ -1,133 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { FilterPill } from "./index" - -describe("FilterPill", () => { - test("renders a FilterPill", async () => { - render( - <FilterPill - data-testid="my-filterpill" - filterKey="TheRequiredKey" - filterValue="TheRequiredValue" - /> - ) - expect(screen.getByTestId("my-filterpill")).toBeInTheDocument() - expect(screen.getByTestId("my-filterpill")).toHaveClass("juno-filterpill") - }) - - test("renders a filter key label as passed", async () => { - render( - <FilterPill - filterKeyLabel="My FilterPill Key" - filterKey="TheRequiredKey" - filterValue="TheRequiredValue" - /> - ) - expect(screen.getByText("My FilterPill Key")).toBeInTheDocument() - }) - - test("renders a filter key if filter key label missing", async () => { - render( - <FilterPill - filterKey="my_filterPill_key" - filterValue="TheRequiredValue" - /> - ) - expect(screen.getByText("my_filterPill_key")).toBeInTheDocument() - }) - - test("renders nothing if filter key label not set", async () => { - // the attribute filterKey and filterValue are required keep them empty to test render nothing - render(<FilterPill data-testid="23" filterKey="" filterValue="" />) - expect(screen.getByTestId("23")).toBeInTheDocument() - expect(screen.getByTestId("23")).toHaveTextContent("") - }) - - test("renders a filter value label as passed", async () => { - render( - <FilterPill - filterValue="TheRequiredValue" - filterValueLabel="My FilterPill Value" - filterKey="TheRequiredKey" - /> - ) - expect(screen.getByText("My FilterPill Value")).toBeInTheDocument() - }) - - test("renders a filter value if value label missing", async () => { - render( - <FilterPill - filterKey="TheRequiredKey" - filterValue="my_filterPill_value" - /> - ) - expect(screen.getByText("my_filterPill_value")).toBeInTheDocument() - }) - - test("renders nothing if filter value or value label not given", async () => { - // the attribute filterKey and filterValue are required keep them empty to test render nothing - render(<FilterPill data-testid="23" filterKey="" filterValue="" />) - expect(screen.getByTestId("23")).toBeInTheDocument() - expect(screen.getByTestId("23")).toHaveTextContent("") - }) - - test("an onClose handler is called as passed and returns the uid", () => { - const handleClose = jest.fn() - render( - <FilterPill - uid="uidAbc" - filterKey="TheRequiredKey" - filterValue="TheRequiredValue" - onClose={handleClose} - /> - ) - screen.getByRole("button").click() - expect(handleClose).toHaveBeenCalledTimes(1) - expect(handleClose).toHaveBeenCalledWith("uidAbc") - }) - - test("an onClose handler is called as passed and returns the filterKey if uid missing", () => { - const handleClose = jest.fn() - render( - <FilterPill - filterKey="abc" - filterValue="TheRequiredValue" - onClose={handleClose} - /> - ) - screen.getByRole("button").click() - expect(handleClose).toHaveBeenCalledTimes(1) - expect(handleClose).toHaveBeenCalledWith("abc") - }) - - test("renders a custom className", async () => { - render( - <FilterPill - data-testid="my-filterpill" - filterKey="TheRequiredKey" - filterValue="TheRequiredValue" - className="my-custom-class" - /> - ) - expect(screen.getByTestId("my-filterpill")).toBeInTheDocument() - expect(screen.getByTestId("my-filterpill")).toHaveClass("my-custom-class") - }) - - test("renders all props as passed", async () => { - render( - <FilterPill - data-testid="23" - filterKey="TheRequiredKey" - filterValue="TheRequiredValue" - data-lolol={true} - /> - ) - expect(screen.getByTestId("23")).toBeInTheDocument() - expect(screen.getByTestId("23")).toHaveAttribute("data-lolol") - }) -}) diff --git a/libs/juno-ui-components/src/components/FilterPill/index.js b/libs/juno-ui-components/src/components/FilterPill/index.js deleted file mode 100644 index fbe4060a0..000000000 --- a/libs/juno-ui-components/src/components/FilterPill/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { FilterPill } from "./FilterPill.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Filters/Filters.component.js b/libs/juno-ui-components/src/components/Filters/Filters.component.js deleted file mode 100644 index c7d35d204..000000000 --- a/libs/juno-ui-components/src/components/Filters/Filters.component.js +++ /dev/null @@ -1,167 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useState, useEffect } from "react" -import PropTypes from "prop-types" -import { FilterInput } from "../FilterInput/FilterInput.component" - -const filterStyles = ` - jn-mb-px - jn-bg-theme-filters - jn-rounded-t - jn-pt-4 - jn-px-4 - jn-pb-2 -` - -const inputWrapperStyles = ` - jn-w-full - jn-flex - jn-mb-2 -` - -const searchWrapperStyles = ` - jn-ml-auto -` - -const filterPillWrapperStyles = ` - jn-flex - jn-flex-wrap -` - -const errortextStyles = ` - jn-text-theme-error - jn-text-sm - jn-mt-[-0.25rem] - jn-mb-1.5 -` -/** --- Deprecated. For new implementations, combine and compose Input Group, Inputs and Pills as needed. -- -A component to hold a FilterInput, resulting FilterPills, and optional SearchBar for any filter-able content. -*/ - -export const Filters = ({ - search, - filters, - selectedFilterKey, - onSelectedFilterKeyChange, - filterValue, - valuePlaceholder, - onFilterValueChange, - onFilter, - onFilterClear, - children, - className, - loading, - error, - errortext, - ...props -}) => { - const [isLoading, setIsLoading] = useState(false) - const [hasError, setHasError] = useState(false) - - useEffect(() => { - // AP: empty string and boolean results in empty string - // "" && true => "" - // This causes hasError to become a string. Further down, hasError is - // passed on to the TextInput, whose type check logs a warning - // To prevet that check the type of errortext instead! - setHasError( - error || (typeof errortext === "string" && errortext.length > 0) - ) - }, [error, errortext]) - - useEffect(() => { - setIsLoading(loading) - }, [loading]) - - return ( - <div - className={`juno-filters ${ - hasError ? "juno-filters-error " : "" - } ${filterStyles} ${className}`} - {...props} - > - <div className={`juno-filters-input-wrapper ${inputWrapperStyles}`}> - {filters && filters.options ? ( - <FilterInput - keyLabel={filters.keyLabel} - valueLabel={filters.valueLabel} - options={filters.options} - selectedFilterKey={selectedFilterKey} - onSelectedFilterKeyChange={onSelectedFilterKeyChange} - filterValue={filterValue} - valuePlaceholder={valuePlaceholder} - onFilterValueChange={onFilterValueChange} - onFilter={onFilter} - onClear={onFilterClear} - loading={isLoading} - error={hasError} - /> - ) : null} - {search ? ( - <div className={`${searchWrapperStyles}`}>{search}</div> - ) : null} - </div> - {hasError && errortext ? ( - <div className={`juno-filters-errortext ${errortextStyles}`}> - {errortext} - </div> - ) : ( - "" - )} - <div className={`${filterPillWrapperStyles}`}>{children}</div> - </div> - ) -} - -Filters.propTypes = { - /** Pass a SearchInput component */ - search: PropTypes.node, - /** Pass an object describing the filter keyLabel, valueLabel, and the available filter options: - `{ keyLabel: "Select a Filter",` - `valueLabel: "Enter a Value",` - `options: [{label: "Filter 1", key: "filter-1"}, {...}] }` - */ - filters: PropTypes.object, - /** The key of the currently selected filter */ - selectedFilterKey: PropTypes.string, - /** Pass a handler to be executed when the filter key changes */ - onSelectedFilterKeyChange: PropTypes.func, - /** The value of the FilterInput */ - filterValue: PropTypes.string, - /** Optional: Pass a placeholder for the filter value text input */ - valuePlaceholder: PropTypes.string, - /** Pass a handler to be executed whenever the value of the filter value input changes */ - onFilterValueChange: PropTypes.func, - /** Pass a handler to be executed once the user clicks the filter button */ - onFilter: PropTypes.func, - /** Pas a handler to be executed once the Filter input is cleared */ - onFilterClear: PropTypes.func, - /** add custom classNames */ - className: PropTypes.string, - /** Whether the filters are currently loading */ - loading: PropTypes.bool, - /** Whether the filters have an error */ - error: PropTypes.bool, - /** The error message to display. When passed, error is set to true automatically */ - errortext: PropTypes.string, -} - -Filters.defaultProps = { - search: null, - filters: null, - selectedFilterKey: "", - onSelectedFilterKeyChange: undefined, - filterValue: "", - valuePlaceholder: "", - onFilter: undefined, - onFilterValueChange: undefined, - onFilterClear: undefined, - className: "", - loading: false, - error: false, - errortext: "", -} diff --git a/libs/juno-ui-components/src/components/Filters/Filters.stories.js b/libs/juno-ui-components/src/components/Filters/Filters.stories.js deleted file mode 100644 index db544f9d5..000000000 --- a/libs/juno-ui-components/src/components/Filters/Filters.stories.js +++ /dev/null @@ -1,121 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { Filters } from './index.js'; -import { FilterPill } from '../FilterPill/FilterPill.component'; -import { SearchInput } from '../SearchInput/SearchInput.component'; - -export default { - title: 'Deprecated/Filter/Filters', - component: Filters, - argTypes: {}, -}; - -const PillsTemplate = (args) => ( - <Filters {...args}> - {args.filters && args.filters.options && args.filters.options.length - ? args.filters.options.map((filter, i) => ( - <FilterPill - filterKey={filter.key} - filterKeyLabel={filter.label} - filterValue={`value_${i}`} - filterValueLabel={`Value ${i}`} - key={`filter-${i}`} - onClose={() => console.log(filter.key, 'closing')} - /> - )) - : null} - </Filters> -); - -export const Default = { - args: { - valuePlaceholder: 'Enter a value', - filters: { - keyLabel: 'Select a Filter', - options: [{ key: 'filter-1', label: 'Filter 1' }], - }, - }, -}; - -export const Loading = { - args: { - filters: { - keyLabel: 'Select a Filter', - options: [], - }, - loading: true, - }, -}; - -export const WithPills = { - render: PillsTemplate, - - args: { - filters: { - keyLabel: 'Select a Filter', - options: [ - { key: 'filter-01', label: 'Filter 1' }, - { key: 'filter-02', label: 'Filter 2' }, - { key: 'filter-03', label: 'Filter 3' }, - ], - }, - }, -}; - -export const ErrorWithPills = { - render: PillsTemplate, - - args: { - filters: { - options: [ - { key: 'filter-01', label: 'Filter 1' }, - { key: 'filter-02', label: 'Filter 2' }, - { key: 'filter-03', label: 'Filter 3' }, - ], - }, - error: true, - }, -}; - -export const PreseletedWithSearch = { - args: { - selectedFilterKey: 'filter-2', - search: ( - <SearchInput - onSearch={() => { - console.log('Searching…'); - }} - /> - ), - filters: { - keyLabel: 'Select a Filter', - options: [ - { key: 'filter-01', label: 'Filter 1' }, - { key: 'filter-02', label: 'Filter 2' }, - { key: 'filter-03', label: 'Filter 3' }, - ], - }, - }, -}; - -export const SearchOnly = { - args: { - search: ( - <SearchInput - onSearch={() => { - console.log('Searching…'); - }} - /> - ), - }, -}; - -const searchProps = { - onSearch: () => { - console.log('Searching…'); - }, -}; diff --git a/libs/juno-ui-components/src/components/Filters/Filters.test.js b/libs/juno-ui-components/src/components/Filters/Filters.test.js deleted file mode 100644 index a988c07f3..000000000 --- a/libs/juno-ui-components/src/components/Filters/Filters.test.js +++ /dev/null @@ -1,204 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import userEvent from "@testing-library/user-event" -import { Filters } from "./index" -import { SearchInput } from "../SearchInput/index" - -describe("Filters", () => { - test("renders Filters", async () => { - render(<Filters data-testid="my-filters" />) - expect(screen.getByTestId("my-filters")).toBeInTheDocument() - expect(screen.getByTestId("my-filters")).toHaveClass("juno-filters") - }) - - test("renders a FilterInput when filter prop is passed", async () => { - const filters = { options: [{ label: "option 1", value: "option-1" }] } - render(<Filters filters={filters} />) - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toHaveClass("juno-filter-input-select") - }) - - test("renders Select with options as passed", async () => { - const filters = { - keyLabel: "Filter", - options: [ - { label: "option 1", value: "option-1" }, - { label: "option 2", value: "option-2" }, - ], - } - render(<Filters filters={filters} />) - expect(screen.getByRole("option", { name: "Filter" })).toBeInTheDocument() - expect(screen.getByRole("option", { name: "option 1" })).toHaveValue( - "option-1" - ) - expect(screen.getByRole("option", { name: "option 2" })).toHaveValue( - "option-2" - ) - }) - - test("renders a Select with selected filter key as passed", async () => { - const filters = { - options: [ - { label: "option 1", value: "option-1" }, - { label: "option 2", value: "option-2" }, - ], - } - render(<Filters filters={filters} selectedFilterKey="option-2" />) - expect(screen.getByRole("option", { name: "option 2" }).selected).toBe(true) - }) - - test("renders a Filter value text input with an aria-label as passed", async () => { - const filters = { valueLabel: "Enter a filter value", options: [] } - render(<Filters filters={filters} />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute( - "aria-label", - "Enter a filter value" - ) - }) - - test("renders a Filter vlaue text input witn a placeholder as passed", async () => { - const filters = { - valueLabel: "Enter a filter value", - options: [ - { label: "option 1", value: "option-1" }, - { label: "option 2", value: "option-2" }, - ], - } - render(<Filters valuePlaceholder="my placeholder" filters={filters} />) - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveAttribute( - "placeholder", - "my placeholder" - ) - }) - - test("renders a Filter value as passed", async () => { - const filters = { options: [{ label: "option 1", value: "option-1" }] } - render(<Filters filters={filters} filterValue="abc" />) - expect(screen.getByRole("textbox")).toHaveValue("abc") - }) - - test("executes a handler as passed when the filter input value changes", async () => { - const handleFilterValueChange = jest.fn() - const filters = { options: [{ label: "option 1", value: "option-1" }] } - render( - <Filters - filters={filters} - onFilterValueChange={handleFilterValueChange} - /> - ) - await userEvent.type(screen.getByRole("textbox"), "123") - expect(handleFilterValueChange).toHaveBeenCalledTimes(3) - }) - - test("executes a handler as passed when the filter icon is clicked", async () => { - const handleFilter = jest.fn() - const filters = { - label: "Filter", - options: [{ label: "option 1", value: "option-1" }], - } - render(<Filters filters={filters} onFilter={handleFilter} />) - await userEvent.click(screen.getByTitle("Filter")) - expect(handleFilter).toHaveBeenCalledTimes(1) - }) - - test("executes a handler as passed when the input has focus and the user presses enter", async () => { - const handleFilter = jest.fn() - const filters = { - label: "Filter", - options: [{ label: "option 1", value: "option-1" }], - } - render(<Filters filters={filters} onFilter={handleFilter} />) - await userEvent.type(screen.getByRole("textbox"), "{enter}") - expect(handleFilter).toHaveBeenCalledTimes(1) - expect(handleFilter).toHaveBeenCalledTimes(1) - }) - - test("clears the filter input and executes a handler as passed when the filter input clear icon is clicked", async () => { - const handleClear = jest.fn() - const filters = { - label: "Filter", - options: [{ label: "option 1", value: "option-1" }], - } - render( - <Filters - filters={filters} - filterValue="some option" - onFilterClear={handleClear} - /> - ) - expect(screen.getByRole("textbox")).toHaveValue("some option") - await userEvent.click(screen.getByTitle("Clear")) - expect(screen.getByRole("textbox")).toHaveValue("") - expect(handleClear).toHaveBeenCalledTimes(1) - }) - - test("renders a SearchInput as passed", async () => { - render(<Filters search={<SearchInput />}></Filters>) - expect(screen.getByRole("searchbox")).toBeInTheDocument() - }) - - test("renders loading Filters as passed", async () => { - const filters = { - label: "Filter", - options: [{ label: "option 1", value: "option-1" }], - } - render(<Filters filters={filters} loading />) - expect(screen.getByRole("combobox")).toBeDisabled() - expect(screen.getByRole("progressbar")).toBeInTheDocument() - }) - - test("renders Filters with an error as passed", async () => { - const filters = { - label: "Filter", - options: [{ label: "option 1", value: "option-1" }], - } - render(<Filters data-testid="my-filters" filters={filters} error />) - expect(screen.getByRole("combobox")).toBeDisabled() - expect(screen.getByTestId("my-filters")).toBeInTheDocument() - expect(screen.getByTestId("my-filters")).toHaveClass("juno-filters-error") - expect(screen.getByRole("button")).toBeDisabled() - }) - - test("renders Filters with error and an errortext as passed", async () => { - const filters = { - label: "Filter", - options: [{ label: "option 1", value: "option-1" }], - } - render( - <Filters - data-testid="my-filters" - filters={filters} - errortext="These Filters have an error" - /> - ) - expect(screen.getByRole("combobox")).toBeDisabled() - expect(screen.getByTestId("my-filters")).toBeInTheDocument() - expect(screen.getByTestId("my-filters")).toHaveClass("juno-filters-error") - expect( - document.querySelector(".juno-filters-errortext") - ).toBeInTheDocument() - expect(document.querySelector(".juno-filters-errortext")).toHaveTextContent( - "These Filters have an error" - ) - expect(screen.getByRole("button")).toBeDisabled() - }) - - test("renders a custom className", async () => { - render(<Filters data-testid="my-filters" className="my-custom-class" />) - expect(screen.getByTestId("my-filters")).toBeInTheDocument() - expect(screen.getByTestId("my-filters")).toHaveClass("my-custom-class") - }) - - test("renders all props as passed", async () => { - render(<Filters data-testid="23" data-lolol={true} />) - expect(screen.getByTestId("23")).toBeInTheDocument() - expect(screen.getByTestId("23")).toHaveAttribute("data-lolol") - }) -}) diff --git a/libs/juno-ui-components/src/components/Filters/index.js b/libs/juno-ui-components/src/components/Filters/index.js deleted file mode 100644 index 727d1239c..000000000 --- a/libs/juno-ui-components/src/components/Filters/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { Filters } from "./Filters.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Form/Form.component.js b/libs/juno-ui-components/src/components/Form/Form.component.js deleted file mode 100644 index 6a99a0acc..000000000 --- a/libs/juno-ui-components/src/components/Form/Form.component.js +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -const formStyles = ` - jn-mb-8 -` - -const formHeading = ` - jn-text-2xl - jn-font-bold - jn-mb-4 -` - -/** A Form to hold FormSections and/or FormGroups with an optional title. */ -export const Form = ({ - title, - className, - children, - ...props -}) => { - return ( - <form - className={`juno-form ${formStyles} ${className}`} - {...props} - > - {title ? <h1 className={`juno-form-heading ${formHeading}`}>{title}</h1> : ""} - {children} - </form> - ) -} - -Form.propTypes = { - /** Title to be rendered in the Form`. */ - title: PropTypes.string, - /** Custom className */ - className: PropTypes.string, - /** Children to render in the form */ - children: PropTypes.node, -} - -Form.defaultProps = { - title: null, - className: "", - children: null, -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Form/Form.stories.js b/libs/juno-ui-components/src/components/Form/Form.stories.js deleted file mode 100644 index 16f09003f..000000000 --- a/libs/juno-ui-components/src/components/Form/Form.stories.js +++ /dev/null @@ -1,132 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { Form } from './index.js'; -import { FormRow } from '../FormRow/index.js'; -import { FormSection } from '../FormSection/index.js'; -import { FormHint } from '../FormHint/index.js'; -import { TextInput } from '../TextInput/index.js'; -import { Select } from '../Select/index.js'; -import { SelectOption } from '../SelectOption/index.js'; -import { Switch } from '../Switch/index.js'; -import { Textarea } from '../Textarea/index.js'; -import { RadioGroup } from '../RadioGroup/index.js'; -import { Radio } from '../Radio/index.js'; -import { CheckboxGroup } from '../CheckboxGroup/index.js'; -import { Checkbox } from '../Checkbox/index.js'; -import { Button } from '../Button/index.js'; -import { ButtonRow } from '../ButtonRow/index.js'; -import { IntroBox } from '../IntroBox/index.js'; - -export default { - title: 'Forms/Form', - component: Form, - argTypes: { - items: { - table: { - disable: true, - }, - }, - children: { - control: false, - }, - }, -}; - -const Template = ({ children, ...args }) => <Form {...args}>{children}</Form>; - -export const Default = { - render: Template, - - args: { - title: 'A Simple Form', - children: [ - <FormRow key="f-1"> - <TextInput label="First Name" id="first-name" /> - </FormRow>, - <FormRow key="f-2"> - <TextInput label="Last Name" id="last-name" /> - </FormRow>, - <FormRow key="f-3"> - <TextInput label="Email" id="email" type="email" required /> - </FormRow>, - <ButtonRow key="f-4"> - <Button>Cancel</Button> - <Button variant="primary">Submit</Button> - </ButtonRow>, - ], - }, -}; - -export const ComplexForm = { - render: Template, - - args: { - title: 'A Complex Form', - children: [ - <IntroBox text="In order to get to know you, we need to talk about colors." key="ib-1" />, - <FormSection title="First Section of the Form" key="fs-1"> - <FormRow key="fr-1"> - <Select label="Your Favorite Color" placeholder="Select your favorite color…" id="color"> - <SelectOption value="red" key="so-1"> - Red - </SelectOption> - <SelectOption value="blue" key="so-2"> - Blue - </SelectOption> - <SelectOption value="other" key="so-3"> - Other - </SelectOption> - </Select> - <FormHint text="Your favorite color to the best of your knowledge" /> - </FormRow> - <FormRow key="fr-2"> - <TextInput label="First Name" id="first-name" /> - </FormRow> - <FormRow key="fr-3"> - <TextInput label="Last Name" id="last-name" /> - </FormRow> - </FormSection>, - <FormSection title="Second Section of the Form" key="fs-2"> - <RadioGroup - name="color-radios" - label="In case you are not sure, select your true favorite color:" - > - <Radio key="r-1" id="color-red" label="Red" value="red" /> - <Radio key="r-2" id="color-blue" label="Blue" value="blue" /> - <Radio key="r-3" id="color-green" label="Green" value="green" /> - <Radio key="r-4" id="color-yellow" label="Yellow" value="yellow" /> - </RadioGroup> - <CheckboxGroup name="all-about-red" label="What is your opinion towards the color Red?"> - <Checkbox key="c-1" id="overrated" label="Red is vastly overrated" value="overrated" /> - <Checkbox key="c-2" id="blackisred" label="Black is better" value="blackisbetter" /> - </CheckboxGroup> - <FormRow key="fr-4"> - <Textarea - label="Your Message" - id="message" - placeholder="If there is something else we should know about you – now is the time!" - /> - </FormRow> - <FormRow> - <TextInput invalid value="Error!" /> - <FormHint variant="error" text="A textInput with an error for no reason whatsoever." /> - </FormRow> - <FormRow key="fr-5"> - <Switch label="Wake me up at 4.30am" id="wakey" /> - </FormRow> - <FormRow key="fr-6"> - <Switch label="Send me an email, too" id="email-too" /> - </FormRow> - </FormSection>, - <ButtonRow key="br-1"> - <Button>Cancel</Button> - <Button variant="primary-danger">Clear</Button> - <Button variant="primary">Submit</Button> - </ButtonRow>, - ], - }, -}; diff --git a/libs/juno-ui-components/src/components/Form/Form.test.js b/libs/juno-ui-components/src/components/Form/Form.test.js deleted file mode 100644 index 1e40d00ac..000000000 --- a/libs/juno-ui-components/src/components/Form/Form.test.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { Form } from "./index" - -describe("Form", () => { - - test("renders a Form", async () => { - render(<Form data-testid="my-form" />) - expect(screen.getByTestId("my-form")).toBeInTheDocument() - }) - - test("renders a title", async () => { - render(<Form data-testid="my-form" title="My Form" />) - expect(screen.getByTestId("my-form")).toBeInTheDocument() - expect(screen.getByRole("heading")).toHaveClass("juno-form-heading") - expect(screen.getByRole("heading")).toHaveTextContent("My Form") - }) - - test("renders a custom className", async () => { - render(<Form data-testid="my-form" className="my-custom-class" />) - expect(screen.getByTestId("my-form")).toBeInTheDocument() - expect(screen.getByTestId("my-form")).toHaveClass("my-custom-class") - }) - - test("renders children as passed", async () => { - render(<Form data-testid="my-form"><button></button></Form>) - expect(screen.getByRole("button")).toBeInTheDocument() - }) - - test("renders all props as passed", async () => { - render(<Form data-testid="23" data-lolol={true}/>) - expect(screen.getByTestId("23")).toBeInTheDocument() - expect(screen.getByTestId("23")).toHaveAttribute('data-lolol') - }) - -}) diff --git a/libs/juno-ui-components/src/components/Form/index.js b/libs/juno-ui-components/src/components/Form/index.js deleted file mode 100644 index 81b06a027..000000000 --- a/libs/juno-ui-components/src/components/Form/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { Form } from "./Form.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/FormHint/FormHint.component.js b/libs/juno-ui-components/src/components/FormHint/FormHint.component.js deleted file mode 100644 index 37bcf2c95..000000000 --- a/libs/juno-ui-components/src/components/FormHint/FormHint.component.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -const baseStyles = ` - jn-text-xs - jn-mt-1 -` - -const variantStyles = (variant) => { - switch (variant) { - case "success": - return "jn-text-theme-success" - case "error": - return "jn-text-theme-error" - default: - return "jn-text-theme-light" - } -} - -export const FormHint = ({ - children, - text, - variant, - className, - ...props -}) => { - return ( - <div - className={` - juno-form-hint - juno-form-hint-${variant} - ${ baseStyles } - ${ variantStyles(variant) } - ${ className } - `} - {...props} - > - { children || text } - </div> - ) -} - - -FormHint.propTypes = { - /** The children to render as a hint associated with a form element */ - children: PropTypes.node, - /** The text to render. If both children and text are passed, children will rendered */ - text: PropTypes.node, - /** The variant of the the hint. Defaults to 'help'. */ - variant: PropTypes.oneOf(["help", "error", "success"]), - /** Pass a custom className */ - className: PropTypes.string, -} - - -FormHint.defaultProps = { - children: null, - text: "", - variant: "help", - className: undefined, -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/FormHint/FormHint.stories.js b/libs/juno-ui-components/src/components/FormHint/FormHint.stories.js deleted file mode 100644 index 1caa83d97..000000000 --- a/libs/juno-ui-components/src/components/FormHint/FormHint.stories.js +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { FormHint } from './index.js'; - -export default { - title: 'Forms/FormHint', - component: FormHint, - argTypes: { - children: { - control: false, - }, - }, -}; - -const Template = ({ children, ...args }) => <FormHint {...args}>{children}</FormHint>; - -export const Default = { - render: Template, - - args: { - text: 'A simple hint to be associated with a form input', - }, -}; - -export const WithChildren = { - render: Template, - - args: { - children: ( - <> - A FormHint with a <a href="#">Link</a>. - </> - ), - }, -}; - -export const WithTextAsChildren = { - render: Template, - - args: { - text: ( - <> - A FormHint with a <a href="#">Link</a>. - </> - ), - }, -}; - -export const ErrorVariant = { - render: Template, - - args: { - variant: 'error', - text: 'A FormHint containing an error or invalidation message', - }, -}; - -export const SuccessVariant = { - render: Template, - - args: { - variant: 'success', - text: 'A FormHint containg a success or validation message', - }, -}; diff --git a/libs/juno-ui-components/src/components/FormHint/FormHint.test.js b/libs/juno-ui-components/src/components/FormHint/FormHint.test.js deleted file mode 100644 index 3e1bbb25f..000000000 --- a/libs/juno-ui-components/src/components/FormHint/FormHint.test.js +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { FormHint } from "./index" - -describe("FormHint", () => { - - test("renders a FormHint", async () => { - render(<FormHint data-testid="my-form-hint" />) - expect(screen.getByTestId("my-form-hint")).toBeInTheDocument() - }) - - test("renders children as passed", async () => { - render(<FormHint data-testid="my-form-hint"><button></button></FormHint>) - expect(screen.getByTestId("my-form-hint")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeInTheDocument() - }) - - test("renders a text as passed", async () => { - render(<FormHint data-testid="my-form-hint" text="My form-related message"/>) - expect(screen.getByTestId("my-form-hint")).toBeInTheDocument() - expect(screen.getByTestId("my-form-hint")).toHaveTextContent("My form-related message") - }) - - test("renders children if both children and text have been passed", async () => { - render( - <FormHint data-testid="my-form-hint" text="123"> - <>abc</> - </FormHint> - ) - expect(screen.getByTestId("my-form-hint")).toBeInTheDocument() - expect(screen.getByTestId("my-form-hint")).toHaveTextContent("abc") - expect(screen.getByTestId("my-form-hint")).not.toHaveTextContent("123") - }) - - test("renders a help message by default", async () => { - render(<FormHint data-testid="my-form-hint" />) - expect(screen.getByTestId("my-form-hint")).toBeInTheDocument() - expect(screen.getByTestId("my-form-hint")).toHaveClass("juno-form-hint-help") - }) - - test("renders an error message as passed", async () => { - render(<FormHint data-testid="my-form-hint" variant="error" />) - expect(screen.getByTestId("my-form-hint")).toBeInTheDocument() - expect(screen.getByTestId("my-form-hint")).toHaveClass("juno-form-hint-error") - }) - - test("renders a success message as passed", async () => { - render(<FormHint data-testid="my-form-hint" variant="success" />) - expect(screen.getByTestId("my-form-hint")).toBeInTheDocument() - expect(screen.getByTestId("my-form-hint")).toHaveClass("juno-form-hint-success") - }) - - test("renders a custom className", async () => { - render(<FormHint data-testid="my-form-hint" className="my-custom-class" />) - expect(screen.getByTestId("my-form-hint")).toBeInTheDocument() - expect(screen.getByTestId("my-form-hint")).toHaveClass("my-custom-class") - }) - - test("renders all props as passed", async () => { - render(<FormHint data-testid="23" data-lolol={true}/>) - expect(screen.getByTestId("23")).toBeInTheDocument() - expect(screen.getByTestId("23")).toHaveAttribute('data-lolol') - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/FormHint/index.js b/libs/juno-ui-components/src/components/FormHint/index.js deleted file mode 100644 index d62338c7d..000000000 --- a/libs/juno-ui-components/src/components/FormHint/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { FormHint } from "./FormHint.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/FormRow/FormRow.component.js b/libs/juno-ui-components/src/components/FormRow/FormRow.component.js deleted file mode 100644 index 0353732ed..000000000 --- a/libs/juno-ui-components/src/components/FormRow/FormRow.component.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react' -import PropTypes from 'prop-types' - -const formRowStyles = ` - jn-mb-2 -` - -/** -A generic FormRow component. -Used to layout and structure forms. Pass Form elements such as TextInput, Textarea, Select, or Radio and CheckboxGroups as children. -*/ -export const FormRow = ({ - children, - className, - ...props -}) => { - return ( - <div className={`juno-form-row ${formRowStyles} ${className}`} {...props}> - {children} - </div> -)} - -FormRow.propTypes = { - /** The children to render in the formRow. Typically, these will be Input components such as TextInput, Textarea, Select, or Radio and CheckboxGroups*/ - children: PropTypes.node, - /** Add a custom className to a FormRow */ - className: PropTypes.string, -} - - -FormRow.defaultProps = { - children: null, - className: "", -} - diff --git a/libs/juno-ui-components/src/components/FormRow/FormRow.stories.js b/libs/juno-ui-components/src/components/FormRow/FormRow.stories.js deleted file mode 100644 index 42c254e03..000000000 --- a/libs/juno-ui-components/src/components/FormRow/FormRow.stories.js +++ /dev/null @@ -1,28 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { FormRow } from './index.js'; -import { TextInput } from '../TextInput/index.js'; - -export default { - title: 'Forms/FormRow', - component: FormRow, - argTypes: { - children: { - control: false, - }, - }, -}; - -const Template = ({ children, ...args }) => <FormRow {...args}>{children}</FormRow>; - -export const Default = { - render: Template, - - args: { - children: [<TextInput label="TextInput in a FormRow" placeholder="Your input here…" key="1" />], - }, -}; diff --git a/libs/juno-ui-components/src/components/FormRow/FormRow.test.js b/libs/juno-ui-components/src/components/FormRow/FormRow.test.js deleted file mode 100644 index c9b5fceb0..000000000 --- a/libs/juno-ui-components/src/components/FormRow/FormRow.test.js +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { FormRow } from "./index" - -describe("FormSection", () => { - - test("renders a FormRow", async () => { - render(<FormRow data-testid="my-form-row" />) - expect(screen.getByTestId("my-form-row")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<FormRow data-testid="my-form-row" className="my-custom-class" />) - expect(screen.getByTestId("my-form-row")).toBeInTheDocument() - expect(screen.getByTestId("my-form-row")).toHaveClass("my-custom-class") - }) - - test("renders children as passed", async () => { - render(<FormRow><button></button></FormRow>) - expect(screen.getByRole("button")).toBeInTheDocument() - }) - - test("renders all props as passed", async () => { - render(<FormRow data-testid="23" data-lolol={true}/>) - expect(screen.getByTestId("23")).toBeInTheDocument() - expect(screen.getByTestId("23")).toHaveAttribute('data-lolol') - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/FormRow/index.js b/libs/juno-ui-components/src/components/FormRow/index.js deleted file mode 100644 index 580a65a38..000000000 --- a/libs/juno-ui-components/src/components/FormRow/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { FormRow } from "./FormRow.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/FormSection/FormSection.component.js b/libs/juno-ui-components/src/components/FormSection/FormSection.component.js deleted file mode 100644 index 756d92ed0..000000000 --- a/libs/juno-ui-components/src/components/FormSection/FormSection.component.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - - -const formSection = ` - jn-mb-8 - jn-last:mb-0 -` - -const formSectionHeading = ` - jn-text-lg - jn-font-bold - jn-mb-4 -` - -/** A Form section to group form elements inside complex forms with an optional title. */ -export const FormSection = ({ - - title, - children, - className, - ...props -}) => { - return ( - <section - className={`juno-form-section ${formSection} ${className}`} - {...props} - > - {title ? <h1 className={`juno-formsection-heading ${formSectionHeading}`}>{title}</h1> : ""} - {children} - </section> - ) -} - -FormSection.propTypes = { - /** Title, will be rendering as an `<h1>`. */ - title: PropTypes.string, - /** Pass a custpm className */ - className: PropTypes.string, - /** Children to render in the form section */ - children: PropTypes.node, -} - -FormSection.defaultProps = { - title: null, - className: "", - children: null, -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/FormSection/FormSection.stories.js b/libs/juno-ui-components/src/components/FormSection/FormSection.stories.js deleted file mode 100644 index c90639b94..000000000 --- a/libs/juno-ui-components/src/components/FormSection/FormSection.stories.js +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { FormSection } from '../FormSection/FormSection.component'; -import { FormRow } from '../FormRow/FormRow.component'; -import { TextInput } from '../TextInput/TextInput.component'; - -export default { - title: 'Forms/FormSection', - component: FormSection, - argTypes: { - items: { - table: { - disable: true, - }, - }, - children: { - control: false, - }, - }, -}; - -const Template = ({ children, ...args }) => <FormSection {...args}>{children}</FormSection>; - -export const Default = { - render: Template, - - args: { - children: [ - <FormRow key="1"> - <TextInput label="Address Line 1" /> - </FormRow>, - <FormRow key="2"> - <TextInput label="Address Line 2" /> - </FormRow>, - ], - }, -}; - -export const WithTitle = { - render: Template, - - args: { - title: 'Form Section With Title', - children: [ - <FormRow key="1"> - <TextInput label="Address Line 1" /> - </FormRow>, - <FormRow key="2"> - <TextInput label="Address Line 2" /> - </FormRow>, - ], - }, -}; diff --git a/libs/juno-ui-components/src/components/FormSection/FormSection.test.js b/libs/juno-ui-components/src/components/FormSection/FormSection.test.js deleted file mode 100644 index 92448c6f4..000000000 --- a/libs/juno-ui-components/src/components/FormSection/FormSection.test.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { FormSection } from "./index" - -describe("FormSection", () => { - - test("renders a FormSection", async () => { - render(<FormSection data-testid="my-formsection" />) - expect(screen.getByTestId("my-formsection")).toBeInTheDocument() - }) - - test("renders a title", async () => { - render(<FormSection data-testid="my-form-section" title="My Form Section" />) - expect(screen.getByTestId("my-form-section")).toBeInTheDocument() - expect(screen.getByRole("heading")).toHaveClass("juno-formsection-heading") - expect(screen.getByRole("heading")).toHaveTextContent("My Form Section") - }) - - test("renders a custom className", async () => { - render(<FormSection data-testid="my-formsection" className="my-custom-class" />) - expect(screen.getByTestId("my-formsection")).toBeInTheDocument() - expect(screen.getByTestId("my-formsection")).toHaveClass("my-custom-class") - }) - - test("renders children as passed", async () => { - render(<FormSection><button></button></FormSection>) - expect(screen.getByRole("button")).toBeInTheDocument() - }) - - test("renders all props as passed", async () => { - render(<FormSection data-testid="23" data-lolol={true}/>) - expect(screen.getByTestId("23")).toBeInTheDocument() - expect(screen.getByTestId("23")).toHaveAttribute('data-lolol') - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/FormSection/index.js b/libs/juno-ui-components/src/components/FormSection/index.js deleted file mode 100644 index 0e9fd4dda..000000000 --- a/libs/juno-ui-components/src/components/FormSection/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { FormSection } from "./FormSection.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Grid/Grid.component.js b/libs/juno-ui-components/src/components/Grid/Grid.component.js deleted file mode 100644 index e2a0ecf40..000000000 --- a/libs/juno-ui-components/src/components/Grid/Grid.component.js +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -/** -A general-use grid. Use in conjunction with GridColumn and GridRow. -*/ - -export const Grid = ({ - auto, - children, - className, - ...props -}) => { - // auto grid overrides for columns: - const autoStyles = { - "--grid-column-flex-grow": "1", - "--grid-column-flex-shrink": "0", - "--grid-column-flex-basis": "0", - "--grid-column-default-width": "auto", - } - // Override column vars in case 'auto' was passed: - const gridStyles = auto ? autoStyles : {} - return ( - <div className={`juno-grid ${className}`} style={gridStyles} {...props} > - {children} - </div> - ) -} - - -Grid.propTypes = { - /** Whether columns should auto-size or not, default is false. This effectively overrides the 12-columns default grid */ - auto: PropTypes.bool, - /** The children to render in the grid */ - children: PropTypes.node, - /** Add a class to the grid container */ - className: PropTypes.string, -} - -Grid.defaultProps = { - auto: false, - className: "", - children: null, -} diff --git a/libs/juno-ui-components/src/components/Grid/Grid.stories.js b/libs/juno-ui-components/src/components/Grid/Grid.stories.js deleted file mode 100644 index c573acf1c..000000000 --- a/libs/juno-ui-components/src/components/Grid/Grid.stories.js +++ /dev/null @@ -1,159 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { Grid } from './index.js'; -import { GridRow } from '../GridRow/GridRow.component.js'; -import { GridColumn } from '../GridColumn/GridColumn.component.js'; - -export default { - title: 'Layout/Grid/Grid', - component: Grid, - argTypes: { - children: { - control: false, - }, - }, - decorators: [(Story) => <Story className="jn-bg-juno-blue-3 jn-text-juno-grey-blue" />], -}; - -// for the decorator to work like this (passing props to the story) we have to access the passed props from the decorator -// from the context. This might be storybook 6.x-specific. Double check when we upgrade to storybook 7.x -const Template = (args, context) => <Grid {...args} className={context.className}></Grid>; - -export const Default = { - render: Template, - - parameters: { - docs: { - description: { - story: - 'By default, Juno uses a 12-column fluid grid. Columns can be made to span multiple columns by passing `cols={n}`.', - }, - }, - }, - - args: { - children: [ - <GridRow key="1"> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - </GridRow>, - <GridRow key="2"> - <GridColumn>Column</GridColumn> - <GridColumn cols={3}>Column cols-3</GridColumn> - <GridColumn cols={5}>Column cols-6</GridColumn> - <GridColumn cols={2}>Column cols-2</GridColumn> - </GridRow>, - ], - }, -}; - -export const Auto = { - render: Template, - - parameters: { - docs: { - description: { - story: - 'By passing `auto` to the grid, all of its contained columns will automatically size to share available space equally. Columns with `cols={n}` will switch their behaviour to auto-size.', - }, - }, - }, - - args: { - auto: true, - children: [ - <GridRow key="1"> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - </GridRow>, - <GridRow key="2"> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - </GridRow>, - <GridRow key="3"> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - <GridColumn>Column</GridColumn> - </GridRow>, - ], - }, -}; - -export const MixedGrid = { - render: Template, - - args: { - children: ( - <GridRow> - <GridColumn>Column</GridColumn> - <GridColumn auto>Auto Column</GridColumn> - <GridColumn width={10}>Column 10%</GridColumn> - <GridColumn cols={3}>Column cols-3</GridColumn> - </GridRow> - ), - }, -}; - -export const MixedAutoGrid = { - render: Template, - - args: { - auto: true, - children: ( - <GridRow> - <GridColumn>Column</GridColumn> - <GridColumn auto>Auto Column</GridColumn> - <GridColumn width={10}>Column 10%</GridColumn> - <GridColumn cols={3}>Column cols-3</GridColumn> - </GridRow> - ), - }, -}; - -export const NestedGrid = { - render: Template, - - args: { - children: ( - <GridRow> - <GridColumn cols={3}>Column cols-3</GridColumn> - <GridColumn cols={9}> - <Grid> - <GridRow> - <GridColumn width={33.333333} className="bg-juno-blue-2"> - Nested Column 33.333333% - </GridColumn> - <GridColumn width={66.666666} className="bg-juno-blue-2"> - Nested Column 66.666666% - </GridColumn> - </GridRow> - </Grid> - </GridColumn> - </GridRow> - ), - }, -}; diff --git a/libs/juno-ui-components/src/components/Grid/Grid.test.js b/libs/juno-ui-components/src/components/Grid/Grid.test.js deleted file mode 100644 index fd9f5f341..000000000 --- a/libs/juno-ui-components/src/components/Grid/Grid.test.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { Grid} from "./index" - -describe("Grid", () => { - - test("renders a Grid container", async () => { - render(<Grid data-testid="my-grid" />) - expect(screen.getByTestId("my-grid")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<Grid data-testid="my-grid" className="my-grid-class" />) - expect(screen.getByTestId("my-grid")).toHaveClass("my-grid-class") - }) - - test("has modified CSS variables in a style tag for auto grids", async () => { - render(<Grid data-testid="my-auto-grid" auto />) - expect(screen.getByTestId("my-auto-grid")).toHaveAttribute("style") - expect(document.querySelector('.juno-grid').style.getPropertyValue('--grid-column-flex-grow')).toBe('1') - expect(document.querySelector('.juno-grid').style.getPropertyValue('--grid-column-flex-shrink')).toBe('0') - expect(document.querySelector('.juno-grid').style.getPropertyValue('--grid-column-flex-basis')).toBe('0') - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Grid/index.js b/libs/juno-ui-components/src/components/Grid/index.js deleted file mode 100644 index 2527a3fb9..000000000 --- a/libs/juno-ui-components/src/components/Grid/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { Grid } from "./Grid.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/GridColumn/GridColumn.component.js b/libs/juno-ui-components/src/components/GridColumn/GridColumn.component.js deleted file mode 100644 index 3b79913b2..000000000 --- a/libs/juno-ui-components/src/components/GridColumn/GridColumn.component.js +++ /dev/null @@ -1,152 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -const autoColumnStyles = ` - jn-grow - jn-shrink-0 - jn-flex-basis-0 -` -const widthColumnStyles = ` - jn-grow-0 - jn-shrink-1 - jn-flex-basis-auto -` - -const columnBaseStyles = ` - jn-flex-grid-column - jn-p-grid-column -` - -const cols_1 = ` - jn-w-grid-col-1 -` - -const cols_2 = ` - jn-w-grid-col-2 -` - -const cols_3 = ` - jn-w-grid-col-3 -` - -const cols_4 = ` - jn-w-grid-col-4 -` - -const cols_5 = ` - jn-w-grid-col-6 -` - -const cols_6 = ` - jn-w-grid-col-6 -` - -const cols_7 = ` - jn-w-grid-col-7 -` - -const cols_8 = ` - jn-w-grid-col-8 -` - -const cols_9 = ` - jn-w-grid-col-9 -` - -const cols_10 = ` - jn-w-grid-col-10 -` - -const cols_11 = ` - jn-w-grid-col-11 -` - -const cols_12 = ` - jn-w-grid-col-12 -` - -const colsClass = (cols) => { - switch (cols) { - case 1: - return cols_1 - case 2: - return cols_2 - case 3: - return cols_3 - case 4: - return cols_4 - case 5: - return cols_5 - case 6: - return cols_6 - case 7: - return cols_7 - case 8: - return cols_8 - case 9: - return cols_9 - case 10: - return cols_10 - case 11: - return cols_11 - case 12: - return cols_12 - default: - return "jn-w-grid-column-default" - } -} - -/** -A grid column to be used inside a Grid. -*/ - -export const GridColumn = ({ - width, - cols, - auto, - className, - children, - ...props -}) => { - // auto column: - const autoStyles = { - flexGrow: "1", - flexShrink: "0", - flexBasis: "0" - } - // width column: - const widthStyles = width ? { width: width + '%', flexGrow: "0", flexShrink: "0", flexBasis: width + '%' } : {} - // width overrides auto: - const columnStyles = width ? widthStyles : ( auto ? autoStyles : {} ) - return ( - <div className={`juno-grid-column ${columnBaseStyles} ${colsClass(cols)} ${className}`} style={columnStyles} {...props} > - {children} - </div> - ) -} - - -GridColumn.propTypes = { - /** The number of columns to span the column over. */ - cols: PropTypes.number, - /** The width in percent as a number without "%" for auto-layout grids TODO: or "auto". If a width is given, it will override the "cols" prop. */ - width: PropTypes.number, - /** Whether the colum should set an auto width */ - auto: PropTypes.bool, - /** Add a class to a grid column */ - className: PropTypes.string, - /** Children to be rendered in the column element */ - children: PropTypes.node -} - -GridColumn.defaultProps = { - width: null, - cols: null, - auto: false, - className: "", -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/GridColumn/GridColumn.stories.js b/libs/juno-ui-components/src/components/GridColumn/GridColumn.stories.js deleted file mode 100644 index ecc5a080c..000000000 --- a/libs/juno-ui-components/src/components/GridColumn/GridColumn.stories.js +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { GridColumn } from './index.js'; - -export default { - title: 'Layout/Grid/GridColumn', - component: GridColumn, - argTypes: { - children: { - control: false, - }, - }, - decorators: [(Story) => <Story className="jn-bg-juno-blue-3 jn-text-juno-grey-blue" />], -}; - -// for the decorator to work like this (passing props to the story) we have to access the passed props from the decorator -// from the context. This might be storybook 6.x-specific. Double check when we upgrade to storybook 7.x -const Template = (args, context) => ( - <GridColumn {...args} className={context.className}></GridColumn> -); - -export const Default = { - render: Template, - - args: { - children: 'Column', - }, -}; - -export const AutoColumn = { - render: Template, - - args: { - auto: true, - children: 'Auto Column', - }, -}; - -export const WidthColumn = { - render: Template, - - args: { - width: 50, - children: 'Column 50%', - }, -}; diff --git a/libs/juno-ui-components/src/components/GridColumn/GridColumn.test.js b/libs/juno-ui-components/src/components/GridColumn/GridColumn.test.js deleted file mode 100644 index df89c9bb1..000000000 --- a/libs/juno-ui-components/src/components/GridColumn/GridColumn.test.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { GridColumn} from "./index" - -describe("GridColumn", () => { - - test("renders a Grid row", async () => { - render(<GridColumn data-testid="my-grid-column" />) - expect(screen.getByTestId("my-grid-column")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<GridColumn data-testid="my-grid-column" className="my-grid-column-class" />) - expect(screen.getByTestId("my-grid-column")).toHaveClass("my-grid-column-class") - }) - - test("renders modified 'auto' styles when passed", async () => { - render(<GridColumn data-testid="my-auto-column" auto />) - expect(screen.getByTestId("my-auto-column")).toHaveAttribute("style") - expect(document.querySelector('.juno-grid-column').style.getPropertyValue('flex-grow')).toBe('1') - expect(document.querySelector('.juno-grid-column').style.getPropertyValue('flex-shrink')).toBe('0') - expect(document.querySelector('.juno-grid-column').style.getPropertyValue('flex-basis')).toBe('0px') - }) - - test("renders width-related styles in a style tag when passed", async () => { - render(<GridColumn data-testid="my-width-column" width={73} />) - expect(screen.getByTestId("my-width-column")).toHaveAttribute("style") - expect(document.querySelector('.juno-grid-column').style.getPropertyValue('width')).toBe('73%') - expect(document.querySelector('.juno-grid-column').style.getPropertyValue('flex-shrink')).toBe('0') - expect(document.querySelector('.juno-grid-column').style.getPropertyValue('flex-basis')).toBe('73%') - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/GridColumn/index.js b/libs/juno-ui-components/src/components/GridColumn/index.js deleted file mode 100644 index 09e5a13c4..000000000 --- a/libs/juno-ui-components/src/components/GridColumn/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { GridColumn } from "./GridColumn.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/GridRow/GridRow.component.js b/libs/juno-ui-components/src/components/GridRow/GridRow.component.js deleted file mode 100644 index 73660a3db..000000000 --- a/libs/juno-ui-components/src/components/GridRow/GridRow.component.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -const gridRowBaseStyles = ` - jn-flex - jn-flex-wrap - jn-m-grid-row -` -/** -A grid row to hold GridColumn elements inside a Grid. -*/ -export const GridRow = ({ - children, - className, - ...props -}) => { - return ( - <div className={`juno-grid-row ${gridRowBaseStyles} ${className}`} {...props} > - {children} - </div> - ) -} - - -GridRow.propTypes = { - /** The children to render in the grid row */ - children: PropTypes.node, - /** Add a class to the grid row */ - className: PropTypes.string, -} - -GridRow.defaultProps = { - children: null, - className: "" -} diff --git a/libs/juno-ui-components/src/components/GridRow/GridRow.stories.js b/libs/juno-ui-components/src/components/GridRow/GridRow.stories.js deleted file mode 100644 index 434714855..000000000 --- a/libs/juno-ui-components/src/components/GridRow/GridRow.stories.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { GridRow } from './index.js'; -import { GridColumn } from '../GridColumn/GridColumn.component.js'; - -export default { - title: 'Layout/Grid/GridRow', - component: GridRow, - argTypes: { - children: { - control: false, - }, - }, - decorators: [(Story) => <Story className="jn-bg-juno-blue-3 jn-text-juno-grey-blue" />], -}; - -// for the decorator to work like this (passing props to the story) we have to access the passed props from the decorator -// from the context. This might be storybook 6.x-specific. Double check when we upgrade to storybook 7.x -const Template = ({ columns, ...args }, context) => ( - <GridRow {...args} className={context.className}></GridRow> -); - -export const Default = { - render: Template, - - args: { - children: [ - <GridColumn key="1">Column</GridColumn>, - <GridColumn key="2">Column</GridColumn>, - <GridColumn key="3">Column</GridColumn>, - <GridColumn key="4">Column</GridColumn>, - <GridColumn key="5">Column</GridColumn>, - <GridColumn key="6">Column</GridColumn>, - <GridColumn key="7">Column</GridColumn>, - <GridColumn key="8">Column</GridColumn>, - <GridColumn key="9">Column</GridColumn>, - <GridColumn key="10">Column</GridColumn>, - <GridColumn key="11">Column</GridColumn>, - <GridColumn key="12">Column</GridColumn>, - ], - }, -}; diff --git a/libs/juno-ui-components/src/components/GridRow/GridRow.test.js b/libs/juno-ui-components/src/components/GridRow/GridRow.test.js deleted file mode 100644 index ca3bc0a4a..000000000 --- a/libs/juno-ui-components/src/components/GridRow/GridRow.test.js +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { GridRow} from "./index" - -describe("GridRow", () => { - - test("renders a Grid row", async () => { - render(<GridRow data-testid="my-grid-row" />) - expect(screen.getByTestId("my-grid-row")).toBeInTheDocument() - }) - - test("renders a custom className", async () => { - render(<GridRow data-testid="my-grid-row" className="my-grid-row-class" />) - expect(screen.getByTestId("my-grid-row")).toHaveClass("my-grid-row-class") - }) - -}) \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/GridRow/index.js b/libs/juno-ui-components/src/components/GridRow/index.js deleted file mode 100644 index 9a43e32f6..000000000 --- a/libs/juno-ui-components/src/components/GridRow/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { GridRow } from "./GridRow.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Icon/Icon.component.js b/libs/juno-ui-components/src/components/Icon/Icon.component.js deleted file mode 100644 index a82e1f991..000000000 --- a/libs/juno-ui-components/src/components/Icon/Icon.component.js +++ /dev/null @@ -1,826 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { forwardRef } from "react" -import PropTypes from "prop-types" - -/* Import Icons here. The icon svgs in the icons folder correspond to the respective "xyz_24px.svg" from material-ui icons. - */ -import AccessTime from "@material-design-icons/svg/filled/access_time.svg" -import AccountCircle from "@material-design-icons/svg/filled/account_circle.svg" -import AddCircle from "@material-design-icons/svg/filled/add_circle.svg" -import AutoAwesomeMosaic from "@material-design-icons/svg/filled/auto_awesome_mosaic.svg" -import AutoAwesomeMotion from "@material-design-icons/svg/filled/auto_awesome_motion.svg" -import Bolt from "@material-design-icons/svg/filled/bolt.svg" -import CalendarToday from "@material-design-icons/svg/filled/calendar_today.svg" -import Cancel from "@material-design-icons/svg/filled/cancel.svg" -import Check from "@material-design-icons/svg/filled/check.svg" -import CheckCircle from "@material-design-icons/svg/filled/check_circle.svg" -import ChevronLeft from "@material-design-icons/svg/outlined/chevron_left.svg" -import ChevronRight from "@material-design-icons/svg/outlined/chevron_right.svg" -import Close from "@material-design-icons/svg/filled/close.svg" -import ContentCopy from "@material-design-icons/svg/outlined/content_copy.svg" -import Danger from "./icons/juno-danger.svg" -import Dangerous from "@material-design-icons/svg/filled/dangerous.svg" -import Download from "@material-design-icons/svg/filled/download.svg" -import DeleteForever from "@material-design-icons/svg/filled/delete_forever.svg" -import Description from "@material-design-icons/svg/filled/description.svg" -import DNS from "@material-design-icons/svg/filled/dns.svg" -import Edit from "@material-design-icons/svg/filled/edit.svg" -import Error from "@material-design-icons/svg/filled/dangerous.svg" -import ErrorOutline from "@material-design-icons/svg/outlined/error_outline.svg" -import ExitToApp from "@material-design-icons/svg/outlined/exit_to_app.svg" -import ExpandLess from "@material-design-icons/svg/outlined/expand_less.svg" -import ExpandMore from "@material-design-icons/svg/outlined/expand_more.svg" -import FilterAlt from "@material-design-icons/svg/filled/filter_alt.svg" -import Forum from "@material-design-icons/svg/filled/forum.svg" -import Help from "@material-design-icons/svg/filled/help.svg" -import Home from "./icons/home_sharp.svg" -import Info from "@material-design-icons/svg/filled/info.svg" -import Comment from "@material-design-icons/svg/filled/comment.svg" -import ManageAccounts from "@material-design-icons/svg/filled/manage_accounts.svg" -import MonitorHeart from "@material-design-icons/svg/outlined/monitor_heart.svg" -import MoreVert from "@material-design-icons/svg/outlined/more_vert.svg" -import NotificationsOff from "@material-design-icons/svg/outlined/notifications_off.svg" -import OpenInBrowser from "@material-design-icons/svg/outlined/open_in_browser.svg" -import OpenInNew from "@material-design-icons/svg/outlined/open_in_new.svg" -import Place from "./icons/place.svg" -import Success from "@material-design-icons/svg/filled/check_box.svg" -import Search from "@material-design-icons/svg/outlined/search.svg" -import SeverityLow from "./icons/juno_severity_low.svg" -import SeverityMedium from "./icons/juno_severity_medium.svg" -import SeverityHigh from "./icons/juno_severity_high.svg" -import SeverityCritical from "./icons/juno_severity_critical.svg" -import Warning from "@material-design-icons/svg/filled/warning.svg" -import Widgets from "@material-design-icons/svg/filled/widgets.svg" - -/** -Generic Icon component. -*/ -// hover style needs to be revisited. only works if no icon color was passed -const anchorIconStyles = ` - jn-text-current - hover:jn-text-theme-high - focus:jn-outline-none - focus-visible:jn-ring-2 - focus-visible:jn-ring-theme-focus - focus-visible:jn-ring-offset-1 - focus-visible:jn-ring-offset-theme-focus - disabled:jn-opacity-50 - disabled:jn-cursor-not-allowed -` - -// hover style needs to be revisited. only works if no icon color was passed -const buttonIconStyles = ` - hover:jn-text-theme-high - focus:jn-outline-none - focus-visible:jn-ring-2 - focus-visible:jn-ring-theme-focus - focus-visible:jn-ring-offset-1 - focus-visible:jn-ring-offset-theme-focus - disabled:jn-opacity-50 - disabled:jn-cursor-not-allowed -` - -const wrapperStyles = ` - jn-leading-none -` -// export all known icons as an array of their names to be used with PropTypes here and from other components: -export const knownIcons = [ - "accessTime", - "accountCircle", - "addCircle", - "autoAwesomeMosaic", - "autoAwesomeMotion", - "bolt", - "calendarToday", - "cancel", - "check", - "checkCircle", - "chevronLeft", - "chevronRight", - "close", - "comment", - "contentCopy", - "danger", - "dangerous", - "default", - "deleteForever", - "description", - "dns", - "download", - "edit", - "error", - "errorOutline", - "exitToApp", - "expandLess", - "expandMore", - "filterAlt", - "forum", - "help", - "home", - "info", - "manageAccounts", - "monitorHeart", - "moreVert", - "notificationsOff", - "openInBrowser", - "openInNew", - "place", - "search", - "severityLow", - "severityMedium", - "severityHigh", - "severityCritical", - "success", - "warning", - "widgets", -] - -const getColoredSizedIcon = ({ - icon, - color, - size, - title, - iconClassName, - ...iconProps -}) => { - const iconClass = `juno-icon juno-icon-${icon} jn-fill-current ${color} ${iconClassName}` - - switch (icon) { - case "accessTime": - return ( - <AccessTime - width={size} - height={size} - className={iconClass} - alt="time" - title={title ? title : "Time"} - role="img" - {...iconProps} - /> - ) - case "accountCircle": - return ( - <AccountCircle - width={size} - height={size} - className={iconClass} - alt="account" - title={title ? title : "Account"} - role="img" - {...iconProps} - /> - ) - case "addCircle": - return ( - <AddCircle - width={size} - height={size} - className={iconClass} - alt="add" - title={title ? title : "Add"} - role="img" - {...iconProps} - /> - ) - case "autoAwesomeMosaic": - return ( - <AutoAwesomeMosaic - width={size} - height={size} - className={iconClass} - alt="mosaic" - title={title ? title : "Mosaic"} - role="img" - {...iconProps} - /> - ) - case "autoAwesomeMotion": - return ( - <AutoAwesomeMotion - width={size} - height={size} - className={iconClass} - alt="items stacked behind each other" - title={title ? title : "Items stacked behind each other"} - role="img" - {...iconProps} - /> - ) - case "bolt": - return ( - <Bolt - width={size} - height={size} - className={iconClass} - alt="bolt" - title={title ? title : "Bolt"} - role="img" - {...iconProps} - /> - ) - case "calendarToday": - return ( - <CalendarToday - width={size} - height={size} - className={iconClass} - alt="calendar" - title={title ? title : "Calendar"} - role="img" - {...iconProps} - /> - ) - case "cancel": - return ( - <Cancel - width={size} - height={size} - className={iconClass} - alt="cancel" - title={title ? title : "Cancel"} - role="img" - {...iconProps} - /> - ) - case "check": - return ( - <Check - width={size} - height={size} - className={iconClass} - alt="check" - title={title ? title : "Check"} - role="img" - {...iconProps} - /> - ) - case "checkCircle": - return ( - <CheckCircle - width={size} - height={size} - className={iconClass} - alt="checkCircle" - title={title ? title : "CheckCircle"} - role="img" - {...iconProps} - /> - ) - case "chevronLeft": - return ( - <ChevronLeft - width={size} - height={size} - className={iconClass} - alt="chevronLeft" - title={title ? title : "ChevronLeft"} - role="img" - {...iconProps} - /> - ) - case "chevronRight": - return ( - <ChevronRight - width={size} - height={size} - className={iconClass} - alt="chevronRight" - title={title ? title : "ChevronRight"} - role="img" - {...iconProps} - /> - ) - case "close": - return ( - <Close - width={size} - height={size} - className={iconClass} - alt="close" - title={title ? title : "Close"} - role="img" - {...iconProps} - /> - ) - case "comment": - return ( - <Comment - width={size} - height={size} - className={iconClass} - alt="comment" - title={title ? title : "Comment"} - role="img" - {...iconProps} - /> - ) - case "contentCopy": - return ( - <ContentCopy - width={size} - height={size} - className={iconClass} - alt="copy" - title={title ? title : "Copy"} - role="img" - {...iconProps} - /> - ) - case "danger": - return ( - <Danger - width={size} - height={size} - className={iconClass} - alt="danger" - title={title ? title : "Danger"} - role="img" - {...iconProps} - /> - ) - case "dangerous": - return ( - <Dangerous - width={size} - height={size} - className={iconClass} - alt="dangerous" - title={title ? title : "Dangerous"} - role="img" - {...iconProps} - /> - ) - case "deleteForever": - return ( - <DeleteForever - width={size} - height={size} - className={iconClass} - alt="delete forever" - title={title ? title : "Delete Forever"} - role="img" - {...iconProps} - /> - ) - case "description": - return ( - <Description - width={size} - height={size} - className={iconClass} - alt="description" - title={title ? title : "Description"} - role="img" - {...iconProps} - /> - ) - case "dns": - return ( - <DNS - width={size} - height={size} - className={iconClass} - alt="service" - title={title ? title : "Service"} - role="img" - {...iconProps} - /> - ) - case "download": - return ( - <Download - width={size} - height={size} - className={iconClass} - alt="download" - title={title ? title : "download"} - role="img" - {...iconProps} - /> - ) - case "edit": - return ( - <Edit - width={size} - height={size} - className={iconClass} - alt="edit" - title={title ? title : "Edit"} - role="img" - {...iconProps} - /> - ) - case "error": - return ( - <Error - width={size} - height={size} - className={iconClass} - alt="error" - title={title ? title : "Error"} - role="img" - {...iconProps} - /> - ) - case "errorOutline": - return ( - <ErrorOutline - width={size} - height={size} - className={iconClass} - alt="error outline" - title={title ? title : "Error"} - role="img" - {...iconProps} - /> - ) - case "exitToApp": - return ( - <ExitToApp - width={size} - height={size} - className={iconClass} - alt="exit to other app" - title={title ? title : "Exit to app"} - role="img" - {...iconProps} - /> - ) - case "expandLess": - return ( - <ExpandLess - width={size} - height={size} - className={iconClass} - alt="expand less" - title={title ? title : "Expand Less"} - role="img" - {...iconProps} - /> - ) - case "expandMore": - return ( - <ExpandMore - width={size} - height={size} - className={iconClass} - alt="expand more" - title={title ? title : "Expand More"} - role="img" - {...iconProps} - /> - ) - case "filterAlt": - return ( - <FilterAlt - width={size} - height={size} - className={iconClass} - alt="filter" - title={title ? title : "Filter"} - role="img" - {...iconProps} - /> - ) - case "forum": - return ( - <Forum - width={size} - height={size} - className={iconClass} - alt="forum" - title={title ? title : "Forum"} - role="img" - {...iconProps} - /> - ) - case "help": - return ( - <Help - width={size} - height={size} - className={iconClass} - alt="help" - title={title ? title : "Help"} - role="img" - {...iconProps} - /> - ) - case "home": - return ( - <Home - width={size} - height={size} - className={iconClass} - alt="home" - title={title ? title : "Home"} - role="img" - {...iconProps} - /> - ) - case "info": - return ( - <Info - width={size} - height={size} - className={iconClass} - alt="info" - title={title ? title : "Info"} - role="img" - {...iconProps} - /> - ) - case "manageAccounts": - return ( - <ManageAccounts - width={size} - height={size} - className={iconClass} - alt="user account configuration" - title={title ? title : "User account configuration"} - role="img" - {...iconProps} - /> - ) - case "monitorHeart": - return ( - <MonitorHeart - width={size} - height={size} - className={iconClass} - alt="heart monitor" - title={title ? title : "Heart monitor"} - role="img" - {...iconProps} - /> - ) - case "moreVert": - return ( - <MoreVert - width={size} - height={size} - className={iconClass} - alt="more" - title={title ? title : "More"} - role="img" - {...iconProps} - /> - ) - case "notificationsOff": - return ( - <NotificationsOff - width={size} - height={size} - className={iconClass} - alt="notifications off" - title={title ? title : "Notifications off"} - role="img" - {...iconProps} - /> - ) - case "openInBrowser": - return ( - <OpenInBrowser - width={size} - height={size} - className={iconClass} - alt="open in browser" - title={title ? title : "Open in browser"} - role="img" - {...iconProps} - /> - ) - case "openInNew": - return ( - <OpenInNew - width={size} - height={size} - className={iconClass} - alt="open in new tab" - title={title ? title : "Open in new tab"} - role="img" - {...iconProps} - /> - ) - case "place": - return ( - <Place - width={size} - height={size} - className={iconClass} - alt="location" - title={title ? title : "Location"} - role="img" - {...iconProps} - /> - ) - case "search": - return ( - <Search - width={size} - height={size} - className={iconClass} - alt="search" - title={title ? title : "Search"} - role="img" - {...iconProps} - /> - ) - case "severityLow": - return ( - <SeverityLow - width={size} - height={size} - className={iconClass} - alt="Severity low" - title={title ? title : "Severity Low"} - role="img" - {...iconProps} - /> - ) - case "severityMedium": - return ( - <SeverityMedium - width={size} - height={size} - className={iconClass} - alt="Severity medium" - title={title ? title : "Severity Medium"} - role="img" - {...iconProps} - /> - ) - case "severityHigh": - return ( - <SeverityHigh - width={size} - height={size} - className={iconClass} - alt="Severity high" - title={title ? title : "Severity High"} - role="img" - {...iconProps} - /> - ) - case "severityCritical": - return ( - <SeverityCritical - width={size} - height={size} - className={iconClass} - alt="Severity critical" - title={title ? title : "Severity Critical"} - role="img" - {...iconProps} - /> - ) - case "success": - return ( - <Success - width={size} - height={size} - className={iconClass} - alt="success" - title={title ? title : "Success"} - role="img" - {...iconProps} - /> - ) - case "widgets": - return ( - <Widgets - width={size} - height={size} - className={iconClass} - alt="widgets" - title={title ? title : "Widgets"} - role="img" - {...iconProps} - /> - ) - case "warning": - return ( - <Warning - width={size} - height={size} - className={iconClass} - alt="warning" - title={title ? title : "Warning"} - role="img" - {...iconProps} - /> - ) - case "default": // keep explicit default case to allow consuming components to use 'default' w/o throwing warnings - return ( - <Help - width={size} - height={size} - className={iconClass} - alt="help" - title={title ? title : "Help"} - role="img" - {...iconProps} - /> - ) - default: - return ( - <Help - width={size} - height={size} - className={iconClass} - alt="help" - title={title ? title : "Help"} - role="img" - {...iconProps} - /> - ) - } -} - -export const Icon = forwardRef( - ( - { icon, color, size, title, className, href, disabled, onClick, ...props }, - ref - ) => { - // if href or onClick was passed, then we want to add the passed classes and passed arbitrary props to the button or anchor - // otherwise add the passed classes/props to the icon itself - const iconClassName = href || onClick ? "" : className - const iconProps = href || onClick ? {} : props - - const icn = getColoredSizedIcon({ - icon, - color, - size, - title, - iconClassName, - ...iconProps, - }) - - const handleClick = (event) => { - onClick && onClick(event) - } - - const button = ( - <button - onClick={handleClick} - className={`juno-icon-button ${buttonIconStyles} ${className}`} - aria-label={title || icon} - disabled={disabled} - ref={ref} - {...props} - > - {icn} - </button> - ) - - const anchor = ( - <a - href={href} - className={`juno-icon-link ${anchorIconStyles} ${className}`} - aria-label={title || icon} - ref={ref} - {...props} - > - {icn} - </a> - ) - - /* render an <a> if href was passed, otherwise render button if onClick was passes, otherwise render plain icon: */ - /* if plain icon, add ref to the icon. In the other cases the ref goes on the anchor or button */ - return href ? anchor : onClick ? button : <span ref={ref}>{icn}</span> - } -) - -Icon.propTypes = { - /** The icon to display */ - icon: PropTypes.oneOf(knownIcons), - /** By default, Icons will use the `color` of the current context. In order to use a different color just for the icon, a text color class can be passed. These begin with "jn-text-". */ - color: PropTypes.string, - /** The size of the icon as a number of pixels (without "px": "16" will render an icon of 16px x 16px)*/ - size: PropTypes.string, - /** The title of the icon. Important for accessibility, will also show as a tooltip: */ - title: PropTypes.string, - /** A custom className */ - className: PropTypes.string, - /** Optionally specify an href. This will render the Icon inside an <code><a></code> element with the given url. */ - href: PropTypes.string, - /** Disable the Icon. Only applicable when rendering as a button by passing an onClick handler, too. */ - disabled: PropTypes.bool, - /** Optionally specify a click handler. This will render the icon inside a <code><button></code> with the given handler. */ - onClick: PropTypes.func, -} - -Icon.defaultProps = { - icon: null, - color: "", - size: "24", - title: "", - className: "", - href: "", - disabled: false, - onClick: undefined, -} diff --git a/libs/juno-ui-components/src/components/Icon/Icon.stories.js b/libs/juno-ui-components/src/components/Icon/Icon.stories.js deleted file mode 100644 index c32c7df70..000000000 --- a/libs/juno-ui-components/src/components/Icon/Icon.stories.js +++ /dev/null @@ -1,403 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { Icon } from './index.js'; - -export default { - title: 'Components/Icon', - component: Icon, - argTypes: {}, - parameters: { - docs: { - description: { - component: - "A generic icon component. Accepts text color classes for color. Please note that the 'jn-' prefix for tailwind classes is only necessary within the juno ui design system itself. When using icons in your own applications use the normal tailwing-generated text color classes starting with 'text-'", - }, - }, - }, -}; - -export const Default = { - args: { - icon: 'help', - color: 'jn-global-text', - }, -}; - -export const Info_Colored = { - args: { - icon: 'info', - color: 'jn-text-theme-info', - }, -}; - -export const Danger_Colored = { - args: { - icon: 'danger', - color: 'jn-text-theme-danger', - }, -}; - -export const Success_Colored = { - args: { - icon: 'success', - color: 'jn-text-theme-success', - }, -}; - -export const Warning_Colored = { - args: { - icon: 'warning', - color: 'jn-text-theme-warning', - }, -}; - -export const ThemeColor = { - args: { - icon: 'help', - color: 'jn-global-text', - }, -}; - -export const Smaller = { - args: { - ...Default.args, - icon: 'help', - size: '18', - }, -}; - -export const Larger = { - args: { - ...Default.args, - icon: 'help', - size: '64', - }, -}; - -export const IconAsLink = { - args: { - ...Default.args, - href: '#', - title: 'The Icon is a link', - }, -}; - -export const IconAsButton = { - args: { - ...Default.args, - title: 'The Icon is a button', - onClick: () => { - console.log('click'); - }, - }, -}; - -export const Account_Circle = { - args: { - ...Default.args, - icon: 'accountCircle', - }, -}; - -export const Add_Circle = { - args: { - ...Default.args, - icon: 'addCircle', - }, -}; - -export const Auto_Awesome_Mosaic = { - args: { - ...Default.args, - icon: 'autoAwesomeMosaic', - }, -}; - -export const Auto_Awesome_Motion = { - args: { - ...Default.args, - icon: 'autoAwesomeMotion', - }, -}; - -export const Bolt = { - args: { - ...Default.args, - icon: 'bolt', - }, -}; - -export const Cancel = { - args: { - ...Default.args, - icon: 'cancel', - }, -}; - -export const Check = { - args: { - icon: 'check', - }, -}; - -export const CheckCircle = { - args: { - icon: 'checkCircle', - }, -}; - -export const ChevronLeft = { - args: { - icon: 'chevronLeft', - }, -}; - -export const ChevronRight = { - args: { - icon: 'chevronRight', - }, -}; - -export const Close = { - args: { - icon: 'close', - }, -}; - -export const Comment = { - args: { - ...Default.args, - icon: 'comment', - }, -}; - -export const ContentCopy = { - args: { - icon: 'contentCopy', - }, -}; - -export const Danger = { - args: { - ...Default.args, - icon: 'danger', - }, -}; - -export const Dangerous = { - args: { - icon: 'dangerous', - }, -}; - -export const DeleteForever = { - args: { - icon: 'deleteForever', - }, -}; - -export const Description = { - args: { - ...Default.args, - icon: 'description', - }, -}; - -export const DNS = { - args: { - ...Default.args, - icon: 'dns', - }, -}; - -export const Download = { - args: { - icon: 'download', - }, -}; - -export const Edit = { - args: { - ...Default.args, - icon: 'edit', - }, -}; - -export const Error = { - args: { - ...Default.args, - icon: 'dangerous', - }, -}; - -export const Error_Outline = { - args: { - ...Default.args, - icon: 'errorOutline', - }, -}; - -export const Exit_To_App = { - args: { - ...Default.args, - icon: 'exitToApp', - }, -}; - -export const Expand_Less = { - args: { - ...Default.args, - icon: 'expandLess', - }, -}; - -export const Expand_More = { - args: { - ...Default.args, - icon: 'expandMore', - }, -}; - -export const Filter_Alt = { - args: { - ...Default.args, - icon: 'filterAlt', - }, -}; - -export const Forum = { - args: { - ...Default.args, - icon: 'forum', - }, -}; - -export const Help = { - args: { - ...Default.args, - icon: 'help', - }, -}; - -export const Home = { - args: { - ...Default.args, - icon: 'home', - }, -}; - -export const Info = { - args: { - ...Default.args, - icon: 'info', - }, -}; - -export const Manage_Accounts = { - args: { - ...Default.args, - icon: 'manageAccounts', - }, -}; - -export const Monitor_Heart = { - args: { - ...Default.args, - icon: 'monitorHeart', - }, -}; - -export const More_Vert = { - args: { - ...Default.args, - icon: 'moreVert', - }, -}; - -export const Notifications_Off = { - args: { - ...Default.args, - icon: 'notificationsOff', - }, -}; - -export const Open_In_Browser = { - args: { - ...Default.args, - icon: 'openInBrowser', - }, -}; - -export const Open_In_New = { - args: { - ...Default.args, - icon: 'openInNew', - }, -}; - -export const Place = { - args: { - ...Default.args, - icon: 'place', - }, -}; - -export const Search = { - args: { - ...Default.args, - icon: 'search', - }, -}; - -export const SeverityLow = { - args: { - ...Default.args, - icon: 'severityLow', - }, -}; - -export const SeverityMedium = { - args: { - ...Default.args, - icon: 'severityMedium', - }, -}; - -export const SeverityHigh = { - args: { - ...Default.args, - icon: 'severityHigh', - }, -}; - -export const SeverityCritical = { - args: { - ...Default.args, - icon: 'severityCritical', - }, -}; - -export const Success = { - args: { - ...Default.args, - icon: 'success', - }, -}; - -export const Warning = { - args: { - ...Default.args, - icon: 'warning', - }, -}; - -export const Widgets = { - args: { - ...Default.args, - icon: 'widgets', - }, -}; diff --git a/libs/juno-ui-components/src/components/Icon/Icon.test.js b/libs/juno-ui-components/src/components/Icon/Icon.test.js deleted file mode 100644 index c68e4faac..000000000 --- a/libs/juno-ui-components/src/components/Icon/Icon.test.js +++ /dev/null @@ -1,381 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { Icon } from "./index" - -describe("Icon", () => { - test("renders an Icon as passed", async () => { - render(<Icon icon="warning" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "warning") - }) - - test("renders a custom className as passed", async () => { - render(<Icon className="my-custom-class" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveClass("my-custom-class") - }) - - test("renders a default icon when none was passed", async () => { - render(<Icon />) - expect(screen.getByRole("img")).toBeInTheDocument() - // note: currently the default icon is the help icon - expect(screen.getByRole("img")).toHaveAttribute("alt", "help") - }) - - test("renders an Icon with no text class by default so that text color is inherited from context", async () => { - render(<Icon />) - expect(screen.getByRole("img")).toBeInTheDocument() - // check that there is no class that contains 'text-' - expect(screen.getByRole("img")).not.toHaveAttribute( - "class", - expect.stringContaining("text-") - ) - }) - - test("renders an Icon with color as passed", async () => { - render(<Icon color="text-juno-blue" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveClass("text-juno-blue") - }) - - test("renders an Icon with default size", async () => { - render(<Icon />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("width", "24") - expect(screen.getByRole("img")).toHaveAttribute("height", "24") - }) - - test("renders an Icon with size as passed", async () => { - render(<Icon size="48" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("width", "48") - expect(screen.getByRole("img")).toHaveAttribute("height", "48") - }) - - test("renders a custom alt text instead of default when passed", async () => { - render(<Icon alt="my super custom icon alt text" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute( - "alt", - "my super custom icon alt text" - ) - }) - - // Test individual icons: - - test("renders an accessTime icon", async () => { - render(<Icon icon="accessTime" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "time") - }) - - test("renders an accountCircle icon", async () => { - render(<Icon icon="accountCircle" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "account") - }) - - test("renders an addCircle icon", async () => { - render(<Icon icon="addCircle" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "add") - }) - - test("renders a autoAwesomeMosaic icon", async () => { - render(<Icon icon="autoAwesomeMosaic" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "mosaic") - }) - - test("renders a autoAwesomeMotion icon", async () => { - render(<Icon icon="autoAwesomeMotion" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute( - "alt", - "items stacked behind each other" - ) - }) - - test("renders a bolt icon", async () => { - render(<Icon icon="bolt" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "bolt") - }) - - test("renders a cancel icon", async () => { - render(<Icon icon="cancel" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "cancel") - }) - - test("renders a check icon", async () => { - render(<Icon icon="check" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "check") - }) - - test("renders a checkCircle icon", async () => { - render(<Icon icon="checkCircle" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "checkCircle") - }) - - test("renders a chevronLeft icon", async () => { - render(<Icon icon="chevronLeft" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "chevronLeft") - }) - - test("renders a chevronRight icon", async () => { - render(<Icon icon="chevronRight" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "chevronRight") - }) - - test("renders a close icon", async () => { - render(<Icon icon="close" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "close") - }) - - test("renders a copy icon", async () => { - render(<Icon icon="contentCopy" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "copy") - }) - - test("renders a danger icon", async () => { - render(<Icon icon="danger" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "danger") - }) - - test("renders a dangerous icon", async () => { - render(<Icon icon="dangerous" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "dangerous") - }) - - test("renders a deleteForever icon", async () => { - render(<Icon icon="deleteForever" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "delete forever") - }) - - test("renders a description icon", async () => { - render(<Icon icon="description" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "description") - }) - - test("renders a dns icon", async () => { - render(<Icon icon="dns" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "service") - }) - - test("renders an edit icon", async () => { - render(<Icon icon="edit" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "edit") - }) - - test("renders an error icon", async () => { - render(<Icon icon="error" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "error") - }) - - test("renders an outlined error icon", async () => { - render(<Icon icon="errorOutline" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "error outline") - }) - - test("renders an exitToApp icon", async () => { - render(<Icon icon="exitToApp" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "exit to other app") - }) - - test("renders an expandLess icon", async () => { - render(<Icon icon="expandLess" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "expand less") - }) - - test("renders an expandMore icon", async () => { - render(<Icon icon="expandMore" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "expand more") - }) - - test("renders an filterAlt icon", async () => { - render(<Icon icon="filterAlt" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "filter") - }) - - test("renders an forum icon", async () => { - render(<Icon icon="forum" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "forum") - }) - - test("renders a forum help icon", async () => { - render(<Icon icon="help" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "help") - }) - - test("renders a Home icon", async () => { - render(<Icon icon="home" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "home") - }) - - test("renders an info icon", async () => { - render(<Icon icon="info" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "info") - }) - - test("renders a comment icon", async () => { - render(<Icon icon="comment" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "comment") - }) - - test("renders a manageAccounts icon", async () => { - render(<Icon icon="manageAccounts" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute( - "alt", - "user account configuration" - ) - }) - - test("renders an openInBrowser icon", async () => { - render(<Icon icon="openInBrowser" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "open in browser") - }) - - test("renders a place icon", async () => { - render(<Icon icon="place" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "location") - }) - - test("renders a search icon", async () => { - render(<Icon icon="search" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "search") - }) - - test("renders a success icon", async () => { - render(<Icon icon="success" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "success") - }) - - test("renders a warning icon", async () => { - render(<Icon icon="warning" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("alt", "warning") - }) - - test("renders a custom title", async () => { - render(<Icon title="My custom title" />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("title", "My custom title") - }) - - test("renders an <a> element if href is passed as prop", async () => { - render(<Icon href="#" />) - expect(screen.getByRole("link")).toBeInTheDocument() - expect(screen.getByRole("link")).toHaveAttribute("href", "#") - }) - - test("renders an <a> element with correct aria-label-attribute as passed", async () => { - render(<Icon href="#" title="my link title" />) - expect(screen.getByRole("link")).toBeInTheDocument() - expect(screen.getByRole("link")).toHaveAttribute( - "aria-label", - "my link title" - ) - }) - - test("renders an <a> element with correct aria-label-attribute fallback if not passed", async () => { - render(<Icon href="#" icon="warning" />) - expect(screen.getByRole("link")).toBeInTheDocument() - expect(screen.getByRole("link")).toHaveAttribute("aria-label", "warning") - }) - - test("renders a <button> element if a click handler is passed", async () => { - const handleClick = jest.fn() - render(<Icon onClick={handleClick} />) - expect(screen.getByRole("button")).toBeInTheDocument() - }) - - test("renders a <button> element with correct aria-label-attribute as passed", async () => { - const handleClick = jest.fn() - render(<Icon onClick={handleClick} title="my-button-title" />) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveAttribute( - "aria-label", - "my-button-title" - ) - }) - - test("renders a <button> element with correct aria-label-attribute fallback if not passed", async () => { - const handleClick = jest.fn() - render(<Icon onClick={handleClick} icon="warning" />) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveAttribute("aria-label", "warning") - }) - - test("renders a disabled button element as passed", async () => { - const handleClick = jest.fn() - render(<Icon onClick={handleClick} disabled />) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeDisabled() - }) - - test("an onClick handler is called as passed", () => { - const handleClick = jest.fn() - render(<Icon onClick={handleClick} />) - screen.getByRole("button").click() - expect(handleClick).toHaveBeenCalled() - }) - - test("does not execute onClick handler when disabled", async () => { - const handleClick = jest.fn() - render(<Icon onClick={handleClick} disabled />) - screen.getByRole("button").click() - expect(handleClick).not.toHaveBeenCalled() - }) - - test("renders an <a> element and ignore onClick handler if both href and onClick handler are passed", async () => { - const handleClick = jest.fn() - render(<Icon href="#" onClick={handleClick} />) - expect(screen.getByRole("link")).toBeInTheDocument() - expect(screen.getByRole("link")).toHaveAttribute("href", "#") - screen.getByRole("link").click() - expect(handleClick).not.toHaveBeenCalled() - }) - - // Test all props: - - test("renders all props as passed", async () => { - render(<Icon id="icon-1" data-lolol={true} />) - expect(screen.getByRole("img")).toBeInTheDocument() - expect(screen.getByRole("img")).toHaveAttribute("id", "icon-1") - expect(screen.getByRole("img")).toHaveAttribute("data-lolol") - }) -}) diff --git a/libs/juno-ui-components/src/components/Icon/icons/home_sharp.svg b/libs/juno-ui-components/src/components/Icon/icons/home_sharp.svg deleted file mode 100644 index add764f0b..000000000 --- a/libs/juno-ui-components/src/components/Icon/icons/home_sharp.svg +++ /dev/null @@ -1,6 +0,0 @@ -<!-- - ~ SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - ~ SPDX-License-Identifier: Apache-2.0 ---> - -<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8h5z"/></svg> \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Icon/icons/juno-danger.svg b/libs/juno-ui-components/src/components/Icon/icons/juno-danger.svg deleted file mode 100644 index cb8cfcd53..000000000 --- a/libs/juno-ui-components/src/components/Icon/icons/juno-danger.svg +++ /dev/null @@ -1,8 +0,0 @@ -<!-- - ~ SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - ~ SPDX-License-Identifier: Apache-2.0 ---> - -<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> - <path d="M22,17.9999996 L22,19.9999996 L2,19.9999996 L2,17.9999996 L22,17.9999996 Z M12,6.428571 C14.7642857,6.428571 17.0146825,8.23991359 17.1375716,10.5179164 L17.1428571,10.7142853 L17.1428571,16.7142853 L6.85714286,16.7142853 L6.85714286,10.7142853 L6.86242835,10.5179164 C6.98531746,8.23991359 9.23571429,6.428571 12,6.428571 Z M12,7.71428529 L12,15.428571 L15.8571429,15.428571 L15.8571429,11.1428567 L15.851803,10.960591 C15.745448,9.15003461 14.0636603,7.71428529 12,7.71428529 Z M19.075912,3.96838198 L20.490712,5.38218198 L18.370012,7.50438202 L16.955212,6.09058202 L19.075912,3.96838198 Z M4.956739,3.939208 L7.078039,6.060508 L5.663839,7.474708 L3.542539,5.353408 L4.956739,3.939208 Z M13,1.428571 L13,4.428571 L11,4.428571 L11,1.428571 L13,1.428571 Z"></path> -</svg> \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Icon/icons/juno_severity_critical.svg b/libs/juno-ui-components/src/components/Icon/icons/juno_severity_critical.svg deleted file mode 100644 index 7bd6316f8..000000000 --- a/libs/juno-ui-components/src/components/Icon/icons/juno_severity_critical.svg +++ /dev/null @@ -1,10 +0,0 @@ -<!-- - ~ SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - ~ SPDX-License-Identifier: Apache-2.0 ---> - -<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M15.7956 22H14.5955L15.7956 14.2222H11.5955C10.8994 14.2222 10.9114 13.8667 11.1395 13.4889C11.3675 13.1111 11.1995 13.4 11.2235 13.3556C12.7715 10.8222 15.0995 7.04445 18.1956 2H19.3956L18.1956 9.77778H22.3957C22.9837 9.77778 23.0677 10.1444 22.9597 10.3444L22.8757 10.5111C18.1476 18.1667 15.7956 22 15.7956 22Z"/> -<path d="M2 17H8V23H2V17Z"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M2 1L2 15H8V1H2Z"/> -</svg> diff --git a/libs/juno-ui-components/src/components/Icon/icons/juno_severity_high.svg b/libs/juno-ui-components/src/components/Icon/icons/juno_severity_high.svg deleted file mode 100644 index 5cc08d58b..000000000 --- a/libs/juno-ui-components/src/components/Icon/icons/juno_severity_high.svg +++ /dev/null @@ -1,11 +0,0 @@ -<!-- - ~ SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - ~ SPDX-License-Identifier: Apache-2.0 ---> - -<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M15.7956 22H14.5955L15.7956 14.2222H11.5955C10.8994 14.2222 10.9114 13.8667 11.1395 13.4889C11.3675 13.1111 11.1995 13.4 11.2235 13.3556C12.7715 10.8222 15.0995 7.04444 18.1956 2L19.3956 2L18.1956 9.77778H22.3957C22.9837 9.77778 23.0677 10.1444 22.9597 10.3444L22.8757 10.5111C18.1476 18.1667 15.7956 22 15.7956 22Z"/> -<path d="M2 17H8V23H2V17Z"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M2 9V15H8V9H2Z"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M2 1V7H8V1H2Z"/> -</svg> diff --git a/libs/juno-ui-components/src/components/Icon/icons/juno_severity_low.svg b/libs/juno-ui-components/src/components/Icon/icons/juno_severity_low.svg deleted file mode 100644 index 9ce2c516c..000000000 --- a/libs/juno-ui-components/src/components/Icon/icons/juno_severity_low.svg +++ /dev/null @@ -1,11 +0,0 @@ -<!-- - ~ SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - ~ SPDX-License-Identifier: Apache-2.0 ---> - -<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M15.7956 22H14.5955L15.7956 14.2222H11.5955C10.8994 14.2222 10.9114 13.8667 11.1395 13.4889C11.3675 13.1111 11.1995 13.4 11.2235 13.3556C12.7715 10.8222 15.0995 7.04444 18.1956 2L19.3956 2L18.1956 9.77778H22.3957C22.9837 9.77778 23.0677 10.1444 22.9597 10.3444L22.8757 10.5111C18.1476 18.1667 15.7956 22 15.7956 22Z"/> -<path d="M2 17H8V23H2V17Z"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M7 10H3V14H7V10ZM2 9V15H8V9H2Z"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M7 2H3V6H7V2ZM2 1V7H8V1H2Z"/> -</svg> diff --git a/libs/juno-ui-components/src/components/Icon/icons/juno_severity_medium.svg b/libs/juno-ui-components/src/components/Icon/icons/juno_severity_medium.svg deleted file mode 100644 index 15473d1a0..000000000 --- a/libs/juno-ui-components/src/components/Icon/icons/juno_severity_medium.svg +++ /dev/null @@ -1,11 +0,0 @@ -<!-- - ~ SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - ~ SPDX-License-Identifier: Apache-2.0 ---> - -<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M15.7956 22H14.5955L15.7956 14.2222H11.5955C10.8994 14.2222 10.9114 13.8667 11.1395 13.4889C11.3675 13.1111 11.1995 13.4 11.2235 13.3556C12.7715 10.8222 15.0995 7.04444 18.1956 2L19.3956 2L18.1956 9.77778H22.3957C22.9837 9.77778 23.0677 10.1444 22.9597 10.3444L22.8757 10.5111C18.1476 18.1667 15.7956 22 15.7956 22Z"/> -<path d="M2 17H8V23H2V17Z"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M2 9V15H8V9H2Z"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M7 2H3V6H7V2ZM2 1V7H8V1H2Z"/> -</svg> diff --git a/libs/juno-ui-components/src/components/Icon/icons/place.svg b/libs/juno-ui-components/src/components/Icon/icons/place.svg deleted file mode 100644 index f65fb8ae4..000000000 --- a/libs/juno-ui-components/src/components/Icon/icons/place.svg +++ /dev/null @@ -1,6 +0,0 @@ -<!-- - ~ SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - ~ SPDX-License-Identifier: Apache-2.0 ---> - -<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/></svg> \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Icon/index.js b/libs/juno-ui-components/src/components/Icon/index.js deleted file mode 100644 index fe9173ac6..000000000 --- a/libs/juno-ui-components/src/components/Icon/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { Icon } from "./Icon.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/InputGroup/InputGroup.component.js b/libs/juno-ui-components/src/components/InputGroup/InputGroup.component.js deleted file mode 100644 index e063a7262..000000000 --- a/libs/juno-ui-components/src/components/InputGroup/InputGroup.component.js +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import { Stack } from "../Stack/index" -import "./input-group.scss" -import PropTypes from "prop-types" - - - -/** A component to visually group Buttons, TextInput, and Select elements. */ -export const InputGroup = ({ - children, - className, - variant, - disabled, - ...props -}) => { - - const modifiedChildren = () => { - return React.Children.map(children, (child) => { - const ownVariant = child.props.variant || variant - const ownDisabled = child.props.disabled || disabled - return React.cloneElement(child, { - variant: ownVariant, - disabled: ownDisabled - }) - }) - } - - return ( - <Stack className={`juno-input-group juno-input-group-${variant} ${ disabled ? "juno-input-group-disabled" : "" } ${className}`} {...props}> - { modifiedChildren() } - </Stack> - ) -} - -InputGroup.propTypes = { - /** The children to render */ - children: PropTypes.node, - /** Pass a className to the group */ - className: PropTypes.string, - /** Passing a variant prop to the group will set all child Buttons and Select elements to use that variant, unless specified otherwise on the individual child component */ - variant: PropTypes.oneOf(["default", "primary", "primary-danger", "subdued"]), - /** Disable all elements in the InputGroup */ - disabled: PropTypes.bool, -} - -InputGroup.defaultProps = { - children: null, - className: undefined, - variant: "default", - disabled: false, -} diff --git a/libs/juno-ui-components/src/components/InputGroup/InputGroup.stories.js b/libs/juno-ui-components/src/components/InputGroup/InputGroup.stories.js deleted file mode 100644 index 0b024c4a1..000000000 --- a/libs/juno-ui-components/src/components/InputGroup/InputGroup.stories.js +++ /dev/null @@ -1,141 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { InputGroup } from './index.js'; -import { Button } from '../Button/index'; -import { NativeSelect } from '../NativeSelect/index'; -import { NativeSelectOption } from '../NativeSelectOption/index'; -import { TextInput } from '../TextInput/index'; - -export default { - title: 'WiP/InputGroup', - component: InputGroup, - argTypes: { - children: { - control: false, - }, - }, -}; - -export const Default = { - args: { - children: [<Button label="Button 1" />, <Button>Button 2</Button>, <Button label="Button 3" />], - }, -}; - -export const PrimaryInputGroup = { - args: { - variant: 'primary', - children: [ - <Button label="Primary Button" />, - <Button label="Primary Button" />, - <Button label="Primary Button" />, - ], - }, -}; - -export const PrimaryDangerInputGroup = { - args: { - variant: 'primary-danger', - children: [ - <Button label="Primary Danger Button" />, - <Button label="Primary Danger Button" variant="primary" />, - <Button label="Primary Danger Button" />, - ], - }, -}; - -export const SubduedInputGroup = { - args: { - variant: 'subdued', - children: [ - <Button label="Subdued Button" />, - <Button label="Subdued Button" />, - <Button label="Subdued Button" />, - ], - }, -}; - -export const Disabled = { - args: { - disabled: true, - children: [<Button label="Button" />, <Button label="Button" />, <Button label="Button" />], - }, -}; - -export const IconButtons = { - args: { - children: [<Button icon="home" />, <Button icon="help" />, <Button icon="forum" />], - }, -}; - -export const TextInputWithButton = { - args: { - children: [<TextInput placeholder="Enter a value…" />, <Button label="Submit" />], - }, -}; - -export const MultipleTextInputsWithButton = { - args: { - children: [ - <TextInput placeholder="First Name" />, - <TextInput placeholder="Last Name" />, - <Button label="Submit" />, - ], - }, -}; - -export const ButtonWithOptions = { - args: { - children: [ - <Button label="Button with Options" />, - <NativeSelect> - <NativeSelectOption value="1" label="Action 1" /> - <NativeSelectOption value="2" label="Action 2" /> - </NativeSelect>, - ], - }, -}; - -export const SelectWithTextInput = { - args: { - children: [ - <NativeSelect> - <NativeSelectOption value="1" label="Action 1" /> - <NativeSelectOption value="2" label="Action 2" /> - </NativeSelect>, - <TextInput placeholder="Value…" />, - ], - }, -}; - -export const TextInputWithButtonAndOptions = { - args: { - children: [ - <TextInput placeholder="Enter Value…" />, - <Button label="Submit" />, - <NativeSelect placeholder="Other Actions…"> - <NativeSelectOption value="1" label="Save" /> - <NativeSelectOption value="2" label="Delete" /> - </NativeSelect>, - ], - }, -}; - -export const SelectWithSelect = { - args: { - children: [ - <NativeSelect> - <NativeSelectOption value="1" label="Action 1" /> - <NativeSelectOption value="2" label="Action 2" /> - </NativeSelect>, - <NativeSelect> - <NativeSelectOption value="2-1" label="Action 1" /> - <NativeSelectOption value="2-2" label="Action 2" /> - </NativeSelect>, - ], - }, -}; diff --git a/libs/juno-ui-components/src/components/InputGroup/InputGroup.test.js b/libs/juno-ui-components/src/components/InputGroup/InputGroup.test.js deleted file mode 100644 index a31890bfc..000000000 --- a/libs/juno-ui-components/src/components/InputGroup/InputGroup.test.js +++ /dev/null @@ -1,105 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { InputGroup } from "./index" -import { Button } from "../Button/index" -import { TextInput } from "../TextInput/index" -import { NativeSelect } from "../NativeSelect/index" -import { NativeSelectOption } from "../NativeSelectOption/index" - -describe("InputGroup", () => { - - test("renders an InputGroup", async () => { - render(<InputGroup />) - expect(document.querySelector(".juno-input-group")).toBeInTheDocument() - }) - - test("renders children as passed", async () => { - render( - <InputGroup> - <Button label="A Button" /> - <TextInput value="some value"/> - <NativeSelect> - <NativeSelectOption label="A Select Option" value="sel-opt-1" /> - <NativeSelectOption label="Another Select Option" value="sel-opt-2" /> - </NativeSelect> - </InputGroup> - ) - expect(document.querySelector(".juno-input-group")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toHaveTextContent("A Button") - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toHaveValue("some value") - expect(screen.getByRole("combobox")).toBeInTheDocument() // use listbox for radix-based select - }) - - test("renders child button variants as passed to parent", async () => { - render( - <InputGroup variant="primary-danger"> - <Button label="first" /> - <Button label="second" /> - <Button label="third" /> - </InputGroup> - ) - expect(screen.getByRole("button", { name: "first" })).toBeInTheDocument() - expect(screen.getByRole("button", { name: "first" })).toHaveClass("juno-button-primary-danger") - expect(screen.getByRole("button", { name: "second" })).toBeInTheDocument() - expect(screen.getByRole("button", { name: "second" })).toHaveClass("juno-button-primary-danger") - expect(screen.getByRole("button", { name: "third" })).toBeInTheDocument() - expect(screen.getByRole("button", { name: "third" })).toHaveClass("juno-button-primary-danger") - }) - - test("allows child button variant to override variant passed to parent", async () => { - render( - <InputGroup variant="primary-danger"> - <Button label="first" /> - <Button label="second" variant="primary"/> - <Button label="third" /> - </InputGroup> - ) - expect(screen.getByRole("button", { name: "first" })).toBeInTheDocument() - expect(screen.getByRole("button", { name: "first" })).toHaveClass("juno-button-primary-danger") - expect(screen.getByRole("button", { name: "second" })).toBeInTheDocument() - expect(screen.getByRole("button", { name: "second" })).not.toHaveClass("juno-button-primary-danger") - expect(screen.getByRole("button", { name: "second" })).toHaveClass("juno-button-primary") - expect(screen.getByRole("button", { name: "third" })).toBeInTheDocument() - expect(screen.getByRole("button", { name: "third" })).toHaveClass("juno-button-primary-danger") - }) - - test("disables all child elements as passed to parent", async () => { - render( - <InputGroup disabled> - <Button /> - <TextInput /> - <NativeSelect> - <NativeSelectOption label="A Select Option" value="sel-opt-1" /> - <NativeSelectOption label="Another Select Option" value="sel-opt-2" /> - </NativeSelect> - </InputGroup> - ) - expect(screen.getByRole("button")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeDisabled() - expect(screen.getByRole("textbox")).toBeInTheDocument() - expect(screen.getByRole("textbox")).toBeDisabled() - expect(screen.getByRole("combobox")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toBeDisabled() - }) - - test("renders a className a spassed", async () => { - render(<InputGroup className="my-class" />) - expect(document.querySelector(".juno-input-group")).toBeInTheDocument() - expect(document.querySelector(".juno-input-group")).toHaveClass("my-class") - }) - - test("renders all props as passed", async () => { - render(<InputGroup data-test="my-prop" />) - expect(document.querySelector(".juno-input-group")).toBeInTheDocument() - expect(document.querySelector(".juno-input-group")).toHaveAttribute("data-test", "my-prop") - }) - -}) - \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/InputGroup/index.js b/libs/juno-ui-components/src/components/InputGroup/index.js deleted file mode 100644 index fb7cb5f96..000000000 --- a/libs/juno-ui-components/src/components/InputGroup/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { InputGroup} from "./InputGroup.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/InputGroup/input-group.scss b/libs/juno-ui-components/src/components/InputGroup/input-group.scss deleted file mode 100644 index d62f2f93a..000000000 --- a/libs/juno-ui-components/src/components/InputGroup/input-group.scss +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors -// SPDX-License-Identifier: Apache-2.0 - -.juno-input-group { - - // remove border-radius where necessary - .juno-button, - .juno-textinput, - // this is weird for selects as is since these are inside a wrapper each and thus all qualify as first child, and potentially harder for radix-ui based selects, as we would need to select the Select button child?: - .juno-select { - &:not(:first-child, :last-child) { - border-radius: 0; - } - &:first-child { - border-top-right-radius: 0; - border-bottom-right-radius: 0; - } - &:last-child { - border-top-left-radius: 0; - border-bottom-left-radius: 0; - } - } - - // prevent double-borders for identical buttons next to each other: - .juno-button-default + .juno-button-default, - .juno-button-primary + .juno-button-primary, - .juno-button-default-primary-danger + .juno-button-primary-danger, - .juno-button-subdued + .juno-button-subdued { - border-left: 0; - } - -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/IntroBox/IntroBox.component.js b/libs/juno-ui-components/src/components/IntroBox/IntroBox.component.js deleted file mode 100644 index fbf44d02c..000000000 --- a/libs/juno-ui-components/src/components/IntroBox/IntroBox.component.js +++ /dev/null @@ -1,114 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" - -const introbox = (variant, heroImage) => { - return ` - jn-bg-theme-introbox - jn-text-theme-default - jn-flex - jn-rounded-l - jn-overflow-hidden - jn-mb-8 - - ${ - variant === "hero" && heroImage - ? ` - jn-bg-right-top - jn-bg-no-repeat - ` - : "" - } - ` -} - -const introboxBorder = ` - jn-border-l-4 - jn-border-theme-introbox -` - -const introboxContent = (variant, heroImage) => { - return ` - ${heroImage ? `jn-pl-4 jn-pr-56` : `jn-px-4`} - - ${ - variant === "hero" - ? ` - jn-text-xl - jn-min-h-[8rem] - jn-py-4 - jn-flex - jn-flex-col - jn-justify-center - ` - : ` - jn-py-3 - ` - } - ` -} - -const introboxHeading = ` - jn-font-bold -` - -/** -* An Introbox holds generally important information to help understand the contents, purpose, or state of a whole page or view, or individual sections on longer pages. -Use sparingly, there should never be any two or more subsequent instances of Introbox as direct siblings/neighbors on an individual view. -*/ -export const IntroBox = ({ - title, - text, - variant, - heroImage, - className, - children, - ...props -}) => { - - - const isHeroWithImage = React.useMemo(() => { - return heroImage && variant === "hero" - }, [variant, heroImage]) - - return ( - <div - className={`juno-introbox ${introbox(variant, heroImage)} ${className}`} - style={isHeroWithImage ? {backgroundImage: `${heroImage}`} : {}} - {...props} - > - <div className={`${introboxBorder}`}></div> - <div className={`${introboxContent(variant, heroImage)}`}> - {title ? <h1 className={`${introboxHeading}`}>{title}</h1> : ""} - {children ? children : <p>{text}</p>} - </div> - </div> - ) -} - -IntroBox.propTypes = { - /** Pass an optional title */ - title: PropTypes.string, - /** Pass a string of text to be rendered as contents. Alternatively, contents can be passed as children (see below) */ - text: PropTypes.string, - /** Pass a custom class */ - variant: PropTypes.oneOf(["default", "hero"]), - /** optional "hero" flavor image for hero variant. Specify as css bg image string pointing to an image in your app (see template app for an example). Will always be positioned top and right */ - heroImage: PropTypes.string, - /** Pass a custom class */ - className: PropTypes.string, - /** Pass child nodes to be rendered as contents */ - children: PropTypes.node, -} - -IntroBox.defaultProps = { - title: null, - text: null, - variant: "default", - heroImage: null, - className: "", -} diff --git a/libs/juno-ui-components/src/components/IntroBox/IntroBox.stories.js b/libs/juno-ui-components/src/components/IntroBox/IntroBox.stories.js deleted file mode 100644 index 969a00ee8..000000000 --- a/libs/juno-ui-components/src/components/IntroBox/IntroBox.stories.js +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { IntroBox } from './index.js'; -import heroImage from '../../img/app_bg_example.svg?url'; - -export default { - title: 'Components/IntroBox', - component: IntroBox, - argTypes: { - children: { - control: false, - }, - }, -}; - -export const Default = { - args: { - text: 'Default IntroBox.', - }, -}; - -export const WithTitle = { - args: { - title: 'IntroBox', - text: 'IntroBox with title.', - }, -}; - -export const Hero = { - args: { - title: 'IntroBox', - text: 'Hero IntroBox has a larger font size and more padding', - variant: 'hero', - }, -}; - -export const HeroWithBGImage = { - args: { - title: 'IntroBox', - text: 'Hero IntroBox with background image. Background image must be referenced as a css bg image string. Import svg images with query param ?url.', - variant: 'hero', - heroImage: `url(${heroImage})`, - }, -}; diff --git a/libs/juno-ui-components/src/components/IntroBox/IntroBox.test.js b/libs/juno-ui-components/src/components/IntroBox/IntroBox.test.js deleted file mode 100644 index 6ad0547c4..000000000 --- a/libs/juno-ui-components/src/components/IntroBox/IntroBox.test.js +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { IntroBox } from "./index" - -describe("IntroBox", () => { - test("renders an IntroBox", async () => { - render(<IntroBox data-testid="my-introbox" />) - expect(screen.getByTestId("my-introbox")).toBeInTheDocument() - }) - - test("renders an IntroBox with background image as passed if variant hero", async () => { - render( - <IntroBox - data-testid="my-introbox" - variant="hero" - heroImage="url('bg-fake-img')" - /> - ) - expect(screen.getByTestId("my-introbox")).toHaveStyle({backgroundImage: "url('bg-fake-img')"}) - }) - - test("renders an IntroBox without background image as passed if variant is not hero", async () => { - render( - <IntroBox - data-testid="my-introbox" - heroImage="url('bg-fake-img')" - /> - ) - expect(screen.getByTestId("my-introbox")).not.toHaveStyle({backgroundImage: "url('bg-fake-img')"}) - }) - - test("renders a title as passed", async () => { - render(<IntroBox data-testid="my-introbox" title="My IntroBox Heading" />) - expect(screen.getByTestId("my-introbox")).toHaveTextContent( - "My IntroBox Heading" - ) - }) - - test("renders a text as passed", async () => { - render( - <IntroBox data-testid="my-introbox" text="My IntroBox text goes here." /> - ) - expect( - screen.getByText((content, element) => { - return ( - element.tagName.toLowerCase() === "p" && - content.startsWith("My IntroBox text goes here.") - ) - }) - ).toBeTruthy() - }) - - test("renders a custom class as passed", async () => { - render(<IntroBox data-testid="my-introbox" className="my-custom-class" />) - expect(screen.getByTestId("my-introbox")).toHaveClass("my-custom-class") - }) - - test("renders children passed as children", async () => { - render( - <IntroBox data-testid="my-introbox"> - <div>My Introbox text in a div goes here!</div> - </IntroBox> - ) - expect( - screen.getByText((content, element) => { - return ( - element.tagName.toLowerCase() === "div" && - content.startsWith("My Introbox text in a div goes here!") - ) - }) - ).toBeTruthy() - }) - - test("renders text as passed as children if both children and 'text' prop were passed", async () => { - render( - <IntroBox data-testid="my-introbox" text="I should not be here."> - {"My Introbox children text goes here!"} - </IntroBox> - ) - expect(screen.getByTestId("my-introbox")).toHaveTextContent( - "My Introbox children text goes here!" - ) - }) - - test("renders other props as passed", async () => { - render( - <IntroBox data-testid="my-introbox" name="My shiny little IntroBox" /> - ) - expect(screen.getByTestId("my-introbox")).toHaveAttribute( - "name", - "My shiny little IntroBox" - ) - }) -}) diff --git a/libs/juno-ui-components/src/components/IntroBox/index.js b/libs/juno-ui-components/src/components/IntroBox/index.js deleted file mode 100644 index 1c94008d4..000000000 --- a/libs/juno-ui-components/src/components/IntroBox/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { IntroBox } from "./IntroBox.component" \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/JsonViewer/JsonViewer.component.js b/libs/juno-ui-components/src/components/JsonViewer/JsonViewer.component.js deleted file mode 100644 index b4bdb7e30..000000000 --- a/libs/juno-ui-components/src/components/JsonViewer/JsonViewer.component.js +++ /dev/null @@ -1,543 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import PropTypes, { exact } from "prop-types" -import React, { useContext, useLayoutEffect } from "react" -import * as themes from "./themes" -import { SearchInput } from "../SearchInput/SearchInput.component" - -// DEFAULT THEME (DARK) -const DEFAULT_THEME = { - base00: "var(--color-syntax-highlight-base00)", // background - base01: "var(--color-syntax-highlight-base01)", // toolbar: border, background - base02: "var(--color-syntax-highlight-base02)", // border, type background, border - base03: "var(--color-syntax-highlight-base03)", // - - base04: "var(--color-syntax-highlight-base04)", // size - base05: "var(--color-syntax-highlight-base05)", // types: "undefined" - base06: "var(--color-syntax-highlight-base06)", // - - base07: "var(--color-syntax-highlight-base07)", // key, brace - base08: "var(--color-syntax-highlight-base08)", // types: "NaN" - base09: "var(--color-syntax-highlight-base09)", // ..., types: "string" - base0A: "var(--color-syntax-highlight-base0A)", // types: "null", "regex" - base0B: "var(--color-syntax-highlight-base0B)", // types: "float" - base0C: "var(--color-syntax-highlight-base0C)", // array index - base0D: "var(--color-syntax-highlight-base0D)", // expanded icon, types: "date", "function" - base0E: "var(--color-syntax-highlight-base0E)", // collapsed icon, types: "boolean" - base0F: "var(--color-syntax-highlight-base0F)", // copy icon, types: "integer" -} - -// indent size in pixel -const INDENTATION_SIZE = 5 -// default truncate size -const DEFAULT_TRUNCATE_LENGTH = 100 - -// map of color keys to theme -const colorMap = (theme) => ({ - background: theme.base00, - ellipsis: theme.base09, - brace: theme.base07, - key: theme.base07, - index: theme.base0C, - size: theme.base04, - border: theme.base02, - highlight: { - foreground: theme.base06, - background: theme.base02, - }, - toolbar: { - border: theme.base01, - background: theme.base01, - foreground: theme.base07, - }, - icon: { - expanded: theme.base0D, - collapsed: theme.base0E, - expandAll: theme.base0E, - }, - dataType: { - boolean: theme.base0E, - date: theme.base0D, - float: theme.base0B, - function: theme.base0D, - integer: theme.base0F, - string: theme.base09, - nan: theme.base08, - null: theme.base0A, - undefined: theme.base05, - regexp: theme.base0A, - background: theme.base02, - }, -}) - -// get type of value -const type = (value) => { - if (value === null) return "null" - if (Array.isArray(value)) return "array" - if (value instanceof RegExp) return "regex" - if (value instanceof Date) return "date" - const t = (typeof value).toLowerCase() - if (t === "number") { - if (Number.isNaN(value)) return "nan" - return Number.isInteger(value) ? "integer" : "float" - } else return t -} - -// Theme context to provide colors, ident size ect. in component tree -const ThemeContext = React.createContext(DEFAULT_THEME) - -// this component renders the expand icon depends on the expanded prop -// per entry -const ExpandIcon = ({ expanded }) => { - const { colors } = useContext(ThemeContext) - return ( - <svg - fill={expanded ? colors.icon.expanded : colors.icon.collapsed} - width="1em" - height="1em" - viewBox="0 0 1792 1792" - style={{ - verticalAlign: "middle", - color: "var(--color-syntax-highlight-base0E)", - height: "1em", - width: "1em", - }} - > - <title>Expand/Collapse - {expanded ? ( - - ) : ( - - )} - - ) -} - -// Toolbar Icon -const ExpandAllIcon = () => { - const { colors } = useContext(ThemeContext) - return ( - - Expand All - - - ) -} - -// Toolbar Icon -const CollapseAllIcon = () => { - const { colors } = useContext(ThemeContext) - return ( - - Collapse All - - - ) -} - -const StringWithHighlight = ({ value }) => { - const { colors, searchTerm } = useContext(ThemeContext) - - const highlight = React.useMemo(() => { - if ( - value === undefined || - value === null || - !searchTerm || - searchTerm === "" - ) - return null - - try { - const startIndex = value - .toString() - .toLowerCase() - .indexOf(searchTerm.toLowerCase()) - - if (startIndex < 0) return null - - return { start: startIndex, end: startIndex + searchTerm.length } - } catch (e) { - console.debug("JsonViewer:", e) - return null - } - }, [searchTerm]) - - return highlight ? ( - <> - {value.slice(0, highlight.start)} - - {value.slice(highlight.start, highlight.end)} - - {value.slice(highlight.end)} - - ) : ( - value - ) -} - -// Key label (left side) with highlight functionality -const NameLabel = ({ name }) => { - const { colors } = useContext(ThemeContext) - const isIndex = typeof name === "number" - const color = isIndex ? colors.index : colors.key - const label = isIndex ? name : `"${name}"` - - return ( - - {" "} - - - - {" : "} - - ) -} - -// this component show the right side of the json, type + value -// for null, NaN and undefined values a background is shown -// value label (left side) with highlight functionality -const TypeValueLabel = ({ type, value }) => { - const { colors, truncate } = useContext(ThemeContext) - let undefinedValue = ["nan", "null", "undefined"].includes(type) - let label = type === "string" ? `"${value}"` : `${value}` - if (truncate) { - const length = truncate === true ? DEFAULT_TRUNCATE_LENGTH : truncate - if (label.length > length) label = label.slice(0, length - 3) + "..." - } - - return ( - - {!undefinedValue && ( - - {type} - - )} - - - - - ) -} - -const Toolbar = () => { - const { colors, searchTerm, onExpandAll, onSearch } = useContext(ThemeContext) - - return ( -
- - onExpandAll(true)}> - - - onExpandAll(false)}> - - - - - onSearch(e.target.value)} - clear - onClear={() => onSearch(null)} - /> -
- ) -} - -// This component renders a row of json entry -const JsonData = ({ name, value, nestedLevel = 0 }) => { - const { colors, expanded, searchTerm, indentWidth, expandAll } = - useContext(ThemeContext) - const [isExpanded, setIsExpanded] = React.useState( - expanded === true || (expanded !== false && expanded > nestedLevel) - ) - - useLayoutEffect(() => { - if (!expandAll) return - setIsExpanded(expandAll.expanded) - }, [expandAll]) - - useLayoutEffect(() => { - if (value && searchTerm) { - try { - if (JSON.stringify(value).indexOf(searchTerm) > 0) setIsExpanded(true) - } catch (e) {} - } - }, [searchTerm]) - - const dataType = React.useMemo(() => type(value), [value]) - - const children = React.useMemo(() => { - if (dataType === "array") - return value.map((v, i) => ({ name: i, value: v })) - if (dataType === "object") - return Object.keys(value).map((key, i) => ({ - name: key, - value: value[key], - })) - return null - }, [dataType, value]) - - const ExpandButton = React.useCallback( - ({ children }) => ( - { - setIsExpanded(!isExpanded) - }} - > - {children} - - ), - [isExpanded, setIsExpanded] - ) - - return ( -
-
- {/* Expand Button */} - {children && ( - <> - - - {" "} - - )} - {/* NAME */} - {(name || name === 0) && } - - {/* show type and value if no children */} - {!children ? ( - // atomic value, not an array nor an object - - ) : ( - <> - - {dataType === "array" ? "[" : "{"} - - {!isExpanded && ( - <> - {/* Expand Icon */} - - ... - - - {dataType === "array" ? "]" : "}"} - - - )} - - {" "} - {children?.length} {children?.length === 1 ? "item" : "items"} - - - {isExpanded && ( - <> - {/* sub items */} -
- {children?.map((entry, i) => ( - - ))} -
- - {dataType === "array" ? "]" : "}"} - - - )} - - )} -
-
- ) -} - -/** A component to render json data in a nice way. */ -export const JsonViewer = ({ - data, - showRoot, - toolbar, - theme, - expanded, - indentWidth, - style, - truncate, - className, - ...props -}) => { - const currentTheme = (typeof theme === "string" && themes[theme]) || { - ...DEFAULT_THEME, - ...theme, - } - const colors = colorMap(currentTheme) - const [searchTerm, setSearchTerm] = React.useState("") - const [expandAll, setExpandAll] = React.useState(null) - - return ( - - setExpandAll({ expanded: v, timestamp: Date.now() }), - onSearch: (v) => setSearchTerm(v), - }} - > -
- {toolbar && } - -
-
- ) -} - -JsonViewer.propTypes = { - /** Pass a valid json. Required. */ - // data: PropTypes.object.isRequired, - data: PropTypes.oneOfType([PropTypes.object, PropTypes.array]).isRequired, - /** pass a styles object */ - style: PropTypes.object, - /** show toolbar */ - toolbar: PropTypes.bool, - /** show root key */ - showRoot: PropTypes.bool, - /** dark, light or map of colors - * - * @param base00 background - * @param base01 NOT used - * @param base02 border, NaN,null, undefined background - * @param base03 NOT used - * @param base04 size (x items) - * @param base05 type "undefined" - * @param base06 NOT used - * @param base07 key, brace - * @param base08 type "NaN" - * @param base09 ellipsis (...), type "string" - * @param base0A types: "null", "regex" - * @param base0B type "float" - * @param base0C index - * @param base0D expanded icon, types: "date", "function" - * @param base0E collapsed icon, types: "boolean" - * @param base0F copy icon, type "integer" - */ - theme: PropTypes.oneOfType([ - PropTypes.shape({ - base00: PropTypes.string, - base01: PropTypes.string, - base02: PropTypes.string, - base03: PropTypes.string, - base04: PropTypes.string, - base05: PropTypes.string, - base06: PropTypes.string, - base07: PropTypes.string, - base08: PropTypes.string, - base09: PropTypes.string, - base0A: PropTypes.string, - base0B: PropTypes.string, - base0C: PropTypes.string, - base0D: PropTypes.string, - base0E: PropTypes.string, - base0F: PropTypes.string, - }), - PropTypes.oneOf(["dark", "light"]), - ]), - /** expanded can be true|false or a number. The number denotes the hierarchy level to which the object is expanded. */ - expanded: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]), - // cut strings after max length is reached, default length is 100 characters, if set to true. Or specifcy a different character length. */ - truncate: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]), - /* indent width */ - indentWidth: PropTypes.number, - /* add custom classes */ - className: PropTypes.string, -} - -JsonViewer.defaultProps = { - showRoot: false, - indentWidth: 4, - toolbar: false, - expanded: 1, - truncate: false, - style: undefined, - data: {}, - theme: null, -} diff --git a/libs/juno-ui-components/src/components/JsonViewer/JsonViewer.stories.js b/libs/juno-ui-components/src/components/JsonViewer/JsonViewer.stories.js deleted file mode 100644 index f516fbf97..000000000 --- a/libs/juno-ui-components/src/components/JsonViewer/JsonViewer.stories.js +++ /dev/null @@ -1,110 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { JsonViewer } from './index.js'; - -export default { - title: 'Components/JsonViewer', - component: JsonViewer, - description: 'TEST', - argTypes: {}, - parameters: { - controls: { sort: 'alpha' }, - }, -}; - -const data = { - id: 9, - date: new Date(), - getPrice: () => `$12`, - regex: /^(.+)$/, - nan: NaN, - null: null, - title: 'Infinix INBOOK', - description: 'Infinix Inbook X1 Ci3 10th 8GB...', - price: 1099, - discountPercentage: 11.83, - rating: 4.54, - stock: 96, - available: true, - array: [], - brand: 'Infinix', - category: 'laptops', - thumbnail: 'https://i.dummyjson.com/data/products/9/thumbnail.jpg', - test: 'https://i.dummyjson.com/data/products/9/thumbnail.jpg?xxxxxxxxxxxxxxxxnnnnnnnnnnnnnnnnnnnnnnnndddddddddddddddddddddddddddddddd', - test2: - 'LoremipsumdolorsitametconsectetueradipiscingelitAeneancommodoligulaegetdolorAeneanmassaCumsociisnatoquepenatibusetmagnisdisparturientmontesnasceturridiculus', - images: [ - 'https://i.dummyjson.com/data/products/9/1.jpg', - 'https://i.dummyjson.com/data/products/9/2.png', - 'https://i.dummyjson.com/data/products/9/3.png', - 'https://i.dummyjson.com/data/products/9/4.jpg', - 'https://i.dummyjson.com/data/products/9/thumbnail.jpg', - ], -}; - -const dataAsArray = [{hello: ["word", "world", "wod"], foo: "bar"}, {arrays: "are", fun: "to", work: "with, too"}]; - -export const Default = { - args: { - data, - }, -}; - -export const ArrayData = { - args: { - data: dataAsArray, - }, -}; - -export const Light = { - args: { - theme: 'light', - toolbar: true, - data, - }, -}; - -export const Expanded = { - args: { - expanded: true, - data, - }, -}; - -export const WithToolbar = { - args: { - expanded: 1, - toolbar: true, - data, - }, -}; - -export const CustomTheme = { - args: { - theme: { - base00: 'rgb(39, 40, 34)', - base01: 'rgba(73, 72, 62,0.8)', - base02: 'rgb(73, 72, 62)', - base03: '#93a1a1', - base04: 'rgb(165, 159, 133)', - base05: 'rgb(248, 248, 242)', - base06: '#073642', - base07: 'rgb(249, 248, 245)', - base08: 'rgb(249, 38, 114)', - base09: 'rgb(253, 151, 31)', - base0A: 'rgb(244, 191, 117)', - base0B: 'rgb(166, 226, 46)', - base0C: 'rgb(161, 239, 228)', - base0D: 'rgb(102, 217, 239)', - base0E: 'rgb(174, 129, 255)', - base0F: 'rgb(204, 102, 51)', - }, - data: { ...data, test2: undefined }, - toolbar: true, - truncate: false, - }, -}; diff --git a/libs/juno-ui-components/src/components/JsonViewer/JsonViewer.test.js b/libs/juno-ui-components/src/components/JsonViewer/JsonViewer.test.js deleted file mode 100644 index d484e818c..000000000 --- a/libs/juno-ui-components/src/components/JsonViewer/JsonViewer.test.js +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen } from "@testing-library/react" -import { JsonViewer } from "./index" - -describe("JsonViewer", () => { - test("renders json data", async () => { - await render() - expect(screen.getByTestId("my-json-viewer")).toBeInTheDocument() - }) - - - test("renders a custom class as passed", async () => { - await render() - expect(screen.getByTestId("my-json-viewer")).toHaveClass("my-custom-class") - }) - - test("renders other props as passed", async () => { - await render() - expect(screen.getByTestId("my-json-viewer")).toHaveAttribute( - "name", - "My shiny JsonViewer" - ) - }) -}) diff --git a/libs/juno-ui-components/src/components/JsonViewer/index.js b/libs/juno-ui-components/src/components/JsonViewer/index.js deleted file mode 100644 index 17a79c07f..000000000 --- a/libs/juno-ui-components/src/components/JsonViewer/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { JsonViewer } from "./JsonViewer.component" diff --git a/libs/juno-ui-components/src/components/JsonViewer/themes.js b/libs/juno-ui-components/src/components/JsonViewer/themes.js deleted file mode 100644 index 112163045..000000000 --- a/libs/juno-ui-components/src/components/JsonViewer/themes.js +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export const dark = { - base00: "rgb(39, 40, 34)", - base01: "rgb(245, 245, 245)", - base02: "rgb(73, 72, 62)", - base03: "#93a1a1", - base04: "rgb(165, 159, 133)", - base05: "rgb(248, 248, 242)", - base06: "#073642", - base07: "rgb(249, 248, 245)", - base08: "rgb(249, 38, 114)", - base09: "rgb(253, 151, 31)", - base0A: "rgb(244, 191, 117)", - base0B: "rgb(166, 226, 46)", - base0C: "rgb(161, 239, 228)", - base0D: "rgb(102, 217, 239)", - base0E: "rgb(174, 129, 255)", - base0F: "rgb(204, 102, 51)", -} - -export const light = { - base00: "#fff", - base01: "rgb(245, 245, 245)", - base02: "rgb(235, 235, 235)", - base03: "#93a1a1", - base04: "rgba(0, 0, 0, 0.3)", - base05: "#586e75", - base06: "#073642", - base07: "#002b36", - base08: "#d33682", - base09: "#cb4b16", - base0A: "#dc322f", - base0B: "#859900", - base0C: "#6c71c4", - base0D: "#586e75", - base0E: "#2aa198", - base0F: "#268bd2", -} diff --git a/libs/juno-ui-components/src/components/Label/Label.component.js b/libs/juno-ui-components/src/components/Label/Label.component.js deleted file mode 100644 index 41c532c80..000000000 --- a/libs/juno-ui-components/src/components/Label/Label.component.js +++ /dev/null @@ -1,113 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useRef } from "react" -import PropTypes from "prop-types" - -const labelstyles = ` - jn-text-theme-high - jn-text-base - jn-transform - jn-origin-top-left - jn-transition-all - jn-duration-100 - jn-ease-in-out - jn-z-10 -` - -const floatingStyles = ` - jn-absolute -` - -const minimizedStyles = ` - jn-scale-75 - -jn-translate-y-[0.4375rem] -` - -const requiredstyles = ` - jn-inline-block - jn-w-1 - jn-h-1 - jn-rounded-full - jn-align-top - jn-ml-1 - jn-mt-2 - jn-bg-theme-required -` - -const disabledstyles = ` - jn-opacity-50 - jn-cursor-not-allowed -` - -/** -* A re-usable Label component -*/ - -export const Label = React.forwardRef( - ( - { - text, - htmlFor, - required, - disabled, - floating, - minimized, - className, - ...props - }, forwardedRef ) => { - return ( - - ) -}) - -Label.propTypes = { - /** Pass a string of text to be rendered as contents. Required. */ - text: PropTypes.string, - /** An Id of an input element to associate the label with */ - htmlFor: PropTypes.string, - /** Required */ - required: PropTypes.bool, - /** Pass a className */ - className: PropTypes.string, - /** Label for a disabled input */ - disabled: PropTypes.bool, - /** Whether the label is floating */ - floating: PropTypes.bool, - /** Whether the label is minimized. Requires `floating` set to TRUE, otherwise it will have no effect. */ - minimized: PropTypes.bool, -} - -Label.defaultProps = { - text: "", - htmlFor: undefined, - required: false, - className: "", - disabled: false, - floating: false, - minimized: false, -} \ No newline at end of file diff --git a/libs/juno-ui-components/src/components/Label/Label.stories.js b/libs/juno-ui-components/src/components/Label/Label.stories.js deleted file mode 100644 index 68a1dad7b..000000000 --- a/libs/juno-ui-components/src/components/Label/Label.stories.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { Label } from './index.js'; - -export default { - title: 'Forms/Label', - component: Label, - argTypes: {}, -}; - -export const Default = { - args: { - text: 'My Label', - }, -}; - -export const Disabled = { - args: { - text: 'My disabled label', - disabled: true, - }, -}; - -export const Required = { - args: { - text: 'My required label', - required: true, - }, -}; diff --git a/libs/juno-ui-components/src/components/Label/Label.test.js b/libs/juno-ui-components/src/components/Label/Label.test.js deleted file mode 100644 index 7efd0a072..000000000 --- a/libs/juno-ui-components/src/components/Label/Label.test.js +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as React from "react" -import { render, screen} from "@testing-library/react" -import { Label } from "./index" - -describe("Label", () => { - - test("renders a label with a text as passed", async () => { - render(