@wildwinter/app-shell 0.29.0 → 0.31.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/dist/index.cjs +142 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -1
- package/dist/index.d.ts +60 -1
- package/dist/index.js +137 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -891,6 +891,142 @@ function isCaseOnlyPropertyName(name) {
|
|
|
891
891
|
return !isValidPropertyName(name) && isValidPropertyName(name.toLowerCase());
|
|
892
892
|
}
|
|
893
893
|
|
|
894
|
+
// src/property-name-field.ts
|
|
895
|
+
var refSyncs = /* @__PURE__ */ new WeakMap();
|
|
896
|
+
function propertyNameProblem(name) {
|
|
897
|
+
if (isValidPropertyName(name)) return void 0;
|
|
898
|
+
const suggestion = propertyNameify(name);
|
|
899
|
+
const tail = suggestion ? ` Try "${suggestion}", or press Tab.` : "";
|
|
900
|
+
if (RESERVED_PROPERTY_NAMES.includes(name.toLowerCase())) {
|
|
901
|
+
return `Cannot be used: "${name.toLowerCase()}" is a keyword in expressions.${tail}`;
|
|
902
|
+
}
|
|
903
|
+
if (name.includes("-")) return `Cannot be used: a hyphen reads as subtraction in an expression.${tail}`;
|
|
904
|
+
if (/^[0-9]/.test(name)) return `Cannot be used: a name cannot start with a digit.${tail}`;
|
|
905
|
+
if (name !== name.toLowerCase()) {
|
|
906
|
+
return `Cannot be used: expressions fold names, so this would look for "${name.toLowerCase()}".${tail}`;
|
|
907
|
+
}
|
|
908
|
+
return `Cannot be used: only lower case letters, digits and underscores.${tail}`;
|
|
909
|
+
}
|
|
910
|
+
function bindPropertyName(input, onCommit, opts = {}) {
|
|
911
|
+
const hint = opts.hint;
|
|
912
|
+
const sync = () => {
|
|
913
|
+
const v = input.value.trim();
|
|
914
|
+
const problem = v === "" ? void 0 : propertyNameProblem(v);
|
|
915
|
+
input.classList.toggle("illegal", !!problem);
|
|
916
|
+
if (problem) input.title = problem;
|
|
917
|
+
else if (input.title.startsWith("Cannot be used")) {
|
|
918
|
+
if (hint) input.title = hint;
|
|
919
|
+
else input.removeAttribute("title");
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
input.addEventListener("input", () => {
|
|
923
|
+
onCommit(input.value);
|
|
924
|
+
sync();
|
|
925
|
+
});
|
|
926
|
+
input.addEventListener("keydown", (e) => {
|
|
927
|
+
if (e.key !== "Tab" || e.shiftKey) return;
|
|
928
|
+
const typed = input.value.trim();
|
|
929
|
+
if (typed === "" || isValidPropertyName(typed)) return;
|
|
930
|
+
const coerced = propertyNameify(typed);
|
|
931
|
+
if (!coerced || coerced === input.value) return;
|
|
932
|
+
e.preventDefault();
|
|
933
|
+
input.value = coerced;
|
|
934
|
+
onCommit(coerced);
|
|
935
|
+
sync();
|
|
936
|
+
});
|
|
937
|
+
sync();
|
|
938
|
+
}
|
|
939
|
+
function firstIllegalPropertyName(host) {
|
|
940
|
+
return host.querySelector("input.illegal");
|
|
941
|
+
}
|
|
942
|
+
function nearest(name, known) {
|
|
943
|
+
const n = name.toLowerCase();
|
|
944
|
+
const byPrefix = known.filter((k) => k.toLowerCase().startsWith(n) || n.startsWith(k.toLowerCase()));
|
|
945
|
+
if (byPrefix.length === 1) return byPrefix[0];
|
|
946
|
+
let best;
|
|
947
|
+
let bestScore = 3;
|
|
948
|
+
for (const k of known) {
|
|
949
|
+
const a = k.toLowerCase();
|
|
950
|
+
if (Math.abs(a.length - n.length) > 2) continue;
|
|
951
|
+
let prev = Array.from({ length: n.length + 1 }, (_, i) => i);
|
|
952
|
+
for (let i = 1; i <= a.length; i++) {
|
|
953
|
+
const row = [i];
|
|
954
|
+
for (let j = 1; j <= n.length; j++) {
|
|
955
|
+
row[j] = Math.min(prev[j] + 1, row[j - 1] + 1, prev[j - 1] + (a[i - 1] === n[j - 1] ? 0 : 1));
|
|
956
|
+
}
|
|
957
|
+
prev = row;
|
|
958
|
+
}
|
|
959
|
+
const d = prev[n.length];
|
|
960
|
+
if (d < bestScore) {
|
|
961
|
+
bestScore = d;
|
|
962
|
+
best = k;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
return best;
|
|
966
|
+
}
|
|
967
|
+
function propertyRefProblem(name, opts) {
|
|
968
|
+
const scope = opts.scope ? `@${opts.scope}` : "that scope";
|
|
969
|
+
const folded = name.toLowerCase();
|
|
970
|
+
if (!isValidPropertyName(folded)) {
|
|
971
|
+
const suggestion = propertyNameify(name);
|
|
972
|
+
const tail = suggestion ? ` Try "${suggestion}", or press Tab.` : "";
|
|
973
|
+
if (RESERVED_PROPERTY_NAMES.includes(folded)) return `Cannot be used: "${folded}" is a keyword in expressions.${tail}`;
|
|
974
|
+
if (name.includes("-")) return `Cannot be used: a hyphen reads as subtraction in an expression.${tail}`;
|
|
975
|
+
if (/^[0-9]/.test(name)) return `Cannot be used: a name cannot start with a digit.${tail}`;
|
|
976
|
+
return `Cannot be used: only lower case letters, digits and underscores.${tail}`;
|
|
977
|
+
}
|
|
978
|
+
const known = opts.known();
|
|
979
|
+
if (known.some((k) => k.toLowerCase() === folded)) return void 0;
|
|
980
|
+
const near = nearest(folded, known);
|
|
981
|
+
if (near) return `No ${scope} property is called "${name}". Did you mean "${near}"?`;
|
|
982
|
+
if (known.length === 0) return `No ${scope} properties are declared yet. Declare one above first.`;
|
|
983
|
+
const shown = known.slice(0, 3).map((k) => `"${k}"`).join(", ");
|
|
984
|
+
const more = known.length > 3 ? `, and ${known.length - 3} more` : "";
|
|
985
|
+
return `No ${scope} property is called "${name}". Declared: ${shown}${more}.`;
|
|
986
|
+
}
|
|
987
|
+
function bindPropertyRef(input, onCommit, opts) {
|
|
988
|
+
const list = document.createElement("datalist");
|
|
989
|
+
list.id = `shell-propref-${Math.random().toString(36).slice(2, 9)}`;
|
|
990
|
+
input.setAttribute("list", list.id);
|
|
991
|
+
input.after(list);
|
|
992
|
+
const sync = () => {
|
|
993
|
+
const known = opts.known();
|
|
994
|
+
list.replaceChildren(...known.map((k) => {
|
|
995
|
+
const o = document.createElement("option");
|
|
996
|
+
o.value = k;
|
|
997
|
+
return o;
|
|
998
|
+
}));
|
|
999
|
+
const v = input.value.trim();
|
|
1000
|
+
const problem = v === "" ? void 0 : propertyRefProblem(v, opts);
|
|
1001
|
+
input.classList.toggle("illegal", !!problem);
|
|
1002
|
+
if (problem) input.title = problem;
|
|
1003
|
+
else if (input.title.startsWith("Cannot be used") || input.title.startsWith("No ")) {
|
|
1004
|
+
if (opts.hint) input.title = opts.hint;
|
|
1005
|
+
else input.removeAttribute("title");
|
|
1006
|
+
}
|
|
1007
|
+
};
|
|
1008
|
+
refSyncs.set(input, sync);
|
|
1009
|
+
input.addEventListener("input", () => {
|
|
1010
|
+
onCommit(input.value);
|
|
1011
|
+
sync();
|
|
1012
|
+
});
|
|
1013
|
+
input.addEventListener("keydown", (e) => {
|
|
1014
|
+
if (e.key !== "Tab" || e.shiftKey) return;
|
|
1015
|
+
const typed = input.value.trim();
|
|
1016
|
+
if (typed === "" || isValidPropertyName(typed.toLowerCase())) return;
|
|
1017
|
+
const coerced = propertyNameify(typed);
|
|
1018
|
+
if (!coerced || coerced === input.value) return;
|
|
1019
|
+
e.preventDefault();
|
|
1020
|
+
input.value = coerced;
|
|
1021
|
+
onCommit(coerced);
|
|
1022
|
+
sync();
|
|
1023
|
+
});
|
|
1024
|
+
sync();
|
|
1025
|
+
}
|
|
1026
|
+
function revalidatePropertyRefs(host) {
|
|
1027
|
+
for (const input of host.querySelectorAll("input")) refSyncs.get(input)?.();
|
|
1028
|
+
}
|
|
1029
|
+
|
|
894
1030
|
// src/id-editor.ts
|
|
895
1031
|
function openGameIdEditor(opts) {
|
|
896
1032
|
const slugify = opts.slugify ?? gameIdify;
|
|
@@ -1562,6 +1698,8 @@ exports.PANE_MENU = PANE_MENU;
|
|
|
1562
1698
|
exports.PROPERTY_NAME_HINT = PROPERTY_NAME_HINT;
|
|
1563
1699
|
exports.RESERVED_PROPERTY_NAMES = RESERVED_PROPERTY_NAMES;
|
|
1564
1700
|
exports.askIdentity = askIdentity;
|
|
1701
|
+
exports.bindPropertyName = bindPropertyName;
|
|
1702
|
+
exports.bindPropertyRef = bindPropertyRef;
|
|
1565
1703
|
exports.closeAnchoredPanel = closeAnchoredPanel;
|
|
1566
1704
|
exports.closeWithExit = closeWithExit;
|
|
1567
1705
|
exports.colourFor = colourFor;
|
|
@@ -1571,6 +1709,7 @@ exports.createSaveController = createSaveController;
|
|
|
1571
1709
|
exports.dupGuard = dupGuard;
|
|
1572
1710
|
exports.el = el;
|
|
1573
1711
|
exports.expandableRow = expandableRow;
|
|
1712
|
+
exports.firstIllegalPropertyName = firstIllegalPropertyName;
|
|
1574
1713
|
exports.focusNewRow = focusNewRow;
|
|
1575
1714
|
exports.foldVc = foldVc;
|
|
1576
1715
|
exports.gameIdify = gameIdify;
|
|
@@ -1596,8 +1735,11 @@ exports.openNotesEditor = openNotesEditor;
|
|
|
1596
1735
|
exports.paintVcBadges = paintVcBadges;
|
|
1597
1736
|
exports.pinButton = pinButton;
|
|
1598
1737
|
exports.placeAnchored = placeAnchored;
|
|
1738
|
+
exports.propertyNameProblem = propertyNameProblem;
|
|
1599
1739
|
exports.propertyNameify = propertyNameify;
|
|
1740
|
+
exports.propertyRefProblem = propertyRefProblem;
|
|
1600
1741
|
exports.renderStepperBar = renderStepperBar;
|
|
1742
|
+
exports.revalidatePropertyRefs = revalidatePropertyRefs;
|
|
1601
1743
|
exports.saveIndicator = saveIndicator;
|
|
1602
1744
|
exports.showAbout = showAbout;
|
|
1603
1745
|
exports.staleBar = staleBar;
|