🎉 Some fixes

This commit is contained in:
Eva Marco 2025-09-30 10:40:59 +02:00 committed by elhombretecla
parent 1d6389a3eb
commit cad9d03ca1
4 changed files with 80 additions and 64 deletions

View 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*)

View File

@ -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*)

View File

@ -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} />

View File

@ -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" />
),
};