@carto/ps-react-ui 4.5.1 → 4.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/{download-config-DemuQ3Jm.js → download-config-C3I0jWIL.js} +2 -2
  2. package/dist/{download-config-DemuQ3Jm.js.map → download-config-C3I0jWIL.js.map} +1 -1
  3. package/dist/{row-D4VOhcNI.js → row-DZSP99LW.js} +2 -2
  4. package/dist/{row-D4VOhcNI.js.map → row-DZSP99LW.js.map} +1 -1
  5. package/dist/{series-Bola3CmD.js → series-DLNHDWs0.js} +3 -3
  6. package/dist/{series-Bola3CmD.js.map → series-DLNHDWs0.js.map} +1 -1
  7. package/dist/types/hooks/index.d.ts +0 -1
  8. package/dist/types/widgets/actions/brush-toggle/brush-toggle.d.ts +3 -0
  9. package/dist/types/widgets/actions/index.d.ts +4 -4
  10. package/dist/types/widgets/actions/lock-selection/types.d.ts +2 -0
  11. package/dist/types/widgets/actions/relative-data/relative-data.d.ts +7 -2
  12. package/dist/types/widgets/actions/relative-data/types.d.ts +2 -0
  13. package/dist/types/widgets/actions/zoom-toggle/zoom-toggle.d.ts +4 -0
  14. package/dist/types/widgets/category/index.d.ts +10 -2
  15. package/dist/types/widgets/no-data/no-data.d.ts +3 -2
  16. package/dist/types/widgets/no-data/types.d.ts +5 -1
  17. package/dist/types/widgets/stores/index.d.ts +1 -1
  18. package/dist/types/widgets/stores/types.d.ts +10 -10
  19. package/dist/types/widgets/stores/widget-store.d.ts +2 -3
  20. package/dist/types/widgets/table/index.d.ts +6 -2
  21. package/dist/{use-widget-ref-BFazQvJK.js → use-widget-ref-Ddr_SlJJ.js} +2 -2
  22. package/dist/{use-widget-ref-BFazQvJK.js.map → use-widget-ref-Ddr_SlJJ.js.map} +1 -1
  23. package/dist/{use-widget-selector-DqRmWQ1K.js → use-widget-selector-DFl2hW0R.js} +2 -2
  24. package/dist/{use-widget-selector-DqRmWQ1K.js.map → use-widget-selector-DFl2hW0R.js.map} +1 -1
  25. package/dist/{widget-store-CIrb9RKP.js → widget-store-Bw5zRUGg.js} +93 -95
  26. package/dist/widget-store-Bw5zRUGg.js.map +1 -0
  27. package/dist/widgets/actions.js +770 -755
  28. package/dist/widgets/actions.js.map +1 -1
  29. package/dist/widgets/bar.js +2 -2
  30. package/dist/widgets/category.js +3 -3
  31. package/dist/widgets/category.js.map +1 -1
  32. package/dist/widgets/echart.js +2 -2
  33. package/dist/widgets/error.js +37 -2
  34. package/dist/widgets/error.js.map +1 -1
  35. package/dist/widgets/formula.js +5 -5
  36. package/dist/widgets/histogram.js +1 -1
  37. package/dist/widgets/loader.js +1 -1
  38. package/dist/widgets/markdown.js +2 -2
  39. package/dist/widgets/no-data.js +58 -2
  40. package/dist/widgets/no-data.js.map +1 -1
  41. package/dist/widgets/note.js +121 -2
  42. package/dist/widgets/note.js.map +1 -1
  43. package/dist/widgets/pie.js +2 -2
  44. package/dist/widgets/range.js +3 -3
  45. package/dist/widgets/scatterplot.js +2 -2
  46. package/dist/widgets/skeleton-loader.js +1 -1
  47. package/dist/widgets/spread.js +5 -5
  48. package/dist/widgets/stores.js +2 -2
  49. package/dist/widgets/table.js +3 -3
  50. package/dist/widgets/timeseries.js +2 -2
  51. package/dist/widgets/utils.js +1 -1
  52. package/dist/widgets/wrapper.js +2 -2
  53. package/package.json +2 -6
  54. package/src/hooks/index.ts +0 -1
  55. package/src/widgets/actions/brush-toggle/brush-toggle.tsx +18 -22
  56. package/src/widgets/actions/change-column/change-column.test.tsx +1 -1
  57. package/src/widgets/actions/download/download.test.tsx +1 -1
  58. package/src/widgets/actions/index.ts +11 -2
  59. package/src/widgets/actions/lock-selection/lock-selection.test.tsx +14 -0
  60. package/src/widgets/actions/lock-selection/lock-selection.tsx +18 -11
  61. package/src/widgets/actions/lock-selection/types.ts +2 -0
  62. package/src/widgets/actions/relative-data/relative-data.test.tsx +211 -20
  63. package/src/widgets/actions/relative-data/relative-data.tsx +65 -34
  64. package/src/widgets/actions/relative-data/types.ts +2 -0
  65. package/src/widgets/actions/searcher/searcher.tsx +28 -30
  66. package/src/widgets/actions/stack-toggle/stack-toggle.tsx +11 -2
  67. package/src/widgets/actions/zoom-toggle/zoom-toggle.tsx +53 -45
  68. package/src/widgets/category/category-ui.tsx +4 -6
  69. package/src/widgets/category/index.ts +13 -14
  70. package/src/widgets/no-data/no-data.test.tsx +90 -40
  71. package/src/widgets/no-data/no-data.tsx +7 -5
  72. package/src/widgets/no-data/types.ts +5 -1
  73. package/src/widgets/stores/index.ts +2 -0
  74. package/src/widgets/stores/types.ts +10 -18
  75. package/src/widgets/stores/widget-store.test.ts +132 -13
  76. package/src/widgets/stores/widget-store.ts +29 -35
  77. package/src/widgets/table/index.ts +6 -4
  78. package/dist/error-Cj8eUMrl.js +0 -40
  79. package/dist/error-Cj8eUMrl.js.map +0 -1
  80. package/dist/no-data-DkIt7Qt1.js +0 -61
  81. package/dist/no-data-DkIt7Qt1.js.map +0 -1
  82. package/dist/note-t51drNe0.js +0 -124
  83. package/dist/note-t51drNe0.js.map +0 -1
  84. package/dist/types/hooks/use-debounce.d.ts +0 -19
  85. package/dist/types/widgets/category/components/index.d.ts +0 -10
  86. package/dist/types/widgets/index.d.ts +0 -9
  87. package/dist/types/widgets/table/hooks/index.d.ts +0 -6
  88. package/dist/widget-store-CIrb9RKP.js.map +0 -1
  89. package/dist/widgets.js +0 -13
  90. package/dist/widgets.js.map +0 -1
  91. package/src/hooks/use-debounce.ts +0 -55
  92. package/src/widgets/category/components/index.ts +0 -14
  93. package/src/widgets/index.ts +0 -25
  94. package/src/widgets/table/hooks/index.ts +0 -7
@@ -1,5 +1,6 @@
1
1
  import { describe, it, expect, beforeEach } from 'vitest'
2
2
  import { useWidgetStore } from './widget-store'
3
+ import type { ToolRegistration } from './types'
3
4
 
4
5
  describe('WidgetStore', () => {
5
6
  beforeEach(() => {
@@ -465,6 +466,82 @@ describe('WidgetStore', () => {
465
466
  })
466
467
  })
467
468
 
469
+ describe('executeToolPipeline sourceData', () => {
470
+ const widgetId = 'test-widget-source'
471
+
472
+ beforeEach(() => {
473
+ useWidgetStore.getState().clearWidgets()
474
+ })
475
+
476
+ it('stores sourceData alongside data after pipeline execution', async () => {
477
+ useWidgetStore.getState().setWidget(widgetId, {
478
+ type: 'bar',
479
+ isLoading: false,
480
+ })
481
+
482
+ const source = [{ value: 1 }, { value: 2 }]
483
+ await useWidgetStore.getState().executeToolPipeline(widgetId, source)
484
+
485
+ const widget = useWidgetStore.getState().getWidget(widgetId)
486
+ expect(widget?.sourceData).toBe(source)
487
+ expect(widget?.data).toBe(source) // No tools, passthrough
488
+ })
489
+
490
+ it('preserves sourceData when a tool transforms data to empty', async () => {
491
+ useWidgetStore.getState().setWidget(widgetId, {
492
+ type: 'bar',
493
+ isLoading: false,
494
+ })
495
+
496
+ const emptyFilterTool: ToolRegistration = {
497
+ id: 'empty-filter',
498
+ order: 10,
499
+ enabled: true,
500
+ fn: () => [], // Transforms any data to empty array
501
+ }
502
+
503
+ useWidgetStore.getState().registerTool(widgetId, emptyFilterTool)
504
+
505
+ const source = [{ value: 1 }, { value: 2 }]
506
+ await useWidgetStore.getState().executeToolPipeline(widgetId, source)
507
+
508
+ const widget = useWidgetStore.getState().getWidget(widgetId)
509
+ expect(widget?.sourceData).toBe(source)
510
+ expect(widget?.data).toEqual([])
511
+ })
512
+
513
+ it('updates sourceData when input changes but pipeline output stays the same', async () => {
514
+ useWidgetStore.getState().setWidget(widgetId, {
515
+ type: 'bar',
516
+ isLoading: false,
517
+ })
518
+
519
+ const constantTool: ToolRegistration = {
520
+ id: 'constant',
521
+ order: 10,
522
+ enabled: true,
523
+ fn: () => 'constant-output',
524
+ }
525
+
526
+ useWidgetStore.getState().registerTool(widgetId, constantTool)
527
+
528
+ const source1 = [{ value: 1 }]
529
+ await useWidgetStore.getState().executeToolPipeline(widgetId, source1)
530
+
531
+ expect(useWidgetStore.getState().getWidget(widgetId)?.sourceData).toBe(
532
+ source1,
533
+ )
534
+
535
+ const source2 = [{ value: 2 }]
536
+ await useWidgetStore.getState().executeToolPipeline(widgetId, source2)
537
+
538
+ // sourceData should reflect the new input
539
+ expect(useWidgetStore.getState().getWidget(widgetId)?.sourceData).toBe(
540
+ source2,
541
+ )
542
+ })
543
+ })
544
+
468
545
  describe('Config Tool Pipeline', () => {
469
546
  const widgetId = 'test-widget-config'
470
547
 
@@ -478,7 +555,7 @@ describe('WidgetStore', () => {
478
555
  isLoading: false,
479
556
  })
480
557
 
481
- const configTool: import('./types').ToolRegistration = {
558
+ const configTool: ToolRegistration = {
482
559
  id: 'stack-tool',
483
560
  type: 'config',
484
561
  order: 10,
@@ -536,7 +613,7 @@ describe('WidgetStore', () => {
536
613
  isLoading: false,
537
614
  })
538
615
 
539
- const dataTool: import('./types').ToolRegistration = {
616
+ const dataTool: ToolRegistration = {
540
617
  id: 'data-tool',
541
618
  type: 'data',
542
619
  order: 10,
@@ -547,7 +624,7 @@ describe('WidgetStore', () => {
547
624
  },
548
625
  }
549
626
 
550
- const configTool: import('./types').ToolRegistration = {
627
+ const configTool: ToolRegistration = {
551
628
  id: 'config-tool',
552
629
  type: 'config',
553
630
  order: 10,
@@ -575,7 +652,7 @@ describe('WidgetStore', () => {
575
652
  isLoading: false,
576
653
  })
577
654
 
578
- const configTool: import('./types').ToolRegistration = {
655
+ const configTool: ToolRegistration = {
579
656
  id: 'config-tool',
580
657
  type: 'config',
581
658
  order: 10,
@@ -586,7 +663,7 @@ describe('WidgetStore', () => {
586
663
  },
587
664
  }
588
665
 
589
- const disablerTool: import('./types').ToolRegistration = {
666
+ const disablerTool: ToolRegistration = {
590
667
  id: 'disabler',
591
668
  type: 'data',
592
669
  order: 10,
@@ -687,6 +764,48 @@ describe('WidgetStore', () => {
687
764
  })
688
765
  })
689
766
 
767
+ describe('triggerToolPipeline', () => {
768
+ const widgetId = 'test-widget-trigger'
769
+
770
+ beforeEach(() => {
771
+ useWidgetStore.getState().clearWidgets()
772
+ })
773
+
774
+ it('creates new registeredTools reference', () => {
775
+ useWidgetStore.getState().setWidget(widgetId, {
776
+ type: 'bar',
777
+ isLoading: false,
778
+ })
779
+
780
+ useWidgetStore.getState().registerTool(widgetId, {
781
+ id: 'my-tool',
782
+ order: 10,
783
+ enabled: true,
784
+ fn: (data) => data,
785
+ })
786
+
787
+ const toolsBefore =
788
+ useWidgetStore.getState().widgets[widgetId]?.registeredTools
789
+
790
+ useWidgetStore.getState().triggerToolPipeline(widgetId)
791
+
792
+ const toolsAfter =
793
+ useWidgetStore.getState().widgets[widgetId]?.registeredTools
794
+
795
+ // New reference — triggers Effect 4 in WidgetLoader
796
+ expect(toolsBefore).not.toBe(toolsAfter)
797
+
798
+ // But same content
799
+ expect(toolsAfter?.length).toBe(toolsBefore?.length)
800
+ expect(toolsAfter?.[0]?.id).toBe(toolsBefore?.[0]?.id)
801
+ })
802
+
803
+ it('does nothing for non-existent widget', () => {
804
+ useWidgetStore.getState().triggerToolPipeline('non-existent')
805
+ // No error thrown
806
+ })
807
+ })
808
+
690
809
  describe('Tool Dependency Management', () => {
691
810
  const widgetId = 'test-widget-deps'
692
811
 
@@ -698,7 +817,7 @@ describe('WidgetStore', () => {
698
817
  it('skips tools disabled by other enabled tools', async () => {
699
818
  const executionOrder: string[] = []
700
819
 
701
- const toolA: import('./types').ToolRegistration = {
820
+ const toolA: ToolRegistration = {
702
821
  id: 'tool-a',
703
822
  order: 10,
704
823
  enabled: true,
@@ -708,7 +827,7 @@ describe('WidgetStore', () => {
708
827
  },
709
828
  }
710
829
 
711
- const toolB: import('./types').ToolRegistration = {
830
+ const toolB: ToolRegistration = {
712
831
  id: 'tool-b',
713
832
  order: 20,
714
833
  enabled: true,
@@ -718,7 +837,7 @@ describe('WidgetStore', () => {
718
837
  },
719
838
  }
720
839
 
721
- const toolC: import('./types').ToolRegistration = {
840
+ const toolC: ToolRegistration = {
722
841
  id: 'tool-c',
723
842
  order: 30,
724
843
  enabled: true,
@@ -743,7 +862,7 @@ describe('WidgetStore', () => {
743
862
  it('includes tool when disabling tool is not enabled', async () => {
744
863
  const executionOrder: string[] = []
745
864
 
746
- const toolA: import('./types').ToolRegistration = {
865
+ const toolA: ToolRegistration = {
747
866
  id: 'tool-a',
748
867
  order: 10,
749
868
  enabled: true,
@@ -753,7 +872,7 @@ describe('WidgetStore', () => {
753
872
  },
754
873
  }
755
874
 
756
- const toolB: import('./types').ToolRegistration = {
875
+ const toolB: ToolRegistration = {
757
876
  id: 'tool-b',
758
877
  order: 20,
759
878
  enabled: false, // Disabled
@@ -776,7 +895,7 @@ describe('WidgetStore', () => {
776
895
  it('handles multiple tools disabling the same target', async () => {
777
896
  const executionOrder: string[] = []
778
897
 
779
- const toolA: import('./types').ToolRegistration = {
898
+ const toolA: ToolRegistration = {
780
899
  id: 'tool-a',
781
900
  order: 10,
782
901
  enabled: true,
@@ -786,7 +905,7 @@ describe('WidgetStore', () => {
786
905
  },
787
906
  }
788
907
 
789
- const toolB: import('./types').ToolRegistration = {
908
+ const toolB: ToolRegistration = {
790
909
  id: 'tool-b',
791
910
  order: 20,
792
911
  enabled: true,
@@ -797,7 +916,7 @@ describe('WidgetStore', () => {
797
916
  disables: ['tool-a'],
798
917
  }
799
918
 
800
- const toolC: import('./types').ToolRegistration = {
919
+ const toolC: ToolRegistration = {
801
920
  id: 'tool-c',
802
921
  order: 30,
803
922
  enabled: true,
@@ -18,9 +18,8 @@ const activeConfigPipelines = new Map<string, number>()
18
18
  *
19
19
  * **Performance optimizations:**
20
20
  * - `registerTool` skips the store update when structural properties (order, enabled,
21
- * type, disables) haven't changed — only `fn` and `config` are updated via direct
22
- * mutation, avoiding a new `registeredTools` array reference and WidgetLoader
23
- * pipeline cascades.
21
+ * type, disables) haven't changed — only `fn` is updated via direct mutation,
22
+ * avoiding a new `registeredTools` array reference and WidgetLoader pipeline cascades.
24
23
  * - `setToolEnabled` skips the store update when the enabled state is already the
25
24
  * requested value.
26
25
  * - `executeToolPipeline` / `executeConfigPipeline` skip the final `set()` when
@@ -95,9 +94,9 @@ export const useWidgetStore = create<WidgetStore>()((set, get) => ({
95
94
  *
96
95
  * **No-op optimization:** When a tool with the same `id` already exists and its
97
96
  * structural properties (`order`, `enabled`, `type`, `disables`) are unchanged,
98
- * only `fn` and `config` are updated via direct mutation — no store update is
99
- * triggered. This allows action components to include all reactive dependencies
100
- * in their `useEffect` arrays without causing WidgetLoader pipeline cascades.
97
+ * only `fn` is updated via direct mutation — no store update is triggered. This
98
+ * allows action components to include all reactive dependencies in their
99
+ * `useEffect` arrays without causing WidgetLoader pipeline cascades.
101
100
  */
102
101
  registerTool: (widgetId: string, tool: ToolRegistration) => {
103
102
  const current = get().widgets[widgetId]
@@ -105,8 +104,8 @@ export const useWidgetStore = create<WidgetStore>()((set, get) => ({
105
104
  (t: ToolRegistration) => t.id === tool.id,
106
105
  )
107
106
 
108
- // No-op: structural properties unchanged — update fn/config via direct mutation.
109
- // Safe because fn and config are only consumed imperatively during pipeline execution.
107
+ // No-op: structural properties unchanged — update fn via direct mutation.
108
+ // Safe because fn is only consumed imperatively during pipeline execution.
110
109
  if (
111
110
  existingTool?.order === tool.order &&
112
111
  existingTool.enabled === tool.enabled &&
@@ -114,7 +113,6 @@ export const useWidgetStore = create<WidgetStore>()((set, get) => ({
114
113
  existingTool.disables === tool.disables
115
114
  ) {
116
115
  existingTool.fn = tool.fn
117
- if (tool.config) existingTool.config = tool.config
118
116
  return
119
117
  }
120
118
 
@@ -161,31 +159,22 @@ export const useWidgetStore = create<WidgetStore>()((set, get) => ({
161
159
  }
162
160
  }),
163
161
 
164
- updateToolConfig: (
165
- widgetId: string,
166
- toolId: string,
167
- config: Record<string, unknown>,
168
- ) =>
162
+ /**
163
+ * Triggers pipeline re-execution by creating a new `registeredTools` reference.
164
+ * This is a lightweight operation that only bumps the array reference without
165
+ * modifying any tool.
166
+ */
167
+ triggerToolPipeline: (widgetId: string) =>
169
168
  set((state) => {
170
- const current = state.widgets[widgetId]
171
- if (!current) return state
172
-
173
- const registeredTools = current.registeredTools ?? []
174
- const updatedTools = registeredTools.map((tool: ToolRegistration) =>
175
- tool.id === toolId
176
- ? {
177
- ...tool,
178
- config: { ...tool.config, ...config },
179
- }
180
- : tool,
181
- )
169
+ const widget = state.widgets[widgetId]
170
+ if (!widget) return state
182
171
 
183
172
  return {
184
173
  widgets: {
185
174
  ...state.widgets,
186
175
  [widgetId]: {
187
- ...current,
188
- registeredTools: updatedTools,
176
+ ...widget,
177
+ registeredTools: [...(widget.registeredTools ?? [])],
189
178
  },
190
179
  },
191
180
  }
@@ -277,7 +266,7 @@ export const useWidgetStore = create<WidgetStore>()((set, get) => ({
277
266
 
278
267
  try {
279
268
  // Call tool function (may return Promise or direct value)
280
- transformedData = await tool.fn(transformedData, tool.config)
269
+ transformedData = await tool.fn(transformedData)
281
270
  } catch (error) {
282
271
  // eslint-disable-next-line no-console
283
272
  console.error(`Tool ${tool.id} failed for widget ${widgetId}:`, error)
@@ -285,9 +274,13 @@ export const useWidgetStore = create<WidgetStore>()((set, get) => ({
285
274
  }
286
275
  }
287
276
 
288
- // Skip store update if data hasn't changed (e.g., passthrough pipeline with no tools)
277
+ // Skip store update if neither data nor sourceData changed
289
278
  const widgetAfter = get().widgets[widgetId]
290
- if (widgetAfter && Object.is(widgetAfter.data, transformedData)) {
279
+ if (
280
+ widgetAfter &&
281
+ Object.is(widgetAfter.data, transformedData) &&
282
+ Object.is(widgetAfter.sourceData, sourceData)
283
+ ) {
291
284
  if (activePipelines.get(widgetId) === currentExecution) {
292
285
  activePipelines.delete(widgetId)
293
286
  }
@@ -304,6 +297,7 @@ export const useWidgetStore = create<WidgetStore>()((set, get) => ({
304
297
  ...state.widgets,
305
298
  [widgetId]: {
306
299
  ...currentWidget,
300
+ sourceData,
307
301
  data: transformedData,
308
302
  },
309
303
  },
@@ -362,7 +356,7 @@ export const useWidgetStore = create<WidgetStore>()((set, get) => ({
362
356
  }
363
357
 
364
358
  try {
365
- transformedConfig = await tool.fn(transformedConfig, tool.config)
359
+ transformedConfig = await tool.fn(transformedConfig)
366
360
  } catch (error) {
367
361
  // eslint-disable-next-line no-console
368
362
  console.error(
@@ -476,12 +470,12 @@ export const widgetStoreActions: WidgetStoreActions = {
476
470
  get unregisterTool() {
477
471
  return useWidgetStore.getState().unregisterTool
478
472
  },
479
- get updateToolConfig() {
480
- return useWidgetStore.getState().updateToolConfig
481
- },
482
473
  get setToolEnabled() {
483
474
  return useWidgetStore.getState().setToolEnabled
484
475
  },
476
+ get triggerToolPipeline() {
477
+ return useWidgetStore.getState().triggerToolPipeline
478
+ },
485
479
  get executeToolPipeline() {
486
480
  return useWidgetStore.getState().executeToolPipeline
487
481
  },
@@ -8,7 +8,9 @@ export { PaginationActions } from './components/pagination-actions'
8
8
  export { Table } from './table-ui'
9
9
 
10
10
  // Hooks
11
- export { usePagination, useSort, useSelection } from './hooks'
11
+ export { usePagination } from './hooks/use-pagination'
12
+ export { useSort } from './hooks/use-sort'
13
+ export { useSelection } from './hooks/use-selection'
12
14
 
13
15
  // Config
14
16
  export { tableConfig, tableDownloadConfig } from './config'
@@ -45,9 +47,9 @@ export type {
45
47
  PaginationActionsProps,
46
48
  } from './types'
47
49
 
50
+ export type { UsePaginationResult } from './hooks/use-pagination'
51
+ export type { UseSortResult } from './hooks/use-sort'
48
52
  export type {
49
- UsePaginationResult,
50
- UseSortResult,
51
53
  UseSelectionOptions,
52
54
  UseSelectionResult,
53
- } from './hooks'
55
+ } from './hooks/use-selection'
@@ -1,40 +0,0 @@
1
- import { jsx as m, jsxs as u } from "react/jsx-runtime";
2
- import { c as h } from "react/compiler-runtime";
3
- import { AlertTitle as p, Alert as x } from "@mui/material";
4
- import { u as A } from "./use-widget-selector-DqRmWQ1K.js";
5
- function E(t) {
6
- const r = h(5), {
7
- id: l,
8
- children: c,
9
- title: d,
10
- description: g
11
- } = t, {
12
- isLoading: a,
13
- isFetching: f,
14
- error: o
15
- } = A(l, F);
16
- if (a || f)
17
- return c;
18
- if (o) {
19
- const n = d ?? o.title ?? "Error", s = g ?? o.message ?? "An error occurred while loading the widget. Please try again.";
20
- let e;
21
- r[0] !== n ? (e = /* @__PURE__ */ m(p, { children: n }), r[0] = n, r[1] = e) : e = r[1];
22
- let i;
23
- return r[2] !== s || r[3] !== e ? (i = /* @__PURE__ */ u(x, { severity: "error", children: [
24
- e,
25
- s
26
- ] }), r[2] = s, r[3] = e, r[4] = i) : i = r[4], i;
27
- }
28
- return c;
29
- }
30
- function F(t) {
31
- return {
32
- isLoading: t?.isLoading,
33
- isFetching: t?.isFetching,
34
- error: t?.error
35
- };
36
- }
37
- export {
38
- E as W
39
- };
40
- //# sourceMappingURL=error-Cj8eUMrl.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"error-Cj8eUMrl.js","sources":["../src/widgets/error/error.tsx"],"sourcesContent":["import { Alert, AlertTitle } from '@mui/material'\nimport { useWidgetSelector } from '../stores/use-widget-selector'\nimport type { WidgetErrorProps } from './types'\n\n/**\n * Displays an error alert when a widget encounters an error during data loading. Reads error state from the widget store and hides errors during loading/fetching to prevent flashing.\n *\n * @example\n * ```tsx\n * <WidgetError id=\"my-widget\">\n * <WidgetContent />\n * </WidgetError>\n * ```\n */\nexport function WidgetError({\n id,\n children,\n title: titleProp,\n description,\n}: WidgetErrorProps) {\n // Single consolidated subscription instead of 3 separate ones.\n const { isLoading, isFetching, error } = useWidgetSelector(id, (w) => ({\n isLoading: w?.isLoading,\n isFetching: w?.isFetching,\n error: w?.error,\n }))\n\n // Don't show error during loading/fetching states\n if (isLoading || isFetching) {\n return children\n }\n\n // Show error UI if error exists\n if (error) {\n const errorTitle = titleProp ?? error.title ?? 'Error'\n const errorMessage =\n description ??\n error.message ??\n 'An error occurred while loading the widget. Please try again.'\n\n return (\n <Alert severity='error'>\n <AlertTitle>{errorTitle}</AlertTitle>\n {errorMessage}\n </Alert>\n )\n }\n\n // No error, render children\n return children\n}\n"],"names":["WidgetError","t0","$","_c","id","children","title","titleProp","description","isLoading","isFetching","error","useWidgetSelector","_temp","errorTitle","errorMessage","message","t1","AlertTitle","t2","jsxs","Alert","w"],"mappings":";;;;AAcO,SAAAA,EAAAC,GAAA;AAAA,QAAAC,IAAAC,EAAA,CAAA,GAAqB;AAAA,IAAAC,IAAAA;AAAAA,IAAAC,UAAAA;AAAAA,IAAAC,OAAAC;AAAAA,IAAAC,aAAAA;AAAAA,EAAAA,IAAAP,GAO1B;AAAA,IAAAQ,WAAAA;AAAAA,IAAAC,YAAAA;AAAAA,IAAAC,OAAAA;AAAAA,EAAAA,IAAyCC,EAAkBR,GAAIS,CAI7D;AAGF,MAAIJ,KAAAC;AAAuB,WAClBL;AAIT,MAAIM,GAAK;AACP,UAAAG,IAAmBP,KAAaI,EAAKL,SAAlB,SACnBS,IACEP,KACAG,EAAKK,WADL;AAE+D,QAAAC;AAAA,IAAAf,SAAAY,KAI7DG,sBAACC,kBAAuB,GAAahB,OAAAY,GAAAZ,OAAAe,KAAAA,IAAAf,EAAA,CAAA;AAAA,QAAAiB;AAAA,WAAAjB,EAAA,CAAA,MAAAa,KAAAb,SAAAe,KADvCE,IAAA,gBAAAC,EAACC,GAAA,EAAe,UAAA,SACdJ,UAAAA;AAAAA,MAAAA;AAAAA,MACCF;AAAAA,IAAAA,GACH,GAAQb,OAAAa,GAAAb,OAAAe,GAAAf,OAAAiB,KAAAA,IAAAjB,EAAA,CAAA,GAHRiB;AAAAA,EAGQ;AAEX,SAGMd;AAAQ;AAnCV,SAAAQ,EAAAS,GAAA;AAAA,SAOkE;AAAA,IAAAb,WAC1Da,GAACb;AAAAA,IAAWC,YACXY,GAACZ;AAAAA,IAAYC,OAClBW,GAACX;AAAAA,EAAAA;AACT;"}
@@ -1,61 +0,0 @@
1
- import { jsx as f, jsxs as x } from "react/jsx-runtime";
2
- import { c as v } from "react/compiler-runtime";
3
- import { Typography as p, Box as b } from "@mui/material";
4
- import { u as j } from "./use-widget-selector-DqRmWQ1K.js";
5
- const A = {
6
- root: {
7
- display: "flex",
8
- flexDirection: "column",
9
- gap: 1,
10
- // 8px
11
- paddingTop: 1,
12
- // 8px
13
- paddingBottom: 2,
14
- // 16px
15
- paddingX: 2,
16
- // 16px
17
- width: "100%",
18
- minHeight: "100%"
19
- }
20
- };
21
- function B(e) {
22
- const t = v(7), {
23
- id: u,
24
- children: a,
25
- title: l,
26
- description: c,
27
- isEmpty: d
28
- } = e, n = l === void 0 ? "No data available" : l, s = c === void 0 ? "There are no results for the combination of filters applied to your data. Try tweaking your filters, or zoom and pan the map to adjust filters" : c, y = d === void 0 ? E : d, {
29
- isLoading: g,
30
- isFetching: m,
31
- data: h
32
- } = j(u, T);
33
- if (g || m)
34
- return a;
35
- if (y(h)) {
36
- let r;
37
- t[0] !== n ? (r = /* @__PURE__ */ f(p, { variant: "body2", color: "text.primary", children: n }), t[0] = n, t[1] = r) : r = t[1];
38
- let i;
39
- t[2] !== s ? (i = /* @__PURE__ */ f(p, { variant: "caption", color: "text.secondary", children: s }), t[2] = s, t[3] = i) : i = t[3];
40
- let o;
41
- return t[4] !== r || t[5] !== i ? (o = /* @__PURE__ */ x(b, { sx: A.root, children: [
42
- r,
43
- i
44
- ] }), t[4] = r, t[5] = i, t[6] = o) : o = t[6], o;
45
- }
46
- return a;
47
- }
48
- function T(e) {
49
- return {
50
- isLoading: e?.isLoading,
51
- isFetching: e?.isFetching,
52
- data: e?.data
53
- };
54
- }
55
- function E(e) {
56
- return e == null ? !0 : Array.isArray(e) ? !!(e.length === 0 || e.every((t) => Array.isArray(t) && t.length === 0)) : typeof e == "object" ? Object.keys(e).length === 0 : !1;
57
- }
58
- export {
59
- B as W
60
- };
61
- //# sourceMappingURL=no-data-DkIt7Qt1.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"no-data-DkIt7Qt1.js","sources":["../src/widgets/no-data/style.ts","../src/widgets/no-data/no-data.tsx"],"sourcesContent":["import type { SxProps, Theme } from '@mui/material'\n\n/**\n * Styles for NoData component matching Figma design specifications\n * Design reference: node 5781-11028\n */\nexport const styles: Record<string, SxProps<Theme>> = {\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: 1, // 8px\n paddingTop: 1, // 8px\n paddingBottom: 2, // 16px\n paddingX: 2, // 16px\n width: '100%',\n minHeight: '100%',\n },\n}\n","import { Box, Typography } from '@mui/material'\nimport { useWidgetSelector } from '../stores/use-widget-selector'\nimport type { WidgetNoDataProps } from './types'\nimport { styles } from './style'\n\n/**\n * NoData wrapper component that displays empty state UI when widget has no data\n *\n * Integrates with widget store to check loading/fetching state and data availability.\n * Works in conjunction with SkeletonLoader for complete loading/empty state handling.\n *\n * @example Basic usage\n * ```tsx\n * <NoData id=\"my-widget\">\n * <WidgetContent id=\"my-widget\" />\n * </NoData>\n * ```\n *\n * @example With SkeletonLoader\n * ```tsx\n * <SkeletonLoader id=\"my-widget\" Skeleton={MySkeleton}>\n * <NoData id=\"my-widget\">\n * <WidgetContent id=\"my-widget\" />\n * </NoData>\n * </SkeletonLoader>\n * ```\n *\n * @example With custom messages\n * ```tsx\n * <NoData\n * id=\"my-widget\"\n * title=\"No results found\"\n * description=\"Try adjusting your filters\"\n * >\n * <WidgetContent id=\"my-widget\" />\n * </NoData>\n * ```\n */\nexport function WidgetNoData({\n id,\n children,\n title = 'No data available',\n description = 'There are no results for the combination of filters applied to your data. Try tweaking your filters, or zoom and pan the map to adjust filters',\n isEmpty = defaultIsEmpty,\n}: WidgetNoDataProps) {\n // Single consolidated subscription instead of 3 separate ones.\n const { isLoading, isFetching, data } = useWidgetSelector(id, (w) => ({\n isLoading: w?.isLoading,\n isFetching: w?.isFetching,\n data: w?.data,\n }))\n\n // If loading or fetching, show children\n // SkeletonLoader handles loading state, this allows proper composition\n if (isLoading || isFetching) {\n return children\n }\n\n // Check if data is empty\n if (isEmpty(data)) {\n return (\n <Box sx={styles.root}>\n <Typography variant='body2' color='text.primary'>\n {title}\n </Typography>\n <Typography variant='caption' color='text.secondary'>\n {description}\n </Typography>\n </Box>\n )\n }\n\n // Data exists, render children\n return children\n}\n\n/**\n * Default function to determine if data is empty\n * Handles various data structures commonly used in widgets\n */\nfunction defaultIsEmpty(data: unknown): boolean {\n // Null or undefined\n if (data == null) {\n return true\n }\n\n // Arrays (most common case)\n if (Array.isArray(data)) {\n // Empty array\n if (data.length === 0) {\n return true\n }\n\n // Array of arrays (CategoryWidget pattern: [[],[]])\n // Check if all inner arrays are empty\n if (data.every((item) => Array.isArray(item) && item.length === 0)) {\n return true\n }\n\n return false\n }\n\n // Objects\n if (typeof data === 'object') {\n return Object.keys(data).length === 0\n }\n\n // Primitives (numbers, strings, booleans) are considered valid data\n return false\n}\n"],"names":["styles","root","display","flexDirection","gap","paddingTop","paddingBottom","paddingX","width","minHeight","WidgetNoData","t0","$","_c","id","children","title","t1","description","t2","isEmpty","t3","undefined","defaultIsEmpty","isLoading","isFetching","data","useWidgetSelector","_temp","t4","Typography","t5","t6","Box","w","Array","isArray","length","every","item","Object","keys"],"mappings":";;;;AAMO,MAAMA,IAAyC;AAAA,EACpDC,MAAM;AAAA,IACJC,SAAS;AAAA,IACTC,eAAe;AAAA,IACfC,KAAK;AAAA;AAAA,IACLC,YAAY;AAAA;AAAA,IACZC,eAAe;AAAA;AAAA,IACfC,UAAU;AAAA;AAAA,IACVC,OAAO;AAAA,IACPC,WAAW;AAAA,EAAA;AAEf;ACqBO,SAAAC,EAAAC,GAAA;AAAA,QAAAC,IAAAC,EAAA,CAAA,GAAsB;AAAA,IAAAC,IAAAA;AAAAA,IAAAC,UAAAA;AAAAA,IAAAC,OAAAC;AAAAA,IAAAC,aAAAC;AAAAA,IAAAC,SAAAC;AAAAA,EAAAA,IAAAV,GAG3BK,IAAAC,MAAAK,SAAA,sBAAAL,GACAC,IAAAC,MAAAG,SAAA,mJAAAH,GACAC,IAAAC,MAAAC,SAAAC,IAAAF,GAGA;AAAA,IAAAG,WAAAA;AAAAA,IAAAC,YAAAA;AAAAA,IAAAC,MAAAA;AAAAA,EAAAA,IAAwCC,EAAkBb,GAAIc,CAI5D;AAIF,MAAIJ,KAAAC;AAAuB,WAClBV;AAIT,MAAIK,EAAQM,CAAI,GAAC;AAAA,QAAAG;AAAA,IAAAjB,SAAAI,KAGXa,sBAACC,GAAA,EAAmB,SAAA,SAAc,OAAA,gBAC/Bd,UAAAA,GACH,GAAaJ,OAAAI,GAAAJ,OAAAiB,KAAAA,IAAAjB,EAAA,CAAA;AAAA,QAAAmB;AAAA,IAAAnB,SAAAM,KACba,sBAACD,GAAA,EAAmB,SAAA,WAAgB,OAAA,kBACjCZ,UAAAA,GACH,GAAaN,OAAAM,GAAAN,OAAAmB,KAAAA,IAAAnB,EAAA,CAAA;AAAA,QAAAoB;AAAA,WAAApB,EAAA,CAAA,MAAAiB,KAAAjB,SAAAmB,KANfC,sBAACC,GAAA,EAAQ,IAAAjC,EAAMC,MACb4B,UAAAA;AAAAA,MAAAA;AAAAA,MAGAE;AAAAA,IAAAA,GAGF,GAAMnB,OAAAiB,GAAAjB,OAAAmB,GAAAnB,OAAAoB,KAAAA,IAAApB,EAAA,CAAA,GAPNoB;AAAAA,EAOM;AAET,SAGMjB;AAAQ;AAnCV,SAAAa,EAAAM,GAAA;AAAA,SAQiE;AAAA,IAAAV,WACzDU,GAACV;AAAAA,IAAWC,YACXS,GAACT;AAAAA,IAAYC,MACnBQ,GAACR;AAAAA,EAAAA;AACR;AA8BH,SAASH,EAAeG,GAAwB;AAE9C,SAAIA,KAAQ,OACH,KAILS,MAAMC,QAAQV,CAAI,IAEhBA,GAAAA,EAAKW,WAAW,KAMhBX,EAAKY,MAAOC,CAAAA,MAASJ,MAAMC,QAAQG,CAAI,KAAKA,EAAKF,WAAW,CAAC,KAQ/D,OAAOX,KAAS,WACXc,OAAOC,KAAKf,CAAI,EAAEW,WAAW,IAI/B;AACT;"}
@@ -1,124 +0,0 @@
1
- import { jsx as p, jsxs as N } from "react/jsx-runtime";
2
- import { c as R } from "react/compiler-runtime";
3
- import { useState as _, useRef as j, useEffectEvent as z, useEffect as M } from "react";
4
- import { Button as F, Box as W, Link as H, Typography as P } from "@mui/material";
5
- import U from "react-markdown";
6
- const L = {
7
- root: {
8
- typography: "caption",
9
- color: (n) => n.palette.text.secondary,
10
- marginBlockStart: ({
11
- spacing: n
12
- }) => n(1)
13
- },
14
- clamped: {
15
- display: "-webkit-box",
16
- WebkitLineClamp: 3,
17
- WebkitBoxOrient: "vertical",
18
- overflow: "hidden"
19
- },
20
- expanded: {
21
- display: "block"
22
- },
23
- linkButton: {
24
- padding: 0,
25
- minWidth: "auto",
26
- textTransform: "none",
27
- typography: "caption",
28
- fontWeight: 500,
29
- textDecoration: "none",
30
- "&:hover": {
31
- backgroundColor: "transparent"
32
- }
33
- }
34
- }, C = {
35
- showMore: "Show More",
36
- showLess: "Show Less"
37
- }, l = (n) => {
38
- const e = R(2), {
39
- children: t
40
- } = n;
41
- let r;
42
- return e[0] !== t ? (r = /* @__PURE__ */ p(P, { paragraph: !0, color: "inherit", variant: "caption", children: t }), e[0] = t, e[1] = r) : r = e[1], r;
43
- }, $ = {
44
- h1: l,
45
- h2: l,
46
- h3: l,
47
- p: l,
48
- a: ({
49
- children: n,
50
- href: e,
51
- target: t = "_blank",
52
- rel: r = "noopener noreferrer"
53
- }) => /* @__PURE__ */ p(H, { href: e, target: t, rel: r, color: "text.primary", underline: "always", children: n }),
54
- img: () => null,
55
- ul: l,
56
- ol: l,
57
- li: l
58
- };
59
- function Q(n) {
60
- const e = R(27), {
61
- children: t,
62
- labels: r
63
- } = n, S = r === void 0 ? C : r, [o, A] = _(!1), [E, D] = _(!1), h = j(null);
64
- let m;
65
- e[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (m = () => {
66
- if (h.current) {
67
- const v = h.current.scrollHeight > h.current.clientHeight;
68
- D(v);
69
- }
70
- }, e[0] = m) : m = e[0];
71
- const s = z(m);
72
- let u;
73
- e[1] !== s ? (u = () => {
74
- s();
75
- }, e[1] = s, e[2] = u) : u = e[2];
76
- let g;
77
- e[3] !== t ? (g = [t], e[3] = t, e[4] = g) : g = e[4], M(u, g);
78
- let x;
79
- e[5] !== s ? (x = () => {
80
- const v = h.current;
81
- if (!v)
82
- return;
83
- const O = new ResizeObserver(() => {
84
- s();
85
- });
86
- return O.observe(v), () => {
87
- O.disconnect();
88
- };
89
- }, e[5] = s, e[6] = x) : x = e[6];
90
- let w;
91
- if (e[7] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (w = [], e[7] = w) : w = e[7], M(x, w), !t)
92
- return null;
93
- let b;
94
- e[8] !== o ? (b = () => {
95
- A(!o);
96
- }, e[8] = o, e[9] = b) : b = e[9];
97
- const T = b;
98
- let y;
99
- e[10] !== S ? (y = {
100
- ...C,
101
- ...S
102
- }, e[10] = S, e[11] = y) : y = e[11];
103
- const i = y, B = o ? L.expanded : L.clamped;
104
- let c;
105
- e[12] !== B ? (c = {
106
- ...L.root,
107
- ...B
108
- }, e[12] = B, e[13] = c) : c = e[13];
109
- let a;
110
- e[14] !== t ? (a = /* @__PURE__ */ p(U, { components: $, children: t }), e[14] = t, e[15] = a) : a = e[15];
111
- let f;
112
- e[16] !== c || e[17] !== a ? (f = /* @__PURE__ */ p(W, { ref: h, sx: c, children: a }), e[16] = c, e[17] = a, e[18] = f) : f = e[18];
113
- let d;
114
- e[19] !== T || e[20] !== o || e[21] !== i || e[22] !== E ? (d = (E || o) && /* @__PURE__ */ p(F, { onClick: T, variant: "text", color: "primary", sx: L.linkButton, "aria-expanded": o, "aria-label": o ? i.showLess : i.showMore, "aria-controls": "note-content", children: o ? i.showLess : i.showMore }), e[19] = T, e[20] = o, e[21] = i, e[22] = E, e[23] = d) : d = e[23];
115
- let k;
116
- return e[24] !== f || e[25] !== d ? (k = /* @__PURE__ */ N(W, { children: [
117
- f,
118
- d
119
- ] }), e[24] = f, e[25] = d, e[26] = k) : k = e[26], k;
120
- }
121
- export {
122
- Q as W
123
- };
124
- //# sourceMappingURL=note-t51drNe0.js.map