@carto/ps-react-ui 6.0.0 → 6.1.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 (142) hide show
  1. package/dist/actions-BWlS5tpP.js +1150 -0
  2. package/dist/actions-BWlS5tpP.js.map +1 -0
  3. package/dist/category-alzjKzvQ.js +839 -0
  4. package/dist/category-alzjKzvQ.js.map +1 -0
  5. package/dist/{download-Vlzn2jzb.js → download-B4sykOFm.js} +94 -83
  6. package/dist/download-B4sykOFm.js.map +1 -0
  7. package/dist/{echart-DjcbtKgi.js → echart-CV8F50gn.js} +6 -5
  8. package/dist/echart-CV8F50gn.js.map +1 -0
  9. package/dist/{formula-CdHWtepq.js → formula-DJS-JLpk.js} +10 -16
  10. package/dist/{formula-CdHWtepq.js.map → formula-DJS-JLpk.js.map} +1 -1
  11. package/dist/legend.js +34 -21
  12. package/dist/legend.js.map +1 -1
  13. package/dist/{markdown-CY-67NRE.js → markdown-Bn2nKCbn.js} +12 -18
  14. package/dist/{markdown-CY-67NRE.js.map → markdown-Bn2nKCbn.js.map} +1 -1
  15. package/dist/{range-DHQSsl2_.js → range-BpU2zBmq.js} +2 -2
  16. package/dist/{range-DHQSsl2_.js.map → range-BpU2zBmq.js.map} +1 -1
  17. package/dist/{spread-DuM5oTI1.js → spread-CQwFIwuz.js} +10 -16
  18. package/dist/{spread-DuM5oTI1.js.map → spread-CQwFIwuz.js.map} +1 -1
  19. package/dist/{stores-B8CHbgw-.js → stores-DcBOZlU3.js} +30 -24
  20. package/dist/stores-DcBOZlU3.js.map +1 -0
  21. package/dist/{table-BE4uO9pp.js → table-DEdW_fDj.js} +7 -13
  22. package/dist/{table-BE4uO9pp.js.map → table-DEdW_fDj.js.map} +1 -1
  23. package/dist/types/legend/stores/types.d.ts +4 -2
  24. package/dist/types/widgets/actions/download/csv-item.d.ts +3 -3
  25. package/dist/types/widgets/actions/download/index.d.ts +2 -1
  26. package/dist/types/widgets/actions/download/png-item.d.ts +2 -2
  27. package/dist/types/widgets/actions/download/types.d.ts +12 -1
  28. package/dist/types/widgets/actions/download/widget-download.d.ts +26 -0
  29. package/dist/types/widgets/actions/fullscreen/fullscreen.d.ts +20 -13
  30. package/dist/types/widgets/actions/index.d.ts +1 -1
  31. package/dist/types/widgets/actions/searcher/filter.d.ts +3 -2
  32. package/dist/types/widgets/actions/searcher/searcher-toggle.d.ts +3 -0
  33. package/dist/types/widgets/bar/download.d.ts +6 -20
  34. package/dist/types/widgets/category/category-ui.d.ts +9 -1
  35. package/dist/types/widgets/category/download.d.ts +5 -10
  36. package/dist/types/widgets/category/helpers.d.ts +10 -0
  37. package/dist/types/widgets/echart/style.d.ts +1 -0
  38. package/dist/types/widgets/formula/download.d.ts +5 -15
  39. package/dist/types/widgets/histogram/download.d.ts +3 -8
  40. package/dist/types/widgets/index.d.ts +1 -1
  41. package/dist/types/widgets/markdown/download.d.ts +5 -11
  42. package/dist/types/widgets/pie/download.d.ts +3 -8
  43. package/dist/types/widgets/scatterplot/download.d.ts +6 -11
  44. package/dist/types/widgets/spread/download.d.ts +6 -12
  45. package/dist/types/widgets/stores/index.d.ts +1 -1
  46. package/dist/types/widgets/stores/widget-store-registry.d.ts +14 -0
  47. package/dist/types/widgets/table/download.d.ts +7 -13
  48. package/dist/types/widgets/timeseries/download.d.ts +7 -12
  49. package/dist/types/widgets/toolbox/toolbox.d.ts +1 -1
  50. package/dist/types/widgets/wrapper/style.d.ts +31 -2
  51. package/dist/types/widgets/wrapper/widget-actions.d.ts +2 -2
  52. package/dist/types/widgets/wrapper/widget-wrapper.d.ts +2 -2
  53. package/dist/{utils-BStJWhZN.js → utils-C-eWwOhE.js} +2 -2
  54. package/dist/{utils-BStJWhZN.js.map → utils-C-eWwOhE.js.map} +1 -1
  55. package/dist/widgets/actions.js +4 -4
  56. package/dist/widgets/bar.js +11 -17
  57. package/dist/widgets/bar.js.map +1 -1
  58. package/dist/widgets/category.js +1 -1
  59. package/dist/widgets/echart.js +1 -1
  60. package/dist/widgets/formula.js +1 -1
  61. package/dist/widgets/histogram.js +14 -20
  62. package/dist/widgets/histogram.js.map +1 -1
  63. package/dist/widgets/markdown.js +1 -1
  64. package/dist/widgets/pie.js +13 -19
  65. package/dist/widgets/pie.js.map +1 -1
  66. package/dist/widgets/range.js +1 -1
  67. package/dist/widgets/scatterplot.js +13 -19
  68. package/dist/widgets/scatterplot.js.map +1 -1
  69. package/dist/widgets/spread.js +1 -1
  70. package/dist/widgets/stores.js +2 -2
  71. package/dist/widgets/table.js +1 -1
  72. package/dist/widgets/timeseries.js +16 -22
  73. package/dist/widgets/timeseries.js.map +1 -1
  74. package/dist/widgets/utils.js +1 -1
  75. package/dist/widgets.js +364 -376
  76. package/dist/widgets.js.map +1 -1
  77. package/dist/{zoom-toggle-D_VuA01l.js → zoom-toggle-MmLjMTEw.js} +2 -2
  78. package/dist/{zoom-toggle-D_VuA01l.js.map → zoom-toggle-MmLjMTEw.js.map} +1 -1
  79. package/package.json +1 -1
  80. package/src/legend/components/legend-item/legend-item-ui.test.tsx +22 -1
  81. package/src/legend/components/legend-ramp/legend-ramp-ui.tsx +22 -6
  82. package/src/legend/stores/types.ts +4 -2
  83. package/src/widgets/actions/download/csv-item.test.tsx +3 -3
  84. package/src/widgets/actions/download/csv-item.tsx +6 -6
  85. package/src/widgets/actions/download/download.tsx +5 -3
  86. package/src/widgets/actions/download/index.ts +2 -1
  87. package/src/widgets/actions/download/png-item.test.tsx +5 -3
  88. package/src/widgets/actions/download/png-item.tsx +4 -4
  89. package/src/widgets/actions/download/types.ts +15 -1
  90. package/src/widgets/actions/download/widget-download.test.ts +30 -0
  91. package/src/widgets/actions/download/widget-download.ts +41 -0
  92. package/src/widgets/actions/fullscreen/fullscreen-store.test.tsx +155 -0
  93. package/src/widgets/actions/fullscreen/fullscreen.test.tsx +39 -41
  94. package/src/widgets/actions/fullscreen/fullscreen.tsx +198 -96
  95. package/src/widgets/actions/index.ts +3 -0
  96. package/src/widgets/actions/searcher/filter.test.ts +28 -0
  97. package/src/widgets/actions/searcher/filter.ts +22 -4
  98. package/src/widgets/actions/searcher/searcher-toggle.tsx +16 -8
  99. package/src/widgets/actions/searcher/searcher.test.tsx +22 -0
  100. package/src/widgets/actions/searcher/searcher.tsx +17 -7
  101. package/src/widgets/bar/download.test.tsx +5 -3
  102. package/src/widgets/bar/download.tsx +11 -35
  103. package/src/widgets/category/category-ui.tsx +26 -14
  104. package/src/widgets/category/category.tsx +37 -2
  105. package/src/widgets/category/components/category-legend.tsx +1 -2
  106. package/src/widgets/category/download.test.ts +4 -2
  107. package/src/widgets/category/download.ts +14 -27
  108. package/src/widgets/category/helpers.test.ts +17 -0
  109. package/src/widgets/category/helpers.ts +16 -0
  110. package/src/widgets/echart/style.ts +6 -0
  111. package/src/widgets/formula/download.test.tsx +3 -1
  112. package/src/widgets/formula/download.tsx +10 -30
  113. package/src/widgets/histogram/download.test.ts +6 -4
  114. package/src/widgets/histogram/download.ts +13 -26
  115. package/src/widgets/index.ts +1 -0
  116. package/src/widgets/markdown/download.test.ts +2 -2
  117. package/src/widgets/markdown/download.tsx +11 -26
  118. package/src/widgets/pie/download.test.ts +7 -3
  119. package/src/widgets/pie/download.ts +12 -25
  120. package/src/widgets/scatterplot/download.test.ts +4 -2
  121. package/src/widgets/scatterplot/download.ts +15 -28
  122. package/src/widgets/spread/download.test.ts +3 -1
  123. package/src/widgets/spread/download.ts +13 -27
  124. package/src/widgets/stores/index.ts +2 -0
  125. package/src/widgets/stores/widget-store-registry.test.ts +25 -0
  126. package/src/widgets/stores/widget-store-registry.ts +22 -0
  127. package/src/widgets/table/download.test.ts +5 -3
  128. package/src/widgets/table/download.ts +15 -29
  129. package/src/widgets/timeseries/download.test.ts +6 -4
  130. package/src/widgets/timeseries/download.ts +16 -29
  131. package/src/widgets/toolbox/toolbox.tsx +1 -1
  132. package/src/widgets/wrapper/style.ts +38 -2
  133. package/src/widgets/wrapper/widget-actions.tsx +2 -2
  134. package/src/widgets/wrapper/widget-wrapper.test.tsx +32 -2
  135. package/src/widgets/wrapper/widget-wrapper.tsx +62 -36
  136. package/dist/actions-KsX1xdDM.js +0 -1024
  137. package/dist/actions-KsX1xdDM.js.map +0 -1
  138. package/dist/category-CsdDqDzo.js +0 -833
  139. package/dist/category-CsdDqDzo.js.map +0 -1
  140. package/dist/download-Vlzn2jzb.js.map +0 -1
  141. package/dist/echart-DjcbtKgi.js.map +0 -1
  142. package/dist/stores-B8CHbgw-.js.map +0 -1
@@ -1,6 +1,6 @@
1
- import { S as e, T as t } from "./stores-B8CHbgw-.js";
1
+ import { D as e, S as t } from "./stores-DcBOZlU3.js";
2
2
  import { t as n } from "./markdown-content-kYNLOX0T.js";
3
- import { a as r, n as i, r as a } from "./download-Vlzn2jzb.js";
3
+ import { i as r, o as i, t as a } from "./download-B4sykOFm.js";
4
4
  import { c as o } from "react/compiler-runtime";
5
5
  import { Box as s, Skeleton as c, Typography as l } from "@mui/material";
6
6
  import { jsx as u } from "react/jsx-runtime";
@@ -96,7 +96,7 @@ function m(e) {
96
96
  //#endregion
97
97
  //#region src/widgets/markdown/markdown.tsx
98
98
  function h() {
99
- let n = o(2), r = t(), i = e(r, g), a;
99
+ let n = o(2), r = e(), i = t(r, g), a;
100
100
  return n[0] === i ? a = n[1] : (a = /* @__PURE__ */ u(m, { content: i }), n[0] = i, n[1] = a), a;
101
101
  }
102
102
  function g(e) {
@@ -139,27 +139,21 @@ function v(e) {
139
139
  //#endregion
140
140
  //#region src/widgets/markdown/download.tsx
141
141
  function y(e) {
142
- let t = [];
143
- return e.getCaptureEl && t.push(i({
144
- filename: e.filename,
145
- getCaptureEl: e.getCaptureEl,
146
- pixelRatio: e.pngPixelRatio,
147
- backgroundColor: e.pngBackgroundColor
148
- })), t.push({
149
- id: a.markdown,
142
+ return a(e, {
143
+ id: r.markdown,
150
144
  label: "Markdown",
151
- icon: /* @__PURE__ */ u(r, { fontSize: "small" }),
152
- resolve: () => {
153
- let t = e.getData(), n = new Blob([t.content ?? ""], { type: "text/markdown;charset=utf-8;" }), r = URL.createObjectURL(n);
145
+ icon: /* @__PURE__ */ u(i, { fontSize: "small" }),
146
+ resolve: (t) => {
147
+ let n = e.getData(t), r = new Blob([n.content ?? ""], { type: "text/markdown;charset=utf-8;" }), i = URL.createObjectURL(r);
154
148
  return Promise.resolve({
155
- url: r,
149
+ url: i,
156
150
  filename: `${e.filename}.md`,
157
- revoke: () => URL.revokeObjectURL(r)
151
+ revoke: () => URL.revokeObjectURL(i)
158
152
  });
159
153
  }
160
- }), t;
154
+ });
161
155
  }
162
156
  //#endregion
163
157
  export { m as i, v as n, h as r, y as t };
164
158
 
165
- //# sourceMappingURL=markdown-CY-67NRE.js.map
159
+ //# sourceMappingURL=markdown-Bn2nKCbn.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdown-CY-67NRE.js","names":["{ content }: MarkdownUIProps","<Box sx={styles.root}>\n <MarkdownContent\n content={content}\n components={components}\n allowHtml\n allowImages\n />\n </Box>","(s) => {\n const data = s.data as MarkdownWidgetData | undefined\n return data?.content ?? ''\n }","<MarkdownUI content={content} />","{ lines = 5 }: MarkdownSkeletonProps","lines = 5","<Box sx={styles.root}>\n {Array.from({ length: lines }).map((_, i) => (\n <Skeleton\n key={`line-${i}`}\n variant='rectangular'\n sx={styles.line(widths[i % widths.length] ?? '85%')}\n />\n ))}\n </Box>"],"sources":["../src/widgets/markdown/style.ts","../src/widgets/markdown/markdown-ui.tsx","../src/widgets/markdown/markdown.tsx","../src/widgets/markdown/skeleton.tsx","../src/widgets/markdown/download.tsx"],"sourcesContent":["import type { SxProps, Theme } from '@mui/material'\n\nexport const styles = {\n root: {\n color: 'text.primary',\n '& a': { color: 'primary.main' },\n '& code': {\n bgcolor: 'action.hover',\n px: 0.5,\n borderRadius: 0.5,\n fontFamily: 'monospace',\n fontSize: '0.875em',\n },\n '& pre': {\n bgcolor: 'action.hover',\n p: 1.5,\n borderRadius: 1,\n overflowX: 'auto',\n },\n '& blockquote': {\n borderLeft: '3px solid',\n borderColor: 'divider',\n pl: 1.5,\n ml: 0,\n color: 'text.secondary',\n fontStyle: 'italic',\n },\n '& ul, & ol': { pl: 3, my: 1 },\n '& li': { my: 0.25 },\n '& hr': {\n border: 'none',\n borderTop: '1px solid',\n borderColor: 'divider',\n my: 1.5,\n },\n '& table': { borderCollapse: 'collapse', width: '100%' },\n '& th, & td': {\n border: '1px solid',\n borderColor: 'divider',\n px: 1,\n py: 0.5,\n textAlign: 'left',\n },\n },\n paragraph: {\n my: 1,\n },\n heading: {\n mt: 2,\n mb: 1,\n fontWeight: 600,\n },\n} satisfies Record<string, SxProps<Theme>>\n","import { Box, Typography, type TypographyProps } from '@mui/material'\nimport type { Components } from 'react-markdown'\nimport { MarkdownContent } from './markdown-content'\nimport { styles } from './style'\n\nexport interface MarkdownUIProps {\n content: string\n}\n\n/** MUI-styled element mapping for `react-markdown`. */\nconst components: Components = {\n h1: (props) => mdHeading(props, 'h4'),\n h2: (props) => mdHeading(props, 'h5'),\n h3: (props) => mdHeading(props, 'h6'),\n h4: (props) => mdHeading(props, 'subtitle1'),\n h5: (props) => mdHeading(props, 'subtitle2'),\n h6: (props) => mdHeading(props, 'subtitle2'),\n p: ({ children }) => (\n <Typography variant='body2' component='p' sx={styles.paragraph}>\n {children}\n </Typography>\n ),\n}\n\nfunction mdHeading(\n props: { children?: React.ReactNode },\n variant: TypographyProps['variant'],\n) {\n return (\n <Typography variant={variant} component='div' sx={styles.heading}>\n {props.children}\n </Typography>\n )\n}\n\n/**\n * Pure presentational component for the Markdown widget. Delegates the\n * `react-markdown` engine to {@link MarkdownContent} and supplies a\n * document-style MUI element mapping (body2 paragraphs, real heading\n * typography). Opts INTO raw HTML and inline images — the Markdown widget is\n * the one slot in the library where authors can ship rich content. Caption\n * slots like `Note` keep the conservative defaults.\n */\nexport function MarkdownUI({ content }: MarkdownUIProps) {\n return (\n <Box sx={styles.root}>\n <MarkdownContent\n content={content}\n components={components}\n allowHtml\n allowImages\n />\n </Box>\n )\n}\n","import { useWidgetId, useWidget } from '../stores'\nimport { MarkdownUI } from './markdown-ui'\nimport type { MarkdownWidgetData } from './types'\n\n/**\n * Stateful Markdown bridge — reads `data.content` (post-pipeline) from the\n * per-widget store and forwards it to the pure {@link MarkdownUI}. Sits\n * inside `<Widget.Provider>`.\n */\nexport function Markdown() {\n const id = useWidgetId()\n const content = useWidget(id, (s) => {\n const data = s.data as MarkdownWidgetData | undefined\n return data?.content ?? ''\n })\n return <MarkdownUI content={content} />\n}\n","import { Box, Skeleton } from '@mui/material'\nimport type { SxProps, Theme } from '@mui/material'\n\nconst styles = {\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: 1,\n py: 1,\n },\n line: (width: string): SxProps<Theme> => ({ width, height: 18 }),\n} as const\n\nexport interface MarkdownSkeletonProps {\n lines?: number\n}\n\nexport function MarkdownSkeleton({ lines = 5 }: MarkdownSkeletonProps) {\n // Vary widths to mimic prose.\n const widths = ['100%', '95%', '90%', '85%', '70%']\n return (\n <Box sx={styles.root}>\n {Array.from({ length: lines }).map((_, i) => (\n <Skeleton\n key={`line-${i}`}\n variant='rectangular'\n sx={styles.line(widths[i % widths.length] ?? '85%')}\n />\n ))}\n </Box>\n )\n}\n","import {\n DOWNLOAD_ITEM_IDS,\n MarkdownIcon,\n buildPngDownloadItem,\n toCsvString,\n triggerLinkDownload,\n type DownloadItem,\n} from '../actions/download'\nimport type { MarkdownWidgetData } from './types'\n\n/**\n * Download menu items for the Markdown widget. Always includes a `.md`\n * item that saves the markdown source verbatim. When `getCaptureEl` is\n * supplied, prepends a PNG item that rasterises the captured element via\n * `html2canvas`.\n */\nexport function createMarkdownDownloadConfig(args: {\n filename: string\n getData: () => MarkdownWidgetData\n getCaptureEl?: () => HTMLElement | null\n pngPixelRatio?: number\n pngBackgroundColor?: string | null\n}): DownloadItem[] {\n const items: DownloadItem[] = []\n if (args.getCaptureEl) {\n items.push(\n buildPngDownloadItem({\n filename: args.filename,\n getCaptureEl: args.getCaptureEl,\n pixelRatio: args.pngPixelRatio,\n backgroundColor: args.pngBackgroundColor,\n }),\n )\n }\n items.push({\n id: DOWNLOAD_ITEM_IDS.markdown,\n label: 'Markdown',\n icon: <MarkdownIcon fontSize='small' />,\n resolve: () => {\n const data = args.getData()\n const blob = new Blob([data.content ?? ''], {\n type: 'text/markdown;charset=utf-8;',\n })\n const url = URL.createObjectURL(blob)\n return Promise.resolve({\n url,\n filename: `${args.filename}.md`,\n revoke: () => URL.revokeObjectURL(url),\n })\n },\n })\n return items\n}\n\n// Re-export pure helpers consumers may want when building a custom Download item.\nexport { toCsvString, triggerLinkDownload }\n"],"mappings":"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"}
1
+ {"version":3,"file":"markdown-Bn2nKCbn.js","names":["{ content }: MarkdownUIProps","<Box sx={styles.root}>\n <MarkdownContent\n content={content}\n components={components}\n allowHtml\n allowImages\n />\n </Box>","(s) => {\n const data = s.data as MarkdownWidgetData | undefined\n return data?.content ?? ''\n }","<MarkdownUI content={content} />","{ lines = 5 }: MarkdownSkeletonProps","lines = 5","<Box sx={styles.root}>\n {Array.from({ length: lines }).map((_, i) => (\n <Skeleton\n key={`line-${i}`}\n variant='rectangular'\n sx={styles.line(widths[i % widths.length] ?? '85%')}\n />\n ))}\n </Box>"],"sources":["../src/widgets/markdown/style.ts","../src/widgets/markdown/markdown-ui.tsx","../src/widgets/markdown/markdown.tsx","../src/widgets/markdown/skeleton.tsx","../src/widgets/markdown/download.tsx"],"sourcesContent":["import type { SxProps, Theme } from '@mui/material'\n\nexport const styles = {\n root: {\n color: 'text.primary',\n '& a': { color: 'primary.main' },\n '& code': {\n bgcolor: 'action.hover',\n px: 0.5,\n borderRadius: 0.5,\n fontFamily: 'monospace',\n fontSize: '0.875em',\n },\n '& pre': {\n bgcolor: 'action.hover',\n p: 1.5,\n borderRadius: 1,\n overflowX: 'auto',\n },\n '& blockquote': {\n borderLeft: '3px solid',\n borderColor: 'divider',\n pl: 1.5,\n ml: 0,\n color: 'text.secondary',\n fontStyle: 'italic',\n },\n '& ul, & ol': { pl: 3, my: 1 },\n '& li': { my: 0.25 },\n '& hr': {\n border: 'none',\n borderTop: '1px solid',\n borderColor: 'divider',\n my: 1.5,\n },\n '& table': { borderCollapse: 'collapse', width: '100%' },\n '& th, & td': {\n border: '1px solid',\n borderColor: 'divider',\n px: 1,\n py: 0.5,\n textAlign: 'left',\n },\n },\n paragraph: {\n my: 1,\n },\n heading: {\n mt: 2,\n mb: 1,\n fontWeight: 600,\n },\n} satisfies Record<string, SxProps<Theme>>\n","import { Box, Typography, type TypographyProps } from '@mui/material'\nimport type { Components } from 'react-markdown'\nimport { MarkdownContent } from './markdown-content'\nimport { styles } from './style'\n\nexport interface MarkdownUIProps {\n content: string\n}\n\n/** MUI-styled element mapping for `react-markdown`. */\nconst components: Components = {\n h1: (props) => mdHeading(props, 'h4'),\n h2: (props) => mdHeading(props, 'h5'),\n h3: (props) => mdHeading(props, 'h6'),\n h4: (props) => mdHeading(props, 'subtitle1'),\n h5: (props) => mdHeading(props, 'subtitle2'),\n h6: (props) => mdHeading(props, 'subtitle2'),\n p: ({ children }) => (\n <Typography variant='body2' component='p' sx={styles.paragraph}>\n {children}\n </Typography>\n ),\n}\n\nfunction mdHeading(\n props: { children?: React.ReactNode },\n variant: TypographyProps['variant'],\n) {\n return (\n <Typography variant={variant} component='div' sx={styles.heading}>\n {props.children}\n </Typography>\n )\n}\n\n/**\n * Pure presentational component for the Markdown widget. Delegates the\n * `react-markdown` engine to {@link MarkdownContent} and supplies a\n * document-style MUI element mapping (body2 paragraphs, real heading\n * typography). Opts INTO raw HTML and inline images — the Markdown widget is\n * the one slot in the library where authors can ship rich content. Caption\n * slots like `Note` keep the conservative defaults.\n */\nexport function MarkdownUI({ content }: MarkdownUIProps) {\n return (\n <Box sx={styles.root}>\n <MarkdownContent\n content={content}\n components={components}\n allowHtml\n allowImages\n />\n </Box>\n )\n}\n","import { useWidgetId, useWidget } from '../stores'\nimport { MarkdownUI } from './markdown-ui'\nimport type { MarkdownWidgetData } from './types'\n\n/**\n * Stateful Markdown bridge — reads `data.content` (post-pipeline) from the\n * per-widget store and forwards it to the pure {@link MarkdownUI}. Sits\n * inside `<Widget.Provider>`.\n */\nexport function Markdown() {\n const id = useWidgetId()\n const content = useWidget(id, (s) => {\n const data = s.data as MarkdownWidgetData | undefined\n return data?.content ?? ''\n })\n return <MarkdownUI content={content} />\n}\n","import { Box, Skeleton } from '@mui/material'\nimport type { SxProps, Theme } from '@mui/material'\n\nconst styles = {\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: 1,\n py: 1,\n },\n line: (width: string): SxProps<Theme> => ({ width, height: 18 }),\n} as const\n\nexport interface MarkdownSkeletonProps {\n lines?: number\n}\n\nexport function MarkdownSkeleton({ lines = 5 }: MarkdownSkeletonProps) {\n // Vary widths to mimic prose.\n const widths = ['100%', '95%', '90%', '85%', '70%']\n return (\n <Box sx={styles.root}>\n {Array.from({ length: lines }).map((_, i) => (\n <Skeleton\n key={`line-${i}`}\n variant='rectangular'\n sx={styles.line(widths[i % widths.length] ?? '85%')}\n />\n ))}\n </Box>\n )\n}\n","import {\n DOWNLOAD_ITEM_IDS,\n MarkdownIcon,\n withPngItem,\n toCsvString,\n triggerLinkDownload,\n type DownloadItem,\n type WidgetDownloadArgs,\n} from '../actions/download'\nimport type { MarkdownWidgetData } from './types'\n\n/**\n * Download menu items for the Markdown widget. Always includes a `.md` item\n * that saves the markdown source verbatim. When `getCaptureEl` is given,\n * prepends a PNG item that rasterises the captured element via\n * `html2canvas`.\n */\nexport function createMarkdownDownloadConfig(\n args: WidgetDownloadArgs<MarkdownWidgetData>,\n): DownloadItem[] {\n return withPngItem(args, {\n id: DOWNLOAD_ITEM_IDS.markdown,\n label: 'Markdown',\n icon: <MarkdownIcon fontSize='small' />,\n resolve: (ctx) => {\n const data = args.getData(ctx)\n const blob = new Blob([data.content ?? ''], {\n type: 'text/markdown;charset=utf-8;',\n })\n const url = URL.createObjectURL(blob)\n return Promise.resolve({\n url,\n filename: `${args.filename}.md`,\n revoke: () => URL.revokeObjectURL(url),\n })\n },\n })\n}\n\n// Re-export pure helpers consumers may want when building a custom Download item.\nexport { toCsvString, triggerLinkDownload }\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { C as e, T as t } from "./stores-B8CHbgw-.js";
1
+ import { C as e, D as t } from "./stores-DcBOZlU3.js";
2
2
  import { c as n } from "react/compiler-runtime";
3
3
  import { useState as r } from "react";
4
4
  import { Box as i, Skeleton as a, Slider as o, TextField as s, Typography as c } from "@mui/material";
@@ -274,4 +274,4 @@ function x(e, t) {
274
274
  //#endregion
275
275
  export { v as n, f as r, b as t };
276
276
 
277
- //# sourceMappingURL=range-DHQSsl2_.js.map
277
+ //# sourceMappingURL=range-BpU2zBmq.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"range-DHQSsl2_.js","names":["{\n items,\n onChange,\n onChangeCommitted,\n formatter,\n}: RangeUIProps","(n: number) => String(n)","items.map((item, i) => (\n // Composite of the row's track bounds — stable across reorders for\n // any realistic widget configuration. Falls back to a literal +\n // index when bounds collide (degenerate same-min-same-max rows).\n <RangeRow\n key={`range-${item.min}-${item.max}-${i}`}\n index={i}\n item={item}\n fmt={fmt}\n onChange={onChange}\n onChangeCommitted={onChangeCommitted}\n />\n ))","(item, i) => (\n // Composite of the row's track bounds — stable across reorders for\n // any realistic widget configuration. Falls back to a literal +\n // index when bounds collide (degenerate same-min-same-max rows).\n <RangeRow\n key={`range-${item.min}-${item.max}-${i}`}\n index={i}\n item={item}\n fmt={fmt}\n onChange={onChange}\n onChangeCommitted={onChangeCommitted}\n />\n )","<Box sx={styles.root}>\n {items.map((item, i) => (\n // Composite of the row's track bounds — stable across reorders for\n // any realistic widget configuration. Falls back to a literal +\n // index when bounds collide (degenerate same-min-same-max rows).\n <RangeRow\n key={`range-${item.min}-${item.max}-${i}`}\n index={i}\n item={item}\n fmt={fmt}\n onChange={onChange}\n onChangeCommitted={onChangeCommitted}\n />\n ))}\n </Box>","{\n index,\n item,\n fmt,\n onChange,\n onChangeCommitted,\n}: RangeRowProps","item.value ?? [item.min, item.max]","max","min","value","(next: readonly [number, number]): readonly [number, number] => {\n const [lowRaw, highRaw] = next\n const low = Math.min(Math.max(lowRaw, item.min), item.max)\n const high = Math.min(Math.max(highRaw, item.min), item.max)\n return low <= high ? [low, high] : [high, low]\n }","useCallback(\n (next: readonly [number, number]): readonly [number, number] => {\n const [lowRaw, highRaw] = next\n const low = Math.min(Math.max(lowRaw, item.min), item.max)\n const high = Math.min(Math.max(highRaw, item.min), item.max)\n return low <= high ? [low, high] : [high, low]\n },\n [item.min, item.max],\n )","(next: readonly [number, number]) => {\n onChange?.(index, normalize(next))\n }","next","useCallback(\n (next: readonly [number, number]) => {\n onChange?.(index, normalize(next))\n },\n [index, normalize, onChange],\n )","(next: readonly [number, number]) => {\n onChangeCommitted?.(index, normalize(next))\n }","useCallback(\n (next: readonly [number, number]) => {\n onChangeCommitted?.(index, normalize(next))\n },\n [index, normalize, onChangeCommitted],\n )","(next: readonly [number, number]) => {\n const value = normalize(next)\n onChange?.(index, value)\n onChangeCommitted?.(index, value)\n }","useCallback(\n (next: readonly [number, number]) => {\n const value = normalize(next)\n onChange?.(index, value)\n onChangeCommitted?.(index, value)\n },\n [index, normalize, onChange, onChangeCommitted],\n )","(_: Event, raw: number | number[]) => {\n if (!Array.isArray(raw)) return\n // Hoist defaults out of the destructure: react-compiler can't safely\n // reorder MemberExpression defaults inside an array pattern.\n const low = raw[0] ?? item.min\n const high = raw[1] ?? item.max\n commit([low, high])\n }","low","high","(\n _: Event | React.SyntheticEvent,\n raw: number | number[],\n ) => {\n if (!Array.isArray(raw)) return\n const low = raw[0] ?? item.min\n const high = raw[1] ?? item.max\n commitFinal([low, high])\n }","raw","item.color ? { color: item.color } : null","color","{\n ...styles.slider,\n ...(item.color ? { color: item.color } : null),\n }","[...current]","resolveMarks(item.marks)","marks","<Box sx={styles.sliderContainer}>\n <Slider\n sx={{\n ...styles.slider,\n ...(item.color ? { color: item.color } : null),\n }}\n value={[...current]}\n min={item.min}\n max={item.max}\n step={item.step ?? 1}\n marks={resolveMarks(item.marks)}\n disabled={item.disabled}\n valueLabelDisplay='auto'\n valueLabelFormat={fmt}\n onChange={handleSlider}\n onChangeCommitted={handleSliderCommitted}\n />\n </Box>","disabled","item.step ?? 1","item.min","item.max","<BoundInput\n // Bumping the key on a fresh external value resets the local\n // editing state — matches v1's RangeItem behaviour.\n key={`min-${current[0]}`}\n name='min'\n value={current[0]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Minimum value'\n />","current[0]","`min-${current[0]}`","<BoundInput\n key={`max-${current[1]}`}\n name='max'\n value={current[1]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Maximum value'\n />","current[1]","`max-${current[1]}`","<Box sx={styles.inputsRow}>\n {/* Text-input commits (blur / Enter) are final, but also notify\n `onChange` — see `commitText` — so consumers that only wired\n `onChange` still update on a typed value. */}\n <BoundInput\n // Bumping the key on a fresh external value resets the local\n // editing state — matches v1's RangeItem behaviour.\n key={`min-${current[0]}`}\n name='min'\n value={current[0]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Minimum value'\n />\n <BoundInput\n key={`max-${current[1]}`}\n name='max'\n value={current[1]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Maximum value'\n />\n </Box>","item.note ? (\n <Typography variant='caption' sx={styles.note}>\n {item.note}\n </Typography>\n ) : null","note","<Box sx={styles.item}>\n <Box sx={styles.sliderContainer}>\n <Slider\n sx={{\n ...styles.slider,\n ...(item.color ? { color: item.color } : null),\n }}\n value={[...current]}\n min={item.min}\n max={item.max}\n step={item.step ?? 1}\n marks={resolveMarks(item.marks)}\n disabled={item.disabled}\n valueLabelDisplay='auto'\n valueLabelFormat={fmt}\n onChange={handleSlider}\n onChangeCommitted={handleSliderCommitted}\n />\n </Box>\n <Box sx={styles.inputsRow}>\n {/* Text-input commits (blur / Enter) are final, but also notify\n `onChange` — see `commitText` — so consumers that only wired\n `onChange` still update on a typed value. */}\n <BoundInput\n // Bumping the key on a fresh external value resets the local\n // editing state — matches v1's RangeItem behaviour.\n key={`min-${current[0]}`}\n name='min'\n value={current[0]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Minimum value'\n />\n <BoundInput\n key={`max-${current[1]}`}\n name='max'\n value={current[1]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Maximum value'\n />\n </Box>\n {item.note ? (\n <Typography variant='caption' sx={styles.note}>\n {item.note}\n </Typography>\n ) : null}\n </Box>","{\n name,\n value,\n item,\n fmt,\n editing,\n setEditing,\n commit,\n current,\n ariaLabel,\n}: BoundInputProps","() => {\n setEditing(name)\n }","e","editing === name ? raw : fmt(Number(raw))","(e) => setRaw(e.target.value)","{\n htmlInput: { 'aria-label': ariaLabel },\n }","<TextField\n name={name}\n value={display}\n onChange={(e) => setRaw(e.target.value)}\n onFocus={beginEditing}\n onBlur={finishEditingAndCommit}\n onKeyDown={commitOnEnter}\n disabled={item.disabled}\n size='small'\n sx={styles.input}\n slotProps={{\n htmlInput: { 'aria-label': ariaLabel },\n }}\n />","{ onChange, onChangeCommitted }: RangeProps","<RangeUI\n items={slice.data}\n formatter={slice.formatter}\n onChange={onChange}\n onChangeCommitted={onChangeCommitted}\n />","data","formatter","{ count = 1 }: RangeSkeletonProps","count = 1","<Box sx={styles.root}>\n {Array.from({ length: count }).map((_, i) => (\n <Box key={`item-${i}`} sx={styles.item}>\n <Skeleton variant='rectangular' sx={styles.track} />\n <Box sx={styles.inputsRow}>\n <Skeleton variant='rectangular' sx={styles.input} />\n <Skeleton variant='rectangular' sx={styles.input} />\n </Box>\n </Box>\n ))}\n </Box>","(_, i) => (\n <Box key={`item-${i}`} sx={styles.item}>\n <Skeleton variant='rectangular' sx={styles.track} />\n <Box sx={styles.inputsRow}>\n <Skeleton variant='rectangular' sx={styles.input} />\n <Skeleton variant='rectangular' sx={styles.input} />\n </Box>\n </Box>\n )"],"sources":["../src/widgets/range/style.ts","../src/widgets/range/range-ui.tsx","../src/widgets/range/range.tsx","../src/widgets/range/skeleton.tsx"],"sourcesContent":["import type { SxProps, Theme } from '@mui/material'\n\nexport const styles = {\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: 3,\n py: 1,\n },\n item: {\n display: 'flex',\n flexDirection: 'column',\n gap: 1.5,\n },\n sliderContainer: {\n display: 'flex',\n flexDirection: 'column',\n gap: 1,\n px: 1,\n },\n slider: {\n width: '100%',\n '&.Mui-disabled': {\n color: (theme: Theme) => theme.palette.text.disabled,\n },\n },\n inputsRow: {\n display: 'flex',\n gap: 2,\n alignItems: 'center',\n },\n input: {\n flex: 1,\n '& .MuiInputBase-input': {\n textAlign: 'center',\n },\n },\n note: {\n color: 'text.secondary',\n },\n} satisfies Record<string, SxProps<Theme>>\n","import {\n useCallback,\n useState,\n type FocusEvent,\n type KeyboardEvent,\n} from 'react'\nimport { Box, Slider, TextField, Typography } from '@mui/material'\nimport type { RangeDataItem, RangeItemValue } from './types'\nimport { styles } from './style'\n\nexport interface RangeUIProps {\n items: readonly RangeDataItem[]\n /**\n * Fires on every pointer tick while a thumb is being dragged (mirrors\n * MUI `<Slider>`'s `onChange`). Use this to update local UI state —\n * not to persist expensive operations like remote queries.\n */\n onChange?: (index: number, value: RangeItemValue) => void\n /**\n * Fires once when the user *releases* a slider thumb after dragging,\n * after an arrow-key adjustment commits, or when the text inputs\n * blur / Enter. Mirrors MUI `<Slider>`'s `onChangeCommitted`. Use\n * this for side-effects you want to throttle to \"drag end\" — e.g.\n * writing the value to a source filter that triggers refetches.\n */\n onChangeCommitted?: (index: number, value: RangeItemValue) => void\n /** Number formatter for the slider tooltip and the text input display. */\n formatter?: (value: number) => string\n}\n\ntype Bound = 'min' | 'max'\n\n/**\n * Pure presentational component for the Range widget. Renders one MUI Slider\n * per item with editable min/max text inputs below — matching the Range v1\n * UX. Each item is always a two-thumb range; supply `value` to seed the\n * starting selection, otherwise it defaults to `[min, max]`.\n */\nexport function RangeUI({\n items,\n onChange,\n onChangeCommitted,\n formatter,\n}: RangeUIProps) {\n const fmt = formatter ?? ((n: number) => String(n))\n return (\n <Box sx={styles.root}>\n {items.map((item, i) => (\n // Composite of the row's track bounds — stable across reorders for\n // any realistic widget configuration. Falls back to a literal +\n // index when bounds collide (degenerate same-min-same-max rows).\n <RangeRow\n key={`range-${item.min}-${item.max}-${i}`}\n index={i}\n item={item}\n fmt={fmt}\n onChange={onChange}\n onChangeCommitted={onChangeCommitted}\n />\n ))}\n </Box>\n )\n}\n\ninterface RangeRowProps {\n index: number\n item: RangeDataItem\n fmt: (n: number) => string\n onChange?: (index: number, value: RangeItemValue) => void\n onChangeCommitted?: (index: number, value: RangeItemValue) => void\n}\n\nfunction RangeRow({\n index,\n item,\n fmt,\n onChange,\n onChangeCommitted,\n}: RangeRowProps) {\n const current: readonly [number, number] = item.value ?? [item.min, item.max]\n const [editing, setEditing] = useState<'' | Bound>('')\n\n // Clamp inside [min, max] and keep `low <= high`. Pulled out so both the\n // live `onChange` path and the commit path share the same normalization.\n const normalize = useCallback(\n (next: readonly [number, number]): readonly [number, number] => {\n const [lowRaw, highRaw] = next\n const low = Math.min(Math.max(lowRaw, item.min), item.max)\n const high = Math.min(Math.max(highRaw, item.min), item.max)\n return low <= high ? [low, high] : [high, low]\n },\n [item.min, item.max],\n )\n\n const commit = useCallback(\n (next: readonly [number, number]) => {\n onChange?.(index, normalize(next))\n },\n [index, normalize, onChange],\n )\n\n const commitFinal = useCallback(\n (next: readonly [number, number]) => {\n onChangeCommitted?.(index, normalize(next))\n },\n [index, normalize, onChangeCommitted],\n )\n\n // A text-input commit (blur / Enter) is both a value change AND a final\n // commit, so it fires `onChange` *and* `onChangeCommitted`. Firing both\n // keeps the widget responsive for consumers that only wired `onChange`\n // (the pre-`onChangeCommitted` API) — without it, typing a value and\n // pressing Enter would silently no-op for them.\n const commitText = useCallback(\n (next: readonly [number, number]) => {\n const value = normalize(next)\n onChange?.(index, value)\n onChangeCommitted?.(index, value)\n },\n [index, normalize, onChange, onChangeCommitted],\n )\n\n const handleSlider = (_: Event, raw: number | number[]) => {\n if (!Array.isArray(raw)) return\n // Hoist defaults out of the destructure: react-compiler can't safely\n // reorder MemberExpression defaults inside an array pattern.\n const low = raw[0] ?? item.min\n const high = raw[1] ?? item.max\n commit([low, high])\n }\n\n const handleSliderCommitted = (\n _: Event | React.SyntheticEvent,\n raw: number | number[],\n ) => {\n if (!Array.isArray(raw)) return\n const low = raw[0] ?? item.min\n const high = raw[1] ?? item.max\n commitFinal([low, high])\n }\n\n return (\n <Box sx={styles.item}>\n <Box sx={styles.sliderContainer}>\n <Slider\n sx={{\n ...styles.slider,\n ...(item.color ? { color: item.color } : null),\n }}\n value={[...current]}\n min={item.min}\n max={item.max}\n step={item.step ?? 1}\n marks={resolveMarks(item.marks)}\n disabled={item.disabled}\n valueLabelDisplay='auto'\n valueLabelFormat={fmt}\n onChange={handleSlider}\n onChangeCommitted={handleSliderCommitted}\n />\n </Box>\n <Box sx={styles.inputsRow}>\n {/* Text-input commits (blur / Enter) are final, but also notify\n `onChange` — see `commitText` — so consumers that only wired\n `onChange` still update on a typed value. */}\n <BoundInput\n // Bumping the key on a fresh external value resets the local\n // editing state — matches v1's RangeItem behaviour.\n key={`min-${current[0]}`}\n name='min'\n value={current[0]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Minimum value'\n />\n <BoundInput\n key={`max-${current[1]}`}\n name='max'\n value={current[1]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Maximum value'\n />\n </Box>\n {item.note ? (\n <Typography variant='caption' sx={styles.note}>\n {item.note}\n </Typography>\n ) : null}\n </Box>\n )\n}\n\ninterface BoundInputProps {\n name: Bound\n value: number\n item: RangeDataItem\n fmt: (n: number) => string\n editing: '' | Bound\n setEditing: (next: '' | Bound) => void\n /**\n * Called when the user commits a new value (blur / Enter). Text input\n * edits never produce intermediate \"live\" values, so the consumer\n * only needs one callback — the row wires this to `commitFinal`.\n */\n commit: (next: readonly [number, number]) => void\n current: readonly [number, number]\n ariaLabel: string\n}\n\nfunction BoundInput({\n name,\n value,\n item,\n fmt,\n editing,\n setEditing,\n commit,\n current,\n ariaLabel,\n}: BoundInputProps) {\n const [raw, setRaw] = useState<string>(String(value))\n\n const beginEditing = () => {\n setEditing(name)\n }\n const finishEditingAndCommit = (e: FocusEvent<HTMLInputElement>) => {\n setEditing('')\n commitFromText(e.target.value)\n }\n const commitOnEnter = (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n commitFromText((e.target as HTMLInputElement).value)\n ;(e.target as HTMLInputElement).blur()\n }\n }\n\n function commitFromText(input: string) {\n const parsed = parseFloat(input)\n const safe = Number.isFinite(parsed) ? parsed : value\n const next: readonly [number, number] =\n name === 'min' ? [safe, current[1]] : [current[0], safe]\n commit(next)\n }\n\n const display = editing === name ? raw : fmt(Number(raw))\n\n return (\n <TextField\n name={name}\n value={display}\n onChange={(e) => setRaw(e.target.value)}\n onFocus={beginEditing}\n onBlur={finishEditingAndCommit}\n onKeyDown={commitOnEnter}\n disabled={item.disabled}\n size='small'\n sx={styles.input}\n slotProps={{\n htmlInput: { 'aria-label': ariaLabel },\n }}\n />\n )\n}\n\nfunction resolveMarks(\n marks: RangeDataItem['marks'],\n): boolean | { value: number; label?: string }[] | undefined {\n if (marks == null) return undefined\n if (typeof marks === 'boolean') return marks\n return [...marks]\n}\n","import { useWidgetId, useWidgetShallow } from '../stores'\nimport { RangeUI } from './range-ui'\nimport type { RangeItemValue, RangeWidgetData } from './types'\n\ninterface RangeSlice {\n data: RangeWidgetData\n formatter?: (value: number) => string\n}\n\nconst rangeSelector = (s: {\n data: unknown\n formatter?: (value: number) => string\n}): RangeSlice => ({\n data: (s.data ?? []) as RangeWidgetData,\n formatter: s.formatter,\n})\n\nexport interface RangeProps {\n /**\n * Fires on every pointer tick while a thumb is being dragged. Use this\n * for cheap UI updates (local state, optimistic display).\n */\n onChange?: (index: number, value: RangeItemValue) => void\n /**\n * Fires once when the user *releases* a slider thumb (or when the text\n * inputs blur / Enter, or when an arrow-key adjustment settles). Use\n * this for expensive side-effects you want throttled to drag end —\n * e.g. writing the value to a source filter that refetches widgets.\n */\n onChangeCommitted?: (index: number, value: RangeItemValue) => void\n}\n\n/**\n * Stateful Range bridge — reads `data` (post-pipeline) and `formatter` from\n * the per-widget store and forwards them to the pure {@link RangeUI}. Per\n * the destination-owned principle, value changes flow back through\n * `onChange` (per-tick) and `onChangeCommitted` (drag end) — the consumer\n * is expected to update the data prop on `<Provider>`. Use `disabled` on\n * individual `RangeDataItem`s to disable specific rows.\n */\nexport function Range({ onChange, onChangeCommitted }: RangeProps) {\n const id = useWidgetId()\n const slice = useWidgetShallow(id, rangeSelector)\n return (\n <RangeUI\n items={slice.data}\n formatter={slice.formatter}\n onChange={onChange}\n onChangeCommitted={onChangeCommitted}\n />\n )\n}\n","import { Box, Skeleton } from '@mui/material'\nimport type { SxProps, Theme } from '@mui/material'\n\nconst styles = {\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: 3,\n py: 1,\n },\n item: {\n display: 'flex',\n flexDirection: 'column',\n gap: 1.5,\n },\n track: { height: 32 },\n inputsRow: {\n display: 'flex',\n gap: 2,\n },\n input: { flex: 1, height: 40 },\n} satisfies Record<string, SxProps<Theme>>\n\nexport interface RangeSkeletonProps {\n count?: number\n}\n\n/**\n * Loading placeholder for the Range widget. Renders `count` rows, each\n * matching the slider-then-inputs layout of {@link RangeUI} so the layout\n * doesn't jump when data resolves.\n */\nexport function RangeSkeleton({ count = 1 }: RangeSkeletonProps) {\n return (\n <Box sx={styles.root}>\n {Array.from({ length: count }).map((_, i) => (\n <Box key={`item-${i}`} sx={styles.item}>\n <Skeleton variant='rectangular' sx={styles.track} />\n <Box sx={styles.inputsRow}>\n <Skeleton variant='rectangular' sx={styles.input} />\n <Skeleton variant='rectangular' sx={styles.input} />\n </Box>\n </Box>\n ))}\n </Box>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"range-BpU2zBmq.js","names":["{\n items,\n onChange,\n onChangeCommitted,\n formatter,\n}: RangeUIProps","(n: number) => String(n)","items.map((item, i) => (\n // Composite of the row's track bounds — stable across reorders for\n // any realistic widget configuration. Falls back to a literal +\n // index when bounds collide (degenerate same-min-same-max rows).\n <RangeRow\n key={`range-${item.min}-${item.max}-${i}`}\n index={i}\n item={item}\n fmt={fmt}\n onChange={onChange}\n onChangeCommitted={onChangeCommitted}\n />\n ))","(item, i) => (\n // Composite of the row's track bounds — stable across reorders for\n // any realistic widget configuration. Falls back to a literal +\n // index when bounds collide (degenerate same-min-same-max rows).\n <RangeRow\n key={`range-${item.min}-${item.max}-${i}`}\n index={i}\n item={item}\n fmt={fmt}\n onChange={onChange}\n onChangeCommitted={onChangeCommitted}\n />\n )","<Box sx={styles.root}>\n {items.map((item, i) => (\n // Composite of the row's track bounds — stable across reorders for\n // any realistic widget configuration. Falls back to a literal +\n // index when bounds collide (degenerate same-min-same-max rows).\n <RangeRow\n key={`range-${item.min}-${item.max}-${i}`}\n index={i}\n item={item}\n fmt={fmt}\n onChange={onChange}\n onChangeCommitted={onChangeCommitted}\n />\n ))}\n </Box>","{\n index,\n item,\n fmt,\n onChange,\n onChangeCommitted,\n}: RangeRowProps","item.value ?? [item.min, item.max]","max","min","value","(next: readonly [number, number]): readonly [number, number] => {\n const [lowRaw, highRaw] = next\n const low = Math.min(Math.max(lowRaw, item.min), item.max)\n const high = Math.min(Math.max(highRaw, item.min), item.max)\n return low <= high ? [low, high] : [high, low]\n }","useCallback(\n (next: readonly [number, number]): readonly [number, number] => {\n const [lowRaw, highRaw] = next\n const low = Math.min(Math.max(lowRaw, item.min), item.max)\n const high = Math.min(Math.max(highRaw, item.min), item.max)\n return low <= high ? [low, high] : [high, low]\n },\n [item.min, item.max],\n )","(next: readonly [number, number]) => {\n onChange?.(index, normalize(next))\n }","next","useCallback(\n (next: readonly [number, number]) => {\n onChange?.(index, normalize(next))\n },\n [index, normalize, onChange],\n )","(next: readonly [number, number]) => {\n onChangeCommitted?.(index, normalize(next))\n }","useCallback(\n (next: readonly [number, number]) => {\n onChangeCommitted?.(index, normalize(next))\n },\n [index, normalize, onChangeCommitted],\n )","(next: readonly [number, number]) => {\n const value = normalize(next)\n onChange?.(index, value)\n onChangeCommitted?.(index, value)\n }","useCallback(\n (next: readonly [number, number]) => {\n const value = normalize(next)\n onChange?.(index, value)\n onChangeCommitted?.(index, value)\n },\n [index, normalize, onChange, onChangeCommitted],\n )","(_: Event, raw: number | number[]) => {\n if (!Array.isArray(raw)) return\n // Hoist defaults out of the destructure: react-compiler can't safely\n // reorder MemberExpression defaults inside an array pattern.\n const low = raw[0] ?? item.min\n const high = raw[1] ?? item.max\n commit([low, high])\n }","low","high","(\n _: Event | React.SyntheticEvent,\n raw: number | number[],\n ) => {\n if (!Array.isArray(raw)) return\n const low = raw[0] ?? item.min\n const high = raw[1] ?? item.max\n commitFinal([low, high])\n }","raw","item.color ? { color: item.color } : null","color","{\n ...styles.slider,\n ...(item.color ? { color: item.color } : null),\n }","[...current]","resolveMarks(item.marks)","marks","<Box sx={styles.sliderContainer}>\n <Slider\n sx={{\n ...styles.slider,\n ...(item.color ? { color: item.color } : null),\n }}\n value={[...current]}\n min={item.min}\n max={item.max}\n step={item.step ?? 1}\n marks={resolveMarks(item.marks)}\n disabled={item.disabled}\n valueLabelDisplay='auto'\n valueLabelFormat={fmt}\n onChange={handleSlider}\n onChangeCommitted={handleSliderCommitted}\n />\n </Box>","disabled","item.step ?? 1","item.min","item.max","<BoundInput\n // Bumping the key on a fresh external value resets the local\n // editing state — matches v1's RangeItem behaviour.\n key={`min-${current[0]}`}\n name='min'\n value={current[0]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Minimum value'\n />","current[0]","`min-${current[0]}`","<BoundInput\n key={`max-${current[1]}`}\n name='max'\n value={current[1]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Maximum value'\n />","current[1]","`max-${current[1]}`","<Box sx={styles.inputsRow}>\n {/* Text-input commits (blur / Enter) are final, but also notify\n `onChange` — see `commitText` — so consumers that only wired\n `onChange` still update on a typed value. */}\n <BoundInput\n // Bumping the key on a fresh external value resets the local\n // editing state — matches v1's RangeItem behaviour.\n key={`min-${current[0]}`}\n name='min'\n value={current[0]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Minimum value'\n />\n <BoundInput\n key={`max-${current[1]}`}\n name='max'\n value={current[1]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Maximum value'\n />\n </Box>","item.note ? (\n <Typography variant='caption' sx={styles.note}>\n {item.note}\n </Typography>\n ) : null","note","<Box sx={styles.item}>\n <Box sx={styles.sliderContainer}>\n <Slider\n sx={{\n ...styles.slider,\n ...(item.color ? { color: item.color } : null),\n }}\n value={[...current]}\n min={item.min}\n max={item.max}\n step={item.step ?? 1}\n marks={resolveMarks(item.marks)}\n disabled={item.disabled}\n valueLabelDisplay='auto'\n valueLabelFormat={fmt}\n onChange={handleSlider}\n onChangeCommitted={handleSliderCommitted}\n />\n </Box>\n <Box sx={styles.inputsRow}>\n {/* Text-input commits (blur / Enter) are final, but also notify\n `onChange` — see `commitText` — so consumers that only wired\n `onChange` still update on a typed value. */}\n <BoundInput\n // Bumping the key on a fresh external value resets the local\n // editing state — matches v1's RangeItem behaviour.\n key={`min-${current[0]}`}\n name='min'\n value={current[0]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Minimum value'\n />\n <BoundInput\n key={`max-${current[1]}`}\n name='max'\n value={current[1]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Maximum value'\n />\n </Box>\n {item.note ? (\n <Typography variant='caption' sx={styles.note}>\n {item.note}\n </Typography>\n ) : null}\n </Box>","{\n name,\n value,\n item,\n fmt,\n editing,\n setEditing,\n commit,\n current,\n ariaLabel,\n}: BoundInputProps","() => {\n setEditing(name)\n }","e","editing === name ? raw : fmt(Number(raw))","(e) => setRaw(e.target.value)","{\n htmlInput: { 'aria-label': ariaLabel },\n }","<TextField\n name={name}\n value={display}\n onChange={(e) => setRaw(e.target.value)}\n onFocus={beginEditing}\n onBlur={finishEditingAndCommit}\n onKeyDown={commitOnEnter}\n disabled={item.disabled}\n size='small'\n sx={styles.input}\n slotProps={{\n htmlInput: { 'aria-label': ariaLabel },\n }}\n />","{ onChange, onChangeCommitted }: RangeProps","<RangeUI\n items={slice.data}\n formatter={slice.formatter}\n onChange={onChange}\n onChangeCommitted={onChangeCommitted}\n />","data","formatter","{ count = 1 }: RangeSkeletonProps","count = 1","<Box sx={styles.root}>\n {Array.from({ length: count }).map((_, i) => (\n <Box key={`item-${i}`} sx={styles.item}>\n <Skeleton variant='rectangular' sx={styles.track} />\n <Box sx={styles.inputsRow}>\n <Skeleton variant='rectangular' sx={styles.input} />\n <Skeleton variant='rectangular' sx={styles.input} />\n </Box>\n </Box>\n ))}\n </Box>","(_, i) => (\n <Box key={`item-${i}`} sx={styles.item}>\n <Skeleton variant='rectangular' sx={styles.track} />\n <Box sx={styles.inputsRow}>\n <Skeleton variant='rectangular' sx={styles.input} />\n <Skeleton variant='rectangular' sx={styles.input} />\n </Box>\n </Box>\n )"],"sources":["../src/widgets/range/style.ts","../src/widgets/range/range-ui.tsx","../src/widgets/range/range.tsx","../src/widgets/range/skeleton.tsx"],"sourcesContent":["import type { SxProps, Theme } from '@mui/material'\n\nexport const styles = {\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: 3,\n py: 1,\n },\n item: {\n display: 'flex',\n flexDirection: 'column',\n gap: 1.5,\n },\n sliderContainer: {\n display: 'flex',\n flexDirection: 'column',\n gap: 1,\n px: 1,\n },\n slider: {\n width: '100%',\n '&.Mui-disabled': {\n color: (theme: Theme) => theme.palette.text.disabled,\n },\n },\n inputsRow: {\n display: 'flex',\n gap: 2,\n alignItems: 'center',\n },\n input: {\n flex: 1,\n '& .MuiInputBase-input': {\n textAlign: 'center',\n },\n },\n note: {\n color: 'text.secondary',\n },\n} satisfies Record<string, SxProps<Theme>>\n","import {\n useCallback,\n useState,\n type FocusEvent,\n type KeyboardEvent,\n} from 'react'\nimport { Box, Slider, TextField, Typography } from '@mui/material'\nimport type { RangeDataItem, RangeItemValue } from './types'\nimport { styles } from './style'\n\nexport interface RangeUIProps {\n items: readonly RangeDataItem[]\n /**\n * Fires on every pointer tick while a thumb is being dragged (mirrors\n * MUI `<Slider>`'s `onChange`). Use this to update local UI state —\n * not to persist expensive operations like remote queries.\n */\n onChange?: (index: number, value: RangeItemValue) => void\n /**\n * Fires once when the user *releases* a slider thumb after dragging,\n * after an arrow-key adjustment commits, or when the text inputs\n * blur / Enter. Mirrors MUI `<Slider>`'s `onChangeCommitted`. Use\n * this for side-effects you want to throttle to \"drag end\" — e.g.\n * writing the value to a source filter that triggers refetches.\n */\n onChangeCommitted?: (index: number, value: RangeItemValue) => void\n /** Number formatter for the slider tooltip and the text input display. */\n formatter?: (value: number) => string\n}\n\ntype Bound = 'min' | 'max'\n\n/**\n * Pure presentational component for the Range widget. Renders one MUI Slider\n * per item with editable min/max text inputs below — matching the Range v1\n * UX. Each item is always a two-thumb range; supply `value` to seed the\n * starting selection, otherwise it defaults to `[min, max]`.\n */\nexport function RangeUI({\n items,\n onChange,\n onChangeCommitted,\n formatter,\n}: RangeUIProps) {\n const fmt = formatter ?? ((n: number) => String(n))\n return (\n <Box sx={styles.root}>\n {items.map((item, i) => (\n // Composite of the row's track bounds — stable across reorders for\n // any realistic widget configuration. Falls back to a literal +\n // index when bounds collide (degenerate same-min-same-max rows).\n <RangeRow\n key={`range-${item.min}-${item.max}-${i}`}\n index={i}\n item={item}\n fmt={fmt}\n onChange={onChange}\n onChangeCommitted={onChangeCommitted}\n />\n ))}\n </Box>\n )\n}\n\ninterface RangeRowProps {\n index: number\n item: RangeDataItem\n fmt: (n: number) => string\n onChange?: (index: number, value: RangeItemValue) => void\n onChangeCommitted?: (index: number, value: RangeItemValue) => void\n}\n\nfunction RangeRow({\n index,\n item,\n fmt,\n onChange,\n onChangeCommitted,\n}: RangeRowProps) {\n const current: readonly [number, number] = item.value ?? [item.min, item.max]\n const [editing, setEditing] = useState<'' | Bound>('')\n\n // Clamp inside [min, max] and keep `low <= high`. Pulled out so both the\n // live `onChange` path and the commit path share the same normalization.\n const normalize = useCallback(\n (next: readonly [number, number]): readonly [number, number] => {\n const [lowRaw, highRaw] = next\n const low = Math.min(Math.max(lowRaw, item.min), item.max)\n const high = Math.min(Math.max(highRaw, item.min), item.max)\n return low <= high ? [low, high] : [high, low]\n },\n [item.min, item.max],\n )\n\n const commit = useCallback(\n (next: readonly [number, number]) => {\n onChange?.(index, normalize(next))\n },\n [index, normalize, onChange],\n )\n\n const commitFinal = useCallback(\n (next: readonly [number, number]) => {\n onChangeCommitted?.(index, normalize(next))\n },\n [index, normalize, onChangeCommitted],\n )\n\n // A text-input commit (blur / Enter) is both a value change AND a final\n // commit, so it fires `onChange` *and* `onChangeCommitted`. Firing both\n // keeps the widget responsive for consumers that only wired `onChange`\n // (the pre-`onChangeCommitted` API) — without it, typing a value and\n // pressing Enter would silently no-op for them.\n const commitText = useCallback(\n (next: readonly [number, number]) => {\n const value = normalize(next)\n onChange?.(index, value)\n onChangeCommitted?.(index, value)\n },\n [index, normalize, onChange, onChangeCommitted],\n )\n\n const handleSlider = (_: Event, raw: number | number[]) => {\n if (!Array.isArray(raw)) return\n // Hoist defaults out of the destructure: react-compiler can't safely\n // reorder MemberExpression defaults inside an array pattern.\n const low = raw[0] ?? item.min\n const high = raw[1] ?? item.max\n commit([low, high])\n }\n\n const handleSliderCommitted = (\n _: Event | React.SyntheticEvent,\n raw: number | number[],\n ) => {\n if (!Array.isArray(raw)) return\n const low = raw[0] ?? item.min\n const high = raw[1] ?? item.max\n commitFinal([low, high])\n }\n\n return (\n <Box sx={styles.item}>\n <Box sx={styles.sliderContainer}>\n <Slider\n sx={{\n ...styles.slider,\n ...(item.color ? { color: item.color } : null),\n }}\n value={[...current]}\n min={item.min}\n max={item.max}\n step={item.step ?? 1}\n marks={resolveMarks(item.marks)}\n disabled={item.disabled}\n valueLabelDisplay='auto'\n valueLabelFormat={fmt}\n onChange={handleSlider}\n onChangeCommitted={handleSliderCommitted}\n />\n </Box>\n <Box sx={styles.inputsRow}>\n {/* Text-input commits (blur / Enter) are final, but also notify\n `onChange` — see `commitText` — so consumers that only wired\n `onChange` still update on a typed value. */}\n <BoundInput\n // Bumping the key on a fresh external value resets the local\n // editing state — matches v1's RangeItem behaviour.\n key={`min-${current[0]}`}\n name='min'\n value={current[0]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Minimum value'\n />\n <BoundInput\n key={`max-${current[1]}`}\n name='max'\n value={current[1]}\n item={item}\n fmt={fmt}\n editing={editing}\n setEditing={setEditing}\n commit={commitText}\n current={current}\n ariaLabel='Maximum value'\n />\n </Box>\n {item.note ? (\n <Typography variant='caption' sx={styles.note}>\n {item.note}\n </Typography>\n ) : null}\n </Box>\n )\n}\n\ninterface BoundInputProps {\n name: Bound\n value: number\n item: RangeDataItem\n fmt: (n: number) => string\n editing: '' | Bound\n setEditing: (next: '' | Bound) => void\n /**\n * Called when the user commits a new value (blur / Enter). Text input\n * edits never produce intermediate \"live\" values, so the consumer\n * only needs one callback — the row wires this to `commitFinal`.\n */\n commit: (next: readonly [number, number]) => void\n current: readonly [number, number]\n ariaLabel: string\n}\n\nfunction BoundInput({\n name,\n value,\n item,\n fmt,\n editing,\n setEditing,\n commit,\n current,\n ariaLabel,\n}: BoundInputProps) {\n const [raw, setRaw] = useState<string>(String(value))\n\n const beginEditing = () => {\n setEditing(name)\n }\n const finishEditingAndCommit = (e: FocusEvent<HTMLInputElement>) => {\n setEditing('')\n commitFromText(e.target.value)\n }\n const commitOnEnter = (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n commitFromText((e.target as HTMLInputElement).value)\n ;(e.target as HTMLInputElement).blur()\n }\n }\n\n function commitFromText(input: string) {\n const parsed = parseFloat(input)\n const safe = Number.isFinite(parsed) ? parsed : value\n const next: readonly [number, number] =\n name === 'min' ? [safe, current[1]] : [current[0], safe]\n commit(next)\n }\n\n const display = editing === name ? raw : fmt(Number(raw))\n\n return (\n <TextField\n name={name}\n value={display}\n onChange={(e) => setRaw(e.target.value)}\n onFocus={beginEditing}\n onBlur={finishEditingAndCommit}\n onKeyDown={commitOnEnter}\n disabled={item.disabled}\n size='small'\n sx={styles.input}\n slotProps={{\n htmlInput: { 'aria-label': ariaLabel },\n }}\n />\n )\n}\n\nfunction resolveMarks(\n marks: RangeDataItem['marks'],\n): boolean | { value: number; label?: string }[] | undefined {\n if (marks == null) return undefined\n if (typeof marks === 'boolean') return marks\n return [...marks]\n}\n","import { useWidgetId, useWidgetShallow } from '../stores'\nimport { RangeUI } from './range-ui'\nimport type { RangeItemValue, RangeWidgetData } from './types'\n\ninterface RangeSlice {\n data: RangeWidgetData\n formatter?: (value: number) => string\n}\n\nconst rangeSelector = (s: {\n data: unknown\n formatter?: (value: number) => string\n}): RangeSlice => ({\n data: (s.data ?? []) as RangeWidgetData,\n formatter: s.formatter,\n})\n\nexport interface RangeProps {\n /**\n * Fires on every pointer tick while a thumb is being dragged. Use this\n * for cheap UI updates (local state, optimistic display).\n */\n onChange?: (index: number, value: RangeItemValue) => void\n /**\n * Fires once when the user *releases* a slider thumb (or when the text\n * inputs blur / Enter, or when an arrow-key adjustment settles). Use\n * this for expensive side-effects you want throttled to drag end —\n * e.g. writing the value to a source filter that refetches widgets.\n */\n onChangeCommitted?: (index: number, value: RangeItemValue) => void\n}\n\n/**\n * Stateful Range bridge — reads `data` (post-pipeline) and `formatter` from\n * the per-widget store and forwards them to the pure {@link RangeUI}. Per\n * the destination-owned principle, value changes flow back through\n * `onChange` (per-tick) and `onChangeCommitted` (drag end) — the consumer\n * is expected to update the data prop on `<Provider>`. Use `disabled` on\n * individual `RangeDataItem`s to disable specific rows.\n */\nexport function Range({ onChange, onChangeCommitted }: RangeProps) {\n const id = useWidgetId()\n const slice = useWidgetShallow(id, rangeSelector)\n return (\n <RangeUI\n items={slice.data}\n formatter={slice.formatter}\n onChange={onChange}\n onChangeCommitted={onChangeCommitted}\n />\n )\n}\n","import { Box, Skeleton } from '@mui/material'\nimport type { SxProps, Theme } from '@mui/material'\n\nconst styles = {\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: 3,\n py: 1,\n },\n item: {\n display: 'flex',\n flexDirection: 'column',\n gap: 1.5,\n },\n track: { height: 32 },\n inputsRow: {\n display: 'flex',\n gap: 2,\n },\n input: { flex: 1, height: 40 },\n} satisfies Record<string, SxProps<Theme>>\n\nexport interface RangeSkeletonProps {\n count?: number\n}\n\n/**\n * Loading placeholder for the Range widget. Renders `count` rows, each\n * matching the slider-then-inputs layout of {@link RangeUI} so the layout\n * doesn't jump when data resolves.\n */\nexport function RangeSkeleton({ count = 1 }: RangeSkeletonProps) {\n return (\n <Box sx={styles.root}>\n {Array.from({ length: count }).map((_, i) => (\n <Box key={`item-${i}`} sx={styles.item}>\n <Skeleton variant='rectangular' sx={styles.track} />\n <Box sx={styles.inputsRow}>\n <Skeleton variant='rectangular' sx={styles.input} />\n <Skeleton variant='rectangular' sx={styles.input} />\n </Box>\n </Box>\n ))}\n </Box>\n )\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { C as e, T as t } from "./stores-B8CHbgw-.js";
2
- import { n, t as r } from "./download-Vlzn2jzb.js";
3
- import { a as i, c as a, l as o, o as s, s as c, u as l } from "./formula-CdHWtepq.js";
1
+ import { C as e, D as t } from "./stores-DcBOZlU3.js";
2
+ import { n, t as r } from "./download-B4sykOFm.js";
3
+ import { a as i, c as a, l as o, o as s, s as c, u as l } from "./formula-DJS-JLpk.js";
4
4
  import { c as u } from "react/compiler-runtime";
5
5
  import { Box as d, Skeleton as f } from "@mui/material";
6
6
  import { jsx as p, jsxs as m } from "react/jsx-runtime";
@@ -105,16 +105,10 @@ function C(e, t) {
105
105
  //#endregion
106
106
  //#region src/widgets/spread/download.ts
107
107
  function w(e) {
108
- let t = [];
109
- return e.getCaptureEl && t.push(n({
108
+ return r(e, n({
110
109
  filename: e.filename,
111
- getCaptureEl: e.getCaptureEl,
112
- pixelRatio: e.pngPixelRatio,
113
- backgroundColor: e.pngBackgroundColor
114
- })), t.push(r({
115
- filename: e.filename,
116
- getRows: () => {
117
- let t = e.getData(), n = [[
110
+ getRows: (t) => {
111
+ let n = e.getData(t), r = [[
118
112
  "series",
119
113
  "prefix",
120
114
  "min",
@@ -122,7 +116,7 @@ function w(e) {
122
116
  "suffix",
123
117
  "note"
124
118
  ]];
125
- for (let e of t) n.push([
119
+ for (let e of n) r.push([
126
120
  e.series?.name ?? "",
127
121
  e.prefix ?? "",
128
122
  e.min,
@@ -130,9 +124,9 @@ function w(e) {
130
124
  e.suffix ?? "",
131
125
  e.note ?? ""
132
126
  ]);
133
- return n;
127
+ return r;
134
128
  }
135
- })), t;
129
+ }));
136
130
  }
137
131
  //#endregion
138
132
  //#region src/widgets/spread/band.ts
@@ -146,4 +140,4 @@ function T({ value: e, spread: t, variant: n = "percentage" }) {
146
140
  //#endregion
147
141
  export { g as a, b as i, w as n, h as o, S as r, T as t };
148
142
 
149
- //# sourceMappingURL=spread-DuM5oTI1.js.map
143
+ //# sourceMappingURL=spread-CQwFIwuz.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"spread-DuM5oTI1.js","names":["<Value color='inherit'>-</Value>","{ items, formatter, ref }: SpreadUIProps","(n: number) => String(n)","items.map((item, i) => (\n // Composite of series name + min/max bounds for stability across\n // reorders; falls back to the index when bounds happen to collide.\n <Box\n key={`spread-${item.series?.name ?? ''}-${item.min}-${item.max}-${i}`}\n sx={styles.row}\n >\n {item.series ? (\n <Series name={item.series.name} color={item.series.color} />\n ) : null}\n <Box sx={styles.body}>\n <Box sx={styles.valueRow}>\n {item.prefix ? <Prefix>{item.prefix}</Prefix> : null}\n <Value color={item.color}>{fmt(item.min)}</Value>\n <Separator />\n <Value color={item.color}>{fmt(item.max)}</Value>\n {item.suffix ? <Suffix>{item.suffix}</Suffix> : null}\n </Box>\n {item.note ? <Note>{item.note}</Note> : null}\n </Box>\n </Box>\n ))","(item, i) => (\n // Composite of series name + min/max bounds for stability across\n // reorders; falls back to the index when bounds happen to collide.\n <Box\n key={`spread-${item.series?.name ?? ''}-${item.min}-${item.max}-${i}`}\n sx={styles.row}\n >\n {item.series ? (\n <Series name={item.series.name} color={item.series.color} />\n ) : null}\n <Box sx={styles.body}>\n <Box sx={styles.valueRow}>\n {item.prefix ? <Prefix>{item.prefix}</Prefix> : null}\n <Value color={item.color}>{fmt(item.min)}</Value>\n <Separator />\n <Value color={item.color}>{fmt(item.max)}</Value>\n {item.suffix ? <Suffix>{item.suffix}</Suffix> : null}\n </Box>\n {item.note ? <Note>{item.note}</Note> : null}\n </Box>\n </Box>\n )","<Box ref={ref} sx={styles.root}>\n {items.map((item, i) => (\n // Composite of series name + min/max bounds for stability across\n // reorders; falls back to the index when bounds happen to collide.\n <Box\n key={`spread-${item.series?.name ?? ''}-${item.min}-${item.max}-${i}`}\n sx={styles.row}\n >\n {item.series ? (\n <Series name={item.series.name} color={item.series.color} />\n ) : null}\n <Box sx={styles.body}>\n <Box sx={styles.valueRow}>\n {item.prefix ? <Prefix>{item.prefix}</Prefix> : null}\n <Value color={item.color}>{fmt(item.min)}</Value>\n <Separator />\n <Value color={item.color}>{fmt(item.max)}</Value>\n {item.suffix ? <Suffix>{item.suffix}</Suffix> : null}\n </Box>\n {item.note ? <Note>{item.note}</Note> : null}\n </Box>\n </Box>\n ))}\n </Box>","<SpreadUI items={slice.data} formatter={slice.formatter} />","data","formatter","{ count = 1 }: SpreadSkeletonProps","count = 1","<Box sx={styles.root}>\n {Array.from({ length: count }).map((_, i) => (\n <Box key={`row-${i}`} sx={styles.row}>\n <Skeleton variant='rectangular' sx={styles.block} />\n </Box>\n ))}\n </Box>","(_, i) => (\n <Box key={`row-${i}`} sx={styles.row}>\n <Skeleton variant='rectangular' sx={styles.block} />\n </Box>\n )"],"sources":["../src/widgets/spread/separator.tsx","../src/widgets/spread/spread-ui.tsx","../src/widgets/spread/spread.tsx","../src/widgets/spread/skeleton.tsx","../src/widgets/spread/download.ts","../src/widgets/spread/band.ts"],"sourcesContent":["import { Value } from '../formula'\n\n/**\n * Em-dash separator placed between a Spread row's `min` and `max` values.\n * Built from the Formula {@link Value} primitive so typography (h5/600,\n * baseline alignment) matches the numbers around it. Renders with\n * `text.secondary` so it visually recedes between the two bounds.\n */\nexport function Separator() {\n return <Value color='inherit'>-</Value>\n}\n","import { Box } from '@mui/material'\nimport type { Ref } from 'react'\nimport { Note, Prefix, Series, Suffix, Value } from '../formula'\nimport { styles } from '../formula/style'\nimport { Separator } from './separator'\nimport type { SpreadDataItem } from './types'\n\nexport interface SpreadUIProps {\n items: readonly SpreadDataItem[]\n /** Number formatter — applied to each item's `min` and `max`. */\n formatter?: (value: number) => string\n /** Forwarded to the root `<Box>` so consumers can capture the DOM (PNG export). */\n ref?: Ref<HTMLDivElement>\n}\n\n/**\n * Pure presentational component for the Spread widget. Each item renders as\n * a row containing (in order): optional `Series` avatar, a body with\n * `[prefix] min — max [suffix]` plus optional `Note`. Reuses the Formula\n * primitives ({@link Series}, {@link Prefix}, {@link Value}, {@link Suffix},\n * {@link Note}) and the Formula row styles so Spread and Formula stay\n * visually aligned when used together.\n */\nexport function SpreadUI({ items, formatter, ref }: SpreadUIProps) {\n const fmt = formatter ?? ((n: number) => String(n))\n return (\n <Box ref={ref} sx={styles.root}>\n {items.map((item, i) => (\n // Composite of series name + min/max bounds for stability across\n // reorders; falls back to the index when bounds happen to collide.\n <Box\n key={`spread-${item.series?.name ?? ''}-${item.min}-${item.max}-${i}`}\n sx={styles.row}\n >\n {item.series ? (\n <Series name={item.series.name} color={item.series.color} />\n ) : null}\n <Box sx={styles.body}>\n <Box sx={styles.valueRow}>\n {item.prefix ? <Prefix>{item.prefix}</Prefix> : null}\n <Value color={item.color}>{fmt(item.min)}</Value>\n <Separator />\n <Value color={item.color}>{fmt(item.max)}</Value>\n {item.suffix ? <Suffix>{item.suffix}</Suffix> : null}\n </Box>\n {item.note ? <Note>{item.note}</Note> : null}\n </Box>\n </Box>\n ))}\n </Box>\n )\n}\n","import { useWidgetId, useWidgetShallow } from '../stores'\nimport { SpreadUI } from './spread-ui'\nimport type { SpreadWidgetData } from './types'\n\ninterface SpreadSlice {\n data: SpreadWidgetData\n formatter?: (value: number) => string\n}\n\n// Stable empty-data sentinel — keeps the slice's `data` reference stable\n// when the underlying store value is null/undefined so the shallow-equality\n// gate in `useWidgetShallow` doesn't re-render every commit.\nconst EMPTY_DATA: SpreadWidgetData = Object.freeze([]) as SpreadWidgetData\n\nconst spreadSelector = (s: {\n data: unknown\n formatter?: (value: number) => string\n}): SpreadSlice => ({\n data: (s.data ?? EMPTY_DATA) as SpreadWidgetData,\n formatter: s.formatter,\n})\n\n/**\n * Stateful Spread bridge — reads `data` (post-pipeline) and `formatter` from\n * the per-widget store and forwards them to the pure {@link SpreadUI}.\n */\nexport function Spread() {\n const id = useWidgetId()\n const slice = useWidgetShallow(id, spreadSelector)\n return <SpreadUI items={slice.data} formatter={slice.formatter} />\n}\n","import { Box, Skeleton } from '@mui/material'\nimport type { SxProps, Theme } from '@mui/material'\n\nconst styles = {\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n py: 1,\n },\n row: {\n display: 'flex',\n alignItems: 'center',\n gap: 1.5,\n },\n block: { width: 200, height: 32 },\n} satisfies Record<string, SxProps<Theme>>\n\nexport interface SpreadSkeletonProps {\n count?: number\n}\n\n/**\n * Loading placeholder for the Spread widget. Renders `count` rows, each\n * sized for the `min — max` pair so the layout doesn't jump once data\n * resolves. Mirrors the row-per-item structure of {@link SpreadUI}.\n */\nexport function SpreadSkeleton({ count = 1 }: SpreadSkeletonProps) {\n return (\n <Box sx={styles.root}>\n {Array.from({ length: count }).map((_, i) => (\n <Box key={`row-${i}`} sx={styles.row}>\n <Skeleton variant='rectangular' sx={styles.block} />\n </Box>\n ))}\n </Box>\n )\n}\n","import {\n buildCsvDownloadItem,\n buildPngDownloadItem,\n type DownloadItem,\n} from '../actions/download'\nimport type { SpreadWidgetData } from './types'\n\n/**\n * Download menu items for the Spread widget. Always includes a CSV item\n * with `series, prefix, min, max, suffix, note` columns (one row per\n * entry). When `getCaptureEl` is supplied, prepends a PNG item that\n * rasterises the captured element via `html2canvas`.\n */\nexport function createSpreadDownloadConfig(args: {\n filename: string\n getData: () => SpreadWidgetData\n getCaptureEl?: () => HTMLElement | null\n pngPixelRatio?: number\n pngBackgroundColor?: string | null\n}): DownloadItem[] {\n const items: DownloadItem[] = []\n if (args.getCaptureEl) {\n items.push(\n buildPngDownloadItem({\n filename: args.filename,\n getCaptureEl: args.getCaptureEl,\n pixelRatio: args.pngPixelRatio,\n backgroundColor: args.pngBackgroundColor,\n }),\n )\n }\n items.push(\n buildCsvDownloadItem({\n filename: args.filename,\n getRows: () => {\n const data = args.getData()\n const rows: unknown[][] = [\n ['series', 'prefix', 'min', 'max', 'suffix', 'note'],\n ]\n for (const item of data) {\n rows.push([\n item.series?.name ?? '',\n item.prefix ?? '',\n item.min,\n item.max,\n item.suffix ?? '',\n item.note ?? '',\n ])\n }\n return rows\n },\n }),\n )\n return items\n}\n","/**\n * How a `spread` amount is applied to a centre value.\n *\n * - `percentage` — `spread` is a whole-number percentage of the centre\n * value, so `5` means +/-5%.\n * - `absolute` — `spread` is a raw offset in the value's own units.\n */\nexport type SpreadVariant = 'percentage' | 'absolute'\n\nexport interface GetSpreadBandOptions {\n /** The centre value the band is drawn around. */\n value: number\n /** Half-width of the band, read according to `variant`. */\n spread: number\n /** Defaults to `percentage`. */\n variant?: SpreadVariant\n}\n\n/**\n * Derives the `min` / `max` band around a centre value, for feeding a\n * {@link SpreadDataItem} from a single aggregated number (a prediction, a\n * target) plus a tolerance — rather than from a real column range.\n *\n * `spread` is read as a percentage by default, which is what a tolerance\n * almost always is: an absolute offset is meaningless without knowing the\n * value's magnitude, and gets visually lost on large values (+/-5 on a\n * prediction of 204,113 renders as a range indistinguishable from a single\n * number).\n *\n * @example\n * getSpreadBand({ value: 1000, spread: 5 })\n * // -> { min: 950, max: 1050 }\n * getSpreadBand({ value: 1000, spread: 5, variant: 'absolute' })\n * // -> { min: 995, max: 1005 }\n */\nexport function getSpreadBand({\n value,\n spread,\n variant = 'percentage',\n}: GetSpreadBandOptions): { min: number; max: number } {\n const offset = variant === 'absolute' ? spread : (spread / 100) * value\n // Keep `min <= max`: a percentage of a negative centre value (or a negative\n // `spread`) yields a negative offset, which would invert the band.\n const width = Math.abs(offset)\n\n return { min: value - width, max: value + width }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"spread-CQwFIwuz.js","names":["<Value color='inherit'>-</Value>","{ items, formatter, ref }: SpreadUIProps","(n: number) => String(n)","items.map((item, i) => (\n // Composite of series name + min/max bounds for stability across\n // reorders; falls back to the index when bounds happen to collide.\n <Box\n key={`spread-${item.series?.name ?? ''}-${item.min}-${item.max}-${i}`}\n sx={styles.row}\n >\n {item.series ? (\n <Series name={item.series.name} color={item.series.color} />\n ) : null}\n <Box sx={styles.body}>\n <Box sx={styles.valueRow}>\n {item.prefix ? <Prefix>{item.prefix}</Prefix> : null}\n <Value color={item.color}>{fmt(item.min)}</Value>\n <Separator />\n <Value color={item.color}>{fmt(item.max)}</Value>\n {item.suffix ? <Suffix>{item.suffix}</Suffix> : null}\n </Box>\n {item.note ? <Note>{item.note}</Note> : null}\n </Box>\n </Box>\n ))","(item, i) => (\n // Composite of series name + min/max bounds for stability across\n // reorders; falls back to the index when bounds happen to collide.\n <Box\n key={`spread-${item.series?.name ?? ''}-${item.min}-${item.max}-${i}`}\n sx={styles.row}\n >\n {item.series ? (\n <Series name={item.series.name} color={item.series.color} />\n ) : null}\n <Box sx={styles.body}>\n <Box sx={styles.valueRow}>\n {item.prefix ? <Prefix>{item.prefix}</Prefix> : null}\n <Value color={item.color}>{fmt(item.min)}</Value>\n <Separator />\n <Value color={item.color}>{fmt(item.max)}</Value>\n {item.suffix ? <Suffix>{item.suffix}</Suffix> : null}\n </Box>\n {item.note ? <Note>{item.note}</Note> : null}\n </Box>\n </Box>\n )","<Box ref={ref} sx={styles.root}>\n {items.map((item, i) => (\n // Composite of series name + min/max bounds for stability across\n // reorders; falls back to the index when bounds happen to collide.\n <Box\n key={`spread-${item.series?.name ?? ''}-${item.min}-${item.max}-${i}`}\n sx={styles.row}\n >\n {item.series ? (\n <Series name={item.series.name} color={item.series.color} />\n ) : null}\n <Box sx={styles.body}>\n <Box sx={styles.valueRow}>\n {item.prefix ? <Prefix>{item.prefix}</Prefix> : null}\n <Value color={item.color}>{fmt(item.min)}</Value>\n <Separator />\n <Value color={item.color}>{fmt(item.max)}</Value>\n {item.suffix ? <Suffix>{item.suffix}</Suffix> : null}\n </Box>\n {item.note ? <Note>{item.note}</Note> : null}\n </Box>\n </Box>\n ))}\n </Box>","<SpreadUI items={slice.data} formatter={slice.formatter} />","data","formatter","{ count = 1 }: SpreadSkeletonProps","count = 1","<Box sx={styles.root}>\n {Array.from({ length: count }).map((_, i) => (\n <Box key={`row-${i}`} sx={styles.row}>\n <Skeleton variant='rectangular' sx={styles.block} />\n </Box>\n ))}\n </Box>","(_, i) => (\n <Box key={`row-${i}`} sx={styles.row}>\n <Skeleton variant='rectangular' sx={styles.block} />\n </Box>\n )"],"sources":["../src/widgets/spread/separator.tsx","../src/widgets/spread/spread-ui.tsx","../src/widgets/spread/spread.tsx","../src/widgets/spread/skeleton.tsx","../src/widgets/spread/download.ts","../src/widgets/spread/band.ts"],"sourcesContent":["import { Value } from '../formula'\n\n/**\n * Em-dash separator placed between a Spread row's `min` and `max` values.\n * Built from the Formula {@link Value} primitive so typography (h5/600,\n * baseline alignment) matches the numbers around it. Renders with\n * `text.secondary` so it visually recedes between the two bounds.\n */\nexport function Separator() {\n return <Value color='inherit'>-</Value>\n}\n","import { Box } from '@mui/material'\nimport type { Ref } from 'react'\nimport { Note, Prefix, Series, Suffix, Value } from '../formula'\nimport { styles } from '../formula/style'\nimport { Separator } from './separator'\nimport type { SpreadDataItem } from './types'\n\nexport interface SpreadUIProps {\n items: readonly SpreadDataItem[]\n /** Number formatter — applied to each item's `min` and `max`. */\n formatter?: (value: number) => string\n /** Forwarded to the root `<Box>` so consumers can capture the DOM (PNG export). */\n ref?: Ref<HTMLDivElement>\n}\n\n/**\n * Pure presentational component for the Spread widget. Each item renders as\n * a row containing (in order): optional `Series` avatar, a body with\n * `[prefix] min — max [suffix]` plus optional `Note`. Reuses the Formula\n * primitives ({@link Series}, {@link Prefix}, {@link Value}, {@link Suffix},\n * {@link Note}) and the Formula row styles so Spread and Formula stay\n * visually aligned when used together.\n */\nexport function SpreadUI({ items, formatter, ref }: SpreadUIProps) {\n const fmt = formatter ?? ((n: number) => String(n))\n return (\n <Box ref={ref} sx={styles.root}>\n {items.map((item, i) => (\n // Composite of series name + min/max bounds for stability across\n // reorders; falls back to the index when bounds happen to collide.\n <Box\n key={`spread-${item.series?.name ?? ''}-${item.min}-${item.max}-${i}`}\n sx={styles.row}\n >\n {item.series ? (\n <Series name={item.series.name} color={item.series.color} />\n ) : null}\n <Box sx={styles.body}>\n <Box sx={styles.valueRow}>\n {item.prefix ? <Prefix>{item.prefix}</Prefix> : null}\n <Value color={item.color}>{fmt(item.min)}</Value>\n <Separator />\n <Value color={item.color}>{fmt(item.max)}</Value>\n {item.suffix ? <Suffix>{item.suffix}</Suffix> : null}\n </Box>\n {item.note ? <Note>{item.note}</Note> : null}\n </Box>\n </Box>\n ))}\n </Box>\n )\n}\n","import { useWidgetId, useWidgetShallow } from '../stores'\nimport { SpreadUI } from './spread-ui'\nimport type { SpreadWidgetData } from './types'\n\ninterface SpreadSlice {\n data: SpreadWidgetData\n formatter?: (value: number) => string\n}\n\n// Stable empty-data sentinel — keeps the slice's `data` reference stable\n// when the underlying store value is null/undefined so the shallow-equality\n// gate in `useWidgetShallow` doesn't re-render every commit.\nconst EMPTY_DATA: SpreadWidgetData = Object.freeze([]) as SpreadWidgetData\n\nconst spreadSelector = (s: {\n data: unknown\n formatter?: (value: number) => string\n}): SpreadSlice => ({\n data: (s.data ?? EMPTY_DATA) as SpreadWidgetData,\n formatter: s.formatter,\n})\n\n/**\n * Stateful Spread bridge — reads `data` (post-pipeline) and `formatter` from\n * the per-widget store and forwards them to the pure {@link SpreadUI}.\n */\nexport function Spread() {\n const id = useWidgetId()\n const slice = useWidgetShallow(id, spreadSelector)\n return <SpreadUI items={slice.data} formatter={slice.formatter} />\n}\n","import { Box, Skeleton } from '@mui/material'\nimport type { SxProps, Theme } from '@mui/material'\n\nconst styles = {\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n py: 1,\n },\n row: {\n display: 'flex',\n alignItems: 'center',\n gap: 1.5,\n },\n block: { width: 200, height: 32 },\n} satisfies Record<string, SxProps<Theme>>\n\nexport interface SpreadSkeletonProps {\n count?: number\n}\n\n/**\n * Loading placeholder for the Spread widget. Renders `count` rows, each\n * sized for the `min — max` pair so the layout doesn't jump once data\n * resolves. Mirrors the row-per-item structure of {@link SpreadUI}.\n */\nexport function SpreadSkeleton({ count = 1 }: SpreadSkeletonProps) {\n return (\n <Box sx={styles.root}>\n {Array.from({ length: count }).map((_, i) => (\n <Box key={`row-${i}`} sx={styles.row}>\n <Skeleton variant='rectangular' sx={styles.block} />\n </Box>\n ))}\n </Box>\n )\n}\n","import {\n buildCsvDownloadItem,\n withPngItem,\n type DownloadItem,\n type WidgetDownloadArgs,\n} from '../actions/download'\nimport type { SpreadWidgetData } from './types'\n\n/**\n * Download menu items for the Spread widget. Always includes a CSV item with\n * `series, prefix, min, max, suffix, note` columns (one row per entry). When\n * `getCaptureEl` is given, prepends a PNG item that rasterises the captured\n * element via `html2canvas`.\n */\nexport function createSpreadDownloadConfig(\n args: WidgetDownloadArgs<SpreadWidgetData>,\n): DownloadItem[] {\n return withPngItem(\n args,\n buildCsvDownloadItem({\n filename: args.filename,\n getRows: (ctx) => {\n const data = args.getData(ctx)\n const rows: unknown[][] = [\n ['series', 'prefix', 'min', 'max', 'suffix', 'note'],\n ]\n for (const item of data) {\n rows.push([\n item.series?.name ?? '',\n item.prefix ?? '',\n item.min,\n item.max,\n item.suffix ?? '',\n item.note ?? '',\n ])\n }\n return rows\n },\n }),\n )\n}\n","/**\n * How a `spread` amount is applied to a centre value.\n *\n * - `percentage` — `spread` is a whole-number percentage of the centre\n * value, so `5` means +/-5%.\n * - `absolute` — `spread` is a raw offset in the value's own units.\n */\nexport type SpreadVariant = 'percentage' | 'absolute'\n\nexport interface GetSpreadBandOptions {\n /** The centre value the band is drawn around. */\n value: number\n /** Half-width of the band, read according to `variant`. */\n spread: number\n /** Defaults to `percentage`. */\n variant?: SpreadVariant\n}\n\n/**\n * Derives the `min` / `max` band around a centre value, for feeding a\n * {@link SpreadDataItem} from a single aggregated number (a prediction, a\n * target) plus a tolerance — rather than from a real column range.\n *\n * `spread` is read as a percentage by default, which is what a tolerance\n * almost always is: an absolute offset is meaningless without knowing the\n * value's magnitude, and gets visually lost on large values (+/-5 on a\n * prediction of 204,113 renders as a range indistinguishable from a single\n * number).\n *\n * @example\n * getSpreadBand({ value: 1000, spread: 5 })\n * // -> { min: 950, max: 1050 }\n * getSpreadBand({ value: 1000, spread: 5, variant: 'absolute' })\n * // -> { min: 995, max: 1005 }\n */\nexport function getSpreadBand({\n value,\n spread,\n variant = 'percentage',\n}: GetSpreadBandOptions): { min: number; max: number } {\n const offset = variant === 'absolute' ? spread : (spread / 100) * value\n // Keep `min <= max`: a percentage of a negative centre value (or a negative\n // `spread`) yields a negative offset, which would invert the band.\n const width = Math.abs(offset)\n\n return { min: value - width, max: value + width }\n}\n"],"mappings":"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"}
@@ -80,32 +80,38 @@ function A(e, t) {
80
80
  function j(e) {
81
81
  return S.get(e) ?? null;
82
82
  }
83
- function M() {
83
+ function M(e) {
84
+ return (t) => T(t.id ?? e).getState().data;
85
+ }
86
+ function N(e) {
87
+ return (t) => j(t.id ?? e);
88
+ }
89
+ function P() {
84
90
  S.clear();
85
91
  }
86
- function N(e, t) {
92
+ function F(e, t) {
87
93
  t == null ? C.delete(e) : C.set(e, t), w.get(e)?.forEach((e) => e(t));
88
94
  }
89
- function P(e) {
95
+ function I(e) {
90
96
  return C.get(e) ?? null;
91
97
  }
92
- function F(e, t) {
98
+ function L(e, t) {
93
99
  let n = w.get(e);
94
100
  return n || (n = /* @__PURE__ */ new Set(), w.set(e, n)), n.add(t), () => {
95
101
  let n = w.get(e);
96
102
  n && (n.delete(t), n.size === 0 && w.delete(e));
97
103
  };
98
104
  }
99
- function I() {
105
+ function R() {
100
106
  C.clear(), w.clear();
101
107
  }
102
- function L() {
108
+ function z() {
103
109
  return Array.from(y.keys());
104
110
  }
105
- function R(e, t) {
111
+ function B(e, t) {
106
112
  y.set(e, t);
107
113
  }
108
- function z(e, t) {
114
+ function V(e, t) {
109
115
  let n = g(() => ({
110
116
  rawData: t.data,
111
117
  data: t.data,
@@ -124,33 +130,33 @@ function z(e, t) {
124
130
  enabled: o()
125
131
  }));
126
132
  }
127
- function B(e, t) {
133
+ function H(e, t) {
128
134
  y.set(e, t);
129
135
  let n = (b.get(e) ?? 0) + 1;
130
136
  b.set(e, n), n > 1 && o() && !x.has(e) && (console.warn(`[widgets] Duplicate <Widget.Provider id="${e}"> detected. Multiple providers sharing an id will race on prop sync and corrupt the store. Use unique ids per widget instance.`), x.add(e));
131
137
  }
132
- function V(e, t) {
138
+ function U(e, t) {
133
139
  let n = (b.get(e) ?? 1) - 1;
134
140
  n <= 0 ? (b.delete(e), t.keepAlive || y.delete(e)) : b.set(e, n);
135
141
  }
136
- function H(t, n) {
142
+ function W(t, n) {
137
143
  let r = e(2), i;
138
144
  return r[0] === t ? i = r[1] : (i = T(t), r[0] = t, r[1] = i), s(i, n);
139
145
  }
140
- function U(t, n) {
146
+ function G(t, n) {
141
147
  let r = e(2), i;
142
148
  return r[0] === t ? i = r[1] : (i = T(t), r[0] = t, r[1] = i), s(i, u(n));
143
149
  }
144
150
  //#endregion
145
151
  //#region src/widgets/stores/use-echart-instance.ts
146
- var W = () => null;
147
- function G(t) {
152
+ var K = () => null;
153
+ function q(t) {
148
154
  let n = e(3), r, i;
149
- return n[0] === t ? (r = n[1], i = n[2]) : (r = (e) => F(t, e), i = () => P(t), n[0] = t, n[1] = r, n[2] = i), a(r, i, W);
155
+ return n[0] === t ? (r = n[1], i = n[2]) : (r = (e) => L(t, e), i = () => I(t), n[0] = t, n[1] = r, n[2] = i), a(r, i, K);
150
156
  }
151
157
  //#endregion
152
158
  //#region src/widgets/stores/use-transform.ts
153
- function K(t, n, a) {
159
+ function J(t, n, a) {
154
160
  let o = e(29);
155
161
  if (n.length === 0) throw Error("[widgets] useTransform requires at least one pair.");
156
162
  let c;
@@ -213,7 +219,7 @@ function K(t, n, a) {
213
219
  S.current = [];
214
220
  }, D = [l], o[20] = l, o[21] = E, o[22] = D), r(E, D);
215
221
  let O;
216
- o[23] === b ? O = o[24] : (O = () => b(q), o[23] = b, o[24] = O);
222
+ o[23] === b ? O = o[24] : (O = () => b(Y), o[23] = b, o[24] = O);
217
223
  let k = O, A;
218
224
  return o[25] !== g || o[26] !== b || o[27] !== k ? (A = {
219
225
  enabled: g,
@@ -221,23 +227,23 @@ function K(t, n, a) {
221
227
  toggle: k
222
228
  }, o[25] = g, o[26] = b, o[27] = k, o[28] = A) : A = o[28], A;
223
229
  }
224
- function q(e) {
230
+ function Y(e) {
225
231
  return !e;
226
232
  }
227
- function J(t, n, r, i) {
233
+ function X(t, n, r, i) {
228
234
  let a = e(3), o;
229
235
  return a[0] !== n || a[1] !== r ? (o = [{
230
236
  descriptor: n,
231
237
  fn: r
232
- }], a[0] = n, a[1] = r, a[2] = o) : o = a[2], K(t, o, i);
238
+ }], a[0] = n, a[1] = r, a[2] = o) : o = a[2], J(t, o, i);
233
239
  }
234
240
  //#endregion
235
241
  //#region src/widgets/stores/use-transform-enabled.ts
236
- function Y(t, n) {
242
+ function Z(t, n) {
237
243
  let r = e(2), i;
238
- return r[0] === n ? i = r[1] : (i = (e) => e.transformStates?.[n]?.enabled === !0, r[0] = n, r[1] = i), U(t, i);
244
+ return r[0] === n ? i = r[1] : (i = (e) => e.transformStates?.[n]?.enabled === !0, r[0] = n, r[1] = i), G(t, i);
239
245
  }
240
246
  //#endregion
241
- export { U as C, d as D, g as E, p as O, H as S, v as T, A as _, L as a, F as b, k as c, j as d, P as f, O as g, B as h, G as i, f as k, z as l, E as m, J as n, M as o, T as p, K as r, I as s, Y as t, D as u, N as v, _ as w, V as x, R as y };
247
+ export { p as A, G as C, v as D, _ as E, g as O, W as S, M as T, A as _, z as a, L as b, k as c, j as d, I as f, O as g, H as h, q as i, f as j, d as k, V as l, E as m, X as n, P as o, T as p, J as r, R as s, Z as t, D as u, F as v, N as w, U as x, B as y };
242
248
 
243
- //# sourceMappingURL=stores-B8CHbgw-.js.map
249
+ //# sourceMappingURL=stores-DcBOZlU3.js.map