@syntrologie/adapt-feedback 2.28.0 → 2.29.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.
@@ -23,6 +23,9 @@ export declare class SyntroFeedbackElement extends LitElement {
23
23
  _direction: {
24
24
  state: boolean;
25
25
  };
26
+ _entering: {
27
+ state: boolean;
28
+ };
26
29
  };
27
30
  static styles: import("lit").CSSResult;
28
31
  config: FeedbackConfig | undefined;
@@ -30,7 +33,14 @@ export declare class SyntroFeedbackElement extends LitElement {
30
33
  tileId: string;
31
34
  private _engine;
32
35
  private _direction;
36
+ /** Transient: true while a step-slide is playing; gates the animation. */
37
+ private _entering;
38
+ private _settleArmed;
39
+ private _settleTimer;
33
40
  willUpdate(changed: Map<string, unknown>): void;
41
+ disconnectedCallback(): void;
42
+ connectedCallback(): void;
43
+ updated(): void;
34
44
  private _onAnswer;
35
45
  private _goBack;
36
46
  private _renderStepInput;
@@ -1 +1 @@
1
- {"version":3,"file":"FeedbackWidget.d.ts","sourceRoot":"","sources":["../src/FeedbackWidget.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAGrD,OAAO,4BAA4B,CAAC;AACpC,OAAO,0BAA0B,CAAC;AAClC,OAAO,yBAAyB,CAAC;AACjC,OAAO,4BAA4B,CAAC;AACpC,OAAO,0BAA0B,CAAC;AAClC,OAAO,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAc,MAAM,YAAY,CAAC;AAEpF,qBAAa,qBAAsB,SAAQ,UAAU;IACnD,OAAgB,UAAU;;;;;;;;;;;;;;;;MAMxB;IAEF,OAAgB,MAAM,0BAwFpB;IAEF,MAAM,EAAE,cAAc,GAAG,SAAS,CAAC;IACnC,OAAO,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAC3C,MAAM,EAAE,MAAM,CAAqB;IAEnC,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,UAAU,CAAiC;IAE1C,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAUjD,OAAO,CAAC,SAAS,CA4Bf;IAEF,OAAO,CAAC,OAAO,CAQb;IAEF,OAAO,CAAC,gBAAgB;IAgDf,MAAM;CAuDhB;AAiBD,eAAO,MAAM,0BAA0B;qBACpB,WAAW,gBAAgB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAkEpE,CAAC"}
1
+ {"version":3,"file":"FeedbackWidget.d.ts","sourceRoot":"","sources":["../src/FeedbackWidget.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAGrD,OAAO,4BAA4B,CAAC;AACpC,OAAO,0BAA0B,CAAC;AAClC,OAAO,yBAAyB,CAAC;AACjC,OAAO,4BAA4B,CAAC;AACpC,OAAO,0BAA0B,CAAC;AAClC,OAAO,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAc,MAAM,YAAY,CAAC;AAEpF,qBAAa,qBAAsB,SAAQ,UAAU;IACnD,OAAgB,UAAU;;;;;;;;;;;;;;;;;;;MAOxB;IAEF,OAAgB,MAAM,0BAsGpB;IAEF,MAAM,EAAE,cAAc,GAAG,SAAS,CAAC;IACnC,OAAO,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAC3C,MAAM,EAAE,MAAM,CAAqB;IAEnC,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,UAAU,CAAiC;IACnD,0EAA0E;IAC1E,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,YAAY,CAA4C;IAEvD,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAUxC,oBAAoB,IAAI,IAAI;IAQ5B,iBAAiB,IAAI,IAAI;IAOzB,OAAO,IAAI,IAAI;IA0BxB,OAAO,CAAC,SAAS,CAoCf;IAEF,OAAO,CAAC,OAAO,CAYb;IAEF,OAAO,CAAC,gBAAgB;IAgDf,MAAM;CAwDhB;AAiBD,eAAO,MAAM,0BAA0B;qBACpB,WAAW,gBAAgB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAkEpE,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  FeedbackWidgetLitMountable,
3
3
  SyntroFeedbackElement
4
- } from "./chunk-6CCN3QKN.js";
4
+ } from "./chunk-AJOEEXTA.js";
5
5
  export {
6
6
  FeedbackWidgetLitMountable,
7
7
  SyntroFeedbackElement
@@ -1,3 +1,11 @@
1
+ // ../../../node_modules/@lit/context/lib/create-context.js
2
+ function n(n2) {
3
+ return n2;
4
+ }
5
+
6
+ // ../../sdk-contracts/dist/canvas-context.js
7
+ var canvasRuntimeContext = n("syntrologie:canvas-runtime");
8
+
1
9
  // ../../sdk-contracts/dist/mount-plumbing.js
2
10
  var MOUNT_PLUMBING_KEYS = ["instanceId", "runtime", "tileId"];
3
11
  function stripMountPlumbing(config) {
@@ -11,6 +19,9 @@ function stripMountPlumbing(config) {
11
19
  return out;
12
20
  }
13
21
 
22
+ // ../../sdk-contracts/dist/routes.js
23
+ var utf8Decoder = new TextDecoder("utf-8", { fatal: false });
24
+
14
25
  // ../../sdk-contracts/dist/schemas.js
15
26
  import { z } from "zod";
16
27
  var AnchorIdZ = z.object({
@@ -99,6 +110,8 @@ var FrequencyLimitConditionZ = z.object({
99
110
  var MatchOpZ = z.object({
100
111
  equals: z.union([z.string(), z.number(), z.boolean()]).optional(),
101
112
  contains: z.string().optional()
113
+ }).refine((operator) => Number(operator.equals !== void 0) + Number(operator.contains !== void 0) === 1, {
114
+ message: "Exactly one of equals or contains must be specified."
102
115
  }).describe("Match operator for counter filters. Exactly one of equals or contains must be specified.");
103
116
  var CounterDefZ = z.object({
104
117
  events: z.array(CountableEventZ).min(1).describe("Event names to count. Use values from the countable events enum."),
@@ -188,7 +201,7 @@ var FlowEngine = class {
188
201
  this._answers = /* @__PURE__ */ new Map();
189
202
  this._validate(steps);
190
203
  this._steps = steps;
191
- this._stepMap = new Map(steps.map((s) => [s.id, s]));
204
+ this._stepMap = new Map(steps.map((s4) => [s4.id, s4]));
192
205
  this._path = [steps[0].id];
193
206
  }
194
207
  get currentStep() {
@@ -241,7 +254,7 @@ var FlowEngine = class {
241
254
  return this._nextInArray(step.id);
242
255
  }
243
256
  _nextInArray(currentId) {
244
- const idx = this._steps.findIndex((s) => s.id === currentId);
257
+ const idx = this._steps.findIndex((s4) => s4.id === currentId);
245
258
  return this._steps[idx + 1].id;
246
259
  }
247
260
  _evaluateRule(rule, value) {
@@ -276,12 +289,12 @@ var FlowEngine = class {
276
289
  }
277
290
  ids.add(step.id);
278
291
  }
279
- const hasEnd = steps.some((s) => s.type === "end");
292
+ const hasEnd = steps.some((s4) => s4.type === "end");
280
293
  if (!hasEnd) {
281
294
  throw new FlowEngineValidationError('At least one step must have type "end"');
282
295
  }
283
- for (let i = 0; i < steps.length; i++) {
284
- const step = steps[i];
296
+ for (let i2 = 0; i2 < steps.length; i2++) {
297
+ const step = steps[i2];
285
298
  if (typeof step.next === "string") {
286
299
  if (!ids.has(step.next)) {
287
300
  throw new FlowEngineValidationError(
@@ -297,7 +310,7 @@ var FlowEngine = class {
297
310
  }
298
311
  }
299
312
  }
300
- if (step.type !== "end" && step.next === void 0 && i === steps.length - 1) {
313
+ if (step.type !== "end" && step.next === void 0 && i2 === steps.length - 1) {
301
314
  throw new FlowEngineValidationError(
302
315
  `Step "${step.id}" is last in the array with no explicit "next" and is not an end step`
303
316
  );
@@ -470,18 +483,18 @@ var NpsInput = class extends LitElement3 {
470
483
  );
471
484
  }
472
485
  render() {
473
- const items = Array.from({ length: 11 }, (_, i) => i);
486
+ const items = Array.from({ length: 11 }, (_, i2) => i2);
474
487
  return html3`
475
488
  <div>
476
489
  <div class="nps-scale">
477
490
  ${items.map(
478
- (n) => html3`
491
+ (n2) => html3`
479
492
  <button
480
493
  type="button"
481
- aria-label="Score ${n}"
482
- aria-pressed=${this.value === n ? "true" : "false"}
483
- @click=${() => this._select(n)}
484
- >${n}</button>
494
+ aria-label="Score ${n2}"
495
+ aria-pressed=${this.value === n2 ? "true" : "false"}
496
+ @click=${() => this._select(n2)}
497
+ >${n2}</button>
485
498
  `
486
499
  )}
487
500
  </div>
@@ -556,18 +569,18 @@ var RatingInput = class extends LitElement4 {
556
569
  }
557
570
  render() {
558
571
  const count = this.max || 5;
559
- const items = Array.from({ length: count }, (_, i) => i + 1);
572
+ const items = Array.from({ length: count }, (_, i2) => i2 + 1);
560
573
  return html4`
561
574
  <div class="rating-row">
562
575
  ${items.map(
563
- (n) => html4`
576
+ (n2) => html4`
564
577
  <button
565
578
  type="button"
566
- aria-label="Rate ${n} of ${count}"
567
- aria-pressed=${this.value === n ? "true" : "false"}
568
- class=${this.value === n ? "selected" : ""}
569
- @click=${() => this._select(n)}
570
- >${n}</button>
579
+ aria-label="Rate ${n2} of ${count}"
580
+ aria-pressed=${this.value === n2 ? "true" : "false"}
581
+ class=${this.value === n2 ? "selected" : ""}
582
+ @click=${() => this._select(n2)}
583
+ >${n2}</button>
571
584
  `
572
585
  )}
573
586
  </div>
@@ -619,8 +632,8 @@ var TextInput = class extends LitElement5 {
619
632
  this.value = "";
620
633
  this.required = true;
621
634
  this._currentText = "";
622
- this._handleInput = (e) => {
623
- this._currentText = e.target.value;
635
+ this._handleInput = (e2) => {
636
+ this._currentText = e2.target.value;
624
637
  this.requestUpdate();
625
638
  };
626
639
  this._submit = () => {
@@ -784,10 +797,13 @@ var SyntroFeedbackElement = class extends LitElement7 {
784
797
  super(...arguments);
785
798
  this.tileId = "feedback-widget";
786
799
  this._direction = "forward";
787
- this._onAnswer = (e) => {
800
+ /** Transient: true while a step-slide is playing; gates the animation. */
801
+ this._entering = true;
802
+ this._settleArmed = false;
803
+ this._onAnswer = (e2) => {
788
804
  if (!this._engine || !this.config) return;
789
805
  const step = this._engine.currentStep;
790
- const { value } = e.detail;
806
+ const { value } = e2.detail;
791
807
  this.runtime?.events.publish("feedback:response", {
792
808
  surveyId: this.tileId,
793
809
  stepId: step.id,
@@ -795,6 +811,10 @@ var SyntroFeedbackElement = class extends LitElement7 {
795
811
  value,
796
812
  stepIndex: this._engine.stepIndex
797
813
  });
814
+ if (this._direction !== "forward") {
815
+ this._entering = true;
816
+ this._settleArmed = false;
817
+ }
798
818
  this._direction = "forward";
799
819
  this._engine.answer(value);
800
820
  const updated = Object.create(
@@ -812,6 +832,10 @@ var SyntroFeedbackElement = class extends LitElement7 {
812
832
  };
813
833
  this._goBack = () => {
814
834
  if (!this._engine) return;
835
+ if (this._direction !== "back") {
836
+ this._entering = true;
837
+ this._settleArmed = false;
838
+ }
815
839
  this._direction = "back";
816
840
  this._engine.goBack();
817
841
  this._engine = Object.create(
@@ -829,6 +853,35 @@ var SyntroFeedbackElement = class extends LitElement7 {
829
853
  }
830
854
  }
831
855
  }
856
+ disconnectedCallback() {
857
+ if (this._settleTimer !== void 0) clearTimeout(this._settleTimer);
858
+ this._settleArmed = false;
859
+ super.disconnectedCallback();
860
+ }
861
+ connectedCallback() {
862
+ super.connectedCallback();
863
+ if (this._entering) this.requestUpdate();
864
+ }
865
+ updated() {
866
+ if (!this._entering || this._settleArmed) return;
867
+ const content = this.shadowRoot?.querySelector(".step-content");
868
+ if (!content) return;
869
+ this._settleArmed = true;
870
+ const settle = () => {
871
+ if (this._settleTimer !== void 0) {
872
+ clearTimeout(this._settleTimer);
873
+ this._settleTimer = void 0;
874
+ }
875
+ content.removeEventListener("animationend", onEnd);
876
+ this._settleArmed = false;
877
+ this._entering = false;
878
+ };
879
+ const onEnd = (e2) => {
880
+ if (e2.target === content) settle();
881
+ };
882
+ content.addEventListener("animationend", onEnd);
883
+ this._settleTimer = setTimeout(settle, 500);
884
+ }
832
885
  _renderStepInput(step) {
833
886
  const prevAnswer = this._engine?.answers.get(step.id);
834
887
  switch (step.type) {
@@ -879,9 +932,10 @@ var SyntroFeedbackElement = class extends LitElement7 {
879
932
  const showProgress = this.config.showProgress !== false;
880
933
  const allowBack = this.config.allowBack === true;
881
934
  const canGoBack = allowBack && this._engine.path.length > 1 && step.type !== "end";
882
- const totalSteps = this.config.steps.filter((s) => s.type !== "end").length;
935
+ const totalSteps = this.config.steps.filter((s4) => s4.type !== "end").length;
883
936
  const progressPct = totalSteps > 0 ? this._engine.stepsCompleted / totalSteps * 100 : 0;
884
- const animClass = this._direction === "forward" ? "slide-in-right" : "slide-in-left";
937
+ const slideClass = this._direction === "forward" ? "slide-in-right" : "slide-in-left";
938
+ const animClass = this._entering ? `is-entering ${slideClass}` : "";
885
939
  return html7`
886
940
  ${this.config.title ? html7`<div class="header">${this.config.title}</div>` : nothing}
887
941
  ${showProgress && step.type !== "end" ? html7`<div class="progress-bar">
@@ -908,7 +962,8 @@ SyntroFeedbackElement.properties = {
908
962
  runtime: { attribute: false },
909
963
  tileId: { type: String },
910
964
  _engine: { state: true },
911
- _direction: { state: true }
965
+ _direction: { state: true },
966
+ _entering: { state: true }
912
967
  };
913
968
  SyntroFeedbackElement.styles = css7`
914
969
  :host {
@@ -944,14 +999,21 @@ SyntroFeedbackElement.styles = css7`
944
999
  }
945
1000
  .step-content {
946
1001
  padding: 16px;
1002
+ /* Resting state is VISIBLE (GPU/compositing hazard fix): the step-slide
1003
+ carried animation-fill-mode:both from a keyframe that starts at
1004
+ opacity:0, so a dropped/suppressed animation stranded the step blank.
1005
+ The slide is now gated behind the transient .is-entering class; at rest
1006
+ the step is simply visible. */
1007
+ }
1008
+ .step-content.is-entering {
947
1009
  animation-duration: 0.25s;
948
1010
  animation-fill-mode: both;
949
1011
  animation-timing-function: ease-out;
950
1012
  }
951
- .step-content.slide-in-right {
1013
+ .step-content.is-entering.slide-in-right {
952
1014
  animation-name: slideInRight;
953
1015
  }
954
- .step-content.slide-in-left {
1016
+ .step-content.is-entering.slide-in-left {
955
1017
  animation-name: slideInLeft;
956
1018
  }
957
1019
  @keyframes slideInRight {
@@ -962,6 +1024,13 @@ SyntroFeedbackElement.styles = css7`
962
1024
  from { transform: translateX(-30px); opacity: 0; }
963
1025
  to { transform: translateX(0); opacity: 1; }
964
1026
  }
1027
+ @media (prefers-reduced-motion: reduce) {
1028
+ .step-content.is-entering {
1029
+ animation: none;
1030
+ opacity: 1;
1031
+ transform: none;
1032
+ }
1033
+ }
965
1034
  .prompt {
966
1035
  font-size: 15px;
967
1036
  font-weight: 500;
@@ -1031,8 +1100,8 @@ var FeedbackWidgetLitMountable = {
1031
1100
  el.style.cssText = "display:flex;flex-direction:column;height:100%;width:100%;";
1032
1101
  container.appendChild(el);
1033
1102
  let completed = false;
1034
- const onAnswer = (e) => {
1035
- const detail = e.detail;
1103
+ const onAnswer = (e2) => {
1104
+ const detail = e2.detail;
1036
1105
  if (tracker && !tracker.isComplete) {
1037
1106
  tracker.answer(detail.value);
1038
1107
  if (tracker.isComplete) completed = true;
@@ -1058,4 +1127,32 @@ export {
1058
1127
  SyntroFeedbackElement,
1059
1128
  FeedbackWidgetLitMountable
1060
1129
  };
1061
- //# sourceMappingURL=chunk-6CCN3QKN.js.map
1130
+ /*! Bundled license information:
1131
+
1132
+ @lit/context/lib/context-request-event.js:
1133
+ @lit/context/lib/create-context.js:
1134
+ @lit/context/lib/controllers/context-consumer.js:
1135
+ @lit/context/lib/value-notifier.js:
1136
+ @lit/context/lib/controllers/context-provider.js:
1137
+ @lit/context/lib/context-root.js:
1138
+ (**
1139
+ * @license
1140
+ * Copyright 2021 Google LLC
1141
+ * SPDX-License-Identifier: BSD-3-Clause
1142
+ *)
1143
+
1144
+ @lit/context/lib/decorators/provide.js:
1145
+ (**
1146
+ * @license
1147
+ * Copyright 2017 Google LLC
1148
+ * SPDX-License-Identifier: BSD-3-Clause
1149
+ *)
1150
+
1151
+ @lit/context/lib/decorators/consume.js:
1152
+ (**
1153
+ * @license
1154
+ * Copyright 2022 Google LLC
1155
+ * SPDX-License-Identifier: BSD-3-Clause
1156
+ *)
1157
+ */
1158
+ //# sourceMappingURL=chunk-AJOEEXTA.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../node_modules/@lit/context/src/lib/create-context.ts", "../../../sdk-contracts/dist/canvas-context.js", "../../../sdk-contracts/dist/mount-plumbing.js", "../../../sdk-contracts/dist/routes.js", "../../../sdk-contracts/dist/schemas.js", "../src/FeedbackWidget.ts", "../src/engine/FlowEngine.ts", "../src/rendering/ChoiceInput.ts", "../src/rendering/EndScreen.ts", "../src/rendering/NpsInput.ts", "../src/rendering/RatingInput.ts", "../src/rendering/TextInput.ts", "../src/rendering/ThumbsInput.ts"],
4
+ "sourcesContent": ["/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * The Context type defines a type brand to associate a key value with the context value type\n */\nexport type Context<KeyType, ValueType> = KeyType & {__context__: ValueType};\n\n/**\n * @deprecated use Context instead\n */\nexport type ContextKey<KeyType, ValueType> = Context<KeyType, ValueType>;\n\n/**\n * A helper type which can extract a Context value type from a Context type\n */\nexport type ContextType<Key extends Context<unknown, unknown>> =\n Key extends Context<unknown, infer ValueType> ? ValueType : never;\n\n/**\n * Creates a typed Context.\n *\n * Contexts are compared with strict equality.\n *\n * If you want two separate `createContext()` calls to referer to the same\n * context, then use a key that will by equal under strict equality like a\n * string for `Symbol.for()`:\n *\n * ```ts\n * // true\n * createContext('my-context') === createContext('my-context')\n * // true\n * createContext(Symbol.for('my-context')) === createContext(Symbol.for('my-context'))\n * ```\n *\n * If you want a context to be unique so that it's guaranteed to not collide\n * with other contexts, use a key that's unique under strict equality, like\n * a `Symbol()` or object.:\n *\n * ```\n * // false\n * createContext({}) === createContext({})\n * // false\n * createContext(Symbol('my-context')) === createContext(Symbol('my-context'))\n * ```\n *\n * @param key a context key value\n * @template ValueType the type of value that can be provided by this context.\n * @returns the context key value cast to `Context<K, ValueType>`\n */\nexport function createContext<ValueType, K = unknown>(key: K) {\n return key as Context<K, ValueType>;\n}\n", "/**\n * Canvas runtime context \u2014 the shared @lit/context symbol both\n * runtime-sdk (the provider) and canvas-sdk / canvas authors (the\n * consumers) use to thread a narrow runtime handle through the canvas\n * element tree.\n *\n * Living here keeps the symbol identity stable across both packages.\n * If canvas-sdk created its own symbol with `createContext(...)`, it\n * would never match the one runtime-sdk publishes, and `<sc-mount>`\n * would silently see `undefined` instead of the widget registry.\n *\n * The shape declared here is a NARROW VIEW of `SmartCanvasRuntime`.\n * Canvas-side code reads only this subset. The runtime-sdk's\n * `SmartCanvasRuntime` type is a structural superset.\n */\nimport { createContext } from '@lit/context';\n/**\n * The @lit/context symbol. Both runtime-sdk's ContextProvider and\n * canvas-sdk's ContextConsumer must import THIS exact symbol \u2014 not a\n * symbol with the same string name \u2014 for context propagation to work.\n */\nexport const canvasRuntimeContext = createContext('syntrologie:canvas-runtime');\n", "/**\n * Mount contract types and helper for adaptive widget mountables.\n *\n * The `WidgetRegistry` in `@syntrologie/runtime-sdk` delivers props to each\n * mountable as `{ ...tile.props, instanceId, runtime, tileId? }` spread flat\n * (see `MountableContract.test.ts` in runtime-sdk for the end-to-end lockdown).\n *\n * Adaptives that strip plumbing manually maintain private blacklists that\n * silently drift when the contract grows (PR #2234 and #2238 documented this).\n * `stripMountPlumbing` centralizes the list so adding a new plumbing key in\n * the future is a one-line change here that every adaptive picks up automatically.\n *\n * Adaptives whose widget schemas use Zod `.strict()` MUST call this before\n * validating, or strict-mode will reject the runtime-injected keys and the\n * widget will silently render its empty/error state.\n */\nexport const MOUNT_PLUMBING_KEYS = ['instanceId', 'runtime', 'tileId'];\nexport function stripMountPlumbing(config) {\n if (!config || typeof config !== 'object') {\n return {};\n }\n const out = { ...config };\n for (const key of MOUNT_PLUMBING_KEYS) {\n delete out[key];\n }\n return out;\n}\n", "/**\n * Canonical route normalization. See `routes.md` for rules and\n * `normalize-route.cases.json` for the parity corpus shared with the\n * Python implementation in syntrologie_common/sdk/routing.py.\n *\n * Two exports \u2014 `normalizeRoute` for literal paths, `normalizeRoutePattern`\n * for activation patterns containing `*`, `**`, `:param`. Today they share\n * an implementation because the rules happen to be wildcard-safe (no\n * lowercase, unreserved-only decode, slash collapse preserves `**`).\n * The seam is preserved as separate exports so the API can diverge\n * without consumer churn if rules change.\n */\n// RFC 3986 reserved characters (gen-delims + sub-delims). When a `%XX`\n// sequence decodes to one of these bytes, we keep the percent-encoded\n// form \u2014 decoding would re-segment the path or change its meaning.\nconst RESERVED_BYTES = new Set([\n 0x21, // !\n 0x23, // #\n 0x24, // $\n 0x26, // &\n 0x27, // '\n 0x28, // (\n 0x29, // )\n 0x2a, // *\n 0x2b, // +\n 0x2c, // ,\n 0x2f, // /\n 0x3a, // :\n 0x3b, // ;\n 0x3d, // =\n 0x3f, // ?\n 0x40, // @\n 0x5b, // [\n 0x5d, // ]\n]);\nconst utf8Decoder = new TextDecoder('utf-8', { fatal: false });\n/** Decode `%XX` sequences for unreserved bytes only. Collapses\n * adjacent `%XX` runs into a UTF-8 decode so `%C3%A9` \u2192 `\u00E9`. */\nfunction decodeUnreservedOnly(input) {\n let out = '';\n let pending = [];\n const flushPending = () => {\n if (pending.length === 0)\n return;\n const bytes = new Uint8Array(pending);\n out += utf8Decoder.decode(bytes);\n pending = [];\n };\n let i = 0;\n while (i < input.length) {\n const ch = input[i];\n if (ch === '%' && i + 2 < input.length && isHex(input[i + 1]) && isHex(input[i + 2])) {\n const byte = parseInt(input.slice(i + 1, i + 3), 16);\n if (RESERVED_BYTES.has(byte)) {\n flushPending();\n // Keep raw, but normalize hex case to uppercase so the\n // canonical form is stable across input casing.\n out += `%${input.slice(i + 1, i + 3).toUpperCase()}`;\n i += 3;\n }\n else {\n pending.push(byte);\n i += 3;\n }\n }\n else {\n flushPending();\n out += ch;\n i += 1;\n }\n }\n flushPending();\n return out;\n}\nfunction isHex(c) {\n return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');\n}\n/** Strip query string and hash fragment. */\nfunction stripQueryAndHash(s) {\n const q = s.indexOf('?');\n if (q !== -1)\n s = s.slice(0, q);\n const h = s.indexOf('#');\n if (h !== -1)\n s = s.slice(0, h);\n return s;\n}\n/**\n * Normalize a literal path (e.g. `window.location.pathname`, an\n * action's `route` field, a wiki route key).\n *\n * Throws `TypeError` if the input is not an absolute path. Callers\n * that want a soft API should use {@link normalizeRouteWithChange}.\n */\nexport function normalizeRoute(path) {\n if (typeof path !== 'string' || path.length === 0) {\n throw new TypeError('normalizeRoute: input must be a non-empty string');\n }\n if (!path.startsWith('/')) {\n throw new TypeError(`normalizeRoute: input must be absolute (start with '/'); got ${JSON.stringify(path)}`);\n }\n let s = stripQueryAndHash(path);\n s = decodeUnreservedOnly(s);\n s = s.replace(/\\/+/g, '/');\n if (s.length > 1 && s.endsWith('/'))\n s = s.slice(0, -1);\n return s;\n}\n/**\n * Normalize an activation route pattern. Preserves `*`, `**`,\n * `:param` exactly. Today equivalent to {@link normalizeRoute} \u2014 kept\n * as a separate export so rules can diverge later without API churn.\n */\nexport function normalizeRoutePattern(pattern) {\n return normalizeRoute(pattern);\n}\n/**\n * Normalize a route and report whether the input was already\n * canonical. Used by authoring tools to decide whether to emit a\n * warning to the LLM.\n */\nexport function normalizeRouteWithChange(path) {\n const canonical = normalizeRoute(path);\n return { canonical, changed: canonical !== path };\n}\n/** Pattern-side counterpart of {@link normalizeRouteWithChange}. */\nexport function normalizeRoutePatternWithChange(pattern) {\n const canonical = normalizeRoutePattern(pattern);\n return { canonical, changed: canonical !== pattern };\n}\n/**\n * Case-insensitive comparison of two already-canonical paths. Use\n * this anywhere two routes are compared for equality (wiki lookups,\n * non-pattern action route gates) \u2014 preserves casing in the inputs\n * while honoring case-insensitive routing on the customer's site.\n */\nexport function routesMatch(a, b) {\n return a.toLowerCase() === b.toLowerCase();\n}\n", "/**\n * Shared Zod schemas for decision strategies, conditions, and event scoping.\n *\n * These are the canonical definitions \u2014 runtime-sdk and all adaptive packages\n * should import from here instead of duplicating.\n */\nimport { z } from 'zod';\n// =============================================================================\n// ANCHOR ID SCHEMA\n// =============================================================================\nexport const AnchorIdZ = z\n .object({\n selector: z.string(),\n route: z.union([z.string(), z.array(z.string())]),\n})\n .strict();\n// =============================================================================\n// AUTHORING FIELDS \u2014 id / title / description / validation\n//\n// Shared fields every action carries. `id` is the action identifier the\n// runtime uses to dispatch, dedupe, and drop/replace actions \u2014 it is NOT\n// stripped before serving. `title` / `description` / `validation` are\n// authoring-only metadata stripped server-side in `to_runtime_config`\n// (platform/backend/app/domains/experiments/helpers.py).\n//\n// They all appear in the JSON Schema (and therefore in the tactician's\n// prompt) because the LLM needs to know they are valid action properties \u2014\n// otherwise schema validation would reject what the prompt commands.\n//\n// Each action variant should `.extend(AuthoringFieldsZ)` alongside any\n// triggerWhen/condition extensions.\n// =============================================================================\nexport const AuthoringFieldsZ = {\n id: z.string().optional().describe('Stable action identifier (e.g. \"act_3db6a14d2ab0\").'),\n title: z\n .string()\n .max(200)\n .optional()\n .describe('Authoring-only: short label shown on the action plan dashboard. Stripped before serving to the runtime SDK.'),\n description: z\n .string()\n .max(1000)\n .optional()\n .describe('Authoring-only: one-sentence explanation of what this action does and why. Stripped before serving to the runtime SDK.'),\n validation: z\n .array(z.string().max(500))\n .max(10)\n .optional()\n .describe('Authoring-only: ordered steps a reviewer can follow to trigger this action and visually confirm it works. Each entry is one step. Stripped before serving to the runtime SDK.'),\n};\n// =============================================================================\n// TRIGGER VOCABULARY \u2014 canonical lists of valid event names, metric keys, etc.\n// These flow through to the JSON schema as enums and are used by the LLM prompt.\n// =============================================================================\n/** Events that can be counted in event_count conditions.\n *\n * Every value here must be an event the runtime actually emits \u2014 either a\n * PostHog-autocapture normalization (ui.click/scroll/input/change/submit) or\n * an event-processor detector (ui.hover/idle/scroll_thrash/focus_bounce/\n * hesitate/rage_click). Do not add aspirational names; a trigger counting an\n * event nothing emits never fires.\n */\nexport const COUNTABLE_EVENTS = [\n // User interactions (from PostHog autocapture normalization)\n 'ui.click',\n 'ui.scroll',\n 'ui.input',\n 'ui.change',\n 'ui.submit',\n // Behavioral detectors (from event-processor)\n 'ui.hover',\n 'ui.idle',\n 'ui.scroll_thrash',\n 'ui.focus_bounce',\n 'ui.hesitate',\n 'ui.rage_click',\n // Navigation\n 'nav.page_view',\n 'nav.page_leave',\n];\nexport const CountableEventZ = z\n .enum(COUNTABLE_EVENTS)\n .describe('Event name to count. ui.* = user interactions and behavioral detectors (hesitate, rage_click, scroll_thrash, focus_bounce, idle, hover); nav.* = page navigation.');\n/** Valid session metric keys. */\nexport const SESSION_METRIC_KEYS = ['time_on_page', 'page_views', 'scroll_depth'];\nexport const SessionMetricKeyZ = z\n .enum(SESSION_METRIC_KEYS)\n .describe('Session metric key. time_on_page = seconds on current page, page_views = pages visited this session, scroll_depth = 0-100 percentage.');\n/** Element chain match field prefixes for counter filters. */\nexport const ELEMENT_MATCH_FIELDS = ['tag_name', '$el_text'];\n// Note: attr__* is a dynamic prefix (attr__data-id, attr__class, attr__href, etc.)\n// and cannot be enumerated. The match key is either one of ELEMENT_MATCH_FIELDS\n// or starts with \"attr__\".\n// =============================================================================\n// CONDITION SCHEMAS\n// =============================================================================\nexport const PageUrlConditionZ = z\n .object({\n type: z.literal('page_url'),\n url: z.string().describe('URL path to match (e.g. \"/pricing\", \"/dashboard\")'),\n})\n .describe('Fires when the current page URL matches. Use for page-specific actions. ' +\n 'Example: {\"type\": \"page_url\", \"url\": \"/pricing\"}');\nexport const RouteConditionZ = z\n .object({\n type: z.literal('route'),\n routeId: z.string().describe('Named route ID from the route filter'),\n})\n .describe('Fires when the current route matches a named route ID.');\nexport const AnchorVisibleConditionZ = z\n .object({\n type: z.literal('anchor_visible'),\n anchorId: z.string().describe('CSS selector of the anchor element'),\n state: z\n .enum(['visible', 'present', 'absent'])\n .describe('\"visible\" = in viewport, \"present\" = in DOM, \"absent\" = not in DOM'),\n})\n .describe(\"Fires based on a DOM element's visibility state. \" +\n 'Example: {\"type\": \"anchor_visible\", \"anchorId\": \"#cta-button\", \"state\": \"visible\"}');\nexport const EventOccurredConditionZ = z\n .object({\n type: z.literal('event_occurred'),\n eventName: z.string().describe('Event name (e.g. \"ui.click\", \"$pageview\")'),\n withinMs: z.number().optional().describe('Time window in ms. Omit = any time this session.'),\n})\n .describe('Fires when a specific event has occurred during this session. ' +\n 'Example: {\"type\": \"event_occurred\", \"eventName\": \"ui.click\", \"withinMs\": 5000}');\nexport const StateEqualsConditionZ = z\n .object({\n type: z.literal('state_equals'),\n key: z\n .string()\n .describe('Key in the SDK persistent state store (localStorage). Only valid for keys the host app explicitly sets via syntro.state.set().'),\n value: z.unknown().describe('Expected value to match against'),\n})\n .describe('Checks the SDK persistent state store (localStorage). ONLY for host-app state set via syntro.state.set() \u2014 ' +\n 'NOT for user attributes like region, device, or UTM params (those are handled by segment targeting). ' +\n 'Do NOT use this for targeting. If you do not know the valid state keys, do not use this condition type.');\nexport const ViewportConditionZ = z\n .object({\n type: z.literal('viewport'),\n minWidth: z.number().optional().describe('Minimum viewport width in pixels'),\n maxWidth: z.number().optional().describe('Maximum viewport width in pixels'),\n minHeight: z.number().optional().describe('Minimum viewport height in pixels'),\n maxHeight: z.number().optional().describe('Maximum viewport height in pixels'),\n})\n .describe('Fires based on viewport (screen) size. Use for responsive behavior. ' +\n 'Example: {\"type\": \"viewport\", \"minWidth\": 768} \u2014 fires on tablet and larger.');\nexport const SessionMetricConditionZ = z\n .object({\n type: z.literal('session_metric'),\n key: SessionMetricKeyZ,\n operator: z.enum(['gte', 'lte', 'eq', 'gt', 'lt']),\n threshold: z.number().describe('Numeric threshold to compare against'),\n})\n .describe('Fires when a session metric crosses a threshold. Valid keys: \"time_on_page\" (seconds), ' +\n '\"page_views\" (count), \"scroll_depth\" (0-100). ' +\n 'Example: {\"type\": \"session_metric\", \"key\": \"time_on_page\", \"operator\": \"gte\", \"threshold\": 30}');\nexport const DismissedConditionZ = z\n .object({\n type: z.literal('dismissed'),\n key: z.string().describe('Dismissal key (usually a tile or action ID)'),\n inverted: z\n .boolean()\n .optional()\n .describe('When true, fires if NOT dismissed (default behavior)'),\n})\n .describe('Checks if an item has been dismissed by the user. Use with inverted: true to show only if not dismissed.');\nexport const CooldownActiveConditionZ = z\n .object({\n type: z.literal('cooldown_active'),\n key: z.string().describe('Cooldown key'),\n inverted: z.boolean().optional().describe('When true, fires if cooldown is NOT active'),\n})\n .describe('Checks if a cooldown timer is currently active. Use to prevent showing the same intervention too frequently.');\nexport const FrequencyLimitConditionZ = z\n .object({\n type: z.literal('frequency_limit'),\n key: z.string().describe('Frequency counter key'),\n limit: z.number().describe('Maximum allowed count'),\n inverted: z.boolean().optional().describe('When true, fires if limit NOT reached'),\n})\n .describe('Checks if a frequency limit has been reached. Use to cap how many times an action fires per session.');\nexport const MatchOpZ = z\n .object({\n equals: z.union([z.string(), z.number(), z.boolean()]).optional(),\n contains: z.string().optional(),\n})\n .refine((operator) => Number(operator.equals !== undefined) + Number(operator.contains !== undefined) === 1, {\n message: 'Exactly one of equals or contains must be specified.',\n})\n .describe('Match operator for counter filters. Exactly one of equals or contains must be specified.');\nexport const CounterDefZ = z\n .object({\n events: z\n .array(CountableEventZ)\n .min(1)\n .describe('Event names to count. Use values from the countable events enum.'),\n match: z\n .record(z.string(), MatchOpZ)\n .optional()\n .describe('Property filters. Keys are event prop names or element-chain fields ' +\n '(tag_name, $el_text, attr__*). All entries AND together.'),\n})\n .describe('Defines what events to count. Registered as an accumulator predicate at config-load time.');\nexport const EventCountConditionZ = z\n .object({\n type: z.literal('event_count'),\n key: z.string().describe('Unique key for this counter (used for accumulator registration)'),\n operator: z.enum(['gte', 'lte', 'eq', 'gt', 'lt']),\n count: z.number().int().min(0).describe('Target count threshold'),\n withinMs: z\n .number()\n .positive()\n .optional()\n .describe('Time window in ms. Omit = count across entire session.'),\n counter: CounterDefZ.optional().describe('Inline counter definition. Defines what events to count.'),\n})\n .describe('Fires when accumulated event count crosses a threshold. Most powerful trigger type. ' +\n 'Example: {\"type\": \"event_count\", \"key\": \"pricing-clicks\", \"operator\": \"gte\", \"count\": 3, ' +\n '\"counter\": {\"events\": [\"ui.click\"], \"match\": {\"attr__data-cta\": {\"contains\": \"pricing\"}}}}');\nexport const ConditionZ = z.discriminatedUnion('type', [\n PageUrlConditionZ,\n RouteConditionZ,\n AnchorVisibleConditionZ,\n EventOccurredConditionZ,\n StateEqualsConditionZ,\n ViewportConditionZ,\n SessionMetricConditionZ,\n DismissedConditionZ,\n CooldownActiveConditionZ,\n FrequencyLimitConditionZ,\n EventCountConditionZ,\n]);\n// =============================================================================\n// STRATEGY SCHEMAS\n// =============================================================================\nexport const RuleZ = z\n .object({\n conditions: z\n .array(ConditionZ)\n .describe('Array of conditions \u2014 ALL must match (AND logic) for this rule to fire.'),\n value: z\n .unknown()\n .describe('Value returned when all conditions match. For triggerWhen: true = fire the action.'),\n})\n .describe('A single rule. ALL conditions must match (AND logic). Rules in a strategy are evaluated ' +\n 'top-to-bottom \u2014 first rule where all conditions match wins and returns its value.');\nexport const RuleStrategyZ = z\n .object({\n type: z.literal('rules'),\n rules: z\n .array(RuleZ)\n .describe('Ordered list of rules. Evaluated top-to-bottom \u2014 first match wins.'),\n default: z\n .unknown()\n .describe('Fallback value when no rule matches. For triggerWhen: false = do not fire by default.'),\n})\n .describe('Rule-based strategy. Evaluates rules top-to-bottom. First rule where ALL conditions match ' +\n 'returns its value. If no rule matches, returns default. ' +\n 'For triggerWhen: set value=true on matching rules, default=false.');\nexport const ScoreStrategyZ = z\n .object({\n type: z.literal('score'),\n field: z.string(),\n threshold: z.number(),\n above: z.unknown(),\n below: z.unknown(),\n})\n .describe('Score-based strategy. Compares a field value against a threshold.');\nexport const ModelStrategyZ = z\n .object({\n type: z.literal('model'),\n modelId: z.string(),\n inputs: z.array(z.string()),\n outputMapping: z.record(z.string(), z.unknown()),\n default: z.unknown(),\n})\n .describe('ML model strategy. Sends inputs to a model and maps outputs.');\nexport const ExternalStrategyZ = z\n .object({\n type: z.literal('external'),\n endpoint: z.string(),\n method: z.enum(['GET', 'POST']).optional(),\n default: z.unknown(),\n timeoutMs: z.number().optional(),\n})\n .describe('External API strategy. Calls an endpoint to determine the value.');\nexport const DecisionStrategyZ = z.discriminatedUnion('type', [\n RuleStrategyZ,\n ScoreStrategyZ,\n ModelStrategyZ,\n ExternalStrategyZ,\n]);\n/** Canonical Zod schema for the optional triggerWhen field on actions and adaptive items. */\nexport const TriggerWhenZ = DecisionStrategyZ.nullable().optional();\n// =============================================================================\n// TRIGGER DOCUMENTATION \u2014 examples and match field docs\n// Exported as constants so the schema generator can inject them into the\n// JSON schema. The Python prompt builder reads them from the schema.\n// =============================================================================\n/** Complete triggerWhen examples showing the full rules wrapper structure. */\nexport const TRIGGER_EXAMPLES = [\n {\n name: 'Click count on a specific element',\n description: 'Fire when user clicks an element with data-id=\"hero-cta\" 2+ times',\n triggerWhen: {\n type: 'rules',\n rules: [\n {\n conditions: [\n {\n type: 'event_count',\n key: 'cta-clicks',\n operator: 'gte',\n count: 2,\n counter: {\n events: ['ui.click'],\n match: { 'attr__data-id': { equals: 'hero-cta' } },\n },\n },\n ],\n value: true,\n },\n ],\n default: false,\n },\n },\n {\n name: 'Time on page threshold',\n description: 'Fire after user spends 30+ seconds on the page',\n triggerWhen: {\n type: 'rules',\n rules: [\n {\n conditions: [\n {\n type: 'session_metric',\n key: 'time_on_page',\n operator: 'gte',\n threshold: 30,\n },\n ],\n value: true,\n },\n ],\n default: false,\n },\n },\n {\n name: 'Element visible in viewport',\n description: 'Fire when a DOM element becomes visible',\n triggerWhen: {\n type: 'rules',\n rules: [\n {\n conditions: [\n {\n type: 'anchor_visible',\n anchorId: '#pricing-section',\n state: 'visible',\n },\n ],\n value: true,\n },\n ],\n default: false,\n },\n },\n {\n name: 'No trigger (fire immediately)',\n description: 'Action fires as soon as the segment matches \u2014 no in-session condition needed',\n triggerWhen: null,\n },\n];\n/** Documentation for counter.match field keys. */\nexport const MATCH_FIELD_DOCS = {\n tag_name: 'HTML tag name (e.g. \"button\", \"a\", \"input\")',\n $el_text: 'Visible text content of the element',\n 'attr__*': 'HTML attribute prefixed with attr__. Example: attr__data-id matches the data-id attribute, ' +\n 'attr__class matches the class attribute, attr__href matches the href attribute.',\n};\n// =============================================================================\n// EVENT SCOPE SCHEMA\n// =============================================================================\n/** Scopes a widget to specific events/URLs. */\nexport const EventScopeZ = z.object({\n events: z.array(z.string()),\n urlContains: z.string().optional(),\n props: z.record(z.union([z.string(), z.number(), z.boolean()])).optional(),\n});\n// =============================================================================\n// NOTIFY SCHEMA\n// =============================================================================\n/** Toast notification config for triggerWhen transitions. */\nexport const NotifyZ = z\n .object({\n title: z.string().optional(),\n body: z.string().optional(),\n icon: z.string().optional(),\n})\n .nullable()\n .optional();\n", "import { type MountPlumbing, stripMountPlumbing } from '@syntrologie/sdk-contracts';\nimport { css, html, LitElement, nothing } from 'lit';\n\nimport { FlowEngine } from './engine/FlowEngine.js';\nimport './rendering/ChoiceInput.js';\nimport './rendering/EndScreen.js';\nimport './rendering/NpsInput.js';\nimport './rendering/RatingInput.js';\nimport './rendering/TextInput.js';\nimport './rendering/ThumbsInput.js';\nimport type { FeedbackConfig, FeedbackWidgetRuntime, SurveyStep } from './types.js';\n\nexport class SyntroFeedbackElement extends LitElement {\n static override properties = {\n config: { attribute: false },\n runtime: { attribute: false },\n tileId: { type: String },\n _engine: { state: true },\n _direction: { state: true },\n _entering: { state: true },\n };\n\n static override styles = css`\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n font-family: var(--sc-font-family, system-ui, -apple-system, sans-serif);\n color: var(--sc-content-text-color, #111827);\n }\n .header {\n padding: 12px 16px 8px;\n font-size: 15px;\n font-weight: 600;\n color: var(--sc-content-text-color, #111827);\n }\n .progress-bar {\n height: 3px;\n background: var(--sc-content-border-color, #e5e7eb);\n margin: 0 16px;\n border-radius: 2px;\n overflow: hidden;\n }\n .progress-fill {\n height: 100%;\n background: var(--sc-color-primary, #4f46e5);\n border-radius: 2px;\n transition: width 0.3s ease;\n }\n .step-container {\n flex: 1;\n overflow: hidden;\n position: relative;\n }\n .step-content {\n padding: 16px;\n /* Resting state is VISIBLE (GPU/compositing hazard fix): the step-slide\n carried animation-fill-mode:both from a keyframe that starts at\n opacity:0, so a dropped/suppressed animation stranded the step blank.\n The slide is now gated behind the transient .is-entering class; at rest\n the step is simply visible. */\n }\n .step-content.is-entering {\n animation-duration: 0.25s;\n animation-fill-mode: both;\n animation-timing-function: ease-out;\n }\n .step-content.is-entering.slide-in-right {\n animation-name: slideInRight;\n }\n .step-content.is-entering.slide-in-left {\n animation-name: slideInLeft;\n }\n @keyframes slideInRight {\n from { transform: translateX(30px); opacity: 0; }\n to { transform: translateX(0); opacity: 1; }\n }\n @keyframes slideInLeft {\n from { transform: translateX(-30px); opacity: 0; }\n to { transform: translateX(0); opacity: 1; }\n }\n @media (prefers-reduced-motion: reduce) {\n .step-content.is-entering {\n animation: none;\n opacity: 1;\n transform: none;\n }\n }\n .prompt {\n font-size: 15px;\n font-weight: 500;\n line-height: 1.4;\n margin-bottom: 4px;\n }\n .description {\n font-size: 13px;\n color: var(--sc-content-text-secondary-color, #6b7280);\n margin-bottom: 8px;\n line-height: 1.4;\n }\n .footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 16px 12px;\n gap: 8px;\n }\n .back-btn {\n padding: 6px 14px;\n border-radius: 6px;\n border: 1px solid var(--sc-content-border-color, #e5e7eb);\n background: transparent;\n color: var(--sc-content-text-secondary-color, #6b7280);\n font-size: 13px;\n cursor: pointer;\n transition: border-color 0.15s;\n }\n .back-btn:hover {\n border-color: var(--sc-content-text-color, #111827);\n }\n .step-count {\n font-size: 12px;\n color: var(--sc-content-text-secondary-color, #9ca3af);\n }\n `;\n\n config: FeedbackConfig | undefined;\n runtime: FeedbackWidgetRuntime | undefined;\n tileId: string = 'feedback-widget';\n\n private _engine: FlowEngine | undefined;\n private _direction: 'forward' | 'back' = 'forward';\n /** Transient: true while a step-slide is playing; gates the animation. */\n private _entering = true;\n private _settleArmed = false;\n private _settleTimer: ReturnType<typeof setTimeout> | undefined;\n\n override willUpdate(changed: Map<string, unknown>) {\n if (changed.has('config') && this.config?.steps?.length) {\n try {\n this._engine = new FlowEngine(this.config.steps);\n } catch {\n this._engine = undefined;\n }\n }\n }\n\n override disconnectedCallback(): void {\n if (this._settleTimer !== undefined) clearTimeout(this._settleTimer);\n // Re-arm on reconnect: a DOM move mid-slide would otherwise strand\n // .is-entering (blank step when the animation is suppressed \u2014 THE hazard).\n this._settleArmed = false;\n super.disconnectedCallback();\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Reconnect does not schedule a Lit update; nudge one so updated() re-arms\n // the slide belt when a DOM move interrupted it.\n if (this._entering) this.requestUpdate();\n }\n\n override updated(): void {\n // Arm the slide settle once per entering: remove .is-entering on the step's\n // own animationend (fast path) and an always-firing belt so a dropped\n // animation can never leave .is-entering (and its opacity:0 keyframe fill)\n // stuck on the step. Removal is a visual no-op \u2014 the step rests visible.\n if (!this._entering || this._settleArmed) return;\n const content = this.shadowRoot?.querySelector('.step-content') as HTMLElement | null;\n if (!content) return;\n this._settleArmed = true;\n const settle = (): void => {\n if (this._settleTimer !== undefined) {\n clearTimeout(this._settleTimer);\n this._settleTimer = undefined;\n }\n content.removeEventListener('animationend', onEnd);\n this._settleArmed = false;\n this._entering = false;\n };\n const onEnd = (e: Event): void => {\n if (e.target === content) settle();\n };\n content.addEventListener('animationend', onEnd);\n // slide is 0.25s with no delay; belt margin covers a late frame.\n this._settleTimer = setTimeout(settle, 500);\n }\n\n private _onAnswer = (e: CustomEvent<{ value: string | number }>) => {\n if (!this._engine || !this.config) return;\n const step = this._engine.currentStep;\n const { value } = e.detail;\n\n this.runtime?.events.publish('feedback:response', {\n surveyId: this.tileId,\n stepId: step.id,\n stepType: step.type,\n value,\n stepIndex: this._engine.stepIndex,\n });\n\n // Pixel-identical replay semantics: the old CSS restarted the slide only\n // when animation-name changed (a direction flip) \u2014 .step-content persists\n // across steps, so same-direction navigation never replayed. Re-arm the\n // transient class only when the direction actually changes.\n if (this._direction !== 'forward') {\n this._entering = true;\n this._settleArmed = false;\n }\n this._direction = 'forward';\n this._engine.answer(value);\n const updated: FlowEngine = Object.create(\n Object.getPrototypeOf(this._engine),\n Object.getOwnPropertyDescriptors(this._engine)\n );\n this._engine = updated;\n\n if (updated.isComplete) {\n this.runtime?.events.publish('feedback:completed', {\n surveyId: this.tileId,\n stepsCompleted: updated.stepsCompleted,\n abandoned: false,\n });\n }\n };\n\n private _goBack = () => {\n if (!this._engine) return;\n if (this._direction !== 'back') {\n this._entering = true;\n this._settleArmed = false;\n }\n this._direction = 'back';\n this._engine.goBack();\n this._engine = Object.create(\n Object.getPrototypeOf(this._engine),\n Object.getOwnPropertyDescriptors(this._engine)\n );\n };\n\n private _renderStepInput(step: SurveyStep) {\n const prevAnswer = this._engine?.answers.get(step.id);\n\n switch (step.type) {\n case 'thumbs':\n return html`<sf-thumbs-input\n .value=${prevAnswer as number | undefined}\n @step-answer=${this._onAnswer}\n ></sf-thumbs-input>`;\n\n case 'rating':\n return html`<sf-rating-input\n .max=${step.ratingMax ?? 5}\n .value=${prevAnswer as number | undefined}\n @step-answer=${this._onAnswer}\n ></sf-rating-input>`;\n\n case 'nps':\n return html`<sf-nps-input\n .lowLabel=${step.npsLowLabel ?? 'Not likely'}\n .highLabel=${step.npsHighLabel ?? 'Very likely'}\n .value=${prevAnswer as number | undefined}\n @step-answer=${this._onAnswer}\n ></sf-nps-input>`;\n\n case 'choice':\n return html`<sf-choice-input\n .options=${step.options ?? []}\n .value=${prevAnswer as string | undefined}\n @step-answer=${this._onAnswer}\n ></sf-choice-input>`;\n\n case 'text':\n return html`<sf-text-input\n .placeholder=${step.placeholder ?? ''}\n .value=${(prevAnswer as string) ?? ''}\n .required=${step.required !== false}\n @step-answer=${this._onAnswer}\n ></sf-text-input>`;\n\n case 'end':\n return html`<sf-end-screen .message=${step.prompt}></sf-end-screen>`;\n\n default:\n return nothing;\n }\n }\n\n override render() {\n if (!this._engine || !this.config) {\n return html`<div style=\"padding:16px;color:var(--sc-content-text-secondary-color,#87919f)\">\n Survey widget requires config.\n </div>`;\n }\n\n const step = this._engine.currentStep;\n const showProgress = this.config.showProgress !== false;\n const allowBack = this.config.allowBack === true;\n const canGoBack = allowBack && this._engine.path.length > 1 && step.type !== 'end';\n const totalSteps = this.config.steps.filter((s) => s.type !== 'end').length;\n const progressPct = totalSteps > 0 ? (this._engine.stepsCompleted / totalSteps) * 100 : 0;\n const slideClass = this._direction === 'forward' ? 'slide-in-right' : 'slide-in-left';\n const animClass = this._entering ? `is-entering ${slideClass}` : '';\n\n return html`\n ${this.config.title ? html`<div class=\"header\">${this.config.title}</div>` : nothing}\n ${\n showProgress && step.type !== 'end'\n ? html`<div class=\"progress-bar\">\n <div class=\"progress-fill\" style=\"width:${progressPct}%\"></div>\n </div>`\n : nothing\n }\n <div class=\"step-container\">\n <div class=\"step-content ${animClass}\" key=${step.id}>\n ${\n step.type !== 'end'\n ? html`\n <div class=\"prompt\">${step.prompt}</div>\n ${step.description ? html`<div class=\"description\">${step.description}</div>` : nothing}\n `\n : nothing\n }\n ${this._renderStepInput(step)}\n </div>\n </div>\n ${\n canGoBack || (step.type !== 'end' && showProgress)\n ? html`<div class=\"footer\">\n ${\n canGoBack\n ? html`<button type=\"button\" class=\"back-btn\" @click=${this._goBack}>\u2190 Back</button>`\n : html`<span></span>`\n }\n ${\n step.type !== 'end'\n ? html`<span class=\"step-count\">${this._engine.stepsCompleted + 1} of ${totalSteps}</span>`\n : nothing\n }\n </div>`\n : nothing\n }\n `;\n }\n}\n\ncustomElements.define('syntro-feedback', SyntroFeedbackElement);\n\n// The runtime SDK (SyntroTileCard + WidgetRegistry) delivers tile.props spread\n// flat into mountConfig, alongside `instanceId` and `runtime`. Mountables must\n// destructure flat \u2014 there is no nested `config` field. The legacy `config`\n// and `tileId` keys are accepted for direct callers (e.g. unit tests or\n// imperative mounts that opt into the nested shape).\ntype FlatMountConfig = FeedbackConfig & {\n runtime?: FeedbackWidgetRuntime;\n instanceId?: string;\n tileId?: string;\n /** Legacy nested-config escape hatch for direct callers. */\n config?: FeedbackConfig;\n};\n\nexport const FeedbackWidgetLitMountable = {\n mount(container: HTMLElement, mountConfig?: Record<string, unknown>) {\n const incoming = (mountConfig ?? null) as\n | (Partial<FlatMountConfig> & MountPlumbing & Record<string, unknown>)\n | null;\n const runtime = incoming?.runtime as FeedbackWidgetRuntime | undefined;\n const instanceId = incoming?.instanceId;\n const tileId = incoming?.tileId;\n const nestedConfig = incoming?.config;\n\n // Strip the canonical plumbing keys, then peel off the legacy nested\n // `config` escape hatch to recover the flat FeedbackConfig shape.\n const flat = stripMountPlumbing<Record<string, unknown>>(incoming);\n if ('config' in flat) {\n delete (flat as { config?: unknown }).config;\n }\n\n const feedbackConfig: FeedbackConfig | undefined =\n nestedConfig ?? ({ ...(flat as unknown as FeedbackConfig) } as FeedbackConfig);\n const resolvedTileId = tileId ?? instanceId ?? 'feedback-widget';\n\n if (!feedbackConfig?.steps?.length) {\n container.innerHTML =\n '<div style=\"padding:16px;color:var(--sc-content-text-secondary-color,#87919f)\">Feedback widget requires config.</div>';\n return () => {\n container.innerHTML = '';\n };\n }\n\n let tracker: FlowEngine | undefined;\n try {\n tracker = new FlowEngine(feedbackConfig.steps);\n } catch {\n // invalid config \u2014 element will show its own error\n }\n\n const el = document.createElement('syntro-feedback') as SyntroFeedbackElement;\n el.config = feedbackConfig;\n el.runtime = runtime;\n el.tileId = resolvedTileId;\n el.style.cssText = 'display:flex;flex-direction:column;height:100%;width:100%;';\n\n container.appendChild(el);\n\n let completed = false;\n const onAnswer = (e: Event) => {\n const detail = (e as CustomEvent<{ value: string | number }>).detail;\n if (tracker && !tracker.isComplete) {\n tracker.answer(detail.value);\n if (tracker.isComplete) completed = true;\n }\n };\n el.addEventListener('step-answer', onAnswer);\n\n return () => {\n el.removeEventListener('step-answer', onAnswer);\n if (!completed && runtime && tracker) {\n runtime.events.publish('feedback:abandoned', {\n surveyId: resolvedTileId,\n lastStepId: tracker.currentStep.id,\n stepsCompleted: tracker.stepsCompleted,\n abandoned: true,\n });\n }\n el.remove();\n };\n },\n};\n", "import type { BranchRule, SurveyStep } from '../types';\n\nexport class FlowEngineValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'FlowEngineValidationError';\n }\n}\n\nexport class FlowEngine {\n private _steps: SurveyStep[];\n private _stepMap: Map<string, SurveyStep>;\n private _answers: Map<string, string | number> = new Map();\n private _path: string[];\n\n constructor(steps: SurveyStep[]) {\n this._validate(steps);\n this._steps = steps;\n this._stepMap = new Map(steps.map((s) => [s.id, s]));\n this._path = [steps[0].id];\n }\n\n get currentStep(): SurveyStep {\n const id = this._path[this._path.length - 1];\n return this._stepMap.get(id)!;\n }\n\n get answers(): ReadonlyMap<string, string | number> {\n return this._answers;\n }\n\n get path(): readonly string[] {\n return this._path;\n }\n\n get isComplete(): boolean {\n return this.currentStep.type === 'end';\n }\n\n get stepsCompleted(): number {\n return this._path.filter((id) => this._answers.has(id)).length;\n }\n\n get stepIndex(): number {\n return this._path.length - 1;\n }\n\n getStep(id: string): SurveyStep | undefined {\n return this._stepMap.get(id);\n }\n\n answer(value: string | number): void {\n const step = this.currentStep;\n if (step.type === 'end') return;\n\n this._answers.set(step.id, value);\n const nextId = this._resolveNext(step, value);\n\n const currentIdx = this._path.length - 1;\n this._path = this._path.slice(0, currentIdx + 1);\n this._path.push(nextId);\n }\n\n goBack(): void {\n if (this._path.length <= 1) return;\n this._path = this._path.slice(0, -1);\n }\n\n private _resolveNext(step: SurveyStep, value: string | number): string {\n if (step.next === undefined) {\n return this._nextInArray(step.id);\n }\n\n if (typeof step.next === 'string') {\n return step.next;\n }\n\n for (const rule of step.next) {\n if (this._evaluateRule(rule, value)) {\n return rule.goto;\n }\n }\n\n return this._nextInArray(step.id);\n }\n\n private _nextInArray(currentId: string): string {\n const idx = this._steps.findIndex((s) => s.id === currentId);\n return this._steps[idx + 1].id;\n }\n\n private _evaluateRule(rule: BranchRule, value: string | number): boolean {\n const { op, value: ruleValue } = rule.if;\n\n switch (op) {\n case 'eq':\n return value === ruleValue;\n case 'neq':\n return value !== ruleValue;\n case 'lt':\n return Number(value) < Number(ruleValue);\n case 'lte':\n return Number(value) <= Number(ruleValue);\n case 'gt':\n return Number(value) > Number(ruleValue);\n case 'gte':\n return Number(value) >= Number(ruleValue);\n case 'in':\n return Array.isArray(ruleValue) && ruleValue.includes(String(value));\n default:\n return false;\n }\n }\n\n private _validate(steps: SurveyStep[]): void {\n if (steps.length === 0) {\n throw new FlowEngineValidationError('Steps array must not be empty');\n }\n\n const ids = new Set<string>();\n for (const step of steps) {\n if (ids.has(step.id)) {\n throw new FlowEngineValidationError(`Duplicate step ID: \"${step.id}\"`);\n }\n ids.add(step.id);\n }\n\n const hasEnd = steps.some((s) => s.type === 'end');\n if (!hasEnd) {\n throw new FlowEngineValidationError('At least one step must have type \"end\"');\n }\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i];\n if (typeof step.next === 'string') {\n if (!ids.has(step.next)) {\n throw new FlowEngineValidationError(\n `Step \"${step.id}\" has next target \"${step.next}\" which does not exist`\n );\n }\n } else if (Array.isArray(step.next)) {\n for (const rule of step.next) {\n if (!ids.has(rule.goto)) {\n throw new FlowEngineValidationError(\n `Step \"${step.id}\" has branch rule targeting \"${rule.goto}\" which does not exist`\n );\n }\n }\n }\n\n if (step.type !== 'end' && step.next === undefined && i === steps.length - 1) {\n throw new FlowEngineValidationError(\n `Step \"${step.id}\" is last in the array with no explicit \"next\" and is not an end step`\n );\n }\n }\n }\n}\n", "import { css, html, LitElement } from 'lit';\n\nexport class ChoiceInput extends LitElement {\n static override properties = {\n options: { attribute: false },\n value: { type: String },\n };\n\n static override styles = css`\n :host { display: block; }\n .choices {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 8px 0;\n }\n button {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 10px 14px;\n border-radius: 8px;\n border: 2px solid var(--sc-content-border-color, #e5e7eb);\n background: var(--sc-content-bg-color, #fff);\n color: var(--sc-content-text-color, #111827);\n font-size: 14px;\n text-align: left;\n cursor: pointer;\n transition: border-color 0.15s, background 0.15s;\n }\n button:hover {\n border-color: var(--sc-color-primary, #4f46e5);\n }\n button[aria-pressed=\"true\"] {\n border-color: var(--sc-color-primary, #4f46e5);\n background: var(--sc-color-primary-light, #eef2ff);\n }\n .radio {\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: 2px solid var(--sc-content-border-color, #e5e7eb);\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n button[aria-pressed=\"true\"] .radio {\n border-color: var(--sc-color-primary, #4f46e5);\n }\n .radio-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: transparent;\n }\n button[aria-pressed=\"true\"] .radio-dot {\n background: var(--sc-color-primary, #4f46e5);\n }\n `;\n\n options: string[] = [];\n value: string | undefined;\n\n private _select(opt: string) {\n this.value = opt;\n this.dispatchEvent(\n new CustomEvent('step-answer', {\n detail: { value: opt },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n override render() {\n return html`\n <div class=\"choices\" role=\"radiogroup\">\n ${(this.options ?? []).map(\n (opt) => html`\n <button\n type=\"button\"\n role=\"radio\"\n aria-pressed=${this.value === opt ? 'true' : 'false'}\n @click=${() => this._select(opt)}\n >\n <span class=\"radio\"><span class=\"radio-dot\"></span></span>\n ${opt}\n </button>\n `\n )}\n </div>\n `;\n }\n}\n\ncustomElements.define('sf-choice-input', ChoiceInput);\n", "import { css, html, LitElement } from 'lit';\n\nexport class EndScreen extends LitElement {\n static override properties = {\n message: { type: String },\n };\n\n static override styles = css`\n :host { display: block; }\n .end-wrap {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 24px 16px;\n text-align: center;\n gap: 12px;\n }\n .checkmark {\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: var(--sc-color-primary-light, #eef2ff);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 24px;\n }\n .message {\n color: var(--sc-content-text-color, #111827);\n font-size: 16px;\n font-weight: 500;\n line-height: 1.5;\n }\n `;\n\n message: string = 'Thank you!';\n\n override render() {\n return html`\n <div class=\"end-wrap\">\n <div class=\"checkmark\">\u2713</div>\n <div class=\"message\">${this.message}</div>\n </div>\n `;\n }\n}\n\ncustomElements.define('sf-end-screen', EndScreen);\n", "import { css, html, LitElement } from 'lit';\n\nexport class NpsInput extends LitElement {\n static override properties = {\n lowLabel: { type: String },\n highLabel: { type: String },\n value: { type: Number },\n };\n\n static override styles = css`\n :host { display: block; }\n .nps-scale {\n display: flex;\n gap: 4px;\n justify-content: center;\n padding: 12px 0 4px;\n }\n button {\n min-width: 32px;\n height: 36px;\n border-radius: 6px;\n border: 2px solid var(--sc-content-border-color, #e5e7eb);\n background: var(--sc-content-bg-color, #fff);\n color: var(--sc-content-text-color, #111827);\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: border-color 0.15s, background 0.15s;\n padding: 0 4px;\n }\n button:hover {\n border-color: var(--sc-color-primary, #4f46e5);\n }\n button[aria-pressed=\"true\"] {\n border-color: var(--sc-color-primary, #4f46e5);\n background: var(--sc-color-primary, #4f46e5);\n color: #fff;\n }\n .labels {\n display: flex;\n justify-content: space-between;\n padding: 4px 2px 0;\n font-size: 12px;\n color: var(--sc-content-text-secondary-color, #6b7280);\n }\n `;\n\n lowLabel: string = 'Not likely';\n highLabel: string = 'Very likely';\n value: number | undefined;\n\n private _select(val: number) {\n this.value = val;\n this.dispatchEvent(\n new CustomEvent('step-answer', {\n detail: { value: val },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n override render() {\n const items = Array.from({ length: 11 }, (_, i) => i);\n return html`\n <div>\n <div class=\"nps-scale\">\n ${items.map(\n (n) => html`\n <button\n type=\"button\"\n aria-label=\"Score ${n}\"\n aria-pressed=${this.value === n ? 'true' : 'false'}\n @click=${() => this._select(n)}\n >${n}</button>\n `\n )}\n </div>\n <div class=\"labels\">\n <span>${this.lowLabel}</span>\n <span>${this.highLabel}</span>\n </div>\n </div>\n `;\n }\n}\n\ncustomElements.define('sf-nps-input', NpsInput);\n", "import { css, html, LitElement } from 'lit';\n\nexport class RatingInput extends LitElement {\n static override properties = {\n max: { type: Number },\n value: { type: Number },\n };\n\n static override styles = css`\n :host { display: block; }\n .rating-row {\n display: flex;\n gap: 8px;\n justify-content: center;\n padding: 12px 0;\n }\n button {\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: 2px solid var(--sc-content-border-color, #e5e7eb);\n background: var(--sc-content-bg-color, #fff);\n color: var(--sc-content-text-color, #111827);\n font-size: 16px;\n font-weight: 600;\n cursor: pointer;\n transition: transform 0.1s, border-color 0.15s, background 0.15s;\n }\n button:hover {\n border-color: var(--sc-color-primary, #4f46e5);\n }\n button[aria-pressed=\"true\"],\n button.selected {\n border-color: var(--sc-color-primary, #4f46e5);\n background: var(--sc-color-primary, #4f46e5);\n color: #fff;\n }\n `;\n\n max: number = 5;\n value: number | undefined;\n\n private _select(val: number) {\n this.value = val;\n this.dispatchEvent(\n new CustomEvent('step-answer', {\n detail: { value: val },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n override render() {\n const count = this.max || 5;\n const items = Array.from({ length: count }, (_, i) => i + 1);\n return html`\n <div class=\"rating-row\">\n ${items.map(\n (n) => html`\n <button\n type=\"button\"\n aria-label=\"Rate ${n} of ${count}\"\n aria-pressed=${this.value === n ? 'true' : 'false'}\n class=${this.value === n ? 'selected' : ''}\n @click=${() => this._select(n)}\n >${n}</button>\n `\n )}\n </div>\n `;\n }\n}\n\ncustomElements.define('sf-rating-input', RatingInput);\n", "import { css, html, LitElement } from 'lit';\n\nexport class TextInput extends LitElement {\n static override properties = {\n placeholder: { type: String },\n value: { type: String },\n required: { type: Boolean },\n };\n\n static override styles = css`\n :host { display: block; }\n .text-wrap {\n padding: 8px 0;\n }\n textarea {\n width: 100%;\n min-height: 80px;\n padding: 10px 12px;\n border-radius: 8px;\n border: 2px solid var(--sc-content-border-color, #e5e7eb);\n background: var(--sc-content-bg-color, #fff);\n color: var(--sc-content-text-color, #111827);\n font-family: inherit;\n font-size: 14px;\n resize: vertical;\n box-sizing: border-box;\n transition: border-color 0.15s;\n }\n textarea:focus {\n outline: none;\n border-color: var(--sc-color-primary, #4f46e5);\n }\n textarea::placeholder {\n color: var(--sc-content-text-secondary-color, #9ca3af);\n }\n .submit-row {\n display: flex;\n justify-content: flex-end;\n padding-top: 8px;\n }\n button {\n padding: 8px 20px;\n border-radius: 8px;\n border: none;\n background: var(--sc-color-primary, #4f46e5);\n color: #fff;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: opacity 0.15s;\n }\n button:hover { opacity: 0.9; }\n button:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n }\n `;\n\n placeholder: string = '';\n value: string = '';\n required: boolean = true;\n\n private _currentText = '';\n\n private _handleInput = (e: Event) => {\n this._currentText = (e.target as HTMLTextAreaElement).value;\n this.requestUpdate();\n };\n\n private _submit = () => {\n if (this.required && !this._currentText.trim()) return;\n this.dispatchEvent(\n new CustomEvent('step-answer', {\n detail: { value: this._currentText },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n override connectedCallback() {\n super.connectedCallback();\n this._currentText = this.value || '';\n }\n\n override render() {\n const canSubmit = !this.required || this._currentText.trim().length > 0;\n return html`\n <div class=\"text-wrap\">\n <textarea\n .value=${this._currentText}\n placeholder=${this.placeholder || 'Type your answer...'}\n @input=${this._handleInput}\n ></textarea>\n <div class=\"submit-row\">\n <button type=\"button\" ?disabled=${!canSubmit} @click=${this._submit}>\n Submit\n </button>\n </div>\n </div>\n `;\n }\n}\n\ncustomElements.define('sf-text-input', TextInput);\n", "import { css, html, LitElement } from 'lit';\n\nexport class ThumbsInput extends LitElement {\n static override properties = {\n value: { type: Number },\n };\n\n static override styles = css`\n :host { display: block; }\n .thumbs-row {\n display: flex;\n gap: 16px;\n justify-content: center;\n padding: 12px 0;\n }\n button {\n width: 64px;\n height: 64px;\n border-radius: 50%;\n border: 2px solid var(--sc-content-border-color, #e5e7eb);\n background: var(--sc-content-bg-color, #fff);\n font-size: 28px;\n cursor: pointer;\n transition: transform 0.15s, border-color 0.15s, background 0.15s;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n button:hover {\n transform: scale(1.1);\n border-color: var(--sc-color-primary, #4f46e5);\n }\n button[aria-pressed=\"true\"] {\n border-color: var(--sc-color-primary, #4f46e5);\n background: var(--sc-color-primary-light, #eef2ff);\n }\n `;\n\n value: number | undefined;\n\n private _select(val: number) {\n this.value = val;\n this.dispatchEvent(\n new CustomEvent('step-answer', {\n detail: { value: val },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n override render() {\n return html`\n <div class=\"thumbs-row\">\n <button\n type=\"button\"\n aria-label=\"Thumbs up\"\n aria-pressed=${this.value === 1 ? 'true' : 'false'}\n @click=${() => this._select(1)}\n >\\u{1F44D}</button>\n <button\n type=\"button\"\n aria-label=\"Thumbs down\"\n aria-pressed=${this.value === 0 ? 'true' : 'false'}\n @click=${() => this._select(0)}\n >\\u{1F44E}</button>\n </div>\n `;\n }\n}\n\ncustomElements.define('sf-thumbs-input', ThumbsInput);\n"],
5
+ "mappings": "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",
6
+ "names": ["createContext", "key", "css", "html", "LitElement", "s", "i", "css", "html", "LitElement", "css", "html", "LitElement", "i", "n", "css", "html", "LitElement", "i", "n", "css", "html", "LitElement", "e", "css", "html", "LitElement", "LitElement", "e", "html", "s", "css"]
7
+ }
package/dist/runtime.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  FeedbackWidgetLitMountable
3
- } from "./chunk-6CCN3QKN.js";
3
+ } from "./chunk-AJOEEXTA.js";
4
4
 
5
5
  // src/runtime.ts
6
6
  var runtime = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syntrologie/adapt-feedback",
3
- "version": "2.28.0",
3
+ "version": "2.29.0",
4
4
  "description": "Adaptive Feedback - Multi-step survey widget with branching logic and PostHog events",
5
5
  "license": "Proprietary",
6
6
  "private": false,
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../sdk-contracts/dist/mount-plumbing.js", "../../../sdk-contracts/dist/schemas.js", "../src/FeedbackWidget.ts", "../src/engine/FlowEngine.ts", "../src/rendering/ChoiceInput.ts", "../src/rendering/EndScreen.ts", "../src/rendering/NpsInput.ts", "../src/rendering/RatingInput.ts", "../src/rendering/TextInput.ts", "../src/rendering/ThumbsInput.ts"],
4
- "sourcesContent": ["/**\n * Mount contract types and helper for adaptive widget mountables.\n *\n * The `WidgetRegistry` in `@syntrologie/runtime-sdk` delivers props to each\n * mountable as `{ ...tile.props, instanceId, runtime, tileId? }` spread flat\n * (see `MountableContract.test.ts` in runtime-sdk for the end-to-end lockdown).\n *\n * Adaptives that strip plumbing manually maintain private blacklists that\n * silently drift when the contract grows (PR #2234 and #2238 documented this).\n * `stripMountPlumbing` centralizes the list so adding a new plumbing key in\n * the future is a one-line change here that every adaptive picks up automatically.\n *\n * Adaptives whose widget schemas use Zod `.strict()` MUST call this before\n * validating, or strict-mode will reject the runtime-injected keys and the\n * widget will silently render its empty/error state.\n */\nexport const MOUNT_PLUMBING_KEYS = ['instanceId', 'runtime', 'tileId'];\nexport function stripMountPlumbing(config) {\n if (!config || typeof config !== 'object') {\n return {};\n }\n const out = { ...config };\n for (const key of MOUNT_PLUMBING_KEYS) {\n delete out[key];\n }\n return out;\n}\n", "/**\n * Shared Zod schemas for decision strategies, conditions, and event scoping.\n *\n * These are the canonical definitions \u2014 runtime-sdk and all adaptive packages\n * should import from here instead of duplicating.\n */\nimport { z } from 'zod';\n// =============================================================================\n// ANCHOR ID SCHEMA\n// =============================================================================\nexport const AnchorIdZ = z\n .object({\n selector: z.string(),\n route: z.union([z.string(), z.array(z.string())]),\n})\n .strict();\n// =============================================================================\n// AUTHORING FIELDS \u2014 id / title / description / validation\n//\n// Shared fields every action carries. `id` is the action identifier the\n// runtime uses to dispatch, dedupe, and drop/replace actions \u2014 it is NOT\n// stripped before serving. `title` / `description` / `validation` are\n// authoring-only metadata stripped server-side in `to_runtime_config`\n// (platform/backend/app/domains/experiments/helpers.py).\n//\n// They all appear in the JSON Schema (and therefore in the tactician's\n// prompt) because the LLM needs to know they are valid action properties \u2014\n// otherwise schema validation would reject what the prompt commands.\n//\n// Each action variant should `.extend(AuthoringFieldsZ)` alongside any\n// triggerWhen/condition extensions.\n// =============================================================================\nexport const AuthoringFieldsZ = {\n id: z.string().optional().describe('Stable action identifier (e.g. \"act_3db6a14d2ab0\").'),\n title: z\n .string()\n .max(200)\n .optional()\n .describe('Authoring-only: short label shown on the action plan dashboard. Stripped before serving to the runtime SDK.'),\n description: z\n .string()\n .max(1000)\n .optional()\n .describe('Authoring-only: one-sentence explanation of what this action does and why. Stripped before serving to the runtime SDK.'),\n validation: z\n .array(z.string().max(500))\n .max(10)\n .optional()\n .describe('Authoring-only: ordered steps a reviewer can follow to trigger this action and visually confirm it works. Each entry is one step. Stripped before serving to the runtime SDK.'),\n};\n// =============================================================================\n// TRIGGER VOCABULARY \u2014 canonical lists of valid event names, metric keys, etc.\n// These flow through to the JSON schema as enums and are used by the LLM prompt.\n// =============================================================================\n/** Events that can be counted in event_count conditions.\n *\n * Every value here must be an event the runtime actually emits \u2014 either a\n * PostHog-autocapture normalization (ui.click/scroll/input/change/submit) or\n * an event-processor detector (ui.hover/idle/scroll_thrash/focus_bounce/\n * hesitate/rage_click). Do not add aspirational names; a trigger counting an\n * event nothing emits never fires.\n */\nexport const COUNTABLE_EVENTS = [\n // User interactions (from PostHog autocapture normalization)\n 'ui.click',\n 'ui.scroll',\n 'ui.input',\n 'ui.change',\n 'ui.submit',\n // Behavioral detectors (from event-processor)\n 'ui.hover',\n 'ui.idle',\n 'ui.scroll_thrash',\n 'ui.focus_bounce',\n 'ui.hesitate',\n 'ui.rage_click',\n // Navigation\n 'nav.page_view',\n 'nav.page_leave',\n];\nexport const CountableEventZ = z\n .enum(COUNTABLE_EVENTS)\n .describe('Event name to count. ui.* = user interactions and behavioral detectors (hesitate, rage_click, scroll_thrash, focus_bounce, idle, hover); nav.* = page navigation.');\n/** Valid session metric keys. */\nexport const SESSION_METRIC_KEYS = ['time_on_page', 'page_views', 'scroll_depth'];\nexport const SessionMetricKeyZ = z\n .enum(SESSION_METRIC_KEYS)\n .describe('Session metric key. time_on_page = seconds on current page, page_views = pages visited this session, scroll_depth = 0-100 percentage.');\n/** Element chain match field prefixes for counter filters. */\nexport const ELEMENT_MATCH_FIELDS = ['tag_name', '$el_text'];\n// Note: attr__* is a dynamic prefix (attr__data-id, attr__class, attr__href, etc.)\n// and cannot be enumerated. The match key is either one of ELEMENT_MATCH_FIELDS\n// or starts with \"attr__\".\n// =============================================================================\n// CONDITION SCHEMAS\n// =============================================================================\nexport const PageUrlConditionZ = z\n .object({\n type: z.literal('page_url'),\n url: z.string().describe('URL path to match (e.g. \"/pricing\", \"/dashboard\")'),\n})\n .describe('Fires when the current page URL matches. Use for page-specific actions. ' +\n 'Example: {\"type\": \"page_url\", \"url\": \"/pricing\"}');\nexport const RouteConditionZ = z\n .object({\n type: z.literal('route'),\n routeId: z.string().describe('Named route ID from the route filter'),\n})\n .describe('Fires when the current route matches a named route ID.');\nexport const AnchorVisibleConditionZ = z\n .object({\n type: z.literal('anchor_visible'),\n anchorId: z.string().describe('CSS selector of the anchor element'),\n state: z\n .enum(['visible', 'present', 'absent'])\n .describe('\"visible\" = in viewport, \"present\" = in DOM, \"absent\" = not in DOM'),\n})\n .describe(\"Fires based on a DOM element's visibility state. \" +\n 'Example: {\"type\": \"anchor_visible\", \"anchorId\": \"#cta-button\", \"state\": \"visible\"}');\nexport const EventOccurredConditionZ = z\n .object({\n type: z.literal('event_occurred'),\n eventName: z.string().describe('Event name (e.g. \"ui.click\", \"$pageview\")'),\n withinMs: z.number().optional().describe('Time window in ms. Omit = any time this session.'),\n})\n .describe('Fires when a specific event has occurred during this session. ' +\n 'Example: {\"type\": \"event_occurred\", \"eventName\": \"ui.click\", \"withinMs\": 5000}');\nexport const StateEqualsConditionZ = z\n .object({\n type: z.literal('state_equals'),\n key: z\n .string()\n .describe('Key in the SDK persistent state store (localStorage). Only valid for keys the host app explicitly sets via syntro.state.set().'),\n value: z.unknown().describe('Expected value to match against'),\n})\n .describe('Checks the SDK persistent state store (localStorage). ONLY for host-app state set via syntro.state.set() \u2014 ' +\n 'NOT for user attributes like region, device, or UTM params (those are handled by segment targeting). ' +\n 'Do NOT use this for targeting. If you do not know the valid state keys, do not use this condition type.');\nexport const ViewportConditionZ = z\n .object({\n type: z.literal('viewport'),\n minWidth: z.number().optional().describe('Minimum viewport width in pixels'),\n maxWidth: z.number().optional().describe('Maximum viewport width in pixels'),\n minHeight: z.number().optional().describe('Minimum viewport height in pixels'),\n maxHeight: z.number().optional().describe('Maximum viewport height in pixels'),\n})\n .describe('Fires based on viewport (screen) size. Use for responsive behavior. ' +\n 'Example: {\"type\": \"viewport\", \"minWidth\": 768} \u2014 fires on tablet and larger.');\nexport const SessionMetricConditionZ = z\n .object({\n type: z.literal('session_metric'),\n key: SessionMetricKeyZ,\n operator: z.enum(['gte', 'lte', 'eq', 'gt', 'lt']),\n threshold: z.number().describe('Numeric threshold to compare against'),\n})\n .describe('Fires when a session metric crosses a threshold. Valid keys: \"time_on_page\" (seconds), ' +\n '\"page_views\" (count), \"scroll_depth\" (0-100). ' +\n 'Example: {\"type\": \"session_metric\", \"key\": \"time_on_page\", \"operator\": \"gte\", \"threshold\": 30}');\nexport const DismissedConditionZ = z\n .object({\n type: z.literal('dismissed'),\n key: z.string().describe('Dismissal key (usually a tile or action ID)'),\n inverted: z\n .boolean()\n .optional()\n .describe('When true, fires if NOT dismissed (default behavior)'),\n})\n .describe('Checks if an item has been dismissed by the user. Use with inverted: true to show only if not dismissed.');\nexport const CooldownActiveConditionZ = z\n .object({\n type: z.literal('cooldown_active'),\n key: z.string().describe('Cooldown key'),\n inverted: z.boolean().optional().describe('When true, fires if cooldown is NOT active'),\n})\n .describe('Checks if a cooldown timer is currently active. Use to prevent showing the same intervention too frequently.');\nexport const FrequencyLimitConditionZ = z\n .object({\n type: z.literal('frequency_limit'),\n key: z.string().describe('Frequency counter key'),\n limit: z.number().describe('Maximum allowed count'),\n inverted: z.boolean().optional().describe('When true, fires if limit NOT reached'),\n})\n .describe('Checks if a frequency limit has been reached. Use to cap how many times an action fires per session.');\nexport const MatchOpZ = z\n .object({\n equals: z.union([z.string(), z.number(), z.boolean()]).optional(),\n contains: z.string().optional(),\n})\n .describe('Match operator for counter filters. Exactly one of equals or contains must be specified.');\nexport const CounterDefZ = z\n .object({\n events: z\n .array(CountableEventZ)\n .min(1)\n .describe('Event names to count. Use values from the countable events enum.'),\n match: z\n .record(z.string(), MatchOpZ)\n .optional()\n .describe('Property filters. Keys are event prop names or element-chain fields ' +\n '(tag_name, $el_text, attr__*). All entries AND together.'),\n})\n .describe('Defines what events to count. Registered as an accumulator predicate at config-load time.');\nexport const EventCountConditionZ = z\n .object({\n type: z.literal('event_count'),\n key: z.string().describe('Unique key for this counter (used for accumulator registration)'),\n operator: z.enum(['gte', 'lte', 'eq', 'gt', 'lt']),\n count: z.number().int().min(0).describe('Target count threshold'),\n withinMs: z\n .number()\n .positive()\n .optional()\n .describe('Time window in ms. Omit = count across entire session.'),\n counter: CounterDefZ.optional().describe('Inline counter definition. Defines what events to count.'),\n})\n .describe('Fires when accumulated event count crosses a threshold. Most powerful trigger type. ' +\n 'Example: {\"type\": \"event_count\", \"key\": \"pricing-clicks\", \"operator\": \"gte\", \"count\": 3, ' +\n '\"counter\": {\"events\": [\"ui.click\"], \"match\": {\"attr__data-cta\": {\"contains\": \"pricing\"}}}}');\nexport const ConditionZ = z.discriminatedUnion('type', [\n PageUrlConditionZ,\n RouteConditionZ,\n AnchorVisibleConditionZ,\n EventOccurredConditionZ,\n StateEqualsConditionZ,\n ViewportConditionZ,\n SessionMetricConditionZ,\n DismissedConditionZ,\n CooldownActiveConditionZ,\n FrequencyLimitConditionZ,\n EventCountConditionZ,\n]);\n// =============================================================================\n// STRATEGY SCHEMAS\n// =============================================================================\nexport const RuleZ = z\n .object({\n conditions: z\n .array(ConditionZ)\n .describe('Array of conditions \u2014 ALL must match (AND logic) for this rule to fire.'),\n value: z\n .unknown()\n .describe('Value returned when all conditions match. For triggerWhen: true = fire the action.'),\n})\n .describe('A single rule. ALL conditions must match (AND logic). Rules in a strategy are evaluated ' +\n 'top-to-bottom \u2014 first rule where all conditions match wins and returns its value.');\nexport const RuleStrategyZ = z\n .object({\n type: z.literal('rules'),\n rules: z\n .array(RuleZ)\n .describe('Ordered list of rules. Evaluated top-to-bottom \u2014 first match wins.'),\n default: z\n .unknown()\n .describe('Fallback value when no rule matches. For triggerWhen: false = do not fire by default.'),\n})\n .describe('Rule-based strategy. Evaluates rules top-to-bottom. First rule where ALL conditions match ' +\n 'returns its value. If no rule matches, returns default. ' +\n 'For triggerWhen: set value=true on matching rules, default=false.');\nexport const ScoreStrategyZ = z\n .object({\n type: z.literal('score'),\n field: z.string(),\n threshold: z.number(),\n above: z.unknown(),\n below: z.unknown(),\n})\n .describe('Score-based strategy. Compares a field value against a threshold.');\nexport const ModelStrategyZ = z\n .object({\n type: z.literal('model'),\n modelId: z.string(),\n inputs: z.array(z.string()),\n outputMapping: z.record(z.string(), z.unknown()),\n default: z.unknown(),\n})\n .describe('ML model strategy. Sends inputs to a model and maps outputs.');\nexport const ExternalStrategyZ = z\n .object({\n type: z.literal('external'),\n endpoint: z.string(),\n method: z.enum(['GET', 'POST']).optional(),\n default: z.unknown(),\n timeoutMs: z.number().optional(),\n})\n .describe('External API strategy. Calls an endpoint to determine the value.');\nexport const DecisionStrategyZ = z.discriminatedUnion('type', [\n RuleStrategyZ,\n ScoreStrategyZ,\n ModelStrategyZ,\n ExternalStrategyZ,\n]);\n/** Canonical Zod schema for the optional triggerWhen field on actions and adaptive items. */\nexport const TriggerWhenZ = DecisionStrategyZ.nullable().optional();\n// =============================================================================\n// TRIGGER DOCUMENTATION \u2014 examples and match field docs\n// Exported as constants so the schema generator can inject them into the\n// JSON schema. The Python prompt builder reads them from the schema.\n// =============================================================================\n/** Complete triggerWhen examples showing the full rules wrapper structure. */\nexport const TRIGGER_EXAMPLES = [\n {\n name: 'Click count on a specific element',\n description: 'Fire when user clicks an element with data-id=\"hero-cta\" 2+ times',\n triggerWhen: {\n type: 'rules',\n rules: [\n {\n conditions: [\n {\n type: 'event_count',\n key: 'cta-clicks',\n operator: 'gte',\n count: 2,\n counter: {\n events: ['ui.click'],\n match: { 'attr__data-id': { equals: 'hero-cta' } },\n },\n },\n ],\n value: true,\n },\n ],\n default: false,\n },\n },\n {\n name: 'Time on page threshold',\n description: 'Fire after user spends 30+ seconds on the page',\n triggerWhen: {\n type: 'rules',\n rules: [\n {\n conditions: [\n {\n type: 'session_metric',\n key: 'time_on_page',\n operator: 'gte',\n threshold: 30,\n },\n ],\n value: true,\n },\n ],\n default: false,\n },\n },\n {\n name: 'Element visible in viewport',\n description: 'Fire when a DOM element becomes visible',\n triggerWhen: {\n type: 'rules',\n rules: [\n {\n conditions: [\n {\n type: 'anchor_visible',\n anchorId: '#pricing-section',\n state: 'visible',\n },\n ],\n value: true,\n },\n ],\n default: false,\n },\n },\n {\n name: 'No trigger (fire immediately)',\n description: 'Action fires as soon as the segment matches \u2014 no in-session condition needed',\n triggerWhen: null,\n },\n];\n/** Documentation for counter.match field keys. */\nexport const MATCH_FIELD_DOCS = {\n tag_name: 'HTML tag name (e.g. \"button\", \"a\", \"input\")',\n $el_text: 'Visible text content of the element',\n 'attr__*': 'HTML attribute prefixed with attr__. Example: attr__data-id matches the data-id attribute, ' +\n 'attr__class matches the class attribute, attr__href matches the href attribute.',\n};\n// =============================================================================\n// EVENT SCOPE SCHEMA\n// =============================================================================\n/** Scopes a widget to specific events/URLs. */\nexport const EventScopeZ = z.object({\n events: z.array(z.string()),\n urlContains: z.string().optional(),\n props: z.record(z.union([z.string(), z.number(), z.boolean()])).optional(),\n});\n// =============================================================================\n// NOTIFY SCHEMA\n// =============================================================================\n/** Toast notification config for triggerWhen transitions. */\nexport const NotifyZ = z\n .object({\n title: z.string().optional(),\n body: z.string().optional(),\n icon: z.string().optional(),\n})\n .nullable()\n .optional();\n", "import { type MountPlumbing, stripMountPlumbing } from '@syntrologie/sdk-contracts';\nimport { css, html, LitElement, nothing } from 'lit';\n\nimport { FlowEngine } from './engine/FlowEngine.js';\nimport './rendering/ChoiceInput.js';\nimport './rendering/EndScreen.js';\nimport './rendering/NpsInput.js';\nimport './rendering/RatingInput.js';\nimport './rendering/TextInput.js';\nimport './rendering/ThumbsInput.js';\nimport type { FeedbackConfig, FeedbackWidgetRuntime, SurveyStep } from './types.js';\n\nexport class SyntroFeedbackElement extends LitElement {\n static override properties = {\n config: { attribute: false },\n runtime: { attribute: false },\n tileId: { type: String },\n _engine: { state: true },\n _direction: { state: true },\n };\n\n static override styles = css`\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n font-family: var(--sc-font-family, system-ui, -apple-system, sans-serif);\n color: var(--sc-content-text-color, #111827);\n }\n .header {\n padding: 12px 16px 8px;\n font-size: 15px;\n font-weight: 600;\n color: var(--sc-content-text-color, #111827);\n }\n .progress-bar {\n height: 3px;\n background: var(--sc-content-border-color, #e5e7eb);\n margin: 0 16px;\n border-radius: 2px;\n overflow: hidden;\n }\n .progress-fill {\n height: 100%;\n background: var(--sc-color-primary, #4f46e5);\n border-radius: 2px;\n transition: width 0.3s ease;\n }\n .step-container {\n flex: 1;\n overflow: hidden;\n position: relative;\n }\n .step-content {\n padding: 16px;\n animation-duration: 0.25s;\n animation-fill-mode: both;\n animation-timing-function: ease-out;\n }\n .step-content.slide-in-right {\n animation-name: slideInRight;\n }\n .step-content.slide-in-left {\n animation-name: slideInLeft;\n }\n @keyframes slideInRight {\n from { transform: translateX(30px); opacity: 0; }\n to { transform: translateX(0); opacity: 1; }\n }\n @keyframes slideInLeft {\n from { transform: translateX(-30px); opacity: 0; }\n to { transform: translateX(0); opacity: 1; }\n }\n .prompt {\n font-size: 15px;\n font-weight: 500;\n line-height: 1.4;\n margin-bottom: 4px;\n }\n .description {\n font-size: 13px;\n color: var(--sc-content-text-secondary-color, #6b7280);\n margin-bottom: 8px;\n line-height: 1.4;\n }\n .footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 16px 12px;\n gap: 8px;\n }\n .back-btn {\n padding: 6px 14px;\n border-radius: 6px;\n border: 1px solid var(--sc-content-border-color, #e5e7eb);\n background: transparent;\n color: var(--sc-content-text-secondary-color, #6b7280);\n font-size: 13px;\n cursor: pointer;\n transition: border-color 0.15s;\n }\n .back-btn:hover {\n border-color: var(--sc-content-text-color, #111827);\n }\n .step-count {\n font-size: 12px;\n color: var(--sc-content-text-secondary-color, #9ca3af);\n }\n `;\n\n config: FeedbackConfig | undefined;\n runtime: FeedbackWidgetRuntime | undefined;\n tileId: string = 'feedback-widget';\n\n private _engine: FlowEngine | undefined;\n private _direction: 'forward' | 'back' = 'forward';\n\n override willUpdate(changed: Map<string, unknown>) {\n if (changed.has('config') && this.config?.steps?.length) {\n try {\n this._engine = new FlowEngine(this.config.steps);\n } catch {\n this._engine = undefined;\n }\n }\n }\n\n private _onAnswer = (e: CustomEvent<{ value: string | number }>) => {\n if (!this._engine || !this.config) return;\n const step = this._engine.currentStep;\n const { value } = e.detail;\n\n this.runtime?.events.publish('feedback:response', {\n surveyId: this.tileId,\n stepId: step.id,\n stepType: step.type,\n value,\n stepIndex: this._engine.stepIndex,\n });\n\n this._direction = 'forward';\n this._engine.answer(value);\n const updated: FlowEngine = Object.create(\n Object.getPrototypeOf(this._engine),\n Object.getOwnPropertyDescriptors(this._engine)\n );\n this._engine = updated;\n\n if (updated.isComplete) {\n this.runtime?.events.publish('feedback:completed', {\n surveyId: this.tileId,\n stepsCompleted: updated.stepsCompleted,\n abandoned: false,\n });\n }\n };\n\n private _goBack = () => {\n if (!this._engine) return;\n this._direction = 'back';\n this._engine.goBack();\n this._engine = Object.create(\n Object.getPrototypeOf(this._engine),\n Object.getOwnPropertyDescriptors(this._engine)\n );\n };\n\n private _renderStepInput(step: SurveyStep) {\n const prevAnswer = this._engine?.answers.get(step.id);\n\n switch (step.type) {\n case 'thumbs':\n return html`<sf-thumbs-input\n .value=${prevAnswer as number | undefined}\n @step-answer=${this._onAnswer}\n ></sf-thumbs-input>`;\n\n case 'rating':\n return html`<sf-rating-input\n .max=${step.ratingMax ?? 5}\n .value=${prevAnswer as number | undefined}\n @step-answer=${this._onAnswer}\n ></sf-rating-input>`;\n\n case 'nps':\n return html`<sf-nps-input\n .lowLabel=${step.npsLowLabel ?? 'Not likely'}\n .highLabel=${step.npsHighLabel ?? 'Very likely'}\n .value=${prevAnswer as number | undefined}\n @step-answer=${this._onAnswer}\n ></sf-nps-input>`;\n\n case 'choice':\n return html`<sf-choice-input\n .options=${step.options ?? []}\n .value=${prevAnswer as string | undefined}\n @step-answer=${this._onAnswer}\n ></sf-choice-input>`;\n\n case 'text':\n return html`<sf-text-input\n .placeholder=${step.placeholder ?? ''}\n .value=${(prevAnswer as string) ?? ''}\n .required=${step.required !== false}\n @step-answer=${this._onAnswer}\n ></sf-text-input>`;\n\n case 'end':\n return html`<sf-end-screen .message=${step.prompt}></sf-end-screen>`;\n\n default:\n return nothing;\n }\n }\n\n override render() {\n if (!this._engine || !this.config) {\n return html`<div style=\"padding:16px;color:var(--sc-content-text-secondary-color,#87919f)\">\n Survey widget requires config.\n </div>`;\n }\n\n const step = this._engine.currentStep;\n const showProgress = this.config.showProgress !== false;\n const allowBack = this.config.allowBack === true;\n const canGoBack = allowBack && this._engine.path.length > 1 && step.type !== 'end';\n const totalSteps = this.config.steps.filter((s) => s.type !== 'end').length;\n const progressPct = totalSteps > 0 ? (this._engine.stepsCompleted / totalSteps) * 100 : 0;\n const animClass = this._direction === 'forward' ? 'slide-in-right' : 'slide-in-left';\n\n return html`\n ${this.config.title ? html`<div class=\"header\">${this.config.title}</div>` : nothing}\n ${\n showProgress && step.type !== 'end'\n ? html`<div class=\"progress-bar\">\n <div class=\"progress-fill\" style=\"width:${progressPct}%\"></div>\n </div>`\n : nothing\n }\n <div class=\"step-container\">\n <div class=\"step-content ${animClass}\" key=${step.id}>\n ${\n step.type !== 'end'\n ? html`\n <div class=\"prompt\">${step.prompt}</div>\n ${step.description ? html`<div class=\"description\">${step.description}</div>` : nothing}\n `\n : nothing\n }\n ${this._renderStepInput(step)}\n </div>\n </div>\n ${\n canGoBack || (step.type !== 'end' && showProgress)\n ? html`<div class=\"footer\">\n ${\n canGoBack\n ? html`<button type=\"button\" class=\"back-btn\" @click=${this._goBack}>\u2190 Back</button>`\n : html`<span></span>`\n }\n ${\n step.type !== 'end'\n ? html`<span class=\"step-count\">${this._engine.stepsCompleted + 1} of ${totalSteps}</span>`\n : nothing\n }\n </div>`\n : nothing\n }\n `;\n }\n}\n\ncustomElements.define('syntro-feedback', SyntroFeedbackElement);\n\n// The runtime SDK (SyntroTileCard + WidgetRegistry) delivers tile.props spread\n// flat into mountConfig, alongside `instanceId` and `runtime`. Mountables must\n// destructure flat \u2014 there is no nested `config` field. The legacy `config`\n// and `tileId` keys are accepted for direct callers (e.g. unit tests or\n// imperative mounts that opt into the nested shape).\ntype FlatMountConfig = FeedbackConfig & {\n runtime?: FeedbackWidgetRuntime;\n instanceId?: string;\n tileId?: string;\n /** Legacy nested-config escape hatch for direct callers. */\n config?: FeedbackConfig;\n};\n\nexport const FeedbackWidgetLitMountable = {\n mount(container: HTMLElement, mountConfig?: Record<string, unknown>) {\n const incoming = (mountConfig ?? null) as\n | (Partial<FlatMountConfig> & MountPlumbing & Record<string, unknown>)\n | null;\n const runtime = incoming?.runtime as FeedbackWidgetRuntime | undefined;\n const instanceId = incoming?.instanceId;\n const tileId = incoming?.tileId;\n const nestedConfig = incoming?.config;\n\n // Strip the canonical plumbing keys, then peel off the legacy nested\n // `config` escape hatch to recover the flat FeedbackConfig shape.\n const flat = stripMountPlumbing<Record<string, unknown>>(incoming);\n if ('config' in flat) {\n delete (flat as { config?: unknown }).config;\n }\n\n const feedbackConfig: FeedbackConfig | undefined =\n nestedConfig ?? ({ ...(flat as unknown as FeedbackConfig) } as FeedbackConfig);\n const resolvedTileId = tileId ?? instanceId ?? 'feedback-widget';\n\n if (!feedbackConfig?.steps?.length) {\n container.innerHTML =\n '<div style=\"padding:16px;color:var(--sc-content-text-secondary-color,#87919f)\">Feedback widget requires config.</div>';\n return () => {\n container.innerHTML = '';\n };\n }\n\n let tracker: FlowEngine | undefined;\n try {\n tracker = new FlowEngine(feedbackConfig.steps);\n } catch {\n // invalid config \u2014 element will show its own error\n }\n\n const el = document.createElement('syntro-feedback') as SyntroFeedbackElement;\n el.config = feedbackConfig;\n el.runtime = runtime;\n el.tileId = resolvedTileId;\n el.style.cssText = 'display:flex;flex-direction:column;height:100%;width:100%;';\n\n container.appendChild(el);\n\n let completed = false;\n const onAnswer = (e: Event) => {\n const detail = (e as CustomEvent<{ value: string | number }>).detail;\n if (tracker && !tracker.isComplete) {\n tracker.answer(detail.value);\n if (tracker.isComplete) completed = true;\n }\n };\n el.addEventListener('step-answer', onAnswer);\n\n return () => {\n el.removeEventListener('step-answer', onAnswer);\n if (!completed && runtime && tracker) {\n runtime.events.publish('feedback:abandoned', {\n surveyId: resolvedTileId,\n lastStepId: tracker.currentStep.id,\n stepsCompleted: tracker.stepsCompleted,\n abandoned: true,\n });\n }\n el.remove();\n };\n },\n};\n", "import type { BranchRule, SurveyStep } from '../types';\n\nexport class FlowEngineValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'FlowEngineValidationError';\n }\n}\n\nexport class FlowEngine {\n private _steps: SurveyStep[];\n private _stepMap: Map<string, SurveyStep>;\n private _answers: Map<string, string | number> = new Map();\n private _path: string[];\n\n constructor(steps: SurveyStep[]) {\n this._validate(steps);\n this._steps = steps;\n this._stepMap = new Map(steps.map((s) => [s.id, s]));\n this._path = [steps[0].id];\n }\n\n get currentStep(): SurveyStep {\n const id = this._path[this._path.length - 1];\n return this._stepMap.get(id)!;\n }\n\n get answers(): ReadonlyMap<string, string | number> {\n return this._answers;\n }\n\n get path(): readonly string[] {\n return this._path;\n }\n\n get isComplete(): boolean {\n return this.currentStep.type === 'end';\n }\n\n get stepsCompleted(): number {\n return this._path.filter((id) => this._answers.has(id)).length;\n }\n\n get stepIndex(): number {\n return this._path.length - 1;\n }\n\n getStep(id: string): SurveyStep | undefined {\n return this._stepMap.get(id);\n }\n\n answer(value: string | number): void {\n const step = this.currentStep;\n if (step.type === 'end') return;\n\n this._answers.set(step.id, value);\n const nextId = this._resolveNext(step, value);\n\n const currentIdx = this._path.length - 1;\n this._path = this._path.slice(0, currentIdx + 1);\n this._path.push(nextId);\n }\n\n goBack(): void {\n if (this._path.length <= 1) return;\n this._path = this._path.slice(0, -1);\n }\n\n private _resolveNext(step: SurveyStep, value: string | number): string {\n if (step.next === undefined) {\n return this._nextInArray(step.id);\n }\n\n if (typeof step.next === 'string') {\n return step.next;\n }\n\n for (const rule of step.next) {\n if (this._evaluateRule(rule, value)) {\n return rule.goto;\n }\n }\n\n return this._nextInArray(step.id);\n }\n\n private _nextInArray(currentId: string): string {\n const idx = this._steps.findIndex((s) => s.id === currentId);\n return this._steps[idx + 1].id;\n }\n\n private _evaluateRule(rule: BranchRule, value: string | number): boolean {\n const { op, value: ruleValue } = rule.if;\n\n switch (op) {\n case 'eq':\n return value === ruleValue;\n case 'neq':\n return value !== ruleValue;\n case 'lt':\n return Number(value) < Number(ruleValue);\n case 'lte':\n return Number(value) <= Number(ruleValue);\n case 'gt':\n return Number(value) > Number(ruleValue);\n case 'gte':\n return Number(value) >= Number(ruleValue);\n case 'in':\n return Array.isArray(ruleValue) && ruleValue.includes(String(value));\n default:\n return false;\n }\n }\n\n private _validate(steps: SurveyStep[]): void {\n if (steps.length === 0) {\n throw new FlowEngineValidationError('Steps array must not be empty');\n }\n\n const ids = new Set<string>();\n for (const step of steps) {\n if (ids.has(step.id)) {\n throw new FlowEngineValidationError(`Duplicate step ID: \"${step.id}\"`);\n }\n ids.add(step.id);\n }\n\n const hasEnd = steps.some((s) => s.type === 'end');\n if (!hasEnd) {\n throw new FlowEngineValidationError('At least one step must have type \"end\"');\n }\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i];\n if (typeof step.next === 'string') {\n if (!ids.has(step.next)) {\n throw new FlowEngineValidationError(\n `Step \"${step.id}\" has next target \"${step.next}\" which does not exist`\n );\n }\n } else if (Array.isArray(step.next)) {\n for (const rule of step.next) {\n if (!ids.has(rule.goto)) {\n throw new FlowEngineValidationError(\n `Step \"${step.id}\" has branch rule targeting \"${rule.goto}\" which does not exist`\n );\n }\n }\n }\n\n if (step.type !== 'end' && step.next === undefined && i === steps.length - 1) {\n throw new FlowEngineValidationError(\n `Step \"${step.id}\" is last in the array with no explicit \"next\" and is not an end step`\n );\n }\n }\n }\n}\n", "import { css, html, LitElement } from 'lit';\n\nexport class ChoiceInput extends LitElement {\n static override properties = {\n options: { attribute: false },\n value: { type: String },\n };\n\n static override styles = css`\n :host { display: block; }\n .choices {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 8px 0;\n }\n button {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 10px 14px;\n border-radius: 8px;\n border: 2px solid var(--sc-content-border-color, #e5e7eb);\n background: var(--sc-content-bg-color, #fff);\n color: var(--sc-content-text-color, #111827);\n font-size: 14px;\n text-align: left;\n cursor: pointer;\n transition: border-color 0.15s, background 0.15s;\n }\n button:hover {\n border-color: var(--sc-color-primary, #4f46e5);\n }\n button[aria-pressed=\"true\"] {\n border-color: var(--sc-color-primary, #4f46e5);\n background: var(--sc-color-primary-light, #eef2ff);\n }\n .radio {\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: 2px solid var(--sc-content-border-color, #e5e7eb);\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n button[aria-pressed=\"true\"] .radio {\n border-color: var(--sc-color-primary, #4f46e5);\n }\n .radio-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: transparent;\n }\n button[aria-pressed=\"true\"] .radio-dot {\n background: var(--sc-color-primary, #4f46e5);\n }\n `;\n\n options: string[] = [];\n value: string | undefined;\n\n private _select(opt: string) {\n this.value = opt;\n this.dispatchEvent(\n new CustomEvent('step-answer', {\n detail: { value: opt },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n override render() {\n return html`\n <div class=\"choices\" role=\"radiogroup\">\n ${(this.options ?? []).map(\n (opt) => html`\n <button\n type=\"button\"\n role=\"radio\"\n aria-pressed=${this.value === opt ? 'true' : 'false'}\n @click=${() => this._select(opt)}\n >\n <span class=\"radio\"><span class=\"radio-dot\"></span></span>\n ${opt}\n </button>\n `\n )}\n </div>\n `;\n }\n}\n\ncustomElements.define('sf-choice-input', ChoiceInput);\n", "import { css, html, LitElement } from 'lit';\n\nexport class EndScreen extends LitElement {\n static override properties = {\n message: { type: String },\n };\n\n static override styles = css`\n :host { display: block; }\n .end-wrap {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 24px 16px;\n text-align: center;\n gap: 12px;\n }\n .checkmark {\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: var(--sc-color-primary-light, #eef2ff);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 24px;\n }\n .message {\n color: var(--sc-content-text-color, #111827);\n font-size: 16px;\n font-weight: 500;\n line-height: 1.5;\n }\n `;\n\n message: string = 'Thank you!';\n\n override render() {\n return html`\n <div class=\"end-wrap\">\n <div class=\"checkmark\">\u2713</div>\n <div class=\"message\">${this.message}</div>\n </div>\n `;\n }\n}\n\ncustomElements.define('sf-end-screen', EndScreen);\n", "import { css, html, LitElement } from 'lit';\n\nexport class NpsInput extends LitElement {\n static override properties = {\n lowLabel: { type: String },\n highLabel: { type: String },\n value: { type: Number },\n };\n\n static override styles = css`\n :host { display: block; }\n .nps-scale {\n display: flex;\n gap: 4px;\n justify-content: center;\n padding: 12px 0 4px;\n }\n button {\n min-width: 32px;\n height: 36px;\n border-radius: 6px;\n border: 2px solid var(--sc-content-border-color, #e5e7eb);\n background: var(--sc-content-bg-color, #fff);\n color: var(--sc-content-text-color, #111827);\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: border-color 0.15s, background 0.15s;\n padding: 0 4px;\n }\n button:hover {\n border-color: var(--sc-color-primary, #4f46e5);\n }\n button[aria-pressed=\"true\"] {\n border-color: var(--sc-color-primary, #4f46e5);\n background: var(--sc-color-primary, #4f46e5);\n color: #fff;\n }\n .labels {\n display: flex;\n justify-content: space-between;\n padding: 4px 2px 0;\n font-size: 12px;\n color: var(--sc-content-text-secondary-color, #6b7280);\n }\n `;\n\n lowLabel: string = 'Not likely';\n highLabel: string = 'Very likely';\n value: number | undefined;\n\n private _select(val: number) {\n this.value = val;\n this.dispatchEvent(\n new CustomEvent('step-answer', {\n detail: { value: val },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n override render() {\n const items = Array.from({ length: 11 }, (_, i) => i);\n return html`\n <div>\n <div class=\"nps-scale\">\n ${items.map(\n (n) => html`\n <button\n type=\"button\"\n aria-label=\"Score ${n}\"\n aria-pressed=${this.value === n ? 'true' : 'false'}\n @click=${() => this._select(n)}\n >${n}</button>\n `\n )}\n </div>\n <div class=\"labels\">\n <span>${this.lowLabel}</span>\n <span>${this.highLabel}</span>\n </div>\n </div>\n `;\n }\n}\n\ncustomElements.define('sf-nps-input', NpsInput);\n", "import { css, html, LitElement } from 'lit';\n\nexport class RatingInput extends LitElement {\n static override properties = {\n max: { type: Number },\n value: { type: Number },\n };\n\n static override styles = css`\n :host { display: block; }\n .rating-row {\n display: flex;\n gap: 8px;\n justify-content: center;\n padding: 12px 0;\n }\n button {\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: 2px solid var(--sc-content-border-color, #e5e7eb);\n background: var(--sc-content-bg-color, #fff);\n color: var(--sc-content-text-color, #111827);\n font-size: 16px;\n font-weight: 600;\n cursor: pointer;\n transition: transform 0.1s, border-color 0.15s, background 0.15s;\n }\n button:hover {\n border-color: var(--sc-color-primary, #4f46e5);\n }\n button[aria-pressed=\"true\"],\n button.selected {\n border-color: var(--sc-color-primary, #4f46e5);\n background: var(--sc-color-primary, #4f46e5);\n color: #fff;\n }\n `;\n\n max: number = 5;\n value: number | undefined;\n\n private _select(val: number) {\n this.value = val;\n this.dispatchEvent(\n new CustomEvent('step-answer', {\n detail: { value: val },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n override render() {\n const count = this.max || 5;\n const items = Array.from({ length: count }, (_, i) => i + 1);\n return html`\n <div class=\"rating-row\">\n ${items.map(\n (n) => html`\n <button\n type=\"button\"\n aria-label=\"Rate ${n} of ${count}\"\n aria-pressed=${this.value === n ? 'true' : 'false'}\n class=${this.value === n ? 'selected' : ''}\n @click=${() => this._select(n)}\n >${n}</button>\n `\n )}\n </div>\n `;\n }\n}\n\ncustomElements.define('sf-rating-input', RatingInput);\n", "import { css, html, LitElement } from 'lit';\n\nexport class TextInput extends LitElement {\n static override properties = {\n placeholder: { type: String },\n value: { type: String },\n required: { type: Boolean },\n };\n\n static override styles = css`\n :host { display: block; }\n .text-wrap {\n padding: 8px 0;\n }\n textarea {\n width: 100%;\n min-height: 80px;\n padding: 10px 12px;\n border-radius: 8px;\n border: 2px solid var(--sc-content-border-color, #e5e7eb);\n background: var(--sc-content-bg-color, #fff);\n color: var(--sc-content-text-color, #111827);\n font-family: inherit;\n font-size: 14px;\n resize: vertical;\n box-sizing: border-box;\n transition: border-color 0.15s;\n }\n textarea:focus {\n outline: none;\n border-color: var(--sc-color-primary, #4f46e5);\n }\n textarea::placeholder {\n color: var(--sc-content-text-secondary-color, #9ca3af);\n }\n .submit-row {\n display: flex;\n justify-content: flex-end;\n padding-top: 8px;\n }\n button {\n padding: 8px 20px;\n border-radius: 8px;\n border: none;\n background: var(--sc-color-primary, #4f46e5);\n color: #fff;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: opacity 0.15s;\n }\n button:hover { opacity: 0.9; }\n button:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n }\n `;\n\n placeholder: string = '';\n value: string = '';\n required: boolean = true;\n\n private _currentText = '';\n\n private _handleInput = (e: Event) => {\n this._currentText = (e.target as HTMLTextAreaElement).value;\n this.requestUpdate();\n };\n\n private _submit = () => {\n if (this.required && !this._currentText.trim()) return;\n this.dispatchEvent(\n new CustomEvent('step-answer', {\n detail: { value: this._currentText },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n override connectedCallback() {\n super.connectedCallback();\n this._currentText = this.value || '';\n }\n\n override render() {\n const canSubmit = !this.required || this._currentText.trim().length > 0;\n return html`\n <div class=\"text-wrap\">\n <textarea\n .value=${this._currentText}\n placeholder=${this.placeholder || 'Type your answer...'}\n @input=${this._handleInput}\n ></textarea>\n <div class=\"submit-row\">\n <button type=\"button\" ?disabled=${!canSubmit} @click=${this._submit}>\n Submit\n </button>\n </div>\n </div>\n `;\n }\n}\n\ncustomElements.define('sf-text-input', TextInput);\n", "import { css, html, LitElement } from 'lit';\n\nexport class ThumbsInput extends LitElement {\n static override properties = {\n value: { type: Number },\n };\n\n static override styles = css`\n :host { display: block; }\n .thumbs-row {\n display: flex;\n gap: 16px;\n justify-content: center;\n padding: 12px 0;\n }\n button {\n width: 64px;\n height: 64px;\n border-radius: 50%;\n border: 2px solid var(--sc-content-border-color, #e5e7eb);\n background: var(--sc-content-bg-color, #fff);\n font-size: 28px;\n cursor: pointer;\n transition: transform 0.15s, border-color 0.15s, background 0.15s;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n button:hover {\n transform: scale(1.1);\n border-color: var(--sc-color-primary, #4f46e5);\n }\n button[aria-pressed=\"true\"] {\n border-color: var(--sc-color-primary, #4f46e5);\n background: var(--sc-color-primary-light, #eef2ff);\n }\n `;\n\n value: number | undefined;\n\n private _select(val: number) {\n this.value = val;\n this.dispatchEvent(\n new CustomEvent('step-answer', {\n detail: { value: val },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n override render() {\n return html`\n <div class=\"thumbs-row\">\n <button\n type=\"button\"\n aria-label=\"Thumbs up\"\n aria-pressed=${this.value === 1 ? 'true' : 'false'}\n @click=${() => this._select(1)}\n >\\u{1F44D}</button>\n <button\n type=\"button\"\n aria-label=\"Thumbs down\"\n aria-pressed=${this.value === 0 ? 'true' : 'false'}\n @click=${() => this._select(0)}\n >\\u{1F44E}</button>\n </div>\n `;\n }\n}\n\ncustomElements.define('sf-thumbs-input', ThumbsInput);\n"],
5
- "mappings": "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",
6
- "names": ["css", "html", "LitElement", "css", "html", "LitElement", "css", "html", "LitElement", "css", "html", "LitElement", "css", "html", "LitElement", "css", "html", "LitElement", "LitElement", "html", "css"]
7
- }