# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/02_franken.ipynb.

# %% auto 0
__all__ = ['franken_class_map', 'TextT', 'TextFont', 'PParagraph', 'PLarge', 'PLead', 'PSmall', 'PMuted', 'CodeSpan',
           'Blockquote', 'CodeBlock', 'H1', 'H2', 'H3', 'H4', 'ButtonT', 'Button', 'ContainerT', 'BackgroundT',
           'Container', 'Titled', 'DividerT', 'Divider', 'DividerSplit', 'DividerLine', 'Article', 'ArticleTitle',
           'ArticleMeta', 'SectionT', 'Section', 'Form', 'Fieldset', 'Legend', 'Input', 'Select', 'Radio', 'CheckboxX',
           'Range', 'TextArea', 'Switch', 'FormLabel', 'LabelT', 'Label', 'UkFormSection', 'GenericLabelInput',
           'LabelInput', 'LabelRange', 'LabelTextArea', 'LabelSwitch', 'LabelRadio', 'LabelCheckboxX', 'LabelSelect',
           'Options', 'UkSelect', 'LabelUkSelect', 'AT', 'ListT', 'UkList', 'ModalContainer', 'ModalDialog',
           'ModalHeader', 'ModalBody', 'ModalFooter', 'ModalTitle', 'ModalCloseButton', 'Modal', 'PaddingT',
           'PositionT', 'Placeholder', 'Progress', 'UkIcon', 'UkIconLink', 'DiceBearAvatar', 'FlexT', 'Grid',
           'DivFullySpaced', 'DivCentered', 'DivLAligned', 'DivRAligned', 'DivVStacked', 'DivHStacked', 'NavT',
           'NavContainer', 'NavParentLi', 'NavDividerLi', 'NavHeaderLi', 'NavSubtitle', 'NavCloseLi', 'NavBarContainer',
           'NavBarLSide', 'NavBarRSide', 'NavBarCenter', 'NavBarNav', 'NavBarSubtitle', 'NavBarNavContainer',
           'NavBarParentIcon', 'NavBar', 'SliderContainer', 'SliderItems', 'SliderNav', 'Slider',
           'DropDownNavContainer', 'TabContainer', 'CardT', 'CardTitle', 'CardHeader', 'CardBody', 'CardFooter',
           'CardContainer', 'Card', 'TableT', 'Table', 'Td', 'Th', 'Tbody', 'TableFromLists', 'TableFromDicts',
           'apply_classes', 'render_md']

# %% ../nbs/02_franken.ipynb
import fasthtml.common as fh
from .foundations import *
from fasthtml.common import Div, P, Span, FT
from enum import Enum, auto
from fasthtml.components import Uk_select,Uk_icon
from typing import Union
from fastcore.all import *

# %% ../nbs/02_franken.ipynb
class TextT(VEnum):
    'Text Styles from https://franken-ui.dev/docs/text'
    def _generate_next_value_(name, start, count, last_values):
        return str2ukcls('text', name)
    
    # Text Style
    lead,meta, italic = auto(), auto(), auto()
    # Text Size
    sm, default, lg = 'uk-text-small', 'uk-text', 'uk-text-large'
    # Text Weight
    light, normal, bold, lighter, bolder = auto(),auto(),auto(),auto(),auto()
    # Text Transform
    capitalize,uppercase, lowercase = auto(),auto(),auto()
    # Text Decoration
    decoration_none = auto()
    # Text Color
    muted,primary,secondary, success,warning, danger = auto(),auto(),auto(),auto(),auto(),auto()
    # Text Alignment
    left, right,center,justify = auto(), auto(), auto(), auto()
    # Vertical Alignment
    top,middle,bottom, baseline = auto(),auto(),auto(),auto()
    
    # Text Wrapping
    truncate,break_,nowrap = auto(),auto(),auto()

# %% ../nbs/02_franken.ipynb
class TextFont(Enum):
    "Combinations of TextT that are particularly useful"
    def __add__(self, other):   return stringify((self, other))
    def __radd__(self, other):  return stringify((other, self)) 
    def __str__(self): return self.value
    muted_sm = stringify((TextT.muted, TextT.sm))
    muted_lg = stringify((TextT.muted, TextT.lg))
    bold_sm = stringify((TextT.bold, TextT.sm))
    md_weight_sm = stringify((TextT.sm, 'font-medium'))

# %% ../nbs/02_franken.ipynb
def PParagraph(*c, # Contents of P tag (often text)
               cls='', # Classes in addition to paragraph styling
               **kwargs # Additional args for P tag
               )->FT: # P(..., cls='uk-paragraph')
    "P Tag with paragraph style applied"
    return fh.P(*c, cls=('uk-paragraph', stringify(cls)), **kwargs)
def PLarge(*c, # Contents of P tag (often text)
           cls='', # Classes in addition to paragraph styling
           **kwargs # Additional args for P tag
           )->FT: # P(..., cls='uk-text-large')
    "P Tag with large style applied"
    return fh.P(*c, cls=('uk-text-large', stringify(cls)), **kwargs)
def PLead(*c, # Contents of P tag (often text)
          cls='', # Classes in addition to paragraph styling
          **kwargs # Additional args for P tag
          )->FT: # P(..., cls='uk-text-lead')
    "P Tag with lead style applied"
    return fh.P(*c, cls=('uk-text-lead', stringify(cls)), **kwargs)
def PSmall(*c, # Contents of P tag (often text)
           cls='', # Classes in addition to paragraph styling
           **kwargs # Additional args for P tag
           )->FT: # P(..., cls='uk-text-small')
    "P Tag with small style applied"
    return fh.P(*c, cls=('uk-text-small', stringify(cls)), **kwargs)
def PMuted(*c, # Contents of P tag (often text)
           cls='', # Classes in addition to paragraph styling
           **kwargs # Additional args for P tag
           )->FT: # P(..., cls='uk-text-muted')
    "P Tag with muted style applied"
    return fh.P(*c, cls=('uk-text-muted', stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def CodeSpan(*c, # Contents of CodeSpan tag (inline text code snippets)
             cls=(), # Classes in addition to CodeSpan styling
             **kwargs # Additional args for CodeSpan tag
             )->FT: # Code(..., cls='uk-codespan')
    "A CodeSpan with Styling"
    return fh.Code(*c, cls=('uk-codespan', stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def Blockquote(*c:FT|str, # Contents of Blockquote tag (often text)
               cls:Enum|str|tuple=(), # Classes in addition to Blockquote styling
               **kwargs # Additional args for Blockquote tag
               )->FT: # Blockquote(..., cls='uk-blockquote')
    "Blockquote with Styling"
    return fh.Blockquote(*c, cls=('uk-blockquote',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def CodeBlock(*c: str, # Contents of Code tag (often text)
              cls: Enum | str | tuple = (), # Classes for the outer container
              code_cls: Enum | str | tuple = (), # Classes for the code tag
              **kwargs # Additional args for Code tag
              ) -> FT: # Div(Pre(Code(..., cls='uk-codeblock), cls='multiple tailwind styles'), cls='uk-block')
    "CodeBlock with Styling"
    return Div(
        Pre(Code(*c, cls=('uk-codeblock', stringify(code_cls)), **kwargs),
            cls=('bg-gray-100 dark:bg-gray-800 dark:text-gray-200 p-0.4 rounded text-sm font-mono')),
        cls=('uk-block', stringify(cls)))

# %% ../nbs/02_franken.ipynb
def H1(*c:FT|str, # Contents of H1 tag (often text)
       cls:Enum|str|tuple=(), # Classes in addition to H1 styling
       **kwargs # Additional args for H1 tag
       )->FT: # H1(..., cls='uk-h1')
    "H1 with styling and appropriate size"
    return fh.H1(*c, cls=('uk-h1',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def H2(*c:FT|str, # Contents of H2 tag (often text)
       cls:Enum|str|tuple=(), # Classes in addition to H2 styling
       **kwargs # Additional args for H2 tag
       )->FT: # H2(..., cls='uk-h2')
    "H2 with styling and appropriate size"
    return fh.H2(*c, cls=('uk-h2',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def H3(*c:FT|str, # Contents of H3 tag (often text)
       cls:Enum|str|tuple=(), # Classes in addition to H3 styling
       **kwargs # Additional args for H3 tag
       )->FT: # H3(..., cls='uk-h3')
    "H3 with styling and appropriate size"
    return fh.H3(*c, cls=('uk-h3',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def H4(*c:FT|str, # Contents of H4 tag (often text)
       cls:Enum|str|tuple=(), # Classes in addition to H4 styling
       **kwargs # Additional args for H4 tag
       )->FT: # H4(..., cls='uk-h4')
    "H4 with styling and appropriate size"
    return fh.H4(*c, cls=('uk-h4',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
class ButtonT(VEnum):
    "Options for styling Buttons"
    def _generate_next_value_(name, start, count, last_values): return str2ukcls('button', name)
    default = auto()
    primary = auto()
    secondary = auto()
    danger = auto()
    text = auto()
    link = auto()
    ghost = auto()

# %% ../nbs/02_franken.ipynb
def Button(*c: Union[str, FT], # Contents of `Button` tag (often text)
           cls: Union[str, Enum]=ButtonT.default, # Classes in addition to `Button` styling (use `ButtonT` for built in styles)
           submit=True, # Whether the button should submit a form
           **kwargs # Additional args for `Button` tag
           ) -> FT: # Button(..., cls='uk-button')
    "Button with Styling (defaults to `submit` for form submission)"
    if 'type' not in kwargs: kwargs['type'] = 'submit' if submit else 'button'
    return fh.Button(*c, cls=('uk-button', stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
class ContainerT(VEnum):
    'Max width container sizes from https://franken-ui.dev/docs/container'
    xs = 'uk-container-xsmall'
    sm = 'uk-container-small'
    lg = 'uk-container-large'
    xl = 'uk-container-xlarge'
    expand = 'uk-container-expand'

# %% ../nbs/02_franken.ipynb
class BackgroundT(VEnum):
    def _generate_next_value_(name, start, count, last_values): return str2ukcls('background', name)
    muted = auto()
    primary = auto()
    secondary = auto()
    default = auto()

# %% ../nbs/02_franken.ipynb
def Container(*c, # Contents of Container tag (often other FT Components)
              cls=('mt-5', ContainerT.xl), # Classes in addition to Container styling
              **kwargs # Additional args for Container (`Div` tag)
              )->FT: # Container(..., cls='uk-container')
    "Div to be used as a container that often wraps large sections or a page of content"
    return Div(*c, cls=('uk-container',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def Titled(title:str="FastHTML app", # Title of the page
           *c, # Contents of the page (often other tags)
           cls=ContainerT.xl, # Classes in addition to Container styling
           **kwargs # Additional args for Container (`Div` tag)
           )->FT: # Title, Main(Container(H1(title), content))
    "Creates a standard page structure for titled page.  Main(Container(title, content))"
    return fh.Title(title), fh.Main(Container(H1(title), *c, cls=cls, **kwargs))

# %% ../nbs/02_franken.ipynb
class DividerT(VEnum):
    "Divider Styles from https://franken-ui.dev/docs/divider"
    def _generate_next_value_(name, start, count, last_values): return str2ukcls('divider', name)
    icon=auto()
    sm='uk-divider-small'
    vertical=auto()

# %% ../nbs/02_franken.ipynb
def Divider(*c, # contents of Divider tag (often nothing)
            cls=('my-4', DividerT.icon), # Classes in addition to Divider styling
            **kwargs # Additional args for Divider tag
            )->FT: #  Hr(..., cls='uk-divider-icon') or Div(..., cls='uk-divider-vertical')
    "Divider with default styling and margin"
    cls = stringify(cls)
    container = Div if 'uk-divider-vertical' in cls else Hr
    return container(*c, cls=cls, **kwargs)

# %% ../nbs/02_franken.ipynb
def DividerSplit(*c, cls=(), line_cls=(), text_cls=()):
    "Creates a simple horizontal line divider with configurable thickness and vertical spacing"
    cls, line_cls, text_cls = map(stringify,(cls, line_cls, text_cls))
    return Div(cls='relative ' + cls)(
        Div(cls="absolute inset-0 flex items-center " + line_cls)(Span(cls="w-full border-t border-border")),
        Div(cls="relative flex justify-center " + text_cls)(Span(cls="bg-background px-2 ")(*c)))

# %% ../nbs/02_franken.ipynb
def DividerLine(lwidth=2, y_space=4): return Hr(cls=f"my-{y_space} h-[{lwidth}px] w-full bg-secondary")

# %% ../nbs/02_franken.ipynb
def Article(*c, # contents of Article tag (often other tags)
            cls=(), # Classes in addition to Article styling
            **kwargs # Additional args for Article tag
            )->FT: # Article(..., cls='uk-article')
    "A styled article container for blog posts or similar content"
    return fh.Article(*c, cls=('uk-article',stringify(cls)), **kwargs)

def ArticleTitle(*c, # contents of ArticleTitle tag (often other tags)
                 cls=(), # Classes in addition to ArticleTitle styling
                 **kwargs # Additional args for ArticleTitle tag
                 )->FT: # H1(..., cls='uk-article-title')
    "A title component for use within an Article"
    return H1(*c, cls=('uk-article-title',stringify(cls)), **kwargs)

def ArticleMeta(*c, # contents of ArticleMeta tag (often other tags)
                cls=(), # Classes in addition to ArticleMeta styling
                **kwargs # Additional args for ArticleMeta tag
                )->FT: # P(..., cls='uk-article-meta')
    "A metadata component for use within an Article showing things like date, author etc"
    return P(*c, cls=('uk-article-meta',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
class SectionT(VEnum):
    'Section styles from https://franken-ui.dev/docs/section'
    def _generate_next_value_(name, start, count, last_values): return str2ukcls('section', name)
    default = auto()
    muted = auto()
    primary = auto()
    secondary = auto()
    xs = 'uk-section-xsmall'
    sm = 'uk-section-small'
    lg = 'uk-section-large'
    xl = 'uk-section-xlarge'
    remove_vertical = auto()

# %% ../nbs/02_franken.ipynb
def Section(*c, # contents of Section tag (often other tags)
            cls=(), # Classes in addition to Section styling
            **kwargs # Additional args for Section tag
            )->FT: # Div(..., cls='uk-section')
    "Section with styling and margins"
    return fh.Div(*c, cls=('uk-section',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def Form(*c, # contents of Form tag (often Buttons, FormLabels, and LabelInputs)
          cls='space-y-3', # Classes in addition to Form styling (default is 'space-y-3' to prevent scrunched up form elements)
          **kwargs # Additional args for Form tag
          )->FT: # Form(..., cls='space-y-3')
    "A Form with default spacing between form elements"
    return fh.Form(*c, cls=stringify(cls), **kwargs)

# %% ../nbs/02_franken.ipynb
def Fieldset(*c, # contents of Fieldset tag (often other tags)
             cls=(), # Classes in addition to Fieldset styling
             **kwargs # Additional args for Fieldset tag
             )->FT: # Fieldset(..., cls='uk-fieldset')
    "A Fieldset with default styling"
    return fh.Fieldset(*c, cls=('uk-fieldset',stringify(cls)), **kwargs)

def Legend(*c, # contents of Legend tag (often other tags)
           cls=(), # Classes in addition to Legend styling
           **kwargs # Additional args for Legend tag
           )->FT: # Legend(..., cls='uk-legend')
    "A Legend with default styling"
    return fh.Legend(*c, cls=('uk-legend',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def Input(*c, # contents of Input tag (often nothing)
          cls=(), # Classes in addition to Input styling
          **kwargs # Additional args for Input tag
          )->FT: # Input(..., cls='uk-input')
    "An Input with default styling"
    return fh.Input(*c, cls=('uk-input',stringify(cls)), **kwargs)

def Select(*option, # options for the select dropdown
           cls=(), # Classes in addition to Select styling
           **kwargs # Additional args for Select tag
           )->FT: # Select(..., cls='uk-select')
    "A Select with default styling, though often `UkSelect` is a better choice"
    return fh.Select(*option, cls=('uk-select',stringify(cls)), **kwargs)
def Radio(*c, # contents of Radio tag (often nothing)
           cls=(), # Classes in addition to Radio styling
           **kwargs # Additional args for Radio tag
           )->FT: # Input(..., cls='uk-radio', type='radio')
    "A Radio with default styling"
    return fh.Input(*c, cls=('uk-radio',stringify(cls)), type='radio', **kwargs)
def CheckboxX(*c, # contents of CheckboxX tag (often nothing)
               cls=(), # Classes in addition to CheckboxX styling
               **kwargs # Additional args for CheckboxX tag
               )->FT: # Input(..., cls='uk-checkbox', type='checkbox')
    "A Checkbox with default styling"
    return fh.Input(*c, cls=('uk-checkbox',stringify(cls)), type='checkbox', **kwargs)
def Range(*c, # contents of Range tag (often nothing)
           cls=(), # Classes in addition to Range styling
           **kwargs # Additional args for Range tag
           )->FT: # Input(..., cls='uk-range', type='range')
    "A Range with default styling"
    return fh.Input(*c, cls=('uk-range',stringify(cls)), type='range', **kwargs)
def TextArea(*c, # contents of TextArea tag (often text)
             cls=(), # Classes in addition to TextArea styling
             **kwargs # Additional args for TextArea tag
             )->FT: # TextArea(..., cls='uk-textarea')
    "A Textarea with default styling"
    return fh.Textarea(*c, cls=('uk-textarea',stringify(cls)), **kwargs)
def Switch(*c, # contents of Switch tag (often nothing)
           cls=(), # Classes in addition to Switch styling
           **kwargs # Additional args for Switch tag
           )->FT: # Input(..., cls='uk-toggle-switch uk-toggle-switch-primary min-w-9', type='checkbox')
    "A Switch with default styling"
    return fh.Input(*c, cls=('uk-toggle-switch uk-toggle-switch-primary min-w-9',stringify(cls)), type='checkbox', **kwargs)

# %% ../nbs/02_franken.ipynb
def FormLabel(*c, # contents of FormLabel tag (often text)
               cls=(), # Classes in addition to FormLabel styling
               **kwargs # Additional args for FormLabel tag
               )->FT: # Label(..., cls='uk-form-label')
    "A Label with default styling"
    return fh.Label(*c, cls=('uk-form-label',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
class LabelT(VEnum):
    def _generate_next_value_(name, start, count, last_values): return str2ukcls('label', name)
    primary = auto()
    secondary = auto()
    danger = auto()

# %% ../nbs/02_franken.ipynb
def Label(*c, # contents of Label tag (often text)
           cls=(), # Classes in addition to Label styling
           **kwargs # Additional args for Label tag
           )->FT: # Label(..., cls='uk-label')
    "FrankenUI labels, which look like pills"
    return fh.Label(*c, cls=('uk-label',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def UkFormSection(title, description, *c, button_txt='Update', outer_margin=6, inner_margin=6):
    "A form section with a title, description and optional button"
    return Div(cls=f'space-y-{inner_margin} py-{outer_margin}')(
        Div(H3(title), P(description, cls=TextFont.muted_sm)),
        DividerSplit(), *c,
        Div(Button(button_txt, cls=ButtonT.primary)) if button_txt else None)

# %% ../nbs/02_franken.ipynb
def GenericLabelInput(
               label:str|FT, # FormLabel content (often text)
               lbl_cls='', # Additional classes for FormLabel
               input_cls='', # Additional classes for user input (Input, Select, etc)
               container=Div, # Container to wrap label and input in (default is Div)
               cls='', # Classes on container (default is '')
               id='', # id for label and input (`id`, `name` and `for` attributes are set to this value)
               input_fn=noop, # User input FT component 
                **kwargs # Additional args for user input
                ): 
    "`Div(Label,Input)` component with Uk styling injected appropriately. Generally you should higher level API, such as `LabelInput` which is created for you in this library"
    if isinstance(label, str) or label.tag != 'label': 
        label = FormLabel(cls=stringify(lbl_cls), fr=id)(label)
    inp = input_fn(id=id, cls=stringify(input_cls), **kwargs)        
    if container: return container(label, inp, cls=stringify(cls))
    return label, inp

# %% ../nbs/02_franken.ipynb
def LabelInput(label:str|FT, # FormLabel content (often text)
               lbl_cls='', # Additional classes for `FormLabel`
               input_cls='', # Additional classes for `Input`
               cls='space-y-2', # Classes on container (default is `'space-y-2'` to prevent scrunched up form elements)
               id='', # id for `FormLabel` and `Input` (`id`, `name` and `for` attributes are set to this value)
                **kwargs # Additional args for `Input`
               )->FT:  # Div(cls='space-y-2')(`FormLabel`, `Input`)
    "A `FormLabel` and `Input` pair that provides default spacing and links/names them based on id"
    return GenericLabelInput(label=label, lbl_cls=lbl_cls, input_cls=input_cls,
                             container=Div, cls=cls, id=id, input_fn=Input, **kwargs)

# %% ../nbs/02_franken.ipynb
def LabelRange(label:str|FT, # FormLabel content (often text)
               lbl_cls='', # Additional classes for `FormLabel`
               input_cls='', # Additional classes for `Range`
               cls='space-y-2', # Classes on container (default is `'space-y-2'` to prevent scrunched up form elements)
               id='', # id for `FormLabel` and `Range` (`id`, `name` and `for` attributes are set to this value)
                **kwargs # Additional args for `Range`
               )->FT:  # Div(cls='space-y-2')(`FormLabel`, `Range`)
    "A `FormLabel` and `Range` pair that provides default spacing and links/names them based on id"
    return GenericLabelInput(label=label, lbl_cls=lbl_cls, input_cls=input_cls,
                             container=Div, cls=cls, id=id, input_fn=Range, **kwargs)

# %% ../nbs/02_franken.ipynb
def LabelTextArea(label:str|FT, # FormLabel content (often text)
                  value='', # Value for the textarea
                  lbl_cls='', # Additional classes for `FormLabel`
                  input_cls='', # Additional classes for `TextArea`
                  cls='space-y-2', # Classes on container (default is `'space-y-2'` to prevent scrunched up form elements)
                  id='', # id for `FormLabel` and `TextArea` (`id`, `name` and `for` attributes are set to this value)
                  **kwargs # Additional args for `TextArea`
                  )->FT:  # Div(cls='space-y-2')(`FormLabel`, `TextArea`)
    def text_area_with_value(**kw): return TextArea(value, **kw)
    return GenericLabelInput(label=label, lbl_cls=lbl_cls, input_cls=input_cls,
                             container=Div, cls=cls, id=id, input_fn=text_area_with_value, **kwargs)

# %% ../nbs/02_franken.ipynb
@delegates(GenericLabelInput, but=['input_fn','cls'])
def LabelSwitch(label:str|FT, # FormLabel content (often text)
               lbl_cls='', # Additional classes for `FormLabel`
               input_cls='', # Additional classes for `Switch`
               cls='space-x-2', # Classes on container (default is `'space-x-2'` to prevent scrunched up form elements)
               id='', # id for `FormLabel` and `Switch` (`id`, `name` and `for` attributes are set to this value)
                **kwargs # Additional args for `Switch`
               )->FT:  # Div(cls='space-y-2')(`FormLabel`, `Switch`)
    return GenericLabelInput(label=label, lbl_cls=lbl_cls, input_cls=input_cls,
                             container=Div, cls=cls, id=id, input_fn=Switch, **kwargs)

# %% ../nbs/02_franken.ipynb
def LabelRadio(label:str|FT, # FormLabel content (often text)
               lbl_cls='', # Additional classes for `FormLabel`
               input_cls='', # Additional classes for `Radio`
               container=Div, # Container to wrap label and input in (default is Div)
               cls='flex items-center space-x-2', # Classes on container (default is 'flex items-center space-x-2')
               id='', # id for `FormLabel` and `Radio` (`id`, `name` and `for` attributes are set to this value)
                **kwargs # Additional args for `Radio`
               )->FT:  # Div(cls='flex items-center space-x-2')(`FormLabel`, `Radio`)
    "A FormLabel and Radio pair that provides default spacing and links/names them based on id"
    if isinstance(label, str) or label.tag != 'label': 
        label = FormLabel(cls=stringify(lbl_cls), fr=id)(label)
    inp = Radio(id=id, cls=stringify(input_cls), **kwargs)        
    if container: return container(inp, label, cls=stringify(cls))
    return inp, label

# %% ../nbs/02_franken.ipynb
def LabelCheckboxX(label:str|FT, # FormLabel content (often text)
               lbl_cls='', # Additional classes for `FormLabel`
               input_cls='', # Additional classes for `CheckboxX`
               container=Div, # Container to wrap label and input in (default is Div)
               cls='flex items-center space-x-2', # Classes on container (default is 'flex items-center space-x-2')
               id='', # id for `FormLabel` and `CheckboxX` (`id`, `name` and `for` attributes are set to this value)
                **kwargs # Additional args for `CheckboxX`
               )->FT:  # Div(cls='flex items-center space-x-2')(`FormLabel`, `CheckboxX`)
    "A FormLabel and CheckboxX pair that provides default spacing and links/names them based on id"
    id = kwargs.pop('id', fh.unqid())
    if isinstance(label, str) or label.tag != 'label': 
        label = FormLabel(cls=stringify(lbl_cls), fr=id)(label)
    inp = CheckboxX(id=id, cls=stringify(input_cls), **kwargs)        
    if container: return container(inp, label, cls=stringify(cls))
    return inp, label

# %% ../nbs/02_franken.ipynb
def LabelSelect(*option, # Options for the select dropdown (can use `Options` helper function to create)
               label:str|FT, # FormLabel content (often text)
               lbl_cls='', # Additional classes for `FormLabel`
               input_cls='', # Additional classes for `Select`
               container=Div, # Container to wrap label and input in (default is Div)
               cls='space-y-2', # Classes on container (default is 'space-y-2')
               id='', # id for `FormLabel` and `Select` (`id`, `name` and `for` attributes are set to this value)
                **kwargs # Additional args for `Select`
                ):
    "A FormLabel and Select pair that provides default spacing and links/names them based on id (usually UkLabelSelect is a better choice)"
    if isinstance(label, str) or label.tag != 'label': 
        label = FormLabel(lbl_cls=stringify(lbl_cls), fr=id)(label)
    inp = Select(*option, id=id, cls=stringify(input_cls), **kwargs)        
    if container: return container(label, inp, cls=stringify(cls))
    return label, inp

# %% ../nbs/02_franken.ipynb
def Options(*c,                    # Content for an `Option`
            selected_idx:int=None, # Index location of selected `Option`
            disabled_idxs:set=None # Idex locations of disabled `Options`
           ):
    "Helper function to wrap things into `Option`s for use in `UkSelect`"
    return [fh.Option(o,selected=i==selected_idx, disabled=disabled_idxs and i in disabled_idxs) for i,o in enumerate(c)]

# %% ../nbs/02_franken.ipynb
def UkSelect(*option,            # Options for the select dropdown (can use `Options` helper function to create)
             inp_cls=(),         # Additional classes for the select input
             cls=('space-y-2',), # Classes for the outer div
             id="",              # ID for the select input
             name="",            # Name attribute for the select input
             placeholder="",     # Placeholder text for the select input
             searchable=False,   # Whether the select should be searchable
             **kwargs):          # Additional arguments passed to Uk_select
    "Creates a select dropdown with uk styling and option for adding a search box"
    inp_cls, cls = map(stringify, (inp_cls, cls))
    select = Uk_select(*option, cls=inp_cls, uk_cloak=True, id=id, 
                       name=name, placeholder=placeholder, searchable=searchable, **kwargs)
    return Div(cls=cls)(select)

# %% ../nbs/02_franken.ipynb
def LabelUkSelect(*option,            # Options for the select dropdown (can use `Options` helper function to create)
             label=(),           # String or FT component for the label
             lbl_cls=(),         # Additional classes for the label
             inp_cls=(),         # Additional classes for the select input
             cls=('space-y-2',), # Classes for the outer div
             id="",              # ID for the select input
             name="",            # Name attribute for the select input
             placeholder="",     # Placeholder text for the select input
             searchable=False,   # Whether the select should be searchable
             **kwargs):          # Additional arguments passed to Uk_select
    "A FormLabel and Select pair that provides default spacing and links/names them based on id"
    lbl_cls, inp_cls, cls = map(stringify, (lbl_cls, inp_cls, cls))
    if label: 
        lbl = FormLabel(cls=f'{lbl_cls}', fr=id)(label) 
    select = Uk_select(*option, cls=inp_cls, uk_cloak=True, id=id, 
                       name=name if name else id, placeholder=placeholder, searchable=searchable, **kwargs)
    return Div(cls=cls)(lbl, select) if label else Div(cls=cls)(select)

# %% ../nbs/02_franken.ipynb
class AT(VEnum):
    'Link styles from https://franken-ui.dev/docs/link'
    def _generate_next_value_(name, start, count, last_values): return str2ukcls('link', name)
    muted = auto()
    text = auto()
    reset = auto()
    primary = 'uk-link text-primary hover:text-primary-focus underline'


# %% ../nbs/02_franken.ipynb
class ListT(VEnum):
    'List styles from https://franken-ui.dev/docs/list'
    def _generate_next_value_(name, start, count, last_values): return str2ukcls('list', name)
    disc = auto()
    circle = auto()
    square = auto()
    decimal = auto()
    hyphen = auto()
    muted = auto()
    primary = auto()
    secondary = auto()
    bullet = auto()
    divider = auto()
    striped = auto()

# %% ../nbs/02_franken.ipynb
def UkList(*li, # `Li` tags to put in the list
           cls=(), # Additional classes on the list
           **kwargs # Additional args for `Ul` tag
           )->FT: # Ul(..., cls='uk-list')
    "Creates a list with styling"
    return fh.Ul(*li, cls=('uk-list',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def ModalContainer(*c, # Components to put in the modal (often `ModalDialog`)
                     cls=(), # Additional classes on the `ModalContainer`
                     **kwargs # Additional args for `Div` tag
                     )->FT: # Div(..., cls='uk-modal uk-modal-container')
    "Creates a modal container that components go in"
    return fh.Div(*c, cls=('uk-modal uk-modal-container',stringify(cls)), uk_modal=True, **kwargs)
def ModalDialog(*c, # Components to put in the `ModalDialog` (often `ModalBody`, `ModalHeader`, etc)
                  cls=(), # Additional classes on the `ModalDialog`
                  **kwargs # Additional args for `Div` tag
                  )->FT: # Div(..., cls='uk-modal-dialog')
    "Creates a modal dialog"
    return fh.Div(*c, cls=('uk-modal-dialog',   stringify(cls)),                **kwargs)
def ModalHeader(*c, # Components to put in the `ModalHeader`
                  cls=(), # Additional classes on the `ModalHeader`
                  **kwargs # Additional args for `Div` tag
                  )->FT: # Div(..., cls='uk-modal-header')
    "Creates a modal header"
    return fh.Div(*c, cls=('uk-modal-header',   stringify(cls)),                **kwargs)
def ModalBody(*c, # Components to put in the `ModalBody` (often forms, sign in buttons, images, etc.)
               cls=(), # Additional classes on the `ModalBody`
               **kwargs # Additional args for `Div` tag
               )->FT: # Div(..., cls='uk-modal-body')
    "Creates a modal body"
    return fh.Div(*c, cls=('uk-modal-body',     stringify(cls)),                **kwargs)
def ModalFooter(*c, # Components to put in the `ModalFooter` (often buttons)
                 cls=(), # Additional classes on the `ModalFooter`
                 **kwargs # Additional args for `Div` tag
                 )->FT: # Div(..., cls='uk-modal-footer')
    "Creates a modal footer"
    return fh.Div(*c, cls=('uk-modal-footer',   stringify(cls)),                **kwargs)
def ModalTitle(*c, # Components to put in the `ModalTitle` (often text)
                cls=(), # Additional classes on the `ModalTitle`
                **kwargs # Additional args for `H2` tag
                )->FT: # H2(..., cls='uk-modal-title')
    "Creates a modal title"
    return fh.H2(*c,  cls=('uk-modal-title',  stringify(cls)),  **kwargs)
def ModalCloseButton(*c, # Components to put in the button (often text and/or an icon)
                      cls=(), # Additional classes on the button
                      htmx=False, # Whether to use HTMX to close the modal (must add hx_get to a route that closes the modal)
                      **kwargs # Additional args for `Button` tag
                      )->FT: # Button(..., cls='uk-modal-close') + `hx_target` and `hx_swap` if htmx is True
    "Creates a button that closes a modal with js"
    if htmx: 
        kwargs['hx_target'] = 'closest .uk-modal'
        kwargs['hx_swap'] = 'delete'
    return Button(*c, cls=('uk-modal-close', stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def Modal(*c,                 # Components to put in the `ModalBody` (often forms, sign in buttons, images, etc.)
        header=None,          # Components that go in the `ModalHeader` (often a `ModalTitle`)
        footer=None,          # Components that go in the `ModalFooter` (often a `ModalCloseButton`)
        cls=(),               # Additional classes on the outermost `ModalContainer` 
        dialog_cls=(),        # Additional classes on the `ModalDialog` 
        header_cls='p-6',     # Additional classes on the `ModalHeader`
        body_cls='space-y-6', # Additional classes on the `ModalBody`
        footer_cls=(),        # Additional classes on the `ModalFooter`
        id='',                # id for the outermost container
        open=False,           # Whether the modal is open (typically used for HTMX controlled modals)
        **kwargs              # Additional args for the outermost `Div` tag
        )->FT: # Fully styled modal FT Component
    "Creates a modal with the appropriate classes to put the boilerplate in the appropriate places for you"
    if open:
        cls = stringify((cls, 'uk-open'))
        kwargs['style'] = stringify((kwargs.get('style',''), 'display: block;'))
    cls, dialog_cls, header_cls, body_cls, footer_cls = map(stringify, (cls, dialog_cls, header_cls, body_cls, footer_cls))
    res = []
    if header: res.append(ModalHeader(cls=header_cls)(header))
    res.append(ModalBody(cls=body_cls)(*c))
    if footer: res.append(ModalFooter(cls=footer_cls)(footer))
    return ModalContainer(ModalDialog(*res, cls=dialog_cls), cls=cls, id=id, **kwargs)

# %% ../nbs/02_franken.ipynb
class PaddingT(VEnum):
    'Padding Modifiers from https://franken-ui.dev/docs/padding'
    def _generate_next_value_(name, start, count, last_values): return str2ukcls('padding', name)
    xs = 'uk-padding-xs'
    sm = 'uk-padding-sm'
    default = ''
    md = 'uk-padding-md'
    lg = 'uk-padding-lg'
    xl = 'uk-padding-xl'
    remove = auto()
    remove_top = auto()
    remove_bottom = auto()
    remove_left = auto()
    remove_right = auto()
    remove_vertical = auto()
    remove_horizontal = auto()

# %% ../nbs/02_franken.ipynb
class PositionT(VEnum):
    'Position modifiers from https://franken-ui.dev/docs/position'
    def _generate_next_value_(name, start, count, last_values): return str2ukcls('position', name)
    top = auto()
    bottom = auto()
    left = auto()
    right = auto()
    top_left = auto()
    top_center = auto()
    top_right = auto()
    center = auto()
    center_left = auto()
    center_right = auto()
    bottom_left = auto()
    bottom_center = auto()
    bottom_right = auto()
    center_horizontal = auto()
    center_vertical = auto()

# %% ../nbs/02_franken.ipynb
def Placeholder(*c, # Components to put in the placeholder
                  cls=(), # Additional classes on the placeholder
                  **kwargs # Additional args for `Div` tag
                  )->FT: # Div(..., cls='uk-placeholder')
    "Creates a placeholder"
    return fh.Div(*c, cls=('uk-placeholder',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def Progress(*c, # Components to put in the progress bar (often nothing)
             cls=(), # Additional classes on the progress bar
             value="", # Value of the progress bar
             max="100", # Max value of the progress bar (defaults to 100 for percentage)
             **kwargs # Additional args for `Progress` tag
             )->FT: # Progress(..., cls='uk-progress')
    "Creates a progress bar"
    return fh.Progress(*c, value=value, max=max, cls=('uk-progress',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def UkIcon(icon:str, # Icon name from [lucide icons](https://lucide.dev/icons/)
           height:int=None, 
           width:int=None, 
           stroke_width:int=None, # Thickness of lines
           cls=(), # Additional classes on the `Uk_icon` tag
           **kwargs # Additional args for `Uk_icon` tag
           )->FT: # a lucide icon of the specified size 
    "Creates an icon using lucide icons"
    return Uk_icon(icon=icon, height=height, width=width, stroke_width=stroke_width, cls=cls, **kwargs)

# %% ../nbs/02_franken.ipynb
def UkIconLink(icon:str,  # Icon name from [lucide icons](https://lucide.dev/icons/)
           height:int=None, 
           width:int=None, 
           stroke_width:int=None, # Thickness of lines
           cls=(), # Additional classes on the icon
           button:bool=False, # Whether to use a button (defaults to a link)
           **kwargs # Additional args for `A` or `Button` tag
           )->FT: # a lucide icon  button or link of the specified size
    "Creates an icon link using lucide icons"
    fn = fh.Button if button else fh.A
    return fn(cls=(f"uk-icon-{'button' if button else 'link'}", stringify(cls)), **kwargs)(
        UkIcon(icon=icon, height=height, width=width, stroke_width=stroke_width))

# %% ../nbs/02_franken.ipynb
def DiceBearAvatar(seed_name:str, # Seed name (ie 'Isaac Flath')
                   h:int=20,         # Height 
                   w:int=20,          # Width
                  ):          # Span with Avatar
    "Creates an Avatar using https://dicebear.com/"
    url = 'https://api.dicebear.com/8.x/lorelei/svg?seed='
    return Span(cls=f"relative flex h-{h} w-{w} shrink-0 overflow-hidden rounded-full bg-secondary")(
            fh.Img(cls=f"aspect-square h-{h} w-{w}", alt="Avatar", loading="lazy", src=f"{url}{seed_name}"))

# %% ../nbs/02_franken.ipynb
class FlexT(VEnum):
    'Flexbox modifiers from UIkit'
    def _generate_next_value_(name, start, count, last_values): return str2ukcls('flex', name)
    
    # Display
    block, inline = 'uk-flex', auto()
    # Horizontal Alignment
    left, center, right, between, around = auto(), auto(), auto(), auto(), auto()
    # Vertical Alignment
    stretch, top, middle, bottom = auto(), auto(), auto(), auto()
    # Direction
    row, row_reverse, column, column_reverse = auto(), auto(), auto(), auto()
    # Wrap
    nowrap, wrap, wrap_reverse = auto(), auto(), auto()

# %% ../nbs/02_franken.ipynb
def Grid(*div, # `Div` components to put in the grid
         cols_min:int=1, # Minimum number of columns at any screen size
         cols_max:int=4, # Maximum number of columns allowed at any screen size
         cols_sm:int=None, # Number of columns on small screens
         cols_md:int=None, # Number of columns on medium screens
         cols_lg:int=None, # Number of columns on large screens
         cols_xl:int=None, # Number of columns on extra large screens
         cols:int=None, # Number of columns on all screens
         cls='gap-4', # Additional classes on the grid (tip: `gap` provides spacing for grids)
         **kwargs # Additional args for `Div` tag
         )->FT: # Responsive grid component
    "Creates a responsive grid layout with smart defaults based on content"
    if cols: cols_min = cols_sm = cols_md = cols_lg = cols_xl = cols
    else:
        n = len(div)
        cols_max = min(n, cols_max)
        cols_sm = cols_sm or min(n, cols_min, cols_max)
        cols_md = cols_md or min(n, cols_min+1, cols_max) 
        cols_lg = cols_lg or min(n, cols_min+2, cols_max) 
        cols_xl = cols_xl or cols_max
    return Div(cls=(f'grid grid-cols-{cols_min} sm:grid-cols-{cols_sm} md:grid-cols-{cols_md} lg:grid-cols-{cols_lg} xl:grid-cols-{cols_xl}', stringify(cls)), **kwargs)(*div)

# %% ../nbs/02_franken.ipynb
def DivFullySpaced(*c,                # Components
                   cls='uk-width-1-1',# Classes for outer div (`uk-width-1-1` makes it use all available width)
                   **kwargs           # Additional args for outer div
                  ):                  # Div with spaced components via flex classes
    "Creates a flex div with it's components having as much space between them as possible"
    cls = stringify(cls)
    return Div(cls=(FlexT.block,FlexT.between,FlexT.middle,cls), **kwargs)(*c)

# %% ../nbs/02_franken.ipynb
def DivCentered(*c,      # Components
                cls='space--4',  # Classes for outer div (`space-y-4` provides spacing between components)
                vstack=True, # Whether to stack the components vertically
                **kwargs # Additional args for outer div
               )->FT: # Div with components centered in it
    "Creates a flex div with it's components centered in it"
    cls=stringify(cls)
    return Div(cls=(FlexT.block,(FlexT.column if vstack else FlexT.row),FlexT.middle,FlexT.center,cls),**kwargs)(*c)

# %% ../nbs/02_franken.ipynb
def DivLAligned(*c, # Components
                cls='space-x-4',  # Classes for outer div
                **kwargs # Additional args for outer div
               )->FT: # Div with components aligned to the left
    "Creates a flex div with it's components aligned to the left"
    cls=stringify(cls)
    return Div(cls=(FlexT.block,FlexT.left,FlexT.middle,cls), **kwargs)(*c)

# %% ../nbs/02_franken.ipynb
def DivRAligned(*c, # Components
                cls='space-x-4',  # Classes for outer div
                **kwargs # Additional args for outer div
               )->FT: # Div with components aligned to the right
    "Creates a flex div with it's components aligned to the right"
    cls=stringify(cls)
    return Div(cls=(FlexT.block,FlexT.right,FlexT.middle,cls), **kwargs)(*c)

# %% ../nbs/02_franken.ipynb
def DivVStacked(*c, # Components
                cls='space-y-4', # Additional classes on the div  (tip: `space-y-4` provides spacing between components)
                **kwargs # Additional args for the div
               )->FT: # Div with components stacked vertically
    "Creates a flex div with it's components stacked vertically"
    cls=stringify(cls)
    return Div(cls=(FlexT.block,FlexT.column,FlexT.middle,cls), **kwargs)(*c)

# %% ../nbs/02_franken.ipynb
def DivHStacked(*c, # Components
                cls='space-x-4', # Additional classes on the div (`space-x-4` provides spacing between components)
                **kwargs # Additional args for the div
               )->FT: # Div with components stacked horizontally
    "Creates a flex div with it's components stacked horizontally"
    cls=stringify(cls)
    return Div(cls=(FlexT.block,FlexT.row,FlexT.middle,cls), **kwargs)(*c)

# %% ../nbs/02_franken.ipynb
class NavT(VEnum):
    def _generate_next_value_(name, start, count, last_values): return str2ukcls('nav', name)
    default = auto()
    primary = auto()
    secondary = auto()

# %% ../nbs/02_franken.ipynb
def NavContainer(*li, # List items are navigation elements (Special `Li` such as `NavParentLi`, `NavDividerLi`, `NavHeaderLi`, `NavSubtitle`, `NavCloseLi` can also be used)
                 cls=NavT.primary, # Additional classes on the nav
                 parent=True, # Whether this nav is a *parent* or *sub* nav
                 uk_nav=False, #True for default collapsible behavior, see [frankenui docs](https://franken-ui.dev/docs/nav#component-options) for more advanced options
                 **kwargs # Additional args
                 )->FT: # FT Component that is a list of `Li` styled for a sidebar navigation menu
    "Creates a navigation container (useful for creating a sidebar navigation).  A Nav is a list (NavBar is something different)"
    return fh.Ul(*li, uk_nav=uk_nav, cls=(f"uk-nav{'' if parent else '-sub'}", stringify(cls)),**kwargs)

# %% ../nbs/02_franken.ipynb
def NavParentLi(*nav_container, # `NavContainer` container for a nested nav with `parent=False`)
                cls=(), # Additional classes on the li
                **kwargs # Additional args for the li
               )->FT: # Navigation list item
    "Creates a navigation list item with a parent nav for nesting"
    return fh.Li(*nav_container,  cls=('uk-parent',  stringify(cls)),**kwargs)
def NavDividerLi(*c, # Components
                 cls=(), # Additional classes on the li
                 **kwargs # Additional args for the li
                )->FT: # Navigation list item with a divider
    "Creates a navigation list item with a divider"
    return fh.Li(*c, cls=('uk-nav-divider', stringify(cls)),**kwargs)
def NavHeaderLi(*c, # Components
                cls=(), # Additional classes on the li
                **kwargs # Additional args for the li
               )->FT: # Navigation list item with a header
    "Creates a navigation list item with a header"
    return fh.Li(*c, cls=('uk-nav-header', stringify(cls)),**kwargs)
def NavSubtitle(*c, # Components
                 cls=TextFont.muted_sm, # Additional classes on the div
                 **kwargs # Additional args for the div
                )->FT: # Navigation subtitle
    "Creates a navigation subtitle"
    return fh.Div(*c, cls=('uk-nav-subtitle', stringify(cls)),**kwargs)
def NavCloseLi(*c, # Components
               cls=(), # Additional classes on the li
               **kwargs # Additional args for the li
              )->FT: # Navigation list item with a close button
    "Creates a navigation list item with a close button"
    return fh.Li(*c, cls=('uk-drop-close', stringify(cls)),**kwargs)

# %% ../nbs/02_franken.ipynb
def NavBarContainer(*navbarside, # Components (typically `NavBarLSide` or `NavBarRSide` or `NavBarCenter`)
                    cls=(), # Additional classes on the container
                    container_cls=ContainerT.expand, # Additional classes on the container
                    uk_navbar=True, # Whether to use a navbar
                    **kwargs # Additional args for the container
                   )->FT: # NavBar container
    "Create a NavBarContainer to put NavBar sides in"
    return fh.Div(Container(Div(*navbarside, uk_navbar=uk_navbar),cls=stringify(container_cls)), cls=('',stringify(cls)), **kwargs) #uk-navbar-container

def NavBarLSide(*c,  # Components
                cls=(), # Additional classes on the div
                **kwargs # Additional args for the div
               )->FT: # NavBar left side
    "Creates a NavBar left side"
    return fh.Div(*c, cls=('uk-navbar-left',  stringify(cls)), **kwargs)
def NavBarRSide(*c,  # Components
                cls=(), # Additional classes on the div
                **kwargs # Additional args for the div
               )->FT: # NavBar right side
    "Creates a NavBar right side"
    return fh.Div(*c, cls=('uk-navbar-right', stringify(cls)), **kwargs)
def NavBarCenter(*c, # Components
                  cls=(), # Additional classes on the div
                  **kwargs # Additional args for the div
                 )->FT: # NavBar center
    "Creates a NavBar center"
    return fh.Div(*c, cls=('uk-navbar-center',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def NavBarNav(*li, # Components
              cls=(), # Additional classes on the nav
              **kwargs # Additional args for the nav
             )->FT: # Nav that is part of a NavBar
    "A Nav that is part of a NavBar that could go in a `NavBarLSide`, `NavBarRSide`, or `NavBarCenter`"
    return fh.Nav(*li, cls=('uk-navbar-nav',      stringify(cls)),                 **kwargs)

# %% ../nbs/02_franken.ipynb
def NavBarSubtitle(title, # Title
                   subtitle, # Subtitle
                   cls=(), # Additional classes on the div
                   subtitle_cls=TextFont.muted_sm, # Additional classes on the subtitle
                   **kwargs # Additional args for the div
                  )->FT: # NavBar subtitle
    "Creates a NavBar subtitle"
    return fh.Div(title,fh.Div(subtitle, cls=('uk-navbar-subtitle', stringify(subtitle_cls))), cls=stringify(cls), **kwargs)

# %% ../nbs/02_franken.ipynb
def NavBarNavContainer(*li, # Components
                       cls=NavT.primary, # Additional classes on the nav
                       parent=True, # Whether to use a parent nav
                       uk_nav=False, #True for default collapsible behavior, see https://franken-ui.dev/docs/nav#component-options for more advanced options
                       **kwargs # Additional args for the nav
                      )->FT: # NavBar nav container
    "Drop Down Nav"
    return Div(cls="uk-navbar-dropdown")(NavContainer(*li, cls=('uk-navbar-dropdown-nav',stringify(cls)), uk_nav=uk_nav, parent=parent, **kwargs))

# %% ../nbs/02_franken.ipynb
def NavBarParentIcon(): return Span(uk_navbar_parent_icon=True)

# %% ../nbs/02_franken.ipynb
def NavBar(nav_links:dict|List[FT]={}, # List of Li(A(...)) components or dict of {"name":"href value"}
           title:str|FT='Title', # `H1(title)` if string else any FT component on left of navbar (Often a logo)
           active:str="" # if `nav_links` is a dict shows an indicator of which page you are on
          )->FT: # Navigation bar
    _id = fh.unqid()
    "Creates a fully responsive navigation bar.  This will collapse to hamburger menu when on mobile."
    _click = f"htmx.find('#{_id}').classList.toggle('hidden')"
    menu_icon = UkIcon("menu", width=30, height=30, cls="md:hidden", hx_on_click=_click)
    
    if isinstance(nav_links, dict):
        def _item(link):
            name, target = link
            return Li(A(name, href=target), cls='uk-active' if active == name else '')
        nav_links = map(_item, nav_links.items())

    return Div(
        Container(
            Div(cls='md:flex md:relative')(
                NavBarLSide(H1(title), menu_icon),
                NavBarRSide(
                    NavBarNav(*nav_links, cls='w-full flex-col md:flex-row'),
                    cls='hidden md:flex md:justify-between',  id=_id))))

# %% ../nbs/02_franken.ipynb
def SliderContainer(
        *c, # Components
        cls='', # Additional classes on the container
        uk_slider=True, # See FrankenUI Slider docs for more options
        **kwargs # Additional args for the container
    ) -> FT: # Div(..., cls='relative', uk_slider=True, ...)
    "Creates a slider container"
    return Div(*c, cls=('relative', stringify(cls)), uk_slider=uk_slider, **kwargs)

# %% ../nbs/02_franken.ipynb
def SliderItems(
        *c, # Components
        cls='', # Additional classes for the items
        **kwargs # Additional args for the items
    ) -> FT: # Div(..., cls='uk-slider-items uk-grid', ...)
    "Creates a slider items container"
    return Div(*c, cls=('uk-slider-items uk-grid', stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def SliderNav(
        cls='uk-position-small uk-hidden-hover', # Additional classes for the navigation
        prev_cls='absolute left-0 top-1/2 -translate-y-1/2', # Additional classes for the previous navigation
        next_cls='absolute right-0 top-1/2 -translate-y-1/2', # Additional classes for the next navigation
        **kwargs # Additional args for the navigation
    ) -> FT: # Left and right navigation arrows for Slider component
    "Navigation arrows for Slider component"
    return (
        fh.A(cls=(prev_cls, stringify(cls)), href='',
             uk_slidenav_previous=True, uk_slider_item='previous', **kwargs),
        fh.A(cls=(next_cls, stringify(cls)), href='',
             uk_slidenav_next=True, uk_slider_item='next', **kwargs)
    )

# %% ../nbs/02_franken.ipynb
def Slider(*c, # Items to show in slider
           cls='', # Classes for slider container
           items_cls='gap-4', # Classes for items container
           nav=True, # Whether to show navigation arrows
           nav_cls='', # Classes for navigation arrows
           **kwargs # Additional args for slider container
    ) -> FT: # SliderContainer(SliderItems(..., cls='gap-4'), SliderNav?)
    "Creates a slider with optional navigation arrows"
    nav_comp = SliderNav(cls=nav_cls) if nav else ()
    return SliderContainer(
        SliderItems(*c, cls=items_cls),
        *nav_comp,
        cls=cls,
        **kwargs
    )

# %% ../nbs/02_franken.ipynb
def DropDownNavContainer(*li, # Components
                         cls=NavT.primary, # Additional classes on the nav
                         parent=True, # Whether to use a parent nav
                         uk_nav=False, #True for default collapsible behavior, see https://franken-ui.dev/docs/nav#component-options for more advanced options
                         uk_dropdown=True, # Whether to use a dropdown
                         **kwargs # Additional args for the nav
                        )->FT: # DropDown nav container
    "A Nav that is part of a DropDown"
    return Div(cls = 'uk-drop uk-dropdown',uk_dropdown=uk_dropdown)(NavContainer(*li, cls=('uk-dropdown-nav',stringify(cls)), uk_nav=uk_nav, parent=parent, **kwargs))

# %% ../nbs/02_franken.ipynb
def TabContainer(*li, # Components
                  cls='', # Additional classes on the `Ul`
                  alt=False, # Whether to use an alternative tab style
                  **kwargs # Additional args for the `Ul`
                 )->FT: # Tab container
    "A TabContainer where children will be different tabs"
    cls = stringify(cls)
    return Ul(cls=(f"uk-tab{'-alt' if alt else ''}",stringify(cls)),**kwargs)(*li)

# %% ../nbs/02_franken.ipynb
class CardT(VEnum):
    'Card styles from UIkit'
    def _generate_next_value_(name, start, count, last_values): return str2ukcls('card', name)
    default = auto()
    primary = auto()
    secondary = auto()
    danger = auto()

# %% ../nbs/02_franken.ipynb
def CardTitle(*c, # Components (often a string)
              cls=(), # Additional classes on the div
              **kwargs # Additional args for the div
             ): 
    "Creates a card title"
    return fh.Div(*c, cls=('uk-card-title',stringify(cls)), **kwargs)

def CardHeader(*c, # Components that goes in the header (often a `ModalTitle` and description)
               cls=(), # Additional classes on the div
               **kwargs # Additional args for the div
              )->FT: # Container for the header of a card
    "Creates a card header"
    return fh.Div(*c, cls=('uk-card-header',stringify(cls)), **kwargs)

def CardBody(*c, # Components that go in the body (Main content of the card such as a form, and image, a signin form, etc.)
              cls=(), # Additional classes on the div
              **kwargs # Additional args for the div
             )->FT: # Container for the body of a card
    "Creates a card body"
    return fh.Div(*c, cls=('uk-card-body',stringify(cls)), **kwargs)

def CardFooter(*c, # Components that go in the footer (often a `ModalCloseButton`)
               cls=(), # Additional classes on the div
               **kwargs # Additional args for the div
              )->FT: # Container for the footer of a card
    "Creates a card footer"
    return fh.Div(*c, cls=('uk-card-footer',stringify(cls)), **kwargs)

def CardContainer(*c, # Components (typically `CardHeader`, `CardBody`, `CardFooter`)
                   cls=CardT.default, # Additional classes on the div
                   **kwargs # Additional args for the div
                  )->FT: # Container for a card
    "Creates a card container"
    return fh.Div(*c, cls=('uk-card',stringify(cls)), **kwargs)

# %% ../nbs/02_franken.ipynb
def Card(*c, # Components that go in the body (Main content of the card such as a form, and image, a signin form, etc.)
        header=None, # A component that goes in the header (often a `ModalTitle` and description)
        footer=None,  # A component that goes in the footer (often a `ModalCloseButton`)
        body_cls='space-y-6', # classes for the body
        header_cls=(), # classes for the header
        footer_cls=(), # classes for the footer
        cls=(), #class for outermost component
        **kwargs # additional arguments for the `CardContainer`
        )->FT: # Card component
    "Creates a Card with a header, body, and footer"
    header_cls, footer_cls, body_cls, cls = map(stringify, (header_cls, footer_cls, body_cls, cls))
    res = []
    if header: res.append(CardHeader(cls=header_cls)(header))
    res.append(CardBody(cls=body_cls)(*c))
    if footer: res.append(CardFooter(cls=footer_cls)(footer))
    return CardContainer(cls=cls, **kwargs)(*res)

# %% ../nbs/02_franken.ipynb
class TableT(VEnum):
    def _generate_next_value_(name, start, count, last_values): return str2ukcls('table', name)
    divider = auto()
    striped = auto()
    hover = auto()
    sm = 'uk-table-small'
    lg = 'uk-table-large'
    justify = auto()
    middle = auto()
    responsive = auto()

# %% ../nbs/02_franken.ipynb
def Table(*c, # Components (typically `Thead`, `Tbody`, `Tfoot`)
          cls=(TableT.middle, TableT.divider, TableT.hover, TableT.sm), # Additional classes on the table
          **kwargs # Additional args for the table
         )->FT: # Table component
    "Creates a table"
    return fh.Table(cls=('uk-table', stringify(cls)), *c, **kwargs)

# %% ../nbs/02_franken.ipynb
def _TableCell(Component, 
               *c, # Components that go in the cell
               cls=(), # Additional classes on the cell container
               shrink=False, # Whether to shrink the cell
               expand=False, # Whether to expand the cell
               small=False, # Whether to use a small table
               **kwargs # Additional args for the cell
              )->FT: # Table cell
    "Creates a table cell"
    cls = stringify(cls)
    if shrink: cls += ' uk-table-shrink'
    if expand: cls += ' uk-table-expand'
    if small: cls += ' uk-table-small'
    return Component(*c,cls=cls, **kwargs)

@delegates(_TableCell, but=['Component'])
def Td(*c,**kwargs):  return _TableCell(fh.Td, *c, **kwargs)
@delegates(_TableCell, but=['Component'])
def Th(*c,**kwargs): return _TableCell(fh.Th, *c, **kwargs)

def Tbody(*rows, cls=(), sortable=False, **kwargs): return fh.Tbody(*rows, cls=stringify(cls), uk_sortable=sortable, **kwargs)

# %% ../nbs/02_franken.ipynb
def TableFromLists(header_data:Sequence, # List of header data
                   body_data:Sequence[Sequence], # List of lists of body data
                   footer_data=None, # List of footer data
                   header_cell_render=Th, # Function(content) -> FT that renders header cells
                   body_cell_render=Td, # Function(key, content) -> FT that renders body cells
                   footer_cell_render=Td, #  Function(key, content) -> FT that renders footer cells
                   cls=(TableT.middle, TableT.divider, TableT.hover, TableT.sm), # Additional classes on the table
                   sortable=False, # Whether to use sortable table
                   **kwargs # Additional args for the table
                  )->FT: # Table from lists
    "Creates a Table from a list of header data and a list of lists of body data"
    return Table(
                Thead(Tr(*map(header_cell_render, header_data))),
                Tbody(*[Tr(*map(body_cell_render, r)) for r in body_data], sortable=sortable),
                Tfoot(Tr(*map(footer_cell_render, footer_data))) if footer_data else '',
                cls=stringify(cls),    
                **kwargs)

# %% ../nbs/02_franken.ipynb
def TableFromDicts(header_data:Sequence, # List of header data
                   body_data:Sequence[dict], # List of dicts of body data
                   footer_data=None, # List of footer data
                   header_cell_render=Th, # Function(content) -> FT that renders header cells
                   body_cell_render=lambda k,v : Td(v), # Function(key, content) -> FT that renders body cells
                   footer_cell_render=lambda k,v : Td(v), #  Function(key, content) -> FT that renders footer cells
                   cls=(TableT.middle, TableT.divider, TableT.hover, TableT.sm), # Additional classes on the table
                   sortable=False, # Whether to use sortable table
                   **kwargs # Additional args for the table
                  )->FT: # Styled Table
    "Creates a Table from a list of header data and a list of dicts of body data"
    return Table(
        Thead(Tr(*[header_cell_render(h) for h in header_data])),
        Tbody(*[Tr(*[body_cell_render(k, r.get(k, '')) for k in header_data]) for r in body_data], sortable=sortable),
        Tfoot(Tr(*[footer_cell_render(k, footer_data.get(k.lower(), '')) for k in header_data])) if footer_data else '',
        cls=stringify(cls),    
        **kwargs
    )

# %% ../nbs/02_franken.ipynb
franken_class_map = {
    'h1': 'uk-h1 text-4xl font-bold mt-12 mb-6',
    'h2': 'uk-h2 text-3xl font-bold mt-10 mb-5', 
    'h3': 'uk-h3 text-2xl font-semibold mt-8 mb-4',
    'h4': 'uk-h4 text-xl font-semibold mt-6 mb-3',
    
    # Body text and links
    'p': 'text-lg leading-relaxed mb-6',
    'a': 'uk-link text-primary hover:text-primary-focus underline',
    
    # Lists with proper spacing
    'ul': 'uk-list uk-list-disc space-y-2 mb-6 ml-6',
    'ol': 'uk-list uk-list-decimal space-y-2 mb-6 ml-6',
    'li': 'leading-relaxed',
    
    # Code and quotes
    'pre': 'bg-base-200 rounded-lg p-4 mb-6',
    'code': 'uk-codespan px-1',
    'pre code': 'uk-codespan px-1 block overflow-x-auto',
    'blockquote': 'uk-blockquote pl-4 border-l-4 border-primary italic mb-6',
    
    # Tables
    'table': 'uk-table uk-table-divider uk-table-hover uk-table-small w-full mb-6',
    'th': 'text-left p-2',
    'td': 'p-2',
    
    # Other elements
    'hr': 'uk-divider-icon my-8',
    'img': 'max-w-full h-auto rounded-lg mb-6'
}

# %% ../nbs/02_franken.ipynb
def apply_classes(html_str:str, # Html string
                  class_map=None, # Class map
                  class_map_mods=None # Class map that will modify the class map map (useful for small changes to a base class map)
                 )->str: # Html string with classes applied
    "Apply classes to html string"
    if not html_str: return html_str
    try:
        from lxml import html, etree
        class_map = ifnone(class_map, franken_class_map)

        if class_map_mods: class_map = {**class_map, **class_map_mods}
        html_str = html.fromstring(html_str)
        for selector, classes in class_map.items():
            # Handle descendant selectors (e.g., 'pre code')
            xpath = '//' + '/descendant::'.join(selector.split())
            for element in html_str.xpath(xpath):
                existing_class = element.get('class', '')
                new_class = f"{existing_class} {classes}".strip()
                element.set('class', new_class)
        return etree.tostring(html_str, encoding='unicode', method='html')
    except ImportError:
        raise ImportError("Install 'lxml' to use the apply_classes function")
    except etree.ParserError:
        return html_str

# %% ../nbs/02_franken.ipynb
def render_md(md_content:str, # Markdown content
               class_map=None, # Class map
               class_map_mods=None # Additional class map
              )->FT: # Rendered markdown
    "Renders markdown using mistletoe and lxml"
    if md_content=='': return md_content
    # Check for required dependencies
    missing = []
    try: import mistletoe
    except ImportError: missing.append('mistletoe')
    try: import lxml
    except ImportError: missing.append('lxml')
    if missing:
        pkgs = ' and '.join(missing)
        raise ImportError(f"Please install {pkgs} to use the render_md function")
        
    html_content = mistletoe.markdown(md_content) #, mcp.PygmentsRenderer)
    return NotStr(apply_classes(html_content, class_map, class_map_mods))
