bend_puzzle/client/input/interaction-state.js
2026-07-31 12:54:46 +09:00

52 lines
2.3 KiB
JavaScript

(function(root,factory){
const api=factory();
if(typeof module==='object'&&module.exports)module.exports=api;
root.BendInteractionState=api;
})(typeof globalThis!=='undefined'?globalThis:this,function(){
'use strict';
const DEFAULT_SCOPES=Object.freeze({
any:Object.freeze(['camera','drawing','claim','wheel','reaction','minimap','dialog']),
pointer:Object.freeze(['camera','drawing','claim','reaction','minimap']),
camera:Object.freeze(['camera','wheel']),
persistence:Object.freeze(['camera','drawing','claim','wheel','reaction','minimap']),
world:Object.freeze(['camera','drawing','claim','wheel','reaction','minimap']),
overview:Object.freeze(['camera','drawing','claim','wheel','reaction','minimap']),
worker:Object.freeze(['drawing','claim'])
});
function createInteractionState(scopeDefinitions=DEFAULT_SCOPES){
const owners=new Map(),listeners=new Set(),scopes=new Map(
Object.entries(scopeDefinitions).map(([name,kinds])=>[name,new Set(kinds)])
);
let revision=0;
const snapshot=()=>Object.freeze({
revision,
activeKinds:Object.freeze([...owners.keys()]),
owners:Object.freeze(Object.fromEntries(owners))
});
const notify=()=>{const state=snapshot();for(const listener of listeners)listener(state)};
const set=(kind,owner)=>{
const key=String(kind||'');if(!key)throw new TypeError('Interaction kind is required');
const next=owner==null||owner===false?null:String(owner),previous=owners.get(key)||null;
if(previous===next)return false;
if(next==null)owners.delete(key);else owners.set(key,next);
revision++;notify();return true;
};
const active=(scope='any')=>{
const kinds=scopes.get(scope);if(!kinds)throw new TypeError(`Unknown interaction scope: ${scope}`);
for(const kind of kinds)if(owners.has(kind))return true;
return false;
};
return Object.freeze({
set,
clear:kind=>set(kind,null),
owner:kind=>owners.get(String(kind||''))||null,
active,
snapshot,
subscribe(listener){if(typeof listener!=='function')throw new TypeError('Listener must be a function');listeners.add(listener);return()=>listeners.delete(listener)}
});
}
return Object.freeze({DEFAULT_SCOPES,createInteractionState});
});