diff --git a/frontend/src/app/main/ui/ds/controls/switcher.cljs b/frontend/src/app/main/ui/ds/controls/switcher.cljs
new file mode 100644
index 0000000000..1efd0b98b2
--- /dev/null
+++ b/frontend/src/app/main/ui/ds/controls/switcher.cljs
@@ -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*)
+
+
diff --git a/frontend/src/app/main/ui/ds/controls/switcher/switcher.cljs b/frontend/src/app/main/ui/ds/controls/switcher/switcher.cljs
index d009b0d422..fe2e0bf304 100644
--- a/frontend/src/app/main/ui/ds/controls/switcher/switcher.cljs
+++ b/frontend/src/app/main/ui/ds/controls/switcher/switcher.cljs
@@ -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*)
diff --git a/frontend/src/app/main/ui/ds/controls/switcher/switcher.mdx b/frontend/src/app/main/ui/ds/controls/switcher/switcher.mdx
index eb86bcd177..2008ab495f 100644
--- a/frontend/src/app/main/ui/ds/controls/switcher/switcher.mdx
+++ b/frontend/src/app/main/ui/ds/controls/switcher/switcher.mdx
@@ -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";
@@ -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.
-
+
## Anatomy
@@ -59,7 +59,7 @@ The switcher component consists of three main parts:
(reset! checked new-checked))}])
```
-
+
### Different Sizes
@@ -71,8 +71,6 @@ The switcher supports three size variants: `"sm"`, `"md"` (default), and `"lg"`.
[:> switcher* {:size "lg" :label "Large"}]
```
-
-
### 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}]
```
-
+
## Design Tokens
@@ -138,4 +136,4 @@ The switcher component uses the following design system tokens:
## Interactive Example
-
+
diff --git a/frontend/src/app/main/ui/ds/controls/switcher/switcher.stories.jsx b/frontend/src/app/main/ui/ds/controls/switcher/switcher.stories.jsx
index 6a7a727cd7..fb494e8b41 100644
--- a/frontend/src/app/main/ui/ds/controls/switcher/switcher.stories.jsx
+++ b/frontend/src/app/main/ui/ds/controls/switcher/switcher.stories.jsx
@@ -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 }) => (
-
+
),
};