# Actions and Behaviors Reference

# Behaviors

Enables visual (non-interactive) highlight for the cell/cells based on the match of an entry property (usually `id`) and a constant or some app state dynamic value:
- storage key (`@{ctx/namespace.key}`)
- screen state key (`@{screen/key}`)
- currently played entry id (comes from Zapp cell style automatically)
- subscribed push topics (`@{push/topics}`, always multi-select)
- and so on

Can be combined with actions to make component behave as a single/multiselect UI control.

## SingleSelect

`current_selection` can use an `@ notation` path or a *string* value.
`selector` is a dot-separated path to the entry property that will be compared with the `current_selection` resolved value. Entry id will be used if field is not provided.

```json
{
  "behavior": {
    "select_mode": "single",
    "current_selection": "@{ctx/user_preferences.genres}",
    "selector": "extensions.tag"
  }
}
```

Constant current selection can be used to highlight a specific cell:

```json
{
  "behavior": {
    "select_mode": "single",
    "current_selection": "premium",
    "selector": "extensions.subscription_type"
  }
}
```

## MultiSelect

Constant `current_selection` is passed as an **array** of values (**NOT** comma-separated strings):

```json
{
  "behavior": {
    "select_mode": "multi",
    "current_selection": ["horror", "action", "comedy"],
    "selector": "extensions.tag"
  }
}
```

`current_selection` can also use an *@ notation* path for dynamic value resolving. For some value providers (storages, screen data), `select_mode` is required to interpret storage value (always a string) as an array of comma-separated values.

```json
{
  "behavior": {
    "select_mode": "multi",
    "current_selection": "@{ctx/user_preferences.genres}",
    "selector": "extensions.tag"
  }
}
```

---

# Actions

Basic actions that can be executed on a cell click.

## Generic Actions

### sendCloudEvent

Sends a cloud event to a specified URL with typed data and metadata.

If `inflateData` is **true**, data params using **@ syntax** will be inflated (resolved from app state/resolvers).

```json
{
  "type": "sendCloudEvent",
  "options": {
    "url": "https://tbn-dsp-curation-api-stage.tbnstage.com/v1/save_network",
    "type": "com.applicaster.selector.action.v1",
    "subject": "preference_selection",
    "data": {
      "entry": "@{entry/}",
      "pin_code": "@{ctx/parent_lock.pin}",
      "const_value": "some_value"
    },
    "inflateData": true
  }
}
```

### showToast

Displays a toast notification on the screen.

**Options:**
- `message` (**required**, string): Main text displayed in the toast notification.
- `id` (optional, string): Unique identifier for the toast. If re-shown with an active id, the existing toast content is updated in place.
- `extraMessage` (optional, string): Secondary line of text. TV renderers display this as a subtitle; mobile renderers ignore it.
- `timeout` (optional, number): Duration in milliseconds before the toast auto-hides. Defaults to `4000` (4 seconds). Pass `0` to keep persistent until manually dismissed.
- `style` (optional, object): Custom style properties for the toast:
  - `backgroundColor` (string): Background color (e.g., `"#000000"`, `"rgba(0, 0, 0, 0.8)"`).
  - `color` (string): Text color for the message (e.g., `"#FFFFFF"`).
  - `fontFamily` (string): Font family for the text.
  - `fontSize` (number): Font size in points.
  - `lineHeight` (number): Line height in points.
  - `letterSpacing` (number): Letter spacing in points.

**Example:**

```json
{
  "type": "showToast",
  "options": {
    "message": "Added to queue",
    "extraMessage": "Up next in your playlist",
    "timeout": 4000,
    "style": {
      "backgroundColor": "#1A1A1A",
      "color": "#FFFFFF",
      "fontSize": 14
    }
  }
}
```

### appRestart

Performs application hot restart. **Must be the last action in the list**.

```json
{
  "type": "appRestart"
}
```

### switchLayout

Switches the application layout. Layout selection is persistent, but only applied if the Layout Manager Plugin is not present in the app.

```json
{
  "type": "switchLayout",
  "options": {
    "layoutId": "5c1e9884-3161-4be4-8519-224392b8ee86"
  }
}
```

Can be combined with a `behavior` feed extension to highlight an entry corresponding to the current layout. `selector` can be used when layout id is stored in the entry extension instead of entry id:

```json
{
  "behavior": {
    "current_selection": "@{ctx/active_layout_id}",
    "select_mode": "single"
  }
}
```

### navigateToScreen

Navigates to the screen associated with the type provided in `typeMapping`. Recommended to be the last action in the list.

```json
{
  "type": "navigateToScreen",
  "options": {
    "typeMapping": "devices"
  }
}
```

### goBack

Navigates the user back in the screen stack. Recommended to be the last action in the list.

**Options:**
- `fallbackToHome` (optional, boolean, default `true`): Go to the home screen when there is no screen to go back to. With `false` and nothing to go back to, the action logs and returns `ActionResult.Error` without navigating. With `true`, the navigator handles the empty stack itself.
- `backToTop` (optional, boolean, default `false`): Return to the first screen of the stack instead of the previous one.

```json
{
  "type": "goBack",
  "options": {
    "fallbackToHome": true,
    "backToTop": false
  }
}
```

### goHome

Navigates the user to the home screen. Has no options: the navigator's `initialLaunch` flag selects the offline home river during app bootstrap, so it is not a per-action choice.

```json
{
  "type": "goHome"
}
```

## Screen-Scoped Actions

Screen state is not persistent and will be lost when the screen is closed. Screen state does not have namespaces.

### screenSetVariable

Sets a screen state variable to a value. Value is taken from:
- The path stored in `selector` property if present in options (error if path is missing or value is not string).
- `entry.extensions.tag` if present.
- `entry.id` otherwise.

```json
{
  "type": "screenSetVariable",
  "options": {
    "key": "apply_filter",
    "value": "true",
    "selector": "extensions.tag"
  }
}
```

### screenToggleFlag

Adds or removes a tag from a comma-separated list of unique tags in a screen state variable. Value is taken from:
- `tag` option if present (does not require entry context). **Note: Not implemented yet!**
- The path stored in `selector` property if present in options (error if path is missing or value is not string).
- `entry.extensions.tag` if present.
- `entry.id` otherwise.

```json
{
  "type": "screenToggleFlag",
  "options": {
    "key": "selected_genres",
    "tag": "horror",
    "selector": "extensions.tag"
  }
}
```

### refreshComponent

Reloads the feed backing the current component. Later, ability to pass component ID or data feed URLs to refresh will be added.

```json
{
  "type": "refreshComponent",
  "options": {}
}
```

## Language Selector Plugin Actions

### setUILanguage

Sets app language and restarts the application to apply the change. If `noConfirmation` is set to true, the action will be executed without a confirmation dialog.

```json
{
  "type": "setUILanguage",
  "options": {
    "languageCode": "en-UK",
    "noConfirmation": true
  }
}
```

## Storage Actions

### localStorageSet

Sets local storage key values in namespaces provided in `content` option.

```json
{
  "type": "localStorageSet",
  "options": {
    "content": {
      "user_preferences": {
        "profile": 154970
      }
    }
  }
}
```

### sessionStorageSet

Sets session storage key values in namespaces provided in `content` option.

```json
{
  "type": "sessionStorageSet",
  "options": {
    "content": {
      "user_preferences": {
        "profile": 154970
      }
    }
  }
}
```

### localStorageToggleFlag

Adds or removes a tag from a comma-separated list of unique tags in a local storage key in the provided namespace. Tag value is taken from:
- `tag` option if present (does not require entry context). **Note: Not implemented yet!**
- The path stored in `selector` property if present in options (error if path is missing or value is not string).
- `entry.extensions.tag` if present.
- `entry.id` otherwise.

Unlike `localStorageSet`, only a single key is supported.

**Options:**
- `key` (string): Storage key path (e.g., `"user_preferences.genres"`).
- `tag` (string, optional): Tag value to toggle.
- `selector` (string, optional): Path to entry property containing tag value.
- `max_items` (number, optional): Maximum number of items that can be stored in the list. If limit is reached, item will not be added and `cancel` will be generated. No limit by default. Note: if storage already holds values over the limit (e.g., loaded externally or limit introduced later), it will not be truncated.

```json
{
  "type": "localStorageToggleFlag",
  "options": {
    "key": "user_preferences.genres",
    "tag": "horror",
    "selector": "extensions.genre_tag",
    "max_items": 3
  }
}
```

### sessionStorageToggleFlag

Adds or removes a tag from a comma-separated list of unique tags in a session storage key in the provided namespace. Tag value is taken from:
- `tag` option if present (does not require entry context). **Note: Not implemented yet!**
- The path stored in `selector` property if present in options (error if path is missing or value is not string).
- `entry.extensions.tag` if present.
- `entry.id` otherwise.

Unlike `sessionStorageSet`, only a single key is supported.

**Options:**
- `key` (string): Storage key path (e.g., `"user_preferences.genres"`).
- `tag` (string, optional): Tag value to toggle.
- `selector` (string, optional): Path to entry property containing tag value.
- `max_items` (number, optional): Maximum number of items that can be stored. If limit is reached, item will not be added and `cancel` will be generated.

```json
{
  "type": "sessionStorageToggleFlag",
  "options": {
    "key": "user_preferences.genres",
    "selector": "extensions.genre_tag",
    "tag": "horror",
    "max_items": 3
  }
}
```

## UI Actions

### openBottomSheet

Opens a bottom sheet menu surface specified by header and content options.

```json
{
  "type": "openBottomSheet",
  "options": {
    "modal_presentation": {
      "type": "bottom_sheet",
      "style_variant": "modal_bottom_sheet"
    },
    "header": {
      "title": "Edit Playlist",
      "subtitle": "My Playlist"
    },
    "content": {
      "title": "My Playlist",
      "itemsUrl": "https://server.com/user/collections/123?editable=true",
      "items": []
    }
  }
}
```

### showTextInput

Triggers a text input bottom sheet/dialog to create or edit text (e.g., playlist names). Defines UI labels and either a single `action` or an array of `actions` to invoke sequentially on submit (such as dispatching a cloud event, showing a toast notification, and refreshing the component).

```json
{
  "type": "showTextInput",
  "options": {
    "headerTitle": "Create New Playlist",
    "inputLabel": "Name your playlist",
    "defaultValue": "",
    "buttonLabel": "Create",
    "actions": [
      {
        "type": "sendCloudEvent",
        "options": {
          "url": "https://server.com/cloud-events",
          "type": "com.applicaster.collection.create.v1",
          "subject": "create_collection",
          "data": {
            "sourceCollectionId": "system_gsc"
          }
        }
      },
      {
        "type": "showToast",
        "options": {
          "message": "Playlist created."
        }
      },
      {
        "type": "refreshComponent"
      }
    ]
  }
}
```

### confirmDialog

Shows a confirmation dialog with provided message and title. If the user confirms, the next action in the array will be executed. If the user cancels, the execution chain is cancelled without generating an error.

```json
{
  "type": "confirmDialog",
  "options": {
    "message": "Region will be changed to UK. Are you sure you want to continue?",
    "title": "Region change",
    "okButtonText": "Yes",
    "cancelButtonText": "No"
  }
}
```

## First Time User Experience Plugin Actions

Available while a First Time User Experience screen is open.

### completeFTUE

Completes and closes the currently opened First Time User Experience screen. Has no options.

```json
{
  "type": "completeFTUE"
}
```

## Screen Hook Wrapper Actions

### completeHook

Completes the currently opened screen hook wrapper hook with a desired result.

**Success completion:**

```json
{
  "type": "completeHook",
  "options": {
    "success": true
  }
}
```

**Error completion:**

```json
{
  "type": "completeHook",
  "options": {
    "errorMessage": "You shall not pass!"
  }
}
```

**Note:** Error will be logged to X-Ray but will not be shown to the user.

---

# Roles

Roles are feed extensions that transform feeds on load by automatically injecting suitable actions and behaviors. Roles are interpreted by feed decorators and client renderers to pick appropriate cell styles, affordances, actions, and behaviors.

## push_topic

Makes the feed able to control push topics. Topic id comes from entry ID or path configured on the plugin level (e.g., `extensions.tag`). Note that properties like `selector`, `initial_value`, etc., are not supported; everything is controlled by push plugin configuration.

```json
{
  "extensions": {
    "role": "push_topic"
  }
}
```

## language_selector

Makes feed perform as Language Selector feed by automatically injecting `setUILanguage` action and single-selection behavior feed extensions. Language code is taken from `extensions.tag` if present, or entry `id`. Language code must match codes entered in Zapp Application settings.

## preference_editor

Allows setting/removing/modifying values in local storage, session storage, or screen state. Supports both multi-select (tags) and single-option (radiobutton) modes.

### Tags (multiselect) mode

Adds ability to use storage values as a *comma-separated list* of unique tags.

**Options:**
- `select_mode` (string): `"multi"`.
- `key` (string): Storage key path (e.g., `"user_preferences.genres"`).
- `scope` (string, optional): Target storage level (`"local"`, `"session"`, `"screen"`). Default is `"local"` (persistent).
- `initial_value` (string, optional): Initialize the value if not present.
- `current_value` (string, optional): Overwrite the value even if already present. Only one of `initial_value` or `current_value` should be passed.
- `max_items` (number, optional): Maximum number of items that can be selected. Optional, no limit by default. Message presented if user attempts to add over the limit. Note: if storage already holds values over the limit, it will not be truncated.

**Feed extension (new format):**

```json
{
  "extensions": {
    "role": "preference_editor",
    "preference_editor_options": {
      "select_mode": "multi",
      "key": "user_preferences.genres",
      "scope": "local",
      "initial_value": "horror,action,comedy",
      "current_value": "horror,action,comedy",
      "max_items": 3
    }
  }
}
```

**Old format with explicit behavior block (QB 13):**

```json
{
  "extensions": {
    "role": "preference_editor",
    "behavior": {
      "select_mode": "multi",
      "current_selection": "@{ctx/user_preferences.genres}"
    },
    "preference_editor_options": {
      "key": "user_preferences.genres",
      "initial_value": "horror,action,comedy",
      "current_value": "horror,action,comedy",
      "max_items": 3
    }
  }
}
```

Tag value is taken from entry `extensions.tag` if present, or entry id otherwise.

**Entry extension example (optional):**

```json
{
  "extensions": {
    "tag": "horror"
  }
}
```

### Single option (radiobutton) mode

Stores only a single current value.

**Options:**
- `select_mode` (string): `"single"`.
- `key` (string): Storage key path (e.g., `"user_preferences.region"`).
- `scope` (string, optional): Target storage level. Default is `"local"`.
- `initial_value` (string, optional): Initialize if not present.
- `current_value` (string, optional): Overwrite if present. Only one of `initial_value` or `current_value` should be passed.

**Feed extension (new format):**

```json
{
  "extensions": {
    "role": "preference_editor",
    "preference_editor_options": {
      "select_mode": "single",
      "key": "user_preferences.region",
      "scope": "local",
      "initial_value": "us",
      "current_value": "us"
    }
  }
}
```

Value is taken from entry `extensions.tag` if present, or entry id otherwise. Passing `selector` to generated behavior is not currently supported.

## collection_selector

Used for feeds where users select items or collections (e.g., choice lists, playlist selection). Works with a `behavior` block defining `select_mode` (`single` | `multi`) and `current_selection`.

```json
{
  "extensions": {
    "role": "collection_selector",
    "behavior": {
      "select_mode": "multi",
      "current_selection": ["playlist-1"]
    }
  }
}
```

## dynamic_collection

See [Dynamic Collections](./dynamic-collections.md) for configuration, item-scoped actions, Cloud Event routing, and complete examples.
