From 2cf7b0322a3ce53472c7aabe303df30f31bb84e8 Mon Sep 17 00:00:00 2001 From: Pawan Kumar Date: Thu, 26 Sep 2024 17:55:12 +0530 Subject: [PATCH 01/12] add datepicker component --- .../widgets/src/components/Calender/index.tsx | 1 + .../src/components/Calender/src/Calendar.tsx | 39 +++++++++++ .../components/Calender/src/CalendarCell.tsx | 18 +++++ .../Calender/src/CalendarHeaderCell.tsx | 19 +++++ .../Calender/src/CalendarHeading.tsx | 21 ++++++ .../src/components/Calender/src/index.ts | 4 ++ .../components/Calender/src/styles.module.css | 66 +++++++++++++++++ .../src/components/Calender/src/types.ts | 10 +++ .../components/ComboBox/src/styles.module.css | 6 ++ .../src/components/DatePicker/index.ts | 1 + .../components/DatePicker/src/DatePicker.tsx | 70 +++++++++++++++++++ .../src/components/DatePicker/src/index.ts | 1 + .../src/components/DatePicker/src/types.ts | 27 +++++++ .../DatePicker/stories/DatePicker.stories.tsx | 41 +++++++++++ .../components/FieldCalenderPopover/index.tsx | 1 + .../src/FieldCalenderPopover.tsx | 17 +++++ .../FieldCalenderPopover/src/index.ts | 1 + .../FieldCalenderPopover/src/types.ts | 0 .../widgets/src/components/Text/src/types.ts | 2 +- .../design-system/widgets/src/index.ts | 2 + .../storybook/.storybook/preview-head.html | 10 --- 21 files changed, 346 insertions(+), 11 deletions(-) create mode 100644 app/client/packages/design-system/widgets/src/components/Calender/index.tsx create mode 100644 app/client/packages/design-system/widgets/src/components/Calender/src/Calendar.tsx create mode 100644 app/client/packages/design-system/widgets/src/components/Calender/src/CalendarCell.tsx create mode 100644 app/client/packages/design-system/widgets/src/components/Calender/src/CalendarHeaderCell.tsx create mode 100644 app/client/packages/design-system/widgets/src/components/Calender/src/CalendarHeading.tsx create mode 100644 app/client/packages/design-system/widgets/src/components/Calender/src/index.ts create mode 100644 app/client/packages/design-system/widgets/src/components/Calender/src/styles.module.css create mode 100644 app/client/packages/design-system/widgets/src/components/Calender/src/types.ts create mode 100644 app/client/packages/design-system/widgets/src/components/DatePicker/index.ts create mode 100644 app/client/packages/design-system/widgets/src/components/DatePicker/src/DatePicker.tsx create mode 100644 app/client/packages/design-system/widgets/src/components/DatePicker/src/index.ts create mode 100644 app/client/packages/design-system/widgets/src/components/DatePicker/src/types.ts create mode 100644 app/client/packages/design-system/widgets/src/components/DatePicker/stories/DatePicker.stories.tsx create mode 100644 app/client/packages/design-system/widgets/src/components/FieldCalenderPopover/index.tsx create mode 100644 app/client/packages/design-system/widgets/src/components/FieldCalenderPopover/src/FieldCalenderPopover.tsx create mode 100644 app/client/packages/design-system/widgets/src/components/FieldCalenderPopover/src/index.ts create mode 100644 app/client/packages/design-system/widgets/src/components/FieldCalenderPopover/src/types.ts diff --git a/app/client/packages/design-system/widgets/src/components/Calender/index.tsx b/app/client/packages/design-system/widgets/src/components/Calender/index.tsx new file mode 100644 index 00000000000..3bd16e178a0 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Calender/index.tsx @@ -0,0 +1 @@ +export * from "./src"; diff --git a/app/client/packages/design-system/widgets/src/components/Calender/src/Calendar.tsx b/app/client/packages/design-system/widgets/src/components/Calender/src/Calendar.tsx new file mode 100644 index 00000000000..21b5afcb8ae --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Calender/src/Calendar.tsx @@ -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 = HeadlessCalendarProps; + +export const Calendar = (props: CalendarProps) => { + return ( + + + + + + + + + {(day) => {day}} + + + {(date) => } + + + + ); +}; diff --git a/app/client/packages/design-system/widgets/src/components/Calender/src/CalendarCell.tsx b/app/client/packages/design-system/widgets/src/components/Calender/src/CalendarCell.tsx new file mode 100644 index 00000000000..4f4d2933439 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Calender/src/CalendarCell.tsx @@ -0,0 +1,18 @@ +import React from "react"; +import { Text } from "@appsmith/wds"; +import { CalendarCell as HeadlessCalendarCell } from "react-aria-components"; + +import styles from "./styles.module.css"; +import type { CalendarCellProps } from "./types"; + +function CalendarCell(props: CalendarCellProps) { + const { date } = props; + + return ( + + {date.day} + + ); +} + +export { CalendarCell }; diff --git a/app/client/packages/design-system/widgets/src/components/Calender/src/CalendarHeaderCell.tsx b/app/client/packages/design-system/widgets/src/components/Calender/src/CalendarHeaderCell.tsx new file mode 100644 index 00000000000..23e5527d078 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Calender/src/CalendarHeaderCell.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import { Text } from "@appsmith/wds"; +import { CalendarHeaderCell as HeadlessCalendarHeaderCell } from "react-aria-components"; + +import type { CalendarHeaderCellProps } from "./types"; + +function CalendarHeaderCell(props: CalendarHeaderCellProps) { + const { children } = props; + + return ( + + + {children} + + + ); +} + +export { CalendarHeaderCell }; diff --git a/app/client/packages/design-system/widgets/src/components/Calender/src/CalendarHeading.tsx b/app/client/packages/design-system/widgets/src/components/Calender/src/CalendarHeading.tsx new file mode 100644 index 00000000000..6da15fee57f --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Calender/src/CalendarHeading.tsx @@ -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, +) { + [props, ref] = useContextProps(props, ref, HeadingContext); + const { children, ...domProps } = props; + + return ( + + {children} + + ); +} + +const _CalendarHeading = forwardRef(CalendarHeading); + +export { _CalendarHeading as CalendarHeading }; diff --git a/app/client/packages/design-system/widgets/src/components/Calender/src/index.ts b/app/client/packages/design-system/widgets/src/components/Calender/src/index.ts new file mode 100644 index 00000000000..2a316877fdc --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Calender/src/index.ts @@ -0,0 +1,4 @@ +export { Calendar } from "./Calendar"; +export { CalendarCell } from "./CalendarCell"; +export { CalendarHeading } from "./CalendarHeading"; +export { CalendarHeaderCell } from "./CalendarHeaderCell"; diff --git a/app/client/packages/design-system/widgets/src/components/Calender/src/styles.module.css b/app/client/packages/design-system/widgets/src/components/Calender/src/styles.module.css new file mode 100644 index 00000000000..b8c09a2a06b --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Calender/src/styles.module.css @@ -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], +.calendar tbody [role="button"][data-focused] { + border-color: var(--color-bd-accent); +} diff --git a/app/client/packages/design-system/widgets/src/components/Calender/src/types.ts b/app/client/packages/design-system/widgets/src/components/Calender/src/types.ts new file mode 100644 index 00000000000..d6a99964fc0 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Calender/src/types.ts @@ -0,0 +1,10 @@ +import { + type CalendarCellProps as HeadlessCalendarCellProps, + type CalendarHeaderCellProps as HeadlessCalendarHeaderCellProps, +} from "react-aria-components"; + +export type CalendarCellProps = HeadlessCalendarCellProps & + React.RefAttributes; + +export type CalendarHeaderCellProps = HeadlessCalendarHeaderCellProps & + React.RefAttributes; diff --git a/app/client/packages/design-system/widgets/src/components/ComboBox/src/styles.module.css b/app/client/packages/design-system/widgets/src/components/ComboBox/src/styles.module.css index 7a9ecadc7e3..0c1e62fe6cf 100644 --- a/app/client/packages/design-system/widgets/src/components/ComboBox/src/styles.module.css +++ b/app/client/packages/design-system/widgets/src/components/ComboBox/src/styles.module.css @@ -31,6 +31,12 @@ padding-inline: var(--inner-spacing-2); } +.input:is([data-date-input]) { + display: flex; + gap: var(--inner-spacing-2); + align-items: center; +} + .inputWrapper:has([data-hovered]) { background-color: var(--color-bg-neutral-subtle-hover); box-shadow: inset 0 0 0 1px var(--color-bd-on-neutral-subtle-hover); diff --git a/app/client/packages/design-system/widgets/src/components/DatePicker/index.ts b/app/client/packages/design-system/widgets/src/components/DatePicker/index.ts new file mode 100644 index 00000000000..3bd16e178a0 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/DatePicker/index.ts @@ -0,0 +1 @@ +export * from "./src"; diff --git a/app/client/packages/design-system/widgets/src/components/DatePicker/src/DatePicker.tsx b/app/client/packages/design-system/widgets/src/components/DatePicker/src/DatePicker.tsx new file mode 100644 index 00000000000..e0bdf7ffb35 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/DatePicker/src/DatePicker.tsx @@ -0,0 +1,70 @@ +import { + FieldError, + FieldDescription, + FieldLabel, + FieldCalenderPopover, + Button, +} from "@appsmith/wds"; +import { getTypographyClassName } from "@appsmith/wds-theming"; +import clsx from "clsx"; +import React from "react"; +import { + DateInput, + DateSegment, + Group, + DatePicker as HeadlessDatePicker, +} from "react-aria-components"; + +import type { DatePickerProps } from "./types"; +import styles from "../../ComboBox/src/styles.module.css"; + +export const DatePicker = (props: DatePickerProps) => { + const { + contextualHelp, + description, + errorMessage, + isLoading, + isRequired, + label, + size = "medium", + ...rest + } = props; + + return ( + + {({ isInvalid }) => ( + <> + + + + {(segment) => } + + + + + ), +}; + +export const ContextualHelp: Story = { + args: { + label: "Date", + placeholder: "Select a date", + contextualHelp: "Click to open the date picker and select a date", + }, +}; + +export const MaxDate: Story = { + args: { + label: "Date", + placeholder: "Select a date", + maxValue: parseDate("2023-06-15"), + }, +}; + +export const MinDate: Story = { + args: { + label: "Date", + placeholder: "Select a date", + minValue: parseDate("2023-06-15"), + }, +}; + +export const Granularity: Story = { + render: () => ( + + + + + + + ), +}; diff --git a/app/client/packages/design-system/widgets/src/index.ts b/app/client/packages/design-system/widgets/src/index.ts index a347f8a4121..23bd1f78aea 100644 --- a/app/client/packages/design-system/widgets/src/index.ts +++ b/app/client/packages/design-system/widgets/src/index.ts @@ -27,6 +27,7 @@ export * from "./components/FieldDescription"; export * from "./components/FieldListPopover"; export * from "./components/FieldCalenderPopover"; export * from "./components/Calender"; +export * from "./components/DatePicker"; export * from "./utils"; export * from "./styles"; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/anvilConfig.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/anvilConfig.ts new file mode 100644 index 00000000000..dc7fe21e103 --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/anvilConfig.ts @@ -0,0 +1,11 @@ +import type { AnvilConfig } from "WidgetProvider/constants"; + +export const anvilConfig: AnvilConfig = { + isLargeWidget: false, + widgetSize: { + minWidth: { + base: "100%", + "180px": "sizing-30", + }, + }, +}; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/autocompleteConfig.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/autocompleteConfig.ts new file mode 100644 index 00000000000..456e9ec2565 --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/autocompleteConfig.ts @@ -0,0 +1,11 @@ +import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils"; + +export const autocompleteConfig = { + "!doc": + "Datepicker is used to capture the date and time from a user. It can be used to filter data base on the input date range as well as to capture personal information such as date of birth", + "!url": "https://docs.appsmith.com/widget-reference/datepicker", + isVisible: DefaultAutocompleteDefinitions.isVisible, + selectedDate: "string", + formattedDate: "string", + isDisabled: "bool", +}; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/defaultsConfig.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/defaultsConfig.ts new file mode 100644 index 00000000000..11395d74024 --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/defaultsConfig.ts @@ -0,0 +1,17 @@ +import { ResponsiveBehavior } from "layoutSystems/common/utils/constants"; +import type { WidgetDefaultProps } from "WidgetProvider/constants"; + +export const defaultsConfig = { + animateLoading: true, + label: "Label", + dateFormat: "YYYY-MM-DD HH:mm", + defaultOptionValue: "", + isRequired: false, + isDisabled: false, + isVisible: true, + isInline: false, + widgetName: "DatePicker", + widgetType: "WDS_DATE_PICKER", + version: 1, + responsiveBehavior: ResponsiveBehavior.Fill, +} as unknown as WidgetDefaultProps; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/index.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/index.ts new file mode 100644 index 00000000000..995925903b3 --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/index.ts @@ -0,0 +1,7 @@ +export * from "./propertyPaneConfig"; +export { metaConfig } from "./metaConfig"; +export { anvilConfig } from "./anvilConfig"; +export { defaultsConfig } from "./defaultsConfig"; +export { settersConfig } from "./settersConfig"; +export { methodsConfig } from "./methodsConfig"; +export { autocompleteConfig } from "./autocompleteConfig"; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/metaConfig.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/metaConfig.ts new file mode 100644 index 00000000000..cad264799b1 --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/metaConfig.ts @@ -0,0 +1,14 @@ +import { WIDGET_TAGS } from "constants/WidgetConstants"; + +export const metaConfig = { + name: "DatePicker", + tags: [WIDGET_TAGS.INPUTS], + needsMeta: true, + searchTags: [ + "date", + "picker", + "date picker", + "date time", + "date time picker", + ], +}; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/methodsConfig.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/methodsConfig.ts new file mode 100644 index 00000000000..ead8d260433 --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/methodsConfig.ts @@ -0,0 +1,6 @@ +import { ComboboxSelectIcon, ComboboxSelectThumbnail } from "appsmith-icons"; + +export const methodsConfig = { + IconCmp: ComboboxSelectIcon, + ThumbnailCmp: ComboboxSelectThumbnail, +}; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/propertyPaneConfig/contentConfig.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/propertyPaneConfig/contentConfig.ts new file mode 100644 index 00000000000..11eddd1f0d6 --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/propertyPaneConfig/contentConfig.ts @@ -0,0 +1,183 @@ +import { ValidationTypes } from "constants/WidgetValidation"; +import { DATE_FORMAT_OPTIONS } from "../../constants"; + +export const propertyPaneContentConfig = [ + { + sectionName: "Data", + children: [ + { + helpText: "Sets the format of the selected date", + propertyName: "dateFormat", + label: "Date format", + controlType: "DROP_DOWN", + isJSConvertible: true, + optionWidth: "340px", + options: DATE_FORMAT_OPTIONS, + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.TEXT }, + hideSubText: true, + }, + { + propertyName: "defaultDate", + label: "Default Date", + helpText: + "Sets the default date of the widget. The date is updated if the default date changes", + controlType: "DATE_PICKER", + placeholderText: "Enter Default Date", + useValidationMessage: true, + isJSConvertible: true, + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.DATE_ISO_STRING }, + }, + { + propertyName: "timePrecision", + label: "Time Precision", + controlType: "DROP_DOWN", + helpText: "Sets the different time picker or hide.", + defaultValue: "day", + options: [ + { + label: "Day", + value: "day", + }, + { + label: "Hour", + value: "hour", + }, + { + label: "Minute", + value: "minute", + }, + { + label: "Second", + value: "second", + }, + ], + isJSConvertible: true, + isBindProperty: true, + isTriggerProperty: false, + validation: { + type: ValidationTypes.TEXT, + params: { + allowedValues: ["day", "hour", "minute", "second"], + default: "day", + }, + }, + }, + ], + }, + { + sectionName: "Label", + children: [ + { + helpText: "Sets the label text of the options widget", + propertyName: "label", + label: "Text", + controlType: "INPUT_TEXT", + placeholderText: "Label", + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.TEXT }, + }, + ], + }, + { + sectionName: "Validations", + children: [ + { + propertyName: "isRequired", + label: "Required", + helpText: "Makes input to the widget mandatory", + controlType: "SWITCH", + isJSConvertible: true, + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.BOOLEAN }, + }, + { + propertyName: "minDate", + label: "Minimum Date", + helpText: "Sets the minimum date that can be selected", + controlType: "DATE_PICKER", + placeholderText: "Enter Minimum Date", + isJSConvertible: true, + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.DATE_ISO_STRING }, + }, + { + propertyName: "maxDate", + label: "Maximum Date", + helpText: "Sets the maximum date that can be selected", + controlType: "DATE_PICKER", + placeholderText: "Enter Maximum Date", + isJSConvertible: true, + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.DATE_ISO_STRING }, + }, + ], + }, + { + sectionName: "General", + children: [ + { + helpText: "Show help text or details about current input", + propertyName: "labelTooltip", + label: "Tooltip", + controlType: "INPUT_TEXT", + placeholderText: "", + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.TEXT }, + }, + { + helpText: "Controls the visibility of the widget", + propertyName: "isVisible", + label: "Visible", + controlType: "SWITCH", + isJSConvertible: true, + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.BOOLEAN }, + }, + { + propertyName: "isDisabled", + label: "Disabled", + helpText: "Disables input to this widget", + controlType: "SWITCH", + isJSConvertible: true, + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.BOOLEAN }, + }, + { + propertyName: "animateLoading", + label: "Animate loading", + controlType: "SWITCH", + helpText: "Controls the loading of the widget", + defaultValue: true, + isJSConvertible: true, + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.BOOLEAN }, + }, + ], + }, + { + sectionName: "Events", + children: [ + { + propertyName: "onDateSelected", + label: "onDateSelected", + helpText: "when a date is selected in the calendar", + controlType: "ACTION_SELECTOR", + isJSConvertible: true, + isBindProperty: true, + isTriggerProperty: true, + }, + ], + }, +]; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/propertyPaneConfig/index.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/propertyPaneConfig/index.ts new file mode 100644 index 00000000000..7f43d3bde57 --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/propertyPaneConfig/index.ts @@ -0,0 +1 @@ +export { propertyPaneContentConfig } from "./contentConfig"; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/settersConfig.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/settersConfig.ts new file mode 100644 index 00000000000..888f2f9bcb7 --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/settersConfig.ts @@ -0,0 +1,12 @@ +export const settersConfig = { + __setters: { + setVisibility: { + path: "isVisible", + type: "boolean", + }, + setDisabled: { + path: "isDisabled", + type: "boolean", + }, + }, +}; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/constants.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/constants.ts new file mode 100644 index 00000000000..3b53c462e71 --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/constants.ts @@ -0,0 +1,88 @@ +import moment from "moment"; +import { SubTextPosition } from "components/constants"; + +export const DATE_FORMAT_OPTIONS = [ + { + label: moment().format("YYYY-MM-DDTHH:mm:ss.sssZ"), + subText: "ISO 8601", + value: "YYYY-MM-DDTHH:mm:ss.sssZ", + }, + { + label: moment().format("LLL"), + subText: "LLL", + value: "LLL", + }, + { + label: moment().format("LL"), + subText: "LL", + value: "LL", + }, + { + label: moment().format("YYYY-MM-DD HH:mm"), + subText: "YYYY-MM-DD HH:mm", + value: "YYYY-MM-DD HH:mm", + }, + { + label: moment().format("YYYY-MM-DDTHH:mm:ss"), + subText: "YYYY-MM-DDTHH:mm:ss", + value: "YYYY-MM-DDTHH:mm:ss", + }, + { + label: moment().format("YYYY-MM-DD hh:mm:ss A"), + subText: "YYYY-MM-DD hh:mm:ss A", + value: "YYYY-MM-DD hh:mm:ss A", + }, + { + label: moment().format("DD/MM/YYYY HH:mm"), + subText: "DD/MM/YYYY HH:mm", + value: "DD/MM/YYYY HH:mm", + }, + { + label: moment().format("D MMMM, YYYY"), + subText: "D MMMM, YYYY", + value: "D MMMM, YYYY", + }, + { + label: moment().format("H:mm A D MMMM, YYYY"), + subText: "H:mm A D MMMM, YYYY", + value: "H:mm A D MMMM, YYYY", + }, + { + label: moment().format("YYYY-MM-DD"), + subText: "YYYY-MM-DD", + value: "YYYY-MM-DD", + }, + { + label: moment().format("MM-DD-YYYY"), + subText: "MM-DD-YYYY", + value: "MM-DD-YYYY", + }, + { + label: moment().format("DD-MM-YYYY"), + subText: "DD-MM-YYYY", + value: "DD-MM-YYYY", + }, + { + label: moment().format("MM/DD/YYYY"), + subText: "MM/DD/YYYY", + value: "MM/DD/YYYY", + }, + { + label: moment().format("DD/MM/YYYY"), + subText: "DD/MM/YYYY", + value: "DD/MM/YYYY", + }, + { + label: moment().format("DD/MM/YY"), + subText: "DD/MM/YY", + value: "DD/MM/YY", + }, + { + label: moment().format("MM/DD/YY"), + subText: "MM/DD/YY", + value: "MM/DD/YY", + }, +].map((x) => ({ + ...x, + subTextPosition: SubTextPosition.BOTTOM, +})); diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/index.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/index.ts new file mode 100644 index 00000000000..8c35d8ef178 --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/index.ts @@ -0,0 +1,3 @@ +import { WDSDatePickerWidget } from "./widget"; + +export { WDSDatePickerWidget }; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/derived.js b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/derived.js new file mode 100644 index 00000000000..7e4be5805db --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/derived.js @@ -0,0 +1,36 @@ +export default { + isValid: (props, moment) => { + const parsedMinDate = new Date(props.minDate); + const parsedMaxDate = new Date(props.maxDate); + const parsedSelectedDate = props.selectedDate + ? moment(new Date(props.selectedDate)) + : null; + + // only do validation when the date is dirty + if (!props.isDirty) { + return true; + } + + if (!parsedSelectedDate && !props.isRequired) { + return true; + } + + if (!parsedSelectedDate && props.isRequired) { + return false; + } + + if (props.minDate && props.maxDate) { + return parsedSelectedDate.isBetween(parsedMinDate, parsedMaxDate); + } + + if (props.minDate) { + return parsedSelectedDate.isAfter(parsedMinDate); + } + + if (props.maxDate) { + return parsedSelectedDate.isBefore(parsedMaxDate); + } + + return true; + }, +}; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/derived.test.js b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/derived.test.js new file mode 100644 index 00000000000..3108e948227 --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/derived.test.js @@ -0,0 +1,64 @@ +import moment from "moment"; +import derived from "./derived"; + +describe("isValid function", () => { + const mockMoment = (date) => moment(date); + + it("should return true when isDirty is false", () => { + const props = { isDirty: false }; + + expect(derived.isValid(props, mockMoment)).toBe(true); + }); + + it("should return true when selectedDate is null and not required", () => { + const props = { isDirty: true, isRequired: false, selectedDate: null }; + + expect(derived.isValid(props, mockMoment)).toBe(true); + }); + + it("should return false when selectedDate is null and required", () => { + const props = { isDirty: true, isRequired: true, selectedDate: null }; + + expect(derived.isValid(props, mockMoment)).toBe(false); + }); + + it("should return true when selectedDate is between minDate and maxDate", () => { + const props = { + isDirty: true, + minDate: "2023-01-01", + maxDate: "2023-12-31", + selectedDate: "2023-06-15", + }; + + expect(derived.isValid(props, mockMoment)).toBe(true); + }); + + it("should return false when selectedDate is before minDate", () => { + const props = { + isDirty: true, + minDate: "2023-01-01", + selectedDate: "2022-12-31", + }; + + expect(derived.isValid(props, mockMoment)).toBe(false); + }); + + it("should return false when selectedDate is after maxDate", () => { + const props = { + isDirty: true, + maxDate: "2023-12-31", + selectedDate: "2024-01-01", + }; + + expect(derived.isValid(props, mockMoment)).toBe(false); + }); + + it("should return true when selectedDate is valid and no min/max dates are set", () => { + const props = { + isDirty: true, + selectedDate: "2023-06-15", + }; + + expect(derived.isValid(props, mockMoment)).toBe(true); + }); +}); diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/helpers.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/helpers.ts new file mode 100644 index 00000000000..3126ddfb9e4 --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/helpers.ts @@ -0,0 +1,15 @@ +import type { WDSDatePickerWidgetProps } from "./types"; + +export function validateInput(props: WDSDatePickerWidgetProps) { + if (!props.isValid) { + return { + validationStatus: "invalid", + errorMessage: "Please select a valid date", + }; + } + + return { + validationStatus: "valid", + errorMessage: "", + }; +} diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/index.tsx b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/index.tsx new file mode 100644 index 00000000000..e36e2a58703 --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/index.tsx @@ -0,0 +1,149 @@ +import React from "react"; +import moment from "moment"; +import BaseWidget from "widgets/BaseWidget"; +import type { WidgetState } from "widgets/BaseWidget"; +import type { + AnvilConfig, + AutocompletionDefinitions, +} from "WidgetProvider/constants"; +import { parseDateTime } from "@internationalized/date"; +import { DatePicker, type DateValue } from "@appsmith/wds"; +import { EventType } from "constants/AppsmithActionConstants/ActionConstants"; + +import * as config from "../config"; +import { validateInput } from "./helpers"; +import derivedPropertyFns from "./derived"; +import type { WDSDatePickerWidgetProps } from "./types"; +import { parseDerivedProperties } from "widgets/WidgetUtils"; + +class WDSDatePickerWidget extends BaseWidget< + WDSDatePickerWidgetProps, + WidgetState +> { + static type = "WDS_DATEPICKER_WIDGET"; + + static getConfig() { + return config.metaConfig; + } + + static getDefaults() { + return config.defaultsConfig; + } + + static getMethods() { + return config.methodsConfig; + } + + static getAnvilConfig(): AnvilConfig | null { + return config.anvilConfig; + } + + static getAutocompleteDefinitions(): AutocompletionDefinitions { + return config.autocompleteConfig; + } + + static getPropertyPaneContentConfig() { + return config.propertyPaneContentConfig; + } + + static getPropertyPaneStyleConfig() { + return []; + } + + static getDerivedPropertiesMap() { + const parsedDerivedProperties = parseDerivedProperties(derivedPropertyFns); + + return { + isValid: `{{(() => {${parsedDerivedProperties.isValid}})()}}`, + selectedDate: `{{ this.value ? moment(this.value).toISOString() : "" }}`, + formattedDate: `{{ this.value ? moment(this.value).format(this.dateFormat) : "" }}`, + }; + } + + static getDefaultPropertiesMap(): Record { + return { + value: "defaultDate", + }; + } + + static getMetaPropertiesMap() { + return { + value: undefined, + isDirty: false, + }; + } + + static getStylesheetConfig() { + return {}; + } + + static getSetterConfig() { + return config.settersConfig; + } + + static getDependencyMap() { + return {}; + } + + componentDidUpdate(prevProps: WDSDatePickerWidgetProps): void { + if (!this.shouldResetDirtyState(prevProps)) { + return; + } + + this.resetDirtyState(); + } + + handleDateChange = (date: DateValue) => { + if (!this.props.isDirty) { + this.props.updateWidgetMetaProperty("isDirty", true); + } + + this.props.updateWidgetMetaProperty("value", date.toString(), { + triggerPropertyName: "onDateSelected", + dynamicString: this.props.onDateSelected, + event: { + type: EventType.ON_DATE_SELECTED, + }, + }); + }; + + private shouldResetDirtyState(prevProps: WDSDatePickerWidgetProps): boolean { + const { defaultDate, isDirty } = this.props; + const hasDefaultDateChanged = defaultDate !== prevProps.defaultDate; + + return hasDefaultDateChanged && isDirty; + } + + private resetDirtyState() { + this.props.updateWidgetMetaProperty("isDirty", false); + } + + private parseDate(date: string | undefined) { + return date + ? parseDateTime(moment(date).format("YYYY-MM-DDTHH:mm:ss")) + : undefined; + } + + getWidgetView() { + const { label, labelTooltip, maxDate, minDate, value, ...rest } = + this.props; + const { errorMessage, validationStatus } = validateInput(this.props); + + return ( + + ); + } +} + +export { WDSDatePickerWidget }; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/types.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/types.ts new file mode 100644 index 00000000000..1fa58c81458 --- /dev/null +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/types.ts @@ -0,0 +1,11 @@ +import type { WidgetProps } from "widgets/BaseWidget"; + +export interface WDSDatePickerWidgetProps extends WidgetProps { + selectedDate: string; + defaultDate: string; + onDateSelected: string; + isRequired?: boolean; + isDisabled?: boolean; + label: string; + labelTooltip?: string; +} diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/widget/index.tsx b/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/widget/index.tsx index 5eec9a47efe..4d7c7b87030 100644 --- a/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/widget/index.tsx +++ b/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/widget/index.tsx @@ -7,13 +7,14 @@ import { mergeWidgetConfig } from "utils/helpers"; import { parseText, validateInput } from "./helper"; import type { WidgetState } from "widgets/BaseWidget"; import type { SetterConfig } from "entities/AppTheming"; -import derivedProperties from "./parsedDerivedProperties"; import { WDSBaseInputWidget } from "../../WDSBaseInputWidget"; import type { DerivedPropertiesMap } from "WidgetProvider/factory"; import { EventType } from "constants/AppsmithActionConstants/ActionConstants"; import type { KeyDownEvent } from "modules/ui-builder/ui/wds/WDSBaseInputWidget/component/types"; import type { WidgetBaseConfiguration } from "WidgetProvider/constants"; import { INPUT_TYPES } from "modules/ui-builder/ui/wds/WDSBaseInputWidget/constants"; +import { parseDerivedProperties } from "widgets/WidgetUtils"; +import derivedPropertyFns from "./derived"; class WDSInputWidget extends WDSBaseInputWidget { static type = "WDS_INPUT_WIDGET"; @@ -52,8 +53,10 @@ class WDSInputWidget extends WDSBaseInputWidget { } static getDerivedPropertiesMap(): DerivedPropertiesMap { + const parsedDerivedProperties = parseDerivedProperties(derivedPropertyFns); + return merge(super.getDerivedPropertiesMap(), { - isValid: `{{(() => {${derivedProperties.isValid}})()}}`, + isValid: `{{(() => {${parsedDerivedProperties.isValid}})()}}`, }); } diff --git a/app/client/src/modules/ui-builder/ui/wds/constants.ts b/app/client/src/modules/ui-builder/ui/wds/constants.ts index 94cd6d91555..f3f8282a429 100644 --- a/app/client/src/modules/ui-builder/ui/wds/constants.ts +++ b/app/client/src/modules/ui-builder/ui/wds/constants.ts @@ -59,6 +59,7 @@ export const WDS_V2_WIDGET_MAP = { MULTILINE_INPUT_WIDGET: "WDS_MULTILINE_INPUT_WIDGET", WDS_SELECT_WIDGET: "WDS_SELECT_WIDGET", WDS_COMBOBOX_WIDGET: "WDS_COMBOBOX_WIDGET", + WDS_DATEPICKER_WIDGET: "WDS_DATEPICKER_WIDGET", // Anvil layout widgets ZONE_WIDGET: anvilWidgets.ZONE_WIDGET, diff --git a/app/client/src/widgets/WidgetUtils.ts b/app/client/src/widgets/WidgetUtils.ts index 8a0a7c33e2f..5ef36f98e66 100644 --- a/app/client/src/widgets/WidgetUtils.ts +++ b/app/client/src/widgets/WidgetUtils.ts @@ -989,3 +989,45 @@ export const checkForOnClick = (e: React.MouseEvent) => { return false; }; + +/** + * Parses the derived properties from the given property functions. Used in getDerivedPropertiesMap + * + * For e.g + * If the input is + * ```js + * { + * isValidDate: (props, moment, _) => { + * return props.value === 1; + * } + * ``` + * + * It will return + * ```js + * { + * isValidDate: "{{ this.value === 1 }}" + * } + * ``` + * + * Main rule to remember is don't use deconstruct the props like `const { value } = props;` in the derived property function. Directly access props like `props.value` + * (Reason is we replace props.value with this.value in the derived property function) + * @param propertyFns + * @returns + */ +export function parseDerivedProperties(propertyFns: Record) { + const derivedProperties: Record = {}; + + for (const [key, value] of Object.entries(propertyFns)) { + if (typeof value === "function") { + const functionBody = value.toString().match(/(?<=\{)(.|\n)*(?=\})/)?.[0]; + + if (functionBody) { + derivedProperties[key] = functionBody + .trim() + .replace(/props\./g, "this."); + } + } + } + + return derivedProperties; +} diff --git a/app/client/src/widgets/index.ts b/app/client/src/widgets/index.ts index f3d09da26f1..2e03f26a38c 100644 --- a/app/client/src/widgets/index.ts +++ b/app/client/src/widgets/index.ts @@ -87,6 +87,7 @@ import { WDSPasswordInputWidget } from "modules/ui-builder/ui/wds/WDSPasswordInp import { WDSNumberInputWidget } from "modules/ui-builder/ui/wds/WDSNumberInputWidget"; import { WDSMultilineInputWidget } from "modules/ui-builder/ui/wds/WDSMultilineInputWidget"; import { WDSSelectWidget } from "modules/ui-builder/ui/wds/WDSSelectWidget"; +import { WDSDatePickerWidget } from "modules/ui-builder/ui/wds/WDSDatePickerWidget"; const LegacyWidgets = [ CanvasWidget, @@ -185,6 +186,7 @@ const WDSWidgets = [ WDSNumberInputWidget, WDSMultilineInputWidget, WDSSelectWidget, + WDSDatePickerWidget, ]; const Widgets = [ From 7f8c87ace6829809d98837b94e72285fd7e10399 Mon Sep 17 00:00:00 2001 From: Pawan Kumar Date: Mon, 30 Sep 2024 12:33:25 +0530 Subject: [PATCH 03/12] update gap --- .../widgets/src/components/ComboBox/src/styles.module.css | 2 +- .../icons/src/components/Icons/ComboboxSelectIcon.tsx | 2 +- .../packages/icons/src/components/Icons/DatePickerIcon.tsx | 2 ++ .../icons/src/components/Thumbnails/DatePickerThumbnail.tsx | 2 ++ .../packages/icons/src/icons/Icons/ComboboxSelect.svg | 2 +- app/client/packages/icons/src/icons/Icons/DatePicker.svg | 1 + .../packages/icons/src/icons/Thumbnails/DatePicker.svg | 1 + app/client/packages/icons/src/index.ts | 2 ++ app/client/packages/icons/src/stories/Icons.mdx | 4 ++++ app/client/packages/icons/src/stories/Thumbnails.mdx | 4 ++++ .../ui/wds/WDSDatePickerWidget/config/methodsConfig.ts | 6 +++--- 11 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 app/client/packages/icons/src/components/Icons/DatePickerIcon.tsx create mode 100644 app/client/packages/icons/src/components/Thumbnails/DatePickerThumbnail.tsx create mode 100644 app/client/packages/icons/src/icons/Icons/DatePicker.svg create mode 100644 app/client/packages/icons/src/icons/Thumbnails/DatePicker.svg diff --git a/app/client/packages/design-system/widgets/src/components/ComboBox/src/styles.module.css b/app/client/packages/design-system/widgets/src/components/ComboBox/src/styles.module.css index 700ce5ba264..58b639c17c8 100644 --- a/app/client/packages/design-system/widgets/src/components/ComboBox/src/styles.module.css +++ b/app/client/packages/design-system/widgets/src/components/ComboBox/src/styles.module.css @@ -33,7 +33,7 @@ .input:is([data-date-input]) { display: flex; - gap: var(--inner-spacing-1); + gap: calc(var(--inner-spacing-1) / 2); align-items: center; } diff --git a/app/client/packages/icons/src/components/Icons/ComboboxSelectIcon.tsx b/app/client/packages/icons/src/components/Icons/ComboboxSelectIcon.tsx index 97516278935..a5543679b2b 100644 --- a/app/client/packages/icons/src/components/Icons/ComboboxSelectIcon.tsx +++ b/app/client/packages/icons/src/components/Icons/ComboboxSelectIcon.tsx @@ -1,2 +1,2 @@ import React from "react"; -export const ComboboxSelectIcon = () => ; +export const ComboboxSelectIcon = () => ; diff --git a/app/client/packages/icons/src/components/Icons/DatePickerIcon.tsx b/app/client/packages/icons/src/components/Icons/DatePickerIcon.tsx new file mode 100644 index 00000000000..663d3e8c330 --- /dev/null +++ b/app/client/packages/icons/src/components/Icons/DatePickerIcon.tsx @@ -0,0 +1,2 @@ +import React from "react"; +export const DatePickerIcon = () => ; diff --git a/app/client/packages/icons/src/components/Thumbnails/DatePickerThumbnail.tsx b/app/client/packages/icons/src/components/Thumbnails/DatePickerThumbnail.tsx new file mode 100644 index 00000000000..1a7e6760799 --- /dev/null +++ b/app/client/packages/icons/src/components/Thumbnails/DatePickerThumbnail.tsx @@ -0,0 +1,2 @@ +import React from "react"; +export const DatePickerThumbnail = () => ; diff --git a/app/client/packages/icons/src/icons/Icons/ComboboxSelect.svg b/app/client/packages/icons/src/icons/Icons/ComboboxSelect.svg index 3c6cf838139..10bb6dca5d4 100644 --- a/app/client/packages/icons/src/icons/Icons/ComboboxSelect.svg +++ b/app/client/packages/icons/src/icons/Icons/ComboboxSelect.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/client/packages/icons/src/icons/Icons/DatePicker.svg b/app/client/packages/icons/src/icons/Icons/DatePicker.svg new file mode 100644 index 00000000000..063d40f8d30 --- /dev/null +++ b/app/client/packages/icons/src/icons/Icons/DatePicker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/client/packages/icons/src/icons/Thumbnails/DatePicker.svg b/app/client/packages/icons/src/icons/Thumbnails/DatePicker.svg new file mode 100644 index 00000000000..aef6eac4db9 --- /dev/null +++ b/app/client/packages/icons/src/icons/Thumbnails/DatePicker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/client/packages/icons/src/index.ts b/app/client/packages/icons/src/index.ts index cba21a55375..125a93430f5 100644 --- a/app/client/packages/icons/src/index.ts +++ b/app/client/packages/icons/src/index.ts @@ -3,6 +3,7 @@ export { CheckboxGroupThumbnail } from "./components/Thumbnails/CheckboxGroupThu export { CheckboxThumbnail } from "./components/Thumbnails/CheckboxThumbnail"; export { ComboboxSelectThumbnail } from "./components/Thumbnails/ComboboxSelectThumbnail"; export { CurrencyInputThumbnail } from "./components/Thumbnails/CurrencyInputThumbnail"; +export { DatePickerThumbnail } from "./components/Thumbnails/DatePickerThumbnail"; export { EmailInputThumbnail } from "./components/Thumbnails/EmailInputThumbnail"; export { HeadingThumbnail } from "./components/Thumbnails/HeadingThumbnail"; export { IconButtonThumbnail } from "./components/Thumbnails/IconButtonThumbnail"; @@ -30,6 +31,7 @@ export { CheckboxGroupIcon } from "./components/Icons/CheckboxGroupIcon"; export { CheckboxIcon } from "./components/Icons/CheckboxIcon"; export { ComboboxSelectIcon } from "./components/Icons/ComboboxSelectIcon"; export { CurrencyInputIcon } from "./components/Icons/CurrencyInputIcon"; +export { DatePickerIcon } from "./components/Icons/DatePickerIcon"; export { EmailInputIcon } from "./components/Icons/EmailInputIcon"; export { HeadingIcon } from "./components/Icons/HeadingIcon"; export { IconButtonIcon } from "./components/Icons/IconButtonIcon"; diff --git a/app/client/packages/icons/src/stories/Icons.mdx b/app/client/packages/icons/src/stories/Icons.mdx index 4641a0ee492..6347cca16ce 100644 --- a/app/client/packages/icons/src/stories/Icons.mdx +++ b/app/client/packages/icons/src/stories/Icons.mdx @@ -1,10 +1,12 @@ import { Meta } from "@storybook/addon-docs"; import { Flex } from "@appsmith/wds"; +import { AIChatIcon } from "../components/Icons/AIChatIcon"; import { ButtonIcon } from "../components/Icons/ButtonIcon"; import { CheckboxGroupIcon } from "../components/Icons/CheckboxGroupIcon"; import { CheckboxIcon } from "../components/Icons/CheckboxIcon"; import { ComboboxSelectIcon } from "../components/Icons/ComboboxSelectIcon"; import { CurrencyInputIcon } from "../components/Icons/CurrencyInputIcon"; +import { DatePickerIcon } from "../components/Icons/DatePickerIcon"; import { EmailInputIcon } from "../components/Icons/EmailInputIcon"; import { HeadingIcon } from "../components/Icons/HeadingIcon"; import { IconButtonIcon } from "../components/Icons/IconButtonIcon"; @@ -36,11 +38,13 @@ Icon set for Entity Explorer Panel, which provides a visual representation of th export const Icons = () => { return ( + + diff --git a/app/client/packages/icons/src/stories/Thumbnails.mdx b/app/client/packages/icons/src/stories/Thumbnails.mdx index d05e30565d9..c99d1d029ba 100644 --- a/app/client/packages/icons/src/stories/Thumbnails.mdx +++ b/app/client/packages/icons/src/stories/Thumbnails.mdx @@ -1,10 +1,12 @@ import { Meta } from "@storybook/addon-docs"; import { Flex } from "@appsmith/wds"; +import { AIChatThumbnail } from "../components/Thumbnails/AIChatThumbnail"; import { ButtonThumbnail } from "../components/Thumbnails/ButtonThumbnail"; import { CheckboxGroupThumbnail } from "../components/Thumbnails/CheckboxGroupThumbnail"; import { CheckboxThumbnail } from "../components/Thumbnails/CheckboxThumbnail"; import { ComboboxSelectThumbnail } from "../components/Thumbnails/ComboboxSelectThumbnail"; import { CurrencyInputThumbnail } from "../components/Thumbnails/CurrencyInputThumbnail"; +import { DatePickerThumbnail } from "../components/Thumbnails/DatePickerThumbnail"; import { EmailInputThumbnail } from "../components/Thumbnails/EmailInputThumbnail"; import { HeadingThumbnail } from "../components/Thumbnails/HeadingThumbnail"; import { IconButtonThumbnail } from "../components/Thumbnails/IconButtonThumbnail"; @@ -37,11 +39,13 @@ Icon set for Widget Explorer Panel, which provides a visual representation of th export const Icons = () => { return ( + + diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/methodsConfig.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/methodsConfig.ts index ead8d260433..f2434d18930 100644 --- a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/methodsConfig.ts +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/methodsConfig.ts @@ -1,6 +1,6 @@ -import { ComboboxSelectIcon, ComboboxSelectThumbnail } from "appsmith-icons"; +import { DatePickerIcon, DatePickerThumbnail } from "appsmith-icons"; export const methodsConfig = { - IconCmp: ComboboxSelectIcon, - ThumbnailCmp: ComboboxSelectThumbnail, + IconCmp: DatePickerIcon, + ThumbnailCmp: DatePickerThumbnail, }; From 333fd4dfc87a2ce03254f578254bae16c485aee8 Mon Sep 17 00:00:00 2001 From: Pawan Kumar Date: Mon, 30 Sep 2024 12:45:02 +0530 Subject: [PATCH 04/12] remove unused code --- app/client/packages/icons/src/stories/Icons.mdx | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/client/packages/icons/src/stories/Icons.mdx b/app/client/packages/icons/src/stories/Icons.mdx index 6347cca16ce..8479f7969fe 100644 --- a/app/client/packages/icons/src/stories/Icons.mdx +++ b/app/client/packages/icons/src/stories/Icons.mdx @@ -1,6 +1,5 @@ import { Meta } from "@storybook/addon-docs"; import { Flex } from "@appsmith/wds"; -import { AIChatIcon } from "../components/Icons/AIChatIcon"; import { ButtonIcon } from "../components/Icons/ButtonIcon"; import { CheckboxGroupIcon } from "../components/Icons/CheckboxGroupIcon"; import { CheckboxIcon } from "../components/Icons/CheckboxIcon"; @@ -38,7 +37,6 @@ Icon set for Entity Explorer Panel, which provides a visual representation of th export const Icons = () => { return ( - From 321cc4385fadcf2814a6192fc3cb8ffabcb2f3c6 Mon Sep 17 00:00:00 2001 From: Pawan Kumar Date: Mon, 30 Sep 2024 12:55:14 +0530 Subject: [PATCH 05/12] self code-review fixes --- .../widgets/src/components/FieldCalenderPopover/src/types.ts | 0 .../design-system/widgets/src/components/Text/src/types.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 app/client/packages/design-system/widgets/src/components/FieldCalenderPopover/src/types.ts diff --git a/app/client/packages/design-system/widgets/src/components/FieldCalenderPopover/src/types.ts b/app/client/packages/design-system/widgets/src/components/FieldCalenderPopover/src/types.ts deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/app/client/packages/design-system/widgets/src/components/Text/src/types.ts b/app/client/packages/design-system/widgets/src/components/Text/src/types.ts index afb97cb6b9b..c2aa405326c 100644 --- a/app/client/packages/design-system/widgets/src/components/Text/src/types.ts +++ b/app/client/packages/design-system/widgets/src/components/Text/src/types.ts @@ -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. */ className?: string; /** The children of the component. */ - children?: ReactNode; + children: ReactNode; /** title attribute for the component */ title?: string; /** Sets the HTML [id](https://developer.mozilla.org/en-US/docs/Web/API/Element/id) for the element. */ From 8f30f3a58941d6d511a5d8d7effc7ea2f700eef9 Mon Sep 17 00:00:00 2001 From: Pawan Kumar Date: Mon, 30 Sep 2024 13:02:43 +0530 Subject: [PATCH 06/12] minor typos --- .../config/propertyPaneConfig/contentConfig.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/propertyPaneConfig/contentConfig.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/propertyPaneConfig/contentConfig.ts index 11eddd1f0d6..618ee23b52a 100644 --- a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/propertyPaneConfig/contentConfig.ts +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/config/propertyPaneConfig/contentConfig.ts @@ -35,7 +35,7 @@ export const propertyPaneContentConfig = [ propertyName: "timePrecision", label: "Time Precision", controlType: "DROP_DOWN", - helpText: "Sets the different time picker or hide.", + helpText: "Sets the time precision or hides the time picker.", defaultValue: "day", options: [ { @@ -72,7 +72,7 @@ export const propertyPaneContentConfig = [ sectionName: "Label", children: [ { - helpText: "Sets the label text of the options widget", + helpText: "Sets the label text of the date picker widget", propertyName: "label", label: "Text", controlType: "INPUT_TEXT", @@ -124,7 +124,7 @@ export const propertyPaneContentConfig = [ sectionName: "General", children: [ { - helpText: "Show help text or details about current input", + helpText: "Shows help text or details about the current input", propertyName: "labelTooltip", label: "Tooltip", controlType: "INPUT_TEXT", From d2cde2944f4210381e4b791dcb81b249fc918b88 Mon Sep 17 00:00:00 2001 From: Pawan Kumar Date: Mon, 30 Sep 2024 14:02:02 +0530 Subject: [PATCH 07/12] self code-review fixes --- .../design-system/widgets/src/components/Text/src/types.ts | 2 +- app/client/packages/icons/src/stories/Thumbnails.mdx | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/client/packages/design-system/widgets/src/components/Text/src/types.ts b/app/client/packages/design-system/widgets/src/components/Text/src/types.ts index c2aa405326c..afb97cb6b9b 100644 --- a/app/client/packages/design-system/widgets/src/components/Text/src/types.ts +++ b/app/client/packages/design-system/widgets/src/components/Text/src/types.ts @@ -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. */ className?: string; /** The children of the component. */ - children: ReactNode; + children?: ReactNode; /** title attribute for the component */ title?: string; /** Sets the HTML [id](https://developer.mozilla.org/en-US/docs/Web/API/Element/id) for the element. */ diff --git a/app/client/packages/icons/src/stories/Thumbnails.mdx b/app/client/packages/icons/src/stories/Thumbnails.mdx index c99d1d029ba..3658ca3d40f 100644 --- a/app/client/packages/icons/src/stories/Thumbnails.mdx +++ b/app/client/packages/icons/src/stories/Thumbnails.mdx @@ -1,6 +1,5 @@ import { Meta } from "@storybook/addon-docs"; import { Flex } from "@appsmith/wds"; -import { AIChatThumbnail } from "../components/Thumbnails/AIChatThumbnail"; import { ButtonThumbnail } from "../components/Thumbnails/ButtonThumbnail"; import { CheckboxGroupThumbnail } from "../components/Thumbnails/CheckboxGroupThumbnail"; import { CheckboxThumbnail } from "../components/Thumbnails/CheckboxThumbnail"; @@ -39,7 +38,6 @@ Icon set for Widget Explorer Panel, which provides a visual representation of th export const Icons = () => { return ( - From 733f523833bab561f0152374452927c7a36b780e Mon Sep 17 00:00:00 2001 From: Pawan Kumar Date: Mon, 30 Sep 2024 16:35:39 +0530 Subject: [PATCH 08/12] update validate helper --- .../ui-builder/ui/wds/WDSDatePickerWidget/widget/helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/helpers.ts b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/helpers.ts index 3126ddfb9e4..a08a462ac33 100644 --- a/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/helpers.ts +++ b/app/client/src/modules/ui-builder/ui/wds/WDSDatePickerWidget/widget/helpers.ts @@ -1,7 +1,7 @@ import type { WDSDatePickerWidgetProps } from "./types"; export function validateInput(props: WDSDatePickerWidgetProps) { - if (!props.isValid) { + if (props.isValid === false) { return { validationStatus: "invalid", errorMessage: "Please select a valid date", From 944346215447a1b527ca942abe952660628f1719 Mon Sep 17 00:00:00 2001 From: Pawan Kumar Date: Mon, 30 Sep 2024 16:44:15 +0530 Subject: [PATCH 09/12] update parseDerivedProperties --- app/client/src/widgets/WidgetUtils.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/client/src/widgets/WidgetUtils.ts b/app/client/src/widgets/WidgetUtils.ts index 5ef36f98e66..1882ef0a424 100644 --- a/app/client/src/widgets/WidgetUtils.ts +++ b/app/client/src/widgets/WidgetUtils.ts @@ -1019,12 +1019,20 @@ export function parseDerivedProperties(propertyFns: Record) { for (const [key, value] of Object.entries(propertyFns)) { if (typeof value === "function") { - const functionBody = value.toString().match(/(?<=\{)(.|\n)*(?=\})/)?.[0]; + const functionString = value.toString(); + const functionBody = functionString.match(/(?<=\{)(.|\n)*(?=\})/)?.[0]; if (functionBody) { - derivedProperties[key] = functionBody + // Extract the parameter name (which could be 'props' or a minified version) + const paramMatch = functionString.match(/\((.*?),/); + const propsParam = paramMatch ? paramMatch[1].trim() : "props"; + + // Replace the parameter name with 'this' + const modifiedBody = functionBody .trim() - .replace(/props\./g, "this."); + .replace(new RegExp(`${propsParam}\\.`, "g"), "this."); + + derivedProperties[key] = modifiedBody; } } } From 63a5e91db556e01340b81dea68103172aa66fe40 Mon Sep 17 00:00:00 2001 From: Pawan Kumar Date: Mon, 30 Sep 2024 16:45:28 +0530 Subject: [PATCH 10/12] update validate helper --- app/client/src/widgets/WidgetUtils.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/client/src/widgets/WidgetUtils.ts b/app/client/src/widgets/WidgetUtils.ts index 1882ef0a424..35ebdad2d84 100644 --- a/app/client/src/widgets/WidgetUtils.ts +++ b/app/client/src/widgets/WidgetUtils.ts @@ -1023,11 +1023,9 @@ export function parseDerivedProperties(propertyFns: Record) { const functionBody = functionString.match(/(?<=\{)(.|\n)*(?=\})/)?.[0]; if (functionBody) { - // Extract the parameter name (which could be 'props' or a minified version) const paramMatch = functionString.match(/\((.*?),/); const propsParam = paramMatch ? paramMatch[1].trim() : "props"; - // Replace the parameter name with 'this' const modifiedBody = functionBody .trim() .replace(new RegExp(`${propsParam}\\.`, "g"), "this."); From 2ce40e9c3b9bec1065086d5c8311afa591f50e6a Mon Sep 17 00:00:00 2001 From: Pawan Kumar Date: Mon, 30 Sep 2024 16:58:57 +0530 Subject: [PATCH 11/12] fix typo --- .../{FieldCalenderPopover => FieldCalendarPopover}/index.tsx | 0 .../src/FieldCalendarPopover.tsx} | 0 .../widgets/src/components/FieldCalendarPopover/src/index.ts | 1 + .../widgets/src/components/FieldCalenderPopover/src/index.ts | 1 - app/client/packages/design-system/widgets/src/index.ts | 2 +- app/client/src/widgets/WidgetUtils.ts | 2 +- 6 files changed, 3 insertions(+), 3 deletions(-) rename app/client/packages/design-system/widgets/src/components/{FieldCalenderPopover => FieldCalendarPopover}/index.tsx (100%) rename app/client/packages/design-system/widgets/src/components/{FieldCalenderPopover/src/FieldCalenderPopover.tsx => FieldCalendarPopover/src/FieldCalendarPopover.tsx} (100%) create mode 100644 app/client/packages/design-system/widgets/src/components/FieldCalendarPopover/src/index.ts delete mode 100644 app/client/packages/design-system/widgets/src/components/FieldCalenderPopover/src/index.ts diff --git a/app/client/packages/design-system/widgets/src/components/FieldCalenderPopover/index.tsx b/app/client/packages/design-system/widgets/src/components/FieldCalendarPopover/index.tsx similarity index 100% rename from app/client/packages/design-system/widgets/src/components/FieldCalenderPopover/index.tsx rename to app/client/packages/design-system/widgets/src/components/FieldCalendarPopover/index.tsx diff --git a/app/client/packages/design-system/widgets/src/components/FieldCalenderPopover/src/FieldCalenderPopover.tsx b/app/client/packages/design-system/widgets/src/components/FieldCalendarPopover/src/FieldCalendarPopover.tsx similarity index 100% rename from app/client/packages/design-system/widgets/src/components/FieldCalenderPopover/src/FieldCalenderPopover.tsx rename to app/client/packages/design-system/widgets/src/components/FieldCalendarPopover/src/FieldCalendarPopover.tsx diff --git a/app/client/packages/design-system/widgets/src/components/FieldCalendarPopover/src/index.ts b/app/client/packages/design-system/widgets/src/components/FieldCalendarPopover/src/index.ts new file mode 100644 index 00000000000..f107be7a4c0 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/FieldCalendarPopover/src/index.ts @@ -0,0 +1 @@ +export * from "./FieldCalendarPopover"; diff --git a/app/client/packages/design-system/widgets/src/components/FieldCalenderPopover/src/index.ts b/app/client/packages/design-system/widgets/src/components/FieldCalenderPopover/src/index.ts deleted file mode 100644 index af65172a52b..00000000000 --- a/app/client/packages/design-system/widgets/src/components/FieldCalenderPopover/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./FieldCalenderPopover"; diff --git a/app/client/packages/design-system/widgets/src/index.ts b/app/client/packages/design-system/widgets/src/index.ts index 23bd1f78aea..7e0e3cfa33b 100644 --- a/app/client/packages/design-system/widgets/src/index.ts +++ b/app/client/packages/design-system/widgets/src/index.ts @@ -25,7 +25,7 @@ export * from "./components/FieldLabel"; export * from "./components/FieldError"; export * from "./components/FieldDescription"; export * from "./components/FieldListPopover"; -export * from "./components/FieldCalenderPopover"; +export * from "./components/FieldCalendarPopover"; export * from "./components/Calender"; export * from "./components/DatePicker"; diff --git a/app/client/src/widgets/WidgetUtils.ts b/app/client/src/widgets/WidgetUtils.ts index 35ebdad2d84..af37060cc8b 100644 --- a/app/client/src/widgets/WidgetUtils.ts +++ b/app/client/src/widgets/WidgetUtils.ts @@ -1009,7 +1009,7 @@ export const checkForOnClick = (e: React.MouseEvent) => { * } * ``` * - * Main rule to remember is don't use deconstruct the props like `const { value } = props;` in the derived property function. Directly access props like `props.value` + * Main rule to remember is don't deconstruct the props like `const { value } = props;` in the derived property function. Directly access props like `props.value` * (Reason is we replace props.value with this.value in the derived property function) * @param propertyFns * @returns From 4daa071d4c5f37059d592786ade0270badbffe05 Mon Sep 17 00:00:00 2001 From: Pawan Kumar Date: Mon, 30 Sep 2024 17:55:22 +0530 Subject: [PATCH 12/12] update disabled styles --- .../src/components/ComboBox/src/styles.module.css | 10 +++++++--- .../src/components/DatePicker/src/DatePicker.tsx | 2 ++ .../DatePicker/stories/DatePicker.stories.tsx | 6 ++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/client/packages/design-system/widgets/src/components/ComboBox/src/styles.module.css b/app/client/packages/design-system/widgets/src/components/ComboBox/src/styles.module.css index 58b639c17c8..c20be204bea 100644 --- a/app/client/packages/design-system/widgets/src/components/ComboBox/src/styles.module.css +++ b/app/client/packages/design-system/widgets/src/components/ComboBox/src/styles.module.css @@ -43,17 +43,17 @@ box-shadow: 0 0 0 1px var(--color-bd-focus); } -.inputWrapper:has([data-hovered]) { +.inputWrapper:has([data-hovered]):not([data-disabled]) { background-color: var(--color-bg-neutral-subtle-hover); box-shadow: inset 0 0 0 1px var(--color-bd-on-neutral-subtle-hover); } -.inputWrapper:has([data-focused]) { +.inputWrapper:has([data-focused]):not([data-disabled]) { background-color: transparent; box-shadow: none; } -.inputWrapper:has([data-focused]):before { +.inputWrapper:has([data-focused]):not([data-disabled]):before { content: ""; left: 0; width: 100%; @@ -72,6 +72,10 @@ box-shadow: 0 0 0 1px var(--color-bd-negative-hover); } +.inputWrapper:has([data-disabled]) { + opacity: var(--opacity-disabled); +} + .formField[data-size="small"] .input { block-size: calc( var(--body-line-height) + var(--body-margin-start) + var(--body-margin-end) diff --git a/app/client/packages/design-system/widgets/src/components/DatePicker/src/DatePicker.tsx b/app/client/packages/design-system/widgets/src/components/DatePicker/src/DatePicker.tsx index e0bdf7ffb35..d3de1c07b22 100644 --- a/app/client/packages/design-system/widgets/src/components/DatePicker/src/DatePicker.tsx +++ b/app/client/packages/design-system/widgets/src/components/DatePicker/src/DatePicker.tsx @@ -23,6 +23,7 @@ export const DatePicker = (props: DatePickerProps) => { contextualHelp, description, errorMessage, + isDisabled, isLoading, isRequired, label, @@ -35,6 +36,7 @@ export const DatePicker = (props: DatePickerProps) => { aria-label={Boolean(label) ? undefined : "DatePicker"} className={styles.formField} data-size={size} + isDisabled={isDisabled} isRequired={isRequired} {...rest} > diff --git a/app/client/packages/design-system/widgets/src/components/DatePicker/stories/DatePicker.stories.tsx b/app/client/packages/design-system/widgets/src/components/DatePicker/stories/DatePicker.stories.tsx index 0667b585df6..3f0f8a8f5e8 100644 --- a/app/client/packages/design-system/widgets/src/components/DatePicker/stories/DatePicker.stories.tsx +++ b/app/client/packages/design-system/widgets/src/components/DatePicker/stories/DatePicker.stories.tsx @@ -60,6 +60,12 @@ export const Loading: Story = { }, }; +export const Disabled: Story = { + args: { + isDisabled: true, + }, +}; + export const Validation: Story = { render: () => (