@tpzdsp/next-toolkit 1.15.0 → 1.15.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tpzdsp/next-toolkit",
3
- "version": "1.15.0",
3
+ "version": "1.15.1",
4
4
  "description": "A reusable React component library for Next.js applications",
5
5
  "engines": {
6
6
  "node": ">= 24.12.0",
@@ -11,6 +11,7 @@ type Props = {
11
11
  title: string;
12
12
  children: ReactNode;
13
13
  defaultOpen?: boolean;
14
+ disabled?: boolean;
14
15
  };
15
16
 
16
17
  export type AccordionProps = ExtendProps<'div', Props>;
@@ -19,6 +20,7 @@ export const Accordion = ({
19
20
  title,
20
21
  children,
21
22
  defaultOpen = false,
23
+ disabled = false,
22
24
  className,
23
25
  ...props
24
26
  }: AccordionProps) => {
@@ -28,14 +30,25 @@ export const Accordion = ({
28
30
  const [isOpen, setIsOpen] = useState(defaultOpen);
29
31
 
30
32
  return (
31
- <div className={cn('flex flex-col border-l-2 border-neutral-100', className)} {...props}>
33
+ <div
34
+ className={cn(
35
+ 'flex flex-col border-l-2 border-neutral-100',
36
+ disabled ? 'opacity-50' : '',
37
+ className,
38
+ )}
39
+ {...props}
40
+ >
32
41
  <button
33
- aria-expanded={isOpen}
34
- aria-controls={contentId}
35
- className="flex justify-between items-center px-2 py-1 bg-[#fefefefe] text-[color:#000000]
36
- border-y-2 border-neutral-100 focus-yellow"
42
+ aria-expanded={disabled ? undefined : isOpen}
43
+ aria-controls={disabled ? undefined : contentId}
44
+ disabled={disabled}
45
+ className={cn(
46
+ `flex justify-between items-center px-2 py-1 bg-[#fefefefe] text-[color:#000000]
47
+ border-y-2 border-neutral-100`,
48
+ disabled ? 'cursor-not-allowed' : 'focus-yellow',
49
+ )}
37
50
  id={buttonId}
38
- onClick={() => setIsOpen(!isOpen)}
51
+ onClick={disabled ? undefined : () => setIsOpen(!isOpen)}
39
52
  type="button"
40
53
  >
41
54
  <span>{title}</span>
@@ -45,14 +58,16 @@ export const Accordion = ({
45
58
  </span>
46
59
  </button>
47
60
 
48
- <section
49
- id={contentId}
50
- aria-labelledby={buttonId}
51
- aria-hidden={!isOpen}
52
- className={cn('p-2 bg-[#efefef]', isOpen ? 'block' : 'hidden')}
53
- >
54
- {children}
55
- </section>
61
+ {!disabled ? (
62
+ <section
63
+ id={contentId}
64
+ aria-labelledby={buttonId}
65
+ aria-hidden={!isOpen}
66
+ className={cn('p-2 bg-[#efefef]', isOpen ? 'block' : 'hidden')}
67
+ >
68
+ {children}
69
+ </section>
70
+ ) : null}
56
71
  </div>
57
72
  );
58
73
  };
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { memo, useEffect, useRef, useState } from 'react';
4
4
 
5
- import { Map, Overlay, View } from 'ol';
5
+ import { Feature, Map, Overlay, View } from 'ol';
6
6
  import { Attribution, ScaleLine, Zoom } from 'ol/control';
7
7
  import { fromLonLat } from 'ol/proj';
8
8
 
@@ -11,7 +11,7 @@ import { FullScreenControl } from './FullScreenControl';
11
11
  import { LayerSwitcherControl } from './LayerSwitcherControl';
12
12
  import { useMap } from './MapContext';
13
13
  import { Popup } from './Popup';
14
- import { getPopupPositionClass } from './utils';
14
+ import { getPopupPositionClass, LAYER_NAMES } from './utils';
15
15
  import type { PopupDirection } from '../types/map';
16
16
 
17
17
  export type MapComponentProps = {
@@ -44,7 +44,7 @@ const arrowStyles: Record<PopupDirection, string> = {
44
44
  * @return {*}
45
45
  */
46
46
  const MapComponentBase = ({ osMapsApiKey, basePath }: MapComponentProps) => {
47
- const [popupFeatures, setPopupFeatures] = useState([]);
47
+ const [popupFeatures, setPopupFeatures] = useState<Feature[]>([]);
48
48
  const [popupCoordinate, setPopupCoordinate] = useState<number[] | null>(null);
49
49
  const [popupPositionClass, setPopupPositionClass] = useState<PopupDirection>('bottom-right');
50
50
 
@@ -117,17 +117,41 @@ const MapComponentBase = ({ osMapsApiKey, basePath }: MapComponentProps) => {
117
117
  return;
118
118
  }
119
119
 
120
- newMap.forEachFeatureAtPixel(event.pixel, (feature) => {
121
- const features = feature.get('features');
120
+ newMap.forEachFeatureAtPixel(event.pixel, (feature, layer) => {
121
+ const clusterFeatures = feature.get('features');
122
+ const layerName = (layer as { get(k: string): unknown } | null)?.get('name');
122
123
 
123
- if (features?.length > 0) {
124
+ if (clusterFeatures?.length > 0) {
124
125
  const coordinate = event.coordinate;
125
126
  const direction = getPopupPositionClass(coordinate, newMap);
126
127
 
127
- setPopupFeatures(features);
128
+ setPopupFeatures(clusterFeatures);
128
129
  setPopupCoordinate(coordinate);
129
130
  setPopupPositionClass(direction);
130
131
  overlay.setPosition(event.coordinate);
132
+
133
+ return true; // stop iteration
134
+ }
135
+
136
+ // Direct feature (e.g. polygon) — only show popup for the sampling points
137
+ // layer, not boundary or AOI layers which may also have name properties.
138
+ if (layerName !== LAYER_NAMES.SamplingPoints) {
139
+ return;
140
+ }
141
+
142
+ const name = feature.get('name');
143
+ const notation = feature.get('notation');
144
+
145
+ if (name || notation) {
146
+ const coordinate = event.coordinate;
147
+ const direction = getPopupPositionClass(coordinate, newMap);
148
+
149
+ setPopupFeatures([feature as Feature]);
150
+ setPopupCoordinate(coordinate);
151
+ setPopupPositionClass(direction);
152
+ overlay.setPosition(event.coordinate);
153
+
154
+ return true; // stop iteration
131
155
  }
132
156
  });
133
157
  });
package/src/map/Popup.tsx CHANGED
@@ -41,13 +41,16 @@ export const Popup = ({
41
41
  rounded-lg divide-y divide-gray-300"
42
42
  >
43
43
  {features.map((feature) => {
44
- const id = feature.get('id');
45
44
  const name = feature.get('name');
46
45
  const notation = feature.get('notation');
47
- const url = `${baseUrl}${notation}`;
46
+ const libraryNotation = feature.get('libraryNotation');
47
+ const identifier = notation ?? name;
48
+ const url = libraryNotation
49
+ ? `${baseUrl}${libraryNotation}/${identifier}`
50
+ : `${baseUrl}${identifier}`;
48
51
 
49
52
  return (
50
- <div key={id}>
53
+ <div key={identifier}>
51
54
  <strong>
52
55
  <ExternalLink
53
56
  href={url}