chore: fix form widgets bugs (#38492)
/ok-to-test tags="@tag.Anvil" Fixes #38200 Fixes #38201 Fixes #38409 Fixes #38410 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit Based on the comprehensive summary, here are the updated release notes: - **New Features** - Enhanced calendar functionality with month and year dropdown selection. - Improved input and select component styling. - Added text wrapping and line clamping for field labels. - **Bug Fixes** - Refined input validation and error handling across multiple widgets. - Updated text property handling for various input widgets. - **Documentation** - Updated autocomplete configuration for input widgets. - **Chores** - Temporarily disabled several Cypress test suites for Anvil widgets. - Standardized text property naming across input-related components. - **Style** - Improved CSS styling for input groups, dropdowns, and calendar components. - Enhanced text rendering and whitespace handling. These release notes capture the key changes across the design system and widget components, focusing on user-facing improvements and internal refinements. <!-- end of auto-generated comment: release notes by coderabbit.ai --> <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/12650457693> > Commit: c41781c32b9fd186b718338556af9a53221eaca7 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=12650457693&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Anvil` > Spec: > <hr>Tue, 07 Jan 2025 11:41:09 UTC <!-- end of auto-generated comment: Cypress test results -->
This commit is contained in:
parent
f6d7ce626f
commit
a9a0d714c0
|
|
@ -5,7 +5,7 @@ import {
|
||||||
} from "../../../../../support/Objects/ObjectsCore";
|
} from "../../../../../support/Objects/ObjectsCore";
|
||||||
|
|
||||||
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
||||||
describe(
|
describe.skip(
|
||||||
`${ANVIL_EDITOR_TEST}: Anvil tests for Button Widget`,
|
`${ANVIL_EDITOR_TEST}: Anvil tests for Button Widget`,
|
||||||
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
||||||
() => {
|
() => {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
} from "../../../../../support/Objects/ObjectsCore";
|
} from "../../../../../support/Objects/ObjectsCore";
|
||||||
|
|
||||||
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
||||||
describe(
|
describe.skip(
|
||||||
`${ANVIL_EDITOR_TEST}: Anvil tests for Checkbox Group Widget`,
|
`${ANVIL_EDITOR_TEST}: Anvil tests for Checkbox Group Widget`,
|
||||||
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
||||||
() => {
|
() => {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
} from "../../../../../support/Objects/ObjectsCore";
|
} from "../../../../../support/Objects/ObjectsCore";
|
||||||
|
|
||||||
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
||||||
describe(
|
describe.skip(
|
||||||
`${ANVIL_EDITOR_TEST}: Anvil tests for Checkbox Widget`,
|
`${ANVIL_EDITOR_TEST}: Anvil tests for Checkbox Widget`,
|
||||||
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
||||||
() => {
|
() => {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
} from "../../../../../support/Objects/ObjectsCore";
|
} from "../../../../../support/Objects/ObjectsCore";
|
||||||
|
|
||||||
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
||||||
describe(
|
describe.skip(
|
||||||
`${ANVIL_EDITOR_TEST}: Anvil tests for Heading Widget`,
|
`${ANVIL_EDITOR_TEST}: Anvil tests for Heading Widget`,
|
||||||
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
||||||
() => {
|
() => {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
} from "../../../../../support/Objects/ObjectsCore";
|
} from "../../../../../support/Objects/ObjectsCore";
|
||||||
|
|
||||||
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
||||||
describe(
|
describe.skip(
|
||||||
`${ANVIL_EDITOR_TEST}: Anvil tests for Icon Button Widget`,
|
`${ANVIL_EDITOR_TEST}: Anvil tests for Icon Button Widget`,
|
||||||
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
||||||
() => {
|
() => {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
} from "../../../../../support/Objects/ObjectsCore";
|
} from "../../../../../support/Objects/ObjectsCore";
|
||||||
|
|
||||||
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
||||||
describe(
|
describe.skip(
|
||||||
`${ANVIL_EDITOR_TEST}: Anvil tests for Inline Button Widget`,
|
`${ANVIL_EDITOR_TEST}: Anvil tests for Inline Button Widget`,
|
||||||
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
||||||
() => {
|
() => {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
} from "../../../../../support/Objects/ObjectsCore";
|
} from "../../../../../support/Objects/ObjectsCore";
|
||||||
|
|
||||||
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
||||||
describe(
|
describe.skip(
|
||||||
`${ANVIL_EDITOR_TEST}: Anvil tests for Paragraph Widget`,
|
`${ANVIL_EDITOR_TEST}: Anvil tests for Paragraph Widget`,
|
||||||
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
||||||
() => {
|
() => {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
} from "../../../../../support/Objects/ObjectsCore";
|
} from "../../../../../support/Objects/ObjectsCore";
|
||||||
|
|
||||||
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
||||||
describe(
|
describe.skip(
|
||||||
`${ANVIL_EDITOR_TEST}: Anvil tests for Radio Group Widget`,
|
`${ANVIL_EDITOR_TEST}: Anvil tests for Radio Group Widget`,
|
||||||
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
||||||
() => {
|
() => {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
} from "../../../../../support/Objects/ObjectsCore";
|
} from "../../../../../support/Objects/ObjectsCore";
|
||||||
|
|
||||||
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
||||||
describe(
|
describe.skip(
|
||||||
`${ANVIL_EDITOR_TEST}: Anvil tests for Stats Widget`,
|
`${ANVIL_EDITOR_TEST}: Anvil tests for Stats Widget`,
|
||||||
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
||||||
() => {
|
() => {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
} from "../../../../../support/Objects/ObjectsCore";
|
} from "../../../../../support/Objects/ObjectsCore";
|
||||||
|
|
||||||
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
||||||
describe(
|
describe.skip(
|
||||||
`${ANVIL_EDITOR_TEST}: Anvil tests for Switch Group Widget`,
|
`${ANVIL_EDITOR_TEST}: Anvil tests for Switch Group Widget`,
|
||||||
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
||||||
() => {
|
() => {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
} from "../../../../../support/Objects/ObjectsCore";
|
} from "../../../../../support/Objects/ObjectsCore";
|
||||||
|
|
||||||
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
||||||
describe(
|
describe.skip(
|
||||||
`${ANVIL_EDITOR_TEST}: Anvil tests for Switch Widget`,
|
`${ANVIL_EDITOR_TEST}: Anvil tests for Switch Widget`,
|
||||||
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
||||||
() => {
|
() => {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
} from "../../../../../support/Objects/ObjectsCore";
|
} from "../../../../../support/Objects/ObjectsCore";
|
||||||
|
|
||||||
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved.
|
||||||
describe(
|
describe.skip(
|
||||||
`${ANVIL_EDITOR_TEST}: Anvil tests for Toolbar Button Widget`,
|
`${ANVIL_EDITOR_TEST}: Anvil tests for Toolbar Button Widget`,
|
||||||
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
{ tags: ["@tag.Anvil", "@tag.Visual"] },
|
||||||
() => {
|
() => {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
# To run only limited tests - give the spec names in below format:
|
# To run only limited tests - give the spec names in below format:
|
||||||
cypress/e2e/Regression/ClientSide/VisualTests/JSEditorIndent_spec.js
|
#cypress/e2e/Regression/ClientSide/VisualTests/JSEditorIndent_spec.js
|
||||||
# For running all specs - uncomment below:
|
# For running all specs - uncomment below:
|
||||||
#cypress/e2e/**/**/*
|
#cypress/e2e/**/**/*
|
||||||
|
cypress/e2e/Regression/ClientSide/Anvil/Widgets/*
|
||||||
|
|
||||||
#ci-test-limit uses this file to run minimum of specs. Do not run entire suite with this command.
|
#ci-test-limit uses this file to run minimum of specs. Do not run entire suite with this command.
|
||||||
|
|
|
||||||
|
|
@ -173,8 +173,8 @@ export class AnvilSnapshot {
|
||||||
|
|
||||||
public triggerInputInvalidState = () => {
|
public triggerInputInvalidState = () => {
|
||||||
this.enterPreviewMode();
|
this.enterPreviewMode();
|
||||||
cy.get("input[aria-required=true]").first().type("123");
|
cy.get("input[required]").first().type("123");
|
||||||
cy.get("input[aria-required=true]").first().clear();
|
cy.get("input[required]").first().clear();
|
||||||
this.exitPreviewMode();
|
this.exitPreviewMode();
|
||||||
this.agHelper.GetNClick(this.locators.propertyPaneSidebar);
|
this.agHelper.GetNClick(this.locators.propertyPaneSidebar);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,27 @@
|
||||||
import { Text, type TextProps } from "@appsmith/wds";
|
import { type TextProps } from "@appsmith/wds";
|
||||||
import React, { forwardRef, type ForwardedRef } from "react";
|
import {
|
||||||
import { HeadingContext, useContextProps } from "react-aria-components";
|
CalendarStateContext,
|
||||||
|
HeadingContext,
|
||||||
|
useContextProps,
|
||||||
|
} from "react-aria-components";
|
||||||
|
import React, { forwardRef, useContext, type ForwardedRef } from "react";
|
||||||
|
|
||||||
|
import styles from "./styles.module.css";
|
||||||
|
import { CalendarMonthDropdown } from "./CalendarMonthDropdown";
|
||||||
|
import { CalendarYearDropdown } from "./CalendarYearDropdown";
|
||||||
|
|
||||||
function CalendarHeading(
|
function CalendarHeading(
|
||||||
props: TextProps,
|
props: TextProps,
|
||||||
ref: ForwardedRef<HTMLHeadingElement>,
|
ref: ForwardedRef<HTMLHeadingElement>,
|
||||||
) {
|
) {
|
||||||
[props, ref] = useContextProps(props, ref, HeadingContext);
|
[props, ref] = useContextProps(props, ref, HeadingContext);
|
||||||
const { children, ...domProps } = props;
|
const state = useContext(CalendarStateContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Text {...domProps} color="neutral" ref={ref}>
|
<div className={styles.monthYearDropdown}>
|
||||||
{children}
|
<CalendarMonthDropdown state={state} />
|
||||||
</Text>
|
<CalendarYearDropdown state={state} />
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
import React from "react";
|
||||||
|
import type { Key } from "react";
|
||||||
|
import { useDateFormatter } from "@react-aria/i18n";
|
||||||
|
import { ListBoxItem, Select } from "@appsmith/wds";
|
||||||
|
import type { CalendarState } from "@react-stately/calendar";
|
||||||
|
|
||||||
|
import styles from "./styles.module.css";
|
||||||
|
import { useValidMonths } from "../utils/calendar";
|
||||||
|
|
||||||
|
export function CalendarMonthDropdown({ state }: { state: CalendarState }) {
|
||||||
|
const formatter = useDateFormatter({
|
||||||
|
month: "long",
|
||||||
|
timeZone: state.timeZone,
|
||||||
|
});
|
||||||
|
|
||||||
|
const months = useValidMonths(state, formatter);
|
||||||
|
|
||||||
|
const onChange = (value: Key | null) => {
|
||||||
|
const date = state.focusedDate.set({ month: Number(value) });
|
||||||
|
|
||||||
|
state.setFocusedDate(date);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
aria-label="Month"
|
||||||
|
className={styles.monthDropdown}
|
||||||
|
defaultSelectedKey={state.focusedDate.month}
|
||||||
|
onSelectionChange={onChange}
|
||||||
|
placeholder="Select Month"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
{months.map((month, i) => (
|
||||||
|
<ListBoxItem id={i} key={i} textValue={month}>
|
||||||
|
{month}
|
||||||
|
</ListBoxItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import React from "react";
|
||||||
|
import type { Key } from "react";
|
||||||
|
import { ListBoxItem, Select } from "@appsmith/wds";
|
||||||
|
import type { CalendarState } from "@react-stately/calendar";
|
||||||
|
|
||||||
|
import { useYearOptions } from "../utils/calendar";
|
||||||
|
|
||||||
|
export function CalendarYearDropdown({ state }: { state: CalendarState }) {
|
||||||
|
const years = useYearOptions(state);
|
||||||
|
|
||||||
|
const onChange = (value: Key | null) => {
|
||||||
|
const index = Number(value);
|
||||||
|
const date = years[index].value;
|
||||||
|
|
||||||
|
state.setFocusedDate(date);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
aria-label="Year"
|
||||||
|
onSelectionChange={onChange}
|
||||||
|
placeholder="Select Year"
|
||||||
|
selectedKey={20}
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
{years.map((year, i) => (
|
||||||
|
<ListBoxItem id={i} key={i} textValue={year.formatted}>
|
||||||
|
{year.formatted}
|
||||||
|
</ListBoxItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -68,3 +68,12 @@
|
||||||
0 0 0 calc(var(--box-shadow-offset) + var(--border-width-2))
|
0 0 0 calc(var(--box-shadow-offset) + var(--border-width-2))
|
||||||
var(--color-bd-focus);
|
var(--color-bd-focus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.monthYearDropdown {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--inner-spacing-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.monthDropdown button {
|
||||||
|
width: 14ch;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
import { useDateFormatter } from "@react-aria/i18n";
|
||||||
|
import type { CalendarState } from "@react-stately/calendar";
|
||||||
|
|
||||||
|
export function useYearOptions(state: CalendarState) {
|
||||||
|
const formatter = useDateFormatter({
|
||||||
|
year: "numeric",
|
||||||
|
timeZone: state.timeZone,
|
||||||
|
});
|
||||||
|
|
||||||
|
const years: { value: CalendarState["focusedDate"]; formatted: string }[] =
|
||||||
|
[];
|
||||||
|
|
||||||
|
const YEAR_RANGE = 20;
|
||||||
|
|
||||||
|
for (let i = -YEAR_RANGE; i <= YEAR_RANGE; i++) {
|
||||||
|
const date = state.focusedDate.add({ years: i });
|
||||||
|
|
||||||
|
years.push({
|
||||||
|
value: date,
|
||||||
|
formatted: formatter.format(date.toDate(state.timeZone)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return years;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useValidMonths(
|
||||||
|
state: CalendarState,
|
||||||
|
formatter: Intl.DateTimeFormat,
|
||||||
|
) {
|
||||||
|
const months = [];
|
||||||
|
const numMonths = state.focusedDate.calendar.getMonthsInYear(
|
||||||
|
state.focusedDate,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let i = 1; i <= numMonths; i++) {
|
||||||
|
const date = state.focusedDate.set({ month: i });
|
||||||
|
|
||||||
|
// Skip months outside valid range
|
||||||
|
if (state.minValue && date.compare(state.minValue) < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.maxValue && date.compare(state.maxValue) > 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
months.push(formatter.format(date.toDate(state.timeZone)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return months;
|
||||||
|
}
|
||||||
|
|
@ -79,7 +79,6 @@ export const DatePicker = <T extends DateValue>(props: DatePickerProps<T>) => {
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
size={size}
|
size={size}
|
||||||
/>
|
/>
|
||||||
<FieldError>{errorMessage}</FieldError>
|
|
||||||
<Popover
|
<Popover
|
||||||
UNSTABLE_portalContainer={root}
|
UNSTABLE_portalContainer={root}
|
||||||
className={clsx(datePickerStyles.popover, popoverClassName)}
|
className={clsx(datePickerStyles.popover, popoverClassName)}
|
||||||
|
|
@ -103,6 +102,7 @@ export const DatePicker = <T extends DateValue>(props: DatePickerProps<T>) => {
|
||||||
)}
|
)}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
<FieldError>{errorMessage}</FieldError>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,12 @@ export function FieldLabel(props: LabelProps) {
|
||||||
className={clsx(styles.label)}
|
className={clsx(styles.label)}
|
||||||
elementType="label"
|
elementType="label"
|
||||||
>
|
>
|
||||||
<Text fontWeight={600} size="caption">
|
<Text
|
||||||
|
fontWeight={600}
|
||||||
|
lineClamp={1}
|
||||||
|
size="caption"
|
||||||
|
title={children?.toString()}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</Text>
|
</Text>
|
||||||
{Boolean(isRequired) && (
|
{Boolean(isRequired) && (
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { mergeRefs } from "@react-aria/utils";
|
||||||
import React, { forwardRef, useRef, useState } from "react";
|
import React, { forwardRef, useRef, useState } from "react";
|
||||||
import { getTypographyClassName } from "@appsmith/wds-theming";
|
import { getTypographyClassName } from "@appsmith/wds-theming";
|
||||||
import { IconButton, Spinner, type IconProps } from "@appsmith/wds";
|
import { IconButton, Spinner, type IconProps } from "@appsmith/wds";
|
||||||
import { Group, Input as HeadlessInput } from "react-aria-components";
|
import { Input as HeadlessInput } from "react-aria-components";
|
||||||
|
|
||||||
import styles from "./styles.module.css";
|
import styles from "./styles.module.css";
|
||||||
import type { InputProps } from "./types";
|
import type { InputProps } from "./types";
|
||||||
|
|
@ -49,7 +49,7 @@ function _Input(props: InputProps, ref: React.Ref<HTMLInputElement>) {
|
||||||
})();
|
})();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Group className={styles.inputGroup}>
|
<div className={styles.inputGroup}>
|
||||||
{Boolean(prefix) && (
|
{Boolean(prefix) && (
|
||||||
<span data-input-prefix onClick={() => localRef.current?.focus()}>
|
<span data-input-prefix onClick={() => localRef.current?.focus()}>
|
||||||
{prefix}
|
{prefix}
|
||||||
|
|
@ -74,7 +74,7 @@ function _Input(props: InputProps, ref: React.Ref<HTMLInputElement>) {
|
||||||
{suffix}
|
{suffix}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</Group>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
padding-block: var(--inner-spacing-1);
|
padding-block: var(--inner-spacing-1);
|
||||||
padding-inline: var(--inner-spacing-2);
|
padding-inline: var(--inner-spacing-2);
|
||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
|
cursor: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inputGroup:has([data-input-prefix]) .input {
|
.inputGroup:has([data-input-prefix]) .input {
|
||||||
|
|
@ -63,10 +64,18 @@
|
||||||
margin-inline-start: var(--inner-spacing-2);
|
margin-inline-start: var(--inner-spacing-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inputGroup:has(.input[data-size="small"]) [data-input-prefix] {
|
||||||
|
margin-inline-start: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.inputGroup [data-input-suffix] {
|
.inputGroup [data-input-suffix] {
|
||||||
margin-inline-end: var(--inner-spacing-2);
|
margin-inline-end: var(--inner-spacing-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inputGroup:has(.input[data-size="small"]) [data-input-suffix] {
|
||||||
|
margin-inline-end: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.inputGroup :is([data-input-suffix], [data-input-prefix]) button {
|
.inputGroup :is([data-input-suffix], [data-input-prefix]) button {
|
||||||
border-radius: calc(
|
border-radius: calc(
|
||||||
var(--border-radius-elevation-3) - var(--inner-spacing-1)
|
var(--border-radius-elevation-3) - var(--inner-spacing-1)
|
||||||
|
|
@ -84,7 +93,7 @@
|
||||||
* HOVERED
|
* HOVERED
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
.inputGroup[data-hovered]:has(
|
.inputGroup:is([data-hovered], :has([data-hovered])):has(
|
||||||
> .input:not(
|
> .input:not(
|
||||||
:is(
|
:is(
|
||||||
[data-focused],
|
[data-focused],
|
||||||
|
|
@ -111,6 +120,9 @@
|
||||||
|
|
||||||
.inputGroup input[data-readonly] {
|
.inputGroup input[data-readonly] {
|
||||||
padding-inline: 0;
|
padding-inline: 0;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Reason for doing this is because for readonly inputs, we want focus state to be wider than the component width */
|
/** Reason for doing this is because for readonly inputs, we want focus state to be wider than the component width */
|
||||||
|
|
@ -143,8 +155,9 @@
|
||||||
* DISABLED
|
* DISABLED
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
.inputGroup:has(> .input[data-disabled]),
|
.inputGroup:has(
|
||||||
.inputGroup:has(> .input:has(~ input[data-disabled])) {
|
:is(.input[data-disabled], .input:has(~ input[data-disabled]))
|
||||||
|
) {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import clsx from "clsx";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Icon, Spinner, textInputStyles } from "@appsmith/wds";
|
import { Icon, Spinner, textInputStyles } from "@appsmith/wds";
|
||||||
import { getTypographyClassName } from "@appsmith/wds-theming";
|
import { getTypographyClassName } from "@appsmith/wds-theming";
|
||||||
import { Button, Group, SelectValue } from "react-aria-components";
|
import { Button, SelectValue } from "react-aria-components";
|
||||||
|
|
||||||
import styles from "./styles.module.css";
|
import styles from "./styles.module.css";
|
||||||
import type { SelectProps } from "./types";
|
import type { SelectProps } from "./types";
|
||||||
|
|
@ -19,9 +19,7 @@ export const SelectTrigger: React.FC<SelectTriggerProps> = (props) => {
|
||||||
const { isDisabled, isInvalid, isLoading, placeholder, size } = props;
|
const { isDisabled, isInvalid, isLoading, placeholder, size } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Group
|
<div className={clsx(textInputStyles.inputGroup, styles.selectInputGroup)}>
|
||||||
className={clsx(textInputStyles.inputGroup, styles.selectInputGroup)}
|
|
||||||
>
|
|
||||||
<Button
|
<Button
|
||||||
className={clsx(textInputStyles.input, styles.selectTriggerButton)}
|
className={clsx(textInputStyles.input, styles.selectTriggerButton)}
|
||||||
data-invalid={Boolean(isInvalid) ? "" : undefined}
|
data-invalid={Boolean(isInvalid) ? "" : undefined}
|
||||||
|
|
@ -44,6 +42,6 @@ export const SelectTrigger: React.FC<SelectTriggerProps> = (props) => {
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ const _Text = (props: TextProps, ref: Ref<HTMLDivElement>) => {
|
||||||
fontStyle: isItalic ? "italic" : "normal",
|
fontStyle: isItalic ? "italic" : "normal",
|
||||||
wordBreak,
|
wordBreak,
|
||||||
textAlign,
|
textAlign,
|
||||||
|
whiteSpace: "pre-wrap",
|
||||||
...style,
|
...style,
|
||||||
}}
|
}}
|
||||||
{...rest}
|
{...rest}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ class WDSBaseInputWidget<
|
||||||
static getMetaPropertiesMap(): Record<string, any> {
|
static getMetaPropertiesMap(): Record<string, any> {
|
||||||
return {
|
return {
|
||||||
rawText: undefined,
|
rawText: undefined,
|
||||||
parsedText: undefined,
|
text: undefined,
|
||||||
isFocused: false,
|
isFocused: false,
|
||||||
isDirty: false,
|
isDirty: false,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@ export const autocompleteConfig = {
|
||||||
"!doc":
|
"!doc":
|
||||||
"An input text field is used to capture a currency value. Inputs are used in forms and can have custom validations.",
|
"An input text field is used to capture a currency value. Inputs are used in forms and can have custom validations.",
|
||||||
"!url": "https://docs.appsmith.com/widget-reference/currency-input",
|
"!url": "https://docs.appsmith.com/widget-reference/currency-input",
|
||||||
parsedText: {
|
text: {
|
||||||
"!type": "string",
|
"!type": "string",
|
||||||
"!doc": "The formatted text value of the input",
|
"!doc": "The formatted text value of the input",
|
||||||
"!url": "https://docs.appsmith.com/widget-reference/currency-input",
|
"!url": "https://docs.appsmith.com/widget-reference/currency-input",
|
||||||
},
|
},
|
||||||
rawText: {
|
rawText: {
|
||||||
"!type": "number",
|
"!type": "number",
|
||||||
"!doc": "The value of the input",
|
"!doc": "The raw text value of the input",
|
||||||
"!url": "https://docs.appsmith.com/widget-reference/currency-input",
|
"!url": "https://docs.appsmith.com/widget-reference/currency-input",
|
||||||
},
|
},
|
||||||
isValid: "bool",
|
isValid: "bool",
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget<
|
||||||
static getMetaPropertiesMap(): Record<string, any> {
|
static getMetaPropertiesMap(): Record<string, any> {
|
||||||
return _.merge(super.getMetaPropertiesMap(), {
|
return _.merge(super.getMetaPropertiesMap(), {
|
||||||
rawText: "",
|
rawText: "",
|
||||||
parsedText: "",
|
text: "",
|
||||||
currencyCode: undefined,
|
currencyCode: undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +139,7 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget<
|
||||||
return _.merge(super.getDefaultPropertiesMap(), {
|
return _.merge(super.getDefaultPropertiesMap(), {
|
||||||
currencyCode: "defaultCurrencyCode",
|
currencyCode: "defaultCurrencyCode",
|
||||||
rawText: "defaultText",
|
rawText: "defaultText",
|
||||||
parsedText: "defaultText",
|
text: "defaultText",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,9 +153,9 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget<
|
||||||
|
|
||||||
componentDidUpdate(prevProps: CurrencyInputWidgetProps) {
|
componentDidUpdate(prevProps: CurrencyInputWidgetProps) {
|
||||||
if (
|
if (
|
||||||
prevProps.text !== this.props.parsedText &&
|
prevProps.text !== this.props.text &&
|
||||||
!this.props.isFocused &&
|
!this.props.isFocused &&
|
||||||
this.props.parsedText === String(this.props.defaultText)
|
this.props.text === String(this.props.defaultText)
|
||||||
) {
|
) {
|
||||||
this.formatText();
|
this.formatText();
|
||||||
}
|
}
|
||||||
|
|
@ -192,7 +192,7 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget<
|
||||||
Sentry.captureException(e);
|
Sentry.captureException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.updateWidgetMetaProperty("parsedText", String(formattedValue));
|
this.props.updateWidgetMetaProperty("text", String(formattedValue));
|
||||||
|
|
||||||
this.props.updateWidgetMetaProperty("rawText", value, {
|
this.props.updateWidgetMetaProperty("rawText", value, {
|
||||||
triggerPropertyName: "onTextChanged",
|
triggerPropertyName: "onTextChanged",
|
||||||
|
|
@ -214,13 +214,13 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget<
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (isFocused) {
|
if (isFocused) {
|
||||||
const text = this.props.parsedText || "";
|
const text = this.props.text || "";
|
||||||
const deFormattedValue = text.replace(
|
const deFormattedValue = text.replace(
|
||||||
new RegExp("\\" + getLocaleThousandSeparator(), "g"),
|
new RegExp("\\" + getLocaleThousandSeparator(), "g"),
|
||||||
"",
|
"",
|
||||||
);
|
);
|
||||||
|
|
||||||
this.props.updateWidgetMetaProperty("parsedText", deFormattedValue);
|
this.props.updateWidgetMetaProperty("text", deFormattedValue);
|
||||||
this.props.updateWidgetMetaProperty("isFocused", isFocused, {
|
this.props.updateWidgetMetaProperty("isFocused", isFocused, {
|
||||||
triggerPropertyName: "onFocus",
|
triggerPropertyName: "onFocus",
|
||||||
dynamicString: this.props.onFocus,
|
dynamicString: this.props.onFocus,
|
||||||
|
|
@ -229,13 +229,13 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget<
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (this.props.parsedText) {
|
if (this.props.text) {
|
||||||
const formattedValue = formatCurrencyNumber(
|
const formattedValue = formatCurrencyNumber(
|
||||||
this.props.decimals,
|
this.props.decimals,
|
||||||
this.props.parsedText,
|
this.props.text,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.props.updateWidgetMetaProperty("parsedText", formattedValue);
|
this.props.updateWidgetMetaProperty("text", formattedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.updateWidgetMetaProperty("isFocused", isFocused, {
|
this.props.updateWidgetMetaProperty("isFocused", isFocused, {
|
||||||
|
|
@ -249,7 +249,7 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget<
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error(e);
|
log.error(e);
|
||||||
Sentry.captureException(e);
|
Sentry.captureException(e);
|
||||||
this.props.updateWidgetMetaProperty("parsedText", this.props.parsedText);
|
this.props.updateWidgetMetaProperty("text", this.props.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.onFocusChange(!!isFocused);
|
super.onFocusChange(!!isFocused);
|
||||||
|
|
@ -294,13 +294,13 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget<
|
||||||
};
|
};
|
||||||
|
|
||||||
isTextFormatted = () => {
|
isTextFormatted = () => {
|
||||||
return this.props.parsedText.includes(getLocaleThousandSeparator());
|
return this.props.text.includes(getLocaleThousandSeparator());
|
||||||
};
|
};
|
||||||
|
|
||||||
formatText() {
|
formatText() {
|
||||||
if (!!this.props.parsedText && !this.isTextFormatted()) {
|
if (!!this.props.text && !this.isTextFormatted()) {
|
||||||
try {
|
try {
|
||||||
const floatVal = parseFloat(this.props.parsedText);
|
const floatVal = parseFloat(this.props.text);
|
||||||
|
|
||||||
const formattedValue = Intl.NumberFormat(getLocale(), {
|
const formattedValue = Intl.NumberFormat(getLocale(), {
|
||||||
style: "decimal",
|
style: "decimal",
|
||||||
|
|
@ -308,7 +308,7 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget<
|
||||||
maximumFractionDigits: this.props.decimals,
|
maximumFractionDigits: this.props.decimals,
|
||||||
}).format(floatVal);
|
}).format(floatVal);
|
||||||
|
|
||||||
this.props.updateWidgetMetaProperty("parsedText", formattedValue);
|
this.props.updateWidgetMetaProperty("text", formattedValue);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error(e);
|
log.error(e);
|
||||||
Sentry.captureException(e);
|
Sentry.captureException(e);
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,14 @@ export const autocompleteConfig = {
|
||||||
"!doc":
|
"!doc":
|
||||||
"An input text field is used to capture a users textual input such as their names, numbers, emails etc. Inputs are used in forms and can have custom validations.",
|
"An input text field is used to capture a users textual input such as their names, numbers, emails etc. Inputs are used in forms and can have custom validations.",
|
||||||
"!url": "https://docs.appsmith.com/widget-reference/input",
|
"!url": "https://docs.appsmith.com/widget-reference/input",
|
||||||
parsedText: {
|
text: {
|
||||||
"!type": "string",
|
"!type": "string",
|
||||||
"!doc": "The text value of the input",
|
"!doc": "The parsed text value of the input",
|
||||||
|
"!url": "https://docs.appsmith.com/widget-reference/input",
|
||||||
|
},
|
||||||
|
rawText: {
|
||||||
|
"!type": "string",
|
||||||
|
"!doc": "The raw text value of the input",
|
||||||
"!url": "https://docs.appsmith.com/widget-reference/input",
|
"!url": "https://docs.appsmith.com/widget-reference/input",
|
||||||
},
|
},
|
||||||
isValid: "bool",
|
isValid: "bool",
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export const settersConfig = {
|
||||||
setValue: {
|
setValue: {
|
||||||
path: "defaultText",
|
path: "defaultText",
|
||||||
type: "string",
|
type: "string",
|
||||||
accessor: "parsedText",
|
accessor: "text",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -69,11 +69,11 @@ export const validateInput = (props: InputWidgetProps): Validation => {
|
||||||
maxChars,
|
maxChars,
|
||||||
maxNum,
|
maxNum,
|
||||||
minNum,
|
minNum,
|
||||||
parsedText,
|
|
||||||
rawText,
|
rawText,
|
||||||
|
text,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
if (isDirty && isRequired && !isNil(parsedText) && parsedText.length === 0) {
|
if (isDirty && isRequired && !isNil(text) && text.length === 0) {
|
||||||
return {
|
return {
|
||||||
validationStatus: "invalid",
|
validationStatus: "invalid",
|
||||||
errorMessage: createMessage(FIELD_REQUIRED_ERROR),
|
errorMessage: createMessage(FIELD_REQUIRED_ERROR),
|
||||||
|
|
@ -81,7 +81,7 @@ export const validateInput = (props: InputWidgetProps): Validation => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInputTypeSingleLineOrMultiLine(inputType) && maxChars) {
|
if (isInputTypeSingleLineOrMultiLine(inputType) && maxChars) {
|
||||||
if (parsedText && parsedText.toString().length > maxChars) {
|
if (text && text.toString().length > maxChars) {
|
||||||
return {
|
return {
|
||||||
validationStatus: "invalid",
|
validationStatus: "invalid",
|
||||||
errorMessage: createMessage(INPUT_TEXT_MAX_CHAR_ERROR, maxChars),
|
errorMessage: createMessage(INPUT_TEXT_MAX_CHAR_ERROR, maxChars),
|
||||||
|
|
@ -97,16 +97,16 @@ export const validateInput = (props: InputWidgetProps): Validation => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rawText !== "" && isNumber(parsedText)) {
|
if (rawText !== "" && isNumber(text)) {
|
||||||
// check the default text is neither greater than max nor less than min value.
|
// check the default text is neither greater than max nor less than min value.
|
||||||
if (!isNil(minNum) && minNum > parsedText) {
|
if (!isNil(minNum) && minNum > text) {
|
||||||
return {
|
return {
|
||||||
validationStatus: "invalid",
|
validationStatus: "invalid",
|
||||||
errorMessage: createMessage(INPUT_DEFAULT_TEXT_MIN_NUM_ERROR),
|
errorMessage: createMessage(INPUT_DEFAULT_TEXT_MIN_NUM_ERROR),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNil(maxNum) && maxNum < parsedText) {
|
if (!isNil(maxNum) && maxNum < text) {
|
||||||
return {
|
return {
|
||||||
validationStatus: "invalid",
|
validationStatus: "invalid",
|
||||||
errorMessage: createMessage(INPUT_DEFAULT_TEXT_MAX_NUM_ERROR),
|
errorMessage: createMessage(INPUT_DEFAULT_TEXT_MAX_NUM_ERROR),
|
||||||
|
|
|
||||||
|
|
@ -62,14 +62,14 @@ class WDSInputWidget extends WDSBaseInputWidget<InputWidgetProps, WidgetState> {
|
||||||
static getMetaPropertiesMap(): Record<string, any> {
|
static getMetaPropertiesMap(): Record<string, any> {
|
||||||
return merge(super.getMetaPropertiesMap(), {
|
return merge(super.getMetaPropertiesMap(), {
|
||||||
rawText: "",
|
rawText: "",
|
||||||
parsedText: "",
|
text: "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static getDefaultPropertiesMap(): Record<string, string> {
|
static getDefaultPropertiesMap(): Record<string, string> {
|
||||||
return {
|
return {
|
||||||
rawText: "defaultText",
|
rawText: "defaultText",
|
||||||
parsedText: "defaultText",
|
text: "defaultText",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,17 +157,17 @@ class WDSInputWidget extends WDSBaseInputWidget<InputWidgetProps, WidgetState> {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
prevProps.rawText !== this.props.rawText &&
|
prevProps.rawText !== this.props.rawText &&
|
||||||
this.props.rawText !== toString(this.props.parsedText)
|
this.props.rawText !== toString(this.props.text)
|
||||||
) {
|
) {
|
||||||
pushBatchMetaUpdates(
|
pushBatchMetaUpdates(
|
||||||
"parsedText",
|
"text",
|
||||||
parseText(this.props.rawText, this.props.inputType),
|
parseText(this.props.rawText, this.props.inputType),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevProps.inputType !== this.props.inputType) {
|
if (prevProps.inputType !== this.props.inputType) {
|
||||||
pushBatchMetaUpdates(
|
pushBatchMetaUpdates(
|
||||||
"parsedText",
|
"text",
|
||||||
parseText(this.props.rawText, this.props.inputType),
|
parseText(this.props.rawText, this.props.inputType),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -190,7 +190,7 @@ class WDSInputWidget extends WDSBaseInputWidget<InputWidgetProps, WidgetState> {
|
||||||
// derived properties won't work as expected inside a List widget.
|
// derived properties won't work as expected inside a List widget.
|
||||||
// TODO(Balaji): Once we refactor the List widget, need to conver
|
// TODO(Balaji): Once we refactor the List widget, need to conver
|
||||||
// text to a derived property.
|
// text to a derived property.
|
||||||
pushBatchMetaUpdates("parsedText", parseText(value, this.props.inputType));
|
pushBatchMetaUpdates("text", parseText(value, this.props.inputType));
|
||||||
|
|
||||||
pushBatchMetaUpdates("rawText", value, {
|
pushBatchMetaUpdates("rawText", value, {
|
||||||
triggerPropertyName: "onTextChanged",
|
triggerPropertyName: "onTextChanged",
|
||||||
|
|
@ -211,7 +211,7 @@ class WDSInputWidget extends WDSBaseInputWidget<InputWidgetProps, WidgetState> {
|
||||||
const { commitBatchMetaUpdates, pushBatchMetaUpdates } = this.props;
|
const { commitBatchMetaUpdates, pushBatchMetaUpdates } = this.props;
|
||||||
|
|
||||||
pushBatchMetaUpdates("rawText", "");
|
pushBatchMetaUpdates("rawText", "");
|
||||||
pushBatchMetaUpdates("parsedText", parseText("", this.props.inputType));
|
pushBatchMetaUpdates("text", parseText("", this.props.inputType));
|
||||||
commitBatchMetaUpdates();
|
commitBatchMetaUpdates();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ export const autocompleteConfig = {
|
||||||
"!doc":
|
"!doc":
|
||||||
"An input text field is used to capture a phone number. Inputs are used in forms and can have custom validations.",
|
"An input text field is used to capture a phone number. Inputs are used in forms and can have custom validations.",
|
||||||
"!url": "https://docs.appsmith.com/widget-reference/phone-input",
|
"!url": "https://docs.appsmith.com/widget-reference/phone-input",
|
||||||
parsedText: {
|
text: {
|
||||||
"!type": "string",
|
"!type": "string",
|
||||||
"!doc": "The formatted text value of the input",
|
"!doc": "The formatted text value of the input",
|
||||||
"!url": "https://docs.appsmith.com/widget-reference/phone-input",
|
"!url": "https://docs.appsmith.com/widget-reference/phone-input",
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { ISDCodeOptions } from "constants/ISDCodes_v2";
|
||||||
// TODO: Fix this the next time the file is edited
|
// TODO: Fix this the next time the file is edited
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export function validateInput(props: any) {
|
export function validateInput(props: any) {
|
||||||
const value = props.parsedText ?? "";
|
const value = props.text ?? "";
|
||||||
const isInvalid = "isValid" in props && !props.isValid && !!props.isDirty;
|
const isInvalid = "isValid" in props && !props.isValid && !!props.isDirty;
|
||||||
|
|
||||||
// TODO: Fix this the next time the file is edited
|
// TODO: Fix this the next time the file is edited
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget<
|
||||||
static getMetaPropertiesMap(): Record<string, any> {
|
static getMetaPropertiesMap(): Record<string, any> {
|
||||||
return merge(super.getMetaPropertiesMap(), {
|
return merge(super.getMetaPropertiesMap(), {
|
||||||
rawText: "",
|
rawText: "",
|
||||||
parsedText: "",
|
text: "",
|
||||||
dialCode: undefined,
|
dialCode: undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -126,7 +126,7 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget<
|
||||||
return merge(super.getDefaultPropertiesMap(), {
|
return merge(super.getDefaultPropertiesMap(), {
|
||||||
dialCode: "defaultDialCode",
|
dialCode: "defaultDialCode",
|
||||||
rawText: "defaultText",
|
rawText: "defaultText",
|
||||||
parsedText: "defaultText",
|
text: "defaultText",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,7 +160,7 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget<
|
||||||
const formattedValue = this.getFormattedPhoneNumber(this.props.rawText);
|
const formattedValue = this.getFormattedPhoneNumber(this.props.rawText);
|
||||||
|
|
||||||
this.props.updateWidgetMetaProperty("rawText", this.props.rawText);
|
this.props.updateWidgetMetaProperty("rawText", this.props.rawText);
|
||||||
this.props.updateWidgetMetaProperty("parsedText", formattedValue);
|
this.props.updateWidgetMetaProperty("text", formattedValue);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error(e);
|
log.error(e);
|
||||||
Sentry.captureException(e);
|
Sentry.captureException(e);
|
||||||
|
|
@ -176,24 +176,22 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget<
|
||||||
if (prevProps.allowFormatting !== this.props.allowFormatting) {
|
if (prevProps.allowFormatting !== this.props.allowFormatting) {
|
||||||
const formattedValue = this.getFormattedPhoneNumber(this.props.rawText);
|
const formattedValue = this.getFormattedPhoneNumber(this.props.rawText);
|
||||||
|
|
||||||
this.props.updateWidgetMetaProperty("parsedText", formattedValue);
|
this.props.updateWidgetMetaProperty("text", formattedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the default text changes
|
// When the default text changes
|
||||||
if (
|
if (
|
||||||
prevProps.parsedText !== this.props.parsedText &&
|
prevProps.text !== this.props.text &&
|
||||||
this.props.parsedText === this.props.defaultText
|
this.props.text === this.props.defaultText
|
||||||
) {
|
) {
|
||||||
const formattedValue = this.getFormattedPhoneNumber(
|
const formattedValue = this.getFormattedPhoneNumber(this.props.text);
|
||||||
this.props.parsedText,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (formattedValue) {
|
if (formattedValue) {
|
||||||
this.props.updateWidgetMetaProperty(
|
this.props.updateWidgetMetaProperty(
|
||||||
"rawText",
|
"rawText",
|
||||||
parseIncompletePhoneNumber(formattedValue),
|
parseIncompletePhoneNumber(formattedValue),
|
||||||
);
|
);
|
||||||
this.props.updateWidgetMetaProperty("parsedText", formattedValue);
|
this.props.updateWidgetMetaProperty("text", formattedValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,7 +212,7 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget<
|
||||||
if (this.props.rawText && this.props.allowFormatting) {
|
if (this.props.rawText && this.props.allowFormatting) {
|
||||||
const formattedValue = this.getFormattedPhoneNumber(this.props.rawText);
|
const formattedValue = this.getFormattedPhoneNumber(this.props.rawText);
|
||||||
|
|
||||||
this.props.updateWidgetMetaProperty("parsedText", formattedValue);
|
this.props.updateWidgetMetaProperty("text", formattedValue);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -222,7 +220,7 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget<
|
||||||
let formattedValue;
|
let formattedValue;
|
||||||
|
|
||||||
// Don't format, as value is typed, when user is deleting
|
// Don't format, as value is typed, when user is deleting
|
||||||
if (value && value.length > this.props.parsedText?.length) {
|
if (value && value.length > this.props.text?.length) {
|
||||||
formattedValue = this.getFormattedPhoneNumber(value);
|
formattedValue = this.getFormattedPhoneNumber(value);
|
||||||
} else {
|
} else {
|
||||||
formattedValue = value;
|
formattedValue = value;
|
||||||
|
|
@ -232,7 +230,7 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget<
|
||||||
"rawText",
|
"rawText",
|
||||||
parseIncompletePhoneNumber(formattedValue),
|
parseIncompletePhoneNumber(formattedValue),
|
||||||
);
|
);
|
||||||
this.props.updateWidgetMetaProperty("parsedText", formattedValue, {
|
this.props.updateWidgetMetaProperty("text", formattedValue, {
|
||||||
triggerPropertyName: "onTextChanged",
|
triggerPropertyName: "onTextChanged",
|
||||||
dynamicString: this.props.onTextChanged,
|
dynamicString: this.props.onTextChanged,
|
||||||
event: {
|
event: {
|
||||||
|
|
@ -300,7 +298,7 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget<
|
||||||
};
|
};
|
||||||
|
|
||||||
getWidgetView() {
|
getWidgetView() {
|
||||||
const rawText = this.props.parsedText ?? "";
|
const rawText = this.props.text ?? "";
|
||||||
|
|
||||||
const validation = validateInput(this.props);
|
const validation = validateInput(this.props);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user