@carto/ps-react-ui 5.5.0 → 5.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 (51) hide show
  1. package/dist/actions-5-dVhroJ.js +1289 -0
  2. package/dist/actions-5-dVhroJ.js.map +1 -0
  3. package/dist/{category-C6myUFUJ.js → category-DBUD2ZBo.js} +267 -250
  4. package/dist/category-DBUD2ZBo.js.map +1 -0
  5. package/dist/scale-0elCv3tk.js +29 -0
  6. package/dist/scale-0elCv3tk.js.map +1 -0
  7. package/dist/types/widgets-v2/actions/index.d.ts +1 -1
  8. package/dist/types/widgets-v2/actions/relative-data/index.d.ts +1 -0
  9. package/dist/types/widgets-v2/actions/relative-data/labels.d.ts +3 -0
  10. package/dist/types/widgets-v2/actions/relative-data/relative-data.d.ts +16 -2
  11. package/dist/types/widgets-v2/actions/relative-data/scale.d.ts +26 -0
  12. package/dist/types/widgets-v2/actions/relative-data/style.d.ts +12 -0
  13. package/dist/types/widgets-v2/category/category.d.ts +2 -1
  14. package/dist/types/widgets-v2/index.d.ts +1 -1
  15. package/dist/types/widgets-v2/wrapper/collapsed-context.d.ts +7 -0
  16. package/dist/widgets-v2/actions.js +1 -1
  17. package/dist/widgets-v2/bar.js +84 -83
  18. package/dist/widgets-v2/bar.js.map +1 -1
  19. package/dist/widgets-v2/category.js +1 -1
  20. package/dist/widgets-v2/histogram.js +108 -107
  21. package/dist/widgets-v2/histogram.js.map +1 -1
  22. package/dist/widgets-v2/scatterplot.js +120 -119
  23. package/dist/widgets-v2/scatterplot.js.map +1 -1
  24. package/dist/widgets-v2/timeseries.js +90 -89
  25. package/dist/widgets-v2/timeseries.js.map +1 -1
  26. package/dist/widgets-v2.js +223 -217
  27. package/dist/widgets-v2.js.map +1 -1
  28. package/package.json +3 -3
  29. package/src/widgets-v2/actions/index.ts +1 -0
  30. package/src/widgets-v2/actions/relative-data/index.ts +1 -0
  31. package/src/widgets-v2/actions/relative-data/labels.ts +6 -0
  32. package/src/widgets-v2/actions/relative-data/relative-data.test.tsx +78 -1
  33. package/src/widgets-v2/actions/relative-data/relative-data.tsx +137 -20
  34. package/src/widgets-v2/actions/relative-data/scale.ts +48 -0
  35. package/src/widgets-v2/actions/relative-data/style.ts +10 -0
  36. package/src/widgets-v2/bar/options.test.ts +16 -0
  37. package/src/widgets-v2/bar/options.ts +6 -2
  38. package/src/widgets-v2/category/category.relative-data.test.tsx +51 -63
  39. package/src/widgets-v2/category/category.tsx +25 -11
  40. package/src/widgets-v2/histogram/options.ts +6 -2
  41. package/src/widgets-v2/index.ts +1 -0
  42. package/src/widgets-v2/scatterplot/options.test.ts +12 -0
  43. package/src/widgets-v2/scatterplot/options.ts +18 -4
  44. package/src/widgets-v2/timeseries/options.ts +6 -2
  45. package/src/widgets-v2/toolbox/toolbox.test.tsx +28 -0
  46. package/src/widgets-v2/toolbox/toolbox.tsx +9 -0
  47. package/src/widgets-v2/wrapper/collapsed-context.ts +12 -0
  48. package/src/widgets-v2/wrapper/widget-wrapper.tsx +6 -1
  49. package/dist/actions-CwjqEm8Y.js +0 -1177
  50. package/dist/actions-CwjqEm8Y.js.map +0 -1
  51. package/dist/category-C6myUFUJ.js.map +0 -1
@@ -155,6 +155,7 @@ export type {
155
155
  ZoomToggleProps,
156
156
  BrushToggleProps,
157
157
  RelativeDataProps,
158
+ RelativeScale,
158
159
  DownloadProps,
159
160
  DownloadItem,
160
161
  DownloadContext,
@@ -213,6 +213,18 @@ describe('createScatterplotOptionFactory', () => {
213
213
  expect(out.yAxis.min).toBe(0)
214
214
  })
215
215
 
216
+ it("pins the y ends a config transform set (RelativeData 'total')", () => {
217
+ const merge = createScatterplotOptionFactory({ theme })
218
+ const out = merge({ yAxis: { min: -100, max: 100 } }, [
219
+ [
220
+ [1, 47],
221
+ [2, 3],
222
+ ],
223
+ ]) as { yAxis: { min: number; max: number } }
224
+ expect(out.yAxis.max).toBe(100)
225
+ expect(out.yAxis.min).toBe(0)
226
+ })
227
+
216
228
  it('always emits itemStyle.color as a callback (passthrough when no selection)', () => {
217
229
  const merge = createScatterplotOptionFactory({ theme })
218
230
  const out = merge({}, [[[1, 2]]]) as {
@@ -21,6 +21,7 @@ import type {
21
21
  ScatterplotItem,
22
22
  ScatterplotWidgetData,
23
23
  } from './types'
24
+ import { fixedAxisBounds } from '../actions/relative-data/scale'
24
25
 
25
26
  /**
26
27
  * Builds the **structural** ECharts option for a scatterplot widget — both
@@ -189,8 +190,12 @@ export function createScatterplotOptionFactory(
189
190
 
190
191
  const reactiveFormatter = ctx?.formatter
191
192
 
192
- const { niceMinX, niceMaxX, niceMinY, niceMaxY } =
193
- computeScatterBounds(seriesArr)
193
+ const { niceMinX, niceMaxX, niceMinY, niceMaxY } = computeScatterBounds(
194
+ seriesArr,
195
+ // A config transform (RelativeData's `'total'` scale) may pin the
196
+ // y ends; each applies only on the side the data reaches.
197
+ fixedAxisBounds(baseYAxis),
198
+ )
194
199
 
195
200
  // Dim non-selected points via `series.itemStyle.color`. The selection
196
201
  // key is `${seriesIndex}:${dataIndex}`; we read those off the params
@@ -410,6 +415,7 @@ function buildScatterTooltipFormatter(
410
415
 
411
416
  function computeScatterBounds(
412
417
  seriesArr: ScatterplotWidgetData<ScatterplotItem>,
418
+ fixedY: { min?: number; max?: number } = {},
413
419
  ): {
414
420
  niceMinX: number
415
421
  niceMaxX: number
@@ -439,8 +445,16 @@ function computeScatterBounds(
439
445
  // negative mins, and floor max=0 to 1 so the chart always has range.
440
446
  // Scatter can have free coordinates so we apply this per-axis.
441
447
  const niceMaxX = Number.isFinite(maxX) ? (maxX <= 0 ? 1 : niceNum(maxX)) : 1
442
- const niceMaxY = Number.isFinite(maxY) ? (maxY <= 0 ? 1 : niceNum(maxY)) : 1
448
+ const niceMaxY = Number.isFinite(maxY)
449
+ ? maxY <= 0
450
+ ? 1
451
+ : (fixedY.max ?? niceNum(maxY))
452
+ : 1
443
453
  const niceMinX = Number.isFinite(minX) ? (minX < 0 ? niceNum(minX) : 0) : 0
444
- const niceMinY = Number.isFinite(minY) ? (minY < 0 ? niceNum(minY) : 0) : 0
454
+ const niceMinY = Number.isFinite(minY)
455
+ ? minY < 0
456
+ ? (fixedY.min ?? niceNum(minY))
457
+ : 0
458
+ : 0
445
459
  return { niceMinX, niceMaxX, niceMinY, niceMaxY }
446
460
  }
@@ -20,6 +20,7 @@ import type {
20
20
  TimeseriesOptionsInput,
21
21
  TimeseriesWidgetData,
22
22
  } from './types'
23
+ import { fixedAxisBounds } from '../actions/relative-data/scale'
23
24
 
24
25
  /**
25
26
  * Builds the **structural** ECharts option for a timeseries widget —
@@ -188,6 +189,7 @@ export function createTimeseriesOptionFactory(
188
189
  typeof option.yAxis === 'object' && !Array.isArray(option.yAxis)
189
190
  ? option.yAxis
190
191
  : {}
192
+ const fixedY = fixedAxisBounds(baseYAxis)
191
193
  const baseGrid =
192
194
  typeof option.grid === 'object' && !Array.isArray(option.grid)
193
195
  ? option.grid
@@ -302,12 +304,14 @@ export function createTimeseriesOptionFactory(
302
304
  ...(dataZoomLayout ? { dataZoom: dataZoomLayout } : {}),
303
305
  yAxis: {
304
306
  ...baseYAxis,
307
+ // A config transform (RelativeData's `'total'` scale) may pin the
308
+ // ends; each applies only on the side the data reaches.
305
309
  min: (extent: { min: number }) => {
306
- niceMin = extent.min < 0 ? niceNum(extent.min) : 0
310
+ niceMin = extent.min < 0 ? (fixedY.min ?? niceNum(extent.min)) : 0
307
311
  return niceMin
308
312
  },
309
313
  max: (extent: { min: number; max: number }) => {
310
- niceMax = extent.max <= 0 ? 1 : niceNum(extent.max)
314
+ niceMax = extent.max <= 0 ? 1 : (fixedY.max ?? niceNum(extent.max))
311
315
  return niceMax
312
316
  },
313
317
  axisLabel: {
@@ -4,6 +4,9 @@ import { fireEvent, render, screen } from '@testing-library/react'
4
4
  import { IconButton } from '@mui/material'
5
5
  import { Star as StarIcon } from '@mui/icons-material'
6
6
  import { Toolbox } from './toolbox'
7
+ import { Provider } from '../provider/widget-provider'
8
+ import { Wrapper } from '../wrapper/widget-wrapper'
9
+ import { Content } from '../wrapper/widget-content'
7
10
 
8
11
  function makeChildren(n: number) {
9
12
  return Array.from({ length: n }).map((_, i) => (
@@ -197,4 +200,29 @@ describe('<Toolbox>', () => {
197
200
  expect(isItemVisible(`Tool ${i}`)).toBe(true)
198
201
  }
199
202
  })
203
+
204
+ it('closes the overflow popper when its Wrapper collapses', () => {
205
+ render(
206
+ <Provider id='toolbox-collapse' data={[]}>
207
+ <Wrapper title='Spam'>
208
+ <Content>
209
+ <Toolbox visibleCount={2}>{makeChildren(5)}</Toolbox>
210
+ </Content>
211
+ </Wrapper>
212
+ </Provider>,
213
+ )
214
+ fireEvent.click(screen.getByLabelText('More actions'))
215
+ expect(isItemVisible('Tool 5')).toBe(true)
216
+
217
+ // The Accordion keeps its details mounted, so without this the portalled
218
+ // popper stayed floating over the page after the widget collapsed.
219
+ fireEvent.click(screen.getByRole('button', { name: 'Collapse' }))
220
+ expect(screen.queryByLabelText('Close')).toBeNull()
221
+ expect(isItemVisible('Tool 5')).toBe(false)
222
+
223
+ // Expanding again shows the closed toolbox, not the popper.
224
+ fireEvent.click(screen.getByRole('button', { name: 'Expand' }))
225
+ expect(screen.getByLabelText('More actions')).toBeTruthy()
226
+ expect(isItemVisible('Tool 5')).toBe(false)
227
+ })
200
228
  })
@@ -26,6 +26,7 @@ import { Close as CloseIcon } from '@mui/icons-material'
26
26
  import { WidgetOptions } from '@carto/meridian-ds/custom-icons'
27
27
  import { Tooltip } from '../../components'
28
28
  import { DEFAULT_TOOLBOX_LABELS, type ToolboxLabels } from './labels'
29
+ import { useWrapperCollapsed } from '../wrapper/collapsed-context'
29
30
  import { styles } from './style'
30
31
 
31
32
  export interface ToolboxProps {
@@ -166,6 +167,14 @@ export function Toolbox({
166
167
  setOpen(false)
167
168
  }
168
169
 
170
+ // Same pattern when the enclosing Wrapper collapses: its Accordion keeps
171
+ // the details mounted, so the portalled popper would otherwise stay open
172
+ // over the page with no visible trigger.
173
+ const collapsed = useWrapperCollapsed()
174
+ if (collapsed && open) {
175
+ setOpen(false)
176
+ }
177
+
169
178
  // Reparent the host into the active shell whenever `open` (or either
170
179
  // shell) changes. `useLayoutEffect` runs synchronously after commit
171
180
  // (after refs have been written), so the popover Paper ref is already
@@ -0,0 +1,12 @@
1
+ import { createContext, useContext } from 'react'
2
+
3
+ /**
4
+ * Whether the enclosing `<Wrapper>` is collapsed. The Accordion keeps its
5
+ * details mounted, so content that opens portalled UI (the Toolbox popper)
6
+ * reads this to close it. `false` outside a Wrapper.
7
+ */
8
+ export const WrapperCollapsedContext = createContext(false)
9
+
10
+ export function useWrapperCollapsed(): boolean {
11
+ return useContext(WrapperCollapsedContext)
12
+ }
@@ -24,6 +24,7 @@ import { useWidget, useWidgetId } from '../stores'
24
24
  import { Actions, Options } from './widget-actions'
25
25
  import { styles } from './style'
26
26
  import { DEFAULT_WRAPPER_LABELS, type WrapperLabels } from './labels'
27
+ import { WrapperCollapsedContext } from './collapsed-context'
27
28
 
28
29
  export interface WrapperProps {
29
30
  title: string
@@ -188,7 +189,11 @@ export function Wrapper({
188
189
  </Box>
189
190
  )}
190
191
  </Box>
191
- <AccordionDetails sx={styles.detail}>{detailsSlots}</AccordionDetails>
192
+ <AccordionDetails sx={styles.detail}>
193
+ <WrapperCollapsedContext.Provider value={effectiveCollapsed}>
194
+ {detailsSlots}
195
+ </WrapperCollapsedContext.Provider>
196
+ </AccordionDetails>
192
197
  </Accordion>
193
198
  )
194
199
  }