1use crate::ServerMetaContext;
2use leptos::{
3 attr::{any_attribute::AnyAttribute, NextAttribute},
4 component, html,
5 reactive::owner::use_context,
6 tachys::{
7 dom::document,
8 html::attribute::Attribute,
9 hydration::Cursor,
10 view::{
11 add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
12 RenderHtml,
13 },
14 },
15 IntoView,
16};
17
18#[component]
45pub fn Html() -> impl IntoView {
46 HtmlView { attributes: () }
47}
48
49struct HtmlView<At> {
50 attributes: At,
51}
52
53struct HtmlViewState<At>
54where
55 At: Attribute,
56{
57 attributes: At::State,
58}
59
60impl<At> Render for HtmlView<At>
61where
62 At: Attribute,
63{
64 type State = HtmlViewState<At>;
65
66 fn build(self) -> Self::State {
67 let el = document()
68 .document_element()
69 .expect("there to be a <html> element");
70
71 let attributes = self.attributes.build(&el);
72
73 HtmlViewState { attributes }
74 }
75
76 fn rebuild(self, state: &mut Self::State) {
77 self.attributes.rebuild(&mut state.attributes);
78 }
79}
80
81impl<At> AddAnyAttr for HtmlView<At>
82where
83 At: Attribute,
84{
85 type Output<SomeNewAttr: Attribute> =
86 HtmlView<<At as NextAttribute>::Output<SomeNewAttr>>;
87
88 fn add_any_attr<NewAttr: Attribute>(
89 self,
90 attr: NewAttr,
91 ) -> Self::Output<NewAttr>
92 where
93 Self::Output<NewAttr>: RenderHtml,
94 {
95 HtmlView {
96 attributes: self.attributes.add_any_attr(attr),
97 }
98 }
99}
100
101impl<At> RenderHtml for HtmlView<At>
102where
103 At: Attribute,
104{
105 type AsyncOutput = HtmlView<At::AsyncOutput>;
106 type Owned = HtmlView<At::CloneableOwned>;
107
108 const MIN_LENGTH: usize = At::MIN_LENGTH;
109
110 fn dry_resolve(&mut self) {
111 self.attributes.dry_resolve();
112 }
113
114 async fn resolve(self) -> Self::AsyncOutput {
115 HtmlView {
116 attributes: self.attributes.resolve().await,
117 }
118 }
119
120 fn to_html_with_buf(
121 self,
122 _buf: &mut String,
123 _position: &mut Position,
124 _escape: bool,
125 _mark_branches: bool,
126 extra_attrs: Vec<AnyAttribute>,
127 ) {
128 if let Some(meta) = use_context::<ServerMetaContext>() {
129 let mut buf = String::new();
130 _ = html::attributes_to_html(
131 (self.attributes, extra_attrs),
132 &mut buf,
133 );
134 if !buf.is_empty() {
135 _ = meta.html.send(buf);
136 }
137 }
138 }
139
140 fn hydrate<const FROM_SERVER: bool>(
141 self,
142 _cursor: &Cursor,
143 _position: &PositionState,
144 ) -> Self::State {
145 let el = document()
146 .document_element()
147 .expect("there to be a <html> element");
148
149 let attributes = self.attributes.hydrate::<FROM_SERVER>(&el);
150
151 HtmlViewState { attributes }
152 }
153
154 fn into_owned(self) -> Self::Owned {
155 HtmlView {
156 attributes: self.attributes.into_cloneable_owned(),
157 }
158 }
159}
160
161impl<At> Mountable for HtmlViewState<At>
162where
163 At: Attribute,
164{
165 fn unmount(&mut self) {}
166
167 fn mount(
168 &mut self,
169 _parent: &leptos::tachys::renderer::types::Element,
170 _marker: Option<&leptos::tachys::renderer::types::Node>,
171 ) {
172 }
175
176 fn insert_before_this(&self, _child: &mut dyn Mountable) -> bool {
177 false
178 }
179
180 fn elements(&self) -> Vec<leptos::tachys::renderer::types::Element> {
181 vec![document()
182 .document_element()
183 .expect("there to be a <html> element")]
184 }
185}