Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ http_archive(
integrity = "sha256-+GQiTtN6H8TQz/+YkVz73dHeYAZ86/9hAUwTlkISx48=",
strip_prefix = "hermes-880b1645b5dca974f4329dc4108692d301abee0d",
build_file = "@valdi//third-party/hermes:hermes.BUILD",
patch_args = ["-p1"],
patches = ["@valdi//third-party/hermes/patches:nontrivial_memcall.patch"],
)

bazel_dep(name = "boringssl", version = "0.20250415.0")
Expand Down
24 changes: 24 additions & 0 deletions apps/inline_text_children_example/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
load("//bzl/valdi:valdi_application.bzl", "valdi_application")
load("//bzl/valdi:valdi_module.bzl", "valdi_module")

valdi_module(
name = "inline_text_children_example",
srcs = glob([
"**/*.ts",
"**/*.tsx",
]),
visibility = ["//visibility:public"],
deps = [
"//src/valdi_modules/src/valdi/valdi_core",
"//src/valdi_modules/src/valdi/valdi_tsx",
],
)

valdi_application(
name = "inline_text_children_example_app",
ios_bundle_id = "com.snap.valdi.inlinetextchildren",
root_component_path = "App@inline_text_children_example/InlineTextChildrenExample",
title = "Inline Text Children",
version = "1.0.0",
deps = [":inline_text_children_example"],
)
273 changes: 273 additions & 0 deletions apps/inline_text_children_example/InlineTextChildrenExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
import { Component, StatefulComponent } from 'valdi_core/src/Component';
import { Device } from 'valdi_core/src/Device';
import { Style } from 'valdi_core/src/Style';
import { systemBoldFont, systemFont } from 'valdi_core/src/SystemFont';
import { AttributedTextBuilder } from 'valdi_core/src/utils/AttributedTextBuilder';
import { AttributedTextInlineViewVerticalAlignment } from 'valdi_tsx/src/AttributedTextInlineViewAttachment';
import { View } from 'valdi_tsx/src/NativeTemplateElements';

const alignmentText = new AttributedTextBuilder()
.append('Top ')
.appendInlineView(0, AttributedTextInlineViewVerticalAlignment.Top)
.append(' Center ')
.appendInlineView(1, AttributedTextInlineViewVerticalAlignment.Center)
.append(' Bottom ')
.appendInlineView(2, AttributedTextInlineViewVerticalAlignment.Bottom)
.append(' Baseline ')
.appendInlineView(3, AttributedTextInlineViewVerticalAlignment.Baseline)
.append(' inside one wrapped text run.')
.build();

const labelInteractiveText = new AttributedTextBuilder()
.append('A label can host a stateful inline child: ')
.appendInlineView(0, AttributedTextInlineViewVerticalAlignment.Center)
.append(' and the surrounding text is not rebuilt when it changes size.')
.build();

const textViewInteractiveText = new AttributedTextBuilder()
.append('The same stateful child works in a textview: ')
.appendInlineView(0, AttributedTextInlineViewVerticalAlignment.Center)
.append(' so text layout can place a resized view again.')
.build();

const ltrEndInlineText = new AttributedTextBuilder()
.append('Text before ')
.appendInlineView(0, AttributedTextInlineViewVerticalAlignment.Center)
.build();

const rtlEndInlineText = new AttributedTextBuilder()
.append('אבג ')
.appendInlineView(0, AttributedTextInlineViewVerticalAlignment.Center)
.build();

/**
* @ViewModel
* @ExportModel
*/
export interface ViewModel {}

interface MarkerViewModel {
title: string;
color: string;
height: number;
width: number;
}

class AlignmentMarker extends Component<MarkerViewModel> {
onRender(): void {
<view
alignItems="center"
backgroundColor={this.viewModel.color}
borderRadius={5}
height={this.viewModel.height}
justifyContent="center"
width={this.viewModel.width}
>
<label color="#FFFFFF" font={systemBoldFont(9)} textAlign="center" value={this.viewModel.title} width="100%" />
</view>;
}
}

interface ExpandableInlineButtonViewModel {
compactTitle: string;
expandedTitle: string;
}

interface ExpandableInlineButtonState {
expanded: boolean;
}

class ExpandableInlineButton extends StatefulComponent<ExpandableInlineButtonViewModel, ExpandableInlineButtonState> {
state: ExpandableInlineButtonState = {
expanded: false,
};

onRender(): void {
const expanded = this.state.expanded;
<view
accessibilityCategory="button"
alignItems="center"
backgroundColor={expanded ? '#0F766E' : '#2563EB'}
border="1 solid #0F172A"
borderRadius={7}
height={26}
justifyContent="center"
onTap={this.toggle}
paddingLeft={expanded ? 12 : 8}
paddingRight={expanded ? 12 : 8}
width={expanded ? 156 : 82}
>
<label
color="#FFFFFF"
font={systemBoldFont(expanded ? 13 : 12)}
textAlign="center"
value={expanded ? this.viewModel.expandedTitle : this.viewModel.compactTitle}
width="100%"
/>
</view>;
}

private toggle = () => {
this.setState({ expanded: !this.state.expanded });
};
}

/**
* @Component
* @ExportModel
*/
export class App extends Component<ViewModel> {
onRender(): void {
<view backgroundColor="#F8FAFC" height="100%" width="100%">
<scroll height="100%" width="100%">
<view padding={22} paddingTop={22 + Device.getDisplayTopInset()} width="100%">
<label color="#0F172A" font={systemBoldFont(27)} marginBottom={8} value="Inline Text Children" width="100%" />
<label
color="#475569"
font={systemFont(15)}
lineHeight={1.25}
marginBottom={18}
numberOfLines={0}
value="Labels and textviews can embed real Valdi child views. Yoga resolves child size; native text layout places each child inline."
width="100%"
/>

<view style={styles.card} marginBottom={14}>
<label color="#334155" font={systemBoldFont(14)} marginBottom={10} value="Label alignment" width="100%" />
<label
color="#0F172A"
font={systemFont(20)}
lineHeight={1.45}
numberOfLines={0}
value={alignmentText}
width="100%"
>
<AlignmentMarker color="#DC2626" height={12} title="TOP" width={48} />
<AlignmentMarker color="#7C3AED" height={12} title="MID" width={48} />
<AlignmentMarker color="#047857" height={12} title="BOT" width={48} />
<AlignmentMarker color="#0F766E" height={12} title="BASE" width={48} />
</label>
</view>

<view style={styles.card} marginBottom={14}>
<label color="#334155" font={systemBoldFont(14)} marginBottom={10} value="Textview alignment" width="100%" />
<textview
backgroundColor="#FFFFFF"
color="#0F172A"
enabled={false}
font={systemFont(19)}
height={104}
lineHeight={1.45}
numberOfLines={0}
value={alignmentText}
width="100%"
>
<AlignmentMarker color="#EA580C" height={18} title="TOP" width={48} />
<AlignmentMarker color="#2563EB" height={18} title="MID" width={48} />
<AlignmentMarker color="#16A34A" height={18} title="BOT" width={48} />
<AlignmentMarker color="#0F766E" height={18} title="BASE" width={48} />
</textview>
</view>

<view style={styles.card} marginBottom={14}>
<label color="#334155" font={systemBoldFont(14)} marginBottom={10} value="Label LTR vs RTL append position" width="100%" />
<label
color="#64748B"
font={systemFont(13)}
lineHeight={1.25}
marginBottom={10}
numberOfLines={0}
value="Both labels append the inline child after the text. The END pill should sit on the right in LTR and on the left in RTL."
width="100%"
/>
<view alignItems="center" flexDirection="row" marginBottom={8} width="100%">
<label color="#475569" font={systemBoldFont(12)} marginRight={10} textAlign="center" value="LTR" width={34} />
<view
backgroundColor="#F8FAFC"
border="1 solid #CBD5E1"
borderRadius={7}
direction="ltr"
flexGrow={1}
padding={10}
>
<label
color="#0F172A"
font={systemFont(19)}
lineHeight={1.45}
numberOfLines={0}
value={ltrEndInlineText}
width="100%"
>
<AlignmentMarker color="#2563EB" height={18} title="END" width={48} />
</label>
</view>
</view>
<view alignItems="center" flexDirection="row" width="100%">
<label color="#475569" font={systemBoldFont(12)} marginRight={10} textAlign="center" value="RTL" width={34} />
<view
backgroundColor="#F8FAFC"
border="1 solid #CBD5E1"
borderRadius={7}
direction="rtl"
flexGrow={1}
padding={10}
>
<label
color="#0F172A"
font={systemFont(19)}
lineHeight={1.45}
numberOfLines={0}
value={rtlEndInlineText}
width="100%"
>
<AlignmentMarker color="#7C3AED" height={18} title="END" width={48} />
</label>
</view>
</view>
</view>

<view style={styles.card} marginBottom={14}>
<label color="#334155" font={systemBoldFont(14)} marginBottom={10} value="Stateful child in a label" width="100%" />
<label
color="#0F172A"
font={systemFont(19)}
lineHeight={1.45}
numberOfLines={0}
value={labelInteractiveText}
width="100%"
>
<ExpandableInlineButton compactTitle="Expand" expandedTitle="Contract inline" />
</label>
</view>

<view style={styles.card}>
<label color="#334155" font={systemBoldFont(14)} marginBottom={10} value="Stateful child in a textview" width="100%" />
<textview
backgroundColor="#FFFFFF"
color="#0F172A"
enabled={false}
font={systemFont(19)}
height={124}
lineHeight={1.45}
numberOfLines={0}
value={textViewInteractiveText}
width="100%"
>
<ExpandableInlineButton compactTitle="Open" expandedTitle="Close inline view" />
</textview>
</view>
</view>
</scroll>
</view>;
}
}

const styles = {
card: new Style<View>({
backgroundColor: '#FFFFFF',
border: '1 solid #CBD5E1',
borderRadius: 8,
padding: 14,
width: '100%',
}),
};
22 changes: 22 additions & 0 deletions apps/text_animation_group_example/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
load("//bzl/valdi:valdi_application.bzl", "valdi_application")
load("//bzl/valdi:valdi_module.bzl", "valdi_module")

valdi_module(
name = "text_animation_group_example",
srcs = glob([
"**/*.ts",
"**/*.tsx",
]),
visibility = ["//visibility:public"],
deps = [
"//src/valdi_modules/src/valdi/valdi_core",
"//src/valdi_modules/src/valdi/valdi_tsx",
],
)

valdi_application(
name = "text_animation_group_example_app",
root_component_path = "App@text_animation_group_example/TextAnimationGroupExample",
title = "Text Animation Group",
deps = [":text_animation_group_example"],
)
Loading
Loading