From 0f84def7cec837f7e7118f9a14cbdef8655af861 Mon Sep 17 00:00:00 2001 From: Elena Date: Tue, 18 Jun 2024 16:06:58 -0400 Subject: [PATCH 1/8] Install Interweave --- package.json | 1 + pnpm-lock.yaml | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 2405cf2..421d045 100644 --- a/package.json +++ b/package.json @@ -110,6 +110,7 @@ "vitest": "^1.5.0" }, "dependencies": { + "interweave": "^13.1.0", "lodash.isempty": "^4.4.0", "lodash.merge": "^4.6.2", "lodash.range": "^3.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 973a619..c90a5a6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,9 @@ settings: excludeLinksFromLockfile: false dependencies: + interweave: + specifier: ^13.1.0 + version: 13.1.0(react@18.2.0) lodash.isempty: specifier: ^4.4.0 version: 4.4.0 @@ -6417,7 +6420,6 @@ packages: /escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - dev: true /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} @@ -7465,6 +7467,15 @@ packages: side-channel: 1.0.6 dev: true + /interweave@13.1.0(react@18.2.0): + resolution: {integrity: sha512-JIDq0+2NYg0cgL7AB26fBcV0yZdiJvPDBp+aF6k8gq6Cr1kH5Gd2/Xqn7j8z+TGb8jCWZn739jzalCz+nPYwcA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + escape-html: 1.0.3 + react: 18.2.0 + dev: false + /into-stream@7.0.0: resolution: {integrity: sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==} engines: {node: '>=12'} @@ -7937,7 +7948,6 @@ packages: /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true /js-tokens@9.0.0: resolution: {integrity: sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==} @@ -8265,7 +8275,6 @@ packages: hasBin: true dependencies: js-tokens: 4.0.0 - dev: true /loupe@2.3.7: resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} @@ -10088,7 +10097,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 - dev: true /read-pkg-up@11.0.0: resolution: {integrity: sha512-LOVbvF1Q0SZdjClSefZ0Nz5z8u+tIE7mV5NibzmE9VYmDe9CaBbAVtz1veOSZbofrdsilxuDAYnFenukZVp8/Q==} From 870ab1504a4292f0ac4124564045097bf51cd79d Mon Sep 17 00:00:00 2001 From: Elena Date: Tue, 18 Jun 2024 16:07:32 -0400 Subject: [PATCH 2/8] Make tooltips render HTML --- src/controls/TextControl.tsx | 36 ++++++++++++++++---- src/stories/controls/TextControl.stories.tsx | 31 +++++++++++++++-- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/src/controls/TextControl.tsx b/src/controls/TextControl.tsx index bdaa41c..4479f0f 100644 --- a/src/controls/TextControl.tsx +++ b/src/controls/TextControl.tsx @@ -1,16 +1,19 @@ import type { ChangeEvent } from "react" -import { useCallback, useEffect } from "react" +import React, { useCallback, useEffect } from "react" import { Input, Form, InputProps } from "antd" -import type { Rule } from "antd/es/form" +import type { FormItemProps, Rule } from "antd/es/form" import type { ControlElement, ControlProps as JSFControlProps, } from "@jsonforms/core" +import { Interweave } from "interweave" +import ReactDOMServer from "react-dom/server" import type { ControlUISchema, TextControlOptions } from "../ui-schema" import { assertNever } from "../common/assert-never" import { withJsonFormsControlProps } from "@jsonforms/react" import { TextAreaProps } from "antd/es/input/TextArea" + type ControlProps = Omit & { data: string handleChange(path: string, value: string): void @@ -44,7 +47,10 @@ export function TextControl({ (uischema.options as TextControlOptions) ?? {} const formItemProps = "formItemProps" in uischema ? uischema.formItemProps : {} - const tooltip = options.tooltip ? options.tooltip : formItemProps?.tooltip + const { tooltip, ...formItemPropsWOTooltip } = formItemProps as FormItemProps + const mergedTooltip = options.tooltip ? options.tooltip : tooltip ?? "" + const tooltipProps = getTooltipProps(mergedTooltip) + const placeholderText = options.placeholderText const form = Form.useFormInstance() const rules: Rule[] = [ @@ -64,10 +70,13 @@ export function TextControl({ label={label} id={id} name={path} - rules={rules} validateTrigger={["onBlur"]} - tooltip={tooltip} - {...formItemProps} + rules={rules} + tooltip={{ + title: , + ...tooltipProps.rest, + }} + {...formItemPropsWOTooltip} > { + if (!tooltip) { + return { title: "", rest: null } + } else if (typeof tooltip === "string") { + return { title: tooltip, rest: null } + } else if (React.isValidElement(tooltip)) { + return { title: ReactDOMServer.renderToString(tooltip), rest: null } + } else if (typeof tooltip === "object" && "title" in tooltip) { + const { title, ...rest } = tooltip + return { title: String(title), rest } + } else { + return { title: String(tooltip), rest: null } + } +} + export const TextRenderer = withJsonFormsControlProps(TextControl) diff --git a/src/stories/controls/TextControl.stories.tsx b/src/stories/controls/TextControl.stories.tsx index 2d340b2..e90684f 100644 --- a/src/stories/controls/TextControl.stories.tsx +++ b/src/stories/controls/TextControl.stories.tsx @@ -125,7 +125,7 @@ export const RuleDefinedInUISchema: Story = { }, } -export const Tooltip: Story = { +export const FormItemTooltip: Story = { parameters: { controls: { expanded: true } }, tags: ["autodocs"], args: { @@ -137,7 +137,34 @@ export const Tooltip: Story = { type: "Control", scope: "#/properties/name", label: "Name", - formItemProps: { tooltip: "It's what you call yourself" }, + formItemProps: { + tooltip: { + title: "It's what you call yourself", + placement: "right", + }, + }, + }, + ], + } satisfies UISchema, + }, +} + +export const OptionsTooltip: Story = { + parameters: { controls: { expanded: true } }, + tags: ["autodocs"], + args: { + jsonSchema: schema, + uiSchema: { + type: "VerticalLayout", + elements: [ + { + type: "Control", + scope: "#/properties/name", + label: "Name", + options: { + tooltip: + "Choose a random name.", + }, }, ], } satisfies UISchema, From 08e0d5d72b9f5ccf7682f25a0daf9f15f18b1ac2 Mon Sep 17 00:00:00 2001 From: Elena Date: Tue, 18 Jun 2024 16:35:33 -0400 Subject: [PATCH 3/8] Add test --- src/controls/TextControl.test.tsx | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/controls/TextControl.test.tsx b/src/controls/TextControl.test.tsx index aed71b1..fba84ba 100644 --- a/src/controls/TextControl.test.tsx +++ b/src/controls/TextControl.test.tsx @@ -130,3 +130,33 @@ test("renders error messages from rule validation", async () => { await screen.findByText("Only letters are allowed") }) + +test("renders tooltips", async () => { + const uischema = { + type: "VerticalLayout", + elements: [ + { + type: "Control", + scope: "#/properties/name", + label: "Name", + options: { + tooltip: + "Choose a random name.", + }, + }, + ], + } + const schema = { + type: "object", + properties: { name: { type: "string", title: "Name" } }, + } satisfies JSONSchema + + render({ schema, uischema }) + await screen.findByPlaceholderText(schema.properties.name.title, { + exact: false, + }) + const svgEl = screen.getByRole("img", { name: /question-circle/i }) + await userEvent.hover(svgEl) + + await screen.findByText("a random name", { exact: false }) +}) From c43b5f2ec33cab6b08903741a8ffec698e3a1cca Mon Sep 17 00:00:00 2001 From: Elena Date: Tue, 25 Jun 2024 14:19:43 -0400 Subject: [PATCH 4/8] Feedback: update tooltips type --- package.json | 1 - pnpm-lock.yaml | 16 ++++--------- src/controls/TextControl.tsx | 25 ++------------------ src/stories/controls/TextControl.stories.tsx | 17 ++++++++++--- src/ui-schema.ts | 2 +- 5 files changed, 21 insertions(+), 40 deletions(-) diff --git a/package.json b/package.json index 421d045..2405cf2 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,6 @@ "vitest": "^1.5.0" }, "dependencies": { - "interweave": "^13.1.0", "lodash.isempty": "^4.4.0", "lodash.merge": "^4.6.2", "lodash.range": "^3.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c90a5a6..973a619 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,9 +5,6 @@ settings: excludeLinksFromLockfile: false dependencies: - interweave: - specifier: ^13.1.0 - version: 13.1.0(react@18.2.0) lodash.isempty: specifier: ^4.4.0 version: 4.4.0 @@ -6420,6 +6417,7 @@ packages: /escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + dev: true /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} @@ -7467,15 +7465,6 @@ packages: side-channel: 1.0.6 dev: true - /interweave@13.1.0(react@18.2.0): - resolution: {integrity: sha512-JIDq0+2NYg0cgL7AB26fBcV0yZdiJvPDBp+aF6k8gq6Cr1kH5Gd2/Xqn7j8z+TGb8jCWZn739jzalCz+nPYwcA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - dependencies: - escape-html: 1.0.3 - react: 18.2.0 - dev: false - /into-stream@7.0.0: resolution: {integrity: sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==} engines: {node: '>=12'} @@ -7948,6 +7937,7 @@ packages: /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true /js-tokens@9.0.0: resolution: {integrity: sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==} @@ -8275,6 +8265,7 @@ packages: hasBin: true dependencies: js-tokens: 4.0.0 + dev: true /loupe@2.3.7: resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} @@ -10097,6 +10088,7 @@ packages: engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 + dev: true /read-pkg-up@11.0.0: resolution: {integrity: sha512-LOVbvF1Q0SZdjClSefZ0Nz5z8u+tIE7mV5NibzmE9VYmDe9CaBbAVtz1veOSZbofrdsilxuDAYnFenukZVp8/Q==} diff --git a/src/controls/TextControl.tsx b/src/controls/TextControl.tsx index 4479f0f..9d4a282 100644 --- a/src/controls/TextControl.tsx +++ b/src/controls/TextControl.tsx @@ -1,13 +1,11 @@ import type { ChangeEvent } from "react" -import React, { useCallback, useEffect } from "react" +import { useCallback, useEffect } from "react" import { Input, Form, InputProps } from "antd" import type { FormItemProps, Rule } from "antd/es/form" import type { ControlElement, ControlProps as JSFControlProps, } from "@jsonforms/core" -import { Interweave } from "interweave" -import ReactDOMServer from "react-dom/server" import type { ControlUISchema, TextControlOptions } from "../ui-schema" import { assertNever } from "../common/assert-never" @@ -49,7 +47,6 @@ export function TextControl({ "formItemProps" in uischema ? uischema.formItemProps : {} const { tooltip, ...formItemPropsWOTooltip } = formItemProps as FormItemProps const mergedTooltip = options.tooltip ? options.tooltip : tooltip ?? "" - const tooltipProps = getTooltipProps(mergedTooltip) const placeholderText = options.placeholderText const form = Form.useFormInstance() @@ -72,10 +69,7 @@ export function TextControl({ name={path} validateTrigger={["onBlur"]} rules={rules} - tooltip={{ - title: , - ...tooltipProps.rest, - }} + tooltip={mergedTooltip} {...formItemPropsWOTooltip} > { - if (!tooltip) { - return { title: "", rest: null } - } else if (typeof tooltip === "string") { - return { title: tooltip, rest: null } - } else if (React.isValidElement(tooltip)) { - return { title: ReactDOMServer.renderToString(tooltip), rest: null } - } else if (typeof tooltip === "object" && "title" in tooltip) { - const { title, ...rest } = tooltip - return { title: String(title), rest } - } else { - return { title: String(tooltip), rest: null } - } -} - export const TextRenderer = withJsonFormsControlProps(TextControl) diff --git a/src/stories/controls/TextControl.stories.tsx b/src/stories/controls/TextControl.stories.tsx index e90684f..84655b7 100644 --- a/src/stories/controls/TextControl.stories.tsx +++ b/src/stories/controls/TextControl.stories.tsx @@ -139,7 +139,7 @@ export const FormItemTooltip: Story = { label: "Name", formItemProps: { tooltip: { - title: "It's what you call yourself", + title: "It's what you call yourself", placement: "right", }, }, @@ -162,8 +162,19 @@ export const OptionsTooltip: Story = { scope: "#/properties/name", label: "Name", options: { - tooltip: - "Choose a random name.", + tooltip: ( +

+ Choose{" "} + + a random name + + . +

+ ), }, }, ], diff --git a/src/ui-schema.ts b/src/ui-schema.ts index 8667ad3..11417d2 100644 --- a/src/ui-schema.ts +++ b/src/ui-schema.ts @@ -155,7 +155,7 @@ export type AnyOfControlOptions = OneOfControlOptions export type TextControlType = "multiline" | "password" | "singleline" export type TextControlOptions = { - tooltip?: string + tooltip?: React.ReactNode placeholderText?: string required?: boolean rules?: AntDRule[] From a31db2996866ed7b91c57c95093b8d14115e4508 Mon Sep 17 00:00:00 2001 From: Elena Date: Tue, 25 Jun 2024 15:53:44 -0400 Subject: [PATCH 5/8] fix: Deprecate options.tooltip --- src/controls/TextControl.test.tsx | 20 ++++++++- src/stories/controls/TextControl.stories.tsx | 47 ++++++-------------- src/ui-schema.ts | 5 ++- 3 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/controls/TextControl.test.tsx b/src/controls/TextControl.test.tsx index fba84ba..b2add75 100644 --- a/src/controls/TextControl.test.tsx +++ b/src/controls/TextControl.test.tsx @@ -140,8 +140,24 @@ test("renders tooltips", async () => { scope: "#/properties/name", label: "Name", options: { - tooltip: - "Choose a random name.", + formItemProps: { + tooltip: { + title: ( +

+ Choose{" "} + + a random name + + . +

+ ), + placement: "right", + }, + }, }, }, ], diff --git a/src/stories/controls/TextControl.stories.tsx b/src/stories/controls/TextControl.stories.tsx index 84655b7..b9586b4 100644 --- a/src/stories/controls/TextControl.stories.tsx +++ b/src/stories/controls/TextControl.stories.tsx @@ -139,7 +139,19 @@ export const FormItemTooltip: Story = { label: "Name", formItemProps: { tooltip: { - title: "It's what you call yourself", + title: ( +

+ Choose{" "} + + a random name + + . +

+ ), placement: "right", }, }, @@ -148,36 +160,3 @@ export const FormItemTooltip: Story = { } satisfies UISchema, }, } - -export const OptionsTooltip: Story = { - parameters: { controls: { expanded: true } }, - tags: ["autodocs"], - args: { - jsonSchema: schema, - uiSchema: { - type: "VerticalLayout", - elements: [ - { - type: "Control", - scope: "#/properties/name", - label: "Name", - options: { - tooltip: ( -

- Choose{" "} - - a random name - - . -

- ), - }, - }, - ], - } satisfies UISchema, - }, -} diff --git a/src/ui-schema.ts b/src/ui-schema.ts index 11417d2..4b6f997 100644 --- a/src/ui-schema.ts +++ b/src/ui-schema.ts @@ -155,7 +155,10 @@ export type AnyOfControlOptions = OneOfControlOptions export type TextControlType = "multiline" | "password" | "singleline" export type TextControlOptions = { - tooltip?: React.ReactNode + /** + * @deprecated Please use formItemProps.tooltip instead + */ + tooltip?: string placeholderText?: string required?: boolean rules?: AntDRule[] From dffa7685e3d503b2ac14f12011d6baad13606135 Mon Sep 17 00:00:00 2001 From: Elena Date: Tue, 25 Jun 2024 16:41:09 -0400 Subject: [PATCH 6/8] Update test --- src/controls/TextControl.test.tsx | 34 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/controls/TextControl.test.tsx b/src/controls/TextControl.test.tsx index b2add75..58cd618 100644 --- a/src/controls/TextControl.test.tsx +++ b/src/controls/TextControl.test.tsx @@ -139,24 +139,22 @@ test("renders tooltips", async () => { type: "Control", scope: "#/properties/name", label: "Name", - options: { - formItemProps: { - tooltip: { - title: ( -

- Choose{" "} - - a random name - - . -

- ), - placement: "right", - }, + formItemProps: { + tooltip: { + title: ( +

+ Choose{" "} + + a random name + + . +

+ ), + placement: "right", }, }, }, From 916b85ee204d82680965c3d83fc225f7311cb9fc Mon Sep 17 00:00:00 2001 From: Elena Date: Tue, 25 Jun 2024 17:17:43 -0400 Subject: [PATCH 7/8] Address feedback --- src/controls/TextControl.test.tsx | 38 ++++++++++++++++++++++--------- src/controls/TextControl.tsx | 8 +++---- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/controls/TextControl.test.tsx b/src/controls/TextControl.test.tsx index 58cd618..5b4e195 100644 --- a/src/controls/TextControl.test.tsx +++ b/src/controls/TextControl.test.tsx @@ -1,10 +1,10 @@ -import { test, expect } from "vitest" +import { test, expect, describe } from "vitest" import { screen, waitFor } from "@testing-library/react" import { userEvent } from "@testing-library/user-event" import type { JSONSchema } from "json-schema-to-ts" import { render } from "../common/test-render" -import type { UISchema } from "../ui-schema" +import type { TextControlOptions, UISchema } from "../ui-schema" import type { JSONFormData } from "../common/schema-derived-types" const textInputSchema = { @@ -131,8 +131,8 @@ test("renders error messages from rule validation", async () => { await screen.findByText("Only letters are allowed") }) -test("renders tooltips", async () => { - const uischema = { +describe("tooltips", () => { + const getUiSchema = (options?: TextControlOptions) => ({ type: "VerticalLayout", elements: [ { @@ -157,20 +157,36 @@ test("renders tooltips", async () => { placement: "right", }, }, + options, }, ], - } + }) + const schema = { type: "object", properties: { name: { type: "string", title: "Name" } }, } satisfies JSONSchema - render({ schema, uischema }) - await screen.findByPlaceholderText(schema.properties.name.title, { - exact: false, + test("renders tooltip", async () => { + render({ schema, uischema: getUiSchema() }) + await screen.findByPlaceholderText(schema.properties.name.title, { + exact: false, + }) + const svgEl = screen.getByRole("img", { name: /question-circle/i }) + await userEvent.hover(svgEl) + + await screen.findByText("a random name", { exact: false }) }) - const svgEl = screen.getByRole("img", { name: /question-circle/i }) - await userEvent.hover(svgEl) - await screen.findByText("a random name", { exact: false }) + test("renders right tooltip in case both are passed", async () => { + const options = { tooltip: "You should see this tooltip" } + render({ schema, uischema: getUiSchema(options) }) + await screen.findByPlaceholderText(schema.properties.name.title, { + exact: false, + }) + const svgEl = screen.getByRole("img", { name: /question-circle/i }) + await userEvent.hover(svgEl) + + await screen.findByText("You should see this tooltip") + }) }) diff --git a/src/controls/TextControl.tsx b/src/controls/TextControl.tsx index 9d4a282..ddd4c39 100644 --- a/src/controls/TextControl.tsx +++ b/src/controls/TextControl.tsx @@ -1,7 +1,7 @@ import type { ChangeEvent } from "react" import { useCallback, useEffect } from "react" import { Input, Form, InputProps } from "antd" -import type { FormItemProps, Rule } from "antd/es/form" +import type { Rule } from "antd/es/form" import type { ControlElement, ControlProps as JSFControlProps, @@ -45,8 +45,8 @@ export function TextControl({ (uischema.options as TextControlOptions) ?? {} const formItemProps = "formItemProps" in uischema ? uischema.formItemProps : {} - const { tooltip, ...formItemPropsWOTooltip } = formItemProps as FormItemProps - const mergedTooltip = options.tooltip ? options.tooltip : tooltip ?? "" + const { tooltip: formItemTooltip, ...formItemPropsWOTooltip } = formItemProps ?? {} + const tooltip = options.tooltip ? options.tooltip : formItemTooltip ?? "" const placeholderText = options.placeholderText const form = Form.useFormInstance() @@ -69,7 +69,7 @@ export function TextControl({ name={path} validateTrigger={["onBlur"]} rules={rules} - tooltip={mergedTooltip} + tooltip={tooltip} {...formItemPropsWOTooltip} > Date: Tue, 25 Jun 2024 17:23:15 -0400 Subject: [PATCH 8/8] Lint --- src/controls/TextControl.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/controls/TextControl.tsx b/src/controls/TextControl.tsx index ddd4c39..5c85ca7 100644 --- a/src/controls/TextControl.tsx +++ b/src/controls/TextControl.tsx @@ -45,7 +45,8 @@ export function TextControl({ (uischema.options as TextControlOptions) ?? {} const formItemProps = "formItemProps" in uischema ? uischema.formItemProps : {} - const { tooltip: formItemTooltip, ...formItemPropsWOTooltip } = formItemProps ?? {} + const { tooltip: formItemTooltip, ...formItemPropsWOTooltip } = + formItemProps ?? {} const tooltip = options.tooltip ? options.tooltip : formItemTooltip ?? "" const placeholderText = options.placeholderText