1use self::attribute::Attribute;
2use crate::{
3 hydration::Cursor,
4 no_attrs,
5 prelude::{AddAnyAttr, Mountable},
6 renderer::{
7 dom::{Element, Node},
8 CastFrom, Rndr,
9 },
10 view::{Position, PositionState, Render, RenderHtml},
11};
12use attribute::any_attribute::AnyAttribute;
13use std::borrow::Cow;
14
15pub(crate) const FEATURE_CONFLICT_DIAGNOSTIC: &str =
23 "Value is None because the `ssr` feature is active. When `ssr` is \
24 enabled, tachys skips creating client-side values (event handlers, \
25 directives, properties) to avoid cross-thread panics on multithreaded \
26 servers. If you are building a client-side (CSR or hydrate) target, this \
27 means the `ssr` feature is being activated unintentionally via Cargo \
28 feature unification; another dependency in your workspace is enabling \
29 it. Run `cargo tree -e features -i tachys` to identify the source.";
30
31pub mod attribute;
33pub mod class;
35pub mod directive;
37pub mod element;
39pub mod event;
41pub mod islands;
43pub mod node_ref;
45pub mod property;
47pub mod style;
49
50pub struct Doctype {
52 value: &'static str,
53}
54
55pub fn doctype(value: &'static str) -> Doctype {
57 Doctype { value }
58}
59
60impl Render for Doctype {
61 type State = ();
62
63 fn build(self) -> Self::State {}
64
65 fn rebuild(self, _state: &mut Self::State) {}
66}
67
68no_attrs!(Doctype);
69
70impl RenderHtml for Doctype {
71 type AsyncOutput = Self;
72 type Owned = Self;
73
74 const MIN_LENGTH: usize = "<!DOCTYPE html>".len();
75
76 fn dry_resolve(&mut self) {}
77
78 async fn resolve(self) -> Self::AsyncOutput {
79 self
80 }
81
82 fn to_html_with_buf(
83 self,
84 buf: &mut String,
85 _position: &mut Position,
86 _escape: bool,
87 _mark_branches: bool,
88 _extra_attrs: Vec<AnyAttribute>,
89 ) {
90 buf.push_str("<!DOCTYPE ");
91 buf.push_str(self.value);
92 buf.push('>');
93 }
94
95 fn hydrate<const FROM_SERVER: bool>(
96 self,
97 _cursor: &Cursor,
98 _position: &PositionState,
99 ) -> Self::State {
100 }
101
102 fn into_owned(self) -> Self::Owned {
103 self
104 }
105}
106
107pub struct InertElement {
109 html: Cow<'static, str>,
110}
111
112impl InertElement {
113 pub fn new(html: impl Into<Cow<'static, str>>) -> Self {
115 Self { html: html.into() }
116 }
117}
118
119pub struct InertElementState(Cow<'static, str>, Element);
121
122impl Mountable for InertElementState {
123 fn unmount(&mut self) {
124 self.1.unmount();
125 }
126
127 fn mount(&mut self, parent: &Element, marker: Option<&Node>) {
128 self.1.mount(parent, marker)
129 }
130
131 fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
132 self.1.insert_before_this(child)
133 }
134
135 fn elements(&self) -> Vec<crate::renderer::types::Element> {
136 vec![self.1.clone()]
137 }
138}
139
140impl Render for InertElement {
141 type State = InertElementState;
142
143 fn build(self) -> Self::State {
144 let el = Rndr::create_element_from_html(self.html.clone());
145 InertElementState(self.html, el)
146 }
147
148 fn rebuild(self, state: &mut Self::State) {
149 let InertElementState(prev, el) = state;
150 if &self.html != prev {
151 let mut new_el = Rndr::create_element_from_html(self.html.clone());
152 el.insert_before_this(&mut new_el);
153 el.unmount();
154 *el = new_el;
155 *prev = self.html;
156 }
157 }
158}
159
160impl AddAnyAttr for InertElement {
161 type Output<SomeNewAttr: Attribute> = Self;
162
163 fn add_any_attr<NewAttr: Attribute>(
164 self,
165 _attr: NewAttr,
166 ) -> Self::Output<NewAttr>
167 where
168 Self::Output<NewAttr>: RenderHtml,
169 {
170 panic!(
171 "InertElement does not support adding attributes. It should only \
172 be used as a child, and not returned at the top level."
173 )
174 }
175}
176
177impl RenderHtml for InertElement {
178 type AsyncOutput = Self;
179 type Owned = Self;
180
181 const MIN_LENGTH: usize = 0;
182
183 fn html_len(&self) -> usize {
184 self.html.len()
185 }
186
187 fn dry_resolve(&mut self) {}
188
189 async fn resolve(self) -> Self {
190 self
191 }
192
193 fn to_html_with_buf(
194 self,
195 buf: &mut String,
196 position: &mut Position,
197 _escape: bool,
198 _mark_branches: bool,
199 _extra_attrs: Vec<AnyAttribute>,
200 ) {
201 buf.push_str(&self.html);
202 *position = Position::NextChild;
203 }
204
205 fn hydrate<const FROM_SERVER: bool>(
206 self,
207 cursor: &Cursor,
208 position: &PositionState,
209 ) -> Self::State {
210 let curr_position = position.get();
211 if curr_position == Position::FirstChild {
212 cursor.child();
213 } else if curr_position != Position::Current {
214 cursor.sibling();
215 }
216 let el = crate::renderer::types::Element::cast_from(cursor.current())
217 .unwrap();
218 position.set(Position::NextChild);
219 InertElementState(self.html, el)
220 }
221
222 fn into_owned(self) -> Self::Owned {
223 self
224 }
225}