@tpzdsp/next-toolkit 1.12.1 → 1.13.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/README.md +4 -4
- package/package.json +1 -6
- package/src/assets/styles/ol.css +147 -176
- package/src/components/InfoBox/InfoBox.stories.tsx +457 -0
- package/src/components/InfoBox/InfoBox.test.tsx +382 -0
- package/src/components/InfoBox/InfoBox.tsx +177 -0
- package/src/components/InfoBox/hooks/index.ts +3 -0
- package/src/components/InfoBox/hooks/useInfoBoxPosition.test.ts +187 -0
- package/src/components/InfoBox/hooks/useInfoBoxPosition.ts +69 -0
- package/src/components/InfoBox/hooks/useInfoBoxState.test.ts +168 -0
- package/src/components/InfoBox/hooks/useInfoBoxState.ts +71 -0
- package/src/components/InfoBox/hooks/usePortalMount.test.ts +62 -0
- package/src/components/InfoBox/hooks/usePortalMount.ts +15 -0
- package/src/components/InfoBox/types.ts +6 -0
- package/src/components/InfoBox/utils/focusTrapConfig.test.ts +310 -0
- package/src/components/InfoBox/utils/focusTrapConfig.ts +59 -0
- package/src/components/InfoBox/utils/index.ts +2 -0
- package/src/components/InfoBox/utils/positionUtils.test.ts +170 -0
- package/src/components/InfoBox/utils/positionUtils.ts +89 -0
- package/src/components/index.ts +8 -0
- package/src/map/FullScreenControl.ts +126 -0
- package/src/map/LayerSwitcherControl.ts +87 -181
- package/src/map/LayerSwitcherPanel.tsx +173 -0
- package/src/map/MapComponent.tsx +6 -35
- package/src/map/createControlButton.ts +72 -0
- package/src/map/geocoder/Geocoder.test.tsx +115 -0
- package/src/map/geocoder/Geocoder.tsx +393 -0
- package/src/map/geocoder/groupResults.ts +12 -0
- package/src/map/geocoder/index.ts +4 -0
- package/src/map/geocoder/types.ts +11 -0
- package/src/map/index.ts +4 -1
- package/src/map/osOpenNamesSearch.ts +112 -57
- package/src/test/renderers.tsx +9 -20
- package/src/map/geocoder.ts +0 -61
- package/src/ol-geocoder.d.ts +0 -1
package/README.md
CHANGED
|
@@ -139,7 +139,7 @@ interface MyComponentProps extends BaseProps {
|
|
|
139
139
|
|
|
140
140
|
```bash
|
|
141
141
|
# Install OpenLayers dependencies
|
|
142
|
-
npm install ol ol-
|
|
142
|
+
npm install ol ol-mapbox-style proj4
|
|
143
143
|
```
|
|
144
144
|
|
|
145
145
|
```typescript
|
|
@@ -152,14 +152,14 @@ import '@your-org/nextjs-library/styles/ol';
|
|
|
152
152
|
Some components require additional peer dependencies that are marked as optional:
|
|
153
153
|
|
|
154
154
|
- **Select components**: Require `react-select`
|
|
155
|
-
- **Map components**: Require OpenLayers packages (`ol`, `ol-
|
|
155
|
+
- **Map components**: Require OpenLayers packages (`ol`, `ol-mapbox-style`, etc.)
|
|
156
156
|
|
|
157
157
|
```bash
|
|
158
158
|
# For Select components
|
|
159
159
|
npm install react-select
|
|
160
160
|
|
|
161
161
|
# For Map components
|
|
162
|
-
npm install ol ol-
|
|
162
|
+
npm install ol ol-mapbox-style proj4 @turf/turf geojson
|
|
163
163
|
```
|
|
164
164
|
|
|
165
165
|
```typescript
|
|
@@ -451,7 +451,7 @@ npm install react-select
|
|
|
451
451
|
|
|
452
452
|
# Error: Cannot resolve module 'ol/ol.css'
|
|
453
453
|
# Solution: Install OpenLayers dependencies
|
|
454
|
-
npm install ol ol-
|
|
454
|
+
npm install ol ol-mapbox-style proj4
|
|
455
455
|
|
|
456
456
|
# Or import components selectively to avoid these dependencies:
|
|
457
457
|
import { Button, Card } from '@your-org/nextjs-library'; // ✅ No extra deps needed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tpzdsp/next-toolkit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "A reusable React component library for Next.js applications",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">= 24.12.0",
|
|
@@ -171,7 +171,6 @@
|
|
|
171
171
|
"jsonwebtoken": "^9.0.3",
|
|
172
172
|
"next": "^16.1.4",
|
|
173
173
|
"ol": "^10.6.1",
|
|
174
|
-
"ol-geocoder": "^4.3.3",
|
|
175
174
|
"ol-mapbox-style": "^13.0.1",
|
|
176
175
|
"postcss": "^8.5.6",
|
|
177
176
|
"prettier": "^3.8.1",
|
|
@@ -213,7 +212,6 @@
|
|
|
213
212
|
"geojson": "^0.5.0",
|
|
214
213
|
"next": "^16.1.4",
|
|
215
214
|
"ol": "^10.6.1",
|
|
216
|
-
"ol-geocoder": "^4.3.3",
|
|
217
215
|
"ol-mapbox-style": "^13.0.1",
|
|
218
216
|
"proj4": "^2.19.10",
|
|
219
217
|
"react": "^19.2.1",
|
|
@@ -256,9 +254,6 @@
|
|
|
256
254
|
"ol": {
|
|
257
255
|
"optional": true
|
|
258
256
|
},
|
|
259
|
-
"ol-geocoder": {
|
|
260
|
-
"optional": true
|
|
261
|
-
},
|
|
262
257
|
"ol-mapbox-style": {
|
|
263
258
|
"optional": true
|
|
264
259
|
},
|
package/src/assets/styles/ol.css
CHANGED
|
@@ -1,42 +1,93 @@
|
|
|
1
1
|
@import 'ol/ol.css';
|
|
2
|
-
@import 'ol-geocoder/dist/ol-geocoder.min.css';
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* OpenLayers Control Styles
|
|
5
|
+
*
|
|
6
|
+
* This file contains styles for OpenLayers map controls (zoom, layer switcher, fullscreen).
|
|
7
|
+
*
|
|
8
|
+
* Design System:
|
|
9
|
+
* - All control buttons extend the `.ol-btn` base class
|
|
10
|
+
* - Control panels should be implemented as React components with Tailwind CSS
|
|
11
|
+
* - Use CSS custom properties (--focus-color, etc.) for consistent theming
|
|
12
|
+
*
|
|
13
|
+
* To add a new control:
|
|
14
|
+
* 1. Add the `ol-btn` class to your button element
|
|
15
|
+
* 2. Override only the properties you need (e.g., font-size, icon)
|
|
16
|
+
* 3. Position the control container with absolute positioning
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
:root {
|
|
20
|
+
--focus-color: #ffdd00;
|
|
21
|
+
--focus-outline-color: #ffbf47;
|
|
22
|
+
--control-bg: #fff;
|
|
23
|
+
--control-border: #505a5f;
|
|
24
|
+
--control-text: #0b0c0c;
|
|
25
|
+
--control-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Base button class for all OpenLayers controls */
|
|
29
|
+
.ol-btn,
|
|
30
|
+
.ol-btn:hover,
|
|
31
|
+
.ol-btn:active,
|
|
32
|
+
.ol-btn:focus,
|
|
33
|
+
.ol-btn:focus-visible {
|
|
34
|
+
width: 40px !important;
|
|
35
|
+
height: 40px !important;
|
|
36
|
+
border: none !important;
|
|
37
|
+
outline: none !important;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.ol-btn {
|
|
41
|
+
background: var(--control-bg);
|
|
42
|
+
color: var(--control-text);
|
|
43
|
+
font-size: 1.5rem;
|
|
44
|
+
font-weight: bold;
|
|
45
|
+
line-height: 1;
|
|
46
|
+
box-shadow: var(--control-shadow);
|
|
47
|
+
cursor: pointer;
|
|
48
|
+
transition:
|
|
49
|
+
box-shadow 0.2s,
|
|
50
|
+
background 0.2s;
|
|
51
|
+
margin: 0;
|
|
52
|
+
padding: 0;
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
justify-content: center;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Ensure SVG icons in buttons are consistently sized and centered */
|
|
59
|
+
.ol-btn svg {
|
|
60
|
+
width: 20px !important;
|
|
61
|
+
height: 20px !important;
|
|
62
|
+
flex-shrink: 0;
|
|
63
|
+
display: block;
|
|
64
|
+
margin: 0 auto;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.ol-btn:hover,
|
|
68
|
+
.ol-btn:active {
|
|
69
|
+
background: var(--focus-color) !important;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.ol-btn:focus,
|
|
73
|
+
.ol-btn:focus-visible {
|
|
74
|
+
outline: 3px solid var(--focus-outline-color) !important;
|
|
75
|
+
background: var(--focus-color) !important;
|
|
76
|
+
z-index: 2;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* Universal OpenLayers control focus style for non-button elements */
|
|
5
80
|
#map:focus,
|
|
6
81
|
.ol-viewport:focus,
|
|
7
82
|
.ol-control:focus,
|
|
8
|
-
.ol-control button:focus,
|
|
9
|
-
.ol-control button:focus-visible,
|
|
10
83
|
.ol-attribution:focus,
|
|
11
|
-
.ol-attribution button:focus,
|
|
12
|
-
.ol-zoom:focus,
|
|
13
|
-
.ol-zoom button:focus,
|
|
14
|
-
.ol-layer-switcher-toggle:focus,
|
|
15
|
-
.ol-layer-switcher-close:focus,
|
|
16
|
-
.ol-layer-switcher-panel button:focus,
|
|
17
84
|
.ol-attribution ul li a:focus,
|
|
18
|
-
.ol-attribution ul li a:focus-visible
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
outline: 3px solid #ffbf47 !important;
|
|
22
|
-
border-color: #ffbf47 !important;
|
|
85
|
+
.ol-attribution ul li a:focus-visible {
|
|
86
|
+
outline: 3px solid var(--focus-outline-color) !important;
|
|
87
|
+
border-color: var(--focus-outline-color) !important;
|
|
23
88
|
z-index: 2;
|
|
24
89
|
}
|
|
25
90
|
|
|
26
|
-
.ol-geocoder #gcd-input-search:focus,
|
|
27
|
-
.ol-geocoder .gcd-txt-search:focus,
|
|
28
|
-
.ol-geocoder .gcd-txt-search:focus-visible {
|
|
29
|
-
background-color: #ffbf47 !important;
|
|
30
|
-
z-index: 2;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.ol-geocoder .gcd-txt-input:focus,
|
|
34
|
-
.ol-geocoder .gcd-txt-input:focus-visible {
|
|
35
|
-
box-shadow:
|
|
36
|
-
inset 0 0 0 1px #ffbf47,
|
|
37
|
-
inset 0 0 6px #ffbf47;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
91
|
/* Zoom control container */
|
|
41
92
|
.ol-zoom {
|
|
42
93
|
top: 1.5rem;
|
|
@@ -47,61 +98,26 @@
|
|
|
47
98
|
z-index: 10;
|
|
48
99
|
}
|
|
49
100
|
|
|
50
|
-
/*
|
|
101
|
+
/* Apply base button styling to zoom buttons */
|
|
51
102
|
.ol-zoom button,
|
|
52
|
-
.ol-control button {
|
|
53
|
-
width: 40px;
|
|
54
|
-
height: 40px;
|
|
55
|
-
background: #fff;
|
|
56
|
-
color: #0b0c0c;
|
|
57
|
-
font-size: 2rem;
|
|
58
|
-
font-weight: bold;
|
|
59
|
-
line-height: 1;
|
|
60
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
|
|
61
|
-
cursor: pointer;
|
|
62
|
-
transition:
|
|
63
|
-
border-color 0.2s,
|
|
64
|
-
box-shadow 0.2s,
|
|
65
|
-
background 0.2s;
|
|
66
|
-
margin: 0;
|
|
67
|
-
padding: 0;
|
|
68
|
-
display: flex;
|
|
69
|
-
align-items: center;
|
|
70
|
-
justify-content: center;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
103
|
.ol-zoom button:hover,
|
|
74
|
-
.ol-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
.ol-layer-switcher {
|
|
82
|
-
top: 0px;
|
|
83
|
-
right: 1rem;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.ol-layer-switcher-toggle {
|
|
87
|
-
position: absolute;
|
|
88
|
-
top: 110px;
|
|
89
|
-
right: 0px;
|
|
104
|
+
.ol-zoom button:active,
|
|
105
|
+
.ol-zoom button:focus,
|
|
106
|
+
.ol-zoom button:focus-visible {
|
|
107
|
+
width: 40px !important;
|
|
108
|
+
height: 40px !important;
|
|
109
|
+
border: none !important;
|
|
110
|
+
outline: none !important;
|
|
90
111
|
}
|
|
91
112
|
|
|
92
|
-
.ol-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
background: #fff;
|
|
96
|
-
border: 2px solid #505a5f;
|
|
97
|
-
color: #0b0c0c;
|
|
98
|
-
font-size: 1.5rem;
|
|
113
|
+
.ol-zoom button {
|
|
114
|
+
background: var(--control-bg) !important;
|
|
115
|
+
color: var(--control-text) !important;
|
|
99
116
|
font-weight: bold;
|
|
100
117
|
line-height: 1;
|
|
101
|
-
box-shadow:
|
|
118
|
+
box-shadow: var(--control-shadow);
|
|
102
119
|
cursor: pointer;
|
|
103
120
|
transition:
|
|
104
|
-
border-color 0.2s,
|
|
105
121
|
box-shadow 0.2s,
|
|
106
122
|
background 0.2s;
|
|
107
123
|
margin: 0;
|
|
@@ -109,124 +125,79 @@
|
|
|
109
125
|
display: flex;
|
|
110
126
|
align-items: center;
|
|
111
127
|
justify-content: center;
|
|
128
|
+
font-size: 0 !important; /* Hide the default +/- text */
|
|
129
|
+
position: relative;
|
|
112
130
|
}
|
|
113
131
|
|
|
114
|
-
.ol-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
right: -100%;
|
|
118
|
-
display: flex;
|
|
119
|
-
flex-direction: column;
|
|
120
|
-
align-items: stretch;
|
|
121
|
-
padding: 1rem 1rem;
|
|
122
|
-
min-width: 220px;
|
|
123
|
-
background: #fff;
|
|
124
|
-
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
|
125
|
-
gap: 0.5rem;
|
|
126
|
-
transition: right 0.3s ease-in-out;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
.ol-layer-switcher-panel.open {
|
|
130
|
-
right: 3rem;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/* Header for the close button, aligns it to the top-right */
|
|
134
|
-
.ol-layer-switcher-header {
|
|
135
|
-
display: flex;
|
|
136
|
-
justify-content: flex-end;
|
|
137
|
-
align-items: center;
|
|
138
|
-
width: 100%;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/* Small, circular close button */
|
|
142
|
-
.ol-layer-switcher-close {
|
|
143
|
-
font-size: 1.25rem;
|
|
144
|
-
width: 2rem;
|
|
145
|
-
height: 2rem;
|
|
146
|
-
padding: 0;
|
|
147
|
-
background: none;
|
|
148
|
-
border: none;
|
|
149
|
-
color: #505a5f;
|
|
150
|
-
cursor: pointer;
|
|
151
|
-
border-radius: 50%;
|
|
152
|
-
transition: background 0.2s;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
.ol-layer-switcher-close:hover,
|
|
156
|
-
.ol-layer-switcher-close:focus {
|
|
157
|
-
background: #e1e1e1;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/* Content area for basemap buttons */
|
|
161
|
-
.ol-layer-switcher-content {
|
|
162
|
-
display: flex;
|
|
163
|
-
flex-direction: row;
|
|
164
|
-
gap: 10px;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
.ol-layer-switcher-content button {
|
|
168
|
-
display: flex;
|
|
169
|
-
flex-direction: column;
|
|
170
|
-
align-items: center;
|
|
171
|
-
justify-content: center;
|
|
172
|
-
border: 2px solid #ccc;
|
|
173
|
-
background-color: #fff;
|
|
174
|
-
min-width: 135px;
|
|
175
|
-
min-height: 135px;
|
|
176
|
-
cursor: pointer;
|
|
177
|
-
color: #000;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
.ol-layer-switcher-content button:hover {
|
|
181
|
-
background-color: #ddd;
|
|
132
|
+
.ol-zoom button:hover,
|
|
133
|
+
.ol-zoom button:active {
|
|
134
|
+
background: var(--focus-color) !important;
|
|
182
135
|
}
|
|
183
136
|
|
|
184
|
-
.ol-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
transform: scale(1.05);
|
|
190
|
-
transition: all 0.2s ease;
|
|
137
|
+
.ol-zoom button:focus,
|
|
138
|
+
.ol-zoom button:focus-visible {
|
|
139
|
+
outline: 3px solid var(--focus-outline-color) !important;
|
|
140
|
+
background: var(--focus-color) !important;
|
|
141
|
+
z-index: 2;
|
|
191
142
|
}
|
|
192
143
|
|
|
193
|
-
|
|
194
|
-
|
|
144
|
+
/* Override default zoom button text with SVG icons */
|
|
145
|
+
.ol-zoom-in::before,
|
|
146
|
+
.ol-zoom-out::before {
|
|
147
|
+
content: '';
|
|
148
|
+
display: block;
|
|
149
|
+
width: 20px;
|
|
150
|
+
height: 20px;
|
|
151
|
+
background-size: contain;
|
|
152
|
+
background-repeat: no-repeat;
|
|
153
|
+
background-position: center;
|
|
154
|
+
font-size: 0; /* Ensure no text shows */
|
|
195
155
|
}
|
|
196
156
|
|
|
197
|
-
.ol-
|
|
198
|
-
|
|
157
|
+
.ol-zoom-in::before {
|
|
158
|
+
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M12 5v14m-7-7h14" stroke="%230b0c0c" stroke-width="2" stroke-linecap="round"/></svg>');
|
|
199
159
|
}
|
|
200
160
|
|
|
201
|
-
.ol-
|
|
202
|
-
|
|
203
|
-
height: auto;
|
|
204
|
-
border: 2px solid #000;
|
|
161
|
+
.ol-zoom-out::before {
|
|
162
|
+
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M5 12h14" stroke="%230b0c0c" stroke-width="2" stroke-linecap="round"/></svg>');
|
|
205
163
|
}
|
|
206
164
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
165
|
+
/* Layer switcher control */
|
|
166
|
+
.ol-layer-switcher {
|
|
167
|
+
position: absolute;
|
|
168
|
+
top: 110px;
|
|
169
|
+
right: 1rem;
|
|
170
|
+
z-index: 9999;
|
|
210
171
|
}
|
|
211
172
|
|
|
212
|
-
/*
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
173
|
+
/* Full screen control */
|
|
174
|
+
.ol-fullscreen {
|
|
175
|
+
position: absolute;
|
|
176
|
+
top: 155px;
|
|
177
|
+
right: 1rem;
|
|
217
178
|
}
|
|
218
179
|
|
|
219
|
-
|
|
220
|
-
.
|
|
221
|
-
|
|
180
|
+
/* Full screen mode for map container */
|
|
181
|
+
.map-fullscreen {
|
|
182
|
+
position: fixed !important;
|
|
183
|
+
top: 0 !important;
|
|
184
|
+
left: 0 !important;
|
|
185
|
+
right: 0 !important;
|
|
186
|
+
bottom: 0 !important;
|
|
187
|
+
width: 100vw !important;
|
|
188
|
+
height: 100vh !important;
|
|
189
|
+
z-index: 9999 !important;
|
|
190
|
+
margin: 0 !important;
|
|
191
|
+
padding: 0 !important;
|
|
222
192
|
}
|
|
223
193
|
|
|
224
|
-
|
|
225
|
-
.
|
|
226
|
-
|
|
227
|
-
|
|
194
|
+
/* Ensure map fills container in full screen mode */
|
|
195
|
+
.map-fullscreen .ol-viewport {
|
|
196
|
+
width: 100% !important;
|
|
197
|
+
height: 100% !important;
|
|
228
198
|
}
|
|
229
199
|
|
|
230
|
-
|
|
231
|
-
|
|
200
|
+
/* Hide other UI elements when in full screen (optional) */
|
|
201
|
+
.map-fullscreen ~ * {
|
|
202
|
+
display: none;
|
|
232
203
|
}
|