@osdk/react-components 0.9.0 → 0.10.0-main-eb36e21c26aae079311e4a93d4a0ccce8be03d3f
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.
- package/CHANGELOG.md +15 -0
- package/README.md +23 -0
- package/build/browser/action-form/FormFieldApi.js +8 -0
- package/build/browser/action-form/FormFieldApi.js.map +1 -1
- package/build/browser/action-form/fields/AsyncDropdownField.js +81 -0
- package/build/browser/action-form/fields/AsyncDropdownField.js.map +1 -0
- package/build/browser/action-form/fields/AsyncDropdownField.module.css +31 -0
- package/build/browser/action-form/fields/AsyncDropdownField.module.css.js +8 -0
- package/build/browser/action-form/fields/DropdownField.js +29 -14
- package/build/browser/action-form/fields/DropdownField.js.map +1 -1
- package/build/browser/action-form/fields/FormFieldRenderer.js +17 -0
- package/build/browser/action-form/fields/FormFieldRenderer.js.map +1 -1
- package/build/browser/action-form/fields/ObjectSelectField.js +109 -0
- package/build/browser/action-form/fields/ObjectSelectField.js.map +1 -0
- package/build/browser/action-form/utils/getDefaultFieldDefinitions.js +14 -5
- package/build/browser/action-form/utils/getDefaultFieldDefinitions.js.map +1 -1
- package/build/browser/base-components/combobox/Combobox.module.css +23 -2
- package/build/browser/base-components/combobox/Combobox.module.css.js +3 -3
- package/build/browser/filter-list/base/inputs/TextTagsInput.js.map +1 -1
- package/build/browser/shared/hooks/useDebouncedValue.js +35 -0
- package/build/browser/shared/hooks/useDebouncedValue.js.map +1 -0
- package/build/browser/shared/hooks/useEventCallback.js +44 -0
- package/build/browser/shared/hooks/useEventCallback.js.map +1 -0
- package/build/browser/shared/hooks/useInfiniteScroll.js +81 -0
- package/build/browser/shared/hooks/useInfiniteScroll.js.map +1 -0
- package/build/browser/styles.css +73 -2
- package/build/browser/tokens/component-tokens/async-dropdown.css +16 -0
- package/build/browser/tokens.css +1 -0
- package/build/browser/util/UserAgent.js +1 -1
- package/build/browser/util/UserAgent.js.map +1 -1
- package/build/cjs/{chunk-UEY63J2G.cjs → chunk-BVPT34HG.cjs} +9 -9
- package/build/cjs/{chunk-UEY63J2G.cjs.map → chunk-BVPT34HG.cjs.map} +1 -1
- package/build/cjs/{chunk-OXP3XQE4.cjs → chunk-ELKHVDAC.cjs} +47 -47
- package/build/cjs/{chunk-OXP3XQE4.cjs.map → chunk-ELKHVDAC.cjs.map} +1 -1
- package/build/cjs/{chunk-SHTQGKS5.cjs → chunk-KDYLHFR2.cjs} +4 -4
- package/build/cjs/{chunk-SHTQGKS5.cjs.map → chunk-KDYLHFR2.cjs.map} +1 -1
- package/build/cjs/{chunk-RY2GVYT2.cjs → chunk-MVNWOKH2.cjs} +49 -36
- package/build/cjs/chunk-MVNWOKH2.cjs.map +1 -0
- package/build/cjs/{chunk-O5ZAMFDU.cjs → chunk-SLVTPIGM.cjs} +468 -207
- package/build/cjs/chunk-SLVTPIGM.cjs.map +1 -0
- package/build/cjs/{chunk-2FPKTOPE.cjs → chunk-XBXC6VAS.cjs} +2 -2
- package/build/cjs/{chunk-2FPKTOPE.cjs.map → chunk-XBXC6VAS.cjs.map} +1 -1
- package/build/cjs/{chunk-EEES66LS.cjs → chunk-XPXTCNK6.cjs} +3 -3
- package/build/cjs/chunk-XPXTCNK6.cjs.map +1 -0
- package/build/cjs/public/experimental/action-form.cjs +6 -6
- package/build/cjs/public/experimental/action-form.css +24 -1
- package/build/cjs/public/experimental/action-form.css.map +1 -1
- package/build/cjs/public/experimental/action-form.d.cts +48 -3
- package/build/cjs/public/experimental/filter-list.cjs +7 -7
- package/build/cjs/public/experimental/filter-list.css +9 -1
- package/build/cjs/public/experimental/filter-list.css.map +1 -1
- package/build/cjs/public/experimental/object-table.cjs +10 -10
- package/build/cjs/public/experimental/object-table.css +9 -1
- package/build/cjs/public/experimental/object-table.css.map +1 -1
- package/build/cjs/public/experimental/pdf-viewer.cjs +24 -24
- package/build/cjs/public/experimental.cjs +41 -41
- package/build/cjs/public/experimental.css +24 -1
- package/build/cjs/public/experimental.css.map +1 -1
- package/build/esm/action-form/FormFieldApi.js +8 -0
- package/build/esm/action-form/FormFieldApi.js.map +1 -1
- package/build/esm/action-form/fields/AsyncDropdownField.js +81 -0
- package/build/esm/action-form/fields/AsyncDropdownField.js.map +1 -0
- package/build/esm/action-form/fields/AsyncDropdownField.module.css +31 -0
- package/build/esm/action-form/fields/DropdownField.js +29 -14
- package/build/esm/action-form/fields/DropdownField.js.map +1 -1
- package/build/esm/action-form/fields/FormFieldRenderer.js +17 -0
- package/build/esm/action-form/fields/FormFieldRenderer.js.map +1 -1
- package/build/esm/action-form/fields/ObjectSelectField.js +109 -0
- package/build/esm/action-form/fields/ObjectSelectField.js.map +1 -0
- package/build/esm/action-form/utils/getDefaultFieldDefinitions.js +14 -5
- package/build/esm/action-form/utils/getDefaultFieldDefinitions.js.map +1 -1
- package/build/esm/base-components/combobox/Combobox.module.css +23 -2
- package/build/esm/filter-list/base/inputs/TextTagsInput.js.map +1 -1
- package/build/esm/shared/hooks/useDebouncedValue.js +35 -0
- package/build/esm/shared/hooks/useDebouncedValue.js.map +1 -0
- package/build/esm/shared/hooks/useEventCallback.js +44 -0
- package/build/esm/shared/hooks/useEventCallback.js.map +1 -0
- package/build/esm/shared/hooks/useInfiniteScroll.js +81 -0
- package/build/esm/shared/hooks/useInfiniteScroll.js.map +1 -0
- package/build/esm/tokens/component-tokens/async-dropdown.css +16 -0
- package/build/esm/tokens.css +1 -0
- package/build/esm/util/UserAgent.js +1 -1
- package/build/esm/util/UserAgent.js.map +1 -1
- package/build/types/action-form/FormFieldApi.d.ts +48 -3
- package/build/types/action-form/FormFieldApi.d.ts.map +1 -1
- package/build/types/action-form/fields/AsyncDropdownField.d.ts +25 -0
- package/build/types/action-form/fields/AsyncDropdownField.d.ts.map +1 -0
- package/build/types/action-form/fields/DropdownField.d.ts +2 -2
- package/build/types/action-form/fields/DropdownField.d.ts.map +1 -1
- package/build/types/action-form/fields/FormFieldRenderer.d.ts.map +1 -1
- package/build/types/action-form/fields/ObjectSelectField.d.ts +3 -0
- package/build/types/action-form/fields/ObjectSelectField.d.ts.map +1 -0
- package/build/types/shared/hooks/useDebouncedValue.d.ts +5 -0
- package/build/types/shared/hooks/useDebouncedValue.d.ts.map +1 -0
- package/build/types/shared/hooks/useEventCallback.d.ts +13 -0
- package/build/types/shared/hooks/useEventCallback.d.ts.map +1 -0
- package/build/types/shared/hooks/useInfiniteScroll.d.ts +19 -0
- package/build/types/shared/hooks/useInfiniteScroll.d.ts.map +1 -0
- package/package.json +9 -9
- package/build/cjs/chunk-EEES66LS.cjs.map +0 -1
- package/build/cjs/chunk-O5ZAMFDU.cjs.map +0 -1
- package/build/cjs/chunk-RY2GVYT2.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @osdk/react-components
|
|
2
2
|
|
|
3
|
+
## 0.10.0-main-eb36e21c26aae079311e4a93d4a0ccce8be03d3f
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 3a4528c: Add ObjectSelect field for selecting object instances in action forms
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- b355bc3: Add CONTRIBUTING.md for @osdk/react and @osdk/react-components
|
|
12
|
+
- Updated dependencies [eb36e21]
|
|
13
|
+
- Updated dependencies [b355bc3]
|
|
14
|
+
- @osdk/client@2.13.1-main-eb36e21c26aae079311e4a93d4a0ccce8be03d3f
|
|
15
|
+
- @osdk/react@0.16.1-main-eb36e21c26aae079311e4a93d4a0ccce8be03d3f
|
|
16
|
+
- @osdk/api@2.13.1-main-eb36e21c26aae079311e4a93d4a0ccce8be03d3f
|
|
17
|
+
|
|
3
18
|
## 0.9.0
|
|
4
19
|
|
|
5
20
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -6,6 +6,25 @@ React components for building Foundry applications. These components are Ontolog
|
|
|
6
6
|
|
|
7
7
|
Built on top of [@osdk/react](../react), these components use OSDK hooks internally to provide ready-to-use UI elements. While @osdk/react gives you low-level hooks for data fetching, @osdk/react-components provides UI widgets for common patterns like tables and forms.
|
|
8
8
|
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [Installation](#installation)
|
|
12
|
+
- [Setup](#setup)
|
|
13
|
+
- [App Setup](#app-setup)
|
|
14
|
+
- [CSS Setup](#css-setup)
|
|
15
|
+
- [Components](#components)
|
|
16
|
+
- [Component Architecture](#component-architecture)
|
|
17
|
+
- [Core layers](#core-layers-all-components)
|
|
18
|
+
- [Building blocks](#building-blocks-select-components)
|
|
19
|
+
- [Folder Structure](#folder-structure)
|
|
20
|
+
- [Custom Styling](#custom-styling)
|
|
21
|
+
- [Example Usage](#example-usage)
|
|
22
|
+
- [Contributing](#contributing)
|
|
23
|
+
- [Development Workflow](#development-workflow)
|
|
24
|
+
- [Why this package?](#why-this-package)
|
|
25
|
+
- [What this package is (and isn't)](#what-this-package-is-and-isnt)
|
|
26
|
+
- [License](#license)
|
|
27
|
+
|
|
9
28
|
## Installation
|
|
10
29
|
|
|
11
30
|
Run the command to install:
|
|
@@ -267,6 +286,10 @@ function EmployeeDirectory() {
|
|
|
267
286
|
}
|
|
268
287
|
```
|
|
269
288
|
|
|
289
|
+
## Contributing
|
|
290
|
+
|
|
291
|
+
Looking to contribute to the codebase? Read the [contribution guidelines](./CONTRIBUTING.md)
|
|
292
|
+
|
|
270
293
|
## Development Workflow
|
|
271
294
|
|
|
272
295
|
1. In packages/react-components, run `pnpm install` to install the dependencies.
|
|
@@ -72,6 +72,14 @@ export const EMPTY_RANGE = [null, null];
|
|
|
72
72
|
* Object set field displays the summary of the count of the given object set
|
|
73
73
|
*/
|
|
74
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Object select field props for selecting object instances from the ontology.
|
|
77
|
+
* Used for action parameters that accept a single object or multiple objects.
|
|
78
|
+
*
|
|
79
|
+
* Extends DropdownFieldProps with props that ObjectSelectField
|
|
80
|
+
* manages internally (items, search, filtering) omitted from the public surface.
|
|
81
|
+
*/
|
|
82
|
+
|
|
75
83
|
/**
|
|
76
84
|
* Custom field props for user-defined renderers
|
|
77
85
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormFieldApi.js","names":["EMPTY_RANGE"],"sources":["FormFieldApi.ts"],"sourcesContent":["/*\n * Copyright 2026 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n ActionDefinition,\n ActionMetadata,\n ActionParam,\n CompileTimeMetadata,\n DataValueClientToWire,\n ObjectSet,\n ObjectTypeDefinition,\n} from \"@osdk/api\";\nimport type React from \"react\";\n\n/**\n * A form field definition specifies configuration for a single field\n */\nexport interface FormFieldDefinition<\n Q extends ActionDefinition<unknown>,\n K extends FieldKey<Q> = FieldKey<Q>,\n> {\n /**\n * The field's unique key\n */\n fieldKey: K;\n\n /**\n * Display label for the field\n */\n label: string;\n\n /**\n * Default value of the field\n */\n defaultValue?: FieldValueType<Q, K>;\n\n /**\n * The form field component type to render\n */\n fieldComponent: ValidFormFieldForPropertyType<FieldDescriptorType<Q, K>>;\n\n /**\n * Whether the field is required\n */\n isRequired?: boolean;\n\n /**\n * Placeholder text\n */\n placeholder?: string;\n\n /**\n * Additional information to display on this field\n * The placement of helper text depends on the value of helperTextPlacement prop\n */\n helperText?: string;\n\n /**\n * The placement of the helper text either below the field or in a tooltip\n *\n * @default \"tooltip\"\n */\n helperTextPlacement?: \"bottom\" | \"tooltip\";\n\n /**\n * Whether the field is disabled\n */\n isDisabled?: boolean;\n\n /**\n * A callback to customize error messages when a built-in validation rule fails.\n * Receives a discriminated union with the constraint data (e.g., the min value\n * that was exceeded) so the message can reference the threshold.\n *\n * Return a string to override the default message, or `undefined` to keep it.\n */\n onValidationError?: (error: ValidationError) => string | undefined;\n\n /**\n * Additional function to validate the field.\n *\n * Return `undefined` if valid, or an error message string if invalid.\n */\n validate?: (value: FieldValueType<Q, K>) => Promise<string | undefined>;\n\n /**\n * The component props for the form field.\n * Excludes runtime props (value, onChange) which are managed by ActionForm.\n */\n fieldComponentProps: Omit<\n FormFieldPropsByType[\n ValidFormFieldForPropertyType<\n FieldDescriptorType<Q, K>\n >\n ],\n FormManagedProps<\n ValidFormFieldForPropertyType<FieldDescriptorType<Q, K>>\n >\n >;\n}\n\n/**\n * A discriminated union describing which validation rule failed and the\n * constraint data the user needs to build a meaningful error message.\n */\nexport type ValidationError =\n | { type: \"required\" }\n | { type: \"min\"; min: number | Date }\n | { type: \"max\"; max: number | Date }\n | { type: \"minLength\"; minLength: number }\n | { type: \"maxLength\"; maxLength: number }\n | { type: \"maxSize\"; maxSize: number }\n | { type: \"validate\"; message: string };\n\n/**\n * Maps field types to their corresponding props\n */\nexport interface FormFieldPropsByType {\n DATE_RANGE_INPUT: DateRangeInputFieldProps;\n DATETIME_PICKER: DatetimePickerFieldProps;\n DROPDOWN: DropdownFieldProps<unknown, boolean>;\n FILE_PICKER: FilePickerProps;\n NUMBER_INPUT: NumberInputFieldProps;\n OBJECT_SET: ObjectSetFieldProps<ObjectTypeDefinition>;\n RADIO_BUTTONS: RadioButtonsFieldProps<unknown>;\n TEXT_AREA: TextAreaFieldProps;\n TEXT_INPUT: TextInputFieldProps;\n CUSTOM: CustomFieldProps<unknown>;\n}\n\n/**\n * Datetime picker field props.\n *\n * When `formatDate` is omitted, ISO-like format is used (YYYY-MM-DD / YYYY-MM-DD HH:mm).\n */\nexport interface DatetimePickerFieldProps extends BaseFormFieldProps<Date> {\n /**\n * The earliest date the user can select.\n * If provided, this will be added to the field validation.\n */\n min?: Date;\n\n /**\n * The latest date the user can select.\n * If provided, this will be added to the field validation.\n */\n max?: Date;\n\n /**\n * Whether to show time picker.\n */\n showTime?: boolean;\n\n /**\n * Whether to close the popover after selecting a date.\n * @default true when `showTime` is false, false when `showTime` is true\n */\n closeOnSelection?: boolean;\n\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n\n /**\n * Formats a Date for display in the input field when not editing.\n * When typing, the input shows the parsable format (YYYY-MM-DD or YYYY-MM-DD HH:mm).\n * Provide a matching `parseDate` if using a custom format.\n */\n formatDate?: (date: Date) => string;\n\n /**\n * Parses a user-typed string back into a Date.\n * Must be the inverse of `formatDate` — if `formatDate(d)` produces string `s`,\n * then `parseDate(s)` must return an equivalent Date.\n * When omitted, defaults to parsing \"YYYY-MM-DD\" (date-only) or \"YYYY-MM-DD HH:mm\" (with time).\n */\n parseDate?: (text: string) => Date | undefined;\n\n /**\n * Ref forwarded to the portal container element.\n * Used to track portaled content for click-outside detection.\n */\n portalRef?: React.Ref<HTMLDivElement>;\n}\n\n/**\n * A date range represented as a start/end tuple.\n * Either element may be `null` when the range is partially selected.\n */\nexport type DateRange = readonly [Date | null, Date | null];\n\n/** Default empty range — both bounds are null. */\nexport const EMPTY_RANGE: DateRange = [null, null];\n\n/**\n * Date range input field props.\n *\n * Renders two text inputs (start / end) with a shared calendar popover\n * that supports range selection.\n */\nexport interface DateRangeInputFieldProps\n extends BaseFormFieldProps<DateRange>\n{\n /** The earliest selectable date. */\n min?: Date;\n\n /** The latest selectable date. */\n max?: Date;\n\n /** Whether to show time pickers for both dates. */\n showTime?: boolean;\n\n /** Placeholder text for the start date input. */\n placeholderStart?: string;\n\n /** Placeholder text for the end date input. */\n placeholderEnd?: string;\n\n /** Whether to allow start and end on the same day. @default true */\n allowSingleDayRange?: boolean;\n\n /** Formats a Date for display. Defaults to \"YYYY-MM-DD\". */\n formatDate?: (date: Date) => string;\n\n /** Parses a user-typed string back into a Date. */\n parseDate?: (text: string) => Date | undefined;\n}\n\n/**\n * Dropdown field props with selectable items\n */\nexport interface DropdownFieldProps<V, Multiple extends boolean = false>\n extends BaseFormFieldProps<Multiple extends true ? V[] : V>\n{\n /**\n * Available items for the dropdown\n */\n items: V[];\n\n /**\n * Converts an item to a display string. Defaults to `String()`.\n */\n itemToStringLabel?: (item: V) => string;\n\n /**\n * Returns a unique string key for a list item. Used as the React `key`.\n * Falls back to the item's index when not provided.\n */\n itemToKey?: (item: V) => string;\n\n /**\n * Custom equality check for item values. Defaults to `Object.is`.\n * Required when items are objects to ensure correct selection matching.\n */\n isItemEqual?: (a: V, b: V) => boolean;\n\n /**\n * Whether the dropdown allows searching/filtering.\n * When true, renders a Combobox with a search input.\n * When false (default), renders a Select dropdown.\n */\n isSearchable?: boolean;\n\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n\n /**\n * Whether multiple values can be selected\n */\n isMultiple?: Multiple;\n\n /**\n * Ref forwarded to the portal container element.\n * Used to track portaled content for click-outside detection.\n */\n portalRef?: React.Ref<HTMLDivElement>;\n}\n\nexport interface FilePickerProps extends BaseFormFieldProps<File | File[]> {\n /**\n * Whether multiple files can be selected\n */\n isMulti?: boolean;\n\n /**\n * Accepted file types (e.g., \"image/*\", \".pdf\")\n */\n accept?: string | string[];\n\n /**\n * Maximum file size in bytes\n */\n maxSize?: number;\n\n /**\n * The text displayed when no file is selected.\n *\n * @default \"No file chosen\"\n */\n text?: string;\n\n /**\n * The text displayed on the browse button.\n *\n * @default \"Browse\"\n */\n buttonText?: string;\n}\n\n/**\n * Text area field props\n */\nexport interface TextAreaFieldProps extends\n BaseFormFieldProps<string>,\n Pick<\n React.TextareaHTMLAttributes<HTMLTextAreaElement>,\n | \"rows\"\n | \"wrap\"\n /**\n * If provided, this will be added to the field validation\n */\n | \"minLength\"\n /**\n * If provided, this will be added to the field validation\n */\n | \"maxLength\"\n >\n{\n placeholder?: string;\n}\n\nexport interface TextInputFieldProps extends\n BaseFormFieldProps<string>,\n Pick<\n React.InputHTMLAttributes<HTMLInputElement>,\n /**\n * If provided, this will be added to the field validation\n */\n | \"minLength\"\n /**\n * If provided, this will be added to the field validation\n */\n | \"maxLength\"\n >\n{\n placeholder?: string;\n}\n\n/**\n * Number input field props\n */\nexport interface NumberInputFieldProps extends BaseFormFieldProps<number> {\n /**\n * Minimum allowed value.\n */\n min?: number;\n\n /**\n * Maximum allowed value.\n */\n max?: number;\n\n /**\n * Step increment for the input. Used by the stepper buttons and ArrowUp/ArrowDown keyboard stepping.\n *\n * @default 1\n */\n step?: number;\n\n /**\n * Placeholder text shown when the input is empty.\n */\n placeholder?: string;\n}\n\n/**\n * Radio buttons field props\n */\nexport interface RadioButtonsFieldProps<V> extends BaseFormFieldProps<V> {\n /**\n * Available options for radio buttons.\n *\n * Values are compared by reference equality (`===`). When options contain\n * non-primitive values, pass the same object references for `value` and\n * the corresponding option entry.\n */\n options: Option<V>[];\n\n /**\n * Controls the layout direction of the radio buttons.\n *\n * - `\"vertical\"` (default): options are stacked in a column\n * - `\"horizontal\"`: options are laid out in a row, wrapping when needed\n */\n orientation?: \"horizontal\" | \"vertical\";\n}\n\n/**\n * Option interface for radio button options\n */\nexport interface Option<V> {\n label: string;\n value: V;\n}\n\n/**\n * Object set field displays the summary of the count of the given object set\n */\nexport interface ObjectSetFieldProps<T extends ObjectTypeDefinition>\n extends Pick<BaseFormFieldProps<ObjectSet<T>>, \"id\" | \"value\">\n{\n /**\n * Message displayed when no object set is provided.\n *\n * @default \"Object set is not defined\"\n */\n emptyMessage?: string;\n}\n\n/**\n * Custom field props for user-defined renderers\n */\nexport interface CustomFieldProps<V> extends BaseFormFieldProps<V> {\n /**\n * Custom renderer function\n */\n customRenderer: (props: BaseFormFieldProps<V>) => React.ReactNode;\n}\n\nexport interface BaseFormFieldProps<V> {\n /**\n * The HTML `id` attribute for the field input element.\n * Used for `<label htmlFor>` association.\n */\n id?: string;\n\n /**\n * The validation error message for this field, if any.\n * When set, the field should display a visual error state.\n */\n error?: string;\n\n /**\n * The value of the form field\n */\n value: V | null;\n\n /**\n * The default value of the form field.\n */\n defaultValue?: V;\n\n /**\n * Called when the field value changes.\n *\n * ActionForm internally wraps this to pass the key to `onFieldValueChange`:\n * ```\n * <DropdownField\n * {...fieldDef}\n * onChange={(value) => onFieldValueChange(fieldDef.key, value)}\n * />\n * ```\n *\n * @param value The new value of the form field\n */\n onChange?: (value: V | null) => void;\n}\n\nexport type FieldKey<Q extends ActionDefinition<unknown>> =\n keyof ActionParameters<Q>;\n\n/**\n * Extracts parameters from an ActionDefinition\n */\nexport type ActionParameters<Q extends ActionDefinition<unknown>> =\n CompileTimeMetadata<Q>[\"parameters\"];\n\n/**\n * Extracts the value type for a specific parameter\n *\n * TODO: Re-use `BaseType`\n */\nexport type FieldValueType<\n Q extends ActionDefinition<unknown>,\n K extends keyof ActionParameters<Q> = keyof ActionParameters<Q>,\n> = ActionParameters<Q>[K][\"type\"] extends\n ActionMetadata.DataType.Object<infer T> ? ActionParam.ObjectType<T>\n : ActionParameters<Q>[K][\"type\"] extends ActionMetadata.DataType.ObjectSet<\n infer T\n > ? ActionParam.ObjectSetType<T>\n : ActionParameters<Q>[K][\"type\"] extends ActionMetadata.DataType.Struct<\n infer T\n > ? ActionParam.StructType<T>\n : ActionParameters<Q>[K][\"type\"] extends keyof DataValueClientToWire\n ? DataValueClientToWire[ActionParameters<Q>[K][\"type\"]]\n : never;\n\n/**\n * Extracts the parameter type descriptor for a specific action parameter.\n */\nexport type FieldDescriptorType<\n Q extends ActionDefinition<unknown> = ActionDefinition<unknown>,\n K extends keyof ActionParameters<Q> = keyof ActionParameters<Q>,\n> = ActionParameters<Q>[K][\"type\"];\n\n/**\n * Available form field component types\n */\nexport type FieldComponent =\n | \"DATE_RANGE_INPUT\"\n | \"DATETIME_PICKER\"\n | \"DROPDOWN\"\n | \"FILE_PICKER\"\n | \"NUMBER_INPUT\"\n | \"RADIO_BUTTONS\"\n | \"OBJECT_SET\"\n | \"TEXT_AREA\"\n | \"TEXT_INPUT\"\n | \"CUSTOM\";\n\n/**\n * Describes the data type of a form field, independent of OSDK.\n * Mirrors ActionMetadata.DataType to keep the rendering layer OSDK-agnostic.\n */\nexport type FieldType =\n | \"boolean\"\n | \"string\"\n | \"integer\"\n | \"long\"\n | \"double\"\n | \"datetime\"\n | \"timestamp\"\n | \"attachment\"\n | \"marking\"\n | \"mediaReference\"\n | \"objectType\"\n | \"geoshape\"\n | \"geohash\"\n | { type: \"object\"; object: string }\n | { type: \"objectSet\"; objectSet: string }\n | { type: \"interface\"; interface: string }\n | { type: \"struct\"; struct: Record<string, string> };\n\n/**\n * Props managed by form state infrastructure (FieldBridge / RHF).\n * Fields with onChange participate in form state → value and onChange are managed\n * externally. Read-only fields (no onChange, e.g. ObjectSetField) keep value in\n * fieldComponentProps so it bypasses form state cloning.\n */\ntype FormManagedProps<K extends FieldComponent> = \"onChange\" extends\n keyof FormFieldPropsByType[K] ? \"value\" | \"onChange\"\n : \"onChange\";\n\n/**\n * An OSDK-agnostic field definition used by BaseForm and FormFieldRenderer.\n * Contains only the information needed to render a single field — no generics,\n * no compile-time parameter constraints.\n *\n * Implemented as a distributed mapped type: switching on `fieldComponent`\n * narrows `fieldComponentProps` to the correct props type automatically.\n */\nexport type RendererFieldDefinition = {\n [K in FieldComponent]: {\n fieldKey: string;\n fieldComponent: K;\n fieldType?: FieldType;\n label: string;\n isRequired?: boolean;\n placeholder?: string;\n helperText?: string;\n helperTextPlacement?: \"bottom\" | \"tooltip\";\n validate?: (value: unknown) => Promise<string | undefined>;\n onValidationError?: (error: ValidationError) => string | undefined;\n fieldComponentProps: Omit<FormFieldPropsByType[K], FormManagedProps<K>>;\n };\n}[FieldComponent];\n\n/**\n * Gets valid form field types for a given property type\n */\nexport type ValidFormFieldForPropertyType<P extends FieldDescriptorType> =\n P extends \"objectSet\" ? \"OBJECT_SET\"\n : P extends \"object\" ? \"DROPDOWN\"\n : P extends \"mediaReference\" | \"attachment\" ? \"FILE_PICKER\"\n : P extends \"boolean\" ? \"RADIO_BUTTONS\" | \"DROPDOWN\"\n : P extends \"string\" ? \"TEXT_INPUT\" | \"TEXT_AREA\"\n : P extends \"datetime\" | \"timestamp\" ? \"DATETIME_PICKER\"\n : P extends\n | \"double\"\n | \"integer\"\n | \"long\"\n | \"float\"\n | \"short\"\n | \"byte\"\n | \"decimal\" ? \"NUMBER_INPUT\"\n : never;\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAaA;AACA;AACA;;AAqFA;AACA;AACA;AACA;;AAUA;AACA;AACA;;AAcA;AACA;AACA;AACA;AACA;;AAoDA;AACA;AACA;AACA;;AAGA;AACA,OAAO,MAAMA,WAAsB,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC;;AAElD;AACA;AACA;AACA;AACA;AACA;;AA6BA;AACA;AACA;;AAiFA;AACA;AACA;;AAqCA;AACA;AACA;;AAyBA;AACA;AACA;;AAoBA;AACA;AACA;;AAMA;AACA;AACA;;AAYA;AACA;AACA;;AAkDA;AACA;AACA;;AAIA;AACA;AACA;AACA;AACA;;AAgBA;AACA;AACA;;AAMA;AACA;AACA;;AAaA;AACA;AACA;AACA;;AAoBA;AACA;AACA;AACA;AACA;AACA;;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAiBA;AACA;AACA","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"FormFieldApi.js","names":["EMPTY_RANGE"],"sources":["FormFieldApi.ts"],"sourcesContent":["/*\n * Copyright 2026 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n ActionDefinition,\n ActionMetadata,\n ActionParam,\n CompileTimeMetadata,\n DataValueClientToWire,\n ObjectSet,\n ObjectTypeDefinition,\n Osdk,\n} from \"@osdk/api\";\nimport type React from \"react\";\n\n/**\n * A form field definition specifies configuration for a single field\n */\nexport interface FormFieldDefinition<\n Q extends ActionDefinition<unknown>,\n K extends FieldKey<Q> = FieldKey<Q>,\n> {\n /**\n * The field's unique key\n */\n fieldKey: K;\n\n /**\n * Display label for the field\n */\n label: string;\n\n /**\n * Default value of the field\n */\n defaultValue?: FieldValueType<Q, K>;\n\n /**\n * The form field component type to render\n */\n fieldComponent: ValidFormFieldForPropertyType<FieldDescriptorType<Q, K>>;\n\n /**\n * Whether the field is required\n */\n isRequired?: boolean;\n\n /**\n * Placeholder text\n */\n placeholder?: string;\n\n /**\n * Additional information to display on this field\n * The placement of helper text depends on the value of helperTextPlacement prop\n */\n helperText?: string;\n\n /**\n * The placement of the helper text either below the field or in a tooltip\n *\n * @default \"tooltip\"\n */\n helperTextPlacement?: \"bottom\" | \"tooltip\";\n\n /**\n * Whether the field is disabled\n */\n isDisabled?: boolean;\n\n /**\n * A callback to customize error messages when a built-in validation rule fails.\n * Receives a discriminated union with the constraint data (e.g., the min value\n * that was exceeded) so the message can reference the threshold.\n *\n * Return a string to override the default message, or `undefined` to keep it.\n */\n onValidationError?: (error: ValidationError) => string | undefined;\n\n /**\n * Additional function to validate the field.\n *\n * Return `undefined` if valid, or an error message string if invalid.\n */\n validate?: (value: FieldValueType<Q, K>) => Promise<string | undefined>;\n\n /**\n * The component props for the form field.\n * Excludes runtime props (value, onChange) which are managed by ActionForm.\n */\n fieldComponentProps: Omit<\n FormFieldPropsByType[\n ValidFormFieldForPropertyType<\n FieldDescriptorType<Q, K>\n >\n ],\n FormManagedProps<\n ValidFormFieldForPropertyType<FieldDescriptorType<Q, K>>\n >\n >;\n}\n\n/**\n * A discriminated union describing which validation rule failed and the\n * constraint data the user needs to build a meaningful error message.\n */\nexport type ValidationError =\n | { type: \"required\" }\n | { type: \"min\"; min: number | Date }\n | { type: \"max\"; max: number | Date }\n | { type: \"minLength\"; minLength: number }\n | { type: \"maxLength\"; maxLength: number }\n | { type: \"maxSize\"; maxSize: number }\n | { type: \"validate\"; message: string };\n\n/**\n * Maps field types to their corresponding props\n */\nexport interface FormFieldPropsByType {\n DATE_RANGE_INPUT: DateRangeInputFieldProps;\n DATETIME_PICKER: DatetimePickerFieldProps;\n DROPDOWN: DropdownFieldProps<unknown, boolean>;\n FILE_PICKER: FilePickerProps;\n NUMBER_INPUT: NumberInputFieldProps;\n OBJECT_SELECT: ObjectSelectFieldProps<ObjectTypeDefinition>;\n OBJECT_SET: ObjectSetFieldProps<ObjectTypeDefinition>;\n RADIO_BUTTONS: RadioButtonsFieldProps<unknown>;\n TEXT_AREA: TextAreaFieldProps;\n TEXT_INPUT: TextInputFieldProps;\n CUSTOM: CustomFieldProps<unknown>;\n}\n\n/**\n * Datetime picker field props.\n *\n * When `formatDate` is omitted, ISO-like format is used (YYYY-MM-DD / YYYY-MM-DD HH:mm).\n */\nexport interface DatetimePickerFieldProps extends BaseFormFieldProps<Date> {\n /**\n * The earliest date the user can select.\n * If provided, this will be added to the field validation.\n */\n min?: Date;\n\n /**\n * The latest date the user can select.\n * If provided, this will be added to the field validation.\n */\n max?: Date;\n\n /**\n * Whether to show time picker.\n */\n showTime?: boolean;\n\n /**\n * Whether to close the popover after selecting a date.\n * @default true when `showTime` is false, false when `showTime` is true\n */\n closeOnSelection?: boolean;\n\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n\n /**\n * Formats a Date for display in the input field when not editing.\n * When typing, the input shows the parsable format (YYYY-MM-DD or YYYY-MM-DD HH:mm).\n * Provide a matching `parseDate` if using a custom format.\n */\n formatDate?: (date: Date) => string;\n\n /**\n * Parses a user-typed string back into a Date.\n * Must be the inverse of `formatDate` — if `formatDate(d)` produces string `s`,\n * then `parseDate(s)` must return an equivalent Date.\n * When omitted, defaults to parsing \"YYYY-MM-DD\" (date-only) or \"YYYY-MM-DD HH:mm\" (with time).\n */\n parseDate?: (text: string) => Date | undefined;\n\n /**\n * Ref forwarded to the portal container element.\n * Used to track portaled content for click-outside detection.\n */\n portalRef?: React.Ref<HTMLDivElement>;\n}\n\n/**\n * A date range represented as a start/end tuple.\n * Either element may be `null` when the range is partially selected.\n */\nexport type DateRange = readonly [Date | null, Date | null];\n\n/** Default empty range — both bounds are null. */\nexport const EMPTY_RANGE: DateRange = [null, null];\n\n/**\n * Date range input field props.\n *\n * Renders two text inputs (start / end) with a shared calendar popover\n * that supports range selection.\n */\nexport interface DateRangeInputFieldProps\n extends BaseFormFieldProps<DateRange>\n{\n /** The earliest selectable date. */\n min?: Date;\n\n /** The latest selectable date. */\n max?: Date;\n\n /** Whether to show time pickers for both dates. */\n showTime?: boolean;\n\n /** Placeholder text for the start date input. */\n placeholderStart?: string;\n\n /** Placeholder text for the end date input. */\n placeholderEnd?: string;\n\n /** Whether to allow start and end on the same day. @default true */\n allowSingleDayRange?: boolean;\n\n /** Formats a Date for display. Defaults to \"YYYY-MM-DD\". */\n formatDate?: (date: Date) => string;\n\n /** Parses a user-typed string back into a Date. */\n parseDate?: (text: string) => Date | undefined;\n}\n\n/**\n * Dropdown field props with selectable items\n */\nexport interface DropdownFieldProps<V, Multiple extends boolean = false>\n extends BaseFormFieldProps<Multiple extends true ? V[] : V>\n{\n /**\n * Available items for the dropdown\n */\n items: V[];\n\n /**\n * Converts an item to a display string. Defaults to `String()`.\n */\n itemToStringLabel?: (item: V) => string;\n\n /**\n * Returns a unique string key for a list item. Used as the React `key`.\n * Falls back to the item's index when not provided.\n */\n itemToKey?: (item: V) => string;\n\n /**\n * Custom equality check for item values. Defaults to `Object.is`.\n * Required when items are objects to ensure correct selection matching.\n */\n isItemEqual?: (a: V, b: V) => boolean;\n\n /**\n * Whether the dropdown allows searching/filtering.\n * When true, renders a Combobox with a search input.\n * When false (default), renders a Select dropdown.\n */\n isSearchable?: boolean;\n\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n\n /**\n * Whether multiple values can be selected\n */\n isMultiple?: Multiple;\n\n /**\n * Ref forwarded to the portal container element.\n * Used to track portaled content for click-outside detection.\n */\n portalRef?: React.Ref<HTMLDivElement>;\n\n /**\n * Controlled search input value. Must be provided together with `onQueryChange`.\n */\n query?: string;\n\n /**\n * Callback when the search input value changes.\n * Can be used standalone as an event listener or together with `query`\n * for fully controlled search state.\n */\n onQueryChange?: (query: string) => void;\n\n /**\n * When true, disables the combobox's built-in client-side filtering.\n * Use when items are already filtered server-side (e.g. via `onQueryChange`).\n *\n * @default false\n */\n disableClientSideFiltering?: boolean;\n\n /**\n * Status message rendered below the search input and above the item list\n * inside the popup. Use for loading/error/empty messages.\n */\n popupStatus?: React.ReactNode;\n\n /**\n * A React node to render after the item list.\n * Use for infinite scroll sentinels, \"load more\" buttons, etc.\n */\n trailingItem?: React.ReactNode;\n}\n\nexport interface FilePickerProps extends BaseFormFieldProps<File | File[]> {\n /**\n * Whether multiple files can be selected\n */\n isMulti?: boolean;\n\n /**\n * Accepted file types (e.g., \"image/*\", \".pdf\")\n */\n accept?: string | string[];\n\n /**\n * Maximum file size in bytes\n */\n maxSize?: number;\n\n /**\n * The text displayed when no file is selected.\n *\n * @default \"No file chosen\"\n */\n text?: string;\n\n /**\n * The text displayed on the browse button.\n *\n * @default \"Browse\"\n */\n buttonText?: string;\n}\n\n/**\n * Text area field props\n */\nexport interface TextAreaFieldProps extends\n BaseFormFieldProps<string>,\n Pick<\n React.TextareaHTMLAttributes<HTMLTextAreaElement>,\n | \"rows\"\n | \"wrap\"\n /**\n * If provided, this will be added to the field validation\n */\n | \"minLength\"\n /**\n * If provided, this will be added to the field validation\n */\n | \"maxLength\"\n >\n{\n placeholder?: string;\n}\n\nexport interface TextInputFieldProps extends\n BaseFormFieldProps<string>,\n Pick<\n React.InputHTMLAttributes<HTMLInputElement>,\n /**\n * If provided, this will be added to the field validation\n */\n | \"minLength\"\n /**\n * If provided, this will be added to the field validation\n */\n | \"maxLength\"\n >\n{\n placeholder?: string;\n}\n\n/**\n * Number input field props\n */\nexport interface NumberInputFieldProps extends BaseFormFieldProps<number> {\n /**\n * Minimum allowed value.\n */\n min?: number;\n\n /**\n * Maximum allowed value.\n */\n max?: number;\n\n /**\n * Step increment for the input. Used by the stepper buttons and ArrowUp/ArrowDown keyboard stepping.\n *\n * @default 1\n */\n step?: number;\n\n /**\n * Placeholder text shown when the input is empty.\n */\n placeholder?: string;\n}\n\n/**\n * Radio buttons field props\n */\nexport interface RadioButtonsFieldProps<V> extends BaseFormFieldProps<V> {\n /**\n * Available options for radio buttons.\n *\n * Values are compared by reference equality (`===`). When options contain\n * non-primitive values, pass the same object references for `value` and\n * the corresponding option entry.\n */\n options: Option<V>[];\n\n /**\n * Controls the layout direction of the radio buttons.\n *\n * - `\"vertical\"` (default): options are stacked in a column\n * - `\"horizontal\"`: options are laid out in a row, wrapping when needed\n */\n orientation?: \"horizontal\" | \"vertical\";\n}\n\n/**\n * Option interface for radio button options\n */\nexport interface Option<V> {\n label: string;\n value: V;\n}\n\n/**\n * Object set field displays the summary of the count of the given object set\n */\nexport interface ObjectSetFieldProps<T extends ObjectTypeDefinition>\n extends Pick<BaseFormFieldProps<ObjectSet<T>>, \"id\" | \"value\">\n{\n /**\n * Message displayed when no object set is provided.\n *\n * @default \"Object set is not defined\"\n */\n emptyMessage?: string;\n}\n\n/**\n * Object select field props for selecting object instances from the ontology.\n * Used for action parameters that accept a single object or multiple objects.\n *\n * Extends DropdownFieldProps with props that ObjectSelectField\n * manages internally (items, search, filtering) omitted from the public surface.\n */\nexport interface ObjectSelectFieldProps<\n Q extends ObjectTypeDefinition = ObjectTypeDefinition,\n> extends\n Omit<\n DropdownFieldProps<Osdk.Instance<Q>>,\n | \"items\"\n | \"itemToStringLabel\"\n | \"itemToKey\"\n | \"isItemEqual\"\n | \"isSearchable\"\n | \"query\"\n | \"onQueryChange\"\n | \"disableClientSideFiltering\"\n | \"renderItemList\"\n >\n{\n /**\n * The object type definition to search within.\n */\n objectType: Q;\n}\n\n/**\n * Custom field props for user-defined renderers\n */\nexport interface CustomFieldProps<V> extends BaseFormFieldProps<V> {\n /**\n * Custom renderer function\n */\n customRenderer: (props: BaseFormFieldProps<V>) => React.ReactNode;\n}\n\nexport interface BaseFormFieldProps<V> {\n /**\n * The HTML `id` attribute for the field input element.\n * Used for `<label htmlFor>` association.\n */\n id?: string;\n\n /**\n * The validation error message for this field, if any.\n * When set, the field should display a visual error state.\n */\n error?: string;\n\n /**\n * The value of the form field\n */\n value: V | null;\n\n /**\n * The default value of the form field.\n */\n defaultValue?: V;\n\n /**\n * Called when the field value changes.\n *\n * ActionForm internally wraps this to pass the key to `onFieldValueChange`:\n * ```\n * <DropdownField\n * {...fieldDef}\n * onChange={(value) => onFieldValueChange(fieldDef.key, value)}\n * />\n * ```\n *\n * @param value The new value of the form field\n */\n onChange?: (value: V | null) => void;\n}\n\nexport type FieldKey<Q extends ActionDefinition<unknown>> =\n keyof ActionParameters<Q>;\n\n/**\n * Extracts parameters from an ActionDefinition\n */\nexport type ActionParameters<Q extends ActionDefinition<unknown>> =\n CompileTimeMetadata<Q>[\"parameters\"];\n\n/**\n * Extracts the value type for a specific parameter\n *\n * TODO: Re-use `BaseType`\n */\nexport type FieldValueType<\n Q extends ActionDefinition<unknown>,\n K extends keyof ActionParameters<Q> = keyof ActionParameters<Q>,\n> = ActionParameters<Q>[K][\"type\"] extends\n ActionMetadata.DataType.Object<infer T> ? ActionParam.ObjectType<T>\n : ActionParameters<Q>[K][\"type\"] extends ActionMetadata.DataType.ObjectSet<\n infer T\n > ? ActionParam.ObjectSetType<T>\n : ActionParameters<Q>[K][\"type\"] extends ActionMetadata.DataType.Struct<\n infer T\n > ? ActionParam.StructType<T>\n : ActionParameters<Q>[K][\"type\"] extends keyof DataValueClientToWire\n ? DataValueClientToWire[ActionParameters<Q>[K][\"type\"]]\n : never;\n\n/**\n * Extracts the parameter type descriptor for a specific action parameter.\n */\nexport type FieldDescriptorType<\n Q extends ActionDefinition<unknown> = ActionDefinition<unknown>,\n K extends keyof ActionParameters<Q> = keyof ActionParameters<Q>,\n> = ActionParameters<Q>[K][\"type\"];\n\n/**\n * Available form field component types\n */\nexport type FieldComponent =\n | \"DATE_RANGE_INPUT\"\n | \"DATETIME_PICKER\"\n | \"DROPDOWN\"\n | \"FILE_PICKER\"\n | \"NUMBER_INPUT\"\n | \"OBJECT_SELECT\"\n | \"OBJECT_SET\"\n | \"RADIO_BUTTONS\"\n | \"TEXT_AREA\"\n | \"TEXT_INPUT\"\n | \"CUSTOM\";\n\n/**\n * Describes the data type of a form field, independent of OSDK.\n * Mirrors ActionMetadata.DataType to keep the rendering layer OSDK-agnostic.\n */\nexport type FieldType =\n | \"boolean\"\n | \"string\"\n | \"integer\"\n | \"long\"\n | \"double\"\n | \"datetime\"\n | \"timestamp\"\n | \"attachment\"\n | \"marking\"\n | \"mediaReference\"\n | \"objectType\"\n | \"geoshape\"\n | \"geohash\"\n | { type: \"object\"; object: string }\n | { type: \"objectSet\"; objectSet: string }\n | { type: \"interface\"; interface: string }\n | { type: \"struct\"; struct: Record<string, string> };\n\n/**\n * Props managed by form state infrastructure (FieldBridge / RHF).\n * Fields with onChange participate in form state → value and onChange are managed\n * externally. Read-only fields (no onChange, e.g. ObjectSetField) keep value in\n * fieldComponentProps so it bypasses form state cloning.\n */\ntype FormManagedProps<K extends FieldComponent> = \"onChange\" extends\n keyof FormFieldPropsByType[K] ? \"value\" | \"onChange\"\n : \"onChange\";\n\n/**\n * An OSDK-agnostic field definition used by BaseForm and FormFieldRenderer.\n * Contains only the information needed to render a single field — no generics,\n * no compile-time parameter constraints.\n *\n * Implemented as a distributed mapped type: switching on `fieldComponent`\n * narrows `fieldComponentProps` to the correct props type automatically.\n */\nexport type RendererFieldDefinition = {\n [K in FieldComponent]: {\n fieldKey: string;\n fieldComponent: K;\n fieldType?: FieldType;\n label: string;\n isRequired?: boolean;\n placeholder?: string;\n helperText?: string;\n helperTextPlacement?: \"bottom\" | \"tooltip\";\n validate?: (value: unknown) => Promise<string | undefined>;\n onValidationError?: (error: ValidationError) => string | undefined;\n fieldComponentProps: Omit<FormFieldPropsByType[K], FormManagedProps<K>>;\n };\n}[FieldComponent];\n\n/**\n * Gets valid form field types for a given property type\n */\nexport type ValidFormFieldForPropertyType<P extends FieldDescriptorType> =\n P extends { type: \"objectSet\" } ? \"OBJECT_SET\"\n : P extends { type: \"object\" } ? \"OBJECT_SELECT\"\n : P extends \"mediaReference\" | \"attachment\" ? \"FILE_PICKER\"\n : P extends \"boolean\" ? \"RADIO_BUTTONS\" | \"DROPDOWN\"\n : P extends \"string\" ? \"TEXT_INPUT\" | \"TEXT_AREA\"\n : P extends \"datetime\" | \"timestamp\" ? \"DATETIME_PICKER\"\n : P extends\n | \"double\"\n | \"integer\"\n | \"long\"\n | \"float\"\n | \"short\"\n | \"byte\"\n | \"decimal\" ? \"NUMBER_INPUT\"\n : never;\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAcA;AACA;AACA;;AAqFA;AACA;AACA;AACA;;AAUA;AACA;AACA;;AAeA;AACA;AACA;AACA;AACA;;AAoDA;AACA;AACA;AACA;;AAGA;AACA,OAAO,MAAMA,WAAsB,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC;;AAElD;AACA;AACA;AACA;AACA;AACA;;AA6BA;AACA;AACA;;AAiHA;AACA;AACA;;AAqCA;AACA;AACA;;AAyBA;AACA;AACA;;AAoBA;AACA;AACA;;AAMA;AACA;AACA;;AAYA;AACA;AACA;AACA;AACA;AACA;AACA;;AAuBA;AACA;AACA;;AAkDA;AACA;AACA;;AAIA;AACA;AACA;AACA;AACA;;AAgBA;AACA;AACA;;AAMA;AACA;AACA;;AAcA;AACA;AACA;AACA;;AAoBA;AACA;AACA;AACA;AACA;AACA;;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAiBA;AACA;AACA","ignoreList":[]}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2026 Palantir Technologies, Inc. All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import React, { useMemo } from "react";
|
|
19
|
+
import { SkeletonBar } from "../../base-components/skeleton/SkeletonBar.js";
|
|
20
|
+
import { useInfiniteScroll } from "../../shared/hooks/useInfiniteScroll.js";
|
|
21
|
+
import { typedReactMemo } from "../../shared/typedMemo.js";
|
|
22
|
+
import styles from "./AsyncDropdownField.module.css.js";
|
|
23
|
+
import { DropdownField } from "./DropdownField.js";
|
|
24
|
+
export const AsyncDropdownField = typedReactMemo(function ({
|
|
25
|
+
isLoading,
|
|
26
|
+
hasMore,
|
|
27
|
+
isSearching,
|
|
28
|
+
onFetchMore,
|
|
29
|
+
fetchError,
|
|
30
|
+
...dropdownProps
|
|
31
|
+
}) {
|
|
32
|
+
const itemCount = dropdownProps.items.length;
|
|
33
|
+
const popupStatus = useMemo(() => {
|
|
34
|
+
if (fetchError != null) {
|
|
35
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
36
|
+
className: styles.osdkAsyncDropdownError,
|
|
37
|
+
role: "alert"
|
|
38
|
+
}, fetchError.message);
|
|
39
|
+
}
|
|
40
|
+
if (isSearching) {
|
|
41
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
42
|
+
className: styles.osdkAsyncDropdownStatus
|
|
43
|
+
}, "Searching\u2026");
|
|
44
|
+
}
|
|
45
|
+
// Show "Loading…" during the initial fetch before any data arrives,
|
|
46
|
+
// so the user doesn't see a misleading "No results" message.
|
|
47
|
+
if (isLoading && itemCount === 0) {
|
|
48
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
49
|
+
className: styles.osdkAsyncDropdownStatus
|
|
50
|
+
}, "Loading\u2026");
|
|
51
|
+
}
|
|
52
|
+
// "No results" is handled by Combobox.Empty inside DropdownField
|
|
53
|
+
return null;
|
|
54
|
+
}, [fetchError, isSearching, isLoading, itemCount]);
|
|
55
|
+
const infiniteScrollRef = useInfiniteScroll({
|
|
56
|
+
callback: onFetchMore,
|
|
57
|
+
loadedCount: itemCount
|
|
58
|
+
});
|
|
59
|
+
return /*#__PURE__*/React.createElement(DropdownField, _extends({}, dropdownProps, {
|
|
60
|
+
isSearchable: true,
|
|
61
|
+
popupStatus: popupStatus,
|
|
62
|
+
trailingItem: hasMore ? /*#__PURE__*/React.createElement(InfiniteScrollSentinel, {
|
|
63
|
+
key: "sentinel",
|
|
64
|
+
infiniteScrollRef: infiniteScrollRef
|
|
65
|
+
}) : null,
|
|
66
|
+
disableClientSideFiltering: dropdownProps.onQueryChange != null
|
|
67
|
+
}));
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
/** Skeleton placeholder that triggers the next page fetch when it scrolls into view. */
|
|
71
|
+
function InfiniteScrollSentinel({
|
|
72
|
+
infiniteScrollRef
|
|
73
|
+
}) {
|
|
74
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
75
|
+
ref: infiniteScrollRef,
|
|
76
|
+
role: "presentation"
|
|
77
|
+
}, /*#__PURE__*/React.createElement(SkeletonBar, {
|
|
78
|
+
className: styles.osdkAsyncDropdownSkeleton
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=AsyncDropdownField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AsyncDropdownField.js","names":["React","useMemo","SkeletonBar","useInfiniteScroll","typedReactMemo","styles","DropdownField","AsyncDropdownField","isLoading","hasMore","isSearching","onFetchMore","fetchError","dropdownProps","itemCount","items","length","popupStatus","createElement","className","osdkAsyncDropdownError","role","message","osdkAsyncDropdownStatus","infiniteScrollRef","callback","loadedCount","_extends","isSearchable","trailingItem","InfiniteScrollSentinel","key","disableClientSideFiltering","onQueryChange","ref","osdkAsyncDropdownSkeleton"],"sources":["AsyncDropdownField.tsx"],"sourcesContent":["/*\n * Copyright 2026 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useMemo } from \"react\";\nimport { SkeletonBar } from \"../../base-components/skeleton/SkeletonBar.js\";\nimport { useInfiniteScroll } from \"../../shared/hooks/useInfiniteScroll.js\";\nimport { typedReactMemo } from \"../../shared/typedMemo.js\";\nimport type { DropdownFieldProps } from \"../FormFieldApi.js\";\nimport styles from \"./AsyncDropdownField.module.css\";\nimport { DropdownField } from \"./DropdownField.js\";\n\nexport interface AsyncDropdownFieldProps<V, Multiple extends boolean = false>\n extends\n Omit<\n DropdownFieldProps<V, Multiple>,\n \"popupStatus\" | \"trailingItem\"\n >\n{\n /** Whether the data source is currently loading. */\n isLoading: boolean;\n /** Whether the data source is currently searching. */\n isSearching: boolean;\n /** Whether more pages of data are available to fetch. */\n hasMore: boolean;\n\n /**\n * Called when the user scrolls to the bottom and more data is available.\n */\n onFetchMore: () => void;\n\n /**\n * The error from the most recent failed fetch, if any.\n */\n fetchError?: Error;\n}\n\nexport const AsyncDropdownField: <V, Multiple extends boolean = false>(\n props: AsyncDropdownFieldProps<V, Multiple>,\n) => React.ReactElement = typedReactMemo(function AsyncDropdownFieldFn<\n V,\n Multiple extends boolean,\n>({\n isLoading,\n hasMore,\n isSearching,\n onFetchMore,\n fetchError,\n ...dropdownProps\n}: AsyncDropdownFieldProps<V, Multiple>): React.ReactElement {\n const itemCount = dropdownProps.items.length;\n const popupStatus = useMemo(() => {\n if (fetchError != null) {\n return (\n <div className={styles.osdkAsyncDropdownError} role=\"alert\">\n {fetchError.message}\n </div>\n );\n }\n if (isSearching) {\n return <div className={styles.osdkAsyncDropdownStatus}>Searching…</div>;\n }\n // Show \"Loading…\" during the initial fetch before any data arrives,\n // so the user doesn't see a misleading \"No results\" message.\n if (isLoading && itemCount === 0) {\n return <div className={styles.osdkAsyncDropdownStatus}>Loading…</div>;\n }\n // \"No results\" is handled by Combobox.Empty inside DropdownField\n return null;\n }, [fetchError, isSearching, isLoading, itemCount]);\n\n const infiniteScrollRef = useInfiniteScroll({\n callback: onFetchMore,\n loadedCount: itemCount,\n });\n\n return (\n <DropdownField\n {...dropdownProps}\n isSearchable={true}\n popupStatus={popupStatus}\n trailingItem={hasMore\n ? (\n <InfiniteScrollSentinel\n key=\"sentinel\"\n infiniteScrollRef={infiniteScrollRef}\n />\n )\n : null}\n disableClientSideFiltering={dropdownProps.onQueryChange != null}\n />\n );\n});\n\n/** Skeleton placeholder that triggers the next page fetch when it scrolls into view. */\nfunction InfiniteScrollSentinel({\n infiniteScrollRef,\n}: {\n infiniteScrollRef: React.LegacyRef<HTMLDivElement>;\n}): React.ReactElement {\n return (\n <div ref={infiniteScrollRef} role=\"presentation\">\n <SkeletonBar className={styles.osdkAsyncDropdownSkeleton} />\n </div>\n );\n}\n"],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,OAAOA,KAAK,IAAIC,OAAO,QAAQ,OAAO;AACtC,SAASC,WAAW,QAAQ,+CAA+C;AAC3E,SAASC,iBAAiB,QAAQ,yCAAyC;AAC3E,SAASC,cAAc,QAAQ,2BAA2B;AAE1D,OAAOC,MAAM,MAAM,iCAAiC;AACpD,SAASC,aAAa,QAAQ,oBAAoB;AA2BlD,OAAO,MAAMC,kBAEU,GAAGH,cAAc,CAAC,UAGvC;EACAI,SAAS;EACTC,OAAO;EACPC,WAAW;EACXC,WAAW;EACXC,UAAU;EACV,GAAGC;AACiC,CAAC,EAAsB;EAC3D,MAAMC,SAAS,GAAGD,aAAa,CAACE,KAAK,CAACC,MAAM;EAC5C,MAAMC,WAAW,GAAGhB,OAAO,CAAC,MAAM;IAChC,IAAIW,UAAU,IAAI,IAAI,EAAE;MACtB,oBACEZ,KAAA,CAAAkB,aAAA;QAAKC,SAAS,EAAEd,MAAM,CAACe,sBAAuB;QAACC,IAAI,EAAC;MAAO,GACxDT,UAAU,CAACU,OACT,CAAC;IAEV;IACA,IAAIZ,WAAW,EAAE;MACf,oBAAOV,KAAA,CAAAkB,aAAA;QAAKC,SAAS,EAAEd,MAAM,CAACkB;MAAwB,GAAC,iBAAe,CAAC;IACzE;IACA;IACA;IACA,IAAIf,SAAS,IAAIM,SAAS,KAAK,CAAC,EAAE;MAChC,oBAAOd,KAAA,CAAAkB,aAAA;QAAKC,SAAS,EAAEd,MAAM,CAACkB;MAAwB,GAAC,eAAa,CAAC;IACvE;IACA;IACA,OAAO,IAAI;EACb,CAAC,EAAE,CAACX,UAAU,EAAEF,WAAW,EAAEF,SAAS,EAAEM,SAAS,CAAC,CAAC;EAEnD,MAAMU,iBAAiB,GAAGrB,iBAAiB,CAAC;IAC1CsB,QAAQ,EAAEd,WAAW;IACrBe,WAAW,EAAEZ;EACf,CAAC,CAAC;EAEF,oBACEd,KAAA,CAAAkB,aAAA,CAACZ,aAAa,EAAAqB,QAAA,KACRd,aAAa;IACjBe,YAAY,EAAE,IAAK;IACnBX,WAAW,EAAEA,WAAY;IACzBY,YAAY,EAAEpB,OAAO,gBAEjBT,KAAA,CAAAkB,aAAA,CAACY,sBAAsB;MACrBC,GAAG,EAAC,UAAU;MACdP,iBAAiB,EAAEA;IAAkB,CACtC,CAAC,GAEF,IAAK;IACTQ,0BAA0B,EAAEnB,aAAa,CAACoB,aAAa,IAAI;EAAK,EACjE,CAAC;AAEN,CAAC,CAAC;;AAEF;AACA,SAASH,sBAAsBA,CAAC;EAC9BN;AAGF,CAAC,EAAsB;EACrB,oBACExB,KAAA,CAAAkB,aAAA;IAAKgB,GAAG,EAAEV,iBAAkB;IAACH,IAAI,EAAC;EAAc,gBAC9CrB,KAAA,CAAAkB,aAAA,CAAChB,WAAW;IAACiB,SAAS,EAAEd,MAAM,CAAC8B;EAA0B,CAAE,CACxD,CAAC;AAEV","ignoreList":[]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
.osdkAsyncDropdownError {
|
|
18
|
+
color: var(--osdk-async-dropdown-error-color);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.osdkAsyncDropdownStatus {
|
|
22
|
+
padding: var(--osdk-async-dropdown-status-padding);
|
|
23
|
+
color: var(--osdk-async-dropdown-status-color);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.osdkAsyncDropdownSkeleton {
|
|
27
|
+
width: var(--osdk-async-dropdown-skeleton-width);
|
|
28
|
+
height: var(--osdk-async-dropdown-skeleton-height);
|
|
29
|
+
margin: var(--osdk-async-dropdown-skeleton-margin);
|
|
30
|
+
border-radius: var(--osdk-async-dropdown-skeleton-border-radius);
|
|
31
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// CSS Module proxy for AsyncDropdownField.module.css
|
|
2
|
+
const styles = {
|
|
3
|
+
"osdkAsyncDropdownError": "AsyncDropdownField-module__osdkAsyncDropdownError___2jge6Ghr",
|
|
4
|
+
"osdkAsyncDropdownStatus": "AsyncDropdownField-module__osdkAsyncDropdownStatus___7kuVzYlf",
|
|
5
|
+
"osdkAsyncDropdownSkeleton": "AsyncDropdownField-module__osdkAsyncDropdownSkeleton___VszOs-f0"
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export default styles;
|
|
@@ -15,7 +15,7 @@ function _extends() { return _extends = Object.assign ? Object.assign.bind() : f
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import { CaretDown, Cross, Tick } from "@blueprintjs/icons";
|
|
18
|
+
import { CaretDown, Cross, SmallCross, Tick } from "@blueprintjs/icons";
|
|
19
19
|
import React, { useCallback, useState } from "react";
|
|
20
20
|
import { Combobox } from "../../base-components/combobox/Combobox.js";
|
|
21
21
|
import comboboxStyles from "../../base-components/combobox/Combobox.module.css.js";
|
|
@@ -31,12 +31,17 @@ const EMPTY_ARRAY = [];
|
|
|
31
31
|
* reads `isMultiple`.
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
|
-
export
|
|
34
|
+
export const DropdownField = typedReactMemo(function ({
|
|
35
35
|
isSearchable = false,
|
|
36
36
|
isMultiple,
|
|
37
37
|
itemToStringLabel,
|
|
38
38
|
itemToKey,
|
|
39
39
|
value,
|
|
40
|
+
query,
|
|
41
|
+
onQueryChange,
|
|
42
|
+
disableClientSideFiltering,
|
|
43
|
+
popupStatus,
|
|
44
|
+
trailingItem,
|
|
40
45
|
...rest
|
|
41
46
|
}) {
|
|
42
47
|
// Ensure always controlled from first render: multi-select needs [],
|
|
@@ -53,15 +58,22 @@ export function DropdownField({
|
|
|
53
58
|
value: normalizedValue,
|
|
54
59
|
itemToStringLabel: resolvedItemToStringLabel,
|
|
55
60
|
getKey: getKey,
|
|
56
|
-
isSearchable: isSearchable
|
|
61
|
+
isSearchable: isSearchable,
|
|
62
|
+
query: query,
|
|
63
|
+
onQueryChange: onQueryChange,
|
|
64
|
+
disableClientSideFiltering: disableClientSideFiltering,
|
|
65
|
+
popupStatus: popupStatus,
|
|
66
|
+
trailingItem: trailingItem
|
|
57
67
|
}));
|
|
58
68
|
}
|
|
69
|
+
|
|
70
|
+
// TODO: Support trailingItem
|
|
59
71
|
return /*#__PURE__*/React.createElement(SelectDropdown, _extends({}, rest, {
|
|
60
72
|
value: normalizedValue,
|
|
61
73
|
itemToStringLabel: resolvedItemToStringLabel,
|
|
62
74
|
getKey: getKey
|
|
63
75
|
}));
|
|
64
|
-
}
|
|
76
|
+
});
|
|
65
77
|
const SelectDropdown = typedReactMemo(function ({
|
|
66
78
|
id,
|
|
67
79
|
value,
|
|
@@ -99,7 +111,7 @@ const SelectDropdown = typedReactMemo(function ({
|
|
|
99
111
|
className: selectStyles.osdkSelectClear,
|
|
100
112
|
onMouseDown: preventTriggerOpen,
|
|
101
113
|
onClick: handleClear
|
|
102
|
-
}, /*#__PURE__*/React.createElement(
|
|
114
|
+
}, /*#__PURE__*/React.createElement(SmallCross, null)), /*#__PURE__*/React.createElement("span", {
|
|
103
115
|
className: selectStyles.osdkSelectIcon
|
|
104
116
|
}, /*#__PURE__*/React.createElement(CaretDown, null))), /*#__PURE__*/React.createElement(Select.Portal, {
|
|
105
117
|
ref: portalRef
|
|
@@ -119,7 +131,12 @@ const ComboboxDropdown = typedReactMemo(function ({
|
|
|
119
131
|
isMultiple,
|
|
120
132
|
isSearchable,
|
|
121
133
|
placeholder,
|
|
122
|
-
portalRef
|
|
134
|
+
portalRef,
|
|
135
|
+
query,
|
|
136
|
+
onQueryChange,
|
|
137
|
+
disableClientSideFiltering,
|
|
138
|
+
popupStatus,
|
|
139
|
+
trailingItem
|
|
123
140
|
}) {
|
|
124
141
|
const [open, setOpen] = useState(false);
|
|
125
142
|
const hasValue = isMultiple ? Array.isArray(value) && value.length > 0 : value != null;
|
|
@@ -143,11 +160,7 @@ const ComboboxDropdown = typedReactMemo(function ({
|
|
|
143
160
|
const renderItem = useCallback(item => /*#__PURE__*/React.createElement(Combobox.Item, {
|
|
144
161
|
key: getKey(item),
|
|
145
162
|
value: item
|
|
146
|
-
}, itemToStringLabel(item)), [getKey, itemToStringLabel]);
|
|
147
|
-
const renderItemWithIndicator = useCallback(item => /*#__PURE__*/React.createElement(Combobox.Item, {
|
|
148
|
-
key: getKey(item),
|
|
149
|
-
value: item
|
|
150
|
-
}, /*#__PURE__*/React.createElement(Combobox.ItemIndicator, null, /*#__PURE__*/React.createElement(Tick, null)), itemToStringLabel(item)), [getKey, itemToStringLabel]);
|
|
163
|
+
}, isMultiple && /*#__PURE__*/React.createElement(Combobox.ItemIndicator, null, /*#__PURE__*/React.createElement(Tick, null)), itemToStringLabel(item)), [getKey, isMultiple, itemToStringLabel]);
|
|
151
164
|
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Combobox.Root, {
|
|
152
165
|
value: value,
|
|
153
166
|
onValueChange: onChange,
|
|
@@ -157,7 +170,9 @@ const ComboboxDropdown = typedReactMemo(function ({
|
|
|
157
170
|
itemToStringLabel: itemToStringLabel,
|
|
158
171
|
isItemEqualToValue: isItemEqual,
|
|
159
172
|
items: items,
|
|
160
|
-
|
|
173
|
+
inputValue: query,
|
|
174
|
+
onInputValueChange: onQueryChange,
|
|
175
|
+
filter: disableClientSideFiltering ? null : undefined
|
|
161
176
|
}, /*#__PURE__*/React.createElement(Combobox.Trigger, {
|
|
162
177
|
id: id,
|
|
163
178
|
className: isMultiple ? comboboxStyles.osdkComboboxTriggerMulti : undefined
|
|
@@ -184,13 +199,13 @@ const ComboboxDropdown = typedReactMemo(function ({
|
|
|
184
199
|
className: comboboxStyles.osdkComboboxClear,
|
|
185
200
|
onMouseDown: preventTriggerOpen,
|
|
186
201
|
onClick: handleClear
|
|
187
|
-
}, /*#__PURE__*/React.createElement(
|
|
202
|
+
}, /*#__PURE__*/React.createElement(SmallCross, null)), /*#__PURE__*/React.createElement(Combobox.Icon, null, /*#__PURE__*/React.createElement(CaretDown, null))), /*#__PURE__*/React.createElement(Combobox.Portal, {
|
|
188
203
|
ref: portalRef
|
|
189
204
|
}, /*#__PURE__*/React.createElement(Combobox.Positioner, null, /*#__PURE__*/React.createElement(Combobox.Popup, null, isSearchable && /*#__PURE__*/React.createElement("div", {
|
|
190
205
|
className: comboboxStyles.osdkComboboxPopupSearchInput
|
|
191
206
|
}, /*#__PURE__*/React.createElement(Combobox.SearchInput, {
|
|
192
207
|
placeholder: "Search\u2026"
|
|
193
|
-
})), /*#__PURE__*/React.createElement(Combobox.Empty, null, "No results"), /*#__PURE__*/React.createElement(Combobox.List, null,
|
|
208
|
+
})), popupStatus, popupStatus == null && /*#__PURE__*/React.createElement(Combobox.Empty, null, "No results"), /*#__PURE__*/React.createElement(Combobox.List, null, items.map(renderItem), trailingItem))))));
|
|
194
209
|
});
|
|
195
210
|
|
|
196
211
|
// Prevent the clear/remove click from bubbling into the trigger
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DropdownField.js","names":["CaretDown","Cross","Tick","React","useCallback","useState","Combobox","comboboxStyles","Select","selectStyles","typedReactMemo","EMPTY_ARRAY","DropdownField","isSearchable","isMultiple","itemToStringLabel","itemToKey","value","rest","normalizedValue","resolvedItemToStringLabel","defaultItemToStringLabel","getKey","item","createElement","ComboboxDropdown","_extends","SelectDropdown","id","onChange","items","isItemEqual","placeholder","portalRef","open","setOpen","handleClear","Root","onValueChange","onOpenChange","isItemEqualToValue","Trigger","className","osdkSelectValueContainer","Value","osdkSelectPlaceholder","role","osdkSelectClear","onMouseDown","preventTriggerOpen","onClick","osdkSelectIcon","Portal","ref","Positioner","Popup","map","Item","key","hasValue","Array","isArray","length","cleared","handleRemoveItem","itemToRemove","next","filter","v","renderItem","renderItemWithIndicator","ItemIndicator","multiple","autoHighlight","osdkComboboxTriggerMulti","undefined","osdkComboboxValueContainer","osdkComboboxTriggerChips","osdkComboboxTriggerChip","osdkComboboxTriggerChipRemove","size","Fragment","osdkComboboxPlaceholder","osdkComboboxClear","Icon","osdkComboboxPopupSearchInput","SearchInput","Empty","List","e","stopPropagation","preventDefault","String","label"],"sources":["DropdownField.tsx"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CaretDown, Cross, Tick } from \"@blueprintjs/icons\";\nimport React, { useCallback, useState } from \"react\";\nimport { Combobox } from \"../../base-components/combobox/Combobox.js\";\nimport comboboxStyles from \"../../base-components/combobox/Combobox.module.css\";\nimport { Select } from \"../../base-components/select/Select.js\";\nimport selectStyles from \"../../base-components/select/Select.module.css\";\nimport { typedReactMemo } from \"../../shared/typedMemo.js\";\nimport type { DropdownFieldProps } from \"../FormFieldApi.js\";\n\nconst EMPTY_ARRAY: [] = [];\n\n/**\n * SelectDropdown is only used for single-select (the multi-select path\n * always routes to ComboboxDropdown). We keep the `Multiple` generic so\n * the spread from DropdownField type-checks, but SelectDropdown never\n * reads `isMultiple`.\n */\ninterface InnerSelectProps<V, Multiple extends boolean>\n extends Omit<DropdownFieldProps<V, Multiple>, \"isSearchable\">\n{\n itemToStringLabel: (item: V) => string;\n getKey: (item: V) => string;\n}\n\ninterface InnerComboboxProps<V, Multiple extends boolean>\n extends DropdownFieldProps<V, Multiple>\n{\n itemToStringLabel: (item: V) => string;\n getKey: (item: V) => string;\n isSearchable: boolean;\n}\n\nexport function DropdownField<V, Multiple extends boolean = false>({\n isSearchable = false,\n isMultiple,\n itemToStringLabel,\n itemToKey,\n value,\n ...rest\n}: DropdownFieldProps<V, Multiple>): React.ReactElement {\n // Ensure always controlled from first render: multi-select needs [],\n // single-select needs null. Passing undefined switches Base UI from\n // uncontrolled to controlled and triggers a warning.\n const normalizedValue = (value\n ?? (isMultiple ? EMPTY_ARRAY : null)) as typeof value;\n\n const resolvedItemToStringLabel = itemToStringLabel\n ?? defaultItemToStringLabel;\n\n const getKey = useCallback(\n (item: V) => itemToKey?.(item) ?? resolvedItemToStringLabel(item),\n [itemToKey, resolvedItemToStringLabel],\n );\n\n // Multi-select always uses Combobox for the chip-based UI because it looks better\n if (isSearchable || isMultiple) {\n return (\n <ComboboxDropdown\n {...rest}\n isMultiple={isMultiple}\n value={normalizedValue}\n itemToStringLabel={resolvedItemToStringLabel}\n getKey={getKey}\n isSearchable={isSearchable}\n />\n );\n }\n\n return (\n <SelectDropdown\n {...rest}\n value={normalizedValue}\n itemToStringLabel={resolvedItemToStringLabel}\n getKey={getKey}\n />\n );\n}\n\nconst SelectDropdown = typedReactMemo(function SelectDropdownFn<\n V,\n Multiple extends boolean,\n>({\n id,\n value,\n onChange,\n items,\n itemToStringLabel,\n getKey,\n isItemEqual,\n placeholder,\n portalRef,\n}: InnerSelectProps<V, Multiple>): React.ReactElement {\n const [open, setOpen] = useState(false);\n\n const hasValue = value != null;\n\n const handleClear = useCallback(() => {\n // SelectDropdown is always single-select, so cleared value is null.\n (onChange as ((v: V | null) => void) | undefined)?.(null);\n setOpen(false);\n }, [onChange]);\n\n return (\n <div>\n <Select.Root\n value={value}\n onValueChange={onChange}\n open={open}\n onOpenChange={setOpen}\n isItemEqualToValue={isItemEqual}\n itemToStringLabel={itemToStringLabel}\n >\n <Select.Trigger id={id} placeholder={placeholder}>\n <div className={selectStyles.osdkSelectValueContainer}>\n <Select.Value />\n {placeholder != null && (\n <span className={selectStyles.osdkSelectPlaceholder}>\n {placeholder}\n </span>\n )}\n </div>\n {hasValue && (\n <span\n role=\"button\"\n aria-label=\"Clear\"\n className={selectStyles.osdkSelectClear}\n onMouseDown={preventTriggerOpen}\n onClick={handleClear}\n >\n <Cross />\n </span>\n )}\n <span className={selectStyles.osdkSelectIcon}>\n <CaretDown />\n </span>\n </Select.Trigger>\n <Select.Portal ref={portalRef}>\n <Select.Positioner>\n <Select.Popup>\n {items.map((item) => (\n <Select.Item key={getKey(item)} value={item}>\n {itemToStringLabel(item)}\n </Select.Item>\n ))}\n </Select.Popup>\n </Select.Positioner>\n </Select.Portal>\n </Select.Root>\n </div>\n );\n});\n\nconst ComboboxDropdown = typedReactMemo(function ComboboxDropdownFn<\n V,\n Multiple extends boolean,\n>({\n id,\n value,\n onChange,\n items,\n itemToStringLabel,\n getKey,\n isItemEqual,\n isMultiple,\n isSearchable,\n placeholder,\n portalRef,\n}: InnerComboboxProps<V, Multiple>): React.ReactElement {\n const [open, setOpen] = useState(false);\n\n const hasValue = isMultiple\n ? Array.isArray(value) && value.length > 0\n : value != null;\n\n const handleClear = useCallback(() => {\n // TypeScript can't narrow the conditional type `Multiple extends true ? V[] : V`\n // at runtime, so we cast through the known parameter type at this single call site.\n const cleared = isMultiple ? (EMPTY_ARRAY as V[]) : null;\n (onChange as ((v: V[] | V | null) => void) | undefined)?.(cleared);\n // Single-select: close after clearing. Multi-select: keep open for continued selection.\n if (!isMultiple) {\n setOpen(false);\n }\n }, [isMultiple, onChange]);\n\n const handleRemoveItem = useCallback(\n (itemToRemove: V) => {\n if (!isMultiple || !Array.isArray(value)) {\n return;\n }\n const next = value.filter((v) =>\n isItemEqual != null\n ? !isItemEqual(v, itemToRemove)\n : v !== itemToRemove\n );\n (onChange as ((v: V[] | V | null) => void) | undefined)?.(next);\n },\n [isMultiple, value, onChange, isItemEqual],\n );\n\n const renderItem = useCallback(\n (item: V) => (\n <Combobox.Item key={getKey(item)} value={item}>\n {itemToStringLabel(item)}\n </Combobox.Item>\n ),\n [getKey, itemToStringLabel],\n );\n\n const renderItemWithIndicator = useCallback(\n (item: V) => (\n <Combobox.Item key={getKey(item)} value={item}>\n <Combobox.ItemIndicator>\n <Tick />\n </Combobox.ItemIndicator>\n {itemToStringLabel(item)}\n </Combobox.Item>\n ),\n [getKey, itemToStringLabel],\n );\n\n return (\n <div>\n <Combobox.Root\n value={value}\n onValueChange={onChange}\n open={open}\n onOpenChange={setOpen}\n multiple={isMultiple}\n itemToStringLabel={itemToStringLabel}\n isItemEqualToValue={isItemEqual}\n items={items}\n autoHighlight={isSearchable}\n >\n <Combobox.Trigger\n id={id}\n className={isMultiple\n ? comboboxStyles.osdkComboboxTriggerMulti\n : undefined}\n >\n <div className={comboboxStyles.osdkComboboxValueContainer}>\n {isMultiple && Array.isArray(value) && value.length > 0\n ? (\n <div className={comboboxStyles.osdkComboboxTriggerChips}>\n {value.map((item: V) => (\n <span\n key={getKey(item)}\n className={comboboxStyles.osdkComboboxTriggerChip}\n >\n {itemToStringLabel(item)}\n <span\n role=\"button\"\n aria-label={`Remove ${itemToStringLabel(item)}`}\n className={comboboxStyles.osdkComboboxTriggerChipRemove}\n onMouseDown={preventTriggerOpen}\n onClick={() => handleRemoveItem(item)}\n >\n <Cross size={12} />\n </span>\n </span>\n ))}\n </div>\n )\n : (\n <>\n <Combobox.Value />\n {!hasValue && placeholder != null && (\n <span className={comboboxStyles.osdkComboboxPlaceholder}>\n {placeholder}\n </span>\n )}\n </>\n )}\n </div>\n {hasValue && (\n <span\n role=\"button\"\n aria-label=\"Clear\"\n className={comboboxStyles.osdkComboboxClear}\n onMouseDown={preventTriggerOpen}\n onClick={handleClear}\n >\n <Cross />\n </span>\n )}\n <Combobox.Icon>\n <CaretDown />\n </Combobox.Icon>\n </Combobox.Trigger>\n <Combobox.Portal ref={portalRef}>\n <Combobox.Positioner>\n <Combobox.Popup>\n {isSearchable && (\n <div className={comboboxStyles.osdkComboboxPopupSearchInput}>\n <Combobox.SearchInput placeholder=\"Search…\" />\n </div>\n )}\n <Combobox.Empty>No results</Combobox.Empty>\n <Combobox.List>\n {isMultiple ? renderItemWithIndicator : renderItem}\n </Combobox.List>\n </Combobox.Popup>\n </Combobox.Positioner>\n </Combobox.Portal>\n </Combobox.Root>\n </div>\n );\n});\n\n// Prevent the clear/remove click from bubbling into the trigger\n// and toggling the dropdown open/closed.\nfunction preventTriggerOpen(e: React.MouseEvent): void {\n e.stopPropagation();\n e.preventDefault();\n}\n\nfunction defaultItemToStringLabel<V>(item: V): string {\n if (item == null || typeof item !== \"object\") {\n return String(item);\n }\n if (\"label\" in item && item.label != null && typeof item.label === \"string\") {\n return item.label;\n }\n return String(item);\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"DropdownField.js","names":["CaretDown","Cross","SmallCross","Tick","React","useCallback","useState","Combobox","comboboxStyles","Select","selectStyles","typedReactMemo","EMPTY_ARRAY","DropdownField","isSearchable","isMultiple","itemToStringLabel","itemToKey","value","query","onQueryChange","disableClientSideFiltering","popupStatus","trailingItem","rest","normalizedValue","resolvedItemToStringLabel","defaultItemToStringLabel","getKey","item","createElement","ComboboxDropdown","_extends","SelectDropdown","id","onChange","items","isItemEqual","placeholder","portalRef","open","setOpen","handleClear","Root","onValueChange","onOpenChange","isItemEqualToValue","Trigger","className","osdkSelectValueContainer","Value","osdkSelectPlaceholder","role","osdkSelectClear","onMouseDown","preventTriggerOpen","onClick","osdkSelectIcon","Portal","ref","Positioner","Popup","map","Item","key","hasValue","Array","isArray","length","cleared","handleRemoveItem","itemToRemove","next","filter","v","renderItem","ItemIndicator","multiple","inputValue","onInputValueChange","undefined","osdkComboboxTriggerMulti","osdkComboboxValueContainer","osdkComboboxTriggerChips","osdkComboboxTriggerChip","osdkComboboxTriggerChipRemove","size","Fragment","osdkComboboxPlaceholder","osdkComboboxClear","Icon","osdkComboboxPopupSearchInput","SearchInput","Empty","List","e","stopPropagation","preventDefault","String","label"],"sources":["DropdownField.tsx"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CaretDown, Cross, SmallCross, Tick } from \"@blueprintjs/icons\";\nimport React, { useCallback, useState } from \"react\";\nimport { Combobox } from \"../../base-components/combobox/Combobox.js\";\nimport comboboxStyles from \"../../base-components/combobox/Combobox.module.css\";\nimport { Select } from \"../../base-components/select/Select.js\";\nimport selectStyles from \"../../base-components/select/Select.module.css\";\nimport { typedReactMemo } from \"../../shared/typedMemo.js\";\nimport type { DropdownFieldProps } from \"../FormFieldApi.js\";\n\nconst EMPTY_ARRAY: [] = [];\n\n/**\n * SelectDropdown is only used for single-select (the multi-select path\n * always routes to ComboboxDropdown). We keep the `Multiple` generic so\n * the spread from DropdownField type-checks, but SelectDropdown never\n * reads `isMultiple`.\n */\ninterface InnerSelectProps<V, Multiple extends boolean>\n extends Omit<DropdownFieldProps<V, Multiple>, \"isSearchable\">\n{\n itemToStringLabel: (item: V) => string;\n getKey: (item: V) => string;\n portalRef?: React.Ref<HTMLDivElement>;\n query?: string;\n onQueryChange?: (query: string) => void;\n}\n\ninterface InnerComboboxProps<V, Multiple extends boolean>\n extends InnerSelectProps<V, Multiple>\n{\n isSearchable: boolean;\n disableClientSideFiltering?: boolean;\n popupStatus?: React.ReactNode;\n trailingItem?: DropdownFieldProps<V, Multiple>[\"trailingItem\"];\n}\n\nexport const DropdownField: <V, Multiple extends boolean = false>(\n props: DropdownFieldProps<V, Multiple>,\n) => React.ReactElement = typedReactMemo(function DropdownFieldFn<\n V,\n Multiple extends boolean = false,\n>({\n isSearchable = false,\n isMultiple,\n itemToStringLabel,\n itemToKey,\n value,\n query,\n onQueryChange,\n disableClientSideFiltering,\n popupStatus,\n trailingItem,\n ...rest\n}: DropdownFieldProps<V, Multiple>): React.ReactElement {\n // Ensure always controlled from first render: multi-select needs [],\n // single-select needs null. Passing undefined switches Base UI from\n // uncontrolled to controlled and triggers a warning.\n const normalizedValue = (value\n ?? (isMultiple ? EMPTY_ARRAY : null)) as typeof value;\n\n const resolvedItemToStringLabel = itemToStringLabel\n ?? defaultItemToStringLabel;\n\n const getKey = useCallback(\n (item: V) => itemToKey?.(item) ?? resolvedItemToStringLabel(item),\n [itemToKey, resolvedItemToStringLabel],\n );\n\n // Multi-select always uses Combobox for the chip-based UI because it looks better\n if (isSearchable || isMultiple) {\n return (\n <ComboboxDropdown\n {...rest}\n isMultiple={isMultiple}\n value={normalizedValue}\n itemToStringLabel={resolvedItemToStringLabel}\n getKey={getKey}\n isSearchable={isSearchable}\n query={query}\n onQueryChange={onQueryChange}\n disableClientSideFiltering={disableClientSideFiltering}\n popupStatus={popupStatus}\n trailingItem={trailingItem}\n />\n );\n }\n\n // TODO: Support trailingItem\n return (\n <SelectDropdown\n {...rest}\n value={normalizedValue}\n itemToStringLabel={resolvedItemToStringLabel}\n getKey={getKey}\n />\n );\n});\n\nconst SelectDropdown = typedReactMemo(function SelectDropdownFn<\n V,\n Multiple extends boolean,\n>({\n id,\n value,\n onChange,\n items,\n itemToStringLabel,\n getKey,\n isItemEqual,\n placeholder,\n portalRef,\n}: InnerSelectProps<V, Multiple>): React.ReactElement {\n const [open, setOpen] = useState(false);\n\n const hasValue = value != null;\n\n const handleClear = useCallback(() => {\n // SelectDropdown is always single-select, so cleared value is null.\n (onChange as ((v: V | null) => void) | undefined)?.(null);\n setOpen(false);\n }, [onChange]);\n\n return (\n <div>\n <Select.Root\n value={value}\n onValueChange={onChange}\n open={open}\n onOpenChange={setOpen}\n isItemEqualToValue={isItemEqual}\n itemToStringLabel={itemToStringLabel}\n >\n <Select.Trigger id={id} placeholder={placeholder}>\n <div className={selectStyles.osdkSelectValueContainer}>\n <Select.Value />\n {placeholder != null && (\n <span className={selectStyles.osdkSelectPlaceholder}>\n {placeholder}\n </span>\n )}\n </div>\n {hasValue && (\n <span\n role=\"button\"\n aria-label=\"Clear\"\n className={selectStyles.osdkSelectClear}\n onMouseDown={preventTriggerOpen}\n onClick={handleClear}\n >\n <SmallCross />\n </span>\n )}\n <span className={selectStyles.osdkSelectIcon}>\n <CaretDown />\n </span>\n </Select.Trigger>\n <Select.Portal ref={portalRef}>\n <Select.Positioner>\n <Select.Popup>\n {items.map((item) => (\n <Select.Item key={getKey(item)} value={item}>\n {itemToStringLabel(item)}\n </Select.Item>\n ))}\n </Select.Popup>\n </Select.Positioner>\n </Select.Portal>\n </Select.Root>\n </div>\n );\n});\n\nconst ComboboxDropdown = typedReactMemo(function ComboboxDropdownFn<\n V,\n Multiple extends boolean,\n>({\n id,\n value,\n onChange,\n items,\n itemToStringLabel,\n getKey,\n isItemEqual,\n isMultiple,\n isSearchable,\n placeholder,\n portalRef,\n query,\n onQueryChange,\n disableClientSideFiltering,\n popupStatus,\n trailingItem,\n}: InnerComboboxProps<V, Multiple>): React.ReactElement {\n const [open, setOpen] = useState(false);\n\n const hasValue = isMultiple\n ? Array.isArray(value) && value.length > 0\n : value != null;\n\n const handleClear = useCallback(() => {\n // TypeScript can't narrow the conditional type `Multiple extends true ? V[] : V`\n // at runtime, so we cast through the known parameter type at this single call site.\n const cleared = isMultiple ? (EMPTY_ARRAY as V[]) : null;\n (onChange as ((v: V[] | V | null) => void) | undefined)?.(cleared);\n // Single-select: close after clearing. Multi-select: keep open for continued selection.\n if (!isMultiple) {\n setOpen(false);\n }\n }, [isMultiple, onChange]);\n\n const handleRemoveItem = useCallback(\n (itemToRemove: V) => {\n if (!isMultiple || !Array.isArray(value)) {\n return;\n }\n const next = value.filter((v) =>\n isItemEqual != null\n ? !isItemEqual(v, itemToRemove)\n : v !== itemToRemove\n );\n (onChange as ((v: V[] | V | null) => void) | undefined)?.(next);\n },\n [isMultiple, value, onChange, isItemEqual],\n );\n\n const renderItem = useCallback(\n (item: V) => (\n <Combobox.Item key={getKey(item)} value={item}>\n {isMultiple && (\n <Combobox.ItemIndicator>\n <Tick />\n </Combobox.ItemIndicator>\n )}\n {itemToStringLabel(item)}\n </Combobox.Item>\n ),\n [getKey, isMultiple, itemToStringLabel],\n );\n\n return (\n <div>\n <Combobox.Root\n value={value}\n onValueChange={onChange}\n open={open}\n onOpenChange={setOpen}\n multiple={isMultiple}\n itemToStringLabel={itemToStringLabel}\n isItemEqualToValue={isItemEqual}\n items={items}\n inputValue={query}\n onInputValueChange={onQueryChange}\n filter={disableClientSideFiltering ? null : undefined}\n >\n <Combobox.Trigger\n id={id}\n className={isMultiple\n ? comboboxStyles.osdkComboboxTriggerMulti\n : undefined}\n >\n <div className={comboboxStyles.osdkComboboxValueContainer}>\n {isMultiple && Array.isArray(value) && value.length > 0\n ? (\n <div className={comboboxStyles.osdkComboboxTriggerChips}>\n {value.map((item: V) => (\n <span\n key={getKey(item)}\n className={comboboxStyles.osdkComboboxTriggerChip}\n >\n {itemToStringLabel(item)}\n <span\n role=\"button\"\n aria-label={`Remove ${itemToStringLabel(item)}`}\n className={comboboxStyles.osdkComboboxTriggerChipRemove}\n onMouseDown={preventTriggerOpen}\n onClick={() => handleRemoveItem(item)}\n >\n <Cross size={12} />\n </span>\n </span>\n ))}\n </div>\n )\n : (\n <>\n <Combobox.Value />\n {!hasValue && placeholder != null && (\n <span className={comboboxStyles.osdkComboboxPlaceholder}>\n {placeholder}\n </span>\n )}\n </>\n )}\n </div>\n {hasValue && (\n <span\n role=\"button\"\n aria-label=\"Clear\"\n className={comboboxStyles.osdkComboboxClear}\n onMouseDown={preventTriggerOpen}\n onClick={handleClear}\n >\n <SmallCross />\n </span>\n )}\n <Combobox.Icon>\n <CaretDown />\n </Combobox.Icon>\n </Combobox.Trigger>\n <Combobox.Portal ref={portalRef}>\n <Combobox.Positioner>\n <Combobox.Popup>\n {isSearchable && (\n <div className={comboboxStyles.osdkComboboxPopupSearchInput}>\n <Combobox.SearchInput placeholder=\"Search…\" />\n </div>\n )}\n {popupStatus}\n {/* Hide \"No results\" when popupStatus provides its own message (e.g. \"Searching…\") */}\n {popupStatus == null && (\n <Combobox.Empty>No results</Combobox.Empty>\n )}\n <Combobox.List>\n {items.map(renderItem)}\n {trailingItem}\n </Combobox.List>\n </Combobox.Popup>\n </Combobox.Positioner>\n </Combobox.Portal>\n </Combobox.Root>\n </div>\n );\n});\n\n// Prevent the clear/remove click from bubbling into the trigger\n// and toggling the dropdown open/closed.\nfunction preventTriggerOpen(e: React.MouseEvent): void {\n e.stopPropagation();\n e.preventDefault();\n}\n\nfunction defaultItemToStringLabel<V>(item: V): string {\n if (item == null || typeof item !== \"object\") {\n return String(item);\n }\n if (\"label\" in item && item.label != null && typeof item.label === \"string\") {\n return item.label;\n }\n return String(item);\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -24,6 +24,7 @@ import { DatetimePickerField } from "./DatetimePickerField.js";
|
|
|
24
24
|
import { DropdownField } from "./DropdownField.js";
|
|
25
25
|
import { FilePickerField } from "./FilePickerField.js";
|
|
26
26
|
import { NumberInputField } from "./NumberInputField.js";
|
|
27
|
+
import { ObjectSelectField } from "./ObjectSelectField.js";
|
|
27
28
|
import { ObjectSetField } from "./ObjectSetField.js";
|
|
28
29
|
import { RadioButtonsField } from "./RadioButtonsField.js";
|
|
29
30
|
import { TextAreaField } from "./TextAreaField.js";
|
|
@@ -125,6 +126,14 @@ function renderFieldComponent(fieldDefinition, value, onChange, error) {
|
|
|
125
126
|
onChange: onChange,
|
|
126
127
|
error: error
|
|
127
128
|
}, fieldDefinition.fieldComponentProps));
|
|
129
|
+
case "OBJECT_SELECT":
|
|
130
|
+
return /*#__PURE__*/React.createElement(ObjectSelectField, _extends({
|
|
131
|
+
id: fieldDefinition.fieldKey,
|
|
132
|
+
value: narrowToOsdkObject(value),
|
|
133
|
+
onChange: onChange,
|
|
134
|
+
placeholder: fieldDefinition.placeholder,
|
|
135
|
+
error: error
|
|
136
|
+
}, fieldDefinition.fieldComponentProps));
|
|
128
137
|
case "OBJECT_SET":
|
|
129
138
|
return /*#__PURE__*/React.createElement(ObjectSetField, _extends({
|
|
130
139
|
id: fieldDefinition.fieldKey
|
|
@@ -154,6 +163,14 @@ function coerceToFileValue(value) {
|
|
|
154
163
|
}
|
|
155
164
|
return null;
|
|
156
165
|
}
|
|
166
|
+
|
|
167
|
+
/** Narrows the untyped form value to an OsdkObject by checking for $primaryKey. */
|
|
168
|
+
function narrowToOsdkObject(value) {
|
|
169
|
+
if (value != null && typeof value === "object" && "$primaryKey" in value) {
|
|
170
|
+
return value;
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
157
174
|
function assertUnreachableFieldComponent(value) {
|
|
158
175
|
throw new Error(`Unhandled field component: ${String(value)}`);
|
|
159
176
|
}
|