diff --git a/DesignToolbox/DesignToolbox.xcworkspace/xcuserdata/xhrs0459.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/DesignToolbox/DesignToolbox.xcworkspace/xcuserdata/xhrs0459.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
index 48d5dd34f..42f14aa71 100644
--- a/DesignToolbox/DesignToolbox.xcworkspace/xcuserdata/xhrs0459.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
+++ b/DesignToolbox/DesignToolbox.xcworkspace/xcuserdata/xhrs0459.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -3,4 +3,22 @@
uuid = "B4A15A02-0B7C-4A17-81BE-9CA389B02C0B"
type = "0"
version = "2.0">
+
+
+
+
+
+
diff --git a/DesignToolbox/DesignToolbox/Pages/Components/Checkbox/CheckboxConfiguration.swift b/DesignToolbox/DesignToolbox/Pages/Components/Checkbox/CheckboxConfiguration.swift
index 5d329c995..25cef881e 100644
--- a/DesignToolbox/DesignToolbox/Pages/Components/Checkbox/CheckboxConfiguration.swift
+++ b/DesignToolbox/DesignToolbox/Pages/Components/Checkbox/CheckboxConfiguration.swift
@@ -21,7 +21,7 @@ final class CheckboxConfigurationModel: ComponentConfiguration {
// MARK: - Properties
- @Published var isEnabled: Bool {
+ @Published var status: DesignToolboxCheckboxStatus {
didSet { updateCode() }
}
@@ -55,7 +55,27 @@ final class CheckboxConfigurationModel: ComponentConfiguration {
// MARK: - Internal types
- enum DesignToolboxCheckboxLayout: CaseIterable, CustomStringConvertible { // OUDSCheckbox.Layouy is not accessible
+ enum DesignToolboxCheckboxStatus: CaseIterable, CustomStringConvertible { // CheckboxInternalState is not accessible
+ case enabled
+ case disabled
+ case readOnly
+
+ // No l10n, tehchnical names
+ var description: String {
+ switch self {
+ case .enabled:
+ "Enabled"
+ case .disabled:
+ "Disabled"
+ case .readOnly:
+ "Read only"
+ }
+ }
+
+ var id: String { description }
+ }
+
+ enum DesignToolboxCheckboxLayout: CaseIterable, CustomStringConvertible { // OUDSCheckbox.Layout is not accessible
case selectorOnly
case `default`
case inverse
@@ -78,7 +98,7 @@ final class CheckboxConfigurationModel: ComponentConfiguration {
// MARK: - Initializer
override init() {
- isEnabled = true
+ status = .enabled
selectorState = .selected
layout = .selectorOnly
helperText = true
@@ -110,7 +130,7 @@ final class CheckboxConfigurationModel: ComponentConfiguration {
}
private var disableCode: String {
- ".disable(\(isEnabled ? "false" : "true"))"
+ ".disable(\(status != .enabled ? "false" : "true"))"
}
private var helperTextPatern: String {
@@ -134,7 +154,7 @@ final class CheckboxConfigurationModel: ComponentConfiguration {
}
private var isErrorPattern: String {
- if isError && isEnabled {
+ if isError && status == .enabled {
return ", isError: true"
} else {
return ""
@@ -157,9 +177,11 @@ struct CheckboxConfiguration: View {
var body: some View {
VStack(alignment: .leading, spacing: theme.spaces.spaceFixedMedium) {
- Toggle("app_common_enabled_label", isOn: $model.isEnabled)
- .typeHeadingMedium(theme)
- .foregroundStyle(theme.colors.colorContentDefault.color(for: colorScheme))
+ DesignToolboxChoicePicker(title: "app_common_enabled_label", selection: $model.status) {
+ ForEach(CheckboxConfigurationModel.DesignToolboxCheckboxStatus.allCases, id: \.id) { state in
+ Text(LocalizedStringKey(state.description)).tag(state)
+ }
+ }
DesignToolboxChoicePicker(title: "app_components_checkbox_selection_label", selection: $model.selectorState) {
ForEach(OUDSCheckbox.SelectorState.allCases, id: \.id) { state in
@@ -191,7 +213,7 @@ struct CheckboxConfiguration: View {
Toggle("app_components_common_onError_label", isOn: $model.isError)
.typeHeadingMedium(theme)
.foregroundStyle(theme.colors.colorContentDefault.color(for: colorScheme))
- .disabled(!model.isEnabled)
+ .disabled(model.status != .enabled)
DisclosureGroup("Edit texts") {
DesignToolboxTextField(text: $model.labelContent,
diff --git a/DesignToolbox/DesignToolbox/Pages/Components/Checkbox/CheckboxPage.swift b/DesignToolbox/DesignToolbox/Pages/Components/Checkbox/CheckboxPage.swift
index ab9f4b090..eadaec2f5 100644
--- a/DesignToolbox/DesignToolbox/Pages/Components/Checkbox/CheckboxPage.swift
+++ b/DesignToolbox/DesignToolbox/Pages/Components/Checkbox/CheckboxPage.swift
@@ -77,8 +77,10 @@ private struct CheckboxDemo: View {
if model.layout == .selectorOnly {
HStack(alignment: .center) {
Spacer()
- OUDSCheckbox(state: $model.selectorState)
- .disabled(!model.isEnabled)
+ OUDSCheckbox(state: $model.selectorState,
+ isError: model.isError && model.status == CheckboxConfigurationModel.DesignToolboxCheckboxStatus.enabled,
+ isReadOnly: model.status == CheckboxConfigurationModel.DesignToolboxCheckboxStatus.readOnly)
+ .disabled(isDisabled())
Spacer()
}
} else {
@@ -87,9 +89,10 @@ private struct CheckboxDemo: View {
helperText: helperTextContent,
icon: icon,
isInversed: model.layout == CheckboxConfigurationModel.DesignToolboxCheckboxLayout.inverse,
- isError: model.isError && model.isEnabled,
+ isError: model.isError && model.status == CheckboxConfigurationModel.DesignToolboxCheckboxStatus.enabled,
+ isReadOnly: model.status == CheckboxConfigurationModel.DesignToolboxCheckboxStatus.readOnly,
divider: model.divider)
- .disabled(!model.isEnabled)
+ .disabled(isDisabled())
}
}
.padding(.all, theme.spaces.spaceFixedMedium)
@@ -103,4 +106,8 @@ private struct CheckboxDemo: View {
private var icon: Image? {
model.icon ? Image(decorative: "ic_heart") : nil
}
+
+ private func isDisabled() -> Bool {
+ model.status == CheckboxConfigurationModel.DesignToolboxCheckboxStatus.disabled
+ }
}
diff --git a/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxLabel.swift b/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxLabel.swift
index 0e3cb9009..ebb5c1862 100644
--- a/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxLabel.swift
+++ b/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxLabel.swift
@@ -93,7 +93,7 @@ struct OUDSCheckboxLabel: View {
private var labelColor: Color {
switch internalState {
- case .enabled, .pressed, .hover:
+ case .enabled, .pressed, .hover, .readOnly:
(items.isError ? theme.colors.colorContentStatusNegative : theme.colors.colorContentDefault)
.color(for: colorScheme)
case .disabled:
@@ -103,7 +103,7 @@ struct OUDSCheckboxLabel: View {
private var iconColor: Color {
switch internalState {
- case .enabled, .pressed, .hover:
+ case .enabled, .pressed, .hover, .readOnly:
theme.colors.colorContentDefault.color(for: colorScheme)
case .disabled:
theme.colors.colorContentDisabled.color(for: colorScheme)
@@ -112,7 +112,7 @@ struct OUDSCheckboxLabel: View {
private var helperTextColor: Color {
switch internalState {
- case .enabled, .pressed, .hover:
+ case .enabled, .pressed, .hover, .readOnly:
theme.colors.colorContentMuted.color(for: colorScheme)
case .disabled:
theme.colors.colorContentDisabled.color(for: colorScheme)
diff --git a/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxLabeledStyle.swift b/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxLabeledStyle.swift
index 3690d9e2c..ae6afdd15 100644
--- a/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxLabeledStyle.swift
+++ b/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxLabeledStyle.swift
@@ -23,6 +23,7 @@ struct OUDSCheckboxLabeledStyle: ButtonStyle {
let selectorState: OUDSCheckbox.SelectorState
let items: OUDSCheckboxLabel.Items
let isInversed: Bool
+ let isReadOnly: Bool
@State private var isHover: Bool = false
@Environment(\.isEnabled) private var isEnabled
@@ -72,12 +73,16 @@ struct OUDSCheckboxLabeledStyle: ButtonStyle {
theme.select.selectColorBgHover.color(for: colorScheme)
case .pressed:
theme.select.selectColorBgPressed.color(for: colorScheme)
- case .disabled:
+ case .disabled, .readOnly:
theme.select.selectColorBgDisabled.color(for: colorScheme)
}
}
private func internalState(isPressed: Bool) -> OUDSInternalCheckboxState {
+ if isReadOnly {
+ return .readOnly
+ }
+
if !isEnabled {
return .disabled
}
diff --git a/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxNestedStyle.swift b/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxNestedStyle.swift
index 0934abdf3..cc01c699e 100644
--- a/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxNestedStyle.swift
+++ b/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxNestedStyle.swift
@@ -22,6 +22,7 @@ struct OUDSCheckboxNestedStyle: ButtonStyle {
let selectorState: OUDSCheckbox.SelectorState
let isError: Bool
+ let isReadOnly: Bool
@State private var isHover: Bool = false
@Environment(\.isEnabled) private var isEnabled
@@ -38,6 +39,10 @@ struct OUDSCheckboxNestedStyle: ButtonStyle {
// MARK: - Helpers
private func internalState(isPressed: Bool) -> OUDSInternalCheckboxState {
+ if isReadOnly {
+ return .readOnly
+ }
+
if !isEnabled {
return .disabled
}
diff --git a/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxSelectorButtonStyle.swift b/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxSelectorButtonStyle.swift
index 23e241d13..e8f0b8fa5 100644
--- a/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxSelectorButtonStyle.swift
+++ b/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSCheckboxSelectorButtonStyle.swift
@@ -69,7 +69,7 @@ private struct CheckboxSelectorButtonForegroundModifier: ViewModifier {
return hoverColor.color(for: colorScheme)
case .pressed:
return pressedColor.color(for: colorScheme)
- case .disabled:
+ case .disabled, .readOnly:
return disabledColor.color(for: colorScheme)
}
}
@@ -134,7 +134,7 @@ private struct CheckboxSelectorButtonBackgroundModifier: ViewModifier {
return hoverColor
case .pressed:
return pressedColor
- case .disabled:
+ case .disabled, .readOnly:
return disabledColor
}
}
@@ -261,7 +261,7 @@ private struct CheckboxSelectorButtonBorderModifier: ViewModifier {
return hoverColor
case .pressed:
return pressedColor
- case .disabled:
+ case .disabled, .readOnly:
return disabledColor
}
}
@@ -313,7 +313,7 @@ private struct CheckboxSelectorButtonBorderModifier: ViewModifier {
return hoverWidth
case .pressed:
return pressedWidth
- case .disabled:
+ case .disabled, .readOnly:
return disabledWidth
}
}
diff --git a/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSInternalCheckboxState.swift b/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSInternalCheckboxState.swift
index d726c6b46..1a76e824a 100644
--- a/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSInternalCheckboxState.swift
+++ b/OUDS/Core/Components/Sources/Checkbox/Internal/OUDSInternalCheckboxState.swift
@@ -23,10 +23,12 @@ enum OUDSInternalCheckboxState {
/// The component is being pressed
case pressed
- /// The user cannot interart with the component. Also "read only" cases.
+ /// The user cannot interart with the component.
case disabled
- // .loading not managed yet, for next version
+ /// The component is not disabled but user cannoit interact with it still. Almost enabled.
+ case readOnly
+
// .focus not managed as not that much customizable
// .skeleton not managed as dedicated view in the end
}
diff --git a/OUDS/Core/Components/Sources/Checkbox/OUDSCheckbox.swift b/OUDS/Core/Components/Sources/Checkbox/OUDSCheckbox.swift
index 786db9438..0b4f4e1ca 100644
--- a/OUDS/Core/Components/Sources/Checkbox/OUDSCheckbox.swift
+++ b/OUDS/Core/Components/Sources/Checkbox/OUDSCheckbox.swift
@@ -45,10 +45,14 @@ import SwiftUI
/// // The nested layout will be used here.
/// OUDSCheckbox(state: $state)
///
-/// // A leading checkbox with a label
+/// // A leading checkbox with a label.
/// // The default layout will be used here.
/// OUDSCheckbox(state: $state, label: "Hello world")
///
+/// // A leading checkbox with a label, but in read only mode (user cannot interact yet, but not disabled).
+/// // The default layout will be used here.
+/// OUDSCheckbox(state: $state, label: "Hello world", isReadOnly: true)
+///
/// // A leading checkbox with a label, and an helper text.
/// // The default layout will be used here.
/// OUDSCheckbox(state: $state, label: "Bazinga!", helperText: "Doll-Dagga Buzz-Buzz Ziggety-Zag")
@@ -111,16 +115,18 @@ public struct OUDSCheckbox: View {
/// The three available layouts for this component
private enum Layout {
- /// Displays only the checkbox selector, wiht a flag saying if there is an error context
- case selectorOnly(Bool)
+ /// Displays only the checkbox selector, with a first flag saying if there is an error context and a second is in read only mode
+ case selectorOnly(Bool, Bool)
/// Checkbox selector in leading position, icon in trailing position, like LTR mode.
/// Details are defined in the ``OUDSCheckboxLabel.Items``.
- case `default`(OUDSCheckboxLabel.Items)
+ /// Contains a flag saying if read only mode or not.
+ case `default`(OUDSCheckboxLabel.Items, Bool)
/// Icon in leading position, checkbox selector in trailing position, like RTL mode
/// Details are defined in the ``OUDSCheckboxLabel.Items``.
- case inverse(OUDSCheckboxLabel.Items)
+ /// Contains a flag saying if read only mode or not.
+ case inverse(OUDSCheckboxLabel.Items, Bool)
}
// MARK: - Initializers
@@ -130,9 +136,12 @@ public struct OUDSCheckbox: View {
/// - Parameters:
/// - state: A binding to a property that determines wether the selector is ticked, unticked or preticked.
/// - isError: True if the look and feel of the component must reflect an error state, default set to `false`
- public init(state: Binding, isError: Bool = false) {
+ /// - isReadOnly: True if component is in read only, i.e. not really disabled but user cannot interact with it yet, default set to `false`
+ public init(state: Binding,
+ isError: Bool = false,
+ isReadOnly: Bool = false) {
self._state = state
- self.layout = .selectorOnly(isError)
+ self.layout = .selectorOnly(isError, isReadOnly)
}
/// Creates a checkbox with label and optional helper text, icon, divider.
@@ -144,6 +153,7 @@ public struct OUDSCheckbox: View {
/// - icon: An optional icon
/// - isInversed: `True` of the checkbox selector must be in trailing position,` false` otherwise. Default to `false`
/// - isError: `True` if the look and feel of the component must reflect an error state, default set to `false`
+ /// - isReadOnly: True if component is in read only, i.e. not really disabled but user cannot interact with it yet, default set to `false`
/// - divider: If `true` a divider is added at the bottom of the view.
public init(state: Binding,
label: String,
@@ -151,12 +161,23 @@ public struct OUDSCheckbox: View {
icon: Image? = nil,
isInversed: Bool = false,
isError: Bool = false,
+ isReadOnly: Bool = false,
divider: Bool = false) {
self._state = state
if isInversed {
- self.layout = .inverse(.init(label: label, helperText: helperText, icon: icon, isError: isError, divider: divider))
+ self.layout = .inverse(.init(label: label,
+ helperText: helperText,
+ icon: icon,
+ isError: isError,
+ divider: divider),
+ isReadOnly)
} else {
- self.layout = .default(.init(label: label, helperText: helperText, icon: icon, isError: isError, divider: divider))
+ self.layout = .default(.init(label: label,
+ helperText: helperText,
+ icon: icon,
+ isError: isError,
+ divider: divider),
+ isReadOnly)
}
}
@@ -164,21 +185,27 @@ public struct OUDSCheckbox: View {
public var body: some View {
switch layout {
- case .default(let label):
+ case let .default(label, isReadOnly):
Button("") {
- $state.wrappedValue.toggle()
+ if !isReadOnly {
+ $state.wrappedValue.toggle()
+ }
}
- .buttonStyle(OUDSCheckboxLabeledStyle(selectorState: $state.wrappedValue, items: label, isInversed: false))
- case .inverse(let label):
+ .buttonStyle(OUDSCheckboxLabeledStyle(selectorState: $state.wrappedValue, items: label, isInversed: false, isReadOnly: isReadOnly))
+ case let .inverse(label, isReadOnly):
Button("") {
- $state.wrappedValue.toggle()
+ if !isReadOnly {
+ $state.wrappedValue.toggle()
+ }
}
- .buttonStyle(OUDSCheckboxLabeledStyle(selectorState: $state.wrappedValue, items: label, isInversed: true))
- case .selectorOnly(let isError):
+ .buttonStyle(OUDSCheckboxLabeledStyle(selectorState: $state.wrappedValue, items: label, isInversed: true, isReadOnly: isReadOnly))
+ case let .selectorOnly(isError, isReadOnly):
Button("") {
- $state.wrappedValue.toggle()
+ if !isReadOnly {
+ $state.wrappedValue.toggle()
+ }
}
- .buttonStyle(OUDSCheckboxNestedStyle(selectorState: $state.wrappedValue, isError: isError))
+ .buttonStyle(OUDSCheckboxNestedStyle(selectorState: $state.wrappedValue, isError: isError, isReadOnly: isReadOnly))
}
}
}