diff --git a/app/client/packages/design-system/widgets/src/components/ComboBox/src/ComboBox.tsx b/app/client/packages/design-system/widgets/src/components/ComboBox/src/ComboBox.tsx
index 738432dd4b3e..44587284907d 100644
--- a/app/client/packages/design-system/widgets/src/components/ComboBox/src/ComboBox.tsx
+++ b/app/client/packages/design-system/widgets/src/components/ComboBox/src/ComboBox.tsx
@@ -4,10 +4,13 @@ import {
FieldLabel,
FieldError,
inputFieldStyles,
+ useRootContainer,
+ POPOVER_LIST_BOX_MAX_HEIGHT,
} from "@appsmith/wds";
import React from "react";
import { ComboBox as HeadlessCombobox } from "react-aria-components";
+import styles from "./styles.module.css";
import type { ComboBoxProps } from "./types";
import { ComboBoxTrigger } from "./ComboBoxTrigger";
@@ -24,9 +27,7 @@ export const ComboBox = (props: ComboBoxProps) => {
size = "medium",
...rest
} = props;
- const root = document.body.querySelector(
- "[data-theme-provider]",
- ) as HTMLButtonElement;
+ const root = useRootContainer();
return (
{
size={size}
/>
{errorMessage}
-
+
{children}
diff --git a/app/client/packages/design-system/widgets/src/components/ComboBox/src/ComboBoxTrigger.tsx b/app/client/packages/design-system/widgets/src/components/ComboBox/src/ComboBoxTrigger.tsx
index c17bcb4cca89..bf5b8bae0b90 100644
--- a/app/client/packages/design-system/widgets/src/components/ComboBox/src/ComboBoxTrigger.tsx
+++ b/app/client/packages/design-system/widgets/src/components/ComboBox/src/ComboBoxTrigger.tsx
@@ -1,7 +1,5 @@
-import clsx from "clsx";
import React, { useMemo } from "react";
-import { getTypographyClassName } from "@appsmith/wds-theming";
-import { Spinner, textInputStyles, Input, IconButton } from "@appsmith/wds";
+import { Spinner, Input, IconButton } from "@appsmith/wds";
import type { ComboBoxProps } from "./types";
@@ -27,12 +25,5 @@ export const ComboBoxTrigger: React.FC = (props) => {
);
}, [isLoading, size, isDisabled]);
- return (
-
- );
+ return ;
};
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
new file mode 100644
index 000000000000..5a98e2049876
--- /dev/null
+++ b/app/client/packages/design-system/widgets/src/components/ComboBox/src/styles.module.css
@@ -0,0 +1,4 @@
+.comboboxPopover {
+ width: calc(var(--trigger-width) + var(--inner-spacing-2) * 2);
+ transform: translateX(calc(-1 * var(--inner-spacing-1)));
+}
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 3d98fb0b3175..f62f5dd69fb7 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
@@ -5,6 +5,7 @@ import {
Calendar,
inputFieldStyles,
TimeField,
+ useRootContainer,
} from "@appsmith/wds";
import clsx from "clsx";
import React from "react";
@@ -44,6 +45,7 @@ export const DatePicker = (props: DatePickerProps) => {
const timeMaxValue = (
props.maxValue && "hour" in props.maxValue ? props.maxValue : null
) as TimeValue;
+ const root = useRootContainer();
return (
(props: DatePickerProps) => {
{...rest}
>
{({ state }) => {
- const root = document.body.querySelector(
- "[data-theme-provider]",
- ) as HTMLButtonElement;
const timeGranularity =
state.granularity === "hour" ||
state.granularity === "minute" ||
diff --git a/app/client/packages/design-system/widgets/src/components/Input/src/Input.tsx b/app/client/packages/design-system/widgets/src/components/Input/src/Input.tsx
index 3472e2b53ac7..64e03bc95d66 100644
--- a/app/client/packages/design-system/widgets/src/components/Input/src/Input.tsx
+++ b/app/client/packages/design-system/widgets/src/components/Input/src/Input.tsx
@@ -1,5 +1,6 @@
import clsx from "clsx";
-import React, { forwardRef, useState } from "react";
+import { mergeRefs } from "@react-aria/utils";
+import React, { forwardRef, useRef, useState } from "react";
import { getTypographyClassName } from "@appsmith/wds-theming";
import { IconButton, Spinner, type IconProps } from "@appsmith/wds";
import { Group, Input as HeadlessInput } from "react-aria-components";
@@ -9,6 +10,7 @@ import type { InputProps } from "./types";
function _Input(props: InputProps, ref: React.Ref) {
const {
+ className,
defaultValue,
isLoading,
isReadOnly,
@@ -19,6 +21,8 @@ function _Input(props: InputProps, ref: React.Ref) {
value,
...rest
} = props;
+ const localRef = useRef(null);
+ const mergedRef = mergeRefs(ref, localRef);
const [showPassword, setShowPassword] = useState(false);
const togglePasswordVisibility = () => setShowPassword((prev) => !prev);
const isEmpty = !Boolean(value) && !Boolean(defaultValue);
@@ -46,18 +50,30 @@ function _Input(props: InputProps, ref: React.Ref) {
return (
+ {Boolean(prefix) && (
+ localRef.current?.focus()}>
+ {prefix}
+
+ )}
- {Boolean(prefix) && {prefix}}
- {Boolean(suffix) && {suffix}}
+ {Boolean(suffix) && (
+ localRef.current?.focus()}>
+ {suffix}
+
+ )}
);
}
diff --git a/app/client/packages/design-system/widgets/src/components/Input/src/styles.module.css b/app/client/packages/design-system/widgets/src/components/Input/src/styles.module.css
index e36ba4a53650..d0faca4f3a6c 100644
--- a/app/client/packages/design-system/widgets/src/components/Input/src/styles.module.css
+++ b/app/client/packages/design-system/widgets/src/components/Input/src/styles.module.css
@@ -6,12 +6,7 @@
width: 100%;
}
-.input {
- position: relative;
- display: flex;
- flex: 1;
- align-items: center;
- box-sizing: content-box;
+.inputGroup {
max-inline-size: 100%;
padding-block: var(--inner-spacing-1);
padding-inline: var(--inner-spacing-2);
@@ -25,8 +20,12 @@
overflow: hidden;
}
-.input:has(> [data-select-text]) {
- block-size: var(--body-line-height);
+.input {
+ border: none;
+ outline: none;
+ background-color: transparent;
+ flex: 1;
+ padding: 0;
}
.input:is(textarea) {
@@ -57,44 +56,11 @@
);
}
-.inputGroup:has(> [data-input-prefix]) .input {
- padding-left: var(--sizing-8);
-}
-
-.inputGroup:has(> [data-input-prefix]) .input[data-size="large"] {
- padding-left: var(--sizing-12);
-}
-
-.inputGroup:has(> [data-input-prefix]) .input[data-size="small"] {
- padding-left: var(--sizing-6);
-}
-
-.inputGroup:has(> [data-input-prefix]) [data-input-prefix] {
- left: var(--inner-spacing-1);
- position: absolute;
-}
-
-.inputGroup:has(> [data-input-suffix]) .input {
- padding-right: var(--sizing-8);
-}
-
-.inputGroup:has(> [data-input-suffix]) .input[data-size="large"] {
- padding-right: var(--sizing-12);
-}
-
-.inputGroup:has(> [data-input-suffix]) .input[data-size="small"] {
- padding-right: var(--sizing-6);
-}
-
-.inputGroup:has(> [data-input-suffix]) [data-input-suffix] {
- right: var(--inner-spacing-1);
- position: absolute;
-}
-
.inputGroup :is([data-input-suffix], [data-input-prefix]) {
display: flex;
justify-content: center;
align-items: center;
+ height: 0;
}
/**
@@ -102,14 +68,15 @@
* HOVERED
* ----------------------------------------------------------------------------
*/
-.inputGroup[data-hovered]
- .input:not(
- :is(
- [data-focused],
- [data-readonly],
- [data-disabled],
- [data-focus-within],
- :has(~ input[data-disabled="true"])
+.inputGroup[data-hovered]:has(
+ > .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);
@@ -157,8 +124,8 @@
* DISABLED
* ----------------------------------------------------------------------------
*/
-.input[data-disabled],
-.input:has(~ input[data-disabled]) {
+.inputGroup:has(> .input[data-disabled]),
+.inputGroup:has(> .input:has(~ input[data-disabled])) {
cursor: not-allowed;
box-shadow: none;
}
@@ -168,13 +135,14 @@
* INVALID
* ----------------------------------------------------------------------------
*/
-.input[data-invalid] {
+.inputGroup:has(> .input[data-invalid]) {
box-shadow: 0 0 0 1px var(--color-bd-negative);
}
-.inputGroup[data-hovered]
- .input[data-invalid]:not(
- :is([data-focused], [data-readonly], [data-disabled])
+.inputGroup[data-hovered]:has(
+ > .input[data-invalid]:not(
+ :is([data-focused], [data-readonly], [data-disabled])
+ )
) {
box-shadow: 0 0 0 1px var(--color-bd-negative-hover);
}
@@ -184,7 +152,9 @@
* FOCUSSED
* ----------------------------------------------------------------------------
*/
-.input:is([data-focused], [data-focus-within]):not([data-readonly]) {
+.inputGroup:has(
+ > .input:is([data-focused], [data-focus-within]):not([data-readonly])
+ ) {
background-color: transparent;
box-shadow: 0 0 0 2px var(--color-bd-focus);
}
@@ -194,31 +164,17 @@
* SIZE
* ----------------------------------------------------------------------------
*/
-.input[data-size="small"] {
+.inputGroup:has(> .input[data-size="small"]) {
block-size: calc(
- var(--body-line-height) + var(--body-margin-start) + var(--body-margin-end)
+ var(--body-line-height) + var(--body-margin-start) + var(--body-margin-end) +
+ var(--inner-spacing-2) * 2
);
- padding-block: var(--inner-spacing-2);
}
-.input[data-size="large"] {
+.inputGroup:has(> .input[data-size="large"]) {
block-size: calc(
var(--body-line-height) + var(--body-margin-start) + var(--body-margin-end)
);
padding-block: var(--inner-spacing-3);
padding-inline: var(--inner-spacing-3);
}
-
-/**
- * ----------------------------------------------------------------------------
- * SELECT BUTTON's TEXT
- * ----------------------------------------------------------------------------
- */
-.input [data-select-text] {
- display: flex;
- align-items: center;
-}
-
-.input [data-select-text] [data-icon] {
- margin-inline-end: var(--inner-spacing-1);
-}
diff --git a/app/client/packages/design-system/widgets/src/components/Menu/src/Menu.tsx b/app/client/packages/design-system/widgets/src/components/Menu/src/Menu.tsx
index 223ed03d7c17..77cc1f6db4ab 100644
--- a/app/client/packages/design-system/widgets/src/components/Menu/src/Menu.tsx
+++ b/app/client/packages/design-system/widgets/src/components/Menu/src/Menu.tsx
@@ -1,16 +1,20 @@
+import {
+ Popover,
+ listStyles,
+ useRootContainer,
+ POPOVER_LIST_BOX_MAX_HEIGHT,
+} from "@appsmith/wds";
import React, { createContext, useContext } from "react";
-import { listStyles, Popover } from "@appsmith/wds";
import { Menu as HeadlessMenu } from "react-aria-components";
import type { MenuProps } from "./types";
+import clsx from "clsx";
const MenuNestingContext = createContext(0);
export const Menu = (props: MenuProps) => {
- const { children } = props;
- const root = document.body.querySelector(
- "[data-theme-provider]",
- ) as HTMLButtonElement;
+ const { children, className, ...rest } = props;
+ const root = useRootContainer();
const nestingLevel = useContext(MenuNestingContext);
const isRootMenu = nestingLevel === 0;
@@ -18,8 +22,11 @@ export const Menu = (props: MenuProps) => {
return (
{/* Only the parent Popover should be placed in the root. Placing child popoves in root would cause the menu to function incorrectly */}
-
-
+
+
{children}
diff --git a/app/client/packages/design-system/widgets/src/components/Menu/src/types.ts b/app/client/packages/design-system/widgets/src/components/Menu/src/types.ts
index 4c7b10e72f2d..4f514c44c3a1 100644
--- a/app/client/packages/design-system/widgets/src/components/Menu/src/types.ts
+++ b/app/client/packages/design-system/widgets/src/components/Menu/src/types.ts
@@ -1,7 +1,3 @@
import type { MenuProps as AriaMenuProps } from "react-aria-components";
-export interface MenuProps
- extends Omit<
- AriaMenuProps