pub(crate) fn lookup_color(name: &str) -> Option<u32> {
match name {
"amber_50" => Some(0xfffbeb),
"amber_100" => Some(0xfef3c7),
"amber_200" => Some(0xfde68a),
"amber_300" => Some(0xfcd34d),
"amber_400" => Some(0xfbbf24),
"amber_500" => Some(0xf59e0b),
"amber_600" => Some(0xd97706),
"amber_700" => Some(0xb45309),
"amber_800" => Some(0x92400e),
"amber_900" => Some(0x78350f),
"amber_950" => Some(0x451a03),
"blue_50" => Some(0xeff6ff),
"blue_100" => Some(0xdbeafe),
"blue_200" => Some(0xbfdbfe),
"blue_300" => Some(0x93c5fd),
"blue_400" => Some(0x60a5fa),
"blue_500" => Some(0x3b82f6),
"blue_600" => Some(0x2563eb),
"blue_700" => Some(0x1d4ed8),
"blue_800" => Some(0x1e40af),
"blue_900" => Some(0x1e3a8a),
"blue_950" => Some(0x172554),
"cyan_50" => Some(0xecfeff),
"cyan_100" => Some(0xcffafe),
"cyan_200" => Some(0xa5f3fc),
"cyan_300" => Some(0x67e8f9),
"cyan_400" => Some(0x22d3ee),
"cyan_500" => Some(0x06b6d4),
"cyan_600" => Some(0x0891b2),
"cyan_700" => Some(0x0e7490),
"cyan_800" => Some(0x155e75),
"cyan_900" => Some(0x164e63),
"cyan_950" => Some(0x083344),
"emerald_50" => Some(0xecfdf5),
"emerald_100" => Some(0xd1fae5),
"emerald_200" => Some(0xa7f3d0),
"emerald_300" => Some(0x6ee7b7),
"emerald_400" => Some(0x34d399),
"emerald_500" => Some(0x10b981),
"emerald_600" => Some(0x059669),
"emerald_700" => Some(0x047857),
"emerald_800" => Some(0x065f46),
"emerald_900" => Some(0x064e3b),
"emerald_950" => Some(0x022c22),
"fuchsia_50" => Some(0xfdf4ff),
"fuchsia_100" => Some(0xfae8ff),
"fuchsia_200" => Some(0xf5d0fe),
"fuchsia_300" => Some(0xf0abfc),
"fuchsia_400" => Some(0xe879f9),
"fuchsia_500" => Some(0xd946ef),
"fuchsia_600" => Some(0xc026d3),
"fuchsia_700" => Some(0xa21caf),
"fuchsia_800" => Some(0x86198f),
"fuchsia_900" => Some(0x701a75),
"fuchsia_950" => Some(0x4a044e),
"gray_50" => Some(0xf9fafb),
"gray_100" => Some(0xf3f4f6),
"gray_200" => Some(0xe5e7eb),
"gray_300" => Some(0xd1d5db),
"gray_400" => Some(0x9ca3af),
"gray_500" => Some(0x6b7280),
"gray_600" => Some(0x4b5563),
"gray_700" => Some(0x374151),
"gray_800" => Some(0x1f2937),
"gray_900" => Some(0x111827),
"gray_950" => Some(0x030712),
"green_50" => Some(0xf0fdf4),
"green_100" => Some(0xdcfce7),
"green_200" => Some(0xbbf7d0),
"green_300" => Some(0x86efac),
"green_400" => Some(0x4ade80),
"green_500" => Some(0x22c55e),
"green_600" => Some(0x16a34a),
"green_700" => Some(0x15803d),
"green_800" => Some(0x166534),
"green_900" => Some(0x14532d),
"green_950" => Some(0x052e16),
"indigo_50" => Some(0xeef2ff),
"indigo_100" => Some(0xe0e7ff),
"indigo_200" => Some(0xc7d2fe),
"indigo_300" => Some(0xa5b4fc),
"indigo_400" => Some(0x818cf8),
"indigo_500" => Some(0x6366f1),
"indigo_600" => Some(0x4f46e5),
"indigo_700" => Some(0x4338ca),
"indigo_800" => Some(0x3730a3),
"indigo_900" => Some(0x312e81),
"indigo_950" => Some(0x1e1b4b),
"lime_50" => Some(0xf7fee7),
"lime_100" => Some(0xecfccb),
"lime_200" => Some(0xd9f99d),
"lime_300" => Some(0xbef264),
"lime_400" => Some(0xa3e635),
"lime_500" => Some(0x84cc16),
"lime_600" => Some(0x65a30d),
"lime_700" => Some(0x4d7c0f),
"lime_800" => Some(0x3f6212),
"lime_900" => Some(0x365314),
"lime_950" => Some(0x1a2e05),
"neutral_50" => Some(0xfafafa),
"neutral_100" => Some(0xf5f5f5),
"neutral_200" => Some(0xe5e5e5),
"neutral_300" => Some(0xd4d4d4),
"neutral_400" => Some(0xa3a3a3),
"neutral_500" => Some(0x737373),
"neutral_600" => Some(0x525252),
"neutral_700" => Some(0x404040),
"neutral_800" => Some(0x262626),
"neutral_900" => Some(0x171717),
"neutral_950" => Some(0x0a0a0a),
"orange_50" => Some(0xfff7ed),
"orange_100" => Some(0xffedd5),
"orange_200" => Some(0xfed7aa),
"orange_300" => Some(0xfdba74),
"orange_400" => Some(0xfb923c),
"orange_500" => Some(0xf97316),
"orange_600" => Some(0xea580c),
"orange_700" => Some(0xc2410c),
"orange_800" => Some(0x9a3412),
"orange_900" => Some(0x7c2d12),
"orange_950" => Some(0x431407),
"pink_50" => Some(0xfdf2f8),
"pink_100" => Some(0xfce7f3),
"pink_200" => Some(0xfbcfe8),
"pink_300" => Some(0xf9a8d4),
"pink_400" => Some(0xf472b6),
"pink_500" => Some(0xec4899),
"pink_600" => Some(0xdb2777),
"pink_700" => Some(0xbe185d),
"pink_800" => Some(0x9d174d),
"pink_900" => Some(0x831843),
"pink_950" => Some(0x500724),
"purple_50" => Some(0xfaf5ff),
"purple_100" => Some(0xf3e8ff),
"purple_200" => Some(0xe9d5ff),
"purple_300" => Some(0xd8b4fe),
"purple_400" => Some(0xc084fc),
"purple_500" => Some(0xa855f7),
"purple_600" => Some(0x9333ea),
"purple_700" => Some(0x7e22ce),
"purple_800" => Some(0x6b21a8),
"purple_900" => Some(0x581c87),
"purple_950" => Some(0x3b0764),
"red_50" => Some(0xfef2f2),
"red_100" => Some(0xfee2e2),
"red_200" => Some(0xfecaca),
"red_300" => Some(0xfca5a5),
"red_400" => Some(0xf87171),
"red_500" => Some(0xef4444),
"red_600" => Some(0xdc2626),
"red_700" => Some(0xb91c1c),
"red_800" => Some(0x991b1b),
"red_900" => Some(0x7f1d1d),
"red_950" => Some(0x450a0a),
"rose_50" => Some(0xfff1f2),
"rose_100" => Some(0xffe4e6),
"rose_200" => Some(0xfecdd3),
"rose_300" => Some(0xfda4af),
"rose_400" => Some(0xfb7185),
"rose_500" => Some(0xf43f5e),
"rose_600" => Some(0xe11d48),
"rose_700" => Some(0xbe123c),
"rose_800" => Some(0x9f1239),
"rose_900" => Some(0x881337),
"rose_950" => Some(0x4c0519),
"sky_50" => Some(0xf0f9ff),
"sky_100" => Some(0xe0f2fe),
"sky_200" => Some(0xbae6fd),
"sky_300" => Some(0x7dd3fc),
"sky_400" => Some(0x38bdf8),
"sky_500" => Some(0x0ea5e9),
"sky_600" => Some(0x0284c7),
"sky_700" => Some(0x0369a1),
"sky_800" => Some(0x075985),
"sky_900" => Some(0x0c4a6e),
"sky_950" => Some(0x082f49),
"slate_50" => Some(0xf8fafc),
"slate_100" => Some(0xf1f5f9),
"slate_200" => Some(0xe2e8f0),
"slate_300" => Some(0xcbd5e1),
"slate_400" => Some(0x94a3b8),
"slate_500" => Some(0x64748b),
"slate_600" => Some(0x475569),
"slate_700" => Some(0x334155),
"slate_800" => Some(0x1e293b),
"slate_900" => Some(0x0f172a),
"slate_950" => Some(0x020617),
"stone_50" => Some(0xfafaf9),
"stone_100" => Some(0xf5f5f4),
"stone_200" => Some(0xe7e5e4),
"stone_300" => Some(0xd6d3d1),
"stone_400" => Some(0xa8a29e),
"stone_500" => Some(0x78716c),
"stone_600" => Some(0x57534e),
"stone_700" => Some(0x44403c),
"stone_800" => Some(0x292524),
"stone_900" => Some(0x1c1917),
"stone_950" => Some(0x0c0a09),
"teal_50" => Some(0xf0fdfa),
"teal_100" => Some(0xccfbf1),
"teal_200" => Some(0x99f6e4),
"teal_300" => Some(0x5eead4),
"teal_400" => Some(0x2dd4bf),
"teal_500" => Some(0x14b8a6),
"teal_600" => Some(0x0d9488),
"teal_700" => Some(0x0f766e),
"teal_800" => Some(0x115e59),
"teal_900" => Some(0x134e4a),
"teal_950" => Some(0x042f2e),
"violet_50" => Some(0xf5f3ff),
"violet_100" => Some(0xede9fe),
"violet_200" => Some(0xddd6fe),
"violet_300" => Some(0xc4b5fd),
"violet_400" => Some(0xa78bfa),
"violet_500" => Some(0x8b5cf6),
"violet_600" => Some(0x7c3aed),
"violet_700" => Some(0x6d28d9),
"violet_800" => Some(0x5b21b6),
"violet_900" => Some(0x4c1d95),
"violet_950" => Some(0x2e1065),
"yellow_50" => Some(0xfefce8),
"yellow_100" => Some(0xfef9c3),
"yellow_200" => Some(0xfef08a),
"yellow_300" => Some(0xfde047),
"yellow_400" => Some(0xfacc15),
"yellow_500" => Some(0xeab308),
"yellow_600" => Some(0xca8a04),
"yellow_700" => Some(0xa16207),
"yellow_800" => Some(0x854d0e),
"yellow_900" => Some(0x713f12),
"yellow_950" => Some(0x422006),
"zinc_50" => Some(0xfafafa),
"zinc_100" => Some(0xf4f4f5),
"zinc_200" => Some(0xe4e4e7),
"zinc_300" => Some(0xd4d4d8),
"zinc_400" => Some(0xa1a1aa),
"zinc_500" => Some(0x71717a),
"zinc_600" => Some(0x52525b),
"zinc_700" => Some(0x3f3f46),
"zinc_800" => Some(0x27272a),
"zinc_900" => Some(0x18181b),
"zinc_950" => Some(0x09090b),
"black" => Some(0x000000),
"white" => Some(0xffffff),
_ => None,
}
}
#[derive(Clone, Copy)]
pub(crate) struct AttrMethodInfo {
pub(crate) method: &'static str,
pub(crate) needs_id: bool,
pub(crate) multi_arg: bool,
}
#[derive(Clone, Copy)]
struct MethodProperties {
needs_id: bool,
multi_arg: bool,
}
pub(crate) fn lookup_attr_method(name: &str) -> Option<&'static str> {
match name {
"onClick" | "on_click" => Some("on_click"),
"onMouseDown" | "on_mouse_down" => Some("on_mouse_down"),
"onMouseUp" | "on_mouse_up" => Some("on_mouse_up"),
"onMouseMove" | "on_mouse_move" => Some("on_mouse_move"),
"onMouseExit" | "on_mouse_exit" => Some("on_mouse_exit"),
"onMousePressure" | "on_mouse_pressure" => Some("on_mouse_pressure"),
"onPinch" | "on_pinch" => Some("on_pinch"),
"onMouseDownOut" | "on_mouse_down_out" => Some("on_mouse_down_out"),
"onMouseUpOut" | "on_mouse_up_out" => Some("on_mouse_up_out"),
"onAnyMouseDown" | "on_any_mouse_down" => Some("on_any_mouse_down"),
"onAnyMouseUp" | "on_any_mouse_up" => Some("on_any_mouse_up"),
"onKeyDown" | "on_key_down" => Some("on_key_down"),
"onKeyUp" | "on_key_up" => Some("on_key_up"),
"onModifiersChanged" | "on_modifiers_changed" => Some("on_modifiers_changed"),
"onHover" | "on_hover" => Some("on_hover"),
"onAuxClick" | "on_aux_click" => Some("on_aux_click"),
"onScrollWheel" | "on_scroll_wheel" => Some("on_scroll_wheel"),
"onDrag" | "on_drag" => Some("on_drag"),
"onDragMove" | "on_drag_move" => Some("on_drag_move"),
"onDrop" | "on_drop" => Some("on_drop"),
"onAction" | "on_action" => Some("on_action"),
"onBoxedAction" | "on_boxed_action" => Some("on_boxed_action"),
"captureAnyMouseDown" | "capture_any_mouse_down" => Some("capture_any_mouse_down"),
"captureAnyMouseUp" | "capture_any_mouse_up" => Some("capture_any_mouse_up"),
"captureKeyDown" | "capture_key_down" => Some("capture_key_down"),
"captureKeyUp" | "capture_key_up" => Some("capture_key_up"),
"captureAction" | "capture_action" => Some("capture_action"),
"captureMousePressure" | "capture_mouse_pressure" => Some("capture_mouse_pressure"),
"capturePinch" | "capture_pinch" => Some("capture_pinch"),
"blockMouseExceptScroll" => Some("block_mouse_except_scroll"),
"canDrop" => Some("can_drop"),
"debugSelector" => Some("debug_selector"),
"dragOver" => Some("drag_over"),
"groupActive" => Some("group_active"),
"groupHover" => Some("group_hover"),
"inFocus" => Some("in_focus"),
"focusVisible" | "focus_visible" => Some("focus_visible"),
"keyContext" => Some("key_context"),
"tabGroup" => Some("tab_group"),
"tabIndex" => Some("tab_index"),
"tabStop" => Some("tab_stop"),
"trackFocus" => Some("track_focus"),
"windowControlArea" => Some("window_control_area"),
"anchorScroll" => Some("anchor_scroll"),
"hoverableTooltip" => Some("hoverable_tooltip"),
"tooltipShowDelay" => Some("tooltip_show_delay"),
"onA11yAction" | "on_a11y_action" => Some("on_a11y_action"),
"accessibilityId" => Some("accessibility_id"),
"ariaLabel" => Some("aria_label"),
"ariaDescription" => Some("aria_description"),
"ariaKeyShortcuts" => Some("aria_keyshortcuts"),
"ariaActiveDescendant" => Some("aria_active_descendant"),
"a11ySyntheticChildren" => Some("a11y_synthetic_children"),
"ariaSelected" => Some("aria_selected"),
"ariaExpanded" => Some("aria_expanded"),
"ariaToggled" => Some("aria_toggled"),
"ariaNumericValue" => Some("aria_numeric_value"),
"ariaNumericValueStep" => Some("aria_numeric_value_step"),
"ariaValue" => Some("aria_value"),
"ariaPlaceholder" => Some("aria_placeholder"),
"ariaMinNumericValue" => Some("aria_min_numeric_value"),
"ariaMaxNumericValue" => Some("aria_max_numeric_value"),
"ariaOrientation" => Some("aria_orientation"),
"ariaLevel" => Some("aria_level"),
"ariaPositionInSet" => Some("aria_position_in_set"),
"ariaSizeOfSet" => Some("aria_size_of_set"),
"ariaRowIndex" => Some("aria_row_index"),
"ariaColumnIndex" => Some("aria_column_index"),
"ariaRowCount" => Some("aria_row_count"),
"ariaColumnCount" => Some("aria_column_count"),
"imageCache" => Some("image_cache"),
"objectFit" => Some("object_fit"),
"onChildrenPrepainted" => Some("on_children_prepainted"),
"overflowScroll" => Some("overflow_scroll"),
"overflowXScroll" => Some("overflow_x_scroll"),
"overflowYScroll" => Some("overflow_y_scroll"),
"restrictScrollToAxis" => Some("restrict_scroll_to_axis"),
"scrollbarWidth" => Some("scrollbar_width"),
"trackScroll" => Some("track_scroll"),
"withFallback" => Some("with_fallback"),
"withLoading" => Some("with_loading"),
"width" => Some("w"),
"height" => Some("h"),
"minWidth" => Some("min_w"),
"minHeight" => Some("min_h"),
"maxWidth" => Some("max_w"),
"maxHeight" => Some("max_h"),
"gapX" => Some("gap_x"),
"gapY" => Some("gap_y"),
"flexBasis" => Some("flex_basis"),
"fontSize" => Some("text_size"),
"lineHeight" => Some("line_height"),
"fontWeight" => Some("font_weight"),
"fontFamily" => Some("font_family"),
"textAlign" => Some("text_align"),
"textColor" => Some("text_color"),
"backgroundColor" => Some("bg"),
"borderColor" => Some("border_color"),
"borderTop" => Some("border_t"),
"borderBottom" => Some("border_b"),
"borderLeft" => Some("border_l"),
"borderRight" => Some("border_r"),
"roundedTop" => Some("rounded_t"),
"roundedBottom" => Some("rounded_b"),
"roundedTopLeft" => Some("rounded_tl"),
"roundedTopRight" => Some("rounded_tr"),
"roundedBottomLeft" => Some("rounded_bl"),
"roundedBottomRight" => Some("rounded_br"),
"boxShadow" => Some("shadow"),
"externalDragPayload" => Some("external_drag_payload"),
"gridCols" => Some("grid_cols"),
"gridRows" => Some("grid_rows"),
"gridColsMinContent" => Some("grid_cols_min_content"),
"gridColsMaxContent" => Some("grid_cols_max_content"),
"gridRowsMinContent" => Some("grid_rows_min_content"),
"gridRowsMaxContent" => Some("grid_rows_max_content"),
"colSpan" => Some("col_span"),
"rowSpan" => Some("row_span"),
"colStart" => Some("col_start"),
"colEnd" => Some("col_end"),
"rowStart" => Some("row_start"),
"rowEnd" => Some("row_end"),
_ => None,
}
}
pub(crate) fn lookup_attr_method_info(name: &str) -> Option<AttrMethodInfo> {
let method = lookup_attr_method(name)?;
let properties = method_properties(method);
Some(AttrMethodInfo {
method,
needs_id: properties.needs_id,
multi_arg: properties.multi_arg,
})
}
pub(crate) fn lookup_attr_flag_method(name: &str) -> Option<&'static str> {
match name {
"flexGrow" => Some("flex_grow_1"),
"flexShrink" => Some("flex_shrink_1"),
"border_t" => Some("border_t_1"),
"border_b" => Some("border_b_1"),
"border_l" => Some("border_l_1"),
"border_r" => Some("border_r_1"),
"border_x" => Some("border_x_1"),
"border_y" => Some("border_y_1"),
_ => lookup_attr_method(name),
}
}
pub(crate) fn is_stateful_attr(name: &str) -> bool {
if let Some(info) = lookup_attr_method_info(name) {
return info.needs_id;
}
is_stateful_method(name)
}
pub(crate) fn is_stateful_method(method: &str) -> bool {
method_properties(method).needs_id
}
fn method_properties(method: &str) -> MethodProperties {
match method {
"group_active" | "on_a11y_action" | "on_drag" => MethodProperties {
needs_id: true,
multi_arg: true,
},
"active"
| "a11y_synthetic_children"
| "accessibility_id"
| "anchor_scroll"
| "aria_active_descendant"
| "aria_column_count"
| "aria_column_index"
| "aria_description"
| "aria_expanded"
| "aria_keyshortcuts"
| "aria_label"
| "aria_level"
| "aria_max_numeric_value"
| "aria_min_numeric_value"
| "aria_numeric_value"
| "aria_numeric_value_step"
| "aria_orientation"
| "aria_placeholder"
| "aria_position_in_set"
| "aria_row_count"
| "aria_row_index"
| "aria_selected"
| "aria_size_of_set"
| "aria_toggled"
| "aria_value"
| "external_drag_payload"
| "focusable"
| "hoverable_tooltip"
| "on_aux_click"
| "on_click"
| "on_hover"
| "overflow_scroll"
| "overflow_x_scroll"
| "overflow_y_scroll"
| "role"
| "restrict_scroll_to_axis"
| "tooltip"
| "tooltip_show_delay"
| "track_scroll" => MethodProperties {
needs_id: true,
multi_arg: false,
},
"group_hover" | "on_boxed_action" | "on_mouse_down" | "on_mouse_up" | "on_mouse_up_out" => {
MethodProperties {
needs_id: false,
multi_arg: true,
}
}
_ => MethodProperties {
needs_id: false,
multi_arg: false,
},
}
}
pub(crate) fn is_stateful_class(class: &str) -> bool {
matches!(
class,
"overflow-scroll" | "overflow-x-scroll" | "overflow-y-scroll"
)
}
pub(crate) fn lookup_spacing_method(prefix: &str) -> Option<&'static str> {
match prefix {
"gap_" => Some("gap"),
"gap_x_" => Some("gap_x"),
"gap_y_" => Some("gap_y"),
"p_" => Some("p"),
"px_" => Some("px"),
"py_" => Some("py"),
"pt_" => Some("pt"),
"pb_" => Some("pb"),
"pl_" => Some("pl"),
"pr_" => Some("pr"),
"m_" => Some("m"),
"mx_" => Some("mx"),
"my_" => Some("my"),
"mt_" => Some("mt"),
"mb_" => Some("mb"),
"ml_" => Some("ml"),
"mr_" => Some("mr"),
"w_" => Some("w"),
"h_" => Some("h"),
"size_" => Some("size"),
"min_w_" => Some("min_w"),
"max_w_" => Some("max_w"),
"min_h_" => Some("min_h"),
"max_h_" => Some("max_h"),
_ => None,
}
}
pub(crate) const COLOR_FAMILIES: &[&str] = &[
"amber", "blue", "cyan", "emerald", "fuchsia", "gray", "green", "indigo", "lime", "neutral",
"orange", "pink", "purple", "red", "rose", "sky", "slate", "stone", "teal", "violet", "yellow",
"zinc",
];
pub(crate) const COLOR_SHADES: &[&str] = &[
"50", "100", "200", "300", "400", "500", "600", "700", "800", "900", "950",
];
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum LengthClassFamily {
Sizing,
Spacing,
}
impl LengthClassFamily {
pub(crate) const fn allows_percent(self) -> bool {
matches!(self, Self::Sizing)
}
pub(crate) const fn allows_fraction(self) -> bool {
matches!(self, Self::Sizing)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct LengthClassSpec {
pub(crate) prefix: &'static str,
pub(crate) method: &'static str,
pub(crate) family: LengthClassFamily,
}
impl LengthClassSpec {
const fn sizing(prefix: &'static str, method: &'static str) -> Self {
Self {
prefix,
method,
family: LengthClassFamily::Sizing,
}
}
const fn spacing(prefix: &'static str, method: &'static str) -> Self {
Self {
prefix,
method,
family: LengthClassFamily::Spacing,
}
}
}
pub(crate) const LENGTH_CLASS_SPECS: &[LengthClassSpec] = &[
LengthClassSpec::sizing("min-w-", "min_w"),
LengthClassSpec::sizing("max-w-", "max_w"),
LengthClassSpec::sizing("min-h-", "min_h"),
LengthClassSpec::sizing("max-h-", "max_h"),
LengthClassSpec::spacing("gap-x-", "gap_x"),
LengthClassSpec::spacing("gap-y-", "gap_y"),
LengthClassSpec::sizing("size-", "size"),
LengthClassSpec::spacing("gap-", "gap"),
LengthClassSpec::spacing("px-", "px"),
LengthClassSpec::spacing("py-", "py"),
LengthClassSpec::spacing("pt-", "pt"),
LengthClassSpec::spacing("pb-", "pb"),
LengthClassSpec::spacing("pl-", "pl"),
LengthClassSpec::spacing("pr-", "pr"),
LengthClassSpec::spacing("mx-", "mx"),
LengthClassSpec::spacing("my-", "my"),
LengthClassSpec::spacing("mt-", "mt"),
LengthClassSpec::spacing("mb-", "mb"),
LengthClassSpec::spacing("ml-", "ml"),
LengthClassSpec::spacing("mr-", "mr"),
LengthClassSpec::sizing("w-", "w"),
LengthClassSpec::sizing("h-", "h"),
LengthClassSpec::spacing("p-", "p"),
LengthClassSpec::spacing("m-", "m"),
];
pub(crate) fn split_length_class(class: &str) -> Option<(&'static str, &str, LengthClassFamily)> {
for spec in LENGTH_CLASS_SPECS {
if let Some(value) = class.strip_prefix(spec.prefix) {
return Some((spec.method, value, spec.family));
}
}
None
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct CommonClassSupport {
name: &'static str,
strict_no_arg: bool,
dynamic_fast_path: bool,
}
impl CommonClassSupport {
const fn both(name: &'static str) -> Self {
Self {
name,
strict_no_arg: true,
dynamic_fast_path: true,
}
}
const fn strict_only(name: &'static str) -> Self {
Self {
name,
strict_no_arg: true,
dynamic_fast_path: false,
}
}
const fn dynamic_only(name: &'static str) -> Self {
Self {
name,
strict_no_arg: false,
dynamic_fast_path: true,
}
}
}
pub(crate) const COMMON_CLASS_SUPPORT: &[CommonClassSupport] = &[
CommonClassSupport::both("flex"),
CommonClassSupport::both("flex-col"),
CommonClassSupport::both("flex-col-reverse"),
CommonClassSupport::both("flex-row"),
CommonClassSupport::both("flex-row-reverse"),
CommonClassSupport::both("flex-1"),
CommonClassSupport::both("flex-auto"),
CommonClassSupport::both("flex-initial"),
CommonClassSupport::both("flex-none"),
CommonClassSupport::both("flex-grow"),
CommonClassSupport::both("flex-grow-0"),
CommonClassSupport::both("flex-grow-1"),
CommonClassSupport::both("flex-wrap"),
CommonClassSupport::both("flex-wrap-reverse"),
CommonClassSupport::both("flex-nowrap"),
CommonClassSupport::both("flex-shrink"),
CommonClassSupport::both("flex-shrink-0"),
CommonClassSupport::both("flex-shrink-1"),
CommonClassSupport::both("block"),
CommonClassSupport::both("grid"),
CommonClassSupport::both("hidden"),
CommonClassSupport::both("absolute"),
CommonClassSupport::both("relative"),
CommonClassSupport::both("items-center"),
CommonClassSupport::both("items-start"),
CommonClassSupport::both("items-end"),
CommonClassSupport::both("items-baseline"),
CommonClassSupport::both("items-stretch"),
CommonClassSupport::both("justify-center"),
CommonClassSupport::both("justify-between"),
CommonClassSupport::both("justify-start"),
CommonClassSupport::both("justify-end"),
CommonClassSupport::both("justify-around"),
CommonClassSupport::both("justify-evenly"),
CommonClassSupport::both("content-normal"),
CommonClassSupport::both("content-center"),
CommonClassSupport::both("content-start"),
CommonClassSupport::both("content-end"),
CommonClassSupport::both("content-between"),
CommonClassSupport::both("content-around"),
CommonClassSupport::both("content-evenly"),
CommonClassSupport::both("content-stretch"),
CommonClassSupport::both("self-start"),
CommonClassSupport::both("self-end"),
CommonClassSupport::both("self-flex-start"),
CommonClassSupport::both("self-flex-end"),
CommonClassSupport::both("self-center"),
CommonClassSupport::both("self-baseline"),
CommonClassSupport::both("self-stretch"),
CommonClassSupport::dynamic_only("gap-1"),
CommonClassSupport::dynamic_only("gap-2"),
CommonClassSupport::dynamic_only("gap-3"),
CommonClassSupport::dynamic_only("gap-4"),
CommonClassSupport::dynamic_only("gap-5"),
CommonClassSupport::dynamic_only("gap-6"),
CommonClassSupport::dynamic_only("gap-8"),
CommonClassSupport::dynamic_only("gap-10"),
CommonClassSupport::dynamic_only("gap-12"),
CommonClassSupport::dynamic_only("p-1"),
CommonClassSupport::dynamic_only("p-2"),
CommonClassSupport::dynamic_only("p-3"),
CommonClassSupport::dynamic_only("p-4"),
CommonClassSupport::dynamic_only("p-5"),
CommonClassSupport::dynamic_only("p-6"),
CommonClassSupport::dynamic_only("p-8"),
CommonClassSupport::dynamic_only("px-1"),
CommonClassSupport::dynamic_only("px-2"),
CommonClassSupport::dynamic_only("px-3"),
CommonClassSupport::dynamic_only("px-4"),
CommonClassSupport::dynamic_only("px-6"),
CommonClassSupport::dynamic_only("py-1"),
CommonClassSupport::dynamic_only("py-2"),
CommonClassSupport::dynamic_only("py-3"),
CommonClassSupport::dynamic_only("py-4"),
CommonClassSupport::dynamic_only("py-6"),
CommonClassSupport::dynamic_only("pt-1"),
CommonClassSupport::dynamic_only("pt-2"),
CommonClassSupport::dynamic_only("pt-4"),
CommonClassSupport::dynamic_only("pt-6"),
CommonClassSupport::dynamic_only("pb-1"),
CommonClassSupport::dynamic_only("pb-2"),
CommonClassSupport::dynamic_only("pb-4"),
CommonClassSupport::dynamic_only("pb-6"),
CommonClassSupport::dynamic_only("pl-2"),
CommonClassSupport::dynamic_only("pl-4"),
CommonClassSupport::dynamic_only("pr-2"),
CommonClassSupport::dynamic_only("pr-4"),
CommonClassSupport::dynamic_only("m-1"),
CommonClassSupport::dynamic_only("m-2"),
CommonClassSupport::dynamic_only("m-4"),
CommonClassSupport::dynamic_only("mx-1"),
CommonClassSupport::dynamic_only("mx-2"),
CommonClassSupport::dynamic_only("mx-4"),
CommonClassSupport::dynamic_only("my-1"),
CommonClassSupport::dynamic_only("my-2"),
CommonClassSupport::dynamic_only("my-4"),
CommonClassSupport::dynamic_only("mt-1"),
CommonClassSupport::dynamic_only("mt-2"),
CommonClassSupport::dynamic_only("mt-4"),
CommonClassSupport::dynamic_only("mb-1"),
CommonClassSupport::dynamic_only("mb-2"),
CommonClassSupport::dynamic_only("mb-4"),
CommonClassSupport::both("w-full"),
CommonClassSupport::both("h-full"),
CommonClassSupport::both("size-full"),
CommonClassSupport::both("aspect-square"),
CommonClassSupport::strict_only("w-px"),
CommonClassSupport::strict_only("h-px"),
CommonClassSupport::strict_only("size-px"),
CommonClassSupport::strict_only("w-auto"),
CommonClassSupport::strict_only("h-auto"),
CommonClassSupport::both("text-xs"),
CommonClassSupport::both("text-sm"),
CommonClassSupport::both("text-base"),
CommonClassSupport::both("text-lg"),
CommonClassSupport::both("text-xl"),
CommonClassSupport::both("text-2xl"),
CommonClassSupport::both("text-3xl"),
CommonClassSupport::both("text-left"),
CommonClassSupport::both("text-center"),
CommonClassSupport::both("text-right"),
CommonClassSupport::both("whitespace-normal"),
CommonClassSupport::both("whitespace-nowrap"),
CommonClassSupport::both("truncate"),
CommonClassSupport::both("text-ellipsis"),
CommonClassSupport::both("text-ellipsis-start"),
CommonClassSupport::both("text-ellipsis-middle"),
CommonClassSupport::both("no-underline"),
CommonClassSupport::both("italic"),
CommonClassSupport::both("not-italic"),
CommonClassSupport::both("underline"),
CommonClassSupport::both("line-through"),
CommonClassSupport::both("text-decoration-solid"),
CommonClassSupport::both("text-decoration-wavy"),
CommonClassSupport::both("text-decoration-0"),
CommonClassSupport::both("text-decoration-1"),
CommonClassSupport::both("text-decoration-2"),
CommonClassSupport::both("text-decoration-4"),
CommonClassSupport::both("text-decoration-8"),
CommonClassSupport::dynamic_only("font-thin"),
CommonClassSupport::dynamic_only("font-extralight"),
CommonClassSupport::dynamic_only("font-light"),
CommonClassSupport::dynamic_only("font-normal"),
CommonClassSupport::dynamic_only("font-medium"),
CommonClassSupport::dynamic_only("font-semibold"),
CommonClassSupport::dynamic_only("font-bold"),
CommonClassSupport::dynamic_only("font-extrabold"),
CommonClassSupport::dynamic_only("font-black"),
CommonClassSupport::both("border"),
CommonClassSupport::both("border-2"),
CommonClassSupport::both("border-dashed"),
CommonClassSupport::both("border-t"),
CommonClassSupport::both("border-b"),
CommonClassSupport::both("border-l"),
CommonClassSupport::both("border-r"),
CommonClassSupport::both("border-x"),
CommonClassSupport::both("border-y"),
CommonClassSupport::both("border-t-2"),
CommonClassSupport::both("border-b-2"),
CommonClassSupport::both("border-l-2"),
CommonClassSupport::both("border-r-2"),
CommonClassSupport::both("border-x-2"),
CommonClassSupport::both("border-y-2"),
CommonClassSupport::both("rounded-none"),
CommonClassSupport::both("rounded-sm"),
CommonClassSupport::both("rounded-md"),
CommonClassSupport::both("rounded-lg"),
CommonClassSupport::both("rounded-xl"),
CommonClassSupport::strict_only("rounded-2xl"),
CommonClassSupport::strict_only("rounded-3xl"),
CommonClassSupport::both("rounded-full"),
CommonClassSupport::strict_only("rounded-t-none"),
CommonClassSupport::strict_only("rounded-t-sm"),
CommonClassSupport::strict_only("rounded-t-md"),
CommonClassSupport::strict_only("rounded-t-lg"),
CommonClassSupport::strict_only("rounded-t-xl"),
CommonClassSupport::strict_only("rounded-t-2xl"),
CommonClassSupport::strict_only("rounded-t-3xl"),
CommonClassSupport::strict_only("rounded-t-full"),
CommonClassSupport::strict_only("rounded-b-none"),
CommonClassSupport::strict_only("rounded-b-sm"),
CommonClassSupport::strict_only("rounded-b-md"),
CommonClassSupport::strict_only("rounded-b-lg"),
CommonClassSupport::strict_only("rounded-b-xl"),
CommonClassSupport::strict_only("rounded-b-2xl"),
CommonClassSupport::strict_only("rounded-b-3xl"),
CommonClassSupport::strict_only("rounded-b-full"),
CommonClassSupport::strict_only("rounded-r-none"),
CommonClassSupport::strict_only("rounded-r-sm"),
CommonClassSupport::strict_only("rounded-r-md"),
CommonClassSupport::strict_only("rounded-r-lg"),
CommonClassSupport::strict_only("rounded-r-xl"),
CommonClassSupport::strict_only("rounded-r-2xl"),
CommonClassSupport::strict_only("rounded-r-3xl"),
CommonClassSupport::strict_only("rounded-r-full"),
CommonClassSupport::strict_only("rounded-l-none"),
CommonClassSupport::strict_only("rounded-l-sm"),
CommonClassSupport::strict_only("rounded-l-md"),
CommonClassSupport::strict_only("rounded-l-lg"),
CommonClassSupport::strict_only("rounded-l-xl"),
CommonClassSupport::strict_only("rounded-l-2xl"),
CommonClassSupport::strict_only("rounded-l-3xl"),
CommonClassSupport::strict_only("rounded-l-full"),
CommonClassSupport::both("cursor-pointer"),
CommonClassSupport::both("cursor-default"),
CommonClassSupport::both("cursor-text"),
CommonClassSupport::both("cursor-move"),
CommonClassSupport::both("cursor-not-allowed"),
CommonClassSupport::both("cursor-context-menu"),
CommonClassSupport::both("cursor-crosshair"),
CommonClassSupport::both("cursor-vertical-text"),
CommonClassSupport::both("cursor-alias"),
CommonClassSupport::both("cursor-copy"),
CommonClassSupport::both("cursor-no-drop"),
CommonClassSupport::both("cursor-grab"),
CommonClassSupport::both("cursor-grabbing"),
CommonClassSupport::both("cursor-ew-resize"),
CommonClassSupport::both("cursor-ns-resize"),
CommonClassSupport::both("cursor-nesw-resize"),
CommonClassSupport::both("cursor-nwse-resize"),
CommonClassSupport::both("cursor-col-resize"),
CommonClassSupport::both("cursor-row-resize"),
CommonClassSupport::both("cursor-n-resize"),
CommonClassSupport::both("cursor-e-resize"),
CommonClassSupport::both("cursor-s-resize"),
CommonClassSupport::both("cursor-w-resize"),
CommonClassSupport::both("debug-outline"),
CommonClassSupport::both("overflow-hidden"),
CommonClassSupport::both("overflow-x-hidden"),
CommonClassSupport::both("overflow-y-hidden"),
CommonClassSupport::strict_only("overflow-scroll"),
CommonClassSupport::strict_only("overflow-x-scroll"),
CommonClassSupport::strict_only("overflow-y-scroll"),
CommonClassSupport::both("shadow-none"),
CommonClassSupport::both("shadow-2xs"),
CommonClassSupport::both("shadow-xs"),
CommonClassSupport::both("shadow-sm"),
CommonClassSupport::both("shadow-md"),
CommonClassSupport::both("shadow-lg"),
CommonClassSupport::both("shadow-xl"),
CommonClassSupport::both("shadow-2xl"),
CommonClassSupport::dynamic_only("opacity-0"),
CommonClassSupport::dynamic_only("opacity-25"),
CommonClassSupport::dynamic_only("opacity-50"),
CommonClassSupport::dynamic_only("opacity-75"),
CommonClassSupport::dynamic_only("opacity-100"),
CommonClassSupport::both("col-span-full"),
CommonClassSupport::both("col-start-auto"),
CommonClassSupport::both("col-end-auto"),
CommonClassSupport::both("row-span-full"),
CommonClassSupport::both("row-start-auto"),
CommonClassSupport::both("row-end-auto"),
];
pub(crate) fn is_supported_common_no_arg_class(class: &str) -> bool {
COMMON_CLASS_SUPPORT
.iter()
.any(|entry| entry.strict_no_arg && entry.name == class)
}
pub(crate) fn dynamic_common_classes() -> impl Iterator<Item = &'static str> {
COMMON_CLASS_SUPPORT
.iter()
.filter(|entry| entry.dynamic_fast_path)
.map(|entry| entry.name)
}
pub(crate) fn is_valid_text_size(size: &str) -> bool {
matches!(size, "xs" | "sm" | "base" | "lg" | "xl" | "2xl" | "3xl")
}
pub(crate) fn lookup_tag_default(tag: &str) -> Option<&'static str> {
match tag {
"h1" => Some("text-3xl font-bold"),
"h2" => Some("text-2xl font-bold"),
"h3" => Some("text-xl font-bold"),
"h4" => Some("text-lg font-bold"),
"h5" => Some("text-base font-bold"),
"h6" => Some("text-sm font-bold"),
"button" => Some("cursor-pointer"),
"a" => Some("cursor-pointer"),
"input" => Some("px-2 py-1"),
"textarea" => Some("px-2 py-1"),
"ul" => Some("flex flex-col"),
"ol" => Some("flex flex-col"),
"li" => Some("flex items-center"),
"p" => Some("text-base"),
"label" => Some("text-sm"),
"form" => Some("flex flex-col gap-4"),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn color_table_contains_full_tailwind_palette() {
for family in COLOR_FAMILIES {
for shade in COLOR_SHADES {
let key = format!("{family}_{shade}");
assert!(
lookup_color(&key).is_some(),
"缺少颜色: {key}(请在 lookup_color 中补充)"
);
}
}
}
#[test]
fn color_table_contains_black_and_white() {
assert_eq!(lookup_color("black"), Some(0x000000));
assert_eq!(lookup_color("white"), Some(0xffffff));
}
#[test]
fn color_table_spot_check_values() {
assert_eq!(lookup_color("red_500"), Some(0xef4444));
assert_eq!(lookup_color("blue_500"), Some(0x3b82f6));
assert_eq!(lookup_color("green_500"), Some(0x22c55e));
assert_eq!(lookup_color("gray_500"), Some(0x6b7280));
assert_eq!(lookup_color("amber_500"), Some(0xf59e0b));
assert_eq!(lookup_color("purple_500"), Some(0xa855f7));
}
#[test]
fn color_table_unknown_returns_none() {
assert_eq!(lookup_color("not_a_color"), None);
assert_eq!(lookup_color("red_999"), None);
assert_eq!(lookup_color(""), None);
}
#[test]
fn attr_method_camel_case_events() {
let cases = [
("onClick", "on_click"),
("onMouseDown", "on_mouse_down"),
("onKeyDown", "on_key_down"),
("onDragMove", "on_drag_move"),
("onBoxedAction", "on_boxed_action"),
("onAuxClick", "on_aux_click"),
("onA11yAction", "on_a11y_action"),
("onMouseExit", "on_mouse_exit"),
("onMousePressure", "on_mouse_pressure"),
("captureMousePressure", "capture_mouse_pressure"),
("onPinch", "on_pinch"),
("capturePinch", "capture_pinch"),
];
for (attr, method) in cases {
assert_eq!(lookup_attr_method(attr), Some(method), "{attr}");
}
}
#[test]
fn attr_method_snake_case_events() {
assert_eq!(lookup_attr_method("on_click"), Some("on_click"));
assert_eq!(lookup_attr_method("on_mouse_down"), Some("on_mouse_down"));
assert_eq!(lookup_attr_method("on_key_down"), Some("on_key_down"));
}
#[test]
fn attr_method_dimension_aliases() {
assert_eq!(lookup_attr_method("width"), Some("w"));
assert_eq!(lookup_attr_method("height"), Some("h"));
assert_eq!(lookup_attr_method("minWidth"), Some("min_w"));
assert_eq!(lookup_attr_method("maxHeight"), Some("max_h"));
assert_eq!(lookup_attr_method("trackFocus"), Some("track_focus"));
assert_eq!(lookup_attr_method("focusVisible"), Some("focus_visible"));
assert_eq!(
lookup_attr_method("tooltipShowDelay"),
Some("tooltip_show_delay")
);
assert_eq!(lookup_attr_method("groupHover"), Some("group_hover"));
assert_eq!(lookup_attr_method("groupActive"), Some("group_active"));
assert_eq!(lookup_attr_method("ariaLabel"), Some("aria_label"));
assert_eq!(lookup_attr_method("ariaSelected"), Some("aria_selected"));
assert_eq!(lookup_attr_method("fontSize"), Some("text_size"));
assert_eq!(lookup_attr_method("fontFamily"), Some("font_family"));
assert_eq!(lookup_attr_method("textColor"), Some("text_color"));
assert_eq!(lookup_attr_method("backgroundColor"), Some("bg"));
assert_eq!(lookup_attr_method("borderColor"), Some("border_color"));
assert_eq!(lookup_attr_method("flexGrow"), None);
assert_eq!(lookup_attr_method("flexShrink"), None);
assert_eq!(lookup_attr_method("zIndex"), None);
}
#[test]
fn attr_method_keeps_directional_border_value_methods() {
assert_eq!(lookup_attr_method("border_t"), None);
assert_eq!(lookup_attr_method("border_b"), None);
assert_eq!(lookup_attr_method("border_l"), None);
assert_eq!(lookup_attr_method("border_r"), None);
}
#[test]
fn attr_flag_method_maps_directional_border_width_flags() {
assert_eq!(lookup_attr_flag_method("border_t"), Some("border_t_1"));
assert_eq!(lookup_attr_flag_method("border_b"), Some("border_b_1"));
assert_eq!(lookup_attr_flag_method("border_l"), Some("border_l_1"));
assert_eq!(lookup_attr_flag_method("border_r"), Some("border_r_1"));
}
#[test]
fn attr_flag_method_maps_gpui_flex_flags() {
assert_eq!(lookup_attr_flag_method("flexGrow"), Some("flex_grow_1"));
assert_eq!(lookup_attr_flag_method("flexShrink"), Some("flex_shrink_1"));
}
#[test]
fn attr_method_unknown_returns_none() {
assert_eq!(lookup_attr_method("onFocus"), None);
assert_eq!(lookup_attr_method("onDoubleClick"), None);
assert_eq!(lookup_attr_method("unknown_attr"), None);
assert_eq!(lookup_attr_method(""), None);
}
#[test]
fn latest_stateful_aliases_keep_method_properties() {
let cases = [
("accessibilityId", "accessibility_id", false),
("ariaDescription", "aria_description", false),
("ariaKeyShortcuts", "aria_keyshortcuts", false),
("ariaActiveDescendant", "aria_active_descendant", false),
("a11ySyntheticChildren", "a11y_synthetic_children", false),
("ariaNumericValueStep", "aria_numeric_value_step", false),
("ariaValue", "aria_value", false),
("ariaPlaceholder", "aria_placeholder", false),
("restrictScrollToAxis", "restrict_scroll_to_axis", false),
("externalDragPayload", "external_drag_payload", false),
];
for (attr, method, multi_arg) in cases {
let info = lookup_attr_method_info(attr).unwrap_or_else(|| panic!("missing {attr}"));
assert_eq!(info.method, method, "{attr}");
assert!(info.needs_id, "{attr}");
assert_eq!(info.multi_arg, multi_arg, "{attr}");
assert!(is_stateful_attr(method), "{method}");
}
}
#[test]
fn latest_interactive_events_do_not_need_id() {
for attr in [
"onMouseExit",
"on_mouse_exit",
"onMousePressure",
"on_mouse_pressure",
"captureMousePressure",
"capture_mouse_pressure",
"onPinch",
"on_pinch",
"capturePinch",
"capture_pinch",
] {
let info = lookup_attr_method_info(attr).unwrap_or_else(|| panic!("missing {attr}"));
assert!(!info.needs_id, "{attr}");
assert!(!info.multi_arg, "{attr}");
}
}
#[test]
fn latest_styled_aliases_map_without_id() {
let cases = [
("scrollbarWidth", "scrollbar_width"),
("gridColsMinContent", "grid_cols_min_content"),
("gridColsMaxContent", "grid_cols_max_content"),
("gridRowsMinContent", "grid_rows_min_content"),
("gridRowsMaxContent", "grid_rows_max_content"),
];
for (attr, method) in cases {
let info = lookup_attr_method_info(attr).unwrap_or_else(|| panic!("missing {attr}"));
assert_eq!(info.method, method, "{attr}");
assert!(!info.needs_id, "{attr}");
assert!(!info.multi_arg, "{attr}");
assert!(!is_stateful_attr(method), "{method}");
}
}
#[test]
fn pinned_gpui_stateful_snapshot_is_classified() {
let methods: Vec<_> =
include_str!("../../tests/fixtures/gpui_stateful_methods_e973593.txt")
.lines()
.map(str::trim)
.filter(|line| !line.is_empty() && !line.starts_with('#'))
.collect();
assert_eq!(methods.len(), 42);
for method in methods {
assert!(is_stateful_method(method), "unclassified method: {method}");
}
}
#[test]
fn attr_method_info_keeps_behavior_flags_together() {
let a11y = lookup_attr_method_info("onA11yAction").unwrap();
assert_eq!(a11y.method, "on_a11y_action");
assert!(a11y.needs_id);
assert!(a11y.multi_arg);
let mouse_down = lookup_attr_method_info("onMouseDown").unwrap();
assert_eq!(mouse_down.method, "on_mouse_down");
assert!(!mouse_down.needs_id);
assert!(mouse_down.multi_arg);
let focus_visible = lookup_attr_method_info("focusVisible").unwrap();
assert_eq!(focus_visible.method, "focus_visible");
assert!(!focus_visible.needs_id);
assert!(!focus_visible.multi_arg);
let aria_label = lookup_attr_method_info("ariaLabel").unwrap();
assert_eq!(aria_label.method, "aria_label");
assert!(aria_label.needs_id);
assert!(!aria_label.multi_arg);
for attr in ["groupActive", "onA11yAction", "onDrag"] {
let info = lookup_attr_method_info(attr).unwrap();
assert!(info.needs_id, "{attr}");
assert!(info.multi_arg, "{attr}");
}
for attr in [
"groupHover",
"onMouseDown",
"onMouseUp",
"onMouseUpOut",
"onBoxedAction",
] {
let info = lookup_attr_method_info(attr).unwrap();
assert!(!info.needs_id, "{attr}");
assert!(info.multi_arg, "{attr}");
}
}
#[test]
fn stateful_attr_detects_event_handlers() {
assert!(is_stateful_attr("onClick"));
assert!(is_stateful_attr("on_click"));
assert!(is_stateful_attr("onDrag"));
assert!(is_stateful_attr("on_hover"));
}
#[test]
fn stateful_attr_detects_interactive_attrs() {
assert!(is_stateful_attr("active"));
assert!(is_stateful_attr("focusable"));
assert!(is_stateful_attr("overflow_scroll"));
assert!(is_stateful_attr("tooltip"));
assert!(is_stateful_attr("track_scroll"));
assert!(is_stateful_attr("onAuxClick"));
assert!(is_stateful_attr("ariaLabel"));
assert!(is_stateful_attr("role"));
assert!(is_stateful_attr("tooltipShowDelay"));
assert!(is_stateful_attr("groupActive"));
}
#[test]
fn stateful_attr_ignores_styled_trait_methods() {
assert!(!is_stateful_attr("hover"));
assert!(!is_stateful_attr("focus"));
assert!(!is_stateful_attr("group"));
assert!(!is_stateful_attr("groupHover"));
}
#[test]
fn stateful_attr_ignores_non_stateful() {
assert!(!is_stateful_attr("onMouseDown"));
assert!(!is_stateful_attr("captureKeyDown"));
assert!(!is_stateful_attr("class"));
assert!(!is_stateful_attr("id"));
assert!(!is_stateful_attr("flex"));
assert!(!is_stateful_attr("gap"));
}
#[test]
fn spacing_method_covers_all_directions() {
assert_eq!(lookup_spacing_method("gap_"), Some("gap"));
assert_eq!(lookup_spacing_method("gap_x_"), Some("gap_x"));
assert_eq!(lookup_spacing_method("gap_y_"), Some("gap_y"));
assert_eq!(lookup_spacing_method("p_"), Some("p"));
assert_eq!(lookup_spacing_method("px_"), Some("px"));
assert_eq!(lookup_spacing_method("py_"), Some("py"));
assert_eq!(lookup_spacing_method("m_"), Some("m"));
assert_eq!(lookup_spacing_method("mx_"), Some("mx"));
assert_eq!(lookup_spacing_method("my_"), Some("my"));
assert_eq!(lookup_spacing_method("w_"), Some("w"));
assert_eq!(lookup_spacing_method("h_"), Some("h"));
assert_eq!(lookup_spacing_method("min_w_"), Some("min_w"));
assert_eq!(lookup_spacing_method("max_h_"), Some("max_h"));
}
#[test]
fn spacing_method_unknown_returns_none() {
assert_eq!(lookup_spacing_method("text_"), None);
assert_eq!(lookup_spacing_method(""), None);
}
#[test]
fn split_length_class_prefers_long_prefixes() {
assert_eq!(
split_length_class("min-w-[280px]"),
Some(("min_w", "[280px]", LengthClassFamily::Sizing))
);
assert_eq!(
split_length_class("max-h-1/2"),
Some(("max_h", "1/2", LengthClassFamily::Sizing))
);
assert_eq!(
split_length_class("gap-x-[1rem]"),
Some(("gap_x", "[1rem]", LengthClassFamily::Spacing))
);
assert_eq!(
split_length_class("gap-y-4"),
Some(("gap_y", "4", LengthClassFamily::Spacing))
);
}
#[test]
fn split_length_class_separates_sizing_and_spacing_rules() {
assert_eq!(
split_length_class("w-[50%]"),
Some(("w", "[50%]", LengthClassFamily::Sizing))
);
assert_eq!(
split_length_class("size-1/2"),
Some(("size", "1/2", LengthClassFamily::Sizing))
);
assert_eq!(
split_length_class("p-[8px]"),
Some(("p", "[8px]", LengthClassFamily::Spacing))
);
assert_eq!(
split_length_class("m-1/2"),
Some(("m", "1/2", LengthClassFamily::Spacing))
);
assert_eq!(split_length_class("line-clamp-3"), None);
}
#[test]
fn length_class_family_capabilities_match_tailwind_subset() {
assert!(LengthClassFamily::Sizing.allows_percent());
assert!(LengthClassFamily::Sizing.allows_fraction());
assert!(!LengthClassFamily::Spacing.allows_percent());
assert!(!LengthClassFamily::Spacing.allows_fraction());
}
#[test]
fn common_class_metadata_distinguishes_strict_and_dynamic_support() {
assert!(is_supported_common_no_arg_class("flex"));
assert!(is_supported_common_no_arg_class("overflow-scroll"));
assert!(!is_supported_common_no_arg_class("gap-4"));
assert!(!is_supported_common_no_arg_class("font-bold"));
assert!(!is_supported_common_no_arg_class("not-a-class"));
let dynamic = dynamic_common_classes().collect::<Vec<_>>();
assert!(dynamic.contains(&"flex"));
assert!(dynamic.contains(&"gap-4"));
assert!(dynamic.contains(&"font-bold"));
assert!(!dynamic.contains(&"overflow-scroll"));
assert!(!dynamic.contains(&"overflow-x-scroll"));
assert!(!dynamic.contains(&"overflow-y-scroll"));
}
#[test]
fn common_class_metadata_has_no_duplicate_names() {
for (index, entry) in COMMON_CLASS_SUPPORT.iter().enumerate() {
assert!(
!COMMON_CLASS_SUPPORT[..index]
.iter()
.any(|prev| prev.name == entry.name),
"duplicate common class metadata entry: {}",
entry.name
);
}
}
#[test]
fn text_size_validates_known_sizes() {
for size in ["xs", "sm", "base", "lg", "xl", "2xl", "3xl"] {
assert!(is_valid_text_size(size), "应接受文本大小: {size}");
}
}
#[test]
fn text_size_rejects_unknown() {
assert!(!is_valid_text_size("huge"));
assert!(!is_valid_text_size("4xl"));
assert!(!is_valid_text_size("5xl"));
assert!(!is_valid_text_size("6xl"));
assert!(!is_valid_text_size(""));
}
}