Prefix Counter
Auto-generates unique prefixes (cs0, cs1, …) for card stack instances when no explicit prefix is provided. Ensures multi-instance HTML ID uniqueness.
# Test auto-prefix generation
_reset_prefix_counter()
assert _auto_prefix() == "cs0"
assert _auto_prefix() == "cs1"
assert _auto_prefix() == "cs2"
_reset_prefix_counter()
assert _auto_prefix() == "cs0" # Reset works
print ("Prefix counter tests passed!" )
Prefix counter tests passed!
Style Defaults
Module-level constants for focused card emphasis. Computed from the cjm_fasthtml_tailwind and cjm_fasthtml_daisyui libraries so consumers can see (and override) the exact default class strings.
# Verify default class strings
assert _DEFAULT_FOCUS_RING == "ring-1 ring-[color-mix(in_oklch,var(--color-primary),transparent_50%)]"
assert _DEFAULT_FOCUS_SHADOW == "shadow-lg shadow-primary"
assert _DEFAULT_FOCUS_BORDER_RADIUS == "rounded-box"
print ("Style default constants tests passed!" )
Style default constants tests passed!
CardStackStyleConfig
Visual styling for a card stack instance. Spacing values are set as CSS custom properties on the outer container and consumed by child elements via Tailwind’s arbitrary value syntax (e.g., gap-[var(--cs0-section-gap)]). Consumer JS can update them dynamically via style.setProperty().
source
CardStackStyleConfig
def CardStackStyleConfig(
section_gap:str = '1rem' , slot_padding:str = '0.25rem' , viewport_padding_x:str = '0.5rem' ,
viewport_padding_y:str = '0.5rem' , focus_padding_x:str = '0.5rem' , focus_padding_b:str = '1rem' ,
focus_ring:str = 'ring-1 ring-[color-mix(in_oklch,var(--color-primary),transparent_50%)]' ,
focus_shadow:str = 'shadow-lg shadow-primary' , focus_border_radius:str = 'rounded-box'
)-> None :
Visual styling for a card stack instance.
# Test CardStackStyleConfig defaults
style = CardStackStyleConfig()
assert style.section_gap == "1rem"
assert style.slot_padding == "0.25rem"
assert style.viewport_padding_x == "0.5rem"
assert style.viewport_padding_y == "0.5rem"
assert style.focus_padding_x == "0.5rem"
assert style.focus_padding_b == "1rem"
assert style.focus_shadow == "shadow-lg shadow-primary"
assert style.focus_border_radius == "rounded-box"
print ("CardStackStyleConfig defaults tests passed!" )
CardStackStyleConfig defaults tests passed!
# Test css_vars_style generates correct CSS custom property declarations
style = CardStackStyleConfig()
css = style.css_vars_style("cs0" )
assert "--cs0-section-gap: 1rem" in css
assert "--cs0-slot-padding: 0.25rem" in css
assert "--cs0-viewport-padding-x: 0.5rem" in css
assert "--cs0-viewport-padding-y: 0.5rem" in css
assert "--cs0-focus-padding-x: 0.5rem" in css
assert "--cs0-focus-padding-b: 1rem" in css
print ("css_vars_style tests passed!" )
css_vars_style tests passed!
# Test css_vars_style with custom values and different prefix
style = CardStackStyleConfig(section_gap= "0.5rem" , slot_padding= "0.125rem" )
css = style.css_vars_style("chat" )
assert "--chat-section-gap: 0.5rem" in css
assert "--chat-slot-padding: 0.125rem" in css
# Unchanged defaults still present
assert "--chat-viewport-padding-x: 0.5rem" in css
print ("css_vars_style custom values test passed!" )
css_vars_style custom values test passed!
CardStackConfig
Initialization-time settings for a card stack instance. Created once and reused across requests. The prefix drives CardStackHtmlIds and CardStackButtonIds generation for multi-instance support.
source
CardStackConfig
def CardStackConfig(
prefix:str =< factory> , visible_count_options:Tuple= (1 , 3 , 5 , 7 , 9 ), card_width_min:int = 30 , card_width_max:int = 120 ,
card_width_step:int = 5 , card_scale_min:int = 50 , card_scale_max:int = 200 , card_scale_step:int = 10 ,
click_to_focus:bool = False , disable_scroll_in_modes:Tuple= (), show_scrollbar:bool = True ,
style:CardStackStyleConfig=< factory>
)-> None :
Initialization-time settings for a card stack instance.
# Test CardStackConfig defaults with auto-prefix
_reset_prefix_counter()
config1 = CardStackConfig()
config2 = CardStackConfig()
assert config1.prefix == "cs0"
assert config2.prefix == "cs1"
assert config1.prefix != config2.prefix # Unique prefixes
print ("Auto-prefix uniqueness tests passed!" )
Auto-prefix uniqueness tests passed!
# Test CardStackConfig with explicit prefix
config = CardStackConfig(prefix= "text-stack" )
assert config.prefix == "text-stack"
print ("Explicit prefix test passed!" )
Explicit prefix test passed!
# Test CardStackConfig field defaults
_reset_prefix_counter()
config = CardStackConfig()
assert config.visible_count_options == (1 , 3 , 5 , 7 , 9 )
assert config.card_width_min == 30
assert config.card_width_max == 120
assert config.card_width_step == 5
assert config.card_scale_min == 50
assert config.card_scale_max == 200
assert config.card_scale_step == 10
assert config.click_to_focus == False
assert config.disable_scroll_in_modes == ()
assert isinstance (config.style, CardStackStyleConfig)
assert config.style.section_gap == "1rem"
print ("CardStackConfig defaults tests passed!" )
# Test CardStackConfig with custom values
config = CardStackConfig(
prefix= "chat" ,
visible_count_options= (3 , 5 , 7 ),
card_width_min= 40 ,
card_width_max= 100 ,
card_scale_min= 75 ,
card_scale_max= 150 ,
click_to_focus= True ,
disable_scroll_in_modes= ("split" , "edit" ),
style= CardStackStyleConfig(section_gap= "0.5rem" , focus_shadow= "shadow-md" ),
)
assert config.prefix == "chat"
assert config.visible_count_options == (3 , 5 , 7 )
assert config.card_width_min == 40
assert config.card_scale_min == 75
assert config.click_to_focus == True
assert config.disable_scroll_in_modes == ("split" , "edit" )
assert config.style.section_gap == "0.5rem"
assert config.style.focus_shadow == "shadow-md"
assert config.style.slot_padding == "0.25rem" # Unchanged default
print ("CardStackConfig custom value tests passed!" )