diff --git a/.ash_history b/.ash_history index b68ac1994..617aecdcf 100644 --- a/.ash_history +++ b/.ash_history @@ -19,3 +19,4 @@ npm i react-leaflet-markercluster npm run serve npm install @pnp/spfx-property-controls --save --save-exact npm run serve +gulp clean; gulp build; gulp bundle --ship; gulp package-solution --ship; diff --git a/config/package-solution.json b/config/package-solution.json index 428f3e151..7edc5a0d9 100644 --- a/config/package-solution.json +++ b/config/package-solution.json @@ -1,25 +1,25 @@ { "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", "solution": { - "name": "SPFx app dev Map Webpart", + "name": "SPFx app dev - interactive map webpart", "id": "cc048abe-6531-4295-ab7a-12a1c95de606", "version": "1.0.0.0", "includeClientSideAssets": true, "skipFeatureDeployment": true, "isDomainIsolated": false, "developer": { - "name": "", - "websiteUrl": "", + "name": "Sergej Schwabauer", + "websiteUrl": "https://spfx-app.dev/", "privacyUrl": "", "termsOfUseUrl": "", "mpnId": "Undefined-1.14.0" }, "metadata": { "shortDescription": { - "default": "spfxappdev.webparts.map description" + "default": "Includes an interactive map module with which you can create markers" }, "longDescription": { - "default": "spfxappdev.webparts.map description" + "default": "Includes an interactive map module with which you can create markers" }, "screenshotPaths": [], "videoUrl": "", diff --git a/gulpfile.js b/gulpfile.js index 6072bc9ce..b48c692a9 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -3,6 +3,7 @@ const build = require('@microsoft/sp-build-web'); build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`); +build.addSuppression(/Warning - \[sass\] The local CSS class/gi); var getTasks = build.rig.getTasks; build.rig.getTasks = function () { diff --git a/package.json b/package.json index 8a3334ee8..faa1f92df 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "spfxappdev-webparts-map", - "version": "0.0.1", + "version": "1.0.0", "private": true, "main": "lib/index.js", "scripts": { diff --git a/src/components/inlineColorPicker/InlineColorPicker.tsx b/src/components/inlineColorPicker/InlineColorPicker.tsx index aa9b46c93..9627faf5e 100644 --- a/src/components/inlineColorPicker/InlineColorPicker.tsx +++ b/src/components/inlineColorPicker/InlineColorPicker.tsx @@ -21,7 +21,7 @@ export class InlineColorPicker extends React.Component groupName: strings.WebPartPropertyGroupAbout, groupFields: [ PropertyPaneWebPartInformation({ - description: `This is a demo webpart, used to demonstrate all the PnP property controls`, - moreInfoLink: `https://pnp.github.io/sp-dev-fx-property-controls/`, + description: `

Author

+ SPFx-App.dev +

Version

+ ${this.context.manifest.version} +

Web Part Instance id

+ ${this.context.instanceId}`, + moreInfoLink: `https://spfx-app.dev/`, key: '3f860b48-1dc3-496d-bd28-b145672289cc' }) ] diff --git a/src/webparts/map/components/AddOrEditPanel.tsx b/src/webparts/map/components/AddOrEditPanel.tsx index b4dd06765..f4a65a45c 100644 --- a/src/webparts/map/components/AddOrEditPanel.tsx +++ b/src/webparts/map/components/AddOrEditPanel.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { IMarker, IMarkerCategory, MarkerType } from './IMapProps'; import './Map.module.scss'; -import { clone } from '@microsoft/sp-lodash-subset'; +import { cloneDeep } from '@microsoft/sp-lodash-subset'; import { Icon, Panel, TextField, IPanelProps, PrimaryButton, DefaultButton, IChoiceGroupOption, ChoiceGroup, IDropdownOption, Dropdown, getColorFromString, IColor, PanelType, Label, TooltipHost } from 'office-ui-fabric-react'; import { Guid } from '@microsoft/sp-core-library'; import { isNullOrEmpty, isFunction } from '@spfxappdev/utility'; @@ -35,9 +35,9 @@ interface IAddOrEditPanelState { export default class AddOrEditPanel extends React.Component { public state: IAddOrEditPanelState = { - markerItem: clone(this.props.markerItem), - markerCategories: clone(this.props.markerCategories), - isSaveButtonDisabled: true, + markerItem: cloneDeep(this.props.markerItem), + markerCategories: cloneDeep(this.props.markerCategories), + isSaveButtonDisabled: false, isManageCategoriesDialogVisible: false }; @@ -63,7 +63,18 @@ export default class AddOrEditPanel extends React.Component, prevState: Readonly, snapshot?: any): void { + + if(!JSON.stringify(prevProps.markerCategories).Equals(JSON.stringify(this.props.markerCategories)) || + !JSON.stringify(prevProps.markerItem).Equals(JSON.stringify(this.props.markerItem))) { + this.setState({ + markerCategories: cloneDeep(this.props.markerCategories), + markerItem: cloneDeep(this.props.markerItem), + isSaveButtonDisabled: false + }); + } } public render(): React.ReactElement { @@ -74,7 +85,7 @@ export default class AddOrEditPanel extends React.Component { this.onConfigPanelDismiss() }} + onDismiss={() => { this.onConfigPanelDismiss(); }} headerText={this.headerText} closeButtonAriaLabel={strings.CloseLabel} onRenderFooterContent={(props: IPanelProps) => { @@ -233,7 +244,7 @@ export default class AddOrEditPanel extends React.Component); } - const headerLabel: string = this.state.markerItem.type == "Dialog" ? strings.LabelDialogHeader : strings.LabelPanelHeader + const headerLabel: string = this.state.markerItem.type == "Dialog" ? strings.LabelDialogHeader : strings.LabelPanelHeader; return (<> { @@ -255,7 +266,7 @@ export default class AddOrEditPanel extends React.Component - ) + ); } private renderUrlSettings(): JSX.Element { diff --git a/src/webparts/map/components/IMapProps.ts b/src/webparts/map/components/IMapProps.ts index 054f9520d..4ab4bbc65 100644 --- a/src/webparts/map/components/IMapProps.ts +++ b/src/webparts/map/components/IMapProps.ts @@ -6,18 +6,18 @@ export type MarkerType = "Panel"|"Dialog"|"Url"|"None"; export interface IMarkerClickProps { url: IMarkerUrlProperties; - content: IMarkerContentProperties + content: IMarkerContentProperties; } export interface IMarkerUrlProperties { href: string; target: '_self'|'_blank'|'embedded'; -}; +} export interface IMarkerContentProperties { headerText: string; html: string; -}; +} export interface IMarkerIcon { markerColor: string; diff --git a/src/webparts/map/components/ManageMarkerCategoriesDialog.tsx b/src/webparts/map/components/ManageMarkerCategoriesDialog.tsx index 19c7c1954..da2197a13 100644 --- a/src/webparts/map/components/ManageMarkerCategoriesDialog.tsx +++ b/src/webparts/map/components/ManageMarkerCategoriesDialog.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { IMarkerCategory } from './IMapProps'; import './Map.module.scss'; -import { clone } from '@microsoft/sp-lodash-subset'; +import { cloneDeep } from '@microsoft/sp-lodash-subset'; import { Icon, Dialog, TextField, PrimaryButton, DefaultButton, getColorFromString, IColor, DialogFooter, DialogContent, DialogType, MessageBar, TooltipHost } from 'office-ui-fabric-react'; import { Guid } from '@microsoft/sp-core-library'; import { isNullOrEmpty, isFunction } from '@spfxappdev/utility'; @@ -28,7 +28,7 @@ interface IManageMarkerCategoriesDialogState { export default class ManageMarkerCategoriesDialog extends React.Component { public state: IManageMarkerCategoriesDialogState = { - markerCategories: clone(this.props.markerCategories), + markerCategories: cloneDeep(this.props.markerCategories), isSaveButtonDisabled: false, isNewFormVisible: false, isDialogVisible: true @@ -39,7 +39,7 @@ export default class ManageMarkerCategoriesDialog extends React.Component { return (
{this.renderForm(cat, index)} -
) + ); })} } diff --git a/src/webparts/map/components/Map.module.scss b/src/webparts/map/components/Map.module.scss index e6d155eb7..5419b6f06 100644 --- a/src/webparts/map/components/Map.module.scss +++ b/src/webparts/map/components/Map.module.scss @@ -252,4 +252,8 @@ .category-messagebar { margin-bottom: 10px; } + + .CanvasControlToolbar { + z-index: 2000 !important; + } } diff --git a/src/webparts/map/components/Map.tsx b/src/webparts/map/components/Map.tsx index df2b27353..7614eedf0 100644 --- a/src/webparts/map/components/Map.tsx +++ b/src/webparts/map/components/Map.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import * as ReactDom from 'react-dom'; import styles from './Map.module.scss'; import { IMapProps, IMarker, IMarkerCategory, IMarkerIcon, emptyMarkerItem } from './IMapProps'; -import { clone } from '@microsoft/sp-lodash-subset'; +import { cloneDeep } from '@microsoft/sp-lodash-subset'; import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet'; import "leaflet/dist/leaflet.css"; import "react-leaflet-markercluster/dist/styles.min.css"; @@ -33,8 +33,8 @@ interface IMapState { export default class Map extends React.Component { public state: IMapState = { - markerItems: clone(this.props.markerItems), - markerCategories: clone(this.props.markerCategories), + markerItems: cloneDeep(this.props.markerItems), + markerCategories: cloneDeep(this.props.markerCategories), showAddOrEditMarkerPanel: false, showClickContent: false, changePositionMarkerId: '-1' @@ -71,14 +71,14 @@ export default class Map extends React.Component { this.setAllCatagoriesDictionary(); } - componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { + public componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { if(!JSON.stringify(prevProps.markerCategories).Equals(JSON.stringify(this.props.markerCategories))) { this.setState({ - markerCategories: this.props.markerCategories + markerCategories: cloneDeep(this.props.markerCategories) }, () => { this.setAllCatagoriesDictionary(); - }) + }); } } @@ -105,6 +105,7 @@ export default class Map extends React.Component { maxZoom={this.props.maxZoom} scrollWheelZoom={isScrollWheelZoomEnabled} touchZoom={isScrollWheelZoomEnabled} + doubleClickZoom={isScrollWheelZoomEnabled} dragging={isDraggingEnabled} whenCreated={(map: L.Map) => { @@ -329,7 +330,7 @@ export default class Map extends React.Component { - ) + ); })} ); } @@ -352,7 +353,7 @@ export default class Map extends React.Component { return ( { this.onContentPanelOrDialogDismiss() }} + onDismiss={() => { this.onContentPanelOrDialogDismiss(); }} headerText={this.state.currentMarker.markerClickProps.content.headerText} closeButtonAriaLabel="Close" onRenderFooterContent={(props: IPanelProps) => { @@ -521,12 +522,12 @@ export default class Map extends React.Component { } private onCreateNewMarkerContextMenuItemClick(): void { - this.state.currentMarker = clone(emptyMarkerItem); + this.state.currentMarker = cloneDeep(emptyMarkerItem); this.state.currentMarker.latitude = this.lastLatLngRightClickPosition.lat; this.state.currentMarker.longitude = this.lastLatLngRightClickPosition.lng; this.state.showAddOrEditMarkerPanel = true; - this.setState({...this.state}) + this.setState({...this.state}); } private onSetStartView(): void { diff --git a/src/webparts/map/components/MarkerIcon.tsx b/src/webparts/map/components/MarkerIcon.tsx index efdc40b06..d40ddea13 100644 --- a/src/webparts/map/components/MarkerIcon.tsx +++ b/src/webparts/map/components/MarkerIcon.tsx @@ -18,4 +18,4 @@ export const MarkerIcon: React.FunctionComponent = (iconProperties) ); -} \ No newline at end of file +}; \ No newline at end of file