diff --git a/dev/pages/Dashboard.tsx b/dev/pages/Dashboard.tsx new file mode 100644 index 0000000..e2bd274 --- /dev/null +++ b/dev/pages/Dashboard.tsx @@ -0,0 +1,84 @@ +import { + Dashboard, + type DashboardItem, + type DashboardProps, +} from '../../packages/react-components-pro/src/Dashboard.js'; +import { DashboardWidget } from '../../packages/react-components-pro/src/DashboardWidget.js'; +import './dashboard-styles.css'; + +type TestItem = DashboardItem & { + title?: string; + content?: string; + type?: 'kpi' | 'chart'; + header?: string; +}; + +export default function () { + const items: DashboardProps['items'] = [ + { + title: 'Total cost', + content: '+203%', + type: 'kpi', + header: '2023-2024', + }, + { + title: 'Sales', + type: 'chart', + header: '2023-2024', + colspan: 2, + }, + { + title: 'Section', + items: [ + { + title: 'Sales closed this month', + rowspan: 2, + content: '54 000€', + type: 'kpi', + }, + { + title: 'Just some number', + content: '1234', + type: 'kpi', + header: '2014-2024', + }, + ], + }, + { + title: 'Activity since 2023', + type: 'chart', + }, + ]; + + return ( + + editable + items={items} + onDashboardItemMoved={(e) => { + console.log('dashboard-item-moved', e.detail); + }} + onDashboardItemRemoved={(e) => { + console.log('dashboard-item-removed', e.detail); + }} + onDashboardItemResized={(e) => { + console.log('dashboard-item-resized', e.detail); + }} + onDashboardItemSelectedChanged={(e) => { + console.log('dashboard-item-selected-changed', e.detail); + }} + onDashboardItemMoveModeChanged={(e) => { + console.log('dashboard-item-move-mode-changed', e.detail); + }} + onDashboardItemResizeModeChanged={(e) => { + console.log('dashboard-item-resize-mode-changed', e.detail); + }} + > + {({ item }) => ( + + {item.header || ''} + {item.type === 'chart' ?
:
{item.content}
} +
+ )} + + ); +} diff --git a/dev/pages/DashboardLayout.tsx b/dev/pages/DashboardLayout.tsx index d8a7a86..a6fc1fd 100644 --- a/dev/pages/DashboardLayout.tsx +++ b/dev/pages/DashboardLayout.tsx @@ -1,30 +1,45 @@ import { DashboardLayout } from '../../packages/react-components-pro/src/DashboardLayout.js'; +import { DashboardWidget } from '../../packages/react-components-pro/src/DashboardWidget.js'; +import { DashboardSection } from '../../packages/react-components-pro/src/DashboardSection.js'; import type { CSSProperties } from 'react'; +import './dashboard-styles.css'; -const dashboardLayoutItemStyle = { - backgroundColor: '#f5f5f5', - border: '1px solid #e0e0e0', - borderRadius: '4px', - padding: '1em', - textAlign: 'center', - margin: '0.5em', - boxSizing: 'border-box', - height: '100px', +const colspan2 = { + '--vaadin-dashboard-item-colspan': '2', } as CSSProperties; -const dashboardLayoutStyle = { - '--vaadin-dashboard-col-min-width': '200px', - '--vaadin-dashboard-col-max-width': '300px', +const rowspan2 = { + '--vaadin-dashboard-item-rowspan': '2', } as CSSProperties; export default function () { return ( - -
Item 0
-
Item 1
-
Item 2
-
Item 3
-
Item 4
+ + + 2023-2024 +
+203%
+
+ + + 2023-2024 +
+
+ + + +
54 000€
+
+ + + 2014-2024 +
1234
+
+
+ + +

Activity since 2023

+
+
); } diff --git a/dev/pages/dashboard-styles.css b/dev/pages/dashboard-styles.css new file mode 100644 index 0000000..d414805 --- /dev/null +++ b/dev/pages/dashboard-styles.css @@ -0,0 +1,21 @@ +html { + --vaadin-dashboard-col-min-width: 300px; + --vaadin-dashboard-col-max-width: 500px; + --vaadin-dashboard-col-max-count: 3; + --vaadin-dashboard-row-min-height: 300px; +} + +.kpi-number { + font-size: 80px; + font-weight: bold; + color: #4caf50; + height: 100%; + display: flex; + align-items: center; + justify-content: center; +} + +.chart { + height: 100%; + background: repeating-linear-gradient(45deg, #e0e0e0, #e0e0e0 10px, #f5f5f5 10px, #f5f5f5 20px); +} diff --git a/packages/react-components-pro/package.json b/packages/react-components-pro/package.json index 14b55b3..ce95818 100644 --- a/packages/react-components-pro/package.json +++ b/packages/react-components-pro/package.json @@ -108,6 +108,10 @@ "types": "./DashboardLayout.d.ts", "default": "./DashboardLayout.js" }, + "./DashboardSection.js": { + "types": "./DashboardSection.d.ts", + "default": "./DashboardSection.js" + }, "./DashboardWidget.js": { "types": "./DashboardWidget.d.ts", "default": "./DashboardWidget.js" @@ -138,6 +142,7 @@ "./CrudEditColumn": "./CrudEditColumn.js", "./Dashboard": "./Dashboard.js", "./DashboardLayout": "./DashboardLayout.js", + "./DashboardSection": "./DashboardSection.js", "./DashboardWidget": "./DashboardWidget.js", "./GridPro": "./GridPro.js", "./GridProEditColumn": "./GridProEditColumn.js", @@ -148,4 +153,4 @@ "./utils/createComponent.js": "./utils/createComponent.js", "./utils/createComponent.js.map": "./utils/createComponent.js.map" } -} +} \ No newline at end of file diff --git a/packages/react-components-pro/src/Dashboard.ts b/packages/react-components-pro/src/Dashboard.ts deleted file mode 100644 index 7479b1c..0000000 --- a/packages/react-components-pro/src/Dashboard.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './generated/Dashboard.js'; diff --git a/packages/react-components-pro/src/Dashboard.tsx b/packages/react-components-pro/src/Dashboard.tsx new file mode 100644 index 0000000..51f2240 --- /dev/null +++ b/packages/react-components-pro/src/Dashboard.tsx @@ -0,0 +1,54 @@ +/** + * @license + * Copyright (c) 2000 - 2024 Vaadin Ltd. + * + * This program is available under Vaadin Commercial License and Service Terms. + * + * + * See https://vaadin.com/commercial-license-and-service-terms for the full + * license. + */ +import { type ComponentType, type ForwardedRef, forwardRef, type ReactElement, type RefAttributes } from 'react'; +import { + Dashboard as _Dashboard, + type DashboardItem, + type DashboardElement, + type DashboardProps as _DashboardProps, + type DashboardItemModel, +} from './generated/Dashboard.js'; +import { type ReactModelRendererProps, useModelRenderer } from '@vaadin/react-components/renderers/useModelRenderer.js'; + +export * from './generated/Dashboard.js'; + +export type DashboardReactRendererProps = ReactModelRendererProps< + TItem, + DashboardItemModel, + DashboardElement +>; + +export type DashboardProps = Partial< + Omit<_DashboardProps, 'children' | 'renderer'> +> & + Readonly<{ + children?: ComponentType> | null; + renderer?: ComponentType> | null; + }>; + +function Dashboard( + props: DashboardProps, + ref: ForwardedRef>, +): ReactElement | null { + const [portals, renderer] = useModelRenderer(props.renderer ?? props.children); + + return ( + <_Dashboard {...props} ref={ref} renderer={renderer as any}> + {portals} + + ); +} + +const ForwardedDashboard = forwardRef(Dashboard) as ( + props: DashboardProps & RefAttributes>, +) => ReactElement | null; + +export { ForwardedDashboard as Dashboard }; diff --git a/packages/react-components-pro/src/DashboardSection.ts b/packages/react-components-pro/src/DashboardSection.ts new file mode 100644 index 0000000..8e91abf --- /dev/null +++ b/packages/react-components-pro/src/DashboardSection.ts @@ -0,0 +1 @@ +export * from './generated/DashboardSection.js'; diff --git a/scripts/utils/settings.ts b/scripts/utils/settings.ts index de1e2cb..087804d 100644 --- a/scripts/utils/settings.ts +++ b/scripts/utils/settings.ts @@ -17,6 +17,7 @@ export const genericElements = new Map([ ['ComboBox', { numberOfGenerics: 1 }], ['ComboBoxLight', { numberOfGenerics: 1 }], ['Crud', { numberOfGenerics: 1 }], + ['Dashboard', { numberOfGenerics: 1, typeConstraints: ['DashboardItem'] }], ['Grid', { numberOfGenerics: 1 }], ['GridColumn', { numberOfGenerics: 1, nonGenericInterfaces: [NonGenericInterface.EVENT_MAP] }], ['GridFilterColumn', { numberOfGenerics: 1, nonGenericInterfaces: [NonGenericInterface.EVENT_MAP] }],