diff --git a/.eslintrc.yml b/.eslintrc.yml index 0b34654aa06..9146529c60c 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -10,11 +10,11 @@ env: es2022: true extends: - plugin:react/recommended + - plugin:react-hooks/recommended - plugin:import/recommended - plugin:prettier/recommended plugins: - prefer-arrow - - react-hooks settings: react: version: detect @@ -143,8 +143,10 @@ overrides: - files: - '*.stories.tsx' extends: + - 'plugin:react/jsx-runtime' - 'plugin:storybook/recommended' rules: 'react/prop-types': 'off' # inline custom components within stories don't need prop types '@typescript-eslint/no-unused-vars': 'warn' # some samples can include unused vars to show the API / signature 'react/no-unescaped-entities': 'off' + 'react-hooks/rules-of-hooks': 'off' # the CSF-3 render() functions are not detected as react components diff --git a/packages/base/src/hooks/useIsomorphicId.ts b/packages/base/src/hooks/useIsomorphicId.ts index fa5cdab3d29..560db942fe2 100644 --- a/packages/base/src/hooks/useIsomorphicId.ts +++ b/packages/base/src/hooks/useIsomorphicId.ts @@ -16,6 +16,7 @@ export function useIsomorphicId(): string { return Reflect.get(React, 'useId')(); } - const localId = useRef(getRandomId()); + // eslint-disable-next-line react-hooks/rules-of-hooks + const localId = useRef(getRandomId()); // React version never changes at runtime return localId.current; } diff --git a/packages/main/src/components/AnalyticalTable/hooks/useDynamicColumnWidths.ts b/packages/main/src/components/AnalyticalTable/hooks/useDynamicColumnWidths.ts index dd8b6ac6d44..55d4926494a 100644 --- a/packages/main/src/components/AnalyticalTable/hooks/useDynamicColumnWidths.ts +++ b/packages/main/src/components/AnalyticalTable/hooks/useDynamicColumnWidths.ts @@ -19,6 +19,7 @@ const columnsDeps = ( ) => { const isLoadingPlaceholder = !data?.length && webComponentsReactProperties.loading; const hasRows = rows?.length > 0; + // eslint-disable-next-line react-hooks/rules-of-hooks const colsEqual = useMemo(() => { return visibleColumns ?.filter( diff --git a/packages/main/src/components/AnalyticalTable/hooks/useKeyboardNavigation.ts b/packages/main/src/components/AnalyticalTable/hooks/useKeyboardNavigation.ts index cefec92b4fe..a3d46734419 100644 --- a/packages/main/src/components/AnalyticalTable/hooks/useKeyboardNavigation.ts +++ b/packages/main/src/components/AnalyticalTable/hooks/useKeyboardNavigation.ts @@ -45,7 +45,7 @@ const setFocus = (currentlyFocusedCell, nextElement) => { } }; -const getTableProps = (tableProps, { instance: { webComponentsReactProperties, data, columns } }) => { +const useGetTableProps = (tableProps, { instance: { webComponentsReactProperties, data, columns } }) => { const { showOverlay, tableRef } = webComponentsReactProperties; const currentlyFocusedCell = useRef(null); const noData = data.length === 0; @@ -294,5 +294,5 @@ const getTableProps = (tableProps, { instance: { webComponentsReactProperties, d }; export const useKeyboardNavigation = (hooks) => { - hooks.getTableProps.push(getTableProps); + hooks.getTableProps.push(useGetTableProps); }; diff --git a/packages/main/src/components/AnalyticalTable/hooks/useSelectionChangeCallback.ts b/packages/main/src/components/AnalyticalTable/hooks/useSelectionChangeCallback.ts index 5626c972b9d..bd4b9b15b54 100644 --- a/packages/main/src/components/AnalyticalTable/hooks/useSelectionChangeCallback.ts +++ b/packages/main/src/components/AnalyticalTable/hooks/useSelectionChangeCallback.ts @@ -6,6 +6,7 @@ export const useSelectionChangeCallback = (hooks) => { hooks.useControlledState.push((state, { instance }) => { const { selectedRowPayload, selectedRowIds } = state; const { rowsById, preFilteredRowsById, webComponentsReactProperties, dispatch, filters } = instance; + // eslint-disable-next-line react-hooks/rules-of-hooks useEffect(() => { if (selectedRowPayload?.fired) { const { event: e, row: selRow } = selectedRowPayload; diff --git a/packages/main/src/components/AnalyticalTable/pluginHooks/useManualRowSelect.ts b/packages/main/src/components/AnalyticalTable/pluginHooks/useManualRowSelect.ts index cdc1334c222..6464144ea7f 100644 --- a/packages/main/src/components/AnalyticalTable/pluginHooks/useManualRowSelect.ts +++ b/packages/main/src/components/AnalyticalTable/pluginHooks/useManualRowSelect.ts @@ -7,6 +7,7 @@ import { useEffect } from 'react'; */ export const useManualRowSelect = (manualRowSelectedKey = 'isSelected') => { const instanceAfterData = ({ flatRows, toggleRowSelected }) => { + // eslint-disable-next-line react-hooks/rules-of-hooks useEffect(() => { flatRows.forEach(({ id, original }) => { if (manualRowSelectedKey in original) { diff --git a/packages/main/src/components/DynamicPage/__snapshots__/DynamicPage.test.tsx.snap b/packages/main/src/components/DynamicPage/__snapshots__/DynamicPage.test.tsx.snap index cac4113d43f..9264edd75da 100644 --- a/packages/main/src/components/DynamicPage/__snapshots__/DynamicPage.test.tsx.snap +++ b/packages/main/src/components/DynamicPage/__snapshots__/DynamicPage.test.tsx.snap @@ -477,184 +477,198 @@ exports[`DynamicPage hider header button 1`] = ` data-component-name="DynamicPageContent" style="padding-bottom: 0px;" > -
-
- Phone Numbers -
- - Home: - -
- +
- +1 234-567-8901 - -
- -
- + - +1 234-567-5555 - -
-
- Social Accounts -
- - LinkedIn: - -
- +
- /DeniseSmith - -
- - Twitter: - -
- + +1 234-567-8901 + +
+ +
- @DeniseSmith - -
- -
+ +1 234-567-5555 + +
+
+ Social Accounts +
+ + LinkedIn: + +
+ + /DeniseSmith + +
+ + Twitter: + +
+ + @DeniseSmith + +
+ + +
-
- Addresses -
- - Home Address: - -
- +
- 2096 Mission Street - -
- - Mailing Address: - -
- + - PO Box 32114 - -
-
- Mailing Address -
- - Work: - -
- +
- DeniseSmith@sap.com - -
- + + 2096 Mission Street + +
+ + Mailing Address: + +
+ + PO Box 32114 + +
+
+ Mailing Address +
+ + Work: + +
+ + DeniseSmith@sap.com + +
+ +
@@ -1002,718 +1016,774 @@ exports[`DynamicPage with content 1`] = ` data-component-name="DynamicPageContent" style="padding-bottom: 0px;" > -
-
- Phone Numbers -
- - Home: - -
- +
- +1 234-567-8901 - -
- -
- + - +1 234-567-5555 - -
-
- Social Accounts -
- - LinkedIn: - -
- +
- /DeniseSmith - -
- - Twitter: - -
- + +1 234-567-8901 + +
+ +
- @DeniseSmith - -
- -
-
- Addresses -
- - Home Address: - -
- + +1 234-567-5555 + +
+
- 2096 Mission Street - -
- - Mailing Address: - -
- + - PO Box 32114 - -
-
- Mailing Address -
- - Work: - -
- +
- DeniseSmith@sap.com - -
- -
-
- Phone Numbers -
- - Home: - -
- + /DeniseSmith + +
+ - +1 234-567-8901 - -
- -
- +
- +1 234-567-5555 - -
-
- Social Accounts -
- - LinkedIn: - -
- + @DeniseSmith + +
+ +
+
+
+
- /DeniseSmith - -
- - Twitter: - -
- + - @DeniseSmith - -
- -
+
+ + 2096 Mission Street + +
+ + Mailing Address: + +
+ + PO Box 32114 + +
+
+ Mailing Address +
+ + Work: + +
+ + DeniseSmith@sap.com + +
+
+ +
-
- Addresses -
- - Home Address: - -
- +
- 2096 Mission Street - -
- - Mailing Address: - -
- + - PO Box 32114 - -
-
- Mailing Address -
- - Work: - -
- +
- DeniseSmith@sap.com - -
- -
+ +1 234-567-8901 + +
+ +
+ + +1 234-567-5555 + +
+
+ Social Accounts +
+ + LinkedIn: + +
+ + /DeniseSmith + +
+ + Twitter: + +
+ + @DeniseSmith + +
+ +
+
-
- Phone Numbers -
- - Home: - -
- +
- +1 234-567-8901 - -
- -
- + - +1 234-567-5555 - -
-
- Social Accounts -
- - LinkedIn: - -
- +
- /DeniseSmith - -
- - Twitter: - -
- + 2096 Mission Street + +
+ - @DeniseSmith -
-
- -
+
+ + PO Box 32114 + +
+
+ Mailing Address +
+ + Work: + +
+ + DeniseSmith@sap.com + +
+
+
+
-
- Addresses -
- - Home Address: - -
- +
- 2096 Mission Street - -
- - Mailing Address: - -
- + - PO Box 32114 - -
-
- Mailing Address -
- - Work: - -
- +
- DeniseSmith@sap.com - -
- -
+ +1 234-567-8901 + +
+ +
+ + +1 234-567-5555 + +
+
+ Social Accounts +
+ + LinkedIn: + +
+ + /DeniseSmith + +
+ + Twitter: + +
+ + @DeniseSmith + +
+ +
+
-
- Phone Numbers -
- - Home: - -
- +
- +1 234-567-8901 - -
- -
- + - +1 234-567-5555 - -
-
- Social Accounts -
- - LinkedIn: - -
- +
- /DeniseSmith - -
- - Twitter: - -
- + 2096 Mission Street + +
+ - @DeniseSmith -
-
- -
+
+ + PO Box 32114 + +
+
+ Mailing Address +
+ + Work: + +
+ + DeniseSmith@sap.com + +
+
+
+
-
- Addresses -
- - Home Address: - -
- +
- 2096 Mission Street - -
- - Mailing Address: - -
- + - PO Box 32114 - -
-
- Mailing Address -
- - Work: - -
- +
- DeniseSmith@sap.com - -
- + + +1 234-567-8901 + +
+ +
+ + +1 234-567-5555 + +
+
+ Social Accounts +
+ + LinkedIn: + +
+ + /DeniseSmith + +
+ + Twitter: + +
+ + @DeniseSmith + +
+ +
+
+
+
+ Addresses +
+ + Home Address: + +
+ + 2096 Mission Street + +
+ + Mailing Address: + +
+ + PO Box 32114 + +
+
+ Mailing Address +
+ + Work: + +
+ + DeniseSmith@sap.com + +
+
+
diff --git a/packages/main/src/components/Form/Form.cy.tsx b/packages/main/src/components/Form/Form.cy.tsx new file mode 100644 index 00000000000..9fc22f38816 --- /dev/null +++ b/packages/main/src/components/Form/Form.cy.tsx @@ -0,0 +1,74 @@ +import { InputType } from '../../enums/InputType'; +import { Input } from '../../webComponents'; +import { FormGroup } from '../FormGroup'; +import { FormItem } from '../FormItem'; +import { Form } from './index'; + +const component = ( +
+ {false} + {null} + {undefined} + + + + + + + + + + + + + + + + +
+); + +describe('Form', () => { + it('size S - labels and fields should cover full width', () => { + cy.viewport(393, 852); // iPhone 14 Pro + cy.mount(component); + cy.findByText('item 1:').should('have.css', 'grid-column', '1 / span 12'); + cy.findByTestId('formInput').parent().should('have.css', 'grid-column', 'auto / span 12'); + }); + + it('size M - label should cover 2/12, field 10/12', () => { + cy.viewport(834, 1194); // iPad Pro + cy.mount(component); + cy.findByText('item 1:').should('have.css', 'grid-column', '1 / span 2'); + cy.findByTestId('formInput').parent().should('have.css', 'grid-column', 'auto / span 10'); + }); + + it('size L - label should cover 1/3, field 2/3', () => { + cy.viewport(1280, 1024); + cy.mount(component); + cy.findByText('item 1:').should('have.css', 'grid-column', '1 / span 4'); + cy.findByTestId('formInput').parent().should('have.css', 'grid-column', 'auto / span 8'); + }); + + it('size XL - render two columns with 1/3 and 2/3 each', () => { + cy.viewport(1920, 1080); + cy.mount(component); + cy.findByText('item 1:').should('have.css', 'grid-column', '1 / span 4'); + cy.findByText('item 3:').should('have.css', 'grid-column', '13 / span 4'); + cy.findByTestId('formInput').parent().should('have.css', 'grid-column', '5 / span 8'); + cy.findByTestId('formInput2').parent().should('have.css', 'grid-column', '17 / span 8'); + }); + + it('change tag name', () => { + cy.mount( +
+ + + +
+ ); + cy.findByTestId('form').should('have.prop', 'nodeName', 'DIV'); + }); + + // todo pass through props test +}); diff --git a/packages/main/src/components/Form/Form.jss.ts b/packages/main/src/components/Form/Form.jss.ts index 2188c8581aa..b6569043ceb 100644 --- a/packages/main/src/components/Form/Form.jss.ts +++ b/packages/main/src/components/Form/Form.jss.ts @@ -1,69 +1,42 @@ import { ThemingParameters } from '@ui5/webcomponents-react-base'; -const labelSpanClasses = () => { - const styleClasses = {}; - for (let i = 1; i <= 11; i++) { - styleClasses[`labelSpan${i}`] = { - '--ui5wcr_form_content_span': 12 - i, - '--ui5wcr_form_label_span': i - }; - } - return styleClasses; -}; - const styles = { + formContainer: { + containerType: 'inline-size' + }, form: { display: 'grid', alignItems: 'center', rowGap: '0.25rem', columnGap: '0.5rem', - gridTemplateColumns: `repeat(12, 1fr)`, - '--ui5wcr_form_full_span': 'span 12', + gridTemplateColumns: `repeat(calc(12 * var(--ui5wcr_form_columns)), 1fr)`, '--ui5wcr_form_label_text_align': 'end', - '&[data-columns="1"]': {}, - '&[data-columns="2"]': { - gridTemplateColumns: `repeat(24, 1fr)`, - '--ui5wcr_form_full_span': 'span 24' - }, - '&[data-columns="3"]': { - gridTemplateColumns: `repeat(36, 1fr)`, - '--ui5wcr_form_full_span': 'span 36' - }, - '&[data-columns="4"]': { - gridTemplateColumns: `repeat(48, 1fr)`, - '--ui5wcr_form_full_span': 'span 48' - }, - '&[data-columns="5"]': { - gridTemplateColumns: `repeat(60, 1fr)`, - '--ui5wcr_form_full_span': 'span 60' - }, - '&[data-columns="6"]': { - gridTemplateColumns: `repeat(72, 1fr)`, - '--ui5wcr_form_full_span': 'span 72' - }, - '&[data-columns="7"]': { - gridTemplateColumns: `repeat(84, 1fr)`, - '--ui5wcr_form_full_span': 'span 84' - }, - '&[data-columns="8"]': { - gridTemplateColumns: `repeat(96, 1fr)`, - '--ui5wcr_form_full_span': 'span 96' - }, - '&[data-columns="9"]': { - gridTemplateColumns: `repeat(108, 1fr)`, - '--ui5wcr_form_full_span': 'span 108' + '--ui5wcr_form_content_span': 'calc(12 - var(--ui5wcr_form_label_span))', + + '--ui5wcr_form_columns_s': 1, + '--ui5wcr_form_columns_m': 1, + '--ui5wcr_form_columns_l': 1, + '--ui5wcr_form_columns_xl': 2, + '--ui5wcr_form_label_span_s': 12, + '--ui5wcr_form_label_span_m': 2, + '--ui5wcr_form_label_span_l': 4, + '--ui5wcr_form_label_span_xl': 4, + + '@container (max-width: 599px)': { + '--ui5wcr_form_label_span': 'var(--ui5wcr_form_label_span_s)', + '--ui5wcr_form_columns': 'var(--ui5wcr_form_columns_s)' }, - '&[data-columns="10"]': { - gridTemplateColumns: `repeat(120, 1fr)`, - '--ui5wcr_form_full_span': 'span 120' + '@container (min-width: 600px) and (max-width: 1023px)': { + '--ui5wcr_form_label_span': 'var(--ui5wcr_form_label_span_m)', + '--ui5wcr_form_columns': 'var(--ui5wcr_form_columns_m)' }, - '&[data-columns="11"]': { - gridTemplateColumns: `repeat(132, 1fr)`, - '--ui5wcr_form_full_span': 'span 132' + '@container (min-width: 1024px) and (max-width: 1439px)': { + '--ui5wcr_form_label_span': 'var(--ui5wcr_form_label_span_l)', + '--ui5wcr_form_columns': 'var(--ui5wcr_form_columns_l)' }, - '&[data-columns="12"]': { - gridTemplateColumns: `repeat(144, 1fr)`, - '--ui5wcr_form_full_span': 'span 144' + '@container (min-width: 1440px)': { + '--ui5wcr_form_label_span': 'var(--ui5wcr_form_label_span_xl)', + '--ui5wcr_form_columns': 'var(--ui5wcr_form_columns_xl)' } }, solid: { @@ -75,9 +48,8 @@ const styles = { formTitle: { borderBlockEnd: `1px solid ${ThemingParameters.sapGroup_TitleBorderColor}`, marginBlockEnd: '1.75rem', - gridColumn: 'var(--ui5wcr_form_full_span)' + gridColumn: '1 / -1' }, - ...labelSpanClasses(), labelSpan12: { '--ui5wcr_form_content_span': 12, '--ui5wcr_form_label_text_align': 'start', diff --git a/packages/main/src/components/Form/Form.mdx b/packages/main/src/components/Form/Form.mdx new file mode 100644 index 00000000000..6df735f9d37 --- /dev/null +++ b/packages/main/src/components/Form/Form.mdx @@ -0,0 +1,36 @@ +import { ControlsWithNote, DocsHeader, Footer } from '@sb/components'; +import SubcomponentsSection from '@sb/docs/SubcomponentsSection.md?raw'; +import { ArgTypes, Canvas, Description, Markdown, Meta } from '@storybook/blocks'; +import { FormGroup } from '../FormGroup'; +import { FormItem } from '../FormItem'; +import * as ComponentStories from './Form.stories'; + + + + + +
+ +## Example + + + +## Properties + + + +{SubcomponentsSection} + +## Form Group + + + + + +## FormItem + + + + + +