From 1c797dea2f0ee7476997bcd88f32d6e742c486bf Mon Sep 17 00:00:00 2001 From: carly-bartel Date: Mon, 25 Nov 2024 11:51:43 -0500 Subject: [PATCH 01/15] toggle and label component started --- .../Form/Elements/Toggle/Toggle.scss | 2 +- .../src/pages/Settings/AnnotationSettings.jsx | 3 +- .../src/pages/WebhookPage/WebhookList.jsx | 2 +- web/libs/editor/src/common/Toggle/Toggle.scss | 2 +- web/libs/ui/src/index.ts | 2 + web/libs/ui/src/lib/label/label.module.scss | 83 +++++++++++++++++++ web/libs/ui/src/lib/label/label.tsx | 31 +++++++ web/libs/ui/src/lib/toggle/toggle.module.scss | 73 ++++++++++++++++ web/libs/ui/src/lib/toggle/toggle.tsx | 53 ++++++++++++ 9 files changed, 247 insertions(+), 4 deletions(-) create mode 100644 web/libs/ui/src/lib/label/label.module.scss create mode 100644 web/libs/ui/src/lib/label/label.tsx create mode 100644 web/libs/ui/src/lib/toggle/toggle.module.scss create mode 100644 web/libs/ui/src/lib/toggle/toggle.tsx diff --git a/web/apps/labelstudio/src/components/Form/Elements/Toggle/Toggle.scss b/web/apps/labelstudio/src/components/Form/Elements/Toggle/Toggle.scss index ec99e1759727..65be46a922c7 100644 --- a/web/apps/labelstudio/src/components/Form/Elements/Toggle/Toggle.scss +++ b/web/apps/labelstudio/src/components/Form/Elements/Toggle/Toggle.scss @@ -1,4 +1,4 @@ -.toggle { +.toggle { width: 42px; height: 24px; display: block; diff --git a/web/apps/labelstudio/src/pages/Settings/AnnotationSettings.jsx b/web/apps/labelstudio/src/pages/Settings/AnnotationSettings.jsx index 9d08c1c76b1b..d747e1670e4b 100644 --- a/web/apps/labelstudio/src/pages/Settings/AnnotationSettings.jsx +++ b/web/apps/labelstudio/src/pages/Settings/AnnotationSettings.jsx @@ -1,8 +1,9 @@ import { useCallback, useContext, useEffect, useRef, useState } from "react"; import { Button } from "../../components"; -import { Form, TextArea, Toggle } from "../../components/Form"; +import { Form, TextArea } from "../../components/Form"; import { MenubarContext } from "../../components/Menubar/Menubar"; import { Block, Elem } from "../../utils/bem"; +import { Toggle } from "@humansignal/ui"; import { ModelVersionSelector } from "./AnnotationSettings/ModelVersionSelector"; import { ProjectContext } from "../../providers/ProjectProvider"; diff --git a/web/apps/labelstudio/src/pages/WebhookPage/WebhookList.jsx b/web/apps/labelstudio/src/pages/WebhookPage/WebhookList.jsx index 8e983a420423..63233556dd23 100644 --- a/web/apps/labelstudio/src/pages/WebhookPage/WebhookList.jsx +++ b/web/apps/labelstudio/src/pages/WebhookPage/WebhookList.jsx @@ -2,7 +2,7 @@ import { useCallback } from "react"; import { LsPencil } from "../../assets/icons"; import { IconCross } from "@humansignal/ui"; import { Button } from "../../components"; -import { Toggle } from "../../components/Form"; +import { Toggle } from "@humansignal/ui"; import { Block, Elem } from "../../utils/bem"; import "./WebhookPage.scss"; import { format } from "date-fns"; diff --git a/web/libs/editor/src/common/Toggle/Toggle.scss b/web/libs/editor/src/common/Toggle/Toggle.scss index 559ab8d59791..dc7524474ff1 100644 --- a/web/libs/editor/src/common/Toggle/Toggle.scss +++ b/web/libs/editor/src/common/Toggle/Toggle.scss @@ -1,5 +1,5 @@ .toggle { - width: 42px; + width: 42px; height: 24px; display: block; min-width: 42px; diff --git a/web/libs/ui/src/index.ts b/web/libs/ui/src/index.ts index cb0b8bb66de7..d1b64a57b92e 100644 --- a/web/libs/ui/src/index.ts +++ b/web/libs/ui/src/index.ts @@ -1,4 +1,6 @@ export * from "./lib/checkbox/checkbox"; export * from "./lib/Toast/Toast"; +export * from "./lib/toggle/toggle"; +export * from "./lib/label/label"; export * from "./assets/icons"; diff --git a/web/libs/ui/src/lib/label/label.module.scss b/web/libs/ui/src/lib/label/label.module.scss new file mode 100644 index 000000000000..8754089ba274 --- /dev/null +++ b/web/libs/ui/src/lib/label/label.module.scss @@ -0,0 +1,83 @@ +.field-label { + margin-bottom: 0; + + &__text { + padding: 0 16px; + height: 22px; + display: flex; + margin-bottom: 4px; + font-size: 14px; + line-height: 22px; + justify-content: space-between; + } + + &__description { + margin-top: 5px; + font-size: 14px; + line-height: 22px; + color: var(--sand_500); + } + + &__field { + line-height: 0; + } + + &_size_small &__text { + font-size: 10px; + margin: 0; + height: 14px; + line-height: 14px; + } + + &_size_large &__text { + font-weight: 500; + font-size: 16px; + line-height: 22px; + margin-bottom: 16px; + } + + &_flat &__text { + padding: 0; + } + + .input, + .select, + .textarea { + width: 100%; + } + + &[data-required] &__text::after { + content: "Required"; + color: var(--sand_500); + } + + &_placement_right { + display: inline-flex; + flex-direction: row-reverse; + } + + &_placement_left { + display: inline-flex; + } + + &_empty &__text, + &_placement_right &__text, + &_placement_left &__text { + margin-bottom: 0; + font-size: 16px; + line-height: 22px; + height: auto; + align-items: center; + } + + &_placement_right:not(.label_withDescription) &__field, + &_placement_left:not(.label_withDescription) &__field { + display: flex; + align-items: center; + } + + &_placement_right.label_withDescription &__field, + &_placement_left.label_withDescription &__field { + margin-top: 5px; + } +} diff --git a/web/libs/ui/src/lib/label/label.tsx b/web/libs/ui/src/lib/label/label.tsx new file mode 100644 index 000000000000..4221a6547c14 --- /dev/null +++ b/web/libs/ui/src/lib/label/label.tsx @@ -0,0 +1,31 @@ +import { forwardRef } from "react"; +import clsx from "clsx"; +import styles from "./label.module.scss"; + +export const Label = forwardRef( + ({ text, children, required, placement, description, size, large, style, simple, flat }) => { + const tagName = simple ? "div" : "label"; + const mods = { + size, + large, + flat, + placement, + withDescription: !!description, + empty: !children, + }; + + return ( +
+ + + {text} + {description && {description}} + + + {children} +
+ ); + }, +); + +export default Label; \ No newline at end of file diff --git a/web/libs/ui/src/lib/toggle/toggle.module.scss b/web/libs/ui/src/lib/toggle/toggle.module.scss new file mode 100644 index 000000000000..fef50e3227ae --- /dev/null +++ b/web/libs/ui/src/lib/toggle/toggle.module.scss @@ -0,0 +1,73 @@ +.toggle { + width: 42px; + height: 24px; + display: block; + min-width: 42px; + max-height: 24px; + border-radius: 12px; + position: relative; + cursor: pointer; + color: var(--toggle-color, var(--grape_500)); + transition: box-shadow 80ms ease; + background: linear-gradient(0deg, rgb(0 0 0 / 5%), rgb(0 0 0 / 5%)), var(--sand_0); + box-shadow: inset 0 1px 0 rgb(0 0 0 / 5%), inset 0 0 0 1px rgb(0 0 0 / 5%); + background: red; + + &__input { + top: 0; + left: 0; + margin: 0; + opacity: 0; + padding: 0; + width: 100%; + height: 100%; + position: absolute; + } + + &__indicator { + height: 24px; + width: 24px; + display: flex; + align-items: center; + justify-content: center; + transition: all 120ms ease; + + &::before { + content: ""; + width: 10px; + height: 10px; + border-radius: 100%; + transition: all 120ms ease; + background: var(--sand_200); + box-shadow: 0 5px 10px rgb(0 0 0 / 15%), inset 0 -1px 0 rgb(0 0 0 / 10%), inset 0 0 0 1px rgb(0 0 0 / 5%); + } + } + + &_checked &__indicator { + margin-left: 18px; + + &::before { + width: 16px; + height: 16px; + background: currentcolor; + box-shadow: 0 5px 10px var(--grape_100), inset 0 -1px 0 rgb(0 0 0 / 10%); + } + } + + &_disabled { + box-shadow: none; + pointer-events: none; + background: var(--sand_200); + } + + &_disabled &__indicator { + transition: none; + } + + &_disabled &__indicator::before, + &_disabled.toggle_checked &__indicator::before { + box-shadow: none; + transition: none; + background-color: var(--sand_500); + } +} \ No newline at end of file diff --git a/web/libs/ui/src/lib/toggle/toggle.tsx b/web/libs/ui/src/lib/toggle/toggle.tsx new file mode 100644 index 000000000000..d46209005bb5 --- /dev/null +++ b/web/libs/ui/src/lib/toggle/toggle.tsx @@ -0,0 +1,53 @@ +import { forwardRef, useEffect, useMemo, useState } from "react"; +import clsx from "clsx"; +import Label from "../label/label"; +import styles from "./toggle.module.scss"; + +const Toggle = forwardRef( + ( + { className, label, labelProps, description, checked, defaultChecked, onChange, required, style, ...props }, + ) => { + const initialChecked = useMemo(() => defaultChecked ?? checked ?? false, [defaultChecked, checked]); + const [isChecked, setIsChecked] = useState(defaultChecked ?? checked ?? false); + + const mods = {}; + + useEffect(() => { + setIsChecked(initialChecked); + }, [initialChecked]); + + if (isChecked) mods.checked = isChecked; + mods.disabled = props.disabled; + + const formField = ( +
+ { + setIsChecked(e.target.checked); + onChange?.(e); + }} + /> + +
+ ); + + return label ? ( +