@astryxdesign/native 0.7.5-canary.7e855c0 → 0.7.5-canary.85e48a0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apple/README.md +3 -5
- package/apple/Sources/Astryx/Card/Card.swift +93 -20
- package/apple/Sources/Astryx/Theme/Generated/ButterTheme.swift +10 -0
- package/apple/Sources/Astryx/Theme/Generated/ChocolateTheme.swift +10 -0
- package/apple/Sources/Astryx/Theme/Generated/DefaultTheme.swift +10 -0
- package/apple/Sources/Astryx/Theme/Generated/GothicTheme.swift +10 -0
- package/apple/Sources/Astryx/Theme/Generated/MatchaTheme.swift +10 -0
- package/apple/Sources/Astryx/Theme/Generated/NeutralTheme.swift +10 -0
- package/apple/Sources/Astryx/Theme/Generated/StoneTheme.swift +10 -0
- package/apple/Sources/Astryx/Theme/Generated/Tokens.swift +57 -1
- package/apple/Sources/Astryx/Theme/Generated/Y2kTheme.swift +10 -0
- package/apple/Sources/Astryx/Theme/Shadow.swift +39 -0
- package/apple/Sources/Astryx/Tooltip/TooltipPresenter.swift +511 -0
- package/apple/Sources/Astryx/Wire/AstryxNodeView.swift +75 -0
- package/apple/Tests/AstryxTests/CardTests.swift +116 -1
- package/apple/Tests/AstryxTests/TooltipPresenterTests.swift +160 -0
- package/package.json +3 -3
- package/src/theme/swiftIOSTheme.test.ts +28 -3
package/apple/README.md
CHANGED
|
@@ -51,17 +51,15 @@ apple/
|
|
|
51
51
|
that also imports SwiftUI, write `Astryx.Button` and `SwiftUI.Button`. A
|
|
52
52
|
component's parameters use core's prop names
|
|
53
53
|
and values (`variant: .primary`, `size: .lg`, `isLoading`), so code reads
|
|
54
|
-
the same across web and native. `Text` and `
|
|
55
|
-
`TextProps` and `
|
|
56
|
-
exceptions, the interim shape FR5 exempts until they move onto the generated
|
|
54
|
+
the same across web and native. `Text`, `Heading`, and `Card` take the
|
|
55
|
+
generated `TextProps`, `HeadingProps`, and `CardProps`, as AST-093 FR5 asks;
|
|
56
|
+
the others keep four exceptions, the interim shape FR5 exempts until they move onto the generated
|
|
57
57
|
contracts:
|
|
58
58
|
- `Button` takes `action` where core has `onClick`.
|
|
59
59
|
- `Button` takes `fillsWidth` where core has `width="100%"`.
|
|
60
60
|
- `Button` takes `icon` as a shared icon name (`"search"`), which the
|
|
61
61
|
generated `ButtonProps` does not carry yet.
|
|
62
62
|
- `TextInput` takes a `Binding` where core has `value` and `onChange`.
|
|
63
|
-
- `Card` takes `padding` as a whole spacing step, so it cannot spell
|
|
64
|
-
core's `0.5` and `1.5` steps.
|
|
65
63
|
- **`Templates/`** holds one folder per page template, named after the
|
|
66
64
|
`astryx template` id. Templates are clone-only, as on the web: you copy a
|
|
67
65
|
template's folder into your app and own it from then on. They are a
|
|
@@ -1,33 +1,106 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
///
|
|
6
|
-
/// border and the container radius.
|
|
3
|
+
/// A card: one independent item on the theme's card ground. It takes core's
|
|
4
|
+
/// Card props (`CardProps`) and stacks its content top to bottom, as children
|
|
5
|
+
/// flow inside core's Card.
|
|
7
6
|
public struct Card<Content: View>: View {
|
|
8
|
-
let
|
|
7
|
+
public let props: CardProps
|
|
9
8
|
let content: Content
|
|
10
9
|
@Environment(\.astryx) private var astryx
|
|
11
10
|
|
|
12
|
-
/// -
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
/// - Parameters:
|
|
12
|
+
/// - padding: core's `padding`, a step on the spacing scale; step 4 when
|
|
13
|
+
/// nil.
|
|
14
|
+
/// - variant: core's `variant`: the card ground, or `transparent` for none.
|
|
15
|
+
/// Only `default` draws a border.
|
|
16
|
+
/// - elevation: core's `elevation`, the theme's shadow at that depth.
|
|
17
|
+
/// - base: core's base props.
|
|
18
|
+
/// - content: core's `children`.
|
|
19
|
+
public init(
|
|
20
|
+
padding: CardPadding? = nil,
|
|
21
|
+
variant: CardVariant? = nil,
|
|
22
|
+
elevation: CardElevation? = nil,
|
|
23
|
+
base: AstryxBaseProps = AstryxBaseProps(),
|
|
24
|
+
@ViewBuilder content: () -> Content
|
|
25
|
+
) {
|
|
26
|
+
self.props = CardProps(padding: padding, variant: variant, elevation: elevation, base: base)
|
|
15
27
|
self.content = content()
|
|
16
28
|
}
|
|
17
29
|
|
|
18
30
|
public var body: some View {
|
|
19
|
-
let shape = RoundedRectangle(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
VStack(alignment: .leading, spacing: 0) { content }
|
|
26
|
-
.padding(astryx.space(padding))
|
|
31
|
+
let shape = RoundedRectangle(cornerRadius: astryx.tokens.radius.container, style: .continuous)
|
|
32
|
+
let variant = props.variant ?? .default
|
|
33
|
+
// The border sits inside the padding, so the content's inset is the
|
|
34
|
+
// padding step, as in core.
|
|
35
|
+
SwiftUI.VStack(alignment: .leading, spacing: 0) { content }
|
|
36
|
+
.padding(padding)
|
|
27
37
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
28
|
-
.background(shape.fill(astryx.color
|
|
29
|
-
.overlay
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
.background(shape.fill(Self.ground(variant, astryx.tokens.color)))
|
|
39
|
+
.overlay {
|
|
40
|
+
if variant == .default {
|
|
41
|
+
shape.strokeBorder(astryx.tokens.color.border, lineWidth: astryx.tokens.size.borderWidth)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
.astryxShadow(Self.shadow(props.elevation ?? .none, astryx.tokens.shadow), in: shape)
|
|
45
|
+
.astryxBase(props.base)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
var padding: CGFloat {
|
|
49
|
+
let space = astryx.tokens.space
|
|
50
|
+
switch props.padding ?? .v4 {
|
|
51
|
+
case .v0: return space.s0
|
|
52
|
+
case .v0_5: return space.s0_5
|
|
53
|
+
case .v1: return space.s1
|
|
54
|
+
case .v1_5: return space.s1_5
|
|
55
|
+
case .v2: return space.s2
|
|
56
|
+
case .v3: return space.s3
|
|
57
|
+
case .v4: return space.s4
|
|
58
|
+
case .v5: return space.s5
|
|
59
|
+
case .v6: return space.s6
|
|
60
|
+
case .v8: return space.s8
|
|
61
|
+
case .v10: return space.s10
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// The ground core's Card draws for a variant.
|
|
66
|
+
static func ground(_ variant: CardVariant, _ color: ColorTokens) -> Color {
|
|
67
|
+
switch variant {
|
|
68
|
+
case .default: color.backgroundCard
|
|
69
|
+
case .transparent: .clear
|
|
70
|
+
case .muted: color.backgroundMuted
|
|
71
|
+
case .blue: color.backgroundBlue
|
|
72
|
+
case .cyan: color.backgroundCyan
|
|
73
|
+
case .gray: color.backgroundGray
|
|
74
|
+
case .green: color.backgroundGreen
|
|
75
|
+
case .orange: color.backgroundOrange
|
|
76
|
+
case .pink: color.backgroundPink
|
|
77
|
+
case .purple: color.backgroundPurple
|
|
78
|
+
case .red: color.backgroundRed
|
|
79
|
+
case .teal: color.backgroundTeal
|
|
80
|
+
case .yellow: color.backgroundYellow
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/// The theme's shadow at an elevation.
|
|
85
|
+
static func shadow(_ elevation: CardElevation, _ shadow: ShadowTokens) -> [ShadowLayer] {
|
|
86
|
+
switch elevation {
|
|
87
|
+
case .none: []
|
|
88
|
+
case .low: shadow.low
|
|
89
|
+
case .med: shadow.med
|
|
90
|
+
case .high: shadow.high
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
extension Card where Content == AstryxNodeList {
|
|
96
|
+
/// A card from core's props, with its children as the wire tree a logic
|
|
97
|
+
/// core sends; `send` carries the children's callbacks back to the core.
|
|
98
|
+
public init(
|
|
99
|
+
_ props: CardProps,
|
|
100
|
+
children: [AstryxNode],
|
|
101
|
+
send: @escaping @Sendable (AstryxAction) -> Void
|
|
102
|
+
) {
|
|
103
|
+
self.props = props
|
|
104
|
+
self.content = AstryxNodeList(nodes: children, send: send)
|
|
32
105
|
}
|
|
33
106
|
}
|
|
@@ -214,6 +214,11 @@ extension Theme {
|
|
|
214
214
|
size: FontSizeTokens(base: 14, lg: 18, s2xl: 27, s2xs: 7, s3xl: 34, s3xs: 6, s4xl: 43, s4xs: 5, s5xl: 53, sm: 11, xl: 22, xs: 9),
|
|
215
215
|
supporting: TypeStyleTokens(size: 12, weight: 400, leading: 1.4545),
|
|
216
216
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
217
|
+
),
|
|
218
|
+
shadow: ShadowTokens(
|
|
219
|
+
high: [ShadowLayer(x: 0, y: 4, blur: 6, color: Color(astryxRGBA: 0x1D1C111A)), ShadowLayer(x: 0, y: 12, blur: 24, color: Color(astryxRGBA: 0x1D1C1126))],
|
|
220
|
+
low: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x1D1C110D)), ShadowLayer(x: 0, y: 4, blur: 8, color: Color(astryxRGBA: 0x1D1C111A))],
|
|
221
|
+
med: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x1D1C110D)), ShadowLayer(x: 0, y: 4, blur: 12, color: Color(astryxRGBA: 0x1D1C111A))]
|
|
217
222
|
)
|
|
218
223
|
),
|
|
219
224
|
dark: Tokens(
|
|
@@ -423,6 +428,11 @@ extension Theme {
|
|
|
423
428
|
size: FontSizeTokens(base: 14, lg: 18, s2xl: 27, s2xs: 7, s3xl: 34, s3xs: 6, s4xl: 43, s4xs: 5, s5xl: 53, sm: 11, xl: 22, xs: 9),
|
|
424
429
|
supporting: TypeStyleTokens(size: 12, weight: 400, leading: 1.4545),
|
|
425
430
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
431
|
+
),
|
|
432
|
+
shadow: ShadowTokens(
|
|
433
|
+
high: [ShadowLayer(x: 0, y: 4, blur: 6, color: Color(astryxRGBA: 0x1D1C111A)), ShadowLayer(x: 0, y: 12, blur: 24, color: Color(astryxRGBA: 0x1D1C1126))],
|
|
434
|
+
low: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x1D1C110D)), ShadowLayer(x: 0, y: 4, blur: 8, color: Color(astryxRGBA: 0x1D1C111A))],
|
|
435
|
+
med: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x1D1C110D)), ShadowLayer(x: 0, y: 4, blur: 12, color: Color(astryxRGBA: 0x1D1C111A))]
|
|
426
436
|
)
|
|
427
437
|
)
|
|
428
438
|
)
|
|
@@ -214,6 +214,11 @@ extension Theme {
|
|
|
214
214
|
size: FontSizeTokens(base: 14, lg: 17, s2xl: 24, s2xs: 8, s3xl: 29, s3xs: 7, s4xl: 35, s4xs: 6, s5xl: 42, sm: 12, xl: 20, xs: 10),
|
|
215
215
|
supporting: TypeStyleTokens(size: 12, weight: 400, leading: 1.6667),
|
|
216
216
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
217
|
+
),
|
|
218
|
+
shadow: ShadowTokens(
|
|
219
|
+
high: [ShadowLayer(x: 0, y: 4, blur: 6, color: Color(astryxRGBA: 0x4A35201A)), ShadowLayer(x: 0, y: 12, blur: 24, color: Color(astryxRGBA: 0x4A352026))],
|
|
220
|
+
low: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x4A35200D)), ShadowLayer(x: 0, y: 4, blur: 8, color: Color(astryxRGBA: 0x4A35201A))],
|
|
221
|
+
med: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x4A35200D)), ShadowLayer(x: 0, y: 4, blur: 12, color: Color(astryxRGBA: 0x4A35201A))]
|
|
217
222
|
)
|
|
218
223
|
),
|
|
219
224
|
dark: Tokens(
|
|
@@ -423,6 +428,11 @@ extension Theme {
|
|
|
423
428
|
size: FontSizeTokens(base: 14, lg: 17, s2xl: 24, s2xs: 8, s3xl: 29, s3xs: 7, s4xl: 35, s4xs: 6, s5xl: 42, sm: 12, xl: 20, xs: 10),
|
|
424
429
|
supporting: TypeStyleTokens(size: 12, weight: 400, leading: 1.6667),
|
|
425
430
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
431
|
+
),
|
|
432
|
+
shadow: ShadowTokens(
|
|
433
|
+
high: [ShadowLayer(x: 0, y: 4, blur: 6, color: Color(astryxRGBA: 0x4A35201A)), ShadowLayer(x: 0, y: 12, blur: 24, color: Color(astryxRGBA: 0x4A352026))],
|
|
434
|
+
low: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x4A35200D)), ShadowLayer(x: 0, y: 4, blur: 8, color: Color(astryxRGBA: 0x4A35201A))],
|
|
435
|
+
med: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x4A35200D)), ShadowLayer(x: 0, y: 4, blur: 12, color: Color(astryxRGBA: 0x4A35201A))]
|
|
426
436
|
)
|
|
427
437
|
)
|
|
428
438
|
)
|
|
@@ -214,6 +214,11 @@ extension Theme {
|
|
|
214
214
|
size: FontSizeTokens(base: 14, lg: 17, s2xl: 24, s2xs: 8, s3xl: 29, s3xs: 7, s4xl: 35, s4xs: 6, s5xl: 42, sm: 12, xl: 20, xs: 10),
|
|
215
215
|
supporting: TypeStyleTokens(size: 12, weight: 400, leading: 1.6667),
|
|
216
216
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
217
|
+
),
|
|
218
|
+
shadow: ShadowTokens(
|
|
219
|
+
high: [ShadowLayer(x: 0, y: 2, blur: 2, color: Color(astryxRGBA: 0x0000001A)), ShadowLayer(x: 0, y: 8, blur: 24, color: Color(astryxRGBA: 0x0000001A))],
|
|
220
|
+
low: [ShadowLayer(x: 0, y: 1, blur: 1, color: Color(astryxRGBA: 0x0000001A)), ShadowLayer(x: 0, y: 2, blur: 8, color: Color(astryxRGBA: 0x0000001A))],
|
|
221
|
+
med: [ShadowLayer(x: 0, y: 1, blur: 2, color: Color(astryxRGBA: 0x0000001A)), ShadowLayer(x: 0, y: 2, blur: 12, color: Color(astryxRGBA: 0x0000001A))]
|
|
217
222
|
)
|
|
218
223
|
),
|
|
219
224
|
dark: Tokens(
|
|
@@ -423,6 +428,11 @@ extension Theme {
|
|
|
423
428
|
size: FontSizeTokens(base: 14, lg: 17, s2xl: 24, s2xs: 8, s3xl: 29, s3xs: 7, s4xl: 35, s4xs: 6, s5xl: 42, sm: 12, xl: 20, xs: 10),
|
|
424
429
|
supporting: TypeStyleTokens(size: 12, weight: 400, leading: 1.6667),
|
|
425
430
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
431
|
+
),
|
|
432
|
+
shadow: ShadowTokens(
|
|
433
|
+
high: [ShadowLayer(x: 0, y: 2, blur: 2, color: Color(astryxRGBA: 0x00000033)), ShadowLayer(x: 0, y: 8, blur: 24, color: Color(astryxRGBA: 0x0000004D))],
|
|
434
|
+
low: [ShadowLayer(x: 0, y: 1, blur: 1, color: Color(astryxRGBA: 0x00000033)), ShadowLayer(x: 0, y: 2, blur: 8, color: Color(astryxRGBA: 0x00000033))],
|
|
435
|
+
med: [ShadowLayer(x: 0, y: 1, blur: 2, color: Color(astryxRGBA: 0x00000033)), ShadowLayer(x: 0, y: 2, blur: 12, color: Color(astryxRGBA: 0x00000033))]
|
|
426
436
|
)
|
|
427
437
|
)
|
|
428
438
|
)
|
|
@@ -214,6 +214,11 @@ extension Theme {
|
|
|
214
214
|
size: FontSizeTokens(base: 16, lg: 20, s2xl: 31, s2xs: 8, s3xl: 39, s3xs: 7, s4xl: 49, s4xs: 5, s5xl: 61, sm: 13, xl: 25, xs: 10),
|
|
215
215
|
supporting: TypeStyleTokens(size: 13, weight: 400, leading: 1.5385),
|
|
216
216
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
217
|
+
),
|
|
218
|
+
shadow: ShadowTokens(
|
|
219
|
+
high: [ShadowLayer(x: 0, y: 4, blur: 6, color: Color(astryxRGBA: 0x00000040)), ShadowLayer(x: 0, y: 12, blur: 24, color: Color(astryxRGBA: 0x0000004D))],
|
|
220
|
+
low: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x00000033)), ShadowLayer(x: 0, y: 4, blur: 8, color: Color(astryxRGBA: 0x00000040))],
|
|
221
|
+
med: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x00000033)), ShadowLayer(x: 0, y: 4, blur: 12, color: Color(astryxRGBA: 0x00000040))]
|
|
217
222
|
)
|
|
218
223
|
),
|
|
219
224
|
dark: Tokens(
|
|
@@ -423,6 +428,11 @@ extension Theme {
|
|
|
423
428
|
size: FontSizeTokens(base: 16, lg: 20, s2xl: 31, s2xs: 8, s3xl: 39, s3xs: 7, s4xl: 49, s4xs: 5, s5xl: 61, sm: 13, xl: 25, xs: 10),
|
|
424
429
|
supporting: TypeStyleTokens(size: 13, weight: 400, leading: 1.5385),
|
|
425
430
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
431
|
+
),
|
|
432
|
+
shadow: ShadowTokens(
|
|
433
|
+
high: [ShadowLayer(x: 0, y: 4, blur: 6, color: Color(astryxRGBA: 0x00000040)), ShadowLayer(x: 0, y: 12, blur: 24, color: Color(astryxRGBA: 0x0000004D))],
|
|
434
|
+
low: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x00000033)), ShadowLayer(x: 0, y: 4, blur: 8, color: Color(astryxRGBA: 0x00000040))],
|
|
435
|
+
med: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x00000033)), ShadowLayer(x: 0, y: 4, blur: 12, color: Color(astryxRGBA: 0x00000040))]
|
|
426
436
|
)
|
|
427
437
|
)
|
|
428
438
|
)
|
|
@@ -214,6 +214,11 @@ extension Theme {
|
|
|
214
214
|
size: FontSizeTokens(base: 16, lg: 20, s2xl: 31, s2xs: 8, s3xl: 39, s3xs: 7, s4xl: 49, s4xs: 5, s5xl: 61, sm: 13, xl: 25, xs: 10),
|
|
215
215
|
supporting: TypeStyleTokens(size: 13, weight: 400, leading: 1.5385),
|
|
216
216
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
217
|
+
),
|
|
218
|
+
shadow: ShadowTokens(
|
|
219
|
+
high: [ShadowLayer(x: 0, y: 4, blur: 6, color: Color(astryxRGBA: 0x3E481D1A)), ShadowLayer(x: 0, y: 12, blur: 24, color: Color(astryxRGBA: 0x3E481D26))],
|
|
220
|
+
low: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x3E481D0D)), ShadowLayer(x: 0, y: 4, blur: 8, color: Color(astryxRGBA: 0x3E481D1A))],
|
|
221
|
+
med: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x3E481D0D)), ShadowLayer(x: 0, y: 4, blur: 12, color: Color(astryxRGBA: 0x3E481D1A))]
|
|
217
222
|
)
|
|
218
223
|
),
|
|
219
224
|
dark: Tokens(
|
|
@@ -423,6 +428,11 @@ extension Theme {
|
|
|
423
428
|
size: FontSizeTokens(base: 16, lg: 20, s2xl: 31, s2xs: 8, s3xl: 39, s3xs: 7, s4xl: 49, s4xs: 5, s5xl: 61, sm: 13, xl: 25, xs: 10),
|
|
424
429
|
supporting: TypeStyleTokens(size: 13, weight: 400, leading: 1.5385),
|
|
425
430
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
431
|
+
),
|
|
432
|
+
shadow: ShadowTokens(
|
|
433
|
+
high: [ShadowLayer(x: 0, y: 4, blur: 6, color: Color(astryxRGBA: 0x3E481D1A)), ShadowLayer(x: 0, y: 12, blur: 24, color: Color(astryxRGBA: 0x3E481D26))],
|
|
434
|
+
low: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x3E481D0D)), ShadowLayer(x: 0, y: 4, blur: 8, color: Color(astryxRGBA: 0x3E481D1A))],
|
|
435
|
+
med: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x3E481D0D)), ShadowLayer(x: 0, y: 4, blur: 12, color: Color(astryxRGBA: 0x3E481D1A))]
|
|
426
436
|
)
|
|
427
437
|
)
|
|
428
438
|
)
|
|
@@ -214,6 +214,11 @@ extension Theme {
|
|
|
214
214
|
size: FontSizeTokens(base: 14, lg: 17, s2xl: 24, s2xs: 8, s3xl: 29, s3xs: 7, s4xl: 35, s4xs: 6, s5xl: 42, sm: 12, xl: 20, xs: 10),
|
|
215
215
|
supporting: TypeStyleTokens(size: 12, weight: 400, leading: 1.6667),
|
|
216
216
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
217
|
+
),
|
|
218
|
+
shadow: ShadowTokens(
|
|
219
|
+
high: [ShadowLayer(x: 0, y: 4, blur: 6, color: Color(astryxRGBA: 0x0000001A)), ShadowLayer(x: 0, y: 12, blur: 24, color: Color(astryxRGBA: 0x00000026)), ShadowLayer(x: 0, y: 0, blur: 0, spread: 1, isInset: true, color: Color(astryxRGBA: 0x00000000))],
|
|
220
|
+
low: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x0000000D)), ShadowLayer(x: 0, y: 4, blur: 8, color: Color(astryxRGBA: 0x0000001A)), ShadowLayer(x: 0, y: 0, blur: 0, spread: 1, isInset: true, color: Color(astryxRGBA: 0x00000000))],
|
|
221
|
+
med: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x0000000D)), ShadowLayer(x: 0, y: 4, blur: 12, color: Color(astryxRGBA: 0x0000001A)), ShadowLayer(x: 0, y: 0, blur: 0, spread: 1, isInset: true, color: Color(astryxRGBA: 0x00000000))]
|
|
217
222
|
)
|
|
218
223
|
),
|
|
219
224
|
dark: Tokens(
|
|
@@ -423,6 +428,11 @@ extension Theme {
|
|
|
423
428
|
size: FontSizeTokens(base: 14, lg: 17, s2xl: 24, s2xs: 8, s3xl: 29, s3xs: 7, s4xl: 35, s4xs: 6, s5xl: 42, sm: 12, xl: 20, xs: 10),
|
|
424
429
|
supporting: TypeStyleTokens(size: 12, weight: 400, leading: 1.6667),
|
|
425
430
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
431
|
+
),
|
|
432
|
+
shadow: ShadowTokens(
|
|
433
|
+
high: [ShadowLayer(x: 0, y: 4, blur: 6, color: Color(astryxRGBA: 0x00000080)), ShadowLayer(x: 0, y: 12, blur: 24, color: Color(astryxRGBA: 0x000000B3)), ShadowLayer(x: 0, y: 0, blur: 0, spread: 1, isInset: true, color: Color(astryxRGBA: 0xFFFFFF26))],
|
|
434
|
+
low: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x00000040)), ShadowLayer(x: 0, y: 4, blur: 8, color: Color(astryxRGBA: 0x00000066)), ShadowLayer(x: 0, y: 0, blur: 0, spread: 1, isInset: true, color: Color(astryxRGBA: 0xFFFFFF14))],
|
|
435
|
+
med: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x00000059)), ShadowLayer(x: 0, y: 4, blur: 12, color: Color(astryxRGBA: 0x00000080)), ShadowLayer(x: 0, y: 0, blur: 0, spread: 1, isInset: true, color: Color(astryxRGBA: 0xFFFFFF1F))]
|
|
426
436
|
)
|
|
427
437
|
)
|
|
428
438
|
)
|
|
@@ -214,6 +214,11 @@ extension Theme {
|
|
|
214
214
|
size: FontSizeTokens(base: 14, lg: 18, s2xl: 27, s2xs: 7, s3xl: 34, s3xs: 6, s4xl: 43, s4xs: 5, s5xl: 53, sm: 11, xl: 22, xs: 9),
|
|
215
215
|
supporting: TypeStyleTokens(size: 12, weight: 400, leading: 1.4545),
|
|
216
216
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
217
|
+
),
|
|
218
|
+
shadow: ShadowTokens(
|
|
219
|
+
high: [ShadowLayer(x: 0, y: 4, blur: 6, color: Color(astryxRGBA: 0x25252A1A)), ShadowLayer(x: 0, y: 12, blur: 24, color: Color(astryxRGBA: 0x25252A26))],
|
|
220
|
+
low: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x25252A0D)), ShadowLayer(x: 0, y: 4, blur: 8, color: Color(astryxRGBA: 0x25252A1A))],
|
|
221
|
+
med: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x25252A0D)), ShadowLayer(x: 0, y: 4, blur: 12, color: Color(astryxRGBA: 0x25252A1A))]
|
|
217
222
|
)
|
|
218
223
|
),
|
|
219
224
|
dark: Tokens(
|
|
@@ -423,6 +428,11 @@ extension Theme {
|
|
|
423
428
|
size: FontSizeTokens(base: 14, lg: 18, s2xl: 27, s2xs: 7, s3xl: 34, s3xs: 6, s4xl: 43, s4xs: 5, s5xl: 53, sm: 11, xl: 22, xs: 9),
|
|
424
429
|
supporting: TypeStyleTokens(size: 12, weight: 400, leading: 1.4545),
|
|
425
430
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
431
|
+
),
|
|
432
|
+
shadow: ShadowTokens(
|
|
433
|
+
high: [ShadowLayer(x: 0, y: 4, blur: 6, color: Color(astryxRGBA: 0x25252A1A)), ShadowLayer(x: 0, y: 12, blur: 24, color: Color(astryxRGBA: 0x25252A26))],
|
|
434
|
+
low: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x25252A0D)), ShadowLayer(x: 0, y: 4, blur: 8, color: Color(astryxRGBA: 0x25252A1A))],
|
|
435
|
+
med: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x25252A0D)), ShadowLayer(x: 0, y: 4, blur: 12, color: Color(astryxRGBA: 0x25252A1A))]
|
|
426
436
|
)
|
|
427
437
|
)
|
|
428
438
|
)
|
|
@@ -11,19 +11,44 @@ public struct Tokens: Equatable, Sendable {
|
|
|
11
11
|
public var radius: RadiusTokens
|
|
12
12
|
public var size: SizeTokens
|
|
13
13
|
public var font: FontTokens
|
|
14
|
+
public var shadow: ShadowTokens
|
|
14
15
|
|
|
15
16
|
public init(
|
|
16
17
|
color: ColorTokens,
|
|
17
18
|
space: SpaceTokens,
|
|
18
19
|
radius: RadiusTokens,
|
|
19
20
|
size: SizeTokens,
|
|
20
|
-
font: FontTokens
|
|
21
|
+
font: FontTokens,
|
|
22
|
+
shadow: ShadowTokens
|
|
21
23
|
) {
|
|
22
24
|
self.color = color
|
|
23
25
|
self.space = space
|
|
24
26
|
self.radius = radius
|
|
25
27
|
self.size = size
|
|
26
28
|
self.font = font
|
|
29
|
+
self.shadow = shadow
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// One layer of a theme's shadow, as CSS `box-shadow` draws it: a drop
|
|
34
|
+
/// shadow (an offset and a blur), or an inset ring `spread` points wide.
|
|
35
|
+
public struct ShadowLayer: Equatable, Sendable {
|
|
36
|
+
public var x: CGFloat
|
|
37
|
+
public var y: CGFloat
|
|
38
|
+
public var blur: CGFloat
|
|
39
|
+
public var spread: CGFloat
|
|
40
|
+
public var isInset: Bool
|
|
41
|
+
public var color: Color
|
|
42
|
+
|
|
43
|
+
public init(
|
|
44
|
+
x: CGFloat, y: CGFloat, blur: CGFloat, spread: CGFloat = 0, isInset: Bool = false, color: Color
|
|
45
|
+
) {
|
|
46
|
+
self.x = x
|
|
47
|
+
self.y = y
|
|
48
|
+
self.blur = blur
|
|
49
|
+
self.spread = spread
|
|
50
|
+
self.isInset = isInset
|
|
51
|
+
self.color = color
|
|
27
52
|
}
|
|
28
53
|
}
|
|
29
54
|
|
|
@@ -1260,3 +1285,34 @@ public struct FontWeightTokens: Equatable, Sendable {
|
|
|
1260
1285
|
self.semibold = semibold
|
|
1261
1286
|
}
|
|
1262
1287
|
}
|
|
1288
|
+
|
|
1289
|
+
/// The theme's `shadow` tokens, one typed member per token.
|
|
1290
|
+
public struct ShadowTokens: Equatable, Sendable {
|
|
1291
|
+
/// `--shadow-high`
|
|
1292
|
+
public var high: [ShadowLayer]
|
|
1293
|
+
/// `--shadow-low`
|
|
1294
|
+
public var low: [ShadowLayer]
|
|
1295
|
+
/// `--shadow-med`
|
|
1296
|
+
public var med: [ShadowLayer]
|
|
1297
|
+
|
|
1298
|
+
public init(
|
|
1299
|
+
high: [ShadowLayer],
|
|
1300
|
+
low: [ShadowLayer],
|
|
1301
|
+
med: [ShadowLayer]
|
|
1302
|
+
) {
|
|
1303
|
+
self.high = high
|
|
1304
|
+
self.low = low
|
|
1305
|
+
self.med = med
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
/// A token by its CSS name, for code that only has the name. Components
|
|
1309
|
+
/// read the typed members instead.
|
|
1310
|
+
func value(named token: String) -> [ShadowLayer]? {
|
|
1311
|
+
switch token {
|
|
1312
|
+
case "shadow-high": high
|
|
1313
|
+
case "shadow-low": low
|
|
1314
|
+
case "shadow-med": med
|
|
1315
|
+
default: nil
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
@@ -214,6 +214,11 @@ extension Theme {
|
|
|
214
214
|
size: FontSizeTokens(base: 16, lg: 20, s2xl: 31, s2xs: 8, s3xl: 39, s3xs: 7, s4xl: 49, s4xs: 5, s5xl: 61, sm: 13, xl: 25, xs: 10),
|
|
215
215
|
supporting: TypeStyleTokens(size: 12, weight: 400, leading: 1.5385),
|
|
216
216
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
217
|
+
),
|
|
218
|
+
shadow: ShadowTokens(
|
|
219
|
+
high: [ShadowLayer(x: 0, y: 4, blur: 6, color: Color(astryxRGBA: 0x2D241B1A)), ShadowLayer(x: 0, y: 12, blur: 24, color: Color(astryxRGBA: 0x2D241B26))],
|
|
220
|
+
low: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x2D241B0D)), ShadowLayer(x: 0, y: 4, blur: 8, color: Color(astryxRGBA: 0x2D241B1A))],
|
|
221
|
+
med: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x2D241B0D)), ShadowLayer(x: 0, y: 4, blur: 12, color: Color(astryxRGBA: 0x2D241B1A))]
|
|
217
222
|
)
|
|
218
223
|
),
|
|
219
224
|
dark: Tokens(
|
|
@@ -423,6 +428,11 @@ extension Theme {
|
|
|
423
428
|
size: FontSizeTokens(base: 16, lg: 20, s2xl: 31, s2xs: 8, s3xl: 39, s3xs: 7, s4xl: 49, s4xs: 5, s5xl: 61, sm: 13, xl: 25, xs: 10),
|
|
424
429
|
supporting: TypeStyleTokens(size: 12, weight: 400, leading: 1.5385),
|
|
425
430
|
weight: FontWeightTokens(bold: 700, medium: 500, normal: 400, semibold: 600)
|
|
431
|
+
),
|
|
432
|
+
shadow: ShadowTokens(
|
|
433
|
+
high: [ShadowLayer(x: 0, y: 4, blur: 6, color: Color(astryxRGBA: 0x2D241B1A)), ShadowLayer(x: 0, y: 12, blur: 24, color: Color(astryxRGBA: 0x2D241B26))],
|
|
434
|
+
low: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x2D241B0D)), ShadowLayer(x: 0, y: 4, blur: 8, color: Color(astryxRGBA: 0x2D241B1A))],
|
|
435
|
+
med: [ShadowLayer(x: 0, y: 2, blur: 4, color: Color(astryxRGBA: 0x2D241B0D)), ShadowLayer(x: 0, y: 4, blur: 12, color: Color(astryxRGBA: 0x2D241B1A))]
|
|
426
436
|
)
|
|
427
437
|
)
|
|
428
438
|
)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
extension View {
|
|
4
|
+
/// Draws a theme shadow around this view's shape, as CSS `box-shadow` does:
|
|
5
|
+
/// drop layers only outside the shape, so a see-through view shows no
|
|
6
|
+
/// shadow beneath it, and inset rings inside its edge.
|
|
7
|
+
func astryxShadow<S: InsettableShape>(_ layers: [ShadowLayer], in shape: S) -> some View {
|
|
8
|
+
background {
|
|
9
|
+
ZStack {
|
|
10
|
+
ForEach(Array(layers.enumerated()), id: \.offset) { _, layer in
|
|
11
|
+
if !layer.isInset {
|
|
12
|
+
// A CSS blur is twice SwiftUI's shadow radius.
|
|
13
|
+
shape.fill(.black)
|
|
14
|
+
.shadow(color: layer.color, radius: layer.blur / 2, x: layer.x, y: layer.y)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
.mask {
|
|
19
|
+
// Everything but the shape itself.
|
|
20
|
+
Rectangle()
|
|
21
|
+
.padding(-Self.shadowReach(layers))
|
|
22
|
+
.overlay(shape.fill(.black).blendMode(.destinationOut))
|
|
23
|
+
.compositingGroup()
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
.overlay {
|
|
27
|
+
ForEach(Array(layers.enumerated()), id: \.offset) { _, layer in
|
|
28
|
+
if layer.isInset {
|
|
29
|
+
shape.strokeBorder(layer.color, lineWidth: layer.spread)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// How far past the shape the layers can draw.
|
|
36
|
+
fileprivate static func shadowReach(_ layers: [ShadowLayer]) -> CGFloat {
|
|
37
|
+
layers.map { $0.blur + max(abs($0.x), abs($0.y)) }.max().map { $0 + 4 } ?? 0
|
|
38
|
+
}
|
|
39
|
+
}
|