-
+
{typeof children === "function" ? children({ closeDropdown: close }) : children}
diff --git a/plane-src/apps/web/core/components/onboarding/create-workspace.tsx b/plane-src/apps/web/core/components/onboarding/create-workspace.tsx
index c797751..d68a9ea 100644
--- a/plane-src/apps/web/core/components/onboarding/create-workspace.tsx
+++ b/plane-src/apps/web/core/components/onboarding/create-workspace.tsx
@@ -15,8 +15,9 @@ import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { IUser, IWorkspace, TOnboardingSteps } from "@plane/types";
// ui
-import { CustomSelect, Input, Spinner } from "@plane/ui";
+import { Input, Spinner } from "@plane/ui";
import { validateWorkspaceName, validateSlug } from "@plane/utils";
+import { SelectionDropdown } from "@/components/common/selection-dropdown";
// hooks
import { useWorkspace } from "@/hooks/store/use-workspace";
import { useUserProfile, useUserSettings } from "@/hooks/store/user";
@@ -240,25 +241,22 @@ export const CreateWorkspace = observer(function CreateWorkspace(props: Props) {
control={control}
rules={{ required: t("common.errors.required") }}
render={({ field: { value, onChange } }) => (
-
({
+ key: item,
+ title: getOrganizationSizeLabel(item),
+ isChecked: value === item,
+ onClick: () => onChange(item),
+ }))}
+ menuButton={
(value ? getOrganizationSizeLabel(value) : undefined) ?? (
{t("workspace_creation.form.organization_size.placeholder")}
)
}
- buttonClassName="border border-subtle bg-layer-2 !shadow-none !rounded-md"
- input
- >
- {ORGANIZATION_SIZE.map((item) => (
-
- {getOrganizationSizeLabel(item)}
-
- ))}
-
+ menuButtonWrapperClassName="rounded-md border border-subtle bg-layer-2 px-3 py-2 text-13 shadow-none"
+ />
)}
/>
{errors.organization_size && (
diff --git a/plane-src/apps/web/core/components/project/form.tsx b/plane-src/apps/web/core/components/project/form.tsx
index 4de357b..2e44bc6 100644
--- a/plane-src/apps/web/core/components/project/form.tsx
+++ b/plane-src/apps/web/core/components/project/form.tsx
@@ -17,8 +17,9 @@ import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { Tooltip } from "@plane/propel/tooltip";
import { EFileAssetType } from "@plane/types";
import type { IProject, IWorkspace } from "@plane/types";
-import { CustomSelect, Input, TextArea } from "@plane/ui";
+import { Input, TextArea } from "@plane/ui";
import { renderFormattedDate } from "@plane/utils";
+import { SelectionDropdown } from "@/components/common/selection-dropdown";
import { CoverImage } from "@/components/common/cover-image";
import { ImagePickerPopover } from "@/components/core/image-picker-popover";
import { TimezoneSelect } from "@/components/global";
@@ -369,10 +370,22 @@ export function ProjectDetailsForm(props: IProjectDetailsForm) {
render={({ field: { value, onChange } }) => {
const selectedNetwork = NETWORK_CHOICES.find((n) => n.key === value);
return (
-
({
+ key: String(network.key),
+ title: (
+
+
+
+
{t(network.i18n_label)}
+
{t(network.description)}
+
+
+ ),
+ isChecked: value === network.key,
+ onClick: () => onChange(network.key),
+ }))}
+ menuButton={
{selectedNetwork ? (
<>
@@ -384,23 +397,9 @@ export function ProjectDetailsForm(props: IProjectDetailsForm) {
)}
}
- buttonClassName="nodedc-settings-select !h-12 font-medium"
- input
+ menuButtonWrapperClassName="nodedc-settings-select !h-12 font-medium"
disabled={!isAdmin}
- // optionsClassName="w-full"
- >
- {NETWORK_CHOICES.map((network) => (
-
-
-
-
-
{t(network.i18n_label)}
-
{t(network.description)}
-
-
-
- ))}
-
+ />
);
}}
/>
diff --git a/plane-src/apps/web/core/components/project/send-project-invitation-modal.tsx b/plane-src/apps/web/core/components/project/send-project-invitation-modal.tsx
index f87e842..112d37b 100644
--- a/plane-src/apps/web/core/components/project/send-project-invitation-modal.tsx
+++ b/plane-src/apps/web/core/components/project/send-project-invitation-modal.tsx
@@ -13,9 +13,10 @@ import { useTranslation } from "@plane/i18n";
import { Button } from "@plane/propel/button";
import { PlusIcon, CloseIcon, ChevronDownIcon } from "@plane/propel/icons";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
-import { Avatar, CustomSelect, EModalPosition, EModalWidth, ModalCore, SearchSelectionDropdown } from "@plane/ui";
+import { Avatar, EModalPosition, EModalWidth, ModalCore, SearchSelectionDropdown } from "@plane/ui";
// helpers
import { getFileURL } from "@plane/utils";
+import { SelectionDropdown } from "@/components/common/selection-dropdown";
// hooks
import { useMember } from "@/hooks/store/use-member";
import { useUserPermissions } from "@/hooks/store/user";
@@ -245,9 +246,20 @@ export const SendProjectInvitationModal = observer(function SendProjectInvitatio
control={control}
rules={{ required: t("project_invitation_modal.select_role_required") }}
render={({ field }) => (
-
parseInt(key) <= (currentProjectRole ?? EUserPermissions.GUEST))
+ .map(([key, label]) => ({
+ key,
+ title: label,
+ isChecked: String(field.value) === key,
+ onClick: () =>
+ setValue(
+ `members.${index}.role`,
+ EUserPermissions[ROLE[parseInt(key)].toUpperCase() as keyof typeof EUserPermissions]
+ ),
+ }))}
+ menuButton={
{field.value ? ROLE[field.value] : t("project_invitation_modal.select_role")}
@@ -255,20 +267,8 @@ export const SendProjectInvitationModal = observer(function SendProjectInvitatio
}
- input
- >
- {Object.entries(checkCurrentOptionWorkspaceRole(watch(`members.${index}.member_id`))).map(
- ([key, label]) => {
- if (parseInt(key) > (currentProjectRole ?? EUserPermissions.GUEST)) return null;
-
- return (
-
- {label}
-
- );
- }
- )}
-
+ menuButtonWrapperClassName="w-24"
+ />
)}
/>
{errors.members && errors.members[index]?.role && (
diff --git a/plane-src/apps/web/core/components/project/settings/member-columns.tsx b/plane-src/apps/web/core/components/project/settings/member-columns.tsx
index 6af48e2..ab9cdf8 100644
--- a/plane-src/apps/web/core/components/project/settings/member-columns.tsx
+++ b/plane-src/apps/web/core/components/project/settings/member-columns.tsx
@@ -13,8 +13,9 @@ import { Disclosure } from "@headlessui/react";
import { ROLE, EUserPermissions, MEMBER_TRACKER_ELEMENTS } from "@plane/constants";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { EUserProjectRoles, IUser, IWorkspaceMember, TProjectMembership } from "@plane/types";
-import { ActionDropdown, CustomSelect } from "@plane/ui";
+import { ActionDropdown } from "@plane/ui";
import { getFileURL } from "@plane/utils";
+import { SelectionDropdown } from "@/components/common/selection-dropdown";
// hooks
import { useMember } from "@/hooks/store/use-member";
import { useUser, useUserPermissions } from "@/hooks/store/user";
@@ -152,39 +153,35 @@ export const AccountTypeColumn = observer(function AccountTypeColumn(props: Acco
control={control}
rules={{ required: "Role is required." }}
render={() => (
-
{
- if (!workspaceSlug) return;
- await updateMemberRole(workspaceSlug.toString(), projectId.toString(), rowData.member.id, value).catch(
- (err) => {
- console.log(err, "err");
- const error = err.error;
- const errorString = Array.isArray(error) ? error[0] : error;
+ ({
+ key,
+ title: label,
+ isChecked: String(rowData.original_role) === key,
+ onClick: async () => {
+ if (!workspaceSlug) return;
+ await updateMemberRole(workspaceSlug.toString(), projectId.toString(), rowData.member.id, key).catch(
+ (err) => {
+ console.log(err, "err");
+ const error = err.error;
+ const errorString = Array.isArray(error) ? error[0] : error;
- setToast({
- type: TOAST_TYPE.ERROR,
- title: "You can’t change this role yet.",
- message: errorString ?? "An error occurred while updating member role. Please try again.",
- });
- }
- );
- }}
- label={
+ setToast({
+ type: TOAST_TYPE.ERROR,
+ title: "You can’t change this role yet.",
+ message: errorString ?? "An error occurred while updating member role. Please try again.",
+ });
+ }
+ );
+ },
+ }))}
+ menuButton={
{roleLabel}
}
- buttonClassName={`!px-0 !justify-start hover:bg-surface-1 ${errors.role ? "border-danger-strong" : "border-none"}`}
- className="w-32 rounded-md p-0"
- input
- >
- {Object.entries(checkCurrentOptionWorkspaceRole(rowData.member.id)).map(([key, label]) => (
-
- {label}
-
- ))}
-
+ menuButtonWrapperClassName={`w-32 rounded-md p-0 !justify-start !px-0 hover:bg-surface-1 ${errors.role ? "border-danger-strong" : "border-none"}`}
+ />
)}
/>
) : (
diff --git a/plane-src/apps/web/core/components/settings/profile/content/pages/preferences/language-and-timezone-list.tsx b/plane-src/apps/web/core/components/settings/profile/content/pages/preferences/language-and-timezone-list.tsx
index 5ec822a..b099189 100644
--- a/plane-src/apps/web/core/components/settings/profile/content/pages/preferences/language-and-timezone-list.tsx
+++ b/plane-src/apps/web/core/components/settings/profile/content/pages/preferences/language-and-timezone-list.tsx
@@ -8,7 +8,7 @@ import { observer } from "mobx-react";
// plane imports
import { SUPPORTED_LANGUAGES, useTranslation } from "@plane/i18n";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
-import { CustomSelect } from "@plane/ui";
+import { SelectionDropdown } from "@/components/common/selection-dropdown";
// components
import { TimezoneSelect } from "@/components/global";
import { StartOfWeekPreference } from "@/components/profile/start-of-week-preference";
@@ -79,21 +79,17 @@ export const ProfileSettingsLanguageAndTimezonePreferencesList = observer(
title={t("language")}
description={t("language_setting")}
control={
-
({
+ key: item.value,
+ title: item.label,
+ isChecked: profile?.language === item.value,
+ onClick: () => handleLanguageChange(item.value),
+ }))}
+ menuButton={profile?.language ? getLanguageLabel(profile?.language) : "Select a language"}
+ menuButtonWrapperClassName="rounded-md border border-subtle-1 px-3 py-2 text-13"
placement="bottom-end"
- >
- {SUPPORTED_LANGUAGES.map((item) => (
-
- {item.label}
-
- ))}
-
+ />
}
/>
(
- ({
+ key: item,
+ title: item,
+ isChecked: value === item,
+ onClick: () => onChange(item),
+ }))}
+ menuButton={
ORGANIZATION_SIZE.find((c) => c === value) ?? (
{t("workspace_creation.form.organization_size.placeholder")}
)
}
- buttonClassName="border border-subtle bg-layer-2 !shadow-none !rounded-md"
- input
- >
- {ORGANIZATION_SIZE.map((item) => (
-
- {item}
-
- ))}
-
+ menuButtonWrapperClassName="rounded-md border border-subtle bg-layer-2 px-3 py-2 text-13 shadow-none"
+ />
)}
/>
{errors.organization_size && (
diff --git a/plane-src/apps/web/core/components/workspace/invite-modal/fields.tsx b/plane-src/apps/web/core/components/workspace/invite-modal/fields.tsx
index 7681390..18b55aa 100644
--- a/plane-src/apps/web/core/components/workspace/invite-modal/fields.tsx
+++ b/plane-src/apps/web/core/components/workspace/invite-modal/fields.tsx
@@ -11,7 +11,8 @@ import { Controller } from "react-hook-form";
import { ROLE } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { CloseIcon } from "@plane/propel/icons";
-import { CustomSelect, Input } from "@plane/ui";
+import { Input } from "@plane/ui";
+import { SelectionDropdown } from "@/components/common/selection-dropdown";
import { cn } from "@plane/utils";
// hooks
import { useUserPermissions } from "@/hooks/store/user";
@@ -89,22 +90,18 @@ export const InvitationFields = observer(function InvitationFields(props: TInvit
name={`emails.${index}.role`}
rules={{ required: true }}
render={({ field: { value, onChange } }) => (
- {ROLE[value]}}
- onChange={onChange}
- className="w-24 flex-grow"
- input
- >
- {Object.entries(ROLE).map(([key, value]) => {
- if (currentWorkspaceRole && currentWorkspaceRole >= parseInt(key))
- return (
-
- {value}
-
- );
- })}
-
+ Boolean(currentWorkspaceRole && currentWorkspaceRole >= parseInt(key)))
+ .map(([key, roleValue]) => ({
+ key,
+ title: roleValue,
+ isChecked: value === parseInt(key),
+ onClick: () => onChange(parseInt(key)),
+ }))}
+ menuButton={{ROLE[value]}}
+ menuButtonWrapperClassName="w-24 flex-grow px-3 py-2 text-13"
+ />
)}
/>
diff --git a/plane-src/apps/web/core/components/workspace/settings/invitations-list-item.tsx b/plane-src/apps/web/core/components/workspace/settings/invitations-list-item.tsx
index 4bce4d6..91f6a7e 100644
--- a/plane-src/apps/web/core/components/workspace/settings/invitations-list-item.tsx
+++ b/plane-src/apps/web/core/components/workspace/settings/invitations-list-item.tsx
@@ -13,8 +13,9 @@ import { useTranslation } from "@plane/i18n";
import { LinkIcon, TrashIcon, ChevronDownIcon } from "@plane/propel/icons";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { TContextMenuItem } from "@plane/ui";
-import { ActionDropdown, CustomSelect } from "@plane/ui";
+import { ActionDropdown } from "@plane/ui";
import { copyTextToClipboard } from "@plane/utils";
+import { SelectionDropdown } from "@/components/common/selection-dropdown";
// components
import { ConfirmWorkspaceMemberRemove } from "@/components/workspace/confirm-workspace-member-remove";
// hooks
@@ -134,8 +135,38 @@ export const WorkspaceInvitationsListItem = observer(function WorkspaceInvitatio