@j2-health/design-system 0.2.1 → 0.3.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 (31) hide show
  1. package/README.md +38 -9
  2. package/dist/index.cjs +6 -0
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.js +6 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/src/components/barchart/BarChart.cjs +8 -1
  7. package/dist/src/components/barchart/BarChart.cjs.map +1 -1
  8. package/dist/src/components/barchart/BarChart.js +8 -1
  9. package/dist/src/components/barchart/BarChart.js.map +1 -1
  10. package/dist/src/components/filterform/FilterInput.cjs +66 -3
  11. package/dist/src/components/filterform/FilterInput.cjs.map +1 -1
  12. package/dist/src/components/filterform/FilterInput.d.ts +1 -0
  13. package/dist/src/components/filterform/FilterInput.js +68 -5
  14. package/dist/src/components/filterform/FilterInput.js.map +1 -1
  15. package/dist/src/components/filterform/filterHelpers.cjs +24 -1
  16. package/dist/src/components/filterform/filterHelpers.cjs.map +1 -1
  17. package/dist/src/components/filterform/filterHelpers.d.ts +18 -4
  18. package/dist/src/components/filterform/filterHelpers.js +24 -1
  19. package/dist/src/components/filterform/filterHelpers.js.map +1 -1
  20. package/dist/src/components/filterform/index.d.ts +3 -1
  21. package/dist/src/components/filterform/types.d.ts +4 -2
  22. package/dist/src/components/filterform/useFilterField.cjs +54 -19
  23. package/dist/src/components/filterform/useFilterField.cjs.map +1 -1
  24. package/dist/src/components/filterform/useFilterField.d.ts +17 -1
  25. package/dist/src/components/filterform/useFilterField.js +55 -20
  26. package/dist/src/components/filterform/useFilterField.js.map +1 -1
  27. package/dist/src/components/vennDiagram/VennDiagram.cjs +7 -1
  28. package/dist/src/components/vennDiagram/VennDiagram.cjs.map +1 -1
  29. package/dist/src/components/vennDiagram/VennDiagram.js +7 -1
  30. package/dist/src/components/vennDiagram/VennDiagram.js.map +1 -1
  31. package/package.json +6 -6
package/README.md CHANGED
@@ -133,8 +133,7 @@ local checkout has its own `node_modules`.
133
133
 
134
134
  ### Publishing to npm
135
135
 
136
- The package is published publicly (the source is public anyway). Publishing is
137
- tag-driven via
136
+ The package is published publicly (the source is public anyway) by
138
137
  [.github/workflows/publish-workflow.yml](.github/workflows/publish-workflow.yml).
139
138
 
140
139
  There is **no publish token**. npm authenticates the release through trusted
@@ -149,14 +148,44 @@ consequences worth knowing before you change anything here:
149
148
  npm >= 11.5.1, which is exactly what Node 24.5.0 ships. The workflow asserts
150
149
  this rather than letting it surface later as an unexplained 401.
151
150
 
152
- To release a new version from `main`:
151
+ To release a new version maintainers only, since step 2 needs write access to
152
+ this repository:
153
+
154
+ 1. Bump `version` in `package.json` in a pull request — on its own, or in the PR
155
+ carrying the change you want to release — and merge it.
156
+ 2. Dispatch the publish workflow against `main`:
157
+
158
+ ```bash
159
+ $ gh workflow run publish-workflow.yml --ref main
160
+ ```
161
+
162
+ Or, in the UI, **Actions → Publish to npm → Run workflow** with `main` selected.
163
+ Pick the ref carefully: the publish job is *skipped* rather than failed on any
164
+ other ref, so a dispatch from a feature branch reports success without
165
+ publishing.
166
+
167
+ That is the whole procedure. The workflow publishes the version `package.json`
168
+ declares and then creates the matching `vX.Y.Z` tag itself, so you do not
169
+ normally tag by hand — the `tag` job's own comments cover the one case that
170
+ needs it, where publishing succeeds and tagging fails.
171
+
172
+ `npm version` is not the tool here, despite being the obvious one: it writes the
173
+ bump as a local commit, and `main` requires a pull request, so that commit has
174
+ nowhere to push to.
175
+
176
+ Pushing a `v*` tag also triggers a release. Tag the remote `main` commit
177
+ explicitly: a bare `git tag` tags your current `HEAD`, and the workflow accepts
178
+ any tag ref, so a tag on an unmerged branch would publish that branch. Push the
179
+ tag explicitly too — `git push --follow-tags` silently skips lightweight tags and
180
+ would report success without publishing:
153
181
 
154
182
  ```bash
155
- $ npm version minor # or patch / major — bumps package.json and creates the vX.Y.Z tag
156
- $ git push origin main --follow-tags
183
+ $ git fetch origin main
184
+ $ git tag -a v0.3.0 -m v0.3.0 origin/main
185
+ $ git push origin v0.3.0
157
186
  ```
158
187
 
159
- The workflow packs the tarball and builds a scratch consumer against it, then
160
- verifies the tag matches `package.json`, runs lint, tests and type-check, builds
161
- the library, and publishes. Provenance is generated automatically by trusted
162
- publishing, so `--provenance` is not passed.
188
+ The workflow packs the tarball and builds a scratch consumer against it, runs
189
+ lint, tests and type-check, builds the library, and publishes; on a tag push it
190
+ also verifies the tag matches `package.json`. Provenance is generated
191
+ automatically by trusted publishing, so `--provenance` is not passed.
package/dist/index.cjs CHANGED
@@ -24,6 +24,7 @@ const LegacyNavMenu = require("./src/components/legacyNavMenu/LegacyNavMenu.cjs"
24
24
  const ListPopover = require("./src/components/listpopover/ListPopover.cjs");
25
25
  const Menu = require("./src/components/menu/Menu.cjs");
26
26
  const Modal = require("./src/components/modal/Modal.cjs");
27
+ const useFilterField = require("./src/components/filterform/useFilterField.cjs");
27
28
  const NavMenu = require("./src/components/navMenu/NavMenu.cjs");
28
29
  const NotificationModal = require("./src/components/notificationModal/NotificationModal.cjs");
29
30
  const Pagination = require("./src/components/pagination/Pagination.cjs");
@@ -45,6 +46,7 @@ const UserProfile = require("./src/components/legacyNavMenu/UserProfile.cjs");
45
46
  const VennDiagram = require("./src/components/vennDiagram/VennDiagram.cjs");
46
47
  const appTheme = require("./src/appTheme.cjs");
47
48
  const index = require("./src/components/icons/index.cjs");
49
+ const filterHelpers = require("./src/components/filterform/filterHelpers.cjs");
48
50
  const tailwind = require("./tailwind.cjs");
49
51
  const useMessage = require("./src/components/message/useMessage.cjs");
50
52
  const useNotification = require("./src/components/notification/useNotification.cjs");
@@ -76,6 +78,8 @@ exports.LegacyNavMenu = LegacyNavMenu.LegacyNavMenu;
76
78
  exports.ListPopover = ListPopover.ListPopover;
77
79
  exports.Menu = Menu.Menu;
78
80
  exports.Modal = Modal.Modal;
81
+ exports.MultiValueTextOperatorOptions = useFilterField.MultiValueTextOperatorOptions;
82
+ exports.operatorOptionsFor = useFilterField.operatorOptionsFor;
79
83
  exports.NavMenu = NavMenu.NavMenu;
80
84
  exports.NotificationModal = NotificationModal.NotificationModal;
81
85
  exports.Pagination = Pagination.Pagination;
@@ -99,6 +103,8 @@ exports.UserProfile = UserProfile.UserProfile;
99
103
  exports.VennDiagram = VennDiagram.VennDiagram;
100
104
  exports.appTheme = appTheme.appTheme;
101
105
  exports.icons = index;
106
+ exports.isMultiValueTextOperator = filterHelpers.isMultiValueTextOperator;
107
+ exports.normalizeMultiValues = filterHelpers.normalizeMultiValues;
102
108
  exports.tailwindPreset = tailwind.tailwindPreset;
103
109
  exports.useMessage = useMessage.useMessage;
104
110
  exports.useNotification = useNotification.useNotification;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/index.js CHANGED
@@ -22,6 +22,7 @@ import { LegacyNavMenu } from "./src/components/legacyNavMenu/LegacyNavMenu.js";
22
22
  import { ListPopover } from "./src/components/listpopover/ListPopover.js";
23
23
  import { Menu } from "./src/components/menu/Menu.js";
24
24
  import { Modal } from "./src/components/modal/Modal.js";
25
+ import { MultiValueTextOperatorOptions, operatorOptionsFor } from "./src/components/filterform/useFilterField.js";
25
26
  import { NavMenu } from "./src/components/navMenu/NavMenu.js";
26
27
  import { NotificationModal } from "./src/components/notificationModal/NotificationModal.js";
27
28
  import { Pagination, withDesignSystemPaginationOverrides } from "./src/components/pagination/Pagination.js";
@@ -43,6 +44,7 @@ import { UserProfile } from "./src/components/legacyNavMenu/UserProfile.js";
43
44
  import { VennDiagram } from "./src/components/vennDiagram/VennDiagram.js";
44
45
  import { appTheme } from "./src/appTheme.js";
45
46
  import * as index from "./src/components/icons/index.js";
47
+ import { isMultiValueTextOperator, normalizeMultiValues } from "./src/components/filterform/filterHelpers.js";
46
48
  import { tailwindPreset } from "./tailwind.js";
47
49
  import { useMessage } from "./src/components/message/useMessage.js";
48
50
  import { useNotification } from "./src/components/notification/useNotification.js";
@@ -72,6 +74,7 @@ export {
72
74
  ListPopover,
73
75
  Menu,
74
76
  Modal,
77
+ MultiValueTextOperatorOptions,
75
78
  NavMenu,
76
79
  NotificationModal,
77
80
  Pagination,
@@ -94,6 +97,9 @@ export {
94
97
  VennDiagram,
95
98
  appTheme,
96
99
  index as icons,
100
+ isMultiValueTextOperator,
101
+ normalizeMultiValues,
102
+ operatorOptionsFor,
97
103
  tailwindPreset,
98
104
  useMessage,
99
105
  useNotification,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -142,7 +142,14 @@ const BarChart = ({
142
142
  }
143
143
  }
144
144
  };
145
- return /* @__PURE__ */ jsxRuntime.jsx(react.Chart, { ref: chartRef, options });
145
+ return /* @__PURE__ */ jsxRuntime.jsx(
146
+ react.Chart,
147
+ {
148
+ ref: chartRef,
149
+ options,
150
+ containerProps: { className: "highcharts-light" }
151
+ }
152
+ );
146
153
  };
147
154
  exports.BarChart = BarChart;
148
155
  //# sourceMappingURL=BarChart.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"BarChart.cjs","sources":["../../../../src/components/barchart/BarChart.tsx"],"sourcesContent":["import { theme } from 'antd'\nimport type * as Highcharts from 'highcharts'\nimport {\n Chart as HighchartsReact,\n type HighchartsReactRefObject,\n} from '@highcharts/react'\nimport '@highcharts/react/options/Accessibility.js'\nimport '@highcharts/react/options/Exporting.js'\nimport styles from './chart.module.css'\nimport { renderToString } from 'react-dom/server'\n\ntype Series = {\n name?: string\n data: Highcharts.PointOptionsObject[] | number[]\n color?: string\n hoverColor?: string\n}\n\ntype BarChartProps = {\n categories: string[]\n series: Series[]\n min: number\n max: number | undefined | null\n tickInterval: number | undefined\n tickFormat?: (value: number) => string\n xAxisTitle?: string\n yAxisTitle?: string\n gridLineColor?: string\n gridLineDashStyle?: Highcharts.DashStyleValue\n xAxisLabelMaxLines?: number\n tooltip: (\n category: string | number | undefined,\n value: number | null | undefined,\n seriesName: string | undefined\n ) => React.ReactNode\n chartRef?: React.RefObject<HighchartsReactRefObject>\n exporting?: Highcharts.ExportingOptions\n maxBars?: number\n barsWidth?: number\n height?: number\n width?: number\n}\n\nconst BarChart = ({\n categories,\n series,\n min,\n max,\n tickInterval,\n tickFormat,\n xAxisTitle,\n yAxisTitle,\n gridLineColor,\n gridLineDashStyle,\n xAxisLabelMaxLines,\n tooltip,\n exporting,\n chartRef,\n height,\n width,\n maxBars = 50,\n barsWidth = undefined,\n}: BarChartProps) => {\n const limitedCategories = categories.slice(0, maxBars)\n const limitedSeries = series.map((s) => ({\n ...s,\n data: s.data.slice(0, maxBars),\n }))\n\n const { token } = theme.useToken()\n\n const baseFont: Highcharts.CSSObject = {\n fontSize: `${token.fontSize}px`,\n fontFamily: token.fontFamily,\n color: token.colorText,\n }\n\n const options: Highcharts.Options = {\n credits: {\n enabled: false,\n },\n chart: {\n type: 'column',\n ...(height ? { height } : {}),\n ...(width ? { width } : {}),\n },\n plotOptions: {\n column: {\n borderRadius: series[0].data.length > 5 ? '20%' : '15%',\n ...(barsWidth !== undefined ? { pointWidth: barsWidth } : {}),\n },\n },\n exporting: {\n ...exporting,\n enabled: false,\n chartOptions: {\n ...exporting?.chartOptions,\n title: {\n align: 'left',\n text: exporting?.chartOptions?.title?.text,\n style: {\n fontSize: `${token.fontSize}px`,\n fontFamily: 'sans-serif',\n color: token.colorText,\n ...exporting?.chartOptions?.title?.style,\n },\n },\n series: limitedSeries.map((s) => ({\n type: 'column',\n color: s.color ? s.color : '#253761', // --j2-blue-9\n })),\n legend: exporting?.chartOptions?.legend || { enabled: false },\n },\n },\n title: {\n text: '',\n },\n xAxis: {\n categories: limitedCategories,\n title: xAxisTitle\n ? {\n text: xAxisTitle,\n style: { ...baseFont, color: token.colorTextDescription },\n }\n : undefined,\n labels: {\n y: 30,\n style: baseFont,\n ...(xAxisLabelMaxLines\n ? {\n useHTML: true,\n formatter: function (\n this: Highcharts.AxisLabelsFormatterContextObject\n ) {\n return `<div style=\"overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: ${xAxisLabelMaxLines}; -webkit-box-orient: vertical; text-align: center;\">${this.value}</div>`\n },\n }\n : {}),\n },\n },\n yAxis: {\n min: min,\n max: max,\n endOnTick: true,\n gridLineDashStyle: gridLineDashStyle || 'Dot',\n gridLineColor: gridLineColor || 'white',\n title: yAxisTitle\n ? {\n text: yAxisTitle,\n style: { ...baseFont, color: token.colorTextDescription },\n x: -10,\n }\n : undefined,\n tickInterval: tickInterval,\n labels: {\n formatter: tickFormat\n ? ({ value }) => tickFormat(value as number)\n : undefined,\n style: baseFont,\n },\n },\n legend: {\n enabled: false,\n },\n series: limitedSeries.map((s) => ({\n data: s.data,\n name: s.name,\n type: 'column',\n color: s.color || 'var(--j2-blue-11)',\n states: {\n hover: {\n color: s.hoverColor || token.colorPrimaryTextHover,\n },\n },\n })),\n tooltip: {\n useHTML: true,\n outside: true,\n backgroundColor: 'transparent',\n shadow: false,\n padding: 0,\n style: { zIndex: 9999 },\n formatter: function (this) {\n return renderToString(\n <div className={styles.tooltip}>\n {tooltip(this.key, this.y, this.series.name)}\n </div>\n )\n },\n },\n }\n\n return <HighchartsReact ref={chartRef} options={options} />\n}\n\nexport { BarChart }\n"],"names":["theme","renderToString","jsx","styles","HighchartsReact"],"mappings":"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"}
1
+ {"version":3,"file":"BarChart.cjs","sources":["../../../../src/components/barchart/BarChart.tsx"],"sourcesContent":["import { theme } from 'antd'\nimport type * as Highcharts from 'highcharts'\nimport {\n Chart as HighchartsReact,\n type HighchartsReactRefObject,\n} from '@highcharts/react'\nimport '@highcharts/react/options/Accessibility.js'\nimport '@highcharts/react/options/Exporting.js'\nimport styles from './chart.module.css'\nimport { renderToString } from 'react-dom/server'\n\ntype Series = {\n name?: string\n data: Highcharts.PointOptionsObject[] | number[]\n color?: string\n hoverColor?: string\n}\n\ntype BarChartProps = {\n categories: string[]\n series: Series[]\n min: number\n max: number | undefined | null\n tickInterval: number | undefined\n tickFormat?: (value: number) => string\n xAxisTitle?: string\n yAxisTitle?: string\n gridLineColor?: string\n gridLineDashStyle?: Highcharts.DashStyleValue\n xAxisLabelMaxLines?: number\n tooltip: (\n category: string | number | undefined,\n value: number | null | undefined,\n seriesName: string | undefined\n ) => React.ReactNode\n chartRef?: React.RefObject<HighchartsReactRefObject>\n exporting?: Highcharts.ExportingOptions\n maxBars?: number\n barsWidth?: number\n height?: number\n width?: number\n}\n\nconst BarChart = ({\n categories,\n series,\n min,\n max,\n tickInterval,\n tickFormat,\n xAxisTitle,\n yAxisTitle,\n gridLineColor,\n gridLineDashStyle,\n xAxisLabelMaxLines,\n tooltip,\n exporting,\n chartRef,\n height,\n width,\n maxBars = 50,\n barsWidth = undefined,\n}: BarChartProps) => {\n const limitedCategories = categories.slice(0, maxBars)\n const limitedSeries = series.map((s) => ({\n ...s,\n data: s.data.slice(0, maxBars),\n }))\n\n const { token } = theme.useToken()\n\n const baseFont: Highcharts.CSSObject = {\n fontSize: `${token.fontSize}px`,\n fontFamily: token.fontFamily,\n color: token.colorText,\n }\n\n const options: Highcharts.Options = {\n credits: {\n enabled: false,\n },\n chart: {\n type: 'column',\n ...(height ? { height } : {}),\n ...(width ? { width } : {}),\n },\n plotOptions: {\n column: {\n borderRadius: series[0].data.length > 5 ? '20%' : '15%',\n ...(barsWidth !== undefined ? { pointWidth: barsWidth } : {}),\n },\n },\n exporting: {\n ...exporting,\n enabled: false,\n chartOptions: {\n ...exporting?.chartOptions,\n title: {\n align: 'left',\n text: exporting?.chartOptions?.title?.text,\n style: {\n fontSize: `${token.fontSize}px`,\n fontFamily: 'sans-serif',\n color: token.colorText,\n ...exporting?.chartOptions?.title?.style,\n },\n },\n series: limitedSeries.map((s) => ({\n type: 'column',\n color: s.color ? s.color : '#253761', // --j2-blue-9\n })),\n legend: exporting?.chartOptions?.legend || { enabled: false },\n },\n },\n title: {\n text: '',\n },\n xAxis: {\n categories: limitedCategories,\n title: xAxisTitle\n ? {\n text: xAxisTitle,\n style: { ...baseFont, color: token.colorTextDescription },\n }\n : undefined,\n labels: {\n y: 30,\n style: baseFont,\n ...(xAxisLabelMaxLines\n ? {\n useHTML: true,\n formatter: function (\n this: Highcharts.AxisLabelsFormatterContextObject\n ) {\n return `<div style=\"overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: ${xAxisLabelMaxLines}; -webkit-box-orient: vertical; text-align: center;\">${this.value}</div>`\n },\n }\n : {}),\n },\n },\n yAxis: {\n min: min,\n max: max,\n endOnTick: true,\n gridLineDashStyle: gridLineDashStyle || 'Dot',\n gridLineColor: gridLineColor || 'white',\n title: yAxisTitle\n ? {\n text: yAxisTitle,\n style: { ...baseFont, color: token.colorTextDescription },\n x: -10,\n }\n : undefined,\n tickInterval: tickInterval,\n labels: {\n formatter: tickFormat\n ? ({ value }) => tickFormat(value as number)\n : undefined,\n style: baseFont,\n },\n },\n legend: {\n enabled: false,\n },\n series: limitedSeries.map((s) => ({\n data: s.data,\n name: s.name,\n type: 'column',\n color: s.color || 'var(--j2-blue-11)',\n states: {\n hover: {\n color: s.hoverColor || token.colorPrimaryTextHover,\n },\n },\n })),\n tooltip: {\n useHTML: true,\n outside: true,\n backgroundColor: 'transparent',\n shadow: false,\n padding: 0,\n style: { zIndex: 9999 },\n formatter: function (this) {\n return renderToString(\n <div className={styles.tooltip}>\n {tooltip(this.key, this.y, this.series.name)}\n </div>\n )\n },\n },\n }\n\n return (\n <HighchartsReact\n ref={chartRef}\n options={options}\n containerProps={{ className: 'highcharts-light' }}\n />\n )\n}\n\nexport { BarChart }\n"],"names":["theme","renderToString","jsx","styles","HighchartsReact"],"mappings":"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"}
@@ -140,7 +140,14 @@ const BarChart = ({
140
140
  }
141
141
  }
142
142
  };
143
- return /* @__PURE__ */ jsx(Chart, { ref: chartRef, options });
143
+ return /* @__PURE__ */ jsx(
144
+ Chart,
145
+ {
146
+ ref: chartRef,
147
+ options,
148
+ containerProps: { className: "highcharts-light" }
149
+ }
150
+ );
144
151
  };
145
152
  export {
146
153
  BarChart
@@ -1 +1 @@
1
- {"version":3,"file":"BarChart.js","sources":["../../../../src/components/barchart/BarChart.tsx"],"sourcesContent":["import { theme } from 'antd'\nimport type * as Highcharts from 'highcharts'\nimport {\n Chart as HighchartsReact,\n type HighchartsReactRefObject,\n} from '@highcharts/react'\nimport '@highcharts/react/options/Accessibility.js'\nimport '@highcharts/react/options/Exporting.js'\nimport styles from './chart.module.css'\nimport { renderToString } from 'react-dom/server'\n\ntype Series = {\n name?: string\n data: Highcharts.PointOptionsObject[] | number[]\n color?: string\n hoverColor?: string\n}\n\ntype BarChartProps = {\n categories: string[]\n series: Series[]\n min: number\n max: number | undefined | null\n tickInterval: number | undefined\n tickFormat?: (value: number) => string\n xAxisTitle?: string\n yAxisTitle?: string\n gridLineColor?: string\n gridLineDashStyle?: Highcharts.DashStyleValue\n xAxisLabelMaxLines?: number\n tooltip: (\n category: string | number | undefined,\n value: number | null | undefined,\n seriesName: string | undefined\n ) => React.ReactNode\n chartRef?: React.RefObject<HighchartsReactRefObject>\n exporting?: Highcharts.ExportingOptions\n maxBars?: number\n barsWidth?: number\n height?: number\n width?: number\n}\n\nconst BarChart = ({\n categories,\n series,\n min,\n max,\n tickInterval,\n tickFormat,\n xAxisTitle,\n yAxisTitle,\n gridLineColor,\n gridLineDashStyle,\n xAxisLabelMaxLines,\n tooltip,\n exporting,\n chartRef,\n height,\n width,\n maxBars = 50,\n barsWidth = undefined,\n}: BarChartProps) => {\n const limitedCategories = categories.slice(0, maxBars)\n const limitedSeries = series.map((s) => ({\n ...s,\n data: s.data.slice(0, maxBars),\n }))\n\n const { token } = theme.useToken()\n\n const baseFont: Highcharts.CSSObject = {\n fontSize: `${token.fontSize}px`,\n fontFamily: token.fontFamily,\n color: token.colorText,\n }\n\n const options: Highcharts.Options = {\n credits: {\n enabled: false,\n },\n chart: {\n type: 'column',\n ...(height ? { height } : {}),\n ...(width ? { width } : {}),\n },\n plotOptions: {\n column: {\n borderRadius: series[0].data.length > 5 ? '20%' : '15%',\n ...(barsWidth !== undefined ? { pointWidth: barsWidth } : {}),\n },\n },\n exporting: {\n ...exporting,\n enabled: false,\n chartOptions: {\n ...exporting?.chartOptions,\n title: {\n align: 'left',\n text: exporting?.chartOptions?.title?.text,\n style: {\n fontSize: `${token.fontSize}px`,\n fontFamily: 'sans-serif',\n color: token.colorText,\n ...exporting?.chartOptions?.title?.style,\n },\n },\n series: limitedSeries.map((s) => ({\n type: 'column',\n color: s.color ? s.color : '#253761', // --j2-blue-9\n })),\n legend: exporting?.chartOptions?.legend || { enabled: false },\n },\n },\n title: {\n text: '',\n },\n xAxis: {\n categories: limitedCategories,\n title: xAxisTitle\n ? {\n text: xAxisTitle,\n style: { ...baseFont, color: token.colorTextDescription },\n }\n : undefined,\n labels: {\n y: 30,\n style: baseFont,\n ...(xAxisLabelMaxLines\n ? {\n useHTML: true,\n formatter: function (\n this: Highcharts.AxisLabelsFormatterContextObject\n ) {\n return `<div style=\"overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: ${xAxisLabelMaxLines}; -webkit-box-orient: vertical; text-align: center;\">${this.value}</div>`\n },\n }\n : {}),\n },\n },\n yAxis: {\n min: min,\n max: max,\n endOnTick: true,\n gridLineDashStyle: gridLineDashStyle || 'Dot',\n gridLineColor: gridLineColor || 'white',\n title: yAxisTitle\n ? {\n text: yAxisTitle,\n style: { ...baseFont, color: token.colorTextDescription },\n x: -10,\n }\n : undefined,\n tickInterval: tickInterval,\n labels: {\n formatter: tickFormat\n ? ({ value }) => tickFormat(value as number)\n : undefined,\n style: baseFont,\n },\n },\n legend: {\n enabled: false,\n },\n series: limitedSeries.map((s) => ({\n data: s.data,\n name: s.name,\n type: 'column',\n color: s.color || 'var(--j2-blue-11)',\n states: {\n hover: {\n color: s.hoverColor || token.colorPrimaryTextHover,\n },\n },\n })),\n tooltip: {\n useHTML: true,\n outside: true,\n backgroundColor: 'transparent',\n shadow: false,\n padding: 0,\n style: { zIndex: 9999 },\n formatter: function (this) {\n return renderToString(\n <div className={styles.tooltip}>\n {tooltip(this.key, this.y, this.series.name)}\n </div>\n )\n },\n },\n }\n\n return <HighchartsReact ref={chartRef} options={options} />\n}\n\nexport { BarChart }\n"],"names":["HighchartsReact"],"mappings":"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"}
1
+ {"version":3,"file":"BarChart.js","sources":["../../../../src/components/barchart/BarChart.tsx"],"sourcesContent":["import { theme } from 'antd'\nimport type * as Highcharts from 'highcharts'\nimport {\n Chart as HighchartsReact,\n type HighchartsReactRefObject,\n} from '@highcharts/react'\nimport '@highcharts/react/options/Accessibility.js'\nimport '@highcharts/react/options/Exporting.js'\nimport styles from './chart.module.css'\nimport { renderToString } from 'react-dom/server'\n\ntype Series = {\n name?: string\n data: Highcharts.PointOptionsObject[] | number[]\n color?: string\n hoverColor?: string\n}\n\ntype BarChartProps = {\n categories: string[]\n series: Series[]\n min: number\n max: number | undefined | null\n tickInterval: number | undefined\n tickFormat?: (value: number) => string\n xAxisTitle?: string\n yAxisTitle?: string\n gridLineColor?: string\n gridLineDashStyle?: Highcharts.DashStyleValue\n xAxisLabelMaxLines?: number\n tooltip: (\n category: string | number | undefined,\n value: number | null | undefined,\n seriesName: string | undefined\n ) => React.ReactNode\n chartRef?: React.RefObject<HighchartsReactRefObject>\n exporting?: Highcharts.ExportingOptions\n maxBars?: number\n barsWidth?: number\n height?: number\n width?: number\n}\n\nconst BarChart = ({\n categories,\n series,\n min,\n max,\n tickInterval,\n tickFormat,\n xAxisTitle,\n yAxisTitle,\n gridLineColor,\n gridLineDashStyle,\n xAxisLabelMaxLines,\n tooltip,\n exporting,\n chartRef,\n height,\n width,\n maxBars = 50,\n barsWidth = undefined,\n}: BarChartProps) => {\n const limitedCategories = categories.slice(0, maxBars)\n const limitedSeries = series.map((s) => ({\n ...s,\n data: s.data.slice(0, maxBars),\n }))\n\n const { token } = theme.useToken()\n\n const baseFont: Highcharts.CSSObject = {\n fontSize: `${token.fontSize}px`,\n fontFamily: token.fontFamily,\n color: token.colorText,\n }\n\n const options: Highcharts.Options = {\n credits: {\n enabled: false,\n },\n chart: {\n type: 'column',\n ...(height ? { height } : {}),\n ...(width ? { width } : {}),\n },\n plotOptions: {\n column: {\n borderRadius: series[0].data.length > 5 ? '20%' : '15%',\n ...(barsWidth !== undefined ? { pointWidth: barsWidth } : {}),\n },\n },\n exporting: {\n ...exporting,\n enabled: false,\n chartOptions: {\n ...exporting?.chartOptions,\n title: {\n align: 'left',\n text: exporting?.chartOptions?.title?.text,\n style: {\n fontSize: `${token.fontSize}px`,\n fontFamily: 'sans-serif',\n color: token.colorText,\n ...exporting?.chartOptions?.title?.style,\n },\n },\n series: limitedSeries.map((s) => ({\n type: 'column',\n color: s.color ? s.color : '#253761', // --j2-blue-9\n })),\n legend: exporting?.chartOptions?.legend || { enabled: false },\n },\n },\n title: {\n text: '',\n },\n xAxis: {\n categories: limitedCategories,\n title: xAxisTitle\n ? {\n text: xAxisTitle,\n style: { ...baseFont, color: token.colorTextDescription },\n }\n : undefined,\n labels: {\n y: 30,\n style: baseFont,\n ...(xAxisLabelMaxLines\n ? {\n useHTML: true,\n formatter: function (\n this: Highcharts.AxisLabelsFormatterContextObject\n ) {\n return `<div style=\"overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: ${xAxisLabelMaxLines}; -webkit-box-orient: vertical; text-align: center;\">${this.value}</div>`\n },\n }\n : {}),\n },\n },\n yAxis: {\n min: min,\n max: max,\n endOnTick: true,\n gridLineDashStyle: gridLineDashStyle || 'Dot',\n gridLineColor: gridLineColor || 'white',\n title: yAxisTitle\n ? {\n text: yAxisTitle,\n style: { ...baseFont, color: token.colorTextDescription },\n x: -10,\n }\n : undefined,\n tickInterval: tickInterval,\n labels: {\n formatter: tickFormat\n ? ({ value }) => tickFormat(value as number)\n : undefined,\n style: baseFont,\n },\n },\n legend: {\n enabled: false,\n },\n series: limitedSeries.map((s) => ({\n data: s.data,\n name: s.name,\n type: 'column',\n color: s.color || 'var(--j2-blue-11)',\n states: {\n hover: {\n color: s.hoverColor || token.colorPrimaryTextHover,\n },\n },\n })),\n tooltip: {\n useHTML: true,\n outside: true,\n backgroundColor: 'transparent',\n shadow: false,\n padding: 0,\n style: { zIndex: 9999 },\n formatter: function (this) {\n return renderToString(\n <div className={styles.tooltip}>\n {tooltip(this.key, this.y, this.series.name)}\n </div>\n )\n },\n },\n }\n\n return (\n <HighchartsReact\n ref={chartRef}\n options={options}\n containerProps={{ className: 'highcharts-light' }}\n />\n )\n}\n\nexport { BarChart }\n"],"names":["HighchartsReact"],"mappings":"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"}
@@ -4,6 +4,7 @@ const jsxRuntime = require("react/jsx-runtime");
4
4
  const React = require("react");
5
5
  const useFilterField = require("./useFilterField.cjs");
6
6
  const antd = require("antd");
7
+ const filterHelpers = require("./filterHelpers.cjs");
7
8
  const cx = require("classnames");
8
9
  function _interopNamespaceDefault(e) {
9
10
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -46,10 +47,13 @@ const FilterInput = ({
46
47
  value: config.field,
47
48
  disabled: config.disabled
48
49
  }));
50
+ const latestFilterRef = React__namespace.useRef(filter);
51
+ latestFilterRef.current = filter;
49
52
  const handleBlur = () => {
50
- if (filter) {
51
- onBlur == null ? void 0 : onBlur(filter);
52
- }
53
+ setTimeout(() => {
54
+ const latest = latestFilterRef.current;
55
+ if (latest) onBlur == null ? void 0 : onBlur(latest);
56
+ }, 0);
53
57
  };
54
58
  const isInitialMount = React__namespace.useRef(true);
55
59
  const prevFilterRef = React__namespace.useRef(filter);
@@ -57,6 +61,9 @@ const FilterInput = ({
57
61
  if (isInitialMount.current) {
58
62
  isInitialMount.current = false;
59
63
  prevFilterRef.current = filter;
64
+ if (value && filter && wasCorrectedOnInit(value, filter)) {
65
+ onChange == null ? void 0 : onChange(filter);
66
+ }
60
67
  return;
61
68
  }
62
69
  if (filter && filter !== prevFilterRef.current) {
@@ -101,6 +108,8 @@ const FilterInput = ({
101
108
  ] })
102
109
  ] });
103
110
  };
111
+ const sameList = (a, b) => a.length === b.length && a.every((item, i) => item === b[i]);
112
+ const wasCorrectedOnInit = (persisted, current) => persisted.operator !== current.operator || !sameList(persisted.values, current.values) || persisted.errors === void 0 || !sameList(persisted.errors, current.errors ?? []);
104
113
  const ValueInput = ({
105
114
  valueInputConfig,
106
115
  values,
@@ -157,6 +166,18 @@ const ValueInput = ({
157
166
  ] }, `number-input-${index}`)
158
167
  ) });
159
168
  case "text":
169
+ if (valueInputConfig.multiValue) {
170
+ return /* @__PURE__ */ jsxRuntime.jsx(
171
+ MultiValueTextInput,
172
+ {
173
+ values,
174
+ maxValues: valueInputConfig.maxValues,
175
+ onChange,
176
+ onBlur,
177
+ size
178
+ }
179
+ );
180
+ }
160
181
  return /* @__PURE__ */ jsxRuntime.jsx(
161
182
  antd.Input,
162
183
  {
@@ -171,5 +192,47 @@ const ValueInput = ({
171
192
  return null;
172
193
  }
173
194
  };
195
+ const MULTI_VALUE_TOKEN_SEPARATORS = [",", "\n", "\r", " "];
196
+ const MultiValueTextInput = ({
197
+ values,
198
+ maxValues,
199
+ onChange,
200
+ onBlur,
201
+ size
202
+ }) => {
203
+ const chips = (values ?? []).flatMap(
204
+ (value) => value === null || value === void 0 ? [] : [String(value)]
205
+ );
206
+ const over = maxValues !== void 0 && chips.length > maxValues;
207
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 w-full min-w-0", children: [
208
+ /* @__PURE__ */ jsxRuntime.jsx(
209
+ antd.Select,
210
+ {
211
+ mode: "tags",
212
+ tokenSeparators: MULTI_VALUE_TOKEN_SEPARATORS,
213
+ value: chips,
214
+ onChange: (next) => onChange(filterHelpers.normalizeMultiValues(next)),
215
+ onBlur,
216
+ open: false,
217
+ suffixIcon: null,
218
+ placeholder: "Type or paste values, separated by commas",
219
+ className: "w-full",
220
+ size,
221
+ status: over ? "error" : void 0,
222
+ "aria-label": "Values"
223
+ }
224
+ ),
225
+ maxValues !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
226
+ antd.Typography.Text,
227
+ {
228
+ type: over ? "danger" : "secondary",
229
+ className: "text-xs",
230
+ role: over ? "alert" : void 0,
231
+ children: over ? `${filterHelpers.tooManyValuesMessage(maxValues)} — remove ${chips.length - maxValues} to apply` : `${chips.length} / ${maxValues} values`
232
+ }
233
+ )
234
+ ] });
235
+ };
174
236
  exports.FilterInput = FilterInput;
237
+ exports.MULTI_VALUE_TOKEN_SEPARATORS = MULTI_VALUE_TOKEN_SEPARATORS;
175
238
  //# sourceMappingURL=FilterInput.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"FilterInput.cjs","sources":["../../../../src/components/filterform/FilterInput.tsx"],"sourcesContent":["import * as React from 'react'\nimport { FilterConfig } from '.'\nimport { useFilterField } from './useFilterField'\nimport { Input, InputNumber, Select } from 'antd'\nimport { FormFilter } from './types'\nimport cx from 'classnames'\nimport { SizeType } from 'antd/es/config-provider/SizeContext'\n\ntype SelectValueInputConfig = {\n type: 'select'\n valueOptions: { label: string; value: string }[]\n}\n\ntype NumberValueInputConfig = {\n type: 'number'\n inputCount: number\n numberOptions?: { max: number; min: number; step: number }\n}\n\ntype TextValueInputConfig = {\n type: 'text'\n}\n\ntype ValueInputConfig =\n SelectValueInputConfig | NumberValueInputConfig | TextValueInputConfig\n\ntype FilterInputProps = {\n value?: FormFilter\n filterConfigs: FilterConfig[]\n onChange?: (value: FormFilter) => void\n onBlur?: (value: FormFilter) => void\n className?: string\n size?: SizeType\n}\n\nexport const FilterInput = ({\n value,\n filterConfigs,\n onChange,\n onBlur,\n className,\n size = 'middle',\n}: FilterInputProps) => {\n const {\n filter,\n operatorOptions,\n valueInputConfig,\n handleFieldChange,\n handleOperatorChange,\n handleValuesChange,\n } = useFilterField({\n filterConfigs,\n filter: value,\n })\n\n const fieldOptions = filterConfigs.map((config) => ({\n label: config.label,\n value: config.field,\n disabled: config.disabled,\n }))\n\n const handleBlur = () => {\n if (filter) {\n onBlur?.(filter)\n }\n }\n\n // Track if this is a user-driven change (not initialization)\n const isInitialMount = React.useRef(true)\n const prevFilterRef = React.useRef(filter)\n\n React.useEffect(() => {\n // Skip the initial mount to avoid calling onChange during initialization\n if (isInitialMount.current) {\n isInitialMount.current = false\n prevFilterRef.current = filter\n return\n }\n\n // Only call onChange if the filter actually changed\n if (filter && filter !== prevFilterRef.current) {\n prevFilterRef.current = filter\n onChange?.(filter)\n }\n }, [filter, onChange])\n\n return (\n <div className={cx('grid grid-cols-3 gap-2', className)}>\n <Select\n options={fieldOptions}\n value={filter?.field}\n showSearch\n optionFilterProp=\"label\"\n onChange={handleFieldChange}\n size={size}\n />\n <div className=\"col-span-2 flex gap-2\">\n <Select\n options={operatorOptions}\n value={filter?.operator}\n onChange={handleOperatorChange}\n onBlur={handleBlur}\n size={size}\n popupMatchSelectWidth={false}\n />\n {valueInputConfig && (\n <ValueInput\n valueInputConfig={valueInputConfig}\n values={filter?.values}\n onChange={handleValuesChange}\n onBlur={handleBlur}\n size={size}\n />\n )}\n </div>\n </div>\n )\n}\n\ntype ValueInputProps = {\n valueInputConfig: ValueInputConfig\n values?: (string | number | undefined | null)[]\n onChange: (value: (string | number | undefined | null)[]) => void\n onBlur: () => void\n size: SizeType\n}\n\nconst ValueInput = ({\n valueInputConfig,\n values,\n onChange,\n onBlur,\n size,\n}: ValueInputProps) => {\n const handleChange = (value: string | number | null) => {\n if (value === null) {\n onChange([])\n } else {\n onChange([value])\n }\n }\n\n const handleNumberChange = (value: string | number | null, index: number) => {\n const newValues: (string | number | undefined | null)[] = [\n ...(values ?? []),\n ]\n newValues[index] = value\n onChange(newValues)\n }\n\n switch (valueInputConfig.type) {\n case 'select':\n return (\n <Select\n options={valueInputConfig.valueOptions}\n onChange={onChange}\n showSearch\n allowClear\n mode=\"multiple\"\n onBlur={onBlur}\n value={values}\n className=\"w-full truncate\"\n size={size}\n optionFilterProp=\"label\"\n />\n )\n case 'number':\n return (\n <div className=\"flex gap-2 grow\">\n {Array.from({ length: valueInputConfig.inputCount }).map(\n (_, index) => (\n <React.Fragment key={`number-input-${index}`}>\n {index !== 0 && <span className=\"my-auto\">and</span>}\n <InputNumber\n onChange={(value) => handleNumberChange(value, index)}\n onBlur={onBlur}\n value={values?.[index]}\n className=\"basis-1/2\"\n size={size}\n {...(valueInputConfig.numberOptions ?? {})}\n />\n </React.Fragment>\n )\n )}\n </div>\n )\n case 'text':\n return (\n <Input\n onBlur={onBlur}\n value={values?.[0] ?? undefined}\n onChange={(e) => handleChange(e.target.value)}\n className=\"w-full\"\n size={size}\n />\n )\n default:\n return null\n }\n}\n"],"names":["useFilterField","React","jsx","Select","jsxs","InputNumber","Input"],"mappings":"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"}
1
+ {"version":3,"file":"FilterInput.cjs","sources":["../../../../src/components/filterform/FilterInput.tsx"],"sourcesContent":["import * as React from 'react'\nimport { FilterConfig } from '.'\nimport { useFilterField, ValueInputConfig } from './useFilterField'\nimport { Input, InputNumber, Select, Typography } from 'antd'\nimport { FormFilter } from './types'\nimport { normalizeMultiValues, tooManyValuesMessage } from './filterHelpers'\nimport cx from 'classnames'\nimport { SizeType } from 'antd/es/config-provider/SizeContext'\n\ntype FilterInputProps = {\n value?: FormFilter\n filterConfigs: FilterConfig[]\n onChange?: (value: FormFilter) => void\n onBlur?: (value: FormFilter) => void\n className?: string\n size?: SizeType\n}\n\nexport const FilterInput = ({\n value,\n filterConfigs,\n onChange,\n onBlur,\n className,\n size = 'middle',\n}: FilterInputProps) => {\n const {\n filter,\n operatorOptions,\n valueInputConfig,\n handleFieldChange,\n handleOperatorChange,\n handleValuesChange,\n } = useFilterField({\n filterConfigs,\n filter: value,\n })\n\n const fieldOptions = filterConfigs.map((config) => ({\n label: config.label,\n value: config.field,\n disabled: config.disabled,\n }))\n\n // Mirror of the reducer's filter for callbacks that run after a render.\n const latestFilterRef = React.useRef(filter)\n latestFilterRef.current = filter\n\n // Deferred a tick, and read from the ref rather than the closure. A tags\n // `Select` commits unseparated search text as a chip inside its own blur\n // handling, so `onChange` and `onBlur` arrive in the same browser event and\n // React flushes the resulting reducer update only after both return. A\n // synchronous `onBlur` would hand the parent the filter from *before* that\n // last chip — and for a new rule the parent finalizes and unmounts this\n // input, silently dropping the value. After the flush the ref holds it.\n const handleBlur = () => {\n setTimeout(() => {\n const latest = latestFilterRef.current\n if (latest) onBlur?.(latest)\n }, 0)\n }\n\n // Track if this is a user-driven change (not initialization)\n const isInitialMount = React.useRef(true)\n const prevFilterRef = React.useRef(filter)\n\n React.useEffect(() => {\n // Skip the initial mount to avoid calling onChange during initialization\n // — unless initialization itself corrected the persisted filter (an\n // operator the field no longer offers, or a chip list that needed\n // normalizing). Then the parent must learn about it, or it would keep\n // and submit the stale filter until the user happened to touch the rule.\n if (isInitialMount.current) {\n isInitialMount.current = false\n prevFilterRef.current = filter\n if (value && filter && wasCorrectedOnInit(value, filter)) {\n onChange?.(filter)\n }\n return\n }\n\n // Only call onChange if the filter actually changed\n if (filter && filter !== prevFilterRef.current) {\n prevFilterRef.current = filter\n onChange?.(filter)\n }\n }, [filter, onChange])\n\n return (\n <div className={cx('grid grid-cols-3 gap-2', className)}>\n <Select\n options={fieldOptions}\n value={filter?.field}\n showSearch\n optionFilterProp=\"label\"\n onChange={handleFieldChange}\n size={size}\n />\n <div className=\"col-span-2 flex gap-2\">\n <Select\n options={operatorOptions}\n value={filter?.operator}\n onChange={handleOperatorChange}\n onBlur={handleBlur}\n size={size}\n popupMatchSelectWidth={false}\n />\n {valueInputConfig && (\n <ValueInput\n valueInputConfig={valueInputConfig}\n values={filter?.values}\n onChange={handleValuesChange}\n onBlur={handleBlur}\n size={size}\n />\n )}\n </div>\n </div>\n )\n}\n\nconst sameList = (a: readonly unknown[], b: readonly unknown[]) =>\n a.length === b.length && a.every((item, i) => item === b[i])\n\n// Whether initializing from a persisted filter changed anything the parent\n// holds — operator, values, or the validation result. `errors` counts: a\n// persisted rule can be unchanged yet newly invalid (a lowered `maxValues`),\n// or arrive with no `errors` at all (a plain `FilterForm` from storage), and\n// the form's validity is computed from the errors it holds, not from ours.\nconst wasCorrectedOnInit = (persisted: FormFilter, current: FormFilter) =>\n persisted.operator !== current.operator ||\n !sameList(persisted.values, current.values) ||\n persisted.errors === undefined ||\n !sameList(persisted.errors, current.errors ?? [])\n\ntype ValueInputProps = {\n valueInputConfig: ValueInputConfig\n values?: (string | number | undefined | null)[]\n onChange: (value: (string | number | undefined | null)[]) => void\n onBlur: () => void\n size: SizeType\n}\n\nconst ValueInput = ({\n valueInputConfig,\n values,\n onChange,\n onBlur,\n size,\n}: ValueInputProps) => {\n const handleChange = (value: string | number | null) => {\n if (value === null) {\n onChange([])\n } else {\n onChange([value])\n }\n }\n\n const handleNumberChange = (value: string | number | null, index: number) => {\n const newValues: (string | number | undefined | null)[] = [\n ...(values ?? []),\n ]\n newValues[index] = value\n onChange(newValues)\n }\n\n switch (valueInputConfig.type) {\n case 'select':\n return (\n <Select\n options={valueInputConfig.valueOptions}\n onChange={onChange}\n showSearch\n allowClear\n mode=\"multiple\"\n onBlur={onBlur}\n value={values}\n className=\"w-full truncate\"\n size={size}\n optionFilterProp=\"label\"\n />\n )\n case 'number':\n return (\n <div className=\"flex gap-2 grow\">\n {Array.from({ length: valueInputConfig.inputCount }).map(\n (_, index) => (\n <React.Fragment key={`number-input-${index}`}>\n {index !== 0 && <span className=\"my-auto\">and</span>}\n <InputNumber\n onChange={(value) => handleNumberChange(value, index)}\n onBlur={onBlur}\n value={values?.[index]}\n className=\"basis-1/2\"\n size={size}\n {...(valueInputConfig.numberOptions ?? {})}\n />\n </React.Fragment>\n )\n )}\n </div>\n )\n case 'text':\n if (valueInputConfig.multiValue) {\n return (\n <MultiValueTextInput\n values={values}\n maxValues={valueInputConfig.maxValues}\n onChange={onChange}\n onBlur={onBlur}\n size={size}\n />\n )\n }\n return (\n <Input\n onBlur={onBlur}\n value={values?.[0] ?? undefined}\n onChange={(e) => handleChange(e.target.value)}\n className=\"w-full\"\n size={size}\n />\n )\n default:\n return null\n }\n}\n\n// Commas, newlines (both flavours) and tabs: a column pasted from Excel or a\n// comma-separated list from an email both land as one chip per value.\nexport const MULTI_VALUE_TOKEN_SEPARATORS = [',', '\\n', '\\r', '\\t']\n\n/**\n * Chips input for the multi-value text operators (`isAnyOf` / `isNoneOf`).\n *\n * A tags Select rather than a text box split at query time: every token is\n * visible and individually removable before Apply, so a pasted value that\n * itself contains a comma (street addresses do) can be seen and fixed\n * instead of being silently shredded. The dropdown is kept closed — there\n * are no options to pick from; Enter or a separator commits a chip.\n */\nconst MultiValueTextInput = ({\n values,\n maxValues,\n onChange,\n onBlur,\n size,\n}: {\n values?: (string | number | undefined | null)[]\n maxValues?: number\n onChange: (value: (string | number | undefined | null)[]) => void\n onBlur: () => void\n size: SizeType\n}) => {\n // Rendered as stored: `useFilterField` normalizes values on the way into\n // state, so what the chips show is exactly what validation counts and\n // what `onSubmit` emits. (Numbers/nulls can't occur for a text filter;\n // the map is only for the shared `values` type.)\n const chips = (values ?? []).flatMap((value) =>\n value === null || value === undefined ? [] : [String(value)]\n )\n const over = maxValues !== undefined && chips.length > maxValues\n\n return (\n <div className=\"flex flex-col gap-1 w-full min-w-0\">\n <Select\n mode=\"tags\"\n tokenSeparators={MULTI_VALUE_TOKEN_SEPARATORS}\n value={chips}\n onChange={(next: string[]) => onChange(normalizeMultiValues(next))}\n onBlur={onBlur}\n open={false}\n suffixIcon={null}\n placeholder=\"Type or paste values, separated by commas\"\n className=\"w-full\"\n size={size}\n status={over ? 'error' : undefined}\n aria-label=\"Values\"\n />\n {maxValues !== undefined && (\n <Typography.Text\n type={over ? 'danger' : 'secondary'}\n className=\"text-xs\"\n role={over ? 'alert' : undefined}\n >\n {over\n ? `${tooManyValuesMessage(maxValues)} — remove ${\n chips.length - maxValues\n } to apply`\n : `${chips.length} / ${maxValues} values`}\n </Typography.Text>\n )}\n </div>\n )\n}\n"],"names":["useFilterField","React","jsx","Select","jsxs","InputNumber","Input","normalizeMultiValues","Typography","tooManyValuesMessage"],"mappings":"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"}
@@ -11,4 +11,5 @@ type FilterInputProps = {
11
11
  size?: SizeType;
12
12
  };
13
13
  export declare const FilterInput: ({ value, filterConfigs, onChange, onBlur, className, size, }: FilterInputProps) => React.JSX.Element;
14
+ export declare const MULTI_VALUE_TOKEN_SEPARATORS: string[];
14
15
  export {};
@@ -1,7 +1,8 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { useFilterField } from "./useFilterField.js";
4
- import { Select, Input, InputNumber } from "antd";
4
+ import { Select, Input, InputNumber, Typography } from "antd";
5
+ import { normalizeMultiValues, tooManyValuesMessage } from "./filterHelpers.js";
5
6
  import cx from "classnames";
6
7
  const FilterInput = ({
7
8
  value,
@@ -27,10 +28,13 @@ const FilterInput = ({
27
28
  value: config.field,
28
29
  disabled: config.disabled
29
30
  }));
31
+ const latestFilterRef = React.useRef(filter);
32
+ latestFilterRef.current = filter;
30
33
  const handleBlur = () => {
31
- if (filter) {
32
- onBlur == null ? void 0 : onBlur(filter);
33
- }
34
+ setTimeout(() => {
35
+ const latest = latestFilterRef.current;
36
+ if (latest) onBlur == null ? void 0 : onBlur(latest);
37
+ }, 0);
34
38
  };
35
39
  const isInitialMount = React.useRef(true);
36
40
  const prevFilterRef = React.useRef(filter);
@@ -38,6 +42,9 @@ const FilterInput = ({
38
42
  if (isInitialMount.current) {
39
43
  isInitialMount.current = false;
40
44
  prevFilterRef.current = filter;
45
+ if (value && filter && wasCorrectedOnInit(value, filter)) {
46
+ onChange == null ? void 0 : onChange(filter);
47
+ }
41
48
  return;
42
49
  }
43
50
  if (filter && filter !== prevFilterRef.current) {
@@ -82,6 +89,8 @@ const FilterInput = ({
82
89
  ] })
83
90
  ] });
84
91
  };
92
+ const sameList = (a, b) => a.length === b.length && a.every((item, i) => item === b[i]);
93
+ const wasCorrectedOnInit = (persisted, current) => persisted.operator !== current.operator || !sameList(persisted.values, current.values) || persisted.errors === void 0 || !sameList(persisted.errors, current.errors ?? []);
85
94
  const ValueInput = ({
86
95
  valueInputConfig,
87
96
  values,
@@ -138,6 +147,18 @@ const ValueInput = ({
138
147
  ] }, `number-input-${index}`)
139
148
  ) });
140
149
  case "text":
150
+ if (valueInputConfig.multiValue) {
151
+ return /* @__PURE__ */ jsx(
152
+ MultiValueTextInput,
153
+ {
154
+ values,
155
+ maxValues: valueInputConfig.maxValues,
156
+ onChange,
157
+ onBlur,
158
+ size
159
+ }
160
+ );
161
+ }
141
162
  return /* @__PURE__ */ jsx(
142
163
  Input,
143
164
  {
@@ -152,7 +173,49 @@ const ValueInput = ({
152
173
  return null;
153
174
  }
154
175
  };
176
+ const MULTI_VALUE_TOKEN_SEPARATORS = [",", "\n", "\r", " "];
177
+ const MultiValueTextInput = ({
178
+ values,
179
+ maxValues,
180
+ onChange,
181
+ onBlur,
182
+ size
183
+ }) => {
184
+ const chips = (values ?? []).flatMap(
185
+ (value) => value === null || value === void 0 ? [] : [String(value)]
186
+ );
187
+ const over = maxValues !== void 0 && chips.length > maxValues;
188
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 w-full min-w-0", children: [
189
+ /* @__PURE__ */ jsx(
190
+ Select,
191
+ {
192
+ mode: "tags",
193
+ tokenSeparators: MULTI_VALUE_TOKEN_SEPARATORS,
194
+ value: chips,
195
+ onChange: (next) => onChange(normalizeMultiValues(next)),
196
+ onBlur,
197
+ open: false,
198
+ suffixIcon: null,
199
+ placeholder: "Type or paste values, separated by commas",
200
+ className: "w-full",
201
+ size,
202
+ status: over ? "error" : void 0,
203
+ "aria-label": "Values"
204
+ }
205
+ ),
206
+ maxValues !== void 0 && /* @__PURE__ */ jsx(
207
+ Typography.Text,
208
+ {
209
+ type: over ? "danger" : "secondary",
210
+ className: "text-xs",
211
+ role: over ? "alert" : void 0,
212
+ children: over ? `${tooManyValuesMessage(maxValues)} — remove ${chips.length - maxValues} to apply` : `${chips.length} / ${maxValues} values`
213
+ }
214
+ )
215
+ ] });
216
+ };
155
217
  export {
156
- FilterInput
218
+ FilterInput,
219
+ MULTI_VALUE_TOKEN_SEPARATORS
157
220
  };
158
221
  //# sourceMappingURL=FilterInput.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FilterInput.js","sources":["../../../../src/components/filterform/FilterInput.tsx"],"sourcesContent":["import * as React from 'react'\nimport { FilterConfig } from '.'\nimport { useFilterField } from './useFilterField'\nimport { Input, InputNumber, Select } from 'antd'\nimport { FormFilter } from './types'\nimport cx from 'classnames'\nimport { SizeType } from 'antd/es/config-provider/SizeContext'\n\ntype SelectValueInputConfig = {\n type: 'select'\n valueOptions: { label: string; value: string }[]\n}\n\ntype NumberValueInputConfig = {\n type: 'number'\n inputCount: number\n numberOptions?: { max: number; min: number; step: number }\n}\n\ntype TextValueInputConfig = {\n type: 'text'\n}\n\ntype ValueInputConfig =\n SelectValueInputConfig | NumberValueInputConfig | TextValueInputConfig\n\ntype FilterInputProps = {\n value?: FormFilter\n filterConfigs: FilterConfig[]\n onChange?: (value: FormFilter) => void\n onBlur?: (value: FormFilter) => void\n className?: string\n size?: SizeType\n}\n\nexport const FilterInput = ({\n value,\n filterConfigs,\n onChange,\n onBlur,\n className,\n size = 'middle',\n}: FilterInputProps) => {\n const {\n filter,\n operatorOptions,\n valueInputConfig,\n handleFieldChange,\n handleOperatorChange,\n handleValuesChange,\n } = useFilterField({\n filterConfigs,\n filter: value,\n })\n\n const fieldOptions = filterConfigs.map((config) => ({\n label: config.label,\n value: config.field,\n disabled: config.disabled,\n }))\n\n const handleBlur = () => {\n if (filter) {\n onBlur?.(filter)\n }\n }\n\n // Track if this is a user-driven change (not initialization)\n const isInitialMount = React.useRef(true)\n const prevFilterRef = React.useRef(filter)\n\n React.useEffect(() => {\n // Skip the initial mount to avoid calling onChange during initialization\n if (isInitialMount.current) {\n isInitialMount.current = false\n prevFilterRef.current = filter\n return\n }\n\n // Only call onChange if the filter actually changed\n if (filter && filter !== prevFilterRef.current) {\n prevFilterRef.current = filter\n onChange?.(filter)\n }\n }, [filter, onChange])\n\n return (\n <div className={cx('grid grid-cols-3 gap-2', className)}>\n <Select\n options={fieldOptions}\n value={filter?.field}\n showSearch\n optionFilterProp=\"label\"\n onChange={handleFieldChange}\n size={size}\n />\n <div className=\"col-span-2 flex gap-2\">\n <Select\n options={operatorOptions}\n value={filter?.operator}\n onChange={handleOperatorChange}\n onBlur={handleBlur}\n size={size}\n popupMatchSelectWidth={false}\n />\n {valueInputConfig && (\n <ValueInput\n valueInputConfig={valueInputConfig}\n values={filter?.values}\n onChange={handleValuesChange}\n onBlur={handleBlur}\n size={size}\n />\n )}\n </div>\n </div>\n )\n}\n\ntype ValueInputProps = {\n valueInputConfig: ValueInputConfig\n values?: (string | number | undefined | null)[]\n onChange: (value: (string | number | undefined | null)[]) => void\n onBlur: () => void\n size: SizeType\n}\n\nconst ValueInput = ({\n valueInputConfig,\n values,\n onChange,\n onBlur,\n size,\n}: ValueInputProps) => {\n const handleChange = (value: string | number | null) => {\n if (value === null) {\n onChange([])\n } else {\n onChange([value])\n }\n }\n\n const handleNumberChange = (value: string | number | null, index: number) => {\n const newValues: (string | number | undefined | null)[] = [\n ...(values ?? []),\n ]\n newValues[index] = value\n onChange(newValues)\n }\n\n switch (valueInputConfig.type) {\n case 'select':\n return (\n <Select\n options={valueInputConfig.valueOptions}\n onChange={onChange}\n showSearch\n allowClear\n mode=\"multiple\"\n onBlur={onBlur}\n value={values}\n className=\"w-full truncate\"\n size={size}\n optionFilterProp=\"label\"\n />\n )\n case 'number':\n return (\n <div className=\"flex gap-2 grow\">\n {Array.from({ length: valueInputConfig.inputCount }).map(\n (_, index) => (\n <React.Fragment key={`number-input-${index}`}>\n {index !== 0 && <span className=\"my-auto\">and</span>}\n <InputNumber\n onChange={(value) => handleNumberChange(value, index)}\n onBlur={onBlur}\n value={values?.[index]}\n className=\"basis-1/2\"\n size={size}\n {...(valueInputConfig.numberOptions ?? {})}\n />\n </React.Fragment>\n )\n )}\n </div>\n )\n case 'text':\n return (\n <Input\n onBlur={onBlur}\n value={values?.[0] ?? undefined}\n onChange={(e) => handleChange(e.target.value)}\n className=\"w-full\"\n size={size}\n />\n )\n default:\n return null\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FilterInput.js","sources":["../../../../src/components/filterform/FilterInput.tsx"],"sourcesContent":["import * as React from 'react'\nimport { FilterConfig } from '.'\nimport { useFilterField, ValueInputConfig } from './useFilterField'\nimport { Input, InputNumber, Select, Typography } from 'antd'\nimport { FormFilter } from './types'\nimport { normalizeMultiValues, tooManyValuesMessage } from './filterHelpers'\nimport cx from 'classnames'\nimport { SizeType } from 'antd/es/config-provider/SizeContext'\n\ntype FilterInputProps = {\n value?: FormFilter\n filterConfigs: FilterConfig[]\n onChange?: (value: FormFilter) => void\n onBlur?: (value: FormFilter) => void\n className?: string\n size?: SizeType\n}\n\nexport const FilterInput = ({\n value,\n filterConfigs,\n onChange,\n onBlur,\n className,\n size = 'middle',\n}: FilterInputProps) => {\n const {\n filter,\n operatorOptions,\n valueInputConfig,\n handleFieldChange,\n handleOperatorChange,\n handleValuesChange,\n } = useFilterField({\n filterConfigs,\n filter: value,\n })\n\n const fieldOptions = filterConfigs.map((config) => ({\n label: config.label,\n value: config.field,\n disabled: config.disabled,\n }))\n\n // Mirror of the reducer's filter for callbacks that run after a render.\n const latestFilterRef = React.useRef(filter)\n latestFilterRef.current = filter\n\n // Deferred a tick, and read from the ref rather than the closure. A tags\n // `Select` commits unseparated search text as a chip inside its own blur\n // handling, so `onChange` and `onBlur` arrive in the same browser event and\n // React flushes the resulting reducer update only after both return. A\n // synchronous `onBlur` would hand the parent the filter from *before* that\n // last chip — and for a new rule the parent finalizes and unmounts this\n // input, silently dropping the value. After the flush the ref holds it.\n const handleBlur = () => {\n setTimeout(() => {\n const latest = latestFilterRef.current\n if (latest) onBlur?.(latest)\n }, 0)\n }\n\n // Track if this is a user-driven change (not initialization)\n const isInitialMount = React.useRef(true)\n const prevFilterRef = React.useRef(filter)\n\n React.useEffect(() => {\n // Skip the initial mount to avoid calling onChange during initialization\n // — unless initialization itself corrected the persisted filter (an\n // operator the field no longer offers, or a chip list that needed\n // normalizing). Then the parent must learn about it, or it would keep\n // and submit the stale filter until the user happened to touch the rule.\n if (isInitialMount.current) {\n isInitialMount.current = false\n prevFilterRef.current = filter\n if (value && filter && wasCorrectedOnInit(value, filter)) {\n onChange?.(filter)\n }\n return\n }\n\n // Only call onChange if the filter actually changed\n if (filter && filter !== prevFilterRef.current) {\n prevFilterRef.current = filter\n onChange?.(filter)\n }\n }, [filter, onChange])\n\n return (\n <div className={cx('grid grid-cols-3 gap-2', className)}>\n <Select\n options={fieldOptions}\n value={filter?.field}\n showSearch\n optionFilterProp=\"label\"\n onChange={handleFieldChange}\n size={size}\n />\n <div className=\"col-span-2 flex gap-2\">\n <Select\n options={operatorOptions}\n value={filter?.operator}\n onChange={handleOperatorChange}\n onBlur={handleBlur}\n size={size}\n popupMatchSelectWidth={false}\n />\n {valueInputConfig && (\n <ValueInput\n valueInputConfig={valueInputConfig}\n values={filter?.values}\n onChange={handleValuesChange}\n onBlur={handleBlur}\n size={size}\n />\n )}\n </div>\n </div>\n )\n}\n\nconst sameList = (a: readonly unknown[], b: readonly unknown[]) =>\n a.length === b.length && a.every((item, i) => item === b[i])\n\n// Whether initializing from a persisted filter changed anything the parent\n// holds — operator, values, or the validation result. `errors` counts: a\n// persisted rule can be unchanged yet newly invalid (a lowered `maxValues`),\n// or arrive with no `errors` at all (a plain `FilterForm` from storage), and\n// the form's validity is computed from the errors it holds, not from ours.\nconst wasCorrectedOnInit = (persisted: FormFilter, current: FormFilter) =>\n persisted.operator !== current.operator ||\n !sameList(persisted.values, current.values) ||\n persisted.errors === undefined ||\n !sameList(persisted.errors, current.errors ?? [])\n\ntype ValueInputProps = {\n valueInputConfig: ValueInputConfig\n values?: (string | number | undefined | null)[]\n onChange: (value: (string | number | undefined | null)[]) => void\n onBlur: () => void\n size: SizeType\n}\n\nconst ValueInput = ({\n valueInputConfig,\n values,\n onChange,\n onBlur,\n size,\n}: ValueInputProps) => {\n const handleChange = (value: string | number | null) => {\n if (value === null) {\n onChange([])\n } else {\n onChange([value])\n }\n }\n\n const handleNumberChange = (value: string | number | null, index: number) => {\n const newValues: (string | number | undefined | null)[] = [\n ...(values ?? []),\n ]\n newValues[index] = value\n onChange(newValues)\n }\n\n switch (valueInputConfig.type) {\n case 'select':\n return (\n <Select\n options={valueInputConfig.valueOptions}\n onChange={onChange}\n showSearch\n allowClear\n mode=\"multiple\"\n onBlur={onBlur}\n value={values}\n className=\"w-full truncate\"\n size={size}\n optionFilterProp=\"label\"\n />\n )\n case 'number':\n return (\n <div className=\"flex gap-2 grow\">\n {Array.from({ length: valueInputConfig.inputCount }).map(\n (_, index) => (\n <React.Fragment key={`number-input-${index}`}>\n {index !== 0 && <span className=\"my-auto\">and</span>}\n <InputNumber\n onChange={(value) => handleNumberChange(value, index)}\n onBlur={onBlur}\n value={values?.[index]}\n className=\"basis-1/2\"\n size={size}\n {...(valueInputConfig.numberOptions ?? {})}\n />\n </React.Fragment>\n )\n )}\n </div>\n )\n case 'text':\n if (valueInputConfig.multiValue) {\n return (\n <MultiValueTextInput\n values={values}\n maxValues={valueInputConfig.maxValues}\n onChange={onChange}\n onBlur={onBlur}\n size={size}\n />\n )\n }\n return (\n <Input\n onBlur={onBlur}\n value={values?.[0] ?? undefined}\n onChange={(e) => handleChange(e.target.value)}\n className=\"w-full\"\n size={size}\n />\n )\n default:\n return null\n }\n}\n\n// Commas, newlines (both flavours) and tabs: a column pasted from Excel or a\n// comma-separated list from an email both land as one chip per value.\nexport const MULTI_VALUE_TOKEN_SEPARATORS = [',', '\\n', '\\r', '\\t']\n\n/**\n * Chips input for the multi-value text operators (`isAnyOf` / `isNoneOf`).\n *\n * A tags Select rather than a text box split at query time: every token is\n * visible and individually removable before Apply, so a pasted value that\n * itself contains a comma (street addresses do) can be seen and fixed\n * instead of being silently shredded. The dropdown is kept closed — there\n * are no options to pick from; Enter or a separator commits a chip.\n */\nconst MultiValueTextInput = ({\n values,\n maxValues,\n onChange,\n onBlur,\n size,\n}: {\n values?: (string | number | undefined | null)[]\n maxValues?: number\n onChange: (value: (string | number | undefined | null)[]) => void\n onBlur: () => void\n size: SizeType\n}) => {\n // Rendered as stored: `useFilterField` normalizes values on the way into\n // state, so what the chips show is exactly what validation counts and\n // what `onSubmit` emits. (Numbers/nulls can't occur for a text filter;\n // the map is only for the shared `values` type.)\n const chips = (values ?? []).flatMap((value) =>\n value === null || value === undefined ? [] : [String(value)]\n )\n const over = maxValues !== undefined && chips.length > maxValues\n\n return (\n <div className=\"flex flex-col gap-1 w-full min-w-0\">\n <Select\n mode=\"tags\"\n tokenSeparators={MULTI_VALUE_TOKEN_SEPARATORS}\n value={chips}\n onChange={(next: string[]) => onChange(normalizeMultiValues(next))}\n onBlur={onBlur}\n open={false}\n suffixIcon={null}\n placeholder=\"Type or paste values, separated by commas\"\n className=\"w-full\"\n size={size}\n status={over ? 'error' : undefined}\n aria-label=\"Values\"\n />\n {maxValues !== undefined && (\n <Typography.Text\n type={over ? 'danger' : 'secondary'}\n className=\"text-xs\"\n role={over ? 'alert' : undefined}\n >\n {over\n ? `${tooManyValuesMessage(maxValues)} — remove ${\n chips.length - maxValues\n } to apply`\n : `${chips.length} / ${maxValues} values`}\n </Typography.Text>\n )}\n </div>\n )\n}\n"],"names":[],"mappings":"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"}