@manifest-editor/projects 1.0.2

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/dist/index.cjs ADDED
@@ -0,0 +1,1301 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __commonJS = (cb, mod) => function __require() {
10
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
+ var __publicField = (obj, key, value) => {
34
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
35
+ return value;
36
+ };
37
+
38
+ // ../../node_modules/.pnpm/shallowequal@1.1.0/node_modules/shallowequal/index.js
39
+ var require_shallowequal = __commonJS({
40
+ "../../node_modules/.pnpm/shallowequal@1.1.0/node_modules/shallowequal/index.js"(exports, module2) {
41
+ "use strict";
42
+ module2.exports = function shallowEqual2(objA, objB, compare, compareContext) {
43
+ var ret = compare ? compare.call(compareContext, objA, objB) : void 0;
44
+ if (ret !== void 0) {
45
+ return !!ret;
46
+ }
47
+ if (objA === objB) {
48
+ return true;
49
+ }
50
+ if (typeof objA !== "object" || !objA || typeof objB !== "object" || !objB) {
51
+ return false;
52
+ }
53
+ var keysA = Object.keys(objA);
54
+ var keysB = Object.keys(objB);
55
+ if (keysA.length !== keysB.length) {
56
+ return false;
57
+ }
58
+ var bHasOwnProperty = Object.prototype.hasOwnProperty.bind(objB);
59
+ for (var idx = 0; idx < keysA.length; idx++) {
60
+ var key = keysA[idx];
61
+ if (!bHasOwnProperty(key)) {
62
+ return false;
63
+ }
64
+ var valueA = objA[key];
65
+ var valueB = objB[key];
66
+ ret = compare ? compare.call(compareContext, valueA, valueB, key) : void 0;
67
+ if (ret === false || ret === void 0 && valueA !== valueB) {
68
+ return false;
69
+ }
70
+ }
71
+ return true;
72
+ };
73
+ }
74
+ });
75
+
76
+ // ../../node_modules/.pnpm/slugify@1.6.6/node_modules/slugify/slugify.js
77
+ var require_slugify = __commonJS({
78
+ "../../node_modules/.pnpm/slugify@1.6.6/node_modules/slugify/slugify.js"(exports, module2) {
79
+ "use strict";
80
+ (function(name, root, factory) {
81
+ if (typeof exports === "object") {
82
+ module2.exports = factory();
83
+ module2.exports["default"] = factory();
84
+ } else if (typeof define === "function" && define.amd) {
85
+ define(factory);
86
+ } else {
87
+ root[name] = factory();
88
+ }
89
+ })("slugify", exports, function() {
90
+ var charMap = JSON.parse(`{"$":"dollar","%":"percent","&":"and","<":"less",">":"greater","|":"or","\xA2":"cent","\xA3":"pound","\xA4":"currency","\xA5":"yen","\xA9":"(c)","\xAA":"a","\xAE":"(r)","\xBA":"o","\xC0":"A","\xC1":"A","\xC2":"A","\xC3":"A","\xC4":"A","\xC5":"A","\xC6":"AE","\xC7":"C","\xC8":"E","\xC9":"E","\xCA":"E","\xCB":"E","\xCC":"I","\xCD":"I","\xCE":"I","\xCF":"I","\xD0":"D","\xD1":"N","\xD2":"O","\xD3":"O","\xD4":"O","\xD5":"O","\xD6":"O","\xD8":"O","\xD9":"U","\xDA":"U","\xDB":"U","\xDC":"U","\xDD":"Y","\xDE":"TH","\xDF":"ss","\xE0":"a","\xE1":"a","\xE2":"a","\xE3":"a","\xE4":"a","\xE5":"a","\xE6":"ae","\xE7":"c","\xE8":"e","\xE9":"e","\xEA":"e","\xEB":"e","\xEC":"i","\xED":"i","\xEE":"i","\xEF":"i","\xF0":"d","\xF1":"n","\xF2":"o","\xF3":"o","\xF4":"o","\xF5":"o","\xF6":"o","\xF8":"o","\xF9":"u","\xFA":"u","\xFB":"u","\xFC":"u","\xFD":"y","\xFE":"th","\xFF":"y","\u0100":"A","\u0101":"a","\u0102":"A","\u0103":"a","\u0104":"A","\u0105":"a","\u0106":"C","\u0107":"c","\u010C":"C","\u010D":"c","\u010E":"D","\u010F":"d","\u0110":"DJ","\u0111":"dj","\u0112":"E","\u0113":"e","\u0116":"E","\u0117":"e","\u0118":"e","\u0119":"e","\u011A":"E","\u011B":"e","\u011E":"G","\u011F":"g","\u0122":"G","\u0123":"g","\u0128":"I","\u0129":"i","\u012A":"i","\u012B":"i","\u012E":"I","\u012F":"i","\u0130":"I","\u0131":"i","\u0136":"k","\u0137":"k","\u013B":"L","\u013C":"l","\u013D":"L","\u013E":"l","\u0141":"L","\u0142":"l","\u0143":"N","\u0144":"n","\u0145":"N","\u0146":"n","\u0147":"N","\u0148":"n","\u014C":"O","\u014D":"o","\u0150":"O","\u0151":"o","\u0152":"OE","\u0153":"oe","\u0154":"R","\u0155":"r","\u0158":"R","\u0159":"r","\u015A":"S","\u015B":"s","\u015E":"S","\u015F":"s","\u0160":"S","\u0161":"s","\u0162":"T","\u0163":"t","\u0164":"T","\u0165":"t","\u0168":"U","\u0169":"u","\u016A":"u","\u016B":"u","\u016E":"U","\u016F":"u","\u0170":"U","\u0171":"u","\u0172":"U","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017A":"z","\u017B":"Z","\u017C":"z","\u017D":"Z","\u017E":"z","\u018F":"E","\u0192":"f","\u01A0":"O","\u01A1":"o","\u01AF":"U","\u01B0":"u","\u01C8":"LJ","\u01C9":"lj","\u01CB":"NJ","\u01CC":"nj","\u0218":"S","\u0219":"s","\u021A":"T","\u021B":"t","\u0259":"e","\u02DA":"o","\u0386":"A","\u0388":"E","\u0389":"H","\u038A":"I","\u038C":"O","\u038E":"Y","\u038F":"W","\u0390":"i","\u0391":"A","\u0392":"B","\u0393":"G","\u0394":"D","\u0395":"E","\u0396":"Z","\u0397":"H","\u0398":"8","\u0399":"I","\u039A":"K","\u039B":"L","\u039C":"M","\u039D":"N","\u039E":"3","\u039F":"O","\u03A0":"P","\u03A1":"R","\u03A3":"S","\u03A4":"T","\u03A5":"Y","\u03A6":"F","\u03A7":"X","\u03A8":"PS","\u03A9":"W","\u03AA":"I","\u03AB":"Y","\u03AC":"a","\u03AD":"e","\u03AE":"h","\u03AF":"i","\u03B0":"y","\u03B1":"a","\u03B2":"b","\u03B3":"g","\u03B4":"d","\u03B5":"e","\u03B6":"z","\u03B7":"h","\u03B8":"8","\u03B9":"i","\u03BA":"k","\u03BB":"l","\u03BC":"m","\u03BD":"n","\u03BE":"3","\u03BF":"o","\u03C0":"p","\u03C1":"r","\u03C2":"s","\u03C3":"s","\u03C4":"t","\u03C5":"y","\u03C6":"f","\u03C7":"x","\u03C8":"ps","\u03C9":"w","\u03CA":"i","\u03CB":"y","\u03CC":"o","\u03CD":"y","\u03CE":"w","\u0401":"Yo","\u0402":"DJ","\u0404":"Ye","\u0406":"I","\u0407":"Yi","\u0408":"J","\u0409":"LJ","\u040A":"NJ","\u040B":"C","\u040F":"DZ","\u0410":"A","\u0411":"B","\u0412":"V","\u0413":"G","\u0414":"D","\u0415":"E","\u0416":"Zh","\u0417":"Z","\u0418":"I","\u0419":"J","\u041A":"K","\u041B":"L","\u041C":"M","\u041D":"N","\u041E":"O","\u041F":"P","\u0420":"R","\u0421":"S","\u0422":"T","\u0423":"U","\u0424":"F","\u0425":"H","\u0426":"C","\u0427":"Ch","\u0428":"Sh","\u0429":"Sh","\u042A":"U","\u042B":"Y","\u042C":"","\u042D":"E","\u042E":"Yu","\u042F":"Ya","\u0430":"a","\u0431":"b","\u0432":"v","\u0433":"g","\u0434":"d","\u0435":"e","\u0436":"zh","\u0437":"z","\u0438":"i","\u0439":"j","\u043A":"k","\u043B":"l","\u043C":"m","\u043D":"n","\u043E":"o","\u043F":"p","\u0440":"r","\u0441":"s","\u0442":"t","\u0443":"u","\u0444":"f","\u0445":"h","\u0446":"c","\u0447":"ch","\u0448":"sh","\u0449":"sh","\u044A":"u","\u044B":"y","\u044C":"","\u044D":"e","\u044E":"yu","\u044F":"ya","\u0451":"yo","\u0452":"dj","\u0454":"ye","\u0456":"i","\u0457":"yi","\u0458":"j","\u0459":"lj","\u045A":"nj","\u045B":"c","\u045D":"u","\u045F":"dz","\u0490":"G","\u0491":"g","\u0492":"GH","\u0493":"gh","\u049A":"KH","\u049B":"kh","\u04A2":"NG","\u04A3":"ng","\u04AE":"UE","\u04AF":"ue","\u04B0":"U","\u04B1":"u","\u04BA":"H","\u04BB":"h","\u04D8":"AE","\u04D9":"ae","\u04E8":"OE","\u04E9":"oe","\u0531":"A","\u0532":"B","\u0533":"G","\u0534":"D","\u0535":"E","\u0536":"Z","\u0537":"E'","\u0538":"Y'","\u0539":"T'","\u053A":"JH","\u053B":"I","\u053C":"L","\u053D":"X","\u053E":"C'","\u053F":"K","\u0540":"H","\u0541":"D'","\u0542":"GH","\u0543":"TW","\u0544":"M","\u0545":"Y","\u0546":"N","\u0547":"SH","\u0549":"CH","\u054A":"P","\u054B":"J","\u054C":"R'","\u054D":"S","\u054E":"V","\u054F":"T","\u0550":"R","\u0551":"C","\u0553":"P'","\u0554":"Q'","\u0555":"O''","\u0556":"F","\u0587":"EV","\u0621":"a","\u0622":"aa","\u0623":"a","\u0624":"u","\u0625":"i","\u0626":"e","\u0627":"a","\u0628":"b","\u0629":"h","\u062A":"t","\u062B":"th","\u062C":"j","\u062D":"h","\u062E":"kh","\u062F":"d","\u0630":"th","\u0631":"r","\u0632":"z","\u0633":"s","\u0634":"sh","\u0635":"s","\u0636":"dh","\u0637":"t","\u0638":"z","\u0639":"a","\u063A":"gh","\u0641":"f","\u0642":"q","\u0643":"k","\u0644":"l","\u0645":"m","\u0646":"n","\u0647":"h","\u0648":"w","\u0649":"a","\u064A":"y","\u064B":"an","\u064C":"on","\u064D":"en","\u064E":"a","\u064F":"u","\u0650":"e","\u0652":"","\u0660":"0","\u0661":"1","\u0662":"2","\u0663":"3","\u0664":"4","\u0665":"5","\u0666":"6","\u0667":"7","\u0668":"8","\u0669":"9","\u067E":"p","\u0686":"ch","\u0698":"zh","\u06A9":"k","\u06AF":"g","\u06CC":"y","\u06F0":"0","\u06F1":"1","\u06F2":"2","\u06F3":"3","\u06F4":"4","\u06F5":"5","\u06F6":"6","\u06F7":"7","\u06F8":"8","\u06F9":"9","\u0E3F":"baht","\u10D0":"a","\u10D1":"b","\u10D2":"g","\u10D3":"d","\u10D4":"e","\u10D5":"v","\u10D6":"z","\u10D7":"t","\u10D8":"i","\u10D9":"k","\u10DA":"l","\u10DB":"m","\u10DC":"n","\u10DD":"o","\u10DE":"p","\u10DF":"zh","\u10E0":"r","\u10E1":"s","\u10E2":"t","\u10E3":"u","\u10E4":"f","\u10E5":"k","\u10E6":"gh","\u10E7":"q","\u10E8":"sh","\u10E9":"ch","\u10EA":"ts","\u10EB":"dz","\u10EC":"ts","\u10ED":"ch","\u10EE":"kh","\u10EF":"j","\u10F0":"h","\u1E62":"S","\u1E63":"s","\u1E80":"W","\u1E81":"w","\u1E82":"W","\u1E83":"w","\u1E84":"W","\u1E85":"w","\u1E9E":"SS","\u1EA0":"A","\u1EA1":"a","\u1EA2":"A","\u1EA3":"a","\u1EA4":"A","\u1EA5":"a","\u1EA6":"A","\u1EA7":"a","\u1EA8":"A","\u1EA9":"a","\u1EAA":"A","\u1EAB":"a","\u1EAC":"A","\u1EAD":"a","\u1EAE":"A","\u1EAF":"a","\u1EB0":"A","\u1EB1":"a","\u1EB2":"A","\u1EB3":"a","\u1EB4":"A","\u1EB5":"a","\u1EB6":"A","\u1EB7":"a","\u1EB8":"E","\u1EB9":"e","\u1EBA":"E","\u1EBB":"e","\u1EBC":"E","\u1EBD":"e","\u1EBE":"E","\u1EBF":"e","\u1EC0":"E","\u1EC1":"e","\u1EC2":"E","\u1EC3":"e","\u1EC4":"E","\u1EC5":"e","\u1EC6":"E","\u1EC7":"e","\u1EC8":"I","\u1EC9":"i","\u1ECA":"I","\u1ECB":"i","\u1ECC":"O","\u1ECD":"o","\u1ECE":"O","\u1ECF":"o","\u1ED0":"O","\u1ED1":"o","\u1ED2":"O","\u1ED3":"o","\u1ED4":"O","\u1ED5":"o","\u1ED6":"O","\u1ED7":"o","\u1ED8":"O","\u1ED9":"o","\u1EDA":"O","\u1EDB":"o","\u1EDC":"O","\u1EDD":"o","\u1EDE":"O","\u1EDF":"o","\u1EE0":"O","\u1EE1":"o","\u1EE2":"O","\u1EE3":"o","\u1EE4":"U","\u1EE5":"u","\u1EE6":"U","\u1EE7":"u","\u1EE8":"U","\u1EE9":"u","\u1EEA":"U","\u1EEB":"u","\u1EEC":"U","\u1EED":"u","\u1EEE":"U","\u1EEF":"u","\u1EF0":"U","\u1EF1":"u","\u1EF2":"Y","\u1EF3":"y","\u1EF4":"Y","\u1EF5":"y","\u1EF6":"Y","\u1EF7":"y","\u1EF8":"Y","\u1EF9":"y","\u2013":"-","\u2018":"'","\u2019":"'","\u201C":"\\"","\u201D":"\\"","\u201E":"\\"","\u2020":"+","\u2022":"*","\u2026":"...","\u20A0":"ecu","\u20A2":"cruzeiro","\u20A3":"french franc","\u20A4":"lira","\u20A5":"mill","\u20A6":"naira","\u20A7":"peseta","\u20A8":"rupee","\u20A9":"won","\u20AA":"new shequel","\u20AB":"dong","\u20AC":"euro","\u20AD":"kip","\u20AE":"tugrik","\u20AF":"drachma","\u20B0":"penny","\u20B1":"peso","\u20B2":"guarani","\u20B3":"austral","\u20B4":"hryvnia","\u20B5":"cedi","\u20B8":"kazakhstani tenge","\u20B9":"indian rupee","\u20BA":"turkish lira","\u20BD":"russian ruble","\u20BF":"bitcoin","\u2120":"sm","\u2122":"tm","\u2202":"d","\u2206":"delta","\u2211":"sum","\u221E":"infinity","\u2665":"love","\u5143":"yuan","\u5186":"yen","\uFDFC":"rial","\uFEF5":"laa","\uFEF7":"laa","\uFEF9":"lai","\uFEFB":"la"}`);
91
+ var locales = JSON.parse('{"bg":{"\u0419":"Y","\u0426":"Ts","\u0429":"Sht","\u042A":"A","\u042C":"Y","\u0439":"y","\u0446":"ts","\u0449":"sht","\u044A":"a","\u044C":"y"},"de":{"\xC4":"AE","\xE4":"ae","\xD6":"OE","\xF6":"oe","\xDC":"UE","\xFC":"ue","\xDF":"ss","%":"prozent","&":"und","|":"oder","\u2211":"summe","\u221E":"unendlich","\u2665":"liebe"},"es":{"%":"por ciento","&":"y","<":"menor que",">":"mayor que","|":"o","\xA2":"centavos","\xA3":"libras","\xA4":"moneda","\u20A3":"francos","\u2211":"suma","\u221E":"infinito","\u2665":"amor"},"fr":{"%":"pourcent","&":"et","<":"plus petit",">":"plus grand","|":"ou","\xA2":"centime","\xA3":"livre","\xA4":"devise","\u20A3":"franc","\u2211":"somme","\u221E":"infini","\u2665":"amour"},"pt":{"%":"porcento","&":"e","<":"menor",">":"maior","|":"ou","\xA2":"centavo","\u2211":"soma","\xA3":"libra","\u221E":"infinito","\u2665":"amor"},"uk":{"\u0418":"Y","\u0438":"y","\u0419":"Y","\u0439":"y","\u0426":"Ts","\u0446":"ts","\u0425":"Kh","\u0445":"kh","\u0429":"Shch","\u0449":"shch","\u0413":"H","\u0433":"h"},"vi":{"\u0110":"D","\u0111":"d"},"da":{"\xD8":"OE","\xF8":"oe","\xC5":"AA","\xE5":"aa","%":"procent","&":"og","|":"eller","$":"dollar","<":"mindre end",">":"st\xF8rre end"},"nb":{"&":"og","\xC5":"AA","\xC6":"AE","\xD8":"OE","\xE5":"aa","\xE6":"ae","\xF8":"oe"},"it":{"&":"e"},"nl":{"&":"en"},"sv":{"&":"och","\xC5":"AA","\xC4":"AE","\xD6":"OE","\xE5":"aa","\xE4":"ae","\xF6":"oe"}}');
92
+ function replace(string, options) {
93
+ if (typeof string !== "string") {
94
+ throw new Error("slugify: string argument expected");
95
+ }
96
+ options = typeof options === "string" ? { replacement: options } : options || {};
97
+ var locale = locales[options.locale] || {};
98
+ var replacement = options.replacement === void 0 ? "-" : options.replacement;
99
+ var trim = options.trim === void 0 ? true : options.trim;
100
+ var slug = string.normalize().split("").reduce(function(result, ch) {
101
+ var appendChar = locale[ch];
102
+ if (appendChar === void 0)
103
+ appendChar = charMap[ch];
104
+ if (appendChar === void 0)
105
+ appendChar = ch;
106
+ if (appendChar === replacement)
107
+ appendChar = " ";
108
+ return result + appendChar.replace(options.remove || /[^\w\s$*_+~.()'"!\-:@]+/g, "");
109
+ }, "");
110
+ if (options.strict) {
111
+ slug = slug.replace(/[^A-Za-z0-9\s]/g, "");
112
+ }
113
+ if (trim) {
114
+ slug = slug.trim();
115
+ }
116
+ slug = slug.replace(/\s+/g, replacement);
117
+ if (options.lower) {
118
+ slug = slug.toLowerCase();
119
+ }
120
+ return slug;
121
+ }
122
+ replace.extend = function(customMap) {
123
+ Object.assign(charMap, customMap);
124
+ };
125
+ return replace;
126
+ });
127
+ }
128
+ });
129
+
130
+ // src/index.ts
131
+ var src_exports = {};
132
+ __export(src_exports, {
133
+ AppMenu: () => AppMenu,
134
+ Draft: () => Draft,
135
+ DraftTitle: () => DraftTitle,
136
+ DraftTitleEdit: () => DraftTitleEdit,
137
+ DraftTitleEditButton: () => DraftTitleEditButton,
138
+ DraftTitleEditInput: () => DraftTitleEditInput,
139
+ DraftTitleEditor: () => DraftTitleEditor,
140
+ DraftsText: () => DraftsText,
141
+ IconButton: () => IconButton,
142
+ ProjectLoadingReactContext: () => ProjectLoadingReactContext,
143
+ ProjectProvider: () => ProjectProvider,
144
+ ProjectReactContext: () => ProjectReactContext,
145
+ useCurrentProject: () => useCurrentProject,
146
+ useOptionalCurrentProject: () => useOptionalCurrentProject,
147
+ useProjectActionsWithBackend: () => useProjectActionsWithBackend,
148
+ useProjectBackend: () => useProjectBackend,
149
+ useProjectContext: () => useProjectContext,
150
+ useProjectCreators: () => useProjectCreators,
151
+ useProjectLoader: () => useProjectLoader,
152
+ useProjectLoading: () => useProjectLoading
153
+ });
154
+ module.exports = __toCommonJS(src_exports);
155
+
156
+ // src/ProjectContext.tsx
157
+ var import_react = require("react");
158
+
159
+ // ../../node_modules/.pnpm/tiny-invariant@1.3.3/node_modules/tiny-invariant/dist/esm/tiny-invariant.js
160
+ var isProduction = false;
161
+ var prefix = "Invariant failed";
162
+ function invariant(condition, message) {
163
+ if (condition) {
164
+ return;
165
+ }
166
+ if (isProduction) {
167
+ throw new Error(prefix);
168
+ }
169
+ var provided = typeof message === "function" ? message() : message;
170
+ var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
171
+ throw new Error(value);
172
+ }
173
+
174
+ // src/ProjectContext.tsx
175
+ var ProjectReactContext = (0, import_react.createContext)(null);
176
+ var ProjectLoadingReactContext = (0, import_react.createContext)({
177
+ error: void 0,
178
+ isError: false,
179
+ isLoading: false
180
+ });
181
+ function useProjectLoading() {
182
+ return (0, import_react.useContext)(ProjectLoadingReactContext);
183
+ }
184
+ function useProjectContext() {
185
+ const ctx = (0, import_react.useContext)(ProjectReactContext);
186
+ invariant(ctx, "useProjectContext can only be called from inside <ProjectProvider />");
187
+ return ctx;
188
+ }
189
+ function useCurrentProject() {
190
+ const current = useProjectContext().current;
191
+ invariant(current, "No current project");
192
+ return current;
193
+ }
194
+ function useOptionalCurrentProject() {
195
+ const current = useProjectContext().current;
196
+ return current || null;
197
+ }
198
+
199
+ // src/ProjectContext.hooks.ts
200
+ var import_react2 = require("react");
201
+ var import_shallowequal = __toESM(require_shallowequal(), 1);
202
+ var import_tiny_use_debounce = require("tiny-use-debounce");
203
+
204
+ // src/helpers/project-from-manifest.ts
205
+ var import_helpers = require("@iiif/helpers");
206
+ var import_slugify = __toESM(require_slugify(), 1);
207
+ function randomId() {
208
+ return `${Math.random().toString(36).substr(2)}-${Date.now().toString(36)}`;
209
+ }
210
+ function projectFromManifest(manifest, details = {}) {
211
+ const name = (0, import_helpers.getValue)(manifest.label) || "Untitled manifest";
212
+ return {
213
+ id: `manifest-editor://project/${randomId()}`,
214
+ filename: (0, import_slugify.default)(name, { lower: true }),
215
+ name,
216
+ metadata: {
217
+ created: Date.now(),
218
+ modified: Date.now()
219
+ },
220
+ resource: {
221
+ id: manifest.id,
222
+ type: "Manifest"
223
+ },
224
+ publications: [],
225
+ previews: [],
226
+ settings: {},
227
+ storage: {
228
+ type: "manifest-storage",
229
+ data: manifest
230
+ },
231
+ ...details
232
+ };
233
+ }
234
+
235
+ // src/ProjectContext.hooks.ts
236
+ var import_presentation_2 = require("@iiif/parser/presentation-2");
237
+
238
+ // src/helpers/ensure-unique-filename.ts
239
+ var import_slugify2 = __toESM(require_slugify(), 1);
240
+ function ensureUniqueFilename(project, existing) {
241
+ const filenames = existing.map((project2) => project2.filename);
242
+ const name = (project.name || project.filename || "Untitled project").toLowerCase();
243
+ if (project.filename && filenames.indexOf(project.filename) !== -1) {
244
+ project.filename = void 0;
245
+ }
246
+ if (!project.filename) {
247
+ let counter = 0;
248
+ while (!project.filename) {
249
+ const potentialFilename = `${(0, import_slugify2.default)(name, { lower: true })}${counter ? ` (${counter})` : ""}`;
250
+ if (filenames.indexOf(potentialFilename) === -1) {
251
+ project.filename = potentialFilename;
252
+ project.name = `${project.name} (${counter})`;
253
+ break;
254
+ }
255
+ counter++;
256
+ }
257
+ }
258
+ }
259
+
260
+ // src/helpers/project-from-collection.ts
261
+ var import_helpers2 = require("@iiif/helpers");
262
+ var import_slugify3 = __toESM(require_slugify(), 1);
263
+
264
+ // src/helpers/random-id.ts
265
+ function randomId2() {
266
+ return `${Math.random().toString(36).substr(2)}-${Date.now().toString(36)}`;
267
+ }
268
+
269
+ // src/helpers/project-from-collection.ts
270
+ function projectFromCollection(collection, details = {}) {
271
+ const name = (0, import_helpers2.getValue)(collection.label) || "Untitled collection";
272
+ return {
273
+ id: `manifest-editor://project/${randomId2()}`,
274
+ filename: (0, import_slugify3.default)(name, { lower: true }),
275
+ name,
276
+ metadata: {
277
+ created: Date.now(),
278
+ modified: Date.now()
279
+ },
280
+ resource: {
281
+ id: collection.id,
282
+ type: "Collection"
283
+ },
284
+ publications: [],
285
+ previews: [],
286
+ settings: {},
287
+ storage: {
288
+ type: "collection-storage",
289
+ data: collection
290
+ },
291
+ ...details
292
+ };
293
+ }
294
+
295
+ // src/ProjectContext.hooks.ts
296
+ var import_client_vault = require("@manifest-editor/client-vault");
297
+ var import_shell = require("@manifest-editor/shell");
298
+ function useProjectActionsWithBackend(dispatch, backend, storage) {
299
+ async function createProject(payload) {
300
+ const allProjects = await backend.getAllProjects(true);
301
+ const project = { ...payload };
302
+ ensureUniqueFilename(project, allProjects);
303
+ if (!storage.canCreate()) {
304
+ throw new Error("Cannot create project with this storage backend");
305
+ }
306
+ const backendStorage = await storage.create(project, project.storage.data);
307
+ const createdProject = { ...project, storage: backendStorage };
308
+ await backend.createProject(createdProject);
309
+ dispatch({ type: "createProject", payload: createdProject });
310
+ switchProject(project.id);
311
+ }
312
+ function deleteProject(payload) {
313
+ if (backend.canDelete()) {
314
+ dispatch({ type: "deleteProject", payload });
315
+ backend.deleteProject(payload).then(() => {
316
+ console.log("Loader: project deleted");
317
+ });
318
+ }
319
+ }
320
+ function switchProject(payload) {
321
+ dispatch({ type: "switchProject", payload });
322
+ backend.setLastProject(payload).then(() => {
323
+ });
324
+ }
325
+ function deselectProject(payload) {
326
+ dispatch({ type: "deselectProject", payload });
327
+ }
328
+ function forkProject(payload) {
329
+ dispatch({ type: "forkProject", payload });
330
+ throw new Error("Not implemented yet");
331
+ }
332
+ function setLoadingStatus(payload) {
333
+ dispatch({ type: "setLoadingStatus", payload });
334
+ }
335
+ function saveProject(project) {
336
+ console.log("trying to save project...");
337
+ dispatch({ type: "saveProject", payload: project });
338
+ Promise.all([
339
+ //
340
+ backend.updateProject(project),
341
+ storage.saveStorage(project.storage)
342
+ ]).then(() => {
343
+ console.log("Loader: project saved");
344
+ });
345
+ }
346
+ function updateDetails(payload) {
347
+ dispatch({ type: "updateDetails", payload });
348
+ }
349
+ function createPublication(payload) {
350
+ dispatch({ type: "createPublication", payload });
351
+ }
352
+ function updatePublication(payload) {
353
+ dispatch({ type: "updatePublication", payload });
354
+ }
355
+ function removePublication(payload) {
356
+ dispatch({ type: "removePublication", payload });
357
+ }
358
+ function updateSettings(payload) {
359
+ dispatch({ type: "updateSettings", payload });
360
+ }
361
+ function updateThumbnail(payload) {
362
+ dispatch({ type: "updateThumbnail", payload });
363
+ }
364
+ function updateStorage(payload) {
365
+ dispatch({ type: "updateStorage", payload });
366
+ }
367
+ function load(payload) {
368
+ dispatch({ type: "load", payload });
369
+ }
370
+ function setPreview(publication) {
371
+ dispatch({ type: "setPreview", payload: publication });
372
+ }
373
+ function removePreview(id) {
374
+ dispatch({ type: "removePreview", payload: id });
375
+ }
376
+ return (0, import_react2.useMemo)(
377
+ () => ({
378
+ createProject,
379
+ deleteProject,
380
+ switchProject,
381
+ deselectProject,
382
+ forkProject,
383
+ saveProject,
384
+ setLoadingStatus,
385
+ load,
386
+ updateDetails,
387
+ createPublication,
388
+ updatePublication,
389
+ removePublication,
390
+ updateSettings,
391
+ updateThumbnail,
392
+ updateStorage,
393
+ setPreview,
394
+ removePreview
395
+ }),
396
+ // Dispatch always stable.
397
+ // eslint-disable-next-line react-hooks/exhaustive-deps
398
+ []
399
+ );
400
+ }
401
+ function useProjectBackend({ actions, current }, backend) {
402
+ (0, import_react2.useEffect)(() => {
403
+ actions.setLoadingStatus({ loading: true, lastLoaded: 0, loaded: false });
404
+ backend.getAllProjects().then(async (allProjects) => {
405
+ const lastId = await backend.getLastProject();
406
+ const lastValid = allProjects.find((s) => s.id === lastId);
407
+ actions.load({
408
+ allProjects,
409
+ current: lastValid || null,
410
+ loadingStatus: {
411
+ loaded: true,
412
+ loading: false,
413
+ lastLoaded: Date.now()
414
+ }
415
+ });
416
+ });
417
+ }, []);
418
+ }
419
+ function useProjectLoader({ actions, current }, storage) {
420
+ const currentRef = (0, import_react2.useRef)(null);
421
+ const [ready, setIsReady] = (0, import_react2.useState)(false);
422
+ const [error, setError] = (0, import_react2.useState)("");
423
+ const saveChanges = (0, import_react2.useCallback)(() => {
424
+ const project = currentRef.current;
425
+ if (project) {
426
+ storage.saveStorage(project.storage).then(() => {
427
+ const newStorage = storage.getBackendStorage(project);
428
+ if (!(0, import_shallowequal.default)(newStorage, project.storage)) {
429
+ actions.saveProject({
430
+ ...project,
431
+ storage: newStorage
432
+ });
433
+ }
434
+ });
435
+ }
436
+ }, [actions, storage]);
437
+ const debounceSaveChanges = (0, import_tiny_use_debounce.useDebounce)(saveChanges, storage.saveInterval);
438
+ const currentId = current?.id;
439
+ (0, import_react2.useEffect)(() => {
440
+ currentRef.current = current;
441
+ }, [current]);
442
+ const { vault, promise } = (0, import_react2.useMemo)(() => {
443
+ if (current) {
444
+ const [vault2, promise2] = storage.createVaultInstance(current);
445
+ return {
446
+ vault: vault2,
447
+ promise: promise2
448
+ };
449
+ }
450
+ return { vault: null, promise: null };
451
+ }, [storage, currentId]);
452
+ (0, import_react2.useEffect)(() => {
453
+ const currentStorage = storage;
454
+ const currentProject = current;
455
+ const currentVault = vault;
456
+ return () => {
457
+ if (currentVault && currentProject) {
458
+ currentStorage.closeVaultInstance(currentProject, currentVault);
459
+ } else if (currentVault instanceof import_client_vault.ClientVault) {
460
+ currentVault.ws.close();
461
+ }
462
+ };
463
+ }, [storage, current, vault]);
464
+ (0, import_react2.useEffect)(() => {
465
+ setIsReady(false);
466
+ let cancelled = false;
467
+ if (promise) {
468
+ promise.then(() => {
469
+ if (!cancelled) {
470
+ setIsReady(true);
471
+ }
472
+ }).catch((e) => {
473
+ setError(e.message);
474
+ });
475
+ }
476
+ return () => {
477
+ cancelled = true;
478
+ };
479
+ }, [promise]);
480
+ (0, import_react2.useEffect)(() => {
481
+ window.addEventListener("beforeunload", saveChanges, false);
482
+ return () => {
483
+ window.removeEventListener("beforeunload", saveChanges);
484
+ };
485
+ }, [saveChanges]);
486
+ (0, import_react2.useEffect)(() => {
487
+ return () => {
488
+ saveChanges();
489
+ };
490
+ }, [saveChanges, currentId]);
491
+ (0, import_react2.useEffect)(() => {
492
+ if (vault && storage.shouldUpdateWithVault()) {
493
+ return vault.subscribe(debounceSaveChanges, true);
494
+ }
495
+ }, [debounceSaveChanges, storage, vault]);
496
+ return {
497
+ vault,
498
+ ready,
499
+ error
500
+ };
501
+ }
502
+ function useProjectCreators() {
503
+ const { actions } = useProjectContext();
504
+ const createBlankManifest = (0, import_react2.useCallback)(function createBlankManifest2() {
505
+ actions.createProject(
506
+ projectFromManifest({
507
+ "@context": "http://iiif.io/api/presentation/3/context.json",
508
+ id: `https://example.org/${randomId2()}`,
509
+ type: "Manifest",
510
+ label: {
511
+ en: ["Blank Manifest"]
512
+ },
513
+ items: []
514
+ })
515
+ );
516
+ }, []);
517
+ const createProjectFromManifestId = (0, import_react2.useCallback)(
518
+ async function createProjectFromManifestId2(id) {
519
+ let full = await (0, import_shell.getManifestNomalized)(id);
520
+ if (full) {
521
+ if (full["@id"]) {
522
+ full = (0, import_presentation_2.convertPresentation2)(full);
523
+ }
524
+ if (full) {
525
+ actions.createProject(projectFromManifest(full));
526
+ }
527
+ }
528
+ },
529
+ // Actions are stable.
530
+ // eslint-disable-next-line react-hooks/exhaustive-deps
531
+ []
532
+ );
533
+ const createProjectFromCollectionId = (0, import_react2.useCallback)(
534
+ async function createProjectFromCollectionId2(id) {
535
+ let full = await (0, import_shell.getManifestNomalized)(id);
536
+ if (full) {
537
+ if (full["@id"]) {
538
+ full = (0, import_presentation_2.convertPresentation2)(full);
539
+ }
540
+ if (full) {
541
+ actions.createProject(projectFromCollection(full));
542
+ }
543
+ }
544
+ },
545
+ // Actions are stable.
546
+ // eslint-disable-next-line react-hooks/exhaustive-deps
547
+ []
548
+ );
549
+ const createProjectFromManifestJson = (0, import_react2.useCallback)(
550
+ async function createProjectFromManifestId2(json) {
551
+ let full = JSON.parse(json);
552
+ if (full) {
553
+ if (full["@id"]) {
554
+ full = (0, import_presentation_2.convertPresentation2)(full);
555
+ }
556
+ if (full) {
557
+ actions.createProject(projectFromManifest(full));
558
+ }
559
+ }
560
+ },
561
+ // Actions are stable.
562
+ // eslint-disable-next-line react-hooks/exhaustive-deps
563
+ []
564
+ );
565
+ return {
566
+ createProjectFromManifestJson,
567
+ createProjectFromManifestId,
568
+ createProjectFromCollectionId,
569
+ createBlankManifest
570
+ };
571
+ }
572
+
573
+ // src/ProjectContext.internal.tsx
574
+ var import_react3 = require("react");
575
+ var import_shell2 = require("@manifest-editor/shell");
576
+
577
+ // src/ProjectContext.reducer.ts
578
+ var import_immer = require("immer");
579
+ var projectContextReducer = (0, import_immer.produce)(function projectContextReducer2(state, action) {
580
+ if (state.current) {
581
+ switch (action.type) {
582
+ case "removePublication":
583
+ state.current.publications = state.current.publications.filter((p) => p.id !== action.payload);
584
+ break;
585
+ case "saveProject":
586
+ state.current.metadata.modified = Date.now();
587
+ break;
588
+ case "updateDetails":
589
+ state.current.name = action.payload.name;
590
+ state.current.filename = action.payload.filename;
591
+ break;
592
+ case "updateStorage":
593
+ state.current.storage = action.payload;
594
+ break;
595
+ case "createPublication": {
596
+ if (!state.current.publications.find((s) => s.id === action.payload.id)) {
597
+ state.current.publications.push(action.payload);
598
+ }
599
+ break;
600
+ }
601
+ case "updateThumbnail":
602
+ state.current.thumbnail = action.payload;
603
+ break;
604
+ case "updateSettings":
605
+ state.current.settings = action.payload;
606
+ break;
607
+ case "updatePublication": {
608
+ const found = state.current.publications.find((s) => s.id === action.payload.id);
609
+ if (found) {
610
+ found.config = action.payload.config;
611
+ }
612
+ break;
613
+ }
614
+ case "removePreview": {
615
+ const existing = state.current.previews?.findIndex((p) => p.id === action.payload);
616
+ if (existing !== -1) {
617
+ state.current.previews.splice(existing, 1);
618
+ }
619
+ break;
620
+ }
621
+ case "setPreview": {
622
+ const existing = state.current.previews?.findIndex((p) => p.id === action.payload.id);
623
+ if (existing !== -1) {
624
+ state.current.previews.splice(existing, 1, action.payload);
625
+ } else {
626
+ state.current.previews.push(action.payload);
627
+ }
628
+ break;
629
+ }
630
+ }
631
+ }
632
+ switch (action.type) {
633
+ case "load": {
634
+ state.allProjects = action.payload.allProjects;
635
+ state.current = action.payload.current;
636
+ state.loadingStatus = action.payload.loadingStatus;
637
+ break;
638
+ }
639
+ case "forkProject":
640
+ break;
641
+ case "deleteProject":
642
+ state.allProjects = state.allProjects.filter((p) => p.id !== action.payload);
643
+ if (state.current && state.current.id === action.payload) {
644
+ state.current = null;
645
+ }
646
+ break;
647
+ case "deselectProject":
648
+ state.current = null;
649
+ break;
650
+ case "createProject":
651
+ state.allProjects.push(action.payload);
652
+ state.current = action.payload;
653
+ break;
654
+ case "switchProject":
655
+ state.current = state.allProjects.find((p) => p.id === action.payload) || null;
656
+ break;
657
+ case "setLoadingStatus":
658
+ state.loadingStatus = action.payload;
659
+ break;
660
+ }
661
+ });
662
+ function getDefaultProjectContextState(status = {
663
+ loading: false,
664
+ loaded: true,
665
+ lastLoaded: 0
666
+ }) {
667
+ return {
668
+ allProjects: [],
669
+ current: null,
670
+ loadingStatus: status
671
+ };
672
+ }
673
+
674
+ // src/backend/LocalStorageBackend.ts
675
+ var localforage = __toESM(require("localforage"), 1);
676
+ var LocalStorageBackend = class {
677
+ constructor(settings) {
678
+ __publicField(this, "namespace");
679
+ __publicField(this, "saveInterval");
680
+ __publicField(this, "storage");
681
+ this.namespace = settings?.namespace || "default-v1.1";
682
+ this.saveInterval = 5e3;
683
+ this.storage = localforage.createInstance({
684
+ name: "manifest-editor-projects"
685
+ });
686
+ }
687
+ async deleteProject(id) {
688
+ await this.storage.removeItem(`${this.namespace}/projects/${id}`);
689
+ }
690
+ async createProject(project) {
691
+ const index = await this.getProjectIndex();
692
+ await this.storage.setItem(`${this.namespace}/projects/${project.id}`, JSON.stringify(project));
693
+ if (index.indexOf(project.id) === -1) {
694
+ index.push(project.id);
695
+ await this.saveProjectIndex(index);
696
+ }
697
+ }
698
+ canDelete() {
699
+ return true;
700
+ }
701
+ async getAllProjects() {
702
+ try {
703
+ const index = await this.getProjectIndex();
704
+ const projects = [];
705
+ for (const item of index) {
706
+ if (item === "_index") {
707
+ continue;
708
+ }
709
+ const loaded = await this.storage.getItem(`${this.namespace}/projects/${item}`);
710
+ if (loaded) {
711
+ try {
712
+ projects.push(JSON.parse(loaded));
713
+ } catch (e) {
714
+ }
715
+ }
716
+ }
717
+ return projects;
718
+ } catch (e) {
719
+ console.error("Error loading from localstorage", e);
720
+ return [];
721
+ }
722
+ }
723
+ async getLastProject() {
724
+ return this.storage.getItem(`${this.namespace}/last`);
725
+ }
726
+ async setLastProject(id) {
727
+ await this.storage.setItem(`${this.namespace}/last`, id);
728
+ }
729
+ async updateProject(project) {
730
+ await this.storage.setItem(`${this.namespace}/projects/${project.id}`, JSON.stringify(project));
731
+ }
732
+ async saveProjectIndex(index) {
733
+ await this.storage.setItem(`${this.namespace}/_index`, JSON.stringify(index));
734
+ }
735
+ async getProjectIndex() {
736
+ const json = await this.storage.getItem(`${this.namespace}/_index`);
737
+ if (!json) {
738
+ return [];
739
+ }
740
+ const index = JSON.parse(json);
741
+ if (!Array.isArray(index)) {
742
+ return [];
743
+ }
744
+ return index;
745
+ }
746
+ };
747
+
748
+ // src/storage/AbstractVaultLoader.ts
749
+ var import_vault = require("@iiif/helpers/vault");
750
+ var AbstractVaultLoader = class {
751
+ constructor(config = {}) {
752
+ __publicField(this, "vaults", {});
753
+ __publicField(this, "saveInterval");
754
+ this.saveInterval = config.saveInterval || 5e3;
755
+ }
756
+ shouldUpdateWithVault() {
757
+ return true;
758
+ }
759
+ canCreate() {
760
+ return true;
761
+ }
762
+ canDelete() {
763
+ return true;
764
+ }
765
+ createVaultInstance(project) {
766
+ const foundVault = this.vaults[project.storage.data.key];
767
+ if (foundVault) {
768
+ return [foundVault, Promise.resolve()];
769
+ }
770
+ const vault = new import_vault.Vault();
771
+ const promise = async () => {
772
+ const data = await this.getStorage(project.storage);
773
+ await vault.loadManifest(project.resource.id, JSON.parse(JSON.stringify(data?.data)));
774
+ this.vaults[project.storage.data.key] = vault;
775
+ };
776
+ return [vault, promise()];
777
+ }
778
+ closeVaultInstance(project, vault) {
779
+ }
780
+ async saveStorage(storage) {
781
+ const vault = this.vaults[storage.data.key];
782
+ const manifestRef = {
783
+ id: storage.data.id,
784
+ type: storage.data.type
785
+ };
786
+ if (vault) {
787
+ const data = vault.toPresentation3(manifestRef);
788
+ const stored = data.type === "Collection" ? {
789
+ type: "collection-storage",
790
+ data
791
+ } : {
792
+ type: "manifest-storage",
793
+ data
794
+ };
795
+ await this.saveStorageData(stored, storage);
796
+ }
797
+ }
798
+ };
799
+
800
+ // src/storage/LocalStorageLoader.ts
801
+ var import_localforage = __toESM(require("localforage"), 1);
802
+ var LocalStorageLoader = class extends AbstractVaultLoader {
803
+ constructor(settings) {
804
+ super({ saveInterval: 5e3 });
805
+ __publicField(this, "type", "local-storage");
806
+ __publicField(this, "namespace");
807
+ __publicField(this, "storage");
808
+ __publicField(this, "vaults", {});
809
+ this.namespace = settings?.namespace || "default";
810
+ this.storage = import_localforage.default.createInstance({
811
+ name: "local-storage-resource-loader"
812
+ });
813
+ }
814
+ shouldUpdateWithVault() {
815
+ return true;
816
+ }
817
+ async create(project, data) {
818
+ const key = randomId2();
819
+ await localStorage.setItem(`${this.namespace}/store/${key}`, JSON.stringify(data));
820
+ return {
821
+ type: "resource-keyed-storage",
822
+ data: {
823
+ id: data.id,
824
+ type: data.type,
825
+ key
826
+ }
827
+ };
828
+ }
829
+ async getStorage(storage) {
830
+ try {
831
+ const item = await localStorage.getItem(`${this.namespace}/store/${storage.data.key}`);
832
+ const manifest = item ? JSON.parse(item) : null;
833
+ invariant(manifest, "Resource not found");
834
+ if (manifest.type === "Collection") {
835
+ return {
836
+ type: "collection-storage",
837
+ data: manifest
838
+ };
839
+ }
840
+ return {
841
+ type: "manifest-storage",
842
+ data: manifest
843
+ };
844
+ } catch (e) {
845
+ return null;
846
+ }
847
+ }
848
+ async saveStorageData(manifestStorage, storage) {
849
+ await localStorage.setItem(`${this.namespace}/store/${storage.data.key}`, JSON.stringify(manifestStorage.data));
850
+ }
851
+ async deleteStorage(storage) {
852
+ this.vaults[storage.data.key] = null;
853
+ await localStorage.removeItem(`${this.namespace}/store/${storage.data.key}`);
854
+ }
855
+ getBackendStorage(project) {
856
+ return project.storage;
857
+ }
858
+ };
859
+
860
+ // src/ProjectContext.internal.tsx
861
+ var import_react_iiif_vault = require("react-iiif-vault");
862
+ var import_jsx_runtime = require("react/jsx-runtime");
863
+ function ProjectProvider(props) {
864
+ const { currentApp, changeApp } = (0, import_shell2.useApps)();
865
+ const backend = (0, import_react3.useMemo)(() => props.backend || new LocalStorageBackend(), []);
866
+ const storage = (0, import_react3.useMemo)(() => props.storage || new LocalStorageLoader(), []);
867
+ const [state, dispatch] = (0, import_react3.useReducer)(
868
+ projectContextReducer,
869
+ void 0,
870
+ props.initialState || getDefaultProjectContextState
871
+ );
872
+ const actions = useProjectActionsWithBackend(dispatch, backend, storage);
873
+ const context = (0, import_react3.useMemo)(
874
+ () => ({ actions, canDelete: backend.canDelete(), ...state }),
875
+ [actions, backend, state]
876
+ );
877
+ const { vault, ready, error } = useProjectLoader(context, storage);
878
+ const manifestOrCollection = context.current?.resource;
879
+ const loadingStatus = (0, import_react3.useMemo)(() => {
880
+ return { isLoading: !ready, isError: !!error, error };
881
+ }, [ready, error]);
882
+ useProjectBackend(context, backend);
883
+ (0, import_react3.useEffect)(() => {
884
+ if (state.loadingStatus && state.loadingStatus.loaded && ready && (!vault || !manifestOrCollection) && currentApp?.id !== (props.defaultApp || "splash")) {
885
+ changeApp({ id: props.defaultApp || "splash" });
886
+ }
887
+ }, []);
888
+ if (state.loadingStatus && state.loadingStatus.loading || context.current && !manifestOrCollection) {
889
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: "Loading..." });
890
+ }
891
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProjectLoadingReactContext.Provider, { value: loadingStatus, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProjectReactContext.Provider, { value: context, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_iiif_vault.VaultProvider, { vault: vault || void 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_shell2.AppResourceInstanceProvider, { id: context.current?.id, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_shell2.AppResourceProvider, { resource: manifestOrCollection, children: props.children }) }) }, state.current?.id) }) });
892
+ }
893
+
894
+ // ../ui/icons/MenuIcon.tsx
895
+ var import_jsx_runtime2 = require("react/jsx-runtime");
896
+ var MenuIcon = () => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", height: "1rem", viewBox: "0 0 24 24", width: "24px", fill: "#000000", children: [
897
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M0 0h24v24H0z", fill: "none" }),
898
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" })
899
+ ] });
900
+
901
+ // ../ui/atoms/Dropdown.tsx
902
+ var import_styled_components2 = __toESM(require("styled-components"), 1);
903
+
904
+ // ../ui/atoms/Button.tsx
905
+ var import_styled_components = __toESM(require("styled-components"), 1);
906
+ var ButtonReset = import_styled_components.default.button`
907
+ border: none;
908
+ outline: none;
909
+ background-color: transparent;
910
+ margin: 0;
911
+ padding: 0;
912
+ font-size: inherit;
913
+ color: inherit;
914
+ cursor: pointer;
915
+ &:hover {
916
+ color: inherit;
917
+ }
918
+ `;
919
+ var Button = import_styled_components.default.button`
920
+ padding: 0.5rem 1rem;
921
+ color: ${(props) => props.theme.color.main || "none"};
922
+ background-color: ${(props) => props.theme.color.white || "white"};
923
+ border-radius: inherit;
924
+ border: none;
925
+ cursor: pointer;
926
+ display: flex;
927
+ align-items: center;
928
+ font-size: 0.85em;
929
+ :disabled {
930
+ opacity: 0.65;
931
+ cursor: not-allowed;
932
+ }
933
+
934
+ &:hover {
935
+ background: #eee;
936
+ }
937
+ `;
938
+ var SmallButton = (0, import_styled_components.default)(Button)`
939
+ padding: 0.25em ${(props) => props.theme.padding.xs || "0.4em"};
940
+ height: unset;
941
+ background: none;
942
+ `;
943
+ var SecondaryButton = (0, import_styled_components.default)(Button)`
944
+ {
945
+ padding: 0 ${(props) => props.theme.padding.medium || "1rem"};
946
+ color: ${(props) => props.theme.color.main || "#B84C74;"};
947
+ background-color: ${(props) => props.theme.color.white || "white"};
948
+ border: 1px solid ${(props) => props.theme.color.main || "#B84C74;"};
949
+ border-radius: 0.25rem;
950
+ cursor: pointer;
951
+ height: 2rem;
952
+ display: flex;
953
+ align-items: center;
954
+ white-space: nowrap;
955
+ font-size: 0.75rem;
956
+
957
+ :disabled {
958
+ opacity: 0.65;
959
+ cursor: not-allowed;
960
+ }
961
+ }
962
+ `;
963
+ var CalltoButton = (0, import_styled_components.default)(Button)`
964
+ padding: 0 ${(props) => props.theme.padding.medium || "1rem"};
965
+ color: ${(props) => props.theme.color.white || "white"};
966
+ background-color: ${(props) => props.theme.color.main || "#B84C74;"};
967
+ border: 1px solid #eee;
968
+ border-radius: 0.25rem;
969
+ cursor: pointer;
970
+ justify-content: center;
971
+ display: flex;
972
+ align-items: center;
973
+ &:hover {
974
+ background-color: ${(props) => props.theme.color.mainHover || "#B84C74;"};
975
+ }
976
+ `;
977
+ var ButtonGroup = import_styled_components.default.div`
978
+ display: flex;
979
+ flex-direction: row;
980
+ flex-wrap: wrap;
981
+ align-items: flex-start;
982
+ justify-content: ${(props) => props.$right ? "flex-end" : "flex-start"};
983
+ `;
984
+
985
+ // ../ui/atoms/Dropdown.tsx
986
+ var Dropdown = import_styled_components2.default.div`
987
+ position: relative;
988
+ display: inline-block;
989
+ `;
990
+ var DropdownContent = import_styled_components2.default.div`
991
+ display: flex;
992
+ flex-direction: column;
993
+ position: absolute;
994
+ background-color: ${(props) => props.theme.color.white || "white"};
995
+ color: ${(props) => props.theme.color.black || " black"};
996
+ font-size: 0.75rem;
997
+ min-width: 160px;
998
+ box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
999
+ z-index: 150;
1000
+ button {
1001
+ &:hover {
1002
+ background-color: ${(props) => props.theme.color.lightgrey || "lightgrey"};
1003
+ }
1004
+ }
1005
+ `;
1006
+ var DropdownItem = import_styled_components2.default.button`
1007
+ padding: 0 ${(props) => props.theme.padding.small || "0.5rem"};
1008
+ color: ${(props) => props.theme.color.main || "none"};
1009
+ background-color: ${(props) => props.theme.color.white || "white"};
1010
+ border-radius: 0;
1011
+ border: none;
1012
+ cursor: pointer;
1013
+ display: flex;
1014
+ padding: 0.65em 1em;
1015
+ align-items: center;
1016
+ :disabled {
1017
+ opacity: 0.65;
1018
+ cursor: not-allowed;
1019
+ }
1020
+
1021
+ &:hover {
1022
+ background-color: ${(props) => props.theme.color.lightgrey || "lightgrey"};
1023
+ }
1024
+
1025
+ ${(props) => props.$active && import_styled_components2.css`
1026
+ background: #b84c74;
1027
+ color: #fff;
1028
+ &:hover {
1029
+ background: #b84c74;
1030
+ color: #fff;
1031
+ }
1032
+ `}
1033
+ `;
1034
+ var DropdownMenu = import_styled_components2.default.div`
1035
+ display: none;
1036
+ flex-direction: column;
1037
+ position: absolute;
1038
+ background: #fff;
1039
+ color: ${(props) => props.theme.color.black || " black"};
1040
+ font-size: 0.75rem;
1041
+ min-width: 190px;
1042
+ top: calc(100% + 0.5em);
1043
+ box-shadow:
1044
+ 0 4px 15px 0 rgba(0, 0, 0, 0.18),
1045
+ 0 0px 0px 1px rgba(0, 0, 0, 0.15),
1046
+ inset 0 0 0 1px rgba(255, 255, 255, 0.2);
1047
+ border-radius: 3px;
1048
+ z-index: 150;
1049
+ overflow: hidden;
1050
+ padding-bottom: 3px;
1051
+
1052
+ ${Button} {
1053
+ &:hover {
1054
+ background-color: ${(props) => props.theme.color.lightgrey || "lightgrey"};
1055
+ }
1056
+ }
1057
+
1058
+ ${(props) => props.$open && import_styled_components2.css`
1059
+ display: flex;
1060
+ `}
1061
+ `;
1062
+ var DropdownLabel = import_styled_components2.default.div`
1063
+ color: #999;
1064
+ text-transform: uppercase;
1065
+ font-weight: 600;
1066
+ padding: 0.7em;
1067
+ font-size: 0.875em;
1068
+ `;
1069
+ var DropdownDivider = import_styled_components2.default.div`
1070
+ height: 1px;
1071
+ margin: 0 0.5em;
1072
+ background: #eee;
1073
+ `;
1074
+
1075
+ // ../ui/madoc/use-local-storage.ts
1076
+ var import_react4 = require("react");
1077
+
1078
+ // ../../node_modules/.pnpm/mitt@3.0.1/node_modules/mitt/dist/mitt.mjs
1079
+ function mitt_default(n) {
1080
+ return { all: n = n || /* @__PURE__ */ new Map(), on: function(t, e) {
1081
+ var i = n.get(t);
1082
+ i ? i.push(e) : n.set(t, [e]);
1083
+ }, off: function(t, e) {
1084
+ var i = n.get(t);
1085
+ i && (e ? i.splice(i.indexOf(e) >>> 0, 1) : n.set(t, []));
1086
+ }, emit: function(t, e) {
1087
+ var i = n.get(t);
1088
+ i && i.slice().map(function(n2) {
1089
+ n2(e);
1090
+ }), (i = n.get("*")) && i.slice().map(function(n2) {
1091
+ n2(t, e);
1092
+ });
1093
+ } };
1094
+ }
1095
+
1096
+ // ../ui/madoc/use-local-storage.ts
1097
+ globalThis.MS_LS_EMITTER = globalThis.MS_LS_EMITTER || mitt_default();
1098
+ var lsEmitter = globalThis.MS_LS_EMITTER;
1099
+ function useLocalStorage(key, initialValue) {
1100
+ const lastStoredValue = (0, import_react4.useRef)();
1101
+ if (!lastStoredValue.current && initialValue) {
1102
+ lastStoredValue.current = JSON.stringify(initialValue);
1103
+ }
1104
+ const [storedValue, setStoredValue] = (0, import_react4.useState)(() => {
1105
+ try {
1106
+ if (typeof window === "undefined" || typeof window.localStorage === "undefined") {
1107
+ return initialValue;
1108
+ }
1109
+ const item = window.localStorage.getItem(key);
1110
+ if (item) {
1111
+ lastStoredValue.current = item;
1112
+ }
1113
+ return item ? JSON.parse(item) : initialValue;
1114
+ } catch (error) {
1115
+ console.log(error);
1116
+ return initialValue;
1117
+ }
1118
+ });
1119
+ const setValue = (value) => {
1120
+ try {
1121
+ if (typeof window !== "undefined" && typeof window.localStorage !== "undefined") {
1122
+ let prev = initialValue;
1123
+ try {
1124
+ prev = typeof lastStoredValue.current === "undefined" ? initialValue : JSON.parse(lastStoredValue.current);
1125
+ } catch (e) {
1126
+ }
1127
+ const valueToStore = value instanceof Function ? value(prev) : value;
1128
+ setStoredValue(valueToStore);
1129
+ const valueJson = JSON.stringify(valueToStore);
1130
+ window.localStorage.setItem(key, valueJson);
1131
+ if (valueJson !== lastStoredValue.current) {
1132
+ lastStoredValue.current = valueJson;
1133
+ lsEmitter.emit(`change:${key}`, { valueJson });
1134
+ }
1135
+ }
1136
+ } catch (error) {
1137
+ console.log(error);
1138
+ }
1139
+ };
1140
+ (0, import_react4.useEffect)(() => {
1141
+ const listener = ({ valueJson }) => {
1142
+ if (valueJson && valueJson !== lastStoredValue.current) {
1143
+ try {
1144
+ setStoredValue(JSON.parse(valueJson));
1145
+ lastStoredValue.current = valueJson;
1146
+ } catch (e) {
1147
+ }
1148
+ }
1149
+ };
1150
+ lsEmitter.on(`change:${key}`, listener);
1151
+ return () => {
1152
+ lsEmitter.off(`change:${key}`, listener);
1153
+ };
1154
+ }, [key]);
1155
+ return [storedValue, setValue, lastStoredValue];
1156
+ }
1157
+
1158
+ // src/components/AppMenu.tsx
1159
+ var import_react_accessible_dropdown_menu_hook = __toESM(require("react-accessible-dropdown-menu-hook"), 1);
1160
+ var import_shell3 = require("@manifest-editor/shell");
1161
+ var import_styled_components3 = __toESM(require("styled-components"), 1);
1162
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1163
+ var IconButton = import_styled_components3.default.button`
1164
+ height: 1.75em;
1165
+ width: 1.75em;
1166
+ background: #e9e9e9;
1167
+ border-radius: 3px;
1168
+ display: flex;
1169
+ text-align: center;
1170
+ align-items: center;
1171
+ font-size: 1.1em;
1172
+ border: none;
1173
+ justify-content: center;
1174
+
1175
+ &:focus {
1176
+ background: #e94581;
1177
+ color: #fff;
1178
+ svg {
1179
+ fill: #fff;
1180
+ }
1181
+ }
1182
+ `;
1183
+ function AppMenu(props) {
1184
+ const { current: currentProject } = useProjectContext();
1185
+ const [isMenuHidden, setIsMenuHidden] = useLocalStorage("menu-hidden");
1186
+ const { apps, changeApp } = (0, import_shell3.useApps)();
1187
+ const type = currentProject?.resource.type;
1188
+ const filteredApps = Object.values(apps).filter((app) => {
1189
+ if (app.metadata.project && app.metadata.projectType !== type) {
1190
+ return false;
1191
+ }
1192
+ if (!currentProject && app.metadata.project) {
1193
+ return false;
1194
+ }
1195
+ if (app.metadata.type === "launcher") {
1196
+ return false;
1197
+ }
1198
+ return true;
1199
+ });
1200
+ const { itemProps, buttonProps, isOpen, setIsOpen } = (0, import_react_accessible_dropdown_menu_hook.default)(filteredApps.length + 1);
1201
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Dropdown, { children: [
1202
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(IconButton, { ...buttonProps, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MenuIcon, {}) }),
1203
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(DropdownMenu, { $open: isOpen, children: [
1204
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DropdownLabel, { children: "Apps" }),
1205
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DropdownDivider, {}),
1206
+ filteredApps.map((app, key) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1207
+ Button,
1208
+ {
1209
+ ...itemProps[key],
1210
+ onClick: () => {
1211
+ changeApp({ id: app.metadata.id });
1212
+ setIsOpen(false);
1213
+ },
1214
+ children: app.metadata.title
1215
+ },
1216
+ app.metadata.id
1217
+ )),
1218
+ props.hideMenu ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1219
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DropdownLabel, { children: "Quick Settings" }),
1220
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DropdownDivider, {}),
1221
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { ...itemProps[filteredApps.length + 0], onClick: () => setIsMenuHidden(!isMenuHidden), children: isMenuHidden ? "Show menu" : "Hide menu" })
1222
+ ] })
1223
+ ] })
1224
+ ] });
1225
+ }
1226
+
1227
+ // src/components/DraftTitleEditor.tsx
1228
+ var import_react5 = require("react");
1229
+ var import_react_dom = require("react-dom");
1230
+ var import_styled_components4 = __toESM(require("styled-components"), 1);
1231
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1232
+ var Draft = import_styled_components4.default.div`
1233
+ display: flex;
1234
+ flex-direction: row;
1235
+ flex: 1;
1236
+ padding: 0.28em;
1237
+ padding-left: 0.5em;
1238
+ align-items: center;
1239
+ overflow: hidden;
1240
+ `;
1241
+ var DraftsText = import_styled_components4.default.div`
1242
+ color: #828282;
1243
+ padding-right: 1em;
1244
+ `;
1245
+ var DraftTitleEdit = import_styled_components4.default.form`
1246
+ margin: 0;
1247
+ padding: 0;
1248
+ display: flex;
1249
+ flex: 1;
1250
+ `;
1251
+ var DraftTitleEditInput = import_styled_components4.default.input`
1252
+ font-size: 1em;
1253
+ flex: 1;
1254
+ border: 1px solid #999;
1255
+ padding: 0.2em;
1256
+ margin: -0.2em 0;
1257
+ `;
1258
+ var DraftTitleEditButton = (0, import_styled_components4.default)(SmallButton)`
1259
+ font-size: 1em;
1260
+ display: inline-block;
1261
+ `;
1262
+ var DraftTitle = import_styled_components4.default.div`
1263
+ color: #333;
1264
+ flex: 1;
1265
+ text-overflow: ellipsis;
1266
+ white-space: nowrap;
1267
+ overflow: hidden;
1268
+ `;
1269
+ function DraftTitleEditor() {
1270
+ const { actions, current } = useProjectContext();
1271
+ const [editingTitle, setIsEditingTitle] = (0, import_react5.useState)(false);
1272
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Draft, { children: [
1273
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DraftsText, { children: "Drafts" }),
1274
+ current ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: editingTitle ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1275
+ DraftTitleEdit,
1276
+ {
1277
+ onSubmit: (e) => {
1278
+ const form = new FormData(e.target);
1279
+ const data = Object.fromEntries(form.entries());
1280
+ actions.updateDetails(data);
1281
+ setIsEditingTitle(false);
1282
+ },
1283
+ children: [
1284
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DraftTitleEditInput, { id: "project-title", defaultValue: current.name, name: "name" }),
1285
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DraftTitleEditButton, { children: "Save" })
1286
+ ]
1287
+ }
1288
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1289
+ DraftTitle,
1290
+ {
1291
+ onClick: () => {
1292
+ (0, import_react_dom.flushSync)(() => {
1293
+ setIsEditingTitle(true);
1294
+ });
1295
+ document.getElementById("project-title")?.focus();
1296
+ },
1297
+ children: current.name || "Untitled project"
1298
+ }
1299
+ ) }) : null
1300
+ ] });
1301
+ }