0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-22 14:39:45 -05:00

Merge pull request #4938 from penpot/ladybenko-7879-ds-input

🎉 Implement input* component
This commit is contained in:
Eva Marco 2024-08-05 08:58:53 +02:00 committed by GitHub
commit 1c2b6f5ab5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 199 additions and 1 deletions

View file

@ -8,6 +8,7 @@
(:require (:require
[app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.ds.buttons.button :refer [button*]]
[app.main.ui.ds.buttons.icon-button :refer [icon-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.icon :refer [icon* icon-list]]
[app.main.ui.ds.foundations.assets.raw-svg :refer [raw-svg* raw-svg-list]] [app.main.ui.ds.foundations.assets.raw-svg :refer [raw-svg* raw-svg-list]]
[app.main.ui.ds.foundations.typography :refer [typography-list]] [app.main.ui.ds.foundations.typography :refer [typography-list]]
@ -22,6 +23,7 @@
:Heading heading* :Heading heading*
:Icon icon* :Icon icon*
:IconButton icon-button* :IconButton icon-button*
:Input input*
:Loader loader* :Loader loader*
:RawSvg raw-svg* :RawSvg raw-svg*
:Text text* :Text text*

View file

@ -8,3 +8,5 @@
// TODO: create actual tokens once we have them from design // TODO: create actual tokens once we have them from design
$br-8: px2rem(8); $br-8: px2rem(8);
$b-1: px2rem(1);

View file

@ -27,7 +27,7 @@
background: var(--button-bg-color); background: var(--button-bg-color);
color: var(--button-fg-color); color: var(--button-fg-color);
border: 1px solid var(--button-border-color); border: $b-1 solid var(--button-border-color);
&:hover { &:hover {
--button-bg-color: var(--button-hover-bg-color); --button-bg-color: var(--button-hover-bg-color);

View file

@ -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]]))

View file

@ -0,0 +1,51 @@
import { Canvas, Meta } from '@storybook/blocks';
import * as InputStories from "./input.stories";
<Meta title="Forms/Input" />
# Input
The `input*` component is a wrapper to the HTML `<input>` element with custom styling
and additional elements that adds context and, in some cases, adds extra
functionality.
<Canvas of={InputStories.Default} />
## 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}]
```
<Canvas of={InputStories.WithIcon} />
## 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.

View file

@ -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);
}

View file

@ -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 }) => <Input {...args} />,
};
export const Default = {};
export const WithIcon = {
args: {
icon: "effects",
},
};
export const WithPlaceholder = {
args: {
icon: "effects",
value: undefined,
placeholder: "Mixed",
},
};