Skip to content

Commit

Permalink
feat: default layout (#264)
Browse files Browse the repository at this point in the history
Signed-off-by: Pierre-Yves Lapersonne <[email protected]>
  • Loading branch information
pylapp committed Feb 3, 2025
1 parent 29af810 commit 8805e6b
Show file tree
Hide file tree
Showing 10 changed files with 421 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,78 @@ import SwiftUI

// TODO: #264 - Update page

// swiftlint:disable accessibility_label_for_image
struct CheckboxPage: View {

var body: some View {

// Enabled
OUDSCheckbox(status: .selected, style: .default) { print("@@@ high level tap") }
OUDSCheckbox(status: .unselected, style: .default) { }
OUDSCheckbox(status: .undeterminate, style: .default) { }
OUDSCheckbox(status: .errorSelected, style: .default) { }
OUDSCheckbox(status: .errorUnselected, style: .default) { }
OUDSCheckbox(status: .errorUndeterminate, style: .default) { }

// Disabled
OUDSCheckbox(status: .selected, style: .default) { }.disabled(true)
OUDSCheckbox(status: .unselected, style: .default) { }.disabled(true)
OUDSCheckbox(status: .undeterminate, style: .default) { }.disabled(true)
VStack(spacing: 2) {

// Enabled
OUDSCheckbox(label: "Hello world", icon: Image(systemName: "heart"), status: .selected, style: .default) { }
OUDSCheckbox(label: "Hello world", icon: Image(systemName: "heart"), status: .unselected, style: .default) { }
OUDSCheckbox(label: "Hello world", icon: Image(systemName: "heart"), status: .undeterminate, style: .default) { }
OUDSCheckbox(label: "Hello world", icon: Image(systemName: "heart"), status: .errorSelected, style: .default) { }
OUDSCheckbox(label: "Hello world", icon: Image(systemName: "heart"), status: .errorUnselected, style: .default) { }
OUDSCheckbox(label: "Hello world", icon: Image(systemName: "heart"), status: .errorUndeterminate, style: .default) { }

// Disabled
OUDSCheckbox(label: "Hello world", icon: Image(systemName: "heart"), status: .selected, style: .default) { }.disabled(true)
OUDSCheckbox(label: "Hello world", icon: Image(systemName: "heart"), status: .unselected, style: .default) { }.disabled(true)
OUDSCheckbox(label: "Hello world", icon: Image(systemName: "heart"), status: .undeterminate, style: .default) { }.disabled(true)

// Enabled
OUDSCheckbox(label: "Hello", helper: "World", icon: Image(systemName: "heart"), status: .selected, style: .default) { }
OUDSCheckbox(label: "Hello", helper: "World", icon: Image(systemName: "heart"), status: .unselected, style: .default) { }
OUDSCheckbox(label: "Hello", helper: "World", icon: Image(systemName: "heart"), status: .undeterminate, style: .default) { }
OUDSCheckbox(label: "Hello", helper: "World", icon: Image(systemName: "heart"), status: .errorSelected, style: .default) { }
OUDSCheckbox(label: "Hello", helper: "World", icon: Image(systemName: "heart"), status: .errorUnselected, style: .default) { }
OUDSCheckbox(label: "Hello", helper: "World", icon: Image(systemName: "heart"), status: .errorUndeterminate, style: .default) { }

// Disabled
OUDSCheckbox(label: "Hello", helper: "World", icon: Image(systemName: "heart"), status: .selected, style: .default) { }.disabled(true)
OUDSCheckbox(label: "Hello", helper: "World", icon: Image(systemName: "heart"), status: .unselected, style: .default) { }.disabled(true)
OUDSCheckbox(label: "Hello", helper: "World", icon: Image(systemName: "heart"), status: .undeterminate, style: .default) { }.disabled(true)

// Enabled
OUDSCheckbox(label: "Hello", helper: "World", status: .selected, style: .default) { }
OUDSCheckbox(label: "Hello", helper: "World", status: .unselected, style: .default) { }
OUDSCheckbox(label: "Hello", helper: "World", status: .undeterminate, style: .default) { }
OUDSCheckbox(label: "Hello", helper: "World", status: .errorSelected, style: .default) { }
OUDSCheckbox(label: "Hello", helper: "World", status: .errorUnselected, style: .default) { }
OUDSCheckbox(label: "Hello", helper: "World", status: .errorUndeterminate, style: .default) { }

// Disabled
OUDSCheckbox(label: "Hello", helper: "World", status: .selected, style: .default) { }.disabled(true)
OUDSCheckbox(label: "Hello", helper: "World", status: .unselected, style: .default) { }.disabled(true)
OUDSCheckbox(label: "Hello", helper: "World", status: .undeterminate, style: .default) { }.disabled(true)

// Enabled
OUDSCheckbox(label: "Hello world", status: .selected, style: .default) { }
OUDSCheckbox(label: "Hello world", status: .unselected, style: .default) { }
OUDSCheckbox(label: "Hello world", status: .undeterminate, style: .default) { }
OUDSCheckbox(label: "Hello world", status: .errorSelected, style: .default) { }
OUDSCheckbox(label: "Hello world", status: .errorUnselected, style: .default) { }
OUDSCheckbox(label: "Hello world", status: .errorUndeterminate, style: .default) { }

// Disabled
OUDSCheckbox(label: "Hello world", status: .selected, style: .default) { }.disabled(true)
OUDSCheckbox(label: "Hello world", status: .unselected, style: .default) { }.disabled(true)
OUDSCheckbox(label: "Hello world", status: .undeterminate, style: .default) { }.disabled(true)

// Enabled
OUDSCheckbox(status: .selected, style: .default) { print("@@@ high level tap") }
OUDSCheckbox(status: .unselected, style: .default) { }
OUDSCheckbox(status: .undeterminate, style: .default) { }
OUDSCheckbox(status: .errorSelected, style: .default) { }
OUDSCheckbox(status: .errorUnselected, style: .default) { }
OUDSCheckbox(status: .errorUndeterminate, style: .default) { }

// Disabled
OUDSCheckbox(status: .selected, style: .default) { }.disabled(true)
OUDSCheckbox(status: .unselected, style: .default) { }.disabled(true)
OUDSCheckbox(status: .undeterminate, style: .default) { }.disabled(true)
}
}
}
// swiftlint:enable accessibility_label_for_image
167 changes: 167 additions & 0 deletions OUDS/Core/Components/Sources/Checkbox/Internal/Checkbox.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
//
// Software Name: OUDS iOS
// SPDX-FileCopyrightText: Copyright (c) Orange SA
// SPDX-License-Identifier: MIT
//
// This software is distributed under the MIT license,
// the text of which is available at https://opensource.org/license/MIT/
// or see the "LICENSE" file for more details.
//
// Authors: See CONTRIBUTORS.txt
// Software description: A SwiftUI components library with code examples for Orange Unified Design System
//

import SwiftUI

/// The checkbox component with several layouts
struct Checkbox: View {

// MARK: - Properties

private let selectorOnly: Bool
private let label: String?
private let helper: String?
private let icon: Image?
private let hasDivider: Bool
private let status: OUDSCheckbox.Status
private let action: () -> Void

@Environment(\.theme) private var theme

// MARK: - Initializers

init(status: OUDSCheckbox.Status,
action: @escaping () -> Void) {
selectorOnly = true
label = nil
helper = nil
icon = nil
hasDivider = false
self.status = status
self.action = action
}

init(label: String,
status: OUDSCheckbox.Status,
hasDivider: Bool = false,
action: @escaping () -> Void) {
selectorOnly = false
self.label = label
helper = nil
icon = nil
self.hasDivider = hasDivider
self.status = status
self.action = action
}

init(label: String,
helper: String,
status: OUDSCheckbox.Status,
hasDivider: Bool = false,
action: @escaping () -> Void) {
selectorOnly = false
self.label = label
self.helper = helper
icon = nil
self.hasDivider = hasDivider
self.status = status
self.action = action
}

init(label: String,
icon: Image,
status: OUDSCheckbox.Status,
hasDivider: Bool = false,
action: @escaping () -> Void) {
selectorOnly = false
self.label = label
helper = nil
self.icon = icon
self.hasDivider = hasDivider
self.status = status
self.action = action
}

init(label: String,
helper: String,
icon: Image,
status: OUDSCheckbox.Status,
hasDivider: Bool = false,
action: @escaping () -> Void) {
selectorOnly = false
self.label = label
self.helper = helper
self.icon = icon
self.hasDivider = hasDivider
self.status = status
self.action = action
}

// MARK: - Body

var body: some View {
appliedLayout()
.padding(theme.select.selectSpacePaddingInset)
.frame(minWidth: theme.listItem.listItemSizeMinWidth,
minHeight: theme.listItem.listItemSizeMinHeight)
.accessibilityAddTraits(.isButton)
.onTapGesture {
action()
}
.border(Color.black, width: 1) // NOTE: #264 - Debug
}

// MARK: - Layouts

@ViewBuilder
private func appliedLayout() -> some View {
if selectorOnly {
selectorOnlyLayout()
} else {
defaultLayout()
}
}

private func selectorOnlyLayout() -> some View {
CheckboxSelector(isAlone: true, status: status)
.accessibilityAddTraits(.isButton)
.onTapGesture {
action()
}
.modifier(OUDSCheckboxStyle(status: status, item: .checkbox))
}

// We are sure here label can be uwnrapped because of precondition above (selectorOnly)
// swiftlint:disable force_unwrapping
private func defaultLayout() -> some View {
HStack(spacing: theme.listItem.listItemSpaceColumnGap) {
CheckboxSelector(isAlone: false, status: status)
.modifier(OUDSCheckboxStyle(status: status, item: .checkbox))

if let helper {
VStack(spacing: theme.listItem.listItemSpaceRowGap) {
Text(label!)
.typeLabelDefaultLarge(theme)
.modifier(OUDSCheckboxStyle(status: status, item: .label))

Text(helper)
.typeLabelDefaultMedium(theme)
.modifier(OUDSCheckboxStyle(status: status, item: .helper))
}
} else {
Text(label!)
.typeLabelDefaultLarge(theme)
.modifier(OUDSCheckboxStyle(status: status, item: .label))
}

if let icon {
Spacer()

icon
.frame(maxHeight: theme.checkRadio.checkRadioSizeMaxHeightAssetsContainer)
.accessibilityHidden(true)
}
}
}
// swiftlint:enable force_unwrapping
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,10 @@

import SwiftUI

/// The checkbox component with only the selector
/// The square with the tick or not, i.e. the checkbox selector depending to the given ``OUDSCheckbox.Status``
struct CheckboxSelector: View {

let status: OUDSCheckbox.Status
let action: () -> Void

var body: some View {
SelectorBox(status: status)
.accessibilityAddTraits(.isButton)
.onTapGesture {
action()
}
}
}

/// The square with the tick or not, i.e. the checkbox selector depending to the given `OUDSCheckbox.Status`
private struct SelectorBox: View {

let isAlone: Bool
let status: OUDSCheckbox.Status

@Environment(\.theme) private var theme
Expand All @@ -41,27 +27,41 @@ private struct SelectorBox: View {
tickImage(name: "checkmark")
} else if status == .undeterminate || status == .errorUndeterminate {
tickImage(name: "minus")
} else {
} else { // .unselected and .errorUnselected cases
Color.clear
.frame(minWidth: theme.checkRadio.checkRadioSizeMinWidthSelectorOnly,
maxWidth: theme.checkRadio.checkRadioSizeMinWidthSelectorOnly, // TODO: #264 - No token for maw width!
minHeight: theme.checkRadio.checkRadioSizeMinHeightSelectorOnly,
maxHeight: theme.checkRadio.checkRadioSizeMaxHeightSelectorOnly)
.padding(4)
.modifier(OUDSCheckboxStyle(status: status))
.modifier(SelectorFrameModifier(isAlone: isAlone))
}
}

private func tickImage(name: String) -> some View {
Image(systemName: name)
.resizable()
.scaledToFit()
.frame(minWidth: theme.checkRadio.checkRadioSizeMinWidthSelectorOnly,
maxWidth: theme.checkRadio.checkRadioSizeMinWidthSelectorOnly, // TODO: #264 - No token for maw width!
minHeight: theme.checkRadio.checkRadioSizeMinHeightSelectorOnly,
maxHeight: theme.checkRadio.checkRadioSizeMaxHeightSelectorOnly)
.padding(4)
.modifier(OUDSCheckboxStyle(status: status))
.modifier(SelectorFrameModifier(isAlone: isAlone))
.accessibilityHidden(true)
}
}

/// `ViewModifier` for the checbkox slector to define the tokens to use depending to if the checkkox is alone or not
private struct SelectorFrameModifier: ViewModifier {

let isAlone: Bool
@Environment(\.theme) private var theme

// TODO: #264 - Ensure the rules for min/xax height/width are the good ones in Figma
func body(content: Content) -> some View {
content
.frame(width: theme.listItem.listItemSizeIcon,
height: theme.listItem.listItemSizeIcon)
// if isAlone {
// content
// .frame(minWidth: theme.checkRadio.checkRadioSizeMinWidthSelectorOnly,
// minHeight: theme.checkRadio.checkRadioSizeMinHeightSelectorOnly,
// maxHeight: theme.checkRadio.checkRadioSizeMaxHeightSelectorOnly)
// } else {
// content
// .frame(minHeight: theme.listItem.listItemSizeIcon,
// maxHeight: theme.checkRadio.checkRadioSizeMaxHeightAssetsContainer)
// }
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct CheckboxSelectorBackgroundModifier: ViewModifier {
// MARK: - Properties

let status: OUDSCheckbox.Status
let state: InternalCheckboxState
let state: OUDSCheckbox.State

// MARK: - Environment

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ struct CheckboxSelectorBorderModifier: ViewModifier {
// MARK: - Properties

let status: OUDSCheckbox.Status
let state: InternalCheckboxState
let state: OUDSCheckbox.State

// MARK: - Environment

Expand Down
Loading

0 comments on commit 8805e6b

Please sign in to comment.