mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 14:33:47 +00:00
Tweak CSS
Give default styles to visibility properties. Unblocks various playwright behavior
This commit is contained in:
@@ -127,3 +127,74 @@
|
|||||||
testing.expectEqual('important', div.style.getPropertyPriority('color'));
|
testing.expectEqual('important', div.style.getPropertyPriority('color'));
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script id="defaultVisibilityProperties">
|
||||||
|
{
|
||||||
|
// Test default values for visibility-related properties
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const span = document.createElement('span');
|
||||||
|
const anchor = document.createElement('a');
|
||||||
|
|
||||||
|
// Test display defaults on element.style
|
||||||
|
testing.expectEqual('block', div.style.getPropertyValue('display'));
|
||||||
|
testing.expectEqual('inline', span.style.getPropertyValue('display'));
|
||||||
|
testing.expectEqual('inline', anchor.style.getPropertyValue('display'));
|
||||||
|
|
||||||
|
// Test visibility default
|
||||||
|
testing.expectEqual('visible', div.style.getPropertyValue('visibility'));
|
||||||
|
|
||||||
|
// Test opacity default
|
||||||
|
testing.expectEqual('1', div.style.getPropertyValue('opacity'));
|
||||||
|
|
||||||
|
// Test that explicit values override defaults
|
||||||
|
div.style.setProperty('display', 'flex');
|
||||||
|
testing.expectEqual('flex', div.style.getPropertyValue('display'));
|
||||||
|
testing.expectEqual(1, div.style.length);
|
||||||
|
|
||||||
|
// Test that removing property returns to default
|
||||||
|
div.style.setProperty('display', '');
|
||||||
|
testing.expectEqual('block', div.style.getPropertyValue('display'));
|
||||||
|
testing.expectEqual(0, div.style.length);
|
||||||
|
|
||||||
|
// Test that other properties still return empty when not set
|
||||||
|
testing.expectEqual('', div.style.getPropertyValue('color'));
|
||||||
|
testing.expectEqual('', div.style.getPropertyValue('width'));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="computedStyleDefaults">
|
||||||
|
{
|
||||||
|
// Test that getComputedStyle returns default visibility properties
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const span = document.createElement('span');
|
||||||
|
const anchor = document.createElement('a');
|
||||||
|
document.body.appendChild(div);
|
||||||
|
document.body.appendChild(span);
|
||||||
|
document.body.appendChild(anchor);
|
||||||
|
|
||||||
|
// Test element.style defaults
|
||||||
|
testing.expectEqual('block', div.style.display);
|
||||||
|
testing.expectEqual('inline', span.style.display);
|
||||||
|
testing.expectEqual('inline', anchor.style.display);
|
||||||
|
testing.expectEqual('visible', div.style.visibility);
|
||||||
|
testing.expectEqual('1', div.style.opacity);
|
||||||
|
|
||||||
|
// Test getComputedStyle with getPropertyValue
|
||||||
|
const divStyle = window.getComputedStyle(div);
|
||||||
|
const spanStyle = window.getComputedStyle(span);
|
||||||
|
const anchorStyle = window.getComputedStyle(anchor);
|
||||||
|
|
||||||
|
testing.expectEqual('block', divStyle.getPropertyValue('display'));
|
||||||
|
testing.expectEqual('inline', spanStyle.getPropertyValue('display'));
|
||||||
|
testing.expectEqual('inline', anchorStyle.getPropertyValue('display'));
|
||||||
|
testing.expectEqual('visible', divStyle.getPropertyValue('visibility'));
|
||||||
|
testing.expectEqual('1', divStyle.getPropertyValue('opacity'));
|
||||||
|
|
||||||
|
// Test getComputedStyle with named property access (camelCase)
|
||||||
|
testing.expectEqual('block', divStyle.display);
|
||||||
|
testing.expectEqual('inline', spanStyle.display);
|
||||||
|
testing.expectEqual('inline', anchorStyle.display);
|
||||||
|
testing.expectEqual('visible', divStyle.visibility);
|
||||||
|
testing.expectEqual('1', divStyle.opacity);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ const MessageEvent = @import("event/MessageEvent.zig");
|
|||||||
const MediaQueryList = @import("css/MediaQueryList.zig");
|
const MediaQueryList = @import("css/MediaQueryList.zig");
|
||||||
const storage = @import("storage/storage.zig");
|
const storage = @import("storage/storage.zig");
|
||||||
const Element = @import("Element.zig");
|
const Element = @import("Element.zig");
|
||||||
const CSSStyleDeclaration = @import("css/CSSStyleDeclaration.zig");
|
const CSSStyleProperties = @import("css/CSSStyleProperties.zig");
|
||||||
const CustomElementRegistry = @import("CustomElementRegistry.zig");
|
const CustomElementRegistry = @import("CustomElementRegistry.zig");
|
||||||
|
|
||||||
const Window = @This();
|
const Window = @This();
|
||||||
@@ -319,8 +319,8 @@ pub fn matchMedia(_: *const Window, query: []const u8, page: *Page) !*MediaQuery
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getComputedStyle(_: *const Window, _: *Element, page: *Page) !*CSSStyleDeclaration {
|
pub fn getComputedStyle(_: *const Window, element: *Element, page: *Page) !*CSSStyleProperties {
|
||||||
return CSSStyleDeclaration.init(null, page);
|
return CSSStyleProperties.init(element, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn postMessage(self: *Window, message: js.Object, target_origin: ?[]const u8, page: *Page) !void {
|
pub fn postMessage(self: *Window, message: js.Object, target_origin: ?[]const u8, page: *Page) !void {
|
||||||
|
|||||||
@@ -55,7 +55,9 @@ pub fn item(self: *const CSSStyleDeclaration, index: u32) []const u8 {
|
|||||||
|
|
||||||
pub fn getPropertyValue(self: *const CSSStyleDeclaration, property_name: []const u8, page: *Page) []const u8 {
|
pub fn getPropertyValue(self: *const CSSStyleDeclaration, property_name: []const u8, page: *Page) []const u8 {
|
||||||
const normalized = normalizePropertyName(property_name, &page.buf);
|
const normalized = normalizePropertyName(property_name, &page.buf);
|
||||||
const prop = self.findProperty(normalized) orelse return "";
|
const prop = self.findProperty(normalized) orelse {
|
||||||
|
return getDefaultPropertyValue(self, normalized);
|
||||||
|
};
|
||||||
return prop._value.str();
|
return prop._value.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,6 +194,54 @@ fn normalizePropertyName(name: []const u8, buf: []u8) []const u8 {
|
|||||||
return std.ascii.lowerString(buf, name);
|
return std.ascii.lowerString(buf, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn getDefaultPropertyValue(self: *const CSSStyleDeclaration, normalized_name: []const u8) []const u8 {
|
||||||
|
if (std.mem.eql(u8, normalized_name, "visibility")) {
|
||||||
|
return "visible";
|
||||||
|
}
|
||||||
|
if (std.mem.eql(u8, normalized_name, "opacity")) {
|
||||||
|
return "1";
|
||||||
|
}
|
||||||
|
if (std.mem.eql(u8, normalized_name, "display")) {
|
||||||
|
const element = self._element orelse return "";
|
||||||
|
return getDefaultDisplay(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getDefaultDisplay(element: *const Element) []const u8 {
|
||||||
|
switch (element._type) {
|
||||||
|
.html => |html| {
|
||||||
|
return switch (html._type) {
|
||||||
|
.anchor, .br => "inline",
|
||||||
|
.body, .div, .p, .heading, .form, .button, .canvas, .dialog, .embed, .head, .html, .hr, .iframe, .img, .input, .li, .link, .meta, .ol, .option, .script, .select, .slot, .style, .template, .textarea, .title, .ul, .media => "block",
|
||||||
|
.generic, .custom, .unknown, .data => blk: {
|
||||||
|
const tag = element.getTagNameLower();
|
||||||
|
if (isInlineTag(tag)) break :blk "inline";
|
||||||
|
break :blk "block";
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
.svg => return "inline",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isInlineTag(tag_name: []const u8) bool {
|
||||||
|
const inline_tags = [_][]const u8{
|
||||||
|
"abbr", "b", "bdi", "bdo", "cite", "code", "dfn",
|
||||||
|
"em", "i", "kbd", "mark", "q", "s", "samp",
|
||||||
|
"small", "span", "strong", "sub", "sup", "time", "u",
|
||||||
|
"var", "wbr",
|
||||||
|
};
|
||||||
|
|
||||||
|
for (inline_tags) |inline_tag| {
|
||||||
|
if (std.mem.eql(u8, tag_name, inline_tag)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
pub const Property = struct {
|
pub const Property = struct {
|
||||||
_name: String,
|
_name: String,
|
||||||
_value: String,
|
_value: String,
|
||||||
|
|||||||
@@ -106,6 +106,8 @@ fn isKnownCSSProperty(dash_case: []const u8) bool {
|
|||||||
.{ "width", {} },
|
.{ "width", {} },
|
||||||
.{ "height", {} },
|
.{ "height", {} },
|
||||||
.{ "display", {} },
|
.{ "display", {} },
|
||||||
|
.{ "visibility", {} },
|
||||||
|
.{ "opacity", {} },
|
||||||
.{ "position", {} },
|
.{ "position", {} },
|
||||||
.{ "top", {} },
|
.{ "top", {} },
|
||||||
.{ "bottom", {} },
|
.{ "bottom", {} },
|
||||||
@@ -139,10 +141,14 @@ fn camelCaseToDashCase(name: []const u8, buf: []u8) []const u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for vendor prefixes: webkitTransform -> -webkit-transform
|
// Check for vendor prefixes: webkitTransform -> -webkit-transform
|
||||||
const has_vendor_prefix = name.len > 6 and (std.mem.startsWith(u8, name, "webkit") or
|
// Must have uppercase letter after the prefix
|
||||||
std.mem.startsWith(u8, name, "moz") or
|
const has_vendor_prefix = blk: {
|
||||||
std.mem.startsWith(u8, name, "ms") or
|
if (name.len > 6 and std.mem.startsWith(u8, name, "webkit") and std.ascii.isUpper(name[6])) break :blk true;
|
||||||
std.mem.startsWith(u8, name, "o"));
|
if (name.len > 3 and std.mem.startsWith(u8, name, "moz") and std.ascii.isUpper(name[3])) break :blk true;
|
||||||
|
if (name.len > 2 and std.mem.startsWith(u8, name, "ms") and std.ascii.isUpper(name[2])) break :blk true;
|
||||||
|
if (name.len > 1 and std.mem.startsWith(u8, name, "o") and std.ascii.isUpper(name[1])) break :blk true;
|
||||||
|
break :blk false;
|
||||||
|
};
|
||||||
|
|
||||||
var write_pos: usize = 0;
|
var write_pos: usize = 0;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user