@wildwinter/app-shell 0.48.0 → 0.50.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/chunk-JOFRUWTP.js +431 -0
- package/dist/chunk-JOFRUWTP.js.map +1 -0
- package/dist/{chunk-CRUILFAT.js → chunk-TETY2BTN.js} +33 -22
- package/dist/chunk-TETY2BTN.js.map +1 -0
- package/dist/controls.css +103 -0
- package/dist/controls.css.map +1 -1
- package/dist/index.cjs +463 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/{property-list-BgZlkcbz.d.cts → property-list-DlpxIkv6.d.cts} +27 -5
- package/dist/{property-list-BgZlkcbz.d.ts → property-list-DlpxIkv6.d.ts} +27 -5
- package/dist/property-list.cjs +55 -20
- package/dist/property-list.cjs.map +1 -1
- package/dist/property-list.d.cts +1 -1
- package/dist/property-list.d.ts +1 -1
- package/dist/property-list.js +2 -1
- package/dist/value-control.cjs +811 -0
- package/dist/value-control.cjs.map +1 -0
- package/dist/value-control.d.cts +104 -0
- package/dist/value-control.d.ts +104 -0
- package/dist/value-control.js +4 -0
- package/dist/value-control.js.map +1 -0
- package/dist/window-guard.cjs +74 -0
- package/dist/window-guard.cjs.map +1 -0
- package/dist/window-guard.d.cts +32 -0
- package/dist/window-guard.d.ts +32 -0
- package/dist/window-guard.js +67 -0
- package/dist/window-guard.js.map +1 -0
- package/package.json +11 -1
- package/dist/chunk-CRUILFAT.js.map +0 -1
|
@@ -117,17 +117,30 @@ interface PropertyDeclLike {
|
|
|
117
117
|
declare const PROPERTY_TYPES: ReadonlyArray<readonly [PropertyListType, string]>;
|
|
118
118
|
interface DefaultControlOptions {
|
|
119
119
|
/**
|
|
120
|
-
* How the default is stored. `false` (default): the string the field shows
|
|
121
|
-
*
|
|
122
|
-
*
|
|
120
|
+
* How the default is stored. `false` (default): the string the field shows
|
|
121
|
+
* (Storyletter's DTO). `true`: a typed value (boolean, number, string)
|
|
122
|
+
* (Patterpad's model). Either way, no default given DELETES the key: a
|
|
123
|
+
* default is optional in source, and the type's holds (the family's rule,
|
|
124
|
+
* ruled 2026-10-18).
|
|
123
125
|
*/
|
|
124
126
|
typed?: boolean;
|
|
127
|
+
/**
|
|
128
|
+
* An enum may hold "" (none chosen), as a field's may: the select then
|
|
129
|
+
* offers "(none)" beside "default (x)". Off for a property, whose value is
|
|
130
|
+
* always one of its values.
|
|
131
|
+
*/
|
|
132
|
+
noneChosen?: boolean;
|
|
133
|
+
/** What the blank says instead of the type's default, where something else holds when none is given
|
|
134
|
+
* here: a tag's starting value falls back to its group's default, say. */
|
|
135
|
+
unsetLabel?: string;
|
|
125
136
|
}
|
|
126
137
|
/**
|
|
127
138
|
* The type-appropriate control for a declaration's DEFAULT: a true / false
|
|
128
139
|
* picker for a boolean, the value list for an enum, the stage list for a
|
|
129
|
-
* quality
|
|
130
|
-
*
|
|
140
|
+
* quality, a note for flags (a set starts empty), a number or text field
|
|
141
|
+
* otherwise. Leaving it blank gives no default, and the blank says what holds
|
|
142
|
+
* then, "default (x)" (`defaultLabel`): a default is optional, and the type's
|
|
143
|
+
* fills in.
|
|
131
144
|
*/
|
|
132
145
|
declare function defaultControl(p: PropertyDeclLike, onChange?: () => void, opts?: DefaultControlOptions): HTMLElement;
|
|
133
146
|
interface PropertyListOptions<T extends PropertyDeclLike> extends DefaultControlOptions {
|
|
@@ -149,6 +162,15 @@ interface PropertyListOptions<T extends PropertyDeclLike> extends DefaultControl
|
|
|
149
162
|
extraDetails?: (decl: T, index: number) => (HTMLElement | null)[];
|
|
150
163
|
/** Offer the Purpose field. Default true. */
|
|
151
164
|
purpose?: boolean;
|
|
165
|
+
/** What a row declares, in the row's own words ("Field name", "What this field is for", "Delete
|
|
166
|
+
* field"). Default "property". */
|
|
167
|
+
noun?: string;
|
|
168
|
+
/**
|
|
169
|
+
* The rule a name follows. `"property"` (default): the property-name rules, bound and gated, since an
|
|
170
|
+
* expression must be able to reach it. `"free"`: any name, only duplicates refused, for a declaration no
|
|
171
|
+
* expression reads (a Patterpad game-data field's name is the host's word).
|
|
172
|
+
*/
|
|
173
|
+
names?: "property" | "free";
|
|
152
174
|
/**
|
|
153
175
|
* A quality's stage was renamed in place (the declaration's own default
|
|
154
176
|
* already follows it). Given, the rename is handed here INSTEAD of
|
|
@@ -117,17 +117,30 @@ interface PropertyDeclLike {
|
|
|
117
117
|
declare const PROPERTY_TYPES: ReadonlyArray<readonly [PropertyListType, string]>;
|
|
118
118
|
interface DefaultControlOptions {
|
|
119
119
|
/**
|
|
120
|
-
* How the default is stored. `false` (default): the string the field shows
|
|
121
|
-
*
|
|
122
|
-
*
|
|
120
|
+
* How the default is stored. `false` (default): the string the field shows
|
|
121
|
+
* (Storyletter's DTO). `true`: a typed value (boolean, number, string)
|
|
122
|
+
* (Patterpad's model). Either way, no default given DELETES the key: a
|
|
123
|
+
* default is optional in source, and the type's holds (the family's rule,
|
|
124
|
+
* ruled 2026-10-18).
|
|
123
125
|
*/
|
|
124
126
|
typed?: boolean;
|
|
127
|
+
/**
|
|
128
|
+
* An enum may hold "" (none chosen), as a field's may: the select then
|
|
129
|
+
* offers "(none)" beside "default (x)". Off for a property, whose value is
|
|
130
|
+
* always one of its values.
|
|
131
|
+
*/
|
|
132
|
+
noneChosen?: boolean;
|
|
133
|
+
/** What the blank says instead of the type's default, where something else holds when none is given
|
|
134
|
+
* here: a tag's starting value falls back to its group's default, say. */
|
|
135
|
+
unsetLabel?: string;
|
|
125
136
|
}
|
|
126
137
|
/**
|
|
127
138
|
* The type-appropriate control for a declaration's DEFAULT: a true / false
|
|
128
139
|
* picker for a boolean, the value list for an enum, the stage list for a
|
|
129
|
-
* quality
|
|
130
|
-
*
|
|
140
|
+
* quality, a note for flags (a set starts empty), a number or text field
|
|
141
|
+
* otherwise. Leaving it blank gives no default, and the blank says what holds
|
|
142
|
+
* then, "default (x)" (`defaultLabel`): a default is optional, and the type's
|
|
143
|
+
* fills in.
|
|
131
144
|
*/
|
|
132
145
|
declare function defaultControl(p: PropertyDeclLike, onChange?: () => void, opts?: DefaultControlOptions): HTMLElement;
|
|
133
146
|
interface PropertyListOptions<T extends PropertyDeclLike> extends DefaultControlOptions {
|
|
@@ -149,6 +162,15 @@ interface PropertyListOptions<T extends PropertyDeclLike> extends DefaultControl
|
|
|
149
162
|
extraDetails?: (decl: T, index: number) => (HTMLElement | null)[];
|
|
150
163
|
/** Offer the Purpose field. Default true. */
|
|
151
164
|
purpose?: boolean;
|
|
165
|
+
/** What a row declares, in the row's own words ("Field name", "What this field is for", "Delete
|
|
166
|
+
* field"). Default "property". */
|
|
167
|
+
noun?: string;
|
|
168
|
+
/**
|
|
169
|
+
* The rule a name follows. `"property"` (default): the property-name rules, bound and gated, since an
|
|
170
|
+
* expression must be able to reach it. `"free"`: any name, only duplicates refused, for a declaration no
|
|
171
|
+
* expression reads (a Patterpad game-data field's name is the host's word).
|
|
172
|
+
*/
|
|
173
|
+
names?: "property" | "free";
|
|
152
174
|
/**
|
|
153
175
|
* A quality's stage was renamed in place (the declaration's own default
|
|
154
176
|
* already follows it). Given, the rename is handed here INSTEAD of
|
package/dist/property-list.cjs
CHANGED
|
@@ -671,6 +671,31 @@ function firstIllegalPropertyName(host) {
|
|
|
671
671
|
return host.querySelector("input.illegal");
|
|
672
672
|
}
|
|
673
673
|
|
|
674
|
+
// src/value-control.ts
|
|
675
|
+
function fallbackText(decl) {
|
|
676
|
+
const d = decl.default;
|
|
677
|
+
if (d !== void 0 && d !== null) {
|
|
678
|
+
if (typeof d === "boolean") return d ? "True" : "False";
|
|
679
|
+
if (Array.isArray(d)) return d.length === 0 ? "none" : d.join(", ");
|
|
680
|
+
return d === "" ? "none" : String(d);
|
|
681
|
+
}
|
|
682
|
+
switch (decl.type) {
|
|
683
|
+
case "boolean":
|
|
684
|
+
return "False";
|
|
685
|
+
case "number":
|
|
686
|
+
return "0";
|
|
687
|
+
case "enum":
|
|
688
|
+
return decl.values?.[0] ?? "none";
|
|
689
|
+
case "quality":
|
|
690
|
+
return decl.stages?.[0] ?? "first stage";
|
|
691
|
+
case "flags":
|
|
692
|
+
return "none";
|
|
693
|
+
default:
|
|
694
|
+
return "empty";
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
var defaultLabel = (decl) => `default (${fallbackText(decl)})`;
|
|
698
|
+
|
|
674
699
|
// src/property-list.ts
|
|
675
700
|
var PROPERTY_TYPES = [
|
|
676
701
|
["number", "Number"],
|
|
@@ -686,35 +711,37 @@ var option = (value, label, selected) => {
|
|
|
686
711
|
o.selected = selected;
|
|
687
712
|
return o;
|
|
688
713
|
};
|
|
689
|
-
var
|
|
714
|
+
var NONE_CHOSEN = "\0none";
|
|
690
715
|
function defaultControl(p, onChange, opts = {}) {
|
|
691
716
|
const typed = opts.typed === true;
|
|
692
717
|
const write = (raw) => {
|
|
693
|
-
if (raw === "")
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
} else if (typed && p.type === "boolean") p.default = raw === "true";
|
|
718
|
+
if (raw === "") delete p.default;
|
|
719
|
+
else if (raw === NONE_CHOSEN) p.default = "";
|
|
720
|
+
else if (typed && p.type === "boolean") p.default = raw === "true";
|
|
697
721
|
else if (typed && p.type === "number") p.default = Number(raw);
|
|
698
722
|
else p.default = raw;
|
|
699
723
|
onChange?.();
|
|
700
724
|
};
|
|
701
725
|
const current = p.default === void 0 || p.default === null ? "" : String(p.default);
|
|
726
|
+
const unsetLabel = opts.unsetLabel ?? defaultLabel({ ...p, default: void 0 });
|
|
702
727
|
if (p.type === "boolean") {
|
|
703
728
|
const sel = el("select", "field set-default");
|
|
704
|
-
sel.append(option("",
|
|
729
|
+
sel.append(option("", unsetLabel, current === ""), option("true", "True", current === "true"), option("false", "False", current === "false"));
|
|
705
730
|
sel.addEventListener("change", () => write(sel.value));
|
|
706
731
|
return sel;
|
|
707
732
|
}
|
|
708
733
|
if (p.type === "enum") {
|
|
709
734
|
const sel = el("select", "field set-default");
|
|
710
|
-
|
|
735
|
+
const none = opts.noneChosen === true && p.default === "";
|
|
736
|
+
sel.append(option("", unsetLabel, current === "" && !none));
|
|
737
|
+
if (opts.noneChosen) sel.append(option(NONE_CHOSEN, "(none)", none));
|
|
711
738
|
for (const v of p.values ?? []) sel.append(option(v, v, current === v));
|
|
712
739
|
sel.addEventListener("change", () => write(sel.value));
|
|
713
740
|
return sel;
|
|
714
741
|
}
|
|
715
742
|
if (p.type === "quality") {
|
|
716
743
|
const sel = el("select", "field set-default");
|
|
717
|
-
sel.append(option("",
|
|
744
|
+
sel.append(option("", unsetLabel, current === ""));
|
|
718
745
|
for (const v of p.stages ?? []) sel.append(option(v, v, current === v));
|
|
719
746
|
sel.addEventListener("change", () => write(sel.value));
|
|
720
747
|
return sel;
|
|
@@ -726,7 +753,7 @@ function defaultControl(p, onChange, opts = {}) {
|
|
|
726
753
|
}
|
|
727
754
|
const input = el("input", "field set-default");
|
|
728
755
|
input.type = p.type === "number" ? "number" : "text";
|
|
729
|
-
input.placeholder = "Default";
|
|
756
|
+
input.placeholder = p.type === "number" ? `Default (${fallbackText({ type: "number" })})` : "Default";
|
|
730
757
|
input.value = current;
|
|
731
758
|
input.addEventListener("input", () => write(input.value));
|
|
732
759
|
return input;
|
|
@@ -737,24 +764,32 @@ function mountPropertyList(host, decls, opts = {}) {
|
|
|
737
764
|
const types = opts.types ?? PROPERTY_TYPES;
|
|
738
765
|
const list = el("div", "set-list");
|
|
739
766
|
const keep = (parts) => (parts ?? []).filter((p) => p !== null);
|
|
767
|
+
const noun = opts.noun ?? "property";
|
|
768
|
+
const Noun = noun.charAt(0).toUpperCase() + noun.slice(1);
|
|
769
|
+
const freeNames = opts.names === "free";
|
|
740
770
|
const row = (p, i) => {
|
|
741
771
|
const name = el("input", "field set-name");
|
|
742
772
|
name.type = "text";
|
|
743
|
-
name.placeholder =
|
|
773
|
+
name.placeholder = `${Noun} name`;
|
|
744
774
|
name.value = p.name;
|
|
745
775
|
name.spellcheck = false;
|
|
746
|
-
name.
|
|
747
|
-
|
|
748
|
-
p.name = v;
|
|
776
|
+
if (freeNames) name.addEventListener("input", () => {
|
|
777
|
+
p.name = name.value;
|
|
749
778
|
changed();
|
|
750
|
-
}
|
|
779
|
+
});
|
|
780
|
+
else {
|
|
781
|
+
name.dataset["tip"] = PROPERTY_NAME_HINT;
|
|
782
|
+
bindPropertyName(name, (v) => {
|
|
783
|
+
p.name = v;
|
|
784
|
+
changed();
|
|
785
|
+
}, { hint: PROPERTY_NAME_HINT });
|
|
786
|
+
}
|
|
751
787
|
guard.track(name);
|
|
752
788
|
const type = el("select", "field set-type");
|
|
753
789
|
for (const [v, label] of types) type.append(option(v, label, v === p.type));
|
|
754
790
|
type.addEventListener("change", () => {
|
|
755
791
|
p.type = type.value;
|
|
756
|
-
|
|
757
|
-
else p.default = "";
|
|
792
|
+
delete p.default;
|
|
758
793
|
if (p.type === "enum" || p.type === "flags") p.values ??= [];
|
|
759
794
|
else delete p.values;
|
|
760
795
|
if (p.type === "quality") p.stages ??= [];
|
|
@@ -781,7 +816,7 @@ function mountPropertyList(host, decls, opts = {}) {
|
|
|
781
816
|
changed();
|
|
782
817
|
}
|
|
783
818
|
}, i === decls.length - 1);
|
|
784
|
-
const del = iconBtn("close",
|
|
819
|
+
const del = iconBtn("close", `Delete ${noun}`, () => {
|
|
785
820
|
decls.splice(i, 1);
|
|
786
821
|
render();
|
|
787
822
|
changed();
|
|
@@ -806,7 +841,7 @@ function mountPropertyList(host, decls, opts = {}) {
|
|
|
806
841
|
if (opts.purpose !== false) {
|
|
807
842
|
const purpose = el("input", "field set-purpose");
|
|
808
843
|
purpose.type = "text";
|
|
809
|
-
purpose.placeholder =
|
|
844
|
+
purpose.placeholder = `What this ${noun} is for`;
|
|
810
845
|
purpose.value = p.purpose ?? "";
|
|
811
846
|
purpose.addEventListener("input", () => {
|
|
812
847
|
if (purpose.value.trim()) p.purpose = purpose.value;
|
|
@@ -836,9 +871,9 @@ function mountPropertyList(host, decls, opts = {}) {
|
|
|
836
871
|
host.append(list, add);
|
|
837
872
|
return {
|
|
838
873
|
firstDuplicate: () => guard.firstDuplicate(),
|
|
839
|
-
firstIllegalName: () => firstIllegalPropertyName(host),
|
|
874
|
+
firstIllegalName: () => freeNames ? null : firstIllegalPropertyName(host),
|
|
840
875
|
// The Save gate takes both faults; the field's own rollover says which.
|
|
841
|
-
firstInvalid: () => guard.firstDuplicate() ?? firstIllegalPropertyName(host),
|
|
876
|
+
firstInvalid: () => guard.firstDuplicate() ?? (freeNames ? null : firstIllegalPropertyName(host)),
|
|
842
877
|
render
|
|
843
878
|
};
|
|
844
879
|
}
|