@cryptlex/web-components 6.7.1 → 6.7.2
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.
|
@@ -47,7 +47,7 @@ type BaseSearchableResource = {
|
|
|
47
47
|
* @testing
|
|
48
48
|
* - Ensure API client is provided via context; assert keyboard navigation, open/close behavior, and `onBlur` call on popover close.
|
|
49
49
|
*/
|
|
50
|
-
declare function BaseIdSearchInput<T extends BaseSearchableResource, V>({ label, description, errorMessage, requiredIndicator, isDisabled, isInvalid, onBlur, path, onChange, value, renderLabel, accessor, defaultParams, className, emptyOption, ...props }: FormFieldProps & {
|
|
50
|
+
declare function BaseIdSearchInput<T extends BaseSearchableResource, V>({ label, description, errorMessage, requiredIndicator, isDisabled, isInvalid, onBlur, path, onChange, value, renderLabel, accessor, getItemLabel, defaultParams, className, emptyOption, ...props }: FormFieldProps & {
|
|
51
51
|
path: ClientPathsWithMethod<CtxClientType, 'get'>;
|
|
52
52
|
/** Disable interactions. */
|
|
53
53
|
isDisabled?: boolean;
|
|
@@ -55,6 +55,7 @@ declare function BaseIdSearchInput<T extends BaseSearchableResource, V>({ label,
|
|
|
55
55
|
isInvalid?: boolean;
|
|
56
56
|
/** Key used to access an alternate display accessor on item (kept for compatibility). */
|
|
57
57
|
accessor: keyof BaseSearchableResource;
|
|
58
|
+
getItemLabel?: (item: T) => React.ReactNode;
|
|
58
59
|
/** Controlled value. */
|
|
59
60
|
value: V;
|
|
60
61
|
/** Called when popover closes or the field blurs with the current value. */
|
|
@@ -87,7 +88,7 @@ declare function BaseIdSearchInput<T extends BaseSearchableResource, V>({ label,
|
|
|
87
88
|
* />
|
|
88
89
|
*
|
|
89
90
|
*/
|
|
90
|
-
export declare function SingleIdSearchInput<T extends BaseSearchableResource>({ accessor, ...props }: Omit<React.ComponentProps<typeof BaseIdSearchInput<T, string | null>>, 'onSelectionChange' | 'selectionMode' | 'selectedKeys' | 'renderLabel'>): import("react/jsx-runtime").JSX.Element;
|
|
91
|
+
export declare function SingleIdSearchInput<T extends BaseSearchableResource>({ accessor, getItemLabel, ...props }: Omit<React.ComponentProps<typeof BaseIdSearchInput<T, string | null>>, 'onSelectionChange' | 'selectionMode' | 'selectedKeys' | 'renderLabel'>): import("react/jsx-runtime").JSX.Element;
|
|
91
92
|
/**
|
|
92
93
|
* Multi-selection ID search input.
|
|
93
94
|
*
|
|
@@ -108,7 +109,7 @@ export declare function SingleIdSearchInput<T extends BaseSearchableResource>({
|
|
|
108
109
|
* @remarks
|
|
109
110
|
* - The `renderLabel` joins selected item names with commas for compact display.
|
|
110
111
|
*/
|
|
111
|
-
export declare function MultipleIdSearchInput<T extends BaseSearchableResource>({ accessor, ...props }: Omit<React.ComponentProps<typeof BaseIdSearchInput<T, string[]>>, 'renderLabel' | 'onSelectionChange' | 'selectionMode' | 'selectedKeys'>): import("react/jsx-runtime").JSX.Element;
|
|
112
|
+
export declare function MultipleIdSearchInput<T extends BaseSearchableResource>({ accessor, getItemLabel, ...props }: Omit<React.ComponentProps<typeof BaseIdSearchInput<T, string[]>>, 'renderLabel' | 'onSelectionChange' | 'selectionMode' | 'selectedKeys'>): import("react/jsx-runtime").JSX.Element;
|
|
112
113
|
/**
|
|
113
114
|
* Form-integrated single-select ID input (field wrapper).
|
|
114
115
|
*
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as n,jsxs as M}from"react/jsx-runtime";import{useQuery as K}from"@tanstack/react-query";import{useId as _,useState as D}from"react";import{Select as G,Autocomplete as P}from"react-aria-components";import{Loader as Q}from"./loader.js";import{Menu as k,MenuItem as z}from"./menu.js";import{PopoverTrigger as H}from"./popover.js";import{SearchField as J}from"./searchfield.js";import{useCtxClient as U}from"../utilities/ctx-client.js";import{getEmptyLabel as q,isEmptyValue as W}from"../utilities/empty-option.js";import{getFieldErrorMessage as y}from"../utilities/form.js";import{useFieldContext as T}from"../utilities/form-context.js";import{FormField as X}from"./form.js";import{SelectTrigger as Y,SelectPopover as Z}from"./select.js";import{TagGroup as $,Tag as O}from"./tag-group.js";import"../utilities/theme.js";import"clsx";import"./icons.js";import"@icons-pack/react-simple-icons";import"./list-box.js";import"./button.js";import"class-variance-authority";import"@tanstack/react-form";import"./card.js";function g(t){return t.name??t.displayName??""}function ee(t){return Array.isArray(t)&&t.every(r=>{if(!r||typeof r!="object"||!("id"in r)||typeof r.id!="string")return!1;const e="name"in r&&typeof r.name=="string",o="displayName"in r&&typeof r.displayName=="string";return e||o})}function E({label:t,description:r,errorMessage:e,requiredIndicator:o,isDisabled:h,isInvalid:a,onBlur:l,path:s,onChange:m,value:i,renderLabel:d,accessor:f,getItemLabel:S,defaultParams:p,className:V,emptyOption:A,...b}){if(s==="/v3/me")throw Error('Path "/v3/me" is not supported with IdSearch since it is not a searchable resource.');const L=_(),v=b.id||L,w=U(),C=S??g,B=c=>{const u=C(c);return typeof u=="string"?u:g(c)},[I,R]=D(""),{data:N,isError:x,isFetching:F,error:j}=K({queryKey:["get",s,I],queryFn:async()=>{const u=(await w.GET(s,{params:{query:{search:I,...p?.query,limit:50,page:1},path:{...p?.path}}})).data;return u&&ee(u)?u:[]}});return n("div",{className:"group form-field","data-invalid":a?"":void 0,children:n(X,{label:t,description:r,errorMessage:e,requiredIndicator:o,htmlFor:v,children:n(G,{isInvalid:a,children:M(H,{onOpenChange:c=>{c||l?.(i)},children:[n(Y,{id:v,isDisabled:h,className:V??"w-full",children:d(i,N,A)}),n(Z,{placement:"bottom start",children:M(P,{inputValue:I,onInputChange:R,children:[n(J,{className:"p-2",autoFocus:!0}),F&&n("div",{className:"p-input",children:n(Q,{className:"mx-auto"})}),!F&&!x&&n(k,{...b,className:"max-h-48",items:N,renderEmptyState:()=>n("div",{className:"body-sm p-2",children:"No results found."}),children:c=>{const u=c[f]??c.id;return n(z,{id:u,textValue:B(c),children:C(c)},u)}}),x&&n("div",{className:"text-destructive p-icon body-sm",children:j.message})]})})]})})})})}function re({accessor:t,getItemLabel:r,...e}){const o=e.value?[e.value]:[],h=r??g;return n(E,{accessor:t,getItemLabel:r,selectedKeys:o,onSelectionChange:a=>{const l=Array.from(a).filter(s=>typeof s=="string")[0];e.onChange(l)},renderLabel:(a,l,s)=>{if(s&&W(a))return q(s);const m=l?.find(i=>(i[t]??i.id)===a);return m?h(m):""},selectionMode:"single",...e})}function te({accessor:t,getItemLabel:r,...e}){const o=e.value,h=r??g;return n(E,{...e,accessor:t,getItemLabel:r,selectedKeys:o,onSelectionChange:a=>{const l=Array.from(a).filter(s=>typeof s=="string");e.onChange(l.length>0?l:[])},selectionMode:"multiple",className:"w-full h-auto items-start",renderLabel:(a,l,s)=>{if(s&&(!a||a.length===0))return q(s);const m=a??[];return n($,{onRemove:i=>e.onChange(m.filter(d=>!i.has(d))),items:m.map(i=>{const d=l?.find(p=>(p[t]??p.id)===i),f=d?h(d):i,S=typeof f=="string"?f:d?g(d):i;return{id:i,name:f,textValue:S}}),children:i=>n(O,{textValue:i.textValue,children:i.name},i.id)})}})}function qe({isDisabled:t,...r}){const e=T({disabled:t});return n(re,{requiredIndicator:e.isRequired,isDisabled:t||e.isSubmitting,value:e.state.value,onBlur:o=>e.handleBlur(),onChange:o=>e.handleChange(o),isInvalid:!!y(e),errorMessage:y(e),...r})}function Te({isDisabled:t,...r}){const e=T({disabled:t});return n(te,{requiredIndicator:e.isRequired,isDisabled:t||e.isSubmitting,value:e.state.value,onBlur:o=>e.handleBlur(),onChange:o=>e.handleChange(o),isInvalid:!!y(e),errorMessage:y(e),...r})}export{te as MultipleIdSearchInput,re as SingleIdSearchInput,Te as TfMultipleIdSearchInput,qe as TfSingleIdSearchInput};
|
|
2
2
|
//# sourceMappingURL=id-search.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"id-search.js","sources":["../../lib/components/id-search.tsx"],"sourcesContent":["'use client';\nimport { useQuery } from '@tanstack/react-query';\nimport { useId, useState } from 'react';\nimport { Select as AriaSelect, Autocomplete } from 'react-aria-components';\n\nimport type { ClientPathsWithMethod } from 'openapi-fetch';\nimport { Loader } from '../components/loader';\nimport { Menu, MenuItem } from '../components/menu';\nimport { PopoverTrigger } from '../components/popover';\nimport { SearchField } from '../components/searchfield';\nimport { useCtxClient, type CtxClientType } from '../utilities/ctx-client';\nimport { getEmptyLabel, isEmptyValue, type EmptyOption } from '../utilities/empty-option';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { FormField, type FormFieldProps } from './form';\nimport { SelectPopover, SelectTrigger } from './select';\nimport { Tag, TagGroup } from './tag-group';\n\n/**\n * Minimal resource shape used by the ID search inputs.\n * `id` is required; the label comes from `name` or `displayName`.\n *\n * @example\n * const user: BaseSearchableResource = { id: 'u_123', name: 'Nabeel Farooq' };\n * const product: BaseSearchableResource = { id: 'p_123', displayName: 'My Product' };\n */\ntype BaseSearchableResource = {\n /** Unique identifier used as the input value. */\n id: string;\n /** Human-readable label shown to users. */\n name?: string;\n displayName?: string;\n};\n\n/** Resources commonly expose either `name` or `displayName` as their human-readable label. */\nfunction getResourceLabel(item: BaseSearchableResource): string {\n return item.name ?? item.displayName ?? '';\n}\n\n/**\n * Type guard to check if a value is an array of searchable resources\n */\nfunction isSearchableResourceArray<T extends BaseSearchableResource>(value: unknown): value is T[] {\n return (\n Array.isArray(value) &&\n value.every(item => {\n if (!item || typeof item !== 'object' || !('id' in item) || typeof item.id !== 'string') return false;\n const hasName = 'name' in item && typeof item.name === 'string';\n const hasDisplayName = 'displayName' in item && typeof item.displayName === 'string';\n return hasName || hasDisplayName;\n })\n );\n}\n\n/**\n * - Generic, accessible ID-search building block.\n * - Search (powered by react-query)\n * - Renders an accessible Autocomplete + Menu listbox\n * - Exposes a controlled `value`/`onChange` contract so callers (and wrappers) can manage state\n *\n * @template T - resource type extending `BaseSearchableResource` (must have `id`; label is `name` or `displayName`)\n * @template V - controlled value type (e.g. `string` for single-select or `string[]` for multi-select)\n *\n * @param props - props object (see inline property JSDoc for the most important fields)\n *\n * @remarks\n * - Search is automatically handled based on the `resource` prop using the API client from context\n * - When the popover closes, `onBlur` (if provided) is called with the current `value`.\n * - `renderLabel` must convert `value` to a readable string for the control button.\n * - `defaultParams` can be used to pass additional query parameters to the search endpoint\n *\n * @example\n * <BaseIdSearchInput\n * label=\"Owner\"\n * resource=\"user\"\n * value={ownerId}\n * onChange={setOwnerId}\n * renderLabel={(v, data) => data?.find(d => d.id === v)?.name ?? v}\n * />\n *\n * @testing\n * - Ensure API client is provided via context; assert keyboard navigation, open/close behavior, and `onBlur` call on popover close.\n */\nfunction BaseIdSearchInput<T extends BaseSearchableResource, V>({\n label,\n description,\n errorMessage,\n requiredIndicator,\n isDisabled,\n isInvalid,\n onBlur,\n path,\n onChange,\n value,\n renderLabel,\n accessor,\n defaultParams,\n className,\n emptyOption,\n ...props\n}: FormFieldProps & {\n path: ClientPathsWithMethod<CtxClientType, 'get'>;\n /** Disable interactions. */\n isDisabled?: boolean;\n /** Whether the field is invalid. */\n isInvalid?: boolean;\n /** Key used to access an alternate display accessor on item (kept for compatibility). */\n accessor: keyof BaseSearchableResource;\n /** Controlled value. */\n value: V;\n /** Called when popover closes or the field blurs with the current value. */\n onBlur?: (v: V) => void;\n /** Controlled change handler. */\n onChange: (v: V) => void;\n /** Render a human-readable label for the current value using the latest data. */\n renderLabel: (v: V, data: T[] | undefined, emptyOption?: EmptyOption) => string | React.ReactNode;\n /** Default parameters to include in the request. This is useful when using /v3/users?role='admin' or /v3/organizations/ID/user-groups */\n defaultParams?: Record<'path' | 'query', any>;\n /** Optional className to customize the trigger button styling. */\n className?: string;\n /* Optional empty option to show when value is empty. */\n emptyOption?: EmptyOption;\n} & Omit<React.ComponentProps<typeof Menu>, 'items' | 'className'>) {\n if (path === '/v3/me') {\n throw Error('Path \"/v3/me\" is not supported with IdSearch since it is not a searchable resource.');\n }\n\n const generatedId = useId();\n const fieldId = props.id || generatedId;\n const client = useCtxClient();\n\n const [search, _setSearch] = useState('');\n const { data, isError, isFetching, error } = useQuery({\n // This is the schema that openapi-react-query follows as of 0.5.1\n queryKey: ['get', path, search],\n queryFn: async (): Promise<T[]> => {\n const result = await client.GET(path, {\n params: {\n query: {\n search,\n ...defaultParams?.query,\n limit: 50,\n page: 1,\n },\n path: {\n ...defaultParams?.path,\n },\n },\n });\n\n // Type narrowing: result.data is inferred as never due to complex union types\n // We use unknown to bypass this and then validate with our type guard\n const responseData: unknown = result.data;\n if (responseData && isSearchableResourceArray<T>(responseData)) {\n return responseData;\n }\n return [];\n },\n });\n\n return (\n <div className=\"group form-field\" data-invalid={isInvalid ? '' : undefined}>\n <FormField {...{ label, description, errorMessage, requiredIndicator, htmlFor: fieldId }}>\n <AriaSelect isInvalid={isInvalid}>\n <PopoverTrigger\n onOpenChange={o => {\n if (!o) {\n // searchInputRef.current?.focus();\n onBlur?.(value);\n }\n }}\n >\n <SelectTrigger id={fieldId} isDisabled={isDisabled} className={className ?? 'w-full'}>\n {renderLabel(value, data, emptyOption)}\n </SelectTrigger>\n <SelectPopover placement=\"bottom start\">\n <Autocomplete inputValue={search} onInputChange={_setSearch}>\n <SearchField className={'p-2'} autoFocus />\n {isFetching && (\n <div className=\"p-input\">\n <Loader className=\"mx-auto\" />\n </div>\n )}\n {!isFetching && !isError && (\n <Menu\n {...props}\n className={'max-h-48'}\n items={data}\n renderEmptyState={() => <div className=\"body-sm p-2\">No results found.</div>}\n >\n {item => {\n const itemId = item[accessor] ?? item.id;\n return (\n <MenuItem key={itemId} id={itemId}>\n {getResourceLabel(item)}\n </MenuItem>\n );\n }}\n </Menu>\n )}\n {isError && <div className=\"text-destructive p-icon body-sm\">{error.message}</div>}\n </Autocomplete>\n </SelectPopover>\n </PopoverTrigger>\n </AriaSelect>\n </FormField>\n </div>\n );\n}\n\n/**\n * Single-selection ID search input.\n *\n * Thin, typed wrapper around `BaseIdSearchInput` specialized for the very common single-ID case.\n * Adapts the internal selection events into `onChange(id?: string)` and renders the selected label.\n *\n * @template T - resource type (extends BaseSearchableResource)\n *\n * @param props - Inherits `BaseIdSearchInput` props but uses `string[]` value type.\n *\n * @example\n * <SingleIdSearchInput\n * label=\"Reporter\"\n * value={reporterId}\n * onChange={setReporterId}\n * />\n *\n */\nexport function SingleIdSearchInput<T extends BaseSearchableResource>({\n accessor,\n ...props\n}: Omit<\n React.ComponentProps<typeof BaseIdSearchInput<T, string | null>>,\n 'onSelectionChange' | 'selectionMode' | 'selectedKeys' | 'renderLabel'\n>) {\n const selectedKeys = props.value ? [props.value] : [];\n\n return (\n <BaseIdSearchInput\n accessor={accessor}\n selectedKeys={selectedKeys}\n onSelectionChange={e => {\n const val = Array.from(e).filter(v => typeof v === 'string')[0];\n props.onChange(val);\n }}\n renderLabel={(v, d, emptyOption) => {\n // If value is empty and emptyOption is set, show the empty label\n if (emptyOption && isEmptyValue(v)) {\n return getEmptyLabel(emptyOption);\n }\n // Match on the same field the value was derived from (accessor), not always `id`.\n const match = d?.find(di => (di[accessor] ?? di.id) === v);\n return match ? getResourceLabel(match) : '';\n }}\n selectionMode=\"single\"\n {...props}\n />\n );\n}\n\n/**\n * Multi-selection ID search input.\n *\n * Thin wrapper around `BaseIdSearchInput` for the multiple-ID (`string[]`) case.\n * Adapts internal selection events into `onChange(ids: string[])`.\n *\n * @template T - resource type (extends BaseSearchableResource)\n *\n * @param props - Inherits `BaseIdSearchInput` props but uses `string[]` value type.\n *\n * @example\n * <MultipleIdSearchInput\n * label=\"Reviewers\"\n * value={reviewerIds}\n * onChange={setReviewerIds}\n * />\n *\n * @remarks\n * - The `renderLabel` joins selected item names with commas for compact display.\n */\nexport function MultipleIdSearchInput<T extends BaseSearchableResource>({\n accessor,\n ...props\n}: Omit<\n React.ComponentProps<typeof BaseIdSearchInput<T, string[]>>,\n 'renderLabel' | 'onSelectionChange' | 'selectionMode' | 'selectedKeys'\n>) {\n const selectedKeys = props.value;\n\n return (\n <BaseIdSearchInput\n {...props}\n accessor={accessor}\n selectedKeys={selectedKeys}\n onSelectionChange={e => {\n const vals = Array.from(e).filter(v => typeof v === 'string');\n props.onChange(vals.length > 0 ? vals : []);\n }}\n selectionMode=\"multiple\"\n className=\"w-full h-auto items-start\"\n renderLabel={(v, d, emptyOption) => {\n // If array is empty and emptyOption is set, show the empty label\n if (emptyOption && (!v || v.length === 0)) {\n return getEmptyLabel(emptyOption);\n }\n\n const values = v ?? [];\n return (\n <TagGroup\n onRemove={keys => props.onChange(values.filter(value => !keys.has(value)))}\n items={values.map(value => {\n // Match on the same field the value was derived from (accessor), not always `id`.\n const match = d?.find(di => (di[accessor] ?? di.id) === value);\n const name = match ? getResourceLabel(match) : value;\n return {\n id: value,\n name: name,\n };\n })}\n >\n {item => <Tag key={item.id}>{getResourceLabel(item)}</Tag>}\n </TagGroup>\n );\n }}\n />\n );\n}\n\n/**\n * Form-integrated single-select ID input (field wrapper).\n *\n * Integrates `SingleIdSearchInput` into the form system using `useFieldContext`.\n * - wires `value`, `onChange`, and `onBlur`\n * - disables the control while the form is submitting\n * - surfaces field-level error messages\n *\n * @example\n * <TfSingleIdSearchInput name=\"ownerId\" label=\"Owner\" />\n \n */\nexport function TfSingleIdSearchInput({\n isDisabled,\n ...props\n}: Omit<React.ComponentProps<typeof SingleIdSearchInput>, 'value' | 'onChange' | 'onBlur'>) {\n const field = useFieldContext<string | null>({ disabled: isDisabled });\n return (\n <SingleIdSearchInput\n requiredIndicator={field.isRequired}\n isDisabled={isDisabled || field.isSubmitting}\n value={field.state.value}\n onBlur={_ => field.handleBlur()}\n onChange={e => field.handleChange(e)}\n isInvalid={!!getFieldErrorMessage(field)}\n errorMessage={getFieldErrorMessage(field)}\n {...props}\n />\n );\n}\n\n/**\n * Form-integrated multi-select ID input (field wrapper).\n *\n * Integrates `MultipleIdSearchInput` into the form system using `useFieldContext`.\n * - wires `value`, `onChange`, and `onBlur`\n * - disables the control while the form is submitting\n * - surfaces field-level error messages\n *\n * @example\n * <TfMultipleIdSearchInput name=\"reviewerIds\" label=\"Reviewers\" />\n *\n */\nexport function TfMultipleIdSearchInput({\n isDisabled,\n ...props\n}: Omit<React.ComponentProps<typeof MultipleIdSearchInput>, 'value' | 'onChange'>) {\n const field = useFieldContext<string[]>({ disabled: isDisabled });\n return (\n <MultipleIdSearchInput\n requiredIndicator={field.isRequired}\n isDisabled={isDisabled || field.isSubmitting}\n value={field.state.value}\n onBlur={_ => field.handleBlur()}\n onChange={e => field.handleChange(e)}\n isInvalid={!!getFieldErrorMessage(field)}\n errorMessage={getFieldErrorMessage(field)}\n {...props}\n />\n );\n}\n"],"names":["getResourceLabel","item","isSearchableResourceArray","value","hasName","hasDisplayName","BaseIdSearchInput","label","description","errorMessage","requiredIndicator","isDisabled","isInvalid","onBlur","path","onChange","renderLabel","accessor","defaultParams","className","emptyOption","props","generatedId","useId","fieldId","client","useCtxClient","search","_setSearch","useState","data","isError","isFetching","error","useQuery","responseData","jsx","FormField","AriaSelect","jsxs","PopoverTrigger","o","SelectTrigger","SelectPopover","Autocomplete","SearchField","Loader","Menu","itemId","MenuItem","SingleIdSearchInput","selectedKeys","e","val","v","d","isEmptyValue","getEmptyLabel","match","di","MultipleIdSearchInput","vals","values","TagGroup","keys","name","Tag","TfSingleIdSearchInput","field","useFieldContext","_","getFieldErrorMessage","TfMultipleIdSearchInput"],"mappings":"ygCAmCA,SAASA,EAAiBC,EAAsC,CAC5D,OAAOA,EAAK,MAAQA,EAAK,aAAe,EAC5C,CAKA,SAASC,EAA4DC,EAA8B,CAC/F,OACI,MAAM,QAAQA,CAAK,GACnBA,EAAM,MAAMF,GAAQ,CAChB,GAAI,CAACA,GAAQ,OAAOA,GAAS,UAAY,EAAE,OAAQA,IAAS,OAAOA,EAAK,IAAO,SAAU,MAAO,GAChG,MAAMG,EAAU,SAAUH,GAAQ,OAAOA,EAAK,MAAS,SACjDI,EAAiB,gBAAiBJ,GAAQ,OAAOA,EAAK,aAAgB,SAC5E,OAAOG,GAAWC,CACtB,CAAC,CAET,CA+BA,SAASC,EAAuD,CAC5D,MAAAC,EACA,YAAAC,EACA,aAAAC,EACA,kBAAAC,EACA,WAAAC,EACA,UAAAC,EACA,OAAAC,EACA,KAAAC,EACA,SAAAC,EACA,MAAAZ,EACA,YAAAa,EACA,SAAAC,EACA,cAAAC,EACA,UAAAC,EACA,YAAAC,EACA,GAAGC,CACP,EAsBoE,CAChE,GAAIP,IAAS,SACT,MAAM,MAAM,qFAAqF,EAGrG,MAAMQ,EAAcC,EAAA,EACdC,EAAUH,EAAM,IAAMC,EACtBG,EAASC,EAAA,EAET,CAACC,EAAQC,CAAU,EAAIC,EAAS,EAAE,EAClC,CAAE,KAAAC,EAAM,QAAAC,EAAS,WAAAC,EAAY,MAAAC,CAAA,EAAUC,EAAS,CAElD,SAAU,CAAC,MAAOpB,EAAMa,CAAM,EAC9B,QAAS,SAA0B,CAiB/B,MAAMQ,GAhBS,MAAMV,EAAO,IAAIX,EAAM,CAClC,OAAQ,CACJ,MAAO,CACH,OAAAa,EACA,GAAGT,GAAe,MAClB,MAAO,GACP,KAAM,CAAA,EAEV,KAAM,CACF,GAAGA,GAAe,IAAA,CACtB,CACJ,CACH,GAIoC,KACrC,OAAIiB,GAAgBjC,EAA6BiC,CAAY,EAClDA,EAEJ,CAAA,CACX,CAAA,CACH,EAED,OACIC,EAAC,OAAI,UAAU,mBAAmB,eAAcxB,EAAY,GAAK,OAC7D,SAAAwB,EAACC,EAAA,CAAgB,MAAA9B,EAAO,YAAAC,EAAa,aAAAC,EAAc,kBAAAC,EAAmB,QAASc,EAC3E,SAAAY,EAACE,EAAA,CAAW,UAAA1B,EACR,SAAA2B,EAACC,EAAA,CACG,aAAcC,GAAK,CACVA,GAED5B,IAASV,CAAK,CAEtB,EAEA,SAAA,CAAAiC,EAACM,EAAA,CAAc,GAAIlB,EAAS,WAAAb,EAAwB,UAAWQ,GAAa,SACvE,SAAAH,EAAYb,EAAO2B,EAAMV,CAAW,CAAA,CACzC,EACAgB,EAACO,GAAc,UAAU,eACrB,WAACC,EAAA,CAAa,WAAYjB,EAAQ,cAAeC,EAC7C,SAAA,CAAAQ,EAACS,EAAA,CAAY,UAAW,MAAO,UAAS,GAAC,EACxCb,KACI,MAAA,CAAI,UAAU,UACX,SAAAI,EAACU,EAAA,CAAO,UAAU,SAAA,CAAU,CAAA,CAChC,EAEH,CAACd,GAAc,CAACD,GACbK,EAACW,EAAA,CACI,GAAG1B,EACJ,UAAW,WACX,MAAOS,EACP,iBAAkB,IAAMM,EAAC,MAAA,CAAI,UAAU,cAAc,SAAA,oBAAiB,EAErE,SAAAnC,GAAQ,CACL,MAAM+C,EAAS/C,EAAKgB,CAAQ,GAAKhB,EAAK,GACtC,SACKgD,EAAA,CAAsB,GAAID,EACtB,SAAAhD,EAAiBC,CAAI,GADX+C,CAEf,CAER,CAAA,CAAA,EAGPjB,GAAWK,EAAC,MAAA,CAAI,UAAU,kCAAmC,WAAM,OAAA,CAAQ,CAAA,CAAA,CAChF,CAAA,CACJ,CAAA,CAAA,CAAA,CACJ,CACJ,EACJ,EACJ,CAER,CAoBO,SAASc,EAAsD,CAClE,SAAAjC,EACA,GAAGI,CACP,EAGG,CACC,MAAM8B,EAAe9B,EAAM,MAAQ,CAACA,EAAM,KAAK,EAAI,CAAA,EAEnD,OACIe,EAAC9B,EAAA,CACG,SAAAW,EACA,aAAAkC,EACA,kBAAmBC,GAAK,CACpB,MAAMC,EAAM,MAAM,KAAKD,CAAC,EAAE,OAAOE,GAAK,OAAOA,GAAM,QAAQ,EAAE,CAAC,EAC9DjC,EAAM,SAASgC,CAAG,CACtB,EACA,YAAa,CAACC,EAAGC,EAAGnC,IAAgB,CAEhC,GAAIA,GAAeoC,EAAaF,CAAC,EAC7B,OAAOG,EAAcrC,CAAW,EAGpC,MAAMsC,EAAQH,GAAG,KAAKI,IAAOA,EAAG1C,CAAQ,GAAK0C,EAAG,MAAQL,CAAC,EACzD,OAAOI,EAAQ1D,EAAiB0D,CAAK,EAAI,EAC7C,EACA,cAAc,SACb,GAAGrC,CAAA,CAAA,CAGhB,CAsBO,SAASuC,EAAwD,CACpE,SAAA3C,EACA,GAAGI,CACP,EAGG,CACC,MAAM8B,EAAe9B,EAAM,MAE3B,OACIe,EAAC9B,EAAA,CACI,GAAGe,EACJ,SAAAJ,EACA,aAAAkC,EACA,kBAAmBC,GAAK,CACpB,MAAMS,EAAO,MAAM,KAAKT,CAAC,EAAE,OAAOE,GAAK,OAAOA,GAAM,QAAQ,EAC5DjC,EAAM,SAASwC,EAAK,OAAS,EAAIA,EAAO,EAAE,CAC9C,EACA,cAAc,WACd,UAAU,4BACV,YAAa,CAACP,EAAGC,EAAGnC,IAAgB,CAEhC,GAAIA,IAAgB,CAACkC,GAAKA,EAAE,SAAW,GACnC,OAAOG,EAAcrC,CAAW,EAGpC,MAAM0C,EAASR,GAAK,CAAA,EACpB,OACIlB,EAAC2B,EAAA,CACG,SAAUC,GAAQ3C,EAAM,SAASyC,EAAO,OAAO3D,GAAS,CAAC6D,EAAK,IAAI7D,CAAK,CAAC,CAAC,EACzE,MAAO2D,EAAO,IAAI3D,GAAS,CAEvB,MAAMuD,EAAQH,GAAG,KAAKI,IAAOA,EAAG1C,CAAQ,GAAK0C,EAAG,MAAQxD,CAAK,EACvD8D,EAAOP,EAAQ1D,EAAiB0D,CAAK,EAAIvD,EAC/C,MAAO,CACH,GAAIA,EACJ,KAAA8D,CAAA,CAER,CAAC,EAEA,YAAQ7B,EAAC8B,EAAA,CAAmB,WAAiBjE,CAAI,GAA/BA,EAAK,EAA4B,CAAA,CAAA,CAGhE,CAAA,CAAA,CAGZ,CAcO,SAASkE,GAAsB,CAClC,WAAAxD,EACA,GAAGU,CACP,EAA4F,CACxF,MAAM+C,EAAQC,EAA+B,CAAE,SAAU1D,EAAY,EACrE,OACIyB,EAACc,EAAA,CACG,kBAAmBkB,EAAM,WACzB,WAAYzD,GAAcyD,EAAM,aAChC,MAAOA,EAAM,MAAM,MACnB,OAAQE,GAAKF,EAAM,WAAA,EACnB,SAAUhB,GAAKgB,EAAM,aAAahB,CAAC,EACnC,UAAW,CAAC,CAACmB,EAAqBH,CAAK,EACvC,aAAcG,EAAqBH,CAAK,EACvC,GAAG/C,CAAA,CAAA,CAGhB,CAcO,SAASmD,GAAwB,CACpC,WAAA7D,EACA,GAAGU,CACP,EAAmF,CAC/E,MAAM+C,EAAQC,EAA0B,CAAE,SAAU1D,EAAY,EAChE,OACIyB,EAACwB,EAAA,CACG,kBAAmBQ,EAAM,WACzB,WAAYzD,GAAcyD,EAAM,aAChC,MAAOA,EAAM,MAAM,MACnB,OAAQE,GAAKF,EAAM,WAAA,EACnB,SAAUhB,GAAKgB,EAAM,aAAahB,CAAC,EACnC,UAAW,CAAC,CAACmB,EAAqBH,CAAK,EACvC,aAAcG,EAAqBH,CAAK,EACvC,GAAG/C,CAAA,CAAA,CAGhB"}
|
|
1
|
+
{"version":3,"file":"id-search.js","sources":["../../lib/components/id-search.tsx"],"sourcesContent":["'use client';\nimport { useQuery } from '@tanstack/react-query';\nimport { useId, useState } from 'react';\nimport { Select as AriaSelect, Autocomplete } from 'react-aria-components';\n\nimport type { ClientPathsWithMethod } from 'openapi-fetch';\nimport { Loader } from '../components/loader';\nimport { Menu, MenuItem } from '../components/menu';\nimport { PopoverTrigger } from '../components/popover';\nimport { SearchField } from '../components/searchfield';\nimport { useCtxClient, type CtxClientType } from '../utilities/ctx-client';\nimport { getEmptyLabel, isEmptyValue, type EmptyOption } from '../utilities/empty-option';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { FormField, type FormFieldProps } from './form';\nimport { SelectPopover, SelectTrigger } from './select';\nimport { Tag, TagGroup } from './tag-group';\n\n/**\n * Minimal resource shape used by the ID search inputs.\n * `id` is required; the label comes from `name` or `displayName`.\n *\n * @example\n * const user: BaseSearchableResource = { id: 'u_123', name: 'Nabeel Farooq' };\n * const product: BaseSearchableResource = { id: 'p_123', displayName: 'My Product' };\n */\ntype BaseSearchableResource = {\n /** Unique identifier used as the input value. */\n id: string;\n /** Human-readable label shown to users. */\n name?: string;\n displayName?: string;\n};\n\n/** Resources commonly expose either `name` or `displayName` as their human-readable label. */\nfunction getResourceLabel(item: BaseSearchableResource): string {\n return item.name ?? item.displayName ?? '';\n}\n\n/**\n * Type guard to check if a value is an array of searchable resources\n */\nfunction isSearchableResourceArray<T extends BaseSearchableResource>(value: unknown): value is T[] {\n return (\n Array.isArray(value) &&\n value.every(item => {\n if (!item || typeof item !== 'object' || !('id' in item) || typeof item.id !== 'string') return false;\n const hasName = 'name' in item && typeof item.name === 'string';\n const hasDisplayName = 'displayName' in item && typeof item.displayName === 'string';\n return hasName || hasDisplayName;\n })\n );\n}\n\n/**\n * - Generic, accessible ID-search building block.\n * - Search (powered by react-query)\n * - Renders an accessible Autocomplete + Menu listbox\n * - Exposes a controlled `value`/`onChange` contract so callers (and wrappers) can manage state\n *\n * @template T - resource type extending `BaseSearchableResource` (must have `id`; label is `name` or `displayName`)\n * @template V - controlled value type (e.g. `string` for single-select or `string[]` for multi-select)\n *\n * @param props - props object (see inline property JSDoc for the most important fields)\n *\n * @remarks\n * - Search is automatically handled based on the `resource` prop using the API client from context\n * - When the popover closes, `onBlur` (if provided) is called with the current `value`.\n * - `renderLabel` must convert `value` to a readable string for the control button.\n * - `defaultParams` can be used to pass additional query parameters to the search endpoint\n *\n * @example\n * <BaseIdSearchInput\n * label=\"Owner\"\n * resource=\"user\"\n * value={ownerId}\n * onChange={setOwnerId}\n * renderLabel={(v, data) => data?.find(d => d.id === v)?.name ?? v}\n * />\n *\n * @testing\n * - Ensure API client is provided via context; assert keyboard navigation, open/close behavior, and `onBlur` call on popover close.\n */\nfunction BaseIdSearchInput<T extends BaseSearchableResource, V>({\n label,\n description,\n errorMessage,\n requiredIndicator,\n isDisabled,\n isInvalid,\n onBlur,\n path,\n onChange,\n value,\n renderLabel,\n accessor,\n getItemLabel,\n defaultParams,\n className,\n emptyOption,\n ...props\n}: FormFieldProps & {\n path: ClientPathsWithMethod<CtxClientType, 'get'>;\n /** Disable interactions. */\n isDisabled?: boolean;\n /** Whether the field is invalid. */\n isInvalid?: boolean;\n /** Key used to access an alternate display accessor on item (kept for compatibility). */\n accessor: keyof BaseSearchableResource;\n getItemLabel?: (item: T) => React.ReactNode;\n /** Controlled value. */\n value: V;\n /** Called when popover closes or the field blurs with the current value. */\n onBlur?: (v: V) => void;\n /** Controlled change handler. */\n onChange: (v: V) => void;\n /** Render a human-readable label for the current value using the latest data. */\n renderLabel: (v: V, data: T[] | undefined, emptyOption?: EmptyOption) => string | React.ReactNode;\n /** Default parameters to include in the request. This is useful when using /v3/users?role='admin' or /v3/organizations/ID/user-groups */\n defaultParams?: Record<'path' | 'query', any>;\n /** Optional className to customize the trigger button styling. */\n className?: string;\n /* Optional empty option to show when value is empty. */\n emptyOption?: EmptyOption;\n} & Omit<React.ComponentProps<typeof Menu>, 'items' | 'className'>) {\n if (path === '/v3/me') {\n throw Error('Path \"/v3/me\" is not supported with IdSearch since it is not a searchable resource.');\n }\n\n const generatedId = useId();\n const fieldId = props.id || generatedId;\n const client = useCtxClient();\n const itemLabel = getItemLabel ?? getResourceLabel;\n // Typeahead/search needs a plain string; fall back to the plain name when the label is a styled ReactNode.\n const itemTextValue = (item: T): string => {\n const label = itemLabel(item);\n return typeof label === 'string' ? label : getResourceLabel(item);\n };\n\n const [search, _setSearch] = useState('');\n const { data, isError, isFetching, error } = useQuery({\n // This is the schema that openapi-react-query follows as of 0.5.1\n queryKey: ['get', path, search],\n queryFn: async (): Promise<T[]> => {\n const result = await client.GET(path, {\n params: {\n query: {\n search,\n ...defaultParams?.query,\n limit: 50,\n page: 1,\n },\n path: {\n ...defaultParams?.path,\n },\n },\n });\n\n // Type narrowing: result.data is inferred as never due to complex union types\n // We use unknown to bypass this and then validate with our type guard\n const responseData: unknown = result.data;\n if (responseData && isSearchableResourceArray<T>(responseData)) {\n return responseData;\n }\n return [];\n },\n });\n\n return (\n <div className=\"group form-field\" data-invalid={isInvalid ? '' : undefined}>\n <FormField {...{ label, description, errorMessage, requiredIndicator, htmlFor: fieldId }}>\n <AriaSelect isInvalid={isInvalid}>\n <PopoverTrigger\n onOpenChange={o => {\n if (!o) {\n // searchInputRef.current?.focus();\n onBlur?.(value);\n }\n }}\n >\n <SelectTrigger id={fieldId} isDisabled={isDisabled} className={className ?? 'w-full'}>\n {renderLabel(value, data, emptyOption)}\n </SelectTrigger>\n <SelectPopover placement=\"bottom start\">\n <Autocomplete inputValue={search} onInputChange={_setSearch}>\n <SearchField className={'p-2'} autoFocus />\n {isFetching && (\n <div className=\"p-input\">\n <Loader className=\"mx-auto\" />\n </div>\n )}\n {!isFetching && !isError && (\n <Menu\n {...props}\n className={'max-h-48'}\n items={data}\n renderEmptyState={() => <div className=\"body-sm p-2\">No results found.</div>}\n >\n {item => {\n const itemId = item[accessor] ?? item.id;\n return (\n <MenuItem key={itemId} id={itemId} textValue={itemTextValue(item)}>\n {itemLabel(item)}\n </MenuItem>\n );\n }}\n </Menu>\n )}\n {isError && <div className=\"text-destructive p-icon body-sm\">{error.message}</div>}\n </Autocomplete>\n </SelectPopover>\n </PopoverTrigger>\n </AriaSelect>\n </FormField>\n </div>\n );\n}\n\n/**\n * Single-selection ID search input.\n *\n * Thin, typed wrapper around `BaseIdSearchInput` specialized for the very common single-ID case.\n * Adapts the internal selection events into `onChange(id?: string)` and renders the selected label.\n *\n * @template T - resource type (extends BaseSearchableResource)\n *\n * @param props - Inherits `BaseIdSearchInput` props but uses `string[]` value type.\n *\n * @example\n * <SingleIdSearchInput\n * label=\"Reporter\"\n * value={reporterId}\n * onChange={setReporterId}\n * />\n *\n */\nexport function SingleIdSearchInput<T extends BaseSearchableResource>({\n accessor,\n getItemLabel,\n ...props\n}: Omit<\n React.ComponentProps<typeof BaseIdSearchInput<T, string | null>>,\n 'onSelectionChange' | 'selectionMode' | 'selectedKeys' | 'renderLabel'\n>) {\n const selectedKeys = props.value ? [props.value] : [];\n const itemLabel = getItemLabel ?? getResourceLabel;\n\n return (\n <BaseIdSearchInput\n accessor={accessor}\n getItemLabel={getItemLabel}\n selectedKeys={selectedKeys}\n onSelectionChange={e => {\n const val = Array.from(e).filter(v => typeof v === 'string')[0];\n props.onChange(val);\n }}\n renderLabel={(v, d, emptyOption) => {\n // If value is empty and emptyOption is set, show the empty label\n if (emptyOption && isEmptyValue(v)) {\n return getEmptyLabel(emptyOption);\n }\n // Match on the same field the value was derived from (accessor), not always `id`.\n const match = d?.find(di => (di[accessor] ?? di.id) === v);\n return match ? itemLabel(match) : '';\n }}\n selectionMode=\"single\"\n {...props}\n />\n );\n}\n\n/**\n * Multi-selection ID search input.\n *\n * Thin wrapper around `BaseIdSearchInput` for the multiple-ID (`string[]`) case.\n * Adapts internal selection events into `onChange(ids: string[])`.\n *\n * @template T - resource type (extends BaseSearchableResource)\n *\n * @param props - Inherits `BaseIdSearchInput` props but uses `string[]` value type.\n *\n * @example\n * <MultipleIdSearchInput\n * label=\"Reviewers\"\n * value={reviewerIds}\n * onChange={setReviewerIds}\n * />\n *\n * @remarks\n * - The `renderLabel` joins selected item names with commas for compact display.\n */\nexport function MultipleIdSearchInput<T extends BaseSearchableResource>({\n accessor,\n getItemLabel,\n ...props\n}: Omit<\n React.ComponentProps<typeof BaseIdSearchInput<T, string[]>>,\n 'renderLabel' | 'onSelectionChange' | 'selectionMode' | 'selectedKeys'\n>) {\n const selectedKeys = props.value;\n const itemLabel = getItemLabel ?? getResourceLabel;\n\n return (\n <BaseIdSearchInput\n {...props}\n accessor={accessor}\n getItemLabel={getItemLabel}\n selectedKeys={selectedKeys}\n onSelectionChange={e => {\n const vals = Array.from(e).filter(v => typeof v === 'string');\n props.onChange(vals.length > 0 ? vals : []);\n }}\n selectionMode=\"multiple\"\n className=\"w-full h-auto items-start\"\n renderLabel={(v, d, emptyOption) => {\n // If array is empty and emptyOption is set, show the empty label\n if (emptyOption && (!v || v.length === 0)) {\n return getEmptyLabel(emptyOption);\n }\n\n const values = v ?? [];\n return (\n <TagGroup\n onRemove={keys => props.onChange(values.filter(value => !keys.has(value)))}\n items={values.map(value => {\n // Match on the same field the value was derived from (accessor), not always `id`.\n const match = d?.find(di => (di[accessor] ?? di.id) === value);\n const name = match ? itemLabel(match) : value;\n const textValue = typeof name === 'string' ? name : match ? getResourceLabel(match) : value;\n return {\n id: value,\n name,\n textValue,\n };\n })}\n >\n {item => (\n <Tag key={item.id} textValue={item.textValue}>\n {item.name}\n </Tag>\n )}\n </TagGroup>\n );\n }}\n />\n );\n}\n\n/**\n * Form-integrated single-select ID input (field wrapper).\n *\n * Integrates `SingleIdSearchInput` into the form system using `useFieldContext`.\n * - wires `value`, `onChange`, and `onBlur`\n * - disables the control while the form is submitting\n * - surfaces field-level error messages\n *\n * @example\n * <TfSingleIdSearchInput name=\"ownerId\" label=\"Owner\" />\n \n */\nexport function TfSingleIdSearchInput({\n isDisabled,\n ...props\n}: Omit<React.ComponentProps<typeof SingleIdSearchInput>, 'value' | 'onChange' | 'onBlur'>) {\n const field = useFieldContext<string | null>({ disabled: isDisabled });\n return (\n <SingleIdSearchInput\n requiredIndicator={field.isRequired}\n isDisabled={isDisabled || field.isSubmitting}\n value={field.state.value}\n onBlur={_ => field.handleBlur()}\n onChange={e => field.handleChange(e)}\n isInvalid={!!getFieldErrorMessage(field)}\n errorMessage={getFieldErrorMessage(field)}\n {...props}\n />\n );\n}\n\n/**\n * Form-integrated multi-select ID input (field wrapper).\n *\n * Integrates `MultipleIdSearchInput` into the form system using `useFieldContext`.\n * - wires `value`, `onChange`, and `onBlur`\n * - disables the control while the form is submitting\n * - surfaces field-level error messages\n *\n * @example\n * <TfMultipleIdSearchInput name=\"reviewerIds\" label=\"Reviewers\" />\n *\n */\nexport function TfMultipleIdSearchInput({\n isDisabled,\n ...props\n}: Omit<React.ComponentProps<typeof MultipleIdSearchInput>, 'value' | 'onChange'>) {\n const field = useFieldContext<string[]>({ disabled: isDisabled });\n return (\n <MultipleIdSearchInput\n requiredIndicator={field.isRequired}\n isDisabled={isDisabled || field.isSubmitting}\n value={field.state.value}\n onBlur={_ => field.handleBlur()}\n onChange={e => field.handleChange(e)}\n isInvalid={!!getFieldErrorMessage(field)}\n errorMessage={getFieldErrorMessage(field)}\n {...props}\n />\n );\n}\n"],"names":["getResourceLabel","item","isSearchableResourceArray","value","hasName","hasDisplayName","BaseIdSearchInput","label","description","errorMessage","requiredIndicator","isDisabled","isInvalid","onBlur","path","onChange","renderLabel","accessor","getItemLabel","defaultParams","className","emptyOption","props","generatedId","useId","fieldId","client","useCtxClient","itemLabel","itemTextValue","search","_setSearch","useState","data","isError","isFetching","error","useQuery","responseData","jsx","FormField","AriaSelect","jsxs","PopoverTrigger","o","SelectTrigger","SelectPopover","Autocomplete","SearchField","Loader","Menu","itemId","MenuItem","SingleIdSearchInput","selectedKeys","e","val","v","d","isEmptyValue","getEmptyLabel","match","di","MultipleIdSearchInput","vals","values","TagGroup","keys","name","textValue","Tag","TfSingleIdSearchInput","field","useFieldContext","_","getFieldErrorMessage","TfMultipleIdSearchInput"],"mappings":"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"}
|