@12-apps/ui 6.6.0 → 6.7.0
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/dist/{chunk-3KWD5Y5O.js → chunk-RXE5CUUE.js} +8 -4
- package/dist/chunk-RXE5CUUE.js.map +1 -0
- package/dist/data-display/Alert.js +1 -1
- package/dist/data-display/AsyncStateContainer.js +2 -1
- package/dist/data-display/AsyncStateContainer.js.map +1 -1
- package/dist/data-display/Banner.js +4 -2
- package/dist/data-display/Banner.js.map +1 -1
- package/dist/data-display/CardKit.js +3 -1
- package/dist/data-display/CardKit.js.map +1 -1
- package/dist/data-display/Carousel.js +5 -2
- package/dist/data-display/Carousel.js.map +1 -1
- package/dist/data-display/DataViews.js +2 -1
- package/dist/data-display/DataViews.js.map +1 -1
- package/dist/data-display/Lightbox.js +147 -117
- package/dist/data-display/Lightbox.js.map +1 -1
- package/dist/data-display/MapPreview.js +14 -10
- package/dist/data-display/MapPreview.js.map +1 -1
- package/dist/pt-BR.js +37 -1
- package/dist/pt-BR.js.map +1 -1
- package/dist/types/components/data-display/Alert/Alert.d.ts +9 -2
- package/dist/types/components/data-display/Alert/Alert.d.ts.map +1 -1
- package/dist/types/components/data-display/Alert/Alert.types.d.ts +25 -9
- package/dist/types/components/data-display/Alert/Alert.types.d.ts.map +1 -1
- package/dist/types/components/data-display/AsyncStateContainer/AsyncStateContainer.d.ts.map +1 -1
- package/dist/types/components/data-display/AsyncStateContainer/AsyncStateContainer.types.d.ts +6 -0
- package/dist/types/components/data-display/AsyncStateContainer/AsyncStateContainer.types.d.ts.map +1 -1
- package/dist/types/components/data-display/Banner/Banner.d.ts.map +1 -1
- package/dist/types/components/data-display/Banner/Banner.types.d.ts +2 -0
- package/dist/types/components/data-display/Banner/Banner.types.d.ts.map +1 -1
- package/dist/types/components/data-display/CardKit/card-actions-context.d.ts +3 -1
- package/dist/types/components/data-display/CardKit/card-actions-context.d.ts.map +1 -1
- package/dist/types/components/data-display/Carousel/Carousel.chrome.d.ts +3 -0
- package/dist/types/components/data-display/Carousel/Carousel.chrome.d.ts.map +1 -1
- package/dist/types/components/data-display/Carousel/Carousel.parts.d.ts.map +1 -1
- package/dist/types/components/data-display/Carousel/Carousel.types.d.ts +7 -0
- package/dist/types/components/data-display/Carousel/Carousel.types.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-copy.d.ts +2 -0
- package/dist/types/components/data-display/DataViews/data-views-copy.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-table-parts.d.ts.map +1 -1
- package/dist/types/components/data-display/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/types/components/data-display/Lightbox/Lightbox.types.d.ts +9 -0
- package/dist/types/components/data-display/Lightbox/Lightbox.types.d.ts.map +1 -1
- package/dist/types/components/data-display/Lightbox/LightboxControls.d.ts.map +1 -1
- package/dist/types/components/data-display/Lightbox/lightbox-copy-context.d.ts +17 -0
- package/dist/types/components/data-display/Lightbox/lightbox-copy-context.d.ts.map +1 -0
- package/dist/types/components/data-display/MapPreview/MapControlBar.d.ts +7 -0
- package/dist/types/components/data-display/MapPreview/MapControlBar.d.ts.map +1 -1
- package/dist/types/components/data-display/MapPreview/MapLayers.d.ts.map +1 -1
- package/dist/types/components/data-display/MapPreview/MapPreview.types.d.ts +9 -0
- package/dist/types/components/data-display/MapPreview/MapPreview.types.d.ts.map +1 -1
- package/dist/types/components/data-display/MapPreview/MapSearchBar.d.ts +2 -0
- package/dist/types/components/data-display/MapPreview/MapSearchBar.d.ts.map +1 -1
- package/dist/types/copy.d.ts +53 -0
- package/dist/types/copy.d.ts.map +1 -1
- package/dist/types/pt-BR.d.ts +5 -1
- package/dist/types/pt-BR.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/data-display/Alert/Alert.tsx +22 -5
- package/src/components/data-display/Alert/Alert.types.ts +20 -10
- package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.tsx +2 -1
- package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.types.ts +6 -0
- package/src/components/data-display/Banner/Banner.tsx +5 -2
- package/src/components/data-display/Banner/Banner.types.ts +2 -0
- package/src/components/data-display/CardKit/card-actions-context.tsx +4 -0
- package/src/components/data-display/Carousel/Carousel.chrome.tsx +5 -0
- package/src/components/data-display/Carousel/Carousel.parts.tsx +4 -3
- package/src/components/data-display/Carousel/Carousel.types.ts +7 -0
- package/src/components/data-display/DataViews/data-views-copy.ts +2 -0
- package/src/components/data-display/DataViews/data-views-table-parts.tsx +1 -0
- package/src/components/data-display/Lightbox/Lightbox.tsx +3 -0
- package/src/components/data-display/Lightbox/Lightbox.types.ts +9 -0
- package/src/components/data-display/Lightbox/LightboxControls.tsx +28 -15
- package/src/components/data-display/Lightbox/lightbox-copy-context.tsx +42 -0
- package/src/components/data-display/MapPreview/MapControlBar.tsx +17 -9
- package/src/components/data-display/MapPreview/MapLayers.tsx +2 -0
- package/src/components/data-display/MapPreview/MapPreview.types.ts +10 -0
- package/src/components/data-display/MapPreview/MapSearchBar.tsx +4 -1
- package/src/copy.ts +57 -0
- package/src/pt-BR.ts +41 -1
- package/dist/chunk-3KWD5Y5O.js.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
3
|
import { CarouselArrows, CarouselIndicators, CarouselThumbnails } from './Carousel.parts';
|
|
4
|
+
import type { CarouselCopy } from '../../../copy';
|
|
4
5
|
import type {
|
|
5
6
|
CarouselArrowsProps,
|
|
6
7
|
CarouselIndicatorsProps,
|
|
@@ -12,6 +13,8 @@ type IndicatorPosition = NonNullable<CarouselIndicatorsProps['position']>;
|
|
|
12
13
|
type Color = NonNullable<CarouselIndicatorsProps['color']>;
|
|
13
14
|
|
|
14
15
|
export interface CarouselChromeProps {
|
|
16
|
+
/** The two arrows' accessible names, from the mount. */
|
|
17
|
+
copy: CarouselCopy;
|
|
15
18
|
items: CarouselItem[];
|
|
16
19
|
activeIndex: number;
|
|
17
20
|
loop: boolean;
|
|
@@ -34,6 +37,7 @@ export interface CarouselChromeProps {
|
|
|
34
37
|
* as three conditional blocks inside the carousel's own render.
|
|
35
38
|
*/
|
|
36
39
|
export const CarouselChrome: React.FC<CarouselChromeProps> = ({
|
|
40
|
+
copy,
|
|
37
41
|
items,
|
|
38
42
|
activeIndex,
|
|
39
43
|
loop,
|
|
@@ -52,6 +56,7 @@ export const CarouselChrome: React.FC<CarouselChromeProps> = ({
|
|
|
52
56
|
<>
|
|
53
57
|
{showArrows && !disabled && (
|
|
54
58
|
<CarouselArrows
|
|
59
|
+
copy={copy}
|
|
55
60
|
onPrev={onPrev}
|
|
56
61
|
onNext={onNext}
|
|
57
62
|
position={arrowPosition}
|
|
@@ -212,7 +212,8 @@ const arrowSx = (theme: Theme, color: Color, isOverlay: boolean): CSSObject => (
|
|
|
212
212
|
|
|
213
213
|
export const CarouselArrows: React.FC<CarouselArrowsProps> = (props) => {
|
|
214
214
|
const {
|
|
215
|
-
onPrev, onNext, position, disabled, disablePrev, disableNext, color, size, className,
|
|
215
|
+
copy, onPrev, onNext, position, disabled, disablePrev, disableNext, color, size, className,
|
|
216
|
+
style,
|
|
216
217
|
} = withDefaults(props, ARROWS_DEFAULTS) as CarouselArrowsProps &
|
|
217
218
|
Required<Pick<CarouselArrowsProps, keyof typeof ARROWS_DEFAULTS>>;
|
|
218
219
|
|
|
@@ -227,7 +228,7 @@ export const CarouselArrows: React.FC<CarouselArrowsProps> = (props) => {
|
|
|
227
228
|
disabled={disabled || disablePrev}
|
|
228
229
|
size={muiSize(size)}
|
|
229
230
|
className={className}
|
|
230
|
-
aria-label=
|
|
231
|
+
aria-label={copy.previous}
|
|
231
232
|
data-testid="carousel-prev-button"
|
|
232
233
|
sx={{ ...sx, left: offset, ...style }}
|
|
233
234
|
>
|
|
@@ -237,7 +238,7 @@ export const CarouselArrows: React.FC<CarouselArrowsProps> = (props) => {
|
|
|
237
238
|
<IconButton
|
|
238
239
|
onClick={onNext}
|
|
239
240
|
disabled={disabled || disableNext}
|
|
240
|
-
aria-label=
|
|
241
|
+
aria-label={copy.next}
|
|
241
242
|
size={muiSize(size)}
|
|
242
243
|
className={className}
|
|
243
244
|
data-testid="carousel-next-button"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ColorValue, SizeValue } from '../../../tokens/scales';
|
|
2
2
|
import type { CSSProperties, ReactNode } from 'react';
|
|
3
|
+
import type { CarouselCopy } from '../../../copy';
|
|
3
4
|
|
|
4
5
|
export interface CarouselItem {
|
|
5
6
|
id: string;
|
|
@@ -11,6 +12,11 @@ export interface CarouselItem {
|
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export interface CarouselProps {
|
|
15
|
+
/**
|
|
16
|
+
* The two arrows' accessible names. They render a glyph and nothing else,
|
|
17
|
+
* so this pair IS what a screen reader announces for them. REQUIRED.
|
|
18
|
+
*/
|
|
19
|
+
copy: CarouselCopy;
|
|
14
20
|
items: CarouselItem[];
|
|
15
21
|
variant?: 'default' | 'glass' | 'gradient' | 'elevated' | 'minimal' | 'cards';
|
|
16
22
|
size?: SizeValue;
|
|
@@ -58,6 +64,7 @@ export interface CarouselIndicatorsProps {
|
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
export interface CarouselArrowsProps {
|
|
67
|
+
copy: CarouselCopy;
|
|
61
68
|
onPrev: () => void;
|
|
62
69
|
onNext: () => void;
|
|
63
70
|
position?: 'inside' | 'outside' | 'overlay';
|
|
@@ -231,6 +231,8 @@ export interface DataViewsNavCopy {
|
|
|
231
231
|
reset: string;
|
|
232
232
|
/** The inline error when a view could not be refreshed or saved. */
|
|
233
233
|
updateFailed: string;
|
|
234
|
+
/** The dismiss on that failure's alert — a glyph with no visible label. */
|
|
235
|
+
dismissError: string;
|
|
234
236
|
saveFailed: string;
|
|
235
237
|
/** Reopen the save dialog over an existing view. */
|
|
236
238
|
editView: string;
|
|
@@ -3,6 +3,7 @@ import React from 'react';
|
|
|
3
3
|
|
|
4
4
|
import { makeTestId } from './Lightbox.constants';
|
|
5
5
|
import { resolveLightboxProps } from './Lightbox.helpers';
|
|
6
|
+
import { LightboxCopyProvider } from './lightbox-copy-context';
|
|
6
7
|
import type { LightboxProps, LightboxRef } from './Lightbox.types';
|
|
7
8
|
import { LightboxCurrentMedia } from './LightboxCurrentMedia';
|
|
8
9
|
import { LightboxOverlay } from './LightboxOverlay';
|
|
@@ -32,6 +33,7 @@ export const Lightbox = React.forwardRef<LightboxRef, LightboxProps>((componentP
|
|
|
32
33
|
const { currentIndex, currentItem, zoom } = lightbox;
|
|
33
34
|
|
|
34
35
|
return (
|
|
36
|
+
<LightboxCopyProvider copy={props.copy}>
|
|
35
37
|
<Dialog
|
|
36
38
|
open={isOpen}
|
|
37
39
|
onClose={lightbox.close}
|
|
@@ -98,6 +100,7 @@ export const Lightbox = React.forwardRef<LightboxRef, LightboxProps>((componentP
|
|
|
98
100
|
}
|
|
99
101
|
/>
|
|
100
102
|
</Dialog>
|
|
103
|
+
</LightboxCopyProvider>
|
|
101
104
|
);
|
|
102
105
|
});
|
|
103
106
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CSSProperties } from 'react';
|
|
2
|
+
import type { LightboxCopy } from '../../../copy';
|
|
2
3
|
|
|
3
4
|
export interface LightboxItem {
|
|
4
5
|
src: string;
|
|
@@ -12,6 +13,14 @@ export interface AutoplayConfig {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export interface LightboxProps {
|
|
16
|
+
/**
|
|
17
|
+
* Every word this viewer renders — all of them aria-labels on glyph-only
|
|
18
|
+
* controls, so this object IS what a screen-reader user hears for the whole
|
|
19
|
+
* component. REQUIRED: a default could only be one language read aloud to
|
|
20
|
+
* everybody else's users, and the sighted path looks identical either way,
|
|
21
|
+
* which is why the English literals survived so long.
|
|
22
|
+
*/
|
|
23
|
+
copy: LightboxCopy;
|
|
15
24
|
/** Controls visibility; must lock body scroll when true */
|
|
16
25
|
isOpen: boolean;
|
|
17
26
|
/** Fired on close button, backdrop click, Esc, and swipe-down (mobile) */
|
|
@@ -11,22 +11,26 @@ import type { FC } from 'react';
|
|
|
11
11
|
import React from 'react';
|
|
12
12
|
|
|
13
13
|
import { navButtonSx, OVERLAY_Z_INDEX, overlayButtonSx } from './Lightbox.constants';
|
|
14
|
+
import { useLightboxCopy } from './lightbox-copy-context';
|
|
14
15
|
|
|
15
16
|
type TestId = (suffix: string) => string;
|
|
16
17
|
|
|
17
18
|
export const LightboxCloseButton: FC<{ testId: TestId; onClose: () => void }> = ({
|
|
18
19
|
testId,
|
|
19
20
|
onClose,
|
|
20
|
-
}) =>
|
|
21
|
+
}) => {
|
|
22
|
+
const copy = useLightboxCopy();
|
|
23
|
+
return (
|
|
21
24
|
<IconButton
|
|
22
25
|
onClick={onClose}
|
|
23
26
|
sx={{ ...overlayButtonSx, position: 'absolute', top: 16, right: 16, zIndex: OVERLAY_Z_INDEX }}
|
|
24
|
-
aria-label=
|
|
27
|
+
aria-label={copy.close}
|
|
25
28
|
data-testid={testId('close')}
|
|
26
29
|
>
|
|
27
30
|
<CloseIcon />
|
|
28
31
|
</IconButton>
|
|
29
|
-
);
|
|
32
|
+
);
|
|
33
|
+
};
|
|
30
34
|
|
|
31
35
|
const arrowSx = (side: 'left' | 'right') =>
|
|
32
36
|
({
|
|
@@ -52,13 +56,15 @@ export const LightboxNavButtons: FC<LightboxNavButtonsProps> = ({
|
|
|
52
56
|
atEnd,
|
|
53
57
|
onPrev,
|
|
54
58
|
onNext,
|
|
55
|
-
}) =>
|
|
59
|
+
}) => {
|
|
60
|
+
const copy = useLightboxCopy();
|
|
61
|
+
return (
|
|
56
62
|
<>
|
|
57
63
|
<IconButton
|
|
58
64
|
onClick={onPrev}
|
|
59
65
|
disabled={atStart}
|
|
60
66
|
sx={arrowSx('left')}
|
|
61
|
-
aria-label=
|
|
67
|
+
aria-label={copy.previous}
|
|
62
68
|
data-testid={testId('prev')}
|
|
63
69
|
>
|
|
64
70
|
<PrevIcon />
|
|
@@ -68,13 +74,14 @@ export const LightboxNavButtons: FC<LightboxNavButtonsProps> = ({
|
|
|
68
74
|
onClick={onNext}
|
|
69
75
|
disabled={atEnd}
|
|
70
76
|
sx={arrowSx('right')}
|
|
71
|
-
aria-label=
|
|
77
|
+
aria-label={copy.next}
|
|
72
78
|
data-testid={testId('next')}
|
|
73
79
|
>
|
|
74
80
|
<NextIcon />
|
|
75
81
|
</IconButton>
|
|
76
82
|
</>
|
|
77
|
-
);
|
|
83
|
+
);
|
|
84
|
+
};
|
|
78
85
|
|
|
79
86
|
export interface LightboxZoomControlsProps {
|
|
80
87
|
testId: TestId;
|
|
@@ -88,7 +95,9 @@ export const LightboxZoomControls: FC<LightboxZoomControlsProps> = ({
|
|
|
88
95
|
onZoomIn,
|
|
89
96
|
onZoomOut,
|
|
90
97
|
onResetZoom,
|
|
91
|
-
}) =>
|
|
98
|
+
}) => {
|
|
99
|
+
const copy = useLightboxCopy();
|
|
100
|
+
return (
|
|
92
101
|
<Box
|
|
93
102
|
sx={{
|
|
94
103
|
position: 'absolute',
|
|
@@ -101,13 +110,13 @@ export const LightboxZoomControls: FC<LightboxZoomControlsProps> = ({
|
|
|
101
110
|
}}
|
|
102
111
|
data-testid={testId('zoom-controls')}
|
|
103
112
|
>
|
|
104
|
-
<IconButton onClick={onZoomIn} sx={overlayButtonSx} aria-label=
|
|
113
|
+
<IconButton onClick={onZoomIn} sx={overlayButtonSx} aria-label={copy.zoomIn} data-testid={testId('zoom-in')}>
|
|
105
114
|
<ZoomInIcon />
|
|
106
115
|
</IconButton>
|
|
107
116
|
<IconButton
|
|
108
117
|
onClick={onZoomOut}
|
|
109
118
|
sx={overlayButtonSx}
|
|
110
|
-
aria-label=
|
|
119
|
+
aria-label={copy.zoomOut}
|
|
111
120
|
data-testid={testId('zoom-out')}
|
|
112
121
|
>
|
|
113
122
|
<ZoomOutIcon />
|
|
@@ -115,13 +124,14 @@ export const LightboxZoomControls: FC<LightboxZoomControlsProps> = ({
|
|
|
115
124
|
<IconButton
|
|
116
125
|
onClick={onResetZoom}
|
|
117
126
|
sx={overlayButtonSx}
|
|
118
|
-
aria-label=
|
|
127
|
+
aria-label={copy.resetZoom}
|
|
119
128
|
data-testid={testId('zoom-reset')}
|
|
120
129
|
>
|
|
121
130
|
<ResetZoomIcon />
|
|
122
131
|
</IconButton>
|
|
123
132
|
</Box>
|
|
124
|
-
);
|
|
133
|
+
);
|
|
134
|
+
};
|
|
125
135
|
|
|
126
136
|
export interface LightboxAutoplayButtonProps {
|
|
127
137
|
testId: TestId;
|
|
@@ -133,7 +143,9 @@ export const LightboxAutoplayButton: FC<LightboxAutoplayButtonProps> = ({
|
|
|
133
143
|
testId,
|
|
134
144
|
isAutoPlaying,
|
|
135
145
|
onToggle,
|
|
136
|
-
}) =>
|
|
146
|
+
}) => {
|
|
147
|
+
const copy = useLightboxCopy();
|
|
148
|
+
return (
|
|
137
149
|
<IconButton
|
|
138
150
|
onClick={onToggle}
|
|
139
151
|
sx={{
|
|
@@ -144,9 +156,10 @@ export const LightboxAutoplayButton: FC<LightboxAutoplayButtonProps> = ({
|
|
|
144
156
|
transform: 'translateX(-50%)',
|
|
145
157
|
zIndex: OVERLAY_Z_INDEX,
|
|
146
158
|
}}
|
|
147
|
-
aria-label={isAutoPlaying ?
|
|
159
|
+
aria-label={isAutoPlaying ? copy.pause : copy.play}
|
|
148
160
|
data-testid={testId('autoplay')}
|
|
149
161
|
>
|
|
150
162
|
{isAutoPlaying ? <PauseIcon /> : <PlayIcon />}
|
|
151
163
|
</IconButton>
|
|
152
|
-
);
|
|
164
|
+
);
|
|
165
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { createContext, useContext, type ReactNode } from 'react';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
|
|
6
|
+
import type { LightboxCopy } from '../../../copy';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The lightbox's words, for the four control components that render them.
|
|
10
|
+
*
|
|
11
|
+
* A CONTEXT rather than props: the viewer is `Lightbox` → `LightboxOverlay` →
|
|
12
|
+
* three separate control clusters, and threading one object down three hops is
|
|
13
|
+
* how a copy port comes to exist, be required, and go unread. It stays a
|
|
14
|
+
* single REQUIRED prop at the mount, which is the only place a host answers.
|
|
15
|
+
*/
|
|
16
|
+
const LightboxCopyContext = createContext<LightboxCopy | null>(null);
|
|
17
|
+
|
|
18
|
+
export function LightboxCopyProvider({
|
|
19
|
+
copy,
|
|
20
|
+
children,
|
|
21
|
+
}: {
|
|
22
|
+
copy: LightboxCopy;
|
|
23
|
+
children: ReactNode;
|
|
24
|
+
}): React.JSX.Element {
|
|
25
|
+
return <LightboxCopyContext.Provider value={copy}>{children}</LightboxCopyContext.Provider>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The words this viewer renders — THROWS outside a provider rather than
|
|
30
|
+
* falling back.
|
|
31
|
+
*
|
|
32
|
+
* Every one of them is an aria-label on a glyph, so a fallback would be the
|
|
33
|
+
* one failure nobody sees in review: the sighted path renders identically
|
|
34
|
+
* whichever language it is in.
|
|
35
|
+
*/
|
|
36
|
+
export function useLightboxCopy(): LightboxCopy {
|
|
37
|
+
const copy = useContext(LightboxCopyContext);
|
|
38
|
+
if (!copy) {
|
|
39
|
+
throw new Error('useLightboxCopy must be rendered inside a <LightboxCopyProvider>');
|
|
40
|
+
}
|
|
41
|
+
return copy;
|
|
42
|
+
}
|
|
@@ -9,6 +9,7 @@ import React from 'react';
|
|
|
9
9
|
|
|
10
10
|
import { MAX_ZOOM, MIN_ZOOM } from './MapPreview.constants';
|
|
11
11
|
import type { MapType } from './MapPreview.types';
|
|
12
|
+
import type { MapPreviewCopy } from '../../../copy';
|
|
12
13
|
|
|
13
14
|
// Kept module-local: the inferred type of a styled() component cannot be named
|
|
14
15
|
// across a module boundary here (TS2742).
|
|
@@ -41,6 +42,12 @@ const ControlButton = styled(IconButton)(({ theme }) => ({
|
|
|
41
42
|
}));
|
|
42
43
|
|
|
43
44
|
export interface MapControlBarProps {
|
|
45
|
+
/**
|
|
46
|
+
* The six controls' names. Every one is a glyph with a `title` AND an
|
|
47
|
+
* `aria-label`, so this object is both the tooltip and what a screen reader
|
|
48
|
+
* reads — REQUIRED, because a default is one language for every adopter.
|
|
49
|
+
*/
|
|
50
|
+
copy: MapPreviewCopy;
|
|
44
51
|
zoom: number;
|
|
45
52
|
mapType: MapType;
|
|
46
53
|
onZoomIn: () => void;
|
|
@@ -51,6 +58,7 @@ export interface MapControlBarProps {
|
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
export const MapControlBar: FC<MapControlBarProps> = ({
|
|
61
|
+
copy,
|
|
54
62
|
zoom,
|
|
55
63
|
mapType,
|
|
56
64
|
onZoomIn,
|
|
@@ -60,33 +68,33 @@ export const MapControlBar: FC<MapControlBarProps> = ({
|
|
|
60
68
|
onToggleFullscreen,
|
|
61
69
|
}) => (
|
|
62
70
|
<MapControls data-testid="map-controls">
|
|
63
|
-
<Tooltip title=
|
|
71
|
+
<Tooltip title={copy.zoomIn} placement="left">
|
|
64
72
|
<ControlButton
|
|
65
73
|
size="small"
|
|
66
74
|
onClick={onZoomIn}
|
|
67
|
-
aria-label=
|
|
75
|
+
aria-label={copy.zoomIn}
|
|
68
76
|
data-testid="zoom-in-button"
|
|
69
77
|
disabled={zoom >= MAX_ZOOM}
|
|
70
78
|
>
|
|
71
79
|
<ZoomInIcon fontSize="small" />
|
|
72
80
|
</ControlButton>
|
|
73
81
|
</Tooltip>
|
|
74
|
-
<Tooltip title=
|
|
82
|
+
<Tooltip title={copy.zoomOut} placement="left">
|
|
75
83
|
<ControlButton
|
|
76
84
|
size="small"
|
|
77
85
|
onClick={onZoomOut}
|
|
78
|
-
aria-label=
|
|
86
|
+
aria-label={copy.zoomOut}
|
|
79
87
|
data-testid="zoom-out-button"
|
|
80
88
|
disabled={zoom <= MIN_ZOOM}
|
|
81
89
|
>
|
|
82
90
|
<ZoomOutIcon fontSize="small" />
|
|
83
91
|
</ControlButton>
|
|
84
92
|
</Tooltip>
|
|
85
|
-
<Tooltip title=
|
|
93
|
+
<Tooltip title={copy.center} placement="left">
|
|
86
94
|
<ControlButton
|
|
87
95
|
size="small"
|
|
88
96
|
onClick={onCenter}
|
|
89
|
-
aria-label=
|
|
97
|
+
aria-label={copy.center}
|
|
90
98
|
data-testid="center-button"
|
|
91
99
|
>
|
|
92
100
|
<CenterIcon fontSize="small" />
|
|
@@ -96,17 +104,17 @@ export const MapControlBar: FC<MapControlBarProps> = ({
|
|
|
96
104
|
<ControlButton
|
|
97
105
|
size="small"
|
|
98
106
|
onClick={onToggleMapType}
|
|
99
|
-
aria-label=
|
|
107
|
+
aria-label={copy.mapType}
|
|
100
108
|
data-testid="map-type-button"
|
|
101
109
|
>
|
|
102
110
|
<LayersIcon fontSize="small" />
|
|
103
111
|
</ControlButton>
|
|
104
112
|
</Tooltip>
|
|
105
|
-
<Tooltip title=
|
|
113
|
+
<Tooltip title={copy.fullscreen} placement="left">
|
|
106
114
|
<ControlButton
|
|
107
115
|
size="small"
|
|
108
116
|
onClick={onToggleFullscreen}
|
|
109
|
-
aria-label=
|
|
117
|
+
aria-label={copy.fullscreen}
|
|
110
118
|
data-testid="fullscreen-button"
|
|
111
119
|
>
|
|
112
120
|
<FullscreenIcon fontSize="small" />
|
|
@@ -46,6 +46,7 @@ export const MapLayers: FC<MapLayersProps> = ({ settings, zoom, mapType, search,
|
|
|
46
46
|
|
|
47
47
|
{settings.showSearch && (
|
|
48
48
|
<MapSearchBar
|
|
49
|
+
label={settings.copy.search}
|
|
49
50
|
value={search.searchValue}
|
|
50
51
|
placeholder={settings.searchPlaceholder}
|
|
51
52
|
isSearching={search.isSearching}
|
|
@@ -56,6 +57,7 @@ export const MapLayers: FC<MapLayersProps> = ({ settings, zoom, mapType, search,
|
|
|
56
57
|
|
|
57
58
|
{settings.showControls && (
|
|
58
59
|
<MapControlBar
|
|
60
|
+
copy={settings.copy}
|
|
59
61
|
zoom={zoom}
|
|
60
62
|
mapType={mapType}
|
|
61
63
|
onZoomIn={controls.handleZoomIn}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { MapPreviewCopy } from '../../../copy';
|
|
2
|
+
|
|
1
3
|
export type MapType = 'roadmap' | 'satellite' | 'hybrid' | 'terrain';
|
|
2
4
|
|
|
3
5
|
export interface LatLng {
|
|
@@ -20,6 +22,14 @@ export interface HeatmapPoint {
|
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export interface MapPreviewProps {
|
|
25
|
+
/**
|
|
26
|
+
* The control bar's six names and the search field's own. Every control is a
|
|
27
|
+
* glyph carrying a `title` and an `aria-label`, so this is both the tooltip
|
|
28
|
+
* and what a screen reader reads. REQUIRED — `searchPlaceholder` beside it
|
|
29
|
+
* shows the shape this replaces: an English default that read as
|
|
30
|
+
* configurable right up until nobody configured it.
|
|
31
|
+
*/
|
|
32
|
+
copy: MapPreviewCopy;
|
|
23
33
|
/** Map center coordinates */
|
|
24
34
|
center?: { lat: number; lng: number };
|
|
25
35
|
/** Legacy coordinates prop (use center instead) */
|
|
@@ -28,6 +28,8 @@ const SearchField = styled(TextField)(({ theme }) => ({
|
|
|
28
28
|
}));
|
|
29
29
|
|
|
30
30
|
export interface MapSearchBarProps {
|
|
31
|
+
/** The field's accessible name — it renders no visible label. REQUIRED. */
|
|
32
|
+
label: string;
|
|
31
33
|
value: string;
|
|
32
34
|
placeholder: string;
|
|
33
35
|
isSearching: boolean;
|
|
@@ -36,6 +38,7 @@ export interface MapSearchBarProps {
|
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
export const MapSearchBar: FC<MapSearchBarProps> = ({
|
|
41
|
+
label,
|
|
39
42
|
value,
|
|
40
43
|
placeholder,
|
|
41
44
|
isSearching,
|
|
@@ -58,7 +61,7 @@ export const MapSearchBar: FC<MapSearchBarProps> = ({
|
|
|
58
61
|
),
|
|
59
62
|
}}
|
|
60
63
|
disabled={isSearching}
|
|
61
|
-
aria-label=
|
|
64
|
+
aria-label={label}
|
|
62
65
|
/>
|
|
63
66
|
</SearchBar>
|
|
64
67
|
);
|
package/src/copy.ts
CHANGED
|
@@ -129,4 +129,61 @@ export interface CepFieldCopy {
|
|
|
129
129
|
export interface TableFilterCopy {
|
|
130
130
|
/** A numeric range whose maximum is below its minimum. */
|
|
131
131
|
invalidRange: string;
|
|
132
|
+
/** The two free-text bounds, which carry no visible label of their own. */
|
|
133
|
+
rangeMin: string;
|
|
134
|
+
rangeMax: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* The lightbox's controls, every one of them a glyph with no text.
|
|
139
|
+
*
|
|
140
|
+
* So this object IS what a screen-reader user hears for the whole viewer —
|
|
141
|
+
* which is why it shipped as English literals for so long without anyone
|
|
142
|
+
* noticing: the sighted path renders identically either way.
|
|
143
|
+
*/
|
|
144
|
+
export interface LightboxCopy {
|
|
145
|
+
close: string;
|
|
146
|
+
previous: string;
|
|
147
|
+
next: string;
|
|
148
|
+
zoomIn: string;
|
|
149
|
+
zoomOut: string;
|
|
150
|
+
resetZoom: string;
|
|
151
|
+
/** The slideshow toggle, in its two states. */
|
|
152
|
+
play: string;
|
|
153
|
+
pause: string;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** The map preview's control bar — same shape, same reason, as the lightbox. */
|
|
157
|
+
export interface MapPreviewCopy {
|
|
158
|
+
zoomIn: string;
|
|
159
|
+
zoomOut: string;
|
|
160
|
+
center: string;
|
|
161
|
+
mapType: string;
|
|
162
|
+
fullscreen: string;
|
|
163
|
+
search: string;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** The carousel's two arrows, which carry a glyph and nothing else. */
|
|
167
|
+
export interface CarouselCopy {
|
|
168
|
+
previous: string;
|
|
169
|
+
next: string;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* The states a data surface can be in with nothing to draw, and the dismiss
|
|
174
|
+
* every banner-like surface carries.
|
|
175
|
+
*
|
|
176
|
+
* One object rather than six, because these are the same four sentences the
|
|
177
|
+
* table, the grid, the async container, the hover card and the infinite
|
|
178
|
+
* scroller each rendered their own copy of.
|
|
179
|
+
*/
|
|
180
|
+
export interface DataStateCopy {
|
|
181
|
+
/** No rows at all — distinct from "no rows for these filters". */
|
|
182
|
+
empty: string;
|
|
183
|
+
loading: string;
|
|
184
|
+
/** The infinite scroller reached the end. */
|
|
185
|
+
endOfList: string;
|
|
186
|
+
/** An alert's and a banner's dismiss, neither of which has a visible label. */
|
|
187
|
+
dismissAlert: string;
|
|
188
|
+
dismissBanner: string;
|
|
132
189
|
}
|
package/src/pt-BR.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import type { DataViewsCopy } from "./components/data-display/DataViews/data-views-copy";
|
|
2
2
|
import type { SavedViewsLabels } from "./components/layout/ContentToolbar/ContentToolbar.types";
|
|
3
3
|
import type {
|
|
4
|
+
CarouselCopy,
|
|
4
5
|
CategorySelectCopy,
|
|
5
6
|
CepFieldCopy,
|
|
6
7
|
ConfirmActionCopy,
|
|
8
|
+
DataStateCopy,
|
|
9
|
+
LightboxCopy,
|
|
10
|
+
MapPreviewCopy,
|
|
7
11
|
SectionOnboardingCopy,
|
|
8
12
|
TableFilterCopy,
|
|
9
|
-
} from
|
|
13
|
+
} from './copy';
|
|
10
14
|
|
|
11
15
|
/**
|
|
12
16
|
* The pt-BR packs — NAMED constants a host passes by hand, never defaults.
|
|
@@ -101,6 +105,41 @@ export const PT_BR_SAVED_VIEWS_LABELS: SavedViewsLabels = {
|
|
|
101
105
|
|
|
102
106
|
export const PT_BR_TABLE_FILTER_COPY: TableFilterCopy = {
|
|
103
107
|
invalidRange: "O máximo deve ser maior ou igual ao mínimo.",
|
|
108
|
+
rangeMin: "Mínimo",
|
|
109
|
+
rangeMax: "Máximo",
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const PT_BR_LIGHTBOX_COPY: LightboxCopy = {
|
|
113
|
+
close: "Fechar",
|
|
114
|
+
previous: "Anterior",
|
|
115
|
+
next: "Próximo",
|
|
116
|
+
zoomIn: "Aproximar",
|
|
117
|
+
zoomOut: "Afastar",
|
|
118
|
+
resetZoom: "Restaurar o zoom",
|
|
119
|
+
play: "Iniciar a apresentação",
|
|
120
|
+
pause: "Pausar a apresentação",
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const PT_BR_MAP_PREVIEW_COPY: MapPreviewCopy = {
|
|
124
|
+
zoomIn: "Aproximar",
|
|
125
|
+
zoomOut: "Afastar",
|
|
126
|
+
center: "Centralizar o mapa",
|
|
127
|
+
mapType: "Trocar o tipo de mapa",
|
|
128
|
+
fullscreen: "Tela cheia",
|
|
129
|
+
search: "Buscar endereço",
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export const PT_BR_CAROUSEL_COPY: CarouselCopy = {
|
|
133
|
+
previous: "Anterior",
|
|
134
|
+
next: "Próximo",
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export const PT_BR_DATA_STATE_COPY: DataStateCopy = {
|
|
138
|
+
empty: "Nenhum dado por aqui",
|
|
139
|
+
loading: "Carregando…",
|
|
140
|
+
endOfList: "Não há mais itens para carregar",
|
|
141
|
+
dismissAlert: "Fechar o aviso",
|
|
142
|
+
dismissBanner: "Fechar a faixa",
|
|
104
143
|
};
|
|
105
144
|
|
|
106
145
|
export const PT_BR_DATA_VIEWS_COPY: DataViewsCopy = {
|
|
@@ -260,6 +299,7 @@ export const PT_BR_DATA_VIEWS_COPY: DataViewsCopy = {
|
|
|
260
299
|
saveAs: "Salvar como nova",
|
|
261
300
|
reset: "Redefinir",
|
|
262
301
|
updateFailed: "Não foi possível atualizar a visão",
|
|
302
|
+
dismissError: "Fechar o aviso",
|
|
263
303
|
saveFailed: "Não foi possível salvar a alteração da visão.",
|
|
264
304
|
editView: "Renomear e editar",
|
|
265
305
|
pinToSidebar: "Fixar na barra lateral",
|