mirror of
https://github.com/oven-sh/bun
synced 2026-02-28 20:40:59 +01:00
Removed all 194 occurrences of `// autofix` comments across 46 files. These comments marked where `_ = variable;` statements were automatically added to suppress unused variable warnings. The discard statements remain, only the comment suffix is removed. Updated ban-limits.json to enforce this going forward (set to 0). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
950 lines
38 KiB
Zig
950 lines
38 KiB
Zig
pub const css = @import("../css_parser.zig");
|
|
|
|
const Printer = css.Printer;
|
|
const PrintErr = css.PrintErr;
|
|
|
|
const Property = css.Property;
|
|
const PropertyId = css.PropertyId;
|
|
|
|
const CSSNumberFns = css.css_values.number.CSSNumberFns;
|
|
const LengthPercentage = css.css_values.length.LengthPercentage;
|
|
const CSSNumber = css.css_values.number.CSSNumber;
|
|
const LengthPercentageOrAuto = css.css_values.length.LengthPercentageOrAuto;
|
|
const Length = css.css_values.length.LengthValue;
|
|
const CSSInteger = css.css_values.number.CSSInteger;
|
|
|
|
const isFlex2009 = css.prefixes.Feature.isFlex2009;
|
|
|
|
const VendorPrefix = css.VendorPrefix;
|
|
|
|
/// A value for the [flex-direction](https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#propdef-flex-direction) property.
|
|
/// A value for the [flex-direction](https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#propdef-flex-direction) property.
|
|
pub const FlexDirection = enum {
|
|
/// Flex items are laid out in a row.
|
|
row,
|
|
/// Flex items are laid out in a row, and reversed.
|
|
@"row-reverse",
|
|
/// Flex items are laid out in a column.
|
|
column,
|
|
/// Flex items are laid out in a column, and reversed.
|
|
@"column-reverse",
|
|
|
|
const css_impl = css.DefineEnumProperty(@This());
|
|
pub const eql = css_impl.eql;
|
|
pub const hash = css_impl.hash;
|
|
pub const parse = css_impl.parse;
|
|
pub const toCss = css_impl.toCss;
|
|
pub const deepClone = css_impl.deepClone;
|
|
|
|
pub fn default() FlexDirection {
|
|
return .row;
|
|
}
|
|
|
|
pub fn to2009(this: *const FlexDirection) struct { BoxOrient, BoxDirection } {
|
|
return switch (this.*) {
|
|
.row => .{ .horizontal, .normal },
|
|
.column => .{ .vertical, .normal },
|
|
.@"row-reverse" => .{ .horizontal, .reverse },
|
|
.@"column-reverse" => .{ .vertical, .reverse },
|
|
};
|
|
}
|
|
};
|
|
|
|
/// A value for the [flex-wrap](https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#flex-wrap-property) property.
|
|
/// A value for the [flex-wrap](https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#flex-wrap-property) property.
|
|
pub const FlexWrap = enum {
|
|
/// The flex items do not wrap.
|
|
nowrap,
|
|
/// The flex items wrap.
|
|
wrap,
|
|
/// The flex items wrap, in reverse.
|
|
@"wrap-reverse",
|
|
|
|
const css_impl = css.DefineEnumProperty(@This());
|
|
pub const eql = css_impl.eql;
|
|
pub const hash = css_impl.hash;
|
|
pub const parse = css_impl.parse;
|
|
pub const toCss = css_impl.toCss;
|
|
pub const deepClone = css_impl.deepClone;
|
|
|
|
pub fn default() FlexWrap {
|
|
return .nowrap;
|
|
}
|
|
|
|
pub fn fromStandard(this: *const FlexWrap) ?FlexWrap {
|
|
return this;
|
|
}
|
|
};
|
|
|
|
/// A value for the [flex-flow](https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#flex-flow-property) shorthand property.
|
|
pub const FlexFlow = struct {
|
|
/// The direction that flex items flow.
|
|
direction: FlexDirection,
|
|
/// How the flex items wrap.
|
|
wrap: FlexWrap,
|
|
|
|
// (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"flex-flow", PropertyFieldMap);
|
|
|
|
pub const PropertyFieldMap = .{
|
|
.direction = css.PropertyIdTag.@"flex-direction",
|
|
.wrap = css.PropertyIdTag.@"flex-wrap",
|
|
};
|
|
|
|
pub const VendorPrefixMap = .{
|
|
.direction = true,
|
|
.wrap = true,
|
|
};
|
|
|
|
pub fn parse(input: *css.Parser) css.Result(@This()) {
|
|
var direction: ?FlexDirection = null;
|
|
var wrap: ?FlexWrap = null;
|
|
|
|
while (true) {
|
|
if (direction == null) {
|
|
if (input.tryParse(FlexDirection.parse, .{}).asValue()) |value| {
|
|
direction = value;
|
|
continue;
|
|
}
|
|
}
|
|
if (wrap == null) {
|
|
if (input.tryParse(FlexWrap.parse, .{}).asValue()) |value| {
|
|
wrap = value;
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return .{
|
|
.result = FlexFlow{
|
|
.direction = direction orelse FlexDirection.row,
|
|
.wrap = wrap orelse FlexWrap.nowrap,
|
|
},
|
|
};
|
|
}
|
|
|
|
pub fn toCss(this: *const FlexFlow, comptime W: type, dest: *css.Printer(W)) css.PrintErr!void {
|
|
var needs_space = false;
|
|
if (!this.direction.eql(&FlexDirection.default()) or this.wrap.eql(&FlexWrap.default())) {
|
|
try this.direction.toCss(W, dest);
|
|
needs_space = true;
|
|
}
|
|
|
|
if (!this.wrap.eql(&FlexWrap.default())) {
|
|
if (needs_space) {
|
|
try dest.writeStr(" ");
|
|
}
|
|
try this.wrap.toCss(W, dest);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() {
|
|
return css.implementDeepClone(@This(), this, allocator);
|
|
}
|
|
|
|
pub fn eql(lhs: *const @This(), rhs: *const @This()) bool {
|
|
return css.implementEql(@This(), lhs, rhs);
|
|
}
|
|
};
|
|
|
|
/// A value for the [flex](https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#flex-property) shorthand property.
|
|
/// A value for the [flex](https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#flex-property) shorthand property.
|
|
pub const Flex = struct {
|
|
/// The flex grow factor.
|
|
grow: CSSNumber,
|
|
/// The flex shrink factor.
|
|
shrink: CSSNumber,
|
|
/// The flex basis.
|
|
basis: LengthPercentageOrAuto,
|
|
|
|
// (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.flex, PropertyFieldMap);
|
|
|
|
pub const PropertyFieldMap = .{
|
|
.grow = css.PropertyIdTag.@"flex-grow",
|
|
.shrink = css.PropertyIdTag.@"flex-shrink",
|
|
.basis = css.PropertyIdTag.@"flex-basis",
|
|
};
|
|
|
|
pub const VendorPrefixMap = .{
|
|
.grow = true,
|
|
.shrink = true,
|
|
.basis = true,
|
|
};
|
|
|
|
pub fn parse(input: *css.Parser) css.Result(@This()) {
|
|
if (input.tryParse(css.Parser.expectIdentMatching, .{"none"}).isOk()) {
|
|
return .{
|
|
.result = .{
|
|
.grow = 0.0,
|
|
.shrink = 0.0,
|
|
.basis = LengthPercentageOrAuto.auto,
|
|
},
|
|
};
|
|
}
|
|
|
|
var grow: ?CSSNumber = null;
|
|
var shrink: ?CSSNumber = null;
|
|
var basis: ?LengthPercentageOrAuto = null;
|
|
|
|
while (true) {
|
|
if (grow == null) {
|
|
if (input.tryParse(CSSNumberFns.parse, .{}).asValue()) |value| {
|
|
grow = value;
|
|
shrink = input.tryParse(CSSNumberFns.parse, .{}).asValue();
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (basis == null) {
|
|
if (input.tryParse(LengthPercentageOrAuto.parse, .{}).asValue()) |value| {
|
|
basis = value;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return .{
|
|
.result = .{
|
|
.grow = grow orelse 1.0,
|
|
.shrink = shrink orelse 1.0,
|
|
.basis = basis orelse LengthPercentageOrAuto{ .length = LengthPercentage{ .percentage = .{ .v = 0.0 } } },
|
|
},
|
|
};
|
|
}
|
|
|
|
pub fn toCss(this: *const Flex, comptime W: type, dest: *css.Printer(W)) css.PrintErr!void {
|
|
if (this.grow == 0.0 and this.shrink == 0.0 and this.basis == .auto) {
|
|
try dest.writeStr("none");
|
|
return;
|
|
}
|
|
|
|
const ZeroKind = enum {
|
|
NonZero,
|
|
Length,
|
|
Percentage,
|
|
};
|
|
|
|
// If the basis is unitless 0, we must write all three components to disambiguate.
|
|
// If the basis is 0%, we can omit the basis.
|
|
const basis_kind = switch (this.basis) {
|
|
.length => |lp| brk: {
|
|
if (lp == .dimension and lp.dimension.isZero()) break :brk ZeroKind.Length;
|
|
if (lp == .percentage and lp.percentage.isZero()) break :brk ZeroKind.Percentage;
|
|
break :brk ZeroKind.NonZero;
|
|
},
|
|
else => ZeroKind.NonZero,
|
|
};
|
|
|
|
if (this.grow != 1.0 or this.shrink != 1.0 or basis_kind != .NonZero) {
|
|
try CSSNumberFns.toCss(&this.grow, W, dest);
|
|
if (this.shrink != 1.0 or basis_kind == .Length) {
|
|
try dest.writeStr(" ");
|
|
try CSSNumberFns.toCss(&this.shrink, W, dest);
|
|
}
|
|
}
|
|
|
|
if (basis_kind != .Percentage) {
|
|
if (this.grow != 1.0 or this.shrink != 1.0 or basis_kind == .Length) {
|
|
try dest.writeStr(" ");
|
|
}
|
|
try this.basis.toCss(W, dest);
|
|
}
|
|
}
|
|
|
|
pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() {
|
|
return css.implementDeepClone(@This(), this, allocator);
|
|
}
|
|
|
|
pub fn eql(lhs: *const @This(), rhs: *const @This()) bool {
|
|
return css.implementEql(@This(), lhs, rhs);
|
|
}
|
|
};
|
|
|
|
/// A value for the legacy (prefixed) [box-orient](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#orientation) property.
|
|
/// Partially equivalent to `flex-direction` in the standard syntax.
|
|
/// A value for the legacy (prefixed) [box-orient](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#orientation) property.
|
|
/// Partially equivalent to `flex-direction` in the standard syntax.
|
|
pub const BoxOrient = enum {
|
|
/// Items are laid out horizontally.
|
|
horizontal,
|
|
/// Items are laid out vertically.
|
|
vertical,
|
|
/// Items are laid out along the inline axis, according to the writing direction.
|
|
@"inline-axis",
|
|
/// Items are laid out along the block axis, according to the writing direction.
|
|
@"block-axis",
|
|
|
|
const css_impl = css.DefineEnumProperty(@This());
|
|
pub const eql = css_impl.eql;
|
|
pub const hash = css_impl.hash;
|
|
pub const parse = css_impl.parse;
|
|
pub const toCss = css_impl.toCss;
|
|
pub const deepClone = css_impl.deepClone;
|
|
};
|
|
|
|
/// A value for the legacy (prefixed) [box-direction](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#displayorder) property.
|
|
/// Partially equivalent to the `flex-direction` property in the standard syntax.
|
|
pub const BoxDirection = enum {
|
|
/// Items flow in the natural direction.
|
|
normal,
|
|
/// Items flow in the reverse direction.
|
|
reverse,
|
|
|
|
const css_impl = css.DefineEnumProperty(@This());
|
|
pub const eql = css_impl.eql;
|
|
pub const hash = css_impl.hash;
|
|
pub const parse = css_impl.parse;
|
|
pub const toCss = css_impl.toCss;
|
|
pub const deepClone = css_impl.deepClone;
|
|
};
|
|
|
|
pub const FlexAlign = BoxAlign;
|
|
|
|
/// A value for the legacy (prefixed) [box-align](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#alignment) property.
|
|
/// Equivalent to the `align-items` property in the standard syntax.
|
|
/// A value for the legacy (prefixed) [box-align](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#alignment) property.
|
|
/// Equivalent to the `align-items` property in the standard syntax.
|
|
pub const BoxAlign = enum {
|
|
/// Items are aligned to the start.
|
|
start,
|
|
/// Items are aligned to the end.
|
|
end,
|
|
/// Items are centered.
|
|
center,
|
|
/// Items are aligned to the baseline.
|
|
baseline,
|
|
/// Items are stretched.
|
|
stretch,
|
|
|
|
const css_impl = css.DefineEnumProperty(@This());
|
|
pub const eql = css_impl.eql;
|
|
pub const hash = css_impl.hash;
|
|
pub const parse = css_impl.parse;
|
|
pub const toCss = css_impl.toCss;
|
|
pub const deepClone = css_impl.deepClone;
|
|
|
|
pub fn fromStandard(@"align": *const css.css_properties.@"align".AlignItems) ?BoxAlign {
|
|
return switch (@"align".*) {
|
|
.self_position => |sp| if (sp.overflow == null) switch (sp.value) {
|
|
.start, .@"flex-start" => .start,
|
|
.end, .@"flex-end" => .end,
|
|
.center => .center,
|
|
else => null,
|
|
} else null,
|
|
.stretch => .stretch,
|
|
else => null,
|
|
};
|
|
}
|
|
};
|
|
|
|
/// A value for the legacy (prefixed) [box-pack](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#packing) property.
|
|
/// Equivalent to the `justify-content` property in the standard syntax.
|
|
/// A value for the legacy (prefixed) [box-pack](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#packing) property.
|
|
/// Equivalent to the `justify-content` property in the standard syntax.
|
|
pub const BoxPack = enum {
|
|
/// Items are justified to the start.
|
|
start,
|
|
/// Items are justified to the end.
|
|
end,
|
|
/// Items are centered.
|
|
center,
|
|
/// Items are justified to the start and end.
|
|
justify,
|
|
|
|
const css_impl = css.DefineEnumProperty(@This());
|
|
pub const eql = css_impl.eql;
|
|
pub const hash = css_impl.hash;
|
|
pub const parse = css_impl.parse;
|
|
pub const toCss = css_impl.toCss;
|
|
pub const deepClone = css_impl.deepClone;
|
|
|
|
pub fn fromStandard(justify: *const css.css_properties.@"align".JustifyContent) ?BoxPack {
|
|
return switch (justify.*) {
|
|
.content_distribution => |cd| switch (cd) {
|
|
.@"space-between" => .justify,
|
|
else => null,
|
|
},
|
|
.content_position => |cp| if (cp.overflow == null) switch (cp.value) {
|
|
.start, .@"flex-start" => .start,
|
|
.end, .@"flex-end" => .end,
|
|
.center => .center,
|
|
} else null,
|
|
else => null,
|
|
};
|
|
}
|
|
};
|
|
|
|
/// A value for the legacy (prefixed) [box-lines](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#multiple) property.
|
|
/// Equivalent to the `flex-wrap` property in the standard syntax.
|
|
/// A value for the legacy (prefixed) [box-lines](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#multiple) property.
|
|
/// Equivalent to the `flex-wrap` property in the standard syntax.
|
|
pub const BoxLines = enum {
|
|
/// Items are laid out in a single line.
|
|
single,
|
|
/// Items may wrap into multiple lines.
|
|
multiple,
|
|
|
|
const css_impl = css.DefineEnumProperty(@This());
|
|
pub const eql = css_impl.eql;
|
|
pub const hash = css_impl.hash;
|
|
pub const parse = css_impl.parse;
|
|
pub const toCss = css_impl.toCss;
|
|
pub const deepClone = css_impl.deepClone;
|
|
|
|
pub fn fromStandard(wrap: *const FlexWrap) ?BoxLines {
|
|
return switch (wrap.*) {
|
|
.nowrap => .single,
|
|
.wrap => .multiple,
|
|
else => null,
|
|
};
|
|
}
|
|
};
|
|
|
|
// Old flex (2012): https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/
|
|
/// A value for the legacy (prefixed) [flex-pack](https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-pack) property.
|
|
/// Equivalent to the `justify-content` property in the standard syntax.
|
|
/// A value for the legacy (prefixed) [flex-pack](https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-pack) property.
|
|
/// Equivalent to the `justify-content` property in the standard syntax.
|
|
pub const FlexPack = enum {
|
|
/// Items are justified to the start.
|
|
start,
|
|
/// Items are justified to the end.
|
|
end,
|
|
/// Items are centered.
|
|
center,
|
|
/// Items are justified to the start and end.
|
|
justify,
|
|
/// Items are distributed evenly, with half size spaces on either end.
|
|
distribute,
|
|
|
|
const css_impl = css.DefineEnumProperty(@This());
|
|
pub const eql = css_impl.eql;
|
|
pub const hash = css_impl.hash;
|
|
pub const parse = css_impl.parse;
|
|
pub const toCss = css_impl.toCss;
|
|
pub const deepClone = css_impl.deepClone;
|
|
|
|
pub fn fromStandard(justify: *const css.css_properties.@"align".JustifyContent) ?FlexPack {
|
|
return switch (justify.*) {
|
|
.content_distribution => |cd| switch (cd) {
|
|
.@"space-between" => .justify,
|
|
.@"space-around" => .distribute,
|
|
else => null,
|
|
},
|
|
.content_position => |cp| if (cp.overflow == null) switch (cp.value) {
|
|
.start, .@"flex-start" => .start,
|
|
.end, .@"flex-end" => .end,
|
|
.center => .center,
|
|
} else null,
|
|
else => null,
|
|
};
|
|
}
|
|
};
|
|
|
|
/// A value for the legacy (prefixed) [flex-item-align](https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-align) property.
|
|
/// Equivalent to the `align-self` property in the standard syntax.
|
|
/// A value for the legacy (prefixed) [flex-item-align](https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-align) property.
|
|
/// Equivalent to the `align-self` property in the standard syntax.
|
|
pub const FlexItemAlign = enum {
|
|
/// Equivalent to the value of `flex-align`.
|
|
auto,
|
|
/// The item is aligned to the start.
|
|
start,
|
|
/// The item is aligned to the end.
|
|
end,
|
|
/// The item is centered.
|
|
center,
|
|
/// The item is aligned to the baseline.
|
|
baseline,
|
|
/// The item is stretched.
|
|
stretch,
|
|
|
|
const css_impl = css.DefineEnumProperty(@This());
|
|
pub const eql = css_impl.eql;
|
|
pub const hash = css_impl.hash;
|
|
pub const parse = css_impl.parse;
|
|
pub const toCss = css_impl.toCss;
|
|
pub const deepClone = css_impl.deepClone;
|
|
|
|
pub fn fromStandard(justify: *const css.css_properties.@"align".AlignSelf) ?FlexItemAlign {
|
|
return switch (justify.*) {
|
|
.auto => .auto,
|
|
.stretch => .stretch,
|
|
.self_position => |sp| if (sp.overflow == null) switch (sp.value) {
|
|
.start, .@"flex-start" => .start,
|
|
.end, .@"flex-end" => .end,
|
|
.center => .center,
|
|
else => null,
|
|
} else null,
|
|
else => null,
|
|
};
|
|
}
|
|
};
|
|
|
|
/// A value for the legacy (prefixed) [flex-line-pack](https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-line-pack) property.
|
|
/// Equivalent to the `align-content` property in the standard syntax.
|
|
/// A value for the legacy (prefixed) [flex-line-pack](https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-line-pack) property.
|
|
/// Equivalent to the `align-content` property in the standard syntax.
|
|
pub const FlexLinePack = enum {
|
|
/// Content is aligned to the start.
|
|
start,
|
|
/// Content is aligned to the end.
|
|
end,
|
|
/// Content is centered.
|
|
center,
|
|
/// Content is justified.
|
|
justify,
|
|
/// Content is distributed evenly, with half size spaces on either end.
|
|
distribute,
|
|
/// Content is stretched.
|
|
stretch,
|
|
|
|
const css_impl = css.DefineEnumProperty(@This());
|
|
pub const eql = css_impl.eql;
|
|
pub const hash = css_impl.hash;
|
|
pub const parse = css_impl.parse;
|
|
pub const toCss = css_impl.toCss;
|
|
pub const deepClone = css_impl.deepClone;
|
|
|
|
pub fn fromStandard(justify: *const css.css_properties.@"align".AlignContent) ?FlexLinePack {
|
|
return switch (justify.*) {
|
|
.content_distribution => |cd| switch (cd) {
|
|
.@"space-between" => .justify,
|
|
.@"space-around" => .distribute,
|
|
.stretch => .stretch,
|
|
else => null,
|
|
},
|
|
.content_position => |cp| if (cp.overflow == null) switch (cp.value) {
|
|
.start, .@"flex-start" => .start,
|
|
.end, .@"flex-end" => .end,
|
|
.center => .center,
|
|
} else null,
|
|
else => null,
|
|
};
|
|
}
|
|
};
|
|
|
|
pub const BoxOrdinalGroup = CSSInteger;
|
|
|
|
// A handler for flex-related properties that manages both standard and legacy vendor prefixed values.
|
|
pub const FlexHandler = struct {
|
|
/// The flex-direction property value and vendor prefix
|
|
direction: ?struct { FlexDirection, VendorPrefix } = null,
|
|
/// The box-orient property value and vendor prefix (legacy)
|
|
box_orient: ?struct { BoxOrient, VendorPrefix } = null,
|
|
/// The box-direction property value and vendor prefix (legacy)
|
|
box_direction: ?struct { BoxDirection, VendorPrefix } = null,
|
|
/// The flex-wrap property value and vendor prefix
|
|
wrap: ?struct { FlexWrap, VendorPrefix } = null,
|
|
/// The box-lines property value and vendor prefix (legacy)
|
|
box_lines: ?struct { BoxLines, VendorPrefix } = null,
|
|
/// The flex-grow property value and vendor prefix
|
|
grow: ?struct { CSSNumber, VendorPrefix } = null,
|
|
/// The box-flex property value and vendor prefix (legacy)
|
|
box_flex: ?struct { CSSNumber, VendorPrefix } = null,
|
|
/// The flex-positive property value and vendor prefix (legacy)
|
|
flex_positive: ?struct { CSSNumber, VendorPrefix } = null,
|
|
/// The flex-shrink property value and vendor prefix
|
|
shrink: ?struct { CSSNumber, VendorPrefix } = null,
|
|
/// The flex-negative property value and vendor prefix (legacy)
|
|
flex_negative: ?struct { CSSNumber, VendorPrefix } = null,
|
|
/// The flex-basis property value and vendor prefix
|
|
basis: ?struct { LengthPercentageOrAuto, VendorPrefix } = null,
|
|
/// The preferred-size property value and vendor prefix (legacy)
|
|
preferred_size: ?struct { LengthPercentageOrAuto, VendorPrefix } = null,
|
|
/// The order property value and vendor prefix
|
|
order: ?struct { CSSInteger, VendorPrefix } = null,
|
|
/// The box-ordinal-group property value and vendor prefix (legacy)
|
|
box_ordinal_group: ?struct { BoxOrdinalGroup, VendorPrefix } = null,
|
|
/// The flex-order property value and vendor prefix (legacy)
|
|
flex_order: ?struct { CSSInteger, VendorPrefix } = null,
|
|
/// Whether any flex-related properties have been set
|
|
has_any: bool = false,
|
|
|
|
pub fn handleProperty(
|
|
this: *@This(),
|
|
property: *const Property,
|
|
dest: *css.DeclarationList,
|
|
context: *css.PropertyHandlerContext,
|
|
) bool {
|
|
const maybeFlush = struct {
|
|
fn maybeFlush(
|
|
self: *FlexHandler,
|
|
d: *css.DeclarationList,
|
|
ctx: *css.PropertyHandlerContext,
|
|
comptime prop: []const u8,
|
|
val: anytype,
|
|
vp: *const VendorPrefix,
|
|
) void {
|
|
// If two vendor prefixes for the same property have different
|
|
// values, we need to flush what we have immediately to preserve order.
|
|
if (@field(self, prop)) |*field| {
|
|
if (!std.meta.eql(field[0], val.*) and !bun.bits.contains(css.VendorPrefix, field[1], vp.*)) {
|
|
self.flush(d, ctx);
|
|
}
|
|
}
|
|
}
|
|
}.maybeFlush;
|
|
|
|
const propertyHelper = struct {
|
|
fn propertyHelper(
|
|
self: *FlexHandler,
|
|
ctx: *css.PropertyHandlerContext,
|
|
d: *css.DeclarationList,
|
|
comptime prop: []const u8,
|
|
val: anytype,
|
|
vp: *const VendorPrefix,
|
|
) void {
|
|
maybeFlush(self, d, ctx, prop, val, vp);
|
|
|
|
// Otherwise, update the value and add the prefix
|
|
if (@field(self, prop)) |*field| {
|
|
field[0] = css.generic.deepClone(@TypeOf(val.*), val, ctx.allocator);
|
|
bun.bits.insert(css.VendorPrefix, &field[1], vp.*);
|
|
} else {
|
|
@field(self, prop) = .{
|
|
css.generic.deepClone(@TypeOf(val.*), val, ctx.allocator),
|
|
vp.*,
|
|
};
|
|
self.has_any = true;
|
|
}
|
|
}
|
|
}.propertyHelper;
|
|
|
|
switch (property.*) {
|
|
.@"flex-direction" => |*val| {
|
|
if (context.targets.browsers != null) {
|
|
this.box_direction = null;
|
|
this.box_orient = null;
|
|
}
|
|
propertyHelper(this, context, dest, "direction", &val[0], &val[1]);
|
|
},
|
|
.@"box-orient" => |*val| propertyHelper(this, context, dest, "box_orient", &val[0], &val[1]),
|
|
.@"box-direction" => |*val| propertyHelper(this, context, dest, "box_direction", &val[0], &val[1]),
|
|
.@"flex-wrap" => |*val| {
|
|
if (context.targets.browsers != null) {
|
|
this.box_lines = null;
|
|
}
|
|
propertyHelper(this, context, dest, "wrap", &val[0], &val[1]);
|
|
},
|
|
.@"box-lines" => |*val| propertyHelper(this, context, dest, "box_lines", &val[0], &val[1]),
|
|
.@"flex-flow" => |*val| {
|
|
if (context.targets.browsers != null) {
|
|
this.box_direction = null;
|
|
this.box_orient = null;
|
|
}
|
|
propertyHelper(this, context, dest, "direction", &val[0].direction, &val[1]);
|
|
propertyHelper(this, context, dest, "wrap", &val[0].wrap, &val[1]);
|
|
},
|
|
.@"flex-grow" => |*val| {
|
|
if (context.targets.browsers != null) {
|
|
this.box_flex = null;
|
|
this.flex_positive = null;
|
|
}
|
|
propertyHelper(this, context, dest, "grow", &val[0], &val[1]);
|
|
},
|
|
.@"box-flex" => |*val| propertyHelper(this, context, dest, "box_flex", &val[0], &val[1]),
|
|
.@"flex-positive" => |*val| propertyHelper(this, context, dest, "flex_positive", &val[0], &val[1]),
|
|
.@"flex-shrink" => |*val| {
|
|
if (context.targets.browsers != null) {
|
|
this.flex_negative = null;
|
|
}
|
|
propertyHelper(this, context, dest, "shrink", &val[0], &val[1]);
|
|
},
|
|
.@"flex-negative" => |*val| propertyHelper(this, context, dest, "flex_negative", &val[0], &val[1]),
|
|
.@"flex-basis" => |*val| {
|
|
if (context.targets.browsers != null) {
|
|
this.preferred_size = null;
|
|
}
|
|
propertyHelper(this, context, dest, "basis", &val[0], &val[1]);
|
|
},
|
|
.@"flex-preferred-size" => |*val| propertyHelper(this, context, dest, "preferred_size", &val[0], &val[1]),
|
|
.flex => |*val| {
|
|
if (context.targets.browsers != null) {
|
|
this.box_flex = null;
|
|
this.flex_positive = null;
|
|
this.flex_negative = null;
|
|
this.preferred_size = null;
|
|
}
|
|
maybeFlush(this, dest, context, "grow", &val[0].grow, &val[1]);
|
|
maybeFlush(this, dest, context, "shrink", &val[0].shrink, &val[1]);
|
|
maybeFlush(this, dest, context, "basis", &val[0].basis, &val[1]);
|
|
propertyHelper(this, context, dest, "grow", &val[0].grow, &val[1]);
|
|
propertyHelper(this, context, dest, "shrink", &val[0].shrink, &val[1]);
|
|
propertyHelper(this, context, dest, "basis", &val[0].basis, &val[1]);
|
|
},
|
|
.order => |*val| {
|
|
if (context.targets.browsers != null) {
|
|
this.box_ordinal_group = null;
|
|
this.flex_order = null;
|
|
}
|
|
propertyHelper(this, context, dest, "order", &val[0], &val[1]);
|
|
},
|
|
.@"box-ordinal-group" => |*val| propertyHelper(this, context, dest, "box_ordinal_group", &val[0], &val[1]),
|
|
.@"flex-order" => |*val| propertyHelper(this, context, dest, "flex_order", &val[0], &val[1]),
|
|
.unparsed => |*val| {
|
|
if (isFlexProperty(&val.property_id)) {
|
|
this.flush(dest, context);
|
|
dest.append(context.allocator, property.deepClone(context.allocator)) catch unreachable;
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
else => return false,
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
pub fn finalize(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void {
|
|
this.flush(dest, context);
|
|
}
|
|
|
|
fn flush(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void {
|
|
if (!this.has_any) {
|
|
return;
|
|
}
|
|
|
|
this.has_any = false;
|
|
|
|
var direction: ?struct { FlexDirection, VendorPrefix } = bun.take(&this.direction);
|
|
var wrap: ?struct { FlexWrap, VendorPrefix } = bun.take(&this.wrap);
|
|
var grow: ?struct { CSSNumber, VendorPrefix } = bun.take(&this.grow);
|
|
var shrink: ?struct { CSSNumber, VendorPrefix } = bun.take(&this.shrink);
|
|
var basis = bun.take(&this.basis);
|
|
var box_orient = bun.take(&this.box_orient);
|
|
var box_direction = bun.take(&this.box_direction);
|
|
var box_flex = bun.take(&this.box_flex);
|
|
var box_ordinal_group = bun.take(&this.box_ordinal_group);
|
|
var box_lines = bun.take(&this.box_lines);
|
|
var flex_positive = bun.take(&this.flex_positive);
|
|
var flex_negative = bun.take(&this.flex_negative);
|
|
var preferred_size = bun.take(&this.preferred_size);
|
|
var order = bun.take(&this.order);
|
|
var flex_order = bun.take(&this.flex_order);
|
|
|
|
// Legacy properties. These are only set if the final standard properties were unset.
|
|
legacyProperty(this, "box-orient", bun.take(&box_orient), dest, context);
|
|
legacyProperty(this, "box-direction", bun.take(&box_direction), dest, context);
|
|
legacyProperty(this, "box-ordinal-group", bun.take(&box_ordinal_group), dest, context);
|
|
legacyProperty(this, "box-flex", bun.take(&box_flex), dest, context);
|
|
legacyProperty(this, "box-lines", bun.take(&box_lines), dest, context);
|
|
legacyProperty(this, "flex-positive", bun.take(&flex_positive), dest, context);
|
|
legacyProperty(this, "flex-negative", bun.take(&flex_negative), dest, context);
|
|
legacyProperty(this, "flex-preferred-size", bun.take(&preferred_size), dest, context);
|
|
legacyProperty(this, "flex-order", bun.take(&flex_order), dest, context);
|
|
|
|
if (direction) |val| {
|
|
const dir = val[0];
|
|
if (context.targets.browsers) |targets| {
|
|
const prefixes = context.targets.prefixes(css.VendorPrefix.NONE, css.prefixes.Feature.flex_direction);
|
|
var prefixes_2009 = css.VendorPrefix{};
|
|
if (isFlex2009(targets)) {
|
|
prefixes_2009.webkit = true;
|
|
}
|
|
if (prefixes.moz) {
|
|
prefixes_2009.moz = true;
|
|
}
|
|
if (!prefixes_2009.isEmpty()) {
|
|
const orient, const newdir = dir.to2009();
|
|
bun.handleOom(dest.append(context.allocator, Property{ .@"box-orient" = .{ orient, prefixes_2009 } }));
|
|
bun.handleOom(dest.append(context.allocator, Property{ .@"box-direction" = .{ newdir, prefixes_2009 } }));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (direction != null and wrap != null) {
|
|
const dir: *FlexDirection = &direction.?[0];
|
|
const dir_prefix: *VendorPrefix = &direction.?[1];
|
|
const wrapinner: *FlexWrap = &wrap.?[0];
|
|
const wrap_prefix: *VendorPrefix = &wrap.?[1];
|
|
|
|
const intersection = dir_prefix.bitwiseAnd(wrap_prefix.*);
|
|
if (!intersection.isEmpty()) {
|
|
var prefix = context.targets.prefixes(intersection, css.prefixes.Feature.flex_flow);
|
|
// Firefox only implemented the 2009 spec prefixed.
|
|
prefix.moz = false;
|
|
dest.append(context.allocator, Property{ .@"flex-flow" = .{
|
|
FlexFlow{
|
|
.direction = dir.*,
|
|
.wrap = wrapinner.*,
|
|
},
|
|
prefix,
|
|
} }) catch |err| bun.handleOom(err);
|
|
bun.bits.remove(css.VendorPrefix, dir_prefix, intersection);
|
|
bun.bits.remove(css.VendorPrefix, wrap_prefix, intersection);
|
|
}
|
|
}
|
|
|
|
this.singleProperty("flex-direction", bun.take(&direction), null, null, dest, context, "flex_direction");
|
|
this.singleProperty("flex-wrap", bun.take(&wrap), null, .{ BoxLines, "box-lines" }, dest, context, "flex_wrap");
|
|
|
|
if (context.targets.browsers) |targets| {
|
|
if (grow) |val| {
|
|
const g = val[0];
|
|
const prefixes = context.targets.prefixes(css.VendorPrefix.NONE, css.prefixes.Feature.flex_grow);
|
|
var prefixes_2009 = css.VendorPrefix{};
|
|
if (isFlex2009(targets)) {
|
|
prefixes_2009.webkit = true;
|
|
}
|
|
if (prefixes.moz) {
|
|
prefixes_2009.moz = true;
|
|
}
|
|
if (!prefixes_2009.isEmpty()) {
|
|
bun.handleOom(dest.append(context.allocator, Property{ .@"box-flex" = .{ g, prefixes_2009 } }));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (grow != null and shrink != null and basis != null) {
|
|
const g = grow.?[0];
|
|
const g_prefix: *VendorPrefix = &grow.?[1];
|
|
const s = shrink.?[0];
|
|
const s_prefix: *VendorPrefix = &shrink.?[1];
|
|
const b = basis.?[0];
|
|
const b_prefix: *VendorPrefix = &basis.?[1];
|
|
|
|
const intersection = g_prefix.bitwiseAnd(s_prefix.bitwiseAnd(b_prefix.*));
|
|
if (!intersection.isEmpty()) {
|
|
var prefix = context.targets.prefixes(intersection, css.prefixes.Feature.flex);
|
|
// Firefox only implemented the 2009 spec prefixed.
|
|
prefix.moz = false;
|
|
dest.append(context.allocator, Property{ .flex = .{
|
|
Flex{
|
|
.grow = g,
|
|
.shrink = s,
|
|
.basis = b,
|
|
},
|
|
prefix,
|
|
} }) catch |err| bun.handleOom(err);
|
|
bun.bits.remove(css.VendorPrefix, g_prefix, intersection);
|
|
bun.bits.remove(css.VendorPrefix, s_prefix, intersection);
|
|
bun.bits.remove(css.VendorPrefix, b_prefix, intersection);
|
|
}
|
|
}
|
|
|
|
this.singleProperty("flex-grow", bun.take(&grow), "flex-positive", null, dest, context, "flex_grow");
|
|
this.singleProperty("flex-shrink", bun.take(&shrink), "flex-negative", null, dest, context, "flex_shrink");
|
|
this.singleProperty("flex-basis", bun.take(&basis), "flex-preferred-size", null, dest, context, "flex_basis");
|
|
this.singleProperty("order", bun.take(&order), "flex-order", .{ BoxOrdinalGroup, "box-ordinal-group" }, dest, context, "order");
|
|
}
|
|
|
|
fn singleProperty(
|
|
this: *FlexHandler,
|
|
comptime prop: []const u8,
|
|
key: anytype,
|
|
comptime prop_2012: ?[]const u8,
|
|
comptime prop_2009: ?struct { type, []const u8 },
|
|
dest: *css.DeclarationList,
|
|
ctx: *css.PropertyHandlerContext,
|
|
comptime feature_name: []const u8,
|
|
) void {
|
|
_ = this;
|
|
if (key) |value| {
|
|
const val = value[0];
|
|
var prefix = value[1];
|
|
if (!prefix.isEmpty()) {
|
|
prefix = ctx.targets.prefixes(prefix, @field(css.prefixes.Feature, feature_name));
|
|
if (comptime prop_2009) |p2009| {
|
|
if (prefix.none) {
|
|
// 2009 spec, implemented by webkit and firefox
|
|
if (ctx.targets.browsers) |targets| {
|
|
var prefixes_2009 = css.VendorPrefix{};
|
|
if (isFlex2009(targets)) {
|
|
prefixes_2009.webkit = true;
|
|
}
|
|
if (prefix.moz) {
|
|
prefixes_2009.moz = true;
|
|
}
|
|
if (!prefixes_2009.isEmpty()) {
|
|
const s = brk: {
|
|
const T = comptime p2009[0];
|
|
if (comptime T == BoxOrdinalGroup) break :brk @as(?i32, val);
|
|
break :brk p2009[0].fromStandard(&val);
|
|
};
|
|
if (s) |v| {
|
|
dest.append(ctx.allocator, @unionInit(Property, p2009[1], .{
|
|
v,
|
|
prefixes_2009,
|
|
})) catch |err| bun.handleOom(err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (comptime prop_2012) |p2012| {
|
|
var ms = true;
|
|
if (prefix.ms) {
|
|
dest.append(ctx.allocator, @unionInit(Property, p2012, .{
|
|
val,
|
|
css.VendorPrefix.MS,
|
|
})) catch |err| bun.handleOom(err);
|
|
ms = false;
|
|
}
|
|
|
|
if (!ms) {
|
|
prefix.ms = false;
|
|
}
|
|
}
|
|
|
|
// Firefox only implemented the 2009 spec prefixed.
|
|
prefix.moz = false;
|
|
dest.append(ctx.allocator, @unionInit(Property, prop, .{
|
|
val,
|
|
prefix,
|
|
})) catch |err| bun.handleOom(err);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn legacyProperty(this: *FlexHandler, comptime field_name: []const u8, key: anytype, dest: *css.DeclarationList, ctx: *css.PropertyHandlerContext) void {
|
|
_ = this;
|
|
if (key) |value| {
|
|
const val = value[0];
|
|
const prefix = value[1];
|
|
if (!prefix.isEmpty()) {
|
|
dest.append(ctx.allocator, @unionInit(Property, field_name, .{
|
|
val,
|
|
prefix,
|
|
})) catch |err| bun.handleOom(err);
|
|
} else {
|
|
// css.generic.eql(comptime T: type, lhs: *const T, rhs: *const T)
|
|
// css.generic.deinit(@TypeOf(val), &val, ctx.allocator);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn isFlexProperty(property_id: *const PropertyId) bool {
|
|
return switch (property_id.*) {
|
|
.@"flex-direction",
|
|
.@"box-orient",
|
|
.@"box-direction",
|
|
.@"flex-wrap",
|
|
.@"box-lines",
|
|
.@"flex-flow",
|
|
.@"flex-grow",
|
|
.@"box-flex",
|
|
.@"flex-positive",
|
|
.@"flex-shrink",
|
|
.@"flex-negative",
|
|
.@"flex-basis",
|
|
.@"flex-preferred-size",
|
|
.flex,
|
|
.order,
|
|
.@"box-ordinal-group",
|
|
.@"flex-order",
|
|
=> true,
|
|
else => false,
|
|
};
|
|
}
|
|
};
|
|
|
|
const bun = @import("bun");
|
|
const std = @import("std");
|
|
const Allocator = std.mem.Allocator;
|