@designbasekorea/ui-wc 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +27 -0
- package/dist/esm/components/db-app-update.d.ts +60 -0
- package/dist/esm/components/db-app-update.js +1 -0
- package/dist/esm/components/db-easing-editor.d.ts +60 -0
- package/dist/esm/components/db-easing-editor.js +1 -0
- package/dist/esm/components/db-icons.d.ts +1 -1
- package/dist/esm/components/db-icons.js +1 -1
- package/dist/esm/components/db-keyframe-editor.d.ts +76 -0
- package/dist/esm/components/db-keyframe-editor.js +1 -0
- package/dist/esm/components/db-selection-bar.d.ts +42 -0
- package/dist/esm/components/db-selection-bar.js +1 -0
- package/dist/esm/components/db-video-timeline.d.ts +89 -0
- package/dist/esm/components/db-video-timeline.js +1 -0
- package/dist/esm/components/easing-model.d.ts +14 -0
- package/dist/esm/components/easing-model.js +1 -0
- package/dist/esm/components/media-editor-model.d.ts +60 -0
- package/dist/esm/components/media-editor-model.js +1 -0
- package/dist/esm/core/i18n-en.js +1 -1
- package/dist/esm/core/i18n.d.ts +105 -0
- package/dist/esm/core/i18n.js +1 -1
- package/dist/esm/index.d.ts +7 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/node_modules/@designbasekorea/ui-contracts/dist/components.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +626 -156
- package/dist/index.esm.js +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.d.ts +275 -2
- package/dist/react/index.esm.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import './db-button.js';
|
|
2
|
+
import './db-select.js';
|
|
3
|
+
import './db-input.js';
|
|
4
|
+
import { EditorKeyframe } from './media-editor-model.js';
|
|
5
|
+
export { KeyframeEasing, evaluateKeyframes } from './media-editor-model.js';
|
|
6
|
+
|
|
7
|
+
interface KeyframeEditDetail {
|
|
8
|
+
keyframes: EditorKeyframe[];
|
|
9
|
+
action: 'add' | 'delete' | 'move' | 'easing' | 'bezier' | 'value';
|
|
10
|
+
keyframeId: string;
|
|
11
|
+
}
|
|
12
|
+
declare class DbKeyframeEditor extends HTMLElement {
|
|
13
|
+
static get observedAttributes(): string[];
|
|
14
|
+
private _keys;
|
|
15
|
+
private viewport?;
|
|
16
|
+
private chart?;
|
|
17
|
+
private toolbar?;
|
|
18
|
+
private inspector?;
|
|
19
|
+
private cursor?;
|
|
20
|
+
private unsubscribe?;
|
|
21
|
+
private drag?;
|
|
22
|
+
private raf;
|
|
23
|
+
private num;
|
|
24
|
+
get duration(): number;
|
|
25
|
+
set duration(n: number);
|
|
26
|
+
get fps(): number;
|
|
27
|
+
set fps(n: number);
|
|
28
|
+
get zoom(): number;
|
|
29
|
+
set zoom(n: number);
|
|
30
|
+
get currentTime(): number;
|
|
31
|
+
set currentTime(n: number);
|
|
32
|
+
get min(): number;
|
|
33
|
+
set min(n: number);
|
|
34
|
+
get max(): number;
|
|
35
|
+
set max(n: number);
|
|
36
|
+
get disabled(): boolean;
|
|
37
|
+
set disabled(n: boolean);
|
|
38
|
+
get selectedKeyframeId(): string;
|
|
39
|
+
set selectedKeyframeId(id: string);
|
|
40
|
+
get keyframes(): EditorKeyframe[];
|
|
41
|
+
set keyframes(value: EditorKeyframe[]);
|
|
42
|
+
private get scale();
|
|
43
|
+
connectedCallback(): void;
|
|
44
|
+
disconnectedCallback(): void;
|
|
45
|
+
attributeChangedCallback(name: string): void;
|
|
46
|
+
private emit;
|
|
47
|
+
private select;
|
|
48
|
+
private seek;
|
|
49
|
+
private plotBounds;
|
|
50
|
+
private y;
|
|
51
|
+
private syncCursor;
|
|
52
|
+
private svg;
|
|
53
|
+
private render;
|
|
54
|
+
addKeyframe(time?: number, value?: number): void;
|
|
55
|
+
private deleteKey;
|
|
56
|
+
private navigate;
|
|
57
|
+
private onActionClick;
|
|
58
|
+
private changeKey;
|
|
59
|
+
private fieldInput;
|
|
60
|
+
private field;
|
|
61
|
+
private setTangent;
|
|
62
|
+
restoreHandles(): void;
|
|
63
|
+
private point;
|
|
64
|
+
private double;
|
|
65
|
+
private down;
|
|
66
|
+
private update;
|
|
67
|
+
private move;
|
|
68
|
+
private autoScroll;
|
|
69
|
+
private finish;
|
|
70
|
+
private up;
|
|
71
|
+
private cancel;
|
|
72
|
+
private key;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { DbKeyframeEditor, EditorKeyframe };
|
|
76
|
+
export type { KeyframeEditDetail };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./db-button.js";import"./db-select.js";import"./db-input.js";import{subscribeDbLocale as e,t}from"../core/i18n.js";import{applyKeyframeEasing as i,clamp as s,editorEditable as n,keyframeTangents as a,frameTime as r,finite as d,emitEditor as h,editorButton as o,keyframeSegment as l,evaluateKeyframes as m}from"./media-editor-model.js";const c=["linear","hold","ease-in","ease-out","ease-in-out","bezier"];class DbKeyframeEditor extends HTMLElement{constructor(){super(...arguments),this._keys=[],this.raf=0,this.onActionClick=e=>{if(!this.disabled)switch(e.target.dataset.action){case"add":this.addKeyframe();break;case"delete":this.deleteKey();break;case"restore":this.restoreHandles();break;case"previous":this.navigate(-1);break;case"next":this.navigate(1)}},this.fieldInput=e=>{e.target!==this&&e.target.dataset.field&&e.stopImmediatePropagation()},this.field=e=>{const t=e.target.dataset.field;if(!t)return;if(e.stopImmediatePropagation(),this.disabled)return;const s=this._keys.find(e=>e.id===this.selectedKeyframeId);if(!s)return;const n=e.detail?.value;"easing"===t&&c.includes(n)?(this._keys=i(this._keys,s.id,n),this.render(),this.emit("easing",s.id)):"time"!==t&&"value"!==t||""===n||!Number.isFinite(Number(n))||this.changeKey(s.id,"time"===t?Number(n):s.time,"value"===t?Number(n):s.value,"value")},this.double=e=>{if(this.disabled||!(e.target instanceof Element)||!e.target.closest(".db-kf__svg")||e.target.closest("[data-key],[data-handle]"))return;const t=this.point(e.clientX,e.clientY);this.addKeyframe(t.time,t.value)},this.down=e=>{if(this.drag)return;if(this.disabled||0!==e.button||!(e.target instanceof Element))return;const t=e.target.closest("[data-key],[data-handle]");if(!t)return void(e.target.closest(".db-kf__svg")&&"touch"!==e.pointerType&&this.seek(this.point(e.clientX,e.clientY).time));e.preventDefault();const i=t.dataset.key||t.dataset.owner;this.select(i),this.viewport?.focus({preventScroll:!0}),this.drag={id:e.pointerId,keyId:i,handle:t.hasAttribute("data-handle")?Number(t.dataset.handle):void 0,x:e.clientX,y:e.clientY,originX:e.clientX,originY:e.clientY,scroll:this.viewport.scrollLeft,before:this.keyframes,changed:!1,independent:e.metaKey||e.ctrlKey,viewMin:this.plotBounds().min,viewMax:this.plotBounds().max},this.setPointerCapture(e.pointerId),this.raf=requestAnimationFrame(this.autoScroll)},this.move=e=>{if(this.drag?.id!==e.pointerId)return;this.drag.x=e.clientX,this.drag.y=e.clientY;const t=e.metaKey||e.ctrlKey;t&&!this.drag.independent&&(this.drag.freeBase=this.keyframes),this.drag.independent=t,this.update()},this.autoScroll=()=>{if(!this.drag||!this.viewport)return;const e=this.viewport.getBoundingClientRect(),t=this.drag.x,i=this.viewport.scrollLeft;this.viewport.scrollLeft+=t>e.right-40?s((t-e.right+40)/3,0,14):t<e.left+40?-s((e.left+40-t)/3,0,14):0,i!==this.viewport.scrollLeft&&this.update(),this.raf=requestAnimationFrame(this.autoScroll)},this.up=e=>{e.pointerId===this.drag?.id&&this.finish()},this.cancel=()=>this.finish(!0),this.key=e=>{if(this.disabled||n(e.target)||e.metaKey||e.ctrlKey||e.altKey)return;if("Escape"===e.key&&this.drag)return e.preventDefault(),void this.finish(!0);const t=e.target,i=this._keys.find(e=>e.id===(t.dataset.key||t.dataset.owner||this.selectedKeyframeId));if("Enter"===e.key&&t.dataset.key)return e.preventDefault(),void this.select(t.dataset.key);if("Delete"===e.key||"Backspace"===e.key)return e.preventDefault(),void this.deleteKey();if("h"===e.key.toLowerCase())return e.preventDefault(),void this.restoreHandles();if("k"===e.key.toLowerCase())return e.preventDefault(),void this.addKeyframe();if(i&&["ArrowLeft","ArrowRight","ArrowUp","ArrowDown"].includes(e.key)){e.preventDefault();const s=e.shiftKey?10:1;if(t.hasAttribute("data-handle")){const n=Number(t.dataset.handle),r=a(this._keys,this._keys.indexOf(i)),d=0===n?r.outgoing:r.incoming;if(!d)return;const h={time:d.time+("ArrowLeft"===e.key?-s/this.fps:"ArrowRight"===e.key?s/this.fps:0),value:d.value+("ArrowUp"===e.key?s:"ArrowDown"===e.key?-s:0)};this.setTangent(this.keyframes,i.id,n,h,!1),this.render(),this.emit("bezier",i.id),this.querySelector(`[data-handle="${n}"]`)?.focus()}else this.select(i.id),this.changeKey(i.id,i.time+("ArrowLeft"===e.key?-s/this.fps:"ArrowRight"===e.key?s/this.fps:0),i.value+("ArrowUp"===e.key?s:"ArrowDown"===e.key?-s:0),"move")}}}static get observedAttributes(){return["duration","fps","current-time","zoom","min","max","disabled","selected-keyframe-id","label"]}num(e,t){const i=this.getAttribute(e);return i?.trim()&&Number.isFinite(Number(i))?Number(i):t}get duration(){return s(this.num("duration",10),1/this.fps,86400)}set duration(e){this.setAttribute("duration",String(e))}get fps(){return s(Math.round(this.num("fps",30)),1,120)}set fps(e){this.setAttribute("fps",String(e))}get zoom(){return s(this.num("zoom",100),10,800)}set zoom(e){this.setAttribute("zoom",String(e))}get currentTime(){return r(s(this.num("current-time",0),0,this.duration),this.fps)}set currentTime(e){this.setAttribute("current-time",String(e))}get min(){return this.num("min",0)}set min(e){this.setAttribute("min",String(e))}get max(){return Math.max(this.min+.001,this.num("max",100))}set max(e){this.setAttribute("max",String(e))}get disabled(){return this.hasAttribute("disabled")}set disabled(e){this.toggleAttribute("disabled",e)}get selectedKeyframeId(){return this.getAttribute("selected-keyframe-id")||""}set selectedKeyframeId(e){this.setAttribute("selected-keyframe-id",e)}get keyframes(){return this._keys.map(e=>({...e,...e.inTangent?{inTangent:{...e.inTangent}}:{},...e.outTangent?{outTangent:{...e.outTangent}}:{},bezier:e.bezier?[...e.bezier]:void 0}))}set keyframes(e){const t=new Set,i=new Set;this._keys=(Array.isArray(e)?e:[]).filter(e=>e&&"string"==typeof e.id&&!t.has(e.id)&&!!t.add(e.id)).map(e=>({...e,time:r(s(d(e.time,0),0,this.duration),this.fps),value:s(d(e.value,this.min),this.min,this.max),inTangent:e.inTangent?{time:-Math.min(this.duration,Math.abs(d(e.inTangent.time,0))),value:s(d(e.inTangent.value,0),4*-(this.max-this.min),4*(this.max-this.min))}:void 0,outTangent:e.outTangent?{time:Math.min(this.duration,Math.abs(d(e.outTangent.time,0))),value:s(d(e.outTangent.value,0),4*-(this.max-this.min),4*(this.max-this.min))}:void 0,easing:c.includes(e.easing)?e.easing:"linear",bezier:Array.isArray(e.bezier)&&4===e.bezier.length?e.bezier.map(e=>s(d(e,0),0,1)):void 0})).filter(e=>!i.has(e.time)&&!!i.add(e.time)).sort((e,t)=>e.time-t.time),this.render()}get scale(){return.8*this.zoom}connectedCallback(){this.classList.add("designbase-wc-keyframe-editor"),this.setAttribute("role","region"),this.viewport||(this.toolbar=document.createElement("div"),this.toolbar.className="db-kf__toolbar",this.viewport=document.createElement("div"),this.viewport.className="db-kf__viewport",this.viewport.tabIndex=0,this.chart=document.createElement("div"),this.chart.className="db-kf__chart",this.viewport.append(this.chart),this.inspector=document.createElement("div"),this.inspector.className="db-kf__inspector",this.append(this.toolbar,this.viewport,this.inspector)),this.addEventListener("pointerdown",this.down),this.addEventListener("pointermove",this.move),this.addEventListener("pointerup",this.up),this.addEventListener("pointercancel",this.cancel),this.addEventListener("lostpointercapture",this.cancel),this.addEventListener("keydown",this.key),this.addEventListener("dblclick",this.double),this.addEventListener("db-click",this.onActionClick),this.addEventListener("db-change",this.field,!0),this.addEventListener("db-input",this.fieldInput,!0),this.unsubscribe=e(()=>this.render()),this.render()}disconnectedCallback(){this.finish(!0),this.unsubscribe?.(),this.removeEventListener("pointerdown",this.down),this.removeEventListener("pointermove",this.move),this.removeEventListener("pointerup",this.up),this.removeEventListener("pointercancel",this.cancel),this.removeEventListener("lostpointercapture",this.cancel),this.removeEventListener("keydown",this.key),this.removeEventListener("dblclick",this.double),this.removeEventListener("db-click",this.onActionClick),this.removeEventListener("db-change",this.field,!0),this.removeEventListener("db-input",this.fieldInput,!0)}attributeChangedCallback(e){"current-time"===e?this.syncCursor():this.render()}emit(e,t){h(this,"db-change",{keyframes:this.keyframes,action:e,keyframeId:t})}select(e){this.selectedKeyframeId!==e&&(this.selectedKeyframeId=e,h(this,"db-selection-change",{keyframeId:e}))}seek(e){this.currentTime=r(s(e,0,this.duration),this.fps),h(this,"db-seek",{time:this.currentTime})}plotBounds(){if(this.drag)return{min:this.drag.viewMin,max:this.drag.viewMax};let e=this.min,t=this.max;this._keys.forEach((i,s)=>{const n=a(this._keys,s);for(const s of[n.incoming,n.outgoing])s&&(e=Math.min(e,i.value+s.value),t=Math.max(t,i.value+s.value))});const i=.04*(t-e);return{min:e<this.min?e-i:e,max:t>this.max?t+i:t}}y(e){const t=this.plotBounds();return 208-(e-t.min)/(t.max-t.min)*176}syncCursor(){if(this.cursor){const e=40+this.currentTime*this.scale;this.cursor.setAttribute("x1",String(e)),this.cursor.setAttribute("x2",String(e))}}svg(e,t={},i){const s=document.createElementNS("http://www.w3.org/2000/svg",e);for(const[e,i]of Object.entries(t))s.setAttribute(e,String(i));return i&&(s.textContent=i),s}render(){if(!this.chart||!this.toolbar||!this.inspector)return;const e=this.ownerDocument.activeElement?.dataset.key,i=this._keys.find(e=>e.id===this.selectedKeyframeId);this.setAttribute("aria-label",this.getAttribute("label")||t("media.keyframes"));const s=document.createElement("strong");s.textContent=this.getAttribute("label")||t("media.keyframes");const n=document.createElement("div");n.className="db-kf__actions";for(const[e,s,a]of[["previous","chevron-left","media.previousKey"],["add","plus","media.addKey"],["next","chevron-right","media.nextKey"],["delete","trash","media.deleteKey"],["restore","refresh","media.restoreHandles"]]){const r=o(t(a),s,e);r.toggleAttribute("disabled",this.disabled||("delete"===e||"restore"===e)&&!i),n.append(r)}this.toolbar.replaceChildren(s,n);const r=Math.max(320,80+this.duration*this.scale),d=this.svg("svg",{width:r,height:240,viewBox:`0 0 ${r} 240`,class:"db-kf__svg","aria-label":t("media.curve")});for(let e=0;e<=4;e++){const t=this.plotBounds(),i=t.min+(t.max-t.min)*e/4,s=this.y(i);d.append(this.svg("line",{x1:40,y1:s,x2:r-40,y2:s,class:"db-kf__grid"}),this.svg("text",{x:32,y:s+4,"text-anchor":"end",class:"db-kf__label"},String(Math.round(100*i)/100)))}const h=[.1,.5,1,2,5,10,30,60,300,600,3600].find(e=>e*this.scale>=64&&this.duration/e<=200)||3600;for(let e=0;e<=this.duration;e+=h){const t=40+e*this.scale;d.append(this.svg("line",{x1:t,y1:24,x2:t,y2:208,class:"db-kf__grid"}),this.svg("text",{x:t,y:230,"text-anchor":"middle",class:"db-kf__label"},Math.round(100*e)/100+"s"))}for(let e=0;e<this._keys.length-1;e++){const t=this._keys[e],i=this._keys[e+1],s=40+t.time*this.scale,n=40+i.time*this.scale,a=this.y(t.value),r=this.y(i.value),h=l(this._keys,e);d.append(this.svg("path",{d:"hold"===t.easing?`M${s},${a}H${n}V${r}`:`M${s},${a}C${40+h.time1*this.scale},${this.y(h.value1)} ${40+h.time2*this.scale},${this.y(h.value2)} ${n},${r}`,class:"db-kf__curve"}))}this.cursor=this.svg("line",{y1:24,y2:208,class:"db-kf__playhead","pointer-events":"none"}),d.append(this.cursor);for(const e of this._keys){const s=40+e.time*this.scale,n=this.y(e.value),a=this.svg("g",{class:"db-kf__point","data-key":e.id,"data-selected":String(e.id===i?.id),role:"button",tabindex:0,"aria-label":`${t("media.keyframe")} ${e.time.toFixed(2)}s, ${e.value.toFixed(1)}`,"aria-pressed":String(e.id===i?.id),"aria-disabled":String(this.disabled)});a.append(this.svg("circle",{cx:s,cy:n,r:14,fill:"transparent"})),a.append(this.svg("rect",{x:s-3,y:n-3,width:6,height:6,transform:`rotate(45 ${s} ${n})`,class:"db-kf__key"})),d.append(a)}if(i){const e=a(this._keys,this._keys.indexOf(i)),s=40+i.time*this.scale,n=this.y(i.value);for(const[a,r,h]of[["out",0,e.outgoing],["in",1,e.incoming]]){if(!h)continue;let e=h.time*this.scale,o=this.y(i.value+h.value)-n;const l=Math.hypot(e,o),m=l<22;if(m){const t=l>.01?24/l:0;e=t?e*t:"in"===a?-24:24,o=t?o*t:0}const c=s+e,u=n+o;d.append(this.svg("line",{x1:s,y1:n,x2:c,y2:u,class:"db-kf__tangent","data-proxy":String(m)}));const f=this.svg("g",{"data-handle":r,"data-side":a,"data-owner":i.id,"data-collapsed":String(m),class:"db-kf__handle-target",role:"slider",tabindex:0,"aria-label":t("in"===a?"media.inHandle":"media.outHandle"),"aria-valuemin":-this.duration,"aria-valuemax":this.duration,"aria-valuenow":h.time,"aria-valuetext":`${h.time.toFixed(3)}s, ${h.value.toFixed(3)}`});f.append(this.svg("circle",{cx:c,cy:u,r:10,fill:"transparent"}),this.svg("circle",{cx:c,cy:u,r:3,class:"db-kf__handle"})),d.append(f)}}this._keys.length||d.append(this.svg("text",{x:60,y:120,class:"db-kf__label"},t("media.emptyKeys"))),this.chart.replaceChildren(d),this.syncCursor();const m=document.createDocumentFragment();if(i){for(const e of["time","value"]){const s=document.createElement("db-input");s.setAttribute("size","s"),s.setAttribute("type","number"),s.setAttribute("label",t("time"===e?"media.time":"media.value")),s.setAttribute("value",String(Number(i[e].toFixed("time"===e?4:3)))),s.setAttribute("step","time"===e?String(1/this.fps):"1"),s.setAttribute("min",String("time"===e?0:this.min)),s.setAttribute("max",String("time"===e?this.duration:this.max)),s.dataset.field=e,s.toggleAttribute("disabled",this.disabled),m.append(s)}const e=document.createElement("db-select");e.setAttribute("size","s"),e.setAttribute("show-clear-button","false"),e.setAttribute("label",t("media.interpolation")),e.setAttribute("options",JSON.stringify(c.map(e=>({value:e,label:t("media."+e)})))),e.setAttribute("value",i.easing||"linear"),e.dataset.field="easing",e.toggleAttribute("disabled",this.disabled),m.append(e)}else{const e=document.createElement("span");e.textContent=t("media.selectKey"),m.append(e)}const u=document.createElement("span");u.className="db-kf__hint",u.textContent=t("media.tangentHelp"),m.append(u),this.inspector.replaceChildren(m),e&&!this.drag&&this.querySelector(`[data-key="${CSS.escape(e)}"]`)?.focus()}addKeyframe(e=this.currentTime,t=m(this._keys,e)){if(this.disabled)return;e=r(s(e,0,this.duration),this.fps);const i=this._keys.find(t=>Math.abs(t.time-e)<.5/this.fps);if(i)return void this.select(i.id);let n="key-"+Math.round(e*this.fps);for(;this._keys.some(e=>e.id===n);)n+="-1";this._keys.push({id:n,time:e,value:s(t,this.min,this.max),easing:"linear"}),this._keys.sort((e,t)=>e.time-t.time),this.select(n),this.render(),this.emit("add",n)}deleteKey(){const e=this.selectedKeyframeId;if(this.disabled||!this._keys.some(t=>t.id===e))return;const t=this._keys.findIndex(t=>t.id===e);this._keys=this._keys.filter(t=>t.id!==e),this.select(this._keys[Math.min(t,this._keys.length-1)]?.id||""),this.render(),this.emit("delete",e)}navigate(e){const t=(e<0?[...this._keys].reverse():this._keys).find(t=>e<0?t.time<this.currentTime-.5/this.fps:t.time>this.currentTime+.5/this.fps);t&&(this.select(t.id),this.seek(t.time),this.viewport&&(this.viewport.scrollLeft=Math.max(0,t.time*this.scale-this.viewport.clientWidth/2)))}changeKey(e,t,i,n,a=!0){const d=this._keys,o=d.findIndex(t=>t.id===e);o<0||(t=r(s(t,o?d[o-1].time+1/this.fps:0,o<d.length-1?d[o+1].time-1/this.fps:this.duration),this.fps),this._keys=d.map(n=>n.id===e?{...n,time:t,value:s(i,this.min,this.max)}:n),this.render(),a?this.emit(n,e):h(this,"db-input",{keyframes:this.keyframes,keyframeId:e,action:n}))}setTangent(e,t,i,n,r){const d=e.findIndex(e=>e.id===t),h=e[d],o=e[d-1],l=e[d+1];if(!h)return;const m=a(e,d),c=o?h.time-o.time:1/0,u=l?l.time-h.time:1/0,f=(r?0===i?u:c:Math.min(c,u))/2,p=0===i?1:-1,g=p*s(p*n.time,0,f),y=s(n.value,4*-(this.max-this.min),4*(this.max-this.min));let v=m.incoming,b=m.outgoing;r?0===i?b={time:g,value:y}:v={time:g,value:y}:(b=l?{time:Math.abs(g),value:p*y}:void 0,v=o?{time:-Math.abs(g),value:-p*y}:void 0),this._keys=e.map((e,t)=>t===d?{...e,inTangent:v,outTangent:b,tangentMode:r?"free":"aligned",easing:!l||0!==i&&r?e.easing:"bezier"}:t!==d-1||!v||1!==i&&r||"hold"!==e.easing?e:{...e,easing:"bezier"})}restoreHandles(){if(this.disabled)return;const e=this._keys.findIndex(e=>e.id===this.selectedKeyframeId),t=this._keys[e],i=this._keys[e-1],s=this._keys[e+1];if(!t||!i&&!s)return;const n=Math.min(i?t.time-i.time:1/0,s?s.time-t.time:1/0)/3,a=i?(t.value-i.value)/(t.time-i.time):void 0,r=s?(s.value-t.value)/(s.time-t.time):void 0,d=void 0!==a&&void 0!==r?a*r<=0?0:(s.value-i.value)/(s.time-i.time):a??r??0;this.setTangent(this.keyframes,t.id,s?0:1,{time:s?n:-n,value:d*(s?n:-n)},!1),this.render(),this.emit("bezier",t.id)}point(e,t){const i=this.chart.getBoundingClientRect();return{time:(e-i.left-40)/this.scale,value:this.plotBounds().max-(t-i.top-32)/176*(this.plotBounds().max-this.plotBounds().min)}}update(){const e=this.drag;if(!e)return;const t=e.before.find(t=>t.id===e.keyId);if(void 0!==e.handle){const i=this.point(e.x,e.y);this.setTangent(e.independent&&e.freeBase||e.before,e.keyId,e.handle,{time:i.time-t.time,value:i.value-t.value},e.independent),this.render(),h(this,"db-input",{keyframes:this.keyframes,keyframeId:t.id,action:"bezier"})}else this.changeKey(t.id,t.time+(e.x-e.originX+this.viewport.scrollLeft-e.scroll)/this.scale,t.value-(e.y-e.originY)/176*(e.viewMax-e.viewMin),"move",!1);e.changed=JSON.stringify(this._keys)!==JSON.stringify(e.before)}finish(e=!1){const t=this.drag;t&&(cancelAnimationFrame(this.raf),this.drag=void 0,this.hasPointerCapture(t.id)&&this.releasePointerCapture(t.id),e?(this._keys=t.before,h(this,"db-input",{keyframes:this.keyframes,cancelled:!0})):t.changed&&this.emit(void 0!==t.handle?"bezier":"move",t.keyId),this.render(),this.querySelector(`[data-key="${CSS.escape(t.keyId)}"]`)?.focus())}}customElements.get("db-keyframe-editor")||customElements.define("db-keyframe-editor",DbKeyframeEditor);export{DbKeyframeEditor,m as evaluateKeyframes};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import './db-button.js';
|
|
2
|
+
|
|
3
|
+
/** Controlled bulk-selection surface. Consumer-owned action DOM is never moved or cloned. */
|
|
4
|
+
declare class DbSelectionBar extends HTMLElement {
|
|
5
|
+
static get observedAttributes(): string[];
|
|
6
|
+
private summary?;
|
|
7
|
+
private status?;
|
|
8
|
+
private clear?;
|
|
9
|
+
private clearText?;
|
|
10
|
+
private observer?;
|
|
11
|
+
private unsubscribe?;
|
|
12
|
+
private visible;
|
|
13
|
+
private origin?;
|
|
14
|
+
private originalSizes;
|
|
15
|
+
private disabledControls;
|
|
16
|
+
get count(): number;
|
|
17
|
+
set count(value: number);
|
|
18
|
+
get placement(): 'inline' | 'floating';
|
|
19
|
+
set placement(value: 'inline' | 'floating');
|
|
20
|
+
private widthLimit;
|
|
21
|
+
get minWidth(): number;
|
|
22
|
+
set minWidth(value: number);
|
|
23
|
+
get maxWidth(): number;
|
|
24
|
+
set maxWidth(value: number);
|
|
25
|
+
get disabled(): boolean;
|
|
26
|
+
set disabled(value: boolean);
|
|
27
|
+
connectedCallback(): void;
|
|
28
|
+
disconnectedCallback(): void;
|
|
29
|
+
attributeChangedCallback(): void;
|
|
30
|
+
private keydown;
|
|
31
|
+
private requestClear;
|
|
32
|
+
private set;
|
|
33
|
+
private restoreControls;
|
|
34
|
+
private sync;
|
|
35
|
+
}
|
|
36
|
+
declare global {
|
|
37
|
+
interface HTMLElementTagNameMap {
|
|
38
|
+
'db-selection-bar': DbSelectionBar;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { DbSelectionBar };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./db-button.js";import{subscribeDbLocale as t,t as e}from"../core/i18n.js";import{dbUid as s}from"../core/uid.js";class DbSelectionBar extends HTMLElement{constructor(){super(...arguments),this.visible=!1,this.originalSizes=new Map,this.disabledControls=new Map,this.keydown=t=>{"Escape"!==t.key||t.defaultPrevented||t.isComposing||t.composedPath().some(t=>t instanceof HTMLElement&&(t.matches('input,textarea,select,[role="textbox"],[role="dialog"],[role^="menu"]')||t.isContentEditable))||this.count&&!this.disabled&&(t.preventDefault(),this.requestClear("escape"))}}static get observedAttributes(){return["count","placement","floating-scope","size","disabled","selection-label","clear-label","min-width","max-width","aria-label"]}get count(){const t=Number(this.getAttribute("count")??0);return Number.isFinite(t)?Math.max(0,Math.floor(t)):0}set count(t){this.setAttribute("count",String(t))}get placement(){return"floating"===this.getAttribute("placement")?"floating":"inline"}set placement(t){this.setAttribute("placement",t)}widthLimit(t,e){const s=this.getAttribute(t);if(!s?.trim())return e;const i=Number(s);return Number.isFinite(i)&&("max-width"===t?i>0:i>=0)?i:e}get minWidth(){return this.widthLimit("min-width",0)}set minWidth(t){this.setAttribute("min-width",String(t))}get maxWidth(){return this.widthLimit("max-width",960)}set maxWidth(t){this.setAttribute("max-width",String(t))}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",t)}connectedCallback(){this.classList.add("designbase-wc-selection-bar"),this.summary||(this.summary=document.createElement("div"),this.summary.className="designbase-wc-selection-bar__summary",this.summary.dataset.selectionBarChrome="",this.summary.id=s("selection-bar"),this.status=document.createElement("span"),this.status.className="designbase-wc-selection-bar__status",this.status.setAttribute("role","status"),this.status.setAttribute("aria-live","polite"),this.status.setAttribute("aria-atomic","true"),this.clear=document.createElement("db-button"),this.clear.setAttribute("variant","tertiary"),this.clearText=document.createElement("span"),this.clear.append(this.clearText),this.clear.addEventListener("db-click",()=>this.requestClear("button")),this.summary.append(this.status,this.clear),this.prepend(this.summary)),this.setAttribute("role","region"),this.addEventListener("keydown",this.keydown),this.sync(),this.observer=new MutationObserver(()=>this.sync()),this.observer.observe(this,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["disabled"]}),this.unsubscribe=t(()=>this.sync())}disconnectedCallback(){this.observer?.disconnect(),this.unsubscribe?.(),this.removeEventListener("keydown",this.keydown),this.restoreControls();for(const[t,e]of this.originalSizes)this.set(t,"size",e);this.originalSizes.clear()}attributeChangedCallback(){this.isConnected&&this.sync()}requestClear(t){!this.disabled&&this.count&&this.dispatchEvent(new CustomEvent("db-clear",{detail:{count:this.count,source:t},bubbles:!0,composed:!0}))}set(t,e,s){null===s?t.hasAttribute(e)&&t.removeAttribute(e):t.getAttribute(e)!==s&&t.setAttribute(e,s)}restoreControls(){for(const[t,e]of this.disabledControls)this.set(t,"disabled",e);this.disabledControls.clear()}sync(){if(!this.summary||!this.status||!this.clear)return;const t=this.count>0;if(t&&!this.visible){const t=this.ownerDocument.activeElement;this.origin=t instanceof HTMLElement&&!this.contains(t)?t:void 0}!t&&this.visible&&this.contains(this.ownerDocument.activeElement)&&this.origin?.isConnected&&this.origin.focus({preventScroll:!0}),this.visible=t,this.set(this,"data-visible",t?"":null),this.set(this,"aria-hidden",t?null:"true"),this.dataset.placement=this.placement,this.style.setProperty("--_db-selection-bar-min-width",this.minWidth+"px"),this.style.setProperty("--_db-selection-bar-max-width",this.maxWidth+"px"),this.dataset.scope="container"===this.getAttribute("floating-scope")?"container":"viewport",this.dataset.size="m"===this.getAttribute("size")?"m":"s";const s=(this.getAttribute("selection-label")||e("selectionBar.count")).split("{count}").join(String(this.count));this.status.textContent!==s&&(this.status.textContent=s);const i=this.getAttribute("clear-label")||e("selectionBar.clear");this.clearText&&this.clearText.textContent!==i&&(this.clearText.textContent=i),this.set(this.clear,"size",this.dataset.size),this.set(this.clear,"disabled",this.disabled?"":null),this.set(this,"aria-description",this.getAttribute("aria-label")?null:e("selectionBar.label")),this.hasAttribute("aria-labelledby")&&this.getAttribute("aria-labelledby")!==this.summary.id||this.set(this,"aria-labelledby",this.hasAttribute("aria-label")?null:this.summary.id),this.set(this.summary,"aria-label",e("selectionBar.label"));const a=[...this.querySelectorAll(':scope > [slot="actions"] db-button, :scope > [slot="actions"] db-select, :scope > [slot="actions"] button')].filter(t=>"button"!==t.localName||!t.closest("db-button,db-select")),r=a.filter(t=>t.matches("db-button,db-select"));for(const[t,e]of this.originalSizes)r.includes(t)||(this.set(t,"size",e),this.originalSizes.delete(t));for(const t of r)this.originalSizes.has(t)||this.originalSizes.set(t,t.getAttribute("size")),this.set(t,"size",this.dataset.size);for(const[t,e]of this.disabledControls)a.includes(t)||(this.set(t,"disabled",e),this.disabledControls.delete(t));if(this.disabled)for(const t of a)this.disabledControls.has(t)||this.disabledControls.set(t,t.getAttribute("disabled")),this.set(t,"disabled","");else this.restoreControls()}}customElements.get("db-selection-bar")||customElements.define("db-selection-bar",DbSelectionBar);export{DbSelectionBar};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import './db-button.js';
|
|
2
|
+
import { VideoTrack, VideoClip, TimelineMarker } from './media-editor-model.js';
|
|
3
|
+
export { VideoClipEffect } from './media-editor-model.js';
|
|
4
|
+
|
|
5
|
+
interface TimelineEditDetail {
|
|
6
|
+
clips: VideoClip[];
|
|
7
|
+
action: 'move' | 'trim-start' | 'trim-end' | 'fade-in' | 'fade-out' | 'delete' | 'split';
|
|
8
|
+
clipId: string;
|
|
9
|
+
}
|
|
10
|
+
/** Non-overlapping tracks; optimistic drag feedback emits input, one change per committed transaction. */
|
|
11
|
+
declare class DbVideoTimeline extends HTMLElement {
|
|
12
|
+
static get observedAttributes(): string[];
|
|
13
|
+
private _tracks;
|
|
14
|
+
private _clips;
|
|
15
|
+
private _markers;
|
|
16
|
+
private viewport?;
|
|
17
|
+
private canvas?;
|
|
18
|
+
private cursor?;
|
|
19
|
+
private hint?;
|
|
20
|
+
private drag?;
|
|
21
|
+
private raf;
|
|
22
|
+
private unsubscribe?;
|
|
23
|
+
private resize?;
|
|
24
|
+
private resizeDrag?;
|
|
25
|
+
private paneGrip?;
|
|
26
|
+
get rowHeight(): number;
|
|
27
|
+
set rowHeight(n: number);
|
|
28
|
+
get height(): number;
|
|
29
|
+
set height(n: number);
|
|
30
|
+
get minClipDuration(): number;
|
|
31
|
+
set minClipDuration(n: number);
|
|
32
|
+
get shortcuts(): boolean;
|
|
33
|
+
set shortcuts(n: boolean);
|
|
34
|
+
private trackHeight;
|
|
35
|
+
private number;
|
|
36
|
+
get duration(): number;
|
|
37
|
+
set duration(n: number);
|
|
38
|
+
get fps(): number;
|
|
39
|
+
set fps(n: number);
|
|
40
|
+
get zoom(): number;
|
|
41
|
+
set zoom(n: number);
|
|
42
|
+
get currentTime(): number;
|
|
43
|
+
set currentTime(n: number);
|
|
44
|
+
get snap(): boolean;
|
|
45
|
+
set snap(n: boolean);
|
|
46
|
+
get disabled(): boolean;
|
|
47
|
+
set disabled(n: boolean);
|
|
48
|
+
get selectedClipId(): string;
|
|
49
|
+
set selectedClipId(id: string);
|
|
50
|
+
get tracks(): VideoTrack[];
|
|
51
|
+
set tracks(value: VideoTrack[]);
|
|
52
|
+
get clips(): VideoClip[];
|
|
53
|
+
set clips(value: VideoClip[]);
|
|
54
|
+
get markers(): TimelineMarker[];
|
|
55
|
+
set markers(value: TimelineMarker[]);
|
|
56
|
+
private get scale();
|
|
57
|
+
connectedCallback(): void;
|
|
58
|
+
disconnectedCallback(): void;
|
|
59
|
+
attributeChangedCallback(name: string): void;
|
|
60
|
+
private syncHint;
|
|
61
|
+
private syncCursor;
|
|
62
|
+
private seek;
|
|
63
|
+
scrollToTime(time: number): void;
|
|
64
|
+
setZoom(value: number): void;
|
|
65
|
+
private node;
|
|
66
|
+
private render;
|
|
67
|
+
private select;
|
|
68
|
+
private timeAt;
|
|
69
|
+
private down;
|
|
70
|
+
private move;
|
|
71
|
+
private snapped;
|
|
72
|
+
private updateDrag;
|
|
73
|
+
private autoScroll;
|
|
74
|
+
private finish;
|
|
75
|
+
private up;
|
|
76
|
+
private cancel;
|
|
77
|
+
private rollback;
|
|
78
|
+
private onActionClick;
|
|
79
|
+
splitSelected(): void;
|
|
80
|
+
private trackIndexAt;
|
|
81
|
+
private finishResize;
|
|
82
|
+
private doubleResize;
|
|
83
|
+
private changeZoom;
|
|
84
|
+
private wheel;
|
|
85
|
+
private key;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export { DbVideoTimeline, TimelineMarker, VideoClip, VideoTrack };
|
|
89
|
+
export type { TimelineEditDetail };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./db-button.js";import{t,subscribeDbLocale as e}from"../core/i18n.js";import{clamp as i,emitEditor as s,editorEditable as r,finite as a,frameTime as d,editorButton as n,editorTimecode as h}from"./media-editor-model.js";class DbVideoTimeline extends HTMLElement{constructor(){super(...arguments),this._tracks=[],this._clips=[],this._markers=[],this.raf=0,this.down=t=>{if(this.drag||this.resizeDrag)return;if(this.disabled||0!==t.button||!(t.target instanceof Element)||t.target.closest("db-button"))return;const e=t.target.closest("[data-track-resize]"),i=t.target.closest("[data-pane-resize]");if(e||i){t.preventDefault(),this.viewport?.focus({preventScroll:!0});const i=this._tracks.find(t=>t.id===e?.dataset.trackResize);return this.resizeDrag={id:t.pointerId,trackId:i?.id,startY:t.clientY,initial:i?this.trackHeight(i):this.viewport.getBoundingClientRect().height,beforeTracks:this.tracks,beforeHeight:this.height},void this.setPointerCapture(t.pointerId)}const s=t.target.closest("[data-marker]");if(s)return void this.seek(Number(s.dataset.marker));const r=t.target.closest("[data-clip]"),a=this._clips.find(t=>t.id===r?.dataset.clip);if(a){if(this.select(a.id),this._tracks.find(t=>t.id===a.trackId)?.locked)return;this.viewport?.focus({preventScroll:!0})}else if(!t.target.closest("[data-seek],[data-playhead]"))return;if("touch"===t.pointerType&&!a&&!t.target.closest(".db-vt__ruler,[data-playhead]"))return;t.preventDefault();const d=t.target.closest("[data-trim]")?.dataset.trim,n=t.target.closest("[data-fade]")?.dataset.fade;this.drag={kind:a?"in"===n?"fade-in":"out"===n?"fade-out":"start"===d?"trim-start":"end"===d?"trim-end":"move":"seek",id:t.pointerId,clipId:a?.id,originX:t.clientX,originY:t.clientY,scroll:this.viewport.scrollLeft,before:this.clips,x:t.clientX,y:t.clientY,changed:!1,shift:t.shiftKey,ripple:t.metaKey||t.ctrlKey,duplicate:a&&!d&&!n&&t.altKey?`clip-${crypto.randomUUID()}`:void 0},this.setPointerCapture(t.pointerId),a||this.seek(this.timeAt(t.clientX)),this.raf=requestAnimationFrame(this.autoScroll)},this.move=t=>{if(this.resizeDrag?.id===t.pointerId){const e=this.resizeDrag,r=Math.round(e.initial+t.clientY-e.startY);return void(e.trackId?(this._tracks=e.beforeTracks.map(t=>t.id===e.trackId?{...t,height:i(r,32,120)}:t),this.render(),s(this,"db-track-input",{tracks:this.tracks})):(this.height=i(r,120,720),s(this,"db-resize-input",{height:this.height})))}this.drag?.id===t.pointerId&&(this.drag.x=t.clientX,this.drag.y=t.clientY,this.drag.shift=t.shiftKey,this.drag.ripple=t.metaKey||t.ctrlKey,"move"===this.drag.kind&&t.altKey&&!this.drag.duplicate&&(this.drag.duplicate=`clip-${crypto.randomUUID()}`),this.updateDrag())},this.autoScroll=()=>{if(!this.drag||!this.viewport)return;const t=this.viewport.getBoundingClientRect(),e=this.drag.x,s=e>t.right-48?i((e-t.right+48)/3,0,18):e<t.left+144+32?-i((t.left+176-e)/3,0,18):0,r=this.viewport.scrollLeft;this.viewport.scrollLeft+=s,r!==this.viewport.scrollLeft&&this.updateDrag(),this.raf=requestAnimationFrame(this.autoScroll)},this.up=t=>{this.resizeDrag?.id!==t.pointerId?this.drag?.id===t.pointerId&&(this.drag.changed&&(this.drag.x=t.clientX,this.drag.y=t.clientY,this.updateDrag()),this.finish()):this.finishResize()},this.cancel=()=>{this.finish(!0),this.finishResize(!0)},this.onActionClick=t=>{const e=t.target,i=e.dataset.action;if(!this.disabled&&("scroll"===i&&this.viewport?.scrollBy({left:Math.max(160,this.viewport.clientWidth-144),behavior:matchMedia("(prefers-reduced-motion: reduce)").matches?"instant":"smooth"}),"lock"===i||"mute"===i)){const t=e.dataset.track;this._tracks=this._tracks.map(e=>e.id===t?{...e,["lock"===i?"locked":"muted"]:!e["lock"===i?"locked":"muted"]}:e),this.render(),s(this,"db-track-change",{tracks:this.tracks})}},this.doubleResize=t=>{if(this.disabled||!(t.target instanceof Element))return;const e=t.target.closest("[data-track-resize],[data-pane-resize]");e&&(e.dataset.trackResize?(this._tracks=this._tracks.map(t=>t.id===e.dataset.trackResize?{...t,height:this.rowHeight}:t),this.render(),s(this,"db-track-change",{tracks:this.tracks})):(this.height=0,s(this,"db-resize",{height:0})))},this.wheel=t=>{if(this.disabled||!this.shortcuts||this.drag||this.resizeDrag||!t.metaKey&&!t.ctrlKey)return;t.preventDefault(),t.stopPropagation();const e=Math.exp(-t.deltaY*(1===t.deltaMode?.04:.002));this.changeZoom(this.zoom*e,t.clientX-this.viewport.getBoundingClientRect().left,"wheel")},this.key=t=>{if(this.disabled||r(t.target)||t.isComposing)return;if("Escape"===t.key&&this.drag)return t.preventDefault(),void this.finish(!0);if("Escape"===t.key&&this.resizeDrag)return t.preventDefault(),void this.finishResize(!0);const e=t.target.closest("[data-track-resize],[data-pane-resize]");if(e&&["ArrowUp","ArrowDown","Home"].includes(t.key)){t.preventDefault();const r="ArrowUp"===t.key?-1:1;return void(e.dataset.trackResize?(this._tracks=this._tracks.map(s=>s.id===e.dataset.trackResize?{...s,height:"Home"===t.key?this.rowHeight:i(this.trackHeight(s)+r*(t.shiftKey?8:2),32,120)}:s),this.render(),s(this,"db-track-change",{tracks:this.tracks}),this.querySelector(`[data-track-resize="${CSS.escape(e.dataset.trackResize)}"]`)?.focus()):(this.height="Home"===t.key?0:i((this.height||this.viewport.clientHeight)+r*(t.shiftKey?24:8),120,720),s(this,"db-resize",{height:this.height}),this.paneGrip?.focus()))}if(this.shortcuts&&!t.altKey&&["+","=","-","0"].includes(t.key))return t.preventDefault(),t.stopPropagation(),void("0"===t.key?this.changeZoom((this.viewport.clientWidth-144)/this.duration/.8,void 0,"fit"):this.changeZoom(this.zoom*("-"===t.key?1/1.2:1.2)));if(this.disabled||r(t.target)||t.ctrlKey||t.metaKey||t.altKey)return;const a=t.target.closest("[data-trim],[data-fade]");if(a&&["ArrowLeft","ArrowRight"].includes(t.key)){const e=a.closest("[data-clip]"),i=this._clips.find(t=>t.id===e?.dataset.clip);if(!i||this._tracks.find(t=>t.id===i.trackId)?.locked)return;t.preventDefault();const s="start"===a.dataset.trim?"trim-start":"end"===a.dataset.trim?"trim-end":"in"===a.dataset.fade?"fade-in":"fade-out";this.drag={kind:s,id:-1,clipId:i.id,originX:0,originY:0,scroll:this.viewport.scrollLeft,before:this.clips,x:("ArrowLeft"===t.key?-1:1)*(t.shiftKey?10:1)/this.fps*this.scale,y:0,changed:!1,shift:!0,ripple:t.metaKey||t.ctrlKey},this.updateDrag(),this.finish();const r=a.dataset.focus;return void Array.from(this.querySelectorAll("[data-focus]")).find(t=>t.dataset.focus===r)?.focus({preventScroll:!0})}if(["ArrowLeft","ArrowRight","Home","End"].includes(t.key))t.preventDefault(),this.seek("Home"===t.key?0:"End"===t.key?this.duration:this.currentTime+("ArrowLeft"===t.key?-1:1)*(t.shiftKey?10:1)/this.fps),this.scrollToTime(this.currentTime);else if("s"===t.key.toLowerCase())t.preventDefault(),this.splitSelected();else if("Delete"===t.key||"Backspace"===t.key){const e=this._clips.find(t=>t.id===this.selectedClipId);if(!e||this._tracks.find(t=>t.id===e.trackId)?.locked)return;t.preventDefault(),this._clips=this._clips.filter(t=>t.id!==e.id),this.select(""),this.render(),s(this,"db-change",{clips:this.clips,clipId:e.id,action:"delete"})}else"Enter"===t.key&&t.target instanceof HTMLElement&&t.target.dataset.clip&&(t.preventDefault(),this.select(t.target.dataset.clip))}}static get observedAttributes(){return["duration","fps","current-time","zoom","snap","disabled","selected-clip-id","row-height","height","min-clip-duration","shortcuts"]}get rowHeight(){return i(this.number("row-height",42),32,120)}set rowHeight(t){this.setAttribute("row-height",String(t))}get height(){const t=this.number("height",0);return t>0?i(t,120,720):0}set height(t){t>0?this.setAttribute("height",String(t)):this.removeAttribute("height")}get minClipDuration(){return Math.min(this.duration,Math.max(1/this.fps,Math.ceil(this.number("min-clip-duration",.5)*this.fps)/this.fps))}set minClipDuration(t){this.setAttribute("min-clip-duration",String(t))}get shortcuts(){return"false"!==this.getAttribute("shortcuts")}set shortcuts(t){this.setAttribute("shortcuts",String(t))}trackHeight(t){return i(a(t.height,this.rowHeight),32,120)}number(t,e){const i=this.getAttribute(t);return i?.trim()&&Number.isFinite(Number(i))?Number(i):e}get duration(){return i(this.number("duration",30),1/this.fps,86400)}set duration(t){this.setAttribute("duration",String(t))}get fps(){return i(Math.round(this.number("fps",30)),1,120)}set fps(t){this.setAttribute("fps",String(t))}get zoom(){return i(this.number("zoom",100),10,800)}set zoom(t){this.setAttribute("zoom",String(t))}get currentTime(){return d(i(this.number("current-time",0),0,this.duration),this.fps)}set currentTime(t){this.setAttribute("current-time",String(t))}get snap(){return"false"!==this.getAttribute("snap")}set snap(t){this.setAttribute("snap",String(t))}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",t)}get selectedClipId(){return this.getAttribute("selected-clip-id")||""}set selectedClipId(t){this.setAttribute("selected-clip-id",t)}get tracks(){return this._tracks.map(t=>({...t}))}set tracks(t){const e=new Set;this._tracks=(Array.isArray(t)?t:[]).filter(t=>t&&"string"==typeof t.id&&!e.has(t.id)&&!!e.add(t.id)).map(t=>({...t,label:String(t.label||t.id),kind:["video","audio","title","mixed"].includes(t.kind)?t.kind:"video"})),this.render()}get clips(){return this._clips.map(t=>({...t,...t.effects?{effects:t.effects.map(t=>({...t}))}:{}}))}set clips(t){if(this.drag)return;const e=new Set;this._clips=(Array.isArray(t)?t:[]).filter(t=>t&&"string"==typeof t.id&&!e.has(t.id)&&!!e.add(t.id)).map(t=>{const e=d(i(a(t.start,0),0,this.duration-1/this.fps),this.fps),s=Math.min(this.duration-e,Math.max(1/this.fps,d(a(t.duration,1),this.fps))),r=d(i(a(t.fadeIn,0),0,s),this.fps),n=d(i(a(t.fadeOut,0),0,Math.max(0,s-r)),this.fps);return{...t,label:String(t.label||t.id),start:e,duration:s,sourceOffset:Math.max(0,a(t.sourceOffset,0)),...void 0!==t.fadeIn?{fadeIn:r}:{},...void 0!==t.fadeOut?{fadeOut:n}:{},...t.effects?{effects:Array.isArray(t.effects)?t.effects.filter(t=>t&&"string"==typeof t.id).map(t=>({...t,label:String(t.label||t.id)})):[]}:{}}}),this.render()}get markers(){return this._markers.map(t=>({...t}))}set markers(t){this._markers=(Array.isArray(t)?t:[]).filter(t=>t&&"string"==typeof t.id&&Number.isFinite(t.time)).map(t=>({...t,label:String(t.label),time:i(t.time,0,this.duration)})),this.render()}get scale(){return.8*this.zoom}connectedCallback(){if(this.classList.add("designbase-wc-video-timeline"),this.setAttribute("role","region"),!this.viewport){this.viewport=document.createElement("div"),this.viewport.className="db-vt__viewport",this.viewport.tabIndex=0,this.canvas=document.createElement("div"),this.canvas.className="db-vt__canvas",this.viewport.append(this.canvas),this.hint=document.createElement("div"),this.hint.className="db-vt__hint";const e=n(t("media.more"),"chevron-right","scroll");this.hint.append(e),this.paneGrip=document.createElement("div"),this.paneGrip.className="db-vt__pane-resize",this.paneGrip.dataset.paneResize="",this.paneGrip.tabIndex=0,this.paneGrip.setAttribute("role","separator"),this.paneGrip.setAttribute("aria-orientation","horizontal"),this.append(this.viewport,this.hint,this.paneGrip),this.viewport.addEventListener("scroll",()=>this.syncHint())}this.viewport.addEventListener("wheel",this.wheel,{passive:!1}),this.addEventListener("dblclick",this.doubleResize),this.addEventListener("pointerdown",this.down),this.addEventListener("pointermove",this.move),this.addEventListener("pointerup",this.up),this.addEventListener("pointercancel",this.cancel),this.addEventListener("lostpointercapture",this.cancel),this.addEventListener("keydown",this.key),this.addEventListener("db-click",this.onActionClick),this.unsubscribe=e(()=>this.render()),this.resize=new ResizeObserver(()=>this.syncHint()),this.resize.observe(this),this.render()}disconnectedCallback(){this.rollback(),this.resize?.disconnect(),this.unsubscribe?.(),this.viewport?.removeEventListener("wheel",this.wheel),this.removeEventListener("dblclick",this.doubleResize),this.finishResize(!0),this.removeEventListener("pointerdown",this.down),this.removeEventListener("pointermove",this.move),this.removeEventListener("pointerup",this.up),this.removeEventListener("pointercancel",this.cancel),this.removeEventListener("lostpointercapture",this.cancel),this.removeEventListener("keydown",this.key),this.removeEventListener("db-click",this.onActionClick)}attributeChangedCallback(t){"disabled"===t&&this.disabled&&(this.finish(!0),this.finishResize(!0)),"current-time"===t?this.syncCursor():this.render()}syncHint(){if(this.syncCursor(),this.viewport)for(const t of this.querySelectorAll("[data-marker]"))t.style.visibility=Number(t.dataset.marker)*this.scale<this.viewport.scrollLeft?"hidden":"";this.viewport&&this.hint&&(this.hint.hidden=this.viewport.scrollLeft+this.viewport.clientWidth>=this.viewport.scrollWidth-2)}syncCursor(){this.cursor&&(this.cursor.style.left=144+this.currentTime*this.scale+"px",this.cursor.style.visibility=this.currentTime*this.scale<(this.viewport?.scrollLeft||0)?"hidden":"",this.cursor.setAttribute("aria-valuenow",String(this.currentTime)),this.cursor.setAttribute("aria-valuetext",h(this.currentTime,this.fps)))}seek(t){this.currentTime=d(i(t,0,this.duration),this.fps),s(this,"db-seek",{time:this.currentTime})}scrollToTime(t){this.viewport&&(this.viewport.scrollLeft=Math.max(0,i(t,0,this.duration)*this.scale-(this.viewport.clientWidth-144)/2))}setZoom(t){const e=this.currentTime;this.zoom=t,this.scrollToTime(e)}node(t,e,i){const s=document.createElement(t);return s.className=e,void 0!==i&&(s.textContent=i),s}render(){if(!this.canvas||!this.viewport)return;this.querySelector(":scope > .db-vt__readout")?.remove(),this.viewport.style.height=this.height?`${this.height}px`:"",this.viewport.style.maxHeight=this.height?"720px":"360px",this.paneGrip&&(this.paneGrip.setAttribute("aria-label",t("media.resizeTimeline")),this.paneGrip.setAttribute("title",t("media.resizeTimelineHint")),this.paneGrip.setAttribute("aria-valuemin","120"),this.paneGrip.setAttribute("aria-valuemax","720"),this.paneGrip.setAttribute("aria-valuenow",String(this.height||this.viewport.clientHeight)));const e=this.hint?.querySelector("db-button");e?.setAttribute("aria-label",t("media.more")),e?.setAttribute("title",t("media.more"));const s=this.ownerDocument.activeElement?.dataset.focus,r=document.createDocumentFragment(),a=this.node("div","db-vt__ruler"),d=this.node("span","db-vt__corner",t("media.tracks"));a.append(d);const o=[1/this.fps,.1,.25,.5,1,2,5,10,30,60,300,600,3600].find(t=>t*this.scale>=64&&this.duration/t<=200)||3600;for(let t=0;t<=this.duration;t+=o){const e=this.node("span","db-vt__tick",h(t,this.fps));e.style.left=144+t*this.scale+"px",a.append(e)}a.dataset.seek="",r.append(a),this._tracks.forEach((e,s)=>{const a=this.node("div","db-vt__row");a.dataset.track=e.id,a.dataset.kind=e.kind,a.style.setProperty("--db-vt-track-height",`${this.trackHeight(e)}px`),a.dataset.condensed=String(this.trackHeight(e)<44),a.dataset.locked=String(!!e.locked),a.dataset.muted=String(!!e.muted);const d=this.node("div","db-vt__track");d.append(this.node("span","db-vt__track-name",e.label));for(const i of["lock","mute"]){const s=t("lock"===i?e.locked?"media.trackLocked":"media.trackUnlocked":e.muted?"media.soundOff":"media.soundOn"),r=n(`${s} · ${e.label}`,"lock"===i?e.locked?"lock":"unlock":e.muted?"mute":"volume-up",i);r.setAttribute("variant","ghost"),r.dataset.track=e.id,r.setAttribute("aria-pressed",String("lock"===i?!!e.locked:!!e.muted)),r.toggleAttribute("disabled",this.disabled),d.append(r)}a.append(d);const c=this.node("div","db-vt__lane");c.dataset.seek="",c.style.width=this.duration*this.scale+"px",c.style.setProperty("--tick",o*this.scale+"px"),this._clips.filter(t=>t.trackId===e.id).forEach(s=>{const r=this.node("div","db-vt__clip");r.dataset.clip=s.id,r.dataset.focus=s.id,r.dataset.selected=String(this.selectedClipId===s.id),r.setAttribute("role","group"),r.tabIndex=0,r.setAttribute("aria-label",`${s.label}, ${h(s.start,this.fps)}, ${t("media.duration")} ${h(s.duration,this.fps)}`),r.setAttribute("aria-disabled",String(this.disabled||!!e.locked));const a=this.selectedClipId===s.id;r.dataset.appearance=s.appearance||("audio"===(s.kind||e.kind)?"waveform":"standard"),r.dataset.narrow=String(s.duration*this.scale<100),r.dataset.editing=String(this.drag?.clipId===s.id),r.style.left=s.start*this.scale+"px",r.style.width=`${Math.max(24,s.duration*this.scale)}px`,r.dataset.hitProxy=String(s.duration*this.scale<24),r.style.setProperty("--db-vt-actual-width",s.duration*this.scale+"px");for(const i of["start","end"]){const d=this.node("span","db-vt__trim");d.dataset.trim=i,d.dataset.focus=`${s.id}-trim-${i}`,d.tabIndex=!a||this.disabled||e.locked?-1:0,d.setAttribute("role","slider"),d.setAttribute("aria-label",`${t("start"===i?"media.trimStart":"media.trimEnd")} · ${s.label}`),d.setAttribute("aria-valuemin","0"),d.setAttribute("aria-valuemax",String(this.duration)),d.setAttribute("aria-valuenow",String("start"===i?s.start:s.start+s.duration)),d.setAttribute("aria-valuetext",h("start"===i?s.start:s.start+s.duration,this.fps)),d.setAttribute("title",t("start"===i?"media.trimStart":"media.trimEnd")),d.append(this.node("i","db-vt__grip")),r.append(d)}if("filmstrip"===s.appearance&&s.thumbnail){const t=this.node("div","db-vt__filmstrip");t.setAttribute("aria-hidden","true");for(let e=0;e<Math.min(24,Math.ceil(s.duration*this.scale/64));e++){const e=document.createElement("img");e.src=s.thumbnail,e.alt="",e.draggable=!1,t.append(e)}r.append(t)}for(const d of["in","out"]){const n=i("in"===d?s.fadeIn||0:s.fadeOut||0,0,s.duration),h=this.node("span","db-vt__fade");if(h.dataset.fadeArea=d,h.style.width=n*this.scale+"px",h.setAttribute("aria-hidden","true"),r.append(h),a){const i=this.node("span","db-vt__fade-handle");i.dataset.fade=d,i.dataset.focus=`${s.id}-fade-${d}`,i.style["in"===d?"left":"right"]=n*this.scale+"px",i.tabIndex=this.disabled||e.locked?-1:0,i.setAttribute("role","slider"),i.setAttribute("aria-label",`${t("in"===d?"media.fadeIn":"media.fadeOut")} · ${s.label}`),i.setAttribute("aria-valuemin","0"),i.setAttribute("aria-valuemax",String(s.duration)),i.setAttribute("aria-valuenow",String(n)),i.setAttribute("title",t("in"===d?"media.fadeIn":"media.fadeOut")),r.append(i)}}if(r.append(this.node("span","db-vt__clip-label",s.label)),"audio"===(s.kind||e.kind)||"waveform"===s.appearance){const t=this.node("span","db-vt__wave");t.setAttribute("aria-hidden","true");for(let e=0;e<Math.min(160,Math.ceil(s.duration*this.scale/7));e++){const i=this.node("i","");i.style.height=20+75*Math.abs(Math.sin(1.7*e)*Math.cos(.4*e))+"%",t.append(i)}r.append(t)}if(s.effects?.length){const e=this.node("span","db-vt__effects");e.setAttribute("aria-label",t("media.effects"));for(const t of s.effects){const i=this.node("span","db-vt__effect",t.label);i.dataset.enabled=String(!1!==t.enabled),i.dataset.kind=t.kind,i.setAttribute("title",t.label),e.append(i)}r.append(e)}c.append(r)}),a.append(c);const l=this.node("div","db-vt__track-resize");l.dataset.trackResize=e.id,l.tabIndex=0,l.setAttribute("role","separator"),l.setAttribute("aria-orientation","horizontal"),l.setAttribute("aria-label",`${t("media.resizeTrack")} · ${e.label}`),l.setAttribute("aria-valuemin","32"),l.setAttribute("aria-valuemax","120"),l.setAttribute("aria-valuenow",String(this.trackHeight(e))),a.append(l),r.append(a)});for(const e of this._markers){const i=this.node("button","db-vt__marker");i.type="button",i.dataset.marker=String(e.time),i.style.left=144+e.time*this.scale+"px";const s=`${t("media.marker")} · ${e.label} · ${h(e.time,this.fps)}`;i.setAttribute("aria-label",s),i.setAttribute("title",s),r.append(i)}if(this.cursor=this.node("div","db-vt__playhead"),this.cursor.dataset.playhead="",this.cursor.tabIndex=0,this.cursor.setAttribute("role","slider"),this.cursor.dataset.focus="playhead",this.cursor.setAttribute("aria-label",t("media.playhead")),this.cursor.setAttribute("aria-valuemin","0"),this.cursor.setAttribute("aria-valuemax",String(this.duration)),this.cursor.setAttribute("aria-disabled",String(this.disabled)),r.append(this.cursor),this._tracks.length||r.append(this.node("p","db-vt__empty",t("media.emptyTracks"))),this.canvas.style.width=144+this.duration*this.scale+"px",this.drag?.clipId){const e=this._clips.find(t=>t.id===this.drag?.clipId);if(e){const i="fade-in"===this.drag.kind?e.fadeIn||0:"fade-out"===this.drag.kind?e.fadeOut||0:"trim-end"===this.drag.kind?e.start+e.duration:e.start,s=this.node("div","db-vt__readout",`${t("media."+("trim-start"===this.drag.kind?"trimStart":"trim-end"===this.drag.kind?"trimEnd":"fade-in"===this.drag.kind?"fadeIn":"fade-out"===this.drag.kind?"fadeOut":"time"))} ${h(i,this.fps)} / ${t("media.duration")} ${h(e.duration,this.fps)}`);this.append(s)}}this.canvas.replaceChildren(r),this.viewport.setAttribute("aria-label",t("media.timeline")),this.syncCursor(),this.syncHint(),s&&!this.drag&&Array.from(this.querySelectorAll("[data-focus]")).find(t=>t.dataset.focus===s)?.focus({preventScroll:!0})}select(t){this.selectedClipId!==t&&(this.selectedClipId=t,s(this,"db-selection-change",{clipId:t}))}timeAt(t){return(t-this.viewport.getBoundingClientRect().left+this.viewport.scrollLeft-144)/this.scale}snapped(t,e){let i=d(t,this.fps);if(this.snap&&!this.drag?.shift){const t=[0,this.currentTime,...this._markers.map(t=>t.time),...this._clips.filter(t=>t.id!==e).flatMap(t=>[t.start,t.start+t.duration])].reduce((t,e)=>Math.abs(e-i)<Math.abs(t-i)?e:t,1/0);Math.abs(t-i)*this.scale<=8&&(i=d(t,this.fps))}return i}updateDrag(){const t=this.drag;if(!t)return;if("seek"===t.kind)return void this.seek(this.timeAt(t.x));const e=t.before.find(e=>e.id===t.clipId);if(!e)return;const r=(t.x-t.originX+this.viewport.scrollLeft-t.scroll)/this.scale;let a=e.start,n=e.duration,h=e.sourceOffset||0,o=e.trackId;if("fade-in"===t.kind||"fade-out"===t.kind){const a="fade-in"===t.kind?"fadeIn":"fadeOut",n="fade-in"===t.kind?e.fadeOut||0:e.fadeIn||0,h=d(i((e[a]||0)+("fade-in"===t.kind?r:-r),0,Math.max(0,e.duration-n)),this.fps);return this._clips=t.before.map(t=>t.id===e.id?{...t,[a]:h}:t),t.changed=JSON.stringify(this._clips)!==JSON.stringify(t.before),this.render(),void s(this,"db-input",{clips:this.clips,clipId:e.id,action:t.kind})}if("move"===t.kind){a=this.snapped(a+r,e.id);const s=this.canvas.getBoundingClientRect(),d=this.trackIndexAt(t.y-s.top-36),h=this._tracks[i(d,0,this._tracks.length-1)],c=this._tracks.find(t=>t.id===e.trackId);!h||h.locked||"mixed"!==h.kind&&h.kind!==(e.kind||c?.kind)||(o=h.id),a=i(a,0,this.duration-n)}else if("trim-start"===t.kind)a=i(this.snapped(a+r,e.id),Math.max(0,e.start-h),e.start+n-Math.min(this.minClipDuration,e.start+n-Math.max(0,e.start-h))),n=e.start+e.duration-a,h+=a-e.start;else{const t=e.sourceDuration?Math.min(this.duration-a,e.sourceDuration-h):this.duration-a;n=i(this.snapped(a+n+r,e.id)-a,Math.min(this.minClipDuration,t),t)}const c=t.ripple&&("trim-start"===t.kind||"trim-end"===t.kind),l=t.before.filter(t=>t.id!==e.id&&t.trackId===e.trackId&&t.start>=e.start+e.duration-1e-6);let p=0;if(c){"trim-start"===t.kind&&(a=e.start);const i=Math.max(e.start+e.duration,...l.map(t=>t.start+t.duration));n=Math.min(n,e.duration+this.duration-i),p=d(n-e.duration,this.fps)}let u=t.before.map(t=>l.some(e=>e.id===t.id)&&c?{...t,start:d(t.start+p,this.fps)}:t);if("move"===t.kind&&t.ripple){const i=t.before.filter(i=>i.trackId===o&&(t.duplicate||i.id!==e.id)).sort((t,e)=>t.start-e.start),s=i.find(t=>a>t.start+1e-6&&a<t.start+t.duration-1e-6);s&&(a=s.start);let r=a+n;const h=new Map;for(const t of i){if(t.start<a-1e-6)continue;const e=Math.max(t.start,r);h.set(t.id,e),r=e+t.duration}if(r>this.duration+1e-6)return;u=t.before.map(t=>h.has(t.id)?{...t,start:d(h.get(t.id),this.fps)}:t)}if(u.some(i=>(t.duplicate||i.id!==e.id)&&i.trackId===o&&a<i.start+i.duration-1e-6&&a+n>i.start+1e-6))return;const f=t.duplicate||e.id;t.duplicate&&(u=[...u,{...e,id:f}]),this._clips=u.map(t=>t.id===f?{...t,kind:t.kind||("mixed"===this._tracks.find(t=>t.id===e.trackId)?.kind?"video":this._tracks.find(t=>t.id===e.trackId)?.kind),start:d(a,this.fps),duration:d(n,this.fps),sourceOffset:d(h,this.fps),trackId:o,...void 0!==t.fadeIn?{fadeIn:Math.min(t.fadeIn,n)}:{},...void 0!==t.fadeOut?{fadeOut:Math.min(t.fadeOut,Math.max(0,n-(t.fadeIn||0)))}:{}}:t),t.changed=JSON.stringify(this._clips)!==JSON.stringify(t.before),this.render(),s(this,"db-input",{clips:this.clips,clipId:e.id,action:t.kind})}finish(t=!1){const e=this.drag;e&&(cancelAnimationFrame(this.raf),this.drag=void 0,this.hasPointerCapture(e.id)&&this.releasePointerCapture(e.id),t?(this._clips=e.before,this.render(),s(this,"db-input",{clips:this.clips,clipId:e.clipId,action:e.kind,cancelled:!0})):e.changed&&e.clipId&&"seek"!==e.kind&&s(this,"db-change",{clips:this.clips,clipId:e.clipId,action:e.kind}),this.render(),this.viewport?.focus({preventScroll:!0}))}rollback(){this.finish(!0)}splitSelected(){const t=this._clips.find(t=>t.id===this.selectedClipId);if(this.disabled||!t||this._tracks.find(e=>e.id===t.trackId)?.locked||t.duration<2*this.minClipDuration||this.currentTime<t.start+this.minClipDuration||this.currentTime>t.start+t.duration-this.minClipDuration)return;const e=this.currentTime;let i=t.id+"-split";for(;this._clips.some(t=>t.id===i);)i+="-1";this._clips=this._clips.flatMap(s=>s.id===t.id?[{...s,duration:e-s.start,fadeOut:0,fadeIn:Math.min(s.fadeIn||0,e-s.start)},{...s,id:i,fadeIn:0,fadeOut:Math.min(s.fadeOut||0,s.start+s.duration-e),start:e,duration:s.start+s.duration-e,sourceOffset:(s.sourceOffset||0)+e-s.start}]:[s]),this.render(),s(this,"db-change",{clips:this.clips,action:"split",clipId:t.id})}trackIndexAt(t){let e=0;for(let i=0;i<this._tracks.length;i++)if(e+=this.trackHeight(this._tracks[i]),t<e)return i;return this._tracks.length-1}finishResize(t=!1){const e=this.resizeDrag;e&&(this.resizeDrag=void 0,this.hasPointerCapture(e.id)&&this.releasePointerCapture(e.id),t?(this._tracks=e.beforeTracks,this.height=e.beforeHeight,this.render(),s(this,e.trackId?"db-track-input":"db-resize-input",e.trackId?{tracks:this.tracks,cancelled:!0}:{height:this.height,cancelled:!0})):s(this,e.trackId?"db-track-change":"db-resize",e.trackId?{tracks:this.tracks}:{height:this.height}))}changeZoom(t,e,r="keyboard"){if(!this.viewport)return;const a=this.zoom,d=e??Math.min(this.viewport.clientWidth-8,Math.max(152,144+this.currentTime*this.scale-this.viewport.scrollLeft)),n=(this.viewport.scrollLeft+d-144)/this.scale;this.zoom=Math.round(100*i(t,10,800))/100,this.viewport.scrollLeft="fit"===r?0:Math.max(0,144+n*this.scale-d),this.zoom!==a&&s(this,"db-zoom-change",{value:this.zoom,previousValue:a,anchorTime:n,source:r})}}customElements.get("db-video-timeline")||customElements.define("db-video-timeline",DbVideoTimeline);export{DbVideoTimeline};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type EasingCurve = [number, number, number, number];
|
|
2
|
+
interface EasingPreset {
|
|
3
|
+
id: string;
|
|
4
|
+
curve: EasingCurve;
|
|
5
|
+
group: 'basic' | 'expressive';
|
|
6
|
+
}
|
|
7
|
+
declare const EASING_PRESETS: readonly EasingPreset[];
|
|
8
|
+
declare function evaluateEasing(value: EasingCurve, time: number): number;
|
|
9
|
+
/** Normalized velocity (progress / normalized time). 1 = constant speed; multiply by value delta / duration for real units/s. */
|
|
10
|
+
declare function evaluateEasingVelocity(value: EasingCurve, time: number): number;
|
|
11
|
+
declare function easingCss(value: EasingCurve): string;
|
|
12
|
+
|
|
13
|
+
export { EASING_PRESETS, easingCss, evaluateEasing, evaluateEasingVelocity };
|
|
14
|
+
export type { EasingCurve, EasingPreset };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{clamp as e,finite as r}from"./media-editor-model.js";const i=[{id:"linear",curve:[0,0,1,1],group:"basic"},{id:"ease",curve:[.25,.1,.25,1],group:"basic"},{id:"ease-in",curve:[.42,0,1,1],group:"basic"},{id:"ease-out",curve:[0,0,.58,1],group:"basic"},{id:"ease-in-out",curve:[.42,0,.58,1],group:"basic"},{id:"smooth",curve:[.45,0,.55,1],group:"expressive"},{id:"snappy",curve:[.76,0,.24,1],group:"expressive"},{id:"swift",curve:[.16,1,.3,1],group:"expressive"},{id:"gentle",curve:[.37,0,.63,1],group:"expressive"},{id:"emphasized",curve:[.2,0,0,1],group:"expressive"}];function normalizeEasing(i){return Array.isArray(i)&&4===i.length?i.map((i,a)=>Math.round(1e4*e(r(i,a<2?0:1),0,1))/1e4):[.42,0,.58,1]}const cubic=(e,r,i)=>3*(1-e)**2*e*r+3*(1-e)*e*e*i+e**3,derivative=(e,r,i)=>3*(1-e)**2*r+6*(1-e)*e*(i-r)+3*e*e*(1-i);function parameter(e,r){let i=0,a=1;for(let s=0;s<28;s++){const s=(i+a)/2;cubic(s,e[0],e[2])<r?i=s:a=s}return(i+a)/2}function evaluateEasing(r,i){const a=normalizeEasing(r),s=e(i,0,1);return 0===s||1===s?s:cubic(parameter(a,s),a[1],a[3])}function evaluateEasingVelocity(r,i){const a=normalizeEasing(r),s=parameter(a,e(i,1e-5,.99999)),n=derivative(s,a[0],a[2]);return derivative(s,a[1],a[3])/Math.max(1e-6,n)}function easingCss(e){return`cubic-bezier(${normalizeEasing(e).join(", ")})`}export{i as EASING_PRESETS,easingCss,evaluateEasing,evaluateEasingVelocity,normalizeEasing};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import './db-button.js';
|
|
2
|
+
|
|
3
|
+
/** Time is seconds; editing is quantized to integral frames at the specified FPS. */
|
|
4
|
+
interface VideoTrack {
|
|
5
|
+
id: string;
|
|
6
|
+
label: string;
|
|
7
|
+
kind: 'video' | 'audio' | 'title' | 'mixed';
|
|
8
|
+
locked?: boolean;
|
|
9
|
+
muted?: boolean;
|
|
10
|
+
height?: number;
|
|
11
|
+
}
|
|
12
|
+
interface VideoClipEffect {
|
|
13
|
+
id: string;
|
|
14
|
+
label: string;
|
|
15
|
+
kind: 'color' | 'blur' | 'transform' | 'opacity' | 'speed';
|
|
16
|
+
enabled?: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface VideoClip {
|
|
19
|
+
kind?: 'video' | 'audio' | 'title';
|
|
20
|
+
id: string;
|
|
21
|
+
trackId: string;
|
|
22
|
+
label: string;
|
|
23
|
+
start: number;
|
|
24
|
+
duration: number;
|
|
25
|
+
sourceOffset?: number;
|
|
26
|
+
sourceDuration?: number;
|
|
27
|
+
fadeIn?: number;
|
|
28
|
+
fadeOut?: number;
|
|
29
|
+
effects?: VideoClipEffect[];
|
|
30
|
+
appearance?: 'standard' | 'filmstrip' | 'waveform' | 'compact';
|
|
31
|
+
thumbnail?: string;
|
|
32
|
+
}
|
|
33
|
+
interface TimelineMarker {
|
|
34
|
+
id: string;
|
|
35
|
+
time: number;
|
|
36
|
+
label: string;
|
|
37
|
+
}
|
|
38
|
+
type KeyframeEasing = 'linear' | 'hold' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'bezier';
|
|
39
|
+
interface KeyframeTangent {
|
|
40
|
+
time: number;
|
|
41
|
+
value: number;
|
|
42
|
+
}
|
|
43
|
+
interface EditorKeyframe {
|
|
44
|
+
id: string;
|
|
45
|
+
time: number;
|
|
46
|
+
value: number;
|
|
47
|
+
easing?: KeyframeEasing;
|
|
48
|
+
bezier?: [number, number, number, number];
|
|
49
|
+
inTangent?: KeyframeTangent;
|
|
50
|
+
outTangent?: KeyframeTangent;
|
|
51
|
+
tangentMode?: 'aligned' | 'free';
|
|
52
|
+
}
|
|
53
|
+
declare function frameTime(time: number, fps?: number): number;
|
|
54
|
+
declare function editorTimecode(time: number, fps?: number): string;
|
|
55
|
+
declare function evaluateKeyframes(keys: EditorKeyframe[], time: number): number;
|
|
56
|
+
declare function keyframeEasingCurve(keys: EditorKeyframe[], id: string): [number, number, number, number] | undefined;
|
|
57
|
+
declare function applyKeyframeEasing(keys: EditorKeyframe[], id: string, easing: KeyframeEasing, bezier?: [number, number, number, number]): EditorKeyframe[];
|
|
58
|
+
|
|
59
|
+
export { applyKeyframeEasing, editorTimecode, evaluateKeyframes, frameTime, keyframeEasingCurve };
|
|
60
|
+
export type { EditorKeyframe, KeyframeEasing, KeyframeTangent, TimelineMarker, VideoClip, VideoClipEffect, VideoTrack };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const clamp=(e,t,n)=>Math.min(n,Math.max(t,e)),finite=(e,t)=>"number"==typeof e&&Number.isFinite(e)?e:t;function frameTime(e,t=30){return Math.round(e*t)/t}function editorTimecode(e,t=30){const n=Math.max(1,Math.round(t)),i=Math.max(0,Math.round(e*n));return[Math.floor(i/(3600*n)),Math.floor(i/(60*n))%60,Math.floor(i/n)%60,i%n].map(e=>String(e).padStart(2,"0")).join(":")}function easingPoints(e){return"bezier"===e.easing?e.bezier||[.25,.1,.25,1]:"ease-in"===e.easing?[.42,0,1,1]:"ease-out"===e.easing?[0,0,.58,1]:"ease-in-out"===e.easing?[.42,0,.58,1]:[0,0,1,1]}const cubic=(e,t,n)=>3*(1-e)**2*e*t+3*(1-e)*e*e*n+e**3;function evaluateKeyframes(e,t){const n=[...e].sort((e,t)=>e.time-t.time);if(!n.length)return 0;if(t<=n[0].time)return n[0].value;const i=n.findIndex(e=>e.time>t);if(i<0)return n[n.length-1].value;const a=n[i-1],u=n[i];if("hold"===a.easing)return a.value;const o=keyframeSegment(n,i-1),r=u.time-a.time,m=clamp((t-a.time)/r,0,1);let s=0,l=1;for(let e=0;e<28;e++){const e=(s+l)/2;cubic(e,(o.time1-a.time)/r,(o.time2-a.time)/r)<m?s=e:l=e}const g=(s+l)/2,v=1-g;return v*v*v*a.value+3*v*v*g*o.value1+3*v*g*g*o.value2+g*g*g*u.value}function keyframeTangents(e,t){const n=e[t],i=e[t-1],a=e[t+1];if(!n)return{};const u="aligned"===n.tangentMode?Math.min(i?n.time-i.time:1/0,a?a.time-n.time:1/0)/2:1/0;let o,r;if(i){const e=n.time-i.time,t=n.value-i.value,a=easingPoints(i);o=n.inTangent?{time:-Math.min(Math.abs(n.inTangent.time),e/2,u),value:n.inTangent.value}:{time:(a[2]-1)*e,value:(a[3]-1)*t}}if(a){const e=a.time-n.time,t=a.value-n.value,i=easingPoints(n);r=n.outTangent?{time:Math.min(Math.abs(n.outTangent.time),e/2,u),value:n.outTangent.value}:{time:i[0]*e,value:i[1]*t}}return{incoming:o,outgoing:r}}function keyframeSegment(e,t){const n=e[t],i=e[t+1],a=i.time-n.time,u=i.value-n.value,o=easingPoints(n),r=keyframeTangents(e,t).outgoing,m=keyframeTangents(e,t+1).incoming;return{time1:n.outTangent?n.time+r.time:n.time+o[0]*a,value1:n.outTangent?n.value+r.value:n.value+o[1]*u,time2:i.inTangent?i.time+m.time:n.time+o[2]*a,value2:i.inTangent?i.value+m.value:n.value+o[3]*u}}function keyframeEasingCurve(e,t){const n=e.findIndex(e=>e.id===t),i=e[n],a=e[n+1];if(!i||!a)return;const u=keyframeSegment(e,n),o=a.time-i.time,r=a.value-i.value;return Math.abs(r)<1e-9?Math.abs(u.value1-i.value)<1e-9&&Math.abs(u.value2-i.value)<1e-9?[0,0,1,1]:void 0:[(u.time1-i.time)/o,(u.value1-i.value)/r,(u.time2-i.time)/o,(u.value2-i.value)/r]}function applyKeyframeEasing(e,t,n,i){const a=e.findIndex(e=>e.id===t);return e.map((e,t)=>t===a?{...e,easing:n,bezier:i,outTangent:void 0,tangentMode:e.inTangent?"free":void 0}:t===a+1?{...e,inTangent:void 0,tangentMode:e.outTangent?"free":void 0}:e)}function editorEditable(e){return e instanceof Element&&!!e.closest("input,textarea,select,[contenteditable=true],db-input,db-select,db-textarea")}function editorButton(e,t,n){const i=document.createElement("db-button");return i.setAttribute("size","s"),i.setAttribute("variant","tertiary"),i.setAttribute("icon-only",""),i.setAttribute("start-icon",t),i.setAttribute("aria-label",e),i.setAttribute("title",e),i.dataset.action=n,i}function emitEditor(e,t,n){e.dispatchEvent(new CustomEvent(t,{detail:n,bubbles:!0,composed:!0}))}export{applyKeyframeEasing,clamp,easingPoints,editorButton,editorEditable,editorTimecode,emitEditor,evaluateKeyframes,finite,frameTime,keyframeEasingCurve,keyframeSegment,keyframeTangents};
|
package/dist/esm/core/i18n-en.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e={"zoom.label":"Zoom controls","zoom.out":"Zoom out","zoom.in":"Zoom in","zoom.value":"Zoom level","zoom.fit":"Fit to screen","zoom.fitShort":"Fit","zoom.fullscreen":"Enter fullscreen","zoom.exitFullscreen":"Exit fullscreen","zoom.fullscreenError":"Fullscreen is unavailable.","toolPanel.close":"Close panel","toolPanel.tabs":"Panel tabs","toolLayout.resize.sidebar":"Resize sidebar width","toolLayout.resize.inspector":"Resize inspector width","toolLayout.resize.bottom":"Resize bottom panel height","password.weak":"Weak","password.fair":"Fair","password.good":"Strong","password.veryStrong":"Very strong","rating.high":"Very good","rating.medium":"Average","rating.low":"Low","rating.label":"Rating {value}","rating.review":"{count} review","rating.reviews":"{count} reviews","countdown.days":"Days","countdown.hours":"Hours","countdown.minutes":"Minutes","countdown.seconds":"Seconds","upload.title":"Drag files here or click to choose","upload.choose":"Choose files","upload.allFormats":"All file types supported","upload.maximum":" (up to {size})","upload.files":"Uploaded files ({count})","upload.retry":"Retry","upload.remove":"Remove","upload.illustration":"Upload illustration","creditCard.security":"Security code {code}","creditCard.label":"{issuer} card{lastFour}, flip","creditCard.ending":", ending in {digits}","creditCard.front":"Front","creditCard.back":"Back","creditCard.showing":"Showing {side}","creditCard.expiry":"Expires {expiry}","creditCard.show":"Press to show {side}","flight.scheduled":"Scheduled","flight.boarding":"Boarding","flight.in-flight":"In flight","flight.landed":"Landed","flight.delayed":"Delayed","flight.cancelled":"Cancelled","flight.title":"Flight status","flight.progress":"Journey progress","boardingPass.origin":"From","boardingPass.destination":"To","boardingPass.passenger":"Passenger","boardingPass.service":"Flight","boardingPass.date":"Date","boardingPass.boarding":"Boarding","boardingPass.departure":"Departure","boardingPass.arrival":"Arrival","boardingPass.terminal":"Terminal","boardingPass.gate":"Gate","boardingPass.seat":"Seat","boardingPass.travelClass":"Class","boardingPass.title":"Boarding pass","wallet.title":"My boarding passes","wallet.empty":"No boarding passes yet.","wallet.journeys":"Choose a journey","receipt.quantity":"Qty","receipt.subtotal":"Subtotal","receipt.discount":"Discount","receipt.tax":"Tax","receipt.total":"Total","receipt.payment":"Payment","receipt.empty":"No items to display.","receipt.invalid":"Check the items and amounts.","receipt.title":"Receipt","ticket.title":"Ticket","paper.codeImage":"Code image","aiElement.emptyFolder":"Empty folder","aiElement.noFiles":"No files to display.","attachment.title":"Attachments","attachment.empty":"No attachments yet.","attachment.queued":"Queued","attachment.uploading":"Uploading","attachment.processing":"Processing","attachment.ready":"Ready","attachment.error":"Failed","attachment.cancelled":"Cancelled","attachment.unknown":"Checking progress…","attachment.cancel":"Cancel","attachment.retry":"Retry","attachment.remove":"Remove from list","attachment.open":"View details","attachment.reload":"Reload","workspace.members":"Workspace members","workspace.invite":"Invite members","workspace.email":"Email","workspace.role":"Role","workspace.chooseRole":"Choose a role","workspace.description":"Review the email address and role of the person you want to invite.","workspace.submit":"Send invitation","workspace.emailError":"Enter a valid email address of up to 254 characters.","workspace.roleError":"Choose a role for the invitation.","workspace.retry":"Reload","workspace.reinvite":"Invite again","workspace.active":"Active","workspace.invited":"Invitation pending","workspace.expired":"Invitation expired","workspace.empty":"No members to display yet.","aiElement.pending":"Pending","aiElement.running":"In progress","aiElement.complete":"Complete","aiElement.error":"Failed","aiElement.cancelled":"Cancelled","aiElement.approval":"Awaiting approval","aiElement.researching":"Reviewing sources","aiElement.researched":"View research","aiElement.thinking":"Thinking","aiElement.reasoning":"Response summary","aiElement.plan":"Plan","aiElement.queue":"Queued requests","aiElement.remove":"Remove","aiElement.queueEmpty":"No queued requests.","aiElement.sources":"Sources","aiElement.citation":"Source","aiElement.checkpoint":"Checkpoint saved","aiElement.restore":"Restore from here","aiElement.confirmation":"Proceed with this action?","aiElement.allow":"Allow","aiElement.reject":"Reject","aiElement.accepted":"Action approved.","aiElement.rejected":"Action rejected.","aiElement.context":"Context","aiElement.tokens":"Tokens","aiElement.unknown":"Usage is not available yet.","aiElement.files":"Files","aiElement.task":"Task progress","aiElement.subagent":"Subagent","aiElement.tool":"Tool call","aiElement.terminal":"Terminal","aiElement.stackTrace":"Error details","aiElement.tests":"Test results","aiElement.passed":"Passed","aiElement.failed":"Failed","aiElement.input":"Input","aiElement.output":"Output","aiElement.user":"User","aiElement.assistant":"AI response","aiElement.copy":"Copy","aiElement.regenerate":"Regenerate","aiElement.like":"Like","aiElement.dislike":"Dislike","aiElement.latest":"Latest response","aiElement.conversation":"AI conversation","notification.title":"Notifications","notification.filters":"Notification filters","notification.all":"All","notification.unread":"Unread","notification.readAll":"Mark displayed notifications as read","notification.markRead":"Mark as read","notification.retry":"Reload","notification.empty":"No notifications yet.","notification.caughtUp":"You’re all caught up.","notification.countUnknown":"Needs review","aiModel.label":"Model","aiModel.choose":"Choose a model","aiModel.empty":"No models are available right now.","aiModel.capabilities":"Capabilities","aiModel.usage":"Usage unit","aiQuote.expires":"Quote expires","aiQuote.title":"Execution estimate","aiQuote.reserved":"Maximum credit reservation","aiQuote.providerCost":"Estimated provider cost","aiQuote.pricingVersion":"Pricing version","aiQuote.unknown":"Unconfirmed","aiQuote.idle":"Choose a model and enter a request to get an estimate.","aiQuote.loading":"Checking the estimate…","aiQuote.executing":"Processing your request. Do not submit it again.","aiQuote.stale":"The model or input has changed. Refresh the estimate.","aiQuote.expired":"The estimate has expired. Request a new estimate.","aiQuote.balanceUnknown":"Your balance is unavailable. Refresh to try again.","aiQuote.insufficient":"Additional credits needed:","aiQuote.ready":"Credits are reserved when execution starts and settled against actual usage when it finishes.","aiQuote.refresh":"Refresh estimate","aiQuote.request":"Get estimate","aiQuote.execute":"Run","plan.current":"Current plan","plan.usage":"Usage this period","plan.allowed":"Included","plan.locked":"Not included","plan.manage":"Manage plan","plan.retry":"Reload","history.title":"Credit history","history.empty":"No history yet.","history.unresolved":"Checking","history.grant":"Granted","history.charge":"Used","history.hold":"Reserved · not settled","history.release":"Reservation released","credits.choosePlan":"Credits to add","credits.rechargeDescription":"Choose an amount and review the price and terms.","credits.paymentAmount":"Payment amount","credits.paymentPending":"Checking payment status","credits.remaining":"Remaining credits","credits.available":"Available credits","credits.unit":"credits","credits.held":"Reserved","credits.spent":"Total used","credits.charged":"Charged","credits.low":"Your credit balance is running low.","credits.recharge":"Add credits","credits.checkout":"Continue to payment","credits.noPlans":"No credit packs are available right now.","aiTask.title":"AI task","aiTask.idle":"Not started","aiTask.queued":"Queued","aiTask.running":"Running","aiTask.succeeded":"Complete","aiTask.failed":"Failed","aiTask.cancelled":"Cancelled","aiTask.needs_attention":"Review needed","aiTask.attentionDescription":"We’re checking the result and usage. Reserved credits remain on hold until the review is complete.",close:"Close","modal.close":"Close modal","drawer.close":"Close drawer","dialog.close":"Close dialog","toast.close":"Dismiss notification",clear:"Clear",clearAll:"Clear all",loading:"Loading",required:"Required",optional:"Optional",error:"Error",success:"Success",warning:"Warning",info:"Information",previous:"Previous",next:"Next","select.placeholder":"Select…","select.noResults":"No results","navigationRail.label":"Main navigation","navigationRail.newNotification":"New notification","navigationRail.notifications":"Notifications","tabs.label":"Tabs","pagination.label":"Pagination","search.label":"Search","media.play":"Play","media.pause":"Pause","media.mute":"Mute","media.unmute":"Unmute","media.settings":"Settings","media.shuffle":"Shuffle","media.repeat":"Repeat","media.previous":"Previous track","media.next":"Next track","media.fullscreen":"Full screen","confirm.ok":"Confirm","confirm.cancel":"Cancel","carousel.slide":"slide","carousel.role":"carousel","carousel.previous":"Previous slide","carousel.next":"Next slide","breadcrumbs.expand":"Show hidden path","input.showPassword":"Show password","input.hidePassword":"Hide password","input.clearSearch":"Clear search","verify.done":"Verified","verify.phoneDone":"Your phone number has been verified.","bentoCard.cta":"View details","tweetCard.loading":"Loading post…","tweetCard.error":"Unable to load this post.","tweetCard.viewOnTwitter":"View on X","tweetCard.like":"Like","tweetCard.retweet":"Repost","tweetCard.reply":"Reply","tweetCard.verified":"Verified account","tweetCard.retry":"Try again","chatComposer.placeholder":"Type a message…","chatComposer.send":"Send","chatComposer.stop":"Stop generating","chatComposer.attach":"Attach","voice.start":"Voice input","voice.stop":"Finish dictation","voice.cancel":"Cancel voice input","voice.starting":"Connecting microphone","voice.listening":"Listening","voice.stopping":"Finishing transcription","voice.error":"Voice recognition failed","voice.unsupported":"Voice input not supported"};export{e as ENGLISH_STRINGS};
|
|
1
|
+
const e={"appUpdate.notice":"Update available","appUpdate.changes":"What’s new","appUpdate.automatic":"Restarts automatically when complete.","appUpdate.install":"Update","appUpdate.inProgress":"Updating","appUpdate.dialogTitle":"App update","appUpdate.toastComplete":"Updated to {version}.","appUpdate.checking.title":"Checking for updates","appUpdate.checking.description":"Looking for a new update.","appUpdate.up-to-date.title":"You’re up to date","appUpdate.up-to-date.description":"You’re using the latest available version.","appUpdate.available.title":"An update is available","appUpdate.available.description":"Download the latest improvements and stability updates.","appUpdate.downloading.title":"Downloading update","appUpdate.downloading.description":"We’ll let you know how to apply it when the download finishes.","appUpdate.ready.title":"Ready to update","appUpdate.ready.description":"Save your work, then restart the app to apply the update.","appUpdate.applying.title":"Applying update","appUpdate.applying.description":"Keep the app open and wait a moment.","appUpdate.complete.title":"Update complete","appUpdate.complete.description":"The new version has been applied successfully.","appUpdate.error.title":"Update could not be completed","appUpdate.error.description":"Check your connection and try again.","appUpdate.offline.title":"Internet connection required","appUpdate.offline.description":"Connect to the internet, then try again.","appUpdate.current":"Current","appUpdate.target":"New version","appUpdate.required":"Required update","appUpdate.later":"Later","appUpdate.download":"Download update","appUpdate.restart":"Restart to update","appUpdate.retry":"Try again","appUpdate.done":"Done","media.restoreHandles":"Restore handles (H)","media.tangentHelp":"Drag: symmetric · Cmd/Ctrl: independent · H: restore · dashed handles reveal collapsed controls.","media.resizeTimeline":"Resize timeline height","media.resizeTimelineHint":"Drag vertically to resize. Double-click or Home for automatic height.","media.resizeTrack":"Resize track height","easing.outVelocity":"Out velocity ×","easing.inVelocity":"In velocity ×","easing.label":"Easing & velocity","easing.graphMode":"Graph mode","easing.value":"Value","easing.speed":"Speed","easing.valueGraph":"Normalized progress curve","easing.speedGraph":"Normalized velocity graph","easing.custom":"Custom curve","easing.presets":"Easing presets","easing.linear":"Linear","easing.ease":"Ease","easing.ease-in":"Ease in","easing.ease-out":"Ease out","easing.ease-in-out":"Ease in/out","easing.smooth":"Smooth","easing.snappy":"Snappy","easing.swift":"Swift out","easing.gentle":"Gentle","easing.emphasized":"Emphasized","easing.outgoing":"Outgoing tangent","easing.incoming":"Incoming tangent","easing.preview":"Play easing preview","easing.velocityHint":"1× = constant speed","easing.speedHelp":"Drag tangent controls to change influence and endpoint velocity. Vertical scale is normalized; multiply by value change / duration for units per second.","easing.valueHelp":"Drag handles or enter exact coordinates. Arrow keys nudge .01; Shift nudges .1. Escape cancels dragging.","media.trimStart":"Trim start","media.trimEnd":"Trim end","media.fadeIn":"Fade in","media.fadeOut":"Fade out","media.effects":"Applied effects","media.timeline":"Video timeline","media.tracks":"Tracks","media.more":"Scroll to more tracks and clips","media.lock":"Lock track","media.trackLocked":"Locked","media.trackUnlocked":"Unlocked","media.soundOn":"Sound on","media.soundOff":"Muted","media.marker":"Timeline marker","media.trackMute":"Mute track","media.duration":"Duration","media.playhead":"Playhead","media.emptyTracks":"No tracks. Connect a tracks array to begin.","media.keyframes":"Keyframes","media.curve":"Value graph","media.previousKey":"Previous keyframe","media.nextKey":"Next keyframe","media.addKey":"Add keyframe (K)","media.deleteKey":"Delete keyframe","media.outHandle":"Outgoing Bezier handle","media.inHandle":"Incoming Bezier handle","media.keyframe":"Keyframe","media.emptyKeys":"Add a keyframe or double-click the graph.","media.selectKey":"Select a keyframe to edit its time, value and interpolation.","media.time":"Time (seconds)","media.value":"Value","media.interpolation":"Interpolation","media.linear":"Linear","media.hold":"Hold","media.ease-in":"Ease in","media.ease-out":"Ease out","media.ease-in-out":"Ease in / out","media.bezier":"Custom Bezier","selectionBar.count":"{count} selected","selectionBar.clear":"Clear","selectionBar.label":"Selection actions","zoom.label":"Zoom controls","zoom.out":"Zoom out","zoom.in":"Zoom in","zoom.value":"Zoom level","zoom.fit":"Fit to screen","zoom.fitShort":"Fit","zoom.fullscreen":"Enter fullscreen","zoom.exitFullscreen":"Exit fullscreen","zoom.fullscreenError":"Fullscreen is unavailable.","toolPanel.close":"Close panel","toolPanel.tabs":"Panel tabs","toolLayout.resize.sidebar":"Resize sidebar width","toolLayout.resize.inspector":"Resize inspector width","toolLayout.resize.bottom":"Resize bottom panel height","password.weak":"Weak","password.fair":"Fair","password.good":"Strong","password.veryStrong":"Very strong","rating.high":"Very good","rating.medium":"Average","rating.low":"Low","rating.label":"Rating {value}","rating.review":"{count} review","rating.reviews":"{count} reviews","countdown.days":"Days","countdown.hours":"Hours","countdown.minutes":"Minutes","countdown.seconds":"Seconds","upload.title":"Drag files here or click to choose","upload.choose":"Choose files","upload.allFormats":"All file types supported","upload.maximum":" (up to {size})","upload.files":"Uploaded files ({count})","upload.retry":"Retry","upload.remove":"Remove","upload.illustration":"Upload illustration","creditCard.security":"Security code {code}","creditCard.label":"{issuer} card{lastFour}, flip","creditCard.ending":", ending in {digits}","creditCard.front":"Front","creditCard.back":"Back","creditCard.showing":"Showing {side}","creditCard.expiry":"Expires {expiry}","creditCard.show":"Press to show {side}","flight.scheduled":"Scheduled","flight.boarding":"Boarding","flight.in-flight":"In flight","flight.landed":"Landed","flight.delayed":"Delayed","flight.cancelled":"Cancelled","flight.title":"Flight status","flight.progress":"Journey progress","boardingPass.origin":"From","boardingPass.destination":"To","boardingPass.passenger":"Passenger","boardingPass.service":"Flight","boardingPass.date":"Date","boardingPass.boarding":"Boarding","boardingPass.departure":"Departure","boardingPass.arrival":"Arrival","boardingPass.terminal":"Terminal","boardingPass.gate":"Gate","boardingPass.seat":"Seat","boardingPass.travelClass":"Class","boardingPass.title":"Boarding pass","wallet.title":"My boarding passes","wallet.empty":"No boarding passes yet.","wallet.journeys":"Choose a journey","receipt.quantity":"Qty","receipt.subtotal":"Subtotal","receipt.discount":"Discount","receipt.tax":"Tax","receipt.total":"Total","receipt.payment":"Payment","receipt.empty":"No items to display.","receipt.invalid":"Check the items and amounts.","receipt.title":"Receipt","ticket.title":"Ticket","paper.codeImage":"Code image","aiElement.emptyFolder":"Empty folder","aiElement.noFiles":"No files to display.","attachment.title":"Attachments","attachment.empty":"No attachments yet.","attachment.queued":"Queued","attachment.uploading":"Uploading","attachment.processing":"Processing","attachment.ready":"Ready","attachment.error":"Failed","attachment.cancelled":"Cancelled","attachment.unknown":"Checking progress…","attachment.cancel":"Cancel","attachment.retry":"Retry","attachment.remove":"Remove from list","attachment.open":"View details","attachment.reload":"Reload","workspace.members":"Workspace members","workspace.invite":"Invite members","workspace.email":"Email","workspace.role":"Role","workspace.chooseRole":"Choose a role","workspace.description":"Review the email address and role of the person you want to invite.","workspace.submit":"Send invitation","workspace.emailError":"Enter a valid email address of up to 254 characters.","workspace.roleError":"Choose a role for the invitation.","workspace.retry":"Reload","workspace.reinvite":"Invite again","workspace.active":"Active","workspace.invited":"Invitation pending","workspace.expired":"Invitation expired","workspace.empty":"No members to display yet.","aiElement.pending":"Pending","aiElement.running":"In progress","aiElement.complete":"Complete","aiElement.error":"Failed","aiElement.cancelled":"Cancelled","aiElement.approval":"Awaiting approval","aiElement.researching":"Reviewing sources","aiElement.researched":"View research","aiElement.thinking":"Thinking","aiElement.reasoning":"Response summary","aiElement.plan":"Plan","aiElement.queue":"Queued requests","aiElement.remove":"Remove","aiElement.queueEmpty":"No queued requests.","aiElement.sources":"Sources","aiElement.citation":"Source","aiElement.checkpoint":"Checkpoint saved","aiElement.restore":"Restore from here","aiElement.confirmation":"Proceed with this action?","aiElement.allow":"Allow","aiElement.reject":"Reject","aiElement.accepted":"Action approved.","aiElement.rejected":"Action rejected.","aiElement.context":"Context","aiElement.tokens":"Tokens","aiElement.unknown":"Usage is not available yet.","aiElement.files":"Files","aiElement.task":"Task progress","aiElement.subagent":"Subagent","aiElement.tool":"Tool call","aiElement.terminal":"Terminal","aiElement.stackTrace":"Error details","aiElement.tests":"Test results","aiElement.passed":"Passed","aiElement.failed":"Failed","aiElement.input":"Input","aiElement.output":"Output","aiElement.user":"User","aiElement.assistant":"AI response","aiElement.copy":"Copy","aiElement.regenerate":"Regenerate","aiElement.like":"Like","aiElement.dislike":"Dislike","aiElement.latest":"Latest response","aiElement.conversation":"AI conversation","notification.title":"Notifications","notification.filters":"Notification filters","notification.all":"All","notification.unread":"Unread","notification.readAll":"Mark displayed notifications as read","notification.markRead":"Mark as read","notification.retry":"Reload","notification.empty":"No notifications yet.","notification.caughtUp":"You’re all caught up.","notification.countUnknown":"Needs review","aiModel.label":"Model","aiModel.choose":"Choose a model","aiModel.empty":"No models are available right now.","aiModel.capabilities":"Capabilities","aiModel.usage":"Usage unit","aiQuote.expires":"Quote expires","aiQuote.title":"Execution estimate","aiQuote.reserved":"Maximum credit reservation","aiQuote.providerCost":"Estimated provider cost","aiQuote.pricingVersion":"Pricing version","aiQuote.unknown":"Unconfirmed","aiQuote.idle":"Choose a model and enter a request to get an estimate.","aiQuote.loading":"Checking the estimate…","aiQuote.executing":"Processing your request. Do not submit it again.","aiQuote.stale":"The model or input has changed. Refresh the estimate.","aiQuote.expired":"The estimate has expired. Request a new estimate.","aiQuote.balanceUnknown":"Your balance is unavailable. Refresh to try again.","aiQuote.insufficient":"Additional credits needed:","aiQuote.ready":"Credits are reserved when execution starts and settled against actual usage when it finishes.","aiQuote.refresh":"Refresh estimate","aiQuote.request":"Get estimate","aiQuote.execute":"Run","plan.current":"Current plan","plan.usage":"Usage this period","plan.allowed":"Included","plan.locked":"Not included","plan.manage":"Manage plan","plan.retry":"Reload","history.title":"Credit history","history.empty":"No history yet.","history.unresolved":"Checking","history.grant":"Granted","history.charge":"Used","history.hold":"Reserved · not settled","history.release":"Reservation released","credits.choosePlan":"Credits to add","credits.rechargeDescription":"Choose an amount and review the price and terms.","credits.paymentAmount":"Payment amount","credits.paymentPending":"Checking payment status","credits.remaining":"Remaining credits","credits.available":"Available credits","credits.unit":"credits","credits.held":"Reserved","credits.spent":"Total used","credits.charged":"Charged","credits.low":"Your credit balance is running low.","credits.recharge":"Add credits","credits.checkout":"Continue to payment","credits.noPlans":"No credit packs are available right now.","aiTask.title":"AI task","aiTask.idle":"Not started","aiTask.queued":"Queued","aiTask.running":"Running","aiTask.succeeded":"Complete","aiTask.failed":"Failed","aiTask.cancelled":"Cancelled","aiTask.needs_attention":"Review needed","aiTask.attentionDescription":"We’re checking the result and usage. Reserved credits remain on hold until the review is complete.",close:"Close","modal.close":"Close modal","drawer.close":"Close drawer","dialog.close":"Close dialog","toast.close":"Dismiss notification",clear:"Clear",clearAll:"Clear all",loading:"Loading",required:"Required",optional:"Optional",error:"Error",success:"Success",warning:"Warning",info:"Information",previous:"Previous",next:"Next","select.placeholder":"Select…","select.noResults":"No results","navigationRail.label":"Main navigation","navigationRail.newNotification":"New notification","navigationRail.notifications":"Notifications","tabs.label":"Tabs","pagination.label":"Pagination","search.label":"Search","media.play":"Play","media.pause":"Pause","media.mute":"Mute","media.unmute":"Unmute","media.settings":"Settings","media.shuffle":"Shuffle","media.repeat":"Repeat","media.previous":"Previous track","media.next":"Next track","media.fullscreen":"Full screen","confirm.ok":"Confirm","confirm.cancel":"Cancel","carousel.slide":"slide","carousel.role":"carousel","carousel.previous":"Previous slide","carousel.next":"Next slide","breadcrumbs.expand":"Show hidden path","input.showPassword":"Show password","input.hidePassword":"Hide password","input.clearSearch":"Clear search","verify.done":"Verified","verify.phoneDone":"Your phone number has been verified.","bentoCard.cta":"View details","tweetCard.loading":"Loading post…","tweetCard.error":"Unable to load this post.","tweetCard.viewOnTwitter":"View on X","tweetCard.like":"Like","tweetCard.retweet":"Repost","tweetCard.reply":"Reply","tweetCard.verified":"Verified account","tweetCard.retry":"Try again","chatComposer.placeholder":"Type a message…","chatComposer.send":"Send","chatComposer.stop":"Stop generating","chatComposer.attach":"Attach","voice.start":"Voice input","voice.stop":"Finish dictation","voice.cancel":"Cancel voice input","voice.starting":"Connecting microphone","voice.listening":"Listening","voice.stopping":"Finishing transcription","voice.error":"Voice recognition failed","voice.unsupported":"Voice input not supported"};export{e as ENGLISH_STRINGS};
|