# frozen_string_literal: true require "hot_module" module HoTModuLe module ShadowEffects # rubocop:disable Naming/MethodName module JSPropertyAliases def textContent=(value) self.content = value end def innerHTML=(value) self.inner_html = value end def method_missing(meth, *args, **kwargs) # rubocop:disable Style/MissingRespondToMissing return super unless meth.to_s.end_with?("=") kebob_cased = meth.to_s .gsub(/([A-Z]+)([A-Z][a-z])/, '\1-\2') .gsub(/([a-z\d])([A-Z])/, '\1-\2') .downcase self[kebob_cased.delete_suffix("=")] = args[0] end end # rubocop:enable Naming/MethodName Nokolexbor::Element.include JSPropertyAliases unless Nokolexbor::Element.instance_methods.include?(:textContent=) module ClassMethods def directive(name, &block) @directives ||= {} @directives[name.to_s] = block end end # @param klass [Class] # @return [void] def self.included(klass) klass.attribute_binding "host-effect", :_shadow_effect_binding klass.singleton_class.attr_reader :directives klass.extend ClassMethods klass.class_eval do directive :show do |_, element, value| element["hidden"] = "" unless value end directive :hide do |_, element, value| element["hidden"] = "" if value end directive :classMap do |_, element, obj| obj.each do |k, v| element.add_class k.to_s if v end end end end def _shadow_effect_binding(attribute:, node:) # rubocop:disable Metrics syntax = attribute.value statements = syntax.split(";").map(&:strip) statements.each do |statement| # rubocop:disable Metrics if statement.start_with?("$el.") # property assignment expression = statement.split("=").map(&:strip) expression[0] = expression[0][4..] value = send(expression[1]) node.send("#{expression[0]}=", value_to_attribute(value)) elsif statement.start_with?("$") # directive directive_name, args_str = statement.strip.match(/(.*)\((.*)\)/).captures arg_strs = args_str.split(",").map(&:strip) arg_strs.unshift("$el") if self.class.directives[directive_name.strip[1..]] args = arg_strs.map do |arg_str| next node if arg_str == "$el" next arg_str[1...-1] if arg_str.start_with?("'") # string literal send(arg_str) end self.class.directives[directive_name.strip[1..]]&.(self, *args) end else # method call method_name, args_str = statement.strip.match(/(.*)\((.*)\)/).captures arg_strs = args_str.split(",").map(&:strip) args = arg_strs.map do |arg_str| next node if arg_str == "$el" next arg_str[1...-1] if arg_str.start_with?("'") # string literal send(arg_str) end send(method_name.strip, *args) end end end end end