From 480d5ba7c351f74c0b2eb70b987ebdb48e00a53f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Mon, 29 Jul 2024 15:58:43 +0200 Subject: [PATCH 1/2] :tada: Implement input* component --- frontend/src/app/main/ui/ds.cljs | 2 + frontend/src/app/main/ui/ds/_borders.scss | 2 + .../src/app/main/ui/ds/buttons/_buttons.scss | 2 +- frontend/src/app/main/ui/ds/forms/input.cljs | 32 ++++++++++ frontend/src/app/main/ui/ds/forms/input.scss | 64 +++++++++++++++++++ .../app/main/ui/ds/forms/input.stories.jsx | 47 ++++++++++++++ 6 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 frontend/src/app/main/ui/ds/forms/input.cljs create mode 100644 frontend/src/app/main/ui/ds/forms/input.scss create mode 100644 frontend/src/app/main/ui/ds/forms/input.stories.jsx diff --git a/frontend/src/app/main/ui/ds.cljs b/frontend/src/app/main/ui/ds.cljs index 9ac05d4f8..85268cf8d 100644 --- a/frontend/src/app/main/ui/ds.cljs +++ b/frontend/src/app/main/ui/ds.cljs @@ -8,6 +8,7 @@ (:require [app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] + [app.main.ui.ds.forms.input :refer [input*]] [app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]] [app.main.ui.ds.foundations.assets.raw-svg :refer [raw-svg* raw-svg-list]] [app.main.ui.ds.foundations.typography :refer [typography-list]] @@ -22,6 +23,7 @@ :Heading heading* :Icon icon* :IconButton icon-button* + :Input input* :Loader loader* :RawSvg raw-svg* :Text text* diff --git a/frontend/src/app/main/ui/ds/_borders.scss b/frontend/src/app/main/ui/ds/_borders.scss index 165ade57d..a424603d1 100644 --- a/frontend/src/app/main/ui/ds/_borders.scss +++ b/frontend/src/app/main/ui/ds/_borders.scss @@ -8,3 +8,5 @@ // TODO: create actual tokens once we have them from design $br-8: px2rem(8); + +$b-1: px2rem(1); diff --git a/frontend/src/app/main/ui/ds/buttons/_buttons.scss b/frontend/src/app/main/ui/ds/buttons/_buttons.scss index 7d8c896ac..b489b4df9 100644 --- a/frontend/src/app/main/ui/ds/buttons/_buttons.scss +++ b/frontend/src/app/main/ui/ds/buttons/_buttons.scss @@ -27,7 +27,7 @@ background: var(--button-bg-color); color: var(--button-fg-color); - border: 1px solid var(--button-border-color); + border: $b-1 solid var(--button-border-color); &:hover { --button-bg-color: var(--button-hover-bg-color); diff --git a/frontend/src/app/main/ui/ds/forms/input.cljs b/frontend/src/app/main/ui/ds/forms/input.cljs new file mode 100644 index 000000000..6b97e5449 --- /dev/null +++ b/frontend/src/app/main/ui/ds/forms/input.cljs @@ -0,0 +1,32 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + +(ns app.main.ui.ds.forms.input + (:require-macros + [app.common.data.macros :as dm] + [app.main.style :as stl]) + (:require + [app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]] + [app.util.dom :as dom] + [rumext.v2 :as mf])) + +(mf/defc input* + {::mf/props :obj} + [{:keys [icon class type ref] :rest props}] + (assert (or (nil? icon) (contains? icon-list icon))) + (let [ref (or ref (mf/use-ref)) + type (or type "text") + icon-class (stl/css-case :input true + :input-with-icon (some? icon)) + props (mf/spread-props props {:class icon-class :ref ref :type type}) + handle-icon-click (mf/use-fn (mf/deps ref) + (fn [_] + (let [input-node (mf/ref-val ref)] + (dom/select-node input-node) + (dom/focus! input-node))))] + [:> "span" {:class (dm/str class " " (stl/css :container))} + (when icon [:> icon* {:id icon :class (stl/css :icon) :on-click handle-icon-click}]) + [:> "input" props]])) \ No newline at end of file diff --git a/frontend/src/app/main/ui/ds/forms/input.scss b/frontend/src/app/main/ui/ds/forms/input.scss new file mode 100644 index 000000000..027e79878 --- /dev/null +++ b/frontend/src/app/main/ui/ds/forms/input.scss @@ -0,0 +1,64 @@ +@use "../_borders.scss" as *; +@use "../_sizes.scss" as *; +@use "../typography.scss" as *; + +.container { + --input-bg-color: var(--color-background-tertiary); + --input-fg-color: var(--color-foreground-primary); + --input-icon-color: var(--color-foreground-secondary); + --input-outline-color: none; + + display: inline-flex; + column-gap: var(--sp-xs); + align-items: center; + position: relative; + + background: var(--input-bg-color); + border-radius: $br-8; + padding: 0 var(--sp-s); + outline-offset: #{$b-1}; + outline: $b-1 solid var(--input-outline-color); + + &:hover { + --input-bg-color: var(--color-background-quaternary); + } + + &:has(*:focus-visible) { + --input-bg-color: var(--color-background-primary); + --input-outline-color: var(--color-accent-primary); + } + + &:has(*:disabled) { + --input-bg-color: var(--color-background-primary); + --input-outline-color: var(--color-background-quaternary); + } +} + +.input { + margin: unset; // remove settings from global css + padding: 0; + appearance: none; + margin-inline-start: var(--sp-xxs); + height: $sz-32; + border: none; + background: none; + + @include use-typography("body-small"); + color: var(--input-fg-color); + + &:focus-visible { + outline: none; + } + + &::selection { + background: var(--color-accent-primary-muted); + } + + &::placeholder { + --input-fg-color: var(--color-foreground-secondary); + } +} + +.icon { + color: var(--color-foreground-secondary); +} diff --git a/frontend/src/app/main/ui/ds/forms/input.stories.jsx b/frontend/src/app/main/ui/ds/forms/input.stories.jsx new file mode 100644 index 000000000..2f0122283 --- /dev/null +++ b/frontend/src/app/main/ui/ds/forms/input.stories.jsx @@ -0,0 +1,47 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) KALEIDOS INC + +import * as React from "react"; +import Components from "@target/components"; + +const { Input } = Components; +const { icons } = Components.meta; + +export default { + title: "Forms/Input", + component: Components.Input, + argTypes: { + icon: { + options: icons, + control: { type: "select" }, + }, + value: { + control: { type: "text" }, + }, + disabled: { control: "boolean" }, + }, + args: { + disabled: false, + value: "Lorem ipsum", + }, + render: ({ ...args }) => , +}; + +export const Default = {}; + +export const WithIcon = { + args: { + icon: "effects", + }, +}; + +export const WithPlaceholder = { + args: { + icon: "effects", + value: undefined, + placeholder: "Mixed", + }, +}; From 2015c484d0e76eb43da02c0c3b887b3defdb311c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Fri, 2 Aug 2024 09:57:19 +0200 Subject: [PATCH 2/2] :books: Add Input component documentation --- frontend/src/app/main/ui/ds/forms/input.mdx | 51 +++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 frontend/src/app/main/ui/ds/forms/input.mdx diff --git a/frontend/src/app/main/ui/ds/forms/input.mdx b/frontend/src/app/main/ui/ds/forms/input.mdx new file mode 100644 index 000000000..2d6d9946a --- /dev/null +++ b/frontend/src/app/main/ui/ds/forms/input.mdx @@ -0,0 +1,51 @@ +import { Canvas, Meta } from '@storybook/blocks'; +import * as InputStories from "./input.stories"; + + + +# Input + +The `input*` component is a wrapper to the HTML `` element with custom styling +and additional elements that adds context and, in some cases, adds extra +functionality. + + + + +## Technical notes + +### Icons + +`input*` accepts an `icon` prop, which must contain an [icon ID](../foundations/assets/icon.mdx). +These are available in the `app.main.ds.foundations.assets.icon` namespace. + +```clj +(ns app.main.ui.foo + (:require + [app.main.ui.ds.foundations.assets.icon :as i])) +``` + +```clj +[:> input* {:icon i/effects}] +``` + + + +## Usage guidelines (design) + +### Where to use + +In forms where the user needs to input any short text or number. + +### When to use + +When the information that is needed is short and needs an element to add context +for using it or additional functionality (like color picker). + +### Size + +The width of the component depends on the content and layout. They can expand to +fill the container or the content area to which they relate (e.g. tabs) and adapt +depending on whether there are one or two input elements with or without buttons +next to them. Their height is always fixed, `32px`, with text area being used for +larger text blocks.