seed 0.3.0

A Rust framework for creating web apps, using WebAssembly
Documentation
//! This file exports helper macros for element creation, populated by a higher-level macro,
//! and macros for creating the parts of elements. (attrs, style, events)

/// Copied from https://github.com/rust-lang/rust/issues/35853.
macro_rules! with_dollar_sign {
    ($($body:tt)*) => {
        macro_rules! __with_dollar_sign { $($body)* }
        __with_dollar_sign!($);
    }
}

/// Create macros exposed to the package that allow shortcuts for Dom elements.
/// In the matching mattern below, we match the name we want to use with the name under
/// the seed::dom_types::Tag enum. Eg the div! macro uses seed::dom_types::Tag::Div.
macro_rules! element {
    // Create shortcut macros for any element; populate these functions in this module.
    ($($Tag:ident => $Tag_camel:ident);+) => {
        // This replaces $d with $ in the inner macro.
        with_dollar_sign! {
            ($d:tt) => {
                $(
                    #[macro_export]
                    macro_rules! $Tag {
                        ( $d($d part:expr),* $d(,)* ) => {
                            {
                                let mut el = El::empty(seed::dom_types::Tag::$Tag_camel);
                                $d ( $d part.update(&mut el); )*
                                el
                            }
                        };
                    }
                )+
            }
        }
   }
}
/// Similar to the element! macro above, but with a namespace for svg.
macro_rules! element_svg {
    // Create shortcut macros for any element; populate these functions in this module.
    ($($Tag:ident => $Tag_camel:ident);+) => {
        // This replaces $d with $ in the inner macro.
        with_dollar_sign! {
            ($d:tt) => {
                $(
                    #[macro_export]
                    macro_rules! $Tag {
                        ( $d($d part:expr),* $d(,)* ) => {
                            {
                                let mut el = El::empty_svg(seed::dom_types::Tag::$Tag_camel);
                                $d ( $d part.update(&mut el); )*
                                el
                            }
                        };
                    }
                )+
            }
        }
   }
}

/// El must be exposed in the module where this is called for these to work.
element! {
    address => Address; article => Article; aside => Aside; footer => Footer;
    header => Header; h1 => H1;
    h2 => H2; h3 => H3; h4 => H4; h5 => H5; h6 => H6;
    hgroup => Hgroup; main => Main; nav => Nav; section => Section;

    blockquote => BlockQuote;
    dd => Dd; dir => Dir; div => Div; dl => Dl; dt => Dt; figcaption => FigCaption; figure => Figure;
    hr => Hr; li => Li; ol => Ol; p => P; pre => Pre; ul => Ul;

    a => A; abbr => Abbr;
    b => B; bdi => Bdi; bdo => Bdo; br => Br; cite => Cite; code => Code; data => Data;
    dfn => Dfn; em => Em; i => I; kbd => Kbd; mark => Mark; q => Q; rb => Rb;
    rp => Rp; rt => Rt; rtc => Rtc; ruby => Ruby; s => S; samp => Samp; small => Small;
    span => Span; strong => Strong; sub => Sub; sup => Sup; time => Time; tt => Tt;
    u => U; var => Var; wbr => Wbr;

    area => Area; audio => Audio; img => Img; map => Map; track => Track; video => Video;

    applet => Applet; embed => Embed; iframe => Iframe;
    noembed => NoEmbed; object => Object; param => Param; picture => Picture; source => Source;

    canvas => Canvas; noscript => NoScript; Script => Script;

    del => Del; ins => Ins;

    caption => Caption; col => Col; colgroup => ColGroup; table => Table; tbody => Tbody;
    td => Td; tfoot => Tfoot; th => Th; thead => Thead; tr => Tr;

    button => Button; datalist => DataList; fieldset => FieldSet; form => Form; input => Input;
    label => Label; legend => Legend; meter => Meter; optgroup => OptGroup; option => Option;
    output => Output; progress => Progress; select => Select; textarea => TextArea;

    details => Details; dialog => Dialog; menu => Menu; menuitem => MenuItem; summary => Summary;

    content => Content; element => Element; shadow => Shadow; slot => Slot; template => Template
}

element_svg! {
    // SVG shape elements
    line_ => Line;
    rect => Rect; circle => Circle; ellipse => Elipse; polygon => Polygon; polyline => Polyline;
    mesh => Mesh; path => Path; defs => Defs; marker => Marker; mask => Mask;
    // SVG container elements
    svg => Svg; g => G;
    // SVG gradient elements
    linear_gradient => LinearGradient; radial_gradient => RadialGradient; mesh_gradient => MeshGradient;
    stop => Stop;
    // SVG gradphics elements
    image => Image;
    // SVG graphics referencing elements
    r#use => Use;
    // SVG text content elements
    text => Text; tref => TRef; tspan => TSpan
}

// TODO:
// Create the following svg macros
// - missing-glyph
// - pattern
// - switch
// - symbol
// - unknown

// - add SVG animation elements
// - add SVG filter primitive elements
// - add SVG descriptive elements
// - add SVG font elements
// - add SVG paint server elements
// - altGlyph
// - altGlyphDef
// - altGlyphItem
// - glyph
// - glyphRef
// - textPath

// Add the following SVG element macros:
//  - clipPath
//  - color-profile
//  - cursor
//  - filter
//  - foreignObject
//  - hatchpath
//  - meshpatch
//  - meshrow
//  - style
//  - view

#[macro_export]
macro_rules! custom {
    ( $($part:expr),* $(,)* ) => {
        {
            let mut el = El::empty(seed::dom_types::Tag::Custom("missingtagname".into()));
            $ ( $part.update(&mut el); )*
            el
        }
    };
}

/// Provide a shortcut for creating attributes.
#[macro_export]
macro_rules! attrs {
    { $($key:expr => $value:expr);* $(;)* } => {
        {
            let mut vals = std::collections::HashMap::new();
            $(
                // We can handle arguments of multiple types by using this:
                // Strings, &strs, bools, numbers etc.
                vals.insert($key.into(), $value.to_string());
            )*
            seed::dom_types::Attrs::new(vals)
        }
     };
}

/// Convenience macro. Ideal when there are multiple classes, and no other attrs.
#[macro_export]
macro_rules! class {
    { $($class:expr),* $(,)* } => {
        {
            let mut result = seed::dom_types::Attrs::empty();
            let mut classes = Vec::new();
            $(
                classes.push($class);
            )*
            result.add_multiple("class".into(), classes);
            result
        }
     };
}

/// Convenience macro, for brevity.
#[macro_export]
macro_rules! id {
    { $id:expr } => {
        {
            seed::dom_types::Attrs::from_id($id)
        }
     };
}

// todo: Once the macro_at_most_once_rep is in stable, you can use $(;)? here (
// todo: and in el creation macros) to make only trailing comma/semicolon acceptable.
/// Provide a shortcut for creating styles.
#[macro_export]
macro_rules! style {
    { $($key:expr => $value:expr);* $(;)* } => {
        {
            let mut vals = std::collections::HashMap::new();
            $(
                // We can handle arguments of multiple types by using this:
                // Strings, &strs, bools, numbers etc.
                vals.insert(String::from($key), $value.to_string());
            )*
            seed::dom_types::Style::new(vals)
        }
     };
}

//#[macro_export]
//macro_rules! events {
//    { $($event_str:expr => $handler:expr);+ } => {
//        {
//            let mut result = Vec::new();
//            $(
//                match $event_str {
////                    _ => result.push(seed::dom_types::Listener::new_input($event_str.into(), $handler)),
//
//
//                    _ => result.push(seed::dom_types::Listener::new_input($event_str.into(), $handler)),
////
////
////
////  "input" => result.push(seed::dom_types::Listener::new_input($event_str.into(), $handler)),
////                    _ => result.push(seed::dom_types::Listener::new($event_str.into(), $handler)),
//
//                }
//
////                result.push(seed::dom_types::Listener::new($event_str.into(), $handler));
//            )+
//            result
//        }
//     };
//}
//

///// Attempt to apply the correct input type based on its trigger.
//#[macro_export]
//macro_rules! ev2 {
//    { $event_str:expr, $handler:expr } => {
//        {
//            match event_str {
//                "input" => seed::dom_types::input_ev($event_str, $handler),
////                "change" => seed::dom_types::input_ev($event_str, $handler),
////
////                "keydown" => seed::dom_types::keyboard_ev($event_str, $handler),
////
////                "click" => seed::dom_types::ev($event_str, $handler),
////                "auxclick" => seed::dom_types::ev($event_str, $handler),
////                "dblclick" => seed::dom_types::ev($event_str, $handler),
////                "contextmenu" => seed::dom_types::input_ev($event_str, $handler),
//
//                _ => seed::dom_types::raw_ev($event_str, $handler),
//
//            }
//        }
//    };
//}

///// Attempt to apply the correct input type based on its trigger.
//#[macro_export]
//macro_rules! ev2 {
//    { input, $handler:expr } => {
//        {
//            seed::dom_types::input_ev("input", $handler),
//        }
//    };
//    { click, $handler:expr } => {
//        {
//            seed::dom_types::simple_ev("click", $handler),
//        }
//    };
//
//
//
//}

/// A convenience function for logging to the web browser's console.  We use
/// a macro instead of a function to allow flexible input types, and multiple
/// inputs.
#[macro_export]
macro_rules! log {
    { $($expr:expr),* $(,)* } => {
        {
            let mut text = String::new();
            $(
                text += &$expr.to_string();
                text += " ";
            )*
            web_sys::console::log_1(&text.into());
        }
     };
}

/// A HashMap literal, where the keys and valsmust implement ToString.
#[macro_export]
macro_rules! hashmap_string {
    { $($key:expr => $value:expr),* $(,)* } => {
        {
            let mut result = std::collections::HashMap::new();
            $(
                // We can handle arguments of multiple types by using this:
                // Strings, &strs, bools, numbers etc.
                result.insert($key.to_string(), $value.to_string());
            )*
            result
        }
     };
}