From 388eac8b8960bacd2f9f0a468702a04cd6ae1358 Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Sun, 19 Jan 2025 12:28:16 +0100 Subject: [PATCH] feat(react-formio): add support Choicesjs and React-select layout to InputTags --- .../forms/form-control/FormControl.tsx | 6 +- .../forms/input-tags/InputTags.interface.ts | 9 ++ .../molecules/forms/input-tags/InputTags.tsx | 64 +++----- .../src/molecules/forms/input-tags/all.ts | 6 + .../ChoicesTags.stories.tsx} | 51 +++++-- .../input-tags/components/ChoicesTags.tsx | 72 +++++++++ .../components/ReactTags.stories.tsx | 140 ++++++++++++++++++ .../forms/input-tags/components/ReactTags.tsx | 38 +++++ .../forms/input-text/InputText.spec.tsx | 2 +- .../molecules/forms/input-text/InputText.tsx | 69 ++++----- .../components/ChoicesSelect.stories.tsx | 1 + .../forms/select/components/ChoicesSelect.tsx | 19 +-- .../select/components/ReactSelect.stories.tsx | 4 +- .../form/builder/FormEdit.stories.tsx | 17 +-- .../src/organisms/form/builder/FormEdit.tsx | 4 +- .../organisms/form/builder/FormParameters.tsx | 10 +- .../src/organisms/form/builder/all.ts | 4 + packages/tailwind-formio/styles/choices.css | 57 +++---- packages/tailwind-formio/styles/form.css | 9 +- .../tailwind-formio/styles/react-select.css | 58 +++++++- 20 files changed, 486 insertions(+), 154 deletions(-) create mode 100644 packages/react-formio/src/molecules/forms/input-tags/InputTags.interface.ts create mode 100644 packages/react-formio/src/molecules/forms/input-tags/all.ts rename packages/react-formio/src/molecules/forms/input-tags/{InputTags.stories.tsx => components/ChoicesTags.stories.tsx} (50%) create mode 100644 packages/react-formio/src/molecules/forms/input-tags/components/ChoicesTags.tsx create mode 100644 packages/react-formio/src/molecules/forms/input-tags/components/ReactTags.stories.tsx create mode 100644 packages/react-formio/src/molecules/forms/input-tags/components/ReactTags.tsx diff --git a/packages/react-formio/src/molecules/forms/form-control/FormControl.tsx b/packages/react-formio/src/molecules/forms/form-control/FormControl.tsx index 9caa00d..8ed3db2 100644 --- a/packages/react-formio/src/molecules/forms/form-control/FormControl.tsx +++ b/packages/react-formio/src/molecules/forms/form-control/FormControl.tsx @@ -22,8 +22,8 @@ export type FormControlProps< Attributes extends HTMLAttributes = InputHTMLAttributes > = BaseFormControlProps & Omit; -export function cleanFormControlProps(props: FormControlProps): any { - return omit(props, ["label", "description", "prefix", "suffix", "size", "shadow"]); +export function cleanFormControlProps(props: FormControlProps, omitted: string[] = []): any { + return omit(props, ["label", "description", "prefix", "suffix", "size", "shadow", ...omitted]); } export function FormControl({ @@ -48,7 +48,7 @@ export function FormControl({ "-with-before": !!before, "-with-after": !!after }, - size && `form-group-${size}`, + size && `-size-${size}`, className )} > diff --git a/packages/react-formio/src/molecules/forms/input-tags/InputTags.interface.ts b/packages/react-formio/src/molecules/forms/input-tags/InputTags.interface.ts new file mode 100644 index 0000000..22343aa --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-tags/InputTags.interface.ts @@ -0,0 +1,9 @@ +import type { InputHTMLAttributes } from "react"; + +import type { FormControlProps } from "../form-control/FormControl"; + +export interface InputTagsProps extends FormControlProps> { + layout?: "html5" | "react" | "choicesjs"; + delimiter?: string; + customProperties?: Record; +} diff --git a/packages/react-formio/src/molecules/forms/input-tags/InputTags.tsx b/packages/react-formio/src/molecules/forms/input-tags/InputTags.tsx index 19bbdb7..fcc118f 100644 --- a/packages/react-formio/src/molecules/forms/input-tags/InputTags.tsx +++ b/packages/react-formio/src/molecules/forms/input-tags/InputTags.tsx @@ -1,50 +1,28 @@ -import Choices from "@formio/choices.js"; -import uniq from "lodash/uniq"; -import { useEffect, useRef } from "react"; +import { ComponentType } from "react"; -import { registerComponent } from "../../../registries/components"; -import { FormControl, FormControlProps } from "../form-control/FormControl"; +import { getComponent, registerComponent } from "../../../registries/components"; +import { type FormControl as DefaultFormControl } from "../form-control/FormControl"; +import type { InputTagsProps } from "./InputTags.interface"; -export interface InputTagsProps extends Omit { - value?: T; - onChange?: (name: string, value: T) => void; - placeholder?: string; - - [key: string]: any; -} - -export function InputTags({ name, value = [], label, onChange, required, description, prefix, suffix, ...props }: InputTagsProps) { - const ref: any = useRef(); - - useEffect(() => { - const instance = new Choices(ref.current, { - delimiter: ",", - editItems: true, - removeItemButton: true - }); - - instance.setValue([].concat(value, [])); - - instance.passedElement.element.addEventListener("addItem", (event: any) => { - onChange && onChange(name, uniq(value.concat(event.detail.value))); - }); - - instance.passedElement.element.addEventListener("removeItem", (event: any) => { - onChange && - onChange( - name, - value.filter((v: string) => v !== event.detail.value) - ); - }); - - return () => { - instance.destroy(); - }; - }, []); +export function InputTags(props: InputTagsProps) { + const { name, id = name, label, required, description, before, after, size, className, layout = "choicesjs", ...otherProps } = props; + const FormControl = getComponent("FormControl"); + const Component = getComponent>>([`InputTags.${layout}`, "Input"]); + console.log("VALUE", props.value); return ( - - + + ); } diff --git a/packages/react-formio/src/molecules/forms/input-tags/all.ts b/packages/react-formio/src/molecules/forms/input-tags/all.ts new file mode 100644 index 0000000..ccd3045 --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-tags/all.ts @@ -0,0 +1,6 @@ +import "../form-control/FormControl"; +import "./components/ChoicesTags"; +import "./components/ReactTags"; +import "../input-text/InputText"; +export * from "./InputTags"; +export * from "./InputTags.interface"; diff --git a/packages/react-formio/src/molecules/forms/input-tags/InputTags.stories.tsx b/packages/react-formio/src/molecules/forms/input-tags/components/ChoicesTags.stories.tsx similarity index 50% rename from packages/react-formio/src/molecules/forms/input-tags/InputTags.stories.tsx rename to packages/react-formio/src/molecules/forms/input-tags/components/ChoicesTags.stories.tsx index 5b61a76..15de383 100644 --- a/packages/react-formio/src/molecules/forms/input-tags/InputTags.stories.tsx +++ b/packages/react-formio/src/molecules/forms/input-tags/components/ChoicesTags.stories.tsx @@ -1,16 +1,28 @@ +import "../all"; + import type { Meta, StoryObj } from "@storybook/react"; -import { iconClass } from "../../../utils/iconClass"; -import { useValue } from "../../__fixtures__/useValue.hook"; -import { InputTags } from "./InputTags"; +import { iconClass } from "../../../../utils/iconClass"; +import { useValue } from "../../../__fixtures__/useValue.hook"; +import { InputTags } from "../InputTags"; /** + * The InputTags component enables users to create new options in the text field. + * * ```tsx + * import {InputTags} from "@tsed/react-formio/molecules/forms/input-tags/all"; + * + * or + * + * import "@tsed/react-formio/molecules/forms/input-tags/components/ChoicesTags"; + * import "@tsed/react-formio/molecules/forms/input-tags/components/ReactTags"; + * import "@tsed/react-formio/molecules/forms/input-text/InputText"; * import {InputTags} from "@tsed/react-formio/molecules/forms/input-tags/InputTags"; + * * ``` */ export default { - title: "forms/InputTags", + title: "forms/InputTags/ChoicesJs", component: InputTags, argTypes: { label: { @@ -29,14 +41,21 @@ export default { placeholder: { control: "text" }, - choices: { - control: "object" - }, description: { control: "text" + }, + layout: { + control: "select", + options: ["choicesjs", "react"] + }, + onChange: { + action: "onChange" } }, parameters: {}, + args: { + layout: "choicesjs" + }, tags: ["autodocs"] } satisfies Meta; @@ -52,10 +71,20 @@ export const Usage: Story = { } }; -export const WithPrefix: Story = { +export const WithSizeOption: Story = { + args: { + name: "name", + label: "Label", + value: ["test"], + size: "small", + placeholder: "Placeholder" + } +}; + +export const AppendBefore: Story = { render(args) { // eslint-disable-next-line react-hooks/rules-of-hooks - return } {...useValue(args)} />; + return } {...useValue(args)} />; }, args: { label: "Label", @@ -66,10 +95,10 @@ export const WithPrefix: Story = { } }; -export const WithSuffix: Story = { +export const AppendAfter: Story = { render(args) { // eslint-disable-next-line react-hooks/rules-of-hooks - return } {...useValue(args)} />; + return } {...useValue(args)} />; }, args: { label: "Label", diff --git a/packages/react-formio/src/molecules/forms/input-tags/components/ChoicesTags.tsx b/packages/react-formio/src/molecules/forms/input-tags/components/ChoicesTags.tsx new file mode 100644 index 0000000..35dcdc2 --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-tags/components/ChoicesTags.tsx @@ -0,0 +1,72 @@ +import Choices from "@formio/choices.js"; +import { useEffect, useRef } from "react"; +import { useDebouncedCallback } from "use-debounce"; + +import { registerComponent } from "../../../../registries/components"; +import { cleanFormControlProps } from "../../form-control/FormControl"; +import type { InputTagsProps } from "../InputTags.interface"; + +export function useChoiceTags(props: InputTagsProps) { + const { value, onChange, name = "", delimiter, customProperties, ...otherProps } = props; + const ref = useRef(null); + const instanceRef = useRef(null); + + const onAdd = useDebouncedCallback((add: Data) => { + const values = ((value || []) as Data[]).concat(add); + + onChange?.(name, [...values]); + }, 100); + + const onDelete = useDebouncedCallback((remove: Data) => { + const values = (value || []).filter((v) => v !== remove); + + onChange?.(name, [...values]); + }); + + useEffect(() => { + if (ref.current) { + const instance = new Choices(ref.current!, { + duplicateItemsAllowed: false, + ...customProperties, + delimiter, + editItems: true, + removeItemButton: true + }); + + instance.setValue((value || []) as string[]); + + instanceRef.current = instance; + + instance.passedElement.element.addEventListener("addItem", (event: { detail: { value: unknown } }) => { + onAdd(event.detail.value as Data); + }); + + instance.passedElement.element.addEventListener("removeItem", (event: { detail: { value: unknown } }) => { + onDelete(event.detail.value as Data); + }); + } + + return () => { + if (instanceRef.current) { + instanceRef.current.destroy(); + } + }; + }, [delimiter]); + + return { + otherProps: { + ...otherProps, + name + }, + ref, + instanceRef + }; +} + +export function ChoicesTags(props: InputTagsProps) { + const { ref, otherProps } = useChoiceTags(props); + + return ; +} + +registerComponent("InputTags.choicesjs", ChoicesTags); diff --git a/packages/react-formio/src/molecules/forms/input-tags/components/ReactTags.stories.tsx b/packages/react-formio/src/molecules/forms/input-tags/components/ReactTags.stories.tsx new file mode 100644 index 0000000..2208ca3 --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-tags/components/ReactTags.stories.tsx @@ -0,0 +1,140 @@ +import "../all"; + +import type { Meta, StoryObj } from "@storybook/react"; +import { type CreatableProps } from "react-select/creatable"; + +import { iconClass } from "../../../../utils/iconClass"; +import { useValue } from "../../../__fixtures__/useValue.hook"; +import { InputTags } from "../InputTags"; + +/** + * The InputTags component enables users to create new options in the text field. + * + * ```tsx + * import {InputTags} from "@tsed/react-formio/molecules/forms/input-tags/all"; + * + * or + * + * import "@tsed/react-formio/molecules/forms/input-tags/components/ReactTags"; + * import "@tsed/react-formio/molecules/forms/input-text/InputText"; + * import {InputTags} from "@tsed/react-formio/molecules/forms/input-tags/InputTags"; + * + * ``` + */ +export default { + title: "forms/InputTags/React", + component: InputTags, + argTypes: { + label: { + control: "text" + }, + name: { + control: "text" + }, + value: { + control: "object" + }, + size: { + control: "select", + options: ["small", "normal"] + }, + placeholder: { + control: "text" + }, + description: { + control: "text" + }, + layout: { + control: "select", + options: ["choicesjs", "react"] + }, + onChange: { + action: "onChange" + } + }, + parameters: {}, + args: { + layout: "react" + }, + tags: ["autodocs"], + render(args) { + // eslint-disable-next-line react-hooks/rules-of-hooks + const { value, onChange } = useValue(args); + + return ; + } +} satisfies Meta; + +type Story = StoryObj; + +export const Usage: Story = { + args: { + name: "name", + label: "Label", + value: ["test"], + size: "", + placeholder: "Placeholder" + } +}; + +export const WithSizeOption: Story = { + args: { + name: "name", + label: "Label", + value: ["test"], + size: "small", + placeholder: "Placeholder" + } +}; + +export const AppendBefore: Story = { + render(args) { + // eslint-disable-next-line react-hooks/rules-of-hooks + return } {...useValue(args)} />; + }, + args: { + label: "Label", + value: [], + name: "name", + size: "", + placeholder: "Placeholder" + } +}; + +export const AppendAfter: Story = { + render(args) { + // eslint-disable-next-line react-hooks/rules-of-hooks + return } {...useValue(args)} />; + }, + args: { + label: "Label", + value: [], + name: "name", + size: "", + placeholder: "Placeholder" + } +}; + +/** + * InputTags using the [react-select](https://react-select.com/) library can + * be customized using the `customProperties` prop. + * + * For example, you can use the `customProperties` prop to add a list of options. + * + * See the [react-select documentation](https://react-select.com/creatable) for more information. + */ +export const CustomProperties: Story = { + args: { + value: [], + name: "name", + label: "Label", + placeholder: "Select or Create...", + customProperties: { + options: [ + { value: "chocolate", label: "Chocolate" }, + { value: "strawberry", label: "Strawberry" }, + { value: "vanilla", label: "Vanilla" } + ] + } satisfies CreatableProps + } +}; diff --git a/packages/react-formio/src/molecules/forms/input-tags/components/ReactTags.tsx b/packages/react-formio/src/molecules/forms/input-tags/components/ReactTags.tsx new file mode 100644 index 0000000..6454268 --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-tags/components/ReactTags.tsx @@ -0,0 +1,38 @@ +import makeAnimated from "react-select/animated"; +import CreatableSelect from "react-select/creatable"; + +import { registerComponent } from "../../../../registries/components"; +import { InputTagsProps } from "../InputTags.interface"; + +const animatedComponents = makeAnimated(); + +export function ReactTags(props: InputTagsProps) { + const { value = [], placeholder, customProperties = {} } = props; + + return ( + { + return { label: v, value: v }; + })} + onChange={(value) => { + props.onChange?.( + props.name, + value.map(({ value }) => { + return value; + }) + ); + }} + /> + ); +} + +registerComponent("InputTags.react", ReactTags); diff --git a/packages/react-formio/src/molecules/forms/input-text/InputText.spec.tsx b/packages/react-formio/src/molecules/forms/input-text/InputText.spec.tsx index b9e8c86..f10c09d 100644 --- a/packages/react-formio/src/molecules/forms/input-text/InputText.spec.tsx +++ b/packages/react-formio/src/molecules/forms/input-text/InputText.spec.tsx @@ -16,7 +16,7 @@ describe("input-text", () => { const input = screen.getByTestId("input_test") as HTMLInputElement; expect(input).toBeInTheDocument(); - expect(input).toHaveClass("form-control-small"); + expect(screen.getByTestId("form-group-test")).toHaveClass("-size-small"); }); it("should display the input-text with placeholder", () => { diff --git a/packages/react-formio/src/molecules/forms/input-text/InputText.tsx b/packages/react-formio/src/molecules/forms/input-text/InputText.tsx index 38ba98e..16426bb 100644 --- a/packages/react-formio/src/molecules/forms/input-text/InputText.tsx +++ b/packages/react-formio/src/molecules/forms/input-text/InputText.tsx @@ -1,29 +1,13 @@ -import { useEffect, useState } from "react"; +import { ComponentType, useEffect, useState } from "react"; import { useDebouncedCallback } from "use-debounce"; -import { registerComponent } from "../../../registries/components"; +import { getComponent, registerComponent } from "../../../registries/components"; import { getEventValue } from "../../../utils/getEventValue"; import { cleanFormControlProps, FormControl } from "../form-control/FormControl"; import { InputTextProps } from "./InputText.interface"; -export function InputText(props: InputTextProps) { - const { - name, - id = name, - value, - label, - onChange, - required, - size, - type, - before, - after, - description, - className, - placeholder, - debounceDelay = 300, - ...otherProps - } = props; +function Input(props: InputTextProps) { + const { name, id = name, value, onChange, required, type, placeholder, debounceDelay = 300, ...otherProps } = props; const [localValue, setValue] = useState(value); const change = useDebouncedCallback(onChange || (() => {}), debounceDelay); @@ -32,6 +16,33 @@ export function InputText(props: InputTextProps) { setValue(value); }, [value]); + return ( + { + const value = getEventValue(event); + setValue(value); + + return change && change(name, value); + }} + /> + ); +} + +registerComponent("Input", Input); + +export function InputText(props: InputTextProps) { + const { name, id = name, label, required, size, before, after, description, className } = props; + const Input = getComponent>>("Input"); + return ( (props: InputTextProps) { size={size} className={className} > - { - const value = getEventValue(event); - setValue(value); - - return change && change(name, value); - }} - /> + ); } diff --git a/packages/react-formio/src/molecules/forms/select/components/ChoicesSelect.stories.tsx b/packages/react-formio/src/molecules/forms/select/components/ChoicesSelect.stories.tsx index f069a3d..46ec8c0 100644 --- a/packages/react-formio/src/molecules/forms/select/components/ChoicesSelect.stories.tsx +++ b/packages/react-formio/src/molecules/forms/select/components/ChoicesSelect.stories.tsx @@ -156,6 +156,7 @@ export const WithDisabledOption: Story = { export const WithSizeOption: Story = { args: { + label: "Label", size: "small", options: [ { diff --git a/packages/react-formio/src/molecules/forms/select/components/ChoicesSelect.tsx b/packages/react-formio/src/molecules/forms/select/components/ChoicesSelect.tsx index 0cb7ec7..730b780 100644 --- a/packages/react-formio/src/molecules/forms/select/components/ChoicesSelect.tsx +++ b/packages/react-formio/src/molecules/forms/select/components/ChoicesSelect.tsx @@ -1,10 +1,10 @@ import Choices from "@formio/choices.js"; import cx from "classnames"; -import omit from "lodash/omit"; import { useEffect, useMemo, useRef } from "react"; import { useDebouncedCallback } from "use-debounce"; import { registerComponent } from "../../../../registries/components"; +import { cleanFormControlProps } from "../../form-control/FormControl"; import type { AllSelectProps } from "../Select.interface"; import { callbackOnCreateTemplates } from "./choices.template"; @@ -75,14 +75,7 @@ export function useChoices({ useEffect(() => { if (!choicesRef.current) { - const { - allowHTML = true, - silent = true, - removeItemButton = true, - shouldSort = false, - itemSelectText = "", - classNames - } = customProperties; + const { allowHTML = true, silent = true, removeItemButton = true, shouldSort = false, itemSelectText = "" } = customProperties; choicesRef.current = new Choices(ref.current, { ...customProperties, allowHTML, @@ -94,10 +87,6 @@ export function useChoices({ placeholderValue: "" as string, itemSelectText, shouldSort, - classNames: { - ...classNames, - containerOuter: `choices ${size || ""}` - }, callbackOnCreateTemplates } as any); } @@ -148,7 +137,9 @@ export function ChoiceSelect(props: AllSelectProps) { {hasTypeChoices && (
-
)} {enableTags && (
- +
)} diff --git a/packages/react-formio/src/organisms/form/builder/all.ts b/packages/react-formio/src/organisms/form/builder/all.ts index 24156e9..066fcc1 100644 --- a/packages/react-formio/src/organisms/form/builder/all.ts +++ b/packages/react-formio/src/organisms/form/builder/all.ts @@ -3,7 +3,11 @@ import "../../../molecules/button/Button"; import "../../../molecules/forms/input-text/InputText"; import "../../../molecules/forms/select/Select"; import "../../../molecules/forms/select/components/HtmlSelect"; +import "../../../molecules/forms/select/components/ChoicesSelect"; +import "../../../molecules/forms/select/components/ReactSelect"; import "../../../molecules/forms/input-tags/InputTags"; +import "../../../molecules/forms/input-tags/components/ReactTags"; +import "../../../molecules/forms/input-tags/components/ChoicesTags"; export * from "./FormBuilder"; export * from "./FormEdit"; diff --git a/packages/tailwind-formio/styles/choices.css b/packages/tailwind-formio/styles/choices.css index cc5f372..6af6cee 100644 --- a/packages/tailwind-formio/styles/choices.css +++ b/packages/tailwind-formio/styles/choices.css @@ -26,15 +26,6 @@ line-height: inherit; } - &__small { - .choices__inner { - @apply px-2; - padding-top: 2px; - min-height: 0; - font-size: 14px; - } - } - &__input { @apply bg-white; } @@ -91,10 +82,6 @@ @apply pb-2; } - &.choices__small .choices__inner { - padding-bottom: 1px; - } - .choices__input { @apply block w-full p-2.5 border-b-1 border-solid border-gray-300 bg-white m-0; } @@ -182,6 +169,7 @@ @apply pb-0; } } + .choices__list--multiple .choices__item { @apply rounded-md bg-primary border-0 text-xs py-1 px-2; font-weight: 600; @@ -189,7 +177,6 @@ } - .is-open .choices__inner, .is-flipped.is-open .choices__inner { @apply rounded-md; } @@ -298,16 +285,6 @@ } @media (min-width: 640px) { - .choices__small { - .choices__list--dropdown .choices__item--selectable { - padding: 5px 10px; - - &:after { - display: none; - } - } - } - .choices__list--dropdown { .choices__item--selectable { padding-right: 100px; @@ -338,7 +315,6 @@ } } - .choices__heading { @apply font-semibold p-2.5 border-solid border-gray-200 text-gray-600; font-size: inherit; @@ -365,3 +341,34 @@ .choices__placeholder { @apply opacity-50; } + +/** + * Choices Size rendering + */ +.form-group.-size-small { + .choices { + .choices__inner { + @apply px-2; + padding-top: 3px; + min-height: 0; + font-size: 14px; + } + + &[data-type*=select-one] .choices__inner { + padding-bottom: 1px; + } + + .choices__list--multiple .choices__item { + @apply py-0.5 px-1 text-xs; + margin-bottom: 3px; + } + + .choices__input { + margin-bottom: 1px; + } + &[data-type*=select-multiple] .choices__button, + &[data-type*=text] .choices__button{ + margin: 0 -2px 0 6px; + } + } +} diff --git a/packages/tailwind-formio/styles/form.css b/packages/tailwind-formio/styles/form.css index 359ed38..29cf185 100644 --- a/packages/tailwind-formio/styles/form.css +++ b/packages/tailwind-formio/styles/form.css @@ -23,14 +23,19 @@ @apply mb-5; } + .form-control { @apply appearance-none bg-white leading-normal px-3 py-2 block w-full rounded-md border-1 border-gray-300 shadow-sm; +} - &.form-control-small { +.form-group.-size-small { + .form-control { @apply px-2 py-1 text-sm; + min-height: 32px; } } + .form-control:disabled, .form-control[readonly] { @apply bg-gray-200 border-transparent shadow-none; } @@ -148,7 +153,7 @@ textarea.form-control { } .field-required:after { - @apply z-1 ml-1; + @apply z-0 ml-1; } .formio-component hr, diff --git a/packages/tailwind-formio/styles/react-select.css b/packages/tailwind-formio/styles/react-select.css index 3bd597c..85a2962 100644 --- a/packages/tailwind-formio/styles/react-select.css +++ b/packages/tailwind-formio/styles/react-select.css @@ -23,7 +23,8 @@ } &__remove { - @apply opacity-80; + @apply opacity-80; + &:hover { @apply bg-transparent text-white opacity-100; } @@ -35,7 +36,56 @@ } } -.input-group-prepend + .react-select-container .react-select__control { - border-top-left-radius: 0; - border-bottom-left-radius: 0; +.form-group.-with-before { + .react-select-container .react-select__control { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } +} + +.form-group.-with-after { + .react-select-container .react-select__control { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } +} + +/** + * React Select size rendering + */ +.form-group.-size-small { + .react-select-container { + .react-select__control { + min-height: 28px; + } + .react-select__indicator { + padding: 3px; + } + .react-select__multi-value { + &__label { + @apply text-white text-xs py-0.5 px-1; + font-weight: 600; + } + + &__remove { + @apply opacity-80; + + &:hover { + @apply bg-transparent text-white opacity-100; + } + } + } + + .react-select__input-container { + margin-top:1px; + margin-bottom: 1px; + } + .react-select__single-value { + @apply text-sm; + } + + .react-select__value-container.react-select__value-container--is-multi { + @apply px-1 py-0; + } + } }