chore: add datepicker component (#37563)
Added daterpicker component along with other components needed for it like Calendar andTimeField Datepicker  Calendar  Timefield  /ok-to-test tags="@tag.Anvil" <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes - **New Features** - Introduced a `Calendar` component for date selection and display. - Added a `DatePicker` component for selecting dates and times with enhanced error handling. - Launched a `TimeField` component for time input with optional prefix and suffix. - Updated `TextField` component replacing the previous `TextInput` for improved usability. - **Bug Fixes** - Enhanced styling and responsiveness of input components. - **Documentation** - Added Storybook stories for `Calendar`, `DatePicker`, and `TimeField` components to showcase functionalities and configurations. - **Chores** - Refactored imports to utilize the new `TextField` component across various widgets. <!-- 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/11970103158> > Commit: a1a552cb0bfdc9754341de5db0a6d8b142479083 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=11970103158&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Anvil` > Spec: > <hr>Fri, 22 Nov 2024 10:01:23 UTC <!-- end of auto-generated comment: Cypress test results -->
This commit is contained in:
parent
afa2324432
commit
d87f7ccd62
|
|
@ -0,0 +1,39 @@
|
||||||
|
import React from "react";
|
||||||
|
import type {
|
||||||
|
DateValue,
|
||||||
|
CalendarProps as HeadlessCalendarProps,
|
||||||
|
} from "react-aria-components";
|
||||||
|
import {
|
||||||
|
CalendarGrid as HeadlessCalendarGrid,
|
||||||
|
CalendarGridBody as HeadlessCalendarGridBody,
|
||||||
|
CalendarGridHeader as HeadlessCalendarGridHeader,
|
||||||
|
Calendar as HeadlessCalendar,
|
||||||
|
} from "react-aria-components";
|
||||||
|
import { Flex, IconButton } from "@appsmith/wds";
|
||||||
|
|
||||||
|
import styles from "./styles.module.css";
|
||||||
|
import { CalendarCell } from "./CalendarCell";
|
||||||
|
import { CalendarHeading } from "./CalendarHeading";
|
||||||
|
import { CalendarHeaderCell } from "./CalendarHeaderCell";
|
||||||
|
|
||||||
|
type CalendarProps<T extends DateValue> = HeadlessCalendarProps<T>;
|
||||||
|
|
||||||
|
export const Calendar = <T extends DateValue>(props: CalendarProps<T>) => {
|
||||||
|
return (
|
||||||
|
<HeadlessCalendar {...props} className={styles.calendar}>
|
||||||
|
<Flex alignItems="center" justifyContent="space-between" width="100%">
|
||||||
|
<IconButton icon="chevron-left" slot="previous" variant="ghost" />
|
||||||
|
<CalendarHeading size="subtitle" />
|
||||||
|
<IconButton icon="chevron-right" slot="next" variant="ghost" />
|
||||||
|
</Flex>
|
||||||
|
<HeadlessCalendarGrid>
|
||||||
|
<HeadlessCalendarGridHeader>
|
||||||
|
{(day) => <CalendarHeaderCell>{day}</CalendarHeaderCell>}
|
||||||
|
</HeadlessCalendarGridHeader>
|
||||||
|
<HeadlessCalendarGridBody>
|
||||||
|
{(date) => <CalendarCell date={date} />}
|
||||||
|
</HeadlessCalendarGridBody>
|
||||||
|
</HeadlessCalendarGrid>
|
||||||
|
</HeadlessCalendar>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
import React from "react";
|
||||||
|
import { Text } from "@appsmith/wds";
|
||||||
|
import {
|
||||||
|
CalendarCell as HeadlessCalendarCell,
|
||||||
|
type CalendarCellProps as HeadlessCalendarCellProps,
|
||||||
|
} from "react-aria-components";
|
||||||
|
|
||||||
|
import styles from "./styles.module.css";
|
||||||
|
|
||||||
|
export type CalendarCellProps = HeadlessCalendarCellProps &
|
||||||
|
React.RefAttributes<HTMLTableCellElement>;
|
||||||
|
|
||||||
|
function CalendarCell(props: CalendarCellProps) {
|
||||||
|
const { date } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HeadlessCalendarCell {...props} className={styles["calendar-cell"]}>
|
||||||
|
<Text>{date.day}</Text>
|
||||||
|
</HeadlessCalendarCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CalendarCell };
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import React from "react";
|
||||||
|
import { Text } from "@appsmith/wds";
|
||||||
|
import { CalendarHeaderCell as HeadlessCalendarHeaderCell } from "react-aria-components";
|
||||||
|
|
||||||
|
import { type CalendarHeaderCellProps as HeadlessCalendarHeaderCellProps } from "react-aria-components";
|
||||||
|
|
||||||
|
export type CalendarHeaderCellProps = HeadlessCalendarHeaderCellProps &
|
||||||
|
React.RefAttributes<HTMLTableCellElement>;
|
||||||
|
|
||||||
|
function CalendarHeaderCell(props: CalendarHeaderCellProps) {
|
||||||
|
const { children } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HeadlessCalendarHeaderCell {...props}>
|
||||||
|
<Text color="neutral" fontWeight={700} textAlign="center">
|
||||||
|
{children}
|
||||||
|
</Text>
|
||||||
|
</HeadlessCalendarHeaderCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CalendarHeaderCell };
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { Text, type TextProps } from "@appsmith/wds";
|
||||||
|
import React, { forwardRef, type ForwardedRef } from "react";
|
||||||
|
import { HeadingContext, useContextProps } from "react-aria-components";
|
||||||
|
|
||||||
|
function CalendarHeading(
|
||||||
|
props: TextProps,
|
||||||
|
ref: ForwardedRef<HTMLHeadingElement>,
|
||||||
|
) {
|
||||||
|
[props, ref] = useContextProps(props, ref, HeadingContext);
|
||||||
|
const { children, ...domProps } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Text {...domProps} color="neutral" ref={ref}>
|
||||||
|
{children}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const _CalendarHeading = forwardRef(CalendarHeading);
|
||||||
|
|
||||||
|
export { _CalendarHeading as CalendarHeading };
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
export { Calendar } from "./Calendar";
|
||||||
|
export { CalendarCell } from "./CalendarCell";
|
||||||
|
export { CalendarHeading } from "./CalendarHeading";
|
||||||
|
export { CalendarHeaderCell } from "./CalendarHeaderCell";
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
.calendar {
|
||||||
|
padding: var(--outer-spacing-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar table {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar thead tr {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
padding-block-start: var(--inner-spacing-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar tbody tr {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar thead th {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
inline-size: var(--sizing-9);
|
||||||
|
block-size: var(--sizing-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar tbody td {
|
||||||
|
padding: var(--inner-spacing-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar tbody [role="button"] {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
inline-size: var(--sizing-9);
|
||||||
|
block-size: var(--sizing-9);
|
||||||
|
border-radius: var(--border-radius-elevation-3);
|
||||||
|
border: var(--border-width-2) solid transparent;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar tbody [role="button"][data-disabled] {
|
||||||
|
opacity: var(--opacity-disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar tbody [role="button"][data-hovered] {
|
||||||
|
background-color: var(--color-bg-accent-subtle-hover);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar tbody [role="button"][data-pressed] {
|
||||||
|
background-color: var(--color-bg-accent-subtle-active);
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar tbody [role="button"][data-selected] {
|
||||||
|
background-color: var(--color-bg-accent);
|
||||||
|
color: var(--color-fg-on-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar tbody [role="button"][data-focus-visible] {
|
||||||
|
outline: var(--border-width-2) solid var(--color-bd-accent);
|
||||||
|
outline-offset: var(--border-width-2);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
import type { Meta, StoryObj } from "@storybook/react";
|
||||||
|
import { Calendar } from "../src";
|
||||||
|
import { today, getLocalTimeZone } from "@internationalized/date";
|
||||||
|
|
||||||
|
const meta: Meta<typeof Calendar> = {
|
||||||
|
component: Calendar,
|
||||||
|
title: "WDS/Widgets/Calendar",
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
component: "A calendar component for date selection and display.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof Calendar>;
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
args: {
|
||||||
|
defaultValue: today(getLocalTimeZone()),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WithMinDate: Story = {
|
||||||
|
args: {
|
||||||
|
defaultValue: today(getLocalTimeZone()),
|
||||||
|
minValue: today(getLocalTimeZone()),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WithMaxDate: Story = {
|
||||||
|
args: {
|
||||||
|
defaultValue: today(getLocalTimeZone()),
|
||||||
|
maxValue: today(getLocalTimeZone()).add({ days: 10 }),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Disabled: Story = {
|
||||||
|
args: {
|
||||||
|
defaultValue: today(getLocalTimeZone()),
|
||||||
|
isDisabled: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ReadOnly: Story = {
|
||||||
|
args: {
|
||||||
|
defaultValue: today(getLocalTimeZone()),
|
||||||
|
isReadOnly: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./src";
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
import {
|
||||||
|
FieldError,
|
||||||
|
FieldLabel,
|
||||||
|
Popover,
|
||||||
|
Calendar,
|
||||||
|
inputFieldStyles,
|
||||||
|
TimeField,
|
||||||
|
} from "@appsmith/wds";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DatePicker as HeadlessDatePicker,
|
||||||
|
type TimeValue,
|
||||||
|
type DateValue,
|
||||||
|
} from "react-aria-components";
|
||||||
|
|
||||||
|
import type { DatePickerProps } from "./types";
|
||||||
|
import datePickerStyles from "./styles.module.css";
|
||||||
|
import { DatepickerTrigger } from "./DatepickerTrigger";
|
||||||
|
|
||||||
|
export const DatePicker = <T extends DateValue>(props: DatePickerProps<T>) => {
|
||||||
|
const {
|
||||||
|
className,
|
||||||
|
contextualHelp,
|
||||||
|
errorMessage,
|
||||||
|
isDisabled,
|
||||||
|
isLoading,
|
||||||
|
isRequired,
|
||||||
|
label,
|
||||||
|
placeholderValue,
|
||||||
|
popoverClassName,
|
||||||
|
size = "medium",
|
||||||
|
...rest
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const placeholder: DateValue | null | undefined = placeholderValue;
|
||||||
|
const timePlaceholder = (
|
||||||
|
placeholder && "hour" in placeholder ? placeholder : null
|
||||||
|
) as TimeValue;
|
||||||
|
const timeMinValue = (
|
||||||
|
props.minValue && "hour" in props.minValue ? props.minValue : null
|
||||||
|
) as TimeValue;
|
||||||
|
const timeMaxValue = (
|
||||||
|
props.maxValue && "hour" in props.maxValue ? props.maxValue : null
|
||||||
|
) as TimeValue;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HeadlessDatePicker
|
||||||
|
aria-label={Boolean(label) ? undefined : "DatePicker"}
|
||||||
|
className={clsx(inputFieldStyles.field, className)}
|
||||||
|
data-size={size}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
isRequired={isRequired}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{({ state }) => {
|
||||||
|
const root = document.body.querySelector(
|
||||||
|
"[data-theme-provider]",
|
||||||
|
) as HTMLButtonElement;
|
||||||
|
const timeGranularity =
|
||||||
|
state.granularity === "hour" ||
|
||||||
|
state.granularity === "minute" ||
|
||||||
|
state.granularity === "second"
|
||||||
|
? state.granularity
|
||||||
|
: null;
|
||||||
|
const showTimeField = !!timeGranularity;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FieldLabel
|
||||||
|
contextualHelp={contextualHelp}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
isRequired={isRequired}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</FieldLabel>
|
||||||
|
<DatepickerTrigger
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
isLoading={isLoading}
|
||||||
|
size={size}
|
||||||
|
/>
|
||||||
|
<FieldError>{errorMessage}</FieldError>
|
||||||
|
<Popover
|
||||||
|
UNSTABLE_portalContainer={root}
|
||||||
|
className={clsx(datePickerStyles.popover, popoverClassName)}
|
||||||
|
>
|
||||||
|
<Dialog className={datePickerStyles.dialog}>
|
||||||
|
<Calendar />
|
||||||
|
{showTimeField && (
|
||||||
|
<div className={datePickerStyles.timeField}>
|
||||||
|
<TimeField
|
||||||
|
granularity={timeGranularity}
|
||||||
|
hideTimeZone={props.hideTimeZone}
|
||||||
|
hourCycle={props.hourCycle}
|
||||||
|
label="Time"
|
||||||
|
maxValue={timeMaxValue}
|
||||||
|
minValue={timeMinValue}
|
||||||
|
onChange={state.setTimeValue}
|
||||||
|
placeholderValue={timePlaceholder}
|
||||||
|
value={state.timeValue}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Dialog>
|
||||||
|
</Popover>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</HeadlessDatePicker>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
import clsx from "clsx";
|
||||||
|
import React, { useMemo } from "react";
|
||||||
|
import type { SIZES } from "@appsmith/wds";
|
||||||
|
import { getTypographyClassName } from "@appsmith/wds-theming";
|
||||||
|
import { textInputStyles, Spinner, IconButton } from "@appsmith/wds";
|
||||||
|
import { DateInput, DateSegment, Group } from "react-aria-components";
|
||||||
|
|
||||||
|
import dateInputStyles from "./styles.module.css";
|
||||||
|
|
||||||
|
interface DatepickerTriggerProps {
|
||||||
|
isLoading?: boolean;
|
||||||
|
size?: Omit<keyof typeof SIZES, "xSmall" | "large">;
|
||||||
|
isDisabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DatepickerTrigger = (props: DatepickerTriggerProps) => {
|
||||||
|
const { isDisabled, isLoading, size } = props;
|
||||||
|
|
||||||
|
const suffix = useMemo(() => {
|
||||||
|
if (Boolean(isLoading)) return <Spinner />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IconButton
|
||||||
|
color={Boolean(isLoading) ? "neutral" : "accent"}
|
||||||
|
icon="calendar-month"
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
isLoading={isLoading}
|
||||||
|
size={size === "medium" ? "small" : "xSmall"}
|
||||||
|
variant={Boolean(isLoading) ? "ghost" : "filled"}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}, [isLoading, size, isDisabled]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Group className={textInputStyles.inputGroup}>
|
||||||
|
<DateInput
|
||||||
|
className={clsx(
|
||||||
|
textInputStyles.input,
|
||||||
|
dateInputStyles.input,
|
||||||
|
getTypographyClassName("body"),
|
||||||
|
)}
|
||||||
|
data-date-input
|
||||||
|
>
|
||||||
|
{(segment) => <DateSegment segment={segment} />}
|
||||||
|
</DateInput>
|
||||||
|
<span data-input-suffix>{suffix}</span>
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
export { DatePicker } from "./Datepicker";
|
||||||
|
export * from "./types";
|
||||||
|
export { default as dateTimeInputStyles } from "./styles.module.css";
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
.input:is([data-date-input]) {
|
||||||
|
display: flex;
|
||||||
|
gap: calc(var(--inner-spacing-1) / 2);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input:is([data-date-input]) [data-focused="true"] {
|
||||||
|
background-color: var(--color-bg-accent);
|
||||||
|
color: var(--color-fg-on-accent);
|
||||||
|
box-shadow: 0 0 0 1px var(--color-bd-focus);
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog .timeField {
|
||||||
|
padding: var(--outer-spacing-3);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import type {
|
||||||
|
DateValue,
|
||||||
|
DatePickerProps as SpectrumDatePickerProps,
|
||||||
|
} from "react-aria-components";
|
||||||
|
import type { SIZES, FieldProps } from "@appsmith/wds";
|
||||||
|
|
||||||
|
export interface DatePickerProps<T extends DateValue>
|
||||||
|
extends Omit<SpectrumDatePickerProps<T>, "slot" | "placeholder">,
|
||||||
|
FieldProps {
|
||||||
|
/** size of the select
|
||||||
|
*
|
||||||
|
* @default medium
|
||||||
|
*/
|
||||||
|
size?: Omit<keyof typeof SIZES, "xSmall" | "large">;
|
||||||
|
/**
|
||||||
|
* className for the popover
|
||||||
|
*/
|
||||||
|
popoverClassName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type { DateValue };
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
import React from "react";
|
||||||
|
import { objectKeys } from "@appsmith/utils";
|
||||||
|
import { Button, Flex, SIZES } from "@appsmith/wds";
|
||||||
|
import { parseDate } from "@internationalized/date";
|
||||||
|
import type { Meta, StoryObj } from "@storybook/react";
|
||||||
|
|
||||||
|
import { DatePicker } from "../src";
|
||||||
|
/**
|
||||||
|
* A date picker allows a user to select a date.
|
||||||
|
*/
|
||||||
|
const meta: Meta<typeof DatePicker> = {
|
||||||
|
component: DatePicker,
|
||||||
|
title: "WDS/Widgets/DatePicker",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof DatePicker>;
|
||||||
|
|
||||||
|
export const Main: Story = {
|
||||||
|
args: {},
|
||||||
|
render: (args) => (
|
||||||
|
<Flex width="sizing-60">
|
||||||
|
<DatePicker {...args} popoverClassName="sb-unstyled" />
|
||||||
|
</Flex>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WithDefaultValue: Story = {
|
||||||
|
args: {
|
||||||
|
label: "Default Value",
|
||||||
|
value: parseDate("2023-06-15"),
|
||||||
|
},
|
||||||
|
render: (args) => (
|
||||||
|
<Flex width="sizing-60">
|
||||||
|
<DatePicker {...args} popoverClassName="sb-unstyled" />
|
||||||
|
</Flex>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The component supports two sizes `small` and `medium`. Default size is `medium`.
|
||||||
|
*/
|
||||||
|
export const Sizes: Story = {
|
||||||
|
render: () => (
|
||||||
|
<Flex direction="column" gap="spacing-4" width="sizing-60">
|
||||||
|
{objectKeys(SIZES)
|
||||||
|
.filter((size) => !["xSmall", "large"].includes(size))
|
||||||
|
.map((size) => (
|
||||||
|
<DatePicker key={size} popoverClassName="sb-unstyled" size={size} />
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Loading: Story = {
|
||||||
|
args: {
|
||||||
|
isLoading: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Disabled: Story = {
|
||||||
|
args: {
|
||||||
|
isDisabled: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Validation: Story = {
|
||||||
|
render: () => (
|
||||||
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
alert("Form submitted");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Flex direction="column" gap="spacing-5" width="sizing-60">
|
||||||
|
<DatePicker
|
||||||
|
isRequired
|
||||||
|
label="Validation"
|
||||||
|
popoverClassName="sb-unstyled"
|
||||||
|
/>
|
||||||
|
<Button type="submit">Submit</Button>
|
||||||
|
</Flex>
|
||||||
|
</form>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ContextualHelp: Story = {
|
||||||
|
args: {
|
||||||
|
label: "Date",
|
||||||
|
contextualHelp: "Click to open the date picker and select a date",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const MaxDate: Story = {
|
||||||
|
args: {
|
||||||
|
label: "Date",
|
||||||
|
maxValue: parseDate("2024-06-15"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const MinDate: Story = {
|
||||||
|
args: {
|
||||||
|
label: "Date",
|
||||||
|
minValue: parseDate("2024-06-15"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Granularity: Story = {
|
||||||
|
render: () => (
|
||||||
|
<Flex direction="column" gap="spacing-5" width="sizing-100">
|
||||||
|
<DatePicker
|
||||||
|
granularity="day"
|
||||||
|
label="Day"
|
||||||
|
popoverClassName="sb-unstyled"
|
||||||
|
/>
|
||||||
|
<DatePicker
|
||||||
|
granularity="hour"
|
||||||
|
label="Hour"
|
||||||
|
popoverClassName="sb-unstyled"
|
||||||
|
/>
|
||||||
|
<DatePicker
|
||||||
|
granularity="minute"
|
||||||
|
label="Minute"
|
||||||
|
popoverClassName="sb-unstyled"
|
||||||
|
/>
|
||||||
|
<DatePicker
|
||||||
|
granularity="second"
|
||||||
|
label="Second"
|
||||||
|
popoverClassName="sb-unstyled"
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
@ -128,7 +128,15 @@
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
.inputGroup[data-hovered]
|
.inputGroup[data-hovered]
|
||||||
.input:not(:is([data-focused], [data-readonly], [data-disabled])) {
|
.input:not(
|
||||||
|
:is(
|
||||||
|
[data-focused],
|
||||||
|
[data-readonly],
|
||||||
|
[data-disabled],
|
||||||
|
[data-focus-within],
|
||||||
|
:has(~ input[data-disabled="true"])
|
||||||
|
)
|
||||||
|
) {
|
||||||
background-color: var(--color-bg-neutral-subtle-hover);
|
background-color: var(--color-bg-neutral-subtle-hover);
|
||||||
box-shadow: inset 0 0 0 1px var(--color-bd-on-neutral-subtle-hover);
|
box-shadow: inset 0 0 0 1px var(--color-bd-on-neutral-subtle-hover);
|
||||||
}
|
}
|
||||||
|
|
@ -175,8 +183,7 @@
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
.input[data-disabled],
|
.input[data-disabled],
|
||||||
.input[data-disabled] :is(input, textarea),
|
.input:has(~ input[data-disabled]) {
|
||||||
.input[data-disabled] label {
|
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
@ -202,7 +209,7 @@
|
||||||
* FOCUSSED
|
* FOCUSSED
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
.input[data-focused]:not([data-readonly]) {
|
.input:is([data-focused], [data-focus-within]):not([data-readonly]) {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
box-shadow: 0 0 0 2px var(--color-bd-focus);
|
box-shadow: 0 0 0 2px var(--color-bd-focus);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import clsx from "clsx";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { PopoverProps } from "react-aria-components";
|
import type { PopoverProps } from "react-aria-components";
|
||||||
import { Popover as HeadlessPopover } from "react-aria-components";
|
import { Popover as HeadlessPopover } from "react-aria-components";
|
||||||
|
|
@ -5,10 +6,10 @@ import { Popover as HeadlessPopover } from "react-aria-components";
|
||||||
import styles from "./styles.module.css";
|
import styles from "./styles.module.css";
|
||||||
|
|
||||||
export const Popover = (props: PopoverProps) => {
|
export const Popover = (props: PopoverProps) => {
|
||||||
const { children, ...rest } = props;
|
const { children, className, ...rest } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeadlessPopover {...rest} className={styles.popover}>
|
<HeadlessPopover {...rest} className={clsx(styles.popover, className)}>
|
||||||
{children}
|
{children}
|
||||||
</HeadlessPopover>
|
</HeadlessPopover>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ export interface TextProps {
|
||||||
/** Sets the CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. Only use as a **last resort**. Use style props instead. */
|
/** Sets the CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. Only use as a **last resort**. Use style props instead. */
|
||||||
className?: string;
|
className?: string;
|
||||||
/** The children of the component. */
|
/** The children of the component. */
|
||||||
children: ReactNode;
|
children?: ReactNode;
|
||||||
/** title attribute for the component */
|
/** title attribute for the component */
|
||||||
title?: string;
|
title?: string;
|
||||||
/** Sets the HTML [id](https://developer.mozilla.org/en-US/docs/Web/API/Element/id) for the element. */
|
/** Sets the HTML [id](https://developer.mozilla.org/en-US/docs/Web/API/Element/id) for the element. */
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./src";
|
||||||
|
|
@ -3,9 +3,9 @@ import React from "react";
|
||||||
import { FieldError, FieldLabel, Input, inputFieldStyles } from "@appsmith/wds";
|
import { FieldError, FieldLabel, Input, inputFieldStyles } from "@appsmith/wds";
|
||||||
import { TextField as HeadlessTextField } from "react-aria-components";
|
import { TextField as HeadlessTextField } from "react-aria-components";
|
||||||
|
|
||||||
import type { TextInputProps } from "./types";
|
import type { TextFieldProps } from "./types";
|
||||||
|
|
||||||
export function TextInput(props: TextInputProps) {
|
export function TextField(props: TextFieldProps) {
|
||||||
const {
|
const {
|
||||||
contextualHelp,
|
contextualHelp,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./TextField";
|
||||||
|
export type { TextFieldProps } from "./types";
|
||||||
|
|
@ -2,7 +2,7 @@ import type { ReactNode } from "react";
|
||||||
import type { FieldProps, SIZES } from "@appsmith/wds";
|
import type { FieldProps, SIZES } from "@appsmith/wds";
|
||||||
import type { TextFieldProps as AriaTextFieldProps } from "react-aria-components";
|
import type { TextFieldProps as AriaTextFieldProps } from "react-aria-components";
|
||||||
|
|
||||||
export interface TextInputProps extends AriaTextFieldProps, FieldProps {
|
export interface TextFieldProps extends AriaTextFieldProps, FieldProps {
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
suffix?: ReactNode;
|
suffix?: ReactNode;
|
||||||
prefix?: ReactNode;
|
prefix?: ReactNode;
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Form } from "react-aria-components";
|
import { Form } from "react-aria-components";
|
||||||
import type { Meta, StoryObj } from "@storybook/react";
|
import type { Meta, StoryObj } from "@storybook/react";
|
||||||
import { Flex, Icon, TextInput, Button } from "@appsmith/wds";
|
import { Flex, Icon, TextField, Button } from "@appsmith/wds";
|
||||||
|
|
||||||
const meta: Meta<typeof TextInput> = {
|
const meta: Meta<typeof TextField> = {
|
||||||
title: "WDS/Widgets/TextInput",
|
title: "WDS/Widgets/TextField",
|
||||||
component: TextInput,
|
component: TextField,
|
||||||
tags: ["autodocs"],
|
tags: ["autodocs"],
|
||||||
args: {
|
args: {
|
||||||
placeholder: "Write something...",
|
placeholder: "Write something...",
|
||||||
|
|
@ -13,7 +13,7 @@ const meta: Meta<typeof TextInput> = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
type Story = StoryObj<typeof TextInput>;
|
type Story = StoryObj<typeof TextField>;
|
||||||
|
|
||||||
export const Main: Story = {
|
export const Main: Story = {
|
||||||
args: {
|
args: {
|
||||||
|
|
@ -36,12 +36,11 @@ export const WithContextualHelp: Story = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WithPrefixAndSuffix: Story = {
|
export const WithPrefixAndSuffix: Story = {
|
||||||
render: (args) => (
|
render: () => (
|
||||||
<Flex direction="column" gap="spacing-4">
|
<Flex direction="column" gap="spacing-4">
|
||||||
<TextInput {...args} suffix={<Icon name="user" size="medium" />} />
|
<TextField suffix={<Icon name="user" size="medium" />} />
|
||||||
<TextInput {...args} prefix={<Icon name="user" size="medium" />} />
|
<TextField prefix={<Icon name="user" size="medium" />} />
|
||||||
<TextInput
|
<TextField
|
||||||
{...args}
|
|
||||||
prefix={<Icon name="user" size="medium" />}
|
prefix={<Icon name="user" size="medium" />}
|
||||||
suffix={<Icon name="user" size="medium" />}
|
suffix={<Icon name="user" size="medium" />}
|
||||||
/>
|
/>
|
||||||
|
|
@ -79,16 +78,14 @@ export const Readonly: Story = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Size: Story = {
|
export const Size: Story = {
|
||||||
render: (args) => (
|
render: () => (
|
||||||
<Flex direction="column" gap="spacing-4">
|
<Flex direction="column" gap="spacing-4">
|
||||||
<TextInput
|
<TextField
|
||||||
{...args}
|
|
||||||
label="Small"
|
label="Small"
|
||||||
prefix={<Icon name="user" size="medium" />}
|
prefix={<Icon name="user" size="medium" />}
|
||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextField
|
||||||
{...args}
|
|
||||||
label="Medium"
|
label="Medium"
|
||||||
prefix={<Icon name="user" size="medium" />}
|
prefix={<Icon name="user" size="medium" />}
|
||||||
size="medium"
|
size="medium"
|
||||||
|
|
@ -98,11 +95,10 @@ export const Size: Story = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Validation: Story = {
|
export const Validation: Story = {
|
||||||
render: (args) => (
|
render: () => (
|
||||||
<Form onSubmit={(e) => e.preventDefault()}>
|
<Form onSubmit={(e) => e.preventDefault()}>
|
||||||
<Flex direction="column" gap="spacing-3" width="sizing-60">
|
<Flex direction="column" gap="spacing-3" width="sizing-60">
|
||||||
<TextInput
|
<TextField
|
||||||
{...args}
|
|
||||||
errorMessage="Please enter a valid email address"
|
errorMessage="Please enter a valid email address"
|
||||||
isRequired
|
isRequired
|
||||||
label="Email"
|
label="Email"
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
export * from "./TextInput";
|
|
||||||
export type { TextInputProps } from "./types";
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./src";
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
import clsx from "clsx";
|
||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
FieldError,
|
||||||
|
FieldLabel,
|
||||||
|
inputFieldStyles,
|
||||||
|
textInputStyles,
|
||||||
|
dateTimeInputStyles,
|
||||||
|
} from "@appsmith/wds";
|
||||||
|
import {
|
||||||
|
DateInput,
|
||||||
|
DateSegment,
|
||||||
|
Group,
|
||||||
|
TimeField as HeadlessTimeField,
|
||||||
|
type TimeValue,
|
||||||
|
} from "react-aria-components";
|
||||||
|
import { getTypographyClassName } from "@appsmith/wds-theming";
|
||||||
|
|
||||||
|
import type { TimeFieldProps } from "./types";
|
||||||
|
|
||||||
|
export function TimeField<T extends TimeValue>(props: TimeFieldProps<T>) {
|
||||||
|
const {
|
||||||
|
contextualHelp,
|
||||||
|
errorMessage,
|
||||||
|
isDisabled,
|
||||||
|
isInvalid,
|
||||||
|
isReadOnly,
|
||||||
|
isRequired,
|
||||||
|
label,
|
||||||
|
prefix,
|
||||||
|
size = "medium",
|
||||||
|
suffix,
|
||||||
|
value,
|
||||||
|
...rest
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HeadlessTimeField
|
||||||
|
{...rest}
|
||||||
|
className={clsx(inputFieldStyles.field)}
|
||||||
|
data-field=""
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
isInvalid={isInvalid}
|
||||||
|
isReadOnly={isReadOnly}
|
||||||
|
isRequired={isRequired}
|
||||||
|
value={value}
|
||||||
|
>
|
||||||
|
<FieldLabel
|
||||||
|
contextualHelp={contextualHelp}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
isRequired={isRequired}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</FieldLabel>
|
||||||
|
<Group className={textInputStyles.inputGroup}>
|
||||||
|
<DateInput
|
||||||
|
className={clsx(
|
||||||
|
textInputStyles.input,
|
||||||
|
dateTimeInputStyles.input,
|
||||||
|
getTypographyClassName("body"),
|
||||||
|
)}
|
||||||
|
data-date-input
|
||||||
|
data-size={Boolean(size) ? size : undefined}
|
||||||
|
>
|
||||||
|
{(segment) => <DateSegment segment={segment} />}
|
||||||
|
</DateInput>
|
||||||
|
{Boolean(prefix) && <span data-input-prefix>{prefix}</span>}
|
||||||
|
{Boolean(suffix) && <span data-input-suffix>{suffix}</span>}
|
||||||
|
</Group>
|
||||||
|
<FieldError>{errorMessage}</FieldError>
|
||||||
|
</HeadlessTimeField>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
export { TimeField } from "./TimeField";
|
||||||
|
export type { TimeFieldProps } from "./types";
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import type { ReactNode } from "react";
|
||||||
|
import type { FieldProps, SIZES } from "@appsmith/wds";
|
||||||
|
import type {
|
||||||
|
TimeFieldProps as AriaTimeFieldProps,
|
||||||
|
TimeValue,
|
||||||
|
} from "react-aria-components";
|
||||||
|
|
||||||
|
export interface TimeFieldProps<T extends TimeValue>
|
||||||
|
extends AriaTimeFieldProps<T>,
|
||||||
|
FieldProps {
|
||||||
|
suffix?: ReactNode;
|
||||||
|
prefix?: ReactNode;
|
||||||
|
size?: Omit<keyof typeof SIZES, "xSmall">;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
import type { Meta, StoryObj } from "@storybook/react";
|
||||||
|
import { TimeField } from "../src";
|
||||||
|
|
||||||
|
import { Time } from "@internationalized/date";
|
||||||
|
|
||||||
|
const meta: Meta<typeof TimeField> = {
|
||||||
|
title: "WDS/Widgets/TimeField",
|
||||||
|
component: TimeField,
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
component:
|
||||||
|
"A time input component that allows users to enter and select time values.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof TimeField>;
|
||||||
|
|
||||||
|
export const Default: Story = {};
|
||||||
|
|
||||||
|
export const WithLabel: Story = {
|
||||||
|
args: {
|
||||||
|
value: new Time(14, 15),
|
||||||
|
label: "With Label",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Disabled: Story = {
|
||||||
|
args: {
|
||||||
|
label: "Disabled",
|
||||||
|
value: new Time(15, 30),
|
||||||
|
isDisabled: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WithError: Story = {
|
||||||
|
args: {
|
||||||
|
isInvalid: true,
|
||||||
|
value: new Time(9, 45),
|
||||||
|
errorMessage: "Please enter a valid time",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Required: Story = {
|
||||||
|
args: {
|
||||||
|
label: "Required",
|
||||||
|
isRequired: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -21,7 +21,7 @@ export * from "./components/ContextualHelp";
|
||||||
export * from "./components/Link";
|
export * from "./components/Link";
|
||||||
export * from "./components/Popover";
|
export * from "./components/Popover";
|
||||||
export * from "./components/FieldError";
|
export * from "./components/FieldError";
|
||||||
export * from "./components/TextInput";
|
export * from "./components/TextField";
|
||||||
export * from "./components/FieldLabel";
|
export * from "./components/FieldLabel";
|
||||||
export * from "./components/Input";
|
export * from "./components/Input";
|
||||||
export * from "./components/Field";
|
export * from "./components/Field";
|
||||||
|
|
@ -32,6 +32,9 @@ export * from "./components/MenuItem";
|
||||||
export * from "./components/Markdown";
|
export * from "./components/Markdown";
|
||||||
export * from "./components/Sidebar";
|
export * from "./components/Sidebar";
|
||||||
export * from "./components/Sheet";
|
export * from "./components/Sheet";
|
||||||
|
export * from "./components/Calendar";
|
||||||
|
export * from "./components/Datepicker";
|
||||||
|
export * from "./components/TimeField";
|
||||||
|
|
||||||
export * from "./utils";
|
export * from "./utils";
|
||||||
export * from "./hooks";
|
export * from "./hooks";
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import {
|
||||||
ModalBody,
|
ModalBody,
|
||||||
ModalFooter,
|
ModalFooter,
|
||||||
ModalContent,
|
ModalContent,
|
||||||
TextInput,
|
TextField,
|
||||||
ComboBox,
|
ComboBox,
|
||||||
Radio,
|
Radio,
|
||||||
ListBoxItem,
|
ListBoxItem,
|
||||||
|
|
@ -139,7 +139,7 @@ export const ComplexForm = () => {
|
||||||
<TextArea label="Your comment" />
|
<TextArea label="Your comment" />
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex gap="spacing-2">
|
<Flex gap="spacing-2">
|
||||||
<TextInput />
|
<TextField />
|
||||||
<ComboBox>
|
<ComboBox>
|
||||||
{[
|
{[
|
||||||
{
|
{
|
||||||
|
|
@ -167,7 +167,7 @@ export const ComplexForm = () => {
|
||||||
<Button>Ok</Button>
|
<Button>Ok</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex gap="spacing-2">
|
<Flex gap="spacing-2">
|
||||||
<TextInput size="small" />
|
<TextField size="small" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
items={[
|
items={[
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -11,17 +11,17 @@
|
||||||
font-family: var(--font-family) !important;
|
font-family: var(--font-family) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
th, td,
|
th:not(.sb-unstyled th), td:not(.sb-unstyled td),
|
||||||
.css-s230ta {
|
.css-s230ta {
|
||||||
border-color: var(--color-bd) !important;
|
border-color: var(--color-bd) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
td,
|
td:not(.sb-unstyled td),
|
||||||
.css-s230ta {
|
.css-s230ta {
|
||||||
background-color: var(--color-bg-elevation-1) !important;
|
background-color: var(--color-bg-elevation-1) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
code:not(:has(span)),
|
code:not(:has(span)):not(.sb-unstyled code),
|
||||||
.css-o1d7ko {
|
.css-o1d7ko {
|
||||||
background-color: var(--color-bg-accent-subtle) !important;
|
background-color: var(--color-bg-accent-subtle) !important;
|
||||||
color: var(--color-fg-on-accent-subtle) !important;
|
color: var(--color-fg-on-accent-subtle) !important;
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Note: adding this so that all links are styled the same way excepts the one that are in the story */
|
/** Note: adding this so that all links are styled the same way excepts the one that are in the story */
|
||||||
a:not(.docs-story a) {
|
a:not(.docs-story a):not(.sb-unstyled a) {
|
||||||
color: var(--color-fg-accent) !important;
|
color: var(--color-fg-accent) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Text, TextInput } from "@appsmith/wds";
|
import { Text, TextField } from "@appsmith/wds";
|
||||||
import type { CurrencyInputComponentProps } from "./types";
|
import type { CurrencyInputComponentProps } from "./types";
|
||||||
import { CurrencyTypeOptions } from "constants/Currency";
|
import { CurrencyTypeOptions } from "constants/Currency";
|
||||||
import { useDebouncedValue } from "@mantine/hooks";
|
import { useDebouncedValue } from "@mantine/hooks";
|
||||||
|
|
@ -24,7 +24,7 @@ export function CurrencyInputComponent(props: CurrencyInputComponentProps) {
|
||||||
const [errorMessage] = useDebouncedValue(props.errorMessage, DEBOUNCE_TIME);
|
const [errorMessage] = useDebouncedValue(props.errorMessage, DEBOUNCE_TIME);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TextInput
|
<TextField
|
||||||
autoComplete={props.autoComplete}
|
autoComplete={props.autoComplete}
|
||||||
autoFocus={props.autoFocus}
|
autoFocus={props.autoFocus}
|
||||||
contextualHelp={props.tooltip}
|
contextualHelp={props.tooltip}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { isNil } from "lodash";
|
import { isNil } from "lodash";
|
||||||
import { TextInput } from "@appsmith/wds";
|
import { TextField } from "@appsmith/wds";
|
||||||
import { Icon, TextArea } from "@appsmith/wds";
|
import { Icon, TextArea } from "@appsmith/wds";
|
||||||
import { useDebouncedValue } from "@mantine/hooks";
|
import { useDebouncedValue } from "@mantine/hooks";
|
||||||
import { INPUT_TYPES } from "modules/ui-builder/ui/wds/WDSBaseInputWidget";
|
import { INPUT_TYPES } from "modules/ui-builder/ui/wds/WDSBaseInputWidget";
|
||||||
|
|
@ -46,7 +46,7 @@ function InputComponent(props: InputComponentProps) {
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const ElementType: React.ElementType =
|
const ElementType: React.ElementType =
|
||||||
props.inputType === INPUT_TYPES.MULTI_LINE_TEXT ? TextArea : TextInput;
|
props.inputType === INPUT_TYPES.MULTI_LINE_TEXT ? TextArea : TextField;
|
||||||
|
|
||||||
const autoComplete = (() => {
|
const autoComplete = (() => {
|
||||||
if (
|
if (
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { ISDCodeOptions } from "constants/ISDCodes_v2";
|
import { ISDCodeOptions } from "constants/ISDCodes_v2";
|
||||||
import { Text, TextInput } from "@appsmith/wds";
|
import { Text, TextField } from "@appsmith/wds";
|
||||||
|
|
||||||
import type { PhoneInputComponentProps } from "./types";
|
import type { PhoneInputComponentProps } from "./types";
|
||||||
|
|
||||||
|
|
@ -16,7 +16,7 @@ export function PhoneInputComponent(props: PhoneInputComponentProps) {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TextInput
|
<TextField
|
||||||
autoComplete={props.autoComplete}
|
autoComplete={props.autoComplete}
|
||||||
autoFocus={props.autoFocus}
|
autoFocus={props.autoFocus}
|
||||||
contextualHelp={props.tooltip}
|
contextualHelp={props.tooltip}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Keys } from "@blueprintjs/core";
|
import { Keys } from "@blueprintjs/core";
|
||||||
import { TextInput } from "@appsmith/wds";
|
import { TextField } from "@appsmith/wds";
|
||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
|
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
|
||||||
|
|
||||||
|
|
@ -46,7 +46,7 @@ function PageNumberInputComponent(props: {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TextInput
|
<TextField
|
||||||
className="t--table-widget-page-input"
|
className="t--table-widget-page-input"
|
||||||
excludeFromTabOrder={props.excludeFromTabOrder}
|
excludeFromTabOrder={props.excludeFromTabOrder}
|
||||||
isDisabled={props.disabled}
|
isDisabled={props.disabled}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { TextInput } from "@appsmith/wds";
|
import { TextField } from "@appsmith/wds";
|
||||||
|
|
||||||
export interface SearchProps {
|
export interface SearchProps {
|
||||||
isVisibleSearch?: boolean;
|
isVisibleSearch?: boolean;
|
||||||
|
|
@ -12,7 +12,7 @@ export const Search = (props: SearchProps) => {
|
||||||
const { excludeFromTabOrder, isVisibleSearch, onSearch, searchKey } = props;
|
const { excludeFromTabOrder, isVisibleSearch, onSearch, searchKey } = props;
|
||||||
|
|
||||||
return isVisibleSearch ? (
|
return isVisibleSearch ? (
|
||||||
<TextInput
|
<TextField
|
||||||
excludeFromTabOrder={excludeFromTabOrder}
|
excludeFromTabOrder={excludeFromTabOrder}
|
||||||
onChange={onSearch}
|
onChange={onSearch}
|
||||||
placeholder="Search..."
|
placeholder="Search..."
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user