0.10.5: clicking + on an empty button slot moves the editor to that state

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
thandClaude Opus 4.7 committed 2026-04-22 18:55:11 +02:00
1 parent 8895fc76ef
commit d3c5b8b640
3 files changed
+62 -1

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "animatr",
"private": true,
"version": "0.10.4",
"version": "0.10.5",
"type": "module",
"scripts": {
"dev": "vite",
+7
View File
@@ -1251,6 +1251,13 @@ function addKfFromPrev(layerId: string, kfs: Keyframe[], time: number) {
const source = prev ?? next
if (!source) return
store.duplicateKeyframeAt(layerId, source.id, time)
// Move the editor onto the slot we just populated, so the stage reflects it.
if (store.activeButtonAssetId) {
if (Math.abs(time - BUTTON_STATE_TIMES.normal) < 1e-3) store.setActiveButtonState('normal')
else if (Math.abs(time - BUTTON_STATE_TIMES.hover) < 1e-3) store.setActiveButtonState('hover')
else if (Math.abs(time - BUTTON_STATE_TIMES.pressed) < 1e-3) store.setActiveButtonState('pressed')
else if (Math.abs(time - BUTTON_STATE_TIMES.disabled) < 1e-3) store.setActiveButtonState('disabled')
}
}
const EASING_OPTIONS: { value: Easing; label: string }[] = [
+54
View File
@@ -6880,6 +6880,60 @@ export function registerAllTests(): void {
expect(probe(BUTTON_STATE_TIMES.pressed)).toBe(false)
expect(probe(BUTTON_STATE_TIMES.disabled)).toBe(false)
})
test('clicking + on an empty button slot inserts the kf AND moves the editor to that state', async () => {
const s = makeFreshStore()
const btn = s.addButtonAsset('B', 100, 100)
s.enterButtonAssetEdit(btn.id)
// addLayer in button-edit seeds a single kf on the current state (normal).
const a = s.addAsset({ kind: 'rect', name: 'R', width: 10, height: 10, fill: '#abc' })
const layer = s.addLayer(a.id)!
expect(layer.keyframes).toHaveLength(1)
expect(s.activeButtonState).toBe('normal')
const handle = mountComponent(Timeline, {})
await nextTick()
// With a kf at normal, three empty slots remain: hover, pressed, disabled (in that order).
const adders = handle.host.querySelectorAll<HTMLButtonElement>('.kf-add')
expect(adders.length).toBe(3)
// Click the last one — the "disabled" slot.
adders[adders.length - 1].click()
await nextTick()
expect(layer.keyframes).toHaveLength(2)
expect(layer.keyframes.some((k) => Math.abs(k.time - BUTTON_STATE_TIMES.disabled) < 1e-6)).toBe(true)
expect(s.activeButtonState).toBe('disabled')
expect(s.playhead).toBe(BUTTON_STATE_TIMES.disabled)
s.exitButtonAssetEdit()
handle.unmount()
})
test('clicking + falls back to the NEXT kf when no prev exists, and moves the editor', async () => {
// Pins the prev ?? next branch: with a lone kf at disabled, the + slot
// at hover must copy from the disabled kf and park the editor on hover.
const s = makeFreshStore()
const btn = s.addButtonAsset('B', 100, 100)
s.enterButtonAssetEdit(btn.id)
s.setActiveButtonState('disabled')
const a = s.addAsset({ kind: 'rect', name: 'R', width: 10, height: 10, fill: '#abc' })
const layer = s.addLayer(a.id)!
expect(layer.keyframes).toHaveLength(1)
expect(layer.keyframes[0].time).toBe(BUTTON_STATE_TIMES.disabled)
const handle = mountComponent(Timeline, {})
await nextTick()
// Three empty slots: normal, hover, pressed (in that order).
const adders = handle.host.querySelectorAll<HTMLButtonElement>('.kf-add')
expect(adders.length).toBe(3)
// Second = hover.
adders[1].click()
await nextTick()
expect(layer.keyframes).toHaveLength(2)
expect(layer.keyframes.some((k) => Math.abs(k.time - BUTTON_STATE_TIMES.hover) < 1e-6)).toBe(true)
expect(s.activeButtonState).toBe('hover')
expect(s.playhead).toBe(BUTTON_STATE_TIMES.hover)
s.exitButtonAssetEdit()
handle.unmount()
})
})
suite('button asset — data model + edit mode', () => {