Add `redacted` modifier (#232)
This commit is contained in:
parent
4c654da456
commit
70d31b2e5b
|
@ -37,6 +37,8 @@
|
|||
B56F22E424BD1C26001738DF /* GridDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56F22E224BD1C26001738DF /* GridDemo.swift */; };
|
||||
B5C76E4A24C73ED5003EABB2 /* AppStorageDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C76E4924C73ED4003EABB2 /* AppStorageDemo.swift */; };
|
||||
B5C76E4B24C73ED5003EABB2 /* AppStorageDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C76E4924C73ED4003EABB2 /* AppStorageDemo.swift */; };
|
||||
B5DBA22B24D509B4003D3347 /* RedactDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5DBA22A24D509B4003D3347 /* RedactDemo.swift */; };
|
||||
B5DBA22C24D509B4003D3347 /* RedactDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5DBA22A24D509B4003D3347 /* RedactDemo.swift */; };
|
||||
D1B4229024B3B9BB00682F74 /* ListDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1B4228E24B3B9BB00682F74 /* ListDemo.swift */; };
|
||||
D1B4229124B3B9BB00682F74 /* ListDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1B4228E24B3B9BB00682F74 /* ListDemo.swift */; };
|
||||
D1B4229224B3B9BB00682F74 /* OutlineGroupDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1B4228F24B3B9BB00682F74 /* OutlineGroupDemo.swift */; };
|
||||
|
@ -101,6 +103,7 @@
|
|||
B56F22DF24BC89FD001738DF /* ColorDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = ColorDemo.swift; sourceTree = "<group>"; tabWidth = 2; };
|
||||
B56F22E224BD1C26001738DF /* GridDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GridDemo.swift; sourceTree = "<group>"; };
|
||||
B5C76E4924C73ED4003EABB2 /* AppStorageDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppStorageDemo.swift; sourceTree = "<group>"; };
|
||||
B5DBA22A24D509B4003D3347 /* RedactDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RedactDemo.swift; sourceTree = "<group>"; };
|
||||
D1B4228E24B3B9BB00682F74 /* ListDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListDemo.swift; sourceTree = "<group>"; };
|
||||
D1B4228F24B3B9BB00682F74 /* OutlineGroupDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutlineGroupDemo.swift; sourceTree = "<group>"; };
|
||||
D1C726F224CB63C6003B576D /* ButtonStyleDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonStyleDemo.swift; sourceTree = "<group>"; };
|
||||
|
@ -176,6 +179,7 @@
|
|||
D1B4228F24B3B9BB00682F74 /* OutlineGroupDemo.swift */,
|
||||
B51F214F24B920B400CF2583 /* PathDemo.swift */,
|
||||
D1EE7EA624C0DD2100C0D127 /* PickerDemo.swift */,
|
||||
B5DBA22A24D509B4003D3347 /* RedactDemo.swift */,
|
||||
3DCDE44324CA6AD400910F17 /* SidebarDemo.swift */,
|
||||
85ED189A24AD425E0085DFA0 /* SpacerDemo.swift */,
|
||||
85ED189B24AD425E0085DFA0 /* TextDemo.swift */,
|
||||
|
@ -328,6 +332,7 @@
|
|||
85ED186A24AD38F20085DFA0 /* UIAppDelegate.swift in Sources */,
|
||||
B56F22E324BD1C26001738DF /* GridDemo.swift in Sources */,
|
||||
D1B4229224B3B9BB00682F74 /* OutlineGroupDemo.swift in Sources */,
|
||||
B5DBA22B24D509B4003D3347 /* RedactDemo.swift in Sources */,
|
||||
B56F22E024BC89FD001738DF /* ColorDemo.swift in Sources */,
|
||||
B51F215024B920B400CF2583 /* PathDemo.swift in Sources */,
|
||||
85ED18AF24AD425E0085DFA0 /* EnvironmentDemo.swift in Sources */,
|
||||
|
@ -353,6 +358,7 @@
|
|||
85ED18AA24AD425E0085DFA0 /* TokamakDemo.swift in Sources */,
|
||||
B56F22E424BD1C26001738DF /* GridDemo.swift in Sources */,
|
||||
D1B4229324B3B9BB00682F74 /* OutlineGroupDemo.swift in Sources */,
|
||||
B5DBA22C24D509B4003D3347 /* RedactDemo.swift in Sources */,
|
||||
B56F22E124BC89FD001738DF /* ColorDemo.swift in Sources */,
|
||||
B51F215124B920B400CF2583 /* PathDemo.swift in Sources */,
|
||||
85ED18A424AD425E0085DFA0 /* SpacerDemo.swift in Sources */,
|
||||
|
@ -515,8 +521,8 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = 288H3WAR3W;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = "iOS Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
|
@ -524,7 +530,9 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "dev.tokamak.Tokamak-Native";
|
||||
PRODUCT_NAME = "TokamakDemo Native";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
@ -537,8 +545,8 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = 288H3WAR3W;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = "iOS Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
|
@ -546,7 +554,9 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "dev.tokamak.Tokamak-Native";
|
||||
PRODUCT_NAME = "TokamakDemo Native";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
|
@ -560,7 +570,7 @@
|
|||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
|
@ -570,7 +580,9 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "dev.tokamak.Tokamak-Native";
|
||||
PRODUCT_NAME = "TokamakDemo Native";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = macosx;
|
||||
SUPPORTED_PLATFORMS = macosx;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
|
@ -584,9 +596,9 @@
|
|||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = 288H3WAR3W;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
|
@ -594,7 +606,9 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "dev.tokamak.Tokamak-Native";
|
||||
PRODUCT_NAME = "TokamakDemo Native";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = macosx;
|
||||
SUPPORTED_PLATFORMS = macosx;
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2020 Tokamak contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Created by Carson Katri on 7/31/20.
|
||||
//
|
||||
|
||||
public struct RedactionReasons: OptionSet {
|
||||
public let rawValue: Int
|
||||
public init(rawValue: Int) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
public static let placeholder: Self = .init(rawValue: 1 << 0)
|
||||
}
|
||||
|
||||
extension View {
|
||||
public func redacted(reason: RedactionReasons) -> some View {
|
||||
environment(\.redactionReasons, reason)
|
||||
}
|
||||
|
||||
public func unredacted() -> some View {
|
||||
environment(\.redactionReasons, [])
|
||||
}
|
||||
}
|
||||
|
||||
private struct RedactionReasonsKey: EnvironmentKey {
|
||||
static let defaultValue: RedactionReasons = []
|
||||
}
|
||||
|
||||
extension EnvironmentValues {
|
||||
public var redactionReasons: RedactionReasons {
|
||||
get {
|
||||
self[RedactionReasonsKey.self]
|
||||
}
|
||||
set {
|
||||
self[RedactionReasonsKey.self] = newValue
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,6 +35,7 @@ public struct Text: View {
|
|||
|
||||
@Environment(\.font) var font
|
||||
@Environment(\.foregroundColor) var foregroundColor
|
||||
@Environment(\.redactionReasons) var redactionReasons
|
||||
|
||||
public enum _Storage {
|
||||
case verbatim(String)
|
||||
|
@ -103,6 +104,8 @@ public struct _TextProxy {
|
|||
.color(subject.foregroundColor),
|
||||
] + subject.modifiers
|
||||
}
|
||||
|
||||
public var redactionReasons: RedactionReasons { subject.redactionReasons }
|
||||
}
|
||||
|
||||
public extension Text {
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright 2020 Tokamak contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Created by Carson Katri on 7/31/20.
|
||||
//
|
||||
|
||||
import TokamakShim
|
||||
|
||||
@available(OSX 11.0, iOS 14.0, *)
|
||||
struct RedactDemo: View {
|
||||
func title(_ text: String) -> some View {
|
||||
Group {
|
||||
Text(text)
|
||||
.font(.headline)
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
|
||||
var content: some View {
|
||||
VStack {
|
||||
Text("Hello, world!")
|
||||
Text("Unredacted text")
|
||||
.unredacted()
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
VStack {
|
||||
title("Unredacted")
|
||||
content
|
||||
.padding()
|
||||
}
|
||||
VStack {
|
||||
title("Redacted")
|
||||
content
|
||||
.redacted(reason: .placeholder)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -87,6 +87,14 @@ var appStorageDemo: NavItem {
|
|||
}
|
||||
}
|
||||
|
||||
var redactDemo: NavItem {
|
||||
if #available(OSX 11.0, iOS 14.0, *) {
|
||||
return NavItem("Redact", destination: RedactDemo())
|
||||
} else {
|
||||
return NavItem(unavailable: "Redact")
|
||||
}
|
||||
}
|
||||
|
||||
var links: [NavItem] {
|
||||
[
|
||||
NavItem("Counter", destination:
|
||||
|
@ -115,6 +123,7 @@ var links: [NavItem] {
|
|||
NavItem("Color", destination: ColorDemo()),
|
||||
appStorageDemo,
|
||||
gridDemo,
|
||||
redactDemo,
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,19 @@ public let tokamakStyles = """
|
|||
padding: 0;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
._tokamak-text-redacted {
|
||||
position: relative;
|
||||
}
|
||||
._tokamak-text-redacted::after {
|
||||
content: " ";
|
||||
background-color: rgb(200, 200, 200);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: calc(100% + .1em);
|
||||
height: 1.2em;
|
||||
border-radius: .1em;
|
||||
}
|
||||
"""
|
||||
|
||||
public let rootNodeStyles = """
|
||||
|
|
|
@ -103,6 +103,9 @@ extension Text: AnyHTML {
|
|||
|
||||
public var tag: String { "span" }
|
||||
public var attributes: [String: String] {
|
||||
let proxy = _TextProxy(self)
|
||||
let isRedacted = proxy.redactionReasons.contains(.placeholder)
|
||||
|
||||
var font: Font?
|
||||
var color: Color?
|
||||
var italic: Bool = false
|
||||
|
@ -111,7 +114,7 @@ extension Text: AnyHTML {
|
|||
var baseline: CGFloat?
|
||||
var strikethrough: (Bool, Color?)?
|
||||
var underline: (Bool, Color?)?
|
||||
for modifier in _TextProxy(self).modifiers {
|
||||
for modifier in proxy.modifiers {
|
||||
switch modifier {
|
||||
case let .color(_color):
|
||||
color = _color
|
||||
|
@ -137,6 +140,7 @@ extension Text: AnyHTML {
|
|||
let textDecoration = !hasStrikethrough && !hasUnderline ?
|
||||
"none" :
|
||||
"\(hasStrikethrough ? "line-through" : "") \(hasUnderline ? "underline" : "")"
|
||||
|
||||
return [
|
||||
"style": """
|
||||
\(font?.styles.filter {
|
||||
|
@ -156,6 +160,7 @@ extension Text: AnyHTML {
|
|||
text-decoration-color: \(strikethrough?.1?.description ?? underline?.1?.description
|
||||
?? "inherit")
|
||||
""",
|
||||
"class": isRedacted ? "_tokamak-text-redacted" : "",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue