mirror of
https://github.com/penpot/penpot.git
synced 2026-05-17 14:03:42 +00:00
🎉 Some fixes
This commit is contained in:
parent
1d6389a3eb
commit
cad9d03ca1
14
frontend/src/app/main/ui/ds/controls/switcher.cljs
Normal file
14
frontend/src/app/main/ui/ds/controls/switcher.cljs
Normal file
@ -0,0 +1,14 @@
|
||||
;; 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.switcher
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.ui.ds.controls.switcher.switcher :as impl]))
|
||||
|
||||
(dm/export impl/switcher*)
|
||||
|
||||
|
||||
@ -8,7 +8,9 @@
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
@ -22,85 +24,88 @@
|
||||
[:disabled {:optional true} :boolean]
|
||||
[:size {:optional true} [:enum "sm" "md" "lg"]]
|
||||
[:aria-label {:optional true} [:maybe :string]]
|
||||
[:class {:optional true} :string]
|
||||
[:data-testid {:optional true} :string]])
|
||||
[:class {:optional true} :string]])
|
||||
|
||||
(mf/defc switcher*
|
||||
{::mf/forward-ref true
|
||||
::mf/schema schema:switcher}
|
||||
[{:keys [id label checked default-checked on-change disabled size aria-label class] :rest props} ref]
|
||||
(let [id (or id (mf/use-id))
|
||||
size (keyword (d/nilv size "md"))
|
||||
size (d/nilv size "md")
|
||||
disabled (d/nilv disabled false)
|
||||
|
||||
|
||||
;; TODO: review which one is better
|
||||
;; Internal state for uncontrolled mode
|
||||
internal-checked* (mf/use-state (d/nilv default-checked false))
|
||||
internal-checked (deref internal-checked*)
|
||||
|
||||
|
||||
;; Determine if controlled or uncontrolled
|
||||
controlled? (some? checked)
|
||||
current-checked (if controlled? checked internal-checked)
|
||||
|
||||
|
||||
;; Toggle handler
|
||||
handle-toggle (mf/use-fn
|
||||
(mf/deps controlled? current-checked on-change internal-checked*)
|
||||
(fn [event]
|
||||
(when-not disabled
|
||||
(let [new-checked (not current-checked)]
|
||||
(when-not controlled?
|
||||
(reset! internal-checked* new-checked))
|
||||
(when on-change
|
||||
(on-change new-checked event))))))
|
||||
|
||||
handle-toggle
|
||||
(mf/use-fn
|
||||
(mf/deps controlled? current-checked on-change internal-checked* disabled)
|
||||
(fn [event]
|
||||
(when-not disabled
|
||||
(let [new-checked (not current-checked)]
|
||||
(when-not controlled?
|
||||
(reset! internal-checked* new-checked))
|
||||
(when on-change
|
||||
(on-change new-checked event))))))
|
||||
|
||||
;; Keyboard events
|
||||
handle-keydown (mf/use-fn
|
||||
(mf/deps handle-toggle)
|
||||
(fn [event]
|
||||
(when (or (= (.-key event) " ") (= (.-key event) "Enter"))
|
||||
(.preventDefault event)
|
||||
(handle-toggle event))))
|
||||
|
||||
handle-keydown
|
||||
(mf/use-fn
|
||||
(mf/deps handle-toggle)
|
||||
(fn [event]
|
||||
(when (or (kbd/space? event) (kbd/enter? event))
|
||||
(dom/prevent-default event)
|
||||
(handle-toggle event))))
|
||||
|
||||
;; Label click handler
|
||||
handle-label-click (mf/use-fn
|
||||
(mf/deps handle-toggle)
|
||||
(fn [event]
|
||||
(.preventDefault event)
|
||||
(handle-toggle event)))
|
||||
|
||||
handle-label-click
|
||||
(mf/use-fn
|
||||
(mf/deps handle-toggle)
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(handle-toggle event)))
|
||||
|
||||
has-label (not (str/blank? label))
|
||||
effective-aria-label (if has-label
|
||||
(or aria-label label)
|
||||
"Toggle switch")]
|
||||
|
||||
[:div {:class (dm/str class " " (stl/css-case :switcher-wrapper true))
|
||||
:data-testid (.-data-testid props)}
|
||||
(or aria-label label)
|
||||
;; TODO: Add translation string
|
||||
;; (tr "linea de traduccion")
|
||||
"Toggle switch")
|
||||
|
||||
props (mf/spread-props props {:id id
|
||||
:ref ref
|
||||
:role "switch"
|
||||
:tabIndex (if disabled -1 0)
|
||||
:aria-checked current-checked
|
||||
:aria-disabled disabled
|
||||
:aria-label effective-aria-label
|
||||
:class (stl/css-case :switcher true
|
||||
:is-checked current-checked
|
||||
:is-disabled disabled
|
||||
:switcher--sm (= size "sm")
|
||||
:switcher--md (= size "md")
|
||||
:switcher--lg (= size "lg"))
|
||||
:on-click handle-toggle
|
||||
:on-key-down handle-keydown})]
|
||||
|
||||
[:div {:class [class (stl/css :switcher-wrapper)]}
|
||||
(when has-label
|
||||
[:label {:for id
|
||||
:class (stl/css-case :switcher-label true
|
||||
:is-disabled disabled)
|
||||
:on-click handle-label-click}
|
||||
label])
|
||||
[:div {:id id
|
||||
:ref ref
|
||||
:role "switch"
|
||||
:tabIndex (if disabled -1 0)
|
||||
:aria-checked current-checked
|
||||
:aria-disabled disabled
|
||||
:aria-label effective-aria-label
|
||||
:class (stl/css-case :switcher true
|
||||
:is-checked current-checked
|
||||
:is-disabled disabled
|
||||
:switcher--sm (= size :sm)
|
||||
:switcher--md (= size :md)
|
||||
:switcher--lg (= size :lg))
|
||||
:on-click handle-toggle
|
||||
:on-key-down handle-keydown}
|
||||
[:> :div props
|
||||
[:div {:class (stl/css-case :switcher-track true
|
||||
:is-checked current-checked
|
||||
:is-disabled disabled)}
|
||||
[:div {:class (stl/css-case :switcher-thumb true
|
||||
:is-checked current-checked
|
||||
:is-disabled disabled)}]]]]))
|
||||
|
||||
;; Export as default
|
||||
(def switcher switcher*)
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
Copyright (c) KALEIDOS INC */ }
|
||||
|
||||
import { Canvas, Meta } from '@storybook/blocks';
|
||||
import * as SwitcherStories from "./switcher.stories";
|
||||
import * as Switcher from "./switcher.stories";
|
||||
|
||||
<Meta title="Controls/Switcher" />
|
||||
|
||||
@ -13,7 +13,7 @@ import * as SwitcherStories from "./switcher.stories";
|
||||
|
||||
The `switcher*` component is a toggle control that allows users to switch between two states (on/off). It provides both controlled and uncontrolled modes, making it suitable for various use cases across the interface.
|
||||
|
||||
<Canvas of={SwitcherStories.DefaultUncontrolled} />
|
||||
<Canvas of={Switcher.DefaultUncontrolled} />
|
||||
|
||||
## Anatomy
|
||||
|
||||
@ -59,7 +59,7 @@ The switcher component consists of three main parts:
|
||||
(reset! checked new-checked))}])
|
||||
```
|
||||
|
||||
<Canvas of={SwitcherStories.Controlled} />
|
||||
<Canvas of={Switcher.Controlled} />
|
||||
|
||||
### Different Sizes
|
||||
|
||||
@ -71,8 +71,6 @@ The switcher supports three size variants: `"sm"`, `"md"` (default), and `"lg"`.
|
||||
[:> switcher* {:size "lg" :label "Large"}]
|
||||
```
|
||||
|
||||
<Canvas of={SwitcherStories.Sizes} />
|
||||
|
||||
### Disabled State
|
||||
|
||||
Disabled switchers are non-interactive and visually distinct. You can control the disabled state using the `disabled` prop in the controls panel.
|
||||
@ -92,7 +90,7 @@ When no visible label is provided, use `aria-label` for accessibility.
|
||||
:default-checked false}]
|
||||
```
|
||||
|
||||
<Canvas of={SwitcherStories.WithoutVisibleLabel} />
|
||||
<Canvas of={Switcher.WithoutVisibleLabel} />
|
||||
|
||||
## Design Tokens
|
||||
|
||||
@ -138,4 +136,4 @@ The switcher component uses the following design system tokens:
|
||||
|
||||
## Interactive Example
|
||||
|
||||
<Canvas of={SwitcherStories.Interactive} />
|
||||
<Canvas of={Switcher.Interactive} />
|
||||
|
||||
@ -11,7 +11,7 @@ const { Switcher } = Components;
|
||||
|
||||
export default {
|
||||
title: "Controls/Switcher",
|
||||
component: Components.Switcher,
|
||||
component: Switcher,
|
||||
argTypes: {
|
||||
checked: {
|
||||
control: { type: "boolean" },
|
||||
@ -44,16 +44,15 @@ export default {
|
||||
},
|
||||
},
|
||||
args: {
|
||||
label: "Enable notifications",
|
||||
disabled: false,
|
||||
size: "md",
|
||||
defaultChecked: false,
|
||||
},
|
||||
parameters: {
|
||||
controls: { exclude: ["id", "class", "dataTestid"] },
|
||||
controls: { exclude: ["id", "class", "dataTestid", "on-change"] },
|
||||
},
|
||||
render: ({ onChange, ...args }) => (
|
||||
<Switcher {...args} onChange={onChange} data-testid="switcher" />
|
||||
<Switcher {...args} onChange={onChange} data-testid="switcher" label="Enable notifications" />
|
||||
),
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user