// // Copyright (c) 2015, Brian Frank and Andy Frank // Licensed under the Academic Free License version 3.0 // // History: // 19 Mar 2015 Andy Frank Creation // using dom ** ** CardBox lays out child elements as a stack of cards, where ** only one card may be visible at a time. ** ** See also: [docDomkit]`docDomkit::Layout#cardBox` ** @Js class CardBox : Box { new make() : super() { this.style.addClass("domkit-CardBox") } ** Selected card instance, or null if no children. Elem? selItem() { selIndex==null ? null : children[selIndex] } ** Selected card index, or null if no children. virtual Int? selIndex { set { old := &selIndex &selIndex = it.max(0).min(children.size) if (old != &selIndex) updateStyle } } ** ** Transition effect to apply when 'selIndex' is changed. ** If null, no effect is applied. ** ** Valid values are: ** - 'slideLeft': animate cards sliding in from right-to-left ** - 'slideRight': animate cards sliding in from left-to-right ** Str? effect := null ** Duratin for `effect` animation to last. Duration effectDur := 350ms protected override Void onAdd(Elem c) { updateStyle } protected override Void onRemove(Elem c) { updateStyle } private Void updateStyle() { // TODO: // currently require style.width/height to be set on CardBox // should probalby check, or throw if not configured? kids := children // implicitly select first card if not specified if (kids.size > 0 && selIndex == null) selIndex = 0 // if effect is set, stage the card we will show next fx := this.effect cur := kids.find |k| { k.style->display == "block" } next := fx == null ? null : children[selIndex] size := fx == null ? null : this.size // if cur is selected short-circuit effect if (cur == null) cur = next if (cur === next) { fx=null; next=null } curIndex := kids.findIndex |k| { k == cur } // if we are not mounted short-circuit effect if (fx != null && !Win.cur.doc.body.containsChild(this)) { fx=null; next=null; } switch (fx) { case "slideLeft": cy := curIndex > selIndex ? "-${size.h}px" : "0px" ny := curIndex < selIndex ? "-${size.h}px" : "0px" cur.style->transform = "translateX(0) translateY($cy)" next.style->transform = "translateX(${size.w}px) translateY($ny)" next.style->display = "block" cur.transition(["transform":"translateX(-${size.w}px) translateY($cy)", "opacity":"0"], null, effectDur) next.transition(["transform":"translateX(0px) translateY($ny)"], null, effectDur) { updateDis } case "slideRight": cy := curIndex > selIndex ? "-${size.h}px" : "0px" ny := curIndex < selIndex ? "-${size.h}px" : "0px" cur.style->transform = "translateX(0) translateY($cy)" next.style->transform = "translateX(-${size.w}px) translateY($ny)" next.style->display = "block" cur.transition(["transform":"translateX(${size.w}px) translateY($cy)", "opacity":"0"], null, effectDur) next.transition(["transform":"translateX(0px) translateY($ny)"], null, effectDur) { updateDis } default: // if no effect, just update display updateDis } } private Void updateDis() { children.each |kid,i| { kid.style->display = i==selIndex ? "block" : "none" kid.style->opacity = "1.0" kid.transition(["transform":"translateX(0) translateY(0)"], null, 0ms) } } }