Skip to content

Commit

Permalink
Fix controls (#28)
Browse files Browse the repository at this point in the history
<!--

Thank you for submitting a pull request!

Here's a checklist you might find useful.
[ ] There is an associated issue that is labelled
  'Bug' or 'help wanted' or is in the Community milestone
[ ] Code is up-to-date with the `main` branch
[ ] You've successfully run `npm test` locally
[ ] There are new or updated tests validating the change

-->

Fixes #

In the search control:
- add a props for placeholder

In the route building control:
- remove the route information bar when clearing the route
- autofocus on the second route point when selecting the first one
- updating the placeholder of the props
  • Loading branch information
matthew44-mappable authored Aug 2, 2024
1 parent 003dfa3 commit 5966513
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 39 deletions.
10 changes: 9 additions & 1 deletion src/controls/MMapRouteControl/MMapWaypointInput/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ export class MMapWaypointInput extends mappable.MMapComplexEntity<MMapWaypointIn
return document.activeElement === this._inputEl;
}

public triggerFocus(): void {
this._inputEl.focus();
}

constructor(props: MMapWaypointInputProps) {
super(props, {container: true});

Expand Down Expand Up @@ -151,7 +155,7 @@ export class MMapWaypointInput extends mappable.MMapComplexEntity<MMapWaypointIn
}
}

protected _onUpdate(): void {
protected _onUpdate(diffProps: Partial<MMapWaypointInputProps>): void {
if (this._props.waypoint !== undefined) {
if (this._props.waypoint === null) {
this._props.waypoint = undefined;
Expand All @@ -160,6 +164,10 @@ export class MMapWaypointInput extends mappable.MMapComplexEntity<MMapWaypointIn
this._search({text: this._props.waypoint.toString()}, this._props.waypoint);
}
}

if (diffProps.inputPlaceholder !== undefined) {
this._inputEl.placeholder = diffProps.inputPlaceholder;
}
}

protected _onDetach(): void {
Expand Down
7 changes: 4 additions & 3 deletions src/controls/MMapRouteControl/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ const svgIcons: Record<AvailableTypes, string> = {
transit: transitSVG
};

const ALLOWED_TYPES: AvailableTypes[] = ['driving', 'truck', 'walking', 'transit'];

export function createSegmentedControl(availableTypes: AvailableTypes[]): HTMLElement {
const element = document.createElement('mappable');
element.classList.add('mappable--route-control_modes');
Expand All @@ -22,14 +24,13 @@ export function createSegmentedControl(availableTypes: AvailableTypes[]): HTMLEl
container.classList.add('mappable--route-control_modes__container');
element.appendChild(container);

// TODO: Do it normally
if (availableTypes.length < 1) {
throw new Error('The route must contain at least one type of route.');
}

const options: {option: HTMLInputElement; label: HTMLLabelElement}[] = [];
(['driving', 'truck', 'walking', 'transit'] as AvailableTypes[]).forEach((routeType) => {
if (!availableTypes.includes(routeType)) {
availableTypes.forEach((routeType) => {
if (!ALLOWED_TYPES.includes(routeType)) {
return;
}
const option = document.createElement('input');
Expand Down
86 changes: 77 additions & 9 deletions src/controls/MMapRouteControl/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import debounce from 'lodash/debounce';
import {
BaseRouteResponse,
DomDetach,
Expand All @@ -10,6 +9,9 @@ import {
SuggestResponse
} from '@mappable-world/mappable-types';
import {RouteOptions, TruckParameters} from '@mappable-world/mappable-types/imperative/route';
import {CustomVuefyOptions} from '@mappable-world/mappable-types/modules/vuefy';
import type TVue from '@vue/runtime-core';
import debounce from 'lodash/debounce';
import {CustomSearch, CustomSuggest} from '../MMapSearchControl';
import {MMapWaypointInput, MMapWaypointInputProps, SelectWaypointArgs} from './MMapWaypointInput';
import {
Expand All @@ -22,7 +24,6 @@ import {
} from './helpers';
import './index.css';
import {formatDistance, formatDuration} from './utils';
import {MMapRouteControlVuefyOptions} from './vue';

export type WaypointsArray = Array<SelectWaypointArgs['feature'] | null>;

Expand All @@ -41,6 +42,7 @@ export type MMapRouteControlProps = {
truckParameters?: TruckParameters;
waypoints?: [LngLat | null, LngLat | null];
waypointsPlaceholders?: [string, string];
autofocus?: boolean;
search?: (args: CustomSearch) => Promise<SearchResponse> | SearchResponse;
suggest?: (args: CustomSuggest) => Promise<SuggestResponse> | SuggestResponse;
route?: (args: CustomRoute) => Promise<BaseRouteResponse[]> | BaseRouteResponse[];
Expand All @@ -55,10 +57,34 @@ const defaultProps = Object.freeze({
clearFieldsText: 'Clear all',
changeOrderText: 'Change the order',
waypointsPlaceholders: ['From', 'To'],
availableTypes: ['driving', 'truck', 'walking', 'transit']
availableTypes: ['driving', 'truck', 'walking', 'transit'],
autofocus: true
});
type DefaultProps = typeof defaultProps;

const MMapRouteControlVuefyOptions: CustomVuefyOptions<MMapRouteControl> = {
props: {
geolocationTextInput: String,
clearFieldsText: String,
changeOrderText: String,
availableTypes: Array as TVue.PropType<AvailableTypes[]>,
truckParameters: Object as TVue.PropType<TruckParameters>,
waypoints: Array as unknown as TVue.PropType<[LngLat | null, LngLat | null]>,
waypointsPlaceholders: Array as unknown as TVue.PropType<[string, string]>,
search: Function as TVue.PropType<MMapRouteControlProps['search']>,
suggest: Function as TVue.PropType<MMapRouteControlProps['suggest']>,
route: Function as TVue.PropType<MMapRouteControlProps['route']>,
onMouseMoveOnMap: Function as TVue.PropType<MMapRouteControlProps['onMouseMoveOnMap']>,
onUpdateWaypoints: Function as TVue.PropType<MMapRouteControlProps['onUpdateWaypoints']>,
onRouteResult: Function as TVue.PropType<MMapRouteControlProps['onRouteResult']>,
onBuildRouteError: Function as TVue.PropType<MMapRouteControlProps['onBuildRouteError']>,
autofocus: {
type: Boolean as TVue.PropType<MMapRouteControlProps['autofocus']>,
default: defaultProps.autofocus
}
}
};

export class MMapRouteControl extends mappable.MMapComplexEntity<MMapRouteControlProps, DefaultProps> {
static defaultProps = defaultProps;
static [mappable.optionsKeyVuefy] = MMapRouteControlVuefyOptions;
Expand Down Expand Up @@ -98,6 +124,8 @@ class MMapCommonRouteControl extends mappable.MMapComplexEntity<MMapRouteControl
private _waypointInputFromElement: MMapWaypointInput;
private _waypointInputToElement: MMapWaypointInput;
private _actionsContainerElement: HTMLElement;
private _changeOrderButton: HTMLButtonElement;
private _clearFieldsButton: HTMLButtonElement;

private _waypoints: WaypointsArray = [null, null];

Expand Down Expand Up @@ -132,8 +160,10 @@ class MMapCommonRouteControl extends mappable.MMapComplexEntity<MMapRouteControl
clearFieldsText: this._props.clearFieldsText,
changeOrderText: this._props.changeOrderText
});
changeOrderButton.addEventListener('click', this._changeOrder);
clearFieldsButton.addEventListener('click', this._clearAll);
this._changeOrderButton = changeOrderButton;
this._changeOrderButton.addEventListener('click', this._changeOrder);
this._clearFieldsButton = clearFieldsButton;
this._clearFieldsButton.addEventListener('click', this._clearAll);
this._actionsContainerElement = container;
this._routeParametersElement.appendChild(this._actionsContainerElement);

Expand Down Expand Up @@ -162,10 +192,28 @@ class MMapCommonRouteControl extends mappable.MMapComplexEntity<MMapRouteControl
}

protected _onUpdate(diffProps: Partial<MMapRouteControlProps>): void {
if (diffProps.waypoints) {
if (diffProps.waypoints !== undefined) {
this._waypointInputFromElement.update({waypoint: diffProps.waypoints[0]});
this._waypointInputToElement.update({waypoint: diffProps.waypoints[1]});
}
if (diffProps.geolocationTextInput !== undefined) {
this._waypointInputFromElement.update({geolocationTextInput: diffProps.geolocationTextInput});
this._waypointInputToElement.update({geolocationTextInput: diffProps.geolocationTextInput});
}
if (diffProps.waypointsPlaceholders !== undefined) {
this._waypointInputFromElement.update({inputPlaceholder: diffProps.waypointsPlaceholders[0]});
this._waypointInputToElement.update({inputPlaceholder: diffProps.waypointsPlaceholders[1]});
}
if (diffProps.clearFieldsText !== undefined) {
this._clearFieldsButton.textContent = diffProps.clearFieldsText;
}
if (diffProps.changeOrderText !== undefined) {
this._changeOrderButton.textContent = diffProps.changeOrderText;
}
if (diffProps.availableTypes !== undefined) {
this._routeModesElement.replaceChildren(...createSegmentedControl(diffProps.availableTypes).children);
this._setRouteMode(diffProps.availableTypes[0]);
}
}

protected _onDetach(): void {
Expand Down Expand Up @@ -204,8 +252,12 @@ class MMapCommonRouteControl extends mappable.MMapComplexEntity<MMapRouteControl
}

private _clearAll = () => {
this._waypointInputToElement.update({waypoint: null});
this._waypointInputFromElement.update({waypoint: null});
this._waypointInputToElement.update({waypoint: null});
this._routeInfoElement.replaceChildren();
if (this._routeInfoElement.parentElement === this._rootElement) {
this._rootElement.removeChild(this._routeInfoElement);
}
};

private _changeOrder = () => {
Expand All @@ -218,17 +270,33 @@ class MMapCommonRouteControl extends mappable.MMapComplexEntity<MMapRouteControl
this._waypoints[index] = feature;
this._props.onUpdateWaypoints?.(this._waypoints);

if (this._props.autofocus) {
this._autofocusNextInput(index);
}

if (this._waypoints.every((point) => point !== null)) {
this._route();
}
}

private _autofocusNextInput(index: number): void {
if (index === 0 && this._waypoints[1] === null) {
this._waypointInputToElement.triggerFocus();
} else if (index === 1 && this._waypoints[0] === null) {
this._waypointInputFromElement.triggerFocus();
}
}

private _onUpdateRouteMode = (e: Event) => {
const target = e.target as HTMLInputElement;
this._routeMode = target.value as RouteOptions['type'];
this._route();
this._setRouteMode(target.value as RouteOptions['type']);
};

private _setRouteMode(mode: AvailableTypes): void {
this._routeMode = mode;
this._route();
}

private _route = debounce(async () => {
if (!this._waypoints.every((point) => point !== null)) {
return;
Expand Down
24 changes: 0 additions & 24 deletions src/controls/MMapRouteControl/vue/index.ts

This file was deleted.

17 changes: 15 additions & 2 deletions src/controls/MMapSearchControl/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,19 @@ export type CustomSearch = {
};

type MMapSearchControlProps = {
placeholder?: string;
search?: ({params, map}: CustomSearch) => Promise<SearchResponse> | SearchResponse;
suggest?: ({text, map}: CustomSuggest) => Promise<SuggestResponse> | SuggestResponse;
searchResult: (result: SearchResponse) => void;
};

class MMapSearchCommonControl extends mappable.MMapComplexEntity<MMapSearchControlProps> {
const defaultProps = Object.freeze({
placeholder: 'Enter an address'
});

class MMapSearchCommonControl extends mappable.MMapComplexEntity<MMapSearchControlProps, typeof defaultProps> {
static defaultProps = defaultProps;

private _detachDom?: DomDetach;
private _rootElement?: HTMLElement;
private _clearButton?: HTMLButtonElement;
Expand Down Expand Up @@ -169,7 +176,7 @@ class MMapSearchCommonControl extends mappable.MMapComplexEntity<MMapSearchContr
this._searchInput.type = 'text';
this._searchInput.autocomplete = 'off';
this._searchInput.classList.add(SEARCH_CONTROL_INPUT_CLASS);
this._searchInput.placeholder = 'Enter an address';
this._searchInput.placeholder = this._props.placeholder;
this._searchInput.addEventListener('input', this._onChangeSearchInput);
this._searchInput.addEventListener('focus', this._onFocusBlurSearchInput);
this._searchInput.addEventListener('blur', this._onFocusBlurSearchInput);
Expand Down Expand Up @@ -212,6 +219,12 @@ class MMapSearchCommonControl extends mappable.MMapComplexEntity<MMapSearchContr
);
}

protected _onUpdate(props: Partial<MMapSearchControlProps>): void {
if (props.placeholder !== undefined) {
this._searchInput.placeholder = props.placeholder;
}
}

protected override _onDetach(): void {
this._removeDirectChild(this._suggestComponent);
this._suggestComponent = undefined;
Expand Down

0 comments on commit 5966513

Please sign in to comment.