mirror of
https://github.com/penpot/penpot.git
synced 2025-01-22 22:49:01 -05:00
Merge pull request #4938 from penpot/ladybenko-7879-ds-input
🎉 Implement input* component
This commit is contained in:
commit
1c2b6f5ab5
7 changed files with 199 additions and 1 deletions
|
@ -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*
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
32
frontend/src/app/main/ui/ds/forms/input.cljs
Normal file
32
frontend/src/app/main/ui/ds/forms/input.cljs
Normal 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]]))
|
51
frontend/src/app/main/ui/ds/forms/input.mdx
Normal file
51
frontend/src/app/main/ui/ds/forms/input.mdx
Normal 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.
|
64
frontend/src/app/main/ui/ds/forms/input.scss
Normal file
64
frontend/src/app/main/ui/ds/forms/input.scss
Normal 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);
|
||||||
|
}
|
47
frontend/src/app/main/ui/ds/forms/input.stories.jsx
Normal file
47
frontend/src/app/main/ui/ds/forms/input.stories.jsx
Normal 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",
|
||||||
|
},
|
||||||
|
};
|
Loading…
Add table
Reference in a new issue