LeCodesdocs

Раскрывающаяся карточка

animateTo анимирует каждое свойство от текущего значения к заданному и фиксирует его — состояние живёт в стиле, а не в таймлайне. Тело раскрывается анимацией собственной высоты, а строки появляются со сдвигом по delay; повторное нажатие на полпути просто перенацеливает анимацию.

Форкнуть в LeCodes
// animateTo tweens an element from where it is now to the values you give, per property, and
// commits them — state lives in the style, not a timeline. The body reveals by animating its
// own height while each line fades in on a staggered `delay`; a second tap retargets everything
// mid-flight instead of queueing. The card is content-sized, so it grows with the body.
const LINES = [
    "Height, opacity and offset each tween on their own.",
    "delay staggers the lines into place.",
    "Tap mid-flight — the next animateTo takes over.",
]
const HIDDEN = { opacity: 0, transform: "translateY(8px)" }

const plus = UIText("+").style({ fontSize: 30, fontWeight: 700, color: "#FF4032" })
const lines = LINES.map(text =>
    UIText(text).style({ fontSize: 14, lineHeight: "1.45em", color: "#8b90a0", ...HIDDEN }))
const body = UIColumn(lines).style({ height: 0, gap: 14, overflow: "hidden" })

let open = false
function toggle() {
    open = !open
    body.animateTo({ height: open ? 150 : 0, duration: 420 })
    plus.animateTo({ transform: open ? "rotate(45deg)" : "rotate(0deg)", duration: 320 })
    lines.forEach((line, i) => line.animateTo({
        ...(open ? { opacity: 1, transform: "translateY(0px)" } : HIDDEN),
        duration: 260, delay: open ? 90 + i * 70 : 0,
    }))
}

const card = UIButton([
    UIRow([
        UIText("Declarative motion").style({ fontSize: 19, fontWeight: 700, color: "white" }),
        UISpacer(),
        plus,
    ]).style({ height: 76, alignItems: "center" }),
    body,
]).style({
    flexDirection: "column", alignItems: "stretch", justifyContent: "flex-start",
    px: 20, pb: 4, borderRadius: 20, bgColor: "#151922", overflow: "hidden",
}).onClick(toggle)

const screen = UIScreen([ card ]).style({ bgColor: "#0b0d12", px: 16, pt: "max(safe-top, 60px)" })

screen.open()

Нажмите «Запустить» — откроется плавающий симулятор. Он остаётся на месте, пока вы читаете: другой пример просто заменит приложение внутри.

Связанные разделы