custom_element.rs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. use std::sync::{Arc, RwLock};
  2. use rustc_hash::FxHashMap;
  3. use crate::{
  4. node::{FromAnyValue, NodeType},
  5. node_ref::AttributeMask,
  6. prelude::{NodeImmutable, NodeMut, RealDom},
  7. real_dom::NodeTypeMut,
  8. shadow_dom::ShadowDom,
  9. NodeId,
  10. };
  11. pub(crate) struct CustomElementRegistry<V: FromAnyValue + Send + Sync> {
  12. builders: FxHashMap<&'static str, CustomElementBuilder<V>>,
  13. }
  14. impl<V: FromAnyValue + Send + Sync> Default for CustomElementRegistry<V> {
  15. fn default() -> Self {
  16. Self {
  17. builders: FxHashMap::default(),
  18. }
  19. }
  20. }
  21. impl<V: FromAnyValue + Send + Sync> CustomElementRegistry<V> {
  22. pub fn register<W: CustomElement<V>>(&mut self) {
  23. self.builders.insert(
  24. W::NAME,
  25. CustomElementBuilder {
  26. create: |dom, light_root_id| Box::new(W::create(dom, light_root_id)),
  27. },
  28. );
  29. }
  30. pub fn add_shadow_dom(&self, mut node: NodeMut<V>) {
  31. let element_tag = if let NodeType::Element(el) = &*node.node_type() {
  32. Some(el.tag.clone())
  33. } else {
  34. None
  35. };
  36. if let Some(element_tag) = element_tag {
  37. if let Some(builder) = self.builders.get(element_tag.as_str()) {
  38. let boxed_widget = {
  39. let light_root_id = node.id();
  40. let dom = node.real_dom_mut();
  41. (builder.create)(dom, light_root_id)
  42. };
  43. let boxed_widget = CustomElementManager {
  44. inner: Arc::new(RwLock::new(boxed_widget)),
  45. };
  46. let NodeTypeMut::Element(mut el) = node.node_type_mut()else{
  47. panic!("The type of the light element should not change when creating a shadow DOM")
  48. };
  49. *el.shadow_root_mut() = Some(ShadowDom::new(boxed_widget).into());
  50. }
  51. }
  52. }
  53. }
  54. struct CustomElementBuilder<V: FromAnyValue + Send + Sync> {
  55. create: fn(&mut RealDom<V>, NodeId) -> Box<dyn CustomElementUpdater<V>>,
  56. }
  57. /// A controlled element that renders to a shadow DOM
  58. pub trait CustomElement<V: FromAnyValue + Send + Sync = ()>: Send + Sync + 'static {
  59. /// The tag the widget is registered under.
  60. const NAME: &'static str;
  61. /// Create a new widget without mounting it.
  62. fn create(dom: &mut RealDom<V>, light_root_id: NodeId) -> Self;
  63. /// The root node of the widget.
  64. fn root(&self) -> NodeId;
  65. /// Called when the attributes of the widget are changed.
  66. fn attributes_changed(&mut self, _dom: &mut RealDom<V>, _attributes: &AttributeMask);
  67. }
  68. /// A factory for creating widgets
  69. trait ElementFactory<W: CustomElementUpdater<V>, V: FromAnyValue + Send + Sync = ()>:
  70. Send + Sync + 'static
  71. {
  72. /// The tag the widget is registered under.
  73. const NAME: &'static str;
  74. /// Create a new widget.
  75. fn create(dom: &mut RealDom<V>, light_root_id: NodeId) -> W;
  76. }
  77. impl<W: CustomElement<V>, V: FromAnyValue + Send + Sync> ElementFactory<W, V> for W {
  78. const NAME: &'static str = W::NAME;
  79. fn create(dom: &mut RealDom<V>, light_root_id: NodeId) -> Self {
  80. Self::create(dom, light_root_id)
  81. }
  82. }
  83. /// A trait for updating widgets
  84. trait CustomElementUpdater<V: FromAnyValue + Send + Sync = ()>: Send + Sync + 'static {
  85. /// Called when the attributes of the widget are changed.
  86. fn attributes_changed(&mut self, dom: &mut RealDom<V>, attributes: &AttributeMask);
  87. /// The root node of the widget.
  88. fn root(&self) -> NodeId;
  89. }
  90. impl<W: CustomElement<V>, V: FromAnyValue + Send + Sync> CustomElementUpdater<V> for W {
  91. fn attributes_changed(&mut self, root: &mut RealDom<V>, attributes: &AttributeMask) {
  92. self.attributes_changed(root, attributes);
  93. }
  94. fn root(&self) -> NodeId {
  95. self.root()
  96. }
  97. }
  98. pub struct CustomElementManager<V: FromAnyValue = ()> {
  99. inner: Arc<RwLock<Box<dyn CustomElementUpdater<V>>>>,
  100. }
  101. impl<V: FromAnyValue + Send + Sync> CustomElementManager<V> {
  102. pub fn root(&self) -> NodeId {
  103. self.inner.read().unwrap().root()
  104. }
  105. }
  106. impl<V: FromAnyValue> Clone for CustomElementManager<V> {
  107. fn clone(&self) -> Self {
  108. Self {
  109. inner: self.inner.clone(),
  110. }
  111. }
  112. }