mirror of
https://github.com/penpot/penpot.git
synced 2025-05-18 10:56:13 +02:00
✨ Add new DS component: InputWithValues (#5777)
* ✨ Add new DS component: InputWithValues * ✨ Fix MR * ✨ Fix MR 2
This commit is contained in:
parent
0f49208040
commit
9c7bb96b1c
6 changed files with 189 additions and 1 deletions
|
@ -11,6 +11,7 @@
|
||||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||||
[app.main.ui.ds.controls.combobox :refer [combobox*]]
|
[app.main.ui.ds.controls.combobox :refer [combobox*]]
|
||||||
[app.main.ui.ds.controls.input :refer [input*]]
|
[app.main.ui.ds.controls.input :refer [input*]]
|
||||||
|
[app.main.ui.ds.controls.input-with-values :refer [input-with-values*]]
|
||||||
[app.main.ui.ds.controls.select :refer [select*]]
|
[app.main.ui.ds.controls.select :refer [select*]]
|
||||||
[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]]
|
||||||
|
@ -44,6 +45,7 @@
|
||||||
:Icon icon*
|
:Icon icon*
|
||||||
:IconButton icon-button*
|
:IconButton icon-button*
|
||||||
:Input input*
|
:Input input*
|
||||||
|
:InputWithValues input-with-values*
|
||||||
:EmptyPlaceholder empty-placeholder*
|
:EmptyPlaceholder empty-placeholder*
|
||||||
:Loader loader*
|
:Loader loader*
|
||||||
:RawSvg raw-svg*
|
:RawSvg raw-svg*
|
||||||
|
|
|
@ -65,7 +65,6 @@
|
||||||
margin: var(--input-margin, unset); // remove settings from global css
|
margin: var(--input-margin, unset); // remove settings from global css
|
||||||
padding: 0;
|
padding: 0;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
margin-inline-start: var(--sp-xxs);
|
|
||||||
height: var(--input-height, #{$sz-32});
|
height: var(--input-height, #{$sz-32});
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
|
@ -93,6 +92,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input-with-icon {
|
||||||
|
margin-inline-start: var(--sp-xxs);
|
||||||
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
color: var(--color-foreground-secondary);
|
color: var(--color-foreground-secondary);
|
||||||
}
|
}
|
||||||
|
|
69
frontend/src/app/main/ui/ds/controls/input_with_values.cljs
Normal file
69
frontend/src/app/main/ui/ds/controls/input_with_values.cljs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
;; 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.controls.input-with-values
|
||||||
|
(:require-macros
|
||||||
|
[app.main.style :as stl])
|
||||||
|
(:require
|
||||||
|
[app.main.ui.ds.controls.input :refer [input*]]
|
||||||
|
[app.util.dom :as dom]
|
||||||
|
[app.util.keyboard :as kbd]
|
||||||
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
(def ^:private schema:input-with-values
|
||||||
|
[:map
|
||||||
|
[:name :string]
|
||||||
|
[:values :string]
|
||||||
|
[:on-blur {:optional true} fn?]])
|
||||||
|
|
||||||
|
|
||||||
|
(mf/defc input-with-values*
|
||||||
|
{::mf/props :obj
|
||||||
|
::mf/schema schema:input-with-values}
|
||||||
|
[{:keys [name values on-blur]}]
|
||||||
|
(let [editing* (mf/use-state false)
|
||||||
|
editing? (deref editing*)
|
||||||
|
input-ref (mf/use-ref)
|
||||||
|
input (mf/ref-val input-ref)
|
||||||
|
title (str name ": " values)
|
||||||
|
on-edit
|
||||||
|
(mf/use-fn
|
||||||
|
(fn [event]
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(reset! editing* true)
|
||||||
|
(dom/focus! input)))
|
||||||
|
on-stop-edit
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps on-blur)
|
||||||
|
(fn [event]
|
||||||
|
(let [new-name (dom/get-target-val event)]
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(reset! editing* false)
|
||||||
|
(when on-blur
|
||||||
|
(on-blur new-name)))))
|
||||||
|
|
||||||
|
handle-key-down
|
||||||
|
(mf/use-fn
|
||||||
|
(fn [event]
|
||||||
|
(let [enter? (kbd/enter? event)
|
||||||
|
esc? (kbd/esc? event)
|
||||||
|
node (dom/get-target event)]
|
||||||
|
(when ^boolean enter? (dom/blur! node))
|
||||||
|
(when ^boolean esc? (dom/blur! node)))))]
|
||||||
|
|
||||||
|
(if editing?
|
||||||
|
[:div {:class (stl/css :input-with-values-edit-container)}
|
||||||
|
[:> input*
|
||||||
|
{:ref input-ref
|
||||||
|
:class (stl/css :input-with-values-editing)
|
||||||
|
:default-value name
|
||||||
|
:auto-focus true
|
||||||
|
:on-blur on-stop-edit
|
||||||
|
:on-key-down handle-key-down}]]
|
||||||
|
[:div {:class (stl/css :input-with-values-container :input-with-values-grid)
|
||||||
|
:title title :on-click on-edit}
|
||||||
|
[:span {:class (stl/css :input-with-values-name)} name]
|
||||||
|
[:span {:class (stl/css :input-with-values-values)} values]])))
|
37
frontend/src/app/main/ui/ds/controls/input_with_values.mdx
Normal file
37
frontend/src/app/main/ui/ds/controls/input_with_values.mdx
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import { Canvas, Meta } from '@storybook/blocks';
|
||||||
|
import * as InputWithValuesStories from "./input_with_values.stories";
|
||||||
|
|
||||||
|
<Meta title="Controls/InputWithValues" />
|
||||||
|
|
||||||
|
# InputWithValues
|
||||||
|
|
||||||
|
The `input-with-values*` acts as an input with an addition of a series of values that are only indicators.
|
||||||
|
|
||||||
|
<Canvas of={InputWithValuesStories.Default} />
|
||||||
|
|
||||||
|
|
||||||
|
## Technical notes
|
||||||
|
|
||||||
|
* You need to pass the mandatory string properties `name` and `values`
|
||||||
|
* You can pass a function property `on-blur` that will be called with the new value when the component lost focus (including when the user press enter or esc)
|
||||||
|
|
||||||
|
```clj
|
||||||
|
[:> input-with-values*
|
||||||
|
{:name name
|
||||||
|
:values values
|
||||||
|
:on-blur on-blur}]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Usage guidelines (design)
|
||||||
|
|
||||||
|
|
||||||
|
### When to use
|
||||||
|
|
||||||
|
When we have an element that need to be editable, and an extra set of values that aren't editables and are only indicators
|
||||||
|
|
||||||
|
|
||||||
|
### Interaction / Behavior
|
||||||
|
* The component starts on "display" mode, showing the name and the values
|
||||||
|
* Once the user clicks on it, the input goes into "active" mode and the only thing that remains and that is editable is the name (the values are hidden)
|
||||||
|
* If the user press enter or esc, the component goes back to "display" mode
|
47
frontend/src/app/main/ui/ds/controls/input_with_values.scss
Normal file
47
frontend/src/app/main/ui/ds/controls/input_with_values.scss
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
|
||||||
|
|
||||||
|
@use "../_borders.scss" as *;
|
||||||
|
@use "../spacing.scss" as *;
|
||||||
|
@use "../_sizes.scss" as *;
|
||||||
|
@use "../typography.scss" as t;
|
||||||
|
|
||||||
|
.input-with-values-container {
|
||||||
|
@include t.use-typography("body-small");
|
||||||
|
border-radius: $br-8;
|
||||||
|
background-color: var(--assets-item-background-color);
|
||||||
|
padding: var(--sp-s);
|
||||||
|
width: 99%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
gap: var(--sp-s);
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
height: $sz-32;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-with-values-edit-container {
|
||||||
|
width: 99%;
|
||||||
|
border-radius: $br-8;
|
||||||
|
height: $sz-32;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-with-values-name,
|
||||||
|
.input-with-values-values {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-with-values-name {
|
||||||
|
color: var(--color-foreground-primary);
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-with-values-values {
|
||||||
|
color: var(--color-foreground-secondary);
|
||||||
|
min-width: 0;
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
// 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 { InputWithValues } = Components;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "Controls/InputWithValues",
|
||||||
|
component: Components.InputWithValues,
|
||||||
|
argTypes: {
|
||||||
|
name: {
|
||||||
|
control: { type: "text" },
|
||||||
|
},
|
||||||
|
values: {
|
||||||
|
control: { type: "text" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
name: "Property 1",
|
||||||
|
values: "Value1, Value2",
|
||||||
|
},
|
||||||
|
render: ({ ...args }) => <InputWithValues {...args} />,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Default = {};
|
Loading…
Add table
Add a link
Reference in a new issue