diff --git a/package-lock.json b/package-lock.json index 0aaa7d8de2..304b8dce2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@terrestris/ol-util": "^14.0.0", "@types/geojson": "^7946.0.10", "@types/lodash": "^4.14.197", + "@types/moment": "^2.13.0", "ag-grid-community": "^28.2.1", "ag-grid-react": "^28.2.1", "jspdf": "^2.5.1", @@ -26,8 +27,7 @@ "moment": "^2.29.4", "proj4": "^2.9.0", "prop-types": "^15.8.1", - "react-dom": "^18.2.0", - "react-rnd": "^10.3.5" + "react-dom": "^18.2.0" }, "devDependencies": { "@babel/cli": "^7.22.15", @@ -7393,6 +7393,15 @@ "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", "dev": true }, + "node_modules/@types/moment": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/@types/moment/-/moment-2.13.0.tgz", + "integrity": "sha512-DyuyYGpV6r+4Z1bUznLi/Y7HpGn4iQ4IVcGn8zrr1P4KotKLdH0sbK1TFR6RGyX6B+G8u83wCzL+bpawKU/hdQ==", + "deprecated": "This is a stub types definition for Moment (https://github.com/moment/moment). Moment provides its own type definitions, so you don't need @types/moment installed!", + "dependencies": { + "moment": "*" + } + }, "node_modules/@types/node": { "version": "20.11.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz", @@ -10478,6 +10487,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "dev": true, "engines": { "node": ">=6" } @@ -14174,11 +14184,6 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, - "node_modules/fast-memoize": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", - "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==" - }, "node_modules/fast-xml-parser": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.3.tgz", @@ -27888,18 +27893,6 @@ "node": ">=0.10.0" } }, - "node_modules/re-resizable": { - "version": "6.9.6", - "resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.9.6.tgz", - "integrity": "sha512-0xYKS5+Z0zk+vICQlcZW+g54CcJTTmHluA7JUUgvERDxnKAnytylcyPsA+BSFi759s5hPlHmBRegFrwXs2FuBQ==", - "dependencies": { - "fast-memoize": "^2.5.1" - }, - "peerDependencies": { - "react": "^16.13.1 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -28336,19 +28329,6 @@ "react": "^18.2.0" } }, - "node_modules/react-draggable": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.5.tgz", - "integrity": "sha512-OMHzJdyJbYTZo4uQE393fHcqqPYsEtkjfMgvCHr6rejT+Ezn4OZbNyGH50vv+SunC1RMvwOTSWkEODQLzw1M9g==", - "dependencies": { - "clsx": "^1.1.1", - "prop-types": "^15.8.1" - }, - "peerDependencies": { - "react": ">= 16.3.0", - "react-dom": ">= 16.3.0" - } - }, "node_modules/react-error-overlay": { "version": "6.0.11", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", @@ -28388,25 +28368,6 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, - "node_modules/react-rnd": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/react-rnd/-/react-rnd-10.4.1.tgz", - "integrity": "sha512-0m887AjQZr6p2ADLNnipquqsDq4XJu/uqVqI3zuoGD19tRm6uB83HmZWydtkilNp5EWsOHbLGF4IjWMdd5du8Q==", - "dependencies": { - "re-resizable": "6.9.6", - "react-draggable": "4.4.5", - "tslib": "2.3.1" - }, - "peerDependencies": { - "react": ">=16.3.0", - "react-dom": ">=16.3.0" - } - }, - "node_modules/react-rnd/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, "node_modules/react-shallow-renderer": { "version": "16.15.0", "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", diff --git a/package.json b/package.json index 0ec924de60..846974f6cb 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,7 @@ "@terrestris/ol-util": "^14.0.0", "@types/geojson": "^7946.0.10", "@types/lodash": "^4.14.197", + "@types/moment": "^2.13.0", "ag-grid-community": "^28.2.1", "ag-grid-react": "^28.2.1", "jspdf": "^2.5.1", @@ -84,8 +85,7 @@ "moment": "^2.29.4", "proj4": "^2.9.0", "prop-types": "^15.8.1", - "react-dom": "^18.2.0", - "react-rnd": "^10.3.5" + "react-dom": "^18.2.0" }, "devDependencies": { "@babel/cli": "^7.22.15", diff --git a/src/Container/AddWmsPanel/AddWmsPanel.example.md b/src/Container/AddWmsPanel/AddWmsPanel.example.md index e1b9508157..cd2114e0e5 100644 --- a/src/Container/AddWmsPanel/AddWmsPanel.example.md +++ b/src/Container/AddWmsPanel/AddWmsPanel.example.md @@ -49,7 +49,7 @@ class AddWmsPanelExample extends React.Component { } onClick() { - CapabilitiesUtil.parseWmsCapabilities(WMS_CAPABILITIES_URL) + CapabilitiesUtil.getWmsCapabilities(WMS_CAPABILITIES_URL) .then(CapabilitiesUtil.getLayersFromWmsCapabilities) .then(layers => { this.setState({ diff --git a/src/Container/AddWmsPanel/AddWmsPanel.less b/src/Container/AddWmsPanel/AddWmsPanel.less index acd30a4978..51fbe2e778 100644 --- a/src/Container/AddWmsPanel/AddWmsPanel.less +++ b/src/Container/AddWmsPanel/AddWmsPanel.less @@ -1,33 +1,16 @@ .add-wms-panel { - .body { - display: flex; - flex-direction: column; - - .ant-checkbox-group { - flex: 1; - height: 100%; - overflow-y: auto; - } - - .add-wms-layer-checkbox-line { - padding: 5px; - margin: 1px; - display: flex; - flex: 1; - align-items: center; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; + display: flex; + flex-direction: column; - .add-wms-add-info-icon { - margin-left: 5px; - } - } + .ant-checkbox-group { + flex: 1; + height: 100%; + overflow-y: auto; + } - .react-geo-titlebar { - .react-geo-simplebutton { - margin-right: 5px; - } - } + .buttons { + display: flex; + gap: 5px; + justify-content: end; } } diff --git a/src/Container/AddWmsPanel/AddWmsPanel.spec.tsx b/src/Container/AddWmsPanel/AddWmsPanel.spec.tsx index e8b7441abe..a27a907328 100644 --- a/src/Container/AddWmsPanel/AddWmsPanel.spec.tsx +++ b/src/Container/AddWmsPanel/AddWmsPanel.spec.tsx @@ -64,9 +64,6 @@ describe('', () => { const dialog = screen.getByRole('dialog'); expect(dialog).toBeVisible(); - const title = within(dialog).getByText(/add wms layer/i); - expect(title).toBeVisible(); - const list = within(dialog).getByRole('list'); expect(list).toBeVisible(); diff --git a/src/Container/AddWmsPanel/AddWmsPanel.tsx b/src/Container/AddWmsPanel/AddWmsPanel.tsx index ce8b673100..da3b3d6081 100644 --- a/src/Container/AddWmsPanel/AddWmsPanel.tsx +++ b/src/Container/AddWmsPanel/AddWmsPanel.tsx @@ -4,8 +4,6 @@ import OlMap from 'ol/Map'; import _isFunction from 'lodash/isFunction'; -import Panel, { PanelProps } from '../../Panel/Panel/Panel'; -import Titlebar from '../../Panel/Titlebar/Titlebar'; import SimpleButton from '../../Button/SimpleButton/SimpleButton'; import Logger from '@terrestris/base-util/dist/Logger'; @@ -27,10 +25,6 @@ interface OwnProps { * Optional text to be shown in cancel button */ cancelText: string; - /** - * Optional text to be shown in panel title - */ - titleText: string; /** * Array containing layers (e.g. `Capability.Layer.Layer` of ol capabilities * parser) @@ -59,7 +53,7 @@ interface AddWmsLayerState { selectedWmsLayers: string[]; } -export type AddWmsPanelProps = OwnProps & PanelProps; +export type AddWmsPanelProps = OwnProps; /** * Panel containing a (checkable) list of AddWmsLayerEntry instances. @@ -79,7 +73,6 @@ export class AddWmsPanel extends React.Component { - const { + const { selectedWmsLayers } = this.state; @@ -136,7 +129,7 @@ export class AddWmsPanel extends React.Component { // Add layer to map if it is not added yet - if (!map.getLayers().getArray().includes(layer) ) { + if (!map.getLayers().getArray().includes(layer)) { map.addLayer(layer); } }); @@ -160,7 +153,7 @@ export class AddWmsPanel extends React.Component { // Add layer to map if it is not added yet - if (!map.getLayers().getArray().includes(layer) ) { + if (!map.getLayers().getArray().includes(layer)) { map.addLayer(layer); } }); @@ -172,70 +165,64 @@ export class AddWmsPanel extends React.Component 0 ? - -
- this.onSelectedLayersChange(value.map(v => v as string))}> - {wmsLayers.map((layer, idx) => -
- -
- )} -
-
- - {addSelectedLayersText} - , + wmsLayers && wmsLayers.length > 0 && +
+
+ this.onSelectedLayersChange(value.map(v => v as string))}> + {wmsLayers.map((layer, idx) => +
+ +
+ )} +
+
+
+ + {addSelectedLayersText} + + + {addAllLayersText} + + { + onCancel && - {addAllLayersText} - , - onCancel ? - - {cancelText} - : null - ]} /> - - : null + {cancelText} + + } +
+
); } } diff --git a/src/Panel/Panel/Panel.example.md b/src/Panel/Panel/Panel.example.md deleted file mode 100644 index 22e75d4762..0000000000 --- a/src/Panel/Panel/Panel.example.md +++ /dev/null @@ -1,117 +0,0 @@ -This example demonstrates the use of Panels - -```jsx -import Panel from '@terrestris/react-geo/dist/Panel/Panel/Panel'; - - -
- Im a div but i can be any node. -
-
-``` - -```jsx -import Panel from '@terrestris/react-geo/dist/Panel/Panel/Panel'; - -
- -
- Content -
-
- -
- Content -
-
-
-``` - -```jsx -import Panel from '@terrestris/react-geo/dist/Panel/Panel/Panel'; - - -
- You can set the tooltip for the collapse icon with the prop `collapseTooltip`. -
-
-``` - -```jsx -import Panel from '@terrestris/react-geo/dist/Panel/Panel/Panel'; - - - - -``` - -```jsx -import Panel from '@terrestris/react-geo/dist/Panel/Panel/Panel'; - - - - -``` - -```jsx -import Panel from '@terrestris/react-geo/dist/Panel/Panel/Panel'; - - - Panel with initial size. - -``` diff --git a/src/Panel/Panel/Panel.less b/src/Panel/Panel/Panel.less deleted file mode 100644 index d2e5357333..0000000000 --- a/src/Panel/Panel/Panel.less +++ /dev/null @@ -1,46 +0,0 @@ -@handlestyle: 5px solid var(--ant-primary-4); - -.react-geo-panel { - z-index: 100; - - .body { - background-color: white; - &:focus { - border: 0; - outline: 0; - } - } - - .resize-handle { - &:hover { - &.resize-handle-right { - border-right: @handlestyle; - } - &.resize-handle-left { - border-left: @handlestyle; - } - &.resize-handle-top { - border-top: @handlestyle; - } - &.resize-handle-bottom { - border-top: @handlestyle; - } - &.resize-handle-bottom-right { - border-bottom: @handlestyle; - border-right: @handlestyle; - } - &.resize-handle-bottom-left { - border-bottom: @handlestyle; - border-left: @handlestyle; - } - &.resize-handle-top-right { - border-top: @handlestyle; - border-right: @handlestyle; - } - &.resize-handle-top-left { - border-top: @handlestyle; - border-left: @handlestyle; - } - } - } -} diff --git a/src/Panel/Panel/Panel.spec.tsx b/src/Panel/Panel/Panel.spec.tsx deleted file mode 100644 index 884db8df54..0000000000 --- a/src/Panel/Panel/Panel.spec.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import TestUtil from '../../Util/TestUtil'; - -import Panel from './Panel'; - -import { - act -} from 'react-dom/test-utils'; - -describe('', () => { - - it('is defined', () => { - expect(Panel).not.toBeUndefined(); - }); - - it('can be rendered', () => { - const wrapper = TestUtil.mountComponent(Panel); - expect(wrapper).not.toBeUndefined(); - }); - - it('passes props to Rnd', () => { - const wrapper = TestUtil.mountComponent(Panel, { - className: 'podolski', - fc: 'koeln' - }); - const rnd = wrapper.find('Rnd').getElements()[0]; - expect(rnd.props.className).toContain('podolski'); - expect(rnd.props.fc).toBe('koeln'); - }); - - describe('#onKeyDown', () => { - - const wrapper = TestUtil.mountComponent(Panel); - - // Mock a DOM to play around - document.body.className = 'react-geo-panel'; - - const element = wrapper.instance()._rnd.getSelfElement(); - - it('is defined', () => { - expect(wrapper.instance().onKeyDown).not.toBeUndefined(); - }); - - it('calls onEscape method if provided in props', () => { - const mockEvt = { - key: 'invalid_key' - }; - - wrapper.setProps({ - onEscape: jest.fn() - }); - - const onEscSpy = jest.spyOn(wrapper.props(), 'onEscape'); - const focusSpy = jest.spyOn(element, 'focus'); - - wrapper.instance().onKeyDown(mockEvt); - expect(onEscSpy).toHaveBeenCalledTimes(0); - expect(focusSpy).toHaveBeenCalledTimes(0); - - // call once again with valid key and onEscape function - mockEvt.key = 'Escape'; - - wrapper.instance().onKeyDown(mockEvt); - expect(onEscSpy).toHaveBeenCalledTimes(1); - expect(focusSpy).toHaveBeenCalledTimes(1); - expect(element.className).toContain(document.activeElement.className); - - onEscSpy.mockRestore(); - focusSpy.mockRestore(); - }); - }); - - describe('#toggleCollapse', () => { - const wrapper = TestUtil.mountComponent(Panel); - - it('is defined', () => { - expect(wrapper.instance().toggleCollapse).not.toBeUndefined(); - }); - - it('inverts the collapsed property on the state', () => { - const oldState = wrapper.state(); - act(() => { - wrapper.instance().toggleCollapse(); - }); - const newState = wrapper.state(); - expect(oldState.collapsed).toBe(!newState.collapsed); - }); - }); - - describe('#onResize', () => { - const wrapper = TestUtil.mountComponent(Panel); - - it('is defined', () => { - expect(wrapper.instance().onResize).not.toBeUndefined(); - }); - - it('sets resizing on the state to true', () => { - act(() => { - wrapper.instance().onResize(null, null, {clientHeight: 1337}); - }); - expect(wrapper.state().height).toBe(1337); - }); - - it('calls corresponding function "onResize" of props if defined', () => { - const onResizeMock = jest.fn(); - const wrapperWithMockedFunction = TestUtil.mountComponent(Panel, { - onResize: onResizeMock - }); - expect(wrapperWithMockedFunction.instance().onResizeStop).not.toBeUndefined(); - wrapperWithMockedFunction.instance().onResize(null, null, {clientHeight: 4711}); - expect(onResizeMock.mock.calls).toHaveLength(1); - }); - }); - - describe('#onResizeStart', () => { - const wrapper = TestUtil.mountComponent(Panel); - - it('is defined', () => { - expect(wrapper.instance().onResizeStart).not.toBeUndefined(); - }); - - it('sets resizing on the state to true', () => { - act(() => { - wrapper.instance().onResizeStart(); - }); - const state = wrapper.state(); - expect(state.resizing).toBe(true); - }); - - it('calls corresponding function "onResizeStart" of props if defined', () => { - const onResizeStartMock = jest.fn(); - const wrapperWithMockedFunction = TestUtil.mountComponent(Panel, { - onResizeStart: onResizeStartMock - }); - expect(wrapperWithMockedFunction.instance().onResizeStart).not.toBeUndefined(); - wrapperWithMockedFunction.instance().onResizeStart(); - expect(onResizeStartMock.mock.calls).toHaveLength(1); - }); - }); - - describe('#onResizeStop', () => { - const wrapper = TestUtil.mountComponent(Panel); - - it('is defined', () => { - expect(wrapper.instance().onResizeStop).not.toBeUndefined(); - }); - - it('sets the el size on the state', () => { - wrapper.instance().onResizeStop(); - const state = wrapper.state(); - expect(state.resizing).toBe(false); - }); - - it('calls corresponding function "onResizeStop" of props if defined', () => { - const onResizeStopMock = jest.fn(); - const wrapperWithMockedFunction = TestUtil.mountComponent(Panel, { - onResizeStop: onResizeStopMock - }); - expect(wrapperWithMockedFunction.instance().onResizeStop).not.toBeUndefined(); - wrapperWithMockedFunction.instance().onResizeStop(); - expect(onResizeStopMock.mock.calls).toHaveLength(1); - }); - }); - -}); diff --git a/src/Panel/Panel/Panel.tsx b/src/Panel/Panel/Panel.tsx deleted file mode 100644 index 85fa1454af..0000000000 --- a/src/Panel/Panel/Panel.tsx +++ /dev/null @@ -1,447 +0,0 @@ -import * as React from 'react'; -import { - Rnd, - ResizeEnable, - ResizableDelta, - Position, - Props as RndProps -} from 'react-rnd'; -import { ResizeDirection } from 're-resizable'; - -import _uniqueId from 'lodash/uniqueId'; -import _isNumber from 'lodash/isNumber'; -import _isFunction from 'lodash/isFunction'; - -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faCompress } from '@fortawesome/free-solid-svg-icons'; - -import Titlebar from '../Titlebar/Titlebar'; -import SimpleButton from '../../Button/SimpleButton/SimpleButton'; - -import { CSS_PREFIX } from '../../constants'; - -import './Panel.less'; - -interface OwnProps { - /** - * Whether to allow dragging or not. Default is false. - */ - draggable: boolean; - /** - * Whether to allow collapsing or not. Default is false. - */ - collapsible: boolean; - /** - * Whether to show panel collapsed initially or not. Default is false. - */ - collapsed: boolean; - /** - * The height of the panel. - */ - height: number | 'inherit' | 'initial' | 'auto'; - /** - * The width of the panel. - */ - width: number | 'inherit' | 'initial' | 'auto'; - /** - * The height of the TitleBar. - */ - titleBarHeight: number; - /** - * The tooltip of the collapse button. - */ - collapseTooltip: string; - /** - * - */ - tools: React.ReactElement[]; - /** - * The enableResizing property is used to set the resizable permission of a - * resizable component. - * The permission of top, right, bottom, left, topRight, bottomRight, - * bottomLeft, topLeft direction resizing. If omitted, all resizer are - * enabled. If you want to permit only right direction resizing, set { - * top:false, - * right:true, - * bottom:false, - * left:false, - * topRight:false, - * bottomRight:false, - * bottomLeft:false, - * topLeft:false - * }. - */ - resizeOpts: ResizeEnable | boolean; - id?: string; - /** - * The children to show in the Window. - */ - children?: React.ReactNode; - /** - * The title text to be shown in the window Header. - */ - title?: string; - /** - * Callback function on `keydown` keyboard event if `escape` key was pressed. - */ - onEscape?: (evt: KeyboardEvent) => void; -} - -interface PanelState { - id?: string; - /** - * Whether to show panel collapsed initially or not. Default is false. - */ - collapsed: boolean; - /** - * The height of the TitleBar. - */ - titleBarHeight: number; - /** - * The height of the panel. - */ - height: number | 'inherit' | 'initial' | 'auto'; - /** - * The width of the panel. - */ - width: number | 'inherit' | 'initial' | 'auto'; - /** - * - */ - resizing: boolean; -} - -export type PanelProps = OwnProps & RndProps; - -/** - * The Panel. - * - * @class The Panel - * @extends React.Component - */ -export class Panel extends React.Component { - - /** - * The default properties. - */ - static defaultProps = { - draggable: false, - collapsible: false, - collapsed: false, - resizeOpts: false, - titleBarHeight: 37.5, - tools: [], - height: 'auto', - width: 'auto', - collapseTooltip: 'Collapse' - }; - - /** - * The className added to this component. - * @private - */ - className = `${CSS_PREFIX}panel`; - - /** - * Printed representation of the pressed escape keyboard key. - * s. https://developer.mozilla.org/de/docs/Web/API/KeyboardEvent/key/Key_Values - * @private - */ - _escapeKeyboardEventKey = 'Esc'; - - /** - * - * - */ - _rnd: Rnd | null = null; - - /** - * Create the Panel. - * - * @constructs Panel - */ - constructor(props: PanelProps) { - super(props); - const id = props.id || _uniqueId('panel-'); - this.state = { - id: id, - collapsed: this.props.collapsible ? this.props.collapsed : false, - titleBarHeight: this.props.title ? props.titleBarHeight : 0, - height: props.height, - width: props.width, - resizing: false - }; - } - - /** - * componentDidMount life cycle method. - * Registers `keydown` listener if `onEscape` function was provided via props. - */ - componentDidMount() { - if (this.props.onEscape) { - document.addEventListener('keydown', this.onKeyDown, false); - } - } - - /** - * componentWillUnmount life cycle method. - * Unregisters `keydown` listener if `onEscape` function was provided via props. - */ - componentWillUnmount() { - if (this.props.onEscape) { - document.removeEventListener('keydown', this.onKeyDown, false); - } - } - - /** - * Calculates the height of the Panel and returns a number. - */ - calculateHeight() { - return this.state.collapsed - ? this.state.titleBarHeight - : this.state.height; - } - - /** - * Calculates the height of the Panel body and returns a valid css height - * expression. - */ - calculateBodyHeight() { - if (this.state.collapsed) { - return '0px'; - } else { - return _isNumber(this.state.height) - ? ((this.state.height as number) - this.state.titleBarHeight) + 'px' - : this.state.height; - } - } - - /** - * Toggles the collapse state of the panel. - */ - toggleCollapse() { - this.setState({ - collapsed: !this.state.collapsed - }, () => { - this._rnd?.updateSize({ - height: this.calculateHeight(), - width: this.state.width - }); - }); - } - - /** - * Function called while resizing. - * - * @param evt The MouseEvent event. - * @param direction A string discribing where the element was grabed. - * @param el The element which gets resized. - * @param delta The delta of the resizing. - * @param position The position of the resizing. - */ - onResize( - evt: MouseEvent | TouchEvent, - direction: ResizeDirection, - el: HTMLElement, - delta: ResizableDelta, - position: Position - ) { - const { onResize } = this.props; - if (_isFunction(onResize)) { - onResize(evt, direction, el, delta, position); - } - this.setState({ - height: el.clientHeight, - width: el.clientWidth - }); - } - - /** - * Function called when resizing is started. - * - * @param evt The MouseEvent event. - * @param direction A string discribing where the element was grabed. - * @param el The element which gets resized. - */ - onResizeStart( - evt: React.MouseEvent | React.TouchEvent, - direction: ResizeDirection, - el: HTMLElement - ) { - const { onResizeStart } = this.props; - if (_isFunction(onResizeStart)) { - onResizeStart(evt, direction, el); - } - this.setState({ - resizing: true - }); - } - - /** - * Function called when resizing is stopped. - * - * @param evt The MouseEvent event. - * @param direction A string discribing where the element was grabed. - * @param el The element which gets resized. - * @param delta The delta of the resizing. - * @param position The position of the resizing. - */ - onResizeStop( - evt: MouseEvent | TouchEvent, - direction: ResizeDirection, - el: HTMLElement, - delta: ResizableDelta, - position: Position - ) { - const { onResizeStop } = this.props; - if (_isFunction(onResizeStop)) { - onResizeStop(evt, direction, el, delta, position); - } - this.setState({ - resizing: false - }); - } - - /** - * Called on keyboard `keydown` event. Will be only triggered if pressed key - * is `Escape` key and `onEscape` function is provided via props. - * @param evt `keydown` event. - */ - onKeyDown = (evt: KeyboardEvent) => { - const { - onEscape - } = this.props; - if (evt && evt.key.startsWith(this._escapeKeyboardEventKey) && onEscape) { - this._rnd?.getSelfElement()?.focus(); - onEscape(evt); - } - }; - - /** - * The render function. - */ - render() { - const { - id, - className, - children, - title, - resizeOpts, - onResize, - onResizeStart, - onResizeStop, - onEscape, - draggable, - collapsible, - collapsed, - height, - width, - titleBarHeight, - collapseTooltip, - tools, - ...rndOpts - } = this.props; - - const toolsClone = tools.map(tool => React.cloneElement(tool)); - - const finalClassName = className - ? `${className} ${this.className}` - : this.className; - - const rndClassName = `${finalClassName} ${this.state.id}`; - const enableResizing = resizeOpts === true ? undefined : resizeOpts; - - if (collapsible) { - toolsClone.unshift( - } - key="collapse-tool" - onClick={this.toggleCollapse.bind(this)} - tooltip={collapseTooltip} - size="small" - />); - } - - const titleBarClassName = draggable ? - 'drag-handle ant-modal-header' : - 'ant-modal-header'; - - const titleBar = title ? - {title} - : null; - - const defaultWidth = this.state.width; - const defaultHeight = this.calculateHeight(); - const { - x, - y - } = rndOpts; - const defX = x && _isNumber(x) - ? x - : _isNumber(defaultWidth) - ? window.innerWidth / 2 - (defaultWidth as number) / 2 - : 0; - const defY = y && _isNumber(y) - ? y - : _isNumber(defaultHeight) - ? window.innerHeight / 2 - (defaultHeight as number) / 2 - : 0; - - return ( - this._rnd = rnd} - default={{ - x: defX, - y: defY, - width: defaultWidth, - height: defaultHeight - }} - dragHandleClassName="drag-handle" - disableDragging={!draggable} - enableResizing={enableResizing as ResizeEnable} - resizeHandleClasses={{ - bottom: 'resize-handle resize-handle-bottom', - bottomLeft: 'resize-handle resize-handle-bottom-left', - bottomRight: 'resize-handle resize-handle-bottom-right', - left: 'resize-handle resize-handle-left', - right: 'resize-handle resize-handle-right', - top: 'resize-handle resize-handle-top', - topLeft: 'resize-handle resize-handle-top-left', - topRight: 'resize-handle resize-handle-top-right' - }} - onResize={this.onResize.bind(this)} - onResizeStart={this.onResizeStart.bind(this)} - onResizeStop={this.onResizeStop.bind(this)} - cancel='.react-geo-titlebar .controls' - {...rndOpts} - > - {titleBar} -
- {children} -
-
- ); - } -} - -export default Panel; diff --git a/src/Panel/Titlebar/Titlebar.example.md b/src/Panel/Titlebar/Titlebar.example.md deleted file mode 100644 index 948ac25526..0000000000 --- a/src/Panel/Titlebar/Titlebar.example.md +++ /dev/null @@ -1,46 +0,0 @@ -This example demonstrates the Titlebar. - -Just a Titlebar: - -```jsx -import Titlebar from '@terrestris/react-geo/dist/Panel/Titlebar/Titlebar'; - - -``` - -A Titlebar with a title: - -```jsx -import Titlebar from '@terrestris/react-geo/dist/Panel/Titlebar/Titlebar'; - - - Title - -``` - -A Titlebar with a title and tools - -```jsx -import SimpleButton from '@terrestris/react-geo/dist/Button/SimpleButton/SimpleButton'; -import Titlebar from '@terrestris/react-geo/dist/Panel/Titlebar/Titlebar'; - -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faGlobe } from '@fortawesome/free-solid-svg-icons'; - - - } - tooltip="globe-tool" - key="globe-tool" - size="small" - /> - ]} -> - A Titlebar with a title and tools - -``` diff --git a/src/Panel/Titlebar/Titlebar.less b/src/Panel/Titlebar/Titlebar.less deleted file mode 100644 index 898658f641..0000000000 --- a/src/Panel/Titlebar/Titlebar.less +++ /dev/null @@ -1,21 +0,0 @@ -.react-geo-titlebar { - padding: 0; - display: flex; - align-items: center; - background-color: #E6E6E6; - font-weight: bold; - - .title { - margin: 5px; - flex: 1; - } - - .controls { - margin: 5px; - display: flex; - - >button { - margin-right: 2px; - } - } -} diff --git a/src/Panel/Titlebar/Titlebar.spec.tsx b/src/Panel/Titlebar/Titlebar.spec.tsx deleted file mode 100644 index 894cc42b44..0000000000 --- a/src/Panel/Titlebar/Titlebar.spec.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import * as React from 'react'; - -import TestUtil from '../../Util/TestUtil'; - -import Titlebar from './Titlebar'; -import SimpleButton from '../../Button/SimpleButton/SimpleButton'; - -describe('', () => { - - it('is defined', () => { - expect(Titlebar).not.toBeUndefined(); - }); - - it('can be rendered', () => { - const wrapper = TestUtil.mountComponent(Titlebar); - expect(wrapper).not.toBeUndefined(); - }); - - it('adds a passed className', () => { - const wrapper = TestUtil.mountComponent(Titlebar, { - className: 'podolski' - }); - expect(wrapper.instance().props.className).toContain('podolski'); - }); - - it('renders the title', () => { - const wrapper = TestUtil.mountComponent(Titlebar, { - children: 'Testtitle' - }); - const title = wrapper.find('span.title'); - expect(title.length).toBe(1); - }); - - it('renders the controls (if set)', () => { - const wrapper = TestUtil.mountComponent(Titlebar, { - children: 'Testtitle' - }); - expect(wrapper.find('span.controls').length).toBe(0); - const wrapperWithTools = TestUtil.mountComponent(Titlebar, { - children: 'Testtitle', - tools: [ - - ] - }); - expect(wrapperWithTools.find('span.controls').length).toBe(1); - }); - -}); diff --git a/src/Panel/Titlebar/Titlebar.tsx b/src/Panel/Titlebar/Titlebar.tsx deleted file mode 100644 index 223e946e93..0000000000 --- a/src/Panel/Titlebar/Titlebar.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import * as React from 'react'; -import _isEmpty from 'lodash/isEmpty'; - -import { CSS_PREFIX } from '../../constants'; - -import './Titlebar.less'; - -export interface BaseProps { - /** - * An optional CSS class which should be added. - */ - className?: string; - /** - * Additional elements to show at the right side of the Titlebar. - */ - tools?: React.ReactNode[]; -} - -export type TitlebarProps = BaseProps & React.HTMLAttributes; - -/** - * Class representing the titlebar. Usually used in a panel. - * - * @class The TitleBar - * @extends React.Component - */ -export class Titlebar extends React.Component { - - /** - * The className added to this component. - * @private - */ - className = `${CSS_PREFIX}titlebar`; - - /** - * The render function. - */ - render() { - const { - className, - tools, - children, - ...passThroughProps - } = this.props; - - const finalClassName = className - ? `${className} ${this.className}` - : this.className; - - return ( -
- - {children} - - { - !_isEmpty(tools) ? - - {tools} - : - null - } -
- ); - } -} - -export default Titlebar; diff --git a/src/Window/Window.example.md b/src/Window/Window.example.md deleted file mode 100644 index e260dee3ce..0000000000 --- a/src/Window/Window.example.md +++ /dev/null @@ -1,121 +0,0 @@ -This example demonstrates the usage of a Window component. - -Click to open window: - -```jsx -import * as React from 'react'; - -import SimpleButton from '@terrestris/react-geo/dist/Button/SimpleButton/SimpleButton'; -import Window from '@terrestris/react-geo/dist/Window/Window'; - -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faTimes } from '@fortawesome/free-solid-svg-icons'; - -class WindowExample extends React.Component { - - constructor(props) { - - super(props); - - this.state = { - simpleWinIsVisible: false, - escWinIsVisible: false - }; - } - - onClickSimple() { - this.setState({ - simpleWinIsVisible: !this.state.simpleWinIsVisible - }); - } - - onClickEsc() { - this.setState({ - escWinIsVisible: !this.state.escWinIsVisible - }); - } - - render() { - return ( -
- - {`${this.state.simpleWinIsVisible ? 'Hide' : 'Show'} a window`} - - - {`${this.state.escWinIsVisible ? 'Hide' : 'Show'} a window with bound 'keydown' listener`} - - - { - this.state.simpleWinIsVisible ? - - } - size="small" - tooltip="Close" - onClick={this.onClickSimple.bind(this)} - /> - ]} - > - This is the content of the window. - : - null - } - { - this.state.escWinIsVisible ? - - } - size="small" - tooltip="Close" - onClick={this.onClickEsc.bind(this)} - /> - ]} - > - Press escape to close me. - : - null - } -
- ); - } -} - -; -``` diff --git a/src/Window/Window.less b/src/Window/Window.less deleted file mode 100644 index 46695e521a..0000000000 --- a/src/Window/Window.less +++ /dev/null @@ -1,14 +0,0 @@ -.react-geo-window-portal { - z-index: 1000; // see @zindex-modal - position: inherit !important; - - .ant-modal-header { - padding: 1px; - - .title { - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - } - } -} diff --git a/src/Window/Window.spec.tsx b/src/Window/Window.spec.tsx deleted file mode 100644 index f233288f65..0000000000 --- a/src/Window/Window.spec.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import Window from './Window'; -import TestUtil from '../Util/TestUtil'; - -import Logger from '@terrestris/base-util/dist/Logger'; - -describe('', () => { - - it('is defined', () => { - expect(Window).not.toBeUndefined(); - }); - - it('can be rendered', () => { - const testIdToMountIn = 'testAppId'; - const divToBeRenderedIn = document.createElement('div'); - divToBeRenderedIn.id = testIdToMountIn; - document.body.appendChild(divToBeRenderedIn); - const wrapper = TestUtil.mountComponent(Window, { - parentId: testIdToMountIn - }); - expect(wrapper).not.toBeUndefined(); - }); - - it('warns if no parentId is provided', () => { - - const loggerSpy = jest.spyOn(Logger, 'warn'); - - TestUtil.mountComponent(Window, {}); - - expect(loggerSpy).toHaveBeenCalled(); - expect(loggerSpy).toHaveBeenCalledWith('No parent element was found! ' + - 'Please ensure that parentId parameter was set correctly (default ' + - 'value is `app`)'); - - loggerSpy.mockRestore(); - }); - - it('is completely removed from parent if component is unmounted', () => { - const testIdToMountIn = 'testAppId'; - const windowId = 'nice-window'; - const otherId = 'other'; - const divToBeRenderedIn = document.createElement('div'); - const divContainingOtherContent = document.createElement('div'); - divContainingOtherContent.id = otherId; - divToBeRenderedIn.id = testIdToMountIn; - document.body.appendChild(divToBeRenderedIn); - document.body.appendChild(divContainingOtherContent); - const wrapper = TestUtil.mountComponent(Window, { - parentId: testIdToMountIn, - id: windowId - }); - - expect(document.getElementById(windowId)).toBeDefined(); - expect(document.getElementById(windowId).id).toBe(windowId); - - // unmount - wrapper.instance().componentWillUnmount(); - - expect(document.getElementById(windowId)).toBeNull(); - }); - - it('changes class of component when className is changed in props', () => { - const testIdToMountIn = 'testAppId'; - const windowId = 'testId1'; - let className = 'test1'; - const divToBeRenderedIn = document.createElement('div'); - divToBeRenderedIn.id = testIdToMountIn; - document.body.appendChild(divToBeRenderedIn); - const wrapper = TestUtil.mountComponent(Window, { - parentId: testIdToMountIn, - className: className, - id: windowId - }); - expect(document.getElementById(windowId)).toBeDefined(); - expect(document.getElementById(windowId).className).toEqual(expect.stringContaining(className)); - className = 'test2'; - wrapper.setProps({ - className: className - }); - expect(document.getElementById(windowId).className).toEqual(expect.stringContaining(className)); - }); - -}); diff --git a/src/Window/Window.tsx b/src/Window/Window.tsx deleted file mode 100644 index 260d86bb2c..0000000000 --- a/src/Window/Window.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import * as React from 'react'; -import ReactDOM from 'react-dom'; - -import _uniqueId from 'lodash/uniqueId'; - -import Panel, { PanelProps } from '../Panel/Panel/Panel'; -import Logger from '@terrestris/base-util/dist/Logger'; - -import { CSS_PREFIX } from '../constants'; - -import './Window.less'; -import { ResizeEnable } from 'react-rnd'; - -interface OwnProps { - /** - * Id of the component - */ - id: string; - /** - * The id of the parent component - * default: app - */ - parentId: string; - /** - * The title text to be shown in the window header. - */ - title: string; - /** - * The resize options. - */ - resizeOpts: ResizeEnable | boolean; - /** - * Wheter the Window should be collapsible or not. - */ - collapsible: boolean; - /** - * Wheter the Window should be draggable or not. - */ - draggable: boolean; - /** - * An optional CSS class which should be added. - */ - className?: string; -} - -interface WindowState { - /** - * The user aname. - */ - resizing: boolean; - /** - * The id of the Window. - */ - id: string; -} - -export type WindowProps = OwnProps & PanelProps; - -/** - * Window component that creates a React portal that renders children into a DOM - * node that exists outside the DOM hierarchy of the parent component. By default, - * Window Component is draggable. - * - * @class Window - * @extends React.Component - */ -export class Window extends React.Component { - - static defaultProps = { - parentId: 'app', - title: 'Window', - resizeOpts: true, - collapsible: true, - draggable: true, - id: _uniqueId('window-') - }; - - /** - * The parent Element of the Window. - * @private - */ - _parent: HTMLElement | null; - - /** - * The Element of the Window. - * @private - */ - _elementDiv: HTMLDivElement; - - /** - * The className added to this component. - * @private - */ - className: string = `${CSS_PREFIX}window-portal`; - - /** - * Create a Window. - * @constructs Window - */ - constructor(props: WindowProps) { - super(props); - - const { parentId } = this.props; - this._parent = document.getElementById(parentId); - - if (!this._parent) { - Logger.warn('No parent element was found! Please ensure that parentId ' + - 'parameter was set correctly (default value is `app`)'); - } - - const div = document.createElement('div'); - div.id = props.id; - this._elementDiv = div; - - this.state = { - id: props.id, - resizing: false - }; - } - - /** - * The portal element is inserted in the DOM tree after - * the Windows's children are mounted, meaning that children - * will be mounted on a detached DOM node. If a child - * component requires to be attached to the DOM tree - * immediately when mounted, for example to measure a - * DOM node, or uses 'autoFocus' in a descendant, add - * state to Window and only render the children when Window - * is inserted in the DOM tree. - */ - componentDidMount() { - if (this._parent) { - this._parent.appendChild(this._elementDiv); - } - } - - /** - * componentWillUnmount - remove child from parent element - */ - componentWillUnmount() { - if (this._parent) { - this._parent.removeChild(this._elementDiv); - } - } - - /** - * The render function. - */ - render() { - const { - className, - children, - parentId, - ...passThroughProps - } = this.props; - - const finalClassName = className - ? `${className} ${this.className}` - : this.className; - - this._elementDiv.className = finalClassName; - - return ReactDOM.createPortal( - - {children} - , - this._elementDiv, - ); - } -} - -export default Window; diff --git a/src/index.ts b/src/index.ts index 4622d5e4cf..77cacf95a5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -34,15 +34,12 @@ import LayerTreeNode from './LayerTree/LayerTreeNode/LayerTreeNode'; import Legend from './Legend/Legend'; import FloatingMapLogo from './Map/FloatingMapLogo/FloatingMapLogo'; import MapComponent from './Map/MapComponent/MapComponent'; -import Panel from './Panel/Panel/Panel'; import TimeLayerSliderPanel from './Panel/TimeLayerSliderPanel/TimeLayerSliderPanel'; -import Titlebar from './Panel/Titlebar/Titlebar'; import LayerTransparencySlider from './Slider/LayerTransparencySlider/LayerTransparencySlider'; import MultiLayerSlider from './Slider/MultiLayerSlider/MultiLayerSlider'; import TimeSlider from './Slider/TimeSlider/TimeSlider'; import Toolbar from './Toolbar/Toolbar'; import UserChip from './UserChip/UserChip'; -import Window from './Window/Window'; import SearchResultsPanel from './Panel/SearchResultsPanel/SearchResultsPanel'; import ClickAwayListener from './Util/ClickAwayListener/ClickAwayListener'; import BackgroundLayerChooser from './BackgroundLayerChooser/BackgroundLayerChooser'; @@ -77,7 +74,6 @@ export { MultiLayerSlider, NominatimSearch, onDropAware, - Panel, PropertyGrid, ScaleCombo, SearchResultsPanel, @@ -86,7 +82,6 @@ export { timeLayerAware, TimeLayerSliderPanel, TimeSlider, - Titlebar, ToggleButton, ToggleGroup, Toolbar, @@ -95,7 +90,6 @@ export { UserChip, WfsSearch, WfsSearchInput, - Window, ZoomButton, ZoomToExtentButton }; diff --git a/styleguide.config.js b/styleguide.config.js index aece6d17e0..6edf8aec85 100644 --- a/styleguide.config.js +++ b/styleguide.config.js @@ -102,9 +102,6 @@ module.exports = { }, { name: 'Map', components: 'src/Map/**/*.tsx' - }, { - name: 'Panel', - components: 'src/Panel/**/*.tsx' }, { name: 'Slider', components: 'src/Slider/**/*.tsx' @@ -114,9 +111,6 @@ module.exports = { }, { name: 'UserChip', components: 'src/UserChip/**/*.tsx' - }, { - name: 'Window', - components: 'src/Window/**/*.tsx' }] }] };