@fieldia/map 0.18.0 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +143 -3
- package/package.json +4 -4
- package/src/index.d.mts +5 -0
- package/src/index.d.ts +5 -0
- package/src/index.js +4 -1
- package/src/index.js.map +1 -1
- package/src/index.mjs +2 -0
- package/src/index.mjs.map +1 -1
- package/src/lib/address-labels.d.mts +33 -0
- package/src/lib/address-labels.d.ts +33 -0
- package/src/lib/address-labels.js +16 -0
- package/src/lib/address-labels.js.map +1 -0
- package/src/lib/address-labels.mjs +12 -0
- package/src/lib/address-labels.mjs.map +1 -0
- package/src/lib/address-line.d.mts +11 -0
- package/src/lib/address-line.d.ts +11 -0
- package/src/lib/address-line.js +51 -0
- package/src/lib/address-line.js.map +1 -0
- package/src/lib/address-line.mjs +47 -0
- package/src/lib/address-line.mjs.map +1 -0
- package/src/lib/address-names.d.mts +38 -0
- package/src/lib/address-names.d.ts +38 -0
- package/src/lib/address-names.js +240 -0
- package/src/lib/address-names.js.map +1 -0
- package/src/lib/address-names.mjs +232 -0
- package/src/lib/address-names.mjs.map +1 -0
- package/src/lib/address-parts.d.mts +146 -0
- package/src/lib/address-parts.d.ts +146 -0
- package/src/lib/address-parts.js +866 -0
- package/src/lib/address-parts.js.map +1 -0
- package/src/lib/address-parts.mjs +851 -0
- package/src/lib/address-parts.mjs.map +1 -0
- package/src/lib/address-search.d.mts +25 -0
- package/src/lib/address-search.d.ts +25 -0
- package/src/lib/address-search.js +70 -0
- package/src/lib/address-search.js.map +1 -0
- package/src/lib/address-search.mjs +67 -0
- package/src/lib/address-search.mjs.map +1 -0
- package/src/lib/address-suggest.d.mts +21 -0
- package/src/lib/address-suggest.d.ts +21 -0
- package/src/lib/address-suggest.js +273 -0
- package/src/lib/address-suggest.js.map +1 -0
- package/src/lib/address-suggest.mjs +270 -0
- package/src/lib/address-suggest.mjs.map +1 -0
- package/src/lib/area-count.d.mts +47 -0
- package/src/lib/area-count.d.ts +47 -0
- package/src/lib/area-count.js +123 -0
- package/src/lib/area-count.js.map +1 -0
- package/src/lib/area-count.mjs +116 -0
- package/src/lib/area-count.mjs.map +1 -0
- package/src/lib/card.d.mts +14 -5
- package/src/lib/card.d.ts +14 -5
- package/src/lib/card.js +67 -12
- package/src/lib/card.js.map +1 -1
- package/src/lib/card.mjs +66 -12
- package/src/lib/card.mjs.map +1 -1
- package/src/lib/embed.d.mts +86 -0
- package/src/lib/embed.d.ts +86 -0
- package/src/lib/embed.js +96 -0
- package/src/lib/embed.js.map +1 -0
- package/src/lib/embed.mjs +93 -0
- package/src/lib/embed.mjs.map +1 -0
- package/src/lib/form-map.js +9 -7
- package/src/lib/form-map.js.map +1 -1
- package/src/lib/form-map.mjs +10 -8
- package/src/lib/form-map.mjs.map +1 -1
- package/src/lib/kinds.d.mts +6 -4
- package/src/lib/kinds.d.ts +6 -4
- package/src/lib/kinds.js +49 -2
- package/src/lib/kinds.js.map +1 -1
- package/src/lib/kinds.mjs +49 -2
- package/src/lib/kinds.mjs.map +1 -1
- package/src/lib/labels.d.mts +2 -0
- package/src/lib/labels.d.ts +2 -0
- package/src/lib/labels.js +4 -0
- package/src/lib/labels.js.map +1 -1
- package/src/lib/labels.mjs +4 -0
- package/src/lib/labels.mjs.map +1 -1
- package/src/lib/list-view.d.mts +37 -1
- package/src/lib/list-view.d.ts +37 -1
- package/src/lib/list-view.js +97 -37
- package/src/lib/list-view.js.map +1 -1
- package/src/lib/list-view.mjs +97 -38
- package/src/lib/list-view.mjs.map +1 -1
- package/src/lib/map-core.d.mts +6 -1
- package/src/lib/map-core.d.ts +6 -1
- package/src/lib/map-core.js +13 -5
- package/src/lib/map-core.js.map +1 -1
- package/src/lib/map-core.mjs +13 -5
- package/src/lib/map-core.mjs.map +1 -1
- package/src/lib/pins.d.mts +20 -8
- package/src/lib/pins.d.ts +20 -8
- package/src/lib/pins.js +60 -15
- package/src/lib/pins.js.map +1 -1
- package/src/lib/pins.mjs +60 -17
- package/src/lib/pins.mjs.map +1 -1
- package/src/lib/place.js +23 -11
- package/src/lib/place.js.map +1 -1
- package/src/lib/place.mjs +23 -11
- package/src/lib/place.mjs.map +1 -1
- package/src/lib/providers.d.mts +16 -0
- package/src/lib/providers.d.ts +16 -0
- package/src/lib/providers.js +71 -112
- package/src/lib/providers.js.map +1 -1
- package/src/lib/providers.mjs +71 -112
- package/src/lib/providers.mjs.map +1 -1
- package/src/lib/regions.js +18 -1
- package/src/lib/regions.js.map +1 -1
- package/src/lib/regions.mjs +18 -1
- package/src/lib/regions.mjs.map +1 -1
- package/src/lib/route-line.d.mts +9 -0
- package/src/lib/route-line.d.ts +9 -0
- package/src/lib/route-line.js +13 -0
- package/src/lib/route-line.js.map +1 -1
- package/src/lib/route-line.mjs +11 -0
- package/src/lib/route-line.mjs.map +1 -1
- package/src/lib/routes.js +6 -2
- package/src/lib/routes.js.map +1 -1
- package/src/lib/routes.mjs +6 -2
- package/src/lib/routes.mjs.map +1 -1
- package/src/lib/search-box.d.mts +20 -2
- package/src/lib/search-box.d.ts +20 -2
- package/src/lib/search-box.js +133 -44
- package/src/lib/search-box.js.map +1 -1
- package/src/lib/search-box.mjs +133 -44
- package/src/lib/search-box.mjs.map +1 -1
- package/src/lib/settings.d.mts +19 -2
- package/src/lib/settings.d.ts +19 -2
- package/src/lib/styles.d.mts +12 -1
- package/src/lib/styles.d.ts +12 -1
- package/src/lib/styles.js +61 -3
- package/src/lib/styles.js.map +1 -1
- package/src/lib/styles.mjs +59 -2
- package/src/lib/styles.mjs.map +1 -1
- package/src/lib/view-box.d.mts +18 -0
- package/src/lib/view-box.d.ts +18 -0
- package/src/lib/view-box.js +31 -0
- package/src/lib/view-box.js.map +1 -0
- package/src/lib/view-box.mjs +25 -0
- package/src/lib/view-box.mjs.map +1 -0
- package/src/lib/widgets.d.mts +3 -0
- package/src/lib/widgets.d.ts +3 -0
- package/src/lib/widgets.js +10 -1
- package/src/lib/widgets.js.map +1 -1
- package/src/lib/widgets.mjs +10 -1
- package/src/lib/widgets.mjs.map +1 -1
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { boxFilter, whole } from './view-box.mjs';
|
|
2
|
+
/**
|
|
3
|
+
* How many records a list map's view holds, said on "Search this area"
|
|
4
|
+
* before it is pressed: counted among the records on hand when they can
|
|
5
|
+
* tell, asked otherwise. Its code comes the first time the button shows.
|
|
6
|
+
*/
|
|
7
|
+
/** Whether a place lies in a box, its edges included, as `between` takes them. */
|
|
8
|
+
export function inBox(at, box) {
|
|
9
|
+
if (at.lat < box.south || at.lat > box.north)
|
|
10
|
+
return false;
|
|
11
|
+
return box.west <= box.east ? at.lng >= box.west && at.lng <= box.east : at.lng >= box.west || at.lng <= box.east;
|
|
12
|
+
}
|
|
13
|
+
/** Whether one box lies within another. */
|
|
14
|
+
export function boxWithin(inner, outer) {
|
|
15
|
+
if (inner.south < outer.south || inner.north > outer.north)
|
|
16
|
+
return false;
|
|
17
|
+
if (whole(outer))
|
|
18
|
+
return true;
|
|
19
|
+
// Each as a stretch eastwards from its west edge; the inner one a world further round, if that is where it fits.
|
|
20
|
+
const span = (box) => [box.west, box.east < box.west ? box.east + 360 : box.east];
|
|
21
|
+
const [w, e] = span(outer);
|
|
22
|
+
const [iw, ie] = span(inner);
|
|
23
|
+
return [0, 360].some((by) => iw + by >= w && ie + by <= e);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The view a search already holds, as the map's "Search this area" puts it
|
|
27
|
+
* (its very conditions, found among the search's), and the search's other
|
|
28
|
+
* conditions: a new view takes its place, as a search bar keeps one.
|
|
29
|
+
*/
|
|
30
|
+
export function ownBox(spec, filter) {
|
|
31
|
+
const said = filter.map((item) => JSON.stringify(item));
|
|
32
|
+
const numbers = (value) => (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === 'number') ? value : null);
|
|
33
|
+
const boxes = [];
|
|
34
|
+
for (const item of filter) {
|
|
35
|
+
if ('any' in item || 'all' in item)
|
|
36
|
+
continue;
|
|
37
|
+
const v = item.value;
|
|
38
|
+
if (spec.point) {
|
|
39
|
+
if (item.field === spec.point && item.op === 'within' && v && ['south', 'west', 'north', 'east'].every((k) => typeof v[k] === 'number'))
|
|
40
|
+
boxes.push(v);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const lat = item.field === spec.latitude && item.op === 'between' ? numbers(v) : null;
|
|
44
|
+
if (!lat)
|
|
45
|
+
continue;
|
|
46
|
+
// Its longitudes: a range, either side of the antimeridian, or (tried last) the world round.
|
|
47
|
+
const sides = [];
|
|
48
|
+
for (const other of filter) {
|
|
49
|
+
if ('any' in other && other.any.length === 2) {
|
|
50
|
+
const [a, b] = other.any;
|
|
51
|
+
if (a.field === spec.longitude && b.field === spec.longitude && typeof a.value === 'number' && typeof b.value === 'number')
|
|
52
|
+
sides.push([a.value, b.value]);
|
|
53
|
+
}
|
|
54
|
+
else if (!('all' in other) && !('any' in other) && other.field === spec.longitude && other.op === 'between' && numbers(other.value))
|
|
55
|
+
sides.push(numbers(other.value));
|
|
56
|
+
}
|
|
57
|
+
for (const [west, east] of [...sides, [-180, 180]])
|
|
58
|
+
boxes.push({ south: lat[0], west, north: lat[1], east });
|
|
59
|
+
}
|
|
60
|
+
for (const box of boxes) {
|
|
61
|
+
const own = boxFilter(spec, box).map((item) => JSON.stringify(item));
|
|
62
|
+
if (!own.every((item) => said.includes(item)))
|
|
63
|
+
continue;
|
|
64
|
+
return { box: { ...box }, rest: filter.filter((_, i) => !own.includes(said[i])) };
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* One question at a time, the last one winning: each ask waits `wait`
|
|
70
|
+
* milliseconds (a run of moves asks once), aborts the one before it, and an
|
|
71
|
+
* answer that comes after a newer ask is dropped. A refusal says nothing.
|
|
72
|
+
*/
|
|
73
|
+
export function lastAsk(wait) {
|
|
74
|
+
let timer;
|
|
75
|
+
let asking = null;
|
|
76
|
+
let asked = 0;
|
|
77
|
+
const stop = () => {
|
|
78
|
+
clearTimeout(timer);
|
|
79
|
+
asking?.abort();
|
|
80
|
+
asking = null;
|
|
81
|
+
asked++;
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
ask(question, answer) {
|
|
85
|
+
stop();
|
|
86
|
+
const mine = asked;
|
|
87
|
+
timer = setTimeout(() => {
|
|
88
|
+
const controller = (asking = new AbortController());
|
|
89
|
+
question(controller.signal).then((value) => mine === asked && !controller.signal.aborted && answer(value), () => undefined);
|
|
90
|
+
}, wait);
|
|
91
|
+
},
|
|
92
|
+
stop,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The count for a view: the records on hand say it when they are all the
|
|
97
|
+
* search finds and the view lies within any area it already holds;
|
|
98
|
+
* otherwise `ask` (the app's count, or its source's) is asked, for the
|
|
99
|
+
* search with the view in the area's place, a moment after the map stops;
|
|
100
|
+
* otherwise there is no number.
|
|
101
|
+
*/
|
|
102
|
+
export function areaCounter(spec, ask, say) {
|
|
103
|
+
const asker = lastAsk(400);
|
|
104
|
+
return {
|
|
105
|
+
count(view, shown) {
|
|
106
|
+
asker.stop();
|
|
107
|
+
const own = ownBox(spec, shown.filter);
|
|
108
|
+
if (shown.all && (!own || boxWithin(view, own.box)))
|
|
109
|
+
return say(shown.places.filter((at) => at && inBox(at, view)).length);
|
|
110
|
+
if (ask)
|
|
111
|
+
asker.ask((signal) => ask([...(own ? own.rest : shown.filter), ...boxFilter(spec, view)], signal), say);
|
|
112
|
+
},
|
|
113
|
+
stop: asker.stop,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=area-count.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"area-count.mjs","sourceRoot":"","sources":["../../../../../libs/map/src/lib/area-count.ts"],"names":[],"mappings":"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"}
|
package/src/lib/card.d.mts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CardLine, type Locale, type MapCard, type Page, type Value } from '@fieldia/core';
|
|
2
2
|
import { type ListMapLabels, type MapLabels } from './labels.mjs';
|
|
3
3
|
import { type MapRecord } from './pins.mjs';
|
|
4
4
|
/**
|
|
5
5
|
* The card a pin opens on a list's map: the record's picture, its title,
|
|
6
|
-
* the
|
|
6
|
+
* the lines the page names, a box to choose it (the same choice as its
|
|
7
7
|
* row's) and a button to open it. Written in the page's direction, though
|
|
8
|
-
* the map under it is left to right; every word goes in as text
|
|
8
|
+
* the map under it is left to right; every word goes in as text, and each
|
|
9
|
+
* of the record's words in its own direction: an English name on an Arabic
|
|
10
|
+
* page reads as typed, "280 m²" stays "280 m²".
|
|
11
|
+
*
|
|
12
|
+
* A page may write its lines bare ("13,900,000 EGP", "Sheikh Zayed · 4 beds
|
|
13
|
+
* · 280 m²"), their labels kept for a screen reader; lead with the first;
|
|
14
|
+
* link the title and the picture to the record's own address; and leave the
|
|
15
|
+
* box to choose off a map people only look at.
|
|
9
16
|
*/
|
|
10
17
|
export interface CardOptions {
|
|
11
18
|
document: Document;
|
|
@@ -16,8 +23,8 @@ export interface CardOptions {
|
|
|
16
23
|
card: MapCard;
|
|
17
24
|
/** The field that names the record. */
|
|
18
25
|
title: string;
|
|
19
|
-
/** The
|
|
20
|
-
fields:
|
|
26
|
+
/** The lines the card shows, in order: a field, a field with its words, or several on one line. */
|
|
27
|
+
fields: CardLine[];
|
|
21
28
|
record: MapRecord;
|
|
22
29
|
/** A box to choose the record, as its row's is: a list's map has one, a form's does not. */
|
|
23
30
|
chosen?: boolean;
|
|
@@ -38,6 +45,8 @@ export interface Card {
|
|
|
38
45
|
/** Where focus goes when the card was opened from the keyboard. */
|
|
39
46
|
focus(): void;
|
|
40
47
|
}
|
|
48
|
+
/** A record's address on the web, when a link may go there: a web, mail or phone address, or a path of this site; never a script. */
|
|
49
|
+
export declare function webAddress(value: Value | undefined): string;
|
|
41
50
|
export declare function drawCard(options: CardOptions): Card;
|
|
42
51
|
/** Pins on one spot that no zoom parts: a list of them, each opening its own card; one with no card is only named. */
|
|
43
52
|
export declare function drawCrowd(options: {
|
package/src/lib/card.d.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CardLine, type Locale, type MapCard, type Page, type Value } from '@fieldia/core';
|
|
2
2
|
import { type ListMapLabels, type MapLabels } from './labels';
|
|
3
3
|
import { type MapRecord } from './pins';
|
|
4
4
|
/**
|
|
5
5
|
* The card a pin opens on a list's map: the record's picture, its title,
|
|
6
|
-
* the
|
|
6
|
+
* the lines the page names, a box to choose it (the same choice as its
|
|
7
7
|
* row's) and a button to open it. Written in the page's direction, though
|
|
8
|
-
* the map under it is left to right; every word goes in as text
|
|
8
|
+
* the map under it is left to right; every word goes in as text, and each
|
|
9
|
+
* of the record's words in its own direction: an English name on an Arabic
|
|
10
|
+
* page reads as typed, "280 m²" stays "280 m²".
|
|
11
|
+
*
|
|
12
|
+
* A page may write its lines bare ("13,900,000 EGP", "Sheikh Zayed · 4 beds
|
|
13
|
+
* · 280 m²"), their labels kept for a screen reader; lead with the first;
|
|
14
|
+
* link the title and the picture to the record's own address; and leave the
|
|
15
|
+
* box to choose off a map people only look at.
|
|
9
16
|
*/
|
|
10
17
|
export interface CardOptions {
|
|
11
18
|
document: Document;
|
|
@@ -16,8 +23,8 @@ export interface CardOptions {
|
|
|
16
23
|
card: MapCard;
|
|
17
24
|
/** The field that names the record. */
|
|
18
25
|
title: string;
|
|
19
|
-
/** The
|
|
20
|
-
fields:
|
|
26
|
+
/** The lines the card shows, in order: a field, a field with its words, or several on one line. */
|
|
27
|
+
fields: CardLine[];
|
|
21
28
|
record: MapRecord;
|
|
22
29
|
/** A box to choose the record, as its row's is: a list's map has one, a form's does not. */
|
|
23
30
|
chosen?: boolean;
|
|
@@ -38,6 +45,8 @@ export interface Card {
|
|
|
38
45
|
/** Where focus goes when the card was opened from the keyboard. */
|
|
39
46
|
focus(): void;
|
|
40
47
|
}
|
|
48
|
+
/** A record's address on the web, when a link may go there: a web, mail or phone address, or a path of this site; never a script. */
|
|
49
|
+
export declare function webAddress(value: Value | undefined): string;
|
|
41
50
|
export declare function drawCard(options: CardOptions): Card;
|
|
42
51
|
/** Pins on one spot that no zoom parts: a list of them, each opening its own card; one with no card is only named. */
|
|
43
52
|
export declare function drawCrowd(options: {
|
package/src/lib/card.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.webAddress = webAddress;
|
|
3
4
|
exports.drawCard = drawCard;
|
|
4
5
|
exports.drawCrowd = drawCrowd;
|
|
6
|
+
const core_1 = require("@fieldia/core");
|
|
5
7
|
const labels_1 = require("./labels");
|
|
6
8
|
const pins_1 = require("./pins");
|
|
7
9
|
function make(doc, tag, className, ...children) {
|
|
@@ -18,30 +20,83 @@ function closeButton(doc, labels, close) {
|
|
|
18
20
|
button.addEventListener('click', close);
|
|
19
21
|
return button;
|
|
20
22
|
}
|
|
23
|
+
/** A record's address on the web, when a link may go there: a web, mail or phone address, or a path of this site; never a script. */
|
|
24
|
+
function webAddress(value) {
|
|
25
|
+
const text = typeof value === 'string' ? value.trim() : '';
|
|
26
|
+
const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(text)?.[1].toLowerCase();
|
|
27
|
+
return text && (!scheme || ['http', 'https', 'mailto', 'tel'].includes(scheme)) ? text : '';
|
|
28
|
+
}
|
|
29
|
+
const plurals = new Map();
|
|
30
|
+
/** The words after a number, in the plural form the page's language gives it: "1 bed", "4 beds". */
|
|
31
|
+
function unitWords(unit, value, locale) {
|
|
32
|
+
if (typeof unit === 'string')
|
|
33
|
+
return unit;
|
|
34
|
+
let rules = plurals.get(locale);
|
|
35
|
+
if (!rules)
|
|
36
|
+
plurals.set(locale, (rules = new Intl.PluralRules(locale)));
|
|
37
|
+
const form = typeof value === 'number' ? rules.select(value) : 'other';
|
|
38
|
+
return unit[form] ?? unit.other;
|
|
39
|
+
}
|
|
40
|
+
/** A part of a line as words: its value as the field shows it, and its own words after it, kept on one line with it. */
|
|
41
|
+
function partWords(page, part, values, locale) {
|
|
42
|
+
const said = (0, pins_1.shown)(page, part.field, values, locale);
|
|
43
|
+
if (said === '' || part.unit === undefined)
|
|
44
|
+
return said;
|
|
45
|
+
const unit = unitWords(part.unit, values[part.field], locale);
|
|
46
|
+
return unit ? `${said}\u00a0${unit}` : said;
|
|
47
|
+
}
|
|
21
48
|
function drawCard(options) {
|
|
22
|
-
const { document: doc, page, locale, labels, record } = options;
|
|
49
|
+
const { document: doc, page, locale, labels, record, card } = options;
|
|
23
50
|
const title = (0, pins_1.shown)(page, options.title, record.values, locale) || String(record.id);
|
|
24
51
|
const element = make(doc, 'div', 'fd-map-card');
|
|
25
52
|
element.dir = options.dir;
|
|
26
53
|
element.setAttribute('role', 'group');
|
|
27
54
|
element.setAttribute('aria-label', title);
|
|
28
55
|
element.dataset['id'] = String(record.id);
|
|
29
|
-
const
|
|
56
|
+
const href = card.href ? webAddress(record.values[card.href]) : '';
|
|
57
|
+
/** A link to the record's own address: one a person can open in a new tab, or copy. */
|
|
58
|
+
const link = (className, ...children) => {
|
|
59
|
+
const a = make(doc, 'a', className, ...children);
|
|
60
|
+
a.href = href;
|
|
61
|
+
return a;
|
|
62
|
+
};
|
|
63
|
+
const picture = card.image ? (0, pins_1.imageSource)(record.values[card.image]) : '';
|
|
30
64
|
if (picture) {
|
|
31
65
|
const img = make(doc, 'img', 'fd-map-card-image');
|
|
32
66
|
img.alt = '';
|
|
33
67
|
img.decoding = 'async';
|
|
34
68
|
img.src = picture;
|
|
35
|
-
|
|
69
|
+
// The picture goes where the title does; the title's link is the one the keys and a screen reader reach.
|
|
70
|
+
if (href) {
|
|
71
|
+
const to = link('fd-map-card-picture', img);
|
|
72
|
+
to.tabIndex = -1;
|
|
73
|
+
to.setAttribute('aria-hidden', 'true');
|
|
74
|
+
element.append(to);
|
|
75
|
+
}
|
|
76
|
+
else
|
|
77
|
+
element.append(img);
|
|
36
78
|
}
|
|
37
79
|
const body = make(doc, 'div', 'fd-map-card-body');
|
|
38
80
|
const close = closeButton(doc, labels, options.close);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
81
|
+
const name = make(doc, 'bdi', '', title);
|
|
82
|
+
body.append(make(doc, 'div', 'fd-map-card-head', make(doc, 'strong', 'fd-map-card-title', href ? link('fd-map-card-link', name) : name), close));
|
|
83
|
+
// Each line: its label (or its parts' labels), and its parts, each a value in its own direction, parted by a dot.
|
|
84
|
+
const lines = (0, core_1.cardLines)({ fields: options.fields })
|
|
85
|
+
.map((parts) => parts.map((part) => ({ part, said: partWords(page, part, record.values, locale) })).filter(({ said }) => said !== ''))
|
|
86
|
+
.filter((parts) => parts.length);
|
|
87
|
+
if (lines.length) {
|
|
88
|
+
const list = make(doc, 'dl', 'fd-map-card-fields', ...lines.map((parts) => {
|
|
89
|
+
const label = parts.map(({ part }) => page.fields[part.field]?.label ?? part.field).join(' · ');
|
|
90
|
+
const value = make(doc, 'dd', '', ...parts.flatMap(({ said }, i) => [...(i ? [' · '] : []), make(doc, 'bdi', '', said)]));
|
|
91
|
+
return make(doc, 'div', '', make(doc, 'dt', '', label), value);
|
|
92
|
+
}));
|
|
93
|
+
// Bare values, their labels said to a screen reader alone; the first line leading.
|
|
94
|
+
if (card.labels === false)
|
|
95
|
+
list.dataset['labels'] = 'hidden';
|
|
96
|
+
if (card.lead)
|
|
97
|
+
list.toggleAttribute('data-lead', true);
|
|
98
|
+
body.append(list);
|
|
99
|
+
}
|
|
45
100
|
const box = make(doc, 'input', 'fd-map-card-check');
|
|
46
101
|
box.type = 'checkbox';
|
|
47
102
|
box.checked = !!options.chosen;
|
|
@@ -56,7 +111,7 @@ function drawCard(options) {
|
|
|
56
111
|
actions.append(button);
|
|
57
112
|
first = button;
|
|
58
113
|
}
|
|
59
|
-
if (options.open &&
|
|
114
|
+
if (options.open && card.open !== false) {
|
|
60
115
|
const open = make(doc, 'button', 'fd-button fd-button-primary fd-map-card-open', labels.openRecord);
|
|
61
116
|
open.type = 'button';
|
|
62
117
|
open.addEventListener('click', () => options.open?.());
|
|
@@ -83,8 +138,8 @@ function drawCrowd(options) {
|
|
|
83
138
|
const close = closeButton(doc, labels, options.close);
|
|
84
139
|
const items = options.records.map(({ record, name, plain }) => {
|
|
85
140
|
if (plain)
|
|
86
|
-
return make(doc, 'li', '', make(doc, 'span', 'fd-map-crowd-item', name));
|
|
87
|
-
const button = make(doc, 'button', 'fd-map-crowd-item', name);
|
|
141
|
+
return make(doc, 'li', '', make(doc, 'span', 'fd-map-crowd-item', make(doc, 'bdi', '', name)));
|
|
142
|
+
const button = make(doc, 'button', 'fd-map-crowd-item', make(doc, 'bdi', '', name));
|
|
88
143
|
button.type = 'button';
|
|
89
144
|
button.dataset['id'] = String(record.id);
|
|
90
145
|
button.addEventListener('click', () => options.pick(record));
|
package/src/lib/card.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card.js","sourceRoot":"","sources":["../../../../../libs/map/src/lib/card.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"card.js","sourceRoot":"","sources":["../../../../../libs/map/src/lib/card.ts"],"names":[],"mappings":"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"}
|
package/src/lib/card.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cardLines } from '@fieldia/core';
|
|
1
2
|
import { fill } from './labels.mjs';
|
|
2
3
|
import { imageSource, shown } from './pins.mjs';
|
|
3
4
|
function make(doc, tag, className, ...children) {
|
|
@@ -14,30 +15,83 @@ function closeButton(doc, labels, close) {
|
|
|
14
15
|
button.addEventListener('click', close);
|
|
15
16
|
return button;
|
|
16
17
|
}
|
|
18
|
+
/** A record's address on the web, when a link may go there: a web, mail or phone address, or a path of this site; never a script. */
|
|
19
|
+
export function webAddress(value) {
|
|
20
|
+
const text = typeof value === 'string' ? value.trim() : '';
|
|
21
|
+
const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(text)?.[1].toLowerCase();
|
|
22
|
+
return text && (!scheme || ['http', 'https', 'mailto', 'tel'].includes(scheme)) ? text : '';
|
|
23
|
+
}
|
|
24
|
+
const plurals = new Map();
|
|
25
|
+
/** The words after a number, in the plural form the page's language gives it: "1 bed", "4 beds". */
|
|
26
|
+
function unitWords(unit, value, locale) {
|
|
27
|
+
if (typeof unit === 'string')
|
|
28
|
+
return unit;
|
|
29
|
+
let rules = plurals.get(locale);
|
|
30
|
+
if (!rules)
|
|
31
|
+
plurals.set(locale, (rules = new Intl.PluralRules(locale)));
|
|
32
|
+
const form = typeof value === 'number' ? rules.select(value) : 'other';
|
|
33
|
+
return unit[form] ?? unit.other;
|
|
34
|
+
}
|
|
35
|
+
/** A part of a line as words: its value as the field shows it, and its own words after it, kept on one line with it. */
|
|
36
|
+
function partWords(page, part, values, locale) {
|
|
37
|
+
const said = shown(page, part.field, values, locale);
|
|
38
|
+
if (said === '' || part.unit === undefined)
|
|
39
|
+
return said;
|
|
40
|
+
const unit = unitWords(part.unit, values[part.field], locale);
|
|
41
|
+
return unit ? `${said}\u00a0${unit}` : said;
|
|
42
|
+
}
|
|
17
43
|
export function drawCard(options) {
|
|
18
|
-
const { document: doc, page, locale, labels, record } = options;
|
|
44
|
+
const { document: doc, page, locale, labels, record, card } = options;
|
|
19
45
|
const title = shown(page, options.title, record.values, locale) || String(record.id);
|
|
20
46
|
const element = make(doc, 'div', 'fd-map-card');
|
|
21
47
|
element.dir = options.dir;
|
|
22
48
|
element.setAttribute('role', 'group');
|
|
23
49
|
element.setAttribute('aria-label', title);
|
|
24
50
|
element.dataset['id'] = String(record.id);
|
|
25
|
-
const
|
|
51
|
+
const href = card.href ? webAddress(record.values[card.href]) : '';
|
|
52
|
+
/** A link to the record's own address: one a person can open in a new tab, or copy. */
|
|
53
|
+
const link = (className, ...children) => {
|
|
54
|
+
const a = make(doc, 'a', className, ...children);
|
|
55
|
+
a.href = href;
|
|
56
|
+
return a;
|
|
57
|
+
};
|
|
58
|
+
const picture = card.image ? imageSource(record.values[card.image]) : '';
|
|
26
59
|
if (picture) {
|
|
27
60
|
const img = make(doc, 'img', 'fd-map-card-image');
|
|
28
61
|
img.alt = '';
|
|
29
62
|
img.decoding = 'async';
|
|
30
63
|
img.src = picture;
|
|
31
|
-
|
|
64
|
+
// The picture goes where the title does; the title's link is the one the keys and a screen reader reach.
|
|
65
|
+
if (href) {
|
|
66
|
+
const to = link('fd-map-card-picture', img);
|
|
67
|
+
to.tabIndex = -1;
|
|
68
|
+
to.setAttribute('aria-hidden', 'true');
|
|
69
|
+
element.append(to);
|
|
70
|
+
}
|
|
71
|
+
else
|
|
72
|
+
element.append(img);
|
|
32
73
|
}
|
|
33
74
|
const body = make(doc, 'div', 'fd-map-card-body');
|
|
34
75
|
const close = closeButton(doc, labels, options.close);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
76
|
+
const name = make(doc, 'bdi', '', title);
|
|
77
|
+
body.append(make(doc, 'div', 'fd-map-card-head', make(doc, 'strong', 'fd-map-card-title', href ? link('fd-map-card-link', name) : name), close));
|
|
78
|
+
// Each line: its label (or its parts' labels), and its parts, each a value in its own direction, parted by a dot.
|
|
79
|
+
const lines = cardLines({ fields: options.fields })
|
|
80
|
+
.map((parts) => parts.map((part) => ({ part, said: partWords(page, part, record.values, locale) })).filter(({ said }) => said !== ''))
|
|
81
|
+
.filter((parts) => parts.length);
|
|
82
|
+
if (lines.length) {
|
|
83
|
+
const list = make(doc, 'dl', 'fd-map-card-fields', ...lines.map((parts) => {
|
|
84
|
+
const label = parts.map(({ part }) => page.fields[part.field]?.label ?? part.field).join(' · ');
|
|
85
|
+
const value = make(doc, 'dd', '', ...parts.flatMap(({ said }, i) => [...(i ? [' · '] : []), make(doc, 'bdi', '', said)]));
|
|
86
|
+
return make(doc, 'div', '', make(doc, 'dt', '', label), value);
|
|
87
|
+
}));
|
|
88
|
+
// Bare values, their labels said to a screen reader alone; the first line leading.
|
|
89
|
+
if (card.labels === false)
|
|
90
|
+
list.dataset['labels'] = 'hidden';
|
|
91
|
+
if (card.lead)
|
|
92
|
+
list.toggleAttribute('data-lead', true);
|
|
93
|
+
body.append(list);
|
|
94
|
+
}
|
|
41
95
|
const box = make(doc, 'input', 'fd-map-card-check');
|
|
42
96
|
box.type = 'checkbox';
|
|
43
97
|
box.checked = !!options.chosen;
|
|
@@ -52,7 +106,7 @@ export function drawCard(options) {
|
|
|
52
106
|
actions.append(button);
|
|
53
107
|
first = button;
|
|
54
108
|
}
|
|
55
|
-
if (options.open &&
|
|
109
|
+
if (options.open && card.open !== false) {
|
|
56
110
|
const open = make(doc, 'button', 'fd-button fd-button-primary fd-map-card-open', labels.openRecord);
|
|
57
111
|
open.type = 'button';
|
|
58
112
|
open.addEventListener('click', () => options.open?.());
|
|
@@ -79,8 +133,8 @@ export function drawCrowd(options) {
|
|
|
79
133
|
const close = closeButton(doc, labels, options.close);
|
|
80
134
|
const items = options.records.map(({ record, name, plain }) => {
|
|
81
135
|
if (plain)
|
|
82
|
-
return make(doc, 'li', '', make(doc, 'span', 'fd-map-crowd-item', name));
|
|
83
|
-
const button = make(doc, 'button', 'fd-map-crowd-item', name);
|
|
136
|
+
return make(doc, 'li', '', make(doc, 'span', 'fd-map-crowd-item', make(doc, 'bdi', '', name)));
|
|
137
|
+
const button = make(doc, 'button', 'fd-map-crowd-item', make(doc, 'bdi', '', name));
|
|
84
138
|
button.type = 'button';
|
|
85
139
|
button.dataset['id'] = String(record.id);
|
|
86
140
|
button.addEventListener('click', () => options.pick(record));
|
package/src/lib/card.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card.mjs","sourceRoot":"","sources":["../../../../../libs/map/src/lib/card.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"card.mjs","sourceRoot":"","sources":["../../../../../libs/map/src/lib/card.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { type DataSource, type Page, type RecordId, type ResolvedFilter, type SortOrder } from '@fieldia/core';
|
|
2
|
+
import type { ListViewPart } from '@fieldia/viewer';
|
|
3
|
+
import type { IconSet } from '@fieldia/widgets';
|
|
4
|
+
import type { LatLng } from './geo.mjs';
|
|
5
|
+
import { type MapSearch, type MapViewChange } from './list-view.mjs';
|
|
6
|
+
import type { MapRecord } from './pins.mjs';
|
|
7
|
+
import type { MapSettings } from './settings.mjs';
|
|
8
|
+
/**
|
|
9
|
+
* A list's map in a page of the app's own, outside the viewer: the page's
|
|
10
|
+
* own list, filters and address beside it, the map drawn by Fieldia. The
|
|
11
|
+
* app gives the page that describes the records (a list with `map`), where
|
|
12
|
+
* the records come from, the search they were found by, and what to do when
|
|
13
|
+
* the map asks for something; it gets the map back, to reload and destroy.
|
|
14
|
+
* The map brings its own base (its buttons, a part hidden, words for a
|
|
15
|
+
* screen reader) on its own element, and Fieldia's colours as tokens the
|
|
16
|
+
* page can set: none of it reaches the page round it.
|
|
17
|
+
*
|
|
18
|
+
* const map = mountListMap(element, {
|
|
19
|
+
* page, // a list page with "map"
|
|
20
|
+
* provider: azureMaps({ key }),
|
|
21
|
+
* dataSource, // or records: [...]
|
|
22
|
+
* filter: () => searchNow(), // the conditions the records are found by
|
|
23
|
+
* start: { center: { lat: 30.05, lng: 31.23 }, zoom: 12 }, // from the address, say
|
|
24
|
+
* onSearch: ({ kind, filter }) => { keep(kind, filter); map.reload(); },
|
|
25
|
+
* onViewChange: ({ center, zoom }) => history.replaceState(null, '', `?at=${center.lat},${center.lng},${zoom}`),
|
|
26
|
+
* onOpenRecord: (id) => location.assign(`/homes/${id}`),
|
|
27
|
+
* onHighlight: (id) => lightRow(id),
|
|
28
|
+
* });
|
|
29
|
+
*/
|
|
30
|
+
export interface ListMapOptions extends MapSettings {
|
|
31
|
+
/** The page that describes the records: their fields, and a list with `map` (where each is, its pin, its card, its height, its gestures). */
|
|
32
|
+
page: Page;
|
|
33
|
+
/** Where the records come from: a source with `list`, asked with the search, the list's order and the map's `limit`. */
|
|
34
|
+
dataSource?: DataSource;
|
|
35
|
+
/** Or the records themselves, found already: each `{ id, values }`, or a function giving them, asked again at each `reload()`. */
|
|
36
|
+
records?: readonly MapRecord[] | (() => readonly MapRecord[] | Promise<readonly MapRecord[]>);
|
|
37
|
+
/** The language: a tag such as `ar-EG`; Fieldia's words in English, Arabic, French or German, and the page's own `translations`. The document's language unless said. */
|
|
38
|
+
locale?: string;
|
|
39
|
+
/**
|
|
40
|
+
* The conditions the records are found by now, as a search bar's are: the
|
|
41
|
+
* map asks its source with them, draws the areas among them, and counts
|
|
42
|
+
* a view within them. A search the map asked for is among them once the app
|
|
43
|
+
* has taken it.
|
|
44
|
+
*/
|
|
45
|
+
filter?: readonly ResolvedFilter[] | (() => readonly ResolvedFilter[]);
|
|
46
|
+
/** The order the records come in: the map shows the same first ones as the page's own list. */
|
|
47
|
+
sort?: readonly SortOrder[] | (() => readonly SortOrder[]);
|
|
48
|
+
/** Where the map opens, from the page's address, say: there it fits no records at first, until the search changes. */
|
|
49
|
+
start?: {
|
|
50
|
+
center: LatLng;
|
|
51
|
+
zoom: number;
|
|
52
|
+
};
|
|
53
|
+
/** The app's icons for the pins, besides Fieldia's and the map's own. */
|
|
54
|
+
icons?: IconSet;
|
|
55
|
+
/** The page's buttons for one record, offered on its card: "Book a viewing". */
|
|
56
|
+
actions?: {
|
|
57
|
+
id: string;
|
|
58
|
+
label: string;
|
|
59
|
+
style?: 'primary' | 'secondary' | 'danger' | 'link';
|
|
60
|
+
}[];
|
|
61
|
+
/** A card's Open: the card has the button when this is given. */
|
|
62
|
+
onOpenRecord?: (id: RecordId) => void;
|
|
63
|
+
/** A pin under the pointer or the focus (null when none): light the record in the page's own list. */
|
|
64
|
+
onHighlight?: (id: RecordId | null) => void;
|
|
65
|
+
/**
|
|
66
|
+
* The map asks for a search: its view (`kind: 'view'`, "Search this area"),
|
|
67
|
+
* an area drawn (`drawn`), or a shaded area pressed (`region`). The app
|
|
68
|
+
* keeps one of each kind, a new one in the last one's place, as a search bar
|
|
69
|
+
* does, puts its conditions in `filter`, and calls `reload()`. Without it the
|
|
70
|
+
* map offers no search: no "Search this area", no tools to draw an area.
|
|
71
|
+
*/
|
|
72
|
+
onSearch?: (search: MapSearch) => void;
|
|
73
|
+
/** The map has stopped, after a move or a zoom: where it stands, to keep in the page's address. Each view once. */
|
|
74
|
+
onViewChange?: (view: MapViewChange) => void;
|
|
75
|
+
/** Whether a record is chosen, and a choice made on its card; the map keeps its own choice when these are not given. */
|
|
76
|
+
isChosen?: (id: RecordId) => boolean;
|
|
77
|
+
onChoose?: (id: RecordId, chosen: boolean) => void;
|
|
78
|
+
/** One of `actions` pressed on a record's card: the button is busy until it is done. */
|
|
79
|
+
onAction?: (id: string, ids: RecordId[]) => void | Promise<void>;
|
|
80
|
+
/** "Nearest first" pressed: the order the page's own list should take too (null: its own again). */
|
|
81
|
+
onSort?: (order: SortOrder[] | null) => void;
|
|
82
|
+
}
|
|
83
|
+
/** A list's map in a page: its element (already in the page), and what the page asks of it. */
|
|
84
|
+
export type ListMapHandle = ListViewPart;
|
|
85
|
+
/** Puts a list's map into `host`, loads its records, and hands it back. Throws when the page cannot be shown, saying why. */
|
|
86
|
+
export declare function mountListMap(host: HTMLElement, options: ListMapOptions): ListMapHandle;
|