@pipe0/react 0.2.4 → 0.2.6

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 (39) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/components/defaults/adapters/context-select-input.mjs +161 -0
  3. package/dist/components/defaults/adapters/context-select-input.mjs.map +1 -1
  4. package/dist/components/defaults/adapters/field-select-input.mjs +33 -0
  5. package/dist/components/defaults/adapters/field-select-input.mjs.map +1 -0
  6. package/dist/components/defaults/adapters/index.d.mts.map +1 -1
  7. package/dist/components/defaults/adapters/index.mjs +4 -0
  8. package/dist/components/defaults/adapters/index.mjs.map +1 -1
  9. package/dist/components/defaults/adapters/pipes-run-if-input.mjs +53 -5
  10. package/dist/components/defaults/adapters/pipes-run-if-input.mjs.map +1 -1
  11. package/dist/components/defaults/adapters/tagged-ordered-multi-create-input.mjs.map +1 -1
  12. package/dist/components/defaults/adapters/typed-fields-select-input.mjs +48 -0
  13. package/dist/components/defaults/adapters/typed-fields-select-input.mjs.map +1 -0
  14. package/dist/components/internal/combobox/suggest-combobox.mjs +35 -6
  15. package/dist/components/internal/combobox/suggest-combobox.mjs.map +1 -1
  16. package/dist/hooks/use-effect-catalog-table.d.mts.map +1 -1
  17. package/dist/hooks/use-effect-catalog-table.mjs +18 -11
  18. package/dist/hooks/use-effect-catalog-table.mjs.map +1 -1
  19. package/dist/hooks/use-form-core.d.mts.map +1 -1
  20. package/dist/hooks/use-form-core.mjs +48 -8
  21. package/dist/hooks/use-form-core.mjs.map +1 -1
  22. package/dist/hooks/use-pipe-catalog-table.d.mts +8 -8
  23. package/dist/hooks/use-pipe-catalog-table.d.mts.map +1 -1
  24. package/dist/hooks/use-pipe-catalog-table.mjs +20 -16
  25. package/dist/hooks/use-pipe-catalog-table.mjs.map +1 -1
  26. package/dist/hooks/use-search-catalog-table.d.mts +6 -6
  27. package/dist/hooks/use-search-catalog-table.d.mts.map +1 -1
  28. package/dist/hooks/use-search-catalog-table.mjs +20 -13
  29. package/dist/hooks/use-search-catalog-table.mjs.map +1 -1
  30. package/dist/hooks/use-searches-catalog-table.d.mts.map +1 -1
  31. package/dist/hooks/use-searches-catalog-table.mjs +20 -13
  32. package/dist/hooks/use-searches-catalog-table.mjs.map +1 -1
  33. package/dist/types/field-props.d.mts +37 -3
  34. package/dist/types/field-props.d.mts.map +1 -1
  35. package/dist/utils/build-section-handlers.mjs +21 -2
  36. package/dist/utils/build-section-handlers.mjs.map +1 -1
  37. package/dist/utils/catalog-helpers.mjs +10 -1
  38. package/dist/utils/catalog-helpers.mjs.map +1 -1
  39. package/package.json +2 -2
@@ -1,23 +1,20 @@
1
- import { fuzzyFilter } from "../utils/catalog-helpers.mjs";
1
+ import { catalogSearchFilter, catalogSearchSort } from "../utils/catalog-helpers.mjs";
2
2
  import { useDebounce } from "./use-debounce.mjs";
3
3
  import { useCallback, useMemo, useState } from "react";
4
- import { filterSearchEntries, getDefaultSearchOutputFields, getInitialSearchTableData, getLoweestSearchCreditAmount, getSearchTableDataAggregates, getStartingCostPerSearchProvider } from "@pipe0/base";
5
- import { createColumnHelper, getCoreRowModel, getFilteredRowModel, useReactTable } from "@tanstack/react-table";
4
+ import { filterSearchEntries, getDefaultSearchOutputFields, getInitialSearchTableData, getLoweestSearchCreditAmount, getSearchSearchTarget, getSearchTableDataAggregates, getStartingCostPerSearchProvider } from "@pipe0/base";
5
+ import { createColumnHelper, getCoreRowModel, getFilteredRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
6
6
 
7
7
  //#region src/hooks/use-search-catalog-table.ts
8
8
  const columnHelper = createColumnHelper();
9
9
  const columns = [
10
10
  columnHelper.accessor("searchId", {
11
11
  filterFn: "includesString",
12
- enableGlobalFilter: true
13
- }),
14
- columnHelper.accessor("description", {
15
- filterFn: "fuzzy",
16
- enableGlobalFilter: true
12
+ enableGlobalFilter: false
17
13
  }),
14
+ columnHelper.accessor("description", { enableGlobalFilter: false }),
18
15
  columnHelper.accessor("label", {
19
16
  filterFn: "includesString",
20
- enableGlobalFilter: true
17
+ enableGlobalFilter: false
21
18
  }),
22
19
  columnHelper.accessor((row) => getDefaultSearchOutputFields(row.searchId) || [], {
23
20
  id: "outputFields",
@@ -27,11 +24,17 @@ const columns = [
27
24
  columnHelper.accessor((row) => row.tags || [], {
28
25
  id: "tags",
29
26
  filterFn: "arrIncludes",
30
- enableGlobalFilter: true
27
+ enableGlobalFilter: false
31
28
  }),
32
29
  columnHelper.accessor((row) => row.provider, {
33
30
  id: "providers",
34
- enableGlobalFilter: true
31
+ enableGlobalFilter: false
32
+ }),
33
+ columnHelper.accessor((row) => getSearchSearchTarget(row), {
34
+ id: "search",
35
+ enableGlobalFilter: true,
36
+ enableSorting: true,
37
+ sortingFn: catalogSearchSort
35
38
  })
36
39
  ];
37
40
  function useSearchCatalogTable(config = {}) {
@@ -44,8 +47,8 @@ function useSearchCatalogTable(config = {}) {
44
47
  data: initialSearchTableData,
45
48
  getCoreRowModel: getCoreRowModel(),
46
49
  getFilteredRowModel: getFilteredRowModel(),
47
- globalFilterFn: fuzzyFilter,
48
- filterFns: { fuzzy: fuzzyFilter },
50
+ getSortedRowModel: getSortedRowModel(),
51
+ globalFilterFn: catalogSearchFilter,
49
52
  getColumnCanGlobalFilter: (column) => column.columnDef.enableGlobalFilter !== false,
50
53
  initialState: {
51
54
  columnFilters: initialColumnFilters,
@@ -57,6 +60,10 @@ function useSearchCatalogTable(config = {}) {
57
60
  const [globalFilterInput, setGlobalFilterInput, setGlobalFilterImmediately] = useDebounce((v) => {
58
61
  if (v === table.getState().globalFilter) return;
59
62
  table.setGlobalFilter(v);
63
+ table.setSorting(v ? [{
64
+ id: "search",
65
+ desc: true
66
+ }] : []);
60
67
  if (v) {
61
68
  setCategory(null);
62
69
  table.setColumnFilters([]);
@@ -1 +1 @@
1
- {"version":3,"file":"use-search-catalog-table.mjs","names":[],"sources":["../../src/hooks/use-search-catalog-table.ts"],"sourcesContent":["import {\n type CatalogFilter,\n filterSearchEntries,\n getDefaultSearchOutputFields,\n getInitialSearchTableData,\n getLoweestSearchCreditAmount,\n getSearchTableDataAggregates,\n getStartingCostPerSearchProvider,\n type SearchCatalogEntry,\n type SearchCatalogTableData,\n type SearchCategory,\n type SearchId,\n} from \"@pipe0/base\";\nimport {\n type ColumnFilter,\n createColumnHelper,\n getCoreRowModel,\n getFilteredRowModel,\n useReactTable,\n} from \"@tanstack/react-table\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport type { CostMode, SearchCardData } from \"../types/catalog-adapters.js\";\nimport { fuzzyFilter } from \"../utils/catalog-helpers.js\";\nimport { useDebounce } from \"./use-debounce.js\";\n\nexport type SearchOutputFieldEntries = Record<string, SearchId[]>;\n\nconst columnHelper = createColumnHelper<SearchCatalogTableData>();\n\nconst columns = [\n columnHelper.accessor(\"searchId\", {\n filterFn: \"includesString\",\n enableGlobalFilter: true,\n }),\n columnHelper.accessor(\"description\", {\n filterFn: \"fuzzy\" as any,\n enableGlobalFilter: true,\n }),\n columnHelper.accessor(\"label\", {\n filterFn: \"includesString\",\n enableGlobalFilter: true,\n }),\n columnHelper.accessor((row) => getDefaultSearchOutputFields(row.searchId) || [], {\n id: \"outputFields\",\n filterFn: \"arrIncludes\",\n enableGlobalFilter: false,\n }),\n columnHelper.accessor((row) => row.tags || [], {\n id: \"tags\",\n filterFn: \"arrIncludes\",\n enableGlobalFilter: true,\n }),\n columnHelper.accessor((row) => row.provider, {\n id: \"providers\",\n enableGlobalFilter: true,\n }),\n];\n\nexport function useSearchCatalogTable(\n config: {\n initialColumnFilters?: ColumnFilter[];\n /** Optional whitelist/blacklist of searches and providers. Memoize. */\n filter?: CatalogFilter;\n } = {},\n) {\n const [category, setCategory] = useState<SearchCategory | null>(null);\n const { initialColumnFilters = [] as ColumnFilter[], filter } = config;\n\n const initialSearchTableData = useMemo(\n () => filterSearchEntries(getInitialSearchTableData(category), filter),\n [category, filter],\n );\n\n // Baseline (config.filter applied, but no category / column / global filter).\n // Drives the stable category-button counts so the row doesn't jump.\n const baselineTableData = useMemo(\n () => filterSearchEntries(getInitialSearchTableData(null), filter),\n [filter],\n );\n\n const table = useReactTable({\n columns,\n data: initialSearchTableData,\n getCoreRowModel: getCoreRowModel(),\n getFilteredRowModel: getFilteredRowModel(),\n globalFilterFn: fuzzyFilter,\n filterFns: {\n fuzzy: fuzzyFilter,\n },\n getColumnCanGlobalFilter: (column) => column.columnDef.enableGlobalFilter !== false,\n initialState: {\n columnFilters: initialColumnFilters,\n pagination: {\n pageSize: 10,\n },\n },\n });\n\n const columnFilters = table.getState().columnFilters;\n\n const aggregates = useMemo(\n () => getSearchTableDataAggregates(initialSearchTableData, category),\n [category, initialSearchTableData],\n );\n\n const [globalFilterInput, setGlobalFilterInput, setGlobalFilterImmediately] = useDebounce((v) => {\n if (v === table.getState().globalFilter) return;\n table.setGlobalFilter(v);\n if (v) {\n setCategory(null);\n table.setColumnFilters([]);\n }\n });\n\n const addColumnFilter = useCallback(\n (id: \"inputFields\" | \"outputFields\" | \"tags\" | \"providers\", value: string) => {\n setGlobalFilterImmediately(\"\");\n table.setColumnFilters([{ id, value }]);\n },\n [setGlobalFilterImmediately, table],\n );\n\n const resetFilters = useCallback(() => {\n setGlobalFilterImmediately(\"\");\n setCategory(null);\n }, [setGlobalFilterImmediately]);\n\n const removeColumnFilter = useCallback(\n (id: \"inputFields\" | \"outputFields\" | \"tags\" | \"providers\") => {\n table.getColumn(id)?.setFilterValue(null);\n },\n [table],\n );\n\n const handleCategoryChange = useCallback(\n (category: SearchCategory | null) => {\n setCategory(category);\n table.setColumnFilters([]);\n setGlobalFilterImmediately(\"\");\n },\n [table, setGlobalFilterImmediately],\n );\n\n const getColumnFilterValue = useCallback(\n (id: \"inputFields\" | \"outputFields\" | \"tags\" | \"providers\") => {\n const res = columnFilters.find((f) => f.id === id)?.value;\n return res as string;\n },\n [columnFilters],\n );\n\n const rows = table.getRowModel().rows;\n const cards = useMemo<SearchCardData[]>(\n () =>\n rows.map((row) => {\n const entry = row.original;\n const latestEntry = (aggregates.searchEntriesByBaseSearch[entry.baseSearch]?.[0] ??\n entry) as SearchCatalogEntry & { searchId: SearchId };\n return {\n searchId: latestEntry.searchId,\n baseSearch: entry.baseSearch,\n label: entry.label,\n description: entry.description,\n provider: entry.provider,\n providers: [entry.provider],\n startingCostPerProvider: getStartingCostPerSearchProvider(latestEntry.searchId),\n startingCreditAmount: getLoweestSearchCreditAmount(latestEntry),\n costMode: (latestEntry.cost.mode ?? \"per_page\") as CostMode,\n defaultOutputFields: getDefaultSearchOutputFields(latestEntry.searchId),\n docPath: latestEntry.docPath,\n entry: entry as SearchCatalogTableData,\n latestEntry,\n };\n }),\n [rows, aggregates.searchEntriesByBaseSearch],\n );\n\n const cardsByCategory = useMemo<{ category: SearchCategory; cards: SearchCardData[] }[]>(() => {\n const groups = new Map<SearchCategory, SearchCardData[]>();\n for (const card of cards) {\n const cats = (card.entry.categories ?? []) as SearchCategory[];\n for (const cat of cats) {\n const arr = groups.get(cat);\n if (arr) arr.push(card);\n else groups.set(cat, [card]);\n }\n }\n return Array.from(groups, ([category, group]) => ({\n category,\n cards: group,\n }));\n }, [cards]);\n\n const categoryCounts = useMemo<Partial<Record<SearchCategory, number>>>(() => {\n const counts: Partial<Record<SearchCategory, number>> = {};\n for (const card of cards) {\n const cats = (card.entry.categories ?? []) as SearchCategory[];\n for (const cat of cats) {\n counts[cat] = (counts[cat] ?? 0) + 1;\n }\n }\n return counts;\n }, [cards]);\n\n // Stable counts based on the baseline (no category / column / global filter\n // applied).\n const baselineCardCount = baselineTableData.length;\n const baselineCategoryCounts = useMemo<Partial<Record<SearchCategory, number>>>(() => {\n const counts: Partial<Record<SearchCategory, number>> = {};\n for (const entry of baselineTableData) {\n const cats = (entry.categories ?? []) as SearchCategory[];\n for (const cat of cats) {\n counts[cat] = (counts[cat] ?? 0) + 1;\n }\n }\n return counts;\n }, [baselineTableData]);\n\n return {\n table,\n cards,\n cardsByCategory,\n categoryCounts,\n baselineCardCount,\n baselineCategoryCounts,\n\n category,\n setCategory: handleCategoryChange,\n globalFilterInput,\n setGlobalFilterInput,\n\n addColumnFilter,\n removeColumnFilter,\n resetFilters,\n getColumnFilterValue,\n\n sortedOutputFieldEntries: aggregates.sortedOutputFieldEntries,\n sortedTagEntries: aggregates.sortedTagEntries,\n sortedProviderEntries: aggregates.sortedProviderEntries,\n\n searchIdsByOutputField: aggregates.searchIdsByOutputField,\n searchIdsByProvider: aggregates.searchIdsByProvider,\n searchIdsByTag: aggregates.searchIdsByTag,\n };\n}\n\nexport type UseSearchCatalogTableReturn = ReturnType<typeof useSearchCatalogTable>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-search-catalog-table.mjs","names":[],"sources":["../../src/hooks/use-search-catalog-table.ts"],"sourcesContent":["import {\n type CatalogFilter,\n filterSearchEntries,\n getDefaultSearchOutputFields,\n getInitialSearchTableData,\n getLoweestSearchCreditAmount,\n getSearchSearchTarget,\n getSearchTableDataAggregates,\n getStartingCostPerSearchProvider,\n type SearchCatalogEntry,\n type SearchCatalogTableData,\n type SearchCategory,\n type SearchId,\n} from \"@pipe0/base\";\nimport {\n type ColumnFilter,\n createColumnHelper,\n getCoreRowModel,\n getFilteredRowModel,\n getSortedRowModel,\n useReactTable,\n} from \"@tanstack/react-table\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport type { CostMode, SearchCardData } from \"../types/catalog-adapters.js\";\nimport { catalogSearchFilter, catalogSearchSort } from \"../utils/catalog-helpers.js\";\nimport { useDebounce } from \"./use-debounce.js\";\n\nexport type SearchOutputFieldEntries = Record<string, SearchId[]>;\n\nconst columnHelper = createColumnHelper<SearchCatalogTableData>();\n\nconst columns = [\n columnHelper.accessor(\"searchId\", {\n filterFn: \"includesString\",\n enableGlobalFilter: false,\n }),\n columnHelper.accessor(\"description\", {\n enableGlobalFilter: false,\n }),\n columnHelper.accessor(\"label\", {\n filterFn: \"includesString\",\n enableGlobalFilter: false,\n }),\n columnHelper.accessor((row) => getDefaultSearchOutputFields(row.searchId) || [], {\n id: \"outputFields\",\n filterFn: \"arrIncludes\",\n enableGlobalFilter: false,\n }),\n columnHelper.accessor((row) => row.tags || [], {\n id: \"tags\",\n filterFn: \"arrIncludes\",\n enableGlobalFilter: false,\n }),\n columnHelper.accessor((row) => row.provider, {\n id: \"providers\",\n enableGlobalFilter: false,\n }),\n // Hidden relevance column — the ONLY globally-filterable one, so the global\n // filter scores each row exactly once and catalogSearchSort can read the\n // score back from this column's filter meta.\n columnHelper.accessor((row) => getSearchSearchTarget(row), {\n id: \"search\",\n enableGlobalFilter: true,\n enableSorting: true,\n sortingFn: catalogSearchSort,\n }),\n];\n\nexport function useSearchCatalogTable(\n config: {\n initialColumnFilters?: ColumnFilter[];\n /** Optional whitelist/blacklist of searches and providers. Memoize. */\n filter?: CatalogFilter;\n } = {},\n) {\n const [category, setCategory] = useState<SearchCategory | null>(null);\n const { initialColumnFilters = [] as ColumnFilter[], filter } = config;\n\n const initialSearchTableData = useMemo(\n () => filterSearchEntries(getInitialSearchTableData(category), filter),\n [category, filter],\n );\n\n // Baseline (config.filter applied, but no category / column / global filter).\n // Drives the stable category-button counts so the row doesn't jump.\n const baselineTableData = useMemo(\n () => filterSearchEntries(getInitialSearchTableData(null), filter),\n [filter],\n );\n\n const table = useReactTable({\n columns,\n data: initialSearchTableData,\n getCoreRowModel: getCoreRowModel(),\n getFilteredRowModel: getFilteredRowModel(),\n getSortedRowModel: getSortedRowModel(),\n globalFilterFn: catalogSearchFilter,\n getColumnCanGlobalFilter: (column) => column.columnDef.enableGlobalFilter !== false,\n initialState: {\n columnFilters: initialColumnFilters,\n pagination: {\n pageSize: 10,\n },\n },\n });\n\n const columnFilters = table.getState().columnFilters;\n\n const aggregates = useMemo(\n () => getSearchTableDataAggregates(initialSearchTableData, category),\n [category, initialSearchTableData],\n );\n\n const [globalFilterInput, setGlobalFilterInput, setGlobalFilterImmediately] = useDebounce((v) => {\n if (v === table.getState().globalFilter) return;\n table.setGlobalFilter(v);\n // Relevance order only while a query is active; empty query restores\n // catalog order.\n table.setSorting(v ? [{ id: \"search\", desc: true }] : []);\n if (v) {\n setCategory(null);\n table.setColumnFilters([]);\n }\n });\n\n const addColumnFilter = useCallback(\n (id: \"inputFields\" | \"outputFields\" | \"tags\" | \"providers\", value: string) => {\n setGlobalFilterImmediately(\"\");\n table.setColumnFilters([{ id, value }]);\n },\n [setGlobalFilterImmediately, table],\n );\n\n const resetFilters = useCallback(() => {\n setGlobalFilterImmediately(\"\");\n setCategory(null);\n }, [setGlobalFilterImmediately]);\n\n const removeColumnFilter = useCallback(\n (id: \"inputFields\" | \"outputFields\" | \"tags\" | \"providers\") => {\n table.getColumn(id)?.setFilterValue(null);\n },\n [table],\n );\n\n const handleCategoryChange = useCallback(\n (category: SearchCategory | null) => {\n setCategory(category);\n table.setColumnFilters([]);\n setGlobalFilterImmediately(\"\");\n },\n [table, setGlobalFilterImmediately],\n );\n\n const getColumnFilterValue = useCallback(\n (id: \"inputFields\" | \"outputFields\" | \"tags\" | \"providers\") => {\n const res = columnFilters.find((f) => f.id === id)?.value;\n return res as string;\n },\n [columnFilters],\n );\n\n const rows = table.getRowModel().rows;\n const cards = useMemo<SearchCardData[]>(\n () =>\n rows.map((row) => {\n const entry = row.original;\n const latestEntry = (aggregates.searchEntriesByBaseSearch[entry.baseSearch]?.[0] ??\n entry) as SearchCatalogEntry & { searchId: SearchId };\n return {\n searchId: latestEntry.searchId,\n baseSearch: entry.baseSearch,\n label: entry.label,\n description: entry.description,\n provider: entry.provider,\n providers: [entry.provider],\n startingCostPerProvider: getStartingCostPerSearchProvider(latestEntry.searchId),\n startingCreditAmount: getLoweestSearchCreditAmount(latestEntry),\n costMode: (latestEntry.cost.mode ?? \"per_page\") as CostMode,\n defaultOutputFields: getDefaultSearchOutputFields(latestEntry.searchId),\n docPath: latestEntry.docPath,\n entry: entry as SearchCatalogTableData,\n latestEntry,\n };\n }),\n [rows, aggregates.searchEntriesByBaseSearch],\n );\n\n const cardsByCategory = useMemo<{ category: SearchCategory; cards: SearchCardData[] }[]>(() => {\n const groups = new Map<SearchCategory, SearchCardData[]>();\n for (const card of cards) {\n const cats = (card.entry.categories ?? []) as SearchCategory[];\n for (const cat of cats) {\n const arr = groups.get(cat);\n if (arr) arr.push(card);\n else groups.set(cat, [card]);\n }\n }\n return Array.from(groups, ([category, group]) => ({\n category,\n cards: group,\n }));\n }, [cards]);\n\n const categoryCounts = useMemo<Partial<Record<SearchCategory, number>>>(() => {\n const counts: Partial<Record<SearchCategory, number>> = {};\n for (const card of cards) {\n const cats = (card.entry.categories ?? []) as SearchCategory[];\n for (const cat of cats) {\n counts[cat] = (counts[cat] ?? 0) + 1;\n }\n }\n return counts;\n }, [cards]);\n\n // Stable counts based on the baseline (no category / column / global filter\n // applied).\n const baselineCardCount = baselineTableData.length;\n const baselineCategoryCounts = useMemo<Partial<Record<SearchCategory, number>>>(() => {\n const counts: Partial<Record<SearchCategory, number>> = {};\n for (const entry of baselineTableData) {\n const cats = (entry.categories ?? []) as SearchCategory[];\n for (const cat of cats) {\n counts[cat] = (counts[cat] ?? 0) + 1;\n }\n }\n return counts;\n }, [baselineTableData]);\n\n return {\n table,\n cards,\n cardsByCategory,\n categoryCounts,\n baselineCardCount,\n baselineCategoryCounts,\n\n category,\n setCategory: handleCategoryChange,\n globalFilterInput,\n setGlobalFilterInput,\n\n addColumnFilter,\n removeColumnFilter,\n resetFilters,\n getColumnFilterValue,\n\n sortedOutputFieldEntries: aggregates.sortedOutputFieldEntries,\n sortedTagEntries: aggregates.sortedTagEntries,\n sortedProviderEntries: aggregates.sortedProviderEntries,\n\n searchIdsByOutputField: aggregates.searchIdsByOutputField,\n searchIdsByProvider: aggregates.searchIdsByProvider,\n searchIdsByTag: aggregates.searchIdsByTag,\n };\n}\n\nexport type UseSearchCatalogTableReturn = ReturnType<typeof useSearchCatalogTable>;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-searches-catalog-table.d.mts","names":[],"sources":["../../src/hooks/use-searches-catalog-table.ts"],"mappings":";;;;;;;KAyBY,0BAAA,GAA6B,MAAA,SAAe,UAAA;AAAA,iBAiCxC,uBAAA,CACd,MAAA;EAAU,oBAAA,GAAuB,YAAA;EAAgB,MAAA,GAAS,aAAA;AAAA;;;;cAkHd,cAAA;WAAuB,gBAAA;EAAA;;;;;0BA1CtD,cAAA;;yCAAc,OAAA,CAAA,cAAA;+EApBiC,KAAA;;;;;;;;;;;KAmIlD,6BAAA,GAAgC,UAAA,QAAkB,uBAAA"}
1
+ {"version":3,"file":"use-searches-catalog-table.d.mts","names":[],"sources":["../../src/hooks/use-searches-catalog-table.ts"],"mappings":";;;;;;;KA2BY,0BAAA,GAA6B,MAAA,SAAe,UAAA;AAAA,iBAyCxC,uBAAA,CACd,MAAA;EAAU,oBAAA,GAAuB,YAAA;EAAgB,MAAA,GAAS,aAAA;AAAA;;;;cAmHd,cAAA;WAAuB,gBAAA;EAAA;;;;;0BA1CtD,cAAA;;yCAAc,OAAA,CAAA,cAAA;+EApBiC,KAAA;;;;;;;;;;;KAmIlD,6BAAA,GAAgC,UAAA,QAAkB,uBAAA"}
@@ -1,23 +1,20 @@
1
- import { fuzzyFilter } from "../utils/catalog-helpers.mjs";
1
+ import { catalogSearchFilter, catalogSearchSort } from "../utils/catalog-helpers.mjs";
2
2
  import { useDebounce } from "./use-debounce.mjs";
3
3
  import { useCallback, useMemo, useState } from "react";
4
- import { filterSearchesEntries, getDefaultSearchesOutputFields, getInitialSearchesTableData, getLoweestSearchesCreditAmount, getSearchesTableDataAggregates, getStartingCostPerSearchesProvider } from "@pipe0/base";
5
- import { createColumnHelper, getCoreRowModel, getFilteredRowModel, useReactTable } from "@tanstack/react-table";
4
+ import { filterSearchesEntries, getDefaultSearchesOutputFields, getInitialSearchesTableData, getLoweestSearchesCreditAmount, getSearchesSearchTarget, getSearchesTableDataAggregates, getStartingCostPerSearchesProvider } from "@pipe0/base";
5
+ import { createColumnHelper, getCoreRowModel, getFilteredRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
6
6
 
7
7
  //#region src/hooks/use-searches-catalog-table.ts
8
8
  const columnHelper = createColumnHelper();
9
9
  const columns = [
10
10
  columnHelper.accessor("searchId", {
11
11
  filterFn: "includesString",
12
- enableGlobalFilter: true
13
- }),
14
- columnHelper.accessor("description", {
15
- filterFn: "fuzzy",
16
- enableGlobalFilter: true
12
+ enableGlobalFilter: false
17
13
  }),
14
+ columnHelper.accessor("description", { enableGlobalFilter: false }),
18
15
  columnHelper.accessor("label", {
19
16
  filterFn: "includesString",
20
- enableGlobalFilter: true
17
+ enableGlobalFilter: false
21
18
  }),
22
19
  columnHelper.accessor((row) => getDefaultSearchesOutputFields(row.searchId) || [], {
23
20
  id: "outputFields",
@@ -27,11 +24,17 @@ const columns = [
27
24
  columnHelper.accessor((row) => row.tags || [], {
28
25
  id: "tags",
29
26
  filterFn: "arrIncludes",
30
- enableGlobalFilter: true
27
+ enableGlobalFilter: false
31
28
  }),
32
29
  columnHelper.accessor((row) => row.provider, {
33
30
  id: "providers",
34
- enableGlobalFilter: true
31
+ enableGlobalFilter: false
32
+ }),
33
+ columnHelper.accessor((row) => getSearchesSearchTarget(row), {
34
+ id: "search",
35
+ enableGlobalFilter: true,
36
+ enableSorting: true,
37
+ sortingFn: catalogSearchSort
35
38
  })
36
39
  ];
37
40
  function useSearchesCatalogTable(config = {}) {
@@ -44,8 +47,8 @@ function useSearchesCatalogTable(config = {}) {
44
47
  data: initialSearchTableData,
45
48
  getCoreRowModel: getCoreRowModel(),
46
49
  getFilteredRowModel: getFilteredRowModel(),
47
- globalFilterFn: fuzzyFilter,
48
- filterFns: { fuzzy: fuzzyFilter },
50
+ getSortedRowModel: getSortedRowModel(),
51
+ globalFilterFn: catalogSearchFilter,
49
52
  getColumnCanGlobalFilter: (column) => column.columnDef.enableGlobalFilter !== false,
50
53
  initialState: {
51
54
  columnFilters: initialColumnFilters,
@@ -57,6 +60,10 @@ function useSearchesCatalogTable(config = {}) {
57
60
  const [globalFilterInput, setGlobalFilterInput, setGlobalFilterImmediately] = useDebounce((v) => {
58
61
  if (v === table.getState().globalFilter) return;
59
62
  table.setGlobalFilter(v);
63
+ table.setSorting(v ? [{
64
+ id: "search",
65
+ desc: true
66
+ }] : []);
60
67
  if (v) {
61
68
  setCategory(null);
62
69
  table.setColumnFilters([]);
@@ -1 +1 @@
1
- {"version":3,"file":"use-searches-catalog-table.mjs","names":[],"sources":["../../src/hooks/use-searches-catalog-table.ts"],"sourcesContent":["import {\n type CatalogFilter,\n filterSearchesEntries,\n getDefaultSearchesOutputFields,\n getInitialSearchesTableData,\n getLoweestSearchesCreditAmount,\n getSearchesTableDataAggregates,\n getStartingCostPerSearchesProvider,\n type SearchCategory,\n type SearchesCatalogEntry,\n type SearchesCatalogTableData,\n type SearchesId,\n} from \"@pipe0/base\";\nimport {\n type ColumnFilter,\n createColumnHelper,\n getCoreRowModel,\n getFilteredRowModel,\n useReactTable,\n} from \"@tanstack/react-table\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport type { CostMode, SearchesCardData } from \"../types/catalog-adapters.js\";\nimport { fuzzyFilter } from \"../utils/catalog-helpers.js\";\nimport { useDebounce } from \"./use-debounce.js\";\n\nexport type SearchesOutputFieldEntries = Record<string, SearchesId[]>;\n\nconst columnHelper = createColumnHelper<SearchesCatalogTableData>();\n\nconst columns = [\n columnHelper.accessor(\"searchId\", {\n filterFn: \"includesString\",\n enableGlobalFilter: true,\n }),\n columnHelper.accessor(\"description\", {\n filterFn: \"fuzzy\" as any,\n enableGlobalFilter: true,\n }),\n columnHelper.accessor(\"label\", {\n filterFn: \"includesString\",\n enableGlobalFilter: true,\n }),\n columnHelper.accessor((row) => getDefaultSearchesOutputFields(row.searchId) || [], {\n id: \"outputFields\",\n filterFn: \"arrIncludes\",\n enableGlobalFilter: false,\n }),\n columnHelper.accessor((row) => row.tags || [], {\n id: \"tags\",\n filterFn: \"arrIncludes\",\n enableGlobalFilter: true,\n }),\n columnHelper.accessor((row) => row.provider, {\n id: \"providers\",\n enableGlobalFilter: true,\n }),\n];\n\nexport function useSearchesCatalogTable(\n config: { initialColumnFilters?: ColumnFilter[]; filter?: CatalogFilter } = {},\n) {\n const [category, setCategory] = useState<SearchCategory | null>(null);\n const { initialColumnFilters = [] as ColumnFilter[], filter } = config;\n\n const initialSearchTableData = useMemo(\n () => filterSearchesEntries(getInitialSearchesTableData(category), filter),\n [category, filter],\n );\n\n // Baseline (config.filter applied, but no category / column / global filter).\n // Drives the stable category-button counts so the row doesn't jump.\n const baselineTableData = useMemo(\n () => filterSearchesEntries(getInitialSearchesTableData(null), filter),\n [filter],\n );\n\n const table = useReactTable({\n columns,\n data: initialSearchTableData,\n getCoreRowModel: getCoreRowModel(),\n getFilteredRowModel: getFilteredRowModel(),\n globalFilterFn: fuzzyFilter,\n filterFns: {\n fuzzy: fuzzyFilter,\n },\n getColumnCanGlobalFilter: (column) => column.columnDef.enableGlobalFilter !== false,\n initialState: {\n columnFilters: initialColumnFilters,\n pagination: {\n pageSize: 10,\n },\n },\n });\n\n const columnFilters = table.getState().columnFilters;\n\n const aggregates = useMemo(\n () => getSearchesTableDataAggregates(initialSearchTableData, category),\n [category, initialSearchTableData],\n );\n\n const [globalFilterInput, setGlobalFilterInput, setGlobalFilterImmediately] = useDebounce((v) => {\n if (v === table.getState().globalFilter) return;\n table.setGlobalFilter(v);\n if (v) {\n setCategory(null);\n table.setColumnFilters([]);\n }\n });\n\n const addColumnFilter = useCallback(\n (id: \"inputFields\" | \"outputFields\" | \"tags\" | \"providers\", value: string) => {\n setGlobalFilterImmediately(\"\");\n table.setColumnFilters([{ id, value }]);\n },\n [setGlobalFilterImmediately, table],\n );\n\n const resetFilters = useCallback(() => {\n setGlobalFilterImmediately(\"\");\n setCategory(null);\n }, [setGlobalFilterImmediately]);\n\n const removeColumnFilter = useCallback(\n (id: \"inputFields\" | \"outputFields\" | \"tags\" | \"providers\") => {\n table.getColumn(id)?.setFilterValue(null);\n },\n [table],\n );\n\n const handleCategoryChange = useCallback(\n (category: SearchCategory | null) => {\n setCategory(category);\n table.setColumnFilters([]);\n setGlobalFilterImmediately(\"\");\n },\n [table, setGlobalFilterImmediately],\n );\n\n const getColumnFilterValue = useCallback(\n (id: \"inputFields\" | \"outputFields\" | \"tags\" | \"providers\") => {\n const res = columnFilters.find((f) => f.id === id)?.value;\n return res as string;\n },\n [columnFilters],\n );\n\n const rows = table.getRowModel().rows;\n const cards = useMemo<SearchesCardData[]>(\n () =>\n rows.map((row) => {\n const entry = row.original;\n const latestEntry = (aggregates.searchEntriesByBaseSearch[entry.baseSearch]?.[0] ??\n entry) as SearchesCatalogEntry & { searchesId: SearchesId };\n return {\n searchesId: latestEntry.searchesId,\n baseSearches: entry.baseSearch,\n label: entry.label,\n description: entry.description,\n provider: entry.provider,\n providers: [entry.provider],\n startingCostPerProvider: getStartingCostPerSearchesProvider(latestEntry.searchesId),\n startingCreditAmount: getLoweestSearchesCreditAmount(latestEntry),\n costMode: latestEntry.cost.mode as CostMode,\n defaultOutputFields: getDefaultSearchesOutputFields(latestEntry.searchesId),\n docPath: latestEntry.docPath,\n entry: entry as SearchesCatalogTableData,\n latestEntry,\n };\n }),\n [rows, aggregates.searchEntriesByBaseSearch],\n );\n\n const cardsByCategory = useMemo<{ category: SearchCategory; cards: SearchesCardData[] }[]>(() => {\n const groups = new Map<SearchCategory, SearchesCardData[]>();\n for (const card of cards) {\n const cats = (card.entry.categories ?? []) as SearchCategory[];\n for (const cat of cats) {\n const arr = groups.get(cat);\n if (arr) arr.push(card);\n else groups.set(cat, [card]);\n }\n }\n return Array.from(groups, ([category, group]) => ({\n category,\n cards: group,\n }));\n }, [cards]);\n\n const categoryCounts = useMemo<Partial<Record<SearchCategory, number>>>(() => {\n const counts: Partial<Record<SearchCategory, number>> = {};\n for (const card of cards) {\n const cats = (card.entry.categories ?? []) as SearchCategory[];\n for (const cat of cats) {\n counts[cat] = (counts[cat] ?? 0) + 1;\n }\n }\n return counts;\n }, [cards]);\n\n // Stable counts based on the baseline (no category / column / global filter\n // applied).\n const baselineCardCount = baselineTableData.length;\n const baselineCategoryCounts = useMemo<Partial<Record<SearchCategory, number>>>(() => {\n const counts: Partial<Record<SearchCategory, number>> = {};\n for (const entry of baselineTableData) {\n const cats = (entry.categories ?? []) as SearchCategory[];\n for (const cat of cats) {\n counts[cat] = (counts[cat] ?? 0) + 1;\n }\n }\n return counts;\n }, [baselineTableData]);\n\n return {\n table,\n cards,\n cardsByCategory,\n categoryCounts,\n baselineCardCount,\n baselineCategoryCounts,\n\n category,\n setCategory: handleCategoryChange,\n globalFilterInput,\n setGlobalFilterInput,\n\n addColumnFilter,\n removeColumnFilter,\n resetFilters,\n getColumnFilterValue,\n\n sortedOutputFieldEntries: aggregates.sortedOutputFieldEntries,\n sortedTagEntries: aggregates.sortedTagEntries,\n sortedProviderEntries: aggregates.sortedProviderEntries,\n\n searchIdsByOutputField: aggregates.searchIdsByOutputField,\n searchIdsByProvider: aggregates.searchIdsByProvider,\n searchIdsByTag: aggregates.searchIdsByTag,\n };\n}\n\nexport type UseSearchesCatalogTableReturn = ReturnType<typeof useSearchesCatalogTable>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-searches-catalog-table.mjs","names":[],"sources":["../../src/hooks/use-searches-catalog-table.ts"],"sourcesContent":["import {\n type CatalogFilter,\n filterSearchesEntries,\n getDefaultSearchesOutputFields,\n getInitialSearchesTableData,\n getLoweestSearchesCreditAmount,\n getSearchesSearchTarget,\n getSearchesTableDataAggregates,\n getStartingCostPerSearchesProvider,\n type SearchCategory,\n type SearchesCatalogEntry,\n type SearchesCatalogTableData,\n type SearchesId,\n} from \"@pipe0/base\";\nimport {\n type ColumnFilter,\n createColumnHelper,\n getCoreRowModel,\n getFilteredRowModel,\n getSortedRowModel,\n useReactTable,\n} from \"@tanstack/react-table\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport type { CostMode, SearchesCardData } from \"../types/catalog-adapters.js\";\nimport { catalogSearchFilter, catalogSearchSort } from \"../utils/catalog-helpers.js\";\nimport { useDebounce } from \"./use-debounce.js\";\n\nexport type SearchesOutputFieldEntries = Record<string, SearchesId[]>;\n\nconst columnHelper = createColumnHelper<SearchesCatalogTableData>();\n\nconst columns = [\n columnHelper.accessor(\"searchId\", {\n filterFn: \"includesString\",\n enableGlobalFilter: false,\n }),\n columnHelper.accessor(\"description\", {\n enableGlobalFilter: false,\n }),\n columnHelper.accessor(\"label\", {\n filterFn: \"includesString\",\n enableGlobalFilter: false,\n }),\n columnHelper.accessor((row) => getDefaultSearchesOutputFields(row.searchId) || [], {\n id: \"outputFields\",\n filterFn: \"arrIncludes\",\n enableGlobalFilter: false,\n }),\n columnHelper.accessor((row) => row.tags || [], {\n id: \"tags\",\n filterFn: \"arrIncludes\",\n enableGlobalFilter: false,\n }),\n columnHelper.accessor((row) => row.provider, {\n id: \"providers\",\n enableGlobalFilter: false,\n }),\n // Hidden relevance column — the ONLY globally-filterable one, so the global\n // filter scores each row exactly once and catalogSearchSort can read the\n // score back from this column's filter meta.\n columnHelper.accessor((row) => getSearchesSearchTarget(row), {\n id: \"search\",\n enableGlobalFilter: true,\n enableSorting: true,\n sortingFn: catalogSearchSort,\n }),\n];\n\nexport function useSearchesCatalogTable(\n config: { initialColumnFilters?: ColumnFilter[]; filter?: CatalogFilter } = {},\n) {\n const [category, setCategory] = useState<SearchCategory | null>(null);\n const { initialColumnFilters = [] as ColumnFilter[], filter } = config;\n\n const initialSearchTableData = useMemo(\n () => filterSearchesEntries(getInitialSearchesTableData(category), filter),\n [category, filter],\n );\n\n // Baseline (config.filter applied, but no category / column / global filter).\n // Drives the stable category-button counts so the row doesn't jump.\n const baselineTableData = useMemo(\n () => filterSearchesEntries(getInitialSearchesTableData(null), filter),\n [filter],\n );\n\n const table = useReactTable({\n columns,\n data: initialSearchTableData,\n getCoreRowModel: getCoreRowModel(),\n getFilteredRowModel: getFilteredRowModel(),\n getSortedRowModel: getSortedRowModel(),\n globalFilterFn: catalogSearchFilter,\n getColumnCanGlobalFilter: (column) => column.columnDef.enableGlobalFilter !== false,\n initialState: {\n columnFilters: initialColumnFilters,\n pagination: {\n pageSize: 10,\n },\n },\n });\n\n const columnFilters = table.getState().columnFilters;\n\n const aggregates = useMemo(\n () => getSearchesTableDataAggregates(initialSearchTableData, category),\n [category, initialSearchTableData],\n );\n\n const [globalFilterInput, setGlobalFilterInput, setGlobalFilterImmediately] = useDebounce((v) => {\n if (v === table.getState().globalFilter) return;\n table.setGlobalFilter(v);\n // Relevance order only while a query is active; empty query restores\n // catalog order.\n table.setSorting(v ? [{ id: \"search\", desc: true }] : []);\n if (v) {\n setCategory(null);\n table.setColumnFilters([]);\n }\n });\n\n const addColumnFilter = useCallback(\n (id: \"inputFields\" | \"outputFields\" | \"tags\" | \"providers\", value: string) => {\n setGlobalFilterImmediately(\"\");\n table.setColumnFilters([{ id, value }]);\n },\n [setGlobalFilterImmediately, table],\n );\n\n const resetFilters = useCallback(() => {\n setGlobalFilterImmediately(\"\");\n setCategory(null);\n }, [setGlobalFilterImmediately]);\n\n const removeColumnFilter = useCallback(\n (id: \"inputFields\" | \"outputFields\" | \"tags\" | \"providers\") => {\n table.getColumn(id)?.setFilterValue(null);\n },\n [table],\n );\n\n const handleCategoryChange = useCallback(\n (category: SearchCategory | null) => {\n setCategory(category);\n table.setColumnFilters([]);\n setGlobalFilterImmediately(\"\");\n },\n [table, setGlobalFilterImmediately],\n );\n\n const getColumnFilterValue = useCallback(\n (id: \"inputFields\" | \"outputFields\" | \"tags\" | \"providers\") => {\n const res = columnFilters.find((f) => f.id === id)?.value;\n return res as string;\n },\n [columnFilters],\n );\n\n const rows = table.getRowModel().rows;\n const cards = useMemo<SearchesCardData[]>(\n () =>\n rows.map((row) => {\n const entry = row.original;\n const latestEntry = (aggregates.searchEntriesByBaseSearch[entry.baseSearch]?.[0] ??\n entry) as SearchesCatalogEntry & { searchesId: SearchesId };\n return {\n searchesId: latestEntry.searchesId,\n baseSearches: entry.baseSearch,\n label: entry.label,\n description: entry.description,\n provider: entry.provider,\n providers: [entry.provider],\n startingCostPerProvider: getStartingCostPerSearchesProvider(latestEntry.searchesId),\n startingCreditAmount: getLoweestSearchesCreditAmount(latestEntry),\n costMode: latestEntry.cost.mode as CostMode,\n defaultOutputFields: getDefaultSearchesOutputFields(latestEntry.searchesId),\n docPath: latestEntry.docPath,\n entry: entry as SearchesCatalogTableData,\n latestEntry,\n };\n }),\n [rows, aggregates.searchEntriesByBaseSearch],\n );\n\n const cardsByCategory = useMemo<{ category: SearchCategory; cards: SearchesCardData[] }[]>(() => {\n const groups = new Map<SearchCategory, SearchesCardData[]>();\n for (const card of cards) {\n const cats = (card.entry.categories ?? []) as SearchCategory[];\n for (const cat of cats) {\n const arr = groups.get(cat);\n if (arr) arr.push(card);\n else groups.set(cat, [card]);\n }\n }\n return Array.from(groups, ([category, group]) => ({\n category,\n cards: group,\n }));\n }, [cards]);\n\n const categoryCounts = useMemo<Partial<Record<SearchCategory, number>>>(() => {\n const counts: Partial<Record<SearchCategory, number>> = {};\n for (const card of cards) {\n const cats = (card.entry.categories ?? []) as SearchCategory[];\n for (const cat of cats) {\n counts[cat] = (counts[cat] ?? 0) + 1;\n }\n }\n return counts;\n }, [cards]);\n\n // Stable counts based on the baseline (no category / column / global filter\n // applied).\n const baselineCardCount = baselineTableData.length;\n const baselineCategoryCounts = useMemo<Partial<Record<SearchCategory, number>>>(() => {\n const counts: Partial<Record<SearchCategory, number>> = {};\n for (const entry of baselineTableData) {\n const cats = (entry.categories ?? []) as SearchCategory[];\n for (const cat of cats) {\n counts[cat] = (counts[cat] ?? 0) + 1;\n }\n }\n return counts;\n }, [baselineTableData]);\n\n return {\n table,\n cards,\n cardsByCategory,\n categoryCounts,\n baselineCardCount,\n baselineCategoryCounts,\n\n category,\n setCategory: handleCategoryChange,\n globalFilterInput,\n setGlobalFilterInput,\n\n addColumnFilter,\n removeColumnFilter,\n resetFilters,\n getColumnFilterValue,\n\n sortedOutputFieldEntries: aggregates.sortedOutputFieldEntries,\n sortedTagEntries: aggregates.sortedTagEntries,\n sortedProviderEntries: aggregates.sortedProviderEntries,\n\n searchIdsByOutputField: aggregates.searchIdsByOutputField,\n searchIdsByProvider: aggregates.searchIdsByProvider,\n searchIdsByTag: aggregates.searchIdsByTag,\n };\n}\n\nexport type UseSearchesCatalogTableReturn = ReturnType<typeof useSearchesCatalogTable>;\n"],"mappings":"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"}
@@ -148,13 +148,25 @@ interface FieldExtras {
148
148
  options: Array<{
149
149
  value: string;
150
150
  label: string;
151
- widgets?: _$_pipe0_base0.WidgetsByKind;
151
+ widgets?: _$_pipe0_base0.WidgetsByKind; /** Opaque per-option payload (e.g. a bucket's contract) for compound adapters. */
152
+ data?: Record<string, string>;
152
153
  }>;
153
154
  selectedValue: string;
154
155
  onSelect: (v: string) => void; /** True while this field's options are being fetched. */
155
156
  pending: boolean; /** Suggestions sub-feature gate. The input itself remains active even when true. */
156
157
  suggestionsDisabled: boolean; /** Reason from the suggestions sub-feature `enabledIf`. */
157
158
  suggestionsDisabledReason?: string;
159
+ /**
160
+ * Per-keystroke server-side option search through the field-context
161
+ * channel. Present when the host wires a `getFieldContext` resolver —
162
+ * adapters upgrade to a searchable combobox when set.
163
+ */
164
+ loadOptions?: (query: string) => Promise<Array<{
165
+ value: string;
166
+ label: string;
167
+ widgets?: _$_pipe0_base0.WidgetsByKind;
168
+ data?: Record<string, string>;
169
+ }>>;
158
170
  };
159
171
  multi_select_input: {
160
172
  options: Array<{
@@ -303,14 +315,36 @@ interface FieldExtras {
303
315
  /**
304
316
  * Bare condition-block editor. `searchSecrets`/`searchConstants` feed the
305
317
  * value cell's `/` reference picker when the meta carries `inputFields`
306
- * (pipes-side conditions with liquid-templated values).
318
+ * (pipes-side conditions with liquid-templated values). When the meta
319
+ * carries an `optionsDef`, `meta.options` holds fetched `field_name`
320
+ * suggestions and the editor upgrades the field-name input to a suggest
321
+ * combobox (free typing preserved).
307
322
  */
308
323
  condition_block_input: {
309
324
  searchSecrets?: (query: string) => Promise<SecretSuggestion[]>;
310
- searchConstants?: (query: string) => Promise<ConstantSuggestion[]>;
325
+ searchConstants?: (query: string) => Promise<ConstantSuggestion[]>; /** True while `field_name` suggestions (`optionsDef`) are being fetched. */
326
+ pending?: boolean;
311
327
  };
312
328
  connector_input: {};
313
329
  fields_select_input: {};
330
+ typed_fields_select_input: {};
331
+ /**
332
+ * Single-column picker (`{ field_name }`). Options come from the CURRENT
333
+ * sheet's columns or — when the meta carries an `optionsDef` — from the
334
+ * field-context fetch (e.g. a sibling-selected sheet's columns). Free
335
+ * typing is always allowed.
336
+ */
337
+ field_select_input: {
338
+ options: Array<{
339
+ value: string;
340
+ label: string;
341
+ widgets?: _$_pipe0_base0.WidgetsByKind; /** Opaque per-option payload (e.g. the column's type/format). */
342
+ data?: Record<string, string>;
343
+ }>; /** True while suggestions are being fetched. */
344
+ pending: boolean; /** Sub-feature gate — the input itself stays editable. */
345
+ suggestionsDisabled: boolean;
346
+ suggestionsDisabledReason?: string;
347
+ };
314
348
  json_schema_input: {};
315
349
  cursor_pagination_metadata: {};
316
350
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"field-props.d.mts","names":[],"sources":["../../src/types/field-props.ts"],"mappings":"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"}
1
+ {"version":3,"file":"field-props.d.mts","names":[],"sources":["../../src/types/field-props.ts"],"mappings":"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"}
@@ -90,13 +90,15 @@ function buildExtras(meta, base, publicKey, loadingCtx) {
90
90
  };
91
91
  if (inputGuards.context_select_input(meta)) {
92
92
  const loadState = loadingCtx?.fieldLoadStates?.[meta.path];
93
+ const searchFieldContext = loadingCtx?.searchFieldContext;
93
94
  return {
94
95
  options: meta.options ?? [],
95
96
  selectedValue: base.value ?? "",
96
97
  onSelect: (v) => base.setValue(v),
97
98
  pending: loadState?.status === "loading",
98
99
  suggestionsDisabled: loadState?.suggestionsDisabled ?? false,
99
- suggestionsDisabledReason: loadState?.suggestionsDisabledReason
100
+ suggestionsDisabledReason: loadState?.suggestionsDisabledReason,
101
+ loadOptions: searchFieldContext ? async (query) => withMergedWidgets(await searchFieldContext(meta.path, query), meta.optionsDef?.widgets) : void 0
100
102
  };
101
103
  }
102
104
  if (inputGuards.tagged_text_input(meta)) {
@@ -327,10 +329,27 @@ function buildExtras(meta, base, publicKey, loadingCtx) {
327
329
  searchSecrets: loadingCtx?.searchSecrets,
328
330
  searchConstants: loadingCtx?.searchConstants
329
331
  };
330
- if (inputGuards.prompt_input(meta) || inputGuards.template_input(meta) || inputGuards.condition_block_input(meta)) return {
332
+ if (inputGuards.prompt_input(meta) || inputGuards.template_input(meta)) return {
331
333
  searchSecrets: loadingCtx?.searchSecrets,
332
334
  searchConstants: loadingCtx?.searchConstants
333
335
  };
336
+ if (inputGuards.condition_block_input(meta)) {
337
+ const loadState = loadingCtx?.fieldLoadStates?.[meta.path];
338
+ return {
339
+ searchSecrets: loadingCtx?.searchSecrets,
340
+ searchConstants: loadingCtx?.searchConstants,
341
+ pending: loadState?.status === "loading"
342
+ };
343
+ }
344
+ if (inputGuards.field_select_input(meta)) {
345
+ const loadState = loadingCtx?.fieldLoadStates?.[meta.path];
346
+ return {
347
+ options: meta.options ?? [],
348
+ pending: loadState?.status === "loading",
349
+ suggestionsDisabled: loadState?.suggestionsDisabled ?? false,
350
+ suggestionsDisabledReason: loadState?.suggestionsDisabledReason
351
+ };
352
+ }
334
353
  return {};
335
354
  }
336
355
  function isEmptyValue(value) {
@@ -1 +1 @@
1
- {"version":3,"file":"build-section-handlers.mjs","names":[],"sources":["../../src/utils/build-section-handlers.ts"],"sourcesContent":["import type { FormSection, GeneratedInputMeta, SecretSuggestion } from \"@pipe0/base\";\nimport { inputGuards } from \"@pipe0/base\";\nimport type { UseFormReturn } from \"react-hook-form\";\nimport type { FieldLoadState } from \"../hooks/use-form-core.js\";\nimport type {\n AnyFieldProps,\n ConstantSuggestion,\n GeneratedFieldProps,\n} from \"../types/field-props.js\";\nimport type { FormGroupHandle, FormSectionHandle } from \"../types/form-handle.js\";\n\nexport interface FieldLoadingContext {\n /** Per-field load states for dynamic context_select_input fields, keyed by path. */\n fieldLoadStates: Record<string, FieldLoadState>;\n /**\n * Curried per-keystroke secrets searcher. Bundles the form-level\n * `environment` / `scopes` / `teamId` so adapters only need to pass the\n * user's typed query. Returns `[]` when no `getSecrets` resolver is wired.\n */\n searchSecrets?: (query: string) => Promise<SecretSuggestion[]>;\n /**\n * Curried per-keystroke constants searcher. Mirrors `searchSecrets`.\n * Returns `[]` when no `getConstants` resolver is wired.\n */\n searchConstants?: (query: string) => Promise<ConstantSuggestion[]>;\n}\n\n/**\n * Builds a fully-typed `GeneratedFieldProps` from raw metadata + form state.\n *\n * The returned object includes:\n * - Base props (kind, meta, value, setValue, error, etc.)\n * - Kind-specific extras (inputProps, options, toggle, etc.)\n */\nexport function buildFieldProps<Meta extends GeneratedInputMeta>(\n meta: Meta,\n form: UseFormReturn<Record<string, unknown>>,\n publicKey: string,\n loadingCtx?: FieldLoadingContext,\n): GeneratedFieldProps<Meta[\"type\"]> {\n const path = meta.path;\n const fieldState = form.getFieldState(path as any);\n const value = form.getValues(path as any);\n const id = `p0-field-${path.replace(/\\./g, \"-\")}`;\n\n const setValue = (v: unknown) =>\n form.setValue(path as any, v, {\n shouldDirty: true,\n shouldTouch: true,\n shouldValidate: true,\n });\n\n // Match the submit-gated behavior used everywhere else (group errorCount,\n // `useFieldError`): don't surface the field's error until the user has\n // attempted a submit. Otherwise `setValue`-triggered validation would\n // flash errors the moment the form is interacted with.\n const hasSubmitted = form.formState.isSubmitted;\n\n const loadState = loadingCtx?.fieldLoadStates?.[path];\n\n const base = {\n kind: meta.type,\n meta,\n form,\n path,\n label: meta.label ?? \"\",\n description: meta.description,\n info: meta.info,\n error: hasSubmitted ? fieldState.error?.message : undefined,\n touched: fieldState.isTouched,\n dirty: fieldState.isDirty,\n id,\n value,\n setValue,\n reset: () => form.resetField(path as any),\n disabled: loadState?.disabled ?? false,\n disabledReason: loadState?.disabledReason,\n };\n\n const extras = buildExtras(meta, { path, id, value, setValue }, publicKey, loadingCtx);\n\n return { ...base, ...extras } as unknown as GeneratedFieldProps<Meta[\"type\"]>;\n}\n\n// Re-export under old name for backward compat\nexport { buildFieldProps as buildFieldHandle };\n\ntype OptionLike = {\n value: string;\n label: string;\n widgets?: Record<string, Record<string, unknown>>;\n};\n\nfunction withMergedWidgets<T extends OptionLike>(\n options: T[],\n staticWidgets: Record<string, Record<string, unknown>> | undefined,\n): T[] {\n if (!staticWidgets) return options;\n return options.map((o) => ({\n ...o,\n widgets: { ...staticWidgets, ...(o.widgets ?? {}) },\n }));\n}\n\nfunction buildExtras(\n meta: GeneratedInputMeta,\n base: {\n path: string;\n id: string;\n value: unknown;\n setValue: (v: unknown) => void;\n },\n publicKey: string,\n loadingCtx?: FieldLoadingContext,\n): Record<string, unknown> {\n if (\n inputGuards.text_input(meta) ||\n inputGuards.int_input(meta) ||\n inputGuards.number_input(meta)\n ) {\n const isNumber = inputGuards.int_input(meta) || inputGuards.number_input(meta);\n return {\n inputProps: {\n type: isNumber ? \"number\" : (meta as any).inputType || \"text\",\n name: base.path,\n id: base.id,\n value: base.value != null ? String(base.value) : \"\",\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => {\n const v = e.target.value;\n base.setValue(isNumber ? (v === \"\" ? null : Number(v)) : v);\n },\n placeholder: meta.placeholder,\n step: inputGuards.number_input(meta) ? \"0.001\" : undefined,\n },\n };\n }\n\n if (inputGuards.textarea_input(meta)) {\n return {\n textareaProps: {\n name: base.path,\n id: base.id,\n value: (base.value as string) ?? \"\",\n onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => base.setValue(e.target.value),\n placeholder: meta.placeholder,\n rows: meta.rows,\n },\n };\n }\n\n if (inputGuards.select_input(meta)) {\n return {\n options: meta.options ?? [],\n selectedValue: (base.value as string) ?? \"\",\n onSelect: (v: string) => base.setValue(v),\n };\n }\n\n if (inputGuards.context_select_input(meta)) {\n const loadState = loadingCtx?.fieldLoadStates?.[meta.path];\n return {\n options: meta.options ?? [],\n selectedValue: (base.value as string) ?? \"\",\n onSelect: (v: string) => base.setValue(v),\n pending: loadState?.status === \"loading\",\n suggestionsDisabled: loadState?.suggestionsDisabled ?? false,\n suggestionsDisabledReason: loadState?.suggestionsDisabledReason,\n };\n }\n\n if (inputGuards.tagged_text_input(meta)) {\n const loadState = loadingCtx?.fieldLoadStates?.[meta.path];\n return {\n options: meta.options ?? [],\n pending: loadState?.status === \"loading\",\n suggestionsDisabled: loadState?.suggestionsDisabled ?? false,\n suggestionsDisabledReason: loadState?.suggestionsDisabledReason,\n searchSecrets: loadingCtx?.searchSecrets,\n searchConstants: loadingCtx?.searchConstants,\n };\n }\n\n if (inputGuards.providers_input(meta)) {\n return {\n options: meta.options ?? [],\n };\n }\n\n if (inputGuards.multi_select_input(meta)) {\n const selected = (base.value as string[]) ?? [];\n return {\n options: meta.options ?? [],\n selected,\n onToggle: (v: string) =>\n base.setValue(selected.includes(v) ? selected.filter((s) => s !== v) : [...selected, v]),\n onClear: () => base.setValue([]),\n };\n }\n\n if (inputGuards.async_multi_select_input(meta)) {\n const selected = (base.value as string[]) ?? [];\n return {\n loadOptions: async (query: string) =>\n withMergedWidgets(\n await meta.optionsDef.options({ query, token: publicKey }),\n meta.optionsDef.widgets,\n ),\n selected,\n onToggle: (v: string) =>\n base.setValue(selected.includes(v) ? selected.filter((s) => s !== v) : [...selected, v]),\n onClear: () => base.setValue([]),\n };\n }\n\n if (inputGuards.boolean_input(meta) || inputGuards.nullable_boolean_input(meta)) {\n return {\n checked: base.value === true,\n isNull: base.value === null || base.value === undefined,\n toggle: () => base.setValue(base.value === true ? false : true),\n clear: () => base.setValue(null),\n };\n }\n\n if (\n inputGuards.include_exclude_input(meta) ||\n inputGuards.include_exclude_select_input(meta) ||\n inputGuards.async_include_exclude_select_input(meta)\n ) {\n const current = (base.value as {\n include: string[];\n exclude: string[];\n }) ?? { include: [], exclude: [] };\n const result: Record<string, unknown> = {\n include: {\n value: current.include,\n add: (v: string) => base.setValue({ ...current, include: [...current.include, v] }),\n remove: (v: string) =>\n base.setValue({\n ...current,\n include: current.include.filter((i) => i !== v),\n }),\n },\n exclude: {\n value: current.exclude,\n add: (v: string) => base.setValue({ ...current, exclude: [...current.exclude, v] }),\n remove: (v: string) =>\n base.setValue({\n ...current,\n exclude: current.exclude.filter((i) => i !== v),\n }),\n },\n };\n const m = meta as any;\n if (m.optionsDef?.options && typeof m.optionsDef.options === \"function\") {\n result.loadOptions = async (query: string) =>\n withMergedWidgets(\n await m.optionsDef.options({ query, token: publicKey }),\n m.optionsDef.widgets,\n );\n } else if (m.optionsDef?.options) {\n result.options = withMergedWidgets(m.optionsDef.options, m.optionsDef.widgets);\n }\n if (m.suggestionsDef?.options) {\n if (typeof m.suggestionsDef.options === \"function\") {\n result.loadOptions = async (query: string) =>\n withMergedWidgets(\n await m.suggestionsDef.options({ query, token: publicKey }),\n m.suggestionsDef.widgets,\n );\n } else {\n result.options = withMergedWidgets(m.suggestionsDef.options, m.suggestionsDef.widgets);\n }\n }\n return result;\n }\n\n if (inputGuards.range_input(meta)) {\n const current = (base.value as {\n from: number | null;\n to: number | null;\n }) ?? { from: null, to: null };\n return {\n from: {\n value: current.from,\n set: (v: number | null) => base.setValue({ ...current, from: v }),\n },\n to: {\n value: current.to,\n set: (v: number | null) => base.setValue({ ...current, to: v }),\n },\n };\n }\n\n if (inputGuards.date_range_input(meta)) {\n const current = (base.value as Record<string, string>) ?? {};\n return {\n from: {\n value: current.gte ?? current.gt ?? \"\",\n set: (v: string) => base.setValue({ ...current, gte: v }),\n },\n to: {\n value: current.lte ?? current.lt ?? \"\",\n set: (v: string) => base.setValue({ ...current, lte: v }),\n },\n };\n }\n\n if (inputGuards.exact_range_input(meta)) {\n const current = (base.value as Record<string, number | null>) ?? {};\n return {\n greaterThan: {\n operator: current.gt != null ? \"gt\" : \"gte\",\n value: current.gt ?? current.gte ?? null,\n setOperator: (op: string) => {\n const otherOp = op === \"gt\" ? \"gte\" : \"gt\";\n const val = current[otherOp] ?? current[op];\n const updated = { ...current };\n delete updated[otherOp];\n if (val != null) updated[op] = val;\n base.setValue(updated);\n },\n setValue: (v: number | null) => {\n const op = current.gt != null ? \"gt\" : \"gte\";\n const updated = { ...current };\n if (v != null) updated[op] = v;\n else delete updated[op];\n base.setValue(updated);\n },\n },\n lessThan: {\n operator: current.lt != null ? \"lt\" : \"lte\",\n value: current.lt ?? current.lte ?? null,\n setOperator: (op: string) => {\n const otherOp = op === \"lt\" ? \"lte\" : \"lt\";\n const val = current[otherOp] ?? current[op];\n const updated = { ...current };\n delete updated[otherOp];\n if (val != null) updated[op] = val;\n base.setValue(updated);\n },\n setValue: (v: number | null) => {\n const op = current.lt != null ? \"lt\" : \"lte\";\n const updated = { ...current };\n if (v != null) updated[op] = v;\n else delete updated[op];\n base.setValue(updated);\n },\n },\n };\n }\n\n if (inputGuards.min_max_int_input(meta)) {\n const current = (base.value as {\n min: number | null;\n max: number | null;\n }) ?? { min: null, max: null };\n return {\n from: {\n value: current.min,\n set: (v: number | null) => base.setValue({ ...current, min: v }),\n },\n to: {\n value: current.max,\n set: (v: number | null) => base.setValue({ ...current, max: v }),\n },\n };\n }\n\n if (inputGuards.multi_create_input(meta) || inputGuards.ordered_multi_create_input(meta)) {\n const items = (base.value as string[]) ?? [];\n const result: Record<string, unknown> = {\n items,\n add: (v: string) => base.setValue([...items, v]),\n remove: (v: string) => base.setValue(items.filter((i) => i !== v)),\n };\n if (inputGuards.ordered_multi_create_input(meta)) {\n result.reorder = (from: number, to: number) => {\n const next = [...items];\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved);\n base.setValue(next);\n };\n }\n const m = meta as any;\n if (m.suggestionsDef?.options) {\n if (typeof m.suggestionsDef.options === \"function\") {\n result.loadOptions = async (query: string) =>\n withMergedWidgets(\n await m.suggestionsDef.options({ query, token: publicKey }),\n m.suggestionsDef.widgets,\n );\n } else {\n result.options = withMergedWidgets(m.suggestionsDef.options, m.suggestionsDef.widgets);\n }\n }\n return result;\n }\n\n if (inputGuards.tagged_ordered_multi_create_input(meta)) {\n const items = (base.value as string[]) ?? [];\n const result: Record<string, unknown> = {\n items,\n setItems: (next: string[]) => base.setValue(next),\n inputFields: meta.inputFields ?? [],\n };\n const m = meta as any;\n if (m.suggestionsDef?.options) {\n if (typeof m.suggestionsDef.options === \"function\") {\n result.loadOptions = async (query: string) =>\n withMergedWidgets(\n await m.suggestionsDef.options({ query, token: publicKey }),\n m.suggestionsDef.widgets,\n );\n } else {\n result.options = withMergedWidgets(m.suggestionsDef.options, m.suggestionsDef.widgets);\n }\n }\n return result;\n }\n\n if (inputGuards.loose_object_input(meta)) {\n const value = (base.value as Record<string, string>) ?? {};\n return {\n value,\n setObject: (next: Record<string, string>) => base.setValue(next),\n searchSecrets: loadingCtx?.searchSecrets,\n searchConstants: loadingCtx?.searchConstants,\n };\n }\n\n if (\n inputGuards.prompt_input(meta) ||\n inputGuards.template_input(meta) ||\n inputGuards.condition_block_input(meta)\n ) {\n return {\n searchSecrets: loadingCtx?.searchSecrets,\n searchConstants: loadingCtx?.searchConstants,\n };\n }\n\n // Remaining types need no extras beyond base\n return {};\n}\n\nfunction isEmptyValue(value: unknown): boolean {\n if (value === null || typeof value === \"undefined\") return true;\n if (typeof value === \"string\") return value === \"\";\n if (Array.isArray(value)) return value.length === 0;\n if (typeof value === \"object\") {\n const keys = Object.keys(value);\n if (keys.length === 0) return true;\n return keys.every((k) => isEmptyValue((value as Record<string, unknown>)[k]));\n }\n return false;\n}\n\nexport function buildSectionHandles(\n formConfig: FormSection[],\n form: UseFormReturn<Record<string, unknown>>,\n publicKey: string,\n loadingCtx?: FieldLoadingContext,\n): FormSectionHandle[] {\n // In onSubmit validation mode, don't flag groups as invalid until the\n // user has actually attempted a submit. This matches RHF's own field-level\n // behavior where `formState.errors` is only populated after the first\n // submit (and updated reactively thereafter per `reValidateMode`).\n const hasSubmitted = form.formState.isSubmitted;\n\n return formConfig\n .map((section) => {\n const groups: FormGroupHandle[] = section.groups\n .map((group) => {\n // Drop a connector field whose mode is \"disabled\" (custom connections\n // unsupported) — there's nothing to configure, so we hide the whole\n // group/section rather than render a \"not supported\" placeholder.\n const fields = group.fields\n .filter(\n (meta) => !(inputGuards.connector_input(meta) && meta.connectorMode === \"disabled\"),\n )\n .map((meta) => buildFieldProps(meta, form, publicKey, loadingCtx)) as AnyFieldProps[];\n\n const groupPathError = form.getFieldState(group.groupPath as any).error;\n const errorCount = hasSubmitted\n ? fields.filter((f) => f.error != null).length + (groupPathError ? 1 : 0)\n : 0;\n const setCount = fields.filter((f) => !isEmptyValue(f.value)).length;\n const dirtyCount = fields.filter((f) => f.dirty).length;\n\n return {\n key: group.groupPath,\n label: group.label,\n description: group.description,\n iconKey: group.iconKey,\n defaultExpand: group.defaultExpand ?? false,\n fields,\n errorCount,\n setCount,\n dirtyCount,\n };\n })\n .filter((group) => group.fields.length > 0);\n\n return {\n key: section.metadata.path,\n label: section.metadata.label,\n description: section.metadata.description,\n groups,\n };\n })\n .filter((section) => section.groups.length > 0);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"build-section-handlers.mjs","names":[],"sources":["../../src/utils/build-section-handlers.ts"],"sourcesContent":["import type { FormSection, GeneratedInputMeta, SecretSuggestion, StoreOption } from \"@pipe0/base\";\nimport { inputGuards } from \"@pipe0/base\";\nimport type { UseFormReturn } from \"react-hook-form\";\nimport type { FieldLoadState } from \"../hooks/use-form-core.js\";\nimport type {\n AnyFieldProps,\n ConstantSuggestion,\n GeneratedFieldProps,\n} from \"../types/field-props.js\";\nimport type { FormGroupHandle, FormSectionHandle } from \"../types/form-handle.js\";\n\nexport interface FieldLoadingContext {\n /** Per-field load states for dynamic context_select_input fields, keyed by path. */\n fieldLoadStates: Record<string, FieldLoadState>;\n /**\n * Curried per-keystroke secrets searcher. Bundles the form-level\n * `environment` / `scopes` / `teamId` so adapters only need to pass the\n * user's typed query. Returns `[]` when no `getSecrets` resolver is wired.\n */\n searchSecrets?: (query: string) => Promise<SecretSuggestion[]>;\n /**\n * Curried per-keystroke constants searcher. Mirrors `searchSecrets`.\n * Returns `[]` when no `getConstants` resolver is wired.\n */\n searchConstants?: (query: string) => Promise<ConstantSuggestion[]>;\n /**\n * Curried per-keystroke field-context searcher: server-side option search\n * for ONE optionsDef-capable field (bundles the live payload). Returns the\n * options directly — never merged into the shared form store. Absent when\n * no `getFieldContext` resolver is wired.\n */\n searchFieldContext?: (fieldPath: string, query: string) => Promise<StoreOption[]>;\n}\n\n/**\n * Builds a fully-typed `GeneratedFieldProps` from raw metadata + form state.\n *\n * The returned object includes:\n * - Base props (kind, meta, value, setValue, error, etc.)\n * - Kind-specific extras (inputProps, options, toggle, etc.)\n */\nexport function buildFieldProps<Meta extends GeneratedInputMeta>(\n meta: Meta,\n form: UseFormReturn<Record<string, unknown>>,\n publicKey: string,\n loadingCtx?: FieldLoadingContext,\n): GeneratedFieldProps<Meta[\"type\"]> {\n const path = meta.path;\n const fieldState = form.getFieldState(path as any);\n const value = form.getValues(path as any);\n const id = `p0-field-${path.replace(/\\./g, \"-\")}`;\n\n const setValue = (v: unknown) =>\n form.setValue(path as any, v, {\n shouldDirty: true,\n shouldTouch: true,\n shouldValidate: true,\n });\n\n // Match the submit-gated behavior used everywhere else (group errorCount,\n // `useFieldError`): don't surface the field's error until the user has\n // attempted a submit. Otherwise `setValue`-triggered validation would\n // flash errors the moment the form is interacted with.\n const hasSubmitted = form.formState.isSubmitted;\n\n const loadState = loadingCtx?.fieldLoadStates?.[path];\n\n const base = {\n kind: meta.type,\n meta,\n form,\n path,\n label: meta.label ?? \"\",\n description: meta.description,\n info: meta.info,\n error: hasSubmitted ? fieldState.error?.message : undefined,\n touched: fieldState.isTouched,\n dirty: fieldState.isDirty,\n id,\n value,\n setValue,\n reset: () => form.resetField(path as any),\n disabled: loadState?.disabled ?? false,\n disabledReason: loadState?.disabledReason,\n };\n\n const extras = buildExtras(meta, { path, id, value, setValue }, publicKey, loadingCtx);\n\n return { ...base, ...extras } as unknown as GeneratedFieldProps<Meta[\"type\"]>;\n}\n\n// Re-export under old name for backward compat\nexport { buildFieldProps as buildFieldHandle };\n\ntype OptionLike = {\n value: string;\n label: string;\n widgets?: Record<string, Record<string, unknown>>;\n};\n\nfunction withMergedWidgets<T extends OptionLike>(\n options: T[],\n staticWidgets: Record<string, Record<string, unknown>> | undefined,\n): T[] {\n if (!staticWidgets) return options;\n return options.map((o) => ({\n ...o,\n widgets: { ...staticWidgets, ...(o.widgets ?? {}) },\n }));\n}\n\nfunction buildExtras(\n meta: GeneratedInputMeta,\n base: {\n path: string;\n id: string;\n value: unknown;\n setValue: (v: unknown) => void;\n },\n publicKey: string,\n loadingCtx?: FieldLoadingContext,\n): Record<string, unknown> {\n if (\n inputGuards.text_input(meta) ||\n inputGuards.int_input(meta) ||\n inputGuards.number_input(meta)\n ) {\n const isNumber = inputGuards.int_input(meta) || inputGuards.number_input(meta);\n return {\n inputProps: {\n type: isNumber ? \"number\" : (meta as any).inputType || \"text\",\n name: base.path,\n id: base.id,\n value: base.value != null ? String(base.value) : \"\",\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => {\n const v = e.target.value;\n base.setValue(isNumber ? (v === \"\" ? null : Number(v)) : v);\n },\n placeholder: meta.placeholder,\n step: inputGuards.number_input(meta) ? \"0.001\" : undefined,\n },\n };\n }\n\n if (inputGuards.textarea_input(meta)) {\n return {\n textareaProps: {\n name: base.path,\n id: base.id,\n value: (base.value as string) ?? \"\",\n onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => base.setValue(e.target.value),\n placeholder: meta.placeholder,\n rows: meta.rows,\n },\n };\n }\n\n if (inputGuards.select_input(meta)) {\n return {\n options: meta.options ?? [],\n selectedValue: (base.value as string) ?? \"\",\n onSelect: (v: string) => base.setValue(v),\n };\n }\n\n if (inputGuards.context_select_input(meta)) {\n const loadState = loadingCtx?.fieldLoadStates?.[meta.path];\n const searchFieldContext = loadingCtx?.searchFieldContext;\n return {\n options: meta.options ?? [],\n selectedValue: (base.value as string) ?? \"\",\n onSelect: (v: string) => base.setValue(v),\n pending: loadState?.status === \"loading\",\n suggestionsDisabled: loadState?.suggestionsDisabled ?? false,\n suggestionsDisabledReason: loadState?.suggestionsDisabledReason,\n // Per-keystroke server-side search through the field-context channel.\n // Static widgets merge exactly as `resolveField` does for store options.\n loadOptions: searchFieldContext\n ? async (query: string) =>\n withMergedWidgets(await searchFieldContext(meta.path, query), meta.optionsDef?.widgets)\n : undefined,\n };\n }\n\n if (inputGuards.tagged_text_input(meta)) {\n const loadState = loadingCtx?.fieldLoadStates?.[meta.path];\n return {\n options: meta.options ?? [],\n pending: loadState?.status === \"loading\",\n suggestionsDisabled: loadState?.suggestionsDisabled ?? false,\n suggestionsDisabledReason: loadState?.suggestionsDisabledReason,\n searchSecrets: loadingCtx?.searchSecrets,\n searchConstants: loadingCtx?.searchConstants,\n };\n }\n\n if (inputGuards.providers_input(meta)) {\n return {\n options: meta.options ?? [],\n };\n }\n\n if (inputGuards.multi_select_input(meta)) {\n const selected = (base.value as string[]) ?? [];\n return {\n options: meta.options ?? [],\n selected,\n onToggle: (v: string) =>\n base.setValue(selected.includes(v) ? selected.filter((s) => s !== v) : [...selected, v]),\n onClear: () => base.setValue([]),\n };\n }\n\n if (inputGuards.async_multi_select_input(meta)) {\n const selected = (base.value as string[]) ?? [];\n return {\n loadOptions: async (query: string) =>\n withMergedWidgets(\n await meta.optionsDef.options({ query, token: publicKey }),\n meta.optionsDef.widgets,\n ),\n selected,\n onToggle: (v: string) =>\n base.setValue(selected.includes(v) ? selected.filter((s) => s !== v) : [...selected, v]),\n onClear: () => base.setValue([]),\n };\n }\n\n if (inputGuards.boolean_input(meta) || inputGuards.nullable_boolean_input(meta)) {\n return {\n checked: base.value === true,\n isNull: base.value === null || base.value === undefined,\n toggle: () => base.setValue(base.value === true ? false : true),\n clear: () => base.setValue(null),\n };\n }\n\n if (\n inputGuards.include_exclude_input(meta) ||\n inputGuards.include_exclude_select_input(meta) ||\n inputGuards.async_include_exclude_select_input(meta)\n ) {\n const current = (base.value as {\n include: string[];\n exclude: string[];\n }) ?? { include: [], exclude: [] };\n const result: Record<string, unknown> = {\n include: {\n value: current.include,\n add: (v: string) => base.setValue({ ...current, include: [...current.include, v] }),\n remove: (v: string) =>\n base.setValue({\n ...current,\n include: current.include.filter((i) => i !== v),\n }),\n },\n exclude: {\n value: current.exclude,\n add: (v: string) => base.setValue({ ...current, exclude: [...current.exclude, v] }),\n remove: (v: string) =>\n base.setValue({\n ...current,\n exclude: current.exclude.filter((i) => i !== v),\n }),\n },\n };\n const m = meta as any;\n if (m.optionsDef?.options && typeof m.optionsDef.options === \"function\") {\n result.loadOptions = async (query: string) =>\n withMergedWidgets(\n await m.optionsDef.options({ query, token: publicKey }),\n m.optionsDef.widgets,\n );\n } else if (m.optionsDef?.options) {\n result.options = withMergedWidgets(m.optionsDef.options, m.optionsDef.widgets);\n }\n if (m.suggestionsDef?.options) {\n if (typeof m.suggestionsDef.options === \"function\") {\n result.loadOptions = async (query: string) =>\n withMergedWidgets(\n await m.suggestionsDef.options({ query, token: publicKey }),\n m.suggestionsDef.widgets,\n );\n } else {\n result.options = withMergedWidgets(m.suggestionsDef.options, m.suggestionsDef.widgets);\n }\n }\n return result;\n }\n\n if (inputGuards.range_input(meta)) {\n const current = (base.value as {\n from: number | null;\n to: number | null;\n }) ?? { from: null, to: null };\n return {\n from: {\n value: current.from,\n set: (v: number | null) => base.setValue({ ...current, from: v }),\n },\n to: {\n value: current.to,\n set: (v: number | null) => base.setValue({ ...current, to: v }),\n },\n };\n }\n\n if (inputGuards.date_range_input(meta)) {\n const current = (base.value as Record<string, string>) ?? {};\n return {\n from: {\n value: current.gte ?? current.gt ?? \"\",\n set: (v: string) => base.setValue({ ...current, gte: v }),\n },\n to: {\n value: current.lte ?? current.lt ?? \"\",\n set: (v: string) => base.setValue({ ...current, lte: v }),\n },\n };\n }\n\n if (inputGuards.exact_range_input(meta)) {\n const current = (base.value as Record<string, number | null>) ?? {};\n return {\n greaterThan: {\n operator: current.gt != null ? \"gt\" : \"gte\",\n value: current.gt ?? current.gte ?? null,\n setOperator: (op: string) => {\n const otherOp = op === \"gt\" ? \"gte\" : \"gt\";\n const val = current[otherOp] ?? current[op];\n const updated = { ...current };\n delete updated[otherOp];\n if (val != null) updated[op] = val;\n base.setValue(updated);\n },\n setValue: (v: number | null) => {\n const op = current.gt != null ? \"gt\" : \"gte\";\n const updated = { ...current };\n if (v != null) updated[op] = v;\n else delete updated[op];\n base.setValue(updated);\n },\n },\n lessThan: {\n operator: current.lt != null ? \"lt\" : \"lte\",\n value: current.lt ?? current.lte ?? null,\n setOperator: (op: string) => {\n const otherOp = op === \"lt\" ? \"lte\" : \"lt\";\n const val = current[otherOp] ?? current[op];\n const updated = { ...current };\n delete updated[otherOp];\n if (val != null) updated[op] = val;\n base.setValue(updated);\n },\n setValue: (v: number | null) => {\n const op = current.lt != null ? \"lt\" : \"lte\";\n const updated = { ...current };\n if (v != null) updated[op] = v;\n else delete updated[op];\n base.setValue(updated);\n },\n },\n };\n }\n\n if (inputGuards.min_max_int_input(meta)) {\n const current = (base.value as {\n min: number | null;\n max: number | null;\n }) ?? { min: null, max: null };\n return {\n from: {\n value: current.min,\n set: (v: number | null) => base.setValue({ ...current, min: v }),\n },\n to: {\n value: current.max,\n set: (v: number | null) => base.setValue({ ...current, max: v }),\n },\n };\n }\n\n if (inputGuards.multi_create_input(meta) || inputGuards.ordered_multi_create_input(meta)) {\n const items = (base.value as string[]) ?? [];\n const result: Record<string, unknown> = {\n items,\n add: (v: string) => base.setValue([...items, v]),\n remove: (v: string) => base.setValue(items.filter((i) => i !== v)),\n };\n if (inputGuards.ordered_multi_create_input(meta)) {\n result.reorder = (from: number, to: number) => {\n const next = [...items];\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved);\n base.setValue(next);\n };\n }\n const m = meta as any;\n if (m.suggestionsDef?.options) {\n if (typeof m.suggestionsDef.options === \"function\") {\n result.loadOptions = async (query: string) =>\n withMergedWidgets(\n await m.suggestionsDef.options({ query, token: publicKey }),\n m.suggestionsDef.widgets,\n );\n } else {\n result.options = withMergedWidgets(m.suggestionsDef.options, m.suggestionsDef.widgets);\n }\n }\n return result;\n }\n\n if (inputGuards.tagged_ordered_multi_create_input(meta)) {\n const items = (base.value as string[]) ?? [];\n const result: Record<string, unknown> = {\n items,\n setItems: (next: string[]) => base.setValue(next),\n inputFields: meta.inputFields ?? [],\n };\n const m = meta as any;\n if (m.suggestionsDef?.options) {\n if (typeof m.suggestionsDef.options === \"function\") {\n result.loadOptions = async (query: string) =>\n withMergedWidgets(\n await m.suggestionsDef.options({ query, token: publicKey }),\n m.suggestionsDef.widgets,\n );\n } else {\n result.options = withMergedWidgets(m.suggestionsDef.options, m.suggestionsDef.widgets);\n }\n }\n return result;\n }\n\n if (inputGuards.loose_object_input(meta)) {\n const value = (base.value as Record<string, string>) ?? {};\n return {\n value,\n setObject: (next: Record<string, string>) => base.setValue(next),\n searchSecrets: loadingCtx?.searchSecrets,\n searchConstants: loadingCtx?.searchConstants,\n };\n }\n\n if (inputGuards.prompt_input(meta) || inputGuards.template_input(meta)) {\n return {\n searchSecrets: loadingCtx?.searchSecrets,\n searchConstants: loadingCtx?.searchConstants,\n };\n }\n\n if (inputGuards.condition_block_input(meta)) {\n const loadState = loadingCtx?.fieldLoadStates?.[meta.path];\n return {\n searchSecrets: loadingCtx?.searchSecrets,\n searchConstants: loadingCtx?.searchConstants,\n // Field-name suggestions themselves ride on `meta.options` (merged from\n // the form store by `resolveField`); only the load state comes through.\n pending: loadState?.status === \"loading\",\n };\n }\n\n if (inputGuards.field_select_input(meta)) {\n const loadState = loadingCtx?.fieldLoadStates?.[meta.path];\n return {\n options: meta.options ?? [],\n pending: loadState?.status === \"loading\",\n suggestionsDisabled: loadState?.suggestionsDisabled ?? false,\n suggestionsDisabledReason: loadState?.suggestionsDisabledReason,\n };\n }\n\n // Remaining types need no extras beyond base\n return {};\n}\n\nfunction isEmptyValue(value: unknown): boolean {\n if (value === null || typeof value === \"undefined\") return true;\n if (typeof value === \"string\") return value === \"\";\n if (Array.isArray(value)) return value.length === 0;\n if (typeof value === \"object\") {\n const keys = Object.keys(value);\n if (keys.length === 0) return true;\n return keys.every((k) => isEmptyValue((value as Record<string, unknown>)[k]));\n }\n return false;\n}\n\nexport function buildSectionHandles(\n formConfig: FormSection[],\n form: UseFormReturn<Record<string, unknown>>,\n publicKey: string,\n loadingCtx?: FieldLoadingContext,\n): FormSectionHandle[] {\n // In onSubmit validation mode, don't flag groups as invalid until the\n // user has actually attempted a submit. This matches RHF's own field-level\n // behavior where `formState.errors` is only populated after the first\n // submit (and updated reactively thereafter per `reValidateMode`).\n const hasSubmitted = form.formState.isSubmitted;\n\n return formConfig\n .map((section) => {\n const groups: FormGroupHandle[] = section.groups\n .map((group) => {\n // Drop a connector field whose mode is \"disabled\" (custom connections\n // unsupported) — there's nothing to configure, so we hide the whole\n // group/section rather than render a \"not supported\" placeholder.\n const fields = group.fields\n .filter(\n (meta) => !(inputGuards.connector_input(meta) && meta.connectorMode === \"disabled\"),\n )\n .map((meta) => buildFieldProps(meta, form, publicKey, loadingCtx)) as AnyFieldProps[];\n\n const groupPathError = form.getFieldState(group.groupPath as any).error;\n const errorCount = hasSubmitted\n ? fields.filter((f) => f.error != null).length + (groupPathError ? 1 : 0)\n : 0;\n const setCount = fields.filter((f) => !isEmptyValue(f.value)).length;\n const dirtyCount = fields.filter((f) => f.dirty).length;\n\n return {\n key: group.groupPath,\n label: group.label,\n description: group.description,\n iconKey: group.iconKey,\n defaultExpand: group.defaultExpand ?? false,\n fields,\n errorCount,\n setCount,\n dirtyCount,\n };\n })\n .filter((group) => group.fields.length > 0);\n\n return {\n key: section.metadata.path,\n label: section.metadata.label,\n description: section.metadata.description,\n groups,\n };\n })\n .filter((section) => section.groups.length > 0);\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { scoreCatalogSearch } from "@pipe0/base";
1
2
  import { BookDashed, Bookmark, Braces, CheckCheck, Hash, HelpCircle, Loader, Pause, ToggleRight, TriangleDashed, Type, X } from "lucide-react";
2
3
  import { rankItem } from "@tanstack/match-sorter-utils";
3
4
 
@@ -29,7 +30,15 @@ const fuzzyFilter = (row, columnId, value, addMeta) => {
29
30
  addMeta({ itemRank });
30
31
  return itemRank.passed;
31
32
  };
33
+ const catalogSearchFilter = (row, columnId, value, addMeta) => {
34
+ const score = scoreCatalogSearch(row.getValue(columnId), String(value ?? ""));
35
+ addMeta({ searchScore: score });
36
+ return score > 0;
37
+ };
38
+ const catalogSearchSort = (rowA, rowB, columnId) => {
39
+ return (rowA.columnFiltersMeta[columnId]?.searchScore ?? 0) - (rowB.columnFiltersMeta[columnId]?.searchScore ?? 0);
40
+ };
32
41
 
33
42
  //#endregion
34
- export { fuzzyFilter, getFieldStatusIcon, getFieldTypeIcon };
43
+ export { catalogSearchFilter, catalogSearchSort, fuzzyFilter, getFieldStatusIcon, getFieldTypeIcon };
35
44
  //# sourceMappingURL=catalog-helpers.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"catalog-helpers.mjs","names":[],"sources":["../../src/utils/catalog-helpers.tsx"],"sourcesContent":["import type { RecordFieldStatus, RecordFieldType } from \"@pipe0/base\";\nimport { rankItem } from \"@tanstack/match-sorter-utils\";\nimport type { FilterFn } from \"@tanstack/react-table\";\nimport {\n BookDashed,\n Bookmark,\n Braces,\n CheckCheck,\n Hash,\n HelpCircle,\n Loader,\n Pause,\n ToggleRight,\n TriangleDashed,\n Type,\n X,\n} from \"lucide-react\";\nimport type { ComponentType } from \"react\";\n\nconst fieldStatusIconMap = {\n completed: CheckCheck,\n failed: X,\n no_result: BookDashed,\n pending: Bookmark,\n processing: Loader,\n queued: Pause,\n skipped: TriangleDashed,\n} satisfies Record<RecordFieldStatus, ComponentType>;\n\nconst FieldTypeIconMap = {\n boolean: ToggleRight,\n json: Braces,\n number: Hash,\n string: Type,\n unknown: HelpCircle,\n} satisfies Record<RecordFieldType, ComponentType>;\n\nexport function getFieldTypeIcon(fieldType: RecordFieldType) {\n return FieldTypeIconMap[fieldType];\n}\n\nexport function getFieldStatusIcon(fieldStatus: RecordFieldStatus) {\n return fieldStatusIconMap[fieldStatus];\n}\n\nexport const fuzzyFilter: FilterFn<any> = (row, columnId, value, addMeta) => {\n const itemRank = rankItem(row.getValue(columnId), value);\n addMeta({ itemRank });\n return itemRank.passed;\n};\n"],"mappings":";;;;AAmBA,MAAM,qBAAqB;CACzB,WAAW;CACX,QAAQ;CACR,WAAW;CACX,SAAS;CACT,YAAY;CACZ,QAAQ;CACR,SAAS;CACV;AAED,MAAM,mBAAmB;CACvB,SAAS;CACT,MAAM;CACN,QAAQ;CACR,QAAQ;CACR,SAAS;CACV;AAED,SAAgB,iBAAiB,WAA4B;AAC3D,QAAO,iBAAiB;;AAG1B,SAAgB,mBAAmB,aAAgC;AACjE,QAAO,mBAAmB;;AAG5B,MAAa,eAA8B,KAAK,UAAU,OAAO,YAAY;CAC3E,MAAM,WAAW,SAAS,IAAI,SAAS,SAAS,EAAE,MAAM;AACxD,SAAQ,EAAE,UAAU,CAAC;AACrB,QAAO,SAAS"}
1
+ {"version":3,"file":"catalog-helpers.mjs","names":[],"sources":["../../src/utils/catalog-helpers.tsx"],"sourcesContent":["import { type RecordFieldStatus, type RecordFieldType, scoreCatalogSearch } from \"@pipe0/base\";\nimport { rankItem } from \"@tanstack/match-sorter-utils\";\nimport type { FilterFn, SortingFn } from \"@tanstack/react-table\";\nimport {\n BookDashed,\n Bookmark,\n Braces,\n CheckCheck,\n Hash,\n HelpCircle,\n Loader,\n Pause,\n ToggleRight,\n TriangleDashed,\n Type,\n X,\n} from \"lucide-react\";\nimport type { ComponentType } from \"react\";\n\nconst fieldStatusIconMap = {\n completed: CheckCheck,\n failed: X,\n no_result: BookDashed,\n pending: Bookmark,\n processing: Loader,\n queued: Pause,\n skipped: TriangleDashed,\n} satisfies Record<RecordFieldStatus, ComponentType>;\n\nconst FieldTypeIconMap = {\n boolean: ToggleRight,\n json: Braces,\n number: Hash,\n string: Type,\n unknown: HelpCircle,\n} satisfies Record<RecordFieldType, ComponentType>;\n\nexport function getFieldTypeIcon(fieldType: RecordFieldType) {\n return FieldTypeIconMap[fieldType];\n}\n\nexport function getFieldStatusIcon(fieldStatus: RecordFieldStatus) {\n return fieldStatusIconMap[fieldStatus];\n}\n\nexport const fuzzyFilter: FilterFn<any> = (row, columnId, value, addMeta) => {\n const itemRank = rankItem(row.getValue(columnId), value);\n addMeta({ itemRank });\n return itemRank.passed;\n};\n\n// Global-filter fn for the catalog tables' hidden \"search\" column (its value\n// is a precomputed CatalogSearchTarget). Stashes the score so\n// catalogSearchSort can order rows by relevance while a query is active.\nexport const catalogSearchFilter: FilterFn<any> = (row, columnId, value, addMeta) => {\n const score = scoreCatalogSearch(row.getValue(columnId), String(value ?? \"\"));\n addMeta({ searchScore: score } as any);\n return score > 0;\n};\n\nexport const catalogSearchSort: SortingFn<any> = (rowA, rowB, columnId) => {\n const a = (rowA.columnFiltersMeta[columnId] as any)?.searchScore ?? 0;\n const b = (rowB.columnFiltersMeta[columnId] as any)?.searchScore ?? 0;\n return a - b; // paired with `desc: true` → highest score first\n};\n"],"mappings":";;;;;AAmBA,MAAM,qBAAqB;CACzB,WAAW;CACX,QAAQ;CACR,WAAW;CACX,SAAS;CACT,YAAY;CACZ,QAAQ;CACR,SAAS;CACV;AAED,MAAM,mBAAmB;CACvB,SAAS;CACT,MAAM;CACN,QAAQ;CACR,QAAQ;CACR,SAAS;CACV;AAED,SAAgB,iBAAiB,WAA4B;AAC3D,QAAO,iBAAiB;;AAG1B,SAAgB,mBAAmB,aAAgC;AACjE,QAAO,mBAAmB;;AAG5B,MAAa,eAA8B,KAAK,UAAU,OAAO,YAAY;CAC3E,MAAM,WAAW,SAAS,IAAI,SAAS,SAAS,EAAE,MAAM;AACxD,SAAQ,EAAE,UAAU,CAAC;AACrB,QAAO,SAAS;;AAMlB,MAAa,uBAAsC,KAAK,UAAU,OAAO,YAAY;CACnF,MAAM,QAAQ,mBAAmB,IAAI,SAAS,SAAS,EAAE,OAAO,SAAS,GAAG,CAAC;AAC7E,SAAQ,EAAE,aAAa,OAAO,CAAQ;AACtC,QAAO,QAAQ;;AAGjB,MAAa,qBAAqC,MAAM,MAAM,aAAa;AAGzE,SAFW,KAAK,kBAAkB,WAAmB,eAAe,MACzD,KAAK,kBAAkB,WAAmB,eAAe"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipe0/react",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "React component library for building forms and catalogs powered by pipe0 pipes and searches.",
5
5
  "license": "MIT",
6
6
  "author": "pipe0",
@@ -84,7 +84,7 @@
84
84
  "react-hook-form": "^7.62.0",
85
85
  "swr": "^2.4.1",
86
86
  "tailwind-merge": "^3.3.1",
87
- "@pipe0/base": "0.5.4"
87
+ "@pipe0/base": "0.5.6"
88
88
  },
89
89
  "devDependencies": {
90
90
  "@base-ui/react": "^1.3.0",