diff --git a/CLAUDE.md b/CLAUDE.md index c04fc98..e7f2e39 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -37,7 +37,7 @@ Sources/DashUIKit/ Components/ Most components (one type per file) EnterAmount/ Amount-entry suite (EnterAmountView, SwapAmountView, …) Geometry/ Layout readers + scale-to-fit helpers - Icons/ Code-drawn icons (XmarkIcon) + Icons/ Code-drawn icons (XmarkIcon, CheckmarkIcon, ChevronIcon, InfoRoundIcon) Illustrations/ Loading / success / error illustrations Table List/ List1View (label/value row) ViewModifiers/ MenuViewModifier (card chrome) diff --git a/README.md b/README.md index e10c9aa..7f558dd 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,8 @@ a component already exists before building your own. | `LoadingIllustration` / `LoadingSpinner` | iOS-style activity spinner | [Feedback](docs/feedback.md) | | `SuccessIllustration` / `ErrorIllustration` | 90×90 status badges | [Feedback](docs/feedback.md) | | `XmarkIcon` | Code-drawn close (✕) icon | [Feedback](docs/feedback.md) | +| `CheckmarkIcon` | Code-drawn selection (✓) mark | [Feedback](docs/feedback.md) | +| `ChevronIcon` | Code-drawn chevron, in any of the four directions | [Feedback](docs/feedback.md) | | Geometry helpers | `readingFrame`, `readingLocation`, `ScrollViewWithOnScrollChanged`, `scaleToFitWidth` | [Utilities](docs/utilities.md) | | Foundation | `Color.dash.*`, `Font.dash.*`, `.dashFont`, `DashIconSource` | [Foundation](docs/foundation.md) | diff --git a/Sources/DashUIKit/Components/BottomSheet.swift b/Sources/DashUIKit/Components/BottomSheet/BottomSheet.swift similarity index 100% rename from Sources/DashUIKit/Components/BottomSheet.swift rename to Sources/DashUIKit/Components/BottomSheet/BottomSheet.swift diff --git a/Sources/DashUIKit/Components/BottomSheet/SheetFeature.swift b/Sources/DashUIKit/Components/BottomSheet/SheetFeature.swift new file mode 100644 index 0000000..c0c1bd8 --- /dev/null +++ b/Sources/DashUIKit/Components/BottomSheet/SheetFeature.swift @@ -0,0 +1,141 @@ +// +// Created by Roman Chornyi +// Copyright © 2026 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import SwiftUI + +// MARK: - SheetFeature + +/// One "here is what this gives you" line inside a `BottomSheet`: an icon +/// beside a name and a sentence explaining it. Stack several to describe what a +/// feature unlocks. +/// +/// The icon slot is a `ViewBuilder` rather than a `DashIconSource` because the +/// leading mark is not always an image — a tinted glyph, a badge or a coloured +/// container all appear in this position. It is sized to 40×40 here so a column +/// of features stays aligned whatever each row puts in it. +@available(iOS 14, macOS 11, *) +public struct SheetFeature: View { + public var title: String + public var description: String + @ViewBuilder public var icon: () -> Icon + + public init( + title: String, + description: String, + @ViewBuilder icon: @escaping () -> Icon + ) { + self.title = title + self.description = description + self.icon = icon + } + + public var body: some View { + HStack(alignment: .top, spacing: 16) { + icon() + .frame(width: 40, height: 40) + + VStack(alignment: .leading, spacing: 2) { + // `.subheadMedium`, not `.subhead` + `.fontWeight`: the + // modifier is macOS 13, and the weight belongs to a type token + // anyway — the library carries both weights of this size. + Text(title) + .dashFont(.subheadMedium) + .foregroundColor(Color.dash.primaryText) + + Text(description) + .dashFont(.subhead) + .foregroundColor(Color.dash.primaryText) + } + .padding(.top, 10) + .frame(maxWidth: .infinity, alignment: .topLeading) + } + } +} + +@available(iOS 14, macOS 11, *) +public extension SheetFeature where Icon == AnyView { + /// Convenience for an asset in the icon slot. + /// + /// `iconColor` is optional on purpose. Given one, the image is drawn as a + /// template in that colour — right for a single-colour glyph. Left `nil`, + /// the asset renders as authored, which is the only way an icon carrying + /// more than one colour keeps them: a template draws the alpha channel in + /// a single tint and flattens the rest away. + init( + title: String, + description: String, + icon source: DashIconSource, + iconColor: Color? = nil + ) { + // Built before the call so the slot receives exactly `AnyView`; a + // `@ViewBuilder` if/else would hand back `_ConditionalContent`. + // `.renderingMode` also lives on `Image`, so it is applied before the + // layout modifiers erase the type. + let rendered: AnyView + if let iconColor { + rendered = AnyView( + Image(dash: source) + .renderingMode(.template) + .resizable() + .scaledToFit() + .foregroundColor(iconColor)) + } else { + rendered = AnyView( + Image(dash: source) + .resizable() + .scaledToFit()) + } + self.init(title: title, description: description) { rendered } + } +} + +#if DEBUG + +@available(iOS 17, macOS 14, *) +#Preview("Feature list") { + VStack(alignment: .leading, spacing: 16) { + SheetFeature( + title: "Identity", + description: "Register a username and be paid by name instead of an address.", + icon: .custom("feature-identity", bundle: .dashUIKit)) + SheetFeature( + title: "Platform", + description: "Store contacts and profile data on Dash Platform.", + icon: .custom("feature-platform", bundle: .dashUIKit)) + SheetFeature( + title: "Shield", + description: "Move funds into shielded balances that stay off the public ledger.", + icon: .custom("feature-shield", bundle: .dashUIKit)) + } + .padding(20) + .background(Color.dash.primaryBackground) +} + +@available(iOS 17, macOS 14, *) +#Preview("Custom icon slot") { + SheetFeature( + title: "Anything in the slot", + description: "The icon is a ViewBuilder, so a badge or a coloured container fits too." + ) { + Circle().fill(Color.dash.blueAlpha10) + .overlay(InfoRoundIcon(size: 20)) + } + .padding(20) + .background(Color.dash.primaryBackground) +} + +#endif diff --git a/Sources/DashUIKit/Components/ConverterCard/ConverterCard.swift b/Sources/DashUIKit/Components/ConverterCard/ConverterCard.swift index 79bbd41..50e8c48 100644 --- a/Sources/DashUIKit/Components/ConverterCard/ConverterCard.swift +++ b/Sources/DashUIKit/Components/ConverterCard/ConverterCard.swift @@ -24,6 +24,9 @@ import SwiftUI /// /// Pass `onSwap` to show a tappable `diagonal-up-down` button; omit it (or pass `nil`) for a /// static `arrow-down` indicator when the card is non-swappable. +/// +/// A row given an `onTap` becomes a button and grows a trailing chevron, so a +/// row that opens a picker reads as one at rest. @available(iOS 14, macOS 11, *) public struct ConverterCard: View { @@ -52,7 +55,10 @@ public struct ConverterCard: View { public var body: some View { VStack(spacing: Layout.cardSpacing) { ForEach(Array(orderedItems.enumerated()), id: \.element.id) { index, item in - ConverterCardRow(slot: index == 0 ? .top : .bottom) { + ConverterCardRow( + slot: index == 0 ? .top : .bottom, + isInteractive: item.onTap != nil + ) { row(item: item) } } @@ -75,9 +81,25 @@ public struct ConverterCard: View { /// spacing — never on the bottom row — so it stays correct when the rows differ in height. private var seamY: CGFloat { topRowHeight + Layout.cardSpacing / 2 } + /// A row with an `onTap` becomes a plain button over the whole row area + /// (`contentShape` keeps the padding and the spacer tappable); without + /// one it stays inert, exactly as before the action existed. + @ViewBuilder + private func row(item: ConverterCardItem) -> some View { + if let onTap = item.onTap { + Button(action: onTap) { + rowContent(item: item) + .contentShape(Rectangle()) + } + .buttonStyle(.plain) + } else { + rowContent(item: item) + } + } + /// Row layout mirrors `MenuItem` (icon 30pt, 10pt padding) but stays flexible enough for a /// custom icon/trailing view and a multi-line subtitle. - private func row(item: ConverterCardItem) -> some View { + private func rowContent(item: ConverterCardItem) -> some View { HStack(spacing: 10) { leading(item) @@ -100,6 +122,14 @@ public struct ConverterCard: View { Spacer(minLength: 8) trailing(item) + + // A row that opens something says so. `onTap` is the only signal + // the card has for that, and it is exactly the right one: the two + // are set together by definition. + if item.onTap != nil { + ChevronIcon() + .padding(.leading, 2) + } } .padding(10) } @@ -175,6 +205,25 @@ struct ConverterCard_Previews: PreviewProvider { ) .previewDisplayName("Static (no swap)") + // Tappable from-row: the whole row is a plain button carrying the + // trailing chevron; the bottom row stays inert and chevron-less. + ConverterCard( + fromItem: ConverterCardItem( + icon: .system("d.circle.fill"), + title: "Tap to pick a source", + subtitle: "From", + dashBalance: 245_000_000, + onTap: {} + ), + toItem: ConverterCardItem( + icon: .system("person.crop.circle.fill"), + title: "Identity", + subtitle: "To", + showsBalance: false + ) + ) + .previewDisplayName("Tappable from-row") + // Unequal rows — badge must stay on the seam when the bottom row is taller. ConverterCard( fromItem: ConverterCardItem( diff --git a/Sources/DashUIKit/Components/ConverterCard/ConverterCardItem.swift b/Sources/DashUIKit/Components/ConverterCard/ConverterCardItem.swift index 1dd5519..c12f97c 100644 --- a/Sources/DashUIKit/Components/ConverterCard/ConverterCardItem.swift +++ b/Sources/DashUIKit/Components/ConverterCard/ConverterCardItem.swift @@ -48,6 +48,10 @@ public struct ConverterCardItem: Identifiable { public let trailingView: AnyView? /// When `false` (and no `trailingView`), the row hides its trailing balance. public let showsBalance: Bool + /// Invoked when the whole row is tapped (e.g. to open an endpoint picker). + /// `nil` — the default — leaves the row inert, exactly as before this + /// parameter existed. + public let onTap: (() -> Void)? public init( id: AnyHashable? = nil, @@ -59,7 +63,8 @@ public struct ConverterCardItem: Identifiable { dashBalance: Int64 = 0, fiat: String? = nil, trailingView: AnyView? = nil, - showsBalance: Bool = true + showsBalance: Bool = true, + onTap: (() -> Void)? = nil ) { self.id = id ?? AnyHashable(title) self.icon = icon @@ -71,5 +76,6 @@ public struct ConverterCardItem: Identifiable { self.fiat = fiat self.trailingView = trailingView self.showsBalance = showsBalance + self.onTap = onTap } } diff --git a/Sources/DashUIKit/Components/ConverterCard/ConverterCardRow.swift b/Sources/DashUIKit/Components/ConverterCard/ConverterCardRow.swift index a2fd207..4b61fe2 100644 --- a/Sources/DashUIKit/Components/ConverterCard/ConverterCardRow.swift +++ b/Sources/DashUIKit/Components/ConverterCard/ConverterCardRow.swift @@ -40,16 +40,21 @@ struct ConverterRowHeightKey: PreferenceKey { // MARK: - ConverterCardRow -/// One card in the conversion stack: wraps arbitrary content with the shared, non-interactive -/// card chrome and reports its height via `ConverterRowHeightKey` for its `slot`. +/// One card in the conversion stack: wraps arbitrary content with the shared card chrome and +/// reports its height via `ConverterRowHeightKey` for its `slot`. +/// +/// The chrome swallows touches by default: a row is display-only, and the badge drawn over the +/// seam is the card's only control. A row that carries its own action opts back in with +/// `isInteractive` — without it the button inside the content would never see the tap. @available(iOS 14, macOS 11, *) struct ConverterCardRow: View { let slot: ConverterRowSlot + var isInteractive: Bool = false @ViewBuilder var content: () -> Content var body: some View { content() - .allowsHitTesting(false) + .allowsHitTesting(isInteractive) .padding(6) .background(Color.dash.secondaryBackground) .clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous)) diff --git a/Sources/DashUIKit/Components/DashAmount.swift b/Sources/DashUIKit/Components/DashAmount.swift index 115145a..23efd6d 100644 --- a/Sources/DashUIKit/Components/DashAmount.swift +++ b/Sources/DashUIKit/Components/DashAmount.swift @@ -31,22 +31,29 @@ public enum DashAmountSign { // MARK: - Internal formatter -private enum DashAmountFormat { +public enum DashAmountFormat { static let duffsPerDash: Decimal = 100_000_000 - static let numberFormatter: NumberFormatter = { + /// Five is what a balance wants: enough to be exact at everyday sizes, + /// short enough not to dominate a row. It is NOT enough for every figure — + /// a Core fee of a few hundred duffs rounds to zero at five places — so the + /// digit count is a parameter and this is only its default. + public static let defaultMaximumFractionDigits = 5 + + static func numberFormatter(maximumFractionDigits: Int) -> NumberFormatter { let f = NumberFormatter() f.numberStyle = .decimal f.locale = .current f.minimumFractionDigits = 0 - f.maximumFractionDigits = 5 + f.maximumFractionDigits = maximumFractionDigits f.usesGroupingSeparator = true return f - }() + } - static func string(forDuffs duffs: Int64) -> String { + static func string(forDuffs duffs: Int64, maximumFractionDigits: Int) -> String { let value = Decimal(duffs) / duffsPerDash - return numberFormatter.string(from: value as NSNumber) ?? "\(value)" + return numberFormatter(maximumFractionDigits: maximumFractionDigits) + .string(from: value as NSNumber) ?? "\(value)" } } @@ -60,19 +67,24 @@ public struct DashAmount: View { public var weight: Font.Weight public var dashSymbolFactor: CGFloat public var sign: DashAmountSign + /// Raise it for a figure the default would round away — a Core network fee + /// is a few hundred duffs, which is zero at five places. + public var maximumFractionDigits: Int public init( amount: Int64, fontSize: CGFloat = 13, weight: Font.Weight = .medium, dashSymbolFactor: CGFloat = 1, - sign: DashAmountSign = .negativeOnly + sign: DashAmountSign = .negativeOnly, + maximumFractionDigits: Int = DashAmountFormat.defaultMaximumFractionDigits ) { self.amount = amount self.fontSize = fontSize self.weight = weight self.dashSymbolFactor = dashSymbolFactor self.sign = sign + self.maximumFractionDigits = maximumFractionDigits } public var body: some View { @@ -85,7 +97,7 @@ public struct DashAmount: View { Text(prefix) .font(.system(size: fontSize, weight: weight)) } - Text(DashAmountFormat.string(forDuffs: abs(amount))) + Text(DashAmountFormat.string(forDuffs: abs(amount), maximumFractionDigits: maximumFractionDigits)) .font(.system(size: fontSize, weight: weight)) .lineLimit(1) DashIcon.Common.iconDashCurrency.image diff --git a/Sources/DashUIKit/Components/EnterAmount/DualSwapAmountView.swift b/Sources/DashUIKit/Components/EnterAmount/DualSwapAmountView.swift index fce30a6..2830e6c 100644 --- a/Sources/DashUIKit/Components/EnterAmount/DualSwapAmountView.swift +++ b/Sources/DashUIKit/Components/EnterAmount/DualSwapAmountView.swift @@ -39,6 +39,8 @@ internal struct DualSwapAmountView: View { /// When `true`, primary amount occupies the large/top slot; when `false`, secondary does. let isPrimarySelected: Bool let isCurrencySelectorHidden: Bool + /// Stands in for the B row's value when the amount is rejected. + var secondaryErrorMessage: String? = nil let onSwap: () -> Void let onSelectCurrency: () -> Void let onPaste: (() -> Void)? @@ -54,6 +56,7 @@ internal struct DualSwapAmountView: View { secondarySymbol: secondaryCurrency.symbol, showSecondaryDashLogo: secondaryCurrency == .dash, showSecondaryCurrencyButton: !isCurrencySelectorHidden, + secondaryErrorMessage: secondaryErrorMessage, onSecondaryCurrencyTap: onSelectCurrency, swapAnimationKey: isPrimarySelected ) diff --git a/Sources/DashUIKit/Components/EnterAmount/EnterAmountView.swift b/Sources/DashUIKit/Components/EnterAmount/EnterAmountView.swift index ff92126..d984248 100644 --- a/Sources/DashUIKit/Components/EnterAmount/EnterAmountView.swift +++ b/Sources/DashUIKit/Components/EnterAmount/EnterAmountView.swift @@ -60,6 +60,10 @@ public struct EnterAmountView: View { public var primaryCurrency: CurrencyOption = .dash /// Currency for the secondary logical value. public var secondaryCurrency: CurrencyOption = .fiat("USD") + /// Shown in red in place of the secondary amount. Keep it short: it sits + /// in a slot sized for a converted figure. + public var errorMessage: String? = nil + /// When `true`, `primaryAmount` occupies the large slot; when `false`, `secondaryAmount` does. public var isPrimarySelected: Bool = true /// Hides the currency-select chevron when `true`. @@ -122,7 +126,8 @@ public struct EnterAmountView: View { onSwap: (() -> Void)? = nil, onCurrencyTap: (() -> Void)? = nil, onPaste: (() -> Void)? = nil, - onSelectInputType: ((String) -> Void)? = nil + onSelectInputType: ((String) -> Void)? = nil, + errorMessage: String? = nil ) { self._value = .constant("") self._selectedCurrency = .constant(.dash) @@ -130,6 +135,7 @@ public struct EnterAmountView: View { self.style = .dualSwap self.primaryAmount = primaryAmount self.secondaryAmount = secondaryAmount + self.errorMessage = errorMessage self.primaryCurrency = primaryCurrency self.secondaryCurrency = secondaryCurrency self.isPrimarySelected = isPrimarySelected @@ -194,6 +200,7 @@ public struct EnterAmountView: View { secondaryCurrency: secondaryCurrency, isPrimarySelected: isPrimarySelected, isCurrencySelectorHidden: isCurrencySelectorHidden, + secondaryErrorMessage: errorMessage, onSwap: onSwap ?? {}, onSelectCurrency: onCurrencyTap ?? {}, onPaste: onPaste diff --git a/Sources/DashUIKit/Components/EnterAmount/SwapAmountView.swift b/Sources/DashUIKit/Components/EnterAmount/SwapAmountView.swift index 4cb8d36..b7d1c64 100644 --- a/Sources/DashUIKit/Components/EnterAmount/SwapAmountView.swift +++ b/Sources/DashUIKit/Components/EnterAmount/SwapAmountView.swift @@ -45,6 +45,10 @@ public struct SwapAmountView: View { public var showSecondaryDashLogo: Bool = false /// Show a currency-select chevron beside the B row's amount. public var showSecondaryCurrencyButton: Bool = false + /// Replaces the B row's value, symbol and chevron with a red message. + /// A rejected amount has to say something where the converted value + /// would be, so it takes that slot instead of adding a line under it. + public var secondaryErrorMessage: String? = nil /// Action fired when the secondary-row chevron is tapped. public var onSecondaryCurrencyTap: (() -> Void)? = nil /// When non-nil, enables the animated dual-swap ZStack layout and acts as the animation key. @@ -67,6 +71,7 @@ public struct SwapAmountView: View { secondarySymbol: String? = nil, showSecondaryDashLogo: Bool = false, showSecondaryCurrencyButton: Bool = false, + secondaryErrorMessage: String? = nil, onSecondaryCurrencyTap: (() -> Void)? = nil, swapAnimationKey: Bool? = nil ) { @@ -81,7 +86,7 @@ public struct SwapAmountView: View { self.onPaste = onPaste self.secondarySymbol = secondarySymbol self.showSecondaryDashLogo = showSecondaryDashLogo - self.showSecondaryCurrencyButton = showSecondaryCurrencyButton + self.secondaryErrorMessage = secondaryErrorMessage self.onSecondaryCurrencyTap = onSecondaryCurrencyTap self.swapAnimationKey = swapAnimationKey } @@ -147,6 +152,7 @@ public struct SwapAmountView: View { showSecondaryDashLogo: showSecondaryDashLogo, showSecondaryCurrencyButton: showSecondaryCurrencyButton, onSecondaryCurrencyTap: onSecondaryCurrencyTap, + secondaryErrorMessage: secondaryErrorMessage, isPrimaryLarge: isPrimaryLarge ) } @@ -275,6 +281,7 @@ private struct AnimatedSwapLayout: View { let showSecondaryDashLogo: Bool let showSecondaryCurrencyButton: Bool let onSecondaryCurrencyTap: (() -> Void)? + let secondaryErrorMessage: String? let isPrimaryLarge: Bool // MARK: Phase state @@ -309,6 +316,7 @@ private struct AnimatedSwapLayout: View { showSecondaryDashLogo: Bool, showSecondaryCurrencyButton: Bool, onSecondaryCurrencyTap: (() -> Void)?, + secondaryErrorMessage: String?, isPrimaryLarge: Bool ) { self.amount = amount @@ -321,6 +329,7 @@ private struct AnimatedSwapLayout: View { self.secondarySymbol = secondarySymbol self.showSecondaryDashLogo = showSecondaryDashLogo self.showSecondaryCurrencyButton = showSecondaryCurrencyButton + self.secondaryErrorMessage = secondaryErrorMessage self.onSecondaryCurrencyTap = onSecondaryCurrencyTap self.isPrimaryLarge = isPrimaryLarge _fontPrimary = State(initialValue: isPrimaryLarge) @@ -353,17 +362,29 @@ private struct AnimatedSwapLayout: View { .scaleEffect(scaleA, anchor: .center) .offset(y: offsetPrimary ? SwapAnimLayout.primaryOffset : SwapAnimLayout.secondaryOffset) - // B row — always carries the secondary logical value; shows optional chevron + // B row — the secondary logical value, or the message standing in + // for it; shows optional chevron HStack(spacing: 6) { - rowContent( - font: bFont, - displayText: displaySecondary, - symbol: secondarySymbol, - showLogo: showSecondaryDashLogo, - dashSize: dashSize - ) - - if showSecondaryCurrencyButton { + if let secondaryErrorMessage { + // `subhead` outright, not `bFont`: that one turns into + // `largeTitle` when the secondary slot is the large one, + // and the message must stay the size of the converted + // figure it replaces however the slots are arranged. + Text(secondaryErrorMessage) + .font(Font.dash.subhead) + .foregroundColor(Color.dash.red) + .lineLimit(1) + } else { + rowContent( + font: bFont, + displayText: displaySecondary, + symbol: secondarySymbol, + showLogo: showSecondaryDashLogo, + dashSize: dashSize + ) + } + + if showSecondaryCurrencyButton && secondaryErrorMessage == nil { Button { onSecondaryCurrencyTap?() } label: { DashIcon.Common.chevronDownCurrencySelect.image .resizable() diff --git a/Sources/DashUIKit/Components/Icons/CheckmarkIcon.swift b/Sources/DashUIKit/Components/Icons/CheckmarkIcon.swift new file mode 100644 index 0000000..375e588 --- /dev/null +++ b/Sources/DashUIKit/Components/Icons/CheckmarkIcon.swift @@ -0,0 +1,103 @@ +// +// Created by Roman Chornyi +// Copyright © 2026 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import SwiftUI + +// MARK: - CheckmarkIcon + +/// A code-drawn "✓" (selected) mark. Mirrors the source SVG (15×12 viewBox, the +/// polyline 1,5.85 → 5.48,10.7 → 14,1, round caps/joins). Scales cleanly to any +/// `size`, which sets the WIDTH — the height follows the source aspect ratio, so +/// the tick never squares off into something the design did not draw. +/// +/// The default colour is `Color.dash.blue`, which is the `#008DE4` the SVG +/// strokes with; naming the token rather than the hex keeps it following the +/// palette. +@available(iOS 14, macOS 11, *) +public struct CheckmarkIcon: View { + public var size: CGFloat = 15 + public var color: Color = Color.dash.blue + public var lineWidth: CGFloat = 2 + + /// A public struct gets no public memberwise initializer, so this one is + /// written out to keep the call site unchanged for module-internal users + /// and available to app code. + public init( + size: CGFloat = 15, + color: Color = Color.dash.blue, + lineWidth: CGFloat = 2 + ) { + self.size = size + self.color = color + self.lineWidth = lineWidth + } + + public var body: some View { + CheckmarkShape() + .stroke(color, style: StrokeStyle(lineWidth: lineWidth, lineCap: .round, lineJoin: .round)) + .frame(width: size, height: size * CheckmarkShape.aspectRatio) + } +} + +// MARK: - CheckmarkShape + +/// The tick polyline, normalized from the 15×12 source viewBox so it keeps its +/// proportions at any size. +@available(iOS 14, macOS 11, *) +private struct CheckmarkShape: Shape { + private static let viewBox = CGSize(width: 15, height: 12) + + /// Height per unit of width — `CheckmarkIcon` sizes by width. + static let aspectRatio: CGFloat = viewBox.height / viewBox.width + + /// Start, elbow and end of the tick, in source-viewBox units. + private static let points = [ + CGPoint(x: 1, y: 5.85), + CGPoint(x: 5.48, y: 10.7), + CGPoint(x: 14, y: 1), + ] + + func path(in rect: CGRect) -> Path { + let scaled = Self.points.map { point in + CGPoint( + x: rect.minX + rect.width * point.x / Self.viewBox.width, + y: rect.minY + rect.height * point.y / Self.viewBox.height) + } + + var path = Path() + path.move(to: scaled[0]) + path.addLine(to: scaled[1]) + path.addLine(to: scaled[2]) + return path + } +} + +#if DEBUG + +@available(iOS 17, macOS 14, *) +#Preview { + VStack(spacing: 24) { + CheckmarkIcon() + CheckmarkIcon(size: 24, color: .white, lineWidth: 3) + .padding(20) + .background(Circle().fill(Color.dash.blue)) + CheckmarkIcon(size: 40, color: Color.dash.green, lineWidth: 4) + } + .padding() +} + +#endif diff --git a/Sources/DashUIKit/Components/Icons/ChevronIcon.swift b/Sources/DashUIKit/Components/Icons/ChevronIcon.swift new file mode 100644 index 0000000..8539ab1 --- /dev/null +++ b/Sources/DashUIKit/Components/Icons/ChevronIcon.swift @@ -0,0 +1,177 @@ +// +// Created by Roman Chornyi +// Copyright © 2026 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import SwiftUI + +// MARK: - ChevronIcon + +/// A code-drawn chevron, in any of the four directions. +/// +/// Mirrors the source SVG (7×12 viewBox, the polyline 0.8,10.8 → 5.8,5.8 → +/// 0.8,0.8, 1.6 stroke, round caps/joins) — that is the `.right` chevron, and +/// the other three are the same glyph rotated, so all four keep one geometry +/// and one line weight. +/// +/// `size` sets the LONG side; the short one follows the source aspect ratio, so +/// a chevron never squashes into something the design did not draw. A `.up` / +/// `.down` chevron is therefore wider than it is tall, which is what rotating +/// the drawn one gives you. +/// +/// The default colour is `Color.dash.gray300Alpha90` — the palette entry for +/// the `#B0B6BC` at 90% the SVG strokes with. +@available(iOS 14, macOS 11, *) +public struct ChevronIcon: View { + + /// Where the chevron points. + public enum Direction { + case right + case left + case up + case down + + /// Rotation applied to the drawn `.right` chevron. + var angle: Angle { + switch self { + case .right: return .degrees(0) + case .down: return .degrees(90) + case .left: return .degrees(180) + case .up: return .degrees(270) + } + } + + /// True when the rotation exchanges the glyph's width and height. + var isVertical: Bool { + switch self { + case .up, .down: return true + case .left, .right: return false + } + } + } + + public var direction: Direction = .right + /// The chevron's long side — its height when pointing left/right, its + /// width when pointing up/down. + public var size: CGFloat = 12 + public var color: Color = Color.dash.gray300Alpha90 + public var lineWidth: CGFloat = 1.6 + + /// A public struct gets no public memberwise initializer, so this one is + /// written out to keep the call site unchanged for module-internal users + /// and available to app code. + public init( + direction: Direction = .right, + size: CGFloat = 12, + color: Color = Color.dash.gray300Alpha90, + lineWidth: CGFloat = 1.6 + ) { + self.direction = direction + self.size = size + self.color = color + self.lineWidth = lineWidth + } + + public var body: some View { + ChevronShape() + .stroke(color, style: StrokeStyle(lineWidth: lineWidth, lineCap: .round, lineJoin: .round)) + // Drawn at the `.right` orientation, then rotated. The outer frame + // swaps the axes for the vertical directions so the rotated glyph + // reports the space it actually occupies — a `.down` chevron that + // still measured 7×12 would leave a gap beside it and clip above. + .frame(width: size * ChevronShape.aspectRatio, height: size) + .rotationEffect(direction.angle) + .frame( + width: direction.isVertical ? size : size * ChevronShape.aspectRatio, + height: direction.isVertical ? size * ChevronShape.aspectRatio : size) + } +} + +// MARK: - ChevronShape + +/// The chevron polyline, normalized from the 7×12 source viewBox so it keeps +/// its proportions at any size. Points right; `ChevronIcon` rotates it. +@available(iOS 14, macOS 11, *) +private struct ChevronShape: Shape { + private static let viewBox = CGSize(width: 7, height: 12) + + /// Width per unit of height — `ChevronIcon` sizes by the long side, which + /// for the drawn orientation is the height. + static let aspectRatio: CGFloat = viewBox.width / viewBox.height + + /// Top, point and bottom of the chevron, in source-viewBox units. + private static let points = [ + CGPoint(x: 0.8, y: 0.8), + CGPoint(x: 5.8, y: 5.8), + CGPoint(x: 0.8, y: 10.8), + ] + + func path(in rect: CGRect) -> Path { + let scaled = Self.points.map { point in + CGPoint( + x: rect.minX + rect.width * point.x / Self.viewBox.width, + y: rect.minY + rect.height * point.y / Self.viewBox.height) + } + + var path = Path() + path.move(to: scaled[0]) + path.addLine(to: scaled[1]) + path.addLine(to: scaled[2]) + return path + } +} + +#if DEBUG + +@available(iOS 17, macOS 14, *) +#Preview("Four directions") { + HStack(spacing: 32) { + ChevronIcon(direction: .left) + ChevronIcon(direction: .right) + ChevronIcon(direction: .up) + ChevronIcon(direction: .down) + } + .padding() + .background(Color.dash.primaryBackground) +} + +/// Each one drawn on its own bounds, so the frame the rotation reports is +/// visible: left/right are tall, up/down are wide. +@available(iOS 17, macOS 14, *) +#Preview("Measured bounds") { + HStack(spacing: 24) { + ForEach([ChevronIcon.Direction.left, .right, .up, .down], id: \.angle.degrees) { direction in + ChevronIcon(direction: direction, size: 40, color: Color.dash.blue, lineWidth: 4) + .background(Color.dash.gray300Alpha20) + } + } + .padding() + .background(Color.dash.primaryBackground) +} + +@available(iOS 17, macOS 14, *) +#Preview("Dark") { + HStack(spacing: 32) { + ChevronIcon(direction: .left) + ChevronIcon(direction: .right) + ChevronIcon(direction: .up) + ChevronIcon(direction: .down) + } + .padding() + .background(Color.dash.primaryBackground) + .preferredColorScheme(.dark) +} + +#endif diff --git a/Sources/DashUIKit/Components/Icons/InfoRoundIcon.swift b/Sources/DashUIKit/Components/Icons/InfoRoundIcon.swift new file mode 100644 index 0000000..e6c4fa5 --- /dev/null +++ b/Sources/DashUIKit/Components/Icons/InfoRoundIcon.swift @@ -0,0 +1,116 @@ +// +// Copyright © 2026 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import SwiftUI + +// MARK: - InfoRoundIcon + +/// A filled disc carrying a white "i" — the affordance for "there is more to +/// say about this". +/// +/// Drawn rather than shipped as an asset, for the same reason `XmarkIcon` is: +/// it stays crisp at any size, and the disc takes the `Blue` token instead of +/// baking `#008DE4` into a PDF that would then miss a palette change. +@available(iOS 14, macOS 11, *) +public struct InfoRoundIcon: View { + public var size: CGFloat = 19 + public var color: Color = Color.dash.blue + public var glyphColor: Color = Color.dash.white + + /// A public struct gets no public memberwise initializer, so this one is + /// written out to keep the call site available to app code. + public init( + size: CGFloat = 19, + color: Color = Color.dash.blue, + glyphColor: Color = Color.dash.white + ) { + self.size = size + self.color = color + self.glyphColor = glyphColor + } + + public var body: some View { + ZStack { + Circle() + .fill(color) + InfoGlyphShape() + .stroke( + glyphColor, + style: StrokeStyle( + lineWidth: size * Self.strokeRatio, + lineCap: .round, + lineJoin: .round)) + } + .frame(width: size, height: size) + } + + /// 1.6 of the 19-unit source viewBox. + private static let strokeRatio: CGFloat = 1.6 / 19 +} + +// MARK: - InfoGlyphShape + +/// The "i": a stem below the middle and a dot above it. Both are normalized +/// from the 19-unit source viewBox so the glyph keeps its proportions at any +/// size. +/// +/// The dot is a 0.01-long segment rather than a circle — with a round cap that +/// renders as a dot of exactly the stem's weight, which is how the source +/// draws it and what keeps the two visually matched at every size. +@available(iOS 14, macOS 11, *) +private struct InfoGlyphShape: Shape { + private let centerXRatio: CGFloat = 9.2998 / 19 + private let stemTopRatio: CGFloat = 9.30005 / 19 + private let stemBottomRatio: CGFloat = 12.6056 / 19 + private let dotTopRatio: CGFloat = 5.99451 / 19 + private let dotBottomRatio: CGFloat = 6.00451 / 19 + + func path(in rect: CGRect) -> Path { + let x = rect.minX + rect.width * centerXRatio + + var path = Path() + path.move(to: CGPoint(x: x, y: rect.minY + rect.height * stemTopRatio)) + path.addLine(to: CGPoint(x: x, y: rect.minY + rect.height * stemBottomRatio)) + path.move(to: CGPoint(x: x, y: rect.minY + rect.height * dotTopRatio)) + path.addLine(to: CGPoint(x: x, y: rect.minY + rect.height * dotBottomRatio)) + return path + } +} + +#if DEBUG + +@available(iOS 17, macOS 14, *) +#Preview("Sizes") { + HStack(alignment: .center, spacing: 12) { + InfoRoundIcon(size: 14) + InfoRoundIcon() + InfoRoundIcon(size: 28) + InfoRoundIcon(size: 44) + } + .padding() +} + +@available(iOS 17, macOS 14, *) +#Preview("Recoloured") { + HStack(spacing: 12) { + InfoRoundIcon(size: 32, color: Color.dash.gray300) + InfoRoundIcon(size: 32, color: Color.dash.orange) + } + .padding() + .background(Color.dash.primaryBackground) +} + +#endif diff --git a/Sources/DashUIKit/Components/MenuItem.swift b/Sources/DashUIKit/Components/MenuItem.swift index 10e9b26..61ed051 100644 --- a/Sources/DashUIKit/Components/MenuItem.swift +++ b/Sources/DashUIKit/Components/MenuItem.swift @@ -29,7 +29,23 @@ public enum MenuItemAccessory { /// Dash amount with an optional pre-formatted fiat sub-line. /// The caller converts the fiat value via its own exchange infrastructure; /// the library only renders the string it receives. - case balance(dash: Int64, sign: DashAmountSign = .negativeOnly, fiat: String? = nil) + case balance(dash: Int64, sign: DashAmountSign = .negativeOnly, fiat: String? = nil, + maximumFractionDigits: Int = DashAmountFormat.defaultMaximumFractionDigits) + /// A picker row: the design system's tick on the chosen one. + /// + /// The mark keeps its slot while unselected, so nothing in the row shifts + /// horizontally as the selection moves down a list. + case selection(isSelected: Bool) +} + +/// The glyph beside a row's title that says there is more to explain. +/// +/// `.round` is the design system's own info mark; `.icon` stays open for a row +/// that needs to flag something else entirely. +@available(iOS 14, macOS 11, *) +public enum MenuItemInfo { + case round(color: Color) + case icon(DashIconSource) } @available(iOS 14, macOS 11, *) @@ -40,7 +56,7 @@ public struct MenuItem: View { public var disabledLeadingIcon: DashIconSource? public var title: String public var helpText: String? - public var infoIcon: DashIconSource? + public var info: MenuItemInfo? public var accessory: MenuItemAccessory public init( @@ -49,7 +65,7 @@ public struct MenuItem: View { disabledLeadingIcon: DashIconSource? = nil, title: String, helpText: String? = nil, - infoIcon: DashIconSource? = nil, + info: MenuItemInfo? = nil, accessory: MenuItemAccessory = .none ) { self.leadingIcon = leadingIcon @@ -57,7 +73,7 @@ public struct MenuItem: View { self.disabledLeadingIcon = disabledLeadingIcon self.title = title self.helpText = helpText - self.infoIcon = infoIcon + self.info = info self.accessory = accessory } @@ -89,9 +105,15 @@ public struct MenuItem: View { .dashFont(.subheadMedium) .foregroundColor(isEnabled ? Color.dash.primaryText : Color.dash.secondaryText) - if let icon = infoIcon { - Image(dash: icon) - .frame(width: 20, height: 20, alignment: .center) + if let info { + switch info { + case .round(let color): + InfoRoundIcon(size: 19, color: color) + .frame(width: 20, height: 20, alignment: .center) + case .icon(let icon): + Image(dash: icon) + .frame(width: 20, height: 20, alignment: .center) + } } } @@ -110,8 +132,11 @@ public struct MenuItem: View { case .none: EmptyView() case .toggle(let isOn): - Toggle("", isOn: isOn) - .labelsHidden() + // `SwitchView`, not `Toggle`: the system switch is green and sized + // by UIKit, so a menu row rendered here did not match the switch + // the same design system hands out everywhere else. It reads + // `isEnabled` from the environment, which `.disabled` sets. + SwitchView(isOn: isOn) .disabled(!isEnabled) case .text(let value): Text(value) @@ -119,9 +144,9 @@ public struct MenuItem: View { .foregroundColor(Color.dash.secondaryText) case .button(let button): button - case .balance(let dash, let sign, let fiat): + case .balance(let dash, let sign, let fiat, let maximumFractionDigits): VStack(alignment: .trailing, spacing: 1) { - DashAmount(amount: dash, sign: sign) + DashAmount(amount: dash, sign: sign, maximumFractionDigits: maximumFractionDigits) .foregroundColor(Color.dash.primaryText) if dash != 0, dash != .max, dash != .min, let fiat { @@ -130,6 +155,10 @@ public struct MenuItem: View { .foregroundColor(Color.dash.secondaryText) } } + case .selection(let isSelected): + CheckmarkIcon() + .opacity(isSelected ? 1 : 0) + .accessibilityHidden(!isSelected) } } } @@ -152,11 +181,11 @@ public struct MenuItem: View { } @available(iOS 17, macOS 14, *) -#Preview("Title + infoIcon + helpText") { +#Preview("Title + info + helpText") { MenuItem( title: "Network fee", helpText: "Estimated cost for this transaction", - infoIcon: .system("info.circle"), + info: .round(color: Color.dash.gray300Alpha70), accessory: .text("0.0001 DASH") ) .padding(.horizontal) @@ -245,6 +274,31 @@ public struct MenuItem: View { .padding(.horizontal) } +/// A picker list: one row marked, the rest holding the tick's slot empty. +@available(iOS 17, macOS 14, *) +#Preview("Accessory: selection") { + VStack(spacing: 0) { + MenuItem( + leadingIcon: DashIcon.Menu.dashLogoSquare.source, + title: "Transparent", + accessory: .selection(isSelected: true) + ) + + MenuItem( + leadingIcon: DashIcon.Features.platform.source, + title: "Platform", + accessory: .selection(isSelected: false) + ) + + MenuItem( + leadingIcon: DashIcon.Features.shield.source, + title: "Shielded", + accessory: .selection(isSelected: false) + ) + } + .padding(.horizontal) +} + @available(iOS 17, macOS 14, *) #Preview("Enabled vs disabled") { VStack(spacing: 0) { diff --git a/Sources/DashUIKit/Components/NumericKeyboardView.swift b/Sources/DashUIKit/Components/NumericKeyboardView.swift index b49dfe4..1950fa4 100644 --- a/Sources/DashUIKit/Components/NumericKeyboardView.swift +++ b/Sources/DashUIKit/Components/NumericKeyboardView.swift @@ -84,6 +84,11 @@ enum NumericKeyboardLocaleSupport { public struct NumericKeyboardView: View { private enum Layout { + /// The panel the keypad sits on: inset from the screen edges, + /// clear of the home indicator, and rounded at the top. + static let panelHorizontalPadding: CGFloat = 20 + static let panelVerticalPadding: CGFloat = 20 + static let panelCornerRadius: CGFloat = 32 static let rootSpacing: CGFloat = 20 static let rowsSpacing: CGFloat = 10 static let rowSpacing: CGFloat = 10 @@ -135,7 +140,26 @@ public struct NumericKeyboardView: View { helperTextRow(helperText) actionButtonView } - .background(Color.dash.secondaryBackground) + .padding(.horizontal, Layout.panelHorizontalPadding) + .padding(.vertical, Layout.panelVerticalPadding) + .frame(maxWidth: .infinity) + // Rounded at the top only, and run down into the bottom safe area. + // + // Drawn as a fully rounded rectangle pushed below its own frame by the + // radius, so the bottom corners are never on screen. + // `UnevenRoundedRectangle` says that in one line but is iOS 16, and + // this library ships to 14; `background(alignment:content:)` is 15. + // Both are avoidable, the deployment target is not. + // + // `.continuous` because the circular default kinks visibly where the + // arc meets the top edge at this radius. + .background( + RoundedRectangle(cornerRadius: Layout.panelCornerRadius, style: .continuous) + .fill(Color.dash.secondaryBackground) + .padding(.bottom, -Layout.panelCornerRadius) + .ignoresSafeArea(edges: .bottom), + alignment: .top + ) } private var keyboardRowsView: some View { @@ -221,8 +245,8 @@ public struct NumericKeyboardView: View { @available(iOS 17, macOS 14, *) #Preview { - VStack { - Spacer() + ZStack { + Color.red.opacity(0.3) NumericKeyboardView( value: .constant(""), @@ -233,8 +257,6 @@ public struct NumericKeyboardView: View { inProgress: false, actionHandler: { print("Action button tapped") } ) - .padding(.horizontal, 20) - .background(.red.opacity(0.3)) } } diff --git a/Sources/DashUIKit/Foundation/Icon_DashUI.swift b/Sources/DashUIKit/Foundation/Icon_DashUI.swift index 3f5e278..a97588f 100644 --- a/Sources/DashUIKit/Foundation/Icon_DashUI.swift +++ b/Sources/DashUIKit/Foundation/Icon_DashUI.swift @@ -73,6 +73,23 @@ public enum DashIcon { case dashDex = "illustration-dash-dex" } + // MARK: - Features + /// `Features` + /// + /// The illustrated rows of an explainer sheet (`SheetFeature`). Several + /// come in a plain and a `-purple` variant — the plain one is tinted by + /// the caller, the purple one carries its own colour. + public enum Features: String, CaseIterable, DashIconAsset { + case identity = "feature-identity" + case instant = "feature-instant" + case platform = "feature-platform" + case platformPurple = "feature-platform-purple" + case shield = "feature-shield" + case shieldPurple = "feature-shield-purple" + case timer = "feature-timer" + case timerPurple = "feature-timer-purple" + } + // MARK: - Checkbox /// `Components/Checkbox` public enum Checkbox: String, CaseIterable, DashIconAsset { @@ -80,6 +97,22 @@ public enum DashIcon { case checkmarkUnchecked = "checkbox-checkmark-unchecked" } + // MARK: - SegmentedControl + /// `Segmented control` + /// + /// One arrow per direction, in that direction's colour, plus a grey + /// `-disabled` twin for the segment that is not selected. The colour is + /// in the artwork rather than applied at the call site, so a segment + /// switches file rather than tint when the selection moves. + public enum SegmentedControl: String, CaseIterable, DashIconAsset { + case receive = "segmented-control-receive" + case receiveDisabled = "segmented-control-receive-disabled" + case send = "segmented-control-send" + case sendDisabled = "segmented-control-send-disabled" + case transfer = "segmented-control-transfer" + case transferDisabled = "segmented-control-transfer-disabled" + } + // MARK: - SearchBar /// `Components/SearchBar` public enum SearchBar: String, CaseIterable, DashIconAsset { @@ -168,6 +201,7 @@ public enum DashIcon { case spendingConfirmation = "menu-spending-confirmation" case staking = "menu-staking" case support = "menu-support" + case swapDashCoin = "menu-swap-dash-coin" case tools = "menu-tools" case tools2 = "menu-tools-2" case topper = "menu-topper" diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-identity.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-identity.imageset/Contents.json new file mode 100644 index 0000000..e036d3b --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-identity.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "feature-identity.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "feature-identity@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "feature-identity@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-identity.imageset/feature-identity.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-identity.imageset/feature-identity.png new file mode 100644 index 0000000..2d1f21a Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-identity.imageset/feature-identity.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-identity.imageset/feature-identity@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-identity.imageset/feature-identity@2x.png new file mode 100644 index 0000000..5202957 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-identity.imageset/feature-identity@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-identity.imageset/feature-identity@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-identity.imageset/feature-identity@3x.png new file mode 100644 index 0000000..16702fc Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-identity.imageset/feature-identity@3x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-instant.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-instant.imageset/Contents.json new file mode 100644 index 0000000..3c64342 --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-instant.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "feature-instant.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "feature-instant@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "feature-instant@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-instant.imageset/feature-instant.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-instant.imageset/feature-instant.png new file mode 100644 index 0000000..9a6fd96 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-instant.imageset/feature-instant.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-instant.imageset/feature-instant@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-instant.imageset/feature-instant@2x.png new file mode 100644 index 0000000..21f7f0f Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-instant.imageset/feature-instant@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-instant.imageset/feature-instant@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-instant.imageset/feature-instant@3x.png new file mode 100644 index 0000000..22bf9f1 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-instant.imageset/feature-instant@3x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform-purple.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform-purple.imageset/Contents.json new file mode 100644 index 0000000..4b192b4 --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform-purple.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "feature-platform-purple.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "feature-platform-purple@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "feature-platform-purple@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform-purple.imageset/feature-platform-purple.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform-purple.imageset/feature-platform-purple.png new file mode 100644 index 0000000..3da58ea Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform-purple.imageset/feature-platform-purple.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform-purple.imageset/feature-platform-purple@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform-purple.imageset/feature-platform-purple@2x.png new file mode 100644 index 0000000..4fda13a Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform-purple.imageset/feature-platform-purple@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform-purple.imageset/feature-platform-purple@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform-purple.imageset/feature-platform-purple@3x.png new file mode 100644 index 0000000..03329d5 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform-purple.imageset/feature-platform-purple@3x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform.imageset/Contents.json new file mode 100644 index 0000000..c989bf6 --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "feature-platform.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "feature-platform@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "feature-platform@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform.imageset/feature-platform.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform.imageset/feature-platform.png new file mode 100644 index 0000000..28d7946 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform.imageset/feature-platform.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform.imageset/feature-platform@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform.imageset/feature-platform@2x.png new file mode 100644 index 0000000..4a56d8b Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform.imageset/feature-platform@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform.imageset/feature-platform@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform.imageset/feature-platform@3x.png new file mode 100644 index 0000000..14da13f Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-platform.imageset/feature-platform@3x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield-purple.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield-purple.imageset/Contents.json new file mode 100644 index 0000000..ab8214c --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield-purple.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "feature-shield-purple.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "feature-shield-purple@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "feature-shield-purple@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield-purple.imageset/feature-shield-purple.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield-purple.imageset/feature-shield-purple.png new file mode 100644 index 0000000..e88ade5 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield-purple.imageset/feature-shield-purple.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield-purple.imageset/feature-shield-purple@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield-purple.imageset/feature-shield-purple@2x.png new file mode 100644 index 0000000..603df0c Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield-purple.imageset/feature-shield-purple@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield-purple.imageset/feature-shield-purple@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield-purple.imageset/feature-shield-purple@3x.png new file mode 100644 index 0000000..af1d247 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield-purple.imageset/feature-shield-purple@3x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield.imageset/Contents.json new file mode 100644 index 0000000..b6b4eea --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "feature-shield.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "feature-shield@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "feature-shield@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield.imageset/feature-shield.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield.imageset/feature-shield.png new file mode 100644 index 0000000..b843d6a Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield.imageset/feature-shield.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield.imageset/feature-shield@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield.imageset/feature-shield@2x.png new file mode 100644 index 0000000..1820fbb Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield.imageset/feature-shield@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield.imageset/feature-shield@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield.imageset/feature-shield@3x.png new file mode 100644 index 0000000..9b394ce Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-shield.imageset/feature-shield@3x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer-purple.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer-purple.imageset/Contents.json new file mode 100644 index 0000000..fd8b195 --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer-purple.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "feature-timer-purple.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "feature-timer-purple@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "feature-timer-purple@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer-purple.imageset/feature-timer-purple.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer-purple.imageset/feature-timer-purple.png new file mode 100644 index 0000000..54824ed Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer-purple.imageset/feature-timer-purple.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer-purple.imageset/feature-timer-purple@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer-purple.imageset/feature-timer-purple@2x.png new file mode 100644 index 0000000..1a42d27 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer-purple.imageset/feature-timer-purple@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer-purple.imageset/feature-timer-purple@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer-purple.imageset/feature-timer-purple@3x.png new file mode 100644 index 0000000..3ff45c7 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer-purple.imageset/feature-timer-purple@3x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer.imageset/Contents.json new file mode 100644 index 0000000..f76355e --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "feature-timer.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "feature-timer@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "feature-timer@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer.imageset/feature-timer.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer.imageset/feature-timer.png new file mode 100644 index 0000000..7afaa7f Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer.imageset/feature-timer.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer.imageset/feature-timer@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer.imageset/feature-timer@2x.png new file mode 100644 index 0000000..a966e36 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer.imageset/feature-timer@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer.imageset/feature-timer@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer.imageset/feature-timer@3x.png new file mode 100644 index 0000000..dcf9508 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Features/feature-timer.imageset/feature-timer@3x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Icons/copy-outline.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Icons/copy-outline.imageset/Contents.json index 9204d47..e5e004d 100644 --- a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Icons/copy-outline.imageset/Contents.json +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Icons/copy-outline.imageset/Contents.json @@ -1,23 +1,56 @@ { - "images" : [ + "images": [ { - "filename" : "copy-outline.png", - "idiom" : "universal", - "scale" : "1x" + "filename": "copy-outline.png", + "idiom": "universal", + "scale": "1x" }, { - "filename" : "copy-outline@2x.png", - "idiom" : "universal", - "scale" : "2x" + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "filename": "copy-outline-dark.png", + "idiom": "universal", + "scale": "1x" }, { - "filename" : "copy-outline@3x.png", - "idiom" : "universal", - "scale" : "3x" + "filename": "copy-outline@2x.png", + "idiom": "universal", + "scale": "2x" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "filename": "copy-outline-dark@2x.png", + "idiom": "universal", + "scale": "2x" + }, + { + "filename": "copy-outline@3x.png", + "idiom": "universal", + "scale": "3x" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "filename": "copy-outline-dark@3x.png", + "idiom": "universal", + "scale": "3x" } ], - "info" : { - "author" : "xcode", - "version" : 1 + "info": { + "author": "xcode", + "version": 1 } -} +} \ No newline at end of file diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Icons/copy-outline.imageset/copy-outline-dark.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Icons/copy-outline.imageset/copy-outline-dark.png new file mode 100644 index 0000000..55aeaec Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Icons/copy-outline.imageset/copy-outline-dark.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Icons/copy-outline.imageset/copy-outline-dark@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Icons/copy-outline.imageset/copy-outline-dark@2x.png new file mode 100644 index 0000000..541907d Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Icons/copy-outline.imageset/copy-outline-dark@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Icons/copy-outline.imageset/copy-outline-dark@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Icons/copy-outline.imageset/copy-outline-dark@3x.png new file mode 100644 index 0000000..3e31c62 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Icons/copy-outline.imageset/copy-outline-dark@3x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Menu/menu-swap-dash-coin.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Menu/menu-swap-dash-coin.imageset/Contents.json new file mode 100644 index 0000000..f36027f --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Menu/menu-swap-dash-coin.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "menu-swap-dash-coin.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "menu-swap-dash-coin@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "menu-swap-dash-coin@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Menu/menu-swap-dash-coin.imageset/menu-swap-dash-coin.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Menu/menu-swap-dash-coin.imageset/menu-swap-dash-coin.png new file mode 100644 index 0000000..703703d Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Menu/menu-swap-dash-coin.imageset/menu-swap-dash-coin.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Menu/menu-swap-dash-coin.imageset/menu-swap-dash-coin@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Menu/menu-swap-dash-coin.imageset/menu-swap-dash-coin@2x.png new file mode 100644 index 0000000..e64c47f Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Menu/menu-swap-dash-coin.imageset/menu-swap-dash-coin@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Menu/menu-swap-dash-coin.imageset/menu-swap-dash-coin@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Menu/menu-swap-dash-coin.imageset/menu-swap-dash-coin@3x.png new file mode 100644 index 0000000..0898e21 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Menu/menu-swap-dash-coin.imageset/menu-swap-dash-coin@3x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive-disabled.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive-disabled.imageset/Contents.json new file mode 100644 index 0000000..f9ccdac --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive-disabled.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "segmented-control-receive-disabled.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "segmented-control-receive-disabled@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "segmented-control-receive-disabled@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive-disabled.imageset/segmented-control-receive-disabled.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive-disabled.imageset/segmented-control-receive-disabled.png new file mode 100644 index 0000000..42c0de5 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive-disabled.imageset/segmented-control-receive-disabled.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive-disabled.imageset/segmented-control-receive-disabled@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive-disabled.imageset/segmented-control-receive-disabled@2x.png new file mode 100644 index 0000000..57463d4 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive-disabled.imageset/segmented-control-receive-disabled@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive-disabled.imageset/segmented-control-receive-disabled@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive-disabled.imageset/segmented-control-receive-disabled@3x.png new file mode 100644 index 0000000..2e00ec8 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive-disabled.imageset/segmented-control-receive-disabled@3x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive.imageset/Contents.json new file mode 100644 index 0000000..2b49d76 --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "segmented-control-receive.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "segmented-control-receive@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "segmented-control-receive@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive.imageset/segmented-control-receive.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive.imageset/segmented-control-receive.png new file mode 100644 index 0000000..ade1738 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive.imageset/segmented-control-receive.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive.imageset/segmented-control-receive@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive.imageset/segmented-control-receive@2x.png new file mode 100644 index 0000000..a2a3eeb Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive.imageset/segmented-control-receive@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive.imageset/segmented-control-receive@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive.imageset/segmented-control-receive@3x.png new file mode 100644 index 0000000..8869156 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-receive.imageset/segmented-control-receive@3x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send-disabled.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send-disabled.imageset/Contents.json new file mode 100644 index 0000000..e75676e --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send-disabled.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "segmented-control-send-disabled.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "segmented-control-send-disabled@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "segmented-control-send-disabled@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send-disabled.imageset/segmented-control-send-disabled.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send-disabled.imageset/segmented-control-send-disabled.png new file mode 100644 index 0000000..cdee0ee Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send-disabled.imageset/segmented-control-send-disabled.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send-disabled.imageset/segmented-control-send-disabled@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send-disabled.imageset/segmented-control-send-disabled@2x.png new file mode 100644 index 0000000..b414309 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send-disabled.imageset/segmented-control-send-disabled@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send-disabled.imageset/segmented-control-send-disabled@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send-disabled.imageset/segmented-control-send-disabled@3x.png new file mode 100644 index 0000000..1e1b754 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send-disabled.imageset/segmented-control-send-disabled@3x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send.imageset/Contents.json new file mode 100644 index 0000000..d226017 --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "segmented-control-send.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "segmented-control-send@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "segmented-control-send@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send.imageset/segmented-control-send.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send.imageset/segmented-control-send.png new file mode 100644 index 0000000..2cae9d5 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send.imageset/segmented-control-send.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send.imageset/segmented-control-send@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send.imageset/segmented-control-send@2x.png new file mode 100644 index 0000000..a50ccff Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send.imageset/segmented-control-send@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send.imageset/segmented-control-send@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send.imageset/segmented-control-send@3x.png new file mode 100644 index 0000000..5e76990 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-send.imageset/segmented-control-send@3x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer-disabled.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer-disabled.imageset/Contents.json new file mode 100644 index 0000000..3b7f9c7 --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer-disabled.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "segmented-control-transfer-disabled.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "segmented-control-transfer-disabled@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "segmented-control-transfer-disabled@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer-disabled.imageset/segmented-control-transfer-disabled.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer-disabled.imageset/segmented-control-transfer-disabled.png new file mode 100644 index 0000000..2d46761 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer-disabled.imageset/segmented-control-transfer-disabled.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer-disabled.imageset/segmented-control-transfer-disabled@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer-disabled.imageset/segmented-control-transfer-disabled@2x.png new file mode 100644 index 0000000..1928d92 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer-disabled.imageset/segmented-control-transfer-disabled@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer-disabled.imageset/segmented-control-transfer-disabled@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer-disabled.imageset/segmented-control-transfer-disabled@3x.png new file mode 100644 index 0000000..7b87f3a Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer-disabled.imageset/segmented-control-transfer-disabled@3x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer.imageset/Contents.json b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer.imageset/Contents.json new file mode 100644 index 0000000..af0764e --- /dev/null +++ b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "segmented-control-transfer.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "segmented-control-transfer@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "segmented-control-transfer@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer.imageset/segmented-control-transfer.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer.imageset/segmented-control-transfer.png new file mode 100644 index 0000000..02225b8 Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer.imageset/segmented-control-transfer.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer.imageset/segmented-control-transfer@2x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer.imageset/segmented-control-transfer@2x.png new file mode 100644 index 0000000..5a2605f Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer.imageset/segmented-control-transfer@2x.png differ diff --git a/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer.imageset/segmented-control-transfer@3x.png b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer.imageset/segmented-control-transfer@3x.png new file mode 100644 index 0000000..ca2bf7a Binary files /dev/null and b/Sources/DashUIKit/Resources/Media.xcassets/Icons & Illustrations/Segmented control/segmented-control-transfer.imageset/segmented-control-transfer@3x.png differ diff --git a/docs/README.md b/docs/README.md index a41ec75..8ff032f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -23,7 +23,7 @@ and callbacks; they render and report intent. They require `import DashUIKit` an `NavigationBarElement`, `TopIntroView`, `BottomSheet`, `MenuViewModifier`. - **[Feedback](feedback.md)** — `Toast`, `SystemMessageView`, `LoadingIllustration` / `LoadingSpinner`, `SuccessIllustration`, `ErrorIllustration`, - `XmarkIcon`. + `XmarkIcon`, `CheckmarkIcon`, `ChevronIcon`, `InfoRoundIcon`. - **[Utilities](utilities.md)** — geometry readers (`readingFrame`, `readingLocation`), `ScrollViewWithOnScrollChanged`, `scaleToFitWidth`. @@ -32,6 +32,7 @@ and callbacks; they render and report intent. They require `import DashUIKit` an | Symbol | Page | |---|---| | `AddressFieldView` | [Buttons & inputs](buttons-and-inputs.md#addressfieldview) | +| `SheetFeature` | [Navigation & containers](navigation-and-containers.md#sheetfeature) | | `BottomSheet` | [Navigation & containers](navigation-and-containers.md#bottomsheet) | | `Bundle.dashUIKit` | [Foundation](foundation.md#bundle) | | `CoinSelector` | [Lists & rows](lists-and-rows.md#coinselector) | @@ -52,7 +53,7 @@ and callbacks; they render and report intent. They require `import DashUIKit` an | `ErrorIllustration` | [Feedback](feedback.md#successillustration--errorillustration) | | `List1View` | [Lists & rows](lists-and-rows.md#list1view) | | `LoadingIllustration` / `LoadingSpinner` | [Feedback](feedback.md#loadingillustration--loadingspinner) | -| `MenuItem` (`MenuItemAccessory`) | [Lists & rows](lists-and-rows.md#menuitem) | +| `MenuItem` (`MenuItemAccessory`, `MenuItemInfo`) | [Lists & rows](lists-and-rows.md#menuitem) | | `MenuViewModifier` | [Navigation & containers](navigation-and-containers.md#menuviewmodifier) | | `NavigationBar` / `NavigationBarElement` | [Navigation & containers](navigation-and-containers.md#navigationbar) | | `NumericKeyboardView` | [Buttons & inputs](buttons-and-inputs.md#numerickeyboardview) | @@ -69,3 +70,6 @@ and callbacks; they render and report intent. They require `import DashUIKit` an | `TopIntroView` | [Navigation & containers](navigation-and-containers.md#topintroview) | | `TransactionView` | [Lists & rows](lists-and-rows.md#transactionview) | | `XmarkIcon` | [Feedback](feedback.md#xmarkicon) | +| `CheckmarkIcon` | [Feedback](feedback.md#checkmarkicon) | +| `ChevronIcon` | [Feedback](feedback.md#chevronicon) | +| `InfoRoundIcon` | [Feedback](feedback.md#inforoundicon) | diff --git a/docs/feedback.md b/docs/feedback.md index cd08d4a..0702607 100644 --- a/docs/feedback.md +++ b/docs/feedback.md @@ -96,6 +96,25 @@ ErrorIllustration() --- +## InfoRoundIcon + +File `Components/Icons/InfoRoundIcon.swift` · `@available(iOS 14, macOS 11, *)` · public + +A code-drawn round "i" — a filled disc with a white glyph — for the "there is more to say +about this" affordance. Geometry is normalized from a 19×19 SVG, so stem and dot keep +their weight and position at any `size`. + +```swift +InfoRoundIcon() // 19pt, Blue disc +InfoRoundIcon(size: 20, color: Color.dash.gray300Alpha70) // muted, beside a menu title +``` + +The disc reads `Color.dash.blue` by default and the glyph `Color.dash.white`, so both +follow the palette instead of a baked-in hex. `MenuItem` renders it for +`MenuItemInfo.round`. + +--- + ## XmarkIcon File `Components/Icons/XmarkIcon.swift` · `@available(iOS 14, macOS 11, *)` · public @@ -112,3 +131,49 @@ XmarkIcon(size: 24, color: .white, lineWidth: 2) > `Shape`, it stays crisp at any `size` and honours `color` / `lineWidth`. The > asset remains the right choice where the navigation bar's exact artwork is > wanted. + +--- + +## CheckmarkIcon + +File `Components/Icons/CheckmarkIcon.swift` · `@available(iOS 14, macOS 11, *)` · public + +A code-drawn "✓" selection mark (a `Shape` stroking the polyline of a 15×12 SVG, round +caps and joins). Backs `MenuItemAccessory.selection`. + +```swift +CheckmarkIcon(size: 24, color: .white, lineWidth: 3) +``` + +> `size` sets the **width**; the height follows the source aspect ratio (12/15), unlike +> `XmarkIcon`, whose artwork is square. The default colour is `Color.dash.blue` — the +> token the source SVG's `#008DE4` corresponds to — so the mark follows the palette +> rather than a frozen hex. + +--- + +## ChevronIcon + +File `Components/Icons/ChevronIcon.swift` · `@available(iOS 14, macOS 11, *)` · public + +A code-drawn chevron, in any of the four directions (a `Shape` stroking the polyline of a +7×12 SVG, round caps and joins). `ConverterCard` puts one on every row that carries an +`onTap`, so a row that opens a picker reads as one at rest. + +```swift +ChevronIcon() // points right, 12pt tall +ChevronIcon(direction: .down, size: 16) +ChevronIcon(direction: .left, color: Color.dash.blue, lineWidth: 2) +``` + +| Property | Default | Notes | +| --- | --- | --- | +| `direction` | `.right` | `.right` / `.left` / `.up` / `.down` | +| `size` | `12` | The **long** side — height for left/right, width for up/down | +| `color` | `Color.dash.gray300Alpha90` | The palette entry for the source SVG's `#B0B6BC` at 90% | +| `lineWidth` | `1.6` | Source stroke width | + +> Only the `.right` chevron is drawn; the rest are that glyph rotated, so all four share one +> geometry and one line weight. The frame swaps axes with the rotation, so a `.up` / `.down` +> chevron measures wider than tall and lays out without a gap beside it. + diff --git a/docs/foundation.md b/docs/foundation.md index 86d0b34..fb0a41c 100644 --- a/docs/foundation.md +++ b/docs/foundation.md @@ -114,8 +114,13 @@ Bundled custom assets (under `Media.xcassets/Icons & Illustrations/`) include na (`navigationbar-back/close/plus/info`), search icons, currency glyphs (`icon_dash_currency`, `enter-amount-dash`, `chevron-down-currency-select`), checkbox icons, text-field icons (`text-field-qr`, `text-field-clear`), menu icons -(`menu-send/receive`, `support`, …), and illustrations (`illustration-dash-dex`, -`illustration-xmark`, `checkmark`, `crowdnode.warning`). +(`menu-send/receive`, `support`, …), explainer-sheet feature icons +(`feature-shield`, `feature-timer`, `feature-identity`, `feature-platform`, each +with a `-purple` variant where one exists), segmented-control arrows +(`segmented-control-receive/transfer/send`, each with a grey `-disabled` twin for +the unselected segment), and illustrations +(`illustration-dash-dex`, `illustration-xmark`, `checkmark`, +`crowdnode.warning`). --- diff --git a/docs/lists-and-rows.md b/docs/lists-and-rows.md index 4574a39..8db289b 100644 --- a/docs/lists-and-rows.md +++ b/docs/lists-and-rows.md @@ -38,7 +38,7 @@ is tappable when you wrap it in a `Button`. File `Components/MenuItem.swift` · `@available(iOS 14, macOS 11, *)` -A settings/menu row: optional leading icon, title with optional inline info icon, optional +A settings/menu row: optional leading icon, title with optional inline info glyph, optional help text, and a flexible trailing **accessory**. ```swift @@ -46,22 +46,31 @@ MenuItem( leadingIcon: .custom("menu-send", bundle: .dashUIKit), // DashIconSource? title: "Network fee", helpText: "Estimated cost for this transaction", - infoIcon: .system("info.circle"), + info: .round(color: Color.dash.gray300Alpha70), accessory: .text("0.0001 DASH") ) ``` +**`MenuItemInfo`** — the glyph beside the title, when the row has something to explain: + +- `.round(color: Color)` — the design system's `InfoRoundIcon`, recoloured to suit the row +- `.icon(DashIconSource)` — any other glyph + **`MenuItemAccessory`** — the trailing look (extend this enum rather than overriding per-call fonts/colors, to keep rows consistent): - `.none` -- `.toggle(isOn: Binding)` — a `Toggle` +- `.toggle(isOn: Binding)` — a `SwitchView` (the design system's switch, not the + system green `Toggle`); it takes the row's enabled state from the environment - `.text(String)` - `.button(DashButton)` — embed a `DashButton` - `.balance(dash: Int64, sign: DashAmountSign = .negativeOnly, fiat: String? = nil)` — a `DashAmount` (duffs) with an optional pre-formatted fiat sub-line. The fiat line is hidden for zero / `.max` / `.min` amounts. The library only renders the fiat string you pass — it does no conversion. +- `.selection(isSelected: Bool)` — a `CheckmarkIcon` on the chosen row of a picker list. + Unselected rows keep the mark's slot (drawn at zero opacity), so nothing shifts + horizontally as the selection moves. --- diff --git a/docs/navigation-and-containers.md b/docs/navigation-and-containers.md index 4d01b03..961e6ef 100644 --- a/docs/navigation-and-containers.md +++ b/docs/navigation-and-containers.md @@ -59,7 +59,7 @@ Use it for screen headers that sit above the main content rather than inside a n ## BottomSheet -File `Components/BottomSheet.swift` · `@available(iOS 14, macOS 11, *)` +File `Components/BottomSheet/BottomSheet.swift` · `@available(iOS 14, macOS 11, *)` Sheet chrome to put **inside** a SwiftUI `.sheet { }`: a grabber, a `NavigationBar` header (optional back button + title + close), and your content. Two height modes. @@ -114,6 +114,31 @@ home-indicator inset that `presentationDetents([.height])` adds back, so that st outside the sheet's own stack — without the presentation fill it shows the system background as a pale band along the bottom edge, whatever the content is styled with. +## SheetFeature + +File `Components/BottomSheet/SheetFeature.swift` · `@available(iOS 14, macOS 11, *)` · public + +One "here is what this gives you" line for a `BottomSheet`: an icon beside a name and a +sentence. Stack several to describe what a feature unlocks. + +```swift +SheetFeature( + title: "Identity", + description: "Register a username and be paid by name instead of an address.", + icon: .custom("feature-identity", bundle: .dashUIKit), + iconColor: Color.dash.purple) // omit to keep the asset's own colours + +SheetFeature(title: "Custom", description: "…") { // or any view in the slot + Circle().fill(Color.dash.blueAlpha10) +} +``` + +The icon slot is a `ViewBuilder`, not a `DashIconSource`, because the leading mark is not +always an image — a badge or a coloured container belongs there too. It is framed to 40×40 +so a column of features stays aligned whatever each row puts in it. The convenience initializer takes an optional `iconColor`: given one, the asset is drawn +as a template in that colour; omitted, it renders as authored — the only way an icon with +more than one colour keeps them, since a template flattens everything to a single tint. + --- ## MenuViewModifier