mirror of
https://github.com/penpot/penpot.git
synced 2025-01-23 23:18:48 -05:00
Merge pull request #5017 from penpot/eva-add-select-to-ds
✨ Add select component to the DS
This commit is contained in:
commit
53f580ad40
10 changed files with 534 additions and 4 deletions
|
@ -9,7 +9,8 @@
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[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.controls.input :refer [input*]]
|
||||||
|
[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]]
|
||||||
[app.main.ui.ds.foundations.typography :refer [typography-list]]
|
[app.main.ui.ds.foundations.typography :refer [typography-list]]
|
||||||
|
@ -33,6 +34,7 @@
|
||||||
:Input input*
|
:Input input*
|
||||||
:Loader loader*
|
:Loader loader*
|
||||||
:RawSvg raw-svg*
|
:RawSvg raw-svg*
|
||||||
|
:Select select*
|
||||||
:Text text*
|
:Text text*
|
||||||
:TabSwitcher tab-switcher*
|
:TabSwitcher tab-switcher*
|
||||||
:Toast toast*
|
:Toast toast*
|
||||||
|
|
|
@ -9,4 +9,6 @@
|
||||||
// TODO: create actual tokens once we have them from design
|
// TODO: create actual tokens once we have them from design
|
||||||
$sz-16: px2rem(16);
|
$sz-16: px2rem(16);
|
||||||
$sz-32: px2rem(32);
|
$sz-32: px2rem(32);
|
||||||
|
$sz-36: px2rem(36);
|
||||||
$sz-224: px2rem(224);
|
$sz-224: px2rem(224);
|
||||||
|
$sz-400: px2rem(400);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
;;
|
;;
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.ds.forms.input
|
(ns app.main.ui.ds.controls.input
|
||||||
(:require-macros
|
(:require-macros
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.main.style :as stl])
|
[app.main.style :as stl])
|
|
@ -1,7 +1,7 @@
|
||||||
import { Canvas, Meta } from '@storybook/blocks';
|
import { Canvas, Meta } from '@storybook/blocks';
|
||||||
import * as InputStories from "./input.stories";
|
import * as InputStories from "./input.stories";
|
||||||
|
|
||||||
<Meta title="Forms/Input" />
|
<Meta title="Controls/Input" />
|
||||||
|
|
||||||
# Input
|
# Input
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
// 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 "../_borders.scss" as *;
|
||||||
@use "../_sizes.scss" as *;
|
@use "../_sizes.scss" as *;
|
||||||
@use "../typography.scss" as *;
|
@use "../typography.scss" as *;
|
|
@ -11,7 +11,7 @@ const { Input } = Components;
|
||||||
const { icons } = Components.meta;
|
const { icons } = Components.meta;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: "Forms/Input",
|
title: "Controls/Input",
|
||||||
component: Components.Input,
|
component: Components.Input,
|
||||||
argTypes: {
|
argTypes: {
|
||||||
icon: {
|
icon: {
|
245
frontend/src/app/main/ui/ds/controls/select.cljs
Normal file
245
frontend/src/app/main/ui/ds/controls/select.cljs
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
;; 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.select
|
||||||
|
(: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] :as i]
|
||||||
|
[app.util.array :as array]
|
||||||
|
[app.util.dom :as dom]
|
||||||
|
[app.util.keyboard :as kbd]
|
||||||
|
[app.util.object :as obj]
|
||||||
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
(mf/defc option*
|
||||||
|
{::mf/props :obj
|
||||||
|
::mf/private true}
|
||||||
|
[{:keys [id label icon aria-label on-click selected set-ref focused] :rest props}]
|
||||||
|
[:> :li {:value id
|
||||||
|
:class (stl/css-case :option true
|
||||||
|
:option-with-icon (some? icon)
|
||||||
|
:option-current focused)
|
||||||
|
:aria-selected selected
|
||||||
|
|
||||||
|
:ref (fn [node]
|
||||||
|
(set-ref node id))
|
||||||
|
:role "option"
|
||||||
|
:id id
|
||||||
|
:on-click on-click
|
||||||
|
:data-id id}
|
||||||
|
|
||||||
|
(when (some? icon)
|
||||||
|
[:> icon*
|
||||||
|
{:id icon
|
||||||
|
:size "s"
|
||||||
|
:class (stl/css :option-icon)
|
||||||
|
:aria-hidden (when label true)
|
||||||
|
:aria-label (when (not label) aria-label)}])
|
||||||
|
|
||||||
|
[:span {:class (stl/css :option-text)} label]
|
||||||
|
(when selected
|
||||||
|
[:> icon*
|
||||||
|
{:id i/tick
|
||||||
|
:size "s"
|
||||||
|
:class (stl/css :option-check)
|
||||||
|
:aria-hidden (when label true)}])])
|
||||||
|
|
||||||
|
(mf/defc options-dropdown*
|
||||||
|
{::mf/props :obj
|
||||||
|
::mf/private true}
|
||||||
|
[{:keys [set-ref on-click options selected focused] :rest props}]
|
||||||
|
(let [props (mf/spread-props props
|
||||||
|
{:class (stl/css :option-list)
|
||||||
|
:tab-index "-1"
|
||||||
|
:role "listbox"})]
|
||||||
|
[:> "ul" props
|
||||||
|
(for [option ^js options]
|
||||||
|
(let [id (obj/get option "id")
|
||||||
|
label (obj/get option "label")
|
||||||
|
aria-label (obj/get option "aria-label")
|
||||||
|
icon (obj/get option "icon")]
|
||||||
|
[:> option* {:selected (= id selected)
|
||||||
|
:key id
|
||||||
|
:id id
|
||||||
|
:label label
|
||||||
|
:icon icon
|
||||||
|
:aria-label aria-label
|
||||||
|
:set-ref set-ref
|
||||||
|
:focused (= id focused)
|
||||||
|
:on-click on-click}]))]))
|
||||||
|
|
||||||
|
(def ^:private schema:select-option
|
||||||
|
[:and
|
||||||
|
[:map {:title "option"}
|
||||||
|
[:id :string]
|
||||||
|
[:icon {:optional true}
|
||||||
|
[:and :string [:fn #(contains? icon-list %)]]]
|
||||||
|
[:label {:optional true} :string]
|
||||||
|
[:aria-label {:optional true} :string]]
|
||||||
|
[:fn {:error/message "invalid data: missing required props"}
|
||||||
|
(fn [option]
|
||||||
|
(or (and (contains? option :icon)
|
||||||
|
(or (contains? option :label)
|
||||||
|
(contains? option :aria-label)))
|
||||||
|
(contains? option :label)))]])
|
||||||
|
|
||||||
|
(def ^:private schema:select
|
||||||
|
[:map
|
||||||
|
[:disabled {:optional true} :boolean]
|
||||||
|
[:class {:optional true} :string]
|
||||||
|
[:icon {:optional true}
|
||||||
|
[:and :string [:fn #(contains? icon-list %)]]]
|
||||||
|
[:default-selected {:optional true} :string]
|
||||||
|
[:options [:vector {:min 1} schema:select-option]]])
|
||||||
|
|
||||||
|
(defn- get-option
|
||||||
|
[options id]
|
||||||
|
(or (array/find #(= id (obj/get % "id")) options)
|
||||||
|
(aget options 0)))
|
||||||
|
|
||||||
|
(defn- get-selected-option-id
|
||||||
|
[options default]
|
||||||
|
(let [option (get-option options default)]
|
||||||
|
(obj/get option "id")))
|
||||||
|
|
||||||
|
(defn- handle-focus-change
|
||||||
|
[options focused* new-index options-nodes-refs]
|
||||||
|
(let [option (aget options new-index)
|
||||||
|
id (obj/get option "id")
|
||||||
|
nodes (mf/ref-val options-nodes-refs)
|
||||||
|
node (obj/get nodes id)]
|
||||||
|
(reset! focused* id)
|
||||||
|
(dom/scroll-into-view-if-needed! node)))
|
||||||
|
|
||||||
|
(defn- handle-selection
|
||||||
|
[focused* selected* open*]
|
||||||
|
(when-let [focused (deref focused*)]
|
||||||
|
(reset! selected* focused))
|
||||||
|
(reset! open* false)
|
||||||
|
(reset! focused* nil))
|
||||||
|
|
||||||
|
(mf/defc select*
|
||||||
|
{::mf/props :obj
|
||||||
|
::mf/schema schema:select}
|
||||||
|
[{:keys [disabled default-selected on-change options class] :rest props}]
|
||||||
|
(let [open* (mf/use-state false)
|
||||||
|
open (deref open*)
|
||||||
|
on-click
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps disabled)
|
||||||
|
(fn [event]
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(when-not disabled
|
||||||
|
(swap! open* not))))
|
||||||
|
|
||||||
|
selected* (mf/use-state #(get-selected-option-id options default-selected))
|
||||||
|
selected (deref selected*)
|
||||||
|
|
||||||
|
focused* (mf/use-state nil)
|
||||||
|
focused (deref focused*)
|
||||||
|
|
||||||
|
on-option-click
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps on-change)
|
||||||
|
(fn [event]
|
||||||
|
(let [node (dom/get-current-target event)
|
||||||
|
id (dom/get-data node "id")]
|
||||||
|
(reset! selected* id)
|
||||||
|
(reset! focused* nil)
|
||||||
|
(reset! open* false)
|
||||||
|
(when (fn? on-change)
|
||||||
|
(on-change id)))))
|
||||||
|
|
||||||
|
options-nodes-refs (mf/use-ref nil)
|
||||||
|
options-ref (mf/use-ref nil)
|
||||||
|
|
||||||
|
set-ref
|
||||||
|
(mf/use-fn
|
||||||
|
(fn [node id]
|
||||||
|
(let [refs (or (mf/ref-val options-nodes-refs) #js {})
|
||||||
|
refs (if node
|
||||||
|
(obj/set! refs id node)
|
||||||
|
(obj/unset! refs id))]
|
||||||
|
(mf/set-ref-val! options-nodes-refs refs))))
|
||||||
|
|
||||||
|
on-blur
|
||||||
|
(mf/use-fn
|
||||||
|
(fn [event]
|
||||||
|
(let [click-outside (nil? (.-relatedTarget event))]
|
||||||
|
(when click-outside
|
||||||
|
(reset! focused* nil)
|
||||||
|
(reset! open* false)))))
|
||||||
|
|
||||||
|
on-key-down
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps focused disabled)
|
||||||
|
(fn [event]
|
||||||
|
(when-not disabled
|
||||||
|
(let [options (mf/ref-val options-ref)
|
||||||
|
len (alength options)
|
||||||
|
index (array/find-index #(= (deref focused*) (obj/get % "id")) options)]
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(cond
|
||||||
|
(kbd/home? event)
|
||||||
|
(handle-focus-change options focused* 0 options-nodes-refs)
|
||||||
|
|
||||||
|
(kbd/up-arrow? event)
|
||||||
|
(handle-focus-change options focused* (mod (- index 1) len) options-nodes-refs)
|
||||||
|
|
||||||
|
(kbd/down-arrow? event)
|
||||||
|
(handle-focus-change options focused* (mod (+ index 1) len) options-nodes-refs)
|
||||||
|
|
||||||
|
(or (kbd/space? event) (kbd/enter? event))
|
||||||
|
(when (deref open*)
|
||||||
|
(dom/prevent-default event)
|
||||||
|
(handle-selection focused* selected* open*))
|
||||||
|
|
||||||
|
(kbd/esc? event)
|
||||||
|
(do (reset! open* false)
|
||||||
|
(reset! focused* nil)))))))
|
||||||
|
|
||||||
|
class (dm/str class " " (stl/css :select))
|
||||||
|
|
||||||
|
props (mf/spread-props props {:class class
|
||||||
|
:role "combobox"
|
||||||
|
:aria-controls "listbox"
|
||||||
|
:aria-haspopup "listbox"
|
||||||
|
:aria-activedescendant focused
|
||||||
|
:aria-expanded open
|
||||||
|
:on-key-down on-key-down
|
||||||
|
:disabled disabled
|
||||||
|
:on-click on-click
|
||||||
|
:on-blur on-blur})
|
||||||
|
|
||||||
|
selected-option (get-option options selected)
|
||||||
|
label (obj/get selected-option "label")
|
||||||
|
icon (obj/get selected-option "icon")]
|
||||||
|
|
||||||
|
(mf/with-effect [options]
|
||||||
|
(mf/set-ref-val! options-ref options))
|
||||||
|
|
||||||
|
[:div {:class (stl/css :select-wrapper)}
|
||||||
|
[:> :button props
|
||||||
|
[:span {:class (stl/css-case :select-header true
|
||||||
|
:header-icon (some? icon))}
|
||||||
|
(when icon
|
||||||
|
[:> icon* {:id icon
|
||||||
|
:size "s"
|
||||||
|
:aria-hidden true}])
|
||||||
|
[:span {:class (stl/css :header-label)}
|
||||||
|
label]]
|
||||||
|
[:> icon* {:id i/arrow
|
||||||
|
:class (stl/css :arrow)
|
||||||
|
:size "s"
|
||||||
|
:aria-hidden true}]]
|
||||||
|
(when open
|
||||||
|
[:> options-dropdown* {:on-click on-option-click
|
||||||
|
:options options
|
||||||
|
:selected selected
|
||||||
|
:focused focused
|
||||||
|
:set-ref set-ref}])]))
|
63
frontend/src/app/main/ui/ds/controls/select.mdx
Normal file
63
frontend/src/app/main/ui/ds/controls/select.mdx
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import { Canvas, Meta } from '@storybook/blocks';
|
||||||
|
import * as SelectStories from "./select.stories";
|
||||||
|
|
||||||
|
<Meta title="Controls/Select" />
|
||||||
|
|
||||||
|
# Select
|
||||||
|
|
||||||
|
Select lets users choose one option from an options menu.
|
||||||
|
|
||||||
|
## Variants
|
||||||
|
|
||||||
|
**Text**: We will use this variant when there are enough space and icons don't add any useful context.
|
||||||
|
|
||||||
|
<Canvas of={SelectStories.Default} />
|
||||||
|
|
||||||
|
**Icon and text**: We will use this variant when there are enough space and icons add any useful context.
|
||||||
|
<Canvas of={SelectStories.WithIcons} />
|
||||||
|
|
||||||
|
## Technical notes
|
||||||
|
|
||||||
|
### Icons
|
||||||
|
|
||||||
|
Each option of `select*` may accept an `icon`, 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
|
||||||
|
[:> select*
|
||||||
|
{:options [{ :label "Code"
|
||||||
|
:id "option-code"
|
||||||
|
:icon i/fill-content }
|
||||||
|
{ :label "Design"
|
||||||
|
:id "option-design"
|
||||||
|
:icon i/pentool }
|
||||||
|
{ :label "Menu"
|
||||||
|
:id "option-menu" }
|
||||||
|
]}]
|
||||||
|
```
|
||||||
|
|
||||||
|
<Canvas of={SelectStories.WithIcons} />
|
||||||
|
|
||||||
|
## Usage guidelines (design)
|
||||||
|
|
||||||
|
### Where to use
|
||||||
|
|
||||||
|
Used in a wide range of applications in the app,
|
||||||
|
to select among available text-based options,
|
||||||
|
sometimes with icons that offers additional context.
|
||||||
|
|
||||||
|
### When to use
|
||||||
|
|
||||||
|
Consider using select when you have 5 or more options to choose from.
|
||||||
|
|
||||||
|
### Interaction / Behavior
|
||||||
|
|
||||||
|
When the user clicks on the clickable area, a list of
|
||||||
|
options appears. When an option is chosen, the list is closed.
|
147
frontend/src/app/main/ui/ds/controls/select.scss
Normal file
147
frontend/src/app/main/ui/ds/controls/select.scss
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
// 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 "../_sizes.scss" as *;
|
||||||
|
@use "../typography.scss" as *;
|
||||||
|
|
||||||
|
.select-wrapper {
|
||||||
|
--select-icon-fg-color: var(--color-foreground-secondary);
|
||||||
|
--select-fg-color: var(--color-foreground-primary);
|
||||||
|
--select-bg-color: var(--color-background-tertiary);
|
||||||
|
--select-outline-color: none;
|
||||||
|
--select-border-color: none;
|
||||||
|
--select-dropdown-border-color: var(--color-background-quaternary);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
--select-bg-color: var(--color-background-quaternary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include use-typography("body-small");
|
||||||
|
position: relative;
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto;
|
||||||
|
gap: var(--sp-xxs);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select {
|
||||||
|
&:focus-visible {
|
||||||
|
--select-outline-color: var(--color-accent-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
--select-bg-color: var(--color-background-primary);
|
||||||
|
--select-border-color: var(--color-background-quaternary);
|
||||||
|
--select-fg-color: var(--color-foreground-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
gap: var(--sp-xs);
|
||||||
|
height: $sz-32;
|
||||||
|
width: 100%;
|
||||||
|
padding: var(--sp-s);
|
||||||
|
border: none;
|
||||||
|
border-radius: $br-8;
|
||||||
|
outline: $b-1 solid var(--select-outline-color);
|
||||||
|
border: $b-1 solid var(--select-border-color);
|
||||||
|
background: var(--select-bg-color);
|
||||||
|
color: var(--select-fg-color);
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
color: var(--select-icon-fg-color);
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-header {
|
||||||
|
display: grid;
|
||||||
|
justify-items: start;
|
||||||
|
gap: var(--sp-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-label {
|
||||||
|
@include use-typography("body-small");
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
padding-inline-start: var(--sp-xxs);
|
||||||
|
text-align: left;
|
||||||
|
color: var(--select-fg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-icon {
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
color: var(--select-icon-fg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-list {
|
||||||
|
--options-dropdown-bg-color: var(--color-background-tertiary);
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: $sz-36;
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--options-dropdown-bg-color);
|
||||||
|
border-radius: $br-8;
|
||||||
|
border: $b-1 solid var(--select-dropdown-border-color);
|
||||||
|
padding-block: var(--sp-xs);
|
||||||
|
margin-block-end: 0;
|
||||||
|
max-height: $sz-400;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option {
|
||||||
|
--select-option-fg-color: var(--color-foreground-primary);
|
||||||
|
--select-option-bg-color: unset;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
--select-option-bg-color: var(--color-background-quaternary);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[aria-selected="true"] {
|
||||||
|
--select-option-bg-color: var(--color-background-quaternary);
|
||||||
|
}
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
justify-items: start;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
gap: var(--sp-xs);
|
||||||
|
width: 100%;
|
||||||
|
height: $sz-32;
|
||||||
|
padding: var(--sp-s);
|
||||||
|
border-radius: $br-8;
|
||||||
|
outline: $b-1 solid var(--select-outline-color);
|
||||||
|
outline-offset: -1px;
|
||||||
|
background-color: var(--select-option-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-with-icon {
|
||||||
|
grid-template-columns: auto 1fr auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-text {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
padding-inline-start: var(--sp-xxs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-icon {
|
||||||
|
color: var(--select-icon-fg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-current {
|
||||||
|
--select-option-outline-color: var(--color-accent-primary);
|
||||||
|
outline: $b-1 solid var(--select-option-outline-color);
|
||||||
|
}
|
65
frontend/src/app/main/ui/ds/controls/select.stories.jsx
Normal file
65
frontend/src/app/main/ui/ds/controls/select.stories.jsx
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
// 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 { Select } = Components;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "Controls/Select",
|
||||||
|
component: Select,
|
||||||
|
argTypes: {
|
||||||
|
disabled: { control: "boolean" },
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
disabled: false,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "Code",
|
||||||
|
id: "option-code",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Design",
|
||||||
|
id: "option-design",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Menu",
|
||||||
|
id: "opeion-menu",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
defaultSelected: "option-code",
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
controls: {
|
||||||
|
exclude: ["options", "defaultSelected"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
render: ({ ...args }) => <Select {...args} />,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Default = {};
|
||||||
|
|
||||||
|
export const WithIcons = {
|
||||||
|
args: {
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "Code",
|
||||||
|
id: "option-code",
|
||||||
|
icon: "fill-content",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Design",
|
||||||
|
id: "option-design",
|
||||||
|
icon: "pentool",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Menu",
|
||||||
|
id: "option-menu",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
Loading…
Add table
Reference in a new issue