diff --git a/Userland/Libraries/LibWeb/CSS/Default.css b/Userland/Libraries/LibWeb/CSS/Default.css index ac5b17868894a2..5bd1f55a65f7cc 100644 --- a/Userland/Libraries/LibWeb/CSS/Default.css +++ b/Userland/Libraries/LibWeb/CSS/Default.css @@ -26,7 +26,7 @@ label { } /* FIXME: This is a temporary hack until we can render a native-looking frame for these. */ -input, textarea { +input:not([type=submit], input[type=button], input[type=reset], input[type=color], input[type=checkbox], input[type=radio]), textarea { border: 1px solid ButtonBorder; min-width: 80px; min-height: 16px; @@ -44,14 +44,6 @@ textarea { height: attr(rows lh, 2lh); } -input[type=submit], input[type=button], input[type=reset], input[type=checkbox], input[type=radio] { - border: none; - min-width: unset; - min-height: unset; - width: unset; - cursor: unset; -} - input::placeholder { color: GrayText; } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp index 5d495b1c1ef230..80c611537c5293 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp @@ -61,6 +61,7 @@ void HTMLInputElement::visit_edges(Cell::Visitor& visitor) visitor.visit(m_text_node); visitor.visit(m_placeholder_element); visitor.visit(m_placeholder_text_node); + visitor.visit(m_color_well_element); visitor.visit(m_legacy_pre_activation_behavior_checked_element_in_group.ptr()); visitor.visit(m_selected_files); } @@ -70,7 +71,7 @@ JS::GCPtr HTMLInputElement::create_layout_node(NonnullRefPtr(document(), *this, move(style)); if (type_state() == TypeAttributeState::Checkbox) @@ -317,6 +318,9 @@ void HTMLInputElement::did_pick_color(Optional picked_color) m_value = value_sanitization_algorithm(picked_color.value().to_deprecated_string_without_alpha()); m_dirty_value = true; + if (m_color_well_element) + MUST(m_color_well_element->style_for_bindings()->set_property(CSS::PropertyID::BackgroundColor, m_value)); + // the user agent must queue an element task on the user interaction task source queue_an_element_task(HTML::Task::Source::UserInteraction, [this] { // given the input element to fire an event named input at the input element, with the bubbles and composed attributes initialized to true @@ -387,7 +391,9 @@ WebIDL::ExceptionOr HTMLInputElement::set_value(String const& value) auto old_value = move(m_value); // 2. Set the element's value to the new value. - // NOTE: This is done as part of step 4 below. + // NOTE: For the TextNode this is done as part of step 4 below. + if (type_state() == TypeAttributeState::Color && m_color_well_element) + MUST(m_color_well_element->style_for_bindings()->set_property(CSS::PropertyID::BackgroundColor, m_value)); // 3. Set the element's dirty value flag to true. m_dirty_value = true; @@ -507,7 +513,6 @@ void HTMLInputElement::create_shadow_tree_if_needed() if (shadow_root_internal()) return; - // FIXME: This could be better factored. Everything except the below types becomes a text input. switch (type_state()) { case TypeAttributeState::RadioButton: case TypeAttributeState::Checkbox: @@ -515,12 +520,19 @@ void HTMLInputElement::create_shadow_tree_if_needed() case TypeAttributeState::SubmitButton: case TypeAttributeState::ResetButton: case TypeAttributeState::ImageButton: + break; case TypeAttributeState::Color: - return; + create_color_input_shadow_tree(); + break; + // FIXME: This could be better factored. Everything except the above types becomes a text input. default: + create_text_input_shadow_tree(); break; } +} +void HTMLInputElement::create_text_input_shadow_tree() +{ auto shadow_root = heap().allocate(realm(), document(), *this, Bindings::ShadowRootMode::Closed); auto initial_value = m_value; auto element = DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML).release_value_but_fixme_should_propagate_errors(); @@ -568,6 +580,35 @@ void HTMLInputElement::create_shadow_tree_if_needed() set_shadow_root(shadow_root); } +void HTMLInputElement::create_color_input_shadow_tree() +{ + auto shadow_root = heap().allocate(realm(), document(), *this, Bindings::ShadowRootMode::Closed); + + auto color = value_sanitization_algorithm(m_value); + + auto border = DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML).release_value_but_fixme_should_propagate_errors(); + MUST(border->set_attribute(HTML::AttributeNames::style, R"~~~( + width: fit-content; + height: fit-content; + padding: 4px; + border: 1px solid ButtonBorder; + background-color: ButtonFace; +)~~~"_string)); + + m_color_well_element = DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML).release_value_but_fixme_should_propagate_errors(); + MUST(m_color_well_element->set_attribute(HTML::AttributeNames::style, R"~~~( + width: 24px; + height: 24px; + border: 1px solid ButtonBorder; + box-sizing: border-box; +)~~~"_string)); + MUST(m_color_well_element->style_for_bindings()->set_property(CSS::PropertyID::BackgroundColor, color)); + + MUST(border->append_child(*m_color_well_element)); + MUST(shadow_root->append_child(border)); + set_shadow_root(shadow_root); +} + void HTMLInputElement::did_receive_focus() { auto* browsing_context = document().browsing_context(); @@ -611,11 +652,17 @@ void HTMLInputElement::attribute_changed(FlyString const& name, Optionalstyle_for_bindings()->set_property(CSS::PropertyID::BackgroundColor, m_value)); } } else { if (!m_dirty_value) { m_value = value_sanitization_algorithm(*value); update_placeholder_visibility(); + + if (type_state() == TypeAttributeState::Color && m_color_well_element) + MUST(m_color_well_element->style_for_bindings()->set_property(CSS::PropertyID::BackgroundColor, m_value)); } } } else if (name == HTML::AttributeNames::placeholder) { @@ -950,10 +997,14 @@ void HTMLInputElement::reset_algorithm() // and then invoke the value sanitization algorithm, if the type attribute's current state defines one. m_value = value_sanitization_algorithm(m_value); + if (m_text_node) { m_text_node->set_data(MUST(String::from_deprecated_string(m_value))); update_placeholder_visibility(); } + + if (type_state() == TypeAttributeState::Color && m_color_well_element) + MUST(m_color_well_element->style_for_bindings()->set_property(CSS::PropertyID::BackgroundColor, m_value)); } void HTMLInputElement::form_associated_element_was_inserted() diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h index 749d79f35b8120..927ce0b5ce2ef0 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h @@ -166,6 +166,8 @@ class HTMLInputElement final static TypeAttributeState parse_type_attribute(StringView); void create_shadow_tree_if_needed(); + void create_text_input_shadow_tree(); + void create_color_input_shadow_tree(); WebIDL::ExceptionOr run_input_activation_behavior(); void set_checked_within_group(); @@ -179,6 +181,7 @@ class HTMLInputElement final JS::GCPtr m_placeholder_text_node; JS::GCPtr m_inner_text_element; + JS::GCPtr m_color_well_element; JS::GCPtr m_text_node; bool m_checked { false };