@revenuecat/purchases-ui-js 4.8.9 → 4.8.10

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.
Files changed (38) hide show
  1. package/dist/components/button/ButtonNode.svelte +10 -11
  2. package/dist/components/carousel/Carousel.svelte +5 -5
  3. package/dist/components/icon/Icon.svelte +6 -24
  4. package/dist/components/image/Image.svelte +6 -24
  5. package/dist/components/input-text/InputText.svelte +10 -21
  6. package/dist/components/paywall/Paywall.stories.svelte +17 -0
  7. package/dist/components/paywall/Paywall.svelte +11 -0
  8. package/dist/components/paywall/Sheet.svelte +4 -4
  9. package/dist/components/stack/Stack.svelte +9 -28
  10. package/dist/components/tabs/TabControlToggle.svelte +5 -7
  11. package/dist/components/tabs/Tabs.svelte +26 -26
  12. package/dist/components/tabs/fixtures/tab-state-paywall.d.ts +25 -0
  13. package/dist/components/tabs/fixtures/tab-state-paywall.js +432 -0
  14. package/dist/components/text/TextNode.svelte +8 -37
  15. package/dist/components/timeline/Timeline.svelte +6 -25
  16. package/dist/components/timeline/TimelineItem.svelte +4 -4
  17. package/dist/components/video/Video.svelte +8 -25
  18. package/dist/components/web-view/WebView.svelte +6 -23
  19. package/dist/components/web-view/web-view-sdk.d.ts +21 -33
  20. package/dist/components/web-view/web-view-sdk.js +37 -47
  21. package/dist/components/workflows/Workflow.svelte +37 -7
  22. package/dist/components/workflows/fixtures/state-two-page-workflow.d.ts +2 -0
  23. package/dist/components/workflows/fixtures/state-two-page-workflow.js +80 -0
  24. package/dist/stores/condition-context.svelte.d.ts +14 -0
  25. package/dist/stores/condition-context.svelte.js +41 -0
  26. package/dist/stores/state.d.ts +29 -0
  27. package/dist/stores/state.js +136 -0
  28. package/dist/types/components/button.d.ts +2 -0
  29. package/dist/types/components/carousel.d.ts +2 -0
  30. package/dist/types/components/tabs.d.ts +2 -0
  31. package/dist/types/overrides.d.ts +9 -1
  32. package/dist/types/overrides.js +1 -0
  33. package/dist/types/paywall.d.ts +3 -0
  34. package/dist/types/state.d.ts +30 -0
  35. package/dist/types/state.js +11 -0
  36. package/dist/utils/style-utils.d.ts +21 -15
  37. package/dist/utils/style-utils.js +86 -61
  38. package/package.json +1 -1
@@ -1,15 +1,15 @@
1
1
  <script lang="ts">
2
2
  import Stack from "../stack/Stack.svelte";
3
+ import { useConditionContext } from "../../stores/condition-context.svelte";
3
4
  import { getInputValidationContext } from "../../stores/inputValidation";
4
5
  import { getLocalizationContext } from "../../stores/localization";
5
6
  import { getPaywallContext } from "../../stores/paywall";
6
- import { getSelectedStateContext } from "../../stores/selected";
7
7
  import type { ButtonProps } from "../../types/components/button";
8
8
  import type {
9
9
  ButtonInteractionData,
10
10
  PackageSelectionSheetInteractionData,
11
11
  } from "../../types/paywall-component-interaction";
12
- import { getActiveStateProps } from "../../utils/style-utils";
12
+ import { resolveOverrideProperties } from "../../utils/style-utils";
13
13
  import { fromStore, readable } from "svelte/store";
14
14
  import { isWorkflowButtonInputGated } from "./button-input-gating";
15
15
 
@@ -19,20 +19,19 @@
19
19
  { type: "navigate_to"; destination: "sheet" }
20
20
  >;
21
21
 
22
- const selectedState = getSelectedStateContext();
23
- const { action } = $derived.by(() => {
24
- return {
25
- ...props,
26
- ...getActiveStateProps($selectedState, props.overrides),
27
- };
28
- });
29
-
30
22
  const {
31
23
  emitComponentInteraction,
32
24
  onButtonAction,
33
25
  hideBackButtons,
34
26
  selectedPackageId,
35
27
  } = getPaywallContext();
28
+ const buildConditionContext = useConditionContext();
29
+ const { action, stack } = $derived.by(() => {
30
+ return {
31
+ ...props,
32
+ ...resolveOverrideProperties(buildConditionContext(), props.overrides),
33
+ };
34
+ });
36
35
  const validationContext = getInputValidationContext();
37
36
  const { getLocalizedString } = getLocalizationContext();
38
37
 
@@ -190,7 +189,7 @@
190
189
  inputSatisfied.current,
191
190
  )}
192
191
  <Stack
193
- {...props.stack}
192
+ {...stack}
194
193
  {onclick}
195
194
  style={isDisabled
196
195
  ? { opacity: "0.4", "pointer-events": "none", cursor: "not-allowed" }
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { getColorModeContext } from "../../stores/color-mode";
3
+ import { useConditionContext } from "../../stores/condition-context.svelte";
3
4
  import { getPaywallContext } from "../../stores/paywall";
4
- import { getSelectedStateContext } from "../../stores/selected";
5
5
  import BackgroundVideoSurface from "../paywall/BackgroundVideoSurface.svelte";
6
6
  import type { CarouselProps } from "../../types/components/carousel";
7
7
  import {
@@ -20,7 +20,7 @@
20
20
  mapSpacing,
21
21
  px,
22
22
  } from "../../utils/base-utils";
23
- import { getActiveStateProps } from "../../utils/style-utils";
23
+ import { resolveOverrideProperties } from "../../utils/style-utils";
24
24
  import { onMount } from "svelte";
25
25
  import {
26
26
  clamp,
@@ -32,7 +32,8 @@
32
32
  import PageControl from "./PageControl.svelte";
33
33
 
34
34
  const props: CarouselProps = $props();
35
- const selectedState = getSelectedStateContext();
35
+ const { emitComponentInteraction } = getPaywallContext();
36
+ const buildConditionContext = useConditionContext();
36
37
  const {
37
38
  pages,
38
39
  padding,
@@ -51,13 +52,12 @@
51
52
  } = $derived.by(() => {
52
53
  return {
53
54
  ...props,
54
- ...getActiveStateProps($selectedState, props.overrides),
55
+ ...resolveOverrideProperties(buildConditionContext(), props.overrides),
55
56
  };
56
57
  });
57
58
 
58
59
  const getColorMode = getColorModeContext();
59
60
  const colorMode = $derived(getColorMode());
60
- const { emitComponentInteraction } = getPaywallContext();
61
61
 
62
62
  const hasVideoBg = $derived(background?.type === "video");
63
63
  const videoSurface = $derived.by(() => {
@@ -1,9 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { getColorModeContext } from "../../stores/color-mode";
3
- import { getOptionalPackageInfoContext } from "../../stores/packageInfo";
4
- import { getPaywallContext } from "../../stores/paywall";
5
- import { getSelectedStateContext } from "../../stores/selected";
6
- import { getOptionalVariablesContext } from "../../stores/variables";
3
+ import { useConditionContext } from "../../stores/condition-context.svelte";
7
4
  import type { IconProps } from "../../types/components/icon";
8
5
  import {
9
6
  css,
@@ -14,16 +11,10 @@
14
11
  mapSize,
15
12
  mapSpacing,
16
13
  } from "../../utils/base-utils";
17
- import {
18
- evaluateVisibilityConditions,
19
- getActiveStateProps,
20
- } from "../../utils/style-utils";
14
+ import { resolveOverrideProperties } from "../../utils/style-utils";
21
15
 
22
16
  const props: IconProps = $props();
23
- const selectedState = getSelectedStateContext();
24
- const packageInfo = getOptionalPackageInfoContext();
25
- const { selectedPackageId } = getPaywallContext();
26
- const variables = getOptionalVariablesContext();
17
+ const buildConditionContext = useConditionContext({ state: true });
27
18
  const {
28
19
  base_url,
29
20
  formats,
@@ -32,10 +23,11 @@
32
23
  padding,
33
24
  color,
34
25
  icon_background: background,
26
+ visible,
35
27
  } = $derived.by(() => {
36
28
  return {
37
29
  ...props,
38
- ...getActiveStateProps($selectedState, props.overrides),
30
+ ...resolveOverrideProperties(buildConditionContext(), props.overrides),
39
31
  };
40
32
  });
41
33
 
@@ -56,17 +48,7 @@
56
48
  }),
57
49
  );
58
50
 
59
- const isVisible = $derived(
60
- evaluateVisibilityConditions(
61
- {
62
- selectedPackageId: $selectedPackageId,
63
- packageInfo: $packageInfo,
64
- variables: $variables ?? {},
65
- },
66
- props.overrides,
67
- props.visible,
68
- ),
69
- );
51
+ const isVisible = $derived(visible !== false);
70
52
 
71
53
  const webpUrl = $derived(`${base_url}/${formats.webp}`);
72
54
  const icon = $derived(
@@ -1,9 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { getColorModeContext } from "../../stores/color-mode";
3
- import { getOptionalPackageInfoContext } from "../../stores/packageInfo";
4
- import { getPaywallContext } from "../../stores/paywall";
5
- import { getSelectedStateContext } from "../../stores/selected";
6
- import { getOptionalVariablesContext } from "../../stores/variables";
3
+ import { useConditionContext } from "../../stores/condition-context.svelte";
7
4
  import type { ImageProps } from "../../types/components/image";
8
5
  import {
9
6
  css,
@@ -13,19 +10,13 @@
13
10
  mapSize,
14
11
  mapSpacing,
15
12
  } from "../../utils/base-utils";
16
- import {
17
- evaluateVisibilityConditions,
18
- getActiveStateProps,
19
- } from "../../utils/style-utils";
13
+ import { resolveOverrideProperties } from "../../utils/style-utils";
20
14
  import ClipPath from "./ClipPath.svelte";
21
15
  import Overlay from "./Overlay.svelte";
22
16
 
23
17
  const props: ImageProps = $props();
24
18
 
25
- const selectedState = getSelectedStateContext();
26
- const packageInfo = getOptionalPackageInfoContext();
27
- const { selectedPackageId } = getPaywallContext();
28
- const variables = getOptionalVariablesContext();
19
+ const buildConditionContext = useConditionContext({ state: true });
29
20
  const {
30
21
  id,
31
22
  source,
@@ -37,10 +28,11 @@
37
28
  color_overlay,
38
29
  border,
39
30
  shadow,
31
+ visible,
40
32
  } = $derived.by(() => {
41
33
  return {
42
34
  ...props,
43
- ...getActiveStateProps($selectedState, props.overrides),
35
+ ...resolveOverrideProperties(buildConditionContext(), props.overrides),
44
36
  };
45
37
  });
46
38
 
@@ -122,17 +114,7 @@
122
114
  color_overlay && mapColorMode(colorMode, color_overlay),
123
115
  );
124
116
 
125
- const isVisible = $derived(
126
- evaluateVisibilityConditions(
127
- {
128
- selectedPackageId: $selectedPackageId,
129
- packageInfo: $packageInfo,
130
- variables: $variables ?? {},
131
- },
132
- props.overrides,
133
- props.visible,
134
- ),
135
- );
117
+ const isVisible = $derived(visible !== false);
136
118
  </script>
137
119
 
138
120
  {#if isVisible}
@@ -1,8 +1,8 @@
1
1
  <script lang="ts">
2
2
  import { getColorModeContext } from "../../stores/color-mode";
3
+ import { useConditionContext } from "../../stores/condition-context.svelte";
3
4
  import { getInputValidationContext } from "../../stores/inputValidation";
4
5
  import { getLocalizationContext } from "../../stores/localization";
5
- import { getOptionalPackageInfoContext } from "../../stores/packageInfo";
6
6
  import { getPaywallContext } from "../../stores/paywall";
7
7
  import { getOptionalVariablesContext } from "../../stores/variables";
8
8
  import { FontWeights, TextAlignments } from "../../types";
@@ -23,11 +23,7 @@
23
23
  getScopedFontFamily,
24
24
  isFontRCFMManaged,
25
25
  } from "../../utils/font-utils";
26
- import {
27
- evaluateVisibilityConditions,
28
- getErrorStateProps,
29
- getFocusStateProps,
30
- } from "../../utils/style-utils";
26
+ import { resolveOverrideProperties } from "../../utils/style-utils";
31
27
  import { replaceVariables } from "../../utils/variable-utils";
32
28
  import type { FormEventHandler, HTMLInputAttributes } from "svelte/elements";
33
29
  import { mapTextColor } from "../text/text-utils";
@@ -38,6 +34,8 @@
38
34
  let error = $state(false);
39
35
  let valid = $state(!props.required);
40
36
 
37
+ const buildConditionContext = useConditionContext({ state: true });
38
+
41
39
  const {
42
40
  placeholder_lid,
43
41
  keyboard_type,
@@ -63,11 +61,14 @@
63
61
  placeholder_horizontal_alignment,
64
62
  placeholder_color,
65
63
  background_color,
64
+ visible,
66
65
  } = $derived.by(() => {
67
66
  return {
68
67
  ...props,
69
- ...getFocusStateProps(focused, props.overrides),
70
- ...getErrorStateProps(error, props.overrides),
68
+ ...resolveOverrideProperties(
69
+ buildConditionContext({ focus: focused, error }),
70
+ props.overrides,
71
+ ),
71
72
  };
72
73
  });
73
74
 
@@ -126,9 +127,7 @@
126
127
  onInputChanged,
127
128
  onSensitiveInputChanged,
128
129
  onReservedAttributeChanged,
129
- selectedPackageId,
130
130
  } = getPaywallContext();
131
- const packageInfo = getOptionalPackageInfoContext();
132
131
 
133
132
  const verticalAlignItems = $derived(
134
133
  vertical_alignment === "top"
@@ -220,17 +219,7 @@
220
219
  keyboard_type === "password" ? "text" : keyboard_type,
221
220
  );
222
221
 
223
- const isVisible = $derived(
224
- evaluateVisibilityConditions(
225
- {
226
- selectedPackageId: $selectedPackageId,
227
- packageInfo: $packageInfo,
228
- variables: $variables ?? {},
229
- },
230
- props.overrides,
231
- props.visible,
232
- ),
233
- );
222
+ const isVisible = $derived(visible !== false);
234
223
 
235
224
  if (validationContext) {
236
225
  $effect(() => {
@@ -32,6 +32,7 @@
32
32
  import { STACK_PAYWALL } from "./fixtures/stack-paywall";
33
33
  import { VARIABLES } from "./fixtures/variables";
34
34
  import { CUSTOM_VARIABLES_PAYWALL } from "./fixtures/custom-variables-paywall";
35
+ import { TAB_STATE_PAYWALL } from "../tabs/fixtures/tab-state-paywall";
35
36
  import { COUNTDOWN_PAYWALL } from "../countdown/fixtures/countdown-paywall";
36
37
  import { mockDateDecorator } from "storybook-mock-date-decorator";
37
38
  import {
@@ -101,6 +102,22 @@
101
102
  }}
102
103
  />
103
104
 
105
+ <Story
106
+ name="State-driven - tab state"
107
+ decorators={[viewportDecorator(375, 640, 0)]}
108
+ play={async ({ canvasElement }) => {
109
+ const annualTab = Array.from(canvasElement.querySelectorAll("button")).find(
110
+ (button) => button.textContent?.includes("Annual"),
111
+ );
112
+ annualTab?.click();
113
+ await waitForAnimations();
114
+ }}
115
+ args={{
116
+ paywallData: TAB_STATE_PAYWALL,
117
+ preferredColorMode: "light",
118
+ }}
119
+ />
120
+
104
121
  <Story
105
122
  name="Sheet"
106
123
  decorators={[viewportDecorator(500, 500, 0)]}
@@ -10,6 +10,11 @@
10
10
  } from "../../stores/inputValidation";
11
11
  import { setLocalizationContext } from "../../stores/localization";
12
12
  import { setPaywallContext } from "../../stores/paywall";
13
+ import {
14
+ PaywallStateStore,
15
+ getPaywallStateContext,
16
+ setPaywallStateContext,
17
+ } from "../../stores/state";
13
18
  import {
14
19
  setVariablesContext,
15
20
  type VariablesStore,
@@ -322,6 +327,12 @@
322
327
  hideBackButtons,
323
328
  });
324
329
 
330
+ // State store: reuse an ancestor store (when nested in a workflow) or create a standalone one.
331
+ const ancestorStateStore = getPaywallStateContext();
332
+ const stateStore = ancestorStateStore ?? new PaywallStateStore();
333
+ stateStore.registerDeclarations(paywallData.state_declarations ?? {});
334
+ if (!ancestorStateStore) setPaywallStateContext(stateStore);
335
+
325
336
  const inputValidationContext = createInputValidationContext();
326
337
  setInputValidationContext(inputValidationContext);
327
338
  setInitialInputSelectionsContext(initialInputSelections);
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { getColorModeContext } from "../../stores/color-mode";
3
+ import { useConditionContext } from "../../stores/condition-context.svelte";
3
4
  import { getPaywallContext } from "../../stores/paywall";
4
- import { getSelectedStateContext } from "../../stores/selected";
5
5
  import BackgroundVideoSurface from "./BackgroundVideoSurface.svelte";
6
6
  import type { SheetProps } from "../../types/components/sheet";
7
7
  import {
@@ -13,18 +13,18 @@
13
13
  videoBackgroundHostStyles,
14
14
  } from "../../utils/video-background-host";
15
15
  import { css, mapSize } from "../../utils/base-utils";
16
- import { getActiveStateProps } from "../../utils/style-utils";
16
+ import { resolveOverrideProperties } from "../../utils/style-utils";
17
17
  import { onMount } from "svelte";
18
18
  import Stack from "../stack/Stack.svelte";
19
19
 
20
20
  const props: SheetProps = $props();
21
21
  const { stack } = props;
22
22
 
23
- const selectedState = getSelectedStateContext();
23
+ const buildConditionContext = useConditionContext({ state: true });
24
24
  const { size, background, background_blur, position } = $derived.by(() => {
25
25
  return {
26
26
  ...props,
27
- ...getActiveStateProps($selectedState, props.overrides),
27
+ ...resolveOverrideProperties(buildConditionContext(), props.overrides),
28
28
  };
29
29
  });
30
30
 
@@ -1,11 +1,7 @@
1
1
  <script lang="ts">
2
2
  import Node from "../paywall/Node.svelte";
3
3
  import { getColorModeContext } from "../../stores/color-mode";
4
- import { getHoverStateContext } from "../../stores/hover";
5
- import { getOptionalPackageInfoContext } from "../../stores/packageInfo";
6
- import { getPaywallContext } from "../../stores/paywall";
7
- import { getSelectedStateContext } from "../../stores/selected";
8
- import { getOptionalVariablesContext } from "../../stores/variables";
4
+ import { useConditionContext } from "../../stores/condition-context.svelte";
9
5
  import BackgroundVideoSurface from "../paywall/BackgroundVideoSurface.svelte";
10
6
  import type { StackProps } from "../../types/components/stack";
11
7
  import {
@@ -26,11 +22,7 @@
26
22
  px,
27
23
  type CSS,
28
24
  } from "../../utils/base-utils";
29
- import {
30
- evaluateVisibilityConditions,
31
- getActiveStateProps,
32
- getHoverStateProps,
33
- } from "../../utils/style-utils";
25
+ import { resolveOverrideProperties } from "../../utils/style-utils";
34
26
  import type { Snippet } from "svelte";
35
27
  import {
36
28
  mapBadge,
@@ -51,11 +43,10 @@
51
43
  const props: StackProps & MiscProps = $props();
52
44
  const { onclick, children, class: classProp, testId } = props;
53
45
 
54
- const selectedState = getSelectedStateContext();
55
- const hoverState = getHoverStateContext();
56
- const packageInfo = getOptionalPackageInfoContext();
57
- const { selectedPackageId } = getPaywallContext();
58
- const variables = getOptionalVariablesContext();
46
+ const buildConditionContext = useConditionContext({
47
+ state: true,
48
+ hover: true,
49
+ });
59
50
  const {
60
51
  components,
61
52
  size,
@@ -69,11 +60,11 @@
69
60
  shape,
70
61
  shadow,
71
62
  badge,
63
+ visible,
72
64
  } = $derived.by(() => {
73
65
  return {
74
66
  ...props,
75
- ...getHoverStateProps($hoverState, props.overrides),
76
- ...getActiveStateProps($selectedState, props.overrides),
67
+ ...resolveOverrideProperties(buildConditionContext(), props.overrides),
77
68
  };
78
69
  });
79
70
 
@@ -134,17 +125,7 @@
134
125
 
135
126
  const badgeStyle = $derived(css(mapBadge(badge, border?.width)));
136
127
 
137
- const isVisible = $derived(
138
- evaluateVisibilityConditions(
139
- {
140
- selectedPackageId: $selectedPackageId,
141
- packageInfo: $packageInfo,
142
- variables: $variables ?? {},
143
- },
144
- props.overrides,
145
- props.visible,
146
- ),
147
- );
128
+ const isVisible = $derived(visible !== false);
148
129
  </script>
149
130
 
150
131
  {#if isVisible}
@@ -1,17 +1,15 @@
1
1
  <script lang="ts">
2
2
  import { getColorModeContext } from "../../stores/color-mode";
3
- import {
4
- getSelectedStateContext,
5
- setSelectedStateContext,
6
- } from "../../stores/selected";
3
+ import { useConditionContext } from "../../stores/condition-context.svelte";
4
+ import { setSelectedStateContext } from "../../stores/selected";
7
5
  import type { TabControlToggleProps } from "../../types/components/tabs";
8
6
  import { css, mapColor } from "../../utils/base-utils";
9
- import { getActiveStateProps } from "../../utils/style-utils";
7
+ import { resolveOverrideProperties } from "../../utils/style-utils";
10
8
  import { getTabsContext } from "./tabs-context";
11
9
 
12
10
  const props: TabControlToggleProps = $props();
13
11
 
14
- const selectedState = getSelectedStateContext();
12
+ const buildConditionContext = useConditionContext({ state: true });
15
13
  const {
16
14
  default_value,
17
15
  thumb_color_on,
@@ -21,7 +19,7 @@
21
19
  } = $derived.by(() => {
22
20
  return {
23
21
  ...props,
24
- ...getActiveStateProps($selectedState, props.overrides),
22
+ ...resolveOverrideProperties(buildConditionContext(), props.overrides),
25
23
  };
26
24
  });
27
25
 
@@ -1,9 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { getColorModeContext } from "../../stores/color-mode";
3
- import { getOptionalPackageInfoContext } from "../../stores/packageInfo";
4
3
  import { getPaywallContext } from "../../stores/paywall";
5
- import { getSelectedStateContext } from "../../stores/selected";
6
- import { getOptionalVariablesContext } from "../../stores/variables";
7
4
  import BackgroundVideoSurface from "../paywall/BackgroundVideoSurface.svelte";
8
5
  import type { TabsProps } from "../../types/components/tabs";
9
6
  import {
@@ -22,29 +19,28 @@
22
19
  mapSize,
23
20
  mapSpacing,
24
21
  } from "../../utils/base-utils";
25
- import {
26
- evaluateVisibilityConditions,
27
- getActiveStateProps,
28
- } from "../../utils/style-utils";
22
+ import { resolveOverrideProperties } from "../../utils/style-utils";
23
+ import { useConditionContext } from "../../stores/condition-context.svelte";
24
+ import { getPaywallStateContext } from "../../stores/state";
29
25
  import { derived, get, readable, writable } from "svelte/store";
30
26
  import Stack from "../stack/Stack.svelte";
31
27
  import { setTabsContext, type SelectTab } from "./tabs-context";
32
28
 
33
29
  const props: TabsProps = $props();
34
- const { name, control, tabs, default_tab_id } = props;
30
+ const { name, control, tabs, default_tab_id, state_updates } = props;
35
31
 
36
- const selectedState = getSelectedStateContext();
37
- const packageInfo = getOptionalPackageInfoContext();
38
- const { selectedPackageId } = getPaywallContext();
39
- const variables = getOptionalVariablesContext();
40
- const { size, padding, margin, background, shape, border, shadow } =
32
+ const buildConditionContext = useConditionContext();
33
+ const stateStore = getPaywallStateContext();
34
+ const { size, padding, margin, background, shape, border, shadow, visible } =
41
35
  $derived.by(() => {
42
36
  return {
43
37
  ...props,
44
- ...getActiveStateProps($selectedState, props.overrides),
38
+ ...resolveOverrideProperties(buildConditionContext(), props.overrides),
45
39
  };
46
40
  });
47
41
 
42
+ const isVisible = $derived(visible !== false);
43
+
48
44
  const getColorMode = getColorModeContext();
49
45
  const colorMode = $derived(getColorMode());
50
46
 
@@ -119,24 +115,28 @@
119
115
  }
120
116
  };
121
117
 
118
+ // Publish the selected tab id into the state store: once on initial setup, then
119
+ // only when the selection actually changes (parity with iOS TabsComponentView's
120
+ // didSeedInitialState + onChangeOf(selectedTabId)). Tracking the last published
121
+ // id keeps a hidden -> visible transition from republishing and clobbering a
122
+ // value another component has already set. Gated behind visibility so a hidden
123
+ // Tabs never publishes. state_declarations.default (which seeds the store) is
124
+ // expected to match default_tab_id (published here); iOS relies on the same.
125
+ let lastPublishedTabId: string | undefined;
126
+ $effect(() => {
127
+ if (!isVisible || !state_updates?.length) return;
128
+ const tabId = tabs[$selectedTabIndex]?.id;
129
+ if (tabId == null || tabId === lastPublishedTabId) return;
130
+ lastPublishedTabId = tabId;
131
+ stateStore?.applyUpdates(state_updates, tabId);
132
+ });
133
+
122
134
  setTabsContext({
123
135
  control: readable(control),
124
136
  selectedTabId: derived(tab, (tab) => tab?.id ?? ""),
125
137
  selectTab,
126
138
  isActive: derived(selectedTabIndex, (value) => value === 1),
127
139
  });
128
-
129
- const isVisible = $derived(
130
- evaluateVisibilityConditions(
131
- {
132
- selectedPackageId: $selectedPackageId,
133
- packageInfo: $packageInfo,
134
- variables: $variables ?? {},
135
- },
136
- props.overrides,
137
- props.visible,
138
- ),
139
- );
140
140
  </script>
141
141
 
142
142
  {#if isVisible}
@@ -0,0 +1,25 @@
1
+ import type { TextNodeProps } from "../../../types/components/text";
2
+ import type { PaywallData } from "../../../types/paywall";
3
+ import type { StateDeclaration, StateUpdate } from "../../../types/state";
4
+ import type { UIConfig } from "../../../types/ui-config";
5
+ export declare function createStateConditionText({ id, textLid, stateKey, stateValue, conditionOperator, hiddenWhenMatches, }: {
6
+ id: string;
7
+ textLid: string;
8
+ stateKey: string;
9
+ stateValue: string;
10
+ conditionOperator: "=" | "!=";
11
+ hiddenWhenMatches: boolean;
12
+ }): TextNodeProps;
13
+ export declare function buildTabStatePaywall({ defaultTabId, stateDeclarations, tabsStateUpdates, siblingComponents, tabsVisible, localizations, paywallId, }: {
14
+ defaultTabId: string;
15
+ stateDeclarations?: Record<string, StateDeclaration>;
16
+ tabsStateUpdates?: StateUpdate[];
17
+ siblingComponents?: TextNodeProps[];
18
+ tabsVisible?: boolean;
19
+ localizations?: Record<string, string>;
20
+ paywallId?: string;
21
+ }): {
22
+ paywallData: PaywallData;
23
+ uiConfig: UIConfig;
24
+ };
25
+ export declare const TAB_STATE_PAYWALL: PaywallData;