zustand-yjs
Version:
Zustand Stores with Yjs
372 lines (329 loc) • 11.4 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var create = require('zustand');
var react = require('react');
var shallow = require('zustand/shallow');
var Y = require('yjs');
var _extends = require('@babel/runtime/helpers/extends');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n["default"] = e;
return Object.freeze(n);
}
var create__default = /*#__PURE__*/_interopDefaultLegacy(create);
var shallow__default = /*#__PURE__*/_interopDefaultLegacy(shallow);
var Y__namespace = /*#__PURE__*/_interopNamespace(Y);
var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends);
exports.YDocEnum = void 0;
(function (YDocEnum) {
YDocEnum[YDocEnum["GUID"] = 0] = "GUID";
YDocEnum[YDocEnum["DOC"] = 1] = "DOC";
YDocEnum[YDocEnum["MOUNT"] = 2] = "MOUNT";
YDocEnum[YDocEnum["UN_MOUNT"] = 3] = "UN_MOUNT";
YDocEnum[YDocEnum["USE_CNT"] = 4] = "USE_CNT";
})(exports.YDocEnum || (exports.YDocEnum = {}));
exports.ObserveEnum = void 0;
(function (ObserveEnum) {
ObserveEnum[ObserveEnum["TYPE"] = 0] = "TYPE";
ObserveEnum[ObserveEnum["OBSERVE"] = 1] = "OBSERVE";
ObserveEnum[ObserveEnum["USE_CNT"] = 2] = "USE_CNT";
})(exports.ObserveEnum || (exports.ObserveEnum = {}));
var newStartAwareness = function newStartAwareness(setAwareness) {
var startAwareness = function startAwareness(provider) {
var awareness = provider.awareness;
var updateAwareness = function updateAwareness() {
setAwareness(provider, Array.from(awareness.getStates().values()));
};
updateAwareness();
awareness.on('update', updateAwareness);
return function () {
awareness.off('update', updateAwareness);
};
};
return startAwareness;
};
var useYStore = create__default["default"](function (set, get) {
return {
yDocs: [],
yAwareness: [],
observers: [],
data: [],
update: function update(type, data) {
var dataSet = get().data;
set({
data: [].concat(dataSet.filter(function (_ref) {
var t = _ref[0];
return t !== type;
}), [[type, data]])
});
},
listenType: function listenType(type, listen) {
var observers = get().observers;
var match = observers.find(function (_ref2) {
var observer = _ref2[0];
return observer === type;
});
if (match) {
set({
observers: [].concat(observers.filter(function (obs) {
return obs !== match;
}), [[match[exports.ObserveEnum.TYPE], match[exports.ObserveEnum.OBSERVE], match[exports.ObserveEnum.USE_CNT] + 1]])
});
} else {
type.observe(listen);
set({
observers: [].concat(observers, [[type, listen, 1]])
});
}
},
unListenType: function unListenType(type) {
var observers = get().observers;
var match = observers.find(function (_ref3) {
var t = _ref3[0];
return t === type;
});
if (!match) {
console.warn('Type ', type, " wasn't mounted");
return;
}
var observerCount = match[exports.ObserveEnum.USE_CNT] - 1;
if (observerCount > 0) {
set({
observers: [].concat(observers.filter(function (obs) {
return obs !== match;
}), [[match[exports.ObserveEnum.TYPE], match[exports.ObserveEnum.OBSERVE], observerCount]])
});
} else {
type.unobserve(match[exports.ObserveEnum.OBSERVE]);
set({
observers: [].concat(observers.filter(function (obs) {
return obs !== match;
})),
data: [].concat(get().data.filter(function (_ref4) {
var t = _ref4[0];
return t !== type;
}))
});
}
},
unMountYDoc: function unMountYDoc(yDoc) {
var yDocs = get().yDocs;
var yAwareness = get().yAwareness;
var match = yDocs.find(function (_ref5) {
var doc = _ref5[1];
return doc === yDoc;
});
if (!match) {
console.warn('Can not unmount doc ', yDoc.guid, ' . Doc not found');
return;
}
var observerCount = match[exports.YDocEnum.USE_CNT] - 1;
if (observerCount > 0) {
set({
yDocs: [].concat(yDocs.filter(function (yDoc) {
return yDoc !== match;
}), [[match[exports.YDocEnum.GUID], match[exports.YDocEnum.DOC], match[exports.YDocEnum.MOUNT], match[exports.YDocEnum.UN_MOUNT], observerCount]])
});
} else {
var unMount = match[exports.YDocEnum.UN_MOUNT];
if (unMount) unMount();
set({
yDocs: yDocs.filter(function (yDoc) {
return yDoc !== match;
}),
yAwareness: yAwareness.filter(function (_ref6) {
var yDocName = _ref6[0];
return yDocName !== match[0];
})
});
}
},
mountYDoc: function mountYDoc(yDoc, mount) {
var yDocs = get().yDocs;
var yAwareness = get().yAwareness;
var match = yDocs.find(function (_ref7) {
var name = _ref7[0];
return name === yDoc.guid;
});
if (match) {
if (match[exports.YDocEnum.MOUNT] !== mount) {
console.warn('A different connection function was already provided for ', match[exports.YDocEnum.GUID], '. This unMount function will be ignored');
}
match[exports.YDocEnum.USE_CNT]++;
set({
yDocs: [].concat(yDocs.filter(function (_ref8) {
var name = _ref8[0];
return name !== yDoc.guid;
}), [match])
});
} else {
var unMount = mount(yDoc, newStartAwareness(function (protocol, changes) {
set({
yAwareness: [].concat(yAwareness, [[yDoc.guid, protocol.awareness, changes]])
});
}));
set({
yDocs: [].concat(yDocs, [[yDoc.guid, yDoc, mount, unMount, 1]])
});
}
}
};
});
var useYStore$1 = useYStore;
var useYObserve = function useYObserve(yType, serialize) {
var _useYStore = useYStore$1(function (state) {
return [state.listenType, state.unListenType, state.update];
}, shallow__default["default"]),
listen = _useYStore[0],
unListen = _useYStore[1],
update = _useYStore[2];
react.useEffect(function () {
listen(yType, function () {
return update(yType, serialize());
});
update(yType, serialize());
return function () {
return unListen(yType);
};
}, []);
};
var useYObserve$1 = useYObserve;
var useYArray = function useYArray(yArray) {
useYObserve$1(yArray, function () {
return yArray.toArray();
});
var dataSet = useYStore$1(function (state) {
return state.data;
});
var data = react.useMemo(function () {
var match = dataSet.find(function (_ref) {
var type = _ref[0];
return type === yArray;
});
if (!match) return [];
return match[1];
}, [yArray, dataSet]);
var noBinding = function noBinding(funcKey) {
return function () {
throw new Error("Y.Array#" + funcKey.toString() + " is not implemented");
};
};
return {
forEach: yArray.forEach ? yArray.forEach.bind(yArray) : noBinding('forEach'),
map: yArray.map ? yArray.map.bind(yArray) : noBinding('map'),
slice: yArray.slice ? yArray.slice.bind(yArray) : noBinding('slice'),
get: yArray.get ? yArray.get.bind(yArray) : noBinding('get'),
delete: yArray.delete ? yArray.delete.bind(yArray) : noBinding('delete'),
unshift: yArray.unshift ? yArray.unshift.bind(yArray) : noBinding('unshift'),
push: yArray.push ? yArray.push.bind(yArray) : noBinding('push'),
insert: yArray.insert ? yArray.insert.bind(yArray) : noBinding('insert'),
data: data
};
};
var useYArray$1 = useYArray;
var useYMap = function useYMap(yMap) {
useYObserve$1(yMap, function () {
return yMap.toJSON();
});
var dataSet = useYStore$1(function (state) {
return state.data;
});
var data = react.useMemo(function () {
var match = dataSet.find(function (_ref) {
var type = _ref[0];
return type === yMap;
});
if (!match) return {};
return match[1];
}, [yMap, dataSet]);
var noBinding = function noBinding(funcKey) {
return function () {
throw new Error("Y.Map#" + funcKey.toString() + " is not implemented");
};
};
return {
keys: yMap.keys ? yMap.keys.bind(yMap) : noBinding('keys'),
values: yMap.values ? yMap.values.bind(yMap) : noBinding('values'),
entries: yMap.entries ? yMap.entries.bind(yMap) : noBinding('entries'),
forEach: yMap.forEach ? yMap.forEach.bind(yMap) : noBinding('forEach'),
delete: yMap.delete ? yMap.delete.bind(yMap) : noBinding('delete'),
set: yMap.set ? yMap.set.bind(yMap) : noBinding('set'),
get: yMap.get ? yMap.get.bind(yMap) : noBinding('get'),
has: yMap.has ? yMap.has.bind(yMap) : noBinding('has'),
data: data
};
};
var useYMap$1 = useYMap;
var useYDoc = function useYDoc(name, mount) {
var _useYStore = useYStore$1(function (state) {
return [state.mountYDoc, state.unMountYDoc, state.yDocs];
}, shallow__default["default"]),
mountYDoc = _useYStore[0],
unMountYDoc = _useYStore[1],
yDocs = _useYStore[2];
var yDoc = react.useMemo(function () {
var match = yDocs.find(function (_ref) {
var docGuid = _ref[0];
return docGuid === name;
});
if (match) return match[exports.YDocEnum.DOC];
var yDoc = new Y__namespace.Doc();
yDoc.guid = name;
mountYDoc(yDoc, mount);
return yDoc;
}, [yDocs, name]);
react.useEffect(function () {
return function () {
return unMountYDoc(yDoc);
};
}, [unMountYDoc, name]);
return yDoc;
};
var useYDoc$1 = useYDoc;
var useYAwareness = function useYAwareness(yDoc) {
var matches = useYStore$1(react.useCallback(function (state) {
return state.yAwareness.filter(function (_ref) {
var guid = _ref[0];
return guid === yDoc.guid;
});
}, [yDoc.guid]));
var _useMemo = react.useMemo(function () {
if (matches.length === 0) return [[], {
error: 'Awareness not registered. Use startAwareness method from your YDoc connect function.'
}];
var _matches$ = matches[0];
_matches$[0];
var awareness = _matches$[1],
changes = _matches$[2];
return [changes, awareness];
}, [matches]),
awarenessData = _useMemo[0],
awareness = _useMemo[1];
var awarenessSetData = react.useCallback(function (newState) {
if (awareness.error) {
console.error(awareness.error);
} else {
var previousState = awareness.getLocalState();
awareness.setLocalState(_extends__default["default"]({}, previousState, newState));
}
}, [awareness]);
return [awarenessData, awarenessSetData];
};
var useYAwareness$1 = useYAwareness;
exports.useYArray = useYArray$1;
exports.useYAwareness = useYAwareness$1;
exports.useYDoc = useYDoc$1;
exports.useYMap = useYMap$1;