mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-14 15:28:57 +00:00
219 lines
4.1 KiB
Markdown
219 lines
4.1 KiB
Markdown
# css
|
|
|
|
Lightpanda css implements CSS selectors parsing and matching in Zig.
|
|
This package is a port of the Go lib [andybalholm/cascadia](https://github.com/andybalholm/cascadia).
|
|
|
|
## Usage
|
|
|
|
### Query parser
|
|
|
|
```zig
|
|
const css = @import("css.zig");
|
|
|
|
const selector = try css.parse(alloc, "h1", .{});
|
|
defer selector.deinit(alloc);
|
|
```
|
|
|
|
### DOM tree match
|
|
|
|
The lib expects a `Node` interface implementation to match your DOM tree.
|
|
|
|
```zig
|
|
pub const Node = struct {
|
|
pub fn firstChild(_: Node) !?Node {
|
|
return error.TODO;
|
|
}
|
|
|
|
pub fn lastChild(_: Node) !?Node {
|
|
return error.TODO;
|
|
}
|
|
|
|
pub fn nextSibling(_: Node) !?Node {
|
|
return error.TODO;
|
|
}
|
|
|
|
pub fn prevSibling(_: Node) !?Node {
|
|
return error.TODO;
|
|
}
|
|
|
|
pub fn parent(_: Node) !?Node {
|
|
return error.TODO;
|
|
}
|
|
|
|
pub fn isElement(_: Node) bool {
|
|
return false;
|
|
}
|
|
|
|
pub fn isDocument(_: Node) bool {
|
|
return false;
|
|
}
|
|
|
|
pub fn isComment(_: Node) bool {
|
|
return false;
|
|
}
|
|
|
|
pub fn isText(_: Node) bool {
|
|
return false;
|
|
}
|
|
|
|
pub fn isEmptyText(_: Node) !bool {
|
|
return error.TODO;
|
|
}
|
|
|
|
pub fn tag(_: Node) ![]const u8 {
|
|
return error.TODO;
|
|
}
|
|
|
|
pub fn attr(_: Node, _: []const u8) !?[]const u8 {
|
|
return error.TODO;
|
|
}
|
|
|
|
pub fn eql(_: Node, _: Node) bool {
|
|
return false;
|
|
}
|
|
};
|
|
```
|
|
|
|
You also need do define a `Matcher` implementing a `match` function to
|
|
accumulate the results.
|
|
|
|
```zig
|
|
const Matcher = struct {
|
|
const Nodes = std.ArrayList(Node);
|
|
|
|
nodes: Nodes,
|
|
|
|
fn init(alloc: std.mem.Allocator) Matcher {
|
|
return .{ .nodes = Nodes.init(alloc) };
|
|
}
|
|
|
|
fn deinit(m: *Matcher) void {
|
|
m.nodes.deinit();
|
|
}
|
|
|
|
pub fn match(m: *Matcher, n: Node) !void {
|
|
try m.nodes.append(n);
|
|
}
|
|
};
|
|
```
|
|
|
|
Then you can use the lib itself.
|
|
|
|
```zig
|
|
var matcher = Matcher.init(alloc);
|
|
defer matcher.deinit();
|
|
|
|
try css.matchAll(selector, node, &matcher);
|
|
_ = try css.matchFirst(selector, node, &matcher); // returns true if a node matched.
|
|
```
|
|
|
|
## Features
|
|
|
|
* [x] parse query selector
|
|
* [x] `matchAll`
|
|
* [x] `matchFirst`
|
|
* [ ] specificity
|
|
|
|
### Selectors implemented
|
|
|
|
#### Selectors
|
|
|
|
* [x] Class selectors
|
|
* [x] Id selectors
|
|
* [x] Type selectors
|
|
* [x] Universal selectors
|
|
* [ ] Nesting selectors
|
|
|
|
#### Combinators
|
|
|
|
* [x] Child combinator
|
|
* [ ] Column combinator
|
|
* [x] Descendant combinator
|
|
* [ ] Namespace combinator
|
|
* [x] Next-sibling combinator
|
|
* [x] Selector list combinator
|
|
* [x] Subsequent-sibling combinator
|
|
|
|
#### Attribute
|
|
|
|
* [x] `[attr]`
|
|
* [x] `[attr=value]`
|
|
* [x] `[attr|=value]`
|
|
* [x] `[attr^=value]`
|
|
* [x] `[attr$=value]`
|
|
* [ ] `[attr*=value]`
|
|
* [x] `[attr operator value i]`
|
|
* [ ] `[attr operator value s]`
|
|
|
|
#### Pseudo classes
|
|
|
|
* [ ] `:active`
|
|
* [ ] `:any-link`
|
|
* [ ] `:autofill`
|
|
* [ ] `:blank Experimental`
|
|
* [x] `:checked`
|
|
* [ ] `:current Experimental`
|
|
* [ ] `:default`
|
|
* [ ] `:defined`
|
|
* [ ] `:dir() Experimental`
|
|
* [x] `:disabled`
|
|
* [x] `:empty`
|
|
* [x] `:enabled`
|
|
* [ ] `:first`
|
|
* [x] `:first-child`
|
|
* [x] `:first-of-type`
|
|
* [ ] `:focus`
|
|
* [ ] `:focus-visible`
|
|
* [ ] `:focus-within`
|
|
* [ ] `:fullscreen`
|
|
* [ ] `:future Experimental`
|
|
* [x] `:has() Experimental`
|
|
* [ ] `:host`
|
|
* [ ] `:host()`
|
|
* [ ] `:host-context() Experimental`
|
|
* [ ] `:hover`
|
|
* [ ] `:indeterminate`
|
|
* [ ] `:in-range`
|
|
* [ ] `:invalid`
|
|
* [ ] `:is()`
|
|
* [x] `:lang()`
|
|
* [x] `:last-child`
|
|
* [x] `:last-of-type`
|
|
* [ ] `:left`
|
|
* [x] `:link`
|
|
* [ ] `:local-link Experimental`
|
|
* [ ] `:modal`
|
|
* [x] `:not()`
|
|
* [x] `:nth-child()`
|
|
* [x] `:nth-last-child()`
|
|
* [x] `:nth-last-of-type()`
|
|
* [x] `:nth-of-type()`
|
|
* [x] `:only-child`
|
|
* [x] `:only-of-type`
|
|
* [ ] `:optional`
|
|
* [ ] `:out-of-range`
|
|
* [ ] `:past Experimental`
|
|
* [ ] `:paused`
|
|
* [ ] `:picture-in-picture`
|
|
* [ ] `:placeholder-shown`
|
|
* [ ] `:playing`
|
|
* [ ] `:read-only`
|
|
* [ ] `:read-write`
|
|
* [ ] `:required`
|
|
* [ ] `:right`
|
|
* [x] `:root`
|
|
* [ ] `:scope`
|
|
* [ ] `:state() Experimental`
|
|
* [ ] `:target`
|
|
* [ ] `:target-within Experimental`
|
|
* [ ] `:user-invalid Experimental`
|
|
* [ ] `:valid`
|
|
* [ ] `:visited`
|
|
* [ ] `:where()`
|
|
* [ ] `:contains()`
|
|
* [ ] `:containsown()`
|
|
* [ ] `:matched()`
|
|
* [ ] `:matchesown()`
|
|
* [x] `:root`
|
|
|