@carto/ps-react-ui 4.4.2 → 4.5.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.
Files changed (157) hide show
  1. package/dist/download-config-DemuQ3Jm.js +56 -0
  2. package/dist/download-config-DemuQ3Jm.js.map +1 -0
  3. package/dist/error-Cj8eUMrl.js +40 -0
  4. package/dist/error-Cj8eUMrl.js.map +1 -0
  5. package/dist/formatter-B9Bxn1k7.js +6 -0
  6. package/dist/formatter-B9Bxn1k7.js.map +1 -0
  7. package/dist/no-data-DkIt7Qt1.js +61 -0
  8. package/dist/no-data-DkIt7Qt1.js.map +1 -0
  9. package/dist/row-D4VOhcNI.js +34 -0
  10. package/dist/row-D4VOhcNI.js.map +1 -0
  11. package/dist/series-Bola3CmD.js +90 -0
  12. package/dist/series-Bola3CmD.js.map +1 -0
  13. package/dist/styles-Y8q7Jff3.js +118 -0
  14. package/dist/styles-Y8q7Jff3.js.map +1 -0
  15. package/dist/types/widgets/actions/brush-toggle/types.d.ts +8 -2
  16. package/dist/types/widgets/category/components/category-row-multi.d.ts +2 -1
  17. package/dist/types/widgets/category/components/category-row-single.d.ts +2 -1
  18. package/dist/types/widgets/category/types.d.ts +1 -0
  19. package/dist/types/widgets/echart/shared-resize-observer.d.ts +12 -0
  20. package/dist/types/widgets/echart/types.d.ts +2 -0
  21. package/dist/types/widgets/histogram/config.d.ts +15 -3
  22. package/dist/types/widgets/histogram/index.d.ts +2 -1
  23. package/dist/types/widgets/histogram/types.d.ts +6 -3
  24. package/dist/types/widgets/stores/index.d.ts +2 -1
  25. package/dist/types/widgets/stores/types.d.ts +2 -0
  26. package/dist/types/widgets/stores/use-widget-selector.d.ts +35 -0
  27. package/dist/types/widgets/stores/widget-store-performance.test.d.ts +1 -0
  28. package/dist/types/widgets/stores/widget-store.d.ts +49 -27
  29. package/dist/types/widgets/table/types.d.ts +1 -1
  30. package/dist/types/widgets/utils/chart-config/index.d.ts +1 -1
  31. package/dist/types/widgets/utils/chart-config/option-builders.d.ts +13 -8
  32. package/dist/types/widgets/utils/formatter.d.ts +1 -0
  33. package/dist/types/widgets/utils/index.d.ts +1 -1
  34. package/dist/use-widget-ref-BFazQvJK.js +22 -0
  35. package/dist/use-widget-ref-BFazQvJK.js.map +1 -0
  36. package/dist/use-widget-selector-DqRmWQ1K.js +12 -0
  37. package/dist/use-widget-selector-DqRmWQ1K.js.map +1 -0
  38. package/dist/widget-store-CIrb9RKP.js +263 -0
  39. package/dist/widget-store-CIrb9RKP.js.map +1 -0
  40. package/dist/widgets/actions.js +799 -817
  41. package/dist/widgets/actions.js.map +1 -1
  42. package/dist/widgets/bar.js +53 -47
  43. package/dist/widgets/bar.js.map +1 -1
  44. package/dist/widgets/category.js +261 -255
  45. package/dist/widgets/category.js.map +1 -1
  46. package/dist/widgets/echart.js +109 -99
  47. package/dist/widgets/echart.js.map +1 -1
  48. package/dist/widgets/error.js +1 -1
  49. package/dist/widgets/formula.js +71 -63
  50. package/dist/widgets/formula.js.map +1 -1
  51. package/dist/widgets/histogram.js +119 -80
  52. package/dist/widgets/histogram.js.map +1 -1
  53. package/dist/widgets/loader.js +53 -60
  54. package/dist/widgets/loader.js.map +1 -1
  55. package/dist/widgets/markdown.js +51 -50
  56. package/dist/widgets/markdown.js.map +1 -1
  57. package/dist/widgets/no-data.js +1 -1
  58. package/dist/widgets/pie.js +111 -99
  59. package/dist/widgets/pie.js.map +1 -1
  60. package/dist/widgets/range.js +146 -144
  61. package/dist/widgets/range.js.map +1 -1
  62. package/dist/widgets/scatterplot.js +50 -44
  63. package/dist/widgets/scatterplot.js.map +1 -1
  64. package/dist/widgets/skeleton-loader.js +18 -17
  65. package/dist/widgets/skeleton-loader.js.map +1 -1
  66. package/dist/widgets/spread.js +110 -94
  67. package/dist/widgets/spread.js.map +1 -1
  68. package/dist/widgets/stores.js +5 -2
  69. package/dist/widgets/stores.js.map +1 -1
  70. package/dist/widgets/table.js +422 -436
  71. package/dist/widgets/table.js.map +1 -1
  72. package/dist/widgets/timeseries.js +52 -46
  73. package/dist/widgets/timeseries.js.map +1 -1
  74. package/dist/widgets/toolbar-actions.js +101 -6693
  75. package/dist/widgets/toolbar-actions.js.map +1 -1
  76. package/dist/widgets/utils.js +16 -14
  77. package/dist/widgets/utils.js.map +1 -1
  78. package/dist/widgets/wrapper.js +156 -158
  79. package/dist/widgets/wrapper.js.map +1 -1
  80. package/dist/widgets.js +4 -4
  81. package/package.json +5 -4
  82. package/src/hooks/use-widget-ref.ts +3 -4
  83. package/src/widgets/README.md +3 -3
  84. package/src/widgets/actions/brush-toggle/brush-toggle.tsx +60 -79
  85. package/src/widgets/actions/brush-toggle/types.ts +8 -2
  86. package/src/widgets/actions/change-column/change-column.tsx +15 -15
  87. package/src/widgets/actions/change-column/sortable-column-item.tsx +3 -1
  88. package/src/widgets/actions/download/download.tsx +4 -3
  89. package/src/widgets/actions/fullscreen/fullscreen.tsx +7 -11
  90. package/src/widgets/actions/lock-selection/lock-selection.tsx +12 -15
  91. package/src/widgets/actions/relative-data/relative-data.tsx +22 -26
  92. package/src/widgets/actions/searcher/searcher-toggle.tsx +11 -12
  93. package/src/widgets/actions/searcher/searcher.tsx +20 -21
  94. package/src/widgets/actions/stack-toggle/stack-toggle.tsx +15 -21
  95. package/src/widgets/actions/zoom-toggle/zoom-toggle.tsx +27 -43
  96. package/src/widgets/bar/config.ts +22 -14
  97. package/src/widgets/category/category-ui.tsx +31 -27
  98. package/src/widgets/category/components/category-row-multi.tsx +6 -2
  99. package/src/widgets/category/components/category-row-single.tsx +5 -1
  100. package/src/widgets/category/types.ts +1 -0
  101. package/src/widgets/echart/echart-ui.test.tsx +20 -16
  102. package/src/widgets/echart/echart-ui.tsx +6 -12
  103. package/src/widgets/echart/echart.tsx +13 -27
  104. package/src/widgets/echart/shared-resize-observer.ts +45 -0
  105. package/src/widgets/echart/types.ts +2 -0
  106. package/src/widgets/error/error.tsx +7 -9
  107. package/src/widgets/formula/components/prefix.tsx +4 -6
  108. package/src/widgets/formula/components/row.tsx +4 -4
  109. package/src/widgets/formula/components/series.tsx +4 -6
  110. package/src/widgets/formula/components/suffix.tsx +4 -6
  111. package/src/widgets/formula/components/value.tsx +9 -16
  112. package/src/widgets/histogram/config.ts +101 -20
  113. package/src/widgets/histogram/index.ts +6 -1
  114. package/src/widgets/histogram/types.ts +9 -3
  115. package/src/widgets/loader/loader.tsx +31 -44
  116. package/src/widgets/markdown/markdown.tsx +4 -7
  117. package/src/widgets/no-data/no-data.tsx +7 -10
  118. package/src/widgets/pie/config.ts +17 -5
  119. package/src/widgets/range/components/range-item.tsx +20 -18
  120. package/src/widgets/scatterplot/config.ts +8 -3
  121. package/src/widgets/skeleton-loader/skeleton-loader.tsx +2 -5
  122. package/src/widgets/spread/components/max-value.tsx +14 -16
  123. package/src/widgets/spread/components/min-value.tsx +14 -16
  124. package/src/widgets/stores/index.ts +2 -1
  125. package/src/widgets/stores/types.ts +2 -0
  126. package/src/widgets/stores/use-widget-selector.ts +47 -0
  127. package/src/widgets/stores/widget-store-performance.test.ts +750 -0
  128. package/src/widgets/stores/widget-store.test.ts +81 -0
  129. package/src/widgets/stores/widget-store.ts +225 -44
  130. package/src/widgets/table/config.ts +0 -1
  131. package/src/widgets/table/hooks/use-pagination.ts +28 -52
  132. package/src/widgets/table/hooks/use-selection.ts +20 -24
  133. package/src/widgets/table/hooks/use-sort.ts +22 -39
  134. package/src/widgets/table/types.ts +1 -1
  135. package/src/widgets/timeseries/config.ts +21 -13
  136. package/src/widgets/utils/chart-config/index.ts +1 -1
  137. package/src/widgets/utils/chart-config/option-builders.ts +22 -12
  138. package/src/widgets/utils/formatter.ts +2 -1
  139. package/src/widgets/utils/index.ts +1 -1
  140. package/src/widgets/wrapper/wrapper-ui.tsx +12 -13
  141. package/src/widgets/wrapper/wrapper.tsx +4 -6
  142. package/dist/error-CEkRPccv.js +0 -39
  143. package/dist/error-CEkRPccv.js.map +0 -1
  144. package/dist/formatter-B1Xh8XDH.js +0 -5
  145. package/dist/formatter-B1Xh8XDH.js.map +0 -1
  146. package/dist/no-data-hR3KcJ-_.js +0 -60
  147. package/dist/no-data-hR3KcJ-_.js.map +0 -1
  148. package/dist/row-DTCV0Ocm.js +0 -35
  149. package/dist/row-DTCV0Ocm.js.map +0 -1
  150. package/dist/series-CYNOu2Ju.js +0 -91
  151. package/dist/series-CYNOu2Ju.js.map +0 -1
  152. package/dist/styles-C_8vOEep.js +0 -167
  153. package/dist/styles-C_8vOEep.js.map +0 -1
  154. package/dist/use-widget-ref-wtFLDFCD.js +0 -25
  155. package/dist/use-widget-ref-wtFLDFCD.js.map +0 -1
  156. package/dist/widget-store-CzDt8oSK.js +0 -163
  157. package/dist/widget-store-CzDt8oSK.js.map +0 -1
@@ -29,6 +29,8 @@ export interface WidgetsStoreProps {
29
29
  registeredTools?: ToolRegistration[];
30
30
  /** Formatter function for widget values */
31
31
  formatter?: (value: number) => string;
32
+ /** Formatter function for widget label/category values */
33
+ labelFormatter?: (value: string | number) => string | number;
32
34
  /** Locale for number formatting (e.g., 'en-US', 'es-ES', 'fr-FR') */
33
35
  locale?: string;
34
36
  }
@@ -0,0 +1,35 @@
1
+ import { WidgetState } from './types';
2
+ /**
3
+ * Scoped selector hook for reading a single widget's state from the store.
4
+ *
5
+ * Consolidates multiple `useWidgetStore(useShallow(...))` calls into a single
6
+ * subscription per component. The selector receives only this widget's state
7
+ * (or undefined if not yet registered), and uses shallow comparison to avoid
8
+ * re-renders when unrelated properties change.
9
+ *
10
+ * @param widgetId - The widget ID to subscribe to.
11
+ * @param selector - A function that extracts the needed properties from the widget state.
12
+ * Must be a stable reference (inline arrow is fine due to useCallback wrapping).
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * // Before: 4 separate subscriptions
17
+ * const title = useWidgetStore(useShallow((s) => s.getWidget(id)?.title))
18
+ * const collapsed = useWidgetStore(useShallow((s) => s.getWidget(id)?.collapsed))
19
+ * const disabled = useWidgetStore(useShallow((s) => s.getWidget(id)?.disabled))
20
+ * const isFetching = useWidgetStore(useShallow((s) => s.getWidget(id)?.isFetching))
21
+ *
22
+ * // After: 1 subscription
23
+ * const { title, collapsed, disabled, isFetching } = useWidgetSelector(id, (w) => ({
24
+ * title: w?.title, collapsed: w?.collapsed, disabled: w?.disabled, isFetching: w?.isFetching,
25
+ * }))
26
+ *
27
+ * // With extra dependencies (e.g., index prop):
28
+ * const value = useWidgetSelector(
29
+ * id,
30
+ * (w) => (w as MyState | undefined)?.data?.[index]?.value,
31
+ * [index],
32
+ * )
33
+ * ```
34
+ */
35
+ export declare function useWidgetSelector<T>(widgetId: string, selector: (widget: WidgetState | undefined) => T): T;
@@ -1,39 +1,61 @@
1
- import { WidgetStore } from './types';
1
+ import { WidgetStore, WidgetStoreActions } from './types';
2
2
  /**
3
3
  * Zustand store for managing widget state across the application.
4
4
  *
5
- * This store provides centralized state management for all widget UI components
5
+ * Provides centralized state management for all widget UI components, including
6
+ * data/config transformation pipelines via registered tools.
6
7
  *
7
- * @example
8
+ * **Performance optimizations:**
9
+ * - `registerTool` skips the store update when structural properties (order, enabled,
10
+ * type, disables) haven't changed — only `fn` and `config` are updated via direct
11
+ * mutation, avoiding a new `registeredTools` array reference and WidgetLoader
12
+ * pipeline cascades.
13
+ * - `setToolEnabled` skips the store update when the enabled state is already the
14
+ * requested value.
15
+ * - `executeToolPipeline` / `executeConfigPipeline` skip the final `set()` when
16
+ * the transformed data/config is referentially identical to what's already in the store.
17
+ * - Both pipelines support cancellation — newer executions for the same widget
18
+ * automatically cancel in-progress ones.
19
+ *
20
+ * @example Reading widget state (prefer useWidgetSelector for performance)
8
21
  * ```tsx
9
- * // Import the store
10
- * import { useWidgetStore } from '@carto/ps-react-ui/widgets'
11
- *
12
- * // Use in a component
13
- * function MyWidget() {
14
- * const setWidget = useWidgetStore((state) => state.setWidget)
15
- * const widget = useWidgetStore((state) => state.widgets['my-widget'])
16
- *
17
- * useEffect(() => {
18
- * setWidget({
19
- * id: 'my-widget',
20
- * type: 'formula',
21
- * title: 'Total Sales',
22
- * isLoading: false,
23
- * visible: true,
24
- * data: { value: 1000, prefix: '$' }
25
- * })
26
- * }, [setWidget])
27
- *
28
- * return <div>{widget?.data?.value}</div>
22
+ * import { useWidgetSelector } from '@carto/ps-react-ui/widgets'
23
+ *
24
+ * function MyWidget({ id }: { id: string }) {
25
+ * const { title, data } = useWidgetSelector(id, (w) => ({
26
+ * title: w?.title,
27
+ * data: w?.data,
28
+ * }))
29
+ * return <div>{title}: {JSON.stringify(data)}</div>
29
30
  * }
30
31
  * ```
31
32
  *
32
- * @example
33
+ * @example Writing widget state
33
34
  * ```tsx
34
- * // Get widgets by type
35
- * const getWidgetsByType = useWidgetStore((state) => state.getWidgetsByType)
36
- * const formulaWidgets = getWidgetsByType('formula')
35
+ * import { widgetStoreActions } from '@carto/ps-react-ui/widgets'
36
+ *
37
+ * const { setWidget } = widgetStoreActions
38
+ * setWidget('my-widget', { type: 'formula', isLoading: false, data: { value: 1000 } })
37
39
  * ```
38
40
  */
39
41
  export declare const useWidgetStore: import('node_modules/zustand/esm/react.mjs').UseBoundStore<import('node_modules/zustand/esm/vanilla.mjs').StoreApi<WidgetStore>>;
42
+ /**
43
+ * Stable references to store actions, accessible without creating a subscription.
44
+ *
45
+ * Use this instead of `useWidgetStore((state) => state.setWidget)` to avoid
46
+ * unnecessary subscriber evaluations. Actions are stable functions that never
47
+ * change, so subscribing to them wastes cycles on every store update.
48
+ *
49
+ * @example
50
+ * ```tsx
51
+ * import { widgetStoreActions } from '@carto/ps-react-ui/widgets'
52
+ *
53
+ * const { setWidget, registerTool } = widgetStoreActions
54
+ *
55
+ * useEffect(() => {
56
+ * registerTool(id, { id: 'my-tool', order: 10, enabled: true, fn: (d) => d })
57
+ * return () => widgetStoreActions.unregisterTool(id, 'my-tool')
58
+ * }, [id])
59
+ * ```
60
+ */
61
+ export declare const widgetStoreActions: WidgetStoreActions;
@@ -75,7 +75,7 @@ export interface TableWidgetConfig {
75
75
  /** Enable row selection with checkboxes */
76
76
  selectable?: boolean;
77
77
  /** Currently selected row IDs */
78
- selected: (string | number)[];
78
+ selected?: (string | number)[];
79
79
  /** Pagination and sort mode: local (client-side) or remote (server-side) */
80
80
  mode: Mode;
81
81
  /** Pagination configuration */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Shared utilities for chart widget configuration
3
3
  */
4
- export { defaultFormatter } from '../formatter';
4
+ export { defaultFormatter, defaultLabelFormatter } from '../formatter';
5
5
  export { createChartWidgetConfig } from './config-factory';
6
6
  export type { ChartWidgetBaseConfig, CreateChartWidgetConfigParams, } from './config-factory';
7
7
  export { flattenObjectArrayToCSV, scatterplotDataToCSV } from './csv-modifiers';
@@ -14,10 +14,15 @@ export declare function niceNum(value: number): number;
14
14
  /**
15
15
  * Builds standard legend configuration for chart widgets
16
16
  *
17
- * @param hasLegend - Whether to show the legend
17
+ * @param params - Legend configuration parameters
18
+ * @param params.hasLegend - Whether to show the legend
19
+ * @param params.labelFormatter - Optional formatter for legend item names
18
20
  * @returns Legend configuration object
19
21
  */
20
- export declare function buildLegendConfig(hasLegend: boolean): LegendComponentOption;
22
+ export declare function buildLegendConfig({ hasLegend, labelFormatter, }: {
23
+ hasLegend: boolean;
24
+ labelFormatter?: (value: string | number) => string | number;
25
+ }): LegendComponentOption;
21
26
  /**
22
27
  * Builds standard grid configuration with legend-aware spacing
23
28
  *
@@ -49,16 +54,16 @@ export declare function createTooltipPositioner(theme: Theme): (point: [number,
49
54
  */
50
55
  export declare function createAxisLabelFormatter(formatter?: (value: number) => string): ((value: number) => string) | undefined;
51
56
  /**
52
- * Applies formatter to xAxis configuration
53
- * Only applies to single axis objects (not arrays) with type 'value'
57
+ * Applies labelFormatter to xAxis configuration
58
+ * Applies to any xAxis regardless of axis type (category, value, etc.)
54
59
  *
55
60
  * @param xAxis - Existing xAxis configuration
56
- * @param formatter - Optional formatter function from widget config
57
- * @returns Updated xAxis configuration or undefined if no changes needed
61
+ * @param labelFormatter - Optional labelFormatter function from widget config
62
+ * @returns Updated xAxis configuration
58
63
  */
59
- export declare function applyXAxisFormatter(xAxis: unknown, formatter?: (value: number) => string): {
64
+ export declare function applyXAxisFormatter(xAxis: unknown, formatter?: (value: string | number) => string | number): {
60
65
  axisLabel: {
61
- formatter: ((value: number) => string) | undefined;
66
+ formatter: ((value: string | number) => string) | undefined;
62
67
  };
63
68
  type?: string;
64
69
  };
@@ -1 +1,2 @@
1
1
  export declare const defaultFormatter: (value: number) => string;
2
+ export declare const defaultLabelFormatter: (value: string | number) => string | number;
@@ -1,4 +1,4 @@
1
- export { defaultFormatter } from './formatter';
1
+ export { defaultFormatter, defaultLabelFormatter } from './formatter';
2
2
  export { createChartWidgetConfig } from './chart-config';
3
3
  export type { ChartWidgetBaseConfig, CreateChartWidgetConfigParams, } from './chart-config';
4
4
  export { flattenObjectArrayToCSV, scatterplotDataToCSV } from './chart-config';
@@ -0,0 +1,22 @@
1
+ import { c as l } from "react/compiler-runtime";
2
+ import { useRef as c, useEffect as i } from "react";
3
+ import { w as m } from "./widget-store-CIrb9RKP.js";
4
+ function R(t) {
5
+ const e = l(4), n = c(null), s = c(null);
6
+ let o, r;
7
+ e[0] !== t ? (o = () => {
8
+ n.current && m.setWidget(t, {
9
+ refUI: n,
10
+ instance: s
11
+ });
12
+ }, r = [t], e[0] = t, e[1] = o, e[2] = r) : (o = e[1], r = e[2]), i(o, r);
13
+ let f;
14
+ return e[3] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (f = {
15
+ ref: n,
16
+ instance: s
17
+ }, e[3] = f) : f = e[3], f;
18
+ }
19
+ export {
20
+ R as u
21
+ };
22
+ //# sourceMappingURL=use-widget-ref-BFazQvJK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-widget-ref-BFazQvJK.js","sources":["../src/hooks/use-widget-ref.ts"],"sourcesContent":["import { useEffect, useRef } from 'react'\nimport { widgetStoreActions } from '../widgets/stores/widget-store'\n\n/**\n * Registers a DOM element ref and an ECharts instance ref with the widget store.\n * This allows other parts of the application (e.g., screenshot export) to access the widget's DOM element.\n *\n * @param widgetId - The widget ID to register the refs under.\n * @returns An object with `ref` (DOM element) and `instance` (ECharts instance) refs.\n *\n * @example\n * ```tsx\n * function MyWidget({ id }: { id: string }) {\n * const { ref } = useWidgetRef<HTMLDivElement>(id)\n *\n * return <div ref={ref}>Widget content</div>\n * }\n * ```\n */\nexport function useWidgetRef<T extends HTMLElement = HTMLElement>(\n widgetId: string,\n) {\n const ref = useRef<T | null>(null)\n const instance = useRef<echarts.ECharts | null>(null)\n\n useEffect(() => {\n if (ref.current) {\n widgetStoreActions.setWidget(widgetId, { refUI: ref, instance: instance })\n }\n }, [widgetId])\n\n return { ref, instance }\n}\n"],"names":["useWidgetRef","widgetId","$","_c","ref","useRef","instance","t0","t1","current","widgetStoreActions","setWidget","refUI","useEffect","t2","Symbol","for"],"mappings":";;;AAmBO,SAAAA,EAAAC,GAAA;AAAA,QAAAC,IAAAC,EAAA,CAAA,GAGLC,IAAYC,EAAiB,IAAI,GACjCC,IAAiBD,EAA+B,IAAI;AAAC,MAAAE,GAAAC;AAAA,EAAAN,SAAAD,KAE3CM,IAAAA,MAAA;AACR,IAAIH,EAAGK,WACLC,EAAkBC,UAAWV,GAAU;AAAA,MAAAW,OAASR;AAAAA,MAAGE,UAAAA;AAAAA,IAAAA,CAAsB;AAAA,EAC1E,GACAE,IAAA,CAACP,CAAQ,GAACC,OAAAD,GAAAC,OAAAK,GAAAL,OAAAM,MAAAD,IAAAL,EAAA,CAAA,GAAAM,IAAAN,EAAA,CAAA,IAJbW,EAAUN,GAIPC,CAAU;AAAC,MAAAM;AAAA,SAAAZ,EAAA,CAAA,MAAAa,uBAAAC,IAAA,2BAAA,KAEPF,IAAA;AAAA,IAAAV,KAAAA;AAAAA,IAAAE,UAAAA;AAAAA,EAAAA,GAAiBJ,OAAAY,KAAAA,IAAAZ,EAAA,CAAA,GAAjBY;AAAiB;"}
@@ -0,0 +1,12 @@
1
+ import { c as i } from "react/compiler-runtime";
2
+ import { u as m } from "./widget-store-CIrb9RKP.js";
3
+ import { useShallow as s } from "zustand/shallow";
4
+ function a(r, e) {
5
+ const o = i(3);
6
+ let t;
7
+ return o[0] !== e || o[1] !== r ? (t = (u) => e(u.widgets[r]), o[0] = e, o[1] = r, o[2] = t) : t = o[2], m(s(t));
8
+ }
9
+ export {
10
+ a as u
11
+ };
12
+ //# sourceMappingURL=use-widget-selector-DqRmWQ1K.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-widget-selector-DqRmWQ1K.js","sources":["../src/widgets/stores/use-widget-selector.ts"],"sourcesContent":["import { useWidgetStore } from './widget-store'\nimport type { WidgetState } from './types'\nimport { useShallow } from 'zustand/shallow'\n\n/**\n * Scoped selector hook for reading a single widget's state from the store.\n *\n * Consolidates multiple `useWidgetStore(useShallow(...))` calls into a single\n * subscription per component. The selector receives only this widget's state\n * (or undefined if not yet registered), and uses shallow comparison to avoid\n * re-renders when unrelated properties change.\n *\n * @param widgetId - The widget ID to subscribe to.\n * @param selector - A function that extracts the needed properties from the widget state.\n * Must be a stable reference (inline arrow is fine due to useCallback wrapping).\n *\n * @example\n * ```tsx\n * // Before: 4 separate subscriptions\n * const title = useWidgetStore(useShallow((s) => s.getWidget(id)?.title))\n * const collapsed = useWidgetStore(useShallow((s) => s.getWidget(id)?.collapsed))\n * const disabled = useWidgetStore(useShallow((s) => s.getWidget(id)?.disabled))\n * const isFetching = useWidgetStore(useShallow((s) => s.getWidget(id)?.isFetching))\n *\n * // After: 1 subscription\n * const { title, collapsed, disabled, isFetching } = useWidgetSelector(id, (w) => ({\n * title: w?.title, collapsed: w?.collapsed, disabled: w?.disabled, isFetching: w?.isFetching,\n * }))\n *\n * // With extra dependencies (e.g., index prop):\n * const value = useWidgetSelector(\n * id,\n * (w) => (w as MyState | undefined)?.data?.[index]?.value,\n * [index],\n * )\n * ```\n */\nexport function useWidgetSelector<T>(\n widgetId: string,\n selector: (widget: WidgetState | undefined) => T,\n): T {\n return useWidgetStore(\n useShallow((state: { widgets: Record<string, WidgetState> }) =>\n selector(state.widgets[widgetId]),\n ),\n )\n}\n"],"names":["useWidgetSelector","widgetId","selector","$","_c","t0","state","widgets","useWidgetStore","useShallow"],"mappings":";;;AAqCO,SAAAA,EAAAC,GAAAC,GAAA;AAAA,QAAAC,IAAAC,EAAA,CAAA;AAAA,MAAAC;AAAA,SAAAF,EAAA,CAAA,MAAAD,KAAAC,SAAAF,KAKQI,IAAAC,CAAAA,MACTJ,EAASI,EAAKC,QAASN,CAAQ,CAAC,GAACE,OAAAD,GAAAC,OAAAF,GAAAE,OAAAE,KAAAA,IAAAF,EAAA,CAAA,GAF9BK,EACLC,EAAWJ,CAEX,CACF;AAAC;"}
@@ -0,0 +1,263 @@
1
+ import { create as y } from "zustand";
2
+ const b = /* @__PURE__ */ new Map(), w = /* @__PURE__ */ new Map(), u = y()((T, p) => ({
3
+ // State
4
+ widgets: {},
5
+ // Actions
6
+ /** Merges partial state into the widget entry. Creates the widget if it doesn't exist. */
7
+ setWidget: (e, o) => {
8
+ T((s) => {
9
+ const t = s.widgets[e] ?? {};
10
+ return {
11
+ widgets: {
12
+ ...s.widgets,
13
+ [e]: {
14
+ ...t,
15
+ ...o,
16
+ id: e
17
+ }
18
+ }
19
+ };
20
+ });
21
+ },
22
+ removeWidget: (e) => T((o) => {
23
+ const s = {
24
+ ...o.widgets
25
+ };
26
+ return delete s[e], {
27
+ widgets: s
28
+ };
29
+ }),
30
+ clearWidgets: () => T({
31
+ widgets: {}
32
+ }),
33
+ getWidget: (e) => p().widgets[e],
34
+ /**
35
+ * Registers a transformation tool for a widget's data or config pipeline.
36
+ *
37
+ * **No-op optimization:** When a tool with the same `id` already exists and its
38
+ * structural properties (`order`, `enabled`, `type`, `disables`) are unchanged,
39
+ * only `fn` and `config` are updated via direct mutation — no store update is
40
+ * triggered. This allows action components to include all reactive dependencies
41
+ * in their `useEffect` arrays without causing WidgetLoader pipeline cascades.
42
+ */
43
+ registerTool: (e, o) => {
44
+ const t = p().widgets[e]?.registeredTools?.find((n) => n.id === o.id);
45
+ if (t?.order === o.order && t.enabled === o.enabled && t.type === o.type && t.disables === o.disables) {
46
+ t.fn = o.fn, o.config && (t.config = o.config);
47
+ return;
48
+ }
49
+ T((n) => {
50
+ const g = n.widgets[e] ?? {}, c = (g.registeredTools ?? []).filter((f) => f.id !== o.id);
51
+ return {
52
+ widgets: {
53
+ ...n.widgets,
54
+ [e]: {
55
+ ...g,
56
+ id: e,
57
+ registeredTools: [...c, o]
58
+ }
59
+ }
60
+ };
61
+ });
62
+ },
63
+ unregisterTool: (e, o) => T((s) => {
64
+ const t = s.widgets[e];
65
+ if (!t) return s;
66
+ const g = (t.registeredTools ?? []).filter((d) => d.id !== o);
67
+ return {
68
+ widgets: {
69
+ ...s.widgets,
70
+ [e]: {
71
+ ...t,
72
+ registeredTools: g
73
+ }
74
+ }
75
+ };
76
+ }),
77
+ updateToolConfig: (e, o, s) => T((t) => {
78
+ const n = t.widgets[e];
79
+ if (!n) return t;
80
+ const d = (n.registeredTools ?? []).map((c) => c.id === o ? {
81
+ ...c,
82
+ config: {
83
+ ...c.config,
84
+ ...s
85
+ }
86
+ } : c);
87
+ return {
88
+ widgets: {
89
+ ...t.widgets,
90
+ [e]: {
91
+ ...n,
92
+ registeredTools: d
93
+ }
94
+ }
95
+ };
96
+ }),
97
+ /**
98
+ * Updates a tool's enabled state.
99
+ *
100
+ * **No-op optimization:** Skips the store update if the tool already has the
101
+ * requested enabled value.
102
+ */
103
+ setToolEnabled: (e, o, s) => {
104
+ const t = p().widgets[e];
105
+ t && t.registeredTools?.find((g) => g.id === o)?.enabled === s || T((n) => {
106
+ const g = n.widgets[e];
107
+ if (!g) return n;
108
+ const c = (g.registeredTools ?? []).map((f) => f.id === o ? {
109
+ ...f,
110
+ enabled: s
111
+ } : f);
112
+ return {
113
+ widgets: {
114
+ ...n.widgets,
115
+ [e]: {
116
+ ...g,
117
+ registeredTools: c
118
+ }
119
+ }
120
+ };
121
+ });
122
+ },
123
+ /**
124
+ * Executes the data transformation pipeline for a widget.
125
+ *
126
+ * Filters to enabled data-type tools (respecting `disables`), sorts by `order`,
127
+ * and chains their `fn` calls. Supports async tools.
128
+ *
129
+ * **Cancellation:** Newer executions for the same widget automatically cancel
130
+ * in-progress ones via a version counter.
131
+ *
132
+ * **No-op optimization:** Skips the final `set()` if the transformed data is
133
+ * referentially identical (`Object.is`) to what's already in the store.
134
+ */
135
+ executeToolPipeline: async (e, o) => {
136
+ const s = p().widgets[e];
137
+ if (!s) return;
138
+ const t = (b.get(e) ?? 0) + 1;
139
+ b.set(e, t);
140
+ const n = s, g = /* @__PURE__ */ new Set();
141
+ for (const i of n.registeredTools ?? [])
142
+ i.enabled && i.disables && i.disables.forEach((l) => g.add(l));
143
+ const d = [...n.registeredTools ?? []].filter((i) => (i.type ?? "data") === "data" && i.enabled && !g.has(i.id)).sort((i, l) => i.order - l.order);
144
+ let c = o;
145
+ for (const i of d) {
146
+ if (b.get(e) !== t)
147
+ return;
148
+ try {
149
+ c = await i.fn(c, i.config);
150
+ } catch (l) {
151
+ console.error(`Tool ${i.id} failed for widget ${e}:`, l);
152
+ }
153
+ }
154
+ const f = p().widgets[e];
155
+ if (f && Object.is(f.data, c)) {
156
+ b.get(e) === t && b.delete(e);
157
+ return;
158
+ }
159
+ T((i) => {
160
+ const l = i.widgets[e];
161
+ return l ? {
162
+ widgets: {
163
+ ...i.widgets,
164
+ [e]: {
165
+ ...l,
166
+ data: c
167
+ }
168
+ }
169
+ } : i;
170
+ }), b.get(e) === t && b.delete(e);
171
+ },
172
+ /**
173
+ * Executes the config transformation pipeline for a widget.
174
+ *
175
+ * Filters to enabled config-type tools (respecting `disables`), sorts by `order`,
176
+ * and chains their `fn` calls. The transformed config is spread into the widget state.
177
+ *
178
+ * **Cancellation:** Newer executions for the same widget automatically cancel
179
+ * in-progress ones via a version counter.
180
+ *
181
+ * **No-op optimization:** Skips the final `set()` when the config object is unchanged
182
+ * and all its properties already match what's in the store.
183
+ */
184
+ executeConfigPipeline: async (e, o) => {
185
+ const s = p().widgets[e];
186
+ if (!s) return;
187
+ const t = (w.get(e) ?? 0) + 1;
188
+ w.set(e, t);
189
+ const n = /* @__PURE__ */ new Set();
190
+ for (const r of s.registeredTools ?? [])
191
+ r.enabled && r.disables && r.disables.forEach((a) => n.add(a));
192
+ const g = [...s.registeredTools ?? []].filter((r) => r.type === "config" && r.enabled && !n.has(r.id)).sort((r, a) => r.order - a.order);
193
+ let d = o;
194
+ for (const r of g) {
195
+ if (w.get(e) !== t)
196
+ return;
197
+ try {
198
+ d = await r.fn(d, r.config);
199
+ } catch (a) {
200
+ console.error(`Config tool ${r.id} failed for widget ${e}:`, a);
201
+ }
202
+ }
203
+ const c = o, f = d, i = p().widgets[e], l = i?._lastConfig, W = {};
204
+ for (const r of Object.keys(f)) {
205
+ const a = !Object.is(f[r], c[r]), C = !l || !(r in l), m = !C && Object.is(i[r], l[r]);
206
+ (a || C || m) && (W[r] = f[r]);
207
+ }
208
+ const S = Object.keys(W).some((r) => !Object.is(i?.[r], W[r])), h = !Object.is(d, l);
209
+ if (!S && !h) {
210
+ w.get(e) === t && w.delete(e);
211
+ return;
212
+ }
213
+ T((r) => {
214
+ const a = r.widgets[e];
215
+ return a ? {
216
+ widgets: {
217
+ ...r.widgets,
218
+ [e]: {
219
+ ...a,
220
+ ...W,
221
+ _lastConfig: d
222
+ }
223
+ }
224
+ } : r;
225
+ }), w.get(e) === t && w.delete(e);
226
+ }
227
+ })), P = {
228
+ get setWidget() {
229
+ return u.getState().setWidget;
230
+ },
231
+ get removeWidget() {
232
+ return u.getState().removeWidget;
233
+ },
234
+ get clearWidgets() {
235
+ return u.getState().clearWidgets;
236
+ },
237
+ get getWidget() {
238
+ return u.getState().getWidget;
239
+ },
240
+ get registerTool() {
241
+ return u.getState().registerTool;
242
+ },
243
+ get unregisterTool() {
244
+ return u.getState().unregisterTool;
245
+ },
246
+ get updateToolConfig() {
247
+ return u.getState().updateToolConfig;
248
+ },
249
+ get setToolEnabled() {
250
+ return u.getState().setToolEnabled;
251
+ },
252
+ get executeToolPipeline() {
253
+ return u.getState().executeToolPipeline;
254
+ },
255
+ get executeConfigPipeline() {
256
+ return u.getState().executeConfigPipeline;
257
+ }
258
+ };
259
+ export {
260
+ u,
261
+ P as w
262
+ };
263
+ //# sourceMappingURL=widget-store-CIrb9RKP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget-store-CIrb9RKP.js","sources":["../src/widgets/stores/widget-store.ts"],"sourcesContent":["import { create } from 'zustand'\nimport type {\n WidgetState,\n WidgetStore,\n ToolRegistration,\n WidgetStoreActions,\n} from './types'\n\n// Track active pipeline executions for cancellation\nconst activePipelines = new Map<string, number>()\nconst activeConfigPipelines = new Map<string, number>()\n\n/**\n * Zustand store for managing widget state across the application.\n *\n * Provides centralized state management for all widget UI components, including\n * data/config transformation pipelines via registered tools.\n *\n * **Performance optimizations:**\n * - `registerTool` skips the store update when structural properties (order, enabled,\n * type, disables) haven't changed — only `fn` and `config` are updated via direct\n * mutation, avoiding a new `registeredTools` array reference and WidgetLoader\n * pipeline cascades.\n * - `setToolEnabled` skips the store update when the enabled state is already the\n * requested value.\n * - `executeToolPipeline` / `executeConfigPipeline` skip the final `set()` when\n * the transformed data/config is referentially identical to what's already in the store.\n * - Both pipelines support cancellation — newer executions for the same widget\n * automatically cancel in-progress ones.\n *\n * @example Reading widget state (prefer useWidgetSelector for performance)\n * ```tsx\n * import { useWidgetSelector } from '@carto/ps-react-ui/widgets'\n *\n * function MyWidget({ id }: { id: string }) {\n * const { title, data } = useWidgetSelector(id, (w) => ({\n * title: w?.title,\n * data: w?.data,\n * }))\n * return <div>{title}: {JSON.stringify(data)}</div>\n * }\n * ```\n *\n * @example Writing widget state\n * ```tsx\n * import { widgetStoreActions } from '@carto/ps-react-ui/widgets'\n *\n * const { setWidget } = widgetStoreActions\n * setWidget('my-widget', { type: 'formula', isLoading: false, data: { value: 1000 } })\n * ```\n */\nexport const useWidgetStore = create<WidgetStore>()((set, get) => ({\n // State\n widgets: {},\n\n // Actions\n\n /** Merges partial state into the widget entry. Creates the widget if it doesn't exist. */\n setWidget: (id, widget) => {\n set((state) => {\n const prev = state.widgets[id] ?? ({} as WidgetStore['widgets'][string])\n return {\n widgets: {\n ...state.widgets,\n [id]: {\n ...prev,\n ...widget,\n id,\n },\n },\n }\n })\n },\n\n removeWidget: (id) =>\n set((state) => {\n const widgets = { ...state.widgets }\n\n delete widgets[id]\n\n return { widgets }\n }),\n\n clearWidgets: () =>\n set({\n widgets: {},\n }),\n\n getWidget: <T extends WidgetState>(id: string) => {\n return get().widgets[id] as T | undefined\n },\n\n /**\n * Registers a transformation tool for a widget's data or config pipeline.\n *\n * **No-op optimization:** When a tool with the same `id` already exists and its\n * structural properties (`order`, `enabled`, `type`, `disables`) are unchanged,\n * only `fn` and `config` are updated via direct mutation — no store update is\n * triggered. This allows action components to include all reactive dependencies\n * in their `useEffect` arrays without causing WidgetLoader pipeline cascades.\n */\n registerTool: (widgetId: string, tool: ToolRegistration) => {\n const current = get().widgets[widgetId]\n const existingTool = current?.registeredTools?.find(\n (t: ToolRegistration) => t.id === tool.id,\n )\n\n // No-op: structural properties unchanged — update fn/config via direct mutation.\n // Safe because fn and config are only consumed imperatively during pipeline execution.\n if (\n existingTool?.order === tool.order &&\n existingTool.enabled === tool.enabled &&\n existingTool.type === tool.type &&\n existingTool.disables === tool.disables\n ) {\n existingTool.fn = tool.fn\n if (tool.config) existingTool.config = tool.config\n return\n }\n\n set((state) => {\n const widget = state.widgets[widgetId] ?? ({} as WidgetState)\n const registeredTools = widget.registeredTools ?? []\n\n // Remove existing tool with same id if present\n const filteredTools = registeredTools.filter(\n (t: ToolRegistration) => t.id !== tool.id,\n )\n\n return {\n widgets: {\n ...state.widgets,\n [widgetId]: {\n ...widget,\n id: widgetId,\n registeredTools: [...filteredTools, tool],\n },\n },\n }\n })\n },\n\n unregisterTool: (widgetId: string, toolId: string) =>\n set((state) => {\n const current = state.widgets[widgetId]\n if (!current) return state\n\n const registeredTools = current.registeredTools ?? []\n const filteredTools = registeredTools.filter(\n (t: ToolRegistration) => t.id !== toolId,\n )\n\n return {\n widgets: {\n ...state.widgets,\n [widgetId]: {\n ...current,\n registeredTools: filteredTools,\n },\n },\n }\n }),\n\n updateToolConfig: (\n widgetId: string,\n toolId: string,\n config: Record<string, unknown>,\n ) =>\n set((state) => {\n const current = state.widgets[widgetId]\n if (!current) return state\n\n const registeredTools = current.registeredTools ?? []\n const updatedTools = registeredTools.map((tool: ToolRegistration) =>\n tool.id === toolId\n ? {\n ...tool,\n config: { ...tool.config, ...config },\n }\n : tool,\n )\n\n return {\n widgets: {\n ...state.widgets,\n [widgetId]: {\n ...current,\n registeredTools: updatedTools,\n },\n },\n }\n }),\n\n /**\n * Updates a tool's enabled state.\n *\n * **No-op optimization:** Skips the store update if the tool already has the\n * requested enabled value.\n */\n setToolEnabled: (widgetId: string, toolId: string, enabled: boolean) => {\n const current = get().widgets[widgetId]\n if (current) {\n const tool = current.registeredTools?.find(\n (t: ToolRegistration) => t.id === toolId,\n )\n if (tool?.enabled === enabled) return\n }\n\n set((state) => {\n const widget = state.widgets[widgetId]\n if (!widget) return state\n\n const registeredTools = widget.registeredTools ?? []\n const updatedTools = registeredTools.map((tool: ToolRegistration) =>\n tool.id === toolId ? { ...tool, enabled } : tool,\n )\n\n return {\n widgets: {\n ...state.widgets,\n [widgetId]: {\n ...widget,\n registeredTools: updatedTools,\n },\n },\n }\n })\n },\n\n /**\n * Executes the data transformation pipeline for a widget.\n *\n * Filters to enabled data-type tools (respecting `disables`), sorts by `order`,\n * and chains their `fn` calls. Supports async tools.\n *\n * **Cancellation:** Newer executions for the same widget automatically cancel\n * in-progress ones via a version counter.\n *\n * **No-op optimization:** Skips the final `set()` if the transformed data is\n * referentially identical (`Object.is`) to what's already in the store.\n */\n executeToolPipeline: async (widgetId: string, sourceData: unknown) => {\n const widget = get().widgets[widgetId]\n if (!widget) return\n\n // Cancel any in-progress pipeline for this widget\n const currentExecution = (activePipelines.get(widgetId) ?? 0) + 1\n activePipelines.set(widgetId, currentExecution)\n\n const widgetWithTools = widget\n\n // Build set of tool IDs that should be disabled\n const disabledToolIds = new Set<string>()\n for (const tool of widgetWithTools.registeredTools ?? []) {\n if (tool.enabled && tool.disables) {\n tool.disables.forEach((id) => disabledToolIds.add(id))\n }\n }\n\n // Sort tools by order and filter enabled data-only tools, excluding disabled tools\n const sortedTools = [...(widgetWithTools.registeredTools ?? [])]\n .filter(\n (tool) =>\n (tool.type ?? 'data') === 'data' &&\n tool.enabled &&\n !disabledToolIds.has(tool.id),\n )\n .sort((a, b) => a.order - b.order)\n\n // Execute pipeline - handle both sync and async tools\n let transformedData = sourceData\n for (const tool of sortedTools) {\n // Check if this execution was cancelled\n if (activePipelines.get(widgetId) !== currentExecution) {\n return\n }\n\n try {\n // Call tool function (may return Promise or direct value)\n transformedData = await tool.fn(transformedData, tool.config)\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error(`Tool ${tool.id} failed for widget ${widgetId}:`, error)\n // Continue with current data to prevent one tool from breaking all\n }\n }\n\n // Skip store update if data hasn't changed (e.g., passthrough pipeline with no tools)\n const widgetAfter = get().widgets[widgetId]\n if (widgetAfter && Object.is(widgetAfter.data, transformedData)) {\n if (activePipelines.get(widgetId) === currentExecution) {\n activePipelines.delete(widgetId)\n }\n return\n }\n\n // Single store update with final transformed data\n set((state) => {\n const currentWidget = state.widgets[widgetId]\n if (!currentWidget) return state\n\n return {\n widgets: {\n ...state.widgets,\n [widgetId]: {\n ...currentWidget,\n data: transformedData,\n },\n },\n }\n })\n\n // Clean up tracking\n if (activePipelines.get(widgetId) === currentExecution) {\n activePipelines.delete(widgetId)\n }\n },\n\n /**\n * Executes the config transformation pipeline for a widget.\n *\n * Filters to enabled config-type tools (respecting `disables`), sorts by `order`,\n * and chains their `fn` calls. The transformed config is spread into the widget state.\n *\n * **Cancellation:** Newer executions for the same widget automatically cancel\n * in-progress ones via a version counter.\n *\n * **No-op optimization:** Skips the final `set()` when the config object is unchanged\n * and all its properties already match what's in the store.\n */\n executeConfigPipeline: async (widgetId: string, baseConfig: object) => {\n const widget = get().widgets[widgetId]\n if (!widget) return\n\n // Cancel any in-progress config pipeline for this widget\n const currentExecution = (activeConfigPipelines.get(widgetId) ?? 0) + 1\n activeConfigPipelines.set(widgetId, currentExecution)\n\n // Build set of tool IDs that should be disabled (cross-type disabling works)\n const disabledToolIds = new Set<string>()\n for (const tool of widget.registeredTools ?? []) {\n if (tool.enabled && tool.disables) {\n tool.disables.forEach((id) => disabledToolIds.add(id))\n }\n }\n\n // Filter to config tools only, sort by order\n const sortedTools = [...(widget.registeredTools ?? [])]\n .filter(\n (tool) =>\n tool.type === 'config' &&\n tool.enabled &&\n !disabledToolIds.has(tool.id),\n )\n .sort((a, b) => a.order - b.order)\n\n // Chain config tools\n let transformedConfig: unknown = baseConfig\n for (const tool of sortedTools) {\n if (activeConfigPipelines.get(widgetId) !== currentExecution) {\n return\n }\n\n try {\n transformedConfig = await tool.fn(transformedConfig, tool.config)\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error(\n `Config tool ${tool.id} failed for widget ${widgetId}:`,\n error,\n )\n }\n }\n\n // Build a patch that only includes properties the pipeline should set.\n // A property is applied when:\n // 1. A config tool explicitly changed it (transformedConfig[k] !== baseConfig[k])\n // 2. First pipeline run for this widget (no _lastConfig yet)\n // 3. The widget value still matches what the pipeline last set — meaning the\n // user hasn't modified it via setWidget, so it's safe to overwrite.\n // A property is SKIPPED when the widget value differs from _lastConfig,\n // meaning the user (or a hook) changed it since the last pipeline run.\n const base = baseConfig as Record<string, unknown>\n const result = transformedConfig as Record<string, unknown>\n const widgetNow = get().widgets[widgetId] as unknown as Record<\n string,\n unknown\n >\n const lastConfig = widgetNow?._lastConfig as\n | Record<string, unknown>\n | undefined\n\n const patch: Record<string, unknown> = {}\n for (const key of Object.keys(result)) {\n const toolChanged = !Object.is(result[key], base[key])\n const isFirstRun = !lastConfig || !(key in lastConfig)\n const userUnmodified =\n !isFirstRun && Object.is(widgetNow[key], lastConfig[key])\n\n if (toolChanged || isFirstRun || userUnmodified) {\n patch[key] = result[key]\n }\n }\n\n // Skip store update if every patch value already matches the widget\n const hasChanges = Object.keys(patch).some(\n (k) => !Object.is(widgetNow?.[k], patch[k]),\n )\n const configRefChanged = !Object.is(transformedConfig, lastConfig)\n\n if (!hasChanges && !configRefChanged) {\n if (activeConfigPipelines.get(widgetId) === currentExecution) {\n activeConfigPipelines.delete(widgetId)\n }\n return\n }\n\n // Apply the patch and store the pipeline output for next run's comparison\n set((state) => {\n const currentWidget = state.widgets[widgetId]\n if (!currentWidget) return state\n\n return {\n widgets: {\n ...state.widgets,\n [widgetId]: {\n ...currentWidget,\n ...patch,\n _lastConfig: transformedConfig,\n },\n },\n }\n })\n\n if (activeConfigPipelines.get(widgetId) === currentExecution) {\n activeConfigPipelines.delete(widgetId)\n }\n },\n}))\n\n/**\n * Stable references to store actions, accessible without creating a subscription.\n *\n * Use this instead of `useWidgetStore((state) => state.setWidget)` to avoid\n * unnecessary subscriber evaluations. Actions are stable functions that never\n * change, so subscribing to them wastes cycles on every store update.\n *\n * @example\n * ```tsx\n * import { widgetStoreActions } from '@carto/ps-react-ui/widgets'\n *\n * const { setWidget, registerTool } = widgetStoreActions\n *\n * useEffect(() => {\n * registerTool(id, { id: 'my-tool', order: 10, enabled: true, fn: (d) => d })\n * return () => widgetStoreActions.unregisterTool(id, 'my-tool')\n * }, [id])\n * ```\n */\nexport const widgetStoreActions: WidgetStoreActions = {\n get setWidget() {\n return useWidgetStore.getState().setWidget\n },\n get removeWidget() {\n return useWidgetStore.getState().removeWidget\n },\n get clearWidgets() {\n return useWidgetStore.getState().clearWidgets\n },\n get getWidget() {\n return useWidgetStore.getState().getWidget\n },\n get registerTool() {\n return useWidgetStore.getState().registerTool\n },\n get unregisterTool() {\n return useWidgetStore.getState().unregisterTool\n },\n get updateToolConfig() {\n return useWidgetStore.getState().updateToolConfig\n },\n get setToolEnabled() {\n return useWidgetStore.getState().setToolEnabled\n },\n get executeToolPipeline() {\n return useWidgetStore.getState().executeToolPipeline\n },\n get executeConfigPipeline() {\n return useWidgetStore.getState().executeConfigPipeline\n },\n} as WidgetStoreActions\n"],"names":["activePipelines","Map","activeConfigPipelines","useWidgetStore","create","set","get","widgets","setWidget","id","widget","state","prev","removeWidget","clearWidgets","getWidget","registerTool","widgetId","tool","existingTool","registeredTools","find","t","order","enabled","type","disables","fn","config","filteredTools","filter","unregisterTool","toolId","current","updateToolConfig","updatedTools","map","setToolEnabled","executeToolPipeline","sourceData","currentExecution","widgetWithTools","disabledToolIds","Set","forEach","add","sortedTools","has","sort","a","b","transformedData","error","console","widgetAfter","Object","is","data","delete","currentWidget","executeConfigPipeline","baseConfig","transformedConfig","base","result","widgetNow","lastConfig","_lastConfig","patch","key","keys","toolChanged","isFirstRun","userUnmodified","hasChanges","some","k","configRefChanged","widgetStoreActions","getState"],"mappings":";AASA,MAAMA,wBAAsBC,IAAAA,GACtBC,wBAA4BD,IAAAA,GAyCrBE,IAAiBC,EAAAA,EAAsB,CAACC,GAAKC,OAAS;AAAA;AAAA,EAEjEC,SAAS,CAAA;AAAA;AAAA;AAAA,EAKTC,WAAWA,CAACC,GAAIC,MAAW;AACzBL,IAAAA,EAAKM,CAAAA,MAAU;AACb,YAAMC,IAAOD,EAAMJ,QAAQE,CAAE,KAAM,CAAA;AACnC,aAAO;AAAA,QACLF,SAAS;AAAA,UACP,GAAGI,EAAMJ;AAAAA,UACT,CAACE,CAAE,GAAG;AAAA,YACJ,GAAGG;AAAAA,YACH,GAAGF;AAAAA,YACHD,IAAAA;AAAAA,UAAAA;AAAAA,QACF;AAAA,MACF;AAAA,IAEJ,CAAC;AAAA,EACH;AAAA,EAEAI,cAAeJ,CAAAA,MACbJ,EAAKM,CAAAA,MAAU;AACb,UAAMJ,IAAU;AAAA,MAAE,GAAGI,EAAMJ;AAAAA,IAAAA;AAE3B,kBAAOA,EAAQE,CAAE,GAEV;AAAA,MAAEF,SAAAA;AAAAA,IAAAA;AAAAA,EACX,CAAC;AAAA,EAEHO,cAAcA,MACZT,EAAI;AAAA,IACFE,SAAS,CAAA;AAAA,EAAC,CACX;AAAA,EAEHQ,WAAW,CAAwBN,MAC1BH,EAAAA,EAAMC,QAAQE,CAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYzBO,cAAcA,CAACC,GAAkBC,MAA2B;AAE1D,UAAMC,IADUb,IAAMC,QAAQU,CAAQ,GACRG,iBAAiBC,KAC7C,CAACC,MAAwBA,EAAEb,OAAOS,EAAKT,EACzC;AAIA,QACEU,GAAcI,UAAUL,EAAKK,SAC7BJ,EAAaK,YAAYN,EAAKM,WAC9BL,EAAaM,SAASP,EAAKO,QAC3BN,EAAaO,aAAaR,EAAKQ,UAC/B;AACAP,MAAAA,EAAaQ,KAAKT,EAAKS,IACnBT,EAAKU,WAAQT,EAAaS,SAASV,EAAKU;AAC5C;AAAA,IACF;AAEAvB,IAAAA,EAAKM,CAAAA,MAAU;AACb,YAAMD,IAASC,EAAMJ,QAAQU,CAAQ,KAAM,CAAA,GAIrCY,KAHkBnB,EAAOU,mBAAmB,CAAA,GAGZU,OACpC,CAACR,MAAwBA,EAAEb,OAAOS,EAAKT,EACzC;AAEA,aAAO;AAAA,QACLF,SAAS;AAAA,UACP,GAAGI,EAAMJ;AAAAA,UACT,CAACU,CAAQ,GAAG;AAAA,YACV,GAAGP;AAAAA,YACHD,IAAIQ;AAAAA,YACJG,iBAAiB,CAAC,GAAGS,GAAeX,CAAI;AAAA,UAAA;AAAA,QAC1C;AAAA,MACF;AAAA,IAEJ,CAAC;AAAA,EACH;AAAA,EAEAa,gBAAgBA,CAACd,GAAkBe,MACjC3B,EAAKM,CAAAA,MAAU;AACb,UAAMsB,IAAUtB,EAAMJ,QAAQU,CAAQ;AACtC,QAAI,CAACgB,EAAS,QAAOtB;AAGrB,UAAMkB,KADkBI,EAAQb,mBAAmB,CAAA,GACbU,OACpC,CAACR,MAAwBA,EAAEb,OAAOuB,CACpC;AAEA,WAAO;AAAA,MACLzB,SAAS;AAAA,QACP,GAAGI,EAAMJ;AAAAA,QACT,CAACU,CAAQ,GAAG;AAAA,UACV,GAAGgB;AAAAA,UACHb,iBAAiBS;AAAAA,QAAAA;AAAAA,MACnB;AAAA,IACF;AAAA,EAEJ,CAAC;AAAA,EAEHK,kBAAkBA,CAChBjB,GACAe,GACAJ,MAEAvB,EAAKM,CAAAA,MAAU;AACb,UAAMsB,IAAUtB,EAAMJ,QAAQU,CAAQ;AACtC,QAAI,CAACgB,EAAS,QAAOtB;AAGrB,UAAMwB,KADkBF,EAAQb,mBAAmB,CAAA,GACdgB,IAAI,CAAClB,MACxCA,EAAKT,OAAOuB,IACR;AAAA,MACE,GAAGd;AAAAA,MACHU,QAAQ;AAAA,QAAE,GAAGV,EAAKU;AAAAA,QAAQ,GAAGA;AAAAA,MAAAA;AAAAA,IAAO,IAEtCV,CACN;AAEA,WAAO;AAAA,MACLX,SAAS;AAAA,QACP,GAAGI,EAAMJ;AAAAA,QACT,CAACU,CAAQ,GAAG;AAAA,UACV,GAAGgB;AAAAA,UACHb,iBAAiBe;AAAAA,QAAAA;AAAAA,MACnB;AAAA,IACF;AAAA,EAEJ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQHE,gBAAgBA,CAACpB,GAAkBe,GAAgBR,MAAqB;AACtE,UAAMS,IAAU3B,IAAMC,QAAQU,CAAQ;AACtC,IAAIgB,KACWA,EAAQb,iBAAiBC,KACpC,CAACC,MAAwBA,EAAEb,OAAOuB,CACpC,GACUR,YAAYA,KAGxBnB,EAAKM,CAAAA,MAAU;AACb,YAAMD,IAASC,EAAMJ,QAAQU,CAAQ;AACrC,UAAI,CAACP,EAAQ,QAAOC;AAGpB,YAAMwB,KADkBzB,EAAOU,mBAAmB,CAAA,GACbgB,IAAI,CAAClB,MACxCA,EAAKT,OAAOuB,IAAS;AAAA,QAAE,GAAGd;AAAAA,QAAMM,SAAAA;AAAAA,MAAAA,IAAYN,CAC9C;AAEA,aAAO;AAAA,QACLX,SAAS;AAAA,UACP,GAAGI,EAAMJ;AAAAA,UACT,CAACU,CAAQ,GAAG;AAAA,YACV,GAAGP;AAAAA,YACHU,iBAAiBe;AAAAA,UAAAA;AAAAA,QACnB;AAAA,MACF;AAAA,IAEJ,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcAG,qBAAqB,OAAOrB,GAAkBsB,MAAwB;AACpE,UAAM7B,IAASJ,IAAMC,QAAQU,CAAQ;AACrC,QAAI,CAACP,EAAQ;AAGb,UAAM8B,KAAoBxC,EAAgBM,IAAIW,CAAQ,KAAK,KAAK;AAChEjB,IAAAA,EAAgBK,IAAIY,GAAUuB,CAAgB;AAE9C,UAAMC,IAAkB/B,GAGlBgC,wBAAsBC,IAAAA;AAC5B,eAAWzB,KAAQuB,EAAgBrB,mBAAmB,CAAA;AACpD,MAAIF,EAAKM,WAAWN,EAAKQ,YACvBR,EAAKQ,SAASkB,QAASnC,CAAAA,MAAOiC,EAAgBG,IAAIpC,CAAE,CAAC;AAKzD,UAAMqC,IAAc,CAAC,GAAIL,EAAgBrB,mBAAmB,CAAA,CAAG,EAC5DU,OACEZ,CAAAA,OACEA,EAAKO,QAAQ,YAAY,UAC1BP,EAAKM,WACL,CAACkB,EAAgBK,IAAI7B,EAAKT,EAAE,CAChC,EACCuC,KAAK,CAACC,GAAGC,MAAMD,EAAE1B,QAAQ2B,EAAE3B,KAAK;AAGnC,QAAI4B,IAAkBZ;AACtB,eAAWrB,KAAQ4B,GAAa;AAE9B,UAAI9C,EAAgBM,IAAIW,CAAQ,MAAMuB;AACpC;AAGF,UAAI;AAEFW,QAAAA,IAAkB,MAAMjC,EAAKS,GAAGwB,GAAiBjC,EAAKU,MAAM;AAAA,MAC9D,SAASwB,GAAO;AAEdC,gBAAQD,MAAM,QAAQlC,EAAKT,EAAE,sBAAsBQ,CAAQ,KAAKmC,CAAK;AAAA,MAEvE;AAAA,IACF;AAGA,UAAME,IAAchD,IAAMC,QAAQU,CAAQ;AAC1C,QAAIqC,KAAeC,OAAOC,GAAGF,EAAYG,MAAMN,CAAe,GAAG;AAC/D,MAAInD,EAAgBM,IAAIW,CAAQ,MAAMuB,KACpCxC,EAAgB0D,OAAOzC,CAAQ;AAEjC;AAAA,IACF;AAGAZ,IAAAA,EAAKM,CAAAA,MAAU;AACb,YAAMgD,IAAgBhD,EAAMJ,QAAQU,CAAQ;AAC5C,aAAK0C,IAEE;AAAA,QACLpD,SAAS;AAAA,UACP,GAAGI,EAAMJ;AAAAA,UACT,CAACU,CAAQ,GAAG;AAAA,YACV,GAAG0C;AAAAA,YACHF,MAAMN;AAAAA,UAAAA;AAAAA,QACR;AAAA,MACF,IATyBxC;AAAAA,IAW7B,CAAC,GAGGX,EAAgBM,IAAIW,CAAQ,MAAMuB,KACpCxC,EAAgB0D,OAAOzC,CAAQ;AAAA,EAEnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA2C,uBAAuB,OAAO3C,GAAkB4C,MAAuB;AACrE,UAAMnD,IAASJ,IAAMC,QAAQU,CAAQ;AACrC,QAAI,CAACP,EAAQ;AAGb,UAAM8B,KAAoBtC,EAAsBI,IAAIW,CAAQ,KAAK,KAAK;AACtEf,IAAAA,EAAsBG,IAAIY,GAAUuB,CAAgB;AAGpD,UAAME,wBAAsBC,IAAAA;AAC5B,eAAWzB,KAAQR,EAAOU,mBAAmB,CAAA;AAC3C,MAAIF,EAAKM,WAAWN,EAAKQ,YACvBR,EAAKQ,SAASkB,QAASnC,CAAAA,MAAOiC,EAAgBG,IAAIpC,CAAE,CAAC;AAKzD,UAAMqC,IAAc,CAAC,GAAIpC,EAAOU,mBAAmB,CAAA,CAAG,EACnDU,OACEZ,CAAAA,MACCA,EAAKO,SAAS,YACdP,EAAKM,WACL,CAACkB,EAAgBK,IAAI7B,EAAKT,EAAE,CAChC,EACCuC,KAAK,CAACC,GAAGC,MAAMD,EAAE1B,QAAQ2B,EAAE3B,KAAK;AAGnC,QAAIuC,IAA6BD;AACjC,eAAW3C,KAAQ4B,GAAa;AAC9B,UAAI5C,EAAsBI,IAAIW,CAAQ,MAAMuB;AAC1C;AAGF,UAAI;AACFsB,QAAAA,IAAoB,MAAM5C,EAAKS,GAAGmC,GAAmB5C,EAAKU,MAAM;AAAA,MAClE,SAASwB,GAAO;AAEdC,gBAAQD,MACN,eAAelC,EAAKT,EAAE,sBAAsBQ,CAAQ,KACpDmC,CACF;AAAA,MACF;AAAA,IACF;AAUA,UAAMW,IAAOF,GACPG,IAASF,GACTG,IAAY3D,IAAMC,QAAQU,CAAQ,GAIlCiD,IAAaD,GAAWE,aAIxBC,IAAiC,CAAA;AACvC,eAAWC,KAAOd,OAAOe,KAAKN,CAAM,GAAG;AACrC,YAAMO,IAAc,CAAChB,OAAOC,GAAGQ,EAAOK,CAAG,GAAGN,EAAKM,CAAG,CAAC,GAC/CG,IAAa,CAACN,KAAc,EAAEG,KAAOH,IACrCO,IACJ,CAACD,KAAcjB,OAAOC,GAAGS,EAAUI,CAAG,GAAGH,EAAWG,CAAG,CAAC;AAE1D,OAAIE,KAAeC,KAAcC,OAC/BL,EAAMC,CAAG,IAAIL,EAAOK,CAAG;AAAA,IAE3B;AAGA,UAAMK,IAAanB,OAAOe,KAAKF,CAAK,EAAEO,KACnCC,CAAAA,MAAM,CAACrB,OAAOC,GAAGS,IAAYW,CAAC,GAAGR,EAAMQ,CAAC,CAAC,CAC5C,GACMC,IAAmB,CAACtB,OAAOC,GAAGM,GAAmBI,CAAU;AAEjE,QAAI,CAACQ,KAAc,CAACG,GAAkB;AACpC,MAAI3E,EAAsBI,IAAIW,CAAQ,MAAMuB,KAC1CtC,EAAsBwD,OAAOzC,CAAQ;AAEvC;AAAA,IACF;AAGAZ,IAAAA,EAAKM,CAAAA,MAAU;AACb,YAAMgD,IAAgBhD,EAAMJ,QAAQU,CAAQ;AAC5C,aAAK0C,IAEE;AAAA,QACLpD,SAAS;AAAA,UACP,GAAGI,EAAMJ;AAAAA,UACT,CAACU,CAAQ,GAAG;AAAA,YACV,GAAG0C;AAAAA,YACH,GAAGS;AAAAA,YACHD,aAAaL;AAAAA,UAAAA;AAAAA,QACf;AAAA,MACF,IAVyBnD;AAAAA,IAY7B,CAAC,GAEGT,EAAsBI,IAAIW,CAAQ,MAAMuB,KAC1CtC,EAAsBwD,OAAOzC,CAAQ;AAAA,EAEzC;AACF,EAAE,GAqBW6D,IAAyC;AAAA,EACpD,IAAItE,YAAY;AACd,WAAOL,EAAe4E,WAAWvE;AAAAA,EACnC;AAAA,EACA,IAAIK,eAAe;AACjB,WAAOV,EAAe4E,WAAWlE;AAAAA,EACnC;AAAA,EACA,IAAIC,eAAe;AACjB,WAAOX,EAAe4E,WAAWjE;AAAAA,EACnC;AAAA,EACA,IAAIC,YAAY;AACd,WAAOZ,EAAe4E,WAAWhE;AAAAA,EACnC;AAAA,EACA,IAAIC,eAAe;AACjB,WAAOb,EAAe4E,WAAW/D;AAAAA,EACnC;AAAA,EACA,IAAIe,iBAAiB;AACnB,WAAO5B,EAAe4E,WAAWhD;AAAAA,EACnC;AAAA,EACA,IAAIG,mBAAmB;AACrB,WAAO/B,EAAe4E,WAAW7C;AAAAA,EACnC;AAAA,EACA,IAAIG,iBAAiB;AACnB,WAAOlC,EAAe4E,WAAW1C;AAAAA,EACnC;AAAA,EACA,IAAIC,sBAAsB;AACxB,WAAOnC,EAAe4E,WAAWzC;AAAAA,EACnC;AAAA,EACA,IAAIsB,wBAAwB;AAC1B,WAAOzD,EAAe4E,WAAWnB;AAAAA,EACnC;AACF;"}