@autobusal/common 1.33.4 → 1.33.6
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/Autocomplete/Autocomplete.tsx +5 -1
- package/CHANGELOG.md +12 -0
- package/Calendar/Calendar.tsx +8 -2
- package/Drive/Drive.tsx +3 -2
- package/Map/Tiles.tsx +56 -0
- package/Passengers/Passengers.tsx +8 -2
- package/package.json +1 -1
|
@@ -9,6 +9,9 @@ import { AutocompleteData } from './types';
|
|
|
9
9
|
|
|
10
10
|
interface Props {
|
|
11
11
|
name: 'from' | 'to'
|
|
12
|
+
/* Edited: Claude - 2026-08-15: accessible name for the visible input -
|
|
13
|
+
see the note in RoutesSearch. Optional so existing callers are unchanged. */
|
|
14
|
+
label?: string
|
|
12
15
|
defaultValue: string
|
|
13
16
|
data: AutocompleteData[]
|
|
14
17
|
validation: string
|
|
@@ -17,7 +20,7 @@ interface Props {
|
|
|
17
20
|
onUpdate: UseFormSetValue<any>
|
|
18
21
|
}
|
|
19
22
|
|
|
20
|
-
const Autocomplete = ({ name, defaultValue, data, validation, t, refs, onUpdate }: Props): JSX.Element => {
|
|
23
|
+
const Autocomplete = ({ name, label, defaultValue, data, validation, t, refs, onUpdate }: Props): JSX.Element => {
|
|
21
24
|
const found = data.filter(item => {
|
|
22
25
|
return item.value === defaultValue;
|
|
23
26
|
});
|
|
@@ -104,6 +107,7 @@ const Autocomplete = ({ name, defaultValue, data, validation, t, refs, onUpdate
|
|
|
104
107
|
<input
|
|
105
108
|
type="text"
|
|
106
109
|
name={ `${ name }_slug` }
|
|
110
|
+
aria-label={ label }
|
|
107
111
|
autoComplete="off"
|
|
108
112
|
value={ q }
|
|
109
113
|
onChange={ (event) => onChange(event) }
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.33.6
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **New `Map/Tiles` component - the one place the basemap comes from.** The same `TileLayer` line was copy-pasted into `Drive.tsx`, `@autobusal/map`'s `Display.tsx` and magus's own `RouteMap.tsx`, with a fourth copy in the mobile app, all hardcoding `tile.openstreetmap.org`. OSM's Tile Usage Policy does not cover commercial or heavy application use, and those servers throttle or block by referer and volume without notice - so the exposure was never the bill, it was that reacting to a block meant editing three repos, publishing to npm, redeploying both frontends and shipping a mobile store release.
|
|
8
|
+
|
|
9
|
+
The URL now comes from `/settings/get` (`map.tile_url`) rather than the build, so all four clients switch from one server env var. `null` - the state until a provider is chosen - means the built-in OpenStreetMap default, so this changes nothing for anyone on upgrade. Attribution is rendered by the component rather than travelling with the URL, since ODbL requires it whoever serves the tiles.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- `Drive.tsx` renders `<Tiles />` instead of its own `TileLayer`.
|
|
14
|
+
|
|
3
15
|
## 1.33.4
|
|
4
16
|
|
|
5
17
|
### Added
|
package/Calendar/Calendar.tsx
CHANGED
|
@@ -9,6 +9,12 @@ import { Container } from './styles';
|
|
|
9
9
|
interface Props {
|
|
10
10
|
type: 'picker' | 'dob' | 'date'
|
|
11
11
|
name: string
|
|
12
|
+
/* Edited: Claude - 2026-08-15: accessible name for the visible input.
|
|
13
|
+
These controls render a bare <input> with no <label>, no id and no
|
|
14
|
+
aria-*, so every one of them reached a screen reader unnamed - 5 of 5
|
|
15
|
+
on the search form, which is the site's primary conversion path.
|
|
16
|
+
Optional, so existing callers are unaffected. */
|
|
17
|
+
label?: string
|
|
12
18
|
defaultValue?: string
|
|
13
19
|
t: TFunction<'general'>
|
|
14
20
|
validation?: string
|
|
@@ -30,7 +36,7 @@ interface Props {
|
|
|
30
36
|
onChange?: (value: string) => void
|
|
31
37
|
}
|
|
32
38
|
|
|
33
|
-
const Calendar = ({ type, name, defaultValue, t, validation, minDate, refs, onUpdate, onChange }: Props): JSX.Element => {
|
|
39
|
+
const Calendar = ({ type, name, label, defaultValue, t, validation, minDate, refs, onUpdate, onChange }: Props): JSX.Element => {
|
|
34
40
|
const [ show, setShow ] = useState<boolean>(false);
|
|
35
41
|
|
|
36
42
|
/**
|
|
@@ -69,7 +75,7 @@ const Calendar = ({ type, name, defaultValue, t, validation, minDate, refs, onUp
|
|
|
69
75
|
|
|
70
76
|
return (
|
|
71
77
|
<Container ref={ ref }>
|
|
72
|
-
<input type="text" autoComplete="off" readOnly={ true } value={ prepared } onClick={ () => setShow(true) } />
|
|
78
|
+
<input type="text" aria-label={ label } autoComplete="off" readOnly={ true } value={ prepared } onClick={ () => setShow(true) } />
|
|
73
79
|
|
|
74
80
|
{ show && (
|
|
75
81
|
<Picker
|
package/Drive/Drive.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { TFunction } from 'i18next';
|
|
2
|
-
import { MapContainer,
|
|
2
|
+
import { MapContainer, Marker, Popup, Polyline } from 'react-leaflet';
|
|
3
3
|
import { latLngBounds } from 'leaflet';
|
|
4
4
|
import { getCoordinates, getPosition, hasPosition, autobusMarker } from './utilities';
|
|
5
|
+
import Tiles from '../Map/Tiles';
|
|
5
6
|
import { Container, Loading, Disclaimer } from './styles';
|
|
6
7
|
import { LocationData } from '@autobusal/providers/types/locations';
|
|
7
8
|
import { useGetDriveData } from './services';
|
|
@@ -79,7 +80,7 @@ const Drive = ({ locations, t }: Props): JSX.Element => {
|
|
|
79
80
|
maxZoom={ 15 }
|
|
80
81
|
scrollWheelZoom={ true }
|
|
81
82
|
>
|
|
82
|
-
<
|
|
83
|
+
<Tiles />
|
|
83
84
|
|
|
84
85
|
{ markers }
|
|
85
86
|
|
package/Map/Tiles.tsx
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { TileLayer } from 'react-leaflet';
|
|
2
|
+
import { useGetSettings } from '@autobusal/providers/services';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The one place the basemap comes from.
|
|
6
|
+
*
|
|
7
|
+
* Added: Claude (audit) - Date: 2026-08-17
|
|
8
|
+
*
|
|
9
|
+
* The same TileLayer line was copy-pasted into common's Drive.tsx and map's
|
|
10
|
+
* Display.tsx, with a third copy in the mobile app's Leaflet HTML. All three
|
|
11
|
+
* hardcoded `tile.openstreetmap.org`, whose Tile Usage Policy does not cover
|
|
12
|
+
* commercial or heavy application use - those servers are donation funded for
|
|
13
|
+
* OSM's own purposes and they throttle or block by referer and volume, without
|
|
14
|
+
* notice.
|
|
15
|
+
*
|
|
16
|
+
* The exposure was never the bill, it was how long a switch would take. With
|
|
17
|
+
* the URL inlined in a published package, reacting to a block meant editing
|
|
18
|
+
* three repos, publishing to npm, redeploying both frontends AND shipping a
|
|
19
|
+
* mobile store release - days of broken maps, the last stretch of it waiting
|
|
20
|
+
* on app review.
|
|
21
|
+
*
|
|
22
|
+
* SO THE URL COMES FROM /settings/get, NOT FROM THE BUILD. That is the mobile
|
|
23
|
+
* app's constraint (a compiled-in URL there needs a store release to change),
|
|
24
|
+
* and following it here means all three clients switch from ONE place - a
|
|
25
|
+
* server env var and a cache flush - rather than each on its own release
|
|
26
|
+
* cadence. `useGetSettings` is already resolved at bootstrap with
|
|
27
|
+
* `staleTime: Infinity`, so this reads the warm cache and costs no request.
|
|
28
|
+
*
|
|
29
|
+
* `tile_url` is null until a provider is actually chosen, which means the
|
|
30
|
+
* OpenStreetMap default below - so this lands with nothing changing anywhere
|
|
31
|
+
* and waits on no decision.
|
|
32
|
+
*
|
|
33
|
+
* ATTRIBUTION IS NOT PART OF THE SWITCH. ODbL requires crediting OpenStreetMap
|
|
34
|
+
* for the underlying data whoever serves the tiles, so it is rendered here
|
|
35
|
+
* rather than travelling with the URL - a provider swap must not be able to
|
|
36
|
+
* drop it. A provider needing its own credit too should have it appended, not
|
|
37
|
+
* substituted.
|
|
38
|
+
*/
|
|
39
|
+
const OPENSTREETMAP = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
|
|
40
|
+
|
|
41
|
+
const ATTRIBUTION = "© <a href='http://osm.org/copyright'>OpenStreetMap</a> contributors";
|
|
42
|
+
|
|
43
|
+
interface Props {
|
|
44
|
+
/** Overrides the configured basemap. Rarely needed - prefer the server setting. */
|
|
45
|
+
url?: string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const Tiles = ({ url }: Props): JSX.Element => {
|
|
49
|
+
const { data: settings } = useGetSettings();
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<TileLayer attribution={ ATTRIBUTION } url={ url ?? settings.map?.tile_url ?? OPENSTREETMAP } />
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default Tiles;
|
|
@@ -7,6 +7,12 @@ import { getText } from './utilities';
|
|
|
7
7
|
import { Container } from './styles';
|
|
8
8
|
|
|
9
9
|
interface Props {
|
|
10
|
+
/* Edited: Claude - 2026-08-15: accessible name for the visible input.
|
|
11
|
+
These controls render a bare <input> with no <label>, no id and no
|
|
12
|
+
aria-*, so every one of them reached a screen reader unnamed - 5 of 5
|
|
13
|
+
on the search form, which is the site's primary conversion path.
|
|
14
|
+
Optional, so existing callers are unaffected. */
|
|
15
|
+
label?: string
|
|
10
16
|
defaultAdults: number
|
|
11
17
|
defaultChildren: number
|
|
12
18
|
defaultBabies: number
|
|
@@ -15,7 +21,7 @@ interface Props {
|
|
|
15
21
|
onUpdate: UseFormSetValue<any>
|
|
16
22
|
}
|
|
17
23
|
|
|
18
|
-
const Passengers = ({ defaultAdults, defaultChildren, defaultBabies, t, refs, onUpdate }: Props): JSX.Element => {
|
|
24
|
+
const Passengers = ({ label, defaultAdults, defaultChildren, defaultBabies, t, refs, onUpdate }: Props): JSX.Element => {
|
|
19
25
|
const [ show, setShow ] = useState<boolean>(false);
|
|
20
26
|
const [ adults, setAdults ] = useState<number>(defaultAdults);
|
|
21
27
|
const [ children, setChildren ] = useState<number>(defaultChildren);
|
|
@@ -54,7 +60,7 @@ const Passengers = ({ defaultAdults, defaultChildren, defaultBabies, t, refs, on
|
|
|
54
60
|
|
|
55
61
|
return (
|
|
56
62
|
<Container ref={ ref }>
|
|
57
|
-
<input type="text" value={ display } readOnly={ true } onClick={ () => setShow(!show) } />
|
|
63
|
+
<input type="text" aria-label={ label } value={ display } readOnly={ true } onClick={ () => setShow(!show) } />
|
|
58
64
|
|
|
59
65
|
{ show &&
|
|
60
66
|
<Persons
|