maplibre-gl-plugin-template 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.cjs","sources":["../src/lib/core/PluginControlReact.tsx","../src/lib/hooks/usePluginState.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport { PluginControl } from './PluginControl';\nimport type { PluginControlReactProps } from './types';\n\n/**\n * React wrapper component for PluginControl.\n *\n * This component manages the lifecycle of a PluginControl instance,\n * adding it to the map on mount and removing it on unmount.\n *\n * @example\n * ```tsx\n * import { PluginControlReact } from 'maplibre-gl-plugin-template/react';\n *\n * function MyMap() {\n * const [map, setMap] = useState<Map | null>(null);\n *\n * return (\n * <>\n * <div ref={mapContainer} />\n * {map && (\n * <PluginControlReact\n * map={map}\n * title=\"My Control\"\n * collapsed={false}\n * />\n * )}\n * </>\n * );\n * }\n * ```\n *\n * @param props - Component props including map instance and control options\n * @returns null - This component renders nothing directly\n */\nexport function PluginControlReact({\n map,\n onStateChange,\n ...options\n}: PluginControlReactProps): null {\n const controlRef = useRef<PluginControl | null>(null);\n\n useEffect(() => {\n if (!map) return;\n\n // Create the control instance\n const control = new PluginControl(options);\n controlRef.current = control;\n\n // Register state change handler if provided\n if (onStateChange) {\n control.on('statechange', (event) => {\n onStateChange(event.state);\n });\n }\n\n // Add control to map\n map.addControl(control, options.position || 'top-right');\n\n // Cleanup on unmount\n return () => {\n if (map.hasControl(control)) {\n map.removeControl(control);\n }\n controlRef.current = null;\n };\n }, [map]);\n\n // Update options when they change\n useEffect(() => {\n if (controlRef.current) {\n // Handle collapsed state changes\n const currentState = controlRef.current.getState();\n if (options.collapsed !== undefined && options.collapsed !== currentState.collapsed) {\n if (options.collapsed) {\n controlRef.current.collapse();\n } else {\n controlRef.current.expand();\n }\n }\n }\n }, [options.collapsed]);\n\n return null;\n}\n","import { useState, useCallback } from 'react';\nimport type { PluginState } from '../core/types';\n\n/**\n * Default initial state for the plugin\n */\nconst DEFAULT_STATE: PluginState = {\n collapsed: true,\n panelWidth: 300,\n data: {},\n};\n\n/**\n * Custom hook for managing plugin state in React applications.\n *\n * This hook provides a simple way to track and update the state\n * of a PluginControl from React components.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { state, setCollapsed, setData, reset } = usePluginState();\n *\n * return (\n * <div>\n * <button onClick={() => setCollapsed(!state.collapsed)}>\n * {state.collapsed ? 'Expand' : 'Collapse'}\n * </button>\n * <PluginControlReact\n * map={map}\n * collapsed={state.collapsed}\n * onStateChange={(newState) => setState(newState)}\n * />\n * </div>\n * );\n * }\n * ```\n *\n * @param initialState - Optional initial state values\n * @returns Object containing state and update functions\n */\nexport function usePluginState(initialState?: Partial<PluginState>) {\n const [state, setState] = useState<PluginState>({\n ...DEFAULT_STATE,\n ...initialState,\n });\n\n /**\n * Sets the collapsed state\n */\n const setCollapsed = useCallback((collapsed: boolean) => {\n setState((prev) => ({ ...prev, collapsed }));\n }, []);\n\n /**\n * Sets the panel width\n */\n const setPanelWidth = useCallback((panelWidth: number) => {\n setState((prev) => ({ ...prev, panelWidth }));\n }, []);\n\n /**\n * Sets custom data in the state\n */\n const setData = useCallback((data: Record<string, unknown>) => {\n setState((prev) => ({ ...prev, data: { ...prev.data, ...data } }));\n }, []);\n\n /**\n * Resets the state to default values\n */\n const reset = useCallback(() => {\n setState({ ...DEFAULT_STATE, ...initialState });\n }, [initialState]);\n\n /**\n * Toggles the collapsed state\n */\n const toggle = useCallback(() => {\n setState((prev) => ({ ...prev, collapsed: !prev.collapsed }));\n }, []);\n\n return {\n state,\n setState,\n setCollapsed,\n setPanelWidth,\n setData,\n reset,\n toggle,\n };\n}\n"],"names":["useRef","useEffect","PluginControl","useState","useCallback"],"mappings":";;;;AAmCO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAkC;AAChC,QAAM,aAAaA,MAAAA,OAA6B,IAAI;AAEpDC,QAAAA,UAAU,MAAM;AACd,QAAI,CAAC,IAAK;AAGV,UAAM,UAAU,IAAIC,cAAAA,cAAc,OAAO;AACzC,eAAW,UAAU;AAGrB,QAAI,eAAe;AACjB,cAAQ,GAAG,eAAe,CAAC,UAAU;AACnC,sBAAc,MAAM,KAAK;AAAA,MAC3B,CAAC;AAAA,IACH;AAGA,QAAI,WAAW,SAAS,QAAQ,YAAY,WAAW;AAGvD,WAAO,MAAM;AACX,UAAI,IAAI,WAAW,OAAO,GAAG;AAC3B,YAAI,cAAc,OAAO;AAAA,MAC3B;AACA,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAGRD,QAAAA,UAAU,MAAM;AACd,QAAI,WAAW,SAAS;AAEtB,YAAM,eAAe,WAAW,QAAQ,SAAA;AACxC,UAAI,QAAQ,cAAc,UAAa,QAAQ,cAAc,aAAa,WAAW;AACnF,YAAI,QAAQ,WAAW;AACrB,qBAAW,QAAQ,SAAA;AAAA,QACrB,OAAO;AACL,qBAAW,QAAQ,OAAA;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,QAAQ,SAAS,CAAC;AAEtB,SAAO;AACT;AC9EA,MAAM,gBAA6B;AAAA,EACjC,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,MAAM,CAAA;AACR;AA+BO,SAAS,eAAe,cAAqC;AAClE,QAAM,CAAC,OAAO,QAAQ,IAAIE,eAAsB;AAAA,IAC9C,GAAG;AAAA,IACH,GAAG;AAAA,EAAA,CACJ;AAKD,QAAM,eAAeC,kBAAY,CAAC,cAAuB;AACvD,aAAS,CAAC,UAAU,EAAE,GAAG,MAAM,YAAY;AAAA,EAC7C,GAAG,CAAA,CAAE;AAKL,QAAM,gBAAgBA,kBAAY,CAAC,eAAuB;AACxD,aAAS,CAAC,UAAU,EAAE,GAAG,MAAM,aAAa;AAAA,EAC9C,GAAG,CAAA,CAAE;AAKL,QAAM,UAAUA,kBAAY,CAAC,SAAkC;AAC7D,aAAS,CAAC,UAAU,EAAE,GAAG,MAAM,MAAM,EAAE,GAAG,KAAK,MAAM,GAAG,KAAA,IAAS;AAAA,EACnE,GAAG,CAAA,CAAE;AAKL,QAAM,QAAQA,MAAAA,YAAY,MAAM;AAC9B,aAAS,EAAE,GAAG,eAAe,GAAG,cAAc;AAAA,EAChD,GAAG,CAAC,YAAY,CAAC;AAKjB,QAAM,SAASA,MAAAA,YAAY,MAAM;AAC/B,aAAS,CAAC,UAAU,EAAE,GAAG,MAAM,WAAW,CAAC,KAAK,UAAA,EAAY;AAAA,EAC9D,GAAG,CAAA,CAAE;AAEL,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;;;"}
package/dist/react.mjs ADDED
@@ -0,0 +1,79 @@
1
+ import { useRef, useEffect, useState, useCallback } from "react";
2
+ import { P as PluginControl } from "./PluginControl-CwImH8Ra.js";
3
+ function PluginControlReact({
4
+ map,
5
+ onStateChange,
6
+ ...options
7
+ }) {
8
+ const controlRef = useRef(null);
9
+ useEffect(() => {
10
+ if (!map) return;
11
+ const control = new PluginControl(options);
12
+ controlRef.current = control;
13
+ if (onStateChange) {
14
+ control.on("statechange", (event) => {
15
+ onStateChange(event.state);
16
+ });
17
+ }
18
+ map.addControl(control, options.position || "top-right");
19
+ return () => {
20
+ if (map.hasControl(control)) {
21
+ map.removeControl(control);
22
+ }
23
+ controlRef.current = null;
24
+ };
25
+ }, [map]);
26
+ useEffect(() => {
27
+ if (controlRef.current) {
28
+ const currentState = controlRef.current.getState();
29
+ if (options.collapsed !== void 0 && options.collapsed !== currentState.collapsed) {
30
+ if (options.collapsed) {
31
+ controlRef.current.collapse();
32
+ } else {
33
+ controlRef.current.expand();
34
+ }
35
+ }
36
+ }
37
+ }, [options.collapsed]);
38
+ return null;
39
+ }
40
+ const DEFAULT_STATE = {
41
+ collapsed: true,
42
+ panelWidth: 300,
43
+ data: {}
44
+ };
45
+ function usePluginState(initialState) {
46
+ const [state, setState] = useState({
47
+ ...DEFAULT_STATE,
48
+ ...initialState
49
+ });
50
+ const setCollapsed = useCallback((collapsed) => {
51
+ setState((prev) => ({ ...prev, collapsed }));
52
+ }, []);
53
+ const setPanelWidth = useCallback((panelWidth) => {
54
+ setState((prev) => ({ ...prev, panelWidth }));
55
+ }, []);
56
+ const setData = useCallback((data) => {
57
+ setState((prev) => ({ ...prev, data: { ...prev.data, ...data } }));
58
+ }, []);
59
+ const reset = useCallback(() => {
60
+ setState({ ...DEFAULT_STATE, ...initialState });
61
+ }, [initialState]);
62
+ const toggle = useCallback(() => {
63
+ setState((prev) => ({ ...prev, collapsed: !prev.collapsed }));
64
+ }, []);
65
+ return {
66
+ state,
67
+ setState,
68
+ setCollapsed,
69
+ setPanelWidth,
70
+ setData,
71
+ reset,
72
+ toggle
73
+ };
74
+ }
75
+ export {
76
+ PluginControlReact,
77
+ usePluginState
78
+ };
79
+ //# sourceMappingURL=react.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.mjs","sources":["../src/lib/core/PluginControlReact.tsx","../src/lib/hooks/usePluginState.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport { PluginControl } from './PluginControl';\nimport type { PluginControlReactProps } from './types';\n\n/**\n * React wrapper component for PluginControl.\n *\n * This component manages the lifecycle of a PluginControl instance,\n * adding it to the map on mount and removing it on unmount.\n *\n * @example\n * ```tsx\n * import { PluginControlReact } from 'maplibre-gl-plugin-template/react';\n *\n * function MyMap() {\n * const [map, setMap] = useState<Map | null>(null);\n *\n * return (\n * <>\n * <div ref={mapContainer} />\n * {map && (\n * <PluginControlReact\n * map={map}\n * title=\"My Control\"\n * collapsed={false}\n * />\n * )}\n * </>\n * );\n * }\n * ```\n *\n * @param props - Component props including map instance and control options\n * @returns null - This component renders nothing directly\n */\nexport function PluginControlReact({\n map,\n onStateChange,\n ...options\n}: PluginControlReactProps): null {\n const controlRef = useRef<PluginControl | null>(null);\n\n useEffect(() => {\n if (!map) return;\n\n // Create the control instance\n const control = new PluginControl(options);\n controlRef.current = control;\n\n // Register state change handler if provided\n if (onStateChange) {\n control.on('statechange', (event) => {\n onStateChange(event.state);\n });\n }\n\n // Add control to map\n map.addControl(control, options.position || 'top-right');\n\n // Cleanup on unmount\n return () => {\n if (map.hasControl(control)) {\n map.removeControl(control);\n }\n controlRef.current = null;\n };\n }, [map]);\n\n // Update options when they change\n useEffect(() => {\n if (controlRef.current) {\n // Handle collapsed state changes\n const currentState = controlRef.current.getState();\n if (options.collapsed !== undefined && options.collapsed !== currentState.collapsed) {\n if (options.collapsed) {\n controlRef.current.collapse();\n } else {\n controlRef.current.expand();\n }\n }\n }\n }, [options.collapsed]);\n\n return null;\n}\n","import { useState, useCallback } from 'react';\nimport type { PluginState } from '../core/types';\n\n/**\n * Default initial state for the plugin\n */\nconst DEFAULT_STATE: PluginState = {\n collapsed: true,\n panelWidth: 300,\n data: {},\n};\n\n/**\n * Custom hook for managing plugin state in React applications.\n *\n * This hook provides a simple way to track and update the state\n * of a PluginControl from React components.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { state, setCollapsed, setData, reset } = usePluginState();\n *\n * return (\n * <div>\n * <button onClick={() => setCollapsed(!state.collapsed)}>\n * {state.collapsed ? 'Expand' : 'Collapse'}\n * </button>\n * <PluginControlReact\n * map={map}\n * collapsed={state.collapsed}\n * onStateChange={(newState) => setState(newState)}\n * />\n * </div>\n * );\n * }\n * ```\n *\n * @param initialState - Optional initial state values\n * @returns Object containing state and update functions\n */\nexport function usePluginState(initialState?: Partial<PluginState>) {\n const [state, setState] = useState<PluginState>({\n ...DEFAULT_STATE,\n ...initialState,\n });\n\n /**\n * Sets the collapsed state\n */\n const setCollapsed = useCallback((collapsed: boolean) => {\n setState((prev) => ({ ...prev, collapsed }));\n }, []);\n\n /**\n * Sets the panel width\n */\n const setPanelWidth = useCallback((panelWidth: number) => {\n setState((prev) => ({ ...prev, panelWidth }));\n }, []);\n\n /**\n * Sets custom data in the state\n */\n const setData = useCallback((data: Record<string, unknown>) => {\n setState((prev) => ({ ...prev, data: { ...prev.data, ...data } }));\n }, []);\n\n /**\n * Resets the state to default values\n */\n const reset = useCallback(() => {\n setState({ ...DEFAULT_STATE, ...initialState });\n }, [initialState]);\n\n /**\n * Toggles the collapsed state\n */\n const toggle = useCallback(() => {\n setState((prev) => ({ ...prev, collapsed: !prev.collapsed }));\n }, []);\n\n return {\n state,\n setState,\n setCollapsed,\n setPanelWidth,\n setData,\n reset,\n toggle,\n };\n}\n"],"names":[],"mappings":";;AAmCO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAkC;AAChC,QAAM,aAAa,OAA6B,IAAI;AAEpD,YAAU,MAAM;AACd,QAAI,CAAC,IAAK;AAGV,UAAM,UAAU,IAAI,cAAc,OAAO;AACzC,eAAW,UAAU;AAGrB,QAAI,eAAe;AACjB,cAAQ,GAAG,eAAe,CAAC,UAAU;AACnC,sBAAc,MAAM,KAAK;AAAA,MAC3B,CAAC;AAAA,IACH;AAGA,QAAI,WAAW,SAAS,QAAQ,YAAY,WAAW;AAGvD,WAAO,MAAM;AACX,UAAI,IAAI,WAAW,OAAO,GAAG;AAC3B,YAAI,cAAc,OAAO;AAAA,MAC3B;AACA,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAGR,YAAU,MAAM;AACd,QAAI,WAAW,SAAS;AAEtB,YAAM,eAAe,WAAW,QAAQ,SAAA;AACxC,UAAI,QAAQ,cAAc,UAAa,QAAQ,cAAc,aAAa,WAAW;AACnF,YAAI,QAAQ,WAAW;AACrB,qBAAW,QAAQ,SAAA;AAAA,QACrB,OAAO;AACL,qBAAW,QAAQ,OAAA;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,QAAQ,SAAS,CAAC;AAEtB,SAAO;AACT;AC9EA,MAAM,gBAA6B;AAAA,EACjC,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,MAAM,CAAA;AACR;AA+BO,SAAS,eAAe,cAAqC;AAClE,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAsB;AAAA,IAC9C,GAAG;AAAA,IACH,GAAG;AAAA,EAAA,CACJ;AAKD,QAAM,eAAe,YAAY,CAAC,cAAuB;AACvD,aAAS,CAAC,UAAU,EAAE,GAAG,MAAM,YAAY;AAAA,EAC7C,GAAG,CAAA,CAAE;AAKL,QAAM,gBAAgB,YAAY,CAAC,eAAuB;AACxD,aAAS,CAAC,UAAU,EAAE,GAAG,MAAM,aAAa;AAAA,EAC9C,GAAG,CAAA,CAAE;AAKL,QAAM,UAAU,YAAY,CAAC,SAAkC;AAC7D,aAAS,CAAC,UAAU,EAAE,GAAG,MAAM,MAAM,EAAE,GAAG,KAAK,MAAM,GAAG,KAAA,IAAS;AAAA,EACnE,GAAG,CAAA,CAAE;AAKL,QAAM,QAAQ,YAAY,MAAM;AAC9B,aAAS,EAAE,GAAG,eAAe,GAAG,cAAc;AAAA,EAChD,GAAG,CAAC,YAAY,CAAC;AAKjB,QAAM,SAAS,YAAY,MAAM;AAC/B,aAAS,CAAC,UAAU,EAAE,GAAG,MAAM,WAAW,CAAC,KAAK,UAAA,EAAY;AAAA,EAC9D,GAAG,CAAA,CAAE;AAEL,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;"}
@@ -0,0 +1,4 @@
1
+ export { PluginControl } from './lib/core/PluginControl';
2
+ export type { PluginControlOptions, PluginState, PluginControlEvent, PluginControlEventHandler, } from './lib/core/types';
3
+ export { clamp, formatNumericValue, generateId, debounce, throttle, classNames, } from './lib/utils';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,iCAAiC,CAAC;AAGzC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGzD,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,KAAK,EACL,kBAAkB,EAClB,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,UAAU,GACX,MAAM,aAAa,CAAC"}
@@ -0,0 +1,113 @@
1
+ import { IControl, Map as MapLibreMap } from 'maplibre-gl';
2
+ import { PluginControlOptions, PluginState, PluginControlEvent, PluginControlEventHandler } from './types';
3
+ /**
4
+ * A template MapLibre GL control that can be customized for various plugin needs.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * const control = new PluginControl({
9
+ * title: 'My Custom Control',
10
+ * collapsed: false,
11
+ * panelWidth: 320,
12
+ * });
13
+ * map.addControl(control, 'top-right');
14
+ * ```
15
+ */
16
+ export declare class PluginControl implements IControl {
17
+ private _map?;
18
+ private _container?;
19
+ private _panel?;
20
+ private _options;
21
+ private _state;
22
+ private _eventHandlers;
23
+ /**
24
+ * Creates a new PluginControl instance.
25
+ *
26
+ * @param options - Configuration options for the control
27
+ */
28
+ constructor(options?: Partial<PluginControlOptions>);
29
+ /**
30
+ * Called when the control is added to the map.
31
+ * Implements the IControl interface.
32
+ *
33
+ * @param map - The MapLibre GL map instance
34
+ * @returns The control's container element
35
+ */
36
+ onAdd(map: MapLibreMap): HTMLElement;
37
+ /**
38
+ * Called when the control is removed from the map.
39
+ * Implements the IControl interface.
40
+ */
41
+ onRemove(): void;
42
+ /**
43
+ * Gets the current state of the control.
44
+ *
45
+ * @returns The current plugin state
46
+ */
47
+ getState(): PluginState;
48
+ /**
49
+ * Updates the control state.
50
+ *
51
+ * @param newState - Partial state to merge with current state
52
+ */
53
+ setState(newState: Partial<PluginState>): void;
54
+ /**
55
+ * Toggles the collapsed state of the control panel.
56
+ */
57
+ toggle(): void;
58
+ /**
59
+ * Expands the control panel.
60
+ */
61
+ expand(): void;
62
+ /**
63
+ * Collapses the control panel.
64
+ */
65
+ collapse(): void;
66
+ /**
67
+ * Registers an event handler.
68
+ *
69
+ * @param event - The event type to listen for
70
+ * @param handler - The callback function
71
+ */
72
+ on(event: PluginControlEvent, handler: PluginControlEventHandler): void;
73
+ /**
74
+ * Removes an event handler.
75
+ *
76
+ * @param event - The event type
77
+ * @param handler - The callback function to remove
78
+ */
79
+ off(event: PluginControlEvent, handler: PluginControlEventHandler): void;
80
+ /**
81
+ * Gets the map instance.
82
+ *
83
+ * @returns The MapLibre GL map instance or undefined if not added to a map
84
+ */
85
+ getMap(): MapLibreMap | undefined;
86
+ /**
87
+ * Gets the control container element.
88
+ *
89
+ * @returns The container element or undefined if not added to a map
90
+ */
91
+ getContainer(): HTMLElement | undefined;
92
+ /**
93
+ * Emits an event to all registered handlers.
94
+ *
95
+ * @param event - The event type to emit
96
+ */
97
+ private _emit;
98
+ /**
99
+ * Creates the main container element for the control.
100
+ * Contains a toggle button (29x29) matching navigation control size.
101
+ *
102
+ * @returns The container element
103
+ */
104
+ private _createContainer;
105
+ /**
106
+ * Creates the panel element with header and content areas.
107
+ * Panel is positioned as a dropdown below the toggle button.
108
+ *
109
+ * @returns The panel element
110
+ */
111
+ private _createPanel;
112
+ }
113
+ //# sourceMappingURL=PluginControl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PluginControl.d.ts","sourceRoot":"","sources":["../../../../src/lib/core/PluginControl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,WAAW,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,KAAK,EACV,oBAAoB,EACpB,WAAW,EACX,kBAAkB,EAClB,yBAAyB,EAC1B,MAAM,SAAS,CAAC;AAkBjB;;;;;;;;;;;;GAYG;AACH,qBAAa,aAAc,YAAW,QAAQ;IAC5C,OAAO,CAAC,IAAI,CAAC,CAAc;IAC3B,OAAO,CAAC,UAAU,CAAC,CAAc;IACjC,OAAO,CAAC,MAAM,CAAC,CAAc;IAC7B,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,cAAc,CAA0C;IAEhE;;;;OAIG;gBACS,OAAO,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC;IASnD;;;;;;OAMG;IACH,KAAK,CAAC,GAAG,EAAE,WAAW,GAAG,WAAW;IAcpC;;;OAGG;IACH,QAAQ,IAAI,IAAI;IAQhB;;;;OAIG;IACH,QAAQ,IAAI,WAAW;IAIvB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI;IAK9C;;OAEG;IACH,MAAM,IAAI,IAAI;IAgBd;;OAEG;IACH,MAAM,IAAI,IAAI;IAMd;;OAEG;IACH,QAAQ,IAAI,IAAI;IAMhB;;;;;OAKG;IACH,EAAE,CAAC,KAAK,EAAE,kBAAkB,EAAE,OAAO,EAAE,yBAAyB,GAAG,IAAI;IAOvE;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,kBAAkB,EAAE,OAAO,EAAE,yBAAyB,GAAG,IAAI;IAIxE;;;;OAIG;IACH,MAAM,IAAI,WAAW,GAAG,SAAS;IAIjC;;;;OAIG;IACH,YAAY,IAAI,WAAW,GAAG,SAAS;IAIvC;;;;OAIG;IACH,OAAO,CAAC,KAAK;IAQb;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IA4BxB;;;;;OAKG;IACH,OAAO,CAAC,YAAY;CAqCrB"}
@@ -0,0 +1,34 @@
1
+ import { PluginControlReactProps } from './types';
2
+ /**
3
+ * React wrapper component for PluginControl.
4
+ *
5
+ * This component manages the lifecycle of a PluginControl instance,
6
+ * adding it to the map on mount and removing it on unmount.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * import { PluginControlReact } from 'maplibre-gl-plugin-template/react';
11
+ *
12
+ * function MyMap() {
13
+ * const [map, setMap] = useState<Map | null>(null);
14
+ *
15
+ * return (
16
+ * <>
17
+ * <div ref={mapContainer} />
18
+ * {map && (
19
+ * <PluginControlReact
20
+ * map={map}
21
+ * title="My Control"
22
+ * collapsed={false}
23
+ * />
24
+ * )}
25
+ * </>
26
+ * );
27
+ * }
28
+ * ```
29
+ *
30
+ * @param props - Component props including map instance and control options
31
+ * @returns null - This component renders nothing directly
32
+ */
33
+ export declare function PluginControlReact({ map, onStateChange, ...options }: PluginControlReactProps): null;
34
+ //# sourceMappingURL=PluginControlReact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PluginControlReact.d.ts","sourceRoot":"","sources":["../../../../src/lib/core/PluginControlReact.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,GAAG,EACH,aAAa,EACb,GAAG,OAAO,EACX,EAAE,uBAAuB,GAAG,IAAI,CA6ChC"}
@@ -0,0 +1,72 @@
1
+ import { Map } from 'maplibre-gl';
2
+ /**
3
+ * Options for configuring the PluginControl
4
+ */
5
+ export interface PluginControlOptions {
6
+ /**
7
+ * Whether the control panel should start collapsed (showing only the toggle button)
8
+ * @default true
9
+ */
10
+ collapsed?: boolean;
11
+ /**
12
+ * Position of the control on the map
13
+ * @default 'top-right'
14
+ */
15
+ position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
16
+ /**
17
+ * Title displayed in the control header
18
+ * @default 'Plugin Control'
19
+ */
20
+ title?: string;
21
+ /**
22
+ * Width of the control panel in pixels
23
+ * @default 300
24
+ */
25
+ panelWidth?: number;
26
+ /**
27
+ * Custom CSS class name for the control container
28
+ */
29
+ className?: string;
30
+ }
31
+ /**
32
+ * Internal state of the plugin control
33
+ */
34
+ export interface PluginState {
35
+ /**
36
+ * Whether the control panel is currently collapsed
37
+ */
38
+ collapsed: boolean;
39
+ /**
40
+ * Current panel width in pixels
41
+ */
42
+ panelWidth: number;
43
+ /**
44
+ * Any custom state data
45
+ */
46
+ data?: Record<string, unknown>;
47
+ }
48
+ /**
49
+ * Props for the React wrapper component
50
+ */
51
+ export interface PluginControlReactProps extends PluginControlOptions {
52
+ /**
53
+ * MapLibre GL map instance
54
+ */
55
+ map: Map;
56
+ /**
57
+ * Callback fired when the control state changes
58
+ */
59
+ onStateChange?: (state: PluginState) => void;
60
+ }
61
+ /**
62
+ * Event types emitted by the plugin control
63
+ */
64
+ export type PluginControlEvent = 'collapse' | 'expand' | 'statechange';
65
+ /**
66
+ * Event handler function type
67
+ */
68
+ export type PluginControlEventHandler = (event: {
69
+ type: PluginControlEvent;
70
+ state: PluginState;
71
+ }) => void;
72
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/lib/core/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAEvC;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,UAAU,GAAG,WAAW,GAAG,aAAa,GAAG,cAAc,CAAC;IAErE;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,oBAAoB;IACnE;;OAEG;IACH,GAAG,EAAE,GAAG,CAAC;IAET;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;CAC9C;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,QAAQ,GAAG,aAAa,CAAC;AAEvE;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,KAAK,IAAI,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { usePluginState } from './usePluginState';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { PluginState } from '../core/types';
2
+ /**
3
+ * Custom hook for managing plugin state in React applications.
4
+ *
5
+ * This hook provides a simple way to track and update the state
6
+ * of a PluginControl from React components.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * function MyComponent() {
11
+ * const { state, setCollapsed, setData, reset } = usePluginState();
12
+ *
13
+ * return (
14
+ * <div>
15
+ * <button onClick={() => setCollapsed(!state.collapsed)}>
16
+ * {state.collapsed ? 'Expand' : 'Collapse'}
17
+ * </button>
18
+ * <PluginControlReact
19
+ * map={map}
20
+ * collapsed={state.collapsed}
21
+ * onStateChange={(newState) => setState(newState)}
22
+ * />
23
+ * </div>
24
+ * );
25
+ * }
26
+ * ```
27
+ *
28
+ * @param initialState - Optional initial state values
29
+ * @returns Object containing state and update functions
30
+ */
31
+ export declare function usePluginState(initialState?: Partial<PluginState>): {
32
+ state: PluginState;
33
+ setState: import('react').Dispatch<import('react').SetStateAction<PluginState>>;
34
+ setCollapsed: (collapsed: boolean) => void;
35
+ setPanelWidth: (panelWidth: number) => void;
36
+ setData: (data: Record<string, unknown>) => void;
37
+ reset: () => void;
38
+ toggle: () => void;
39
+ };
40
+ //# sourceMappingURL=usePluginState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePluginState.d.ts","sourceRoot":"","sources":["../../../../src/lib/hooks/usePluginState.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAWjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,cAAc,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC;;;8BASnB,OAAO;gCAOL,MAAM;oBAOlB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;EA2B3D"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Clamps a value between a minimum and maximum.
3
+ *
4
+ * @param value - The value to clamp
5
+ * @param min - The minimum allowed value
6
+ * @param max - The maximum allowed value
7
+ * @returns The clamped value
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * clamp(5, 0, 10); // returns 5
12
+ * clamp(-5, 0, 10); // returns 0
13
+ * clamp(15, 0, 10); // returns 10
14
+ * ```
15
+ */
16
+ export declare function clamp(value: number, min: number, max: number): number;
17
+ /**
18
+ * Formats a numeric value with appropriate decimal places based on step size.
19
+ *
20
+ * @param value - The value to format
21
+ * @param step - The step size to determine decimal places
22
+ * @returns The formatted value as a string
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * formatNumericValue(5, 1); // returns "5"
27
+ * formatNumericValue(0.5, 0.1); // returns "0.5"
28
+ * formatNumericValue(0.55, 0.01); // returns "0.55"
29
+ * ```
30
+ */
31
+ export declare function formatNumericValue(value: number, step: number): string;
32
+ /**
33
+ * Generates a unique ID string.
34
+ *
35
+ * @param prefix - Optional prefix for the ID
36
+ * @returns A unique ID string
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * generateId('control'); // returns "control-abc123"
41
+ * generateId(); // returns "abc123"
42
+ * ```
43
+ */
44
+ export declare function generateId(prefix?: string): string;
45
+ /**
46
+ * Debounces a function call.
47
+ *
48
+ * @param fn - The function to debounce
49
+ * @param delay - The delay in milliseconds
50
+ * @returns A debounced version of the function
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const debouncedUpdate = debounce(() => updateMap(), 100);
55
+ * window.addEventListener('resize', debouncedUpdate);
56
+ * ```
57
+ */
58
+ export declare function debounce<T extends (...args: unknown[]) => void>(fn: T, delay: number): (...args: Parameters<T>) => void;
59
+ /**
60
+ * Throttles a function call.
61
+ *
62
+ * @param fn - The function to throttle
63
+ * @param limit - The minimum time between calls in milliseconds
64
+ * @returns A throttled version of the function
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * const throttledScroll = throttle(() => handleScroll(), 100);
69
+ * window.addEventListener('scroll', throttledScroll);
70
+ * ```
71
+ */
72
+ export declare function throttle<T extends (...args: unknown[]) => void>(fn: T, limit: number): (...args: Parameters<T>) => void;
73
+ /**
74
+ * Creates a CSS class string from an object of class names.
75
+ *
76
+ * @param classes - Object with class names as keys and boolean values
77
+ * @returns A space-separated string of class names
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * classNames({ active: true, disabled: false, visible: true });
82
+ * // returns "active visible"
83
+ * ```
84
+ */
85
+ export declare function classNames(classes: Record<string, boolean>): string;
86
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../src/lib/utils/helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAErE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAItE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAGlD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,EAC7D,EAAE,EAAE,CAAC,EACL,KAAK,EAAE,MAAM,GACZ,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAYlC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,EAC7D,EAAE,EAAE,CAAC,EACL,KAAK,EAAE,MAAM,GACZ,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAYlC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAKnE"}
@@ -0,0 +1,2 @@
1
+ export { clamp, formatNumericValue, generateId, debounce, throttle, classNames, } from './helpers';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,kBAAkB,EAClB,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,UAAU,GACX,MAAM,WAAW,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { PluginControlReact } from './lib/core/PluginControlReact';
2
+ export { usePluginState } from './lib/hooks';
3
+ export type { PluginControlOptions, PluginState, PluginControlReactProps, PluginControlEvent, PluginControlEventHandler, } from './lib/core/types';
4
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/react.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7C,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,uBAAuB,EACvB,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,101 @@
1
+ {
2
+ "name": "maplibre-gl-plugin-template",
3
+ "version": "0.1.0",
4
+ "description": "A template for creating MapLibre GL JS plugins with TypeScript and React support",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/types/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/types/index.d.ts",
13
+ "default": "./dist/index.mjs"
14
+ },
15
+ "require": {
16
+ "types": "./dist/types/index.d.ts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ },
20
+ "./react": {
21
+ "import": {
22
+ "types": "./dist/types/react.d.ts",
23
+ "default": "./dist/react.mjs"
24
+ },
25
+ "require": {
26
+ "types": "./dist/types/react.d.ts",
27
+ "default": "./dist/react.cjs"
28
+ }
29
+ },
30
+ "./style.css": "./dist/maplibre-gl-plugin-template.css"
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md",
35
+ "LICENSE"
36
+ ],
37
+ "sideEffects": [
38
+ "*.css"
39
+ ],
40
+ "scripts": {
41
+ "dev": "vite",
42
+ "build": "tsc -p tsconfig.build.json && vite build",
43
+ "build:examples": "vite build --config vite.examples.config.ts",
44
+ "preview": "vite preview",
45
+ "test": "vitest --run",
46
+ "test:ui": "vitest --ui",
47
+ "test:coverage": "vitest --coverage",
48
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
49
+ "format": "prettier --write \"src/**/*.{ts,tsx,css}\"",
50
+ "prepublishOnly": "npm run build"
51
+ },
52
+ "keywords": [
53
+ "maplibre",
54
+ "maplibre-gl",
55
+ "map",
56
+ "plugin",
57
+ "control",
58
+ "react",
59
+ "typescript"
60
+ ],
61
+ "author": "Your Name",
62
+ "license": "MIT",
63
+ "repository": {
64
+ "type": "git",
65
+ "url": "https://github.com/your-username/maplibre-gl-plugin-template.git"
66
+ },
67
+ "peerDependencies": {
68
+ "maplibre-gl": ">=3.0.0",
69
+ "react": ">=18.0.0",
70
+ "react-dom": ">=18.0.0"
71
+ },
72
+ "peerDependenciesMeta": {
73
+ "react": {
74
+ "optional": true
75
+ },
76
+ "react-dom": {
77
+ "optional": true
78
+ }
79
+ },
80
+ "devDependencies": {
81
+ "@testing-library/react": "^16.0.0",
82
+ "@testing-library/user-event": "^14.5.0",
83
+ "@types/node": "^22.0.0",
84
+ "@types/react": "^18.3.0",
85
+ "@types/react-dom": "^18.3.0",
86
+ "@typescript-eslint/eslint-plugin": "^8.18.0",
87
+ "@typescript-eslint/parser": "^8.18.0",
88
+ "@vitejs/plugin-react": "^4.3.0",
89
+ "@vitest/ui": "^2.1.0",
90
+ "eslint": "^9.17.0",
91
+ "jsdom": "^25.0.0",
92
+ "maplibre-gl": "^4.7.1",
93
+ "prettier": "^3.4.0",
94
+ "react": "^18.3.0",
95
+ "react-dom": "^18.3.0",
96
+ "typescript": "^5.7.0",
97
+ "vite": "^6.0.0",
98
+ "vite-plugin-dts": "^4.3.0",
99
+ "vitest": "^2.1.0"
100
+ }
101
+ }