clanga
Version:
Generate responsive and reusable CSS using clean JavaScript. No more raw CSS or utility class clutter.
389 lines (269 loc) • 11.1 kB
JavaScript
import {style, componenet } from "./compiler.js";
export function Style( selector , responsive_styles ) {
return style( selector , responsive_styles , false );
}
// simple yet very very useful to extend styles (this is designed to overwrite exiting styles)
export function Edit( style_component , responsive_styles ) {
return style( style_component.selector , responsive_styles , true );
}
export function Sheet( responsive_styles ) {
const style_componenet = new componenet();
style_componenet.extend( responsive_styles );
return style_componenet;
}
export class Clanga {
constructor() {
this.styles = {};
this.children_styles = null;
this.is_y_stretched = false;
this.is_x_stretched = false;
}
align({
top , bottom , right , left , z , fixed=false , sticky=false,
relative=false, xcenter=false , ycenter=false , wstretch=false , hstretch=false
}) {
if ( ! this.styles ) {
this.styles = {};
}
// set position
let is_positioned = false;
if( is_positioned ) {
throw new Error( "you can either use \"fixed\" or \"relative\" or \"sticky\" but never together (if none specified it will default to absolute)" )
}
if ( fixed ) {
if( is_positioned ) {
throw new Error( "you can either use \"fixed\" or \"relative\" or \"sticky\" but never together (if none specified it will default to absolute)" )
}
this.__apply_style( "position" , "fixed" );
is_positioned = true
}
if ( relative ) {
if( is_positioned ) {
throw new Error( "you can either use \"fixed\" or \"relative\" or \"sticky\" but never together (if left blank it will default to absolute" )
}
this.__apply_style( "position" , "relative" );
}
if ( sticky ) {
if( is_positioned ) {
throw new Error( "you can either use \"fixed\" or \"relative\" or \"sticky\" but never together (if left blank it will default to absolute" )
}
this.__apply_style( "position" , "sticky" );
}
if( ! is_positioned ) {
this.__apply_style( "position" , "absolute" );
}
// preventing conflicts between center properties and absolute positioning options
if( (ycenter && (top || bottom)) || (ycenter && hstretch) ) {
new Error( "you cannot use \"ycenter\" and properties like \"bottom\", \"top\" or \"hstretch\"." );
}
if( xcenter && (right || left) || (ycenter && wstretch) ) {
new Error( "you cannot use \"xcenter\" and properties like \"right\", \"left\" or \"wstretch\"." );
}
// center element
let is_center_used = false;
if( ycenter ) {
is_center_used = true;
bottom = "50%"
}
if( xcenter ) {
is_center_used = true;
right = "50%"
}
if ( is_center_used ) {
this.__apply_style( "transform" , `translate( ${xcenter?"50%":"0"} , ${ycenter?"50%":"0"} )` );
}
this.__apply_style( "z-index" , z );
// add positioning styles
if ( hstretch ) {
this.is_y_stretched = true
this.__apply_style( "top" , top?top:"0px" );
this.__apply_style( "height" , `calc( 100% - ${top?top:"0px"} - ${bottom?bottom:"0px"} )` );
} else {
this.__apply_style( "top" , top );
this.__apply_style( "bottom" , bottom );
}
if ( wstretch ) {
this.is_x_stretched = true
this.__apply_style( "left" , left?left:"0px" );
this.__apply_style( "width" , `calc( 100% - ${left?left:"0px"} - ${right?right:"0px"} )` );
} else {
this.__apply_style( "left" , left );
this.__apply_style( "right" , right );
}
return this;
}
pad({left , top , right , bottom , all}) {
this.__apply_style( "padding" , all );
this.__apply_style( "padding-top" , top );
this.__apply_style( "padding-bottom" , bottom );
this.__apply_style( "padding-right" , right );
this.__apply_style( "padding-left" , left );
return this;
}
color( {fg , bg} ) {
this.__apply_style( "color" , fg );
this.__apply_style( "background-color" , bg );
return this;
}
shape( { border , radius , w , h } ) {
if ( ! this.styles ) {
this.styles = {};
}
this.__apply_style( "border" , border );
this.__apply_style( "border-radius" , radius );
// because .align sets "width" and "height" you gotta prevent this from overwriting it
if ( w ) {
if (this.is_x_stretched ) {
throw new Error( "you cannot use \"wstretch\" and \"w\" together" )
}
this.__apply_style( "width" , w );
}
if ( h ) {
if (this.is_y_stretched ) {
throw new Error( "you cannot use \"hstretch\" and \"h\" together" )
}
this.__apply_style( "height" , h );
}
return this;
}
font({
family , line_height , weight , size , variant_caps , stretch , word_spacing ,
letter_spacing , variant , indent , word_break_mode , hyphens , overflow , break_word ,
align , align_last , transform , decoration , decoration_color , decoration_style ,
direction , writing_mode , white_space ,
}) {
this.__apply_style( "font-family" , family );
this.__apply_style( "font-size" , size );
this.__apply_style( "font-weight" , weight );
this.__apply_style( "line-height" , line_height );
this.__apply_style( "font-stretch" , stretch );
this.__apply_style( "font-variant-caps" , variant_caps );
this.__apply_style( "font-variant" , variant );
this.__apply_style( "word-spacing" , word_spacing );
this.__apply_style( "letter-spacing" , letter_spacing );
this.__apply_style( "text-indent" , indent );
this.__apply_style( "text-align" , align );
this.__apply_style( "text-align-last" , align_last );
this.__apply_style( "text-transform" , transform );
this.__apply_style( "text-decoration" , decoration );
this.__apply_style( "text-decoration-color" , decoration_color );
this.__apply_style( "text-decoration-style" , decoration_style );
this.__apply_style( "direction" , direction );
this.__apply_style( "writing-mode" , writing_mode );
this.__apply_style( "word-break" , word_break_mode );
this.__apply_style( "white-space" , white_space );
this.__apply_style("hyphens" , hyphens );
this.__apply_style( "overflow-wrap" , break_word?"":"break-word" );
this.__apply_style( "text-overflow" , overflow );
return this;
}
extra( extra_styles ) {
if ( ! this.styles ) {
this.styles = {};
}
for( let property in extra_styles ) {
this.styles[ property ] = extra_styles[ property ];
}
return this;
}
substyle( subclass , children_styles ) {
if ( ! this.children_styles ) {
this.children_styles = {}
}
this.children_styles[ subclass ] = {}
this.children_styles[ subclass ] = children_styles.styles;
return this;
}
child( nth_child , children_styles ) {
this.substyle( `:nth-child(${nth_child})` , children_styles );
return this;
}
__apply_style( property , style , empty=undefined ) {
if( !style ) {
style = empty;
}
if ( ! this.styles ) {
this.styles = {};
}
this.styles[ property ] = style;
}
}
export class FlexObj extends Clanga {
constructor() {
super();
this.mode = "";
this.is_wrap = true;
}
use ( { gap, mode , wrap=true , reverse=false , reverse_wrap=false } ) {
if ( ! this.styles ) {
this.styles = {};
}
this.__apply_style( "display" , "flex" );
if ( mode === "row" ) {
this.__apply_style( "flex-direction" , reverse?"row-reverse":"row" );
} else if ( mode === "col" ) {
this.__apply_style( "flex-direction" , reverse?"column-reverse":"column" );
} else {
console.error( "mode in Flex can only be \"row\" or \"column\" " );
}
this.mode = mode;
this.is_wrap = wrap;
this.__apply_style( "gap" , gap );
this.__apply_style( "flex-wrap" , wrap?( reverse_wrap?"wrap-reverse":"wrap" ):"nowrap" );
return this;
}
justify ( { row , col } ) {
if ( ! this.styles ) {
this.styles = {};
}
if ( ! this.mode ) {
this.mode = "row";
}
let justify_content , align_items;
if ( this.mode === "row" ) {
justify_content = row;
align_items = col;
} else if ( this.mode === "col" ) {
justify_content = col;
align_items = row;
} else {
console.error( "mode in Flex can only be \"row\" or \"column\" " );
}
this.__apply_style( "align-items" , this.is_wrap ? null : align_items );
this.__apply_style( "align-content" , this.is_wrap ? align_items : null );
this.__apply_style( "justify-content" , justify_content );
return this;
}
itemClass( subclass , { grow , shrink , basis , align , order } ) {
this.substyle( subclass , (new Clanga).extra( {
"flex-grow" : grow?grow:"0",
"flex-shrink" : shrink?shrink:"0",
"flex-basis" : basis?basis:"auto",
"order" : order?order:"0",
"align-self" : align?align:"auto",
} ) );
return this;
}
item( nth_child , { grow , shrink , basis , align , order } ) {
this.child( nth_child , Clanga.extra( {
"flex-grow" : grow?grow:"0",
"flex-shrink" : shrink?shrink:"0",
"flex-basis" : basis?basis:"auto",
"order" : order?order:"0",
"align-self" : align?align:"auto",
} ) );
return this;
}
}
export function Div() {
return new Clanga;
}
export function Flex() {
return new FlexObj;
}
export function hsl(hue, saturation, lightness, alpha) {
return `hsl(${hue.toString()},${saturation.toString()},${lightness.toString()},${ alpha?alpha:"1" })` ;
}
export function rgb(red, green, blue , alpha ) {
return `rgba(${red.toString()},${green.toString()},${blue.toString()},${ alpha?alpha:"1" })`;
}