@page-speed/maps 0.1.4 → 0.1.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.
Files changed (46) hide show
  1. package/README.md +120 -0
  2. package/dist/components/geo-map.cjs +1237 -0
  3. package/dist/components/geo-map.cjs.map +1 -0
  4. package/dist/components/geo-map.d.cts +138 -0
  5. package/dist/components/geo-map.d.ts +138 -0
  6. package/dist/components/geo-map.js +1216 -0
  7. package/dist/components/geo-map.js.map +1 -0
  8. package/dist/components/index.cjs +1359 -0
  9. package/dist/components/index.cjs.map +1 -0
  10. package/dist/components/index.d.cts +5 -0
  11. package/dist/components/index.d.ts +5 -0
  12. package/dist/components/index.js +1335 -0
  13. package/dist/components/index.js.map +1 -0
  14. package/dist/components/map-marker.cjs +137 -0
  15. package/dist/components/map-marker.cjs.map +1 -0
  16. package/dist/components/map-marker.d.cts +76 -0
  17. package/dist/components/map-marker.d.ts +76 -0
  18. package/dist/components/map-marker.js +130 -0
  19. package/dist/components/map-marker.js.map +1 -0
  20. package/dist/index.cjs +929 -21
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +2 -0
  23. package/dist/index.d.ts +2 -0
  24. package/dist/index.js +910 -21
  25. package/dist/index.js.map +1 -1
  26. package/dist/types/index.d.cts +5 -5
  27. package/dist/types/index.d.ts +5 -5
  28. package/dist/utils/cn.cjs +13 -0
  29. package/dist/utils/cn.cjs.map +1 -0
  30. package/dist/utils/cn.d.cts +16 -0
  31. package/dist/utils/cn.d.ts +16 -0
  32. package/dist/utils/cn.js +11 -0
  33. package/dist/utils/cn.js.map +1 -0
  34. package/dist/utils/index.cjs +63 -0
  35. package/dist/utils/index.cjs.map +1 -1
  36. package/dist/utils/index.d.cts +4 -0
  37. package/dist/utils/index.d.ts +4 -0
  38. package/dist/utils/index.js +42 -1
  39. package/dist/utils/index.js.map +1 -1
  40. package/dist/utils/simple-pressable.cjs +63 -0
  41. package/dist/utils/simple-pressable.cjs.map +1 -0
  42. package/dist/utils/simple-pressable.d.cts +20 -0
  43. package/dist/utils/simple-pressable.d.ts +20 -0
  44. package/dist/utils/simple-pressable.js +41 -0
  45. package/dist/utils/simple-pressable.js.map +1 -0
  46. package/package.json +29 -2
@@ -0,0 +1,130 @@
1
+ import { clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+
5
+ // src/utils/cn.ts
6
+ function cn(...inputs) {
7
+ return twMerge(clsx(inputs));
8
+ }
9
+ var SIZE_CONFIG = {
10
+ sm: {
11
+ outer: "size-10",
12
+ middle: "size-7",
13
+ inner: "size-5",
14
+ dot: "size-2"
15
+ },
16
+ md: {
17
+ outer: "size-14",
18
+ middle: "size-10",
19
+ inner: "size-7",
20
+ dot: "size-2.5"
21
+ },
22
+ lg: {
23
+ outer: "size-20",
24
+ middle: "size-14",
25
+ inner: "size-10",
26
+ dot: "size-3.5"
27
+ }
28
+ };
29
+ function MapMarker({
30
+ size = "md",
31
+ isSelected = false,
32
+ dotColor,
33
+ innerRingColor,
34
+ middleRingColor,
35
+ outerRingColor,
36
+ className,
37
+ onClick,
38
+ interactive = true,
39
+ "aria-label": ariaLabel = "Map location marker"
40
+ }) {
41
+ const sizeConfig = SIZE_CONFIG[size];
42
+ const content = /* @__PURE__ */ jsxs(
43
+ "div",
44
+ {
45
+ className: cn(
46
+ "relative flex items-center justify-center rounded-full transition-transform duration-200",
47
+ sizeConfig.outer,
48
+ isSelected && "scale-110",
49
+ className
50
+ ),
51
+ style: { backgroundColor: outerRingColor },
52
+ children: [
53
+ /* @__PURE__ */ jsx(
54
+ "div",
55
+ {
56
+ className: cn(
57
+ "absolute rounded-full transition-all duration-200",
58
+ sizeConfig.middle
59
+ ),
60
+ style: { backgroundColor: middleRingColor }
61
+ }
62
+ ),
63
+ /* @__PURE__ */ jsx(
64
+ "div",
65
+ {
66
+ className: cn(
67
+ "absolute rounded-full transition-all duration-200",
68
+ sizeConfig.inner
69
+ ),
70
+ style: { backgroundColor: innerRingColor }
71
+ }
72
+ ),
73
+ /* @__PURE__ */ jsx(
74
+ "div",
75
+ {
76
+ className: cn(
77
+ "absolute rounded-full transition-all duration-200",
78
+ sizeConfig.dot
79
+ ),
80
+ style: { backgroundColor: dotColor }
81
+ }
82
+ )
83
+ ]
84
+ }
85
+ );
86
+ if (!interactive) {
87
+ return content;
88
+ }
89
+ return /* @__PURE__ */ jsx(
90
+ "button",
91
+ {
92
+ type: "button",
93
+ className: "group cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-full",
94
+ onClick,
95
+ "aria-label": ariaLabel,
96
+ children: /* @__PURE__ */ jsx(
97
+ "div",
98
+ {
99
+ className: cn(
100
+ "transition-transform duration-200 group-hover:scale-110",
101
+ isSelected && "scale-110"
102
+ ),
103
+ children: content
104
+ }
105
+ )
106
+ }
107
+ );
108
+ }
109
+ function NeutralMapMarker(props) {
110
+ return /* @__PURE__ */ jsx(
111
+ MapMarker,
112
+ {
113
+ ...props,
114
+ dotColor: "hsl(var(--neutral-900, 0 0% 9%))",
115
+ innerRingColor: "hsl(var(--neutral-400, 0 0% 64%))",
116
+ middleRingColor: "hsl(var(--neutral-300, 0 0% 78%))",
117
+ outerRingColor: "hsl(var(--neutral-200, 0 0% 88%))"
118
+ }
119
+ );
120
+ }
121
+ function createMapMarkerElement(config) {
122
+ return function MarkerElement({ isSelected }) {
123
+ return /* @__PURE__ */ jsx(MapMarker, { ...config, isSelected, interactive: false });
124
+ };
125
+ }
126
+ var map_marker_default = MapMarker;
127
+
128
+ export { MapMarker, NeutralMapMarker, createMapMarkerElement, map_marker_default as default };
129
+ //# sourceMappingURL=map-marker.js.map
130
+ //# sourceMappingURL=map-marker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/cn.ts","../../src/components/map-marker.tsx"],"names":[],"mappings":"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","file":"map-marker.js","sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Utility function to merge Tailwind CSS classes with proper conflict resolution.\n * Uses clsx for conditional class names and tailwind-merge for deduplication.\n *\n * @param inputs - Class names to merge\n * @returns Merged class string\n *\n * @example\n * cn(\"px-2 py-1\", \"px-4\") // => \"py-1 px-4\"\n * cn(\"text-red-500\", condition && \"text-blue-500\") // => \"text-blue-500\" (if condition is true)\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport type MapMarkerSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface MapMarkerProps {\n /** Size variant of the marker */\n size?: MapMarkerSize;\n /** Whether the marker is currently selected/active */\n isSelected?: boolean;\n /** Custom color for the center dot (defaults to neutral-900) */\n dotColor?: string;\n /** Custom color for the inner ring (defaults to neutral-400) */\n innerRingColor?: string;\n /** Custom color for the middle ring (defaults to neutral-300) */\n middleRingColor?: string;\n /** Custom color for the outer ring (defaults to neutral-200) */\n outerRingColor?: string;\n /** Additional class name for the wrapper */\n className?: string;\n /** Click handler for the marker */\n onClick?: (event: React.MouseEvent) => void;\n /** Whether the marker is interactive/clickable */\n interactive?: boolean;\n /** Accessible label for the marker */\n \"aria-label\"?: string;\n}\n\nconst SIZE_CONFIG: Record<\n MapMarkerSize,\n {\n outer: string;\n middle: string;\n inner: string;\n dot: string;\n }\n> = {\n sm: {\n outer: \"size-10\",\n middle: \"size-7\",\n inner: \"size-5\",\n dot: \"size-2\",\n },\n md: {\n outer: \"size-14\",\n middle: \"size-10\",\n inner: \"size-7\",\n dot: \"size-2.5\",\n },\n lg: {\n outer: \"size-20\",\n middle: \"size-14\",\n inner: \"size-10\",\n dot: \"size-3.5\",\n },\n};\n\n/**\n * A reusable map marker component with concentric circle design.\n * Can be used directly with MapLibre markers via the `element` prop.\n *\n * @example\n * // Basic usage\n * <MapMarker />\n *\n * @example\n * // With MapLibre GeoMap\n * const markers = [{\n * id: 'location-1',\n * latitude: 40.7128,\n * longitude: -74.0060,\n * markerElement: ({ isSelected }) => (\n * <MapMarker isSelected={isSelected} size=\"md\" />\n * ),\n * }];\n *\n * @example\n * // Custom colors\n * <MapMarker\n * dotColor=\"#1E40AF\"\n * innerRingColor=\"#3B82F6\"\n * middleRingColor=\"#93C5FD\"\n * outerRingColor=\"#DBEAFE\"\n * />\n */\nexport function MapMarker({\n size = \"md\",\n isSelected = false,\n dotColor,\n innerRingColor,\n middleRingColor,\n outerRingColor,\n className,\n onClick,\n interactive = true,\n \"aria-label\": ariaLabel = \"Map location marker\",\n}: MapMarkerProps) {\n const sizeConfig = SIZE_CONFIG[size];\n\n const content = (\n <div\n className={cn(\n \"relative flex items-center justify-center rounded-full transition-transform duration-200\",\n sizeConfig.outer,\n isSelected && \"scale-110\",\n className\n )}\n style={{ backgroundColor: outerRingColor }}\n >\n {/* Middle ring */}\n <div\n className={cn(\n \"absolute rounded-full transition-all duration-200\",\n sizeConfig.middle\n )}\n style={{ backgroundColor: middleRingColor }}\n />\n\n {/* Inner ring */}\n <div\n className={cn(\n \"absolute rounded-full transition-all duration-200\",\n sizeConfig.inner\n )}\n style={{ backgroundColor: innerRingColor }}\n />\n\n {/* Center dot */}\n <div\n className={cn(\n \"absolute rounded-full transition-all duration-200\",\n sizeConfig.dot\n )}\n style={{ backgroundColor: dotColor }}\n />\n </div>\n );\n\n if (!interactive) {\n return content;\n }\n\n return (\n <button\n type=\"button\"\n className=\"group cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-full\"\n onClick={onClick}\n aria-label={ariaLabel}\n >\n <div\n className={cn(\n \"transition-transform duration-200 group-hover:scale-110\",\n isSelected && \"scale-110\"\n )}\n >\n {content}\n </div>\n </button>\n );\n}\n\n/**\n * Pre-configured marker with neutral gray colors matching the reference design.\n */\nexport function NeutralMapMarker(\n props: Omit<\n MapMarkerProps,\n \"dotColor\" | \"innerRingColor\" | \"middleRingColor\" | \"outerRingColor\"\n >\n) {\n return (\n <MapMarker\n {...props}\n dotColor=\"hsl(var(--neutral-900, 0 0% 9%))\"\n innerRingColor=\"hsl(var(--neutral-400, 0 0% 64%))\"\n middleRingColor=\"hsl(var(--neutral-300, 0 0% 78%))\"\n outerRingColor=\"hsl(var(--neutral-200, 0 0% 88%))\"\n />\n );\n}\n\n/**\n * Factory function to create a marker element for use with MapLibre/GeoMap.\n * Returns a function compatible with the `markerElement` prop.\n *\n * @example\n * const markers = [{\n * id: 'location-1',\n * latitude: 40.7128,\n * longitude: -74.0060,\n * markerElement: createMapMarkerElement({ size: 'lg' }),\n * }];\n */\nexport function createMapMarkerElement(\n config?: Omit<MapMarkerProps, \"isSelected\" | \"onClick\">\n) {\n return function MarkerElement({ isSelected }: { isSelected: boolean }) {\n return <MapMarker {...config} isSelected={isSelected} interactive={false} />;\n };\n}\n\nexport default MapMarker;\n"]}