diff --git a/src/css/css_parser.zig b/src/css/css_parser.zig index e1e20a705d..a73ff1d3fe 100644 --- a/src/css/css_parser.zig +++ b/src/css/css_parser.zig @@ -170,6 +170,7 @@ pub const VendorPrefix = packed struct(u8) { pub const NONE = VendorPrefix{ .none = true }; pub const WEBKIT = VendorPrefix{ .webkit = true }; pub const MOZ = VendorPrefix{ .moz = true }; + pub const MS = VendorPrefix{ .ms = true }; pub const O = VendorPrefix{ .o = true }; /// Fields listed here so we can iterate them in the order we want @@ -881,6 +882,8 @@ pub fn DefineEnumProperty(comptime T: type) type { // @panic("TODO renable this"); } + pub fn deinit(_: *T, _: std.mem.Allocator) void {} + pub fn toCss(this: *const T, comptime W: type, dest: *Printer(W)) PrintErr!void { return dest.writeStr(asStr(this)); } @@ -4901,7 +4904,7 @@ const Tokenizer = struct { } } // else: escaped EOF, do nothing. - // continue; + continue; }, 0 => { this.advance(1); diff --git a/src/css/declaration.zig b/src/css/declaration.zig index f0c0604b63..2ce5b57cf9 100644 --- a/src/css/declaration.zig +++ b/src/css/declaration.zig @@ -23,6 +23,7 @@ const ScrollMarginHandler = css.css_properties.margin_padding.ScrollMarginHandle const FontHandler = css.css_properties.font.FontHandler; const InsetHandler = css.css_properties.margin_padding.InsetHandler; const SizeHandler = css.css_properties.size.SizeHandler; +const FlexHandler = css.css_properties.flex.FlexHandler; /// A CSS declaration block. /// @@ -332,6 +333,7 @@ pub fn parse_declaration( pub const DeclarationHandler = struct { background: BackgroundHandler = .{}, border: BorderHandler = .{}, + flex: FlexHandler = .{}, size: SizeHandler = .{}, margin: MarginHandler = .{}, padding: PaddingHandler = .{}, @@ -356,6 +358,7 @@ pub const DeclarationHandler = struct { this.background.finalize(&this.decls, context); this.border.finalize(&this.decls, context); + this.flex.finalize(&this.decls, context); this.size.finalize(&this.decls, context); this.margin.finalize(&this.decls, context); this.padding.finalize(&this.decls, context); @@ -369,6 +372,7 @@ pub const DeclarationHandler = struct { // return this.background.handleProperty(property, &this.decls, context); return this.background.handleProperty(property, &this.decls, context) or this.border.handleProperty(property, &this.decls, context) or + this.flex.handleProperty(property, &this.decls, context) or this.size.handleProperty(property, &this.decls, context) or this.margin.handleProperty(property, &this.decls, context) or this.padding.handleProperty(property, &this.decls, context) or diff --git a/src/css/properties/border.zig b/src/css/properties/border.zig index 3cb48e1354..26120ab545 100644 --- a/src/css/properties/border.zig +++ b/src/css/properties/border.zig @@ -200,8 +200,6 @@ pub const LineStyle = enum { return true; } - pub fn deinit(_: *const @This(), _: std.mem.Allocator) void {} - pub fn default() LineStyle { return .none; } diff --git a/src/css/properties/flex.zig b/src/css/properties/flex.zig index d9dcdfbc6a..5f52f82f20 100644 --- a/src/css/properties/flex.zig +++ b/src/css/properties/flex.zig @@ -10,6 +10,9 @@ const Printer = css.Printer; const PrintErr = css.PrintErr; const Error = css.Error; +const Property = css.Property; +const PropertyId = css.PropertyId; + const ContainerName = css.css_rules.container.ContainerName; const CSSNumberFns = css.css_values.number.CSSNumberFns; @@ -29,7 +32,9 @@ const NumberOrPercentage = css.css_values.percentage.NumberOrPercentage; const CustomIdentList = css.css_values.ident.CustomIdentList; const Angle = css.css_values.angle.Angle; const Url = css.css_values.url.Url; -const CSSInteger = css.css_values.integer.CSSInteger; +const CSSInteger = css.css_values.number.CSSInteger; + +const isFlex2009 = css.prefixes.Feature.isFlex2009; const VendorPrefix = css.VendorPrefix; @@ -50,6 +55,15 @@ pub const FlexDirection = enum { 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. @@ -67,9 +81,12 @@ pub const FlexWrap = enum { 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. /// 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. @@ -333,6 +350,14 @@ pub const BoxLines = enum { multiple, pub usingnamespace css.DefineEnumProperty(@This()); + + 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/ @@ -397,390 +422,418 @@ pub const FlexLinePack = enum { pub usingnamespace css.DefineEnumProperty(@This()); }; +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 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, -// 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 !field[1].contains(vp.*)) { -// self.flush(dest, context); -// } -// } -// } -// }.maybeFlush; + 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 !field[1].contains(vp.*)) { + self.flush(d, ctx); + } + } + } + }.maybeFlush; -// const propertyHelper = struct { -// fn propertyHelper( -// self: *FlexHandler, -// comptime prop: []const u8, -// val: anytype, -// vp: *const VendorPrefix, -// ) void { -// maybeFlush(self, prop, val, vp); + 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] = val.deepClone(context.allocator); -// field[1].insert(vp.*); -// } else { -// @field(self, prop) = .{ -// val.deepClone(context.allocator), -// vp.*, -// }; -// self.has_any = true; -// } -// } -// }.propertyHelper; + // Otherwise, update the value and add the prefix + if (@field(self, prop)) |*field| { + field[0] = css.generic.deepClone(@TypeOf(val.*), val, ctx.allocator); + field[1].insert(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, "direction", &val[0], &val[1]); -// }, -// .box_orient => |*val| propertyHelper(this, "box_orient", &val[0], &val[1]), -// .box_direction => |*val| propertyHelper(this, "box_direction", &val[0], &val[1]), -// .flex_wrap => |*val| { -// if (context.targets.browsers != null) { -// this.box_lines = null; -// } -// propertyHelper(this, "wrap", &val[0], &val[1]); -// }, -// .box_lines => |*val| propertyHelper(this, "box_lines", &val[0], &val[1]), -// .flex_flow => |*val| { -// if (context.targets.browsers != null) { -// this.box_direction = null; -// this.box_orient = null; -// } -// propertyHelper(this, "direction", &val[0].direction, &val[1]); -// propertyHelper(this, "wrap", &val[0].wrap, &val[1]); -// }, -// .flex_grow => |*val| { -// if (context.targets.browsers != null) { -// this.box_flex = null; -// this.flex_positive = null; -// } -// propertyHelper(this, "grow", &val[0], &val[1]); -// }, -// .box_flex => |*val| propertyHelper(this, "box_flex", &val[0], &val[1]), -// .flex_positive => |*val| propertyHelper(this, "flex_positive", &val[0], &val[1]), -// .flex_shrink => |*val| { -// if (context.targets.browsers != null) { -// this.flex_negative = null; -// } -// propertyHelper(this, "shrink", &val[0], &val[1]); -// }, -// .flex_negative => |*val| propertyHelper(this, "flex_negative", &val[0], &val[1]), -// .flex_basis => |*val| { -// if (context.targets.browsers != null) { -// this.preferred_size = null; -// } -// propertyHelper(this, "basis", &val[0], &val[1]); -// }, -// .flex_preferred_size => |*val| propertyHelper(this, "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, "grow", &val[0].grow, &val[1]); -// maybeFlush(this, "shrink", &val[0].shrink, &val[1]); -// maybeFlush(this, "basis", &val[0].basis, &val[1]); -// propertyHelper(this, "grow", &val[0].grow, &val[1]); -// propertyHelper(this, "shrink", &val[0].shrink, &val[1]); -// propertyHelper(this, "basis", &val[0].basis, &val[1]); -// }, -// .order => |*val| { -// if (context.targets.browsers != null) { -// this.box_ordinal_group = null; -// this.flex_order = null; -// } -// propertyHelper(this, "order", &val[0], &val[1]); -// }, -// .box_ordinal_group => |*val| propertyHelper(this, "box_ordinal_group", &val[0], &val[1]), -// .flex_order => |*val| propertyHelper(this, "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, -// } + 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; -// } + return true; + } -// pub fn finalize(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { -// this.flush(dest, context); -// } + 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; -// } + fn flush(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { + if (!this.has_any) { + return; + } -// this.has_any = false; + this.has_any = false; -// var direction = bun.take(&this.direction); -// var wrap = bun.take(&this.wrap); -// var grow = bun.take(&this.grow); -// var shrink = bun.take(&this.shrink); -// var basis = bun.take(&this.basis); -// const box_orient = bun.take(&this.box_orient); -// const box_direction = bun.take(&this.box_direction); -// const box_flex = bun.take(&this.box_flex); -// const box_ordinal_group = bun.take(&this.box_ordinal_group); -// const box_lines = bun.take(&this.box_lines); -// const flex_positive = bun.take(&this.flex_positive); -// const flex_negative = bun.take(&this.flex_negative); -// const preferred_size = bun.take(&this.preferred_size); -// const order = bun.take(&this.order); -// const flex_order = bun.take(&this.flex_order); + 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. -// if (box_orient) |val| { -// if (!val[1].isEmpty()) { -// dest.append(context.allocator, Property{ .box_orient = val }) catch unreachable; -// } -// } + // 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 (box_direction) |val| { -// if (!val[1].isEmpty()) { -// dest.append(context.allocator, Property{ .box_direction = val }) catch unreachable; -// } -// } + 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.empty(); + if (isFlex2009(targets)) { + prefixes_2009.insert(css.VendorPrefix.WEBKIT); + } + if (prefixes.contains(css.VendorPrefix.MOZ)) { + prefixes_2009.insert(css.VendorPrefix.MOZ); + } + if (!prefixes_2009.isEmpty()) { + const orient, const newdir = dir.to2009(); + dest.append(context.allocator, Property{ .@"box-orient" = .{ orient, prefixes_2009 } }) catch bun.outOfMemory(); + dest.append(context.allocator, Property{ .@"box-direction" = .{ newdir, prefixes_2009 } }) catch bun.outOfMemory(); + } + } + } -// if (box_ordinal_group) |val| { -// if (!val[1].isEmpty()) { -// dest.append(context.allocator, Property{ .box_ordinal_group = val }) catch unreachable; -// } -// } + 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]; -// if (box_flex) |val| { -// if (!val[1].isEmpty()) { -// dest.append(context.allocator, Property{ .box_flex = val }) catch unreachable; -// } -// } + 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.remove(css.VendorPrefix.MOZ); + dest.append(context.allocator, Property{ .@"flex-flow" = .{ + FlexFlow{ + .direction = dir.*, + .wrap = wrapinner.*, + }, + prefix, + } }) catch bun.outOfMemory(); + dir_prefix.remove(intersection); + wrap_prefix.remove(intersection); + } + } -// if (box_lines) |val| { -// if (!val[1].isEmpty()) { -// dest.append(context.allocator, Property{ .box_lines = val }) catch unreachable; -// } -// } + 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 (flex_positive) |val| { -// if (!val[1].isEmpty()) { -// dest.append(context.allocator, Property{ .flex_positive = val }) catch unreachable; -// } -// } + 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.empty(); + if (isFlex2009(targets)) { + prefixes_2009.insert(css.VendorPrefix.WEBKIT); + } + if (prefixes.contains(css.VendorPrefix.MOZ)) { + prefixes_2009.insert(css.VendorPrefix.MOZ); + } + if (!prefixes_2009.isEmpty()) { + dest.append(context.allocator, Property{ .@"box-flex" = .{ g, prefixes_2009 } }) catch bun.outOfMemory(); + } + } + } -// if (flex_negative) |val| { -// if (!val[1].isEmpty()) { -// dest.append(context.allocator, Property{ .flex_negative = val }) catch unreachable; -// } -// } + 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]; -// if (preferred_size) |val| { -// if (!val[1].isEmpty()) { -// dest.append(context.allocator, Property{ .flex_preferred_size = val }) catch unreachable; -// } -// } + 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.remove(css.VendorPrefix.MOZ); + dest.append(context.allocator, Property{ .flex = .{ + Flex{ + .grow = g, + .shrink = s, + .basis = b, + }, + prefix, + } }) catch bun.outOfMemory(); + g_prefix.remove(intersection); + s_prefix.remove(intersection); + b_prefix.remove(intersection); + } + } -// if (flex_order) |val| { -// if (!val[1].isEmpty()) { -// dest.append(context.allocator, Property{ .flex_order = val }) catch unreachable; -// } -// } + 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"); + } -// // Handle direction -// if (direction) |dir| { -// if (context.targets.browsers) |targets| { -// const prefixes = context.targets.prefixes(VendorPrefix{ .none = true }, .flex_direction); -// var prefixes_2009 = VendorPrefix{}; -// if (isFlexbox2009(targets)) { -// prefixes_2009.insert(.webkit); -// } -// if (prefixes.contains(.moz)) { -// prefixes_2009.insert(.moz); -// } -// if (!prefixes_2009.isEmpty()) { -// const orient_dir = dir[0].to2009(); -// dest.append(context.allocator, Property{ .box_orient = .{ orient_dir[0], prefixes_2009 } }) catch unreachable; -// dest.append(context.allocator, Property{ .box_direction = .{ orient_dir[1], prefixes_2009 } }) catch unreachable; -// } -// } -// } + 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; // autofix + 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.contains(css.VendorPrefix.NONE)) { + // 2009 spec, implemented by webkit and firefox + if (ctx.targets.browsers) |targets| { + var prefixes_2009 = css.VendorPrefix.empty(); + if (isFlex2009(targets)) { + prefixes_2009.insert(css.VendorPrefix.WEBKIT); + } + if (prefix.contains(css.VendorPrefix.MOZ)) { + prefixes_2009.insert(css.VendorPrefix.MOZ); + } + 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 bun.outOfMemory(); + } + } + } + } + } -// // Handle flex-flow -// if (direction != null and wrap != null) { -// const intersection = direction.?[1].intersect(wrap.?[1]); -// if (!intersection.isEmpty()) { -// var prefix = context.targets.prefixes(intersection, .flex_flow); -// // Firefox only implemented the 2009 spec prefixed. -// prefix.remove(.moz); -// dest.append(context.allocator, Property{ .flex_flow = .{ -// .{ -// .direction = direction.?[0], -// .wrap = wrap.?[0], -// }, -// prefix, -// } }) catch unreachable; -// direction.?[1].remove(intersection); -// wrap.?[1].remove(intersection); -// } -// } + if (comptime prop_2012) |p2012| { + var ms = true; + if (prefix.contains(css.VendorPrefix.MS)) { + dest.append(ctx.allocator, @unionInit(Property, p2012, .{ + val, + css.VendorPrefix.MS, + })) catch bun.outOfMemory(); + ms = false; + } -// // Handle flex shorthand -// if (grow != null and shrink != null and basis != null) { -// const intersection = grow.?[1].intersect(shrink.?[1]).intersect(basis.?[1]); -// if (!intersection.isEmpty()) { -// var prefix = context.targets.prefixes(intersection, .flex); -// // Firefox only implemented the 2009 spec prefixed. -// prefix.remove(.moz); -// dest.append(context.allocator, Property{ .flex = .{ -// .{ -// .grow = grow.?[0], -// .shrink = shrink.?[0], -// .basis = basis.?[0], -// }, -// prefix, -// } }) catch unreachable; -// grow.?[1].remove(intersection); -// shrink.?[1].remove(intersection); -// basis.?[1].remove(intersection); -// } -// } + if (!ms) { + prefix.remove(css.VendorPrefix.MS); + } + } -// // Handle remaining individual properties -// if (direction) |dir| { -// if (!dir[1].isEmpty()) { -// var prefix = context.targets.prefixes(dir[1], .flex_direction); -// // Firefox only implemented the 2009 spec prefixed. -// prefix.remove(.moz); -// dest.append(context.allocator, Property{ .flex_direction = .{ dir[0], prefix } }) catch unreachable; -// } -// } + // Firefox only implemented the 2009 spec prefixed. + prefix.remove(css.VendorPrefix.MOZ); + dest.append(ctx.allocator, @unionInit(Property, prop, .{ + val, + prefix, + })) catch bun.outOfMemory(); + } + } + } -// if (wrap) |w| { -// if (!w[1].isEmpty()) { -// var prefix = context.targets.prefixes(w[1], .flex_wrap); -// // Firefox only implemented the 2009 spec prefixed. -// prefix.remove(.moz); -// dest.append(context.allocator, Property{ .flex_wrap = .{ w[0], prefix } }) catch unreachable; -// } -// } + fn legacyProperty(this: *FlexHandler, comptime field_name: []const u8, key: anytype, dest: *css.DeclarationList, ctx: *css.PropertyHandlerContext) void { + _ = this; // autofix + 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 bun.outOfMemory(); + } else { + // css.generic.eql(comptime T: type, lhs: *const T, rhs: *const T) + // css.generic.deinit(@TypeOf(val), &val, ctx.allocator); + } + } + } -// if (grow) |g| { -// if (!g[1].isEmpty()) { -// var prefix = context.targets.prefixes(g[1], .flex_grow); -// // Firefox only implemented the 2009 spec prefixed. -// prefix.remove(.moz); -// dest.append(context.allocator, Property{ .flex_grow = .{ g[0], prefix } }) catch unreachable; -// } -// } - -// if (shrink) |s| { -// if (!s[1].isEmpty()) { -// var prefix = context.targets.prefixes(s[1], .flex_shrink); -// // Firefox only implemented the 2009 spec prefixed. -// prefix.remove(.moz); -// dest.append(context.allocator, Property{ .flex_shrink = .{ s[0], prefix } }) catch unreachable; -// } -// } - -// if (basis) |b| { -// if (!b[1].isEmpty()) { -// var prefix = context.targets.prefixes(b[1], .flex_basis); -// // Firefox only implemented the 2009 spec prefixed. -// prefix.remove(.moz); -// dest.append(context.allocator, Property{ .flex_basis = .{ b[0], prefix } }) catch unreachable; -// } -// } - -// if (order) |o| { -// if (!o[1].isEmpty()) { -// var prefix = context.targets.prefixes(o[1], .order); -// // Firefox only implemented the 2009 spec prefixed. -// prefix.remove(.moz); -// dest.append(context.allocator, Property{ .order = .{ o[0], prefix } }) catch unreachable; -// } -// } -// } - -// 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, -// }; -// } -// }; + 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, + }; + } +}; diff --git a/src/css/properties/generate_properties.ts b/src/css/properties/generate_properties.ts index 453032e916..f34bd3060d 100644 --- a/src/css/properties/generate_properties.ts +++ b/src/css/properties/generate_properties.ts @@ -283,7 +283,7 @@ function generatePropertyImpl(property_defs: Record): strin ${Object.entries(property_defs) .map(([name, meta]) => { if (meta.valid_prefixes !== undefined) - return `.${escapeIdent(name)} => |*v| css.generic.eql(${meta.ty}, &v[0], &v[0]) and v[1].eq(rhs.${escapeIdent(name)}[1]),`; + return `.${escapeIdent(name)} => |*v| css.generic.eql(${meta.ty}, &v[0], &rhs.${escapeIdent(name)}[0]) and v[1].eq(rhs.${escapeIdent(name)}[1]),`; return `.${escapeIdent(name)} => |*v| css.generic.eql(${meta.ty}, v, &rhs.${escapeIdent(name)}),`; }) .join("\n")} diff --git a/src/css/properties/properties_generated.zig b/src/css/properties/properties_generated.zig index 8df0d795a9..72ea851826 100644 --- a/src/css/properties/properties_generated.zig +++ b/src/css/properties/properties_generated.zig @@ -6730,10 +6730,10 @@ pub const Property = union(PropertyIdTag) { .@"background-size" => |*v| css.generic.eql(SmallList(background.BackgroundSize, 1), v, &rhs.@"background-size"), .@"background-repeat" => |*v| css.generic.eql(SmallList(background.BackgroundRepeat, 1), v, &rhs.@"background-repeat"), .@"background-attachment" => |*v| css.generic.eql(SmallList(background.BackgroundAttachment, 1), v, &rhs.@"background-attachment"), - .@"background-clip" => |*v| css.generic.eql(SmallList(background.BackgroundClip, 1), &v[0], &v[0]) and v[1].eq(rhs.@"background-clip"[1]), + .@"background-clip" => |*v| css.generic.eql(SmallList(background.BackgroundClip, 1), &v[0], &rhs.@"background-clip"[0]) and v[1].eq(rhs.@"background-clip"[1]), .@"background-origin" => |*v| css.generic.eql(SmallList(background.BackgroundOrigin, 1), v, &rhs.@"background-origin"), .background => |*v| css.generic.eql(SmallList(background.Background, 1), v, &rhs.background), - .@"box-shadow" => |*v| css.generic.eql(SmallList(box_shadow.BoxShadow, 1), &v[0], &v[0]) and v[1].eq(rhs.@"box-shadow"[1]), + .@"box-shadow" => |*v| css.generic.eql(SmallList(box_shadow.BoxShadow, 1), &v[0], &rhs.@"box-shadow"[0]) and v[1].eq(rhs.@"box-shadow"[1]), .opacity => |*v| css.generic.eql(css.css_values.alpha.AlphaValue, v, &rhs.opacity), .color => |*v| css.generic.eql(CssColor, v, &rhs.color), .display => |*v| css.generic.eql(display.Display, v, &rhs.display), @@ -6750,12 +6750,12 @@ pub const Property = union(PropertyIdTag) { .@"min-inline-size" => |*v| css.generic.eql(size.Size, v, &rhs.@"min-inline-size"), .@"max-block-size" => |*v| css.generic.eql(size.MaxSize, v, &rhs.@"max-block-size"), .@"max-inline-size" => |*v| css.generic.eql(size.MaxSize, v, &rhs.@"max-inline-size"), - .@"box-sizing" => |*v| css.generic.eql(size.BoxSizing, &v[0], &v[0]) and v[1].eq(rhs.@"box-sizing"[1]), + .@"box-sizing" => |*v| css.generic.eql(size.BoxSizing, &v[0], &rhs.@"box-sizing"[0]) and v[1].eq(rhs.@"box-sizing"[1]), .@"aspect-ratio" => |*v| css.generic.eql(size.AspectRatio, v, &rhs.@"aspect-ratio"), .overflow => |*v| css.generic.eql(overflow.Overflow, v, &rhs.overflow), .@"overflow-x" => |*v| css.generic.eql(overflow.OverflowKeyword, v, &rhs.@"overflow-x"), .@"overflow-y" => |*v| css.generic.eql(overflow.OverflowKeyword, v, &rhs.@"overflow-y"), - .@"text-overflow" => |*v| css.generic.eql(overflow.TextOverflow, &v[0], &v[0]) and v[1].eq(rhs.@"text-overflow"[1]), + .@"text-overflow" => |*v| css.generic.eql(overflow.TextOverflow, &v[0], &rhs.@"text-overflow"[0]) and v[1].eq(rhs.@"text-overflow"[1]), .position => |*v| css.generic.eql(position.Position, v, &rhs.position), .top => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.top), .bottom => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.bottom), @@ -6793,21 +6793,21 @@ pub const Property = union(PropertyIdTag) { .@"border-block-end-width" => |*v| css.generic.eql(BorderSideWidth, v, &rhs.@"border-block-end-width"), .@"border-inline-start-width" => |*v| css.generic.eql(BorderSideWidth, v, &rhs.@"border-inline-start-width"), .@"border-inline-end-width" => |*v| css.generic.eql(BorderSideWidth, v, &rhs.@"border-inline-end-width"), - .@"border-top-left-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), &v[0], &v[0]) and v[1].eq(rhs.@"border-top-left-radius"[1]), - .@"border-top-right-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), &v[0], &v[0]) and v[1].eq(rhs.@"border-top-right-radius"[1]), - .@"border-bottom-left-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), &v[0], &v[0]) and v[1].eq(rhs.@"border-bottom-left-radius"[1]), - .@"border-bottom-right-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), &v[0], &v[0]) and v[1].eq(rhs.@"border-bottom-right-radius"[1]), + .@"border-top-left-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), &v[0], &rhs.@"border-top-left-radius"[0]) and v[1].eq(rhs.@"border-top-left-radius"[1]), + .@"border-top-right-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), &v[0], &rhs.@"border-top-right-radius"[0]) and v[1].eq(rhs.@"border-top-right-radius"[1]), + .@"border-bottom-left-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), &v[0], &rhs.@"border-bottom-left-radius"[0]) and v[1].eq(rhs.@"border-bottom-left-radius"[1]), + .@"border-bottom-right-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), &v[0], &rhs.@"border-bottom-right-radius"[0]) and v[1].eq(rhs.@"border-bottom-right-radius"[1]), .@"border-start-start-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), v, &rhs.@"border-start-start-radius"), .@"border-start-end-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), v, &rhs.@"border-start-end-radius"), .@"border-end-start-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), v, &rhs.@"border-end-start-radius"), .@"border-end-end-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), v, &rhs.@"border-end-end-radius"), - .@"border-radius" => |*v| css.generic.eql(BorderRadius, &v[0], &v[0]) and v[1].eq(rhs.@"border-radius"[1]), + .@"border-radius" => |*v| css.generic.eql(BorderRadius, &v[0], &rhs.@"border-radius"[0]) and v[1].eq(rhs.@"border-radius"[1]), .@"border-image-source" => |*v| css.generic.eql(Image, v, &rhs.@"border-image-source"), .@"border-image-outset" => |*v| css.generic.eql(Rect(LengthOrNumber), v, &rhs.@"border-image-outset"), .@"border-image-repeat" => |*v| css.generic.eql(BorderImageRepeat, v, &rhs.@"border-image-repeat"), .@"border-image-width" => |*v| css.generic.eql(Rect(BorderImageSideWidth), v, &rhs.@"border-image-width"), .@"border-image-slice" => |*v| css.generic.eql(BorderImageSlice, v, &rhs.@"border-image-slice"), - .@"border-image" => |*v| css.generic.eql(BorderImage, &v[0], &v[0]) and v[1].eq(rhs.@"border-image"[1]), + .@"border-image" => |*v| css.generic.eql(BorderImage, &v[0], &rhs.@"border-image"[0]) and v[1].eq(rhs.@"border-image"[1]), .@"border-color" => |*v| css.generic.eql(BorderColor, v, &rhs.@"border-color"), .@"border-style" => |*v| css.generic.eql(BorderStyle, v, &rhs.@"border-style"), .@"border-width" => |*v| css.generic.eql(BorderWidth, v, &rhs.@"border-width"), @@ -6832,42 +6832,42 @@ pub const Property = union(PropertyIdTag) { .@"outline-color" => |*v| css.generic.eql(CssColor, v, &rhs.@"outline-color"), .@"outline-style" => |*v| css.generic.eql(OutlineStyle, v, &rhs.@"outline-style"), .@"outline-width" => |*v| css.generic.eql(BorderSideWidth, v, &rhs.@"outline-width"), - .@"flex-direction" => |*v| css.generic.eql(FlexDirection, &v[0], &v[0]) and v[1].eq(rhs.@"flex-direction"[1]), - .@"flex-wrap" => |*v| css.generic.eql(FlexWrap, &v[0], &v[0]) and v[1].eq(rhs.@"flex-wrap"[1]), - .@"flex-flow" => |*v| css.generic.eql(FlexFlow, &v[0], &v[0]) and v[1].eq(rhs.@"flex-flow"[1]), - .@"flex-grow" => |*v| css.generic.eql(CSSNumber, &v[0], &v[0]) and v[1].eq(rhs.@"flex-grow"[1]), - .@"flex-shrink" => |*v| css.generic.eql(CSSNumber, &v[0], &v[0]) and v[1].eq(rhs.@"flex-shrink"[1]), - .@"flex-basis" => |*v| css.generic.eql(LengthPercentageOrAuto, &v[0], &v[0]) and v[1].eq(rhs.@"flex-basis"[1]), - .flex => |*v| css.generic.eql(Flex, &v[0], &v[0]) and v[1].eq(rhs.flex[1]), - .order => |*v| css.generic.eql(CSSInteger, &v[0], &v[0]) and v[1].eq(rhs.order[1]), - .@"align-content" => |*v| css.generic.eql(AlignContent, &v[0], &v[0]) and v[1].eq(rhs.@"align-content"[1]), - .@"justify-content" => |*v| css.generic.eql(JustifyContent, &v[0], &v[0]) and v[1].eq(rhs.@"justify-content"[1]), + .@"flex-direction" => |*v| css.generic.eql(FlexDirection, &v[0], &rhs.@"flex-direction"[0]) and v[1].eq(rhs.@"flex-direction"[1]), + .@"flex-wrap" => |*v| css.generic.eql(FlexWrap, &v[0], &rhs.@"flex-wrap"[0]) and v[1].eq(rhs.@"flex-wrap"[1]), + .@"flex-flow" => |*v| css.generic.eql(FlexFlow, &v[0], &rhs.@"flex-flow"[0]) and v[1].eq(rhs.@"flex-flow"[1]), + .@"flex-grow" => |*v| css.generic.eql(CSSNumber, &v[0], &rhs.@"flex-grow"[0]) and v[1].eq(rhs.@"flex-grow"[1]), + .@"flex-shrink" => |*v| css.generic.eql(CSSNumber, &v[0], &rhs.@"flex-shrink"[0]) and v[1].eq(rhs.@"flex-shrink"[1]), + .@"flex-basis" => |*v| css.generic.eql(LengthPercentageOrAuto, &v[0], &rhs.@"flex-basis"[0]) and v[1].eq(rhs.@"flex-basis"[1]), + .flex => |*v| css.generic.eql(Flex, &v[0], &rhs.flex[0]) and v[1].eq(rhs.flex[1]), + .order => |*v| css.generic.eql(CSSInteger, &v[0], &rhs.order[0]) and v[1].eq(rhs.order[1]), + .@"align-content" => |*v| css.generic.eql(AlignContent, &v[0], &rhs.@"align-content"[0]) and v[1].eq(rhs.@"align-content"[1]), + .@"justify-content" => |*v| css.generic.eql(JustifyContent, &v[0], &rhs.@"justify-content"[0]) and v[1].eq(rhs.@"justify-content"[1]), .@"place-content" => |*v| css.generic.eql(PlaceContent, v, &rhs.@"place-content"), - .@"align-self" => |*v| css.generic.eql(AlignSelf, &v[0], &v[0]) and v[1].eq(rhs.@"align-self"[1]), + .@"align-self" => |*v| css.generic.eql(AlignSelf, &v[0], &rhs.@"align-self"[0]) and v[1].eq(rhs.@"align-self"[1]), .@"justify-self" => |*v| css.generic.eql(JustifySelf, v, &rhs.@"justify-self"), .@"place-self" => |*v| css.generic.eql(PlaceSelf, v, &rhs.@"place-self"), - .@"align-items" => |*v| css.generic.eql(AlignItems, &v[0], &v[0]) and v[1].eq(rhs.@"align-items"[1]), + .@"align-items" => |*v| css.generic.eql(AlignItems, &v[0], &rhs.@"align-items"[0]) and v[1].eq(rhs.@"align-items"[1]), .@"justify-items" => |*v| css.generic.eql(JustifyItems, v, &rhs.@"justify-items"), .@"place-items" => |*v| css.generic.eql(PlaceItems, v, &rhs.@"place-items"), .@"row-gap" => |*v| css.generic.eql(GapValue, v, &rhs.@"row-gap"), .@"column-gap" => |*v| css.generic.eql(GapValue, v, &rhs.@"column-gap"), .gap => |*v| css.generic.eql(Gap, v, &rhs.gap), - .@"box-orient" => |*v| css.generic.eql(BoxOrient, &v[0], &v[0]) and v[1].eq(rhs.@"box-orient"[1]), - .@"box-direction" => |*v| css.generic.eql(BoxDirection, &v[0], &v[0]) and v[1].eq(rhs.@"box-direction"[1]), - .@"box-ordinal-group" => |*v| css.generic.eql(CSSInteger, &v[0], &v[0]) and v[1].eq(rhs.@"box-ordinal-group"[1]), - .@"box-align" => |*v| css.generic.eql(BoxAlign, &v[0], &v[0]) and v[1].eq(rhs.@"box-align"[1]), - .@"box-flex" => |*v| css.generic.eql(CSSNumber, &v[0], &v[0]) and v[1].eq(rhs.@"box-flex"[1]), - .@"box-flex-group" => |*v| css.generic.eql(CSSInteger, &v[0], &v[0]) and v[1].eq(rhs.@"box-flex-group"[1]), - .@"box-pack" => |*v| css.generic.eql(BoxPack, &v[0], &v[0]) and v[1].eq(rhs.@"box-pack"[1]), - .@"box-lines" => |*v| css.generic.eql(BoxLines, &v[0], &v[0]) and v[1].eq(rhs.@"box-lines"[1]), - .@"flex-pack" => |*v| css.generic.eql(FlexPack, &v[0], &v[0]) and v[1].eq(rhs.@"flex-pack"[1]), - .@"flex-order" => |*v| css.generic.eql(CSSInteger, &v[0], &v[0]) and v[1].eq(rhs.@"flex-order"[1]), - .@"flex-align" => |*v| css.generic.eql(BoxAlign, &v[0], &v[0]) and v[1].eq(rhs.@"flex-align"[1]), - .@"flex-item-align" => |*v| css.generic.eql(FlexItemAlign, &v[0], &v[0]) and v[1].eq(rhs.@"flex-item-align"[1]), - .@"flex-line-pack" => |*v| css.generic.eql(FlexLinePack, &v[0], &v[0]) and v[1].eq(rhs.@"flex-line-pack"[1]), - .@"flex-positive" => |*v| css.generic.eql(CSSNumber, &v[0], &v[0]) and v[1].eq(rhs.@"flex-positive"[1]), - .@"flex-negative" => |*v| css.generic.eql(CSSNumber, &v[0], &v[0]) and v[1].eq(rhs.@"flex-negative"[1]), - .@"flex-preferred-size" => |*v| css.generic.eql(LengthPercentageOrAuto, &v[0], &v[0]) and v[1].eq(rhs.@"flex-preferred-size"[1]), + .@"box-orient" => |*v| css.generic.eql(BoxOrient, &v[0], &rhs.@"box-orient"[0]) and v[1].eq(rhs.@"box-orient"[1]), + .@"box-direction" => |*v| css.generic.eql(BoxDirection, &v[0], &rhs.@"box-direction"[0]) and v[1].eq(rhs.@"box-direction"[1]), + .@"box-ordinal-group" => |*v| css.generic.eql(CSSInteger, &v[0], &rhs.@"box-ordinal-group"[0]) and v[1].eq(rhs.@"box-ordinal-group"[1]), + .@"box-align" => |*v| css.generic.eql(BoxAlign, &v[0], &rhs.@"box-align"[0]) and v[1].eq(rhs.@"box-align"[1]), + .@"box-flex" => |*v| css.generic.eql(CSSNumber, &v[0], &rhs.@"box-flex"[0]) and v[1].eq(rhs.@"box-flex"[1]), + .@"box-flex-group" => |*v| css.generic.eql(CSSInteger, &v[0], &rhs.@"box-flex-group"[0]) and v[1].eq(rhs.@"box-flex-group"[1]), + .@"box-pack" => |*v| css.generic.eql(BoxPack, &v[0], &rhs.@"box-pack"[0]) and v[1].eq(rhs.@"box-pack"[1]), + .@"box-lines" => |*v| css.generic.eql(BoxLines, &v[0], &rhs.@"box-lines"[0]) and v[1].eq(rhs.@"box-lines"[1]), + .@"flex-pack" => |*v| css.generic.eql(FlexPack, &v[0], &rhs.@"flex-pack"[0]) and v[1].eq(rhs.@"flex-pack"[1]), + .@"flex-order" => |*v| css.generic.eql(CSSInteger, &v[0], &rhs.@"flex-order"[0]) and v[1].eq(rhs.@"flex-order"[1]), + .@"flex-align" => |*v| css.generic.eql(BoxAlign, &v[0], &rhs.@"flex-align"[0]) and v[1].eq(rhs.@"flex-align"[1]), + .@"flex-item-align" => |*v| css.generic.eql(FlexItemAlign, &v[0], &rhs.@"flex-item-align"[0]) and v[1].eq(rhs.@"flex-item-align"[1]), + .@"flex-line-pack" => |*v| css.generic.eql(FlexLinePack, &v[0], &rhs.@"flex-line-pack"[0]) and v[1].eq(rhs.@"flex-line-pack"[1]), + .@"flex-positive" => |*v| css.generic.eql(CSSNumber, &v[0], &rhs.@"flex-positive"[0]) and v[1].eq(rhs.@"flex-positive"[1]), + .@"flex-negative" => |*v| css.generic.eql(CSSNumber, &v[0], &rhs.@"flex-negative"[0]) and v[1].eq(rhs.@"flex-negative"[1]), + .@"flex-preferred-size" => |*v| css.generic.eql(LengthPercentageOrAuto, &v[0], &rhs.@"flex-preferred-size"[0]) and v[1].eq(rhs.@"flex-preferred-size"[1]), .@"margin-top" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"margin-top"), .@"margin-bottom" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"margin-bottom"), .@"margin-left" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"margin-left"), @@ -6920,23 +6920,23 @@ pub const Property = union(PropertyIdTag) { .@"font-variant-caps" => |*v| css.generic.eql(FontVariantCaps, v, &rhs.@"font-variant-caps"), .@"line-height" => |*v| css.generic.eql(LineHeight, v, &rhs.@"line-height"), .font => |*v| css.generic.eql(Font, v, &rhs.font), - .@"text-decoration-color" => |*v| css.generic.eql(CssColor, &v[0], &v[0]) and v[1].eq(rhs.@"text-decoration-color"[1]), - .@"text-emphasis-color" => |*v| css.generic.eql(CssColor, &v[0], &v[0]) and v[1].eq(rhs.@"text-emphasis-color"[1]), + .@"text-decoration-color" => |*v| css.generic.eql(CssColor, &v[0], &rhs.@"text-decoration-color"[0]) and v[1].eq(rhs.@"text-decoration-color"[1]), + .@"text-emphasis-color" => |*v| css.generic.eql(CssColor, &v[0], &rhs.@"text-emphasis-color"[0]) and v[1].eq(rhs.@"text-emphasis-color"[1]), .@"text-shadow" => |*v| css.generic.eql(SmallList(TextShadow, 1), v, &rhs.@"text-shadow"), .direction => |*v| css.generic.eql(Direction, v, &rhs.direction), .composes => |*v| css.generic.eql(Composes, v, &rhs.composes), - .@"mask-image" => |*v| css.generic.eql(SmallList(Image, 1), &v[0], &v[0]) and v[1].eq(rhs.@"mask-image"[1]), + .@"mask-image" => |*v| css.generic.eql(SmallList(Image, 1), &v[0], &rhs.@"mask-image"[0]) and v[1].eq(rhs.@"mask-image"[1]), .@"mask-mode" => |*v| css.generic.eql(SmallList(MaskMode, 1), v, &rhs.@"mask-mode"), - .@"mask-repeat" => |*v| css.generic.eql(SmallList(BackgroundRepeat, 1), &v[0], &v[0]) and v[1].eq(rhs.@"mask-repeat"[1]), + .@"mask-repeat" => |*v| css.generic.eql(SmallList(BackgroundRepeat, 1), &v[0], &rhs.@"mask-repeat"[0]) and v[1].eq(rhs.@"mask-repeat"[1]), .@"mask-position-x" => |*v| css.generic.eql(SmallList(HorizontalPosition, 1), v, &rhs.@"mask-position-x"), .@"mask-position-y" => |*v| css.generic.eql(SmallList(VerticalPosition, 1), v, &rhs.@"mask-position-y"), - .@"mask-position" => |*v| css.generic.eql(SmallList(Position, 1), &v[0], &v[0]) and v[1].eq(rhs.@"mask-position"[1]), - .@"mask-clip" => |*v| css.generic.eql(SmallList(MaskClip, 1), &v[0], &v[0]) and v[1].eq(rhs.@"mask-clip"[1]), - .@"mask-origin" => |*v| css.generic.eql(SmallList(GeometryBox, 1), &v[0], &v[0]) and v[1].eq(rhs.@"mask-origin"[1]), - .@"mask-size" => |*v| css.generic.eql(SmallList(BackgroundSize, 1), &v[0], &v[0]) and v[1].eq(rhs.@"mask-size"[1]), + .@"mask-position" => |*v| css.generic.eql(SmallList(Position, 1), &v[0], &rhs.@"mask-position"[0]) and v[1].eq(rhs.@"mask-position"[1]), + .@"mask-clip" => |*v| css.generic.eql(SmallList(MaskClip, 1), &v[0], &rhs.@"mask-clip"[0]) and v[1].eq(rhs.@"mask-clip"[1]), + .@"mask-origin" => |*v| css.generic.eql(SmallList(GeometryBox, 1), &v[0], &rhs.@"mask-origin"[0]) and v[1].eq(rhs.@"mask-origin"[1]), + .@"mask-size" => |*v| css.generic.eql(SmallList(BackgroundSize, 1), &v[0], &rhs.@"mask-size"[0]) and v[1].eq(rhs.@"mask-size"[1]), .@"mask-composite" => |*v| css.generic.eql(SmallList(MaskComposite, 1), v, &rhs.@"mask-composite"), .@"mask-type" => |*v| css.generic.eql(MaskType, v, &rhs.@"mask-type"), - .mask => |*v| css.generic.eql(SmallList(Mask, 1), &v[0], &v[0]) and v[1].eq(rhs.mask[1]), + .mask => |*v| css.generic.eql(SmallList(Mask, 1), &v[0], &rhs.mask[0]) and v[1].eq(rhs.mask[1]), .@"mask-border-source" => |*v| css.generic.eql(Image, v, &rhs.@"mask-border-source"), .@"mask-border-mode" => |*v| css.generic.eql(MaskBorderMode, v, &rhs.@"mask-border-mode"), .@"mask-border-slice" => |*v| css.generic.eql(BorderImageSlice, v, &rhs.@"mask-border-slice"), @@ -6945,13 +6945,13 @@ pub const Property = union(PropertyIdTag) { .@"mask-border-repeat" => |*v| css.generic.eql(BorderImageRepeat, v, &rhs.@"mask-border-repeat"), .@"mask-border" => |*v| css.generic.eql(MaskBorder, v, &rhs.@"mask-border"), .@"-webkit-mask-composite" => |*v| css.generic.eql(SmallList(WebKitMaskComposite, 1), v, &rhs.@"-webkit-mask-composite"), - .@"mask-source-type" => |*v| css.generic.eql(SmallList(WebKitMaskSourceType, 1), &v[0], &v[0]) and v[1].eq(rhs.@"mask-source-type"[1]), - .@"mask-box-image" => |*v| css.generic.eql(BorderImage, &v[0], &v[0]) and v[1].eq(rhs.@"mask-box-image"[1]), - .@"mask-box-image-source" => |*v| css.generic.eql(Image, &v[0], &v[0]) and v[1].eq(rhs.@"mask-box-image-source"[1]), - .@"mask-box-image-slice" => |*v| css.generic.eql(BorderImageSlice, &v[0], &v[0]) and v[1].eq(rhs.@"mask-box-image-slice"[1]), - .@"mask-box-image-width" => |*v| css.generic.eql(Rect(BorderImageSideWidth), &v[0], &v[0]) and v[1].eq(rhs.@"mask-box-image-width"[1]), - .@"mask-box-image-outset" => |*v| css.generic.eql(Rect(LengthOrNumber), &v[0], &v[0]) and v[1].eq(rhs.@"mask-box-image-outset"[1]), - .@"mask-box-image-repeat" => |*v| css.generic.eql(BorderImageRepeat, &v[0], &v[0]) and v[1].eq(rhs.@"mask-box-image-repeat"[1]), + .@"mask-source-type" => |*v| css.generic.eql(SmallList(WebKitMaskSourceType, 1), &v[0], &rhs.@"mask-source-type"[0]) and v[1].eq(rhs.@"mask-source-type"[1]), + .@"mask-box-image" => |*v| css.generic.eql(BorderImage, &v[0], &rhs.@"mask-box-image"[0]) and v[1].eq(rhs.@"mask-box-image"[1]), + .@"mask-box-image-source" => |*v| css.generic.eql(Image, &v[0], &rhs.@"mask-box-image-source"[0]) and v[1].eq(rhs.@"mask-box-image-source"[1]), + .@"mask-box-image-slice" => |*v| css.generic.eql(BorderImageSlice, &v[0], &rhs.@"mask-box-image-slice"[0]) and v[1].eq(rhs.@"mask-box-image-slice"[1]), + .@"mask-box-image-width" => |*v| css.generic.eql(Rect(BorderImageSideWidth), &v[0], &rhs.@"mask-box-image-width"[0]) and v[1].eq(rhs.@"mask-box-image-width"[1]), + .@"mask-box-image-outset" => |*v| css.generic.eql(Rect(LengthOrNumber), &v[0], &rhs.@"mask-box-image-outset"[0]) and v[1].eq(rhs.@"mask-box-image-outset"[1]), + .@"mask-box-image-repeat" => |*v| css.generic.eql(BorderImageRepeat, &v[0], &rhs.@"mask-box-image-repeat"[0]) and v[1].eq(rhs.@"mask-box-image-repeat"[1]), .unparsed => |*u| u.eql(&rhs.unparsed), .all => true, .custom => |*c| c.eql(&rhs.custom), diff --git a/test/js/bun/css/css.test.ts b/test/js/bun/css/css.test.ts index b15333c82f..3e256d1e8e 100644 --- a/test/js/bun/css/css.test.ts +++ b/test/js/bun/css/css.test.ts @@ -22,6 +22,33 @@ function error_test(css: string, error: unknown) { } describe("css tests", () => { + // #16596 + cssTest( + `.flexrow { + flex-direction: row; +} + +.flexcol { + flex-direction: column; +} + +.hello { + flex-wrap: wrap; +} + +.world { + flex-wrap: nowrap; +}`, + ".flexrow {\n flex-direction: row;\n}\n\n.flexcol {\n flex-direction: column;\n}\n\n.hello {\n flex-wrap: wrap;\n}\n\n.world {\n flex-wrap: nowrap;\n}\n", + ); + // test escape sequences + cssTest( + `.foo { + content: "\\2b"; +}`, + '.foo{content:"+";}', + ); + describe("pseudo-class edge case", () => { cssTest( indoc`[type="file"]::file-selector-button:-moz-any() { @@ -2980,6 +3007,1196 @@ describe("css tests", () => { ); }); + describe("flex", () => { + cssTest( + ` + .foo { + flex-direction: column; + flex-wrap: wrap; + } + `, + ` + .foo { + flex-flow: column wrap; + } + `, + ); + + cssTest( + ` + .foo { + flex-direction: row; + flex-wrap: wrap; + } + `, + ` + .foo { + flex-flow: wrap; + } + `, + ); + + cssTest( + ` + .foo { + flex-direction: row; + flex-wrap: nowrap; + } + `, + ` + .foo { + flex-flow: row; + } + `, + ); + + cssTest( + ` + .foo { + flex-direction: column; + flex-wrap: nowrap; + } + `, + ` + .foo { + flex-flow: column; + } + `, + ); + + cssTest( + ` + .foo { + flex-grow: 1; + flex-shrink: 1; + flex-basis: 0%; + } + `, + ` + .foo { + flex: 1; + } + `, + ); + + cssTest( + ` + .foo { + flex-grow: 1; + flex-shrink: 1; + flex-basis: 0; + } + `, + ` + .foo { + flex: 1 1 0; + } + `, + ); + + cssTest( + ` + .foo { + flex-grow: 1; + flex-shrink: 1; + flex-basis: 0px; + } + `, + ` + .foo { + flex: 1 1 0; + } + `, + ); + + cssTest( + ` + .foo { + flex-grow: 1; + flex-shrink: 2; + flex-basis: 0%; + } + `, + ` + .foo { + flex: 1 2; + } + `, + ); + + cssTest( + ` + .foo { + flex-grow: 2; + flex-shrink: 1; + flex-basis: 0%; + } + `, + ` + .foo { + flex: 2; + } + `, + ); + + cssTest( + ` + .foo { + flex-grow: 2; + flex-shrink: 2; + flex-basis: 0%; + } + `, + ` + .foo { + flex: 2 2; + } + `, + ); + + cssTest( + ` + .foo { + flex-grow: 1; + flex-shrink: 1; + flex-basis: 10px; + } + `, + ` + .foo { + flex: 10px; + } + `, + ); + + cssTest( + ` + .foo { + flex-grow: 2; + flex-shrink: 1; + flex-basis: 10px; + } + `, + ` + .foo { + flex: 2 10px; + } + `, + ); + + cssTest( + ` + .foo { + flex-grow: 1; + flex-shrink: 0; + flex-basis: 0%; + } + `, + ` + .foo { + flex: 1 0; + } + `, + ); + + cssTest( + ` + .foo { + flex-grow: 1; + flex-shrink: 0; + flex-basis: auto; + } + `, + ` + .foo { + flex: 1 0 auto; + } + `, + ); + + cssTest( + ` + .foo { + flex-grow: 1; + flex-shrink: 1; + flex-basis: auto; + } + `, + ` + .foo { + flex: auto; + } + `, + ); + + cssTest( + ` + .foo { + flex: 0 0; + flex-grow: 1; + } + `, + ` + .foo { + flex: 1 0; + } + `, + ); + + cssTest( + ` + .foo { + flex: 0 0; + flex-grow: var(--grow); + } + `, + ` + .foo { + flex: 0 0; + flex-grow: var(--grow); + } + `, + ); + + // cssTest( + // ` + // .foo { + // align-content: center; + // justify-content: center; + // } + // `, + // ` + // .foo { + // place-content: center; + // } + // `, + // ); + + // cssTest( + // ` + // .foo { + // align-content: first baseline; + // justify-content: safe right; + // } + // `, + // ` + // .foo { + // place-content: baseline safe right; + // } + // `, + // ); + + // cssTest( + // ` + // .foo { + // place-content: first baseline unsafe left; + // } + // `, + // ` + // .foo { + // place-content: baseline unsafe left; + // } + // `, + // ); + + // cssTest( + // ` + // .foo { + // place-content: center center; + // } + // `, + // ` + // .foo { + // place-content: center; + // } + // `, + // ); + + // cssTest( + // ` + // .foo { + // align-self: center; + // justify-self: center; + // } + // `, + // ` + // .foo { + // place-self: center; + // } + // `, + // ); + + // cssTest( + // ` + // .foo { + // align-self: center; + // justify-self: unsafe left; + // } + // `, + // ` + // .foo { + // place-self: center unsafe left; + // } + // `, + // ); + + // cssTest( + // ` + // .foo { + // align-items: center; + // justify-items: center; + // } + // `, + // ` + // .foo { + // place-items: center; + // } + // `, + // ); + + // cssTest( + // ` + // .foo { + // align-items: center; + // justify-items: legacy left; + // } + // `, + // ` + // .foo { + // place-items: center legacy left; + // } + // `, + // ); + + // cssTest( + // ` + // .foo { + // place-items: center; + // justify-items: var(--justify); + // } + // `, + // ` + // .foo { + // place-items: center; + // justify-items: var(--justify); + // } + // `, + // ); + + // cssTest( + // ` + // .foo { + // row-gap: 10px; + // column-gap: 20px; + // } + // `, + // ` + // .foo { + // gap: 10px 20px; + // } + // `, + // ); + + // cssTest( + // ` + // .foo { + // row-gap: 10px; + // column-gap: 10px; + // } + // `, + // ` + // .foo { + // gap: 10px; + // } + // `, + // ); + + // cssTest( + // ` + // .foo { + // gap: 10px; + // column-gap: 20px; + // } + // `, + // ` + // .foo { + // gap: 10px 20px; + // } + // `, + // ); + + // cssTest( + // ` + // .foo { + // column-gap: 20px; + // gap: 10px; + // } + // `, + // ` + // .foo { + // gap: 10px; + // } + // `, + // ); + + // cssTest( + // ` + // .foo { + // row-gap: normal; + // column-gap: 20px; + // } + // `, + // ` + // .foo { + // gap: normal 20px; + // } + // `, + // ); + + cssTest( + ` + .foo { + -webkit-flex-grow: 1; + -webkit-flex-shrink: 1; + -webkit-flex-basis: auto; + } + `, + ` + .foo { + -webkit-flex: auto; + } + `, + ); + cssTest( + ` + .foo { + -webkit-flex-grow: 1; + -webkit-flex-shrink: 1; + -webkit-flex-basis: auto; + flex-grow: 1; + flex-shrink: 1; + flex-basis: auto; + } + `, + ` + .foo { + -webkit-flex: auto; + flex: auto; + } + `, + ); + prefix_test( + ` + .foo { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + flex-direction: row; + } + `, + ` + .foo { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -webkit-flex-direction: row; + flex-direction: row; + } + `, + { + safari: 4 << 16, + }, + ); + prefix_test( + ` + .foo { + flex-direction: row; + } + `, + ` + .foo { + -webkit-box-orient: horizontal; + -moz-box-orient: horizontal; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + } + `, + { + safari: 4 << 16, + firefox: 4 << 16, + ie: 10 << 16, + }, + ); + prefix_test( + ` + .foo { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -moz-box-orient: horizontal; + -moz-box-direction: normal; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + } + `, + ` + .foo { + flex-direction: row; + } + `, + { + safari: 14 << 16, + }, + ); + prefix_test( + ` + .foo { + flex-wrap: wrap; + } + `, + ` + .foo { + -webkit-box-lines: multiple; + -moz-box-lines: multiple; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + } + `, + { + safari: 4 << 16, + firefox: 4 << 16, + ie: 10 << 16, + }, + ); + prefix_test( + ` + .foo { + -webkit-box-lines: multiple; + -moz-box-lines: multiple; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + } + `, + ` + .foo { + flex-wrap: wrap; + } + `, + { + safari: 11 << 16, + }, + ); + prefix_test( + ` + .foo { + flex-flow: row wrap; + } + `, + ` + .foo { + -webkit-box-orient: horizontal; + -moz-box-orient: horizontal; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-flex-flow: wrap; + -ms-flex-flow: wrap; + flex-flow: wrap; + } + `, + { + safari: 4 << 16, + firefox: 4 << 16, + ie: 10 << 16, + }, + ); + prefix_test( + ` + .foo { + -webkit-box-orient: horizontal; + -moz-box-orient: horizontal; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-flex-flow: wrap; + -ms-flex-flow: wrap; + flex-flow: wrap; + } + `, + ` + .foo { + flex-flow: wrap; + } + `, + { + safari: 11 << 16, + }, + ); + prefix_test( + ` + .foo { + flex-grow: 1; + } + `, + ` + .foo { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -ms-flex-positive: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + } + `, + { + safari: 4 << 16, + firefox: 4 << 16, + ie: 10 << 16, + }, + ); + prefix_test( + ` + .foo { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -ms-flex-positive: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + } + `, + ` + .foo { + flex-grow: 1; + } + `, + { + safari: 11 << 16, + }, + ); + prefix_test( + ` + .foo { + flex-shrink: 1; + } + `, + ` + .foo { + -ms-flex-negative: 1; + -webkit-flex-shrink: 1; + flex-shrink: 1; + } + `, + { + safari: 4 << 16, + firefox: 4 << 16, + ie: 10 << 16, + }, + ); + prefix_test( + ` + .foo { + -ms-flex-negative: 1; + -webkit-flex-shrink: 1; + flex-shrink: 1; + } + `, + ` + .foo { + flex-shrink: 1; + } + `, + { + safari: 11 << 16, + }, + ); + prefix_test( + ` + .foo { + flex-basis: 1px; + } + `, + ` + .foo { + -ms-flex-preferred-size: 1px; + -webkit-flex-basis: 1px; + flex-basis: 1px; + } + `, + { + safari: 4 << 16, + firefox: 4 << 16, + ie: 10 << 16, + }, + ); + prefix_test( + ` + .foo { + -ms-flex-preferred-size: 1px; + -webkit-flex-basis: 1px; + flex-basis: 1px; + } + `, + ` + .foo { + flex-basis: 1px; + } + `, + { + safari: 11 << 16, + }, + ); + prefix_test( + ` + .foo { + flex: 1; + } + `, + ` + .foo { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + } + `, + { + safari: 4 << 16, + firefox: 4 << 16, + ie: 10 << 16, + }, + ); + prefix_test( + ` + .foo { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + } + `, + ` + .foo { + flex: 1; + } + `, + { + safari: 11 << 16, + }, + ); + // prefix_test( + // ` + // .foo { + // align-content: space-between; + // } + // `, + // ` + // .foo { + // -ms-flex-line-pack: justify; + // -webkit-align-content: space-between; + // align-content: space-between; + // } + // `, + // { + // safari: 4 << 16, + // firefox: 4 << 16, + // ie: 10 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // -ms-flex-line-pack: justify; + // -webkit-align-content: space-between; + // align-content: space-between; + // } + // `, + // ` + // .foo { + // align-content: space-between; + // } + // `, + // { + // safari: 11 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // justify-content: space-between; + // } + // `, + // ` + // .foo { + // -webkit-box-pack: justify; + // -moz-box-pack: justify; + // -ms-flex-pack: justify; + // -webkit-justify-content: space-between; + // justify-content: space-between; + // } + // `, + // { + // safari: 4 << 16, + // firefox: 4 << 16, + // ie: 10 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // -webkit-box-pack: justify; + // -moz-box-pack: justify; + // -ms-flex-pack: justify; + // -webkit-justify-content: space-between; + // justify-content: space-between; + // } + // `, + // ` + // .foo { + // justify-content: space-between; + // } + // `, + // { + // safari: 11 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // place-content: space-between flex-end; + // } + // `, + // ` + // .foo { + // -ms-flex-line-pack: justify; + // -webkit-box-pack: end; + // -moz-box-pack: end; + // -ms-flex-pack: end; + // -webkit-align-content: space-between; + // align-content: space-between; + // -webkit-justify-content: flex-end; + // justify-content: flex-end; + // } + // `, + // { + // safari: 4 << 16, + // firefox: 4 << 16, + // ie: 10 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // -ms-flex-line-pack: justify; + // -webkit-box-pack: end; + // -moz-box-pack: end; + // -ms-flex-pack: end; + // -webkit-align-content: space-between; + // -webkit-justify-content: flex-end; + // place-content: space-between flex-end; + // } + // `, + // ` + // .foo { + // place-content: space-between flex-end; + // } + // `, + // { + // safari: 11 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // place-content: space-between flex-end; + // } + // `, + // ` + // .foo { + // align-content: space-between; + // justify-content: flex-end; + // } + // `, + // { + // chrome: 30 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // place-content: space-between flex-end; + // } + // `, + // ` + // .foo { + // place-content: space-between flex-end; + // } + // `, + // { + // chrome: 60 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // align-self: flex-end; + // } + // `, + // ` + // .foo { + // -ms-flex-item-align: end; + // -webkit-align-self: flex-end; + // align-self: flex-end; + // } + // `, + // { + // safari: 4 << 16, + // firefox: 4 << 16, + // ie: 10 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // -ms-flex-item-align: end; + // -webkit-align-self: flex-end; + // align-self: flex-end; + // } + // `, + // ` + // .foo { + // align-self: flex-end; + // } + // `, + // { + // safari: 11 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // place-self: center flex-end; + // } + // `, + // ` + // .foo { + // -ms-flex-item-align: center; + // -webkit-align-self: center; + // align-self: center; + // justify-self: flex-end; + // } + // `, + // { + // safari: 4 << 16, + // firefox: 4 << 16, + // ie: 10 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // -ms-flex-item-align: center; + // -webkit-align-self: center; + // place-self: center flex-end; + // } + // `, + // ` + // .foo { + // place-self: center flex-end; + // } + // `, + // { + // safari: 11 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // place-self: center flex-end; + // } + // `, + // ` + // .foo { + // align-self: center; + // justify-self: flex-end; + // } + // `, + // { + // chrome: 57 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // place-self: center flex-end; + // } + // `, + // ` + // .foo { + // place-self: center flex-end; + // } + // `, + // { + // chrome: 59 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // align-items: flex-end; + // } + // `, + // ` + // .foo { + // -webkit-box-align: end; + // -moz-box-align: end; + // -ms-flex-align: end; + // -webkit-align-items: flex-end; + // align-items: flex-end; + // } + // `, + // { + // safari: 4 << 16, + // firefox: 4 << 16, + // ie: 10 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // -webkit-box-align: end; + // -moz-box-align: end; + // -ms-flex-align: end; + // -webkit-align-items: flex-end; + // align-items: flex-end; + // } + // `, + // ` + // .foo { + // align-items: flex-end; + // } + // `, + // { + // safari: 11 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // place-items: flex-end center; + // } + // `, + // ` + // .foo { + // -webkit-box-align: end; + // -moz-box-align: end; + // -ms-flex-align: end; + // -webkit-align-items: flex-end; + // align-items: flex-end; + // justify-items: center; + // } + // `, + // { + // safari: 4 << 16, + // firefox: 4 << 16, + // ie: 10 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // -webkit-box-align: end; + // -moz-box-align: end; + // -ms-flex-align: end; + // -webkit-align-items: flex-end; + // place-items: flex-end center; + // } + // `, + // ` + // .foo { + // place-items: flex-end center; + // } + // `, + // { + // safari: 11 << 16, + // }, + // ); + // prefix_test( + // ` + // .foo { + // place-items: flex-end center; + // } + // `, + // ` + // .foo { + // align-items: flex-end; + // justify-items: center; + // } + // `, + // { + // safari: 10 << 16, + // }, + // ); + prefix_test( + ` + .foo { + order: 1; + } + `, + ` + .foo { + -webkit-box-ordinal-group: 1; + -moz-box-ordinal-group: 1; + -ms-flex-order: 1; + -webkit-order: 1; + order: 1; + } + `, + { + safari: 4 << 16, + firefox: 4 << 16, + ie: 10 << 16, + }, + ); + prefix_test( + ` + .foo { + -webkit-box-ordinal-group: 1; + -moz-box-ordinal-group: 1; + -ms-flex-order: 1; + -webkit-order: 1; + order: 1; + } + `, + ` + .foo { + order: 1; + } + `, + { + safari: 11 << 16, + }, + ); + prefix_test( + ` + .foo { + -ms-flex: 0 0 8%; + flex: 0 0 5%; + } + `, + ` + .foo { + -ms-flex: 0 0 8%; + flex: 0 0 5%; + } + `, + { + safari: 11 << 16, + }, + ); + }); + describe("linear-gradient", () => { minify_test(".foo { background: linear-gradient(yellow, blue) }", ".foo{background:linear-gradient(#ff0,#00f)}"); minify_test(