Add composition and slots documentation to storybook

This commit is contained in:
Xavier Julian 2025-05-22 13:01:37 +02:00 committed by Xaviju
parent 556a68a78f
commit 066b252522
6 changed files with 118 additions and 12 deletions

View file

@ -12,6 +12,9 @@
[app.main.ui.ds.controls.combobox :refer [combobox*]]
[app.main.ui.ds.controls.input :refer [input*]]
[app.main.ui.ds.controls.select :refer [select*]]
[app.main.ui.ds.controls.utilities.hint-message :refer [hint-message*]]
[app.main.ui.ds.controls.utilities.input-field :refer [input-field*]]
[app.main.ui.ds.controls.utilities.label :refer [label*]]
[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]]
@ -49,6 +52,9 @@
:Icon icon*
:IconButton icon-button*
:Input input*
:Label label*
:InputField input-field*
:HintMessage hint-message*
:InputWithMeta input-with-meta*
:EmptyPlaceholder empty-placeholder*
:Loader loader*

View file

@ -26,6 +26,31 @@ These are available in the `app.main.ds.foundations.assets.icon` namespace.
[:> input* {:icon i/effects}]
```
## Destructuring the component
The `input*` component is composed of `label*`, `input-field*`, and `hint-message*` components. If you only need some of these components or require them to be broken down, you can build them as a group of components.
```clj
[:> label* {:for id :is-optional true} label]
[:> input-field* {:id id}]
[:> hint-message* {:id id :message message :type "warning}]
```
<Canvas of={InputStories.Composable} />
#### `input-field*` slots
The `input-field*` offers two slots where developers can include external components as properties.
- **slot-start**: adds a component to the beginning of the input
- **slot-end**: adds a component to the end of the input
```clj
[:> input-field* {:id id :slot-start component-one :slot-end component-two}]
```
<Canvas of={InputStories.Slots} />
## Usage guidelines (design)
### Where to use

View file

@ -8,6 +8,10 @@ import * as React from "react";
import Components from "@target/components";
const { Input } = Components;
const { Label } = Components;
const { InputField } = Components;
const { HintMessage } = Components;
const { IconButton } = Components;
const { icons } = Components.meta;
export default {
@ -85,3 +89,77 @@ export const Seamless = {
variant: "seamless",
},
};
export const Composable = {
argTypes: {
label: { control: "text" },
labelArgs: { control: "object" },
inputArgs: { control: "object" },
hintArgs: { control: "object" },
},
args: {
label: "Label",
labelArgs: {
htmlFor: "input",
isOptional: false,
},
inputArgs: {
id: "input",
variant: "comfortable",
type: "text",
placeholder: "Placeholder",
},
hintArgs: {
id: "input",
message: "This is a hint text to help user.",
type: "hint",
},
},
render: ({ ...args }) => {
return (
<>
<Label {...args.labelArgs}>{args.label}</Label>
<InputField {...args.inputArgs} />
<HintMessage {...args.hintArgs} />
</>
);
},
};
export const Slots = {
argTypes: {
label: { control: "text" },
labelArgs: { control: "object" },
inputArgs: { control: "object" },
hintArgs: { control: "object" },
},
args: {
inputArgs: {
id: "input",
variant: "comfortable",
type: "text",
placeholder: "Placeholder",
slotStart: (
<IconButton
icon="search"
variant="ghost"
aria-label="Slot Start component"
/>
),
slotEnd: (
<IconButton
icon="status-tick"
variant="ghost"
aria-label="Slot End component"
/>
),
},
},
render: ({ ...args }) => {
return (
<>
<InputField {...args.inputArgs} />
</>
);
},
};

View file

@ -13,7 +13,6 @@
--input-bg-color: var(--color-background-tertiary);
--input-fg-color: var(--color-foreground-primary);
--input-icon-color: var(--color-foreground-secondary);
--input-text-indent: 0;
--input-outline-color: none;
--input-height: #{$sz-32};
--input-margin: unset;
@ -81,7 +80,6 @@
border: none;
background: none;
inline-size: 100%;
text-indent: var(--input-text-indent, 0);
font-family: inherit;
font-size: inherit;

View file

@ -32,11 +32,10 @@
(let [id (mf/use-id)
input-ref (mf/use-ref)
swatch
(when color
(mf/html [:> input-token-color-bullet*
{:color color
:class (stl/css :slot-start)
:on-click display-colorpicker}]))
(mf/html [:> input-token-color-bullet*
{:color color
:class (stl/css :slot-start)
:on-click display-colorpicker}])
props (mf/spread-props props {:id id
:type "text"

View file

@ -238,7 +238,7 @@
(let [create? (not (instance? ctob/Token token))
token (or token {:type token-type})
token-properties (dwta/get-token-properties token)
color? (cft/color-token? token)
is-color-token (cft/color-token? token)
selected-set-tokens (mf/deref refs/workspace-selected-token-set-tokens)
active-theme-tokens (cond-> (mf/deref refs/workspace-active-theme-sets-tokens)
@ -321,7 +321,7 @@
(valid-name? @token-name-ref))
;; Value
color* (mf/use-state (when color? (:value token)))
color* (mf/use-state (when is-color-token (:value token)))
color (deref color*)
color-ramp-open* (mf/use-state false)
color-ramp-open? (deref color-ramp-open*)
@ -345,7 +345,7 @@
:else
(:resolved-value token-or-err))]
(when color? (reset! color* (if error? nil v)))
(when is-color-token (reset! color* (if error? nil v)))
(reset! token-resolve-result* v))))
on-update-value-debounced (use-debonced-resolve-callback token-name-ref token active-theme-tokens set-resolve-value)
@ -354,7 +354,7 @@
(fn [e]
(let [value (dom/get-target-val e)
;; Automatically add # for hex values
value' (if (and color? (tinycolor/hex-without-hash-prefix? value))
value' (if (and is-color-token (tinycolor/hex-without-hash-prefix? value))
(let [hex (dm/str "#" value)]
(dom/set-value! (mf/ref-val value-input-ref) hex)
hex)
@ -560,7 +560,7 @@
:label (tr "workspace.tokens.token-value")
:default-value (mf/ref-val value-ref)
:ref value-input-ref
:color color
:color (when is-color-token color)
:on-change on-update-value
:error (not (nil? (:errors token-resolve-result)))
:display-colorpicker on-display-colorpicker'