@realnation/builder-shared-sdk 2.0.0 → 2.2.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.
|
@@ -48,16 +48,32 @@ export interface InteractionStyle {
|
|
|
48
48
|
export type StyleKeyCase = 'camel' | 'kebab';
|
|
49
49
|
/** Rewrites the compound property names; transition / transform / opacity are already valid CSS. */
|
|
50
50
|
export declare function toKebabStyle(style: InteractionStyle): InteractionStyle;
|
|
51
|
+
/** Whether the operator configured any second appearance at all. Untouched keys are absent. */
|
|
52
|
+
export declare function hasSelectedAppearance(property: InteractionProperty | null | undefined): boolean;
|
|
53
|
+
export interface InteractionEnabledOptions {
|
|
54
|
+
/**
|
|
55
|
+
* The caller decides when the element is selected, so the trigger has nothing
|
|
56
|
+
* to decide for it. Inferred from passing an explicit `active` to style().
|
|
57
|
+
*/
|
|
58
|
+
selfDriven?: boolean;
|
|
59
|
+
}
|
|
51
60
|
/**
|
|
52
61
|
* Whether the element has an interaction state at all.
|
|
53
62
|
*
|
|
54
|
-
*
|
|
55
|
-
* question
|
|
56
|
-
* the change looks like once something
|
|
57
|
-
*
|
|
58
|
-
*
|
|
63
|
+
* For elements the platform drives, the trigger is the master switch: it
|
|
64
|
+
* answers the first question, does this element react to anything? Easing only
|
|
65
|
+
* describes what the change looks like once something triggers it.
|
|
66
|
+
*
|
|
67
|
+
* For an element whose owner supplies its own `active` — personality-test's
|
|
68
|
+
* options, where "selected" means the answer the player picked — the trigger
|
|
69
|
+
* has nothing left to decide, and making the operator pick an arbitrary one
|
|
70
|
+
* just to switch the section on would be a riddle. There the switch is simply
|
|
71
|
+
* whether a second appearance was configured.
|
|
72
|
+
*
|
|
73
|
+
* Either way an element nobody configured behaves exactly as it did before
|
|
74
|
+
* this feature existed. Every entry point checks this first.
|
|
59
75
|
*/
|
|
60
|
-
export declare function isInteractionEnabled(property: InteractionProperty | null | undefined): boolean;
|
|
76
|
+
export declare function isInteractionEnabled(property: InteractionProperty | null | undefined, options?: InteractionEnabledOptions): boolean;
|
|
61
77
|
export declare function interactionTriggerOf(property: InteractionProperty | null | undefined): InteractionTrigger;
|
|
62
78
|
export declare function interactionDurationOf(property: InteractionProperty | null | undefined): number;
|
|
63
79
|
/**
|
|
@@ -76,6 +92,8 @@ export interface InteractionStyleOptions {
|
|
|
76
92
|
instant?: boolean;
|
|
77
93
|
/** Key style of the returned object. Defaults to camelCase. */
|
|
78
94
|
keys?: StyleKeyCase;
|
|
95
|
+
/** See isInteractionEnabled. Set by style() when the caller supplies `active`. */
|
|
96
|
+
selfDriven?: boolean;
|
|
79
97
|
}
|
|
80
98
|
/**
|
|
81
99
|
* The style to merge onto an element for a given state.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/interaction/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,wEAAwE;AACxE,eAAO,MAAM,gBAAgB;;;;;;;;;;CAUnB,CAAC;AAEX,uFAAuF;AACvF,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAChF,eAAO,MAAM,oBAAoB,EAAE,SAAS,kBAAkB,EAAiD,CAAC;AAEhH,uFAAuF;AACvF,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,OAAO,CAAC;AAO7C,oGAAoG;AACpG,wBAAgB,YAAY,CAAC,KAAK,EAAE,gBAAgB,GAAG,gBAAgB,CAItE;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/interaction/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,wEAAwE;AACxE,eAAO,MAAM,gBAAgB;;;;;;;;;;CAUnB,CAAC;AAEX,uFAAuF;AACvF,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAChF,eAAO,MAAM,oBAAoB,EAAE,SAAS,kBAAkB,EAAiD,CAAC;AAEhH,uFAAuF;AACvF,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,OAAO,CAAC;AAO7C,oGAAoG;AACpG,wBAAgB,YAAY,CAAC,KAAK,EAAE,gBAAgB,GAAG,gBAAgB,CAItE;AAeD,+FAA+F;AAC/F,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAG/F;AAED,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,EAChD,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAGT;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,GAAG,kBAAkB,CAGzG;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAE9F;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAG5F;AAED,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+DAA+D;IAC/D,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,kFAAkF;IAClF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,EAChD,MAAM,EAAE,OAAO,EACf,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CAsClB"}
|
|
@@ -39,16 +39,38 @@ const num = (value, fallback) => {
|
|
|
39
39
|
const n = Number(value);
|
|
40
40
|
return Number.isFinite(n) ? n : fallback;
|
|
41
41
|
};
|
|
42
|
+
const SELECTED_APPEARANCE_KEYS = [
|
|
43
|
+
INTERACTION_KEYS.bgColor,
|
|
44
|
+
INTERACTION_KEYS.borderColor,
|
|
45
|
+
INTERACTION_KEYS.rotation,
|
|
46
|
+
INTERACTION_KEYS.scale,
|
|
47
|
+
INTERACTION_KEYS.opacity,
|
|
48
|
+
];
|
|
49
|
+
/** Whether the operator configured any second appearance at all. Untouched keys are absent. */
|
|
50
|
+
export function hasSelectedAppearance(property) {
|
|
51
|
+
if (!property)
|
|
52
|
+
return false;
|
|
53
|
+
return SELECTED_APPEARANCE_KEYS.some((k) => property[k] != null && property[k] !== '');
|
|
54
|
+
}
|
|
42
55
|
/**
|
|
43
56
|
* Whether the element has an interaction state at all.
|
|
44
57
|
*
|
|
45
|
-
*
|
|
46
|
-
* question
|
|
47
|
-
* the change looks like once something
|
|
48
|
-
*
|
|
49
|
-
*
|
|
58
|
+
* For elements the platform drives, the trigger is the master switch: it
|
|
59
|
+
* answers the first question, does this element react to anything? Easing only
|
|
60
|
+
* describes what the change looks like once something triggers it.
|
|
61
|
+
*
|
|
62
|
+
* For an element whose owner supplies its own `active` — personality-test's
|
|
63
|
+
* options, where "selected" means the answer the player picked — the trigger
|
|
64
|
+
* has nothing left to decide, and making the operator pick an arbitrary one
|
|
65
|
+
* just to switch the section on would be a riddle. There the switch is simply
|
|
66
|
+
* whether a second appearance was configured.
|
|
67
|
+
*
|
|
68
|
+
* Either way an element nobody configured behaves exactly as it did before
|
|
69
|
+
* this feature existed. Every entry point checks this first.
|
|
50
70
|
*/
|
|
51
|
-
export function isInteractionEnabled(property) {
|
|
71
|
+
export function isInteractionEnabled(property, options = {}) {
|
|
72
|
+
if (options.selfDriven)
|
|
73
|
+
return hasSelectedAppearance(property);
|
|
52
74
|
return interactionTriggerOf(property) !== 'none';
|
|
53
75
|
}
|
|
54
76
|
export function interactionTriggerOf(property) {
|
|
@@ -78,7 +100,7 @@ export function interactionPeriodOf(property) {
|
|
|
78
100
|
* an unset colour must inherit the normal appearance rather than reset it.
|
|
79
101
|
*/
|
|
80
102
|
export function interactionStyle(property, active, options = {}) {
|
|
81
|
-
if (!isInteractionEnabled(property))
|
|
103
|
+
if (!isInteractionEnabled(property, { selfDriven: options.selfDriven }))
|
|
82
104
|
return {};
|
|
83
105
|
const bag = property;
|
|
84
106
|
// An instant change is still expressible: set the duration to zero. Easing
|
|
@@ -19,6 +19,17 @@ export interface UseInteractionStateOptions {
|
|
|
19
19
|
*/
|
|
20
20
|
keys?: StyleKeyCase;
|
|
21
21
|
}
|
|
22
|
+
export interface InteractionBindOptions {
|
|
23
|
+
/**
|
|
24
|
+
* Makes Click behave like a radio group instead of an independent toggle:
|
|
25
|
+
* picking one clears the others, and clicking the picked one keeps it picked.
|
|
26
|
+
*
|
|
27
|
+
* Single-choice answers need this. Without it a player who picks A and then B
|
|
28
|
+
* leaves both looking chosen, which is worse than no feedback at all.
|
|
29
|
+
* Ignored by the other triggers, where a transient state has no siblings.
|
|
30
|
+
*/
|
|
31
|
+
group?: string;
|
|
32
|
+
}
|
|
22
33
|
export interface InteractionStateApi {
|
|
23
34
|
/**
|
|
24
35
|
* The style to merge onto an element.
|
|
@@ -28,7 +39,7 @@ export interface InteractionStateApi {
|
|
|
28
39
|
*/
|
|
29
40
|
style(property: InteractionProperty | null | undefined, key: string, active?: boolean): InteractionStyle;
|
|
30
41
|
/** Event handlers to v-bind. Empty unless the trigger is Hover / Press or Click. */
|
|
31
|
-
bind(property: InteractionProperty | null | undefined, key: string): Record<string, () => void>;
|
|
42
|
+
bind(property: InteractionProperty | null | undefined, key: string, options?: InteractionBindOptions): Record<string, () => void>;
|
|
32
43
|
/**
|
|
33
44
|
* Restarts the timed triggers for exactly these elements.
|
|
34
45
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vue.d.ts","sourceRoot":"","sources":["../../src/interaction/vue.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEtF,wFAAwF;AACxF,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,CAAC;CAClD;AAED,MAAM,WAAW,0BAA0B;IACzC,gFAAgF;IAChF,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IACnD,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,8EAA8E;IAC9E,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IACrC;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,YAAY,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAC;IACzG,oFAAoF;IACpF,IAAI,
|
|
1
|
+
{"version":3,"file":"vue.d.ts","sourceRoot":"","sources":["../../src/interaction/vue.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEtF,wFAAwF;AACxF,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,CAAC;CAClD;AAED,MAAM,WAAW,0BAA0B;IACzC,gFAAgF;IAChF,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IACnD,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,8EAA8E;IAC9E,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IACrC;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,YAAY,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAC;IACzG,oFAAoF;IACpF,IAAI,CACF,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,EAChD,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,CAAC;IAC9B;;;;;;OAMG;IACH,IAAI,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACxC,oEAAoE;IACpE,IAAI,IAAI,IAAI,CAAC;IACb,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/B,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;CAC3C;AAUD,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,0BAA+B,GAAG,mBAAmB,CAqGjG"}
|
package/dist/interaction/vue.js
CHANGED
|
@@ -35,27 +35,52 @@ export function useInteractionState(options = {}) {
|
|
|
35
35
|
// for its first frame; one boolean cannot say both things.
|
|
36
36
|
const instant = reactive({});
|
|
37
37
|
const timers = new Map();
|
|
38
|
+
// Which group each key belongs to, so a radio click knows whom to clear.
|
|
39
|
+
const groups = new Map();
|
|
38
40
|
// Guards the deferred On Appear callback: by the time the frame lands the
|
|
39
41
|
// player may already have navigated on, and the element is gone.
|
|
40
42
|
let generation = 0;
|
|
41
43
|
const stop = () => {
|
|
42
44
|
timers.forEach((handle) => clearTimer(handle));
|
|
43
45
|
timers.clear();
|
|
46
|
+
groups.clear();
|
|
44
47
|
generation += 1;
|
|
45
48
|
};
|
|
46
49
|
const api = {
|
|
47
50
|
style(property, key, forced) {
|
|
48
51
|
const on = forced ?? active[key] ?? false;
|
|
49
|
-
|
|
52
|
+
// Passing `active` at all is the declaration: this caller owns the timing,
|
|
53
|
+
// so the configured trigger is not what decides whether the state exists.
|
|
54
|
+
return interactionStyle(property, on, {
|
|
55
|
+
instant: instant[key] === true,
|
|
56
|
+
keys: options.keys,
|
|
57
|
+
selfDriven: forced !== undefined,
|
|
58
|
+
});
|
|
50
59
|
},
|
|
51
|
-
bind(property, key) {
|
|
60
|
+
bind(property, key, bindOptions = {}) {
|
|
52
61
|
if (!isInteractionEnabled(property))
|
|
53
62
|
return {};
|
|
54
63
|
const trigger = interactionTriggerOf(property);
|
|
55
64
|
if (trigger === 'click') {
|
|
65
|
+
const group = bindOptions.group;
|
|
66
|
+
if (group)
|
|
67
|
+
groups.set(key, group);
|
|
56
68
|
// Deliberately not stopping propagation: the element may also carry a
|
|
57
|
-
// link
|
|
58
|
-
|
|
69
|
+
// link, a node connection, or the game's own answer handler, and the
|
|
70
|
+
// visual state is only a layer on top of whatever else happens.
|
|
71
|
+
return {
|
|
72
|
+
onClick: () => {
|
|
73
|
+
if (!group) {
|
|
74
|
+
active[key] = !active[key];
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
groups.forEach((g, k) => {
|
|
78
|
+
if (g === group && k !== key)
|
|
79
|
+
active[k] = false;
|
|
80
|
+
});
|
|
81
|
+
active[key] = true;
|
|
82
|
+
},
|
|
83
|
+
};
|
|
59
84
|
}
|
|
60
85
|
if (trigger !== 'hover')
|
|
61
86
|
return {};
|