fresh_core/
text_property.rs1use crate::api::OverlayOptions;
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11use std::ops::Range;
12
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ts_rs::TS)]
15#[ts(export)]
16pub struct TextProperty {
17 pub start: usize,
19 pub end: usize,
21 #[ts(type = "Record<string, any>")]
23 pub properties: HashMap<String, serde_json::Value>,
24}
25
26impl TextProperty {
27 pub fn new(start: usize, end: usize) -> Self {
29 Self {
30 start,
31 end,
32 properties: HashMap::new(),
33 }
34 }
35
36 pub fn with_property(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
38 self.properties.insert(key.into(), value);
39 self
40 }
41
42 pub fn with_properties(mut self, props: HashMap<String, serde_json::Value>) -> Self {
44 self.properties.extend(props);
45 self
46 }
47
48 pub fn contains(&self, pos: usize) -> bool {
50 pos >= self.start && pos < self.end
51 }
52
53 pub fn overlaps(&self, range: &Range<usize>) -> bool {
55 self.start < range.end && self.end > range.start
56 }
57
58 pub fn get(&self, key: &str) -> Option<&serde_json::Value> {
60 self.properties.get(key)
61 }
62
63 pub fn get_as<T: for<'de> Deserialize<'de>>(&self, key: &str) -> Option<T> {
65 self.properties
66 .get(key)
67 .and_then(|v| serde_json::from_value(v.clone()).ok())
68 }
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS)]
73#[serde(rename_all = "camelCase")]
74#[ts(export, rename_all = "camelCase")]
75pub struct InlineOverlay {
76 pub start: usize,
78 pub end: usize,
80 #[ts(type = "Partial<OverlayOptions>")]
82 pub style: OverlayOptions,
83 #[ts(type = "Record<string, any>")]
85 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
86 pub properties: HashMap<String, serde_json::Value>,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS)]
91#[serde(rename_all = "camelCase")]
92#[ts(export, rename_all = "camelCase")]
93pub struct TextPropertyEntry {
94 pub text: String,
96 #[ts(type = "Record<string, any>")]
98 #[serde(default)]
99 pub properties: HashMap<String, serde_json::Value>,
100 #[serde(default, skip_serializing_if = "Option::is_none")]
102 pub style: Option<OverlayOptions>,
103 #[serde(default, skip_serializing_if = "Vec::is_empty")]
105 pub inline_overlays: Vec<InlineOverlay>,
106}
107
108impl TextPropertyEntry {
109 pub fn text(text: impl Into<String>) -> Self {
111 Self {
112 text: text.into(),
113 properties: HashMap::new(),
114 style: None,
115 inline_overlays: Vec::new(),
116 }
117 }
118
119 pub fn with_property(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
121 self.properties.insert(key.into(), value);
122 self
123 }
124
125 pub fn with_properties(mut self, props: HashMap<String, serde_json::Value>) -> Self {
127 self.properties = props;
128 self
129 }
130
131 pub fn with_style(mut self, style: OverlayOptions) -> Self {
133 self.style = Some(style);
134 self
135 }
136
137 pub fn with_inline_overlay(mut self, start: usize, end: usize, style: OverlayOptions) -> Self {
139 self.inline_overlays.push(InlineOverlay {
140 start,
141 end,
142 style,
143 properties: HashMap::new(),
144 });
145 self
146 }
147}